eslint 9.38.0 → 9.39.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 CHANGED
@@ -342,8 +342,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
342
342
  <h3>Platinum Sponsors</h3>
343
343
  <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="128"></a></p><h3>Gold Sponsors</h3>
344
344
  <p><a href="https://qlty.sh/"><img src="https://images.opencollective.com/qltysh/33d157d/logo.png" alt="Qlty Software" height="96"></a> <a href="https://trunk.io/"><img src="https://images.opencollective.com/trunkio/fb92d60/avatar.png" alt="trunk.io" height="96"></a> <a href="https://shopify.engineering/"><img src="https://avatars.githubusercontent.com/u/8085" alt="Shopify" height="96"></a></p><h3>Silver Sponsors</h3>
345
- <p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
346
- <p><a href="https://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://sentry.io"><img src="https://github.com/getsentry.png" alt="Sentry" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://opensource.mercedes-benz.com/"><img src="https://avatars.githubusercontent.com/u/34240465" alt="Mercedes-Benz Group" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
345
+ <p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/e6d15e1/logo.png" alt="Vite" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/2d6c3b6/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301" alt="American Express" height="64"></a> <a href="https://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
346
+ <p><a href="https://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://sentry.io"><img src="https://github.com/getsentry.png" alt="Sentry" height="32"></a> <a href="https://icons8.com/"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340" alt="GitBook" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104" alt="Nx" height="32"></a> <a href="https://opensource.mercedes-benz.com/"><img src="https://avatars.githubusercontent.com/u/34240465" alt="Mercedes-Benz Group" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="LambdaTest" height="32"></a></p>
347
347
  <h3>Technology Sponsors</h3>
348
348
  Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.
349
349
  <p><a href="https://netlify.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/netlify-icon.svg" alt="Netlify" height="32"></a> <a href="https://algolia.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/algolia-icon.svg" alt="Algolia" height="32"></a> <a href="https://1password.com"><img src="https://raw.githubusercontent.com/eslint/eslint.org/main/src/assets/images/techsponsors/1password-icon.svg" alt="1Password" height="32"></a></p>
@@ -17,6 +17,7 @@ const { pathToFileURL } = require("node:url");
17
17
  const { SHARE_ENV, Worker } = require("node:worker_threads");
18
18
  const { version } = require("../../package.json");
19
19
  const { defaultConfig } = require("../config/default-config");
20
+ const timing = require("../linter/timing");
20
21
 
21
22
  const {
22
23
  createDebug,
@@ -503,6 +504,11 @@ async function runWorkers(
503
504
  worstNetLintingRatio,
504
505
  netLintingRatio,
505
506
  );
507
+
508
+ if (timing.enabled && indexedResults.timings) {
509
+ timing.mergeData(indexedResults.timings);
510
+ }
511
+
506
512
  for (const result of indexedResults) {
507
513
  const { index } = result;
508
514
  delete result.index;
@@ -522,7 +528,17 @@ async function runWorkers(
522
528
  for (let index = 0; index < workerCount; ++index) {
523
529
  promises[index] = new Promise(workerExecutor);
524
530
  }
525
- await Promise.all(promises);
531
+
532
+ try {
533
+ await Promise.all(promises);
534
+ } catch (error) {
535
+ /*
536
+ * If any worker fails, suppress timing display in the main thread
537
+ * to avoid printing partial or misleading timing output.
538
+ */
539
+ timing.disableDisplay();
540
+ throw error;
541
+ }
526
542
 
527
543
  if (worstNetLintingRatio < LOW_NET_LINTING_RATIO) {
528
544
  warnOnLowNetLintingRatio();
@@ -29,6 +29,7 @@ const {
29
29
  processOptions,
30
30
  } = require("./eslint-helpers");
31
31
  const { WarningService } = require("../services/warning-service");
32
+ const timing = require("../linter/timing");
32
33
 
33
34
  const depsLoadedTime = hrtimeBigint();
34
35
 
@@ -39,7 +40,7 @@ const depsLoadedTime = hrtimeBigint();
39
40
  /** @typedef {import("../types").ESLint.LintResult} LintResult */
40
41
  /** @typedef {import("../types").ESLint.Options} ESLintOptions */
41
42
  /** @typedef {LintResult & { index?: number; }} IndexedLintResult */
42
- /** @typedef {IndexedLintResult[] & { netLintingDuration: bigint; }} WorkerLintResults */
43
+ /** @typedef {IndexedLintResult[] & { netLintingDuration: bigint; timings?: Record<string, number>; }} WorkerLintResults */
43
44
  /**
44
45
  * @typedef {Object} WorkerData - Data passed to the worker thread.
45
46
  * @property {ESLintOptions | string} eslintOptionsOrURL - The unprocessed ESLint options or the URL of the options module.
@@ -57,6 +58,12 @@ const debug = createDebug(`eslint:worker:thread-${threadId}`);
57
58
  // Main
58
59
  //------------------------------------------------------------------------------
59
60
 
61
+ /*
62
+ * Prevent timing module from printing profiling output from worker threads.
63
+ * The main thread is responsible for displaying any aggregated timings.
64
+ */
65
+ timing.disableDisplay();
66
+
60
67
  debug("Dependencies loaded in %t", depsLoadedTime - startTime);
61
68
 
62
69
  (async () => {
@@ -158,5 +165,9 @@ debug("Dependencies loaded in %t", depsLoadedTime - startTime);
158
165
  indexedResults.netLintingDuration =
159
166
  lintingDuration - loadConfigTotalDuration - readFileCounter.duration;
160
167
 
168
+ if (timing.enabled) {
169
+ indexedResults.timings = timing.getData();
170
+ }
171
+
161
172
  parentPort.postMessage(indexedResults);
162
173
  })();
@@ -426,7 +426,7 @@ function validateSuggestions(suggest, messages) {
426
426
 
427
427
  if (typeof suggestion.fix !== "function") {
428
428
  throw new TypeError(
429
- `context.report() called with a suggest option without a fix function. See: ${suggestion}`,
429
+ `context.report() called with a suggest option without a fix function. See: ${JSON.stringify(suggestion, null, 2)}`,
430
430
  );
431
431
  }
432
432
  });
@@ -17,8 +17,9 @@ const vk = require("eslint-visitor-keys");
17
17
  //-----------------------------------------------------------------------------
18
18
 
19
19
  /**
20
- * @import { ESQueryParsedSelector } from "./esquery.js";
21
20
  * @import { Language, SourceCode } from "@eslint/core";
21
+ * @import { ESQueryOptions } from "esquery";
22
+ * @import { ESQueryParsedSelector } from "./esquery.js";
22
23
  * @import { SourceCodeVisitor } from "./source-code-visitor.js";
23
24
  */
24
25
 
@@ -47,11 +48,10 @@ class ESQueryHelper {
47
48
  * Creates a new instance.
48
49
  * @param {SourceCodeVisitor} visitor The visitor containing the functions to call.
49
50
  * @param {ESQueryOptions} esqueryOptions `esquery` options for traversing custom nodes.
50
- * @returns {NodeEventGenerator} new instance
51
51
  */
52
52
  constructor(visitor, esqueryOptions) {
53
53
  /**
54
- * The emitter to use during traversal.
54
+ * The visitor to use during traversal.
55
55
  * @type {SourceCodeVisitor}
56
56
  */
57
57
  this.visitor = visitor;
@@ -288,7 +288,10 @@ class SourceCodeTraverser {
288
288
  false,
289
289
  )
290
290
  .forEach(selector => {
291
- visitor.callSync(selector, step.target);
291
+ visitor.callSync(
292
+ selector,
293
+ ...(step.args ?? [step.target]),
294
+ );
292
295
  });
293
296
  currentAncestry.unshift(step.target);
294
297
  } else {
@@ -300,7 +303,10 @@ class SourceCodeTraverser {
300
303
  true,
301
304
  )
302
305
  .forEach(selector => {
303
- visitor.callSync(selector, step.target);
306
+ visitor.callSync(
307
+ selector,
308
+ ...(step.args ?? [step.target]),
309
+ );
304
310
  });
305
311
  }
306
312
  } catch (err) {
@@ -131,6 +131,7 @@ function display(data) {
131
131
  /* c8 ignore next */
132
132
  module.exports = (function () {
133
133
  const data = Object.create(null);
134
+ let displayEnabled = true;
134
135
 
135
136
  /**
136
137
  * Time the run
@@ -158,9 +159,42 @@ module.exports = (function () {
158
159
  };
159
160
  }
160
161
 
162
+ /**
163
+ * Returns a shallow copy of the collected timings data.
164
+ * @returns {Record<string, number>} mapping of ruleId to total time in ms
165
+ */
166
+ function getData() {
167
+ return { ...data };
168
+ }
169
+
170
+ /**
171
+ * Merges rule timing totals collected elsewhere into this process' totals.
172
+ * @param {Record<string, number>} dataToMerge mapping of ruleId to total time in ms
173
+ * @returns {void}
174
+ */
175
+ function mergeData(dataToMerge) {
176
+ for (const [key, value] of Object.entries(dataToMerge)) {
177
+ if (typeof data[key] === "undefined") {
178
+ data[key] = 0;
179
+ }
180
+ data[key] += value;
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Disables printing of timing data on process exit.
186
+ * Intended for worker threads or non-main contexts.
187
+ * @returns {void}
188
+ */
189
+ function disableDisplay() {
190
+ displayEnabled = false;
191
+ }
192
+
161
193
  if (enabled) {
162
194
  process.on("exit", () => {
163
- display(data);
195
+ if (displayEnabled && Object.keys(data).length > 0) {
196
+ display(data);
197
+ }
164
198
  });
165
199
  }
166
200
 
@@ -168,5 +202,8 @@ module.exports = (function () {
168
202
  time,
169
203
  enabled,
170
204
  getListSize,
205
+ getData,
206
+ mergeData,
207
+ disableDisplay,
171
208
  };
172
209
  })();
@@ -68,6 +68,7 @@ module.exports = {
68
68
  },
69
69
 
70
70
  create(context) {
71
+ const sourceCode = context.sourceCode;
71
72
  const option = context.options[0];
72
73
  let threshold = THRESHOLD_DEFAULT;
73
74
  let VARIANT = "classic";
@@ -177,12 +178,10 @@ module.exports = {
177
178
  name = "class field initializer";
178
179
  } else if (codePath.origin === "class-static-block") {
179
180
  name = "class static block";
181
+ loc = sourceCode.getFirstToken(node).loc;
180
182
  } else {
181
183
  name = astUtils.getFunctionNameWithKind(node);
182
- loc = astUtils.getFunctionHeadLoc(
183
- node,
184
- context.sourceCode,
185
- );
184
+ loc = astUtils.getFunctionHeadLoc(node, sourceCode);
186
185
  }
187
186
 
188
187
  context.report({
@@ -46,7 +46,10 @@ module.exports = {
46
46
  */
47
47
  function report(node) {
48
48
  context.report({
49
- node,
49
+ loc: {
50
+ start: node.loc.start,
51
+ end: sourceCode.getTokenBefore(node.body).loc.end,
52
+ },
50
53
  messageId: "incorrectDirection",
51
54
  });
52
55
  }
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("./utils/ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -58,10 +64,15 @@ module.exports = {
58
64
 
59
65
  // Checks and reports duplications.
60
66
  const defs = variable.defs.filter(isParameter);
67
+ const loc = {
68
+ start: astUtils.getOpeningParenOfParams(node, sourceCode)
69
+ .loc.start,
70
+ end: sourceCode.getTokenBefore(node.body).loc.end,
71
+ };
61
72
 
62
73
  if (defs.length >= 2) {
63
74
  context.report({
64
- node,
75
+ loc,
65
76
  messageId: "unexpected",
66
77
  data: { name: variable.name },
67
78
  });
@@ -106,7 +106,7 @@ module.exports = {
106
106
 
107
107
  if (isDuplicate) {
108
108
  context.report({
109
- node,
109
+ loc: node.key.loc,
110
110
  messageId: "unexpected",
111
111
  data: { name },
112
112
  });
@@ -19,6 +19,86 @@ const OPTIONS = {
19
19
  //------------------------------------------------------------------------------
20
20
  const astUtils = require("./utils/ast-utils");
21
21
 
22
+ //--------------------------------------------------------------------------
23
+ // Helpers
24
+ //--------------------------------------------------------------------------
25
+ const CTOR_PREFIX_REGEX = /[^_$0-9]/u;
26
+ const JSDOC_COMMENT_REGEX = /^\s*\*/u;
27
+
28
+ /**
29
+ * Determines if the first character of the name is a capital letter.
30
+ * @param {string} name The name of the node to evaluate.
31
+ * @returns {boolean} True if the first character of the property name is a capital letter, false if not.
32
+ * @private
33
+ */
34
+ function isConstructor(name) {
35
+ const match = CTOR_PREFIX_REGEX.exec(name);
36
+
37
+ // Not a constructor if name has no characters apart from '_', '$' and digits e.g. '_', '$$', '_8'
38
+ if (!match) {
39
+ return false;
40
+ }
41
+
42
+ const firstChar = name.charAt(match.index);
43
+
44
+ return firstChar === firstChar.toUpperCase();
45
+ }
46
+
47
+ /**
48
+ * Determines if the property can have a shorthand form.
49
+ * @param {ASTNode} property Property AST node
50
+ * @returns {boolean} True if the property can have a shorthand form
51
+ * @private
52
+ */
53
+ function canHaveShorthand(property) {
54
+ return (
55
+ property.kind !== "set" &&
56
+ property.kind !== "get" &&
57
+ property.type !== "SpreadElement" &&
58
+ property.type !== "SpreadProperty" &&
59
+ property.type !== "ExperimentalSpreadProperty"
60
+ );
61
+ }
62
+
63
+ /**
64
+ * Checks whether a node is a string literal.
65
+ * @param {ASTNode} node Any AST node.
66
+ * @returns {boolean} `true` if it is a string literal.
67
+ */
68
+ function isStringLiteral(node) {
69
+ return node.type === "Literal" && typeof node.value === "string";
70
+ }
71
+
72
+ /**
73
+ * Determines if the property is a shorthand or not.
74
+ * @param {ASTNode} property Property AST node
75
+ * @returns {boolean} True if the property is considered shorthand, false if not.
76
+ * @private
77
+ */
78
+ function isShorthand(property) {
79
+ // property.method is true when `{a(){}}`.
80
+ return property.shorthand || property.method;
81
+ }
82
+
83
+ /**
84
+ * Determines if the property's key and method or value are named equally.
85
+ * @param {ASTNode} property Property AST node
86
+ * @returns {boolean} True if the key and value are named equally, false if not.
87
+ * @private
88
+ */
89
+ function isRedundant(property) {
90
+ const value = property.value;
91
+
92
+ if (value.type === "FunctionExpression") {
93
+ return !value.id; // Only anonymous should be shorthand method.
94
+ }
95
+ if (value.type === "Identifier") {
96
+ return astUtils.getStaticPropertyName(property) === value.name;
97
+ }
98
+
99
+ return false;
100
+ }
101
+
22
102
  //------------------------------------------------------------------------------
23
103
  // Rule Definition
24
104
  //------------------------------------------------------------------------------
@@ -139,86 +219,6 @@ module.exports = {
139
219
  const AVOID_EXPLICIT_RETURN_ARROWS = !!PARAMS.avoidExplicitReturnArrows;
140
220
  const sourceCode = context.sourceCode;
141
221
 
142
- //--------------------------------------------------------------------------
143
- // Helpers
144
- //--------------------------------------------------------------------------
145
-
146
- const CTOR_PREFIX_REGEX = /[^_$0-9]/u;
147
-
148
- /**
149
- * Determines if the first character of the name is a capital letter.
150
- * @param {string} name The name of the node to evaluate.
151
- * @returns {boolean} True if the first character of the property name is a capital letter, false if not.
152
- * @private
153
- */
154
- function isConstructor(name) {
155
- const match = CTOR_PREFIX_REGEX.exec(name);
156
-
157
- // Not a constructor if name has no characters apart from '_', '$' and digits e.g. '_', '$$', '_8'
158
- if (!match) {
159
- return false;
160
- }
161
-
162
- const firstChar = name.charAt(match.index);
163
-
164
- return firstChar === firstChar.toUpperCase();
165
- }
166
-
167
- /**
168
- * Determines if the property can have a shorthand form.
169
- * @param {ASTNode} property Property AST node
170
- * @returns {boolean} True if the property can have a shorthand form
171
- * @private
172
- */
173
- function canHaveShorthand(property) {
174
- return (
175
- property.kind !== "set" &&
176
- property.kind !== "get" &&
177
- property.type !== "SpreadElement" &&
178
- property.type !== "SpreadProperty" &&
179
- property.type !== "ExperimentalSpreadProperty"
180
- );
181
- }
182
-
183
- /**
184
- * Checks whether a node is a string literal.
185
- * @param {ASTNode} node Any AST node.
186
- * @returns {boolean} `true` if it is a string literal.
187
- */
188
- function isStringLiteral(node) {
189
- return node.type === "Literal" && typeof node.value === "string";
190
- }
191
-
192
- /**
193
- * Determines if the property is a shorthand or not.
194
- * @param {ASTNode} property Property AST node
195
- * @returns {boolean} True if the property is considered shorthand, false if not.
196
- * @private
197
- */
198
- function isShorthand(property) {
199
- // property.method is true when `{a(){}}`.
200
- return property.shorthand || property.method;
201
- }
202
-
203
- /**
204
- * Determines if the property's key and method or value are named equally.
205
- * @param {ASTNode} property Property AST node
206
- * @returns {boolean} True if the key and value are named equally, false if not.
207
- * @private
208
- */
209
- function isRedundant(property) {
210
- const value = property.value;
211
-
212
- if (value.type === "FunctionExpression") {
213
- return !value.id; // Only anonymous should be shorthand method.
214
- }
215
- if (value.type === "Identifier") {
216
- return astUtils.getStaticPropertyName(property) === value.name;
217
- }
218
-
219
- return false;
220
- }
221
-
222
222
  /**
223
223
  * Ensures that an object's properties are consistently shorthand, or not shorthand at all.
224
224
  * @param {ASTNode} node Property AST node
@@ -582,6 +582,19 @@ module.exports = {
582
582
  node.key.name === node.value.name &&
583
583
  APPLY_TO_PROPS
584
584
  ) {
585
+ // Skip if there are JSDoc comments inside the property (e.g., JSDoc type annotations)
586
+ const comments = sourceCode.getCommentsInside(node);
587
+ if (
588
+ comments.some(
589
+ comment =>
590
+ comment.type === "Block" &&
591
+ JSDOC_COMMENT_REGEX.test(comment.value) &&
592
+ comment.value.includes("@type"),
593
+ )
594
+ ) {
595
+ return;
596
+ }
597
+
585
598
  // {x: x} should be written as {x}
586
599
  context.report({
587
600
  node,
@@ -606,6 +619,18 @@ module.exports = {
606
619
  return;
607
620
  }
608
621
 
622
+ const comments = sourceCode.getCommentsInside(node);
623
+ if (
624
+ comments.some(
625
+ comment =>
626
+ comment.type === "Block" &&
627
+ comment.value.startsWith("*") &&
628
+ comment.value.includes("@type"),
629
+ )
630
+ ) {
631
+ return;
632
+ }
633
+
609
634
  // {"x": x} should be written as {x}
610
635
  context.report({
611
636
  node,
@@ -2729,4 +2729,5 @@ module.exports = {
2729
2729
  isStartOfExpressionStatement,
2730
2730
  needsPrecedingSemicolon,
2731
2731
  isImportAttributeKey,
2732
+ getOpeningParenOfParams,
2732
2733
  };
@@ -33,7 +33,6 @@ import type {
33
33
  LanguageOptions as GenericLanguageOptions,
34
34
  RuleContext as CoreRuleContext,
35
35
  RuleDefinition,
36
- RuleVisitor,
37
36
  SourceRange,
38
37
  TextSourceCode,
39
38
  TraversalStep,
@@ -56,11 +55,40 @@ import type {
56
55
  ProcessorFile as CoreProcessorFile,
57
56
  JavaScriptParserOptionsConfig,
58
57
  RulesMeta,
58
+ RuleConfig,
59
59
  RuleTextEditor,
60
60
  RuleTextEdit,
61
+ RuleVisitor,
62
+ BaseConfig as CoreBaseConfig,
63
+ RuleFixer as CoreRuleFixer,
64
+ ViolationReportBase,
65
+ ViolationMessage,
66
+ ViolationLocation,
67
+ SuggestionMessage,
68
+ LintSuggestion as CoreLintSuggestion,
69
+ JavaScriptSourceType,
70
+ HasRules as CoreHasRules,
71
+ SuggestedEditBase,
72
+ SuggestedEdit,
73
+ ViolationReport,
61
74
  } from "@eslint/core";
62
75
  import { LegacyESLint } from "./use-at-your-own-risk.js";
63
76
 
77
+ //------------------------------------------------------------------------------
78
+ // Helpers
79
+ //------------------------------------------------------------------------------
80
+
81
+ /** Adds matching `:exit` selectors for all properties of a `RuleVisitor`. */
82
+ type WithExit<RuleVisitorType extends RuleVisitor> = {
83
+ [Key in keyof RuleVisitorType as
84
+ | Key
85
+ | `${Key & string}:exit`]: RuleVisitorType[Key];
86
+ };
87
+
88
+ //------------------------------------------------------------------------------
89
+ // Exports
90
+ //------------------------------------------------------------------------------
91
+
64
92
  export namespace AST {
65
93
  type TokenType =
66
94
  | "Boolean"
@@ -133,6 +161,10 @@ export namespace Scope {
133
161
  references: Reference[];
134
162
  through: Reference[];
135
163
  functionExpressionScope: boolean;
164
+ implicit?: {
165
+ variables: Variable[];
166
+ set: Map<string, Variable>;
167
+ };
136
168
  }
137
169
 
138
170
  interface Variable {
@@ -173,7 +205,14 @@ export namespace Scope {
173
205
  node: ESTree.FunctionDeclaration | ESTree.FunctionExpression;
174
206
  parent: null;
175
207
  }
176
- | { type: "ImplicitGlobalVariable"; node: ESTree.Program; parent: null }
208
+ | {
209
+ type: "ImplicitGlobalVariable";
210
+ node:
211
+ | ESTree.AssignmentExpression
212
+ | ESTree.ForInStatement
213
+ | ESTree.ForOfStatement;
214
+ parent: null;
215
+ }
177
216
  | {
178
217
  type: "ImportBinding";
179
218
  node:
@@ -640,480 +679,35 @@ export namespace Rule {
640
679
  LangOptions: Linter.LanguageOptions;
641
680
  Code: SourceCode;
642
681
  RuleOptions: any[];
643
- Visitor: NodeListener;
682
+ Visitor: RuleListener;
644
683
  Node: JSSyntaxElement;
645
684
  MessageIds: string;
646
685
  ExtRuleDocs: {};
647
686
  }> {
648
- create(context: RuleContext): NodeListener;
687
+ create(context: RuleContext): RuleListener;
649
688
  }
650
689
 
651
690
  type NodeTypes = ESTree.Node["type"];
652
- interface NodeListener extends RuleVisitor {
653
- ArrayExpression?:
654
- | ((node: ESTree.ArrayExpression & NodeParentExtension) => void)
655
- | undefined;
656
- "ArrayExpression:exit"?:
657
- | ((node: ESTree.ArrayExpression & NodeParentExtension) => void)
658
- | undefined;
659
- ArrayPattern?:
660
- | ((node: ESTree.ArrayPattern & NodeParentExtension) => void)
661
- | undefined;
662
- "ArrayPattern:exit"?:
663
- | ((node: ESTree.ArrayPattern & NodeParentExtension) => void)
664
- | undefined;
665
- ArrowFunctionExpression?:
666
- | ((
667
- node: ESTree.ArrowFunctionExpression & NodeParentExtension,
668
- ) => void)
669
- | undefined;
670
- "ArrowFunctionExpression:exit"?:
671
- | ((
672
- node: ESTree.ArrowFunctionExpression & NodeParentExtension,
673
- ) => void)
674
- | undefined;
675
- AssignmentExpression?:
676
- | ((
677
- node: ESTree.AssignmentExpression & NodeParentExtension,
678
- ) => void)
679
- | undefined;
680
- "AssignmentExpression:exit"?:
681
- | ((
682
- node: ESTree.AssignmentExpression & NodeParentExtension,
683
- ) => void)
684
- | undefined;
685
- AssignmentPattern?:
686
- | ((node: ESTree.AssignmentPattern & NodeParentExtension) => void)
687
- | undefined;
688
- "AssignmentPattern:exit"?:
689
- | ((node: ESTree.AssignmentPattern & NodeParentExtension) => void)
690
- | undefined;
691
- AwaitExpression?:
692
- | ((node: ESTree.AwaitExpression & NodeParentExtension) => void)
693
- | undefined;
694
- "AwaitExpression:exit"?:
695
- | ((node: ESTree.AwaitExpression & NodeParentExtension) => void)
696
- | undefined;
697
- BinaryExpression?:
698
- | ((node: ESTree.BinaryExpression & NodeParentExtension) => void)
699
- | undefined;
700
- "BinaryExpression:exit"?:
701
- | ((node: ESTree.BinaryExpression & NodeParentExtension) => void)
702
- | undefined;
703
- BlockStatement?:
704
- | ((node: ESTree.BlockStatement & NodeParentExtension) => void)
705
- | undefined;
706
- "BlockStatement:exit"?:
707
- | ((node: ESTree.BlockStatement & NodeParentExtension) => void)
708
- | undefined;
709
- BreakStatement?:
710
- | ((node: ESTree.BreakStatement & NodeParentExtension) => void)
711
- | undefined;
712
- "BreakStatement:exit"?:
713
- | ((node: ESTree.BreakStatement & NodeParentExtension) => void)
714
- | undefined;
715
- CallExpression?:
716
- | ((node: ESTree.CallExpression & NodeParentExtension) => void)
717
- | undefined;
718
- "CallExpression:exit"?:
719
- | ((node: ESTree.CallExpression & NodeParentExtension) => void)
720
- | undefined;
721
- CatchClause?:
722
- | ((node: ESTree.CatchClause & NodeParentExtension) => void)
723
- | undefined;
724
- "CatchClause:exit"?:
725
- | ((node: ESTree.CatchClause & NodeParentExtension) => void)
726
- | undefined;
727
- ChainExpression?:
728
- | ((node: ESTree.ChainExpression & NodeParentExtension) => void)
729
- | undefined;
730
- "ChainExpression:exit"?:
731
- | ((node: ESTree.ChainExpression & NodeParentExtension) => void)
732
- | undefined;
733
- ClassBody?:
734
- | ((node: ESTree.ClassBody & NodeParentExtension) => void)
735
- | undefined;
736
- "ClassBody:exit"?:
737
- | ((node: ESTree.ClassBody & NodeParentExtension) => void)
738
- | undefined;
739
- ClassDeclaration?:
740
- | ((node: ESTree.ClassDeclaration & NodeParentExtension) => void)
741
- | undefined;
742
- "ClassDeclaration:exit"?:
743
- | ((node: ESTree.ClassDeclaration & NodeParentExtension) => void)
744
- | undefined;
745
- ClassExpression?:
746
- | ((node: ESTree.ClassExpression & NodeParentExtension) => void)
747
- | undefined;
748
- "ClassExpression:exit"?:
749
- | ((node: ESTree.ClassExpression & NodeParentExtension) => void)
750
- | undefined;
751
- ConditionalExpression?:
752
- | ((
753
- node: ESTree.ConditionalExpression & NodeParentExtension,
754
- ) => void)
755
- | undefined;
756
- "ConditionalExpression:exit"?:
757
- | ((
758
- node: ESTree.ConditionalExpression & NodeParentExtension,
759
- ) => void)
760
- | undefined;
761
- ContinueStatement?:
762
- | ((node: ESTree.ContinueStatement & NodeParentExtension) => void)
763
- | undefined;
764
- "ContinueStatement:exit"?:
765
- | ((node: ESTree.ContinueStatement & NodeParentExtension) => void)
766
- | undefined;
767
- DebuggerStatement?:
768
- | ((node: ESTree.DebuggerStatement & NodeParentExtension) => void)
769
- | undefined;
770
- "DebuggerStatement:exit"?:
771
- | ((node: ESTree.DebuggerStatement & NodeParentExtension) => void)
772
- | undefined;
773
- DoWhileStatement?:
774
- | ((node: ESTree.DoWhileStatement & NodeParentExtension) => void)
775
- | undefined;
776
- "DoWhileStatement:exit"?:
777
- | ((node: ESTree.DoWhileStatement & NodeParentExtension) => void)
778
- | undefined;
779
- EmptyStatement?:
780
- | ((node: ESTree.EmptyStatement & NodeParentExtension) => void)
781
- | undefined;
782
- "EmptyStatement:exit"?:
783
- | ((node: ESTree.EmptyStatement & NodeParentExtension) => void)
784
- | undefined;
785
- ExportAllDeclaration?:
786
- | ((
787
- node: ESTree.ExportAllDeclaration & NodeParentExtension,
788
- ) => void)
789
- | undefined;
790
- "ExportAllDeclaration:exit"?:
791
- | ((
792
- node: ESTree.ExportAllDeclaration & NodeParentExtension,
793
- ) => void)
794
- | undefined;
795
- ExportDefaultDeclaration?:
796
- | ((
797
- node: ESTree.ExportDefaultDeclaration & NodeParentExtension,
798
- ) => void)
799
- | undefined;
800
- "ExportDefaultDeclaration:exit"?:
801
- | ((
802
- node: ESTree.ExportDefaultDeclaration & NodeParentExtension,
803
- ) => void)
804
- | undefined;
805
- ExportNamedDeclaration?:
806
- | ((
807
- node: ESTree.ExportNamedDeclaration & NodeParentExtension,
808
- ) => void)
809
- | undefined;
810
- "ExportNamedDeclaration:exit"?:
811
- | ((
812
- node: ESTree.ExportNamedDeclaration & NodeParentExtension,
813
- ) => void)
814
- | undefined;
815
- ExportSpecifier?:
816
- | ((node: ESTree.ExportSpecifier & NodeParentExtension) => void)
817
- | undefined;
818
- "ExportSpecifier:exit"?:
819
- | ((node: ESTree.ExportSpecifier & NodeParentExtension) => void)
820
- | undefined;
821
- ExpressionStatement?:
822
- | ((node: ESTree.ExpressionStatement & NodeParentExtension) => void)
823
- | undefined;
824
- "ExpressionStatement:exit"?:
825
- | ((node: ESTree.ExpressionStatement & NodeParentExtension) => void)
826
- | undefined;
827
- ForInStatement?:
828
- | ((node: ESTree.ForInStatement & NodeParentExtension) => void)
829
- | undefined;
830
- "ForInStatement:exit"?:
831
- | ((node: ESTree.ForInStatement & NodeParentExtension) => void)
832
- | undefined;
833
- ForOfStatement?:
834
- | ((node: ESTree.ForOfStatement & NodeParentExtension) => void)
835
- | undefined;
836
- "ForOfStatement:exit"?:
837
- | ((node: ESTree.ForOfStatement & NodeParentExtension) => void)
838
- | undefined;
839
- ForStatement?:
840
- | ((node: ESTree.ForStatement & NodeParentExtension) => void)
841
- | undefined;
842
- "ForStatement:exit"?:
843
- | ((node: ESTree.ForStatement & NodeParentExtension) => void)
844
- | undefined;
845
- FunctionDeclaration?:
846
- | ((node: ESTree.FunctionDeclaration & NodeParentExtension) => void)
847
- | undefined;
848
- "FunctionDeclaration:exit"?:
849
- | ((node: ESTree.FunctionDeclaration & NodeParentExtension) => void)
850
- | undefined;
851
- FunctionExpression?:
852
- | ((node: ESTree.FunctionExpression & NodeParentExtension) => void)
853
- | undefined;
854
- "FunctionExpression:exit"?:
855
- | ((node: ESTree.FunctionExpression & NodeParentExtension) => void)
856
- | undefined;
857
- Identifier?:
858
- | ((node: ESTree.Identifier & NodeParentExtension) => void)
859
- | undefined;
860
- "Identifier:exit"?:
861
- | ((node: ESTree.Identifier & NodeParentExtension) => void)
862
- | undefined;
863
- IfStatement?:
864
- | ((node: ESTree.IfStatement & NodeParentExtension) => void)
865
- | undefined;
866
- "IfStatement:exit"?:
867
- | ((node: ESTree.IfStatement & NodeParentExtension) => void)
868
- | undefined;
869
- ImportDeclaration?:
870
- | ((node: ESTree.ImportDeclaration & NodeParentExtension) => void)
871
- | undefined;
872
- "ImportDeclaration:exit"?:
873
- | ((node: ESTree.ImportDeclaration & NodeParentExtension) => void)
874
- | undefined;
875
- ImportDefaultSpecifier?:
876
- | ((
877
- node: ESTree.ImportDefaultSpecifier & NodeParentExtension,
878
- ) => void)
879
- | undefined;
880
- "ImportDefaultSpecifier:exit"?:
881
- | ((
882
- node: ESTree.ImportDefaultSpecifier & NodeParentExtension,
883
- ) => void)
884
- | undefined;
885
- ImportExpression?:
886
- | ((node: ESTree.ImportExpression & NodeParentExtension) => void)
887
- | undefined;
888
- "ImportExpression:exit"?:
889
- | ((node: ESTree.ImportExpression & NodeParentExtension) => void)
890
- | undefined;
891
- ImportNamespaceSpecifier?:
892
- | ((
893
- node: ESTree.ImportNamespaceSpecifier & NodeParentExtension,
894
- ) => void)
895
- | undefined;
896
- "ImportNamespaceSpecifier:exit"?:
897
- | ((
898
- node: ESTree.ImportNamespaceSpecifier & NodeParentExtension,
899
- ) => void)
900
- | undefined;
901
- ImportSpecifier?:
902
- | ((node: ESTree.ImportSpecifier & NodeParentExtension) => void)
903
- | undefined;
904
- "ImportSpecifier:exit"?:
905
- | ((node: ESTree.ImportSpecifier & NodeParentExtension) => void)
906
- | undefined;
907
- LabeledStatement?:
908
- | ((node: ESTree.LabeledStatement & NodeParentExtension) => void)
909
- | undefined;
910
- "LabeledStatement:exit"?:
911
- | ((node: ESTree.LabeledStatement & NodeParentExtension) => void)
912
- | undefined;
913
- Literal?:
914
- | ((node: ESTree.Literal & NodeParentExtension) => void)
915
- | undefined;
916
- "Literal:exit"?:
917
- | ((node: ESTree.Literal & NodeParentExtension) => void)
918
- | undefined;
919
- LogicalExpression?:
920
- | ((node: ESTree.LogicalExpression & NodeParentExtension) => void)
921
- | undefined;
922
- "LogicalExpression:exit"?:
923
- | ((node: ESTree.LogicalExpression & NodeParentExtension) => void)
924
- | undefined;
925
- MemberExpression?:
926
- | ((node: ESTree.MemberExpression & NodeParentExtension) => void)
927
- | undefined;
928
- "MemberExpression:exit"?:
929
- | ((node: ESTree.MemberExpression & NodeParentExtension) => void)
930
- | undefined;
931
- MetaProperty?:
932
- | ((node: ESTree.MetaProperty & NodeParentExtension) => void)
933
- | undefined;
934
- "MetaProperty:exit"?:
935
- | ((node: ESTree.MetaProperty & NodeParentExtension) => void)
936
- | undefined;
937
- MethodDefinition?:
938
- | ((node: ESTree.MethodDefinition & NodeParentExtension) => void)
939
- | undefined;
940
- "MethodDefinition:exit"?:
941
- | ((node: ESTree.MethodDefinition & NodeParentExtension) => void)
942
- | undefined;
943
- NewExpression?:
944
- | ((node: ESTree.NewExpression & NodeParentExtension) => void)
945
- | undefined;
946
- "NewExpression:exit"?:
947
- | ((node: ESTree.NewExpression & NodeParentExtension) => void)
948
- | undefined;
949
- ObjectExpression?:
950
- | ((node: ESTree.ObjectExpression & NodeParentExtension) => void)
951
- | undefined;
952
- "ObjectExpression:exit"?:
953
- | ((node: ESTree.ObjectExpression & NodeParentExtension) => void)
954
- | undefined;
955
- ObjectPattern?:
956
- | ((node: ESTree.ObjectPattern & NodeParentExtension) => void)
957
- | undefined;
958
- "ObjectPattern:exit"?:
959
- | ((node: ESTree.ObjectPattern & NodeParentExtension) => void)
960
- | undefined;
961
- PrivateIdentifier?:
962
- | ((node: ESTree.PrivateIdentifier & NodeParentExtension) => void)
963
- | undefined;
964
- "PrivateIdentifier:exit"?:
965
- | ((node: ESTree.PrivateIdentifier & NodeParentExtension) => void)
966
- | undefined;
967
- Program?: ((node: ESTree.Program) => void) | undefined;
968
- "Program:exit"?: ((node: ESTree.Program) => void) | undefined;
969
- Property?:
970
- | ((node: ESTree.Property & NodeParentExtension) => void)
971
- | undefined;
972
- "Property:exit"?:
973
- | ((node: ESTree.Property & NodeParentExtension) => void)
974
- | undefined;
975
- PropertyDefinition?:
976
- | ((node: ESTree.PropertyDefinition & NodeParentExtension) => void)
977
- | undefined;
978
- "PropertyDefinition:exit"?:
979
- | ((node: ESTree.PropertyDefinition & NodeParentExtension) => void)
980
- | undefined;
981
- RestElement?:
982
- | ((node: ESTree.RestElement & NodeParentExtension) => void)
983
- | undefined;
984
- "RestElement:exit"?:
985
- | ((node: ESTree.RestElement & NodeParentExtension) => void)
986
- | undefined;
987
- ReturnStatement?:
988
- | ((node: ESTree.ReturnStatement & NodeParentExtension) => void)
989
- | undefined;
990
- "ReturnStatement:exit"?:
991
- | ((node: ESTree.ReturnStatement & NodeParentExtension) => void)
992
- | undefined;
993
- SequenceExpression?:
994
- | ((node: ESTree.SequenceExpression & NodeParentExtension) => void)
995
- | undefined;
996
- "SequenceExpression:exit"?:
997
- | ((node: ESTree.SequenceExpression & NodeParentExtension) => void)
998
- | undefined;
999
- SpreadElement?:
1000
- | ((node: ESTree.SpreadElement & NodeParentExtension) => void)
1001
- | undefined;
1002
- "SpreadElement:exit"?:
1003
- | ((node: ESTree.SpreadElement & NodeParentExtension) => void)
1004
- | undefined;
1005
- StaticBlock?:
1006
- | ((node: ESTree.StaticBlock & NodeParentExtension) => void)
1007
- | undefined;
1008
- "StaticBlock:exit"?:
1009
- | ((node: ESTree.StaticBlock & NodeParentExtension) => void)
1010
- | undefined;
1011
- Super?:
1012
- | ((node: ESTree.Super & NodeParentExtension) => void)
1013
- | undefined;
1014
- "Super:exit"?:
1015
- | ((node: ESTree.Super & NodeParentExtension) => void)
1016
- | undefined;
1017
- SwitchCase?:
1018
- | ((node: ESTree.SwitchCase & NodeParentExtension) => void)
1019
- | undefined;
1020
- "SwitchCase:exit"?:
1021
- | ((node: ESTree.SwitchCase & NodeParentExtension) => void)
1022
- | undefined;
1023
- SwitchStatement?:
1024
- | ((node: ESTree.SwitchStatement & NodeParentExtension) => void)
1025
- | undefined;
1026
- "SwitchStatement:exit"?:
1027
- | ((node: ESTree.SwitchStatement & NodeParentExtension) => void)
1028
- | undefined;
1029
- TaggedTemplateExpression?:
1030
- | ((
1031
- node: ESTree.TaggedTemplateExpression & NodeParentExtension,
1032
- ) => void)
1033
- | undefined;
1034
- "TaggedTemplateExpression:exit"?:
1035
- | ((
1036
- node: ESTree.TaggedTemplateExpression & NodeParentExtension,
1037
- ) => void)
1038
- | undefined;
1039
- TemplateElement?:
1040
- | ((node: ESTree.TemplateElement & NodeParentExtension) => void)
1041
- | undefined;
1042
- "TemplateElement:exit"?:
1043
- | ((node: ESTree.TemplateElement & NodeParentExtension) => void)
1044
- | undefined;
1045
- TemplateLiteral?:
1046
- | ((node: ESTree.TemplateLiteral & NodeParentExtension) => void)
1047
- | undefined;
1048
- "TemplateLiteral:exit"?:
1049
- | ((node: ESTree.TemplateLiteral & NodeParentExtension) => void)
1050
- | undefined;
1051
- ThisExpression?:
1052
- | ((node: ESTree.ThisExpression & NodeParentExtension) => void)
1053
- | undefined;
1054
- "ThisExpression:exit"?:
1055
- | ((node: ESTree.ThisExpression & NodeParentExtension) => void)
1056
- | undefined;
1057
- ThrowStatement?:
1058
- | ((node: ESTree.ThrowStatement & NodeParentExtension) => void)
1059
- | undefined;
1060
- "ThrowStatement:exit"?:
1061
- | ((node: ESTree.ThrowStatement & NodeParentExtension) => void)
1062
- | undefined;
1063
- TryStatement?:
1064
- | ((node: ESTree.TryStatement & NodeParentExtension) => void)
1065
- | undefined;
1066
- "TryStatement:exit"?:
1067
- | ((node: ESTree.TryStatement & NodeParentExtension) => void)
1068
- | undefined;
1069
- UnaryExpression?:
1070
- | ((node: ESTree.UnaryExpression & NodeParentExtension) => void)
1071
- | undefined;
1072
- "UnaryExpression:exit"?:
1073
- | ((node: ESTree.UnaryExpression & NodeParentExtension) => void)
1074
- | undefined;
1075
- UpdateExpression?:
1076
- | ((node: ESTree.UpdateExpression & NodeParentExtension) => void)
1077
- | undefined;
1078
- "UpdateExpression:exit"?:
1079
- | ((node: ESTree.UpdateExpression & NodeParentExtension) => void)
1080
- | undefined;
1081
- VariableDeclaration?:
1082
- | ((node: ESTree.VariableDeclaration & NodeParentExtension) => void)
1083
- | undefined;
1084
- "VariableDeclaration:exit"?:
1085
- | ((node: ESTree.VariableDeclaration & NodeParentExtension) => void)
1086
- | undefined;
1087
- VariableDeclarator?:
1088
- | ((node: ESTree.VariableDeclarator & NodeParentExtension) => void)
1089
- | undefined;
1090
- "VariableDeclarator:exit"?:
1091
- | ((node: ESTree.VariableDeclarator & NodeParentExtension) => void)
1092
- | undefined;
1093
- WhileStatement?:
1094
- | ((node: ESTree.WhileStatement & NodeParentExtension) => void)
1095
- | undefined;
1096
- "WhileStatement:exit"?:
1097
- | ((node: ESTree.WhileStatement & NodeParentExtension) => void)
1098
- | undefined;
1099
- WithStatement?:
1100
- | ((node: ESTree.WithStatement & NodeParentExtension) => void)
1101
- | undefined;
1102
- "WithStatement:exit"?:
1103
- | ((node: ESTree.WithStatement & NodeParentExtension) => void)
1104
- | undefined;
1105
- YieldExpression?:
1106
- | ((node: ESTree.YieldExpression & NodeParentExtension) => void)
1107
- | undefined;
1108
- "YieldExpression:exit"?:
1109
- | ((node: ESTree.YieldExpression & NodeParentExtension) => void)
1110
- | undefined;
1111
- }
691
+
692
+ interface NodeListener
693
+ extends WithExit<
694
+ {
695
+ [Node in Rule.Node as Node["type"]]?:
696
+ | ((node: Node) => void)
697
+ | undefined;
698
+ } & {
699
+ // A `Program` visitor's node type has no `parent` property.
700
+ Program?: ((node: AST.Program) => void) | undefined;
701
+ }
702
+ > {}
1112
703
 
1113
704
  interface NodeParentExtension {
1114
705
  parent: Node;
1115
706
  }
1116
- type Node = ESTree.Node & NodeParentExtension;
707
+
708
+ type Node =
709
+ | (AST.Program & { parent: null })
710
+ | (Exclude<ESTree.Node, ESTree.Program> & NodeParentExtension);
1117
711
 
1118
712
  interface RuleListener extends NodeListener {
1119
713
  onCodePathStart?(codePath: CodePath, node: Node): void;
@@ -1124,6 +718,16 @@ export namespace Rule {
1124
718
 
1125
719
  onCodePathSegmentEnd?(segment: CodePathSegment, node: Node): void;
1126
720
 
721
+ onUnreachableCodePathSegmentStart?(
722
+ segment: CodePathSegment,
723
+ node: Node,
724
+ ): void;
725
+
726
+ onUnreachableCodePathSegmentEnd?(
727
+ segment: CodePathSegment,
728
+ node: Node,
729
+ ): void;
730
+
1127
731
  onCodePathSegmentLoop?(
1128
732
  fromSegment: CodePathSegment,
1129
733
  toSegment: CodePathSegment,
@@ -1178,37 +782,21 @@ export namespace Rule {
1178
782
  MessageIds: string;
1179
783
  }> {}
1180
784
 
1181
- type ReportFixer = (
1182
- fixer: RuleFixer,
1183
- ) => null | Fix | IterableIterator<Fix> | Fix[];
785
+ type ReportFixer = CoreRuleFixer;
1184
786
 
1185
- interface ReportDescriptorOptionsBase {
1186
- data?: { [key: string]: string };
787
+ /** @deprecated Use `ReportDescriptorOptions` instead. */
788
+ type ReportDescriptorOptionsBase = ViolationReportBase;
1187
789
 
1188
- fix?: null | ReportFixer;
1189
- }
790
+ type SuggestionReportOptions = SuggestedEditBase;
791
+ type SuggestionDescriptorMessage = SuggestionMessage;
792
+ type SuggestionReportDescriptor = SuggestedEdit;
1190
793
 
1191
- interface SuggestionReportOptions {
1192
- data?: { [key: string]: string };
794
+ // redundant with ReportDescriptorOptionsBase but kept for clarity
795
+ type ReportDescriptorOptions = ViolationReportBase;
1193
796
 
1194
- fix: ReportFixer;
1195
- }
1196
-
1197
- type SuggestionDescriptorMessage = { desc: string } | { messageId: string };
1198
- type SuggestionReportDescriptor = SuggestionDescriptorMessage &
1199
- SuggestionReportOptions;
1200
-
1201
- interface ReportDescriptorOptions extends ReportDescriptorOptionsBase {
1202
- suggest?: SuggestionReportDescriptor[] | null | undefined;
1203
- }
1204
-
1205
- type ReportDescriptor = ReportDescriptorMessage &
1206
- ReportDescriptorLocation &
1207
- ReportDescriptorOptions;
1208
- type ReportDescriptorMessage = { message: string } | { messageId: string };
1209
- type ReportDescriptorLocation =
1210
- | { node: ESTree.Node }
1211
- | { loc: AST.SourceLocation | { line: number; column: number } };
797
+ type ReportDescriptor = ViolationReport<ESTree.Node>;
798
+ type ReportDescriptorMessage = ViolationMessage;
799
+ type ReportDescriptorLocation = ViolationLocation<ESTree.Node>;
1212
800
 
1213
801
  type RuleFixer = RuleTextEditor<ESTree.Node | AST.Token>;
1214
802
  type Fix = RuleTextEdit;
@@ -1222,7 +810,7 @@ export type JSRuleDefinition<
1222
810
  {
1223
811
  LangOptions: Linter.LanguageOptions;
1224
812
  Code: SourceCode;
1225
- Visitor: Rule.NodeListener;
813
+ Visitor: Rule.RuleListener;
1226
814
  Node: JSSyntaxElement;
1227
815
  },
1228
816
  Options
@@ -1318,9 +906,7 @@ export namespace Linter {
1318
906
  *
1319
907
  * @see [Rules](https://eslint.org/docs/latest/use/configure/rules)
1320
908
  */
1321
- type RuleEntry<Options extends any[] = any[]> =
1322
- | RuleSeverity
1323
- | RuleSeverityAndOptions<Options>;
909
+ type RuleEntry<Options extends any[] = any[]> = RuleConfig<Options>;
1324
910
 
1325
911
  /**
1326
912
  * The rules config object is a key/value map of rule names and their severity and options.
@@ -1330,9 +916,8 @@ export namespace Linter {
1330
916
  /**
1331
917
  * A configuration object that may have a `rules` block.
1332
918
  */
1333
- interface HasRules<Rules extends RulesConfig = RulesConfig> {
1334
- rules?: Partial<Rules> | undefined;
1335
- }
919
+ type HasRules<Rules extends RulesConfig = RulesConfig> =
920
+ CoreHasRules<Rules>;
1336
921
 
1337
922
  /**
1338
923
  * The ECMAScript version of the code being linted.
@@ -1342,99 +927,17 @@ export namespace Linter {
1342
927
  /**
1343
928
  * The type of JavaScript source code.
1344
929
  */
1345
- // TODO: Refactor to JavaScriptSourceType when exported from @eslint/core.
1346
- type SourceType = "script" | "module" | "commonjs";
930
+ type SourceType = JavaScriptSourceType;
1347
931
 
1348
932
  /**
1349
933
  * ESLint legacy configuration.
1350
934
  *
1351
935
  * @see [ESLint Legacy Configuration](https://eslint.org/docs/latest/use/configure/)
1352
936
  */
1353
- interface BaseConfig<
937
+ type BaseConfig<
1354
938
  Rules extends RulesConfig = RulesConfig,
1355
939
  OverrideRules extends RulesConfig = Rules,
1356
- > extends HasRules<Rules> {
1357
- $schema?: string | undefined;
1358
-
1359
- /**
1360
- * An environment provides predefined global variables.
1361
- *
1362
- * @see [Environments](https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-environments)
1363
- */
1364
- env?: { [name: string]: boolean } | undefined;
1365
-
1366
- /**
1367
- * Extending configuration files.
1368
- *
1369
- * @see [Extends](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated#extending-configuration-files)
1370
- */
1371
- extends?: string | string[] | undefined;
1372
-
1373
- /**
1374
- * Specifying globals.
1375
- *
1376
- * @see [Globals](https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-globals)
1377
- */
1378
- globals?: Linter.Globals | undefined;
1379
-
1380
- /**
1381
- * Disable processing of inline comments.
1382
- *
1383
- * @see [Disabling Inline Comments](https://eslint.org/docs/latest/use/configure/rules-deprecated#disabling-inline-comments)
1384
- */
1385
- noInlineConfig?: boolean | undefined;
1386
-
1387
- /**
1388
- * Overrides can be used to use a differing configuration for matching sub-directories and files.
1389
- *
1390
- * @see [How do overrides work](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated#how-do-overrides-work)
1391
- */
1392
- overrides?: Array<ConfigOverride<OverrideRules>> | undefined;
1393
-
1394
- /**
1395
- * Parser.
1396
- *
1397
- * @see [Working with Custom Parsers](https://eslint.org/docs/latest/extend/custom-parsers)
1398
- * @see [Specifying Parser](https://eslint.org/docs/latest/use/configure/parser-deprecated)
1399
- */
1400
- parser?: string | undefined;
1401
-
1402
- /**
1403
- * Parser options.
1404
- *
1405
- * @see [Working with Custom Parsers](https://eslint.org/docs/latest/extend/custom-parsers)
1406
- * @see [Specifying Parser Options](https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-parser-options)
1407
- */
1408
- parserOptions?: JavaScriptParserOptionsConfig | undefined;
1409
-
1410
- /**
1411
- * Which third-party plugins define additional rules, environments, configs, etc. for ESLint to use.
1412
- *
1413
- * @see [Configuring Plugins](https://eslint.org/docs/latest/use/configure/plugins-deprecated#configure-plugins)
1414
- */
1415
- plugins?: string[] | undefined;
1416
-
1417
- /**
1418
- * Specifying processor.
1419
- *
1420
- * @see [processor](https://eslint.org/docs/latest/use/configure/plugins-deprecated#specify-a-processor)
1421
- */
1422
- processor?: string | undefined;
1423
-
1424
- /**
1425
- * Report unused eslint-disable comments as warning.
1426
- *
1427
- * @see [Report unused eslint-disable comments](https://eslint.org/docs/latest/use/configure/rules-deprecated#report-unused-eslint-disable-comments)
1428
- */
1429
- reportUnusedDisableDirectives?: boolean | undefined;
1430
-
1431
- /**
1432
- * Settings.
1433
- *
1434
- * @see [Settings](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated#adding-shared-settings)
1435
- */
1436
- settings?: { [name: string]: any } | undefined;
1437
- }
940
+ > = CoreBaseConfig<Rules, OverrideRules>;
1438
941
 
1439
942
  /**
1440
943
  * The overwrites that apply more differing configuration to specific files or directories.
@@ -1477,18 +980,7 @@ export namespace Linter {
1477
980
  reportUnusedDisableDirectives?: boolean | undefined;
1478
981
  }
1479
982
 
1480
- // TODO: Once exported from @eslint/core, remove this and use that instead
1481
- interface LintSuggestion {
1482
- /** A short description. */
1483
- desc: string;
1484
-
1485
- /** Fix result info. */
1486
- fix: Rule.Fix;
1487
-
1488
- /** Id referencing a message for the description. */
1489
- messageId?: string | undefined;
1490
- }
1491
-
983
+ type LintSuggestion = CoreLintSuggestion;
1492
984
  type LintMessage = CoreLintMessage;
1493
985
 
1494
986
  interface LintSuppression {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "9.38.0",
3
+ "version": "9.39.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "type": "commonjs",
@@ -83,8 +83,9 @@
83
83
  "*": "trunk check --fix",
84
84
  "lib/rules/*.js": [
85
85
  "node tools/update-eslint-all.js",
86
+ "node tools/update-eslint-recommended.js",
86
87
  "node tools/update-rule-type-headers.js",
87
- "git add packages/js/src/configs/eslint-all.js lib/types/rules.d.ts"
88
+ "git add packages/js/src/configs/*.js lib/types/rules.d.ts"
88
89
  ],
89
90
  "docs/src/rules/*.md": [
90
91
  "node tools/check-rule-examples.js",
@@ -108,11 +109,11 @@
108
109
  "@eslint-community/eslint-utils": "^4.8.0",
109
110
  "@eslint-community/regexpp": "^4.12.1",
110
111
  "@eslint/config-array": "^0.21.1",
111
- "@eslint/config-helpers": "^0.4.1",
112
- "@eslint/core": "^0.16.0",
112
+ "@eslint/config-helpers": "^0.4.2",
113
+ "@eslint/core": "^0.17.0",
113
114
  "@eslint/eslintrc": "^3.3.1",
114
- "@eslint/js": "9.38.0",
115
- "@eslint/plugin-kit": "^0.4.0",
115
+ "@eslint/js": "9.39.0",
116
+ "@eslint/plugin-kit": "^0.4.1",
116
117
  "@humanfs/node": "^0.16.6",
117
118
  "@humanwhocodes/module-importer": "^1.0.1",
118
119
  "@humanwhocodes/retry": "^0.4.2",
@@ -145,7 +146,7 @@
145
146
  "@babel/core": "^7.4.3",
146
147
  "@babel/preset-env": "^7.4.3",
147
148
  "@cypress/webpack-preprocessor": "^6.0.2",
148
- "@eslint/json": "^0.13.0",
149
+ "@eslint/json": "^0.13.2",
149
150
  "@trunkio/launcher": "^1.3.4",
150
151
  "@types/esquery": "^1.5.4",
151
152
  "@types/node": "^22.13.14",