eslint 10.3.0 → 10.4.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.
Files changed (45) hide show
  1. package/README.md +3 -3
  2. package/lib/config-api.js +7 -1
  3. package/lib/eslint/eslint.js +29 -6
  4. package/lib/linter/code-path-analysis/debug-helpers.js +12 -1
  5. package/lib/rules/capitalized-comments.js +3 -1
  6. package/lib/rules/class-methods-use-this.js +1 -2
  7. package/lib/rules/default-param-last.js +1 -2
  8. package/lib/rules/eqeqeq.js +3 -1
  9. package/lib/rules/for-direction.js +55 -11
  10. package/lib/rules/func-name-matching.js +2 -0
  11. package/lib/rules/func-style.js +1 -2
  12. package/lib/rules/init-declarations.js +7 -8
  13. package/lib/rules/logical-assignment-operators.js +4 -1
  14. package/lib/rules/max-classes-per-file.js +4 -2
  15. package/lib/rules/max-depth.js +3 -0
  16. package/lib/rules/max-lines-per-function.js +3 -0
  17. package/lib/rules/max-lines.js +3 -0
  18. package/lib/rules/max-nested-callbacks.js +3 -0
  19. package/lib/rules/max-params.js +4 -2
  20. package/lib/rules/max-statements.js +3 -0
  21. package/lib/rules/no-array-constructor.js +1 -2
  22. package/lib/rules/no-dupe-class-members.js +1 -2
  23. package/lib/rules/no-duplicate-imports.js +1 -2
  24. package/lib/rules/no-empty-function.js +1 -2
  25. package/lib/rules/no-invalid-this.js +1 -2
  26. package/lib/rules/no-loop-func.js +1 -2
  27. package/lib/rules/no-loss-of-precision.js +1 -2
  28. package/lib/rules/no-magic-numbers.js +29 -24
  29. package/lib/rules/no-restricted-exports.js +8 -8
  30. package/lib/rules/no-restricted-globals.js +1 -2
  31. package/lib/rules/no-restricted-imports.js +1 -2
  32. package/lib/rules/no-restricted-properties.js +2 -0
  33. package/lib/rules/no-restricted-syntax.js +2 -0
  34. package/lib/rules/no-shadow.js +1 -2
  35. package/lib/rules/no-unassigned-vars.js +1 -2
  36. package/lib/rules/no-unused-expressions.js +1 -2
  37. package/lib/rules/no-unused-vars.js +50 -53
  38. package/lib/rules/no-use-before-define.js +1 -2
  39. package/lib/rules/no-useless-constructor.js +1 -2
  40. package/lib/rules/no-var.js +1 -2
  41. package/lib/rules/object-shorthand.js +3 -1
  42. package/lib/rules/one-var.js +3 -1
  43. package/lib/rules/prefer-arrow-callback.js +1 -2
  44. package/lib/types/config-api.d.ts +2 -1
  45. package/package.json +3 -4
package/README.md CHANGED
@@ -315,8 +315,8 @@ Tanuj Kanti
315
315
  </a>
316
316
  </td><td align="center" valign="top" width="11%">
317
317
  <a href="https://github.com/lumirlumir">
318
- <img src="https://github.com/lumirlumir.png?s=75" width="75" height="75" alt="루밀LuMir's Avatar"><br />
319
- 루밀LuMir
318
+ <img src="https://github.com/lumirlumir.png?s=75" width="75" height="75" alt="lumir's Avatar"><br />
319
+ lumir
320
320
  </a>
321
321
  </td><td align="center" valign="top" width="11%">
322
322
  <a href="https://github.com/Pixel998">
@@ -360,7 +360,7 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
360
360
  <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="128"></a></p><h3>Gold Sponsors</h3>
361
361
  <p><a href="https://qlty.sh/"><img src="https://images.opencollective.com/qltysh/33d157d/logo.png" alt="Qlty Software" height="96"></a></p><h3>Silver Sponsors</h3>
362
362
  <p><a href="https://vite.dev/"><img src="https://images.opencollective.com/vite/d472863/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://stackblitz.com"><img src="https://avatars.githubusercontent.com/u/28635252" alt="StackBlitz" height="64"></a></p><h3>Bronze Sponsors</h3>
363
- <p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://opensource.sap.com"><img src="https://avatars.githubusercontent.com/u/2531208" alt="SAP" height="32"></a> <a href="https://www.crawljobs.com/"><img src="https://images.opencollective.com/crawljobs-poland/fa43a17/logo.png" alt="CrawlJobs" height="32"></a> <a href="https://depot.dev"><img src="https://images.opencollective.com/depot/39125a1/logo.png" alt="Depot" 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://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://citadel.co.jp"><img src="https://avatars.githubusercontent.com/u/75781367" alt="Citadel AI" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="TestMu AI Open Source Office (Formerly LambdaTest)" height="32"></a></p>
363
+ <p><a href="https://cybozu.co.jp/"><img src="https://images.opencollective.com/cybozu/933e46d/logo.png" alt="Cybozu" height="32"></a> <a href="https://opensource.sap.com"><img src="https://avatars.githubusercontent.com/u/2531208" alt="SAP" height="32"></a> <a href="https://www.crawljobs.com/"><img src="https://images.opencollective.com/crawljobs-poland/fa43a17/logo.png" alt="CrawlJobs" height="32"></a> <a href="https://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://depot.dev"><img src="https://images.opencollective.com/depot/39125a1/logo.png" alt="Depot" 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://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774" alt="HeroCoders" height="32"></a> <a href="https://citadel.co.jp"><img src="https://avatars.githubusercontent.com/u/75781367" alt="Citadel AI" height="32"></a> <a href="https://www.lambdatest.com"><img src="https://avatars.githubusercontent.com/u/171592363" alt="TestMu AI Open Source Office (Formerly LambdaTest)" height="32"></a></p>
364
364
  <h3>Technology Sponsors</h3>
365
365
  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.
366
366
  <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>
package/lib/config-api.js CHANGED
@@ -4,9 +4,15 @@
4
4
  */
5
5
 
6
6
  "use strict";
7
- const { defineConfig, globalIgnores } = require("@eslint/config-helpers");
7
+
8
+ const {
9
+ defineConfig,
10
+ globalIgnores,
11
+ includeIgnoreFile,
12
+ } = require("@eslint/config-helpers");
8
13
 
9
14
  module.exports = {
10
15
  defineConfig,
11
16
  globalIgnores,
17
+ includeIgnoreFile,
12
18
  };
@@ -107,6 +107,34 @@ function createRulesMeta(rules) {
107
107
  }, {});
108
108
  }
109
109
 
110
+ /**
111
+ * Gets the replacement rule names from a deprecated rule's metadata.
112
+ * @param {RulesMeta} meta The rule metadata.
113
+ * @returns {string[]} Replacement rule names.
114
+ */
115
+ function getDeprecatedRuleReplacements(meta) {
116
+ if (typeof meta.deprecated !== "object") {
117
+ return meta.replacedBy || [];
118
+ }
119
+
120
+ const { replacedBy } = meta.deprecated;
121
+
122
+ if (!Array.isArray(replacedBy)) {
123
+ return [];
124
+ }
125
+
126
+ return replacedBy.map(replacement => {
127
+ if (typeof replacement !== "object" || replacement === null) {
128
+ return "";
129
+ }
130
+
131
+ const pluginName = replacement.plugin?.name;
132
+ const ruleName = replacement.rule?.name;
133
+
134
+ return `${typeof pluginName === "string" ? `${getShorthandName(pluginName, "eslint-plugin")}/` : ""}${typeof ruleName === "string" ? ruleName : ""}`;
135
+ });
136
+ }
137
+
110
138
  /** @type {WeakMap<CalculatedConfig, DeprecatedRuleInfo[]>} */
111
139
  const usedDeprecatedRulesCache = new WeakMap();
112
140
 
@@ -144,12 +172,7 @@ function getOrFindUsedDeprecatedRules(eslint, maybeFilePath) {
144
172
 
145
173
  retv.push({
146
174
  ruleId,
147
- replacedBy: usesNewFormat
148
- ? (meta.deprecated.replacedBy?.map(
149
- replacement =>
150
- `${replacement.plugin?.name !== void 0 ? `${getShorthandName(replacement.plugin.name, "eslint-plugin")}/` : ""}${replacement.rule?.name ?? ""}`,
151
- ) ?? [])
152
- : meta.replacedBy || [],
175
+ replacedBy: getDeprecatedRuleReplacements(meta),
153
176
  info: usesNewFormat ? meta.deprecated : void 0,
154
177
  });
155
178
  }
@@ -45,6 +45,15 @@ function nodeToString(node, label) {
45
45
  }
46
46
  }
47
47
 
48
+ /**
49
+ * Escape text for use in a DOT label.
50
+ * @param {string} value The value to escape.
51
+ * @returns {string} The escaped value.
52
+ */
53
+ function escapeDotLabelText(value) {
54
+ return value.replace(/\\/gu, String.raw`\\`).replace(/"/gu, String.raw`\"`);
55
+ }
56
+
48
57
  //------------------------------------------------------------------------------
49
58
  // Public Interface
50
59
  //------------------------------------------------------------------------------
@@ -147,7 +156,9 @@ module.exports = {
147
156
  }
148
157
 
149
158
  if (segment.internal.nodes.length > 0) {
150
- text += segment.internal.nodes.join("\\n");
159
+ text += segment.internal.nodes
160
+ .map(escapeDotLabelText)
161
+ .join("\\n");
151
162
  } else {
152
163
  text += "????";
153
164
  }
@@ -131,6 +131,8 @@ module.exports = {
131
131
  },
132
132
  ],
133
133
 
134
+ defaultOptions: ["always"],
135
+
134
136
  messages: {
135
137
  unexpectedLowercaseComment:
136
138
  "Comments should not begin with a lowercase character.",
@@ -140,7 +142,7 @@ module.exports = {
140
142
  },
141
143
 
142
144
  create(context) {
143
- const capitalize = context.options[0] || "always",
145
+ const capitalize = context.options[0],
144
146
  normalizedOptions = getAllNormalizedOptions(context.options[1]),
145
147
  sourceCode = context.sourceCode;
146
148
 
@@ -18,8 +18,6 @@ const astUtils = require("./utils/ast-utils");
18
18
  /** @type {import('../types').Rule.RuleModule} */
19
19
  module.exports = {
20
20
  meta: {
21
- dialects: ["javascript", "typescript"],
22
- language: "javascript",
23
21
  type: "suggestion",
24
22
 
25
23
  defaultOptions: [
@@ -32,6 +30,7 @@ module.exports = {
32
30
 
33
31
  docs: {
34
32
  description: "Enforce that class methods utilize `this`",
33
+ dialects: ["JavaScript", "TypeScript"],
35
34
  recommended: false,
36
35
  url: "https://eslint.org/docs/latest/rules/class-methods-use-this",
37
36
  },
@@ -21,12 +21,11 @@ function isRequiredParameter(node) {
21
21
  /** @type {import('../types').Rule.RuleModule} */
22
22
  module.exports = {
23
23
  meta: {
24
- dialects: ["javascript", "typescript"],
25
- language: "javascript",
26
24
  type: "suggestion",
27
25
 
28
26
  docs: {
29
27
  description: "Enforce default parameters to be last",
28
+ dialects: ["JavaScript", "TypeScript"],
30
29
  recommended: false,
31
30
  frozen: true,
32
31
  url: "https://eslint.org/docs/latest/rules/default-param-last",
@@ -59,6 +59,8 @@ module.exports = {
59
59
  ],
60
60
  },
61
61
 
62
+ defaultOptions: ["always"],
63
+
62
64
  fixable: "code",
63
65
 
64
66
  messages: {
@@ -70,7 +72,7 @@ module.exports = {
70
72
  },
71
73
 
72
74
  create(context) {
73
- const config = context.options[0] || "always";
75
+ const config = context.options[0];
74
76
  const options = context.options[1] || {};
75
77
  const sourceCode = context.sourceCode;
76
78
 
@@ -117,6 +117,50 @@ module.exports = {
117
117
  }
118
118
  return 0;
119
119
  }
120
+ /**
121
+ * Collects all expressions that modify the counter.
122
+ * @param {ASTNode} node The expression node to check.
123
+ * @param {string} counter The name of the counter variable.
124
+ * @returns {ASTNode[]} An array of modifying expressions.
125
+ */
126
+ function getModifyingExpressions(node, counter) {
127
+ if (node.type === "SequenceExpression") {
128
+ return node.expressions.flatMap(expr =>
129
+ getModifyingExpressions(expr, counter),
130
+ );
131
+ }
132
+ if (
133
+ node.type === "UpdateExpression" &&
134
+ node.argument.type === "Identifier" &&
135
+ node.argument.name === counter
136
+ ) {
137
+ return [node];
138
+ }
139
+ if (
140
+ node.type === "AssignmentExpression" &&
141
+ node.left.type === "Identifier" &&
142
+ node.left.name === counter
143
+ ) {
144
+ return [node];
145
+ }
146
+ return [];
147
+ }
148
+
149
+ /**
150
+ * Determines the direction of a single update expression for the counter.
151
+ * @param {ASTNode} expr An expression node to check (UpdateExpression or AssignmentExpression).
152
+ * @param {string} counter The variable name of the counter.
153
+ * @returns {number} 1 if incrementing, -1 if decrementing, 0 if unknown or not modifying the counter.
154
+ */
155
+ function getDirectionFromExpression(expr, counter) {
156
+ if (expr.type === "UpdateExpression") {
157
+ return getUpdateDirection(expr, counter);
158
+ }
159
+ if (expr.type === "AssignmentExpression") {
160
+ return getAssignmentDirection(expr, counter);
161
+ }
162
+ return 0;
163
+ }
120
164
 
121
165
  return {
122
166
  ForStatement(node) {
@@ -146,17 +190,17 @@ module.exports = {
146
190
  return;
147
191
  }
148
192
 
149
- if (update.type === "UpdateExpression") {
150
- if (
151
- getUpdateDirection(update, counter) ===
152
- wrongDirection
153
- ) {
154
- report(node);
155
- }
156
- } else if (
157
- update.type === "AssignmentExpression" &&
158
- getAssignmentDirection(update, counter) ===
159
- wrongDirection
193
+ const mutatingExpressions = getModifyingExpressions(
194
+ update,
195
+ counter,
196
+ );
197
+
198
+ if (
199
+ mutatingExpressions.length === 1 &&
200
+ getDirectionFromExpression(
201
+ mutatingExpressions[0],
202
+ counter,
203
+ ) === wrongDirection
160
204
  ) {
161
205
  report(node);
162
206
  }
@@ -105,6 +105,8 @@ module.exports = {
105
105
  ],
106
106
  },
107
107
 
108
+ defaultOptions: ["always"],
109
+
108
110
  messages: {
109
111
  matchProperty:
110
112
  "Function name `{{funcName}}` should match property name `{{name}}`.",
@@ -11,8 +11,6 @@
11
11
  /** @type {import('../types').Rule.RuleModule} */
12
12
  module.exports = {
13
13
  meta: {
14
- dialects: ["javascript", "typescript"],
15
- language: "javascript",
16
14
  type: "suggestion",
17
15
 
18
16
  defaultOptions: [
@@ -27,6 +25,7 @@ module.exports = {
27
25
  docs: {
28
26
  description:
29
27
  "Enforce the consistent use of either `function` declarations or expressions assigned to variables",
28
+ dialects: ["JavaScript", "TypeScript"],
30
29
  recommended: false,
31
30
  frozen: true,
32
31
  url: "https://eslint.org/docs/latest/rules/func-style",
@@ -50,12 +50,11 @@ function isInitialized(node) {
50
50
  module.exports = {
51
51
  meta: {
52
52
  type: "suggestion",
53
- dialects: ["typescript", "javascript"],
54
- language: "javascript",
55
53
 
56
54
  docs: {
57
55
  description:
58
56
  "Require or disallow initialization in variable declarations",
57
+ dialects: ["JavaScript", "TypeScript"],
59
58
  recommended: false,
60
59
  frozen: true,
61
60
  url: "https://eslint.org/docs/latest/rules/init-declarations",
@@ -94,6 +93,9 @@ module.exports = {
94
93
  },
95
94
  ],
96
95
  },
96
+
97
+ defaultOptions: ["always"],
98
+
97
99
  messages: {
98
100
  initialized:
99
101
  "Variable '{{idName}}' should be initialized on declaration.",
@@ -103,10 +105,7 @@ module.exports = {
103
105
  },
104
106
 
105
107
  create(context) {
106
- const MODE_ALWAYS = "always",
107
- MODE_NEVER = "never";
108
-
109
- const mode = context.options[0] || MODE_ALWAYS;
108
+ const mode = context.options[0];
110
109
  const params = context.options[1] || {};
111
110
 
112
111
  // Track whether we're inside a declared namespace
@@ -145,10 +144,10 @@ module.exports = {
145
144
  params.ignoreForLoopInit && isForLoop(node.parent);
146
145
  let messageId = "";
147
146
 
148
- if (mode === MODE_ALWAYS && !initialized) {
147
+ if (mode === "always" && !initialized) {
149
148
  messageId = "initialized";
150
149
  } else if (
151
- mode === MODE_NEVER &&
150
+ mode === "never" &&
152
151
  !CONSTANT_BINDINGS.has(kind) &&
153
152
  initialized &&
154
153
  !isIgnoredForLoop
@@ -259,6 +259,9 @@ module.exports = {
259
259
  },
260
260
  ],
261
261
  },
262
+
263
+ defaultOptions: ["always"],
264
+
262
265
  fixable: "code",
263
266
  hasSuggestions: true,
264
267
  messages: {
@@ -281,7 +284,7 @@ module.exports = {
281
284
  },
282
285
 
283
286
  create(context) {
284
- const mode = context.options[0] === "never" ? "never" : "always";
287
+ const mode = context.options[0];
285
288
  const checkIf =
286
289
  mode === "always" &&
287
290
  context.options.length > 1 &&
@@ -47,16 +47,18 @@ module.exports = {
47
47
  },
48
48
  ],
49
49
 
50
+ defaultOptions: [1],
51
+
50
52
  messages: {
51
53
  maximumExceeded:
52
54
  "File has too many classes ({{ classCount }}). Maximum allowed is {{ max }}.",
53
55
  },
54
56
  },
55
57
  create(context) {
56
- const [option = {}] = context.options;
58
+ const option = context.options[0];
57
59
  const [ignoreExpressions, max] =
58
60
  typeof option === "number"
59
- ? [false, option || 1]
61
+ ? [false, option]
60
62
  : [option.ignoreExpressions, option.max || 1];
61
63
 
62
64
  let classCount = 0;
@@ -44,6 +44,9 @@ module.exports = {
44
44
  ],
45
45
  },
46
46
  ],
47
+
48
+ defaultOptions: [4],
49
+
47
50
  messages: {
48
51
  tooDeeply:
49
52
  "Blocks are nested too deeply ({{depth}}). Maximum allowed is {{maxDepth}}.",
@@ -78,6 +78,9 @@ module.exports = {
78
78
  },
79
79
 
80
80
  schema: [OPTIONS_OR_INTEGER_SCHEMA],
81
+
82
+ defaultOptions: [50],
83
+
81
84
  messages: {
82
85
  exceed: "{{name}} has too many lines ({{lineCount}}). Maximum allowed is {{maxLines}}.",
83
86
  },
@@ -65,6 +65,9 @@ module.exports = {
65
65
  ],
66
66
  },
67
67
  ],
68
+
69
+ defaultOptions: [300],
70
+
68
71
  messages: {
69
72
  exceed: "File has too many lines ({{actual}}). Maximum allowed is {{max}}.",
70
73
  },
@@ -44,6 +44,9 @@ module.exports = {
44
44
  ],
45
45
  },
46
46
  ],
47
+
48
+ defaultOptions: [10],
49
+
47
50
  messages: {
48
51
  exceed: "Too many nested callbacks ({{num}}). Maximum allowed is {{max}}.",
49
52
  },
@@ -20,12 +20,11 @@ const { upperCaseFirst } = require("../shared/string-utils");
20
20
  module.exports = {
21
21
  meta: {
22
22
  type: "suggestion",
23
- dialects: ["typescript", "javascript"],
24
- language: "javascript",
25
23
 
26
24
  docs: {
27
25
  description:
28
26
  "Enforce a maximum number of parameters in function definitions",
27
+ dialects: ["JavaScript", "TypeScript"],
29
28
  recommended: false,
30
29
  url: "https://eslint.org/docs/latest/rules/max-params",
31
30
  },
@@ -65,6 +64,9 @@ module.exports = {
65
64
  ],
66
65
  },
67
66
  ],
67
+
68
+ defaultOptions: [3],
69
+
68
70
  messages: {
69
71
  exceed: "{{name}} has too many parameters ({{count}}). Maximum allowed is {{max}}.",
70
72
  },
@@ -61,6 +61,9 @@ module.exports = {
61
61
  additionalProperties: false,
62
62
  },
63
63
  ],
64
+
65
+ defaultOptions: [10],
66
+
64
67
  messages: {
65
68
  exceed: "{{name}} has too many statements ({{count}}). Maximum allowed is {{max}}.",
66
69
  },
@@ -24,12 +24,11 @@ const {
24
24
  /** @type {import('../types').Rule.RuleModule} */
25
25
  module.exports = {
26
26
  meta: {
27
- dialects: ["javascript", "typescript"],
28
- language: "javascript",
29
27
  type: "suggestion",
30
28
 
31
29
  docs: {
32
30
  description: "Disallow `Array` constructors",
31
+ dialects: ["JavaScript", "TypeScript"],
33
32
  recommended: false,
34
33
  url: "https://eslint.org/docs/latest/rules/no-array-constructor",
35
34
  },
@@ -15,11 +15,10 @@ const astUtils = require("./utils/ast-utils");
15
15
  module.exports = {
16
16
  meta: {
17
17
  type: "problem",
18
- dialects: ["javascript", "typescript"],
19
- language: "javascript",
20
18
 
21
19
  docs: {
22
20
  description: "Disallow duplicate class members",
21
+ dialects: ["JavaScript", "TypeScript"],
23
22
  recommended: true,
24
23
  url: "https://eslint.org/docs/latest/rules/no-dupe-class-members",
25
24
  },
@@ -294,8 +294,6 @@ function handleImportsExports(
294
294
  /** @type {import('../types').Rule.RuleModule} */
295
295
  module.exports = {
296
296
  meta: {
297
- dialects: ["javascript", "typescript"],
298
- language: "javascript",
299
297
  type: "problem",
300
298
 
301
299
  defaultOptions: [
@@ -307,6 +305,7 @@ module.exports = {
307
305
 
308
306
  docs: {
309
307
  description: "Disallow duplicate module imports",
308
+ dialects: ["JavaScript", "TypeScript"],
310
309
  recommended: false,
311
310
  url: "https://eslint.org/docs/latest/rules/no-duplicate-imports",
312
311
  },
@@ -103,8 +103,6 @@ function isParameterPropertiesConstructor(node) {
103
103
  /** @type {import('../types').Rule.RuleModule} */
104
104
  module.exports = {
105
105
  meta: {
106
- dialects: ["javascript", "typescript"],
107
- language: "javascript",
108
106
  hasSuggestions: true,
109
107
  type: "suggestion",
110
108
 
@@ -112,6 +110,7 @@ module.exports = {
112
110
 
113
111
  docs: {
114
112
  description: "Disallow empty functions",
113
+ dialects: ["JavaScript", "TypeScript"],
115
114
  recommended: false,
116
115
  url: "https://eslint.org/docs/latest/rules/no-empty-function",
117
116
  },
@@ -36,8 +36,6 @@ function isCodePathWithLexicalThis(codePath, node) {
36
36
  /** @type {import('../types').Rule.RuleModule} */
37
37
  module.exports = {
38
38
  meta: {
39
- dialects: ["javascript", "typescript"],
40
- language: "javascript",
41
39
  type: "suggestion",
42
40
 
43
41
  defaultOptions: [{ capIsConstructor: true }],
@@ -45,6 +43,7 @@ module.exports = {
45
43
  docs: {
46
44
  description:
47
45
  "Disallow use of `this` in contexts where the value of `this` is `undefined`",
46
+ dialects: ["JavaScript", "TypeScript"],
48
47
  recommended: false,
49
48
  url: "https://eslint.org/docs/latest/rules/no-invalid-this",
50
49
  },
@@ -40,12 +40,11 @@ function isIIFE(node) {
40
40
  module.exports = {
41
41
  meta: {
42
42
  type: "suggestion",
43
- dialects: ["typescript", "javascript"],
44
- language: "javascript",
45
43
 
46
44
  docs: {
47
45
  description:
48
46
  "Disallow function declarations that contain unsafe references inside loop statements",
47
+ dialects: ["JavaScript", "TypeScript"],
49
48
  recommended: false,
50
49
  url: "https://eslint.org/docs/latest/rules/no-loop-func",
51
50
  },
@@ -219,11 +219,10 @@ function losesPrecision(node) {
219
219
  module.exports = {
220
220
  meta: {
221
221
  type: "problem",
222
- dialects: ["typescript", "javascript"],
223
- language: "javascript",
224
222
 
225
223
  docs: {
226
224
  description: "Disallow literal numbers that lose precision",
225
+ dialects: ["JavaScript", "TypeScript"],
227
226
  recommended: true,
228
227
  url: "https://eslint.org/docs/latest/rules/no-loss-of-precision",
229
228
  },
@@ -91,11 +91,10 @@ function isAncestorTSIndexedAccessType(node) {
91
91
  module.exports = {
92
92
  meta: {
93
93
  type: "suggestion",
94
- dialects: ["typescript", "javascript"],
95
- language: "javascript",
96
94
 
97
95
  docs: {
98
96
  description: "Disallow magic numbers",
97
+ dialects: ["JavaScript", "TypeScript"],
99
98
  recommended: false,
100
99
  frozen: true,
101
100
  url: "https://eslint.org/docs/latest/rules/no-magic-numbers",
@@ -107,11 +106,9 @@ module.exports = {
107
106
  properties: {
108
107
  detectObjects: {
109
108
  type: "boolean",
110
- default: false,
111
109
  },
112
110
  enforceConst: {
113
111
  type: "boolean",
114
- default: false,
115
112
  },
116
113
  ignore: {
117
114
  type: "array",
@@ -128,37 +125,45 @@ module.exports = {
128
125
  },
129
126
  ignoreArrayIndexes: {
130
127
  type: "boolean",
131
- default: false,
132
128
  },
133
129
  ignoreDefaultValues: {
134
130
  type: "boolean",
135
- default: false,
136
131
  },
137
132
  ignoreClassFieldInitialValues: {
138
133
  type: "boolean",
139
- default: false,
140
134
  },
141
135
  ignoreEnums: {
142
136
  type: "boolean",
143
- default: false,
144
137
  },
145
138
  ignoreNumericLiteralTypes: {
146
139
  type: "boolean",
147
- default: false,
148
140
  },
149
141
  ignoreReadonlyClassProperties: {
150
142
  type: "boolean",
151
- default: false,
152
143
  },
153
144
  ignoreTypeIndexes: {
154
145
  type: "boolean",
155
- default: false,
156
146
  },
157
147
  },
158
148
  additionalProperties: false,
159
149
  },
160
150
  ],
161
151
 
152
+ defaultOptions: [
153
+ {
154
+ detectObjects: false,
155
+ enforceConst: false,
156
+ ignore: [],
157
+ ignoreArrayIndexes: false,
158
+ ignoreDefaultValues: false,
159
+ ignoreClassFieldInitialValues: false,
160
+ ignoreEnums: false,
161
+ ignoreNumericLiteralTypes: false,
162
+ ignoreReadonlyClassProperties: false,
163
+ ignoreTypeIndexes: false,
164
+ },
165
+ ],
166
+
162
167
  messages: {
163
168
  useConst: "Number constants declarations must use 'const'.",
164
169
  noMagic: "No magic number: {{raw}}.",
@@ -166,19 +171,19 @@ module.exports = {
166
171
  },
167
172
 
168
173
  create(context) {
169
- const config = context.options[0] || {},
170
- detectObjects = !!config.detectObjects,
171
- enforceConst = !!config.enforceConst,
172
- ignore = new Set((config.ignore || []).map(normalizeIgnoreValue)),
173
- ignoreArrayIndexes = !!config.ignoreArrayIndexes,
174
- ignoreDefaultValues = !!config.ignoreDefaultValues,
175
- ignoreClassFieldInitialValues =
176
- !!config.ignoreClassFieldInitialValues,
177
- ignoreEnums = !!config.ignoreEnums,
178
- ignoreNumericLiteralTypes = !!config.ignoreNumericLiteralTypes,
179
- ignoreReadonlyClassProperties =
180
- !!config.ignoreReadonlyClassProperties,
181
- ignoreTypeIndexes = !!config.ignoreTypeIndexes;
174
+ const {
175
+ detectObjects,
176
+ enforceConst,
177
+ ignore: rawIgnore,
178
+ ignoreArrayIndexes,
179
+ ignoreDefaultValues,
180
+ ignoreClassFieldInitialValues,
181
+ ignoreEnums,
182
+ ignoreNumericLiteralTypes,
183
+ ignoreReadonlyClassProperties,
184
+ ignoreTypeIndexes,
185
+ } = context.options[0];
186
+ const ignore = new Set(rawIgnore.map(normalizeIgnoreValue));
182
187
 
183
188
  const okTypes = detectObjects
184
189
  ? []
@@ -92,6 +92,8 @@ module.exports = {
92
92
  },
93
93
  ],
94
94
 
95
+ defaultOptions: [{}],
96
+
95
97
  messages: {
96
98
  restrictedNamed:
97
99
  "'{{name}}' is restricted from being used as an exported name.",
@@ -100,14 +102,12 @@ module.exports = {
100
102
  },
101
103
 
102
104
  create(context) {
103
- const restrictedNames = new Set(
104
- context.options[0] && context.options[0].restrictedNamedExports,
105
- );
106
- const restrictedNamePattern =
107
- context.options[0] &&
108
- context.options[0].restrictedNamedExportsPattern;
109
- const restrictDefaultExports =
110
- context.options[0] && context.options[0].restrictDefaultExports;
105
+ const {
106
+ restrictedNamedExports,
107
+ restrictedNamedExportsPattern: restrictedNamePattern,
108
+ restrictDefaultExports,
109
+ } = context.options[0];
110
+ const restrictedNames = new Set(restrictedNamedExports);
111
111
  const sourceCode = context.sourceCode;
112
112
 
113
113
  /**
@@ -53,12 +53,11 @@ const arrayOfGlobals = {
53
53
  /** @type {import('../types').Rule.RuleModule} */
54
54
  module.exports = {
55
55
  meta: {
56
- dialects: ["javascript", "typescript"],
57
- language: "javascript",
58
56
  type: "suggestion",
59
57
 
60
58
  docs: {
61
59
  description: "Disallow specified global variables",
60
+ dialects: ["JavaScript", "TypeScript"],
62
61
  recommended: false,
63
62
  url: "https://eslint.org/docs/latest/rules/no-restricted-globals",
64
63
  },
@@ -171,11 +171,10 @@ const arrayOfStringsOrObjectPatterns = {
171
171
  module.exports = {
172
172
  meta: {
173
173
  type: "suggestion",
174
- dialects: ["typescript", "javascript"],
175
- language: "javascript",
176
174
 
177
175
  docs: {
178
176
  description: "Disallow specified modules when loaded by `import`",
177
+ dialects: ["JavaScript", "TypeScript"],
179
178
  recommended: false,
180
179
  url: "https://eslint.org/docs/latest/rules/no-restricted-imports",
181
180
  },
@@ -70,6 +70,8 @@ module.exports = {
70
70
  uniqueItems: true,
71
71
  },
72
72
 
73
+ defaultOptions: [],
74
+
73
75
  messages: {
74
76
  restrictedObjectProperty:
75
77
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
@@ -41,6 +41,8 @@ module.exports = {
41
41
  minItems: 0,
42
42
  },
43
43
 
44
+ defaultOptions: [],
45
+
44
46
  messages: {
45
47
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
46
48
  restrictedSyntax: "{{message}}",
@@ -55,8 +55,6 @@ const ALLOWED_FUNCTION_VARIABLE_DEF_TYPES = new Set([
55
55
  module.exports = {
56
56
  meta: {
57
57
  type: "suggestion",
58
- dialects: ["typescript", "javascript"],
59
- language: "javascript",
60
58
 
61
59
  defaultOptions: [
62
60
  {
@@ -72,6 +70,7 @@ module.exports = {
72
70
  docs: {
73
71
  description:
74
72
  "Disallow variable declarations from shadowing variables declared in the outer scope",
73
+ dialects: ["JavaScript", "TypeScript"],
75
74
  recommended: false,
76
75
  url: "https://eslint.org/docs/latest/rules/no-shadow",
77
76
  },
@@ -12,12 +12,11 @@
12
12
  module.exports = {
13
13
  meta: {
14
14
  type: "problem",
15
- dialects: ["typescript", "javascript"],
16
- language: "javascript",
17
15
 
18
16
  docs: {
19
17
  description:
20
18
  "Disallow `let` or `var` variables that are read but never assigned",
19
+ dialects: ["JavaScript", "TypeScript"],
21
20
  recommended: true,
22
21
  url: "https://eslint.org/docs/latest/rules/no-unassigned-vars",
23
22
  },
@@ -29,12 +29,11 @@ function alwaysFalse() {
29
29
  /** @type {import('../types').Rule.RuleModule} */
30
30
  module.exports = {
31
31
  meta: {
32
- dialects: ["javascript", "typescript"],
33
- language: "javascript",
34
32
  type: "suggestion",
35
33
 
36
34
  docs: {
37
35
  description: "Disallow unused expressions",
36
+ dialects: ["JavaScript", "TypeScript"],
38
37
  recommended: false,
39
38
  url: "https://eslint.org/docs/latest/rules/no-unused-expressions",
40
39
  },
@@ -42,6 +42,20 @@ const astUtils = require("./utils/ast-utils");
42
42
  * @property {string} additional Any additional info to be appended at the end.
43
43
  */
44
44
 
45
+ //------------------------------------------------------------------------------
46
+ // Helpers
47
+ //------------------------------------------------------------------------------
48
+
49
+ const DEFAULT_OPTIONS = {
50
+ vars: "all",
51
+ args: "after-used",
52
+ ignoreRestSiblings: false,
53
+ caughtErrors: "all",
54
+ ignoreClassWithStaticInitBlock: false,
55
+ ignoreUsingDeclarations: false,
56
+ reportUsedIgnorePattern: false,
57
+ };
58
+
45
59
  //------------------------------------------------------------------------------
46
60
  // Rule Definition
47
61
  //------------------------------------------------------------------------------
@@ -108,6 +122,8 @@ module.exports = {
108
122
  },
109
123
  ],
110
124
 
125
+ defaultOptions: [DEFAULT_OPTIONS],
126
+
111
127
  messages: {
112
128
  unusedVar:
113
129
  "'{{varName}}' is {{action}} but never used{{additional}}.",
@@ -123,65 +139,46 @@ module.exports = {
123
139
  const REST_PROPERTY_TYPE =
124
140
  /^(?:RestElement|(?:Experimental)?RestProperty)$/u;
125
141
 
126
- const config = {
127
- vars: "all",
128
- args: "after-used",
129
- ignoreRestSiblings: false,
130
- caughtErrors: "all",
131
- ignoreClassWithStaticInitBlock: false,
132
- ignoreUsingDeclarations: false,
133
- reportUsedIgnorePattern: false,
134
- };
142
+ let config;
135
143
 
136
144
  const firstOption = context.options[0];
137
145
 
138
- if (firstOption) {
139
- if (typeof firstOption === "string") {
140
- config.vars = firstOption;
141
- } else {
142
- config.vars = firstOption.vars || config.vars;
143
- config.args = firstOption.args || config.args;
144
- config.ignoreRestSiblings =
145
- firstOption.ignoreRestSiblings || config.ignoreRestSiblings;
146
- config.caughtErrors =
147
- firstOption.caughtErrors || config.caughtErrors;
148
- config.ignoreClassWithStaticInitBlock =
149
- firstOption.ignoreClassWithStaticInitBlock ||
150
- config.ignoreClassWithStaticInitBlock;
151
- config.ignoreUsingDeclarations =
152
- firstOption.ignoreUsingDeclarations ||
153
- config.ignoreUsingDeclarations;
154
- config.reportUsedIgnorePattern =
155
- firstOption.reportUsedIgnorePattern ||
156
- config.reportUsedIgnorePattern;
157
-
158
- if (firstOption.varsIgnorePattern) {
159
- config.varsIgnorePattern = new RegExp(
160
- firstOption.varsIgnorePattern,
161
- "u",
162
- );
163
- }
146
+ if (typeof firstOption === "string") {
147
+ config = {
148
+ ...DEFAULT_OPTIONS,
149
+ vars: firstOption,
150
+ };
151
+ } else {
152
+ config = {
153
+ ...firstOption,
154
+ };
164
155
 
165
- if (firstOption.argsIgnorePattern) {
166
- config.argsIgnorePattern = new RegExp(
167
- firstOption.argsIgnorePattern,
168
- "u",
169
- );
170
- }
156
+ if (firstOption.varsIgnorePattern) {
157
+ config.varsIgnorePattern = new RegExp(
158
+ firstOption.varsIgnorePattern,
159
+ "u",
160
+ );
161
+ }
171
162
 
172
- if (firstOption.caughtErrorsIgnorePattern) {
173
- config.caughtErrorsIgnorePattern = new RegExp(
174
- firstOption.caughtErrorsIgnorePattern,
175
- "u",
176
- );
177
- }
163
+ if (firstOption.argsIgnorePattern) {
164
+ config.argsIgnorePattern = new RegExp(
165
+ firstOption.argsIgnorePattern,
166
+ "u",
167
+ );
168
+ }
178
169
 
179
- if (firstOption.destructuredArrayIgnorePattern) {
180
- config.destructuredArrayIgnorePattern = new RegExp(
181
- firstOption.destructuredArrayIgnorePattern,
182
- "u",
183
- );
184
- }
170
+ if (firstOption.caughtErrorsIgnorePattern) {
171
+ config.caughtErrorsIgnorePattern = new RegExp(
172
+ firstOption.caughtErrorsIgnorePattern,
173
+ "u",
174
+ );
175
+ }
176
+
177
+ if (firstOption.destructuredArrayIgnorePattern) {
178
+ config.destructuredArrayIgnorePattern = new RegExp(
179
+ firstOption.destructuredArrayIgnorePattern,
180
+ "u",
181
+ );
185
182
  }
186
183
  }
187
184
 
@@ -276,13 +276,12 @@ function isClassRefInClassDecorator(variable, reference) {
276
276
  /** @type {import('../types').Rule.RuleModule} */
277
277
  module.exports = {
278
278
  meta: {
279
- dialects: ["javascript", "typescript"],
280
- language: "javascript",
281
279
  type: "problem",
282
280
 
283
281
  docs: {
284
282
  description:
285
283
  "Disallow the use of variables before they are defined",
284
+ dialects: ["JavaScript", "TypeScript"],
286
285
  recommended: false,
287
286
  url: "https://eslint.org/docs/latest/rules/no-use-before-define",
288
287
  },
@@ -164,12 +164,11 @@ function isRedundantSuperCall(body, ctorParams) {
164
164
  /** @type {import('../types').Rule.RuleModule} */
165
165
  module.exports = {
166
166
  meta: {
167
- dialects: ["javascript", "typescript"],
168
- language: "javascript",
169
167
  type: "suggestion",
170
168
 
171
169
  docs: {
172
170
  description: "Disallow unnecessary constructors",
171
+ dialects: ["JavaScript", "TypeScript"],
173
172
  recommended: false,
174
173
  url: "https://eslint.org/docs/latest/rules/no-useless-constructor",
175
174
  },
@@ -229,11 +229,10 @@ function hasReferenceBeforeDeclaration(variable) {
229
229
  module.exports = {
230
230
  meta: {
231
231
  type: "suggestion",
232
- dialects: ["typescript", "javascript"],
233
- language: "javascript",
234
232
 
235
233
  docs: {
236
234
  description: "Require `let` or `const` instead of `var`",
235
+ dialects: ["JavaScript", "TypeScript"],
237
236
  recommended: false,
238
237
  url: "https://eslint.org/docs/latest/rules/no-var",
239
238
  },
@@ -186,6 +186,8 @@ module.exports = {
186
186
  ],
187
187
  },
188
188
 
189
+ defaultOptions: ["always"],
190
+
189
191
  messages: {
190
192
  expectedAllPropertiesShorthanded:
191
193
  "Expected shorthand for all properties.",
@@ -201,7 +203,7 @@ module.exports = {
201
203
  },
202
204
 
203
205
  create(context) {
204
- const APPLY = context.options[0] || OPTIONS.always;
206
+ const APPLY = context.options[0];
205
207
  const APPLY_TO_METHODS =
206
208
  APPLY === OPTIONS.methods || APPLY === OPTIONS.always;
207
209
  const APPLY_TO_PROPS =
@@ -89,6 +89,8 @@ module.exports = {
89
89
  },
90
90
  ],
91
91
 
92
+ defaultOptions: ["always"],
93
+
92
94
  messages: {
93
95
  combineUninitialized:
94
96
  "Combine this with the previous '{{type}}' statement with uninitialized variables.",
@@ -109,7 +111,7 @@ module.exports = {
109
111
  const MODE_ALWAYS = "always";
110
112
  const MODE_NEVER = "never";
111
113
  const MODE_CONSECUTIVE = "consecutive";
112
- const mode = context.options[0] || MODE_ALWAYS;
114
+ const mode = context.options[0];
113
115
 
114
116
  const options = {};
115
117
 
@@ -158,8 +158,6 @@ function hasDuplicateParams(paramsList) {
158
158
  module.exports = {
159
159
  meta: {
160
160
  type: "suggestion",
161
- dialects: ["javascript", "typescript"],
162
- language: "javascript",
163
161
 
164
162
  defaultOptions: [
165
163
  { allowNamedFunctions: false, allowUnboundThis: true },
@@ -167,6 +165,7 @@ module.exports = {
167
165
 
168
166
  docs: {
169
167
  description: "Require using arrow functions for callbacks",
168
+ dialects: ["JavaScript", "TypeScript"],
170
169
  recommended: false,
171
170
  frozen: true,
172
171
  url: "https://eslint.org/docs/latest/rules/prefer-arrow-callback",
@@ -7,6 +7,7 @@ import {
7
7
  type Config,
8
8
  defineConfig,
9
9
  globalIgnores,
10
+ includeIgnoreFile,
10
11
  } from "@eslint/config-helpers";
11
12
 
12
- export { type Config, defineConfig, globalIgnores };
13
+ export { type Config, defineConfig, globalIgnores, includeIgnoreFile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "10.3.0",
3
+ "version": "10.4.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",
@@ -122,7 +122,7 @@
122
122
  "@eslint-community/eslint-utils": "^4.8.0",
123
123
  "@eslint-community/regexpp": "^4.12.2",
124
124
  "@eslint/config-array": "^0.23.5",
125
- "@eslint/config-helpers": "^0.5.5",
125
+ "@eslint/config-helpers": "^0.6.0",
126
126
  "@eslint/core": "^1.2.1",
127
127
  "@eslint/plugin-kit": "^0.7.1",
128
128
  "@humanfs/node": "^0.16.6",
@@ -183,7 +183,7 @@
183
183
  "got": "^11.8.3",
184
184
  "gray-matter": "^4.0.3",
185
185
  "jiti": "^2.6.1",
186
- "knip": "^5.60.2",
186
+ "knip": "^6.13.1",
187
187
  "lint-staged": "^11.0.0",
188
188
  "markdown-it": "^12.2.0",
189
189
  "markdown-it-container": "^3.0.0",
@@ -201,7 +201,6 @@
201
201
  "prettier": "3.8.3",
202
202
  "progress": "^2.0.3",
203
203
  "proxyquire": "^2.0.1",
204
- "recast": "^0.23.0",
205
204
  "regenerator-runtime": "^0.14.0",
206
205
  "semver": "^7.5.3",
207
206
  "shelljs": "^0.10.0",