eslint 3.9.0 → 3.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +60 -1
- package/LICENSE +1 -1
- package/README.md +1 -1
- package/bin/eslint.js +5 -5
- package/conf/eslint.json +1 -0
- package/lib/ast-utils.js +1 -3
- package/lib/cli-engine.js +9 -11
- package/lib/code-path-analysis/debug-helpers.js +4 -4
- package/lib/config/autoconfig.js +23 -35
- package/lib/config/config-file.js +1 -1
- package/lib/config/config-initializer.js +12 -20
- package/lib/config/config-ops.js +7 -9
- package/lib/config/config-rule.js +14 -18
- package/lib/config/config-validator.js +3 -3
- package/lib/config/environments.js +1 -1
- package/lib/config.js +2 -2
- package/lib/eslint.js +21 -23
- package/lib/file-finder.js +1 -1
- package/lib/formatters/checkstyle.js +2 -2
- package/lib/formatters/compact.js +2 -2
- package/lib/formatters/html.js +9 -11
- package/lib/formatters/jslint-xml.js +2 -2
- package/lib/formatters/junit.js +2 -2
- package/lib/formatters/stylish.js +3 -7
- package/lib/formatters/table.js +4 -6
- package/lib/formatters/tap.js +2 -2
- package/lib/formatters/unix.js +2 -2
- package/lib/formatters/visualstudio.js +2 -2
- package/lib/load-rules.js +1 -1
- package/lib/rules/arrow-body-style.js +1 -1
- package/lib/rules/arrow-parens.js +9 -2
- package/lib/rules/brace-style.js +2 -2
- package/lib/rules/comma-spacing.js +2 -2
- package/lib/rules/comma-style.js +51 -4
- package/lib/rules/consistent-this.js +5 -9
- package/lib/rules/constructor-super.js +1 -1
- package/lib/rules/curly.js +10 -7
- package/lib/rules/default-case.js +1 -3
- package/lib/rules/eqeqeq.js +19 -7
- package/lib/rules/func-names.js +23 -4
- package/lib/rules/global-require.js +3 -7
- package/lib/rules/handle-callback-err.js +1 -3
- package/lib/rules/id-length.js +1 -1
- package/lib/rules/indent.js +10 -25
- package/lib/rules/key-spacing.js +4 -4
- package/lib/rules/keyword-spacing.js +1 -1
- package/lib/rules/lines-around-comment.js +5 -11
- package/lib/rules/lines-around-directive.js +23 -4
- package/lib/rules/max-len.js +5 -11
- package/lib/rules/max-lines.js +4 -12
- package/lib/rules/max-statements.js +11 -2
- package/lib/rules/newline-after-var.js +1 -1
- package/lib/rules/newline-before-return.js +2 -4
- package/lib/rules/no-alert.js +2 -4
- package/lib/rules/no-class-assign.js +1 -1
- package/lib/rules/no-const-assign.js +1 -1
- package/lib/rules/no-control-regex.js +2 -2
- package/lib/rules/no-duplicate-case.js +1 -1
- package/lib/rules/no-ex-assign.js +1 -1
- package/lib/rules/no-extend-native.js +3 -7
- package/lib/rules/no-extra-boolean-cast.js +14 -3
- package/lib/rules/no-extra-parens.js +4 -4
- package/lib/rules/no-func-assign.js +1 -1
- package/lib/rules/no-implicit-globals.js +4 -4
- package/lib/rules/no-irregular-whitespace.js +3 -3
- package/lib/rules/no-mixed-operators.js +1 -3
- package/lib/rules/no-mixed-requires.js +2 -2
- package/lib/rules/no-mixed-spaces-and-tabs.js +3 -3
- package/lib/rules/no-multi-spaces.js +1 -1
- package/lib/rules/no-new-symbol.js +1 -1
- package/lib/rules/no-redeclare.js +2 -4
- package/lib/rules/no-restricted-globals.js +2 -2
- package/lib/rules/no-restricted-imports.js +45 -11
- package/lib/rules/no-restricted-modules.js +53 -36
- package/lib/rules/no-restricted-syntax.js +2 -4
- package/lib/rules/no-return-await.js +77 -0
- package/lib/rules/no-tabs.js +1 -1
- package/lib/rules/no-this-before-super.js +2 -2
- package/lib/rules/no-undef.js +1 -1
- package/lib/rules/no-underscore-dangle.js +1 -3
- package/lib/rules/no-unused-vars.js +2 -6
- package/lib/rules/no-use-before-define.js +1 -1
- package/lib/rules/no-useless-escape.js +8 -54
- package/lib/rules/no-useless-return.js +6 -0
- package/lib/rules/no-warning-comments.js +2 -2
- package/lib/rules/object-shorthand.js +21 -10
- package/lib/rules/one-var-declaration-per-line.js +1 -1
- package/lib/rules/prefer-const.js +1 -3
- package/lib/rules/prefer-reflect.js +2 -1
- package/lib/rules/quote-props.js +1 -1
- package/lib/rules/quotes.js +1 -1
- package/lib/rules/radix.js +2 -2
- package/lib/rules/require-jsdoc.js +8 -0
- package/lib/rules/sort-vars.js +1 -1
- package/lib/rules/space-in-parens.js +1 -1
- package/lib/rules/space-infix-ops.js +1 -1
- package/lib/rules/spaced-comment.js +1 -1
- package/lib/rules/symbol-description.js +1 -1
- package/lib/rules/valid-jsdoc.js +3 -3
- package/lib/rules.js +2 -2
- package/lib/testers/event-generator-tester.js +5 -5
- package/lib/testers/rule-tester.js +11 -13
- package/lib/timing.js +11 -13
- package/lib/util/comment-event-generator.js +1 -1
- package/lib/util/glob-util.js +3 -5
- package/lib/util/npm-util.js +1 -1
- package/lib/util/source-code-fixer.js +3 -5
- package/lib/util/source-code-util.js +4 -4
- package/lib/util/source-code.js +3 -3
- package/lib/util/traverser.js +1 -3
- package/lib/util/xml-escape.js +1 -1
- package/package.json +3 -3
package/lib/rules/max-lines.js
CHANGED
@@ -114,26 +114,18 @@ module.exports = {
|
|
114
114
|
|
115
115
|
return {
|
116
116
|
"Program:exit"() {
|
117
|
-
let lines = sourceCode.lines.map(
|
118
|
-
return { lineNumber: i + 1, text };
|
119
|
-
});
|
117
|
+
let lines = sourceCode.lines.map((text, i) => ({ lineNumber: i + 1, text }));
|
120
118
|
|
121
119
|
if (skipBlankLines) {
|
122
|
-
lines = lines.filter(
|
123
|
-
return l.text.trim() !== "";
|
124
|
-
});
|
120
|
+
lines = lines.filter(l => l.text.trim() !== "");
|
125
121
|
}
|
126
122
|
|
127
123
|
if (skipComments) {
|
128
124
|
const comments = sourceCode.getAllComments();
|
129
125
|
|
130
|
-
const commentLines = lodash.flatten(comments.map(
|
131
|
-
return getLinesWithoutCode(comment);
|
132
|
-
}));
|
126
|
+
const commentLines = lodash.flatten(comments.map(comment => getLinesWithoutCode(comment)));
|
133
127
|
|
134
|
-
lines = lines.filter(
|
135
|
-
return !lodash.includes(commentLines, l.lineNumber);
|
136
|
-
});
|
128
|
+
lines = lines.filter(l => !lodash.includes(commentLines, l.lineNumber));
|
137
129
|
}
|
138
130
|
|
139
131
|
if (lines.length > max) {
|
@@ -84,9 +84,18 @@ module.exports = {
|
|
84
84
|
*/
|
85
85
|
function reportIfTooManyStatements(node, count, max) {
|
86
86
|
if (count > max) {
|
87
|
+
const messageEnd = " has too many statements ({{count}}). Maximum allowed is {{max}}.";
|
88
|
+
let name = "This function";
|
89
|
+
|
90
|
+
if (node.id) {
|
91
|
+
name = `Function '${node.id.name}'`;
|
92
|
+
} else if (node.parent.type === "MethodDefinition" || node.parent.type === "Property") {
|
93
|
+
name = `Function '${context.getSource(node.parent.key)}'`;
|
94
|
+
}
|
95
|
+
|
87
96
|
context.report(
|
88
97
|
node,
|
89
|
-
|
98
|
+
name + messageEnd,
|
90
99
|
{ count, max });
|
91
100
|
}
|
92
101
|
}
|
@@ -146,7 +155,7 @@ module.exports = {
|
|
146
155
|
return;
|
147
156
|
}
|
148
157
|
|
149
|
-
topLevelFunctions.forEach(
|
158
|
+
topLevelFunctions.forEach(element => {
|
150
159
|
const count = element.count;
|
151
160
|
const node = element.node;
|
152
161
|
|
@@ -37,7 +37,7 @@ module.exports = {
|
|
37
37
|
const mode = context.options[0] === "never" ? "never" : "always";
|
38
38
|
|
39
39
|
// Cache starting and ending line numbers of comments for faster lookup
|
40
|
-
const commentEndLine = sourceCode.getAllComments().reduce(
|
40
|
+
const commentEndLine = sourceCode.getAllComments().reduce((result, token) => {
|
41
41
|
result[token.loc.start.line] = token.loc.end.line;
|
42
42
|
return result;
|
43
43
|
}, {});
|
@@ -36,9 +36,7 @@ module.exports = {
|
|
36
36
|
function isPrecededByTokens(node, testTokens) {
|
37
37
|
const tokenBefore = sourceCode.getTokenBefore(node);
|
38
38
|
|
39
|
-
return testTokens.some(
|
40
|
-
return tokenBefore.value === token;
|
41
|
-
});
|
39
|
+
return testTokens.some(token => tokenBefore.value === token);
|
42
40
|
}
|
43
41
|
|
44
42
|
/**
|
@@ -82,7 +80,7 @@ module.exports = {
|
|
82
80
|
return numLinesComments;
|
83
81
|
}
|
84
82
|
|
85
|
-
comments.forEach(
|
83
|
+
comments.forEach(comment => {
|
86
84
|
numLinesComments++;
|
87
85
|
|
88
86
|
if (comment.type === "Block") {
|
package/lib/rules/no-alert.js
CHANGED
@@ -41,10 +41,8 @@ function report(context, node, identifierName) {
|
|
41
41
|
* @returns {Reference|null} Returns the found reference or null if none were found.
|
42
42
|
*/
|
43
43
|
function findReference(scope, node) {
|
44
|
-
const references = scope.references.filter(
|
45
|
-
|
46
|
-
reference.identifier.range[1] === node.range[1];
|
47
|
-
});
|
44
|
+
const references = scope.references.filter(reference => reference.identifier.range[0] === node.range[0] &&
|
45
|
+
reference.identifier.range[1] === node.range[1]);
|
48
46
|
|
49
47
|
if (references.length === 1) {
|
50
48
|
return references[0];
|
@@ -30,7 +30,7 @@ module.exports = {
|
|
30
30
|
* @returns {void}
|
31
31
|
*/
|
32
32
|
function checkVariable(variable) {
|
33
|
-
astUtils.getModifyingReferences(variable.references).forEach(
|
33
|
+
astUtils.getModifyingReferences(variable.references).forEach(reference => {
|
34
34
|
context.report(
|
35
35
|
reference.identifier,
|
36
36
|
"'{{name}}' is a class.",
|
@@ -30,7 +30,7 @@ module.exports = {
|
|
30
30
|
* @returns {void}
|
31
31
|
*/
|
32
32
|
function checkVariable(variable) {
|
33
|
-
astUtils.getModifyingReferences(variable.references).forEach(
|
33
|
+
astUtils.getModifyingReferences(variable.references).forEach(reference => {
|
34
34
|
context.report(
|
35
35
|
reference.identifier,
|
36
36
|
"'{{name}}' is constant.",
|
@@ -85,7 +85,7 @@ module.exports = {
|
|
85
85
|
stringControlChars = regexStr.slice(subStrIndex, -1)
|
86
86
|
.split(consecutiveSlashes)
|
87
87
|
.filter(Boolean)
|
88
|
-
.map(
|
88
|
+
.map(x => {
|
89
89
|
const match = x.match(stringControlCharWithoutSlash) || [x];
|
90
90
|
|
91
91
|
return `\\${match[0]}`;
|
@@ -93,7 +93,7 @@ module.exports = {
|
|
93
93
|
}
|
94
94
|
}
|
95
95
|
|
96
|
-
return controlChars.map(
|
96
|
+
return controlChars.map(x => {
|
97
97
|
const hexCode = `0${x.charCodeAt(0).toString(16)}`.slice(-2);
|
98
98
|
|
99
99
|
return `\\x${hexCode}`;
|
@@ -30,7 +30,7 @@ module.exports = {
|
|
30
30
|
* @returns {void}
|
31
31
|
*/
|
32
32
|
function checkVariable(variable) {
|
33
|
-
astUtils.getModifyingReferences(variable.references).forEach(
|
33
|
+
astUtils.getModifyingReferences(variable.references).forEach(reference => {
|
34
34
|
context.report(
|
35
35
|
reference.identifier,
|
36
36
|
"Do not assign to the exception parameter.");
|
@@ -44,14 +44,10 @@ module.exports = {
|
|
44
44
|
|
45
45
|
const config = context.options[0] || {};
|
46
46
|
const exceptions = config.exceptions || [];
|
47
|
-
let modifiedBuiltins = Object.keys(globals.builtin).filter(
|
48
|
-
return builtin[0].toUpperCase() === builtin[0];
|
49
|
-
});
|
47
|
+
let modifiedBuiltins = Object.keys(globals.builtin).filter(builtin => builtin[0].toUpperCase() === builtin[0]);
|
50
48
|
|
51
49
|
if (exceptions.length) {
|
52
|
-
modifiedBuiltins = modifiedBuiltins.filter(
|
53
|
-
return exceptions.indexOf(builtIn) === -1;
|
54
|
-
});
|
50
|
+
modifiedBuiltins = modifiedBuiltins.filter(builtIn => exceptions.indexOf(builtIn) === -1);
|
55
51
|
}
|
56
52
|
|
57
53
|
return {
|
@@ -72,7 +68,7 @@ module.exports = {
|
|
72
68
|
return;
|
73
69
|
}
|
74
70
|
|
75
|
-
modifiedBuiltins.forEach(
|
71
|
+
modifiedBuiltins.forEach(builtin => {
|
76
72
|
if (lhs.object.object.name === builtin) {
|
77
73
|
context.report({
|
78
74
|
node,
|
@@ -17,10 +17,13 @@ module.exports = {
|
|
17
17
|
recommended: true
|
18
18
|
},
|
19
19
|
|
20
|
-
schema: []
|
20
|
+
schema: [],
|
21
|
+
|
22
|
+
fixable: "code"
|
21
23
|
},
|
22
24
|
|
23
25
|
create(context) {
|
26
|
+
const sourceCode = context.getSourceCode();
|
24
27
|
|
25
28
|
// Node types which have a test which will coerce values to booleans.
|
26
29
|
const BOOLEAN_NODE_TYPES = [
|
@@ -70,7 +73,11 @@ module.exports = {
|
|
70
73
|
grandparent.callee.type === "Identifier" &&
|
71
74
|
grandparent.callee.name === "Boolean")
|
72
75
|
) {
|
73
|
-
context.report(
|
76
|
+
context.report({
|
77
|
+
node,
|
78
|
+
message: "Redundant double negation.",
|
79
|
+
fix: fixer => fixer.replaceText(parent, sourceCode.getText(node.argument))
|
80
|
+
});
|
74
81
|
}
|
75
82
|
},
|
76
83
|
CallExpression(node) {
|
@@ -81,7 +88,11 @@ module.exports = {
|
|
81
88
|
}
|
82
89
|
|
83
90
|
if (isInBooleanContext(node, parent)) {
|
84
|
-
context.report(
|
91
|
+
context.report({
|
92
|
+
node,
|
93
|
+
message: "Redundant Boolean call.",
|
94
|
+
fix: fixer => fixer.replaceText(node, sourceCode.getText(node.arguments[0]))
|
95
|
+
});
|
85
96
|
}
|
86
97
|
}
|
87
98
|
};
|
@@ -352,7 +352,7 @@ module.exports = {
|
|
352
352
|
report(node.arguments[0]);
|
353
353
|
}
|
354
354
|
} else {
|
355
|
-
[].forEach.call(node.arguments,
|
355
|
+
[].forEach.call(node.arguments, arg => {
|
356
356
|
if (hasExcessParens(arg) && precedence(arg) >= precedence({type: "AssignmentExpression"})) {
|
357
357
|
report(arg);
|
358
358
|
}
|
@@ -381,7 +381,7 @@ module.exports = {
|
|
381
381
|
|
382
382
|
return {
|
383
383
|
ArrayExpression(node) {
|
384
|
-
[].forEach.call(node.elements,
|
384
|
+
[].forEach.call(node.elements, e => {
|
385
385
|
if (e && hasExcessParens(e) && precedence(e) >= precedence({type: "AssignmentExpression"})) {
|
386
386
|
report(e);
|
387
387
|
}
|
@@ -531,7 +531,7 @@ module.exports = {
|
|
531
531
|
NewExpression: dryCallNew,
|
532
532
|
|
533
533
|
ObjectExpression(node) {
|
534
|
-
[].forEach.call(node.properties,
|
534
|
+
[].forEach.call(node.properties, e => {
|
535
535
|
const v = e.value;
|
536
536
|
|
537
537
|
if (v && hasExcessParens(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) {
|
@@ -557,7 +557,7 @@ module.exports = {
|
|
557
557
|
},
|
558
558
|
|
559
559
|
SequenceExpression(node) {
|
560
|
-
[].forEach.call(node.expressions,
|
560
|
+
[].forEach.call(node.expressions, e => {
|
561
561
|
if (hasExcessParens(e) && precedence(e) >= precedence(node)) {
|
562
562
|
report(e);
|
563
563
|
}
|
@@ -30,7 +30,7 @@ module.exports = {
|
|
30
30
|
* @returns {void}
|
31
31
|
*/
|
32
32
|
function checkReference(references) {
|
33
|
-
astUtils.getModifyingReferences(references).forEach(
|
33
|
+
astUtils.getModifyingReferences(references).forEach(reference => {
|
34
34
|
context.report(
|
35
35
|
reference.identifier,
|
36
36
|
"'{{name}}' is a function.",
|
@@ -25,26 +25,26 @@ module.exports = {
|
|
25
25
|
Program() {
|
26
26
|
const scope = context.getScope();
|
27
27
|
|
28
|
-
scope.variables.forEach(
|
28
|
+
scope.variables.forEach(variable => {
|
29
29
|
if (variable.writeable) {
|
30
30
|
return;
|
31
31
|
}
|
32
32
|
|
33
|
-
variable.defs.forEach(
|
33
|
+
variable.defs.forEach(def => {
|
34
34
|
if (def.type === "FunctionName" || (def.type === "Variable" && def.parent.kind === "var")) {
|
35
35
|
context.report(def.node, "Implicit global variable, assign as global property instead.");
|
36
36
|
}
|
37
37
|
});
|
38
38
|
});
|
39
39
|
|
40
|
-
scope.implicit.variables.forEach(
|
40
|
+
scope.implicit.variables.forEach(variable => {
|
41
41
|
const scopeVariable = scope.set.get(variable.name);
|
42
42
|
|
43
43
|
if (scopeVariable && scopeVariable.writeable) {
|
44
44
|
return;
|
45
45
|
}
|
46
46
|
|
47
|
-
variable.defs.forEach(
|
47
|
+
variable.defs.forEach(def => {
|
48
48
|
context.report(def.node, "Implicit global variable, assign as global property instead.");
|
49
49
|
});
|
50
50
|
});
|
@@ -76,7 +76,7 @@ module.exports = {
|
|
76
76
|
const locStart = node.loc.start;
|
77
77
|
const locEnd = node.loc.end;
|
78
78
|
|
79
|
-
errors = errors.filter(
|
79
|
+
errors = errors.filter(error => {
|
80
80
|
const errorLoc = error[1];
|
81
81
|
|
82
82
|
if (errorLoc.line >= locStart.line && errorLoc.line <= locEnd.line) {
|
@@ -142,7 +142,7 @@ module.exports = {
|
|
142
142
|
function checkForIrregularWhitespace(node) {
|
143
143
|
const sourceLines = sourceCode.lines;
|
144
144
|
|
145
|
-
sourceLines.forEach(
|
145
|
+
sourceLines.forEach((sourceLine, lineIndex) => {
|
146
146
|
const lineNumber = lineIndex + 1;
|
147
147
|
let match;
|
148
148
|
|
@@ -233,7 +233,7 @@ module.exports = {
|
|
233
233
|
}
|
234
234
|
|
235
235
|
// If we have any errors remaining report on them
|
236
|
-
errors.forEach(
|
236
|
+
errors.forEach(error => {
|
237
237
|
context.report.apply(context, error);
|
238
238
|
});
|
239
239
|
};
|
@@ -62,9 +62,7 @@ function normalizeOptions(options) {
|
|
62
62
|
* @returns {boolean} `true` if such group existed.
|
63
63
|
*/
|
64
64
|
function includesBothInAGroup(groups, left, right) {
|
65
|
-
return groups.some(
|
66
|
-
return group.indexOf(left) !== -1 && group.indexOf(right) !== -1;
|
67
|
-
});
|
65
|
+
return groups.some(group => group.indexOf(left) !== -1 && group.indexOf(right) !== -1);
|
68
66
|
}
|
69
67
|
|
70
68
|
//------------------------------------------------------------------------------
|
@@ -169,7 +169,7 @@ module.exports = {
|
|
169
169
|
function isMixed(declarations) {
|
170
170
|
const contains = {};
|
171
171
|
|
172
|
-
declarations.forEach(
|
172
|
+
declarations.forEach(declaration => {
|
173
173
|
const type = getDeclarationType(declaration.init);
|
174
174
|
|
175
175
|
contains[type] = true;
|
@@ -190,7 +190,7 @@ module.exports = {
|
|
190
190
|
function isGrouped(declarations) {
|
191
191
|
const found = {};
|
192
192
|
|
193
|
-
declarations.forEach(
|
193
|
+
declarations.forEach(declaration => {
|
194
194
|
if (getDeclarationType(declaration.init) === DECL_REQUIRE) {
|
195
195
|
found[inferModuleType(declaration.init)] = true;
|
196
196
|
}
|
@@ -89,11 +89,11 @@ module.exports = {
|
|
89
89
|
const lines = sourceCode.lines,
|
90
90
|
comments = sourceCode.getAllComments();
|
91
91
|
|
92
|
-
comments.forEach(
|
92
|
+
comments.forEach(comment => {
|
93
93
|
ignoredLocs.push(comment.loc);
|
94
94
|
});
|
95
95
|
|
96
|
-
ignoredLocs.sort(
|
96
|
+
ignoredLocs.sort((first, second) => {
|
97
97
|
if (beforeLoc(first, second.start.line, second.start.column)) {
|
98
98
|
return 1;
|
99
99
|
}
|
@@ -114,7 +114,7 @@ module.exports = {
|
|
114
114
|
regex = /^(?=[\t ]* \t)/;
|
115
115
|
}
|
116
116
|
|
117
|
-
lines.forEach(
|
117
|
+
lines.forEach((line, i) => {
|
118
118
|
const match = regex.exec(line);
|
119
119
|
|
120
120
|
if (match) {
|
@@ -47,7 +47,7 @@ module.exports = {
|
|
47
47
|
lastCommentIndex = 0;
|
48
48
|
|
49
49
|
if (options && options.exceptions) {
|
50
|
-
Object.keys(options.exceptions).forEach(
|
50
|
+
Object.keys(options.exceptions).forEach(key => {
|
51
51
|
if (options.exceptions[key]) {
|
52
52
|
exceptions[key] = true;
|
53
53
|
} else {
|
@@ -28,7 +28,7 @@ module.exports = {
|
|
28
28
|
const variable = globalScope.set.get("Symbol");
|
29
29
|
|
30
30
|
if (variable && variable.defs.length === 0) {
|
31
|
-
variable.references.forEach(
|
31
|
+
variable.references.forEach(ref => {
|
32
32
|
const node = ref.identifier;
|
33
33
|
|
34
34
|
if (node.parent && node.parent.type === "NewExpression") {
|
@@ -40,14 +40,12 @@ module.exports = {
|
|
40
40
|
* @private
|
41
41
|
*/
|
42
42
|
function findVariablesInScope(scope) {
|
43
|
-
scope.variables.forEach(
|
43
|
+
scope.variables.forEach(variable => {
|
44
44
|
const hasBuiltin = options.builtinGlobals && "writeable" in variable;
|
45
45
|
const count = (hasBuiltin ? 1 : 0) + variable.identifiers.length;
|
46
46
|
|
47
47
|
if (count >= 2) {
|
48
|
-
variable.identifiers.sort(
|
49
|
-
return a.range[1] - b.range[1];
|
50
|
-
});
|
48
|
+
variable.identifiers.sort((a, b) => a.range[1] - b.range[1]);
|
51
49
|
|
52
50
|
for (let i = (hasBuiltin ? 0 : 1), l = variable.identifiers.length; i < l; i++) {
|
53
51
|
context.report(
|
@@ -60,14 +60,14 @@ module.exports = {
|
|
60
60
|
const scope = context.getScope();
|
61
61
|
|
62
62
|
// Report variables declared elsewhere (ex: variables defined as "global" by eslint)
|
63
|
-
scope.variables.forEach(
|
63
|
+
scope.variables.forEach(variable => {
|
64
64
|
if (!variable.defs.length && isRestricted(variable.name)) {
|
65
65
|
variable.references.forEach(reportReference);
|
66
66
|
}
|
67
67
|
});
|
68
68
|
|
69
69
|
// Report variables not declared at all
|
70
|
-
scope.through.forEach(
|
70
|
+
scope.through.forEach(reference => {
|
71
71
|
if (isRestricted(reference.identifier.name)) {
|
72
72
|
reportReference(reference);
|
73
73
|
}
|
@@ -8,6 +8,16 @@
|
|
8
8
|
// Rule Definition
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
|
+
const ignore = require("ignore");
|
12
|
+
|
13
|
+
const arrayOfStrings = {
|
14
|
+
type: "array",
|
15
|
+
items: {
|
16
|
+
type: "string"
|
17
|
+
},
|
18
|
+
uniqueItems: true
|
19
|
+
};
|
20
|
+
|
11
21
|
module.exports = {
|
12
22
|
meta: {
|
13
23
|
docs: {
|
@@ -17,31 +27,55 @@ module.exports = {
|
|
17
27
|
},
|
18
28
|
|
19
29
|
schema: {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
30
|
+
anyOf: [
|
31
|
+
arrayOfStrings,
|
32
|
+
{
|
33
|
+
type: "array",
|
34
|
+
items: [{
|
35
|
+
type: "object",
|
36
|
+
properties: {
|
37
|
+
paths: arrayOfStrings,
|
38
|
+
patterns: arrayOfStrings
|
39
|
+
},
|
40
|
+
additionalProperties: false
|
41
|
+
}],
|
42
|
+
additionalItems: false
|
43
|
+
}
|
44
|
+
]
|
25
45
|
}
|
26
46
|
},
|
27
47
|
|
28
48
|
create(context) {
|
29
|
-
const
|
49
|
+
const options = Array.isArray(context.options) ? context.options : [];
|
50
|
+
const isStringArray = typeof options[0] !== "object";
|
51
|
+
const restrictedPaths = new Set(isStringArray ? context.options : options[0].paths || []);
|
52
|
+
const restrictedPatterns = isStringArray ? [] : options[0].patterns || [];
|
30
53
|
|
31
54
|
// if no imports are restricted we don"t need to check
|
32
|
-
if (
|
55
|
+
if (restrictedPaths.size === 0 && restrictedPatterns.length === 0) {
|
33
56
|
return {};
|
34
57
|
}
|
35
58
|
|
59
|
+
const ig = ignore().add(restrictedPatterns);
|
60
|
+
|
36
61
|
return {
|
37
62
|
ImportDeclaration(node) {
|
38
63
|
if (node && node.source && node.source.value) {
|
39
64
|
|
40
|
-
const
|
65
|
+
const importName = node.source.value.trim();
|
41
66
|
|
42
|
-
if (
|
43
|
-
context.report(
|
44
|
-
|
67
|
+
if (restrictedPaths.has(importName)) {
|
68
|
+
context.report({
|
69
|
+
node,
|
70
|
+
message: "'{{importName}}' import is restricted from being used.",
|
71
|
+
data: { importName }
|
72
|
+
});
|
73
|
+
}
|
74
|
+
if (restrictedPatterns.length > 0 && ig.ignores(importName)) {
|
75
|
+
context.report({
|
76
|
+
node,
|
77
|
+
message: "'{{importName}}' import is restricted from being used by a pattern.",
|
78
|
+
data: { importName }
|
45
79
|
});
|
46
80
|
}
|
47
81
|
}
|
@@ -8,6 +8,16 @@
|
|
8
8
|
// Rule Definition
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
|
+
const ignore = require("ignore");
|
12
|
+
|
13
|
+
const arrayOfStrings = {
|
14
|
+
type: "array",
|
15
|
+
items: {
|
16
|
+
type: "string"
|
17
|
+
},
|
18
|
+
uniqueItems: true
|
19
|
+
};
|
20
|
+
|
11
21
|
module.exports = {
|
12
22
|
meta: {
|
13
23
|
docs: {
|
@@ -17,24 +27,37 @@ module.exports = {
|
|
17
27
|
},
|
18
28
|
|
19
29
|
schema: {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
30
|
+
anyOf: [
|
31
|
+
arrayOfStrings,
|
32
|
+
{
|
33
|
+
type: "array",
|
34
|
+
items: [{
|
35
|
+
type: "object",
|
36
|
+
properties: {
|
37
|
+
paths: arrayOfStrings,
|
38
|
+
patterns: arrayOfStrings
|
39
|
+
},
|
40
|
+
additionalProperties: false
|
41
|
+
}],
|
42
|
+
additionalItems: false
|
43
|
+
}
|
44
|
+
]
|
25
45
|
}
|
26
46
|
},
|
27
47
|
|
28
48
|
create(context) {
|
49
|
+
const options = Array.isArray(context.options) ? context.options : [];
|
50
|
+
const isStringArray = typeof options[0] !== "object";
|
51
|
+
const restrictedPaths = new Set(isStringArray ? context.options : options[0].paths || []);
|
52
|
+
const restrictedPatterns = isStringArray ? [] : options[0].patterns || [];
|
29
53
|
|
30
|
-
//
|
31
|
-
|
32
|
-
|
33
|
-
// if no modules are restricted we don't need to check the CallExpressions
|
34
|
-
if (restrictedModules.length === 0) {
|
54
|
+
// if no imports are restricted we don"t need to check
|
55
|
+
if (restrictedPaths.size === 0 && restrictedPatterns.length === 0) {
|
35
56
|
return {};
|
36
57
|
}
|
37
58
|
|
59
|
+
const ig = ignore().add(restrictedPatterns);
|
60
|
+
|
38
61
|
/**
|
39
62
|
* Function to check if a node is a string literal.
|
40
63
|
* @param {ASTNode} node The node to check.
|
@@ -53,36 +76,30 @@ module.exports = {
|
|
53
76
|
return node.callee.type === "Identifier" && node.callee.name === "require";
|
54
77
|
}
|
55
78
|
|
56
|
-
/**
|
57
|
-
* Function to check if a node has an argument that is an restricted module and return its name.
|
58
|
-
* @param {ASTNode} node The node to check
|
59
|
-
* @returns {undefined|string} restricted module name or undefined if node argument isn't restricted.
|
60
|
-
*/
|
61
|
-
function getRestrictedModuleName(node) {
|
62
|
-
let moduleName;
|
63
|
-
|
64
|
-
// node has arguments and first argument is string
|
65
|
-
if (node.arguments.length && isString(node.arguments[0])) {
|
66
|
-
const argumentValue = node.arguments[0].value.trim();
|
67
|
-
|
68
|
-
// check if argument value is in restricted modules array
|
69
|
-
if (restrictedModules.indexOf(argumentValue) !== -1) {
|
70
|
-
moduleName = argumentValue;
|
71
|
-
}
|
72
|
-
}
|
73
|
-
|
74
|
-
return moduleName;
|
75
|
-
}
|
76
|
-
|
77
79
|
return {
|
78
80
|
CallExpression(node) {
|
79
81
|
if (isRequireCall(node)) {
|
80
|
-
const restrictedModuleName = getRestrictedModuleName(node);
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
// node has arguments and first argument is string
|
84
|
+
if (node.arguments.length && isString(node.arguments[0])) {
|
85
|
+
const moduleName = node.arguments[0].value.trim();
|
86
|
+
|
87
|
+
// check if argument value is in restricted modules array
|
88
|
+
if (restrictedPaths.has(moduleName)) {
|
89
|
+
context.report({
|
90
|
+
node,
|
91
|
+
message: "'{{moduleName}}' module is restricted from being used.",
|
92
|
+
data: { moduleName }
|
93
|
+
});
|
94
|
+
}
|
95
|
+
|
96
|
+
if (restrictedPatterns.length > 0 && ig.ignores(moduleName)) {
|
97
|
+
context.report({
|
98
|
+
node,
|
99
|
+
message: "'{{moduleName}}' module is restricted from being used by a pattern.",
|
100
|
+
data: { moduleName }
|
101
|
+
});
|
102
|
+
}
|
86
103
|
}
|
87
104
|
}
|
88
105
|
}
|