eslint 9.39.1 → 10.0.0-alpha.1

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 (64) hide show
  1. package/README.md +3 -3
  2. package/bin/eslint.js +1 -2
  3. package/lib/api.js +4 -15
  4. package/lib/cli.js +14 -56
  5. package/lib/config/config-loader.js +6 -154
  6. package/lib/eslint/eslint-helpers.js +5 -8
  7. package/lib/eslint/eslint.js +1 -1
  8. package/lib/eslint/index.js +0 -2
  9. package/lib/languages/js/source-code/source-code.js +66 -252
  10. package/lib/languages/js/source-code/token-store/index.js +0 -26
  11. package/lib/languages/js/source-code/token-store/utils.js +29 -8
  12. package/lib/linter/apply-disable-directives.js +0 -1
  13. package/lib/linter/file-context.js +0 -56
  14. package/lib/linter/file-report.js +0 -4
  15. package/lib/linter/linter.js +45 -1086
  16. package/lib/linter/rule-fixer.js +30 -0
  17. package/lib/options.js +62 -182
  18. package/lib/rule-tester/rule-tester.js +265 -194
  19. package/lib/rules/array-bracket-spacing.js +4 -4
  20. package/lib/rules/block-spacing.js +1 -1
  21. package/lib/rules/comma-spacing.js +2 -5
  22. package/lib/rules/computed-property-spacing.js +4 -4
  23. package/lib/rules/dot-notation.js +2 -2
  24. package/lib/rules/func-names.js +2 -0
  25. package/lib/rules/keyword-spacing.js +4 -4
  26. package/lib/rules/no-eval.js +1 -1
  27. package/lib/rules/no-extra-parens.js +1 -1
  28. package/lib/rules/no-invalid-regexp.js +1 -0
  29. package/lib/rules/no-shadow-restricted-names.js +1 -1
  30. package/lib/rules/no-spaced-func.js +1 -1
  31. package/lib/rules/no-unassigned-vars.js +1 -1
  32. package/lib/rules/no-useless-assignment.js +1 -1
  33. package/lib/rules/no-useless-constructor.js +13 -3
  34. package/lib/rules/no-whitespace-before-property.js +1 -1
  35. package/lib/rules/object-curly-spacing.js +2 -8
  36. package/lib/rules/preserve-caught-error.js +1 -1
  37. package/lib/rules/radix.js +25 -48
  38. package/lib/rules/require-yield.js +11 -1
  39. package/lib/rules/rest-spread-spacing.js +1 -4
  40. package/lib/rules/semi-spacing.js +2 -2
  41. package/lib/rules/space-before-blocks.js +1 -1
  42. package/lib/rules/space-before-function-paren.js +1 -4
  43. package/lib/rules/space-in-parens.js +4 -4
  44. package/lib/rules/space-infix-ops.js +4 -7
  45. package/lib/rules/switch-colon-spacing.js +1 -1
  46. package/lib/rules/template-tag-spacing.js +1 -1
  47. package/lib/rules/utils/ast-utils.js +114 -22
  48. package/lib/rules/yield-star-spacing.js +1 -2
  49. package/lib/services/parser-service.js +0 -1
  50. package/lib/services/processor-service.js +0 -1
  51. package/lib/services/warning-service.js +0 -11
  52. package/lib/shared/flags.js +0 -19
  53. package/lib/shared/translate-cli-options.js +106 -164
  54. package/lib/types/index.d.ts +7 -81
  55. package/lib/types/rules.d.ts +11 -2
  56. package/lib/types/use-at-your-own-risk.d.ts +1 -54
  57. package/lib/unsupported-api.js +3 -6
  58. package/package.json +15 -20
  59. package/conf/default-cli-options.js +0 -32
  60. package/lib/cli-engine/cli-engine.js +0 -1109
  61. package/lib/cli-engine/file-enumerator.js +0 -541
  62. package/lib/cli-engine/index.js +0 -7
  63. package/lib/cli-engine/load-rules.js +0 -46
  64. package/lib/eslint/legacy-eslint.js +0 -786
@@ -544,28 +544,6 @@ function negate(f) {
544
544
  return token => !f(token);
545
545
  }
546
546
 
547
- /**
548
- * Checks whether or not a node has a `@this` tag in its comments.
549
- * @param {ASTNode} node A node to check.
550
- * @param {SourceCode} sourceCode A SourceCode instance to get comments.
551
- * @returns {boolean} Whether or not the node has a `@this` tag in its comments.
552
- */
553
- function hasJSDocThisTag(node, sourceCode) {
554
- const jsdocComment = sourceCode.getJSDocComment(node);
555
-
556
- if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
557
- return true;
558
- }
559
-
560
- // Checks `@this` in its leading comments for callbacks,
561
- // because callbacks don't have its JSDoc comment.
562
- // e.g.
563
- // sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
564
- return sourceCode
565
- .getCommentsBefore(node)
566
- .some(comment => thisTagPattern.test(comment.value));
567
- }
568
-
569
547
  /**
570
548
  * Determines if a node is surrounded by parentheses.
571
549
  * @param {SourceCode} sourceCode The ESLint source code object
@@ -725,6 +703,120 @@ function isKeywordToken(token) {
725
703
  return token.type === "Keyword";
726
704
  }
727
705
 
706
+ /**
707
+ * Check to see if its a ES6 export declaration.
708
+ * @param {ASTNode} astNode An AST node.
709
+ * @returns {boolean} whether the given node represents an export declaration.
710
+ * @private
711
+ */
712
+ function looksLikeExport(astNode) {
713
+ return (
714
+ astNode.type === "ExportDefaultDeclaration" ||
715
+ astNode.type === "ExportNamedDeclaration" ||
716
+ astNode.type === "ExportAllDeclaration" ||
717
+ astNode.type === "ExportSpecifier"
718
+ );
719
+ }
720
+
721
+ /**
722
+ * Retrieves the JSDoc comment for a given node.
723
+ * @param {ASTNode} node The AST node to get the comment for.
724
+ * @param {SourceCode} sourceCode A SourceCode instance to get comments.
725
+ * @returns {Token|null} The Block comment token containing the JSDoc comment for the given node or null if not found.
726
+ * @private
727
+ */
728
+ function getJSDocComment(node, sourceCode) {
729
+ /**
730
+ * Checks for the presence of a JSDoc comment for the given node and returns it.
731
+ * @param {ASTNode} astNode The AST node to get the comment for.
732
+ * @returns {Token|null} The Block comment token containing the JSDoc comment for the given node or null if not found.
733
+ * @private
734
+ */
735
+ function findJSDocComment(astNode) {
736
+ const tokenBefore = sourceCode.getTokenBefore(astNode, {
737
+ includeComments: true,
738
+ });
739
+
740
+ if (
741
+ tokenBefore &&
742
+ isCommentToken(tokenBefore) &&
743
+ tokenBefore.type === "Block" &&
744
+ tokenBefore.value.charAt(0) === "*" &&
745
+ astNode.loc.start.line - tokenBefore.loc.end.line <= 1
746
+ ) {
747
+ return tokenBefore;
748
+ }
749
+
750
+ return null;
751
+ }
752
+ let parent = node.parent;
753
+
754
+ switch (node.type) {
755
+ case "ClassDeclaration":
756
+ case "FunctionDeclaration":
757
+ return findJSDocComment(looksLikeExport(parent) ? parent : node);
758
+
759
+ case "ClassExpression":
760
+ return findJSDocComment(parent.parent);
761
+
762
+ case "ArrowFunctionExpression":
763
+ case "FunctionExpression":
764
+ if (
765
+ parent.type !== "CallExpression" &&
766
+ parent.type !== "NewExpression"
767
+ ) {
768
+ while (
769
+ !sourceCode.getCommentsBefore(parent).length &&
770
+ !/Function/u.test(parent.type) &&
771
+ parent.type !== "MethodDefinition" &&
772
+ parent.type !== "Property"
773
+ ) {
774
+ parent = parent.parent;
775
+
776
+ if (!parent) {
777
+ break;
778
+ }
779
+ }
780
+
781
+ if (
782
+ parent &&
783
+ parent.type !== "FunctionDeclaration" &&
784
+ parent.type !== "Program"
785
+ ) {
786
+ return findJSDocComment(parent);
787
+ }
788
+ }
789
+
790
+ return findJSDocComment(node);
791
+
792
+ // falls through
793
+ default:
794
+ return null;
795
+ }
796
+ }
797
+
798
+ /**
799
+ * Checks whether or not a node has a `@this` tag in its comments.
800
+ * @param {ASTNode} node A node to check.
801
+ * @param {SourceCode} sourceCode A SourceCode instance to get comments.
802
+ * @returns {boolean} Whether or not the node has a `@this` tag in its comments.
803
+ */
804
+ function hasJSDocThisTag(node, sourceCode) {
805
+ const jsdocComment = getJSDocComment(node, sourceCode);
806
+
807
+ if (jsdocComment && thisTagPattern.test(jsdocComment.value)) {
808
+ return true;
809
+ }
810
+
811
+ // Checks `@this` in its leading comments for callbacks,
812
+ // because callbacks don't have its JSDoc comment.
813
+ // e.g.
814
+ // sinon.test(/* @this sinon.Sandbox */function() { this.spy(); });
815
+ return sourceCode
816
+ .getCommentsBefore(node)
817
+ .some(comment => thisTagPattern.test(comment.value));
818
+ }
819
+
728
820
  /**
729
821
  * Gets the `(` token of the given function node.
730
822
  * @param {ASTNode} node The function node to get.
@@ -96,8 +96,7 @@ module.exports = {
96
96
  */
97
97
  function checkSpacing(side, leftToken, rightToken) {
98
98
  if (
99
- sourceCode.isSpaceBetweenTokens(leftToken, rightToken) !==
100
- mode[side]
99
+ sourceCode.isSpaceBetween(leftToken, rightToken) !== mode[side]
101
100
  ) {
102
101
  const after = leftToken.value === "*";
103
102
  const spaceRequired = mode[side];
@@ -51,7 +51,6 @@ class ParserService {
51
51
  ok: false,
52
52
  errors: result.errors.map(error => ({
53
53
  ruleId: null,
54
- nodeType: null,
55
54
  fatal: true,
56
55
  severity: 2,
57
56
  message: `Parsing error: ${error.message}`,
@@ -57,7 +57,6 @@ class ProcessorService {
57
57
  message,
58
58
  line: ex.lineNumber,
59
59
  column: ex.column,
60
- nodeType: null,
61
60
  },
62
61
  ],
63
62
  };
@@ -59,17 +59,6 @@ class WarningService {
59
59
  );
60
60
  }
61
61
 
62
- /**
63
- * Emits a warning when the ESLINT_USE_FLAT_CONFIG environment variable is set to "false".
64
- * @returns {void}
65
- */
66
- emitESLintRCWarning() {
67
- this.emitWarning(
68
- "You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.",
69
- "ESLintRCWarning",
70
- );
71
- }
72
-
73
62
  /**
74
63
  * Emits a warning when an inactive flag is used.
75
64
  * This method is used by the Linter and is safe to call outside Node.js.
@@ -28,10 +28,6 @@
28
28
  const activeFlags = new Map([
29
29
  ["test_only", "Used only for testing."],
30
30
  ["test_only_2", "Used only for testing."],
31
- [
32
- "v10_config_lookup_from_file",
33
- "Look up `eslint.config.js` from the file being linted.",
34
- ],
35
31
  [
36
32
  "unstable_native_nodejs_ts_config",
37
33
  "Use native Node.js to load TypeScript configuration.",
@@ -66,21 +62,6 @@ const inactiveFlags = new Map([
66
62
  "Used only for testing flags whose features have been abandoned.",
67
63
  },
68
64
  ],
69
- [
70
- "unstable_ts_config",
71
- {
72
- description: "Enable TypeScript configuration files.",
73
- replacedBy: null,
74
- },
75
- ],
76
- [
77
- "unstable_config_lookup_from_file",
78
- {
79
- description:
80
- "Look up `eslint.config.js` from the file being linted.",
81
- replacedBy: "v10_config_lookup_from_file",
82
- },
83
- ],
84
65
  ]);
85
66
 
86
67
  /**
@@ -19,7 +19,6 @@ const { ModuleImporter } = require("@humanwhocodes/module-importer");
19
19
  //------------------------------------------------------------------------------
20
20
 
21
21
  /** @typedef {import("../types").ESLint.Options} ESLintOptions */
22
- /** @typedef {import("../types").ESLint.LegacyOptions} LegacyESLintOptions */
23
22
  /** @typedef {import("../types").Linter.LintMessage} LintMessage */
24
23
  /** @typedef {import("../options").ParsedCLIOptions} ParsedCLIOptions */
25
24
  /** @typedef {import("../types").ESLint.Plugin} Plugin */
@@ -85,196 +84,139 @@ function quietRuleFilter(rule) {
85
84
  /**
86
85
  * Translates the CLI options into the options expected by the ESLint constructor.
87
86
  * @param {ParsedCLIOptions} cliOptions The CLI options to translate.
88
- * @param {"flat"|"eslintrc"} [configType="eslintrc"] The format of the config to generate.
89
- * @returns {Promise<ESLintOptions | LegacyESLintOptions>} The options object for the ESLint constructor.
87
+ * @returns {Promise<ESLintOptions>} The options object for the ESLint constructor.
90
88
  */
91
- async function translateOptions(
92
- {
93
- cache,
94
- cacheFile,
95
- cacheLocation,
96
- cacheStrategy,
97
- concurrency,
98
- config,
99
- configLookup,
100
- env,
101
- errorOnUnmatchedPattern,
102
- eslintrc,
103
- ext,
104
- fix,
105
- fixDryRun,
106
- fixType,
107
- flag,
108
- global,
109
- ignore,
110
- ignorePath,
111
- ignorePattern,
112
- inlineConfig,
113
- parser,
114
- parserOptions,
115
- plugin,
116
- quiet,
117
- reportUnusedDisableDirectives,
118
- reportUnusedDisableDirectivesSeverity,
119
- reportUnusedInlineConfigs,
120
- resolvePluginsRelativeTo,
121
- rule,
122
- rulesdir,
123
- stats,
124
- warnIgnored,
125
- passOnNoPatterns,
126
- maxWarnings,
127
- },
128
- configType,
129
- ) {
130
- let overrideConfig, overrideConfigFile;
89
+ async function translateOptions({
90
+ cache,
91
+ cacheFile,
92
+ cacheLocation,
93
+ cacheStrategy,
94
+ concurrency,
95
+ config,
96
+ configLookup,
97
+ errorOnUnmatchedPattern,
98
+ ext,
99
+ fix,
100
+ fixDryRun,
101
+ fixType,
102
+ flag,
103
+ global,
104
+ ignore,
105
+ ignorePattern,
106
+ inlineConfig,
107
+ parser,
108
+ parserOptions,
109
+ plugin,
110
+ quiet,
111
+ reportUnusedDisableDirectives,
112
+ reportUnusedDisableDirectivesSeverity,
113
+ reportUnusedInlineConfigs,
114
+ rule,
115
+ stats,
116
+ warnIgnored,
117
+ passOnNoPatterns,
118
+ maxWarnings,
119
+ }) {
131
120
  const importer = new ModuleImporter();
132
121
 
133
- if (configType === "flat") {
134
- overrideConfigFile =
135
- typeof config === "string" ? config : !configLookup;
136
- if (overrideConfigFile === false) {
137
- overrideConfigFile = void 0;
138
- }
139
-
140
- const languageOptions = {};
141
-
142
- if (global) {
143
- languageOptions.globals = global.reduce((obj, name) => {
144
- if (name.endsWith(":true")) {
145
- obj[name.slice(0, -5)] = "writable";
146
- } else {
147
- obj[name] = "readonly";
148
- }
149
- return obj;
150
- }, {});
151
- }
122
+ let overrideConfigFile =
123
+ typeof config === "string" ? config : !configLookup;
124
+ if (overrideConfigFile === false) {
125
+ overrideConfigFile = void 0;
126
+ }
152
127
 
153
- if (parserOptions) {
154
- languageOptions.parserOptions = parserOptions;
155
- }
128
+ const languageOptions = {};
156
129
 
157
- if (parser) {
158
- languageOptions.parser = await importer.import(parser);
159
- }
130
+ if (global) {
131
+ languageOptions.globals = global.reduce((obj, name) => {
132
+ if (name.endsWith(":true")) {
133
+ obj[name.slice(0, -5)] = "writable";
134
+ } else {
135
+ obj[name] = "readonly";
136
+ }
137
+ return obj;
138
+ }, {});
139
+ }
160
140
 
161
- overrideConfig = [
162
- {
163
- ...(Object.keys(languageOptions).length > 0
164
- ? { languageOptions }
165
- : {}),
166
- rules: rule ? rule : {},
167
- },
168
- ];
141
+ if (parserOptions) {
142
+ languageOptions.parserOptions = parserOptions;
143
+ }
169
144
 
170
- if (
171
- reportUnusedDisableDirectives ||
172
- reportUnusedDisableDirectivesSeverity !== void 0
173
- ) {
174
- overrideConfig[0].linterOptions = {
175
- reportUnusedDisableDirectives: reportUnusedDisableDirectives
176
- ? "error"
177
- : normalizeSeverityToString(
178
- reportUnusedDisableDirectivesSeverity,
179
- ),
180
- };
181
- }
145
+ if (parser) {
146
+ languageOptions.parser = await importer.import(parser);
147
+ }
182
148
 
183
- if (reportUnusedInlineConfigs !== void 0) {
184
- overrideConfig[0].linterOptions = {
185
- ...overrideConfig[0].linterOptions,
186
- reportUnusedInlineConfigs: normalizeSeverityToString(
187
- reportUnusedInlineConfigs,
188
- ),
189
- };
190
- }
149
+ const overrideConfig = [
150
+ {
151
+ ...(Object.keys(languageOptions).length > 0
152
+ ? { languageOptions }
153
+ : {}),
154
+ rules: rule ? rule : {},
155
+ },
156
+ ];
157
+
158
+ if (
159
+ reportUnusedDisableDirectives ||
160
+ reportUnusedDisableDirectivesSeverity !== void 0
161
+ ) {
162
+ overrideConfig[0].linterOptions = {
163
+ reportUnusedDisableDirectives: reportUnusedDisableDirectives
164
+ ? "error"
165
+ : normalizeSeverityToString(
166
+ reportUnusedDisableDirectivesSeverity,
167
+ ),
168
+ };
169
+ }
191
170
 
192
- if (plugin) {
193
- overrideConfig[0].plugins = await loadPlugins(importer, plugin);
194
- }
171
+ if (reportUnusedInlineConfigs !== void 0) {
172
+ overrideConfig[0].linterOptions = {
173
+ ...overrideConfig[0].linterOptions,
174
+ reportUnusedInlineConfigs: normalizeSeverityToString(
175
+ reportUnusedInlineConfigs,
176
+ ),
177
+ };
178
+ }
195
179
 
196
- if (ext) {
197
- overrideConfig.push({
198
- files: ext.map(
199
- extension =>
200
- `**/*${extension.startsWith(".") ? "" : "."}${extension}`,
201
- ),
202
- });
203
- }
204
- } else {
205
- overrideConfigFile = config;
180
+ if (plugin) {
181
+ overrideConfig[0].plugins = await loadPlugins(importer, plugin);
182
+ }
206
183
 
207
- overrideConfig = {
208
- env:
209
- env &&
210
- env.reduce((obj, name) => {
211
- obj[name] = true;
212
- return obj;
213
- }, {}),
214
- globals:
215
- global &&
216
- global.reduce((obj, name) => {
217
- if (name.endsWith(":true")) {
218
- obj[name.slice(0, -5)] = "writable";
219
- } else {
220
- obj[name] = "readonly";
221
- }
222
- return obj;
223
- }, {}),
224
- ignorePatterns: ignorePattern,
225
- parser,
226
- parserOptions,
227
- plugins: plugin,
228
- rules: rule,
229
- };
184
+ if (ext) {
185
+ overrideConfig.push({
186
+ files: ext.map(
187
+ extension =>
188
+ `**/*${extension.startsWith(".") ? "" : "."}${extension}`,
189
+ ),
190
+ });
230
191
  }
231
192
 
193
+ /*
194
+ * For performance reasons rules not marked as 'error' are filtered out in quiet mode. As maxWarnings
195
+ * requires rules set to 'warn' to be run, we only filter out 'warn' rules if maxWarnings is not specified.
196
+ */
197
+ const ruleFilter =
198
+ quiet && maxWarnings === -1 ? quietRuleFilter : () => true;
199
+
232
200
  const options = {
233
201
  allowInlineConfig: inlineConfig,
234
202
  cache,
235
203
  cacheLocation: cacheLocation || cacheFile,
236
204
  cacheStrategy,
205
+ concurrency,
237
206
  errorOnUnmatchedPattern,
238
207
  fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
239
208
  fixTypes: fixType,
209
+ flags: flag,
240
210
  ignore,
211
+ ignorePatterns: ignorePattern,
241
212
  overrideConfig,
242
213
  overrideConfigFile,
243
214
  passOnNoPatterns,
215
+ ruleFilter,
216
+ stats,
217
+ warnIgnored,
244
218
  };
245
219
 
246
- if (configType === "flat") {
247
- options.concurrency = concurrency;
248
- options.flags = flag;
249
- options.ignorePatterns = ignorePattern;
250
- options.stats = stats;
251
- options.warnIgnored = warnIgnored;
252
-
253
- /*
254
- * For performance reasons rules not marked as 'error' are filtered out in quiet mode. As maxWarnings
255
- * requires rules set to 'warn' to be run, we only filter out 'warn' rules if maxWarnings is not specified.
256
- */
257
- options.ruleFilter =
258
- quiet && maxWarnings === -1 ? quietRuleFilter : () => true;
259
- } else {
260
- options.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
261
- options.rulePaths = rulesdir;
262
- options.useEslintrc = eslintrc;
263
- options.extensions = ext;
264
- options.ignorePath = ignorePath;
265
- if (
266
- reportUnusedDisableDirectives ||
267
- reportUnusedDisableDirectivesSeverity !== void 0
268
- ) {
269
- options.reportUnusedDisableDirectives =
270
- reportUnusedDisableDirectives
271
- ? "error"
272
- : normalizeSeverityToString(
273
- reportUnusedDisableDirectivesSeverity,
274
- );
275
- }
276
- }
277
-
278
220
  return options;
279
221
  }
280
222