"use strict"
ScopeLinter = require "./ScopeLinter"
module.exports = class Coffeescope2
rule:
name: "check_scope"
description: """
This rule checks the usage of your variables and prevents common
mistakes or enforces style conventions
It can look for and report:
- Undefined variables
- Unused variables and arguments (i.e. values that were
assigned to but never read)
- Arguments that shadow variables from an outer scope (due to
the scoping rules in coffeescript, these can only
be arguments)
- Variables that overwrite other variables from an outer
scope (due to the scoping rules in coffeescript, these can
never be arguments)
Besides the standard level option, this rule looks for
the following additional properties:
environments
- A list of one or more environments from which to import
global variables. Available sets are:
builtin, es5,
es6,
browser,
worker,
node,
commonjs,
amd,
mocha,
jasmine,
jest,
qunit,
phantomjs,
couch,
rhino,
nashorn,
wsh,
jquery,
yui,
shelljs,
prototypejs,
meteor,
mongo,
applescript,
serviceworker,
atomtest,
embertest,
protractor,
shared-node-browser,
webextension,
greasemonkey,
cake.
This influences all the rules defined by this module as it
injects global variables within a file's scope. The
default is ["builtin"] which includes all es3
globals
globals
- An object where keys are variable names and values are
booleans. A value of true means that said variable is
visible in all global scopes and can be assigned to, while
a value of false means that the variable is read-only and a
warning will be issued whenever it's written to. This
influences all the rules defined by this module as it
injects global variables within a file's scope. Defaults to
an empty object: {}.
overwrite
- A boolean representing whether to warn when assigning to a
variable that was defined in a parent scope. Because
coffeescript lacks a `let` statement, assigning to a
variable will only create a new variable if there are no
matching variables of the same name in the current scope.
This rule allows you to discourage code that relies on this
and prevents unintentional occurences. The default value is
true meaning assigning variables from an outer
scope will issue a warning / error.
same_scope
- A boolean representing whether to warn a variable is
modified regardless of the scope it was defined in,
effectively preventing reference mutation. In this regard,
it forces all variables to behave similarly to the
const keyword in ES6+. Defaults to
false.
shadow
- A boolean value that specifies whether shadowing existing
variables is accepted or not. This rule behaves similarly
to `overwrite`, but it only affects function arguments, as
that's the only mechanism provided by coffeescript that can
shadow variables without overwriting them. Defaults to
true
shadow_builtins
- A boolean value that specifies whether shadowing of builtin
global variables (as defined by
environments
and globals) is accepted or not. Due to the
way coffeescript's scopes work, assigning to such a global
will not overwrite it; it will instead create a new
variable in the current scope that will shadow it. Defaults
to false because some browser builtins are
extremely generic: name, status
shadow_exceptions
- A list of regular expressions that further customizes the
behavior of
shadow by allowing one or more
names to be exempt from shadowing warnings. The default
value is ["err", "next"] to allow nesting of
Node.JS-style continuations. To be skipped, the name must
match the entire expression:
-
"ba."
will match
"bar" and
"baz"
but not
"bard" or
"foobar".
-
"ba.*"
will match
"ba" and
"bar" and
"bard".
undefined
- A boolean value that specifies whether to raise a warning /
error in the event an undefined variable is accessed. The
default and highly recommended value is
true. To work around framework-specific
messages, use
environments and / or
globals instead.
hoist_local
- A boolean value that specifies whether to warn about
relying on variable hosting to the top of their scope. The
default value is true because of
coffeescript's semantics. Changing it to false will start
producing warnings whenever you attempt to access a local
variable before you first assigned to it. We recommend
switching this to false as it results in
easier to read code.
hoist_parent
- Similar to
hoist_local, but it allows
referencing a variable before it was defined, provided it
belongs to (is written in) a parent scope. The default
value is true.
unused_variables
- A boolean value that specifies whether to show a message if
a variable is assigned to but its value is never read.
unused_arguments
- A boolean value that specifies whether to raise a warning /
error whenever a function argument is never read. Note that
arguments behave like variables for all intents and
purposes other than scoping and will respect any and all
overwrite and shadow rules and
exceptions.
unused_classes
- A boolean value that specifies whether to raise a warning /
error whenever a class is defined but never used. Classes
that are part of an assignment statement never trigger
this warning. Defaults to true because of
historical reasons and the low rate of false positives
generated on most codebases.
unused_exceptions
- A list of regular expressions that further customizes the
behavior of
unused_ by allowing one or more
names to be exempt from unused warnings. The default value
is ["_.+"] to skip names starting with
underscores. To be skipped, the name must match the entire
expression:
-
"ba."
will match
"bar" and
"baz"
but not
"bard" or
"foobar".
-
"ba.*"
will match
"ba" and
"bar" and
"bard".
"""
level: "warn"
message: "Scope error"
# global variable config
environments: ["builtin"] # which set(s) of global vars to use
globals: {} # should map names to true if writable, false if read-only
overwrite: true # warn when overwriting a variable from outer scope
same_scope: false # don't forbid variable overwriting (const-like)
shadow: true # warn when overwriting a variable from outer scope
shadow_builtins: false # don't warn when "assigning to" a superglobal
shadow_exceptions: ["err", "next"] # list of args that may be shadowed
undefined: true # warn when accessing an undefined variable
hoist_local: true # allow same-scope hoisting
hoist_parent: true # allow parent-scope hoisting
unused_variables: true # warn when a variable is not accessed
unused_arguments: false # warn when an argument is not accessed
unused_classes: true # warn when a class is not instantiated or copied
unused_exceptions: ["_.+"] # list of names that can be unused
lintAST: (root, {config, createError}) ->
for spec in ScopeLinter.default().lint(root, config[@rule.name])
@errors.push(createError(spec))
undefined
module.exports.ScopeLinter = ScopeLinter