eslint 9.25.1 → 9.27.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 (40) hide show
  1. package/README.md +44 -39
  2. package/bin/eslint.js +15 -0
  3. package/conf/rule-type-list.json +2 -1
  4. package/lib/cli-engine/cli-engine.js +8 -8
  5. package/lib/cli.js +6 -5
  6. package/lib/config/config-loader.js +10 -18
  7. package/lib/config/config.js +328 -5
  8. package/lib/eslint/eslint-helpers.js +3 -1
  9. package/lib/eslint/eslint.js +31 -17
  10. package/lib/eslint/legacy-eslint.js +7 -7
  11. package/lib/languages/js/index.js +4 -3
  12. package/lib/languages/js/source-code/source-code.js +10 -6
  13. package/lib/linter/apply-disable-directives.js +1 -1
  14. package/lib/linter/esquery.js +329 -0
  15. package/lib/linter/file-context.js +11 -0
  16. package/lib/linter/linter.js +81 -89
  17. package/lib/linter/node-event-generator.js +94 -251
  18. package/lib/linter/report-translator.js +2 -1
  19. package/lib/options.js +11 -0
  20. package/lib/rule-tester/rule-tester.js +17 -9
  21. package/lib/rules/eqeqeq.js +31 -8
  22. package/lib/rules/index.js +2 -1
  23. package/lib/rules/max-params.js +32 -7
  24. package/lib/rules/no-array-constructor.js +51 -1
  25. package/lib/rules/no-shadow-restricted-names.js +25 -2
  26. package/lib/rules/no-unassigned-vars.js +72 -0
  27. package/lib/rules/no-unused-expressions.js +7 -1
  28. package/lib/rules/no-useless-escape.js +24 -2
  29. package/lib/rules/prefer-named-capture-group.js +7 -1
  30. package/lib/rules/utils/lazy-loading-rule-map.js +2 -2
  31. package/lib/services/processor-service.js +1 -2
  32. package/lib/services/suppressions-service.js +5 -3
  33. package/lib/shared/flags.js +1 -0
  34. package/lib/shared/serialization.js +29 -6
  35. package/lib/types/index.d.ts +126 -6
  36. package/lib/types/rules.d.ts +33 -2
  37. package/package.json +7 -6
  38. package/lib/config/flat-config-helpers.js +0 -128
  39. package/lib/config/rule-validator.js +0 -199
  40. package/lib/shared/types.js +0 -246
@@ -0,0 +1,329 @@
1
+ /**
2
+ * @fileoverview ESQuery wrapper for ESLint.
3
+ * @author Nicholas C. Zakas
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const esquery = require("esquery");
13
+
14
+ //-----------------------------------------------------------------------------
15
+ // Typedefs
16
+ //-----------------------------------------------------------------------------
17
+
18
+ /**
19
+ * @typedef {import("esquery").Selector} ESQuerySelector
20
+ * @typedef {import("esquery").ESQueryOptions} ESQueryOptions
21
+ */
22
+
23
+ //------------------------------------------------------------------------------
24
+ // Classes
25
+ //------------------------------------------------------------------------------
26
+
27
+ /**
28
+ * The result of parsing and analyzing an ESQuery selector.
29
+ */
30
+ class ESQueryParsedSelector {
31
+ /**
32
+ * The raw selector string that was parsed
33
+ * @type {string}
34
+ */
35
+ source;
36
+
37
+ /**
38
+ * Whether this selector is an exit selector
39
+ * @type {boolean}
40
+ */
41
+ isExit;
42
+
43
+ /**
44
+ * An object (from esquery) describing the matching behavior of the selector
45
+ * @type {ESQuerySelector}
46
+ */
47
+ root;
48
+
49
+ /**
50
+ * The node types that could possibly trigger this selector, or `null` if all node types could trigger it
51
+ * @type {string[]|null}
52
+ */
53
+ nodeTypes;
54
+
55
+ /**
56
+ * The number of class, pseudo-class, and attribute queries in this selector
57
+ * @type {number}
58
+ */
59
+ attributeCount;
60
+
61
+ /**
62
+ * The number of identifier queries in this selector
63
+ * @type {number}
64
+ */
65
+ identifierCount;
66
+
67
+ /**
68
+ * Creates a new parsed selector.
69
+ * @param {string} source The raw selector string that was parsed
70
+ * @param {boolean} isExit Whether this selector is an exit selector
71
+ * @param {ESQuerySelector} root An object (from esquery) describing the matching behavior of the selector
72
+ * @param {string[]|null} nodeTypes The node types that could possibly trigger this selector, or `null` if all node types could trigger it
73
+ * @param {number} attributeCount The number of class, pseudo-class, and attribute queries in this selector
74
+ * @param {number} identifierCount The number of identifier queries in this selector
75
+ */
76
+ constructor(
77
+ source,
78
+ isExit,
79
+ root,
80
+ nodeTypes,
81
+ attributeCount,
82
+ identifierCount,
83
+ ) {
84
+ this.source = source;
85
+ this.isExit = isExit;
86
+ this.root = root;
87
+ this.nodeTypes = nodeTypes;
88
+ this.attributeCount = attributeCount;
89
+ this.identifierCount = identifierCount;
90
+ }
91
+
92
+ /**
93
+ * Compares this selector's specifity to another selector for sorting purposes.
94
+ * @param {ESQueryParsedSelector} otherSelector The selector to compare against
95
+ * @returns {number}
96
+ * a value less than 0 if this selector is less specific than otherSelector
97
+ * a value greater than 0 if this selector is more specific than otherSelector
98
+ * a value less than 0 if this selector and otherSelector have the same specificity, and this selector <= otherSelector alphabetically
99
+ * a value greater than 0 if this selector and otherSelector have the same specificity, and this selector > otherSelector alphabetically
100
+ */
101
+ compare(otherSelector) {
102
+ return (
103
+ this.attributeCount - otherSelector.attributeCount ||
104
+ this.identifierCount - otherSelector.identifierCount ||
105
+ (this.source <= otherSelector.source ? -1 : 1)
106
+ );
107
+ }
108
+ }
109
+
110
+ //------------------------------------------------------------------------------
111
+ // Helpers
112
+ //------------------------------------------------------------------------------
113
+
114
+ const selectorCache = new Map();
115
+
116
+ /**
117
+ * Computes the union of one or more arrays
118
+ * @param {...any[]} arrays One or more arrays to union
119
+ * @returns {any[]} The union of the input arrays
120
+ */
121
+ function union(...arrays) {
122
+ return [...new Set(arrays.flat())];
123
+ }
124
+
125
+ /**
126
+ * Computes the intersection of one or more arrays
127
+ * @param {...any[]} arrays One or more arrays to intersect
128
+ * @returns {any[]} The intersection of the input arrays
129
+ */
130
+ function intersection(...arrays) {
131
+ if (arrays.length === 0) {
132
+ return [];
133
+ }
134
+
135
+ let result = [...new Set(arrays[0])];
136
+
137
+ for (const array of arrays.slice(1)) {
138
+ result = result.filter(x => array.includes(x));
139
+ }
140
+ return result;
141
+ }
142
+
143
+ /**
144
+ * Analyzes a parsed selector and returns combined data about it
145
+ * @param {ESQuerySelector} parsedSelector An object (from esquery) describing the matching behavior of the selector
146
+ * @returns {{nodeTypes:string[]|null, attributeCount:number, identifierCount:number}} Object containing selector data.
147
+ */
148
+ function analyzeParsedSelector(parsedSelector) {
149
+ let attributeCount = 0;
150
+ let identifierCount = 0;
151
+
152
+ /**
153
+ * Analyzes a selector and returns the node types that could possibly trigger it.
154
+ * @param {ESQuerySelector} selector The selector to analyze.
155
+ * @returns {string[]|null} The node types that could possibly trigger this selector, or `null` if all node types could trigger it
156
+ */
157
+ function analyzeSelector(selector) {
158
+ switch (selector.type) {
159
+ case "identifier":
160
+ identifierCount++;
161
+ return [selector.value];
162
+
163
+ case "not":
164
+ selector.selectors.map(analyzeSelector);
165
+ return null;
166
+
167
+ case "matches": {
168
+ const typesForComponents =
169
+ selector.selectors.map(analyzeSelector);
170
+
171
+ if (typesForComponents.every(Boolean)) {
172
+ return union(...typesForComponents);
173
+ }
174
+ return null;
175
+ }
176
+
177
+ case "compound": {
178
+ const typesForComponents = selector.selectors
179
+ .map(analyzeSelector)
180
+ .filter(typesForComponent => typesForComponent);
181
+
182
+ // If all of the components could match any type, then the compound could also match any type.
183
+ if (!typesForComponents.length) {
184
+ return null;
185
+ }
186
+
187
+ /*
188
+ * If at least one of the components could only match a particular type, the compound could only match
189
+ * the intersection of those types.
190
+ */
191
+ return intersection(...typesForComponents);
192
+ }
193
+
194
+ case "attribute":
195
+ case "field":
196
+ case "nth-child":
197
+ case "nth-last-child":
198
+ attributeCount++;
199
+ return null;
200
+
201
+ case "child":
202
+ case "descendant":
203
+ case "sibling":
204
+ case "adjacent":
205
+ analyzeSelector(selector.left);
206
+ return analyzeSelector(selector.right);
207
+
208
+ case "class":
209
+ // TODO: abstract into JSLanguage somehow
210
+ if (selector.name === "function") {
211
+ return [
212
+ "FunctionDeclaration",
213
+ "FunctionExpression",
214
+ "ArrowFunctionExpression",
215
+ ];
216
+ }
217
+ return null;
218
+
219
+ default:
220
+ return null;
221
+ }
222
+ }
223
+
224
+ const nodeTypes = analyzeSelector(parsedSelector);
225
+
226
+ return {
227
+ nodeTypes,
228
+ attributeCount,
229
+ identifierCount,
230
+ };
231
+ }
232
+
233
+ /**
234
+ * Tries to parse a simple selector string, such as a single identifier or wildcard.
235
+ * This saves time by avoiding the overhead of esquery parsing for simple cases.
236
+ * @param {string} selector The selector string to parse.
237
+ * @returns {Object|null} An object describing the selector if it is simple, or `null` if it is not.
238
+ */
239
+ function trySimpleParseSelector(selector) {
240
+ if (selector === "*") {
241
+ return {
242
+ type: "wildcard",
243
+ value: "*",
244
+ };
245
+ }
246
+
247
+ if (/^[a-z]+$/iu.test(selector)) {
248
+ return {
249
+ type: "identifier",
250
+ value: selector,
251
+ };
252
+ }
253
+
254
+ return null;
255
+ }
256
+
257
+ /**
258
+ * Parses a raw selector string, and throws a useful error if parsing fails.
259
+ * @param {string} selector The selector string to parse.
260
+ * @returns {Object} An object (from esquery) describing the matching behavior of this selector
261
+ * @throws {Error} An error if the selector is invalid
262
+ */
263
+ function tryParseSelector(selector) {
264
+ try {
265
+ return esquery.parse(selector);
266
+ } catch (err) {
267
+ if (
268
+ err.location &&
269
+ err.location.start &&
270
+ typeof err.location.start.offset === "number"
271
+ ) {
272
+ throw new SyntaxError(
273
+ `Syntax error in selector "${selector}" at position ${err.location.start.offset}: ${err.message}`,
274
+ );
275
+ }
276
+ throw err;
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Parses a raw selector string, and returns the parsed selector along with specificity and type information.
282
+ * @param {string} source A raw AST selector
283
+ * @returns {ESQueryParsedSelector} A selector descriptor
284
+ */
285
+ function parse(source) {
286
+ if (selectorCache.has(source)) {
287
+ return selectorCache.get(source);
288
+ }
289
+
290
+ const cleanSource = source.replace(/:exit$/u, "");
291
+ const parsedSelector =
292
+ trySimpleParseSelector(cleanSource) ?? tryParseSelector(cleanSource);
293
+ const { nodeTypes, attributeCount, identifierCount } =
294
+ analyzeParsedSelector(parsedSelector);
295
+
296
+ const result = new ESQueryParsedSelector(
297
+ source,
298
+ source.endsWith(":exit"),
299
+ parsedSelector,
300
+ nodeTypes,
301
+ attributeCount,
302
+ identifierCount,
303
+ );
304
+
305
+ selectorCache.set(source, result);
306
+ return result;
307
+ }
308
+
309
+ /**
310
+ * Checks if a node matches a given selector.
311
+ * @param {Object} node The node to check against the selector.
312
+ * @param {ESQuerySelector} root The root of the selector to match against.
313
+ * @param {Object[]} ancestry The ancestry of the node being checked, which is an array of nodes from the current node to the root.
314
+ * @param {ESQueryOptions} options The options to use for matching.
315
+ * @returns {boolean} `true` if the node matches the selector, `false` otherwise.
316
+ */
317
+ function matches(node, root, ancestry, options) {
318
+ return esquery.matches(node, root, ancestry, options);
319
+ }
320
+
321
+ //-----------------------------------------------------------------------------
322
+ // Exports
323
+ //-----------------------------------------------------------------------------
324
+
325
+ module.exports = {
326
+ parse,
327
+ matches,
328
+ ESQueryParsedSelector,
329
+ };
@@ -128,6 +128,17 @@ class FileContext {
128
128
  getSourceCode() {
129
129
  return this.sourceCode;
130
130
  }
131
+
132
+ /**
133
+ * Creates a new object with the current object as the prototype and
134
+ * the specified properties as its own properties.
135
+ * @param {Object} extension The properties to add to the new object.
136
+ * @returns {FileContext} A new object with the current object as the prototype
137
+ * and the specified properties as its own properties.
138
+ */
139
+ extend(extension) {
140
+ return Object.freeze(Object.assign(Object.create(this), extension));
141
+ }
131
142
  }
132
143
 
133
144
  exports.FileContext = FileContext;
@@ -34,10 +34,8 @@ const path = require("node:path"),
34
34
  SourceCodeFixer = require("./source-code-fixer"),
35
35
  timing = require("./timing"),
36
36
  ruleReplacements = require("../../conf/replacements.json");
37
- const { getRuleFromConfig } = require("../config/flat-config-helpers");
38
37
  const { FlatConfigArray } = require("../config/flat-config-array");
39
38
  const { startTime, endTime } = require("../shared/stats");
40
- const { RuleValidator } = require("../config/rule-validator");
41
39
  const { assertIsRuleSeverity } = require("../config/flat-config-schema");
42
40
  const {
43
41
  normalizeSeverityToString,
@@ -66,6 +64,7 @@ const { ParserService } = require("../services/parser-service");
66
64
  const { FileContext } = require("./file-context");
67
65
  const { ProcessorService } = require("../services/processor-service");
68
66
  const { containsDifferentProperty } = require("../shared/option-utils");
67
+ const { Config } = require("../config/config");
69
68
  const STEP_KIND_VISIT = 1;
70
69
  const STEP_KIND_CALL = 2;
71
70
 
@@ -73,20 +72,21 @@ const STEP_KIND_CALL = 2;
73
72
  // Typedefs
74
73
  //------------------------------------------------------------------------------
75
74
 
76
- /** @typedef {import("../shared/types").ConfigData} ConfigData */
77
- /** @typedef {import("../shared/types").Environment} Environment */
78
- /** @typedef {import("../shared/types").GlobalConf} GlobalConf */
79
- /** @typedef {import("../shared/types").LintMessage} LintMessage */
80
- /** @typedef {import("../shared/types").SuppressedLintMessage} SuppressedLintMessage */
81
- /** @typedef {import("../shared/types").ParserOptions} ParserOptions */
82
- /** @typedef {import("../shared/types").LanguageOptions} LanguageOptions */
83
- /** @typedef {import("../shared/types").Processor} Processor */
75
+ /** @import { Language, LanguageOptions, RuleConfig, RuleDefinition, RuleSeverity } from "@eslint/core" */
76
+
77
+ /** @typedef {import("../types").Linter.Config} Config */
78
+ /** @typedef {import("../types").ESLint.ConfigData} ConfigData */
79
+ /** @typedef {import("../types").ESLint.Environment} Environment */
80
+ /** @typedef {import("../types").Linter.GlobalConf} GlobalConf */
81
+ /** @typedef {import("../types").Linter.LanguageOptions} JSLanguageOptions */
82
+ /** @typedef {import("../types").Linter.LintMessage} LintMessage */
83
+ /** @typedef {import("../types").Linter.Parser} Parser */
84
+ /** @typedef {import("../types").Linter.ParserOptions} ParserOptions */
85
+ /** @typedef {import("../types").Linter.Processor} Processor */
84
86
  /** @typedef {import("../types").Rule.RuleModule} Rule */
85
- /** @typedef {import("../shared/types").Times} Times */
86
- /** @typedef {import("@eslint/core").Language} Language */
87
- /** @typedef {import("@eslint/core").RuleSeverity} RuleSeverity */
88
- /** @typedef {import("@eslint/core").RuleConfig} RuleConfig */
89
87
  /** @typedef {import("../types").Linter.StringSeverity} StringSeverity */
88
+ /** @typedef {import("../types").Linter.SuppressedLintMessage} SuppressedLintMessage */
89
+ /** @typedef {import("../types").Linter.TimePass} TimePass */
90
90
 
91
91
  /* eslint-disable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/4#issuecomment-778805577 */
92
92
  /**
@@ -111,7 +111,7 @@ const STEP_KIND_CALL = 2;
111
111
  * @property {SourceCode|null} lastSourceCode The `SourceCode` instance that the last `verify()` call used.
112
112
  * @property {SuppressedLintMessage[]} lastSuppressedMessages The `SuppressedLintMessage[]` instance that the last `verify()` call produced.
113
113
  * @property {Map<string, Parser>} parserMap The loaded parsers.
114
- * @property {Times} times The times spent on applying a rule to a file (see `stats` option).
114
+ * @property {{ passes: TimePass[]; }} times The times spent on applying a rule to a file (see `stats` option).
115
115
  * @property {Rules} ruleMap The loaded rules.
116
116
  */
117
117
 
@@ -351,7 +351,7 @@ function asArray(value) {
351
351
 
352
352
  /**
353
353
  * Pushes a problem to inlineConfigProblems if ruleOptions are redundant.
354
- * @param {ConfigData} config Provided config.
354
+ * @param {Config} config Provided config.
355
355
  * @param {Object} loc A line/column location
356
356
  * @param {Array} problems Problems that may be added to.
357
357
  * @param {string} ruleId The rule ID.
@@ -902,7 +902,7 @@ function normalizeFilename(filename) {
902
902
  * Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
903
903
  * consistent shape.
904
904
  * @param {VerifyOptions} providedOptions Options
905
- * @param {ConfigData} config Config.
905
+ * @param {Config|ConfigData} config Config.
906
906
  * @returns {Required<VerifyOptions> & InternalOptions} Normalized options
907
907
  */
908
908
  function normalizeVerifyOptions(providedOptions, config) {
@@ -1011,7 +1011,7 @@ function resolveParserOptions(parser, providedOptions, enabledEnvironments) {
1011
1011
  * @param {Object} config.globals Global variable definitions.
1012
1012
  * @param {Parser} config.parser The parser to use.
1013
1013
  * @param {ParserOptions} config.parserOptions The parserOptions to use.
1014
- * @returns {LanguageOptions} The languageOptions equivalent.
1014
+ * @returns {JSLanguageOptions} The languageOptions equivalent.
1015
1015
  */
1016
1016
  function createLanguageOptions({
1017
1017
  globals: configuredGlobals,
@@ -1091,7 +1091,7 @@ function getRuleOptions(ruleConfig, defaultOptions) {
1091
1091
  /**
1092
1092
  * Analyze scope of the given AST.
1093
1093
  * @param {ASTNode} ast The `Program` node to analyze.
1094
- * @param {LanguageOptions} languageOptions The parser options.
1094
+ * @param {JSLanguageOptions} languageOptions The language options.
1095
1095
  * @param {Record<string, string[]>} visitorKeys The visitor keys.
1096
1096
  * @returns {ScopeManager} The analysis result.
1097
1097
  */
@@ -1113,7 +1113,7 @@ function analyzeScope(ast, languageOptions, visitorKeys) {
1113
1113
 
1114
1114
  /**
1115
1115
  * Runs a rule, and gets its listeners
1116
- * @param {Rule} rule A rule object
1116
+ * @param {RuleDefinition} rule A rule object
1117
1117
  * @param {Context} ruleContext The context that should be passed to the rule
1118
1118
  * @throws {TypeError} If `rule` is not an object with a `create` method
1119
1119
  * @throws {any} Any error during the rule's `create`
@@ -1142,7 +1142,7 @@ function createRuleListeners(rule, ruleContext) {
1142
1142
  * Runs the given rules on the given SourceCode object
1143
1143
  * @param {SourceCode} sourceCode A SourceCode object for the given text
1144
1144
  * @param {Object} configuredRules The rules configuration
1145
- * @param {function(string): Rule} ruleMapper A mapper function from rule names to rules
1145
+ * @param {function(string): RuleDefinition} ruleMapper A mapper function from rule names to rules
1146
1146
  * @param {string | undefined} parserName The name of the parser in the config
1147
1147
  * @param {Language} language The language object used for parsing.
1148
1148
  * @param {LanguageOptions} languageOptions The options for parsing the code.
@@ -1185,7 +1185,7 @@ function runRules(
1185
1185
  * All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
1186
1186
  * properties once for each rule.
1187
1187
  */
1188
- const sharedTraversalContext = new FileContext({
1188
+ const fileContext = new FileContext({
1189
1189
  cwd,
1190
1190
  filename,
1191
1191
  physicalFilename: physicalFilename || filename,
@@ -1201,7 +1201,7 @@ function runRules(
1201
1201
  const lintingProblems = [];
1202
1202
 
1203
1203
  Object.keys(configuredRules).forEach(ruleId => {
1204
- const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
1204
+ const severity = Config.getRuleNumericSeverity(configuredRules[ruleId]);
1205
1205
 
1206
1206
  // not load disabled rules
1207
1207
  if (severity === 0) {
@@ -1221,63 +1221,61 @@ function runRules(
1221
1221
 
1222
1222
  const messageIds = rule.meta && rule.meta.messages;
1223
1223
  let reportTranslator = null;
1224
- const ruleContext = Object.freeze(
1225
- Object.assign(Object.create(sharedTraversalContext), {
1226
- id: ruleId,
1227
- options: getRuleOptions(
1228
- configuredRules[ruleId],
1229
- applyDefaultOptions ? rule.meta?.defaultOptions : void 0,
1230
- ),
1231
- report(...args) {
1232
- /*
1233
- * Create a report translator lazily.
1234
- * In a vast majority of cases, any given rule reports zero errors on a given
1235
- * piece of code. Creating a translator lazily avoids the performance cost of
1236
- * creating a new translator function for each rule that usually doesn't get
1237
- * called.
1238
- *
1239
- * Using lazy report translators improves end-to-end performance by about 3%
1240
- * with Node 8.4.0.
1241
- */
1242
- if (reportTranslator === null) {
1243
- reportTranslator = createReportTranslator({
1244
- ruleId,
1245
- severity,
1246
- sourceCode,
1247
- messageIds,
1248
- disableFixes,
1249
- language,
1250
- });
1251
- }
1252
- const problem = reportTranslator(...args);
1224
+ const ruleContext = fileContext.extend({
1225
+ id: ruleId,
1226
+ options: getRuleOptions(
1227
+ configuredRules[ruleId],
1228
+ applyDefaultOptions ? rule.meta?.defaultOptions : void 0,
1229
+ ),
1230
+ report(...args) {
1231
+ /*
1232
+ * Create a report translator lazily.
1233
+ * In a vast majority of cases, any given rule reports zero errors on a given
1234
+ * piece of code. Creating a translator lazily avoids the performance cost of
1235
+ * creating a new translator function for each rule that usually doesn't get
1236
+ * called.
1237
+ *
1238
+ * Using lazy report translators improves end-to-end performance by about 3%
1239
+ * with Node 8.4.0.
1240
+ */
1241
+ if (reportTranslator === null) {
1242
+ reportTranslator = createReportTranslator({
1243
+ ruleId,
1244
+ severity,
1245
+ sourceCode,
1246
+ messageIds,
1247
+ disableFixes,
1248
+ language,
1249
+ });
1250
+ }
1251
+ const problem = reportTranslator(...args);
1253
1252
 
1254
- if (problem.fix && !(rule.meta && rule.meta.fixable)) {
1255
- throw new Error(
1256
- 'Fixable rules must set the `meta.fixable` property to "code" or "whitespace".',
1257
- );
1258
- }
1253
+ if (problem.fix && !(rule.meta && rule.meta.fixable)) {
1254
+ throw new Error(
1255
+ 'Fixable rules must set the `meta.fixable` property to "code" or "whitespace".',
1256
+ );
1257
+ }
1258
+ if (
1259
+ problem.suggestions &&
1260
+ !(rule.meta && rule.meta.hasSuggestions === true)
1261
+ ) {
1259
1262
  if (
1260
- problem.suggestions &&
1261
- !(rule.meta && rule.meta.hasSuggestions === true)
1263
+ rule.meta &&
1264
+ rule.meta.docs &&
1265
+ typeof rule.meta.docs.suggestion !== "undefined"
1262
1266
  ) {
1263
- if (
1264
- rule.meta &&
1265
- rule.meta.docs &&
1266
- typeof rule.meta.docs.suggestion !== "undefined"
1267
- ) {
1268
- // Encourage migration from the former property name.
1269
- throw new Error(
1270
- "Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.",
1271
- );
1272
- }
1267
+ // Encourage migration from the former property name.
1273
1268
  throw new Error(
1274
- "Rules with suggestions must set the `meta.hasSuggestions` property to `true`.",
1269
+ "Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.",
1275
1270
  );
1276
1271
  }
1277
- lintingProblems.push(problem);
1278
- },
1279
- }),
1280
- );
1272
+ throw new Error(
1273
+ "Rules with suggestions must set the `meta.hasSuggestions` property to `true`.",
1274
+ );
1275
+ }
1276
+ lintingProblems.push(problem);
1277
+ },
1278
+ });
1281
1279
 
1282
1280
  const ruleListenersReturn =
1283
1281
  timing.enabled || stats
@@ -1886,7 +1884,7 @@ class Linter {
1886
1884
  /**
1887
1885
  * Verify with a processor.
1888
1886
  * @param {string|SourceCode} textOrSourceCode The source code.
1889
- * @param {FlatConfig} config The config array.
1887
+ * @param {Config} config The config array.
1890
1888
  * @param {VerifyOptions&ProcessorOptions} options The options.
1891
1889
  * @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
1892
1890
  * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
@@ -1987,7 +1985,7 @@ class Linter {
1987
1985
  /**
1988
1986
  * Verify using flat config and without any processors.
1989
1987
  * @param {VFile} file The file to lint.
1990
- * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
1988
+ * @param {Config} providedConfig An ESLintConfig instance to configure everything.
1991
1989
  * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
1992
1990
  * @throws {Error} If during rule execution.
1993
1991
  * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
@@ -2101,15 +2099,12 @@ class Linter {
2101
2099
  }),
2102
2100
  );
2103
2101
 
2104
- // next we need to verify information about the specified rules
2105
- const ruleValidator = new RuleValidator();
2106
-
2107
2102
  for (const {
2108
2103
  config: inlineConfig,
2109
2104
  loc,
2110
2105
  } of inlineConfigResult.configs) {
2111
2106
  Object.keys(inlineConfig.rules).forEach(ruleId => {
2112
- const rule = getRuleFromConfig(ruleId, config);
2107
+ const rule = config.getRuleDefinition(ruleId);
2113
2108
  const ruleValue = inlineConfig.rules[ruleId];
2114
2109
 
2115
2110
  if (!rule) {
@@ -2219,11 +2214,8 @@ class Linter {
2219
2214
  }
2220
2215
 
2221
2216
  if (shouldValidateOptions) {
2222
- ruleValidator.validate({
2223
- plugins: config.plugins,
2224
- rules: {
2225
- [ruleId]: ruleOptions,
2226
- },
2217
+ config.validateRulesConfig({
2218
+ [ruleId]: ruleOptions,
2227
2219
  });
2228
2220
  }
2229
2221
 
@@ -2271,7 +2263,7 @@ class Linter {
2271
2263
  options.allowInlineConfig && !options.warnInlineConfig
2272
2264
  ? getDirectiveCommentsForFlatConfig(
2273
2265
  sourceCode,
2274
- ruleId => getRuleFromConfig(ruleId, config),
2266
+ ruleId => config.getRuleDefinition(ruleId),
2275
2267
  config.language,
2276
2268
  )
2277
2269
  : { problems: [], disableDirectives: [] };
@@ -2290,7 +2282,7 @@ class Linter {
2290
2282
  lintingProblems = runRules(
2291
2283
  sourceCode,
2292
2284
  configuredRules,
2293
- ruleId => getRuleFromConfig(ruleId, config),
2285
+ ruleId => config.getRuleDefinition(ruleId),
2294
2286
  void 0,
2295
2287
  config.language,
2296
2288
  languageOptions,
@@ -2349,7 +2341,7 @@ class Linter {
2349
2341
  /**
2350
2342
  * Same as linter.verify, except without support for processors.
2351
2343
  * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
2352
- * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
2344
+ * @param {Config} providedConfig An ESLintConfig instance to configure everything.
2353
2345
  * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
2354
2346
  * @throws {Error} If during rule execution.
2355
2347
  * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
@@ -2620,7 +2612,7 @@ class Linter {
2620
2612
 
2621
2613
  /**
2622
2614
  * Gets the times spent on (parsing, fixing, linting) a file.
2623
- * @returns {LintTimes} The times.
2615
+ * @returns {{ passes: TimePass[]; }} The times.
2624
2616
  */
2625
2617
  getTimes() {
2626
2618
  return internalSlotsMap.get(this).times ?? { passes: [] };