eslint 9.14.0 → 9.15.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 (98) hide show
  1. package/README.md +1 -1
  2. package/lib/cli-engine/formatters/stylish.js +3 -3
  3. package/lib/cli-engine/lint-result-cache.js +1 -1
  4. package/lib/config/config.js +40 -24
  5. package/lib/eslint/eslint-helpers.js +9 -13
  6. package/lib/languages/js/index.js +76 -0
  7. package/lib/languages/js/source-code/token-store/index.js +1 -1
  8. package/lib/linter/code-path-analysis/code-path-analyzer.js +1 -1
  9. package/lib/linter/code-path-analysis/fork-context.js +1 -1
  10. package/lib/linter/linter.js +36 -35
  11. package/lib/linter/report-translator.js +1 -1
  12. package/lib/rule-tester/rule-tester.js +1 -1
  13. package/lib/rules/accessor-pairs.js +10 -7
  14. package/lib/rules/array-callback-return.js +10 -8
  15. package/lib/rules/arrow-body-style.js +3 -1
  16. package/lib/rules/camelcase.js +18 -12
  17. package/lib/rules/class-methods-use-this.js +9 -5
  18. package/lib/rules/complexity.js +9 -5
  19. package/lib/rules/consistent-return.js +4 -4
  20. package/lib/rules/consistent-this.js +3 -7
  21. package/lib/rules/curly.js +3 -140
  22. package/lib/rules/default-case.js +3 -1
  23. package/lib/rules/dot-notation.js +9 -6
  24. package/lib/rules/func-names.js +3 -3
  25. package/lib/rules/func-style.js +10 -8
  26. package/lib/rules/getter-return.js +5 -5
  27. package/lib/rules/grouped-accessor-pairs.js +3 -1
  28. package/lib/rules/id-denylist.js +2 -1
  29. package/lib/rules/id-length.js +10 -6
  30. package/lib/rules/id-match.js +13 -16
  31. package/lib/rules/new-cap.js +15 -34
  32. package/lib/rules/no-bitwise.js +4 -5
  33. package/lib/rules/no-cond-assign.js +3 -3
  34. package/lib/rules/no-console.js +3 -2
  35. package/lib/rules/no-constant-condition.js +5 -4
  36. package/lib/rules/no-duplicate-imports.js +5 -4
  37. package/lib/rules/no-else-return.js +4 -5
  38. package/lib/rules/no-empty-function.js +4 -4
  39. package/lib/rules/no-empty-pattern.js +4 -4
  40. package/lib/rules/no-empty.js +6 -5
  41. package/lib/rules/no-eval.js +4 -5
  42. package/lib/rules/no-extend-native.js +3 -3
  43. package/lib/rules/no-extra-boolean-cast.js +3 -3
  44. package/lib/rules/no-fallthrough.js +12 -15
  45. package/lib/rules/no-global-assign.js +3 -2
  46. package/lib/rules/no-implicit-coercion.js +13 -24
  47. package/lib/rules/no-implicit-globals.js +4 -4
  48. package/lib/rules/no-inline-comments.js +4 -6
  49. package/lib/rules/no-inner-declarations.js +4 -2
  50. package/lib/rules/no-invalid-regexp.js +5 -4
  51. package/lib/rules/no-invalid-this.js +4 -4
  52. package/lib/rules/no-irregular-whitespace.js +24 -22
  53. package/lib/rules/no-labels.js +8 -7
  54. package/lib/rules/no-lonely-if.js +8 -2
  55. package/lib/rules/no-multi-assign.js +5 -10
  56. package/lib/rules/no-plusplus.js +4 -9
  57. package/lib/rules/no-promise-executor-return.js +4 -6
  58. package/lib/rules/no-redeclare.js +5 -8
  59. package/lib/rules/no-return-assign.js +3 -1
  60. package/lib/rules/no-self-assign.js +4 -3
  61. package/lib/rules/no-sequences.js +7 -7
  62. package/lib/rules/no-shadow.js +18 -14
  63. package/lib/rules/no-undef.js +4 -4
  64. package/lib/rules/no-underscore-dangle.js +31 -28
  65. package/lib/rules/no-unneeded-ternary.js +4 -4
  66. package/lib/rules/no-unreachable-loop.js +4 -2
  67. package/lib/rules/no-unsafe-negation.js +4 -4
  68. package/lib/rules/no-unsafe-optional-chaining.js +4 -4
  69. package/lib/rules/no-unused-expressions.js +17 -13
  70. package/lib/rules/no-use-before-define.js +14 -13
  71. package/lib/rules/no-useless-computed-key.js +9 -3
  72. package/lib/rules/no-useless-rename.js +7 -8
  73. package/lib/rules/no-void.js +4 -4
  74. package/lib/rules/no-warning-comments.js +9 -7
  75. package/lib/rules/operator-assignment.js +4 -2
  76. package/lib/rules/prefer-arrow-callback.js +5 -8
  77. package/lib/rules/prefer-const.js +5 -3
  78. package/lib/rules/prefer-promise-reject-errors.js +5 -3
  79. package/lib/rules/prefer-regex-literals.js +4 -3
  80. package/lib/rules/radix.js +3 -1
  81. package/lib/rules/require-atomic-updates.js +4 -3
  82. package/lib/rules/sort-imports.js +20 -16
  83. package/lib/rules/sort-keys.js +13 -16
  84. package/lib/rules/sort-vars.js +4 -4
  85. package/lib/rules/strict.js +3 -2
  86. package/lib/rules/unicode-bom.js +4 -2
  87. package/lib/rules/use-isnan.js +7 -4
  88. package/lib/rules/utils/ast-utils.js +141 -0
  89. package/lib/rules/valid-typeof.js +3 -2
  90. package/lib/rules/yoda.js +9 -12
  91. package/lib/shared/assert.js +22 -0
  92. package/lib/shared/deep-merge-arrays.js +60 -0
  93. package/lib/shared/text-table.js +67 -0
  94. package/lib/shared/types.js +1 -0
  95. package/lib/types/index.d.ts +3 -0
  96. package/lib/types/rules/ecmascript-6.d.ts +36 -16
  97. package/lib/types/rules/stylistic-issues.d.ts +3 -0
  98. package/package.json +10 -11
package/README.md CHANGED
@@ -300,7 +300,7 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
300
300
  <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>
301
301
  <p><a href="https://trunk.io/"><img src="https://images.opencollective.com/trunkio/fb92d60/avatar.png" alt="trunk.io" height="96"></a></p><h3>Silver Sponsors</h3>
302
302
  <p><a href="https://www.serptriumph.com/"><img src="https://images.opencollective.com/serp-triumph5/fea3074/logo.png" alt="SERP Triumph" height="64"></a> <a href="https://www.jetbrains.com/"><img src="https://images.opencollective.com/jetbrains/fe76f99/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>
303
- <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://www.wordhint.net/"><img src="https://images.opencollective.com/wordhint/be86813/avatar.png" alt="WordHint" 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://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340?v=4" alt="GitBook" 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></p>
303
+ <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://syntax.fm"><img src="https://github.com/syntaxfm.png" alt="Syntax" height="32"></a> <a href="https://www.wordhint.net/"><img src="https://images.opencollective.com/wordhint/be86813/avatar.png" alt="WordHint" 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://www.gitbook.com"><img src="https://avatars.githubusercontent.com/u/7111340?v=4" alt="GitBook" 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></p>
304
304
  <h3>Technology Sponsors</h3>
305
305
  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.
306
306
  <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>
@@ -6,7 +6,7 @@
6
6
 
7
7
  const chalk = require("chalk"),
8
8
  util = require("node:util"),
9
- table = require("text-table");
9
+ table = require("../../shared/text-table");
10
10
 
11
11
  //------------------------------------------------------------------------------
12
12
  // Helpers
@@ -62,8 +62,8 @@ module.exports = function(results) {
62
62
 
63
63
  return [
64
64
  "",
65
- message.line || 0,
66
- message.column || 0,
65
+ String(message.line || 0),
66
+ String(message.column || 0),
67
67
  messageType,
68
68
  message.message.replace(/([^ ])\.$/u, "$1"),
69
69
  chalk.dim(message.ruleId || "")
@@ -8,11 +8,11 @@
8
8
  // Requirements
9
9
  //-----------------------------------------------------------------------------
10
10
 
11
- const assert = require("node:assert");
12
11
  const fs = require("node:fs");
13
12
  const fileEntryCache = require("file-entry-cache");
14
13
  const stringify = require("json-stable-stringify-without-jsonify");
15
14
  const pkg = require("../../package.json");
15
+ const assert = require("../shared/assert");
16
16
  const hash = require("./hash");
17
17
 
18
18
  const debug = require("debug")("eslint:lint-result-cache");
@@ -9,8 +9,10 @@
9
9
  // Requirements
10
10
  //-----------------------------------------------------------------------------
11
11
 
12
- const { RuleValidator } = require("./rule-validator");
12
+ const { deepMergeArrays } = require("../shared/deep-merge-arrays");
13
+ const { getRuleFromConfig } = require("./flat-config-helpers");
13
14
  const { flatConfigSchema, hasMethod } = require("./flat-config-schema");
15
+ const { RuleValidator } = require("./rule-validator");
14
16
  const { ObjectSchema } = require("@eslint/config-array");
15
17
 
16
18
  //-----------------------------------------------------------------------------
@@ -119,28 +121,6 @@ function languageOptionsToJSON(languageOptions, objectKey = "languageOptions") {
119
121
  return result;
120
122
  }
121
123
 
122
- /**
123
- * Normalizes the rules configuration. Ensure that each rule config is
124
- * an array and that the severity is a number. This function modifies the
125
- * rulesConfig.
126
- * @param {Record<string, any>} rulesConfig The rules configuration to normalize.
127
- * @returns {void}
128
- */
129
- function normalizeRulesConfig(rulesConfig) {
130
-
131
- for (const [ruleId, ruleConfig] of Object.entries(rulesConfig)) {
132
-
133
- // ensure rule config is an array
134
- if (!Array.isArray(ruleConfig)) {
135
- rulesConfig[ruleId] = [ruleConfig];
136
- }
137
-
138
- // normalize severity
139
- rulesConfig[ruleId][0] = severities.get(rulesConfig[ruleId][0]);
140
- }
141
-
142
- }
143
-
144
124
 
145
125
  //-----------------------------------------------------------------------------
146
126
  // Exports
@@ -215,6 +195,11 @@ class Config {
215
195
  throw new TypeError(`Key "languageOptions": ${error.message}`, { cause: error });
216
196
  }
217
197
 
198
+ // Normalize language options if necessary
199
+ if (this.language.normalizeLanguageOptions) {
200
+ this.languageOptions = this.language.normalizeLanguageOptions(this.languageOptions);
201
+ }
202
+
218
203
  // Check processor value
219
204
  if (processor) {
220
205
  this.processor = processor;
@@ -239,7 +224,7 @@ class Config {
239
224
 
240
225
  // Process the rules
241
226
  if (this.rules) {
242
- normalizeRulesConfig(this.rules);
227
+ this.#normalizeRulesConfig();
243
228
  ruleValidator.validate(this);
244
229
  }
245
230
  }
@@ -276,6 +261,37 @@ class Config {
276
261
  processor: this.#processorName
277
262
  };
278
263
  }
264
+
265
+ /**
266
+ * Normalizes the rules configuration. Ensures that each rule config is
267
+ * an array and that the severity is a number. Applies meta.defaultOptions.
268
+ * This function modifies `this.rules`.
269
+ * @returns {void}
270
+ */
271
+ #normalizeRulesConfig() {
272
+ for (const [ruleId, originalConfig] of Object.entries(this.rules)) {
273
+
274
+ // ensure rule config is an array
275
+ let ruleConfig = Array.isArray(originalConfig)
276
+ ? originalConfig
277
+ : [originalConfig];
278
+
279
+ // normalize severity
280
+ ruleConfig[0] = severities.get(ruleConfig[0]);
281
+
282
+ const rule = getRuleFromConfig(ruleId, this);
283
+
284
+ // apply meta.defaultOptions
285
+ const slicedOptions = ruleConfig.slice(1);
286
+ const mergedOptions = deepMergeArrays(rule?.meta?.defaultOptions, slicedOptions);
287
+
288
+ if (mergedOptions.length) {
289
+ ruleConfig = [ruleConfig[0], ...mergedOptions];
290
+ }
291
+
292
+ this.rules[ruleId] = ruleConfig;
293
+ }
294
+ }
279
295
  }
280
296
 
281
297
  module.exports = { Config };
@@ -155,16 +155,14 @@ function isGlobPattern(pattern) {
155
155
  * Used primarily to help with useful error messages.
156
156
  * @param {Object} options The options for the function.
157
157
  * @param {string} options.basePath The directory to search.
158
- * @param {string} options.pattern A glob pattern to match.
158
+ * @param {string} options.pattern An absolute path glob pattern to match.
159
159
  * @returns {Promise<boolean>} True if there is a glob match, false if not.
160
160
  */
161
161
  async function globMatch({ basePath, pattern }) {
162
162
 
163
163
  let found = false;
164
164
  const { hfs } = await import("@humanfs/node");
165
- const patternToUse = path.isAbsolute(pattern)
166
- ? normalizeToPosix(path.relative(basePath, pattern))
167
- : pattern;
165
+ const patternToUse = normalizeToPosix(path.relative(basePath, pattern));
168
166
 
169
167
  const matcher = new Minimatch(patternToUse, MINIMATCH_OPTIONS);
170
168
 
@@ -202,7 +200,7 @@ async function globMatch({ basePath, pattern }) {
202
200
  * ESLint.
203
201
  * @param {Object} options The options for this function.
204
202
  * @param {string} options.basePath The directory to search.
205
- * @param {Array<string>} options.patterns An array of glob patterns
203
+ * @param {Array<string>} options.patterns An array of absolute path glob patterns
206
204
  * to match.
207
205
  * @param {Array<string>} options.rawPatterns An array of glob patterns
208
206
  * as the user inputted them. Used for errors.
@@ -241,9 +239,7 @@ async function globSearch({
241
239
  */
242
240
  const relativeToPatterns = new Map();
243
241
  const matchers = patterns.map((pattern, i) => {
244
- const patternToUse = path.isAbsolute(pattern)
245
- ? normalizeToPosix(path.relative(basePath, pattern))
246
- : pattern;
242
+ const patternToUse = normalizeToPosix(path.relative(basePath, pattern));
247
243
 
248
244
  relativeToPatterns.set(patternToUse, patterns[i]);
249
245
 
@@ -353,7 +349,7 @@ async function globSearch({
353
349
  * that were used in the original search.
354
350
  * @param {Array<string>} options.rawPatterns An array of glob patterns
355
351
  * as the user inputted them. Used for errors.
356
- * @param {Array<string>} options.unmatchedPatterns A non-empty array of glob patterns
352
+ * @param {Array<string>} options.unmatchedPatterns A non-empty array of absolute path glob patterns
357
353
  * that were unmatched in the original search.
358
354
  * @returns {void} Always throws an error.
359
355
  * @throws {NoFilesFoundError} If the first unmatched pattern
@@ -388,7 +384,7 @@ async function throwErrorForUnmatchedPatterns({
388
384
  * Performs multiple glob searches in parallel.
389
385
  * @param {Object} options The options for this function.
390
386
  * @param {Map<string,GlobSearch>} options.searches
391
- * An array of glob patterns to match.
387
+ * A map of absolute path glob patterns to match.
392
388
  * @param {ConfigLoader|LegacyConfigLoader} options.configLoader The config loader to use for
393
389
  * determining what to ignore.
394
390
  * @param {boolean} options.errorOnUnmatchedPattern Determines if an
@@ -597,7 +593,7 @@ async function findFiles({
597
593
  return [
598
594
  ...new Set([
599
595
  ...results,
600
- ...globbyResults.map(filePath => path.resolve(filePath))
596
+ ...globbyResults
601
597
  ])
602
598
  ];
603
599
  }
@@ -618,7 +614,7 @@ function isErrorMessage(message) {
618
614
 
619
615
  /**
620
616
  * Returns result with warning by ignore settings
621
- * @param {string} filePath File path of checked code
617
+ * @param {string} filePath Absolute file path of checked code
622
618
  * @param {string} baseDir Absolute path of base directory
623
619
  * @param {"ignored"|"external"|"unconfigured"} configStatus A status that determines why the file is ignored
624
620
  * @returns {LintResult} Result with single warning
@@ -648,7 +644,7 @@ function createIgnoreResult(filePath, baseDir, configStatus) {
648
644
  }
649
645
 
650
646
  return {
651
- filePath: path.resolve(filePath),
647
+ filePath,
652
648
  messages: [
653
649
  {
654
650
  ruleId: null,
@@ -16,6 +16,7 @@ const espree = require("espree");
16
16
  const eslintScope = require("eslint-scope");
17
17
  const evk = require("eslint-visitor-keys");
18
18
  const { validateLanguageOptions } = require("./validate-language-options");
19
+ const { LATEST_ECMA_VERSION } = require("../../../conf/ecma-version");
19
20
 
20
21
  //-----------------------------------------------------------------------------
21
22
  // Type Definitions
@@ -31,6 +32,7 @@ const { validateLanguageOptions } = require("./validate-language-options");
31
32
 
32
33
  const debug = createDebug("eslint:languages:js");
33
34
  const DEFAULT_ECMA_VERSION = 5;
35
+ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
34
36
 
35
37
  /**
36
38
  * Analyze scope of the given AST.
@@ -55,6 +57,47 @@ function analyzeScope(ast, languageOptions, visitorKeys) {
55
57
  });
56
58
  }
57
59
 
60
+ /**
61
+ * Determines if a given object is Espree.
62
+ * @param {Object} parser The parser to check.
63
+ * @returns {boolean} True if the parser is Espree or false if not.
64
+ */
65
+ function isEspree(parser) {
66
+ return !!(parser === espree || parser[parserSymbol] === espree);
67
+ }
68
+
69
+ /**
70
+ * Normalize ECMAScript version from the initial config into languageOptions (year)
71
+ * format.
72
+ * @param {any} [ecmaVersion] ECMAScript version from the initial config
73
+ * @returns {number} normalized ECMAScript version
74
+ */
75
+ function normalizeEcmaVersionForLanguageOptions(ecmaVersion) {
76
+
77
+ switch (ecmaVersion) {
78
+ case 3:
79
+ return 3;
80
+
81
+ // void 0 = no ecmaVersion specified so use the default
82
+ case 5:
83
+ case void 0:
84
+ return 5;
85
+
86
+ default:
87
+ if (typeof ecmaVersion === "number") {
88
+ return ecmaVersion >= 2015 ? ecmaVersion : ecmaVersion + 2009;
89
+ }
90
+ }
91
+
92
+ /*
93
+ * We default to the latest supported ecmaVersion for everything else.
94
+ * Remember, this is for languageOptions.ecmaVersion, which sets the version
95
+ * that is used for a number of processes inside of ESLint. It's normally
96
+ * safe to assume people want the latest unless otherwise specified.
97
+ */
98
+ return LATEST_ECMA_VERSION;
99
+ }
100
+
58
101
  //-----------------------------------------------------------------------------
59
102
  // Exports
60
103
  //-----------------------------------------------------------------------------
@@ -79,6 +122,39 @@ module.exports = {
79
122
 
80
123
  validateLanguageOptions,
81
124
 
125
+ /**
126
+ * Normalizes the language options.
127
+ * @param {Object} languageOptions The language options to normalize.
128
+ * @returns {Object} The normalized language options.
129
+ */
130
+ normalizeLanguageOptions(languageOptions) {
131
+
132
+ languageOptions.ecmaVersion = normalizeEcmaVersionForLanguageOptions(
133
+ languageOptions.ecmaVersion
134
+ );
135
+
136
+ // Espree expects this information to be passed in
137
+ if (isEspree(languageOptions.parser)) {
138
+ const parserOptions = languageOptions.parserOptions;
139
+
140
+ if (languageOptions.sourceType) {
141
+
142
+ parserOptions.sourceType = languageOptions.sourceType;
143
+
144
+ if (
145
+ parserOptions.sourceType === "module" &&
146
+ parserOptions.ecmaFeatures &&
147
+ parserOptions.ecmaFeatures.globalReturn
148
+ ) {
149
+ parserOptions.ecmaFeatures.globalReturn = false;
150
+ }
151
+ }
152
+ }
153
+
154
+ return languageOptions;
155
+
156
+ },
157
+
82
158
  /**
83
159
  * Determines if a given node matches a given selector class.
84
160
  * @param {string} className The class name to check.
@@ -8,8 +8,8 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const assert = require("node:assert");
12
11
  const { isCommentToken } = require("@eslint-community/eslint-utils");
12
+ const assert = require("../../../../shared/assert");
13
13
  const cursors = require("./cursors");
14
14
  const ForwardTokenCursor = require("./forward-token-cursor");
15
15
  const PaddedTokenCursor = require("./padded-token-cursor");
@@ -9,7 +9,7 @@
9
9
  // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- const assert = require("node:assert"),
12
+ const assert = require("../../shared/assert"),
13
13
  { breakableTypePattern } = require("../../shared/ast-utils"),
14
14
  CodePath = require("./code-path"),
15
15
  CodePathSegment = require("./code-path-segment"),
@@ -13,7 +13,7 @@
13
13
  // Requirements
14
14
  //------------------------------------------------------------------------------
15
15
 
16
- const assert = require("node:assert"),
16
+ const assert = require("../../shared/assert"),
17
17
  CodePathSegment = require("./code-path-segment");
18
18
 
19
19
  //------------------------------------------------------------------------------
@@ -41,6 +41,7 @@ const { startTime, endTime } = require("../shared/stats");
41
41
  const { RuleValidator } = require("../config/rule-validator");
42
42
  const { assertIsRuleSeverity } = require("../config/flat-config-schema");
43
43
  const { normalizeSeverityToString } = require("../shared/severity");
44
+ const { deepMergeArrays } = require("../shared/deep-merge-arrays");
44
45
  const jslang = require("../languages/js");
45
46
  const { activeFlags, inactiveFlags } = require("../shared/flags");
46
47
  const debug = require("debug")("eslint:linter");
@@ -892,14 +893,14 @@ function storeTime(time, timeOpts, slots) {
892
893
  /**
893
894
  * Get the options for a rule (not including severity), if any
894
895
  * @param {RuleConfig} ruleConfig rule configuration
896
+ * @param {Object|undefined} defaultOptions rule.meta.defaultOptions
895
897
  * @returns {Array} of rule options, empty Array if none
896
898
  */
897
- function getRuleOptions(ruleConfig) {
899
+ function getRuleOptions(ruleConfig, defaultOptions) {
898
900
  if (Array.isArray(ruleConfig)) {
899
- return ruleConfig.slice(1);
901
+ return deepMergeArrays(defaultOptions, ruleConfig.slice(1));
900
902
  }
901
- return [];
902
-
903
+ return defaultOptions ?? [];
903
904
  }
904
905
 
905
906
  /**
@@ -957,6 +958,7 @@ function createRuleListeners(rule, ruleContext) {
957
958
  * @param {LanguageOptions} languageOptions The options for parsing the code.
958
959
  * @param {Object} settings The settings that were enabled in the config
959
960
  * @param {string} filename The reported filename of the code
961
+ * @param {boolean} applyDefaultOptions If true, apply rules' meta.defaultOptions in computing their config options.
960
962
  * @param {boolean} disableFixes If true, it doesn't make `fix` properties.
961
963
  * @param {string | undefined} cwd cwd of the cli
962
964
  * @param {string} physicalFilename The full path of the file on disk without any code block information
@@ -967,9 +969,21 @@ function createRuleListeners(rule, ruleContext) {
967
969
  * @throws {Error} If traversal into a node fails.
968
970
  */
969
971
  function runRules(
970
- sourceCode, configuredRules, ruleMapper, parserName, language, languageOptions,
971
- settings, filename, disableFixes, cwd, physicalFilename, ruleFilter,
972
- stats, slots
972
+ sourceCode,
973
+ configuredRules,
974
+ ruleMapper,
975
+ parserName,
976
+ language,
977
+ languageOptions,
978
+ settings,
979
+ filename,
980
+ applyDefaultOptions,
981
+ disableFixes,
982
+ cwd,
983
+ physicalFilename,
984
+ ruleFilter,
985
+ stats,
986
+ slots
973
987
  ) {
974
988
  const emitter = createEmitter();
975
989
 
@@ -1022,7 +1036,7 @@ function runRules(
1022
1036
  Object.create(sharedTraversalContext),
1023
1037
  {
1024
1038
  id: ruleId,
1025
- options: getRuleOptions(configuredRules[ruleId]),
1039
+ options: getRuleOptions(configuredRules[ruleId], applyDefaultOptions ? rule.meta?.defaultOptions : void 0),
1026
1040
  report(...args) {
1027
1041
 
1028
1042
  /*
@@ -1419,6 +1433,7 @@ class Linter {
1419
1433
  languageOptions,
1420
1434
  settings,
1421
1435
  options.filename,
1436
+ true,
1422
1437
  options.disableFixes,
1423
1438
  slots.cwd,
1424
1439
  providedOptions.physicalFilename,
@@ -1640,34 +1655,8 @@ class Linter {
1640
1655
 
1641
1656
  const slots = internalSlotsMap.get(this);
1642
1657
  const config = providedConfig || {};
1658
+ const { settings = {}, languageOptions } = config;
1643
1659
  const options = normalizeVerifyOptions(providedOptions, config);
1644
- const languageOptions = config.languageOptions;
1645
-
1646
- if (config.language === jslang) {
1647
- languageOptions.ecmaVersion = normalizeEcmaVersionForLanguageOptions(
1648
- languageOptions.ecmaVersion
1649
- );
1650
-
1651
- // Espree expects this information to be passed in
1652
- if (isEspree(languageOptions.parser)) {
1653
- const parserOptions = languageOptions.parserOptions;
1654
-
1655
- if (languageOptions.sourceType) {
1656
-
1657
- parserOptions.sourceType = languageOptions.sourceType;
1658
-
1659
- if (
1660
- parserOptions.sourceType === "module" &&
1661
- parserOptions.ecmaFeatures &&
1662
- parserOptions.ecmaFeatures.globalReturn
1663
- ) {
1664
- parserOptions.ecmaFeatures.globalReturn = false;
1665
- }
1666
- }
1667
- }
1668
- }
1669
-
1670
- const settings = config.settings || {};
1671
1660
 
1672
1661
  if (!slots.lastSourceCode) {
1673
1662
  let t;
@@ -1848,6 +1837,17 @@ class Linter {
1848
1837
  if (config.rules[ruleId][0] > 0) {
1849
1838
  shouldValidateOptions = false;
1850
1839
  }
1840
+ } else {
1841
+
1842
+ /**
1843
+ * Since we know the user provided options, apply defaults on top of them
1844
+ */
1845
+ const slicedOptions = ruleOptions.slice(1);
1846
+ const mergedOptions = deepMergeArrays(rule.meta?.defaultOptions, slicedOptions);
1847
+
1848
+ if (mergedOptions.length) {
1849
+ ruleOptions = [ruleOptions[0], ...mergedOptions];
1850
+ }
1851
1851
  }
1852
1852
 
1853
1853
  if (shouldValidateOptions) {
@@ -1917,6 +1917,7 @@ class Linter {
1917
1917
  languageOptions,
1918
1918
  settings,
1919
1919
  options.filename,
1920
+ false,
1920
1921
  options.disableFixes,
1921
1922
  slots.cwd,
1922
1923
  providedOptions.physicalFilename,
@@ -9,7 +9,7 @@
9
9
  // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- const assert = require("node:assert");
12
+ const assert = require("../shared/assert");
13
13
  const { RuleFixer } = require("./rule-fixer");
14
14
  const { interpolate } = require("./interpolate");
15
15
 
@@ -653,7 +653,7 @@ class RuleTester {
653
653
  };
654
654
 
655
655
  if (item.filename) {
656
- flatConfigArrayOptions.basePath = path.parse(item.filename).root;
656
+ flatConfigArrayOptions.basePath = path.parse(item.filename).root || void 0;
657
657
  }
658
658
 
659
659
  const configs = new FlatConfigArray(testerConfig, flatConfigArrayOptions);
@@ -139,6 +139,12 @@ module.exports = {
139
139
  meta: {
140
140
  type: "suggestion",
141
141
 
142
+ defaultOptions: [{
143
+ enforceForClassMembers: true,
144
+ getWithoutSet: false,
145
+ setWithoutGet: true
146
+ }],
147
+
142
148
  docs: {
143
149
  description: "Enforce getter and setter pairs in objects and classes",
144
150
  recommended: false,
@@ -149,16 +155,13 @@ module.exports = {
149
155
  type: "object",
150
156
  properties: {
151
157
  getWithoutSet: {
152
- type: "boolean",
153
- default: false
158
+ type: "boolean"
154
159
  },
155
160
  setWithoutGet: {
156
- type: "boolean",
157
- default: true
161
+ type: "boolean"
158
162
  },
159
163
  enforceForClassMembers: {
160
- type: "boolean",
161
- default: true
164
+ type: "boolean"
162
165
  }
163
166
  },
164
167
  additionalProperties: false
@@ -174,7 +177,7 @@ module.exports = {
174
177
  }
175
178
  },
176
179
  create(context) {
177
- const config = context.options[0] || {};
180
+ const [config] = context.options;
178
181
  const checkGetWithoutSet = config.getWithoutSet === true;
179
182
  const checkSetWithoutGet = config.setWithoutGet !== false;
180
183
  const enforceForClassMembers = config.enforceForClassMembers !== false;
@@ -215,6 +215,12 @@ module.exports = {
215
215
  meta: {
216
216
  type: "problem",
217
217
 
218
+ defaultOptions: [{
219
+ allowImplicit: false,
220
+ checkForEach: false,
221
+ allowVoid: false
222
+ }],
223
+
218
224
  docs: {
219
225
  description: "Enforce `return` statements in callbacks of array methods",
220
226
  recommended: false,
@@ -229,16 +235,13 @@ module.exports = {
229
235
  type: "object",
230
236
  properties: {
231
237
  allowImplicit: {
232
- type: "boolean",
233
- default: false
238
+ type: "boolean"
234
239
  },
235
240
  checkForEach: {
236
- type: "boolean",
237
- default: false
241
+ type: "boolean"
238
242
  },
239
243
  allowVoid: {
240
- type: "boolean",
241
- default: false
244
+ type: "boolean"
242
245
  }
243
246
  },
244
247
  additionalProperties: false
@@ -256,8 +259,7 @@ module.exports = {
256
259
  },
257
260
 
258
261
  create(context) {
259
-
260
- const options = context.options[0] || { allowImplicit: false, checkForEach: false, allowVoid: false };
262
+ const [options] = context.options;
261
263
  const sourceCode = context.sourceCode;
262
264
 
263
265
  let funcInfo = {
@@ -19,6 +19,8 @@ module.exports = {
19
19
  meta: {
20
20
  type: "suggestion",
21
21
 
22
+ defaultOptions: ["as-needed"],
23
+
22
24
  docs: {
23
25
  description: "Require braces around arrow function bodies",
24
26
  recommended: false,
@@ -71,7 +73,7 @@ module.exports = {
71
73
  create(context) {
72
74
  const options = context.options;
73
75
  const always = options[0] === "always";
74
- const asNeeded = !options[0] || options[0] === "as-needed";
76
+ const asNeeded = options[0] === "as-needed";
75
77
  const never = options[0] === "never";
76
78
  const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
77
79
  const sourceCode = context.sourceCode;