eslint 9.0.0-rc.0 → 9.0.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 +6 -10
- package/bin/eslint.js +12 -0
- package/lib/cli.js +2 -0
- package/lib/eslint/eslint-helpers.js +5 -0
- package/lib/eslint/eslint.js +16 -1
- package/lib/linter/linter.js +154 -9
- package/lib/linter/timing.js +16 -8
- package/lib/options.js +25 -1
- 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-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/types.js +34 -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 +6 -5
@@ -9,22 +9,6 @@
|
|
9
9
|
// Helpers
|
10
10
|
//------------------------------------------------------------------------------
|
11
11
|
|
12
|
-
/**
|
13
|
-
* Checks all segments in a set and returns true if any are reachable.
|
14
|
-
* @param {Set<CodePathSegment>} segments The segments to check.
|
15
|
-
* @returns {boolean} True if any segment is reachable; false otherwise.
|
16
|
-
*/
|
17
|
-
function isAnySegmentReachable(segments) {
|
18
|
-
|
19
|
-
for (const segment of segments) {
|
20
|
-
if (segment.reachable) {
|
21
|
-
return true;
|
22
|
-
}
|
23
|
-
}
|
24
|
-
|
25
|
-
return false;
|
26
|
-
}
|
27
|
-
|
28
12
|
/**
|
29
13
|
* Checks whether or not a given node is a constructor.
|
30
14
|
* @param {ASTNode} node A node to check. This node type is one of
|
@@ -165,8 +149,7 @@ module.exports = {
|
|
165
149
|
missingAll: "Expected to call 'super()'.",
|
166
150
|
|
167
151
|
duplicate: "Unexpected duplicate 'super()'.",
|
168
|
-
badSuper: "Unexpected 'super()' because 'super' is not a constructor."
|
169
|
-
unexpected: "Unexpected 'super()'."
|
152
|
+
badSuper: "Unexpected 'super()' because 'super' is not a constructor."
|
170
153
|
}
|
171
154
|
},
|
172
155
|
|
@@ -186,7 +169,7 @@ module.exports = {
|
|
186
169
|
/**
|
187
170
|
* @type {Record<string, SegmentInfo>}
|
188
171
|
*/
|
189
|
-
|
172
|
+
const segInfoMap = Object.create(null);
|
190
173
|
|
191
174
|
/**
|
192
175
|
* Gets the flag which shows `super()` is called in some paths.
|
@@ -194,7 +177,7 @@ module.exports = {
|
|
194
177
|
* @returns {boolean} The flag which shows `super()` is called in some paths
|
195
178
|
*/
|
196
179
|
function isCalledInSomePath(segment) {
|
197
|
-
return segment.reachable && segInfoMap[segment.id]
|
180
|
+
return segment.reachable && segInfoMap[segment.id].calledInSomePaths;
|
198
181
|
}
|
199
182
|
|
200
183
|
/**
|
@@ -212,17 +195,6 @@ module.exports = {
|
|
212
195
|
* @returns {boolean} The flag which shows `super()` is called in all paths.
|
213
196
|
*/
|
214
197
|
function isCalledInEveryPath(segment) {
|
215
|
-
|
216
|
-
/*
|
217
|
-
* If specific segment is the looped segment of the current segment,
|
218
|
-
* skip the segment.
|
219
|
-
* If not skipped, this never becomes true after a loop.
|
220
|
-
*/
|
221
|
-
if (segment.nextSegments.length === 1 &&
|
222
|
-
segment.nextSegments[0]?.isLoopedPrevSegment(segment)) {
|
223
|
-
return true;
|
224
|
-
}
|
225
|
-
|
226
198
|
return segment.reachable && segInfoMap[segment.id].calledInEveryPaths;
|
227
199
|
}
|
228
200
|
|
@@ -279,9 +251,9 @@ module.exports = {
|
|
279
251
|
}
|
280
252
|
|
281
253
|
// Reports if `super()` lacked.
|
282
|
-
const
|
283
|
-
const calledInEveryPaths =
|
284
|
-
const calledInSomePaths =
|
254
|
+
const returnedSegments = codePath.returnedSegments;
|
255
|
+
const calledInEveryPaths = returnedSegments.every(isCalledInEveryPath);
|
256
|
+
const calledInSomePaths = returnedSegments.some(isCalledInSomePath);
|
285
257
|
|
286
258
|
if (!calledInEveryPaths) {
|
287
259
|
context.report({
|
@@ -296,28 +268,38 @@ module.exports = {
|
|
296
268
|
/**
|
297
269
|
* Initialize information of a given code path segment.
|
298
270
|
* @param {CodePathSegment} segment A code path segment to initialize.
|
271
|
+
* @param {CodePathSegment} node Node that starts the segment.
|
299
272
|
* @returns {void}
|
300
273
|
*/
|
301
|
-
onCodePathSegmentStart(segment) {
|
274
|
+
onCodePathSegmentStart(segment, node) {
|
302
275
|
|
303
276
|
funcInfo.currentSegments.add(segment);
|
304
277
|
|
305
|
-
if (!(funcInfo
|
278
|
+
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
306
279
|
return;
|
307
280
|
}
|
308
281
|
|
309
282
|
// Initialize info.
|
310
283
|
const info = segInfoMap[segment.id] = new SegmentInfo();
|
311
284
|
|
312
|
-
|
313
|
-
const prevSegments = segment.prevSegments;
|
314
|
-
|
315
|
-
if (prevSegments.length > 0) {
|
316
|
-
const seenPrevSegments = prevSegments.filter(hasSegmentBeenSeen);
|
285
|
+
const seenPrevSegments = segment.prevSegments.filter(hasSegmentBeenSeen);
|
317
286
|
|
287
|
+
// When there are previous segments, aggregates these.
|
288
|
+
if (seenPrevSegments.length > 0) {
|
318
289
|
info.calledInSomePaths = seenPrevSegments.some(isCalledInSomePath);
|
319
290
|
info.calledInEveryPaths = seenPrevSegments.every(isCalledInEveryPath);
|
320
291
|
}
|
292
|
+
|
293
|
+
/*
|
294
|
+
* ForStatement > *.update segments are a special case as they are created in advance,
|
295
|
+
* without seen previous segments. Since they logically don't affect `calledInEveryPaths`
|
296
|
+
* calculations, and they can never be a lone previous segment of another one, we'll set
|
297
|
+
* their `calledInEveryPaths` to `true` to effectively ignore them in those calculations.
|
298
|
+
* .
|
299
|
+
*/
|
300
|
+
if (node.parent && node.parent.type === "ForStatement" && node.parent.update === node) {
|
301
|
+
info.calledInEveryPaths = true;
|
302
|
+
}
|
321
303
|
},
|
322
304
|
|
323
305
|
onUnreachableCodePathSegmentStart(segment) {
|
@@ -343,25 +325,30 @@ module.exports = {
|
|
343
325
|
* @returns {void}
|
344
326
|
*/
|
345
327
|
onCodePathSegmentLoop(fromSegment, toSegment) {
|
346
|
-
if (!(funcInfo
|
328
|
+
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
347
329
|
return;
|
348
330
|
}
|
349
331
|
|
350
|
-
// Update information inside of the loop.
|
351
|
-
const isRealLoop = toSegment.prevSegments.length >= 2;
|
352
|
-
|
353
332
|
funcInfo.codePath.traverseSegments(
|
354
333
|
{ first: toSegment, last: fromSegment },
|
355
|
-
segment => {
|
356
|
-
const info = segInfoMap[segment.id]
|
334
|
+
(segment, controller) => {
|
335
|
+
const info = segInfoMap[segment.id];
|
336
|
+
|
337
|
+
// skip segments after the loop
|
338
|
+
if (!info) {
|
339
|
+
controller.skip();
|
340
|
+
return;
|
341
|
+
}
|
342
|
+
|
357
343
|
const seenPrevSegments = segment.prevSegments.filter(hasSegmentBeenSeen);
|
344
|
+
const calledInSomePreviousPaths = seenPrevSegments.some(isCalledInSomePath);
|
345
|
+
const calledInEveryPreviousPaths = seenPrevSegments.every(isCalledInEveryPath);
|
358
346
|
|
359
|
-
|
360
|
-
info.
|
361
|
-
info.calledInEveryPaths = seenPrevSegments.every(isCalledInEveryPath);
|
347
|
+
info.calledInSomePaths ||= calledInSomePreviousPaths;
|
348
|
+
info.calledInEveryPaths ||= calledInEveryPreviousPaths;
|
362
349
|
|
363
350
|
// If flags become true anew, reports the valid nodes.
|
364
|
-
if (
|
351
|
+
if (calledInSomePreviousPaths) {
|
365
352
|
const nodes = info.validNodes;
|
366
353
|
|
367
354
|
info.validNodes = [];
|
@@ -375,9 +362,6 @@ module.exports = {
|
|
375
362
|
});
|
376
363
|
}
|
377
364
|
}
|
378
|
-
|
379
|
-
// save just in case we created a new SegmentInfo object
|
380
|
-
segInfoMap[segment.id] = info;
|
381
365
|
}
|
382
366
|
);
|
383
367
|
},
|
@@ -388,7 +372,7 @@ module.exports = {
|
|
388
372
|
* @returns {void}
|
389
373
|
*/
|
390
374
|
"CallExpression:exit"(node) {
|
391
|
-
if (!(funcInfo && funcInfo.
|
375
|
+
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
392
376
|
return;
|
393
377
|
}
|
394
378
|
|
@@ -398,41 +382,34 @@ module.exports = {
|
|
398
382
|
}
|
399
383
|
|
400
384
|
// Reports if needed.
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
let info = null;
|
385
|
+
const segments = funcInfo.currentSegments;
|
386
|
+
let duplicate = false;
|
387
|
+
let info = null;
|
405
388
|
|
406
|
-
|
389
|
+
for (const segment of segments) {
|
407
390
|
|
408
|
-
|
409
|
-
|
391
|
+
if (segment.reachable) {
|
392
|
+
info = segInfoMap[segment.id];
|
410
393
|
|
411
|
-
|
412
|
-
|
413
|
-
}
|
394
|
+
duplicate = duplicate || info.calledInSomePaths;
|
395
|
+
info.calledInSomePaths = info.calledInEveryPaths = true;
|
414
396
|
}
|
397
|
+
}
|
415
398
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
}
|
399
|
+
if (info) {
|
400
|
+
if (duplicate) {
|
401
|
+
context.report({
|
402
|
+
messageId: "duplicate",
|
403
|
+
node
|
404
|
+
});
|
405
|
+
} else if (!funcInfo.superIsConstructor) {
|
406
|
+
context.report({
|
407
|
+
messageId: "badSuper",
|
408
|
+
node
|
409
|
+
});
|
410
|
+
} else {
|
411
|
+
info.validNodes.push(node);
|
430
412
|
}
|
431
|
-
} else if (isAnySegmentReachable(funcInfo.currentSegments)) {
|
432
|
-
context.report({
|
433
|
-
messageId: "unexpected",
|
434
|
-
node
|
435
|
-
});
|
436
413
|
}
|
437
414
|
},
|
438
415
|
|
@@ -442,7 +419,7 @@ module.exports = {
|
|
442
419
|
* @returns {void}
|
443
420
|
*/
|
444
421
|
ReturnStatement(node) {
|
445
|
-
if (!(funcInfo
|
422
|
+
if (!(funcInfo.isConstructor && funcInfo.hasExtends)) {
|
446
423
|
return;
|
447
424
|
}
|
448
425
|
|
@@ -462,14 +439,6 @@ module.exports = {
|
|
462
439
|
info.calledInSomePaths = info.calledInEveryPaths = true;
|
463
440
|
}
|
464
441
|
}
|
465
|
-
},
|
466
|
-
|
467
|
-
/**
|
468
|
-
* Resets state.
|
469
|
-
* @returns {void}
|
470
|
-
*/
|
471
|
-
"Program:exit"() {
|
472
|
-
segInfoMap = Object.create(null);
|
473
442
|
}
|
474
443
|
};
|
475
444
|
}
|
@@ -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
|
+
};
|