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.
@@ -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({ parentComment, type, line: commentToken.loc.end.line, column: commentToken.loc.end.column + 1, ruleId });
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({ parentComment, type, line: commentToken.loc.start.line, column: commentToken.loc.start.column + 1, ruleId });
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
- * Remove the ignored part from a given directive comment and trim it.
322
- * @param {string} value The comment text to strip.
323
- * @returns {string} The stripped text.
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 stripDirectiveComment(value) {
326
- return value.split(/\s-{2,}\s/u)[0].trim();
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 trimmedCommentText = stripDirectiveComment(comment.value);
351
- const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(trimmedCommentText);
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 = trimmedCommentText.slice(match.index + directiveText.length);
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(stripDirectiveComment(match[1]))
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