eslint 9.26.0 → 9.28.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 (41) hide show
  1. package/README.md +7 -2
  2. package/bin/eslint.js +7 -11
  3. package/conf/rule-type-list.json +2 -1
  4. package/lib/cli-engine/cli-engine.js +7 -7
  5. package/lib/cli.js +19 -16
  6. package/lib/config/config-loader.js +42 -39
  7. package/lib/config/config.js +362 -16
  8. package/lib/eslint/eslint-helpers.js +3 -1
  9. package/lib/eslint/eslint.js +31 -13
  10. package/lib/eslint/legacy-eslint.js +6 -6
  11. package/lib/languages/js/source-code/source-code.js +40 -6
  12. package/lib/linter/apply-disable-directives.js +1 -1
  13. package/lib/linter/file-context.js +11 -0
  14. package/lib/linter/linter.js +102 -140
  15. package/lib/linter/report-translator.js +2 -1
  16. package/lib/linter/{node-event-generator.js → source-code-traverser.js} +143 -87
  17. package/lib/options.js +7 -0
  18. package/lib/rule-tester/rule-tester.js +3 -3
  19. package/lib/rules/func-style.js +57 -7
  20. package/lib/rules/index.js +1 -0
  21. package/lib/rules/max-params.js +32 -7
  22. package/lib/rules/no-array-constructor.js +51 -1
  23. package/lib/rules/no-implicit-globals.js +31 -15
  24. package/lib/rules/no-magic-numbers.js +98 -5
  25. package/lib/rules/no-shadow.js +262 -6
  26. package/lib/rules/no-unassigned-vars.js +80 -0
  27. package/lib/rules/no-use-before-define.js +97 -1
  28. package/lib/rules/no-useless-escape.js +24 -2
  29. package/lib/rules/prefer-arrow-callback.js +9 -0
  30. package/lib/rules/prefer-named-capture-group.js +7 -1
  31. package/lib/services/processor-service.js +1 -1
  32. package/lib/services/suppressions-service.js +5 -3
  33. package/lib/services/warning-service.js +85 -0
  34. package/lib/shared/flags.js +1 -0
  35. package/lib/types/index.d.ts +132 -9
  36. package/lib/types/rules.d.ts +66 -3
  37. package/package.json +11 -11
  38. package/lib/config/flat-config-helpers.js +0 -128
  39. package/lib/config/rule-validator.js +0 -199
  40. package/lib/mcp/mcp-server.js +0 -66
  41. package/lib/shared/types.js +0 -229
@@ -53,7 +53,7 @@ const CODE_PATH_EVENTS = [
53
53
  /**
54
54
  * Validates that the given AST has the required information.
55
55
  * @param {ASTNode} ast The Program node of the AST to check.
56
- * @throws {Error} If the AST doesn't contain the correct information.
56
+ * @throws {TypeError} If the AST doesn't contain the correct information.
57
57
  * @returns {void}
58
58
  * @private
59
59
  */
@@ -147,8 +147,8 @@ function sortedMerge(tokens, comments) {
147
147
  * Normalizes a value for a global in a config
148
148
  * @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
149
149
  * a global directive comment
150
- * @returns {("readable"|"writeable"|"off")} The value normalized as a string
151
- * @throws Error if global value is invalid
150
+ * @returns {("readonly"|"writable"|"off")} The value normalized as a string
151
+ * @throws {Error} if global value is invalid
152
152
  */
153
153
  function normalizeConfigGlobal(configuredValue) {
154
154
  switch (configuredValue) {
@@ -316,6 +316,36 @@ function addDeclaredGlobals(
316
316
 
317
317
  return true;
318
318
  });
319
+
320
+ /*
321
+ * "implicit" contains information about implicit global variables (those created
322
+ * implicitly by assigning values to undeclared variables in non-strict code).
323
+ * Since we augment the global scope using configuration, we need to remove
324
+ * the ones that were added by configuration, as they are either built-in
325
+ * or declared elsewhere, therefore not implicit.
326
+ * Since the "implicit" property was not documented, first we'll check if it exists
327
+ * because it's possible that not all custom scope managers create this property.
328
+ * If it exists, we assume it has properties `variables` and `set`. Property
329
+ * `left` is considered optional (for example, typescript-eslint's scope manage
330
+ * has this property named `leftToBeResolved`).
331
+ */
332
+ const { implicit } = globalScope;
333
+ if (typeof implicit === "object" && implicit !== null) {
334
+ implicit.variables = implicit.variables.filter(variable => {
335
+ const name = variable.name;
336
+ if (globalScope.set.has(name)) {
337
+ implicit.set.delete(name);
338
+ return false;
339
+ }
340
+ return true;
341
+ });
342
+
343
+ if (implicit.left) {
344
+ implicit.left = implicit.left.filter(
345
+ reference => !globalScope.set.has(reference.identifier.name),
346
+ );
347
+ }
348
+ }
319
349
  }
320
350
 
321
351
  /**
@@ -471,6 +501,10 @@ class SourceCode extends TokenStore {
471
501
  * @type {string[]}
472
502
  */
473
503
  this.lines = [];
504
+
505
+ /**
506
+ * @type {number[]}
507
+ */
474
508
  this.lineStartIndices = [0];
475
509
 
476
510
  const lineEndingPattern = astUtils.createGlobalLinebreakMatcher();
@@ -528,7 +562,7 @@ class SourceCode extends TokenStore {
528
562
 
529
563
  /**
530
564
  * Gets the entire source text split into an array of lines.
531
- * @returns {Array} The source text as an array of lines.
565
+ * @returns {string[]} The source text as an array of lines.
532
566
  * @public
533
567
  */
534
568
  getLines() {
@@ -687,8 +721,8 @@ class SourceCode extends TokenStore {
687
721
  /**
688
722
  * Converts a source text index into a (line, column) pair.
689
723
  * @param {number} index The index of a character in a file
690
- * @throws {TypeError} If non-numeric index or index out of range.
691
- * @returns {Object} A {line, column} location object with a 0-indexed column
724
+ * @throws {TypeError|RangeError} If non-numeric index or index out of range.
725
+ * @returns {{line: number, column: number}} A {line, column} location object with a 0-indexed column
692
726
  * @public
693
727
  */
694
728
  getLocFromIndex(index) {
@@ -9,7 +9,7 @@
9
9
  // Typedefs
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- /** @typedef {import("../shared/types").LintMessage} LintMessage */
12
+ /** @typedef {import("../types").Linter.LintMessage} LintMessage */
13
13
  /** @typedef {import("@eslint/core").Language} Language */
14
14
  /** @typedef {import("@eslint/core").Position} Position */
15
15
  /** @typedef {import("@eslint/core").RulesConfig} RulesConfig */
@@ -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;
@@ -27,17 +27,14 @@ const path = require("node:path"),
27
27
  { SourceCode } = require("../languages/js/source-code"),
28
28
  applyDisableDirectives = require("./apply-disable-directives"),
29
29
  { ConfigCommentParser } = require("@eslint/plugin-kit"),
30
- NodeEventGenerator = require("./node-event-generator"),
31
30
  createReportTranslator = require("./report-translator"),
32
31
  Rules = require("./rules"),
33
32
  createEmitter = require("./safe-emitter"),
34
33
  SourceCodeFixer = require("./source-code-fixer"),
35
34
  timing = require("./timing"),
36
35
  ruleReplacements = require("../../conf/replacements.json");
37
- const { getRuleFromConfig } = require("../config/flat-config-helpers");
38
36
  const { FlatConfigArray } = require("../config/flat-config-array");
39
37
  const { startTime, endTime } = require("../shared/stats");
40
- const { RuleValidator } = require("../config/rule-validator");
41
38
  const { assertIsRuleSeverity } = require("../config/flat-config-schema");
42
39
  const {
43
40
  normalizeSeverityToString,
@@ -66,8 +63,9 @@ const { ParserService } = require("../services/parser-service");
66
63
  const { FileContext } = require("./file-context");
67
64
  const { ProcessorService } = require("../services/processor-service");
68
65
  const { containsDifferentProperty } = require("../shared/option-utils");
69
- const STEP_KIND_VISIT = 1;
70
- const STEP_KIND_CALL = 2;
66
+ const { Config } = require("../config/config");
67
+ const { WarningService } = require("../services/warning-service");
68
+ const { SourceCodeTraverser } = require("./source-code-traverser");
71
69
 
72
70
  //------------------------------------------------------------------------------
73
71
  // Typedefs
@@ -75,17 +73,19 @@ const STEP_KIND_CALL = 2;
75
73
 
76
74
  /** @import { Language, LanguageOptions, RuleConfig, RuleDefinition, RuleSeverity } from "@eslint/core" */
77
75
 
78
- /** @typedef {import("../shared/types").ConfigData} ConfigData */
79
- /** @typedef {import("../shared/types").Environment} Environment */
80
- /** @typedef {import("../shared/types").GlobalConf} GlobalConf */
81
- /** @typedef {import("../shared/types").LintMessage} LintMessage */
82
- /** @typedef {import("../shared/types").SuppressedLintMessage} SuppressedLintMessage */
83
- /** @typedef {import("../shared/types").ParserOptions} ParserOptions */
84
- /** @typedef {import("../shared/types").Processor} Processor */
85
- /** @typedef {import("../shared/types").Times} Times */
76
+ /** @typedef {import("../types").Linter.Config} Config */
77
+ /** @typedef {import("../types").ESLint.ConfigData} ConfigData */
78
+ /** @typedef {import("../types").ESLint.Environment} Environment */
79
+ /** @typedef {import("../types").Linter.GlobalConf} GlobalConf */
86
80
  /** @typedef {import("../types").Linter.LanguageOptions} JSLanguageOptions */
87
- /** @typedef {import("../types").Linter.StringSeverity} StringSeverity */
81
+ /** @typedef {import("../types").Linter.LintMessage} LintMessage */
82
+ /** @typedef {import("../types").Linter.Parser} Parser */
83
+ /** @typedef {import("../types").Linter.ParserOptions} ParserOptions */
84
+ /** @typedef {import("../types").Linter.Processor} Processor */
88
85
  /** @typedef {import("../types").Rule.RuleModule} Rule */
86
+ /** @typedef {import("../types").Linter.StringSeverity} StringSeverity */
87
+ /** @typedef {import("../types").Linter.SuppressedLintMessage} SuppressedLintMessage */
88
+ /** @typedef {import("../types").Linter.TimePass} TimePass */
89
89
 
90
90
  /* eslint-disable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/4#issuecomment-778805577 */
91
91
  /**
@@ -110,8 +110,9 @@ const STEP_KIND_CALL = 2;
110
110
  * @property {SourceCode|null} lastSourceCode The `SourceCode` instance that the last `verify()` call used.
111
111
  * @property {SuppressedLintMessage[]} lastSuppressedMessages The `SuppressedLintMessage[]` instance that the last `verify()` call produced.
112
112
  * @property {Map<string, Parser>} parserMap The loaded parsers.
113
- * @property {Times} times The times spent on applying a rule to a file (see `stats` option).
113
+ * @property {{ passes: TimePass[]; }} times The times spent on applying a rule to a file (see `stats` option).
114
114
  * @property {Rules} ruleMap The loaded rules.
115
+ * @property {WarningService} warningService The warning service.
115
116
  */
116
117
 
117
118
  /**
@@ -350,7 +351,7 @@ function asArray(value) {
350
351
 
351
352
  /**
352
353
  * Pushes a problem to inlineConfigProblems if ruleOptions are redundant.
353
- * @param {ConfigData} config Provided config.
354
+ * @param {Config} config Provided config.
354
355
  * @param {Object} loc A line/column location
355
356
  * @param {Array} problems Problems that may be added to.
356
357
  * @param {string} ruleId The rule ID.
@@ -901,7 +902,7 @@ function normalizeFilename(filename) {
901
902
  * Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
902
903
  * consistent shape.
903
904
  * @param {VerifyOptions} providedOptions Options
904
- * @param {ConfigData} config Config.
905
+ * @param {Config|ConfigData} config Config.
905
906
  * @returns {Required<VerifyOptions> & InternalOptions} Normalized options
906
907
  */
907
908
  function normalizeVerifyOptions(providedOptions, config) {
@@ -1176,15 +1177,12 @@ function runRules(
1176
1177
  ) {
1177
1178
  const emitter = createEmitter();
1178
1179
 
1179
- // must happen first to assign all node.parent properties
1180
- const eventQueue = sourceCode.traverse();
1181
-
1182
1180
  /*
1183
1181
  * Create a frozen object with the ruleContext properties and methods that are shared by all rules.
1184
1182
  * All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
1185
1183
  * properties once for each rule.
1186
1184
  */
1187
- const sharedTraversalContext = new FileContext({
1185
+ const fileContext = new FileContext({
1188
1186
  cwd,
1189
1187
  filename,
1190
1188
  physicalFilename: physicalFilename || filename,
@@ -1198,9 +1196,10 @@ function runRules(
1198
1196
  });
1199
1197
 
1200
1198
  const lintingProblems = [];
1199
+ const steps = sourceCode.traverse();
1201
1200
 
1202
1201
  Object.keys(configuredRules).forEach(ruleId => {
1203
- const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
1202
+ const severity = Config.getRuleNumericSeverity(configuredRules[ruleId]);
1204
1203
 
1205
1204
  // not load disabled rules
1206
1205
  if (severity === 0) {
@@ -1220,63 +1219,61 @@ function runRules(
1220
1219
 
1221
1220
  const messageIds = rule.meta && rule.meta.messages;
1222
1221
  let reportTranslator = null;
1223
- const ruleContext = Object.freeze(
1224
- Object.assign(Object.create(sharedTraversalContext), {
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);
1222
+ const ruleContext = fileContext.extend({
1223
+ id: ruleId,
1224
+ options: getRuleOptions(
1225
+ configuredRules[ruleId],
1226
+ applyDefaultOptions ? rule.meta?.defaultOptions : void 0,
1227
+ ),
1228
+ report(...args) {
1229
+ /*
1230
+ * Create a report translator lazily.
1231
+ * In a vast majority of cases, any given rule reports zero errors on a given
1232
+ * piece of code. Creating a translator lazily avoids the performance cost of
1233
+ * creating a new translator function for each rule that usually doesn't get
1234
+ * called.
1235
+ *
1236
+ * Using lazy report translators improves end-to-end performance by about 3%
1237
+ * with Node 8.4.0.
1238
+ */
1239
+ if (reportTranslator === null) {
1240
+ reportTranslator = createReportTranslator({
1241
+ ruleId,
1242
+ severity,
1243
+ sourceCode,
1244
+ messageIds,
1245
+ disableFixes,
1246
+ language,
1247
+ });
1248
+ }
1249
+ const problem = reportTranslator(...args);
1252
1250
 
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
- }
1251
+ if (problem.fix && !(rule.meta && rule.meta.fixable)) {
1252
+ throw new Error(
1253
+ 'Fixable rules must set the `meta.fixable` property to "code" or "whitespace".',
1254
+ );
1255
+ }
1256
+ if (
1257
+ problem.suggestions &&
1258
+ !(rule.meta && rule.meta.hasSuggestions === true)
1259
+ ) {
1258
1260
  if (
1259
- problem.suggestions &&
1260
- !(rule.meta && rule.meta.hasSuggestions === true)
1261
+ rule.meta &&
1262
+ rule.meta.docs &&
1263
+ typeof rule.meta.docs.suggestion !== "undefined"
1261
1264
  ) {
1262
- if (
1263
- rule.meta &&
1264
- rule.meta.docs &&
1265
- typeof rule.meta.docs.suggestion !== "undefined"
1266
- ) {
1267
- // Encourage migration from the former property name.
1268
- throw new Error(
1269
- "Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.",
1270
- );
1271
- }
1265
+ // Encourage migration from the former property name.
1272
1266
  throw new Error(
1273
- "Rules with suggestions must set the `meta.hasSuggestions` property to `true`.",
1267
+ "Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.",
1274
1268
  );
1275
1269
  }
1276
- lintingProblems.push(problem);
1277
- },
1278
- }),
1279
- );
1270
+ throw new Error(
1271
+ "Rules with suggestions must set the `meta.hasSuggestions` property to `true`.",
1272
+ );
1273
+ }
1274
+ lintingProblems.push(problem);
1275
+ },
1276
+ });
1280
1277
 
1281
1278
  const ruleListenersReturn =
1282
1279
  timing.enabled || stats
@@ -1346,40 +1343,9 @@ function runRules(
1346
1343
  });
1347
1344
  });
1348
1345
 
1349
- const eventGenerator = new NodeEventGenerator(emitter, {
1350
- visitorKeys: sourceCode.visitorKeys ?? language.visitorKeys,
1351
- fallback: Traverser.getKeys,
1352
- matchClass: language.matchesSelectorClass ?? (() => false),
1353
- nodeTypeKey: language.nodeTypeKey,
1354
- });
1346
+ const traverser = SourceCodeTraverser.getInstance(language);
1355
1347
 
1356
- for (const step of eventQueue) {
1357
- switch (step.kind) {
1358
- case STEP_KIND_VISIT: {
1359
- try {
1360
- if (step.phase === 1) {
1361
- eventGenerator.enterNode(step.target);
1362
- } else {
1363
- eventGenerator.leaveNode(step.target);
1364
- }
1365
- } catch (err) {
1366
- err.currentNode = step.target;
1367
- throw err;
1368
- }
1369
- break;
1370
- }
1371
-
1372
- case STEP_KIND_CALL: {
1373
- emitter.emit(step.target, ...step.args);
1374
- break;
1375
- }
1376
-
1377
- default:
1378
- throw new Error(
1379
- `Invalid traversal step found: "${step.type}".`,
1380
- );
1381
- }
1382
- }
1348
+ traverser.traverseSync(sourceCode, emitter, { steps });
1383
1349
 
1384
1350
  return lintingProblems;
1385
1351
  }
@@ -1484,8 +1450,14 @@ class Linter {
1484
1450
  * @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
1485
1451
  * @param {Array<string>} [config.flags] the feature flags to enable.
1486
1452
  * @param {"flat"|"eslintrc"} [config.configType="flat"] the type of config used.
1453
+ * @param {WarningService} [config.warningService] The warning service to use.
1487
1454
  */
1488
- constructor({ cwd, configType = "flat", flags = [] } = {}) {
1455
+ constructor({
1456
+ cwd,
1457
+ configType = "flat",
1458
+ flags = [],
1459
+ warningService = new WarningService(),
1460
+ } = {}) {
1489
1461
  const processedFlags = [];
1490
1462
 
1491
1463
  flags.forEach(flag => {
@@ -1493,11 +1465,10 @@ class Linter {
1493
1465
  const inactiveFlagData = inactiveFlags.get(flag);
1494
1466
  const inactivityReason =
1495
1467
  getInactivityReasonMessage(inactiveFlagData);
1468
+ const message = `The flag '${flag}' is inactive: ${inactivityReason}`;
1496
1469
 
1497
1470
  if (typeof inactiveFlagData.replacedBy === "undefined") {
1498
- throw new Error(
1499
- `The flag '${flag}' is inactive: ${inactivityReason}`,
1500
- );
1471
+ throw new Error(message);
1501
1472
  }
1502
1473
 
1503
1474
  // if there's a replacement, enable it instead of original
@@ -1505,10 +1476,7 @@ class Linter {
1505
1476
  processedFlags.push(inactiveFlagData.replacedBy);
1506
1477
  }
1507
1478
 
1508
- globalThis.process?.emitWarning?.(
1509
- `The flag '${flag}' is inactive: ${inactivityReason}`,
1510
- `ESLintInactiveFlag_${flag}`,
1511
- );
1479
+ warningService.emitInactiveFlagWarning(flag, message);
1512
1480
 
1513
1481
  return;
1514
1482
  }
@@ -1529,6 +1497,7 @@ class Linter {
1529
1497
  configType, // TODO: Remove after flat config conversion
1530
1498
  parserMap: new Map([["espree", espree]]),
1531
1499
  ruleMap: new Rules(),
1500
+ warningService,
1532
1501
  });
1533
1502
 
1534
1503
  this.version = pkg.version;
@@ -1885,7 +1854,7 @@ class Linter {
1885
1854
  /**
1886
1855
  * Verify with a processor.
1887
1856
  * @param {string|SourceCode} textOrSourceCode The source code.
1888
- * @param {FlatConfig} config The config array.
1857
+ * @param {Config} config The config array.
1889
1858
  * @param {VerifyOptions&ProcessorOptions} options The options.
1890
1859
  * @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
1891
1860
  * @returns {(LintMessage|SuppressedLintMessage)[]} The found problems.
@@ -1986,7 +1955,7 @@ class Linter {
1986
1955
  /**
1987
1956
  * Verify using flat config and without any processors.
1988
1957
  * @param {VFile} file The file to lint.
1989
- * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
1958
+ * @param {Config} providedConfig An ESLintConfig instance to configure everything.
1990
1959
  * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
1991
1960
  * @throws {Error} If during rule execution.
1992
1961
  * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
@@ -2100,15 +2069,12 @@ class Linter {
2100
2069
  }),
2101
2070
  );
2102
2071
 
2103
- // next we need to verify information about the specified rules
2104
- const ruleValidator = new RuleValidator();
2105
-
2106
2072
  for (const {
2107
2073
  config: inlineConfig,
2108
2074
  loc,
2109
2075
  } of inlineConfigResult.configs) {
2110
2076
  Object.keys(inlineConfig.rules).forEach(ruleId => {
2111
- const rule = getRuleFromConfig(ruleId, config);
2077
+ const rule = config.getRuleDefinition(ruleId);
2112
2078
  const ruleValue = inlineConfig.rules[ruleId];
2113
2079
 
2114
2080
  if (!rule) {
@@ -2218,11 +2184,8 @@ class Linter {
2218
2184
  }
2219
2185
 
2220
2186
  if (shouldValidateOptions) {
2221
- ruleValidator.validate({
2222
- plugins: config.plugins,
2223
- rules: {
2224
- [ruleId]: ruleOptions,
2225
- },
2187
+ config.validateRulesConfig({
2188
+ [ruleId]: ruleOptions,
2226
2189
  });
2227
2190
  }
2228
2191
 
@@ -2270,7 +2233,7 @@ class Linter {
2270
2233
  options.allowInlineConfig && !options.warnInlineConfig
2271
2234
  ? getDirectiveCommentsForFlatConfig(
2272
2235
  sourceCode,
2273
- ruleId => getRuleFromConfig(ruleId, config),
2236
+ ruleId => config.getRuleDefinition(ruleId),
2274
2237
  config.language,
2275
2238
  )
2276
2239
  : { problems: [], disableDirectives: [] };
@@ -2289,7 +2252,7 @@ class Linter {
2289
2252
  lintingProblems = runRules(
2290
2253
  sourceCode,
2291
2254
  configuredRules,
2292
- ruleId => getRuleFromConfig(ruleId, config),
2255
+ ruleId => config.getRuleDefinition(ruleId),
2293
2256
  void 0,
2294
2257
  config.language,
2295
2258
  languageOptions,
@@ -2348,7 +2311,7 @@ class Linter {
2348
2311
  /**
2349
2312
  * Same as linter.verify, except without support for processors.
2350
2313
  * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
2351
- * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
2314
+ * @param {Config} providedConfig An ESLintConfig instance to configure everything.
2352
2315
  * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
2353
2316
  * @throws {Error} If during rule execution.
2354
2317
  * @returns {(LintMessage|SuppressedLintMessage)[]} The results as an array of messages or an empty array if no messages.
@@ -2619,7 +2582,7 @@ class Linter {
2619
2582
 
2620
2583
  /**
2621
2584
  * Gets the times spent on (parsing, fixing, linting) a file.
2622
- * @returns {LintTimes} The times.
2585
+ * @returns {{ passes: TimePass[]; }} The times.
2623
2586
  */
2624
2587
  getTimes() {
2625
2588
  return internalSlotsMap.get(this).times ?? { passes: [] };
@@ -2717,6 +2680,14 @@ class Linter {
2717
2680
  options && typeof options.fix !== "undefined" ? options.fix : true;
2718
2681
  const stats = options?.stats;
2719
2682
 
2683
+ const slots = internalSlotsMap.get(this);
2684
+
2685
+ // Remove lint times from the last run.
2686
+ if (stats) {
2687
+ delete slots.times;
2688
+ slots.fixPasses = 0;
2689
+ }
2690
+
2720
2691
  /**
2721
2692
  * This loop continues until one of the following is true:
2722
2693
  *
@@ -2726,14 +2697,6 @@ class Linter {
2726
2697
  * That means anytime a fix is successfully applied, there will be another pass.
2727
2698
  * Essentially, guaranteeing a minimum of two passes.
2728
2699
  */
2729
- const slots = internalSlotsMap.get(this);
2730
-
2731
- // Remove lint times from the last run.
2732
- if (stats) {
2733
- delete slots.times;
2734
- slots.fixPasses = 0;
2735
- }
2736
-
2737
2700
  do {
2738
2701
  passNumber++;
2739
2702
  let tTotal;
@@ -2805,9 +2768,8 @@ class Linter {
2805
2768
  debug(
2806
2769
  `Circular fixes detected after pass ${passNumber}. Exiting fix loop.`,
2807
2770
  );
2808
- globalThis?.process?.emitWarning?.(
2809
- `Circular fixes detected while fixing ${options?.filename ?? "text"}. It is likely that you have conflicting rules in your configuration.`,
2810
- "ESLintCircularFixesWarning",
2771
+ slots.warningService.emitCircularFixesWarning(
2772
+ options?.filename ?? "text",
2811
2773
  );
2812
2774
  break;
2813
2775
  }
@@ -17,7 +17,8 @@ const { interpolate } = require("./interpolate");
17
17
  // Typedefs
18
18
  //------------------------------------------------------------------------------
19
19
 
20
- /** @typedef {import("../shared/types").LintMessage} LintMessage */
20
+ /** @typedef {import("../types").Linter.LintMessage} LintMessage */
21
+ /** @typedef {import("../types").Linter.LintSuggestion} SuggestionResult */
21
22
 
22
23
  /**
23
24
  * An error message description