eslint 9.0.0-rc.0 → 9.1.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 +7 -11
- package/conf/globals.js +1 -0
- package/lib/cli.js +42 -1
- package/lib/config/flat-config-array.js +110 -4
- package/lib/eslint/eslint-helpers.js +84 -45
- package/lib/eslint/eslint.js +24 -5
- package/lib/linter/apply-disable-directives.js +24 -24
- package/lib/linter/linter.js +181 -66
- package/lib/linter/timing.js +16 -8
- package/lib/options.js +27 -3
- package/lib/rule-tester/rule-tester.js +18 -2
- package/lib/rules/camelcase.js +3 -5
- package/lib/rules/constructor-super.js +62 -93
- package/lib/rules/no-constant-condition.js +18 -7
- package/lib/rules/no-lone-blocks.js +1 -1
- package/lib/rules/no-unused-vars.js +179 -29
- package/lib/rules/use-isnan.js +2 -2
- package/lib/shared/stats.js +30 -0
- package/lib/shared/string-utils.js +9 -11
- package/lib/shared/types.js +34 -0
- package/lib/source-code/source-code.js +128 -0
- 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/messages/plugin-conflict.js +1 -1
- package/messages/plugin-invalid.js +1 -1
- package/messages/plugin-missing.js +1 -1
- package/package.json +11 -9
@@ -15,6 +15,11 @@ const astUtils = require("./utils/ast-utils");
|
|
15
15
|
// Typedefs
|
16
16
|
//------------------------------------------------------------------------------
|
17
17
|
|
18
|
+
/**
|
19
|
+
* A simple name for the types of variables that this rule supports
|
20
|
+
* @typedef {'array-destructure'|'catch-clause'|'parameter'|'variable'} VariableType
|
21
|
+
*/
|
22
|
+
|
18
23
|
/**
|
19
24
|
* Bag of data used for formatting the `unusedVar` lint message.
|
20
25
|
* @typedef {Object} UnusedVarMessageData
|
@@ -23,6 +28,13 @@ const astUtils = require("./utils/ast-utils");
|
|
23
28
|
* @property {string} additional Any additional info to be appended at the end.
|
24
29
|
*/
|
25
30
|
|
31
|
+
/**
|
32
|
+
* Bag of data used for formatting the `usedIgnoredVar` lint message.
|
33
|
+
* @typedef {Object} UsedIgnoredVarMessageData
|
34
|
+
* @property {string} varName The name of the unused var.
|
35
|
+
* @property {string} additional Any additional info to be appended at the end.
|
36
|
+
*/
|
37
|
+
|
26
38
|
//------------------------------------------------------------------------------
|
27
39
|
// Rule Definition
|
28
40
|
//------------------------------------------------------------------------------
|
@@ -73,6 +85,9 @@ module.exports = {
|
|
73
85
|
},
|
74
86
|
ignoreClassWithStaticInitBlock: {
|
75
87
|
type: "boolean"
|
88
|
+
},
|
89
|
+
reportUsedIgnorePattern: {
|
90
|
+
type: "boolean"
|
76
91
|
}
|
77
92
|
},
|
78
93
|
additionalProperties: false
|
@@ -82,7 +97,8 @@ module.exports = {
|
|
82
97
|
],
|
83
98
|
|
84
99
|
messages: {
|
85
|
-
unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}."
|
100
|
+
unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}.",
|
101
|
+
usedIgnoredVar: "'{{varName}}' is marked as ignored but is used{{additional}}."
|
86
102
|
}
|
87
103
|
},
|
88
104
|
|
@@ -96,7 +112,8 @@ module.exports = {
|
|
96
112
|
args: "after-used",
|
97
113
|
ignoreRestSiblings: false,
|
98
114
|
caughtErrors: "all",
|
99
|
-
ignoreClassWithStaticInitBlock: false
|
115
|
+
ignoreClassWithStaticInitBlock: false,
|
116
|
+
reportUsedIgnorePattern: false
|
100
117
|
};
|
101
118
|
|
102
119
|
const firstOption = context.options[0];
|
@@ -110,6 +127,7 @@ module.exports = {
|
|
110
127
|
config.ignoreRestSiblings = firstOption.ignoreRestSiblings || config.ignoreRestSiblings;
|
111
128
|
config.caughtErrors = firstOption.caughtErrors || config.caughtErrors;
|
112
129
|
config.ignoreClassWithStaticInitBlock = firstOption.ignoreClassWithStaticInitBlock || config.ignoreClassWithStaticInitBlock;
|
130
|
+
config.reportUsedIgnorePattern = firstOption.reportUsedIgnorePattern || config.reportUsedIgnorePattern;
|
113
131
|
|
114
132
|
if (firstOption.varsIgnorePattern) {
|
115
133
|
config.varsIgnorePattern = new RegExp(firstOption.varsIgnorePattern, "u");
|
@@ -129,6 +147,50 @@ module.exports = {
|
|
129
147
|
}
|
130
148
|
}
|
131
149
|
|
150
|
+
/**
|
151
|
+
* Gets a given variable's description and configured ignore pattern
|
152
|
+
* based on the provided variableType
|
153
|
+
* @param {VariableType} variableType a simple name for the types of variables that this rule supports
|
154
|
+
* @throws {Error} (Unreachable)
|
155
|
+
* @returns {[string | undefined, string | undefined]} the given variable's description and
|
156
|
+
* ignore pattern
|
157
|
+
*/
|
158
|
+
function getVariableDescription(variableType) {
|
159
|
+
let pattern;
|
160
|
+
let variableDescription;
|
161
|
+
|
162
|
+
switch (variableType) {
|
163
|
+
case "array-destructure":
|
164
|
+
pattern = config.destructuredArrayIgnorePattern;
|
165
|
+
variableDescription = "elements of array destructuring";
|
166
|
+
break;
|
167
|
+
|
168
|
+
case "catch-clause":
|
169
|
+
pattern = config.caughtErrorsIgnorePattern;
|
170
|
+
variableDescription = "args";
|
171
|
+
break;
|
172
|
+
|
173
|
+
case "parameter":
|
174
|
+
pattern = config.argsIgnorePattern;
|
175
|
+
variableDescription = "args";
|
176
|
+
break;
|
177
|
+
|
178
|
+
case "variable":
|
179
|
+
pattern = config.varsIgnorePattern;
|
180
|
+
variableDescription = "vars";
|
181
|
+
break;
|
182
|
+
|
183
|
+
default:
|
184
|
+
throw new Error(`Unexpected variable type: ${variableType}`);
|
185
|
+
}
|
186
|
+
|
187
|
+
if (pattern) {
|
188
|
+
pattern = pattern.toString();
|
189
|
+
}
|
190
|
+
|
191
|
+
return [variableDescription, pattern];
|
192
|
+
}
|
193
|
+
|
132
194
|
/**
|
133
195
|
* Generates the message data about the variable being defined and unused,
|
134
196
|
* including the ignore pattern if configured.
|
@@ -136,27 +198,42 @@ module.exports = {
|
|
136
198
|
* @returns {UnusedVarMessageData} The message data to be used with this unused variable.
|
137
199
|
*/
|
138
200
|
function getDefinedMessageData(unusedVar) {
|
139
|
-
const
|
140
|
-
let
|
141
|
-
let pattern;
|
201
|
+
const def = unusedVar.defs && unusedVar.defs[0];
|
202
|
+
let additionalMessageData = "";
|
142
203
|
|
143
|
-
if (
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
type
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
204
|
+
if (def) {
|
205
|
+
let pattern;
|
206
|
+
let variableDescription;
|
207
|
+
|
208
|
+
switch (def.type) {
|
209
|
+
case "CatchClause":
|
210
|
+
if (config.caughtErrorsIgnorePattern) {
|
211
|
+
[variableDescription, pattern] = getVariableDescription("catch-clause");
|
212
|
+
}
|
213
|
+
break;
|
153
214
|
|
154
|
-
|
215
|
+
case "Parameter":
|
216
|
+
if (config.argsIgnorePattern) {
|
217
|
+
[variableDescription, pattern] = getVariableDescription("parameter");
|
218
|
+
}
|
219
|
+
break;
|
220
|
+
|
221
|
+
default:
|
222
|
+
if (config.varsIgnorePattern) {
|
223
|
+
[variableDescription, pattern] = getVariableDescription("variable");
|
224
|
+
}
|
225
|
+
break;
|
226
|
+
}
|
227
|
+
|
228
|
+
if (pattern && variableDescription) {
|
229
|
+
additionalMessageData = `. Allowed unused ${variableDescription} must match ${pattern}`;
|
230
|
+
}
|
231
|
+
}
|
155
232
|
|
156
233
|
return {
|
157
234
|
varName: unusedVar.name,
|
158
235
|
action: "defined",
|
159
|
-
additional
|
236
|
+
additional: additionalMessageData
|
160
237
|
};
|
161
238
|
}
|
162
239
|
|
@@ -167,19 +244,51 @@ module.exports = {
|
|
167
244
|
* @returns {UnusedVarMessageData} The message data to be used with this unused variable.
|
168
245
|
*/
|
169
246
|
function getAssignedMessageData(unusedVar) {
|
170
|
-
const def = unusedVar.defs[0];
|
171
|
-
let
|
247
|
+
const def = unusedVar.defs && unusedVar.defs[0];
|
248
|
+
let additionalMessageData = "";
|
249
|
+
|
250
|
+
if (def) {
|
251
|
+
let pattern;
|
252
|
+
let variableDescription;
|
172
253
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
254
|
+
if (def.name.parent.type === "ArrayPattern" && config.destructuredArrayIgnorePattern) {
|
255
|
+
[variableDescription, pattern] = getVariableDescription("array-destructure");
|
256
|
+
} else if (config.varsIgnorePattern) {
|
257
|
+
[variableDescription, pattern] = getVariableDescription("variable");
|
258
|
+
}
|
259
|
+
|
260
|
+
if (pattern && variableDescription) {
|
261
|
+
additionalMessageData = `. Allowed unused ${variableDescription} must match ${pattern}`;
|
262
|
+
}
|
177
263
|
}
|
178
264
|
|
179
265
|
return {
|
180
266
|
varName: unusedVar.name,
|
181
267
|
action: "assigned a value",
|
182
|
-
additional
|
268
|
+
additional: additionalMessageData
|
269
|
+
};
|
270
|
+
}
|
271
|
+
|
272
|
+
/**
|
273
|
+
* Generate the warning message about a variable being used even though
|
274
|
+
* it is marked as being ignored.
|
275
|
+
* @param {Variable} variable eslint-scope variable object
|
276
|
+
* @param {VariableType} variableType a simple name for the types of variables that this rule supports
|
277
|
+
* @returns {UsedIgnoredVarMessageData} The message data to be used with
|
278
|
+
* this used ignored variable.
|
279
|
+
*/
|
280
|
+
function getUsedIgnoredMessageData(variable, variableType) {
|
281
|
+
const [variableDescription, pattern] = getVariableDescription(variableType);
|
282
|
+
|
283
|
+
let additionalMessageData = "";
|
284
|
+
|
285
|
+
if (pattern && variableDescription) {
|
286
|
+
additionalMessageData = `. Used ${variableDescription} must not match ${pattern}`;
|
287
|
+
}
|
288
|
+
|
289
|
+
return {
|
290
|
+
varName: variable.name,
|
291
|
+
additional: additionalMessageData
|
183
292
|
};
|
184
293
|
}
|
185
294
|
|
@@ -532,8 +641,13 @@ module.exports = {
|
|
532
641
|
* @private
|
533
642
|
*/
|
534
643
|
function isUsedVariable(variable) {
|
535
|
-
|
536
|
-
|
644
|
+
if (variable.eslintUsed) {
|
645
|
+
return true;
|
646
|
+
}
|
647
|
+
|
648
|
+
const functionNodes = getFunctionDefinitions(variable);
|
649
|
+
const isFunctionDefinition = functionNodes.length > 0;
|
650
|
+
|
537
651
|
let rhsNode = null;
|
538
652
|
|
539
653
|
return variable.references.some(ref => {
|
@@ -589,8 +703,13 @@ module.exports = {
|
|
589
703
|
continue;
|
590
704
|
}
|
591
705
|
|
592
|
-
// skip function expression names
|
593
|
-
if (scope.functionExpressionScope
|
706
|
+
// skip function expression names
|
707
|
+
if (scope.functionExpressionScope) {
|
708
|
+
continue;
|
709
|
+
}
|
710
|
+
|
711
|
+
// skip variables marked with markVariableAsUsed()
|
712
|
+
if (!config.reportUsedIgnorePattern && variable.eslintUsed) {
|
594
713
|
continue;
|
595
714
|
}
|
596
715
|
|
@@ -615,6 +734,14 @@ module.exports = {
|
|
615
734
|
config.destructuredArrayIgnorePattern &&
|
616
735
|
config.destructuredArrayIgnorePattern.test(def.name.name)
|
617
736
|
) {
|
737
|
+
if (config.reportUsedIgnorePattern && isUsedVariable(variable)) {
|
738
|
+
context.report({
|
739
|
+
node: def.name,
|
740
|
+
messageId: "usedIgnoredVar",
|
741
|
+
data: getUsedIgnoredMessageData(variable, "array-destructure")
|
742
|
+
});
|
743
|
+
}
|
744
|
+
|
618
745
|
continue;
|
619
746
|
}
|
620
747
|
|
@@ -634,6 +761,14 @@ module.exports = {
|
|
634
761
|
|
635
762
|
// skip ignored parameters
|
636
763
|
if (config.caughtErrorsIgnorePattern && config.caughtErrorsIgnorePattern.test(def.name.name)) {
|
764
|
+
if (config.reportUsedIgnorePattern && isUsedVariable(variable)) {
|
765
|
+
context.report({
|
766
|
+
node: def.name,
|
767
|
+
messageId: "usedIgnoredVar",
|
768
|
+
data: getUsedIgnoredMessageData(variable, "catch-clause")
|
769
|
+
});
|
770
|
+
}
|
771
|
+
|
637
772
|
continue;
|
638
773
|
}
|
639
774
|
} else if (type === "Parameter") {
|
@@ -650,6 +785,14 @@ module.exports = {
|
|
650
785
|
|
651
786
|
// skip ignored parameters
|
652
787
|
if (config.argsIgnorePattern && config.argsIgnorePattern.test(def.name.name)) {
|
788
|
+
if (config.reportUsedIgnorePattern && isUsedVariable(variable)) {
|
789
|
+
context.report({
|
790
|
+
node: def.name,
|
791
|
+
messageId: "usedIgnoredVar",
|
792
|
+
data: getUsedIgnoredMessageData(variable, "parameter")
|
793
|
+
});
|
794
|
+
}
|
795
|
+
|
653
796
|
continue;
|
654
797
|
}
|
655
798
|
|
@@ -661,6 +804,14 @@ module.exports = {
|
|
661
804
|
|
662
805
|
// skip ignored variables
|
663
806
|
if (config.varsIgnorePattern && config.varsIgnorePattern.test(def.name.name)) {
|
807
|
+
if (config.reportUsedIgnorePattern && isUsedVariable(variable)) {
|
808
|
+
context.report({
|
809
|
+
node: def.name,
|
810
|
+
messageId: "usedIgnoredVar",
|
811
|
+
data: getUsedIgnoredMessageData(variable, "variable")
|
812
|
+
});
|
813
|
+
}
|
814
|
+
|
664
815
|
continue;
|
665
816
|
}
|
666
817
|
}
|
@@ -724,6 +875,5 @@ module.exports = {
|
|
724
875
|
}
|
725
876
|
}
|
726
877
|
};
|
727
|
-
|
728
878
|
}
|
729
879
|
};
|
package/lib/rules/use-isnan.js
CHANGED
@@ -182,7 +182,7 @@ module.exports = {
|
|
182
182
|
|
183
183
|
if (
|
184
184
|
(methodName === "indexOf" || methodName === "lastIndexOf") &&
|
185
|
-
node.arguments.length
|
185
|
+
node.arguments.length <= 2 &&
|
186
186
|
isNaNIdentifier(node.arguments[0])
|
187
187
|
) {
|
188
188
|
|
@@ -190,7 +190,7 @@ module.exports = {
|
|
190
190
|
* To retain side effects, it's essential to address `NaN` beforehand, which
|
191
191
|
* is not possible with fixes like `arr.findIndex(Number.isNaN)`.
|
192
192
|
*/
|
193
|
-
const isSuggestable = node.arguments[0].type !== "SequenceExpression";
|
193
|
+
const isSuggestable = node.arguments[0].type !== "SequenceExpression" && !node.arguments[1];
|
194
194
|
const suggestedFixes = [];
|
195
195
|
|
196
196
|
if (isSuggestable) {
|
@@ -0,0 +1,30 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Provides helper functions to start/stop the time measurements
|
3
|
+
* that are provided by the ESLint 'stats' option.
|
4
|
+
* @author Mara Kiefer <http://github.com/mnkiefer>
|
5
|
+
*/
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Start time measurement
|
10
|
+
* @returns {[number, number]} t variable for tracking time
|
11
|
+
*/
|
12
|
+
function startTime() {
|
13
|
+
return process.hrtime();
|
14
|
+
}
|
15
|
+
|
16
|
+
/**
|
17
|
+
* End time measurement
|
18
|
+
* @param {[number, number]} t Variable for tracking time
|
19
|
+
* @returns {number} The measured time in milliseconds
|
20
|
+
*/
|
21
|
+
function endTime(t) {
|
22
|
+
const time = process.hrtime(t);
|
23
|
+
|
24
|
+
return time[0] * 1e3 + time[1] / 1e6;
|
25
|
+
}
|
26
|
+
|
27
|
+
module.exports = {
|
28
|
+
startTime,
|
29
|
+
endTime
|
30
|
+
};
|
@@ -5,12 +5,6 @@
|
|
5
5
|
|
6
6
|
"use strict";
|
7
7
|
|
8
|
-
//------------------------------------------------------------------------------
|
9
|
-
// Requirements
|
10
|
-
//------------------------------------------------------------------------------
|
11
|
-
|
12
|
-
const Graphemer = require("graphemer").default;
|
13
|
-
|
14
8
|
//------------------------------------------------------------------------------
|
15
9
|
// Helpers
|
16
10
|
//------------------------------------------------------------------------------
|
@@ -18,8 +12,8 @@ const Graphemer = require("graphemer").default;
|
|
18
12
|
// eslint-disable-next-line no-control-regex -- intentionally including control characters
|
19
13
|
const ASCII_REGEX = /^[\u0000-\u007f]*$/u;
|
20
14
|
|
21
|
-
/** @type {
|
22
|
-
let
|
15
|
+
/** @type {Intl.Segmenter | undefined} */
|
16
|
+
let segmenter;
|
23
17
|
|
24
18
|
//------------------------------------------------------------------------------
|
25
19
|
// Public Interface
|
@@ -47,11 +41,15 @@ function getGraphemeCount(value) {
|
|
47
41
|
return value.length;
|
48
42
|
}
|
49
43
|
|
50
|
-
|
51
|
-
|
44
|
+
segmenter ??= new Intl.Segmenter("en-US"); // en-US locale should be supported everywhere
|
45
|
+
let graphemeCount = 0;
|
46
|
+
|
47
|
+
// eslint-disable-next-line no-unused-vars -- for-of needs a variable
|
48
|
+
for (const unused of segmenter.segment(value)) {
|
49
|
+
graphemeCount++;
|
52
50
|
}
|
53
51
|
|
54
|
-
return
|
52
|
+
return graphemeCount;
|
55
53
|
}
|
56
54
|
|
57
55
|
module.exports = {
|
package/lib/shared/types.js
CHANGED
@@ -189,11 +189,45 @@ module.exports = {};
|
|
189
189
|
* @property {number} warningCount Number of warnings for the result.
|
190
190
|
* @property {number} fixableErrorCount Number of fixable errors for the result.
|
191
191
|
* @property {number} fixableWarningCount Number of fixable warnings for the result.
|
192
|
+
* @property {Stats} [stats] The performance statistics collected with the `stats` flag.
|
192
193
|
* @property {string} [source] The source code of the file that was linted.
|
193
194
|
* @property {string} [output] The source code of the file that was linted, with as many fixes applied as possible.
|
194
195
|
* @property {DeprecatedRuleInfo[]} usedDeprecatedRules The list of used deprecated rules.
|
195
196
|
*/
|
196
197
|
|
198
|
+
/**
|
199
|
+
* Performance statistics
|
200
|
+
* @typedef {Object} Stats
|
201
|
+
* @property {number} fixPasses The number of times ESLint has applied at least one fix after linting.
|
202
|
+
* @property {Times} times The times spent on (parsing, fixing, linting) a file.
|
203
|
+
*/
|
204
|
+
|
205
|
+
/**
|
206
|
+
* Performance Times for each ESLint pass
|
207
|
+
* @typedef {Object} Times
|
208
|
+
* @property {TimePass[]} passes Time passes
|
209
|
+
*/
|
210
|
+
|
211
|
+
/**
|
212
|
+
* @typedef {Object} TimePass
|
213
|
+
* @property {ParseTime} parse The parse object containing all parse time information.
|
214
|
+
* @property {Record<string, RuleTime>} [rules] The rules object containing all lint time information for each rule.
|
215
|
+
* @property {FixTime} fix The parse object containing all fix time information.
|
216
|
+
* @property {number} total The total time that is spent on (parsing, fixing, linting) a file.
|
217
|
+
*/
|
218
|
+
/**
|
219
|
+
* @typedef {Object} ParseTime
|
220
|
+
* @property {number} total The total time that is spent when parsing a file.
|
221
|
+
*/
|
222
|
+
/**
|
223
|
+
* @typedef {Object} RuleTime
|
224
|
+
* @property {number} total The total time that is spent on a rule.
|
225
|
+
*/
|
226
|
+
/**
|
227
|
+
* @typedef {Object} FixTime
|
228
|
+
* @property {number} total The total time that is spent on applying fixes to the code.
|
229
|
+
*/
|
230
|
+
|
197
231
|
/**
|
198
232
|
* Information provided when the maximum warning threshold is exceeded.
|
199
233
|
* @typedef {Object} MaxWarningsExceeded
|
@@ -373,6 +373,56 @@ class TraversalStep {
|
|
373
373
|
}
|
374
374
|
}
|
375
375
|
|
376
|
+
/**
|
377
|
+
* A class to represent a directive comment.
|
378
|
+
*/
|
379
|
+
class Directive {
|
380
|
+
|
381
|
+
/**
|
382
|
+
* The type of directive.
|
383
|
+
* @type {"disable"|"enable"|"disable-next-line"|"disable-line"}
|
384
|
+
* @readonly
|
385
|
+
*/
|
386
|
+
type;
|
387
|
+
|
388
|
+
/**
|
389
|
+
* The node representing the directive.
|
390
|
+
* @type {ASTNode|Comment}
|
391
|
+
* @readonly
|
392
|
+
*/
|
393
|
+
node;
|
394
|
+
|
395
|
+
/**
|
396
|
+
* Everything after the "eslint-disable" portion of the directive,
|
397
|
+
* but before the "--" that indicates the justification.
|
398
|
+
* @type {string}
|
399
|
+
* @readonly
|
400
|
+
*/
|
401
|
+
value;
|
402
|
+
|
403
|
+
/**
|
404
|
+
* The justification for the directive.
|
405
|
+
* @type {string}
|
406
|
+
* @readonly
|
407
|
+
*/
|
408
|
+
justification;
|
409
|
+
|
410
|
+
/**
|
411
|
+
* Creates a new instance.
|
412
|
+
* @param {Object} options The options for the directive.
|
413
|
+
* @param {"disable"|"enable"|"disable-next-line"|"disable-line"} options.type The type of directive.
|
414
|
+
* @param {ASTNode|Comment} options.node The node representing the directive.
|
415
|
+
* @param {string} options.value The value of the directive.
|
416
|
+
* @param {string} options.justification The justification for the directive.
|
417
|
+
*/
|
418
|
+
constructor({ type, node, value, justification }) {
|
419
|
+
this.type = type;
|
420
|
+
this.node = node;
|
421
|
+
this.value = value;
|
422
|
+
this.justification = justification;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
|
376
426
|
//------------------------------------------------------------------------------
|
377
427
|
// Public Interface
|
378
428
|
//------------------------------------------------------------------------------
|
@@ -921,6 +971,84 @@ class SourceCode extends TokenStore {
|
|
921
971
|
return configNodes;
|
922
972
|
}
|
923
973
|
|
974
|
+
/**
|
975
|
+
* Returns an all directive nodes that enable or disable rules along with any problems
|
976
|
+
* encountered while parsing the directives.
|
977
|
+
* @returns {{problems:Array<Problem>,directives:Array<Directive>}} Information
|
978
|
+
* that ESLint needs to further process the directives.
|
979
|
+
*/
|
980
|
+
getDisableDirectives() {
|
981
|
+
|
982
|
+
// check the cache first
|
983
|
+
const cachedDirectives = this[caches].get("disableDirectives");
|
984
|
+
|
985
|
+
if (cachedDirectives) {
|
986
|
+
return cachedDirectives;
|
987
|
+
}
|
988
|
+
|
989
|
+
const problems = [];
|
990
|
+
const directives = [];
|
991
|
+
|
992
|
+
this.getInlineConfigNodes().forEach(comment => {
|
993
|
+
const { directivePart, justificationPart } = commentParser.extractDirectiveComment(comment.value);
|
994
|
+
|
995
|
+
// Step 1: Extract the directive text
|
996
|
+
const match = directivesPattern.exec(directivePart);
|
997
|
+
|
998
|
+
if (!match) {
|
999
|
+
return;
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
const directiveText = match[1];
|
1003
|
+
|
1004
|
+
// Step 2: Extract the directive value
|
1005
|
+
const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(directiveText);
|
1006
|
+
|
1007
|
+
if (comment.type === "Line" && !lineCommentSupported) {
|
1008
|
+
return;
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
// Step 3: Validate the directive does not span multiple lines
|
1012
|
+
if (directiveText === "eslint-disable-line" && comment.loc.start.line !== comment.loc.end.line) {
|
1013
|
+
const message = `${directiveText} comment should not span multiple lines.`;
|
1014
|
+
|
1015
|
+
problems.push({
|
1016
|
+
ruleId: null,
|
1017
|
+
message,
|
1018
|
+
loc: comment.loc
|
1019
|
+
});
|
1020
|
+
return;
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
// Step 4: Extract the directive value and create the Directive object
|
1024
|
+
const directiveValue = directivePart.slice(match.index + directiveText.length);
|
1025
|
+
|
1026
|
+
switch (directiveText) {
|
1027
|
+
case "eslint-disable":
|
1028
|
+
case "eslint-enable":
|
1029
|
+
case "eslint-disable-next-line":
|
1030
|
+
case "eslint-disable-line": {
|
1031
|
+
const directiveType = directiveText.slice("eslint-".length);
|
1032
|
+
|
1033
|
+
directives.push(new Directive({
|
1034
|
+
type: directiveType,
|
1035
|
+
node: comment,
|
1036
|
+
value: directiveValue,
|
1037
|
+
justification: justificationPart
|
1038
|
+
}));
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
// no default
|
1042
|
+
}
|
1043
|
+
});
|
1044
|
+
|
1045
|
+
const result = { problems, directives };
|
1046
|
+
|
1047
|
+
this[caches].set("disableDirectives", result);
|
1048
|
+
|
1049
|
+
return result;
|
1050
|
+
}
|
1051
|
+
|
924
1052
|
/**
|
925
1053
|
* Applies language options sent in from the core.
|
926
1054
|
* @param {Object} languageOptions The language options for this run.
|
@@ -9,7 +9,7 @@
|
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
11
|
const Cursor = require("./cursor");
|
12
|
-
const
|
12
|
+
const { getLastIndex, getFirstIndex } = require("./utils");
|
13
13
|
|
14
14
|
//------------------------------------------------------------------------------
|
15
15
|
// Exports
|
@@ -31,8 +31,8 @@ module.exports = class BackwardTokenCursor extends Cursor {
|
|
31
31
|
constructor(tokens, comments, indexMap, startLoc, endLoc) {
|
32
32
|
super();
|
33
33
|
this.tokens = tokens;
|
34
|
-
this.index =
|
35
|
-
this.indexEnd =
|
34
|
+
this.index = getLastIndex(tokens, indexMap, endLoc);
|
35
|
+
this.indexEnd = getFirstIndex(tokens, indexMap, startLoc);
|
36
36
|
}
|
37
37
|
|
38
38
|
/** @inheritdoc */
|
@@ -86,5 +86,7 @@ class CursorFactory {
|
|
86
86
|
// Exports
|
87
87
|
//------------------------------------------------------------------------------
|
88
88
|
|
89
|
-
exports
|
90
|
-
|
89
|
+
module.exports = {
|
90
|
+
forward: new CursorFactory(ForwardTokenCursor, ForwardTokenCommentCursor),
|
91
|
+
backward: new CursorFactory(BackwardTokenCursor, BackwardTokenCommentCursor)
|
92
|
+
};
|
@@ -9,7 +9,7 @@
|
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
11
|
const Cursor = require("./cursor");
|
12
|
-
const
|
12
|
+
const { getFirstIndex, search } = require("./utils");
|
13
13
|
|
14
14
|
//------------------------------------------------------------------------------
|
15
15
|
// Exports
|
@@ -32,8 +32,8 @@ module.exports = class ForwardTokenCommentCursor extends Cursor {
|
|
32
32
|
super();
|
33
33
|
this.tokens = tokens;
|
34
34
|
this.comments = comments;
|
35
|
-
this.tokenIndex =
|
36
|
-
this.commentIndex =
|
35
|
+
this.tokenIndex = getFirstIndex(tokens, indexMap, startLoc);
|
36
|
+
this.commentIndex = search(comments, startLoc);
|
37
37
|
this.border = endLoc;
|
38
38
|
}
|
39
39
|
|
@@ -9,7 +9,7 @@
|
|
9
9
|
//------------------------------------------------------------------------------
|
10
10
|
|
11
11
|
const Cursor = require("./cursor");
|
12
|
-
const
|
12
|
+
const { getFirstIndex, getLastIndex } = require("./utils");
|
13
13
|
|
14
14
|
//------------------------------------------------------------------------------
|
15
15
|
// Exports
|
@@ -31,8 +31,8 @@ module.exports = class ForwardTokenCursor extends Cursor {
|
|
31
31
|
constructor(tokens, comments, indexMap, startLoc, endLoc) {
|
32
32
|
super();
|
33
33
|
this.tokens = tokens;
|
34
|
-
this.index =
|
35
|
-
this.indexEnd =
|
34
|
+
this.index = getFirstIndex(tokens, indexMap, startLoc);
|
35
|
+
this.indexEnd = getLastIndex(tokens, indexMap, endLoc);
|
36
36
|
}
|
37
37
|
|
38
38
|
/** @inheritdoc */
|