eslint 9.0.0-beta.2 → 9.0.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 (38) hide show
  1. package/README.md +8 -12
  2. package/bin/eslint.js +14 -1
  3. package/lib/cli.js +30 -11
  4. package/lib/config/flat-config-schema.js +1 -2
  5. package/lib/eslint/eslint-helpers.js +5 -1
  6. package/lib/eslint/eslint.js +16 -1
  7. package/lib/linter/code-path-analysis/code-path-analyzer.js +0 -1
  8. package/lib/linter/index.js +1 -3
  9. package/lib/linter/linter.js +184 -40
  10. package/lib/linter/timing.js +16 -8
  11. package/lib/options.js +25 -1
  12. package/lib/rule-tester/index.js +3 -1
  13. package/lib/rule-tester/rule-tester.js +18 -2
  14. package/lib/rules/camelcase.js +3 -5
  15. package/lib/rules/constructor-super.js +98 -99
  16. package/lib/rules/no-fallthrough.js +41 -16
  17. package/lib/rules/no-lone-blocks.js +1 -1
  18. package/lib/rules/no-this-before-super.js +28 -9
  19. package/lib/rules/no-unused-vars.js +179 -29
  20. package/lib/rules/no-useless-return.js +7 -2
  21. package/lib/rules/use-isnan.js +2 -2
  22. package/lib/rules/utils/lazy-loading-rule-map.js +1 -1
  23. package/lib/rules/utils/unicode/index.js +9 -4
  24. package/lib/shared/runtime-info.js +1 -0
  25. package/lib/shared/stats.js +30 -0
  26. package/lib/shared/types.js +34 -0
  27. package/lib/source-code/index.js +3 -1
  28. package/lib/source-code/source-code.js +165 -1
  29. package/lib/source-code/token-store/backward-token-cursor.js +3 -3
  30. package/lib/source-code/token-store/cursors.js +4 -2
  31. package/lib/source-code/token-store/forward-token-comment-cursor.js +3 -3
  32. package/lib/source-code/token-store/forward-token-cursor.js +3 -3
  33. package/messages/plugin-conflict.js +1 -1
  34. package/messages/plugin-invalid.js +1 -1
  35. package/messages/plugin-missing.js +1 -1
  36. package/package.json +12 -8
  37. package/lib/cli-engine/xml-escape.js +0 -34
  38. package/lib/shared/deprecation-warnings.js +0 -58
package/README.md CHANGED
@@ -59,15 +59,11 @@ After that, you can run ESLint on any file or directory like this:
59
59
 
60
60
  ## Configuration
61
61
 
62
- After running `npm init @eslint/config`, you'll have an `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
63
-
64
- ```json
65
- {
66
- "rules": {
67
- "semi": ["error", "always"],
68
- "quotes": ["error", "double"]
69
- }
70
- }
62
+ After running `npm init @eslint/config`, you'll have an `eslint.config.js` or `eslint.config.mjs` file in your directory. In it, you'll see some rules configured like this:
63
+
64
+ ```js
65
+ import pluginJs from "@eslint/js";
66
+ export default [ pluginJs.configs.recommended, ];
71
67
  ```
72
68
 
73
69
  The names `"semi"` and `"quotes"` are the names of [rules](https://eslint.org/docs/rules) in ESLint. The first value is the error level of the rule and can be one of these values:
@@ -303,10 +299,10 @@ The following companies, organizations, and individuals support ESLint's ongoing
303
299
  <!-- NOTE: This section is autogenerated. Do not manually edit.-->
304
300
  <!--sponsorsstart-->
305
301
  <h3>Platinum Sponsors</h3>
306
- <p><a href="#"><img src="https://images.opencollective.com/2021-frameworks-fund/logo.png" alt="Chrome Frameworks Fund" height="undefined"></a> <a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
307
- <p><a href="https://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a></p><h3>Silver Sponsors</h3>
302
+ <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
303
+ <p><a href="https://bitwarden.com"><img src="https://avatars.githubusercontent.com/u/15990069?v=4" alt="Bitwarden" height="96"></a> <a href="https://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a></p><h3>Silver Sponsors</h3>
308
304
  <p><a href="https://www.jetbrains.com/"><img src="https://images.opencollective.com/jetbrains/eb04ddc/logo.png" alt="JetBrains" 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?v=4" alt="American Express" height="64"></a> <a href="https://www.workleap.com"><img src="https://avatars.githubusercontent.com/u/53535748?u=d1e55d7661d724bf2281c1bfd33cb8f99fe2465f&v=4" alt="Workleap" height="64"></a></p><h3>Bronze Sponsors</h3>
309
- <p><a href="https://www.notion.so"><img src="https://images.opencollective.com/notion/bf3b117/logo.png" alt="notion" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" 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://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104?v=4" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://usenextbase.com"><img src="https://avatars.githubusercontent.com/u/145838380?v=4" alt="Nextbase Starter Kit" height="32"></a></p>
305
+ <p><a href="https://www.notion.so"><img src="https://images.opencollective.com/notion/bf3b117/logo.png" alt="notion" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" 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://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://nx.dev"><img src="https://avatars.githubusercontent.com/u/23692104?v=4" alt="Nx" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://usenextbase.com"><img src="https://avatars.githubusercontent.com/u/145838380?v=4" alt="Nextbase Starter Kit" height="32"></a></p>
310
306
  <!--sponsorsend-->
311
307
 
312
308
  ## Technology Sponsors
package/bin/eslint.js CHANGED
@@ -148,8 +148,21 @@ ${getErrorMessage(error)}`;
148
148
  return;
149
149
  }
150
150
 
151
+ // Call the config inspector if `--inspect-config` is present.
152
+ if (process.argv.includes("--inspect-config")) {
153
+
154
+ console.warn("You can also run this command directly using 'npx @eslint/config-inspector' in the same directory as your configuration file.");
155
+
156
+ const spawn = require("cross-spawn");
157
+
158
+ spawn.sync("npx", ["@eslint/config-inspector"], { encoding: "utf8", stdio: "inherit" });
159
+
160
+ return;
161
+ }
162
+
151
163
  // Otherwise, call the CLI.
152
- const exitCode = await require("../lib/cli").execute(
164
+ const cli = require("../lib/cli");
165
+ const exitCode = await cli.execute(
153
166
  process.argv,
154
167
  process.argv.includes("--stdin") ? await readStdin() : null,
155
168
  true
package/lib/cli.js CHANGED
@@ -37,6 +37,7 @@ const debug = require("debug")("eslint:cli");
37
37
  /** @typedef {import("./eslint/eslint").LintMessage} LintMessage */
38
38
  /** @typedef {import("./eslint/eslint").LintResult} LintResult */
39
39
  /** @typedef {import("./options").ParsedCLIOptions} ParsedCLIOptions */
40
+ /** @typedef {import("./shared/types").Plugin} Plugin */
40
41
  /** @typedef {import("./shared/types").ResultsMeta} ResultsMeta */
41
42
 
42
43
  //------------------------------------------------------------------------------
@@ -47,6 +48,32 @@ const mkdir = promisify(fs.mkdir);
47
48
  const stat = promisify(fs.stat);
48
49
  const writeFile = promisify(fs.writeFile);
49
50
 
51
+ /**
52
+ * Loads plugins with the specified names.
53
+ * @param {{ "import": (name: string) => Promise<any> }} importer An object with an `import` method called once for each plugin.
54
+ * @param {string[]} pluginNames The names of the plugins to be loaded, with or without the "eslint-plugin-" prefix.
55
+ * @returns {Promise<Record<string, Plugin>>} A mapping of plugin short names to implementations.
56
+ */
57
+ async function loadPlugins(importer, pluginNames) {
58
+ const plugins = {};
59
+
60
+ await Promise.all(pluginNames.map(async pluginName => {
61
+
62
+ const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
63
+ const module = await importer.import(longName);
64
+
65
+ if (!("default" in module)) {
66
+ throw new Error(`"${longName}" cannot be used with the \`--plugin\` option because its default module does not provide a \`default\` export`);
67
+ }
68
+
69
+ const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
70
+
71
+ plugins[shortName] = module.default;
72
+ }));
73
+
74
+ return plugins;
75
+ }
76
+
50
77
  /**
51
78
  * Predicate function for whether or not to apply fixes in quiet mode.
52
79
  * If a message is a warning, do not apply a fix.
@@ -104,6 +131,7 @@ async function translateOptions({
104
131
  resolvePluginsRelativeTo,
105
132
  rule,
106
133
  rulesdir,
134
+ stats,
107
135
  warnIgnored,
108
136
  passOnNoPatterns,
109
137
  maxWarnings
@@ -152,17 +180,7 @@ async function translateOptions({
152
180
  }
153
181
 
154
182
  if (plugin) {
155
- const plugins = {};
156
-
157
- for (const pluginName of plugin) {
158
-
159
- const shortName = naming.getShorthandName(pluginName, "eslint-plugin");
160
- const longName = naming.normalizePackageName(pluginName, "eslint-plugin");
161
-
162
- plugins[shortName] = await importer.import(longName);
163
- }
164
-
165
- overrideConfig[0].plugins = plugins;
183
+ overrideConfig[0].plugins = await loadPlugins(importer, plugin);
166
184
  }
167
185
 
168
186
  } else {
@@ -205,6 +223,7 @@ async function translateOptions({
205
223
 
206
224
  if (configType === "flat") {
207
225
  options.ignorePatterns = ignorePattern;
226
+ options.stats = stats;
208
227
  options.warnIgnored = warnIgnored;
209
228
 
210
229
  /*
@@ -588,6 +588,5 @@ const flatConfigSchema = {
588
588
 
589
589
  module.exports = {
590
590
  flatConfigSchema,
591
- assertIsRuleSeverity,
592
- assertIsRuleOptions
591
+ assertIsRuleSeverity
593
592
  };
@@ -685,6 +685,7 @@ function processOptions({
685
685
  overrideConfig = null,
686
686
  overrideConfigFile = null,
687
687
  plugins = {},
688
+ stats = false,
688
689
  warnIgnored = true,
689
690
  passOnNoPatterns = false,
690
691
  ruleFilter = () => true,
@@ -791,6 +792,9 @@ function processOptions({
791
792
  if (Array.isArray(plugins)) {
792
793
  errors.push("'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead.");
793
794
  }
795
+ if (typeof stats !== "boolean") {
796
+ errors.push("'stats' must be a boolean.");
797
+ }
794
798
  if (typeof warnIgnored !== "boolean") {
795
799
  errors.push("'warnIgnored' must be a boolean.");
796
800
  }
@@ -818,6 +822,7 @@ function processOptions({
818
822
  globInputPaths,
819
823
  ignore,
820
824
  ignorePatterns,
825
+ stats,
821
826
  passOnNoPatterns,
822
827
  warnIgnored,
823
828
  ruleFilter
@@ -907,7 +912,6 @@ function getCacheFile(cacheFile, cwd) {
907
912
  //-----------------------------------------------------------------------------
908
913
 
909
914
  module.exports = {
910
- isGlobPattern,
911
915
  findFiles,
912
916
 
913
917
  isNonEmptyString,
@@ -84,6 +84,7 @@ const LintResultCache = require("../cli-engine/lint-result-cache");
84
84
  * doesn't do any config file lookup when `true`; considered to be a config filename
85
85
  * when a string.
86
86
  * @property {Record<string,Plugin>} [plugins] An array of plugin implementations.
87
+ * @property {boolean} [stats] True enables added statistics on lint results.
87
88
  * @property {boolean} warnIgnored Show warnings when the file list includes ignored files
88
89
  * @property {boolean} [passOnNoPatterns=false] When set to true, missing patterns cause
89
90
  * the linting operation to short circuit and not report any failures.
@@ -465,6 +466,7 @@ async function calculateConfigArray(eslint, {
465
466
  * @param {boolean} config.fix If `true` then it does fix.
466
467
  * @param {boolean} config.allowInlineConfig If `true` then it uses directive comments.
467
468
  * @param {Function} config.ruleFilter A predicate function to filter which rules should be run.
469
+ * @param {boolean} config.stats If `true`, then if reports extra statistics with the lint results.
468
470
  * @param {Linter} config.linter The linter instance to verify.
469
471
  * @returns {LintResult} The result of linting.
470
472
  * @private
@@ -477,6 +479,7 @@ function verifyText({
477
479
  fix,
478
480
  allowInlineConfig,
479
481
  ruleFilter,
482
+ stats,
480
483
  linter
481
484
  }) {
482
485
  const filePath = providedFilePath || "<text>";
@@ -497,6 +500,7 @@ function verifyText({
497
500
  filename: filePathToVerify,
498
501
  fix,
499
502
  ruleFilter,
503
+ stats,
500
504
 
501
505
  /**
502
506
  * Check if the linter should adopt a given code block or not.
@@ -528,6 +532,13 @@ function verifyText({
528
532
  result.source = text;
529
533
  }
530
534
 
535
+ if (stats) {
536
+ result.stats = {
537
+ times: linter.getTimes(),
538
+ fixPasses: linter.getFixPassCount()
539
+ };
540
+ }
541
+
531
542
  return result;
532
543
  }
533
544
 
@@ -808,6 +819,7 @@ class ESLint {
808
819
  fix,
809
820
  fixTypes,
810
821
  ruleFilter,
822
+ stats,
811
823
  globInputPaths,
812
824
  errorOnUnmatchedPattern,
813
825
  warnIgnored
@@ -922,6 +934,7 @@ class ESLint {
922
934
  fix: fixer,
923
935
  allowInlineConfig,
924
936
  ruleFilter,
937
+ stats,
925
938
  linter
926
939
  });
927
940
 
@@ -1010,7 +1023,8 @@ class ESLint {
1010
1023
  cwd,
1011
1024
  fix,
1012
1025
  warnIgnored: constructorWarnIgnored,
1013
- ruleFilter
1026
+ ruleFilter,
1027
+ stats
1014
1028
  } = eslintOptions;
1015
1029
  const results = [];
1016
1030
  const startTime = Date.now();
@@ -1034,6 +1048,7 @@ class ESLint {
1034
1048
  fix,
1035
1049
  allowInlineConfig,
1036
1050
  ruleFilter,
1051
+ stats,
1037
1052
  linter
1038
1053
  }));
1039
1054
  }
@@ -222,7 +222,6 @@ function forwardCurrentToHead(analyzer, node) {
222
222
  : "onUnreachableCodePathSegmentStart";
223
223
 
224
224
  debug.dump(`${eventName} ${headSegment.id}`);
225
-
226
225
  CodePathSegment.markUsed(headSegment);
227
226
  analyzer.emitter.emit(
228
227
  eventName,
@@ -1,13 +1,11 @@
1
1
  "use strict";
2
2
 
3
3
  const { Linter } = require("./linter");
4
- const { interpolate } = require("./interpolate");
5
4
  const SourceCodeFixer = require("./source-code-fixer");
6
5
 
7
6
  module.exports = {
8
7
  Linter,
9
8
 
10
9
  // For testers.
11
- SourceCodeFixer,
12
- interpolate
10
+ SourceCodeFixer
13
11
  };