eslint 9.27.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.
- package/lib/cli.js +14 -12
- package/lib/config/config-loader.js +32 -21
- package/lib/config/config.js +34 -11
- package/lib/eslint/eslint.js +5 -4
- package/lib/languages/js/source-code/source-code.js +30 -0
- package/lib/linter/linter.js +27 -58
- package/lib/linter/{node-event-generator.js → source-code-traverser.js} +143 -87
- package/lib/options.js +7 -0
- package/lib/rules/func-style.js +57 -7
- package/lib/rules/no-implicit-globals.js +31 -15
- package/lib/rules/no-magic-numbers.js +98 -5
- package/lib/rules/no-shadow.js +262 -6
- package/lib/rules/no-unassigned-vars.js +14 -6
- package/lib/rules/no-use-before-define.js +97 -1
- package/lib/rules/prefer-arrow-callback.js +9 -0
- package/lib/services/warning-service.js +85 -0
- package/lib/types/index.d.ts +10 -5
- package/lib/types/rules.d.ts +47 -2
- package/package.json +7 -5
package/lib/cli.js
CHANGED
@@ -439,10 +439,8 @@ const cli = {
|
|
439
439
|
debug("Using flat config?", usingFlatConfig);
|
440
440
|
|
441
441
|
if (allowFlatConfig && !usingFlatConfig) {
|
442
|
-
|
443
|
-
|
444
|
-
"ESLintRCWarning",
|
445
|
-
);
|
442
|
+
const { WarningService } = require("./services/warning-service");
|
443
|
+
new WarningService().emitESLintRCWarning();
|
446
444
|
}
|
447
445
|
|
448
446
|
const CLIOptions = createCLIOptions(usingFlatConfig);
|
@@ -736,17 +734,21 @@ const cli = {
|
|
736
734
|
);
|
737
735
|
}
|
738
736
|
|
739
|
-
|
740
|
-
|
737
|
+
if (!options.passOnUnprunedSuppressions) {
|
738
|
+
const unusedSuppressionsCount =
|
739
|
+
Object.keys(unusedSuppressions).length;
|
741
740
|
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
741
|
+
if (unusedSuppressionsCount > 0) {
|
742
|
+
log.error(
|
743
|
+
"There are suppressions left that do not occur anymore. Consider re-running the command with `--prune-suppressions`.",
|
744
|
+
);
|
745
|
+
debug(JSON.stringify(unusedSuppressions, null, 2));
|
746
|
+
|
747
|
+
return 2;
|
748
|
+
}
|
747
749
|
}
|
748
750
|
|
749
|
-
if (shouldExitForFatalErrors
|
751
|
+
if (shouldExitForFatalErrors) {
|
750
752
|
return 2;
|
751
753
|
}
|
752
754
|
|
@@ -15,6 +15,7 @@ const findUp = require("find-up");
|
|
15
15
|
const { pathToFileURL } = require("node:url");
|
16
16
|
const debug = require("debug")("eslint:config-loader");
|
17
17
|
const { FlatConfigArray } = require("./flat-config-array");
|
18
|
+
const { WarningService } = require("../services/warning-service");
|
18
19
|
|
19
20
|
//-----------------------------------------------------------------------------
|
20
21
|
// Types
|
@@ -32,6 +33,7 @@ const { FlatConfigArray } = require("./flat-config-array");
|
|
32
33
|
* @property {Array<string>} [ignorePatterns] The ignore patterns to use.
|
33
34
|
* @property {Config|Array<Config>} [overrideConfig] The override config to use.
|
34
35
|
* @property {boolean} [hasUnstableNativeNodeJsTSConfigFlag] The flag to indicate whether the `unstable_native_nodejs_ts_config` flag is enabled.
|
36
|
+
* @property {WarningService} [warningService] The warning service to use.
|
35
37
|
*/
|
36
38
|
|
37
39
|
//------------------------------------------------------------------------------
|
@@ -137,12 +139,13 @@ function isNativeTypeScriptSupportEnabled() {
|
|
137
139
|
* @since 9.24.0
|
138
140
|
*/
|
139
141
|
async function loadTypeScriptConfigFileWithJiti(filePath, fileURL, mtime) {
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
142
|
+
const { createJiti, version: jitiVersion } =
|
143
|
+
// eslint-disable-next-line no-use-before-define -- `ConfigLoader.loadJiti` can be overwritten for testing
|
144
|
+
await ConfigLoader.loadJiti().catch(() => {
|
145
|
+
throw new Error(
|
146
|
+
"The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.",
|
147
|
+
);
|
148
|
+
});
|
146
149
|
|
147
150
|
// `createJiti` was added in jiti v2.
|
148
151
|
if (typeof createJiti !== "function") {
|
@@ -155,11 +158,15 @@ async function loadTypeScriptConfigFileWithJiti(filePath, fileURL, mtime) {
|
|
155
158
|
* Disabling `moduleCache` allows us to reload a
|
156
159
|
* config file when the last modified timestamp changes.
|
157
160
|
*/
|
158
|
-
|
159
|
-
const jiti = createJiti(__filename, {
|
161
|
+
const jitiOptions = {
|
160
162
|
moduleCache: false,
|
161
|
-
|
162
|
-
|
163
|
+
};
|
164
|
+
|
165
|
+
if (jitiVersion.startsWith("2.1.")) {
|
166
|
+
jitiOptions.interopDefault = false;
|
167
|
+
}
|
168
|
+
|
169
|
+
const jiti = createJiti(__filename, jitiOptions);
|
163
170
|
const config = await jiti.import(fileURL.href);
|
164
171
|
|
165
172
|
importedConfigFileModificationTime.set(filePath, mtime);
|
@@ -301,7 +308,9 @@ class ConfigLoader {
|
|
301
308
|
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
|
302
309
|
*/
|
303
310
|
constructor(options) {
|
304
|
-
this.#options = options
|
311
|
+
this.#options = options.warningService
|
312
|
+
? options
|
313
|
+
: { ...options, warningService: new WarningService() };
|
305
314
|
}
|
306
315
|
|
307
316
|
/**
|
@@ -494,11 +503,12 @@ class ConfigLoader {
|
|
494
503
|
|
495
504
|
/**
|
496
505
|
* Used to import the jiti dependency. This method is exposed internally for testing purposes.
|
497
|
-
* @returns {Promise<
|
498
|
-
* or rejects with an error if jiti is not found.
|
506
|
+
* @returns {Promise<{createJiti: Function|undefined, version: string;}>} A promise that fulfills with an object containing the jiti module's createJiti function and version.
|
499
507
|
*/
|
500
|
-
static loadJiti() {
|
501
|
-
|
508
|
+
static async loadJiti() {
|
509
|
+
const { createJiti } = await import("jiti");
|
510
|
+
const version = require("jiti/package.json").version;
|
511
|
+
return { createJiti, version };
|
502
512
|
}
|
503
513
|
|
504
514
|
/**
|
@@ -561,6 +571,7 @@ class ConfigLoader {
|
|
561
571
|
overrideConfig,
|
562
572
|
hasUnstableNativeNodeJsTSConfigFlag = false,
|
563
573
|
defaultConfigs = [],
|
574
|
+
warningService,
|
564
575
|
} = options;
|
565
576
|
|
566
577
|
debug(
|
@@ -622,10 +633,7 @@ class ConfigLoader {
|
|
622
633
|
}
|
623
634
|
|
624
635
|
if (emptyConfig) {
|
625
|
-
|
626
|
-
`Running ESLint with an empty config (from ${configFilePath}). Please double-check that this is what you want. If you want to run ESLint with an empty config, export [{}] to remove this warning.`,
|
627
|
-
"ESLintEmptyConfigWarning",
|
628
|
-
);
|
636
|
+
warningService.emitEmptyConfigWarning(configFilePath);
|
629
637
|
}
|
630
638
|
}
|
631
639
|
|
@@ -713,8 +721,11 @@ class LegacyConfigLoader extends ConfigLoader {
|
|
713
721
|
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
|
714
722
|
*/
|
715
723
|
constructor(options) {
|
716
|
-
|
717
|
-
|
724
|
+
const normalizedOptions = options.warningService
|
725
|
+
? options
|
726
|
+
: { ...options, warningService: new WarningService() };
|
727
|
+
super(normalizedOptions);
|
728
|
+
this.#options = normalizedOptions;
|
718
729
|
}
|
719
730
|
|
720
731
|
/**
|
package/lib/config/config.js
CHANGED
@@ -265,6 +265,27 @@ function getObjectId(object) {
|
|
265
265
|
return name;
|
266
266
|
}
|
267
267
|
|
268
|
+
/**
|
269
|
+
* Asserts that a value is not a function.
|
270
|
+
* @param {any} value The value to check.
|
271
|
+
* @param {string} key The key of the value in the object.
|
272
|
+
* @param {string} objectKey The key of the object being checked.
|
273
|
+
* @returns {void}
|
274
|
+
* @throws {TypeError} If the value is a function.
|
275
|
+
*/
|
276
|
+
function assertNotFunction(value, key, objectKey) {
|
277
|
+
if (typeof value === "function") {
|
278
|
+
const error = new TypeError(
|
279
|
+
`Cannot serialize key "${key}" in "${objectKey}": Function values are not supported.`,
|
280
|
+
);
|
281
|
+
|
282
|
+
error.messageTemplate = "config-serialize-function";
|
283
|
+
error.messageData = { key, objectKey };
|
284
|
+
|
285
|
+
throw error;
|
286
|
+
}
|
287
|
+
}
|
288
|
+
|
268
289
|
/**
|
269
290
|
* Converts a languageOptions object to a JSON representation.
|
270
291
|
* @param {Record<string, any>} languageOptions The options to create a JSON
|
@@ -274,6 +295,14 @@ function getObjectId(object) {
|
|
274
295
|
* @throws {TypeError} If a function is found in the languageOptions.
|
275
296
|
*/
|
276
297
|
function languageOptionsToJSON(languageOptions, objectKey = "languageOptions") {
|
298
|
+
if (typeof languageOptions.toJSON === "function") {
|
299
|
+
const result = languageOptions.toJSON();
|
300
|
+
|
301
|
+
assertNotFunction(result, "toJSON", objectKey);
|
302
|
+
|
303
|
+
return result;
|
304
|
+
}
|
305
|
+
|
277
306
|
const result = {};
|
278
307
|
|
279
308
|
for (const [key, value] of Object.entries(languageOptions)) {
|
@@ -281,7 +310,10 @@ function languageOptionsToJSON(languageOptions, objectKey = "languageOptions") {
|
|
281
310
|
if (typeof value === "object") {
|
282
311
|
const name = getObjectId(value);
|
283
312
|
|
284
|
-
if (
|
313
|
+
if (typeof value.toJSON === "function") {
|
314
|
+
result[key] = value.toJSON();
|
315
|
+
assertNotFunction(result[key], key, objectKey);
|
316
|
+
} else if (name && hasMethod(value)) {
|
285
317
|
result[key] = name;
|
286
318
|
} else {
|
287
319
|
result[key] = languageOptionsToJSON(value, key);
|
@@ -289,16 +321,7 @@ function languageOptionsToJSON(languageOptions, objectKey = "languageOptions") {
|
|
289
321
|
continue;
|
290
322
|
}
|
291
323
|
|
292
|
-
|
293
|
-
const error = new TypeError(
|
294
|
-
`Cannot serialize key "${key}" in ${objectKey}: Function values are not supported.`,
|
295
|
-
);
|
296
|
-
|
297
|
-
error.messageTemplate = "config-serialize-function";
|
298
|
-
error.messageData = { key, objectKey };
|
299
|
-
|
300
|
-
throw error;
|
301
|
-
}
|
324
|
+
assertNotFunction(value, key, objectKey);
|
302
325
|
}
|
303
326
|
|
304
327
|
result[key] = value;
|
package/lib/eslint/eslint.js
CHANGED
@@ -40,6 +40,7 @@ const { pathToFileURL } = require("node:url");
|
|
40
40
|
const LintResultCache = require("../cli-engine/lint-result-cache");
|
41
41
|
const { Retrier } = require("@humanwhocodes/retry");
|
42
42
|
const { ConfigLoader, LegacyConfigLoader } = require("../config/config-loader");
|
43
|
+
const { WarningService } = require("../services/warning-service");
|
43
44
|
|
44
45
|
/*
|
45
46
|
* This is necessary to allow overwriting writeFile for testing purposes.
|
@@ -431,10 +432,12 @@ class ESLint {
|
|
431
432
|
constructor(options = {}) {
|
432
433
|
const defaultConfigs = [];
|
433
434
|
const processedOptions = processOptions(options);
|
435
|
+
const warningService = new WarningService();
|
434
436
|
const linter = new Linter({
|
435
437
|
cwd: processedOptions.cwd,
|
436
438
|
configType: "flat",
|
437
439
|
flags: mergeEnvironmentFlags(processedOptions.flags),
|
440
|
+
warningService,
|
438
441
|
});
|
439
442
|
|
440
443
|
const cacheFilePath = getCacheFile(
|
@@ -457,6 +460,7 @@ class ESLint {
|
|
457
460
|
hasUnstableNativeNodeJsTSConfigFlag: linter.hasFlag(
|
458
461
|
"unstable_native_nodejs_ts_config",
|
459
462
|
),
|
463
|
+
warningService,
|
460
464
|
};
|
461
465
|
|
462
466
|
this.#configLoader = linter.hasFlag("unstable_config_lookup_from_file")
|
@@ -496,10 +500,7 @@ class ESLint {
|
|
496
500
|
|
497
501
|
// Check for the .eslintignore file, and warn if it's present.
|
498
502
|
if (existsSync(path.resolve(processedOptions.cwd, ".eslintignore"))) {
|
499
|
-
|
500
|
-
'The ".eslintignore" file is no longer supported. Switch to using the "ignores" property in "eslint.config.js": https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files',
|
501
|
-
"ESLintIgnoreWarning",
|
502
|
-
);
|
503
|
+
warningService.emitESLintIgnoreWarning();
|
503
504
|
}
|
504
505
|
}
|
505
506
|
|
@@ -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
|
/**
|
package/lib/linter/linter.js
CHANGED
@@ -27,7 +27,6 @@ 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"),
|
@@ -65,8 +64,8 @@ const { FileContext } = require("./file-context");
|
|
65
64
|
const { ProcessorService } = require("../services/processor-service");
|
66
65
|
const { containsDifferentProperty } = require("../shared/option-utils");
|
67
66
|
const { Config } = require("../config/config");
|
68
|
-
const
|
69
|
-
const
|
67
|
+
const { WarningService } = require("../services/warning-service");
|
68
|
+
const { SourceCodeTraverser } = require("./source-code-traverser");
|
70
69
|
|
71
70
|
//------------------------------------------------------------------------------
|
72
71
|
// Typedefs
|
@@ -113,6 +112,7 @@ const STEP_KIND_CALL = 2;
|
|
113
112
|
* @property {Map<string, Parser>} parserMap The loaded parsers.
|
114
113
|
* @property {{ passes: TimePass[]; }} times The times spent on applying a rule to a file (see `stats` option).
|
115
114
|
* @property {Rules} ruleMap The loaded rules.
|
115
|
+
* @property {WarningService} warningService The warning service.
|
116
116
|
*/
|
117
117
|
|
118
118
|
/**
|
@@ -1177,9 +1177,6 @@ function runRules(
|
|
1177
1177
|
) {
|
1178
1178
|
const emitter = createEmitter();
|
1179
1179
|
|
1180
|
-
// must happen first to assign all node.parent properties
|
1181
|
-
const eventQueue = sourceCode.traverse();
|
1182
|
-
|
1183
1180
|
/*
|
1184
1181
|
* Create a frozen object with the ruleContext properties and methods that are shared by all rules.
|
1185
1182
|
* All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
|
@@ -1199,6 +1196,7 @@ function runRules(
|
|
1199
1196
|
});
|
1200
1197
|
|
1201
1198
|
const lintingProblems = [];
|
1199
|
+
const steps = sourceCode.traverse();
|
1202
1200
|
|
1203
1201
|
Object.keys(configuredRules).forEach(ruleId => {
|
1204
1202
|
const severity = Config.getRuleNumericSeverity(configuredRules[ruleId]);
|
@@ -1345,40 +1343,9 @@ function runRules(
|
|
1345
1343
|
});
|
1346
1344
|
});
|
1347
1345
|
|
1348
|
-
const
|
1349
|
-
visitorKeys: sourceCode.visitorKeys ?? language.visitorKeys,
|
1350
|
-
fallback: Traverser.getKeys,
|
1351
|
-
matchClass: language.matchesSelectorClass ?? (() => false),
|
1352
|
-
nodeTypeKey: language.nodeTypeKey,
|
1353
|
-
});
|
1354
|
-
|
1355
|
-
for (const step of eventQueue) {
|
1356
|
-
switch (step.kind) {
|
1357
|
-
case STEP_KIND_VISIT: {
|
1358
|
-
try {
|
1359
|
-
if (step.phase === 1) {
|
1360
|
-
eventGenerator.enterNode(step.target);
|
1361
|
-
} else {
|
1362
|
-
eventGenerator.leaveNode(step.target);
|
1363
|
-
}
|
1364
|
-
} catch (err) {
|
1365
|
-
err.currentNode = step.target;
|
1366
|
-
throw err;
|
1367
|
-
}
|
1368
|
-
break;
|
1369
|
-
}
|
1370
|
-
|
1371
|
-
case STEP_KIND_CALL: {
|
1372
|
-
emitter.emit(step.target, ...step.args);
|
1373
|
-
break;
|
1374
|
-
}
|
1346
|
+
const traverser = SourceCodeTraverser.getInstance(language);
|
1375
1347
|
|
1376
|
-
|
1377
|
-
throw new Error(
|
1378
|
-
`Invalid traversal step found: "${step.type}".`,
|
1379
|
-
);
|
1380
|
-
}
|
1381
|
-
}
|
1348
|
+
traverser.traverseSync(sourceCode, emitter, { steps });
|
1382
1349
|
|
1383
1350
|
return lintingProblems;
|
1384
1351
|
}
|
@@ -1483,8 +1450,14 @@ class Linter {
|
|
1483
1450
|
* @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
|
1484
1451
|
* @param {Array<string>} [config.flags] the feature flags to enable.
|
1485
1452
|
* @param {"flat"|"eslintrc"} [config.configType="flat"] the type of config used.
|
1453
|
+
* @param {WarningService} [config.warningService] The warning service to use.
|
1486
1454
|
*/
|
1487
|
-
constructor({
|
1455
|
+
constructor({
|
1456
|
+
cwd,
|
1457
|
+
configType = "flat",
|
1458
|
+
flags = [],
|
1459
|
+
warningService = new WarningService(),
|
1460
|
+
} = {}) {
|
1488
1461
|
const processedFlags = [];
|
1489
1462
|
|
1490
1463
|
flags.forEach(flag => {
|
@@ -1492,11 +1465,10 @@ class Linter {
|
|
1492
1465
|
const inactiveFlagData = inactiveFlags.get(flag);
|
1493
1466
|
const inactivityReason =
|
1494
1467
|
getInactivityReasonMessage(inactiveFlagData);
|
1468
|
+
const message = `The flag '${flag}' is inactive: ${inactivityReason}`;
|
1495
1469
|
|
1496
1470
|
if (typeof inactiveFlagData.replacedBy === "undefined") {
|
1497
|
-
throw new Error(
|
1498
|
-
`The flag '${flag}' is inactive: ${inactivityReason}`,
|
1499
|
-
);
|
1471
|
+
throw new Error(message);
|
1500
1472
|
}
|
1501
1473
|
|
1502
1474
|
// if there's a replacement, enable it instead of original
|
@@ -1504,10 +1476,7 @@ class Linter {
|
|
1504
1476
|
processedFlags.push(inactiveFlagData.replacedBy);
|
1505
1477
|
}
|
1506
1478
|
|
1507
|
-
|
1508
|
-
`The flag '${flag}' is inactive: ${inactivityReason}`,
|
1509
|
-
`ESLintInactiveFlag_${flag}`,
|
1510
|
-
);
|
1479
|
+
warningService.emitInactiveFlagWarning(flag, message);
|
1511
1480
|
|
1512
1481
|
return;
|
1513
1482
|
}
|
@@ -1528,6 +1497,7 @@ class Linter {
|
|
1528
1497
|
configType, // TODO: Remove after flat config conversion
|
1529
1498
|
parserMap: new Map([["espree", espree]]),
|
1530
1499
|
ruleMap: new Rules(),
|
1500
|
+
warningService,
|
1531
1501
|
});
|
1532
1502
|
|
1533
1503
|
this.version = pkg.version;
|
@@ -2710,6 +2680,14 @@ class Linter {
|
|
2710
2680
|
options && typeof options.fix !== "undefined" ? options.fix : true;
|
2711
2681
|
const stats = options?.stats;
|
2712
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
|
+
|
2713
2691
|
/**
|
2714
2692
|
* This loop continues until one of the following is true:
|
2715
2693
|
*
|
@@ -2719,14 +2697,6 @@ class Linter {
|
|
2719
2697
|
* That means anytime a fix is successfully applied, there will be another pass.
|
2720
2698
|
* Essentially, guaranteeing a minimum of two passes.
|
2721
2699
|
*/
|
2722
|
-
const slots = internalSlotsMap.get(this);
|
2723
|
-
|
2724
|
-
// Remove lint times from the last run.
|
2725
|
-
if (stats) {
|
2726
|
-
delete slots.times;
|
2727
|
-
slots.fixPasses = 0;
|
2728
|
-
}
|
2729
|
-
|
2730
2700
|
do {
|
2731
2701
|
passNumber++;
|
2732
2702
|
let tTotal;
|
@@ -2798,9 +2768,8 @@ class Linter {
|
|
2798
2768
|
debug(
|
2799
2769
|
`Circular fixes detected after pass ${passNumber}. Exiting fix loop.`,
|
2800
2770
|
);
|
2801
|
-
|
2802
|
-
|
2803
|
-
"ESLintCircularFixesWarning",
|
2771
|
+
slots.warningService.emitCircularFixesWarning(
|
2772
|
+
options?.filename ?? "text",
|
2804
2773
|
);
|
2805
2774
|
break;
|
2806
2775
|
}
|