eslint 4.7.2 → 4.11.0
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 +123 -0
- package/README.md +34 -19
- package/conf/default-cli-options.js +7 -4
- package/conf/eslint-recommended.js +2 -0
- package/lib/ast-utils.js +83 -42
- package/lib/cli-engine.js +53 -17
- package/lib/cli.js +17 -9
- package/lib/code-path-analysis/code-path-analyzer.js +8 -4
- package/lib/code-path-analysis/code-path-segment.js +43 -41
- package/lib/code-path-analysis/code-path-state.js +7 -2
- package/lib/config/autoconfig.js +14 -12
- package/lib/config/config-file.js +8 -51
- package/lib/config/config-initializer.js +10 -6
- package/lib/config/config-ops.js +21 -21
- package/lib/config/config-rule.js +24 -24
- package/lib/config/config-validator.js +38 -36
- package/lib/config/plugins.js +8 -35
- package/lib/config.js +12 -8
- package/lib/formatters/html-template-message.html +1 -1
- package/lib/formatters/html-template-page.html +3 -1
- package/lib/formatters/html.js +2 -1
- package/lib/formatters/junit.js +21 -15
- package/lib/formatters/tap.js +5 -3
- package/lib/ignored-paths.js +5 -3
- package/lib/linter.js +42 -42
- package/lib/logging.js +2 -2
- package/lib/options.js +12 -0
- package/lib/rules/.eslintrc.yml +2 -2
- package/lib/rules/array-bracket-newline.js +39 -25
- package/lib/rules/array-bracket-spacing.js +28 -28
- package/lib/rules/array-callback-return.js +13 -9
- package/lib/rules/array-element-newline.js +8 -8
- package/lib/rules/arrow-body-style.js +12 -6
- package/lib/rules/arrow-parens.js +4 -2
- package/lib/rules/block-spacing.js +1 -1
- package/lib/rules/brace-style.js +14 -14
- package/lib/rules/callback-return.js +2 -1
- package/lib/rules/capitalized-comments.js +2 -1
- package/lib/rules/comma-style.js +3 -1
- package/lib/rules/computed-property-spacing.js +22 -22
- package/lib/rules/consistent-return.js +4 -4
- package/lib/rules/consistent-this.js +4 -2
- package/lib/rules/curly.js +13 -9
- package/lib/rules/dot-notation.js +56 -35
- package/lib/rules/func-call-spacing.js +4 -2
- package/lib/rules/generator-star-spacing.js +3 -3
- package/lib/rules/getter-return.js +2 -1
- package/lib/rules/indent-legacy.js +25 -14
- package/lib/rules/indent.js +101 -91
- package/lib/rules/key-spacing.js +5 -3
- package/lib/rules/lines-around-comment.js +33 -4
- package/lib/rules/lines-around-directive.js +16 -12
- package/lib/rules/lines-between-class-members.js +91 -0
- package/lib/rules/max-len.js +2 -3
- package/lib/rules/max-statements-per-line.js +5 -3
- package/lib/rules/multiline-comment-style.js +294 -0
- package/lib/rules/new-cap.js +2 -1
- package/lib/rules/newline-after-var.js +8 -6
- package/lib/rules/newline-before-return.js +13 -9
- package/lib/rules/no-alert.js +7 -15
- package/lib/rules/no-await-in-loop.js +17 -9
- package/lib/rules/no-bitwise.js +5 -3
- package/lib/rules/no-catch-shadow.js +4 -2
- package/lib/rules/no-console.js +2 -1
- package/lib/rules/no-constant-condition.js +2 -2
- package/lib/rules/no-control-regex.js +2 -1
- package/lib/rules/no-else-return.js +60 -19
- package/lib/rules/no-empty-character-class.js +11 -11
- package/lib/rules/no-extra-parens.js +22 -11
- package/lib/rules/no-extra-semi.js +5 -3
- package/lib/rules/no-global-assign.js +4 -2
- package/lib/rules/no-implicit-coercion.js +6 -6
- package/lib/rules/no-implied-eval.js +2 -1
- package/lib/rules/no-label-var.js +4 -2
- package/lib/rules/no-lone-blocks.js +3 -3
- package/lib/rules/no-lonely-if.js +2 -1
- package/lib/rules/no-loop-func.js +10 -7
- package/lib/rules/no-mixed-requires.js +8 -4
- package/lib/rules/no-native-reassign.js +4 -2
- package/lib/rules/no-param-reassign.js +4 -2
- package/lib/rules/no-regex-spaces.js +1 -1
- package/lib/rules/no-restricted-imports.js +86 -17
- package/lib/rules/no-restricted-modules.js +84 -15
- package/lib/rules/no-restricted-properties.js +10 -10
- package/lib/rules/no-return-await.js +6 -6
- package/lib/rules/no-self-assign.js +4 -2
- package/lib/rules/no-sequences.js +6 -4
- package/lib/rules/no-trailing-spaces.js +14 -8
- package/lib/rules/no-unneeded-ternary.js +3 -1
- package/lib/rules/no-unreachable.js +4 -2
- package/lib/rules/no-unused-labels.js +2 -1
- package/lib/rules/no-use-before-define.js +13 -11
- package/lib/rules/no-useless-call.js +1 -25
- package/lib/rules/no-useless-computed-key.js +2 -1
- package/lib/rules/no-useless-escape.js +31 -23
- package/lib/rules/no-useless-return.js +14 -8
- package/lib/rules/no-var.js +11 -0
- package/lib/rules/no-whitespace-before-property.js +4 -2
- package/lib/rules/object-curly-newline.js +9 -2
- package/lib/rules/object-curly-spacing.js +20 -20
- package/lib/rules/object-shorthand.js +47 -35
- package/lib/rules/operator-assignment.js +9 -9
- package/lib/rules/operator-linebreak.js +15 -11
- package/lib/rules/padding-line-between-statements.js +6 -4
- package/lib/rules/prefer-arrow-callback.js +12 -10
- package/lib/rules/prefer-const.js +18 -10
- package/lib/rules/prefer-destructuring.js +4 -2
- package/lib/rules/prefer-numeric-literals.js +4 -2
- package/lib/rules/prefer-promise-reject-errors.js +16 -16
- package/lib/rules/prefer-rest-params.js +4 -2
- package/lib/rules/prefer-spread.js +1 -25
- package/lib/rules/prefer-template.js +33 -29
- package/lib/rules/quote-props.js +8 -8
- package/lib/rules/require-jsdoc.js +11 -18
- package/lib/rules/semi-style.js +44 -19
- package/lib/rules/semi.js +5 -3
- package/lib/rules/sort-imports.js +11 -6
- package/lib/rules/space-unary-ops.js +67 -69
- package/lib/rules/strict.js +8 -8
- package/lib/rules/valid-jsdoc.js +39 -33
- package/lib/rules/valid-typeof.js +4 -4
- package/lib/rules/wrap-iife.js +4 -4
- package/lib/rules/yoda.js +9 -7
- package/lib/testers/rule-tester.js +63 -40
- package/lib/token-store/backward-token-cursor.js +5 -3
- package/lib/token-store/forward-token-cursor.js +5 -3
- package/lib/token-store/utils.js +8 -4
- package/lib/util/apply-disable-directives.js +56 -27
- package/lib/util/glob.js +1 -1
- package/lib/util/naming.js +112 -0
- package/lib/util/node-event-generator.js +13 -27
- package/lib/util/safe-emitter.js +54 -0
- package/lib/util/source-code-fixer.js +4 -2
- package/lib/util/source-code.js +70 -65
- package/messages/no-config-found.txt +1 -1
- package/package.json +8 -8
- package/lib/internal-rules/.eslintrc.yml +0 -3
- package/lib/internal-rules/internal-consistent-docs-description.js +0 -130
- package/lib/internal-rules/internal-no-invalid-meta.js +0 -188
package/lib/rules/no-alert.js
CHANGED
@@ -53,11 +53,10 @@ function findReference(scope, node) {
|
|
53
53
|
/**
|
54
54
|
* Checks if the given identifier node is shadowed in the given scope.
|
55
55
|
* @param {Object} scope The current scope.
|
56
|
-
* @param {Object} globalScope The global scope.
|
57
56
|
* @param {string} node The identifier node to check
|
58
57
|
* @returns {boolean} Whether or not the name is shadowed.
|
59
58
|
*/
|
60
|
-
function isShadowed(scope,
|
59
|
+
function isShadowed(scope, node) {
|
61
60
|
const reference = findReference(scope, node);
|
62
61
|
|
63
62
|
return reference && reference.resolved && reference.resolved.defs.length > 0;
|
@@ -66,15 +65,15 @@ function isShadowed(scope, globalScope, node) {
|
|
66
65
|
/**
|
67
66
|
* Checks if the given identifier node is a ThisExpression in the global scope or the global window property.
|
68
67
|
* @param {Object} scope The current scope.
|
69
|
-
* @param {Object} globalScope The global scope.
|
70
68
|
* @param {string} node The identifier node to check
|
71
69
|
* @returns {boolean} Whether or not the node is a reference to the global object.
|
72
70
|
*/
|
73
|
-
function isGlobalThisReferenceOrGlobalWindow(scope,
|
71
|
+
function isGlobalThisReferenceOrGlobalWindow(scope, node) {
|
74
72
|
if (scope.type === "global" && node.type === "ThisExpression") {
|
75
73
|
return true;
|
76
|
-
}
|
77
|
-
|
74
|
+
}
|
75
|
+
if (node.name === "window") {
|
76
|
+
return !isShadowed(scope, node);
|
78
77
|
}
|
79
78
|
|
80
79
|
return false;
|
@@ -96,14 +95,7 @@ module.exports = {
|
|
96
95
|
},
|
97
96
|
|
98
97
|
create(context) {
|
99
|
-
let globalScope;
|
100
|
-
|
101
98
|
return {
|
102
|
-
|
103
|
-
Program() {
|
104
|
-
globalScope = context.getScope();
|
105
|
-
},
|
106
|
-
|
107
99
|
CallExpression(node) {
|
108
100
|
const callee = node.callee,
|
109
101
|
currentScope = context.getScope();
|
@@ -112,11 +104,11 @@ module.exports = {
|
|
112
104
|
if (callee.type === "Identifier") {
|
113
105
|
const identifierName = callee.name;
|
114
106
|
|
115
|
-
if (!isShadowed(currentScope,
|
107
|
+
if (!isShadowed(currentScope, callee) && isProhibitedIdentifier(callee.name)) {
|
116
108
|
report(context, node, identifierName);
|
117
109
|
}
|
118
110
|
|
119
|
-
} else if (callee.type === "MemberExpression" && isGlobalThisReferenceOrGlobalWindow(currentScope,
|
111
|
+
} else if (callee.type === "MemberExpression" && isGlobalThisReferenceOrGlobalWindow(currentScope, callee.object)) {
|
120
112
|
const identifierName = getPropertyName(callee);
|
121
113
|
|
122
114
|
if (isProhibitedIdentifier(identifierName)) {
|
@@ -13,8 +13,10 @@ const loopTypes = new Set([
|
|
13
13
|
"DoWhileStatement"
|
14
14
|
]);
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
/*
|
17
|
+
* Node types at which we should stop looking for loops. For example, it is fine to declare an async
|
18
|
+
* function within a loop, and use await inside of that.
|
19
|
+
*/
|
18
20
|
const boundaryTypes = new Set([
|
19
21
|
"FunctionDeclaration",
|
20
22
|
"FunctionExpression",
|
@@ -38,9 +40,11 @@ module.exports = {
|
|
38
40
|
// Reverse so that we can traverse from the deepest node upwards.
|
39
41
|
ancestors.reverse();
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
/*
|
44
|
+
* Create a set of all the ancestors plus this node so that we can check
|
45
|
+
* if this use of await appears in the body of the loop as opposed to
|
46
|
+
* the right-hand side of a for...of, for example.
|
47
|
+
*/
|
44
48
|
const ancestorSet = new Set(ancestors).add(node);
|
45
49
|
|
46
50
|
for (let i = 0; i < ancestors.length; i++) {
|
@@ -48,14 +52,18 @@ module.exports = {
|
|
48
52
|
|
49
53
|
if (boundaryTypes.has(ancestor.type)) {
|
50
54
|
|
51
|
-
|
52
|
-
|
55
|
+
/*
|
56
|
+
* Short-circuit out if we encounter a boundary type. Loops above
|
57
|
+
* this do not matter.
|
58
|
+
*/
|
53
59
|
return;
|
54
60
|
}
|
55
61
|
if (loopTypes.has(ancestor.type)) {
|
56
62
|
|
57
|
-
|
58
|
-
|
63
|
+
/*
|
64
|
+
* Only report if we are actually in the body or another part that gets executed on
|
65
|
+
* every iteration.
|
66
|
+
*/
|
59
67
|
if (
|
60
68
|
ancestorSet.has(ancestor.body) ||
|
61
69
|
ancestorSet.has(ancestor.test) ||
|
package/lib/rules/no-bitwise.js
CHANGED
@@ -51,8 +51,10 @@ module.exports = {
|
|
51
51
|
CatchClause(node) {
|
52
52
|
let scope = context.getScope();
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
/*
|
55
|
+
* When ecmaVersion >= 6, CatchClause creates its own scope
|
56
|
+
* so start from one upper scope to exclude the current node
|
57
|
+
*/
|
56
58
|
if (scope.block === node) {
|
57
59
|
scope = scope.upper;
|
58
60
|
}
|
package/lib/rules/no-console.js
CHANGED
@@ -111,7 +111,8 @@ module.exports = {
|
|
111
111
|
const consoleVar = astUtils.getVariableByName(scope, "console");
|
112
112
|
const shadowed = consoleVar && consoleVar.defs.length > 0;
|
113
113
|
|
114
|
-
/*
|
114
|
+
/*
|
115
|
+
* 'scope.through' includes all references to undefined
|
115
116
|
* variables. If the variable 'console' is not defined, it uses
|
116
117
|
* 'scope.through'.
|
117
118
|
*/
|
@@ -138,7 +138,7 @@ module.exports = {
|
|
138
138
|
function checkConstantConditionLoopInSet(node) {
|
139
139
|
if (loopsInCurrentScope.has(node)) {
|
140
140
|
loopsInCurrentScope.delete(node);
|
141
|
-
context.report({ node, message: "Unexpected constant condition." });
|
141
|
+
context.report({ node: node.test, message: "Unexpected constant condition." });
|
142
142
|
}
|
143
143
|
}
|
144
144
|
|
@@ -150,7 +150,7 @@ module.exports = {
|
|
150
150
|
*/
|
151
151
|
function reportIfConstant(node) {
|
152
152
|
if (node.test && isConstant(node.test, true)) {
|
153
|
-
context.report({ node, message: "Unexpected constant condition." });
|
153
|
+
context.report({ node: node.test, message: "Unexpected constant condition." });
|
154
154
|
}
|
155
155
|
}
|
156
156
|
|
@@ -24,8 +24,15 @@ module.exports = {
|
|
24
24
|
recommended: false
|
25
25
|
},
|
26
26
|
|
27
|
-
schema: [
|
28
|
-
|
27
|
+
schema: [{
|
28
|
+
type: "object",
|
29
|
+
properties: {
|
30
|
+
allowElseIf: {
|
31
|
+
type: "boolean"
|
32
|
+
}
|
33
|
+
},
|
34
|
+
additionalProperties: false
|
35
|
+
}],
|
29
36
|
fixable: "code"
|
30
37
|
},
|
31
38
|
|
@@ -59,10 +66,12 @@ module.exports = {
|
|
59
66
|
firstTokenOfElseBlock = startToken;
|
60
67
|
}
|
61
68
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
69
|
+
/*
|
70
|
+
* If the if block does not have curly braces and does not end in a semicolon
|
71
|
+
* and the else block starts with (, [, /, +, ` or -, then it is not
|
72
|
+
* safe to remove the else keyword, because ASI will not add a semicolon
|
73
|
+
* after the if block
|
74
|
+
*/
|
66
75
|
const ifBlockMaybeUnsafe = node.parent.consequent.type !== "BlockStatement" && lastIfToken.value !== ";";
|
67
76
|
const elseBlockUnsafe = /^[([/+`-]/.test(firstTokenOfElseBlock.value);
|
68
77
|
|
@@ -79,10 +88,12 @@ module.exports = {
|
|
79
88
|
const nextTokenUnsafe = nextToken && /^[([/+`-]/.test(nextToken.value);
|
80
89
|
const nextTokenOnSameLine = nextToken && nextToken.loc.start.line === lastTokenOfElseBlock.loc.start.line;
|
81
90
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
91
|
+
/*
|
92
|
+
* If the else block contents does not end in a semicolon,
|
93
|
+
* and the else block starts with (, [, /, +, ` or -, then it is not
|
94
|
+
* safe to remove the else block, because ASI will not add a semicolon
|
95
|
+
* after the remaining else block contents
|
96
|
+
*/
|
86
97
|
if (nextTokenUnsafe || (nextTokenOnSameLine && nextToken.value !== "}")) {
|
87
98
|
return null;
|
88
99
|
}
|
@@ -94,9 +105,11 @@ module.exports = {
|
|
94
105
|
fixedSource = source;
|
95
106
|
}
|
96
107
|
|
97
|
-
|
98
|
-
|
99
|
-
|
108
|
+
/*
|
109
|
+
* Extend the replacement range to include the entire
|
110
|
+
* function to avoid conflicting with no-useless-return.
|
111
|
+
* https://github.com/eslint/eslint/issues/8026
|
112
|
+
*/
|
100
113
|
return new FixTracker(fixer, sourceCode)
|
101
114
|
.retainEnclosingFunction(node)
|
102
115
|
.replaceTextRange([elseToken.range[0], node.range[1]], fixedSource);
|
@@ -134,13 +147,13 @@ module.exports = {
|
|
134
147
|
|
135
148
|
/**
|
136
149
|
* Check to see if the node is valid for evaluation,
|
137
|
-
* meaning it has an else
|
150
|
+
* meaning it has an else.
|
138
151
|
*
|
139
152
|
* @param {Node} node The node being evaluated
|
140
153
|
* @returns {boolean} True if the node is valid
|
141
154
|
*/
|
142
155
|
function hasElse(node) {
|
143
|
-
return node.alternate && node.consequent
|
156
|
+
return node.alternate && node.consequent;
|
144
157
|
}
|
145
158
|
|
146
159
|
/**
|
@@ -189,14 +202,15 @@ module.exports = {
|
|
189
202
|
return checkForReturnOrIf(node);
|
190
203
|
}
|
191
204
|
|
205
|
+
|
192
206
|
/**
|
193
|
-
* Check the if statement
|
207
|
+
* Check the if statement, but don't catch else-if blocks.
|
194
208
|
* @returns {void}
|
195
209
|
* @param {Node} node The node for the if statement to check
|
196
210
|
* @private
|
197
211
|
*/
|
198
|
-
function
|
199
|
-
const parent =
|
212
|
+
function checkIfWithoutElse(node) {
|
213
|
+
const parent = node.parent;
|
200
214
|
let consequents,
|
201
215
|
alternate;
|
202
216
|
|
@@ -221,13 +235,40 @@ module.exports = {
|
|
221
235
|
}
|
222
236
|
}
|
223
237
|
|
238
|
+
/**
|
239
|
+
* Check the if statement
|
240
|
+
* @returns {void}
|
241
|
+
* @param {Node} node The node for the if statement to check
|
242
|
+
* @private
|
243
|
+
*/
|
244
|
+
function checkIfWithElse(node) {
|
245
|
+
const parent = node.parent;
|
246
|
+
|
247
|
+
|
248
|
+
/*
|
249
|
+
* Fixing this would require splitting one statement into two, so no error should
|
250
|
+
* be reported if this node is in a position where only one statement is allowed.
|
251
|
+
*/
|
252
|
+
if (!astUtils.STATEMENT_LIST_PARENTS.has(parent.type)) {
|
253
|
+
return;
|
254
|
+
}
|
255
|
+
|
256
|
+
const alternate = node.alternate;
|
257
|
+
|
258
|
+
if (alternate && alwaysReturns(node.consequent)) {
|
259
|
+
displayReport(alternate);
|
260
|
+
}
|
261
|
+
}
|
262
|
+
|
263
|
+
const allowElseIf = !(context.options[0] && context.options[0].allowElseIf === false);
|
264
|
+
|
224
265
|
//--------------------------------------------------------------------------
|
225
266
|
// Public API
|
226
267
|
//--------------------------------------------------------------------------
|
227
268
|
|
228
269
|
return {
|
229
270
|
|
230
|
-
"IfStatement:exit":
|
271
|
+
"IfStatement:exit": allowElseIf ? checkIfWithoutElse : checkIfWithElse
|
231
272
|
|
232
273
|
};
|
233
274
|
|
@@ -10,17 +10,17 @@
|
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
12
|
/*
|
13
|
-
plain-English description of the following regexp:
|
14
|
-
0. `^` fix the match at the beginning of the string
|
15
|
-
1. `\/`: the `/` that begins the regexp
|
16
|
-
2. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
3. `\/` the `/` that ends the regexp
|
21
|
-
4. `[gimuy]*`: optional regexp flags
|
22
|
-
5. `$`: fix the match at the end of the string
|
23
|
-
*/
|
13
|
+
* plain-English description of the following regexp:
|
14
|
+
* 0. `^` fix the match at the beginning of the string
|
15
|
+
* 1. `\/`: the `/` that begins the regexp
|
16
|
+
* 2. `([^\\[]|\\.|\[([^\\\]]|\\.)+\])*`: regexp contents; 0 or more of the following
|
17
|
+
* 2.0. `[^\\[]`: any character that's not a `\` or a `[` (anything but escape sequences and character classes)
|
18
|
+
* 2.1. `\\.`: an escape sequence
|
19
|
+
* 2.2. `\[([^\\\]]|\\.)+\]`: a character class that isn't empty
|
20
|
+
* 3. `\/` the `/` that ends the regexp
|
21
|
+
* 4. `[gimuy]*`: optional regexp flags
|
22
|
+
* 5. `$`: fix the match at the end of the string
|
23
|
+
*/
|
24
24
|
const regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+])*\/[gimuy]*$/;
|
25
25
|
|
26
26
|
//------------------------------------------------------------------------------
|
@@ -195,10 +195,12 @@ module.exports = {
|
|
195
195
|
function containsAssignment(node) {
|
196
196
|
if (node.type === "AssignmentExpression") {
|
197
197
|
return true;
|
198
|
-
}
|
198
|
+
}
|
199
|
+
if (node.type === "ConditionalExpression" &&
|
199
200
|
(node.consequent.type === "AssignmentExpression" || node.alternate.type === "AssignmentExpression")) {
|
200
201
|
return true;
|
201
|
-
}
|
202
|
+
}
|
203
|
+
if ((node.left && node.left.type === "AssignmentExpression") ||
|
202
204
|
(node.right && node.right.type === "AssignmentExpression")) {
|
203
205
|
return true;
|
204
206
|
}
|
@@ -219,7 +221,8 @@ module.exports = {
|
|
219
221
|
|
220
222
|
if (node.type === "ReturnStatement") {
|
221
223
|
return node.argument && containsAssignment(node.argument);
|
222
|
-
}
|
224
|
+
}
|
225
|
+
if (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") {
|
223
226
|
return containsAssignment(node.body);
|
224
227
|
}
|
225
228
|
return containsAssignment(node);
|
@@ -369,8 +372,10 @@ module.exports = {
|
|
369
372
|
hasDoubleExcessParens(callee) ||
|
370
373
|
!isIIFE(node) && !hasNewParensException && !(
|
371
374
|
|
372
|
-
|
373
|
-
|
375
|
+
/*
|
376
|
+
* Allow extra parens around a new expression if
|
377
|
+
* there are intervening parentheses.
|
378
|
+
*/
|
374
379
|
callee.type === "MemberExpression" &&
|
375
380
|
doesMemberExpressionContainCallExpression(callee)
|
376
381
|
)
|
@@ -422,8 +427,10 @@ module.exports = {
|
|
422
427
|
return;
|
423
428
|
}
|
424
429
|
|
425
|
-
|
426
|
-
|
430
|
+
/*
|
431
|
+
* If `node.superClass` is a LeftHandSideExpression, parentheses are extra.
|
432
|
+
* Otherwise, parentheses are needed.
|
433
|
+
*/
|
427
434
|
const hasExtraParens = precedence(node.superClass) > PRECEDENCE_OF_UPDATE_EXPR
|
428
435
|
? hasExcessParens(node.superClass)
|
429
436
|
: hasDoubleExcessParens(node.superClass);
|
@@ -557,12 +564,16 @@ module.exports = {
|
|
557
564
|
if (
|
558
565
|
firstLeftToken.value === "let" && (
|
559
566
|
|
560
|
-
|
561
|
-
|
567
|
+
/*
|
568
|
+
* If `let` is the only thing on the left side of the loop, it's the loop variable: `for ((let) of foo);`
|
569
|
+
* Removing it will cause a syntax error, because it will be parsed as the start of a VariableDeclarator.
|
570
|
+
*/
|
562
571
|
firstLeftToken.range[1] === node.left.range[1] ||
|
563
572
|
|
564
|
-
|
565
|
-
|
573
|
+
/*
|
574
|
+
* If `let` is followed by a `[` token, it's a property access on the `let` value: `for ((let[foo]) of bar);`
|
575
|
+
* Removing it will cause the property access to be parsed as a destructuring declaration of `foo` instead.
|
576
|
+
*/
|
566
577
|
astUtils.isOpeningBracketToken(
|
567
578
|
sourceCode.getTokenAfter(firstLeftToken, astUtils.isNotClosingParenToken)
|
568
579
|
)
|
@@ -42,9 +42,11 @@ module.exports = {
|
|
42
42
|
message: "Unnecessary semicolon.",
|
43
43
|
fix(fixer) {
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
/*
|
46
|
+
* Expand the replacement range to include the surrounding
|
47
|
+
* tokens to avoid conflicting with semi.
|
48
|
+
* https://github.com/eslint/eslint/issues/7928
|
49
|
+
*/
|
48
50
|
return new FixTracker(fixer, context.getSourceCode())
|
49
51
|
.retainSurroundingTokens(nodeOrToken)
|
50
52
|
.remove(nodeOrToken);
|
@@ -49,8 +49,10 @@ module.exports = {
|
|
49
49
|
if (reference.init === false &&
|
50
50
|
reference.isWrite() &&
|
51
51
|
|
52
|
-
|
53
|
-
|
52
|
+
/*
|
53
|
+
* Destructuring assignments can have multiple default value,
|
54
|
+
* so possibly there are multiple writeable references for the same identifier.
|
55
|
+
*/
|
54
56
|
(index === 0 || references[index - 1].identifier !== identifier)
|
55
57
|
) {
|
56
58
|
context.report({
|
@@ -189,12 +189,12 @@ module.exports = {
|
|
189
189
|
const sourceCode = context.getSourceCode();
|
190
190
|
|
191
191
|
/**
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
192
|
+
* Reports an error and autofixes the node
|
193
|
+
* @param {ASTNode} node - An ast node to report the error on.
|
194
|
+
* @param {string} recommendation - The recommended code for the issue
|
195
|
+
* @param {bool} shouldFix - Whether this report should fix the node
|
196
|
+
* @returns {void}
|
197
|
+
*/
|
198
198
|
function report(node, recommendation, shouldFix) {
|
199
199
|
shouldFix = typeof shouldFix === "undefined" ? true : shouldFix;
|
200
200
|
|
@@ -125,7 +125,8 @@ module.exports = {
|
|
125
125
|
"CallExpression:exit"(node) {
|
126
126
|
if (node === last(last(impliedEvalAncestorsStack))) {
|
127
127
|
|
128
|
-
/*
|
128
|
+
/*
|
129
|
+
* Destroys the entire sub-stack, rather than just using
|
129
130
|
* last(impliedEvalAncestorsStack).pop(), as a CallExpression is
|
130
131
|
* always the bottom of a impliedEvalAncestorsStack substack.
|
131
132
|
*/
|
@@ -54,8 +54,10 @@ module.exports = {
|
|
54
54
|
// Fetch the innermost scope.
|
55
55
|
const scope = context.getScope();
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
/*
|
58
|
+
* Recursively find the identifier walking up the scope, starting
|
59
|
+
* with the innermost scope.
|
60
|
+
*/
|
59
61
|
if (findIdentifier(scope, node.label.name)) {
|
60
62
|
context.report({ node, message: "Found identifier with same name as label." });
|
61
63
|
}
|
@@ -30,7 +30,7 @@ module.exports = {
|
|
30
30
|
* Reports a node as invalid.
|
31
31
|
* @param {ASTNode} node - The node to be reported.
|
32
32
|
* @returns {void}
|
33
|
-
|
33
|
+
*/
|
34
34
|
function report(node) {
|
35
35
|
const message = node.parent.type === "BlockStatement" ? "Nested block is redundant." : "Block is redundant.";
|
36
36
|
|
@@ -41,7 +41,7 @@ module.exports = {
|
|
41
41
|
* Checks for any ocurrence of a BlockStatement in a place where lists of statements can appear
|
42
42
|
* @param {ASTNode} node The node to check
|
43
43
|
* @returns {boolean} True if the node is a lone block.
|
44
|
-
|
44
|
+
*/
|
45
45
|
function isLoneBlock(node) {
|
46
46
|
return node.parent.type === "BlockStatement" ||
|
47
47
|
node.parent.type === "Program" ||
|
@@ -54,7 +54,7 @@ module.exports = {
|
|
54
54
|
* Checks the enclosing block of the current node for block-level bindings,
|
55
55
|
* and "marks it" as valid if any.
|
56
56
|
* @returns {void}
|
57
|
-
|
57
|
+
*/
|
58
58
|
function markLoneBlock() {
|
59
59
|
if (loneBlocks.length === 0) {
|
60
60
|
return;
|
@@ -45,7 +45,8 @@ module.exports = {
|
|
45
45
|
const lastIfToken = sourceCode.getLastToken(node.consequent);
|
46
46
|
const sourceText = sourceCode.getText();
|
47
47
|
|
48
|
-
if (sourceText.slice(openingElseCurly.range[1],
|
48
|
+
if (sourceText.slice(openingElseCurly.range[1],
|
49
|
+
node.range[0]).trim() || sourceText.slice(node.range[1], closingElseCurly.range[0]).trim()) {
|
49
50
|
|
50
51
|
// Don't fix if there are any non-whitespace characters interfering (e.g. comments)
|
51
52
|
return null;
|
@@ -88,12 +88,11 @@ function getTopLoopNode(node, excludedNode) {
|
|
88
88
|
* Checks whether a given reference which refers to an upper scope's variable is
|
89
89
|
* safe or not.
|
90
90
|
*
|
91
|
-
* @param {ASTNode} funcNode - A target function node.
|
92
91
|
* @param {ASTNode} loopNode - A containing loop node.
|
93
92
|
* @param {eslint-scope.Reference} reference - A reference to check.
|
94
93
|
* @returns {boolean} `true` if the reference is safe or not.
|
95
94
|
*/
|
96
|
-
function isSafe(
|
95
|
+
function isSafe(loopNode, reference) {
|
97
96
|
const variable = reference.resolved;
|
98
97
|
const definition = variable && variable.defs[0];
|
99
98
|
const declaration = definition && definition.parent;
|
@@ -106,8 +105,10 @@ function isSafe(funcNode, loopNode, reference) {
|
|
106
105
|
return true;
|
107
106
|
}
|
108
107
|
|
109
|
-
|
110
|
-
|
108
|
+
/*
|
109
|
+
* Variables which are declared by `let` in the loop is safe.
|
110
|
+
* It's a different instance from the next loop step's.
|
111
|
+
*/
|
111
112
|
if (kind === "let" &&
|
112
113
|
declaration.range[0] > loopNode.range[0] &&
|
113
114
|
declaration.range[1] < loopNode.range[1]
|
@@ -115,8 +116,10 @@ function isSafe(funcNode, loopNode, reference) {
|
|
115
116
|
return true;
|
116
117
|
}
|
117
118
|
|
118
|
-
|
119
|
-
|
119
|
+
/*
|
120
|
+
* WriteReferences which exist after this border are unsafe because those
|
121
|
+
* can modify the variable.
|
122
|
+
*/
|
120
123
|
const border = getTopLoopNode(
|
121
124
|
loopNode,
|
122
125
|
(kind === "let") ? declaration : null
|
@@ -183,7 +186,7 @@ module.exports = {
|
|
183
186
|
const references = context.getScope().through;
|
184
187
|
|
185
188
|
if (references.length > 0 &&
|
186
|
-
!references.every(isSafe.bind(null,
|
189
|
+
!references.every(isSafe.bind(null, loopNode))
|
187
190
|
) {
|
188
191
|
context.report({ node, message: "Don't make functions within a loop." });
|
189
192
|
}
|
@@ -104,14 +104,16 @@ module.exports = {
|
|
104
104
|
|
105
105
|
// "var x = require('util');"
|
106
106
|
return DECL_REQUIRE;
|
107
|
-
}
|
107
|
+
}
|
108
|
+
if (allowCall &&
|
108
109
|
initExpression.type === "CallExpression" &&
|
109
110
|
initExpression.callee.type === "CallExpression"
|
110
111
|
) {
|
111
112
|
|
112
113
|
// "var x = require('diagnose')('sub-module');"
|
113
114
|
return getDeclarationType(initExpression.callee);
|
114
|
-
}
|
115
|
+
}
|
116
|
+
if (initExpression.type === "MemberExpression") {
|
115
117
|
|
116
118
|
// "var x = require('glob').Glob;"
|
117
119
|
return getDeclarationType(initExpression.object);
|
@@ -131,7 +133,8 @@ module.exports = {
|
|
131
133
|
|
132
134
|
// "var x = require('glob').Glob;"
|
133
135
|
return inferModuleType(initExpression.object);
|
134
|
-
}
|
136
|
+
}
|
137
|
+
if (initExpression.arguments.length === 0) {
|
135
138
|
|
136
139
|
// "var x = require();"
|
137
140
|
return REQ_COMPUTED;
|
@@ -149,7 +152,8 @@ module.exports = {
|
|
149
152
|
|
150
153
|
// "var fs = require('fs');"
|
151
154
|
return REQ_CORE;
|
152
|
-
}
|
155
|
+
}
|
156
|
+
if (/^\.{0,2}\//.test(arg.value)) {
|
153
157
|
|
154
158
|
// "var utils = require('./utils');"
|
155
159
|
return REQ_FILE;
|
@@ -53,8 +53,10 @@ module.exports = {
|
|
53
53
|
if (reference.init === false &&
|
54
54
|
reference.isWrite() &&
|
55
55
|
|
56
|
-
|
57
|
-
|
56
|
+
/*
|
57
|
+
* Destructuring assignments can have multiple default value,
|
58
|
+
* so possibly there are multiple writeable references for the same identifier.
|
59
|
+
*/
|
58
60
|
(index === 0 || references[index - 1].identifier !== identifier)
|
59
61
|
) {
|
60
62
|
context.report({
|