eslint 8.57.0 → 9.2.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/README.md +31 -28
- package/bin/eslint.js +4 -3
- package/conf/ecma-version.js +16 -0
- package/conf/globals.js +1 -0
- package/conf/rule-type-list.json +3 -1
- package/lib/api.js +7 -11
- package/lib/cli-engine/cli-engine.js +14 -3
- package/lib/cli-engine/formatters/formatters-meta.json +1 -29
- package/lib/cli-engine/lint-result-cache.js +2 -2
- package/lib/cli.js +115 -36
- package/lib/config/default-config.js +3 -0
- package/lib/config/flat-config-array.js +110 -24
- package/lib/config/flat-config-helpers.js +41 -20
- package/lib/config/flat-config-schema.js +1 -7
- package/lib/config/rule-validator.js +42 -6
- package/lib/eslint/eslint-helpers.js +116 -58
- package/lib/eslint/eslint.js +892 -377
- package/lib/eslint/index.js +2 -2
- package/lib/eslint/legacy-eslint.js +728 -0
- package/lib/linter/apply-disable-directives.js +59 -31
- package/lib/linter/code-path-analysis/code-path-analyzer.js +0 -1
- package/lib/linter/code-path-analysis/code-path.js +32 -30
- package/lib/linter/code-path-analysis/fork-context.js +1 -1
- package/lib/linter/config-comment-parser.js +8 -11
- package/lib/linter/index.js +1 -3
- package/lib/linter/interpolate.js +24 -2
- package/lib/linter/linter.js +428 -207
- package/lib/linter/report-translator.js +3 -3
- package/lib/linter/rules.js +6 -15
- package/lib/linter/source-code-fixer.js +1 -1
- package/lib/linter/timing.js +16 -8
- package/lib/options.js +35 -3
- package/lib/rule-tester/index.js +3 -1
- package/lib/rule-tester/rule-tester.js +424 -347
- package/lib/rules/array-bracket-newline.js +1 -1
- package/lib/rules/array-bracket-spacing.js +1 -1
- package/lib/rules/block-scoped-var.js +1 -1
- package/lib/rules/callback-return.js +2 -2
- package/lib/rules/camelcase.js +3 -5
- package/lib/rules/capitalized-comments.js +10 -7
- package/lib/rules/comma-dangle.js +1 -1
- package/lib/rules/comma-style.js +2 -2
- package/lib/rules/complexity.js +14 -1
- package/lib/rules/constructor-super.js +99 -100
- package/lib/rules/default-case.js +1 -1
- package/lib/rules/eol-last.js +2 -2
- package/lib/rules/function-paren-newline.js +2 -2
- package/lib/rules/indent-legacy.js +5 -5
- package/lib/rules/indent.js +5 -5
- package/lib/rules/index.js +1 -2
- package/lib/rules/key-spacing.js +2 -2
- package/lib/rules/line-comment-position.js +1 -1
- package/lib/rules/lines-around-directive.js +2 -2
- package/lib/rules/max-depth.js +1 -1
- package/lib/rules/max-len.js +3 -3
- package/lib/rules/max-lines.js +3 -3
- package/lib/rules/max-nested-callbacks.js +1 -1
- package/lib/rules/max-params.js +1 -1
- package/lib/rules/max-statements.js +1 -1
- package/lib/rules/multiline-comment-style.js +7 -7
- package/lib/rules/new-cap.js +1 -1
- package/lib/rules/newline-after-var.js +1 -1
- package/lib/rules/newline-before-return.js +1 -1
- package/lib/rules/no-case-declarations.js +13 -1
- package/lib/rules/no-constant-binary-expression.js +7 -8
- package/lib/rules/no-constant-condition.js +18 -7
- package/lib/rules/no-constructor-return.js +2 -2
- package/lib/rules/no-dupe-class-members.js +2 -2
- package/lib/rules/no-else-return.js +1 -1
- package/lib/rules/no-empty-function.js +2 -2
- package/lib/rules/no-empty-static-block.js +1 -1
- package/lib/rules/no-extend-native.js +1 -2
- package/lib/rules/no-extra-semi.js +1 -1
- package/lib/rules/no-fallthrough.js +41 -16
- package/lib/rules/no-implicit-coercion.js +66 -24
- package/lib/rules/no-inner-declarations.js +23 -2
- package/lib/rules/no-invalid-regexp.js +1 -1
- package/lib/rules/no-invalid-this.js +1 -1
- package/lib/rules/no-lone-blocks.js +3 -3
- package/lib/rules/no-loss-of-precision.js +1 -1
- package/lib/rules/no-misleading-character-class.js +225 -69
- package/lib/rules/no-mixed-spaces-and-tabs.js +1 -1
- package/lib/rules/no-multiple-empty-lines.js +1 -1
- package/lib/rules/no-new-native-nonconstructor.js +1 -1
- package/lib/rules/no-new-symbol.js +8 -1
- package/lib/rules/no-restricted-globals.js +1 -1
- package/lib/rules/no-restricted-imports.js +186 -40
- package/lib/rules/no-restricted-modules.js +2 -2
- package/lib/rules/no-return-await.js +1 -1
- package/lib/rules/no-sequences.js +1 -0
- package/lib/rules/no-this-before-super.js +45 -13
- package/lib/rules/no-trailing-spaces.js +2 -3
- package/lib/rules/no-unneeded-ternary.js +1 -1
- package/lib/rules/no-unsafe-optional-chaining.js +1 -1
- package/lib/rules/no-unused-private-class-members.js +1 -1
- package/lib/rules/no-unused-vars.js +197 -36
- package/lib/rules/no-useless-assignment.js +566 -0
- package/lib/rules/no-useless-backreference.js +1 -1
- package/lib/rules/no-useless-computed-key.js +2 -2
- package/lib/rules/no-useless-return.js +7 -2
- package/lib/rules/object-curly-spacing.js +3 -3
- package/lib/rules/object-property-newline.js +1 -1
- package/lib/rules/one-var.js +5 -5
- package/lib/rules/padded-blocks.js +7 -7
- package/lib/rules/prefer-arrow-callback.js +3 -3
- package/lib/rules/prefer-reflect.js +1 -1
- package/lib/rules/prefer-regex-literals.js +1 -1
- package/lib/rules/prefer-template.js +1 -1
- package/lib/rules/radix.js +2 -2
- package/lib/rules/semi-style.js +1 -1
- package/lib/rules/sort-imports.js +1 -1
- package/lib/rules/sort-keys.js +1 -1
- package/lib/rules/sort-vars.js +1 -1
- package/lib/rules/space-unary-ops.js +1 -1
- package/lib/rules/strict.js +1 -1
- package/lib/rules/use-isnan.js +101 -7
- package/lib/rules/utils/ast-utils.js +16 -7
- package/lib/rules/utils/char-source.js +240 -0
- package/lib/rules/utils/lazy-loading-rule-map.js +1 -1
- package/lib/rules/utils/unicode/index.js +9 -4
- package/lib/rules/yield-star-spacing.js +1 -1
- package/lib/shared/runtime-info.js +1 -0
- package/lib/shared/serialization.js +55 -0
- package/lib/shared/stats.js +30 -0
- package/lib/shared/string-utils.js +9 -11
- package/lib/shared/types.js +35 -1
- package/lib/source-code/index.js +3 -1
- package/lib/source-code/source-code.js +299 -85
- package/lib/source-code/token-store/backward-token-cursor.js +3 -3
- package/lib/source-code/token-store/cursors.js +4 -2
- package/lib/source-code/token-store/forward-token-comment-cursor.js +3 -3
- package/lib/source-code/token-store/forward-token-cursor.js +3 -3
- package/lib/source-code/token-store/index.js +2 -2
- package/lib/unsupported-api.js +3 -5
- package/messages/no-config-found.js +1 -1
- package/messages/plugin-conflict.js +1 -1
- package/messages/plugin-invalid.js +1 -1
- package/messages/plugin-missing.js +1 -1
- package/package.json +32 -29
- package/conf/config-schema.js +0 -93
- package/lib/cli-engine/formatters/checkstyle.js +0 -60
- package/lib/cli-engine/formatters/compact.js +0 -60
- package/lib/cli-engine/formatters/jslint-xml.js +0 -41
- package/lib/cli-engine/formatters/junit.js +0 -82
- package/lib/cli-engine/formatters/tap.js +0 -95
- package/lib/cli-engine/formatters/unix.js +0 -58
- package/lib/cli-engine/formatters/visualstudio.js +0 -63
- package/lib/cli-engine/xml-escape.js +0 -34
- package/lib/eslint/flat-eslint.js +0 -1155
- package/lib/rule-tester/flat-rule-tester.js +0 -1131
- package/lib/rules/require-jsdoc.js +0 -122
- package/lib/rules/utils/patterns/letters.js +0 -36
- package/lib/rules/valid-jsdoc.js +0 -516
- package/lib/shared/config-validator.js +0 -347
- package/lib/shared/deprecation-warnings.js +0 -58
- package/lib/shared/relative-module-resolver.js +0 -50
@@ -16,6 +16,11 @@
|
|
16
16
|
//------------------------------------------------------------------------------
|
17
17
|
|
18
18
|
const escapeRegExp = require("escape-string-regexp");
|
19
|
+
const {
|
20
|
+
Legacy: {
|
21
|
+
ConfigOps
|
22
|
+
}
|
23
|
+
} = require("@eslint/eslintrc/universal");
|
19
24
|
|
20
25
|
/**
|
21
26
|
* Compares the locations of two objects in a source file
|
@@ -33,16 +38,16 @@ function compareLocations(itemA, itemB) {
|
|
33
38
|
* @param {Iterable<Directive>} directives Unused directives to be removed.
|
34
39
|
* @returns {Directive[][]} Directives grouped by their parent comment.
|
35
40
|
*/
|
36
|
-
function
|
41
|
+
function groupByParentDirective(directives) {
|
37
42
|
const groups = new Map();
|
38
43
|
|
39
44
|
for (const directive of directives) {
|
40
|
-
const { unprocessedDirective: {
|
45
|
+
const { unprocessedDirective: { parentDirective } } = directive;
|
41
46
|
|
42
|
-
if (groups.has(
|
43
|
-
groups.get(
|
47
|
+
if (groups.has(parentDirective)) {
|
48
|
+
groups.get(parentDirective).push(directive);
|
44
49
|
} else {
|
45
|
-
groups.set(
|
50
|
+
groups.set(parentDirective, [directive]);
|
46
51
|
}
|
47
52
|
}
|
48
53
|
|
@@ -52,19 +57,19 @@ function groupByParentComment(directives) {
|
|
52
57
|
/**
|
53
58
|
* Creates removal details for a set of directives within the same comment.
|
54
59
|
* @param {Directive[]} directives Unused directives to be removed.
|
55
|
-
* @param {Token}
|
60
|
+
* @param {Token} node The backing Comment token.
|
56
61
|
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
57
62
|
*/
|
58
|
-
function createIndividualDirectivesRemoval(directives,
|
63
|
+
function createIndividualDirectivesRemoval(directives, node) {
|
59
64
|
|
60
65
|
/*
|
61
|
-
* `
|
66
|
+
* `node.value` starts right after `//` or `/*`.
|
62
67
|
* All calculated offsets will be relative to this index.
|
63
68
|
*/
|
64
|
-
const commentValueStart =
|
69
|
+
const commentValueStart = node.range[0] + "//".length;
|
65
70
|
|
66
71
|
// Find where the list of rules starts. `\S+` matches with the directive name (e.g. `eslint-disable-line`)
|
67
|
-
const listStartOffset = /^\s*\S+\s+/u.exec(
|
72
|
+
const listStartOffset = /^\s*\S+\s+/u.exec(node.value)[0].length;
|
68
73
|
|
69
74
|
/*
|
70
75
|
* Get the list text without any surrounding whitespace. In order to preserve the original
|
@@ -73,7 +78,7 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
|
|
73
78
|
* // eslint-disable-line rule-one , rule-two , rule-three -- comment
|
74
79
|
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
75
80
|
*/
|
76
|
-
const listText =
|
81
|
+
const listText = node.value
|
77
82
|
.slice(listStartOffset) // remove directive name and all whitespace before the list
|
78
83
|
.split(/\s-{2,}\s/u)[0] // remove `-- comment`, if it exists
|
79
84
|
.trimEnd(); // remove all whitespace after the list
|
@@ -154,19 +159,19 @@ function createIndividualDirectivesRemoval(directives, commentToken) {
|
|
154
159
|
}
|
155
160
|
|
156
161
|
/**
|
157
|
-
* Creates a description of deleting an entire unused disable
|
162
|
+
* Creates a description of deleting an entire unused disable directive.
|
158
163
|
* @param {Directive[]} directives Unused directives to be removed.
|
159
|
-
* @param {Token}
|
160
|
-
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output
|
164
|
+
* @param {Token} node The backing Comment token.
|
165
|
+
* @returns {{ description, fix, unprocessedDirective }} Details for later creation of an output problem.
|
161
166
|
*/
|
162
|
-
function
|
163
|
-
const { range } =
|
167
|
+
function createDirectiveRemoval(directives, node) {
|
168
|
+
const { range } = node;
|
164
169
|
const ruleIds = directives.filter(directive => directive.ruleId).map(directive => `'${directive.ruleId}'`);
|
165
170
|
|
166
171
|
return {
|
167
172
|
description: ruleIds.length <= 2
|
168
173
|
? ruleIds.join(" or ")
|
169
|
-
: `${ruleIds.slice(0, ruleIds.length - 1).join(", ")}, or ${ruleIds
|
174
|
+
: `${ruleIds.slice(0, ruleIds.length - 1).join(", ")}, or ${ruleIds.at(-1)}`,
|
170
175
|
fix: {
|
171
176
|
range,
|
172
177
|
text: " "
|
@@ -181,20 +186,20 @@ function createCommentRemoval(directives, commentToken) {
|
|
181
186
|
* @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
|
182
187
|
*/
|
183
188
|
function processUnusedDirectives(allDirectives) {
|
184
|
-
const directiveGroups =
|
189
|
+
const directiveGroups = groupByParentDirective(allDirectives);
|
185
190
|
|
186
191
|
return directiveGroups.flatMap(
|
187
192
|
directives => {
|
188
|
-
const {
|
189
|
-
const remainingRuleIds = new Set(
|
193
|
+
const { parentDirective } = directives[0].unprocessedDirective;
|
194
|
+
const remainingRuleIds = new Set(parentDirective.ruleIds);
|
190
195
|
|
191
196
|
for (const directive of directives) {
|
192
197
|
remainingRuleIds.delete(directive.ruleId);
|
193
198
|
}
|
194
199
|
|
195
200
|
return remainingRuleIds.size
|
196
|
-
? createIndividualDirectivesRemoval(directives,
|
197
|
-
: [
|
201
|
+
? createIndividualDirectivesRemoval(directives, parentDirective.node)
|
202
|
+
: [createDirectiveRemoval(directives, parentDirective.node)];
|
198
203
|
}
|
199
204
|
);
|
200
205
|
}
|
@@ -337,7 +342,7 @@ function applyDirectives(options) {
|
|
337
342
|
problem.suppressions = problem.suppressions.concat(suppressions);
|
338
343
|
} else {
|
339
344
|
problem.suppressions = suppressions;
|
340
|
-
usedDisableDirectives.add(disableDirectivesForProblem
|
345
|
+
usedDisableDirectives.add(disableDirectivesForProblem.at(-1));
|
341
346
|
}
|
342
347
|
}
|
343
348
|
|
@@ -345,11 +350,11 @@ function applyDirectives(options) {
|
|
345
350
|
}
|
346
351
|
|
347
352
|
const unusedDisableDirectivesToReport = options.directives
|
348
|
-
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive));
|
353
|
+
.filter(directive => directive.type === "disable" && !usedDisableDirectives.has(directive) && !options.rulesToIgnore.has(directive.ruleId));
|
349
354
|
|
350
355
|
|
351
356
|
const unusedEnableDirectivesToReport = new Set(
|
352
|
-
options.directives.filter(directive => directive.unprocessedDirective.type === "enable")
|
357
|
+
options.directives.filter(directive => directive.unprocessedDirective.type === "enable" && !options.rulesToIgnore.has(directive.ruleId))
|
353
358
|
);
|
354
359
|
|
355
360
|
/*
|
@@ -367,7 +372,7 @@ function applyDirectives(options) {
|
|
367
372
|
|
368
373
|
const unusedDirectives = processed
|
369
374
|
.map(({ description, fix, unprocessedDirective }) => {
|
370
|
-
const {
|
375
|
+
const { parentDirective, type, line, column } = unprocessedDirective;
|
371
376
|
|
372
377
|
let message;
|
373
378
|
|
@@ -383,8 +388,8 @@ function applyDirectives(options) {
|
|
383
388
|
return {
|
384
389
|
ruleId: null,
|
385
390
|
message,
|
386
|
-
line: type === "disable-next-line" ?
|
387
|
-
column: type === "disable-next-line" ?
|
391
|
+
line: type === "disable-next-line" ? parentDirective.node.loc.start.line : line,
|
392
|
+
column: type === "disable-next-line" ? parentDirective.node.loc.start.column + 1 : column,
|
388
393
|
severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
|
389
394
|
nodeType: null,
|
390
395
|
...options.disableFixes ? {} : { fix }
|
@@ -410,11 +415,13 @@ function applyDirectives(options) {
|
|
410
415
|
* @param {{ruleId: (string|null), line: number, column: number}[]} options.problems
|
411
416
|
* A list of problems reported by rules, sorted by increasing location in the file, with one-based columns.
|
412
417
|
* @param {"off" | "warn" | "error"} options.reportUnusedDisableDirectives If `"warn"` or `"error"`, adds additional problems for unused directives
|
418
|
+
* @param {Object} options.configuredRules The rules configuration.
|
419
|
+
* @param {Function} options.ruleFilter A predicate function to filter which rules should be executed.
|
413
420
|
* @param {boolean} options.disableFixes If true, it doesn't make `fix` properties.
|
414
421
|
* @returns {{ruleId: (string|null), line: number, column: number, suppressions?: {kind: string, justification: string}}[]}
|
415
422
|
* An object with a list of reported problems, the suppressed of which contain the suppression information.
|
416
423
|
*/
|
417
|
-
module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirectives = "off" }) => {
|
424
|
+
module.exports = ({ directives, disableFixes, problems, configuredRules, ruleFilter, reportUnusedDisableDirectives = "off" }) => {
|
418
425
|
const blockDirectives = directives
|
419
426
|
.filter(directive => directive.type === "disable" || directive.type === "enable")
|
420
427
|
.map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
|
@@ -443,17 +450,38 @@ module.exports = ({ directives, disableFixes, problems, reportUnusedDisableDirec
|
|
443
450
|
}
|
444
451
|
}).sort(compareLocations);
|
445
452
|
|
453
|
+
// This determines a list of rules that are not being run by the given ruleFilter, if present.
|
454
|
+
const rulesToIgnore = configuredRules && ruleFilter
|
455
|
+
? new Set(Object.keys(configuredRules).filter(ruleId => {
|
456
|
+
const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
|
457
|
+
|
458
|
+
// Ignore for disabled rules.
|
459
|
+
if (severity === 0) {
|
460
|
+
return false;
|
461
|
+
}
|
462
|
+
|
463
|
+
return !ruleFilter({ severity, ruleId });
|
464
|
+
}))
|
465
|
+
: new Set();
|
466
|
+
|
467
|
+
// If no ruleId is supplied that means this directive is applied to all rules, so we can't determine if it's unused if any rules are filtered out.
|
468
|
+
if (rulesToIgnore.size > 0) {
|
469
|
+
rulesToIgnore.add(null);
|
470
|
+
}
|
471
|
+
|
446
472
|
const blockDirectivesResult = applyDirectives({
|
447
473
|
problems,
|
448
474
|
directives: blockDirectives,
|
449
475
|
disableFixes,
|
450
|
-
reportUnusedDisableDirectives
|
476
|
+
reportUnusedDisableDirectives,
|
477
|
+
rulesToIgnore
|
451
478
|
});
|
452
479
|
const lineDirectivesResult = applyDirectives({
|
453
480
|
problems: blockDirectivesResult.problems,
|
454
481
|
directives: lineDirectives,
|
455
482
|
disableFixes,
|
456
|
-
reportUnusedDisableDirectives
|
483
|
+
reportUnusedDisableDirectives,
|
484
|
+
rulesToIgnore
|
457
485
|
});
|
458
486
|
|
459
487
|
return reportUnusedDisableDirectives !== "off"
|
@@ -125,20 +125,6 @@ class CodePath {
|
|
125
125
|
return this.internal.thrownForkContext;
|
126
126
|
}
|
127
127
|
|
128
|
-
/**
|
129
|
-
* Tracks the traversal of the code path through each segment. This array
|
130
|
-
* starts empty and segments are added or removed as the code path is
|
131
|
-
* traversed. This array always ends up empty at the end of a code path
|
132
|
-
* traversal. The `CodePathState` uses this to track its progress through
|
133
|
-
* the code path.
|
134
|
-
* This is a passthrough to the underlying `CodePathState`.
|
135
|
-
* @type {CodePathSegment[]}
|
136
|
-
* @deprecated
|
137
|
-
*/
|
138
|
-
get currentSegments() {
|
139
|
-
return this.internal.currentSegments;
|
140
|
-
}
|
141
|
-
|
142
128
|
/**
|
143
129
|
* Traverses all segments in this code path.
|
144
130
|
*
|
@@ -180,9 +166,9 @@ class CodePath {
|
|
180
166
|
const lastSegment = resolvedOptions.last;
|
181
167
|
|
182
168
|
// set up initial location information
|
183
|
-
let record
|
184
|
-
let index
|
185
|
-
let end
|
169
|
+
let record;
|
170
|
+
let index;
|
171
|
+
let end;
|
186
172
|
let segment = null;
|
187
173
|
|
188
174
|
// segments that have already been visited during traversal
|
@@ -191,8 +177,8 @@ class CodePath {
|
|
191
177
|
// tracks the traversal steps
|
192
178
|
const stack = [[startSegment, 0]];
|
193
179
|
|
194
|
-
//
|
195
|
-
|
180
|
+
// segments that have been skipped during traversal
|
181
|
+
const skipped = new Set();
|
196
182
|
|
197
183
|
// indicates if we exited early from the traversal
|
198
184
|
let broken = false;
|
@@ -207,11 +193,7 @@ class CodePath {
|
|
207
193
|
* @returns {void}
|
208
194
|
*/
|
209
195
|
skip() {
|
210
|
-
|
211
|
-
broken = true;
|
212
|
-
} else {
|
213
|
-
skippedSegment = stack[stack.length - 2][0];
|
214
|
-
}
|
196
|
+
skipped.add(segment);
|
215
197
|
},
|
216
198
|
|
217
199
|
/**
|
@@ -236,6 +218,18 @@ class CodePath {
|
|
236
218
|
);
|
237
219
|
}
|
238
220
|
|
221
|
+
/**
|
222
|
+
* Checks if a given previous segment has been skipped.
|
223
|
+
* @param {CodePathSegment} prevSegment A previous segment to check.
|
224
|
+
* @returns {boolean} `true` if the segment has been skipped.
|
225
|
+
*/
|
226
|
+
function isSkipped(prevSegment) {
|
227
|
+
return (
|
228
|
+
skipped.has(prevSegment) ||
|
229
|
+
segment.isLoopedPrevSegment(prevSegment)
|
230
|
+
);
|
231
|
+
}
|
232
|
+
|
239
233
|
// the traversal
|
240
234
|
while (stack.length > 0) {
|
241
235
|
|
@@ -251,7 +245,7 @@ class CodePath {
|
|
251
245
|
* Otherwise, we just read the value and sometimes modify the
|
252
246
|
* record as we traverse.
|
253
247
|
*/
|
254
|
-
record = stack
|
248
|
+
record = stack.at(-1);
|
255
249
|
segment = record[0];
|
256
250
|
index = record[1];
|
257
251
|
|
@@ -272,17 +266,21 @@ class CodePath {
|
|
272
266
|
continue;
|
273
267
|
}
|
274
268
|
|
275
|
-
// Reset the skipping flag if all branches have been skipped.
|
276
|
-
if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
|
277
|
-
skippedSegment = null;
|
278
|
-
}
|
279
269
|
visited.add(segment);
|
280
270
|
|
271
|
+
|
272
|
+
// Skips the segment if all previous segments have been skipped.
|
273
|
+
const shouldSkip = (
|
274
|
+
skipped.size > 0 &&
|
275
|
+
segment.prevSegments.length > 0 &&
|
276
|
+
segment.prevSegments.every(isSkipped)
|
277
|
+
);
|
278
|
+
|
281
279
|
/*
|
282
280
|
* If the most recent segment hasn't been skipped, then we call
|
283
281
|
* the callback, passing in the segment and the controller.
|
284
282
|
*/
|
285
|
-
if (!
|
283
|
+
if (!shouldSkip) {
|
286
284
|
resolvedCallback.call(this, segment, controller);
|
287
285
|
|
288
286
|
// exit if we're at the last segment
|
@@ -298,6 +296,10 @@ class CodePath {
|
|
298
296
|
if (broken) {
|
299
297
|
break;
|
300
298
|
}
|
299
|
+
} else {
|
300
|
+
|
301
|
+
// If the most recent segment has been skipped, then mark it as skipped.
|
302
|
+
skipped.add(segment);
|
301
303
|
}
|
302
304
|
}
|
303
305
|
|
@@ -40,7 +40,7 @@ module.exports = class ConfigCommentParser {
|
|
40
40
|
|
41
41
|
/**
|
42
42
|
* Parses a list of "name:string_value" or/and "name" options divided by comma or
|
43
|
-
* whitespace. Used for "global"
|
43
|
+
* whitespace. Used for "global" comments.
|
44
44
|
* @param {string} string The string to parse.
|
45
45
|
* @param {Comment} comment The comment node which has the string.
|
46
46
|
* @returns {Object} Result map object of names and string values, or null values if no value was provided
|
@@ -75,11 +75,9 @@ module.exports = class ConfigCommentParser {
|
|
75
75
|
parseJsonConfig(string, location) {
|
76
76
|
debug("Parsing JSON config");
|
77
77
|
|
78
|
-
let items = {};
|
79
|
-
|
80
78
|
// Parses a JSON-like comment by the same way as parsing CLI option.
|
81
79
|
try {
|
82
|
-
items = levn.parse("Object", string) || {};
|
80
|
+
const items = levn.parse("Object", string) || {};
|
83
81
|
|
84
82
|
// Some tests say that it should ignore invalid comments such as `/*eslint no-alert:abc*/`.
|
85
83
|
// Also, commaless notations have invalid severity:
|
@@ -102,11 +100,15 @@ module.exports = class ConfigCommentParser {
|
|
102
100
|
* Optionator cannot parse commaless notations.
|
103
101
|
* But we are supporting that. So this is a fallback for that.
|
104
102
|
*/
|
105
|
-
items = {};
|
106
103
|
const normalizedString = string.replace(/([-a-zA-Z0-9/]+):/gu, "\"$1\":").replace(/(\]|[0-9])\s+(?=")/u, "$1,");
|
107
104
|
|
108
105
|
try {
|
109
|
-
items = JSON.parse(`{${normalizedString}}`);
|
106
|
+
const items = JSON.parse(`{${normalizedString}}`);
|
107
|
+
|
108
|
+
return {
|
109
|
+
success: true,
|
110
|
+
config: items
|
111
|
+
};
|
110
112
|
} catch (ex) {
|
111
113
|
debug("Manual parsing failed.");
|
112
114
|
|
@@ -124,11 +126,6 @@ module.exports = class ConfigCommentParser {
|
|
124
126
|
};
|
125
127
|
|
126
128
|
}
|
127
|
-
|
128
|
-
return {
|
129
|
-
success: true,
|
130
|
-
config: items
|
131
|
-
};
|
132
129
|
}
|
133
130
|
|
134
131
|
/**
|
package/lib/linter/index.js
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
"use strict";
|
2
2
|
|
3
3
|
const { Linter } = require("./linter");
|
4
|
-
const interpolate = require("./interpolate");
|
5
4
|
const SourceCodeFixer = require("./source-code-fixer");
|
6
5
|
|
7
6
|
module.exports = {
|
8
7
|
Linter,
|
9
8
|
|
10
9
|
// For testers.
|
11
|
-
SourceCodeFixer
|
12
|
-
interpolate
|
10
|
+
SourceCodeFixer
|
13
11
|
};
|
@@ -9,13 +9,30 @@
|
|
9
9
|
// Public Interface
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
|
12
|
+
/**
|
13
|
+
* Returns a global expression matching placeholders in messages.
|
14
|
+
* @returns {RegExp} Global regular expression matching placeholders
|
15
|
+
*/
|
16
|
+
function getPlaceholderMatcher() {
|
17
|
+
return /\{\{([^{}]+?)\}\}/gu;
|
18
|
+
}
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Replaces {{ placeholders }} in the message with the provided data.
|
22
|
+
* Does not replace placeholders not available in the data.
|
23
|
+
* @param {string} text Original message with potential placeholders
|
24
|
+
* @param {Record<string, string>} data Map of placeholder name to its value
|
25
|
+
* @returns {string} Message with replaced placeholders
|
26
|
+
*/
|
27
|
+
function interpolate(text, data) {
|
13
28
|
if (!data) {
|
14
29
|
return text;
|
15
30
|
}
|
16
31
|
|
32
|
+
const matcher = getPlaceholderMatcher();
|
33
|
+
|
17
34
|
// Substitution content for any {{ }} markers.
|
18
|
-
return text.replace(
|
35
|
+
return text.replace(matcher, (fullMatch, termWithWhitespace) => {
|
19
36
|
const term = termWithWhitespace.trim();
|
20
37
|
|
21
38
|
if (term in data) {
|
@@ -25,4 +42,9 @@ module.exports = (text, data) => {
|
|
25
42
|
// Preserve old behavior: If parameter name not provided, don't replace it.
|
26
43
|
return fullMatch;
|
27
44
|
});
|
45
|
+
}
|
46
|
+
|
47
|
+
module.exports = {
|
48
|
+
getPlaceholderMatcher,
|
49
|
+
interpolate
|
28
50
|
};
|