Skip to content

Commit

Permalink
feat: unflag TypeScript config files (#19266)
Browse files Browse the repository at this point in the history
  • Loading branch information
fasttime authored Dec 27, 2024
1 parent 87a9352 commit 8efc2d0
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 166 deletions.
14 changes: 1 addition & 13 deletions docs/src/use/configure/configuration-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,18 +517,6 @@ For more information about using feature flags, see [Feature Flags](../../flags/

## TypeScript Configuration Files

::: warning
This feature is currently experimental and may change in future versions.
:::

You need to enable this feature through the `unstable_ts_config` feature flag:

```bash
npx eslint --flag unstable_ts_config
```

For more information about using feature flags, see [Feature Flags](../../flags/).

For Deno and Bun, TypeScript configuration files are natively supported; for Node.js, you must install the optional dev dependency [`jiti`](https://github.com/unjs/jiti) in version 2.0.0 or later in your project (this dependency is not automatically installed by ESLint):

```bash
Expand Down Expand Up @@ -591,5 +579,5 @@ If you have multiple ESLint configuration files, ESLint prioritizes JavaScript f
To override this behavior, use the `--config` or `-c` command line option to specify a different configuration file:

```bash
npx eslint --flag unstable_ts_config --config eslint.config.ts
npx eslint --config eslint.config.ts
```
7 changes: 3 additions & 4 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,16 +341,15 @@ const cli = {
/**
* Calculates the command string for the --inspect-config operation.
* @param {string} configFile The path to the config file to inspect.
* @param {boolean} hasUnstableTSConfigFlag `true` if the `unstable_ts_config` flag is enabled, `false` if it's not.
* @returns {Promise<string>} The command string to execute.
*/
async calculateInspectConfigFlags(configFile, hasUnstableTSConfigFlag) {
async calculateInspectConfigFlags(configFile) {

// find the config file
const {
configFilePath,
basePath
} = await locateConfigFileToUse({ cwd: process.cwd(), configFile }, hasUnstableTSConfigFlag);
} = await locateConfigFileToUse({ cwd: process.cwd(), configFile });

return ["--config", configFilePath, "--basePath", basePath];
},
Expand Down Expand Up @@ -451,7 +450,7 @@ const cli = {
try {
const flatOptions = await translateOptions(options, "flat");
const spawn = require("cross-spawn");
const flags = await cli.calculateInspectConfigFlags(flatOptions.overrideConfigFile, flatOptions.flags ? flatOptions.flags.includes("unstable_ts_config") : false);
const flags = await cli.calculateInspectConfigFlags(flatOptions.overrideConfigFile);

spawn.sync("npx", ["@eslint/config-inspector@latest", ...flags], { encoding: "utf8", stdio: "inherit" });
} catch (error) {
Expand Down
31 changes: 9 additions & 22 deletions lib/config/config-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const { FlatConfigArray } = require("./flat-config-array");
* @property {Array<FlatConfigObject>} [defaultConfigs] The default configs to use.
* @property {Array<string>} [ignorePatterns] The ignore patterns to use.
* @property {FlatConfigObject|Array<FlatConfigObject>} overrideConfig The override config to use.
* @property {boolean} allowTS Indicates if TypeScript configuration files are allowed.
*/

//------------------------------------------------------------------------------
Expand All @@ -41,10 +40,7 @@ const { FlatConfigArray } = require("./flat-config-array");
const FLAT_CONFIG_FILENAMES = [
"eslint.config.js",
"eslint.config.mjs",
"eslint.config.cjs"
];

const TS_FLAT_CONFIG_FILENAMES = [
"eslint.config.cjs",
"eslint.config.ts",
"eslint.config.mts",
"eslint.config.cts"
Expand Down Expand Up @@ -119,10 +115,9 @@ function isRunningInDeno() {
/**
* Load the config array from the given filename.
* @param {string} filePath The filename to load from.
* @param {boolean} allowTS Indicates if TypeScript configuration files are allowed.
* @returns {Promise<any>} The config loaded from the config file.
*/
async function loadConfigFile(filePath, allowTS) {
async function loadConfigFile(filePath) {

debug(`Loading config from ${filePath}`);

Expand Down Expand Up @@ -171,7 +166,7 @@ async function loadConfigFile(filePath, allowTS) {
*
* When Node.js supports native TypeScript imports, we can remove this check.
*/
if (allowTS && isTS && !isDeno && !isBun) {
if (isTS && !isDeno && !isBun) {

// eslint-disable-next-line no-use-before-define -- `ConfigLoader.loadJiti` can be overwritten for testing
const { createJiti } = await ConfigLoader.loadJiti().catch(() => {
Expand Down Expand Up @@ -261,8 +256,7 @@ class ConfigLoader {
const resultPromise = ConfigLoader.locateConfigFileToUse({
useConfigFile: this.#options.configFile,
cwd: this.#options.cwd,
fromDirectory,
allowTS: this.#options.allowTS
fromDirectory
});

// ensure `ConfigLoader.locateConfigFileToUse` is called only once for `fromDirectory`
Expand Down Expand Up @@ -443,15 +437,10 @@ class ConfigLoader {
* @param {string|false|undefined} options.useConfigFile The path to the config file to use.
* @param {string} options.cwd Path to a directory that should be considered as the current working directory.
* @param {string} [options.fromDirectory] The directory from which to start searching. Defaults to `cwd`.
* @param {boolean} options.allowTS Indicates if TypeScript configuration files are allowed.
* @returns {Promise<{configFilePath:string|undefined,basePath:string}>} Location information for
* the config file.
*/
static async locateConfigFileToUse({ useConfigFile, cwd, fromDirectory = cwd, allowTS }) {

const configFilenames = allowTS
? [...FLAT_CONFIG_FILENAMES, ...TS_FLAT_CONFIG_FILENAMES]
: FLAT_CONFIG_FILENAMES;
static async locateConfigFileToUse({ useConfigFile, cwd, fromDirectory = cwd }) {

// determine where to load config file from
let configFilePath;
Expand All @@ -464,7 +453,7 @@ class ConfigLoader {
} else if (useConfigFile !== false) {
debug("Searching for eslint.config.js");
configFilePath = await findUp(
configFilenames,
FLAT_CONFIG_FILENAMES,
{ cwd: fromDirectory }
);

Expand Down Expand Up @@ -497,8 +486,7 @@ class ConfigLoader {
ignoreEnabled,
ignorePatterns,
overrideConfig,
defaultConfigs = [],
allowTS
defaultConfigs = []
} = options;

debug(`Calculating config array from config file ${configFilePath} and base path ${basePath}`);
Expand All @@ -509,7 +497,7 @@ class ConfigLoader {
if (configFilePath) {

debug(`Loading config file ${configFilePath}`);
const fileConfig = await loadConfigFile(configFilePath, allowTS);
const fileConfig = await loadConfigFile(configFilePath);

if (Array.isArray(fileConfig)) {
configs.push(...fileConfig);
Expand Down Expand Up @@ -618,8 +606,7 @@ class LegacyConfigLoader extends ConfigLoader {
if (!this.#configFilePath) {
this.#configFilePath = ConfigLoader.locateConfigFileToUse({
useConfigFile: this.#options.configFile,
cwd: this.#options.cwd,
allowTS: this.#options.allowTS
cwd: this.#options.cwd
});
}

Expand Down
7 changes: 2 additions & 5 deletions lib/eslint/eslint.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,15 +266,13 @@ function compareResultsByFilePath(a, b) {
* This function is used primarily by the `--inspect-config` option. For now,
* we will maintain the existing behavior, which is to search up from the cwd.
* @param {ESLintOptions} options The ESLint instance options.
* @param {boolean} allowTS `true` if the `unstable_ts_config` flag is enabled, `false` if it's not.
* @returns {Promise<{configFilePath:string|undefined;basePath:string}>} Location information for
* the config file.
*/
async function locateConfigFileToUse({ configFile, cwd }, allowTS) {
async function locateConfigFileToUse({ configFile, cwd }) {

const configLoader = new ConfigLoader({
cwd,
allowTS,
configFile
});

Expand Down Expand Up @@ -469,8 +467,7 @@ class ESLint {
configFile: processedOptions.configFile,
ignoreEnabled: processedOptions.ignore,
ignorePatterns: processedOptions.ignorePatterns,
defaultConfigs,
allowTS: processedOptions.flags.includes("unstable_ts_config")
defaultConfigs
};

this.#configLoader = processedOptions.flags.includes("unstable_config_lookup_from_file")
Expand Down
6 changes: 3 additions & 3 deletions lib/shared/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@
*/
const activeFlags = new Map([
["test_only", "Used only for testing."],
["unstable_config_lookup_from_file", "Look up `eslint.config.js` from the file being linted."],
["unstable_ts_config", "Enable TypeScript configuration files."]
["unstable_config_lookup_from_file", "Look up `eslint.config.js` from the file being linted."]
]);

/**
* The set of flags that used to be active but no longer have an effect.
* @type {Map<string, string>}
*/
const inactiveFlags = new Map([
["test_only_old", "Used only for testing."]
["test_only_old", "Used only for testing."],
["unstable_ts_config", "This flag is no longer required to enable TypeScript configuration files."]
]);

module.exports = {
Expand Down
31 changes: 2 additions & 29 deletions tests/fixtures/ts-config-files/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,15 @@
* and namespaces from other TypeScript files.
*/

export type RuleLevelAndOptions<Options extends any[] = any[]> = Prepend<
Partial<Options>,
RuleLevel
>;

export type StringSeverity = "off" | "warn" | "error";
import { Linter } from "eslint";

export const enum Severity {
"Off" = 0,
"Warn" = 1,
"Error" = 2,
}

export type RuleLevel = Severity | StringSeverity;

export type RuleEntry<Options extends any[] = any[]> =
| RuleLevel
| RuleLevelAndOptions<Options>;

export interface RulesRecord {
[rule: string]: RuleEntry;
}

export interface FlatConfig<Rules extends RulesRecord = RulesRecord> {
name?: string;
files?: Array<string | string[]>;
ignores?: string[];
linterOptions?: {
noInlineConfig?: boolean;
reportUnusedDisableDirectives?: Severity | StringSeverity | boolean;
};
processor?: string;
plugins?: Record<string, any>;
rules?: Partial<Rules>;
settings?: Record<string, unknown>;
}
export type FlatConfig = Linter.Config;

export namespace ESLintNameSpace {
export const enum StringSeverity {
Expand Down
Loading

0 comments on commit 8efc2d0

Please sign in to comment.