eslint 6.5.0 → 6.7.1
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 +115 -0
- package/README.md +10 -9
- package/conf/config-schema.js +1 -0
- package/conf/default-cli-options.js +1 -1
- package/lib/cli-engine/cascading-config-array-factory.js +40 -14
- package/lib/cli-engine/cli-engine.js +49 -21
- package/lib/cli-engine/config-array/config-array.js +13 -4
- package/lib/cli-engine/config-array/config-dependency.js +2 -0
- package/lib/cli-engine/config-array/extracted-config.js +27 -0
- package/lib/cli-engine/config-array/ignore-pattern.js +231 -0
- package/lib/cli-engine/config-array/index.js +2 -0
- package/lib/cli-engine/config-array/override-tester.js +2 -0
- package/lib/cli-engine/config-array-factory.js +120 -2
- package/lib/cli-engine/file-enumerator.js +51 -30
- package/lib/cli-engine/formatters/html.js +1 -0
- package/lib/init/autoconfig.js +1 -11
- package/lib/init/config-file.js +0 -1
- package/lib/init/config-initializer.js +4 -4
- package/lib/init/config-rule.js +1 -5
- package/lib/init/npm-utils.js +0 -5
- package/lib/linter/code-path-analysis/code-path-analyzer.js +24 -38
- package/lib/linter/code-path-analysis/code-path-segment.js +17 -25
- package/lib/linter/code-path-analysis/code-path-state.js +40 -81
- package/lib/linter/code-path-analysis/code-path.js +10 -11
- package/lib/linter/code-path-analysis/debug-helpers.js +8 -12
- package/lib/linter/code-path-analysis/fork-context.js +23 -34
- package/lib/linter/code-path-analysis/id-generator.js +2 -2
- package/lib/linter/linter.js +121 -95
- package/lib/linter/node-event-generator.js +3 -2
- package/lib/linter/report-translator.js +73 -7
- package/lib/rule-tester/rule-tester.js +46 -14
- package/lib/rules/accessor-pairs.js +8 -8
- package/lib/rules/array-bracket-newline.js +12 -15
- package/lib/rules/array-bracket-spacing.js +12 -12
- package/lib/rules/array-callback-return.js +6 -11
- package/lib/rules/array-element-newline.js +5 -8
- package/lib/rules/arrow-parens.js +0 -1
- package/lib/rules/block-scoped-var.js +3 -3
- package/lib/rules/block-spacing.js +4 -4
- package/lib/rules/camelcase.js +19 -6
- package/lib/rules/capitalized-comments.js +0 -7
- package/lib/rules/class-methods-use-this.js +3 -3
- package/lib/rules/comma-dangle.js +20 -25
- package/lib/rules/comma-spacing.js +1 -1
- package/lib/rules/computed-property-spacing.js +14 -14
- package/lib/rules/consistent-return.js +4 -5
- package/lib/rules/consistent-this.js +5 -5
- package/lib/rules/constructor-super.js +14 -16
- package/lib/rules/curly.js +12 -9
- package/lib/rules/default-param-last.js +1 -0
- package/lib/rules/dot-location.js +11 -12
- package/lib/rules/func-names.js +6 -6
- package/lib/rules/function-call-argument-newline.js +8 -6
- package/lib/rules/generator-star-spacing.js +4 -9
- package/lib/rules/getter-return.js +4 -7
- package/lib/rules/grouped-accessor-pairs.js +224 -0
- package/lib/rules/indent.js +13 -2
- package/lib/rules/index.js +5 -0
- package/lib/rules/init-declarations.js +2 -2
- package/lib/rules/jsx-quotes.js +1 -1
- package/lib/rules/keyword-spacing.js +32 -56
- package/lib/rules/lines-around-directive.js +1 -1
- package/lib/rules/max-len.js +0 -5
- package/lib/rules/max-statements-per-line.js +3 -7
- package/lib/rules/multiline-comment-style.js +237 -106
- package/lib/rules/multiline-ternary.js +3 -3
- package/lib/rules/newline-after-var.js +6 -7
- package/lib/rules/newline-before-return.js +8 -9
- package/lib/rules/newline-per-chained-call.js +2 -4
- package/lib/rules/no-class-assign.js +2 -2
- package/lib/rules/no-compare-neg-zero.js +1 -2
- package/lib/rules/no-cond-assign.js +14 -4
- package/lib/rules/no-confusing-arrow.js +2 -2
- package/lib/rules/no-console.js +4 -8
- package/lib/rules/no-const-assign.js +1 -1
- package/lib/rules/no-constructor-return.js +62 -0
- package/lib/rules/no-dupe-args.js +1 -1
- package/lib/rules/no-dupe-class-members.js +3 -4
- package/lib/rules/no-dupe-else-if.js +122 -0
- package/lib/rules/no-dupe-keys.js +6 -5
- package/lib/rules/no-duplicate-imports.js +14 -18
- package/lib/rules/no-else-return.js +0 -8
- package/lib/rules/no-empty-function.js +2 -4
- package/lib/rules/no-eval.js +10 -18
- package/lib/rules/no-ex-assign.js +1 -1
- package/lib/rules/no-extra-bind.js +5 -12
- package/lib/rules/no-extra-boolean-cast.js +0 -2
- package/lib/rules/no-extra-label.js +4 -9
- package/lib/rules/no-extra-parens.js +17 -15
- package/lib/rules/no-extra-semi.js +5 -6
- package/lib/rules/no-fallthrough.js +6 -6
- package/lib/rules/no-func-assign.js +3 -3
- package/lib/rules/no-global-assign.js +4 -4
- package/lib/rules/no-implicit-coercion.js +10 -10
- package/lib/rules/no-implicit-globals.js +90 -8
- package/lib/rules/no-implied-eval.js +0 -1
- package/lib/rules/no-inline-comments.js +25 -11
- package/lib/rules/no-invalid-this.js +17 -5
- package/lib/rules/no-labels.js +3 -6
- package/lib/rules/no-lone-blocks.js +1 -1
- package/lib/rules/no-loop-func.js +6 -11
- package/lib/rules/no-magic-numbers.js +6 -6
- package/lib/rules/no-misleading-character-class.js +14 -7
- package/lib/rules/no-mixed-operators.js +13 -22
- package/lib/rules/no-mixed-requires.js +0 -1
- package/lib/rules/no-multi-spaces.js +1 -1
- package/lib/rules/no-native-reassign.js +4 -4
- package/lib/rules/no-octal-escape.js +1 -1
- package/lib/rules/no-param-reassign.js +28 -7
- package/lib/rules/no-redeclare.js +1 -1
- package/lib/rules/no-regex-spaces.js +0 -1
- package/lib/rules/no-restricted-imports.js +11 -11
- package/lib/rules/no-self-assign.js +12 -13
- package/lib/rules/no-sequences.js +3 -3
- package/lib/rules/no-setter-return.js +227 -0
- package/lib/rules/no-shadow.js +1 -4
- package/lib/rules/no-tabs.js +8 -2
- package/lib/rules/no-this-before-super.js +12 -13
- package/lib/rules/no-trailing-spaces.js +19 -7
- package/lib/rules/no-underscore-dangle.js +23 -4
- package/lib/rules/no-unmodified-loop-condition.js +16 -29
- package/lib/rules/no-unneeded-ternary.js +3 -3
- package/lib/rules/no-unreachable.js +7 -7
- package/lib/rules/no-unsafe-finally.js +4 -7
- package/lib/rules/no-unsafe-negation.js +32 -9
- package/lib/rules/no-unused-expressions.js +11 -7
- package/lib/rules/no-unused-labels.js +3 -6
- package/lib/rules/no-unused-vars.js +22 -29
- package/lib/rules/no-use-before-define.js +10 -15
- package/lib/rules/no-useless-call.js +4 -4
- package/lib/rules/no-useless-computed-key.js +60 -33
- package/lib/rules/no-useless-concat.js +4 -4
- package/lib/rules/no-useless-constructor.js +14 -22
- package/lib/rules/no-useless-escape.js +29 -8
- package/lib/rules/no-useless-rename.js +15 -7
- package/lib/rules/no-useless-return.js +8 -15
- package/lib/rules/no-var.js +12 -25
- package/lib/rules/no-warning-comments.js +0 -1
- package/lib/rules/no-whitespace-before-property.js +3 -3
- package/lib/rules/object-curly-newline.js +7 -10
- package/lib/rules/object-curly-spacing.js +21 -22
- package/lib/rules/object-shorthand.js +1 -1
- package/lib/rules/one-var-declaration-per-line.js +2 -2
- package/lib/rules/operator-assignment.js +33 -3
- package/lib/rules/padded-blocks.js +1 -1
- package/lib/rules/padding-line-between-statements.js +0 -16
- package/lib/rules/prefer-arrow-callback.js +6 -6
- package/lib/rules/prefer-const.js +27 -28
- package/lib/rules/prefer-destructuring.js +1 -7
- package/lib/rules/prefer-exponentiation-operator.js +189 -0
- package/lib/rules/prefer-named-capture-group.js +0 -1
- package/lib/rules/prefer-numeric-literals.js +32 -4
- package/lib/rules/prefer-object-spread.js +7 -7
- package/lib/rules/prefer-rest-params.js +3 -6
- package/lib/rules/prefer-spread.js +4 -4
- package/lib/rules/prefer-template.js +5 -6
- package/lib/rules/quote-props.js +1 -1
- package/lib/rules/quotes.js +5 -6
- package/lib/rules/radix.js +5 -10
- package/lib/rules/require-await.js +10 -5
- package/lib/rules/require-yield.js +2 -2
- package/lib/rules/rest-spread-spacing.js +1 -1
- package/lib/rules/semi.js +6 -3
- package/lib/rules/sort-imports.js +3 -4
- package/lib/rules/sort-keys.js +1 -3
- package/lib/rules/space-before-blocks.js +1 -2
- package/lib/rules/space-in-parens.js +4 -4
- package/lib/rules/space-infix-ops.js +6 -6
- package/lib/rules/spaced-comment.js +20 -22
- package/lib/rules/strict.js +2 -4
- package/lib/rules/symbol-description.js +1 -2
- package/lib/rules/template-curly-spacing.js +2 -2
- package/lib/rules/use-isnan.js +40 -3
- package/lib/rules/utils/ast-utils.js +84 -85
- package/lib/rules/utils/fix-tracker.js +0 -6
- package/lib/rules/utils/lazy-loading-rule-map.js +0 -1
- package/lib/rules/vars-on-top.js +11 -11
- package/lib/shared/config-ops.js +2 -2
- package/lib/shared/runtime-info.js +8 -8
- package/lib/shared/traverser.js +2 -0
- package/lib/shared/types.js +9 -0
- package/lib/source-code/source-code.js +62 -17
- package/lib/source-code/token-store/backward-token-comment-cursor.js +5 -5
- package/lib/source-code/token-store/backward-token-cursor.js +5 -5
- package/lib/source-code/token-store/cursors.js +17 -19
- package/lib/source-code/token-store/decorative-cursor.js +1 -1
- package/lib/source-code/token-store/filter-cursor.js +2 -2
- package/lib/source-code/token-store/forward-token-comment-cursor.js +5 -5
- package/lib/source-code/token-store/forward-token-cursor.js +5 -5
- package/lib/source-code/token-store/index.js +86 -92
- package/lib/source-code/token-store/limit-cursor.js +2 -2
- package/lib/source-code/token-store/padded-token-cursor.js +7 -7
- package/lib/source-code/token-store/skip-cursor.js +2 -2
- package/lib/source-code/token-store/utils.js +9 -13
- package/package.json +9 -7
- package/lib/cli-engine/ignored-paths.js +0 -362
@@ -22,8 +22,7 @@ const assert = require("assert"),
|
|
22
22
|
|
23
23
|
/**
|
24
24
|
* Gets whether or not a given segment is reachable.
|
25
|
-
*
|
26
|
-
* @param {CodePathSegment} segment - A segment to get.
|
25
|
+
* @param {CodePathSegment} segment A segment to get.
|
27
26
|
* @returns {boolean} `true` if the segment is reachable.
|
28
27
|
*/
|
29
28
|
function isReachable(segment) {
|
@@ -36,11 +35,10 @@ function isReachable(segment) {
|
|
36
35
|
* When `context.segmentsList` is `[[a, b], [c, d], [e, f]]`, `begin` is `0`, and
|
37
36
|
* `end` is `-1`, this creates `[g, h]`. This `g` is from `a`, `c`, and `e`.
|
38
37
|
* This `h` is from `b`, `d`, and `f`.
|
39
|
-
*
|
40
|
-
* @param {
|
41
|
-
* @param {number}
|
42
|
-
* @param {
|
43
|
-
* @param {Function} create - A factory function of new segments.
|
38
|
+
* @param {ForkContext} context An instance.
|
39
|
+
* @param {number} begin The first index of the previous segments.
|
40
|
+
* @param {number} end The last index of the previous segments.
|
41
|
+
* @param {Function} create A factory function of new segments.
|
44
42
|
* @returns {CodePathSegment[]} New segments.
|
45
43
|
*/
|
46
44
|
function makeSegments(context, begin, end, create) {
|
@@ -69,9 +67,8 @@ function makeSegments(context, begin, end, create) {
|
|
69
67
|
* control statement (such as `break`, `continue`) from the `finally` block, the
|
70
68
|
* destination's segments may be half of the source segments. In that case, this
|
71
69
|
* merges segments.
|
72
|
-
*
|
73
|
-
* @param {
|
74
|
-
* @param {CodePathSegment[]} segments - Segments to merge.
|
70
|
+
* @param {ForkContext} context An instance.
|
71
|
+
* @param {CodePathSegment[]} segments Segments to merge.
|
75
72
|
* @returns {CodePathSegment[]} The merged segments.
|
76
73
|
*/
|
77
74
|
function mergeExtraSegments(context, segments) {
|
@@ -100,10 +97,11 @@ function mergeExtraSegments(context, segments) {
|
|
100
97
|
*/
|
101
98
|
class ForkContext {
|
102
99
|
|
100
|
+
// eslint-disable-next-line jsdoc/require-description
|
103
101
|
/**
|
104
|
-
* @param {IdGenerator} idGenerator
|
105
|
-
* @param {ForkContext|null} upper
|
106
|
-
* @param {number} count
|
102
|
+
* @param {IdGenerator} idGenerator An identifier generator for segments.
|
103
|
+
* @param {ForkContext|null} upper An upper fork context.
|
104
|
+
* @param {number} count A number of parallel segments.
|
107
105
|
*/
|
108
106
|
constructor(idGenerator, upper, count) {
|
109
107
|
this.idGenerator = idGenerator;
|
@@ -142,9 +140,8 @@ class ForkContext {
|
|
142
140
|
|
143
141
|
/**
|
144
142
|
* Creates new segments from this context.
|
145
|
-
*
|
146
|
-
* @param {number}
|
147
|
-
* @param {number} end - The last index of previous segments.
|
143
|
+
* @param {number} begin The first index of previous segments.
|
144
|
+
* @param {number} end The last index of previous segments.
|
148
145
|
* @returns {CodePathSegment[]} New segments.
|
149
146
|
*/
|
150
147
|
makeNext(begin, end) {
|
@@ -154,9 +151,8 @@ class ForkContext {
|
|
154
151
|
/**
|
155
152
|
* Creates new segments from this context.
|
156
153
|
* The new segments is always unreachable.
|
157
|
-
*
|
158
|
-
* @param {number}
|
159
|
-
* @param {number} end - The last index of previous segments.
|
154
|
+
* @param {number} begin The first index of previous segments.
|
155
|
+
* @param {number} end The last index of previous segments.
|
160
156
|
* @returns {CodePathSegment[]} New segments.
|
161
157
|
*/
|
162
158
|
makeUnreachable(begin, end) {
|
@@ -167,9 +163,8 @@ class ForkContext {
|
|
167
163
|
* Creates new segments from this context.
|
168
164
|
* The new segments don't have connections for previous segments.
|
169
165
|
* But these inherit the reachable flag from this context.
|
170
|
-
*
|
171
|
-
* @param {number}
|
172
|
-
* @param {number} end - The last index of previous segments.
|
166
|
+
* @param {number} begin The first index of previous segments.
|
167
|
+
* @param {number} end The last index of previous segments.
|
173
168
|
* @returns {CodePathSegment[]} New segments.
|
174
169
|
*/
|
175
170
|
makeDisconnected(begin, end) {
|
@@ -179,8 +174,7 @@ class ForkContext {
|
|
179
174
|
/**
|
180
175
|
* Adds segments into this context.
|
181
176
|
* The added segments become the head.
|
182
|
-
*
|
183
|
-
* @param {CodePathSegment[]} segments - Segments to add.
|
177
|
+
* @param {CodePathSegment[]} segments Segments to add.
|
184
178
|
* @returns {void}
|
185
179
|
*/
|
186
180
|
add(segments) {
|
@@ -192,8 +186,7 @@ class ForkContext {
|
|
192
186
|
/**
|
193
187
|
* Replaces the head segments with given segments.
|
194
188
|
* The current head segments are removed.
|
195
|
-
*
|
196
|
-
* @param {CodePathSegment[]} segments - Segments to add.
|
189
|
+
* @param {CodePathSegment[]} segments Segments to add.
|
197
190
|
* @returns {void}
|
198
191
|
*/
|
199
192
|
replaceHead(segments) {
|
@@ -204,8 +197,7 @@ class ForkContext {
|
|
204
197
|
|
205
198
|
/**
|
206
199
|
* Adds all segments of a given fork context into this context.
|
207
|
-
*
|
208
|
-
* @param {ForkContext} context - A fork context to add.
|
200
|
+
* @param {ForkContext} context A fork context to add.
|
209
201
|
* @returns {void}
|
210
202
|
*/
|
211
203
|
addAll(context) {
|
@@ -220,7 +212,6 @@ class ForkContext {
|
|
220
212
|
|
221
213
|
/**
|
222
214
|
* Clears all secments in this context.
|
223
|
-
*
|
224
215
|
* @returns {void}
|
225
216
|
*/
|
226
217
|
clear() {
|
@@ -229,8 +220,7 @@ class ForkContext {
|
|
229
220
|
|
230
221
|
/**
|
231
222
|
* Creates the root fork context.
|
232
|
-
*
|
233
|
-
* @param {IdGenerator} idGenerator - An identifier generator for segments.
|
223
|
+
* @param {IdGenerator} idGenerator An identifier generator for segments.
|
234
224
|
* @returns {ForkContext} New fork context.
|
235
225
|
*/
|
236
226
|
static newRoot(idGenerator) {
|
@@ -243,9 +233,8 @@ class ForkContext {
|
|
243
233
|
|
244
234
|
/**
|
245
235
|
* Creates an empty fork context preceded by a given context.
|
246
|
-
*
|
247
|
-
* @param {
|
248
|
-
* @param {boolean} forkLeavingPath - A flag which shows inside of `finally` block.
|
236
|
+
* @param {ForkContext} parentContext The parent fork context.
|
237
|
+
* @param {boolean} forkLeavingPath A flag which shows inside of `finally` block.
|
249
238
|
* @returns {ForkContext} New fork context.
|
250
239
|
*/
|
251
240
|
static newEmpty(parentContext, forkLeavingPath) {
|
@@ -18,8 +18,9 @@
|
|
18
18
|
*/
|
19
19
|
class IdGenerator {
|
20
20
|
|
21
|
+
// eslint-disable-next-line jsdoc/require-description
|
21
22
|
/**
|
22
|
-
* @param {string} prefix
|
23
|
+
* @param {string} prefix Optional. A prefix of generated ids.
|
23
24
|
*/
|
24
25
|
constructor(prefix) {
|
25
26
|
this.prefix = String(prefix);
|
@@ -28,7 +29,6 @@ class IdGenerator {
|
|
28
29
|
|
29
30
|
/**
|
30
31
|
* Generates id.
|
31
|
-
*
|
32
32
|
* @returns {string} A generated id.
|
33
33
|
*/
|
34
34
|
next() {
|
package/lib/linter/linter.js
CHANGED
@@ -292,10 +292,15 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) {
|
|
292
292
|
if (!match) {
|
293
293
|
return;
|
294
294
|
}
|
295
|
-
const
|
295
|
+
const directiveText = match[1];
|
296
|
+
const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(directiveText);
|
296
297
|
|
297
|
-
if (
|
298
|
-
|
298
|
+
if (comment.type === "Line" && !lineCommentSupported) {
|
299
|
+
return;
|
300
|
+
}
|
301
|
+
|
302
|
+
if (warnInlineConfig) {
|
303
|
+
const kind = comment.type === "Block" ? `/*${directiveText}*/` : `//${directiveText}`;
|
299
304
|
|
300
305
|
problems.push(createLintingProblem({
|
301
306
|
ruleId: null,
|
@@ -306,108 +311,101 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) {
|
|
306
311
|
return;
|
307
312
|
}
|
308
313
|
|
309
|
-
|
310
|
-
|
314
|
+
if (lineCommentSupported && comment.loc.start.line !== comment.loc.end.line) {
|
315
|
+
const message = `${directiveText} comment should not span multiple lines.`;
|
311
316
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
+
problems.push(createLintingProblem({
|
318
|
+
ruleId: null,
|
319
|
+
message,
|
320
|
+
loc: comment.loc
|
321
|
+
}));
|
322
|
+
return;
|
323
|
+
}
|
317
324
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
325
|
+
const directiveValue = trimmedCommentText.slice(match.index + directiveText.length);
|
326
|
+
|
327
|
+
switch (directiveText) {
|
328
|
+
case "eslint-disable":
|
329
|
+
case "eslint-enable":
|
330
|
+
case "eslint-disable-next-line":
|
331
|
+
case "eslint-disable-line": {
|
332
|
+
const directiveType = directiveText.slice("eslint-".length);
|
333
|
+
const options = { type: directiveType, loc: comment.loc, value: directiveValue, ruleMapper };
|
334
|
+
const { directives, directiveProblems } = createDisableDirectives(options);
|
335
|
+
|
336
|
+
disableDirectives.push(...directives);
|
337
|
+
problems.push(...directiveProblems);
|
338
|
+
break;
|
323
339
|
}
|
324
|
-
} else if (comment.type === "Block") {
|
325
|
-
switch (match[1]) {
|
326
|
-
case "exported":
|
327
|
-
Object.assign(exportedVariables, commentParser.parseStringConfig(directiveValue, comment));
|
328
|
-
break;
|
329
340
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
341
|
+
case "exported":
|
342
|
+
Object.assign(exportedVariables, commentParser.parseStringConfig(directiveValue, comment));
|
343
|
+
break;
|
344
|
+
|
345
|
+
case "globals":
|
346
|
+
case "global":
|
347
|
+
for (const [id, { value }] of Object.entries(commentParser.parseStringConfig(directiveValue, comment))) {
|
348
|
+
let normalizedValue;
|
349
|
+
|
350
|
+
try {
|
351
|
+
normalizedValue = ConfigOps.normalizeConfigGlobal(value);
|
352
|
+
} catch (err) {
|
353
|
+
problems.push(createLintingProblem({
|
354
|
+
ruleId: null,
|
355
|
+
loc: comment.loc,
|
356
|
+
message: err.message
|
357
|
+
}));
|
358
|
+
continue;
|
359
|
+
}
|
360
|
+
|
361
|
+
if (enabledGlobals[id]) {
|
362
|
+
enabledGlobals[id].comments.push(comment);
|
363
|
+
enabledGlobals[id].value = normalizedValue;
|
364
|
+
} else {
|
365
|
+
enabledGlobals[id] = {
|
366
|
+
comments: [comment],
|
367
|
+
value: normalizedValue
|
368
|
+
};
|
369
|
+
}
|
370
|
+
}
|
371
|
+
break;
|
372
|
+
|
373
|
+
case "eslint": {
|
374
|
+
const parseResult = commentParser.parseJsonConfig(directiveValue, comment.loc);
|
375
|
+
|
376
|
+
if (parseResult.success) {
|
377
|
+
Object.keys(parseResult.config).forEach(name => {
|
378
|
+
const rule = ruleMapper(name);
|
379
|
+
const ruleValue = parseResult.config[name];
|
380
|
+
|
381
|
+
if (rule === null) {
|
382
|
+
problems.push(createLintingProblem({ ruleId: name, loc: comment.loc }));
|
383
|
+
return;
|
384
|
+
}
|
334
385
|
|
335
386
|
try {
|
336
|
-
|
387
|
+
validator.validateRuleOptions(rule, name, ruleValue);
|
337
388
|
} catch (err) {
|
338
389
|
problems.push(createLintingProblem({
|
339
|
-
ruleId:
|
340
|
-
|
341
|
-
|
390
|
+
ruleId: name,
|
391
|
+
message: err.message,
|
392
|
+
loc: comment.loc
|
342
393
|
}));
|
343
|
-
continue;
|
344
|
-
}
|
345
394
|
|
346
|
-
|
347
|
-
|
348
|
-
enabledGlobals[id].value = normalizedValue;
|
349
|
-
} else {
|
350
|
-
enabledGlobals[id] = {
|
351
|
-
comments: [comment],
|
352
|
-
value: normalizedValue
|
353
|
-
};
|
395
|
+
// do not apply the config, if found invalid options.
|
396
|
+
return;
|
354
397
|
}
|
355
|
-
}
|
356
|
-
break;
|
357
|
-
|
358
|
-
case "eslint-disable":
|
359
|
-
directiveType = "disable";
|
360
|
-
break;
|
361
|
-
|
362
|
-
case "eslint-enable":
|
363
|
-
directiveType = "enable";
|
364
|
-
break;
|
365
|
-
|
366
|
-
case "eslint": {
|
367
|
-
const parseResult = commentParser.parseJsonConfig(directiveValue, comment.loc);
|
368
|
-
|
369
|
-
if (parseResult.success) {
|
370
|
-
Object.keys(parseResult.config).forEach(name => {
|
371
|
-
const rule = ruleMapper(name);
|
372
|
-
const ruleValue = parseResult.config[name];
|
373
|
-
|
374
|
-
if (rule === null) {
|
375
|
-
problems.push(createLintingProblem({ ruleId: name, loc: comment.loc }));
|
376
|
-
return;
|
377
|
-
}
|
378
|
-
|
379
|
-
try {
|
380
|
-
validator.validateRuleOptions(rule, name, ruleValue);
|
381
|
-
} catch (err) {
|
382
|
-
problems.push(createLintingProblem({
|
383
|
-
ruleId: name,
|
384
|
-
message: err.message,
|
385
|
-
loc: comment.loc
|
386
|
-
}));
|
387
|
-
|
388
|
-
// do not apply the config, if found invalid options.
|
389
|
-
return;
|
390
|
-
}
|
391
|
-
|
392
|
-
configuredRules[name] = ruleValue;
|
393
|
-
});
|
394
|
-
} else {
|
395
|
-
problems.push(parseResult.error);
|
396
|
-
}
|
397
398
|
|
398
|
-
|
399
|
+
configuredRules[name] = ruleValue;
|
400
|
+
});
|
401
|
+
} else {
|
402
|
+
problems.push(parseResult.error);
|
399
403
|
}
|
400
404
|
|
401
|
-
|
405
|
+
break;
|
402
406
|
}
|
403
|
-
}
|
404
|
-
|
405
|
-
if (directiveType !== "") {
|
406
|
-
const options = { type: directiveType, loc: comment.loc, value: directiveValue, ruleMapper };
|
407
|
-
const { directives, directiveProblems } = createDisableDirectives(options);
|
408
407
|
|
409
|
-
|
410
|
-
problems.push(...directiveProblems);
|
408
|
+
// no default
|
411
409
|
}
|
412
410
|
});
|
413
411
|
|
@@ -438,7 +436,7 @@ const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//gu;
|
|
438
436
|
|
439
437
|
/**
|
440
438
|
* Checks whether or not there is a comment which has "eslint-env *" in a given text.
|
441
|
-
* @param {string} text
|
439
|
+
* @param {string} text A source code text to check.
|
442
440
|
* @returns {Object|null} A result of parseListConfig() with "eslint-env *" comment.
|
443
441
|
*/
|
444
442
|
function findEslintEnv(text) {
|
@@ -555,8 +553,7 @@ function resolveGlobals(providedGlobals, enabledEnvironments) {
|
|
555
553
|
|
556
554
|
/**
|
557
555
|
* Strips Unicode BOM from a given text.
|
558
|
-
*
|
559
|
-
* @param {string} text - A text to strip.
|
556
|
+
* @param {string} text A text to strip.
|
560
557
|
* @returns {string} The stripped text.
|
561
558
|
*/
|
562
559
|
function stripUnicodeBOM(text) {
|
@@ -669,6 +666,8 @@ function parse(text, parser, providedParserOptions, filePath) {
|
|
669
666
|
// If the message includes a leading line number, strip it:
|
670
667
|
const message = `Parsing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
|
671
668
|
|
669
|
+
debug("%s\n%s", message, ex.stack);
|
670
|
+
|
672
671
|
return {
|
673
672
|
success: false,
|
674
673
|
error: {
|
@@ -813,9 +812,10 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
|
|
813
812
|
* @param {Object} settings The settings that were enabled in the config
|
814
813
|
* @param {string} filename The reported filename of the code
|
815
814
|
* @param {boolean} disableFixes If true, it doesn't make `fix` properties.
|
815
|
+
* @param {string | undefined} cwd cwd of the cli
|
816
816
|
* @returns {Problem[]} An array of reported problems
|
817
817
|
*/
|
818
|
-
function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes) {
|
818
|
+
function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes, cwd) {
|
819
819
|
const emitter = createEmitter();
|
820
820
|
const nodeQueue = [];
|
821
821
|
let currentNode = sourceCode.ast;
|
@@ -842,6 +842,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
|
|
842
842
|
{
|
843
843
|
getAncestors: () => getAncestors(currentNode),
|
844
844
|
getDeclaredVariables: sourceCode.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
|
845
|
+
getCwd: () => cwd,
|
845
846
|
getFilename: () => filename,
|
846
847
|
getScope: () => getScope(sourceCode.scopeManager, currentNode),
|
847
848
|
getSourceCode: () => sourceCode,
|
@@ -988,6 +989,24 @@ function getRule(slots, ruleId) {
|
|
988
989
|
);
|
989
990
|
}
|
990
991
|
|
992
|
+
/**
|
993
|
+
* Normalize the value of the cwd
|
994
|
+
* @param {string | undefined} cwd raw value of the cwd, path to a directory that should be considered as the current working directory, can be undefined.
|
995
|
+
* @returns {string | undefined} normalized cwd
|
996
|
+
*/
|
997
|
+
function normalizeCwd(cwd) {
|
998
|
+
if (cwd) {
|
999
|
+
return cwd;
|
1000
|
+
}
|
1001
|
+
if (typeof process === "object") {
|
1002
|
+
return process.cwd();
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
// It's more explicit to assign the undefined
|
1006
|
+
// eslint-disable-next-line no-undefined
|
1007
|
+
return undefined;
|
1008
|
+
}
|
1009
|
+
|
991
1010
|
/**
|
992
1011
|
* The map to store private data.
|
993
1012
|
* @type {WeakMap<Linter, LinterInternalSlots>}
|
@@ -1004,8 +1023,14 @@ const internalSlotsMap = new WeakMap();
|
|
1004
1023
|
*/
|
1005
1024
|
class Linter {
|
1006
1025
|
|
1007
|
-
|
1026
|
+
/**
|
1027
|
+
* Initialize the Linter.
|
1028
|
+
* @param {Object} [config] the config object
|
1029
|
+
* @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
|
1030
|
+
*/
|
1031
|
+
constructor({ cwd } = {}) {
|
1008
1032
|
internalSlotsMap.set(this, {
|
1033
|
+
cwd: normalizeCwd(cwd),
|
1009
1034
|
lastConfigArray: null,
|
1010
1035
|
lastSourceCode: null,
|
1011
1036
|
parserMap: new Map([["espree", espree]]),
|
@@ -1137,7 +1162,8 @@ class Linter {
|
|
1137
1162
|
parserName,
|
1138
1163
|
settings,
|
1139
1164
|
options.filename,
|
1140
|
-
options.disableFixes
|
1165
|
+
options.disableFixes,
|
1166
|
+
slots.cwd
|
1141
1167
|
);
|
1142
1168
|
} catch (err) {
|
1143
1169
|
err.message += `\nOccurred while linting ${options.filename}`;
|
@@ -202,6 +202,7 @@ const parseSelector = lodash.memoize(rawSelector => {
|
|
202
202
|
*/
|
203
203
|
class NodeEventGenerator {
|
204
204
|
|
205
|
+
// eslint-disable-next-line jsdoc/require-description
|
205
206
|
/**
|
206
207
|
* @param {SafeEmitter} emitter
|
207
208
|
* An SafeEmitter which is the destination of events. This emitter must already
|
@@ -286,7 +287,7 @@ class NodeEventGenerator {
|
|
286
287
|
|
287
288
|
/**
|
288
289
|
* Emits an event of entering AST node.
|
289
|
-
* @param {ASTNode} node
|
290
|
+
* @param {ASTNode} node A node which was entered.
|
290
291
|
* @returns {void}
|
291
292
|
*/
|
292
293
|
enterNode(node) {
|
@@ -298,7 +299,7 @@ class NodeEventGenerator {
|
|
298
299
|
|
299
300
|
/**
|
300
301
|
* Emits an event of leaving AST node.
|
301
|
-
* @param {ASTNode} node
|
302
|
+
* @param {ASTNode} node A node which was left.
|
302
303
|
* @returns {void}
|
303
304
|
*/
|
304
305
|
leaveNode(node) {
|
@@ -26,6 +26,7 @@ const interpolate = require("./interpolate");
|
|
26
26
|
* @property {Object} [data] Optional data to use to fill in placeholders in the
|
27
27
|
* message.
|
28
28
|
* @property {Function} [fix] The function to call that creates a fix command.
|
29
|
+
* @property {Array<{desc?: string, messageId?: string, fix: Function}>} suggest Suggestion descriptions and functions to create a the associated fixes.
|
29
30
|
*/
|
30
31
|
|
31
32
|
/**
|
@@ -34,14 +35,15 @@ const interpolate = require("./interpolate");
|
|
34
35
|
* @property {string} ruleId
|
35
36
|
* @property {(0|1|2)} severity
|
36
37
|
* @property {(string|undefined)} message
|
37
|
-
* @property {(string|undefined)} messageId
|
38
|
+
* @property {(string|undefined)} [messageId]
|
38
39
|
* @property {number} line
|
39
40
|
* @property {number} column
|
40
|
-
* @property {(number|undefined)} endLine
|
41
|
-
* @property {(number|undefined)} endColumn
|
41
|
+
* @property {(number|undefined)} [endLine]
|
42
|
+
* @property {(number|undefined)} [endColumn]
|
42
43
|
* @property {(string|null)} nodeType
|
43
44
|
* @property {string} source
|
44
|
-
* @property {({text: string, range: (number[]|null)}|null)} fix
|
45
|
+
* @property {({text: string, range: (number[]|null)}|null)} [fix]
|
46
|
+
* @property {Array<{text: string, range: (number[]|null)}|null>} [suggestions]
|
45
47
|
*/
|
46
48
|
|
47
49
|
//------------------------------------------------------------------------------
|
@@ -182,6 +184,29 @@ function normalizeFixes(descriptor, sourceCode) {
|
|
182
184
|
return fix;
|
183
185
|
}
|
184
186
|
|
187
|
+
/**
|
188
|
+
* Gets an array of suggestion objects from the given descriptor.
|
189
|
+
* @param {MessageDescriptor} descriptor The report descriptor.
|
190
|
+
* @param {SourceCode} sourceCode The source code object to get text between fixes.
|
191
|
+
* @param {Object} messages Object of meta messages for the rule.
|
192
|
+
* @returns {Array<SuggestionResult>} The suggestions for the descriptor
|
193
|
+
*/
|
194
|
+
function mapSuggestions(descriptor, sourceCode, messages) {
|
195
|
+
if (!descriptor.suggest || !Array.isArray(descriptor.suggest)) {
|
196
|
+
return [];
|
197
|
+
}
|
198
|
+
|
199
|
+
return descriptor.suggest.map(suggestInfo => {
|
200
|
+
const computedDesc = suggestInfo.desc || messages[suggestInfo.messageId];
|
201
|
+
|
202
|
+
return {
|
203
|
+
...suggestInfo,
|
204
|
+
desc: interpolate(computedDesc, suggestInfo.data),
|
205
|
+
fix: normalizeFixes(suggestInfo, sourceCode)
|
206
|
+
};
|
207
|
+
});
|
208
|
+
}
|
209
|
+
|
185
210
|
/**
|
186
211
|
* Creates information about the report from a descriptor
|
187
212
|
* @param {Object} options Information about the problem
|
@@ -192,6 +217,7 @@ function normalizeFixes(descriptor, sourceCode) {
|
|
192
217
|
* @param {string} [options.messageId] The error message ID.
|
193
218
|
* @param {{start: SourceLocation, end: (SourceLocation|null)}} options.loc Start and end location
|
194
219
|
* @param {{text: string, range: (number[]|null)}} options.fix The fix object
|
220
|
+
* @param {Array<{text: string, range: (number[]|null)}>} options.suggestions The array of suggestions objects
|
195
221
|
* @returns {function(...args): ReportInfo} Function that returns information about the report
|
196
222
|
*/
|
197
223
|
function createProblem(options) {
|
@@ -221,9 +247,47 @@ function createProblem(options) {
|
|
221
247
|
problem.fix = options.fix;
|
222
248
|
}
|
223
249
|
|
250
|
+
if (options.suggestions && options.suggestions.length > 0) {
|
251
|
+
problem.suggestions = options.suggestions;
|
252
|
+
}
|
253
|
+
|
224
254
|
return problem;
|
225
255
|
}
|
226
256
|
|
257
|
+
/**
|
258
|
+
* Validates that suggestions are properly defined. Throws if an error is detected.
|
259
|
+
* @param {Array<{ desc?: string, messageId?: string }>} suggest The incoming suggest data.
|
260
|
+
* @param {Object} messages Object of meta messages for the rule.
|
261
|
+
* @returns {void}
|
262
|
+
*/
|
263
|
+
function validateSuggestions(suggest, messages) {
|
264
|
+
if (suggest && Array.isArray(suggest)) {
|
265
|
+
suggest.forEach(suggestion => {
|
266
|
+
if (suggestion.messageId) {
|
267
|
+
const { messageId } = suggestion;
|
268
|
+
|
269
|
+
if (!messages) {
|
270
|
+
throw new TypeError(`context.report() called with a suggest option with a messageId '${messageId}', but no messages were present in the rule metadata.`);
|
271
|
+
}
|
272
|
+
|
273
|
+
if (!messages[messageId]) {
|
274
|
+
throw new TypeError(`context.report() called with a suggest option with a messageId '${messageId}' which is not present in the 'messages' config: ${JSON.stringify(messages, null, 2)}`);
|
275
|
+
}
|
276
|
+
|
277
|
+
if (suggestion.desc) {
|
278
|
+
throw new TypeError("context.report() called with a suggest option that defines both a 'messageId' and an 'desc'. Please only pass one.");
|
279
|
+
}
|
280
|
+
} else if (!suggestion.desc) {
|
281
|
+
throw new TypeError("context.report() called with a suggest option that doesn't have either a `desc` or `messageId`");
|
282
|
+
}
|
283
|
+
|
284
|
+
if (typeof suggestion.fix !== "function") {
|
285
|
+
throw new TypeError(`context.report() called with a suggest option without a fix function. See: ${suggestion}`);
|
286
|
+
}
|
287
|
+
});
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
227
291
|
/**
|
228
292
|
* Returns a function that converts the arguments of a `context.report` call from a rule into a reported
|
229
293
|
* problem for the Node.js API.
|
@@ -242,17 +306,17 @@ module.exports = function createReportTranslator(metadata) {
|
|
242
306
|
*/
|
243
307
|
return (...args) => {
|
244
308
|
const descriptor = normalizeMultiArgReportCall(...args);
|
309
|
+
const messages = metadata.messageIds;
|
245
310
|
|
246
311
|
assertValidNodeInfo(descriptor);
|
247
312
|
|
248
313
|
let computedMessage;
|
249
314
|
|
250
315
|
if (descriptor.messageId) {
|
251
|
-
if (!
|
316
|
+
if (!messages) {
|
252
317
|
throw new TypeError("context.report() called with a messageId, but no messages were present in the rule metadata.");
|
253
318
|
}
|
254
319
|
const id = descriptor.messageId;
|
255
|
-
const messages = metadata.messageIds;
|
256
320
|
|
257
321
|
if (descriptor.message) {
|
258
322
|
throw new TypeError("context.report() called with a message and a messageId. Please only pass one.");
|
@@ -267,6 +331,7 @@ module.exports = function createReportTranslator(metadata) {
|
|
267
331
|
throw new TypeError("Missing `message` property in report() call; add a message that describes the linting problem.");
|
268
332
|
}
|
269
333
|
|
334
|
+
validateSuggestions(descriptor.suggest, messages);
|
270
335
|
|
271
336
|
return createProblem({
|
272
337
|
ruleId: metadata.ruleId,
|
@@ -275,7 +340,8 @@ module.exports = function createReportTranslator(metadata) {
|
|
275
340
|
message: interpolate(computedMessage, descriptor.data),
|
276
341
|
messageId: descriptor.messageId,
|
277
342
|
loc: normalizeReportLoc(descriptor),
|
278
|
-
fix: metadata.disableFixes ? null : normalizeFixes(descriptor, metadata.sourceCode)
|
343
|
+
fix: metadata.disableFixes ? null : normalizeFixes(descriptor, metadata.sourceCode),
|
344
|
+
suggestions: metadata.disableFixes ? [] : mapSuggestions(descriptor, metadata.sourceCode, messages)
|
279
345
|
});
|
280
346
|
};
|
281
347
|
};
|