Skip to content

Commit 4f880ee

Browse files
authored
feat!: remove v10_* and inactive unstable_* flags (#20225)
* fix!: remove `v10_*` and inactive `unstable_*` flags * format * remove `LegacyConfigLoader` * fix ci * revert removal of CLI test * Merge branch 'main' into remove-v10-config-flags * update the migration guide * update v10 migration guide * revert formatting change * show just one form of the CLI option to avoid confusion
1 parent f18115c commit 4f880ee

9 files changed

Lines changed: 10087 additions & 11492 deletions

File tree

.trunk/trunk.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ lint:
6464
- linters: [markdownlint]
6565
paths:
6666
- CHANGELOG.md
67+
- linters: [eslint]
68+
paths:
69+
- tests/fixtures/**
70+
- docs/_examples/**
6771
actions:
6872
disabled:
6973
- trunk-announce

docs/src/use/configure/configuration-files.md

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -780,32 +780,16 @@ export default {
780780

781781
## Configuration File Resolution
782782

783-
When ESLint is run on the command line, it first checks the current working directory for `eslint.config.js`. If that file is found, then the search stops, otherwise it checks for `eslint.config.mjs`. If that file is found, then the search stops, otherwise it checks for `eslint.config.cjs`. If none of the files are found, it checks the parent directory for each file. This search continues until either a config file is found or the root directory is reached.
783+
When ESLint is run on the command line, it determines configuration for each target file by first looking in the directory that contains the file and then searching up ancestor directories until it finds an `eslint.config.*` file. This behavior improves support for monorepos, where subdirectories can have their own configuration files.
784784

785-
You can prevent this search for `eslint.config.js` by using the `-c` or `--config` option on the command line to specify an alternate configuration file, such as:
785+
You can prevent this search by using the `-c` or `--config` option on the command line to specify an alternate configuration file, such as:
786786

787787
{{ npx_tabs({
788788
package: "eslint",
789789
args: ["--config", "some-other-file.js", "**/*.js"]
790790
}) }}
791791

792-
In this case, ESLint does not search for `eslint.config.js` and instead uses `some-other-file.js`.
793-
794-
### Experimental Configuration File Resolution
795-
796-
::: warning
797-
This feature is experimental and its details may change before being finalized. This behavior will be the new lookup behavior starting in v10.0.0, but you can try it today using a feature flag.
798-
:::
799-
800-
You can use the `v10_config_lookup_from_file` flag to change the way ESLint searches for configuration files. Instead of searching from the current working directory, ESLint will search for a configuration file by first starting in the directory of the file being linted and then searching up its ancestor directories until it finds a `eslint.config.js` file (or any other extension of configuration file). This behavior is better for monorepos, where each subdirectory may have its own configuration file.
801-
802-
To use this feature on the command line, use the `--flag` flag:
803-
804-
```shell
805-
npx eslint --flag v10_config_lookup_from_file .
806-
```
807-
808-
For more information about using feature flags, see [Feature Flags](../../flags/).
792+
In this case, ESLint does not search for configuration files and instead uses `some-other-file.js`.
809793

810794
## TypeScript Configuration Files
811795

docs/src/use/migrate-to-10.0.0.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ The lists below are ordered roughly by the number of users each change is expect
1616
### Breaking changes for users
1717

1818
- [Node.js < v20.19, v21, v23 are no longer supported](#drop-old-node)
19+
- [New configuration file lookup algorithm](#config-lookup-from-file)
1920
- [`no-shadow-restricted-names` now reports `globalThis` by default](#no-shadow-restricted-names)
2021

2122
### Breaking changes for plugin developers
@@ -25,6 +26,7 @@ The lists below are ordered roughly by the number of users each change is expect
2526
### Breaking changes for integration developers
2627

2728
- [Node.js < v20.19, v21, v23 are no longer supported](#drop-old-node)
29+
- [New configuration file lookup algorithm](#config-lookup-from-file)
2830

2931
---
3032

@@ -40,6 +42,20 @@ ESLint is officially dropping support for these versions of Node.js starting wit
4042

4143
**Related issue(s):** [#19969](https://github.com/eslint/eslint/issues/19969)
4244

45+
## <a name="config-lookup-from-file"></a> New configuration file lookup algorithm
46+
47+
In ESLint v9, the alternate config lookup behavior could be enabled with the `v10_config_lookup_from_file` feature flag. This behavior made ESLint locate `eslint.config.*` by starting from the directory of each linted file and searching up towards the filesystem root. In ESLint v10, this behavior is now the default and the `v10_config_lookup_from_file` flag has been removed. Attempting to use this flag will now result in an error.
48+
49+
**To address:**
50+
51+
- Remove any usage of the flag in your setup:
52+
- CLI: remove `--flag v10_config_lookup_from_file`.
53+
- Environment: remove `v10_config_lookup_from_file` from `ESLINT_FLAGS`.
54+
- API: remove `"v10_config_lookup_from_file"` from the `flags` array passed to `new ESLint()` or `new Linter()`.
55+
- If you relied on the previous (cwd-based) lookup behavior, provide an explicit config path with `--config path/to/eslint.config.js`.
56+
57+
**Related issue(s):** [#19967](https://github.com/eslint/eslint/issues/19967)
58+
4359
## <a name="no-shadow-restricted-names"></a> `no-shadow-restricted-names` now reports `globalThis` by default
4460

4561
In ESLint v10, the [`no-shadow-restricted-names`](../rules/no-shadow-restricted-names) rule now treats `globalThis` as a restricted name by default. Consequently, the `reportGlobalThis` option now defaults to `true` (previously `false`). As a result, declarations such as `const globalThis = "foo";` or `function globalThis() {}` will now be reported by default.

lib/config/config-loader.js

Lines changed: 1 addition & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -666,151 +666,4 @@ class ConfigLoader {
666666
}
667667
}
668668

669-
/**
670-
* Encapsulates the loading and caching of configuration files when looking up
671-
* from the current working directory.
672-
*/
673-
class LegacyConfigLoader extends ConfigLoader {
674-
/**
675-
* The options to use when loading configuration files.
676-
* @type {ConfigLoaderOptions}
677-
*/
678-
#options;
679-
680-
/**
681-
* The cached config file path for this instance.
682-
* @type {Promise<{configFilePath:string,basePath:string}|undefined>}
683-
*/
684-
#configFilePath;
685-
686-
/**
687-
* The cached config array for this instance.
688-
* @type {FlatConfigArray|Promise<FlatConfigArray>}
689-
*/
690-
#configArray;
691-
692-
/**
693-
* Creates a new instance.
694-
* @param {ConfigLoaderOptions} options The options to use when loading configuration files.
695-
*/
696-
constructor(options) {
697-
const normalizedOptions = options.warningService
698-
? options
699-
: { ...options, warningService: new WarningService() };
700-
super(normalizedOptions);
701-
this.#options = normalizedOptions;
702-
}
703-
704-
/**
705-
* Determines which config file to use. This is determined by seeing if an
706-
* override config file was specified, and if so, using it; otherwise, as long
707-
* as override config file is not explicitly set to `false`, it will search
708-
* upwards from the cwd for a file named `eslint.config.js`.
709-
* @returns {Promise<{configFilePath:string|undefined,basePath:string}>} Location information for
710-
* the config file.
711-
*/
712-
#locateConfigFileToUse() {
713-
if (!this.#configFilePath) {
714-
this.#configFilePath = ConfigLoader.locateConfigFileToUse({
715-
useConfigFile: this.#options.configFile,
716-
cwd: this.#options.cwd,
717-
});
718-
}
719-
720-
return this.#configFilePath;
721-
}
722-
723-
/**
724-
* Calculates the config array for this run based on inputs.
725-
* @param {string} configFilePath The absolute path to the config file to use if not overridden.
726-
* @param {string} basePath The base path to use for relative paths in the config file.
727-
* @returns {Promise<FlatConfigArray>} The config array for `eslint`.
728-
*/
729-
async #calculateConfigArray(configFilePath, basePath) {
730-
// check for cached version first
731-
if (this.#configArray) {
732-
return this.#configArray;
733-
}
734-
735-
// ensure `ConfigLoader.calculateConfigArray` is called only once
736-
this.#configArray = ConfigLoader.calculateConfigArray(
737-
configFilePath,
738-
basePath,
739-
this.#options,
740-
);
741-
742-
// Unwrap the promise. This is primarily for the sync `getCachedConfigArrayForPath` method.
743-
this.#configArray = await this.#configArray;
744-
745-
return this.#configArray;
746-
}
747-
748-
/**
749-
* Returns the config file path for the given directory. This will either use
750-
* the override config file that was specified in the constructor options or
751-
* search for a config file from the directory of the file being linted.
752-
* @param {string} dirPath The directory path to get the config file path for.
753-
* @returns {Promise<string|undefined>} The config file path or `undefined` if not found.
754-
* @throws {Error} If `fileOrDirPath` is not a non-empty string.
755-
* @throws {Error} If `fileOrDirPath` is not an absolute path.
756-
*/
757-
async findConfigFileForPath(dirPath) {
758-
assertValidFilePath(dirPath);
759-
760-
const { configFilePath } = await this.#locateConfigFileToUse();
761-
762-
return configFilePath;
763-
}
764-
765-
/**
766-
* Returns a configuration object for the given file based on the CLI options.
767-
* This is the same logic used by the ESLint CLI executable to determine
768-
* configuration for each file it processes.
769-
* @param {string} dirPath The path of the directory to retrieve config for.
770-
* @returns {Promise<FlatConfigArray>} A configuration object for the file.
771-
*/
772-
async loadConfigArrayForDirectory(dirPath) {
773-
assertValidFilePath(dirPath);
774-
775-
debug(`[Legacy]: Calculating config for ${dirPath}`);
776-
777-
const { configFilePath, basePath } =
778-
await this.#locateConfigFileToUse();
779-
780-
debug(
781-
`[Legacy]: Using config file ${configFilePath} and base path ${basePath}`,
782-
);
783-
return this.#calculateConfigArray(configFilePath, basePath);
784-
}
785-
786-
/**
787-
* Returns a configuration array for the given directory based on the CLI options.
788-
* This is a synchronous operation and does not read any files from disk. It's
789-
* intended to be used in locations where we know the config file has already
790-
* been loaded and we just need to get the configuration for a file.
791-
* @param {string} dirPath The path of the directory to retrieve a config object for.
792-
* @returns {FlatConfigArray} A configuration object for the file.
793-
* @throws {Error} If `dirPath` is not a non-empty string.
794-
* @throws {Error} If `dirPath` is not an absolute path.
795-
* @throws {Error} If the config file was not already loaded.
796-
*/
797-
getCachedConfigArrayForPath(dirPath) {
798-
assertValidFilePath(dirPath);
799-
800-
debug(`[Legacy]: Looking up cached config for ${dirPath}`);
801-
802-
if (!this.#configArray) {
803-
throw new Error(`Could not find config file for ${dirPath}`);
804-
}
805-
806-
if (typeof this.#configArray.then === "function") {
807-
throw new Error(
808-
`Config array for ${dirPath} has not yet been calculated or an error occurred during the calculation`,
809-
);
810-
}
811-
812-
return this.#configArray;
813-
}
814-
}
815-
816-
module.exports = { ConfigLoader, LegacyConfigLoader };
669+
module.exports = { ConfigLoader };

lib/eslint/eslint-helpers.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const globParent = require("glob-parent");
2020
const { Linter } = require("../linter");
2121
const { getShorthandName } = require("../shared/naming");
2222
const LintResultCache = require("../cli-engine/lint-result-cache");
23-
const { ConfigLoader, LegacyConfigLoader } = require("../config/config-loader");
23+
const { ConfigLoader } = require("../config/config-loader");
2424
const createDebug = require("debug");
2525

2626
//-----------------------------------------------------------------------------
@@ -247,7 +247,7 @@ async function globMatch({ basePath, pattern }) {
247247
* to match.
248248
* @param {Array<string>} options.rawPatterns An array of glob patterns
249249
* as the user inputted them. Used for errors.
250-
* @param {ConfigLoader|LegacyConfigLoader} options.configLoader The config array to use for
250+
* @param {ConfigLoader} options.configLoader The config array to use for
251251
* determining what to ignore.
252252
* @param {boolean} options.errorOnUnmatchedPattern Determines if an error
253253
* should be thrown when a pattern is unmatched.
@@ -425,7 +425,7 @@ async function throwErrorForUnmatchedPatterns({
425425
* @param {Object} options The options for this function.
426426
* @param {Map<string,GlobSearch>} options.searches
427427
* A map of absolute path glob patterns to match.
428-
* @param {ConfigLoader|LegacyConfigLoader} options.configLoader The config loader to use for
428+
* @param {ConfigLoader} options.configLoader The config loader to use for
429429
* determining what to ignore.
430430
* @param {boolean} options.errorOnUnmatchedPattern Determines if an
431431
* unmatched glob pattern should throw an error.
@@ -506,7 +506,7 @@ async function globMultiSearch({
506506
* @param {boolean} args.globInputPaths true to interpret glob patterns,
507507
* false to not interpret glob patterns.
508508
* @param {string} args.cwd The current working directory to find from.
509-
* @param {ConfigLoader|LegacyConfigLoader} args.configLoader The config loader for the current run.
509+
* @param {ConfigLoader} args.configLoader The config loader for the current run.
510510
* @param {boolean} args.errorOnUnmatchedPattern Determines if an unmatched pattern
511511
* should throw an error.
512512
* @returns {Promise<Array<string>>} The fully resolved file paths.
@@ -1428,9 +1428,7 @@ function createConfigLoader(
14281428
warningService,
14291429
};
14301430

1431-
return linter.hasFlag("v10_config_lookup_from_file")
1432-
? new ConfigLoader(configLoaderOptions)
1433-
: new LegacyConfigLoader(configLoaderOptions);
1431+
return new ConfigLoader(configLoaderOptions);
14341432
}
14351433

14361434
//-----------------------------------------------------------------------------

lib/shared/flags.js

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@
2828
const activeFlags = new Map([
2929
["test_only", "Used only for testing."],
3030
["test_only_2", "Used only for testing."],
31-
[
32-
"v10_config_lookup_from_file",
33-
"Look up `eslint.config.js` from the file being linted.",
34-
],
3531
[
3632
"unstable_native_nodejs_ts_config",
3733
"Use native Node.js to load TypeScript configuration.",
@@ -66,21 +62,6 @@ const inactiveFlags = new Map([
6662
"Used only for testing flags whose features have been abandoned.",
6763
},
6864
],
69-
[
70-
"unstable_ts_config",
71-
{
72-
description: "Enable TypeScript configuration files.",
73-
replacedBy: null,
74-
},
75-
],
76-
[
77-
"unstable_config_lookup_from_file",
78-
{
79-
description:
80-
"Look up `eslint.config.js` from the file being linted.",
81-
replacedBy: "v10_config_lookup_from_file",
82-
},
83-
],
8465
]);
8566

8667
/**

tests/lib/cli.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3212,14 +3212,12 @@ describe("cli", () => {
32123212
});
32133213
});
32143214

3215-
describe("v10_config_lookup_from_file", () => {
3216-
const flag = "v10_config_lookup_from_file";
3217-
3215+
describe("config lookup from file", () => {
32183216
it("should throw an error when text is passed and no config file is found", async () => {
32193217
await stdAssert.rejects(
32203218
() =>
32213219
cli.execute(
3222-
`--flag ${flag} --stdin --stdin-filename /foo.js"`,
3220+
'--stdin --stdin-filename /foo.js"',
32233221
"var foo = 'bar';",
32243222
true,
32253223
),

0 commit comments

Comments
 (0)