eslint 8.7.0 → 8.10.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 -6
- package/lib/cli-engine/cli-engine.js +8 -2
- package/lib/cli-engine/file-enumerator.js +2 -2
- package/lib/config/flat-config-array.js +12 -3
- package/lib/config/flat-config-helpers.js +37 -1
- package/lib/config/rule-validator.js +5 -35
- package/lib/eslint/eslint.js +5 -0
- package/lib/linter/apply-disable-directives.js +35 -44
- package/lib/linter/linter.js +91 -23
- package/lib/rule-tester/flat-rule-tester.js +1039 -0
- package/lib/rules/camelcase.js +2 -2
- package/lib/rules/function-paren-newline.js +5 -1
- package/lib/rules/no-confusing-arrow.js +6 -2
- package/lib/rules/no-shadow.js +127 -16
- package/lib/shared/types.js +15 -0
- package/package.json +6 -5
package/lib/linter/linter.js
CHANGED
@@ -59,6 +59,7 @@ const globals = require("../../conf/globals");
|
|
59
59
|
/** @typedef {import("../shared/types").Environment} Environment */
|
60
60
|
/** @typedef {import("../shared/types").GlobalConf} GlobalConf */
|
61
61
|
/** @typedef {import("../shared/types").LintMessage} LintMessage */
|
62
|
+
/** @typedef {import("../shared/types").SuppressedLintMessage} SuppressedLintMessage */
|
62
63
|
/** @typedef {import("../shared/types").ParserOptions} ParserOptions */
|
63
64
|
/** @typedef {import("../shared/types").LanguageOptions} LanguageOptions */
|
64
65
|
/** @typedef {import("../shared/types").Processor} Processor */
|
@@ -77,6 +78,7 @@ const globals = require("../../conf/globals");
|
|
77
78
|
* @property {number} line The line number
|
78
79
|
* @property {number} column The column number
|
79
80
|
* @property {(string|null)} ruleId The rule ID
|
81
|
+
* @property {string} justification The justification of directive
|
80
82
|
*/
|
81
83
|
|
82
84
|
/**
|
@@ -84,6 +86,7 @@ const globals = require("../../conf/globals");
|
|
84
86
|
* @typedef {Object} LinterInternalSlots
|
85
87
|
* @property {ConfigArray|null} lastConfigArray The `ConfigArray` instance that the last `verify()` call used.
|
86
88
|
* @property {SourceCode|null} lastSourceCode The `SourceCode` instance that the last `verify()` call used.
|
89
|
+
* @property {SuppressedLintMessage[]} lastSuppressedMessages The `SuppressedLintMessage[]` instance that the last `verify()` call produced.
|
87
90
|
* @property {Map<string, Parser>} parserMap The loaded parsers.
|
88
91
|
* @property {Rules} ruleMap The loaded rules.
|
89
92
|
*/
|
@@ -287,11 +290,12 @@ function createLintingProblem(options) {
|
|
287
290
|
* @param {token} options.commentToken The Comment token
|
288
291
|
* @param {string} options.value The value after the directive in the comment
|
289
292
|
* comment specified no specific rules, so it applies to all rules (e.g. `eslint-disable`)
|
293
|
+
* @param {string} options.justification The justification of the directive
|
290
294
|
* @param {function(string): {create: Function}} options.ruleMapper A map from rule IDs to defined rules
|
291
295
|
* @returns {Object} Directives and problems from the comment
|
292
296
|
*/
|
293
297
|
function createDisableDirectives(options) {
|
294
|
-
const { commentToken, type, value, ruleMapper } = options;
|
298
|
+
const { commentToken, type, value, justification, ruleMapper } = options;
|
295
299
|
const ruleIds = Object.keys(commentParser.parseListConfig(value));
|
296
300
|
const directiveRules = ruleIds.length ? ruleIds : [null];
|
297
301
|
const result = {
|
@@ -306,9 +310,23 @@ function createDisableDirectives(options) {
|
|
306
310
|
// push to directives, if the rule is defined(including null, e.g. /*eslint enable*/)
|
307
311
|
if (ruleId === null || !!ruleMapper(ruleId)) {
|
308
312
|
if (type === "disable-next-line") {
|
309
|
-
result.directives.push({
|
313
|
+
result.directives.push({
|
314
|
+
parentComment,
|
315
|
+
type,
|
316
|
+
line: commentToken.loc.end.line,
|
317
|
+
column: commentToken.loc.end.column + 1,
|
318
|
+
ruleId,
|
319
|
+
justification
|
320
|
+
});
|
310
321
|
} else {
|
311
|
-
result.directives.push({
|
322
|
+
result.directives.push({
|
323
|
+
parentComment,
|
324
|
+
type,
|
325
|
+
line: commentToken.loc.start.line,
|
326
|
+
column: commentToken.loc.start.column + 1,
|
327
|
+
ruleId,
|
328
|
+
justification
|
329
|
+
});
|
312
330
|
}
|
313
331
|
} else {
|
314
332
|
result.directiveProblems.push(createLintingProblem({ ruleId, loc: commentToken.loc }));
|
@@ -318,12 +336,21 @@ function createDisableDirectives(options) {
|
|
318
336
|
}
|
319
337
|
|
320
338
|
/**
|
321
|
-
*
|
322
|
-
* @param {string} value The comment text to
|
323
|
-
* @returns {string} The
|
339
|
+
* Extract the directive and the justification from a given directive comment and trim them.
|
340
|
+
* @param {string} value The comment text to extract.
|
341
|
+
* @returns {{directivePart: string, justificationPart: string}} The extracted directive and justification.
|
324
342
|
*/
|
325
|
-
function
|
326
|
-
|
343
|
+
function extractDirectiveComment(value) {
|
344
|
+
const match = /\s-{2,}\s/u.exec(value);
|
345
|
+
|
346
|
+
if (!match) {
|
347
|
+
return { directivePart: value.trim(), justificationPart: "" };
|
348
|
+
}
|
349
|
+
|
350
|
+
const directive = value.slice(0, match.index).trim();
|
351
|
+
const justification = value.slice(match.index + match[0].length).trim();
|
352
|
+
|
353
|
+
return { directivePart: directive, justificationPart: justification };
|
327
354
|
}
|
328
355
|
|
329
356
|
/**
|
@@ -347,8 +374,9 @@ function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
|
|
347
374
|
});
|
348
375
|
|
349
376
|
ast.comments.filter(token => token.type !== "Shebang").forEach(comment => {
|
350
|
-
const
|
351
|
-
|
377
|
+
const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
|
378
|
+
|
379
|
+
const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(directivePart);
|
352
380
|
|
353
381
|
if (!match) {
|
354
382
|
return;
|
@@ -383,7 +411,7 @@ function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
|
|
383
411
|
return;
|
384
412
|
}
|
385
413
|
|
386
|
-
const directiveValue =
|
414
|
+
const directiveValue = directivePart.slice(match.index + directiveText.length);
|
387
415
|
|
388
416
|
switch (directiveText) {
|
389
417
|
case "eslint-disable":
|
@@ -391,7 +419,7 @@ function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
|
|
391
419
|
case "eslint-disable-next-line":
|
392
420
|
case "eslint-disable-line": {
|
393
421
|
const directiveType = directiveText.slice("eslint-".length);
|
394
|
-
const options = { commentToken: comment, type: directiveType, value: directiveValue, ruleMapper };
|
422
|
+
const options = { commentToken: comment, type: directiveType, value: directiveValue, justification: justificationPart, ruleMapper };
|
395
423
|
const { directives, directiveProblems } = createDisableDirectives(options);
|
396
424
|
|
397
425
|
disableDirectives.push(...directives);
|
@@ -548,7 +576,7 @@ function findEslintEnv(text) {
|
|
548
576
|
if (match[0].endsWith("*/")) {
|
549
577
|
retv = Object.assign(
|
550
578
|
retv || {},
|
551
|
-
commentParser.parseListConfig(
|
579
|
+
commentParser.parseListConfig(extractDirectiveComment(match[1]).directivePart)
|
552
580
|
);
|
553
581
|
}
|
554
582
|
}
|
@@ -772,14 +800,21 @@ function parse(text, languageOptions, filePath) {
|
|
772
800
|
* problem that ESLint identified just like any other.
|
773
801
|
*/
|
774
802
|
try {
|
803
|
+
debug("Parsing:", filePath);
|
775
804
|
const parseResult = (typeof parser.parseForESLint === "function")
|
776
805
|
? parser.parseForESLint(textToParse, parserOptions)
|
777
806
|
: { ast: parser.parse(textToParse, parserOptions) };
|
807
|
+
|
808
|
+
debug("Parsing successful:", filePath);
|
778
809
|
const ast = parseResult.ast;
|
779
810
|
const parserServices = parseResult.services || {};
|
780
811
|
const visitorKeys = parseResult.visitorKeys || evk.KEYS;
|
812
|
+
|
813
|
+
debug("Scope analysis:", filePath);
|
781
814
|
const scopeManager = parseResult.scopeManager || analyzeScope(ast, languageOptions, visitorKeys);
|
782
815
|
|
816
|
+
debug("Scope analysis successful:", filePath);
|
817
|
+
|
783
818
|
return {
|
784
819
|
success: true,
|
785
820
|
|
@@ -1223,6 +1258,7 @@ class Linter {
|
|
1223
1258
|
cwd: normalizeCwd(cwd),
|
1224
1259
|
lastConfigArray: null,
|
1225
1260
|
lastSourceCode: null,
|
1261
|
+
lastSuppressedMessages: [],
|
1226
1262
|
configType, // TODO: Remove after flat config conversion
|
1227
1263
|
parserMap: new Map([["espree", espree]]),
|
1228
1264
|
ruleMap: new Rules()
|
@@ -1246,7 +1282,7 @@ class Linter {
|
|
1246
1282
|
* @param {ConfigData} providedConfig An ESLintConfig instance to configure everything.
|
1247
1283
|
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
1248
1284
|
* @throws {Error} If during rule execution.
|
1249
|
-
* @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
|
1285
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
1250
1286
|
*/
|
1251
1287
|
_verifyWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
|
1252
1288
|
const slots = internalSlotsMap.get(this);
|
@@ -1428,11 +1464,11 @@ class Linter {
|
|
1428
1464
|
configArray.normalizeSync();
|
1429
1465
|
}
|
1430
1466
|
|
1431
|
-
return this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true);
|
1467
|
+
return this._distinguishSuppressedMessages(this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true));
|
1432
1468
|
}
|
1433
1469
|
|
1434
1470
|
if (typeof config.extractConfig === "function") {
|
1435
|
-
return this._verifyWithConfigArray(textOrSourceCode, config, options);
|
1471
|
+
return this._distinguishSuppressedMessages(this._verifyWithConfigArray(textOrSourceCode, config, options));
|
1436
1472
|
}
|
1437
1473
|
}
|
1438
1474
|
|
@@ -1446,9 +1482,9 @@ class Linter {
|
|
1446
1482
|
* So we cannot apply multiple processors.
|
1447
1483
|
*/
|
1448
1484
|
if (options.preprocess || options.postprocess) {
|
1449
|
-
return this._verifyWithProcessor(textOrSourceCode, config, options);
|
1485
|
+
return this._distinguishSuppressedMessages(this._verifyWithProcessor(textOrSourceCode, config, options));
|
1450
1486
|
}
|
1451
|
-
return this._verifyWithoutProcessors(textOrSourceCode, config, options);
|
1487
|
+
return this._distinguishSuppressedMessages(this._verifyWithoutProcessors(textOrSourceCode, config, options));
|
1452
1488
|
}
|
1453
1489
|
|
1454
1490
|
/**
|
@@ -1457,7 +1493,7 @@ class Linter {
|
|
1457
1493
|
* @param {FlatConfig} config The config array.
|
1458
1494
|
* @param {VerifyOptions&ProcessorOptions} options The options.
|
1459
1495
|
* @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
|
1460
|
-
* @returns {LintMessage[]} The found problems.
|
1496
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
1461
1497
|
*/
|
1462
1498
|
_verifyWithFlatConfigArrayAndProcessor(textOrSourceCode, config, options, configForRecursive) {
|
1463
1499
|
const filename = options.filename || "<input>";
|
@@ -1514,7 +1550,7 @@ class Linter {
|
|
1514
1550
|
* @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
|
1515
1551
|
* @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
|
1516
1552
|
* @throws {Error} If during rule execution.
|
1517
|
-
* @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
|
1553
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
|
1518
1554
|
*/
|
1519
1555
|
_verifyWithFlatConfigArrayAndWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
|
1520
1556
|
const slots = internalSlotsMap.get(this);
|
@@ -1663,7 +1699,7 @@ class Linter {
|
|
1663
1699
|
* @param {string|SourceCode} textOrSourceCode The source code.
|
1664
1700
|
* @param {ConfigArray} configArray The config array.
|
1665
1701
|
* @param {VerifyOptions&ProcessorOptions} options The options.
|
1666
|
-
* @returns {LintMessage[]} The found problems.
|
1702
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
1667
1703
|
*/
|
1668
1704
|
_verifyWithConfigArray(textOrSourceCode, configArray, options) {
|
1669
1705
|
debug("With ConfigArray: %s", options.filename);
|
@@ -1700,7 +1736,7 @@ class Linter {
|
|
1700
1736
|
* @param {VerifyOptions&ProcessorOptions} options The options.
|
1701
1737
|
* @param {boolean} [firstCall=false] Indicates if this is being called directly
|
1702
1738
|
* from verify(). (TODO: Remove once eslintrc is removed.)
|
1703
|
-
* @returns {LintMessage[]} The found problems.
|
1739
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
1704
1740
|
*/
|
1705
1741
|
_verifyWithFlatConfigArray(textOrSourceCode, configArray, options, firstCall = false) {
|
1706
1742
|
debug("With flat config: %s", options.filename);
|
@@ -1740,7 +1776,7 @@ class Linter {
|
|
1740
1776
|
* @param {ConfigData|ExtractedConfig} config The config array.
|
1741
1777
|
* @param {VerifyOptions&ProcessorOptions} options The options.
|
1742
1778
|
* @param {ConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
|
1743
|
-
* @returns {LintMessage[]} The found problems.
|
1779
|
+
* @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
|
1744
1780
|
*/
|
1745
1781
|
_verifyWithProcessor(textOrSourceCode, config, options, configForRecursive) {
|
1746
1782
|
const filename = options.filename || "<input>";
|
@@ -1792,6 +1828,30 @@ class Linter {
|
|
1792
1828
|
return postprocess(messageLists, filenameToExpose);
|
1793
1829
|
}
|
1794
1830
|
|
1831
|
+
/**
|
1832
|
+
* Given a list of reported problems, distinguish problems between normal messages and suppressed messages.
|
1833
|
+
* The normal messages will be returned and the suppressed messages will be stored as lastSuppressedMessages.
|
1834
|
+
* @param {Problem[]} problems A list of reported problems.
|
1835
|
+
* @returns {LintMessage[]} A list of LintMessage.
|
1836
|
+
*/
|
1837
|
+
_distinguishSuppressedMessages(problems) {
|
1838
|
+
const messages = [];
|
1839
|
+
const suppressedMessages = [];
|
1840
|
+
const slots = internalSlotsMap.get(this);
|
1841
|
+
|
1842
|
+
for (const problem of problems) {
|
1843
|
+
if (problem.suppressions) {
|
1844
|
+
suppressedMessages.push(problem);
|
1845
|
+
} else {
|
1846
|
+
messages.push(problem);
|
1847
|
+
}
|
1848
|
+
}
|
1849
|
+
|
1850
|
+
slots.lastSuppressedMessages = suppressedMessages;
|
1851
|
+
|
1852
|
+
return messages;
|
1853
|
+
}
|
1854
|
+
|
1795
1855
|
/**
|
1796
1856
|
* Gets the SourceCode object representing the parsed source.
|
1797
1857
|
* @returns {SourceCode} The SourceCode object.
|
@@ -1800,6 +1860,14 @@ class Linter {
|
|
1800
1860
|
return internalSlotsMap.get(this).lastSourceCode;
|
1801
1861
|
}
|
1802
1862
|
|
1863
|
+
/**
|
1864
|
+
* Gets the list of SuppressedLintMessage produced in the last running.
|
1865
|
+
* @returns {SuppressedLintMessage[]} The list of SuppressedLintMessage
|
1866
|
+
*/
|
1867
|
+
getSuppressedMessages() {
|
1868
|
+
return internalSlotsMap.get(this).lastSuppressedMessages;
|
1869
|
+
}
|
1870
|
+
|
1803
1871
|
/**
|
1804
1872
|
* Defines a new linting rule.
|
1805
1873
|
* @param {string} ruleId A unique rule identifier
|