Skip to content

Commit 8462387

Browse files
benpsnyderFrozenPandaz
authored andcommitted
feat(linter): support eslint.config.cjs and *.cjs extension with flat config (#26637)
(cherry picked from commit 81fe132)
1 parent 95f851c commit 8462387

File tree

5 files changed

+38
-14
lines changed

5 files changed

+38
-14
lines changed

packages/eslint/src/executors/lint/utility/eslint-utils.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ describe('eslint-utils', () => {
162162
});
163163

164164
describe('ESLint Flat Config', () => {
165-
it('should throw if a non eslint.config.js file is used with ESLint Flat Config', async () => {
165+
it('should throw if a non eslint.config.js or eslint.config.cjs file is used with ESLint Flat Config', async () => {
166166
await expect(
167167
resolveAndInstantiateESLint('./.eslintrc.json', {} as any, true)
168168
).rejects.toThrowErrorMatchingInlineSnapshot(
169-
`"When using the new Flat Config with ESLint, all configs must be named eslint.config.js and .eslintrc files may not be used. See https://eslint.org/docs/latest/use/configure/configuration-files-new"`
169+
`"When using the new Flat Config with ESLint, all configs must be named eslint.config.js or eslint.config.cjs and .eslintrc files may not be used. See https://eslint.org/docs/latest/use/configure/configuration-files"`
170170
);
171171
});
172172

packages/eslint/src/executors/lint/utility/eslint-utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ export async function resolveAndInstantiateESLint(
1010
) {
1111
if (useFlatConfig && eslintConfigPath && !isFlatConfig(eslintConfigPath)) {
1212
throw new Error(
13-
'When using the new Flat Config with ESLint, all configs must be named eslint.config.js and .eslintrc files may not be used. See https://eslint.org/docs/latest/use/configure/configuration-files-new'
13+
// todo: add support for eslint.config.mjs,
14+
'When using the new Flat Config with ESLint, all configs must be named eslint.config.js or eslint.config.cjs and .eslintrc files may not be used. See https://eslint.org/docs/latest/use/configure/configuration-files'
1415
);
1516
}
1617
const ESLint = await resolveESLintClass(useFlatConfig);

packages/eslint/src/generators/utils/eslint-file.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import {
77
} from '@nx/devkit';
88
import type { Tree } from '@nx/devkit';
99
import type { Linter } from 'eslint';
10-
import { useFlatConfig } from '../../utils/flat-config';
10+
import {
11+
flatConfigEslintFilename,
12+
useFlatConfig,
13+
} from '../../utils/flat-config';
1114
import {
1215
addBlockToFlatConfigExport,
1316
addCompatToFlatConfig,
@@ -174,7 +177,7 @@ export function addOverrideToLintConfig(
174177
if (useFlatConfig(tree)) {
175178
const fileName = joinPathFragments(
176179
root,
177-
isBase ? baseEsLintFlatConfigFile : 'eslint.config.js'
180+
isBase ? baseEsLintFlatConfigFile : flatConfigEslintFilename(tree)
178181
);
179182
const flatOverride = generateFlatOverride(override);
180183
let content = tree.read(fileName, 'utf8');
@@ -220,7 +223,7 @@ export function updateOverrideInLintConfig(
220223
) => Linter.ConfigOverride<Linter.RulesRecord>
221224
) {
222225
if (useFlatConfig(tree)) {
223-
const fileName = joinPathFragments(root, 'eslint.config.js');
226+
const fileName = joinPathFragments(root, flatConfigEslintFilename(tree));
224227
let content = tree.read(fileName, 'utf8');
225228
content = replaceOverride(content, root, lookup, update);
226229
tree.write(fileName, content);
@@ -262,7 +265,7 @@ export function lintConfigHasOverride(
262265
if (useFlatConfig(tree)) {
263266
const fileName = joinPathFragments(
264267
root,
265-
isBase ? baseEsLintFlatConfigFile : 'eslint.config.js'
268+
isBase ? baseEsLintFlatConfigFile : flatConfigEslintFilename(tree)
266269
);
267270
const content = tree.read(fileName, 'utf8');
268271
return hasOverride(content, lookup);
@@ -282,7 +285,7 @@ export function replaceOverridesInLintConfig(
282285
overrides: Linter.ConfigOverride<Linter.RulesRecord>[]
283286
) {
284287
if (useFlatConfig(tree)) {
285-
const fileName = joinPathFragments(root, 'eslint.config.js');
288+
const fileName = joinPathFragments(root, flatConfigEslintFilename(tree));
286289
let content = tree.read(fileName, 'utf8');
287290
// we will be using compat here so we need to make sure it's added
288291
if (overrides.some(overrideNeedsCompat)) {
@@ -311,7 +314,7 @@ export function addExtendsToLintConfig(
311314
) {
312315
const plugins = Array.isArray(plugin) ? plugin : [plugin];
313316
if (useFlatConfig(tree)) {
314-
const fileName = joinPathFragments(root, 'eslint.config.js');
317+
const fileName = joinPathFragments(root, flatConfigEslintFilename(tree));
315318
const pluginExtends = generatePluginExtendsElement(plugins);
316319
let content = tree.read(fileName, 'utf8');
317320
content = addCompatToFlatConfig(content);
@@ -341,7 +344,7 @@ export function addPluginsToLintConfig(
341344
) {
342345
const plugins = Array.isArray(plugin) ? plugin : [plugin];
343346
if (useFlatConfig(tree)) {
344-
const fileName = joinPathFragments(root, 'eslint.config.js');
347+
const fileName = joinPathFragments(root, flatConfigEslintFilename(tree));
345348
let content = tree.read(fileName, 'utf8');
346349
const mappedPlugins: { name: string; varName: string; imp: string }[] = [];
347350
plugins.forEach((name) => {
@@ -369,7 +372,7 @@ export function addIgnoresToLintConfig(
369372
ignorePatterns: string[]
370373
) {
371374
if (useFlatConfig(tree)) {
372-
const fileName = joinPathFragments(root, 'eslint.config.js');
375+
const fileName = joinPathFragments(root, flatConfigEslintFilename(tree));
373376
const block = generateAst<ts.ObjectLiteralExpression>({
374377
ignores: ignorePatterns.map((path) => mapFilePath(path)),
375378
});

packages/eslint/src/utils/config-file.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { existsSync, statSync } from 'fs';
22
import { basename, dirname, join, resolve } from 'path';
3+
import { eslintFlatConfigFilenames } from './flat-config';
34

4-
// TODO(leo): add support for eslint.config.mjs and eslint.config.cjs
5-
export const ESLINT_FLAT_CONFIG_FILENAMES = ['eslint.config.js'];
5+
export const ESLINT_FLAT_CONFIG_FILENAMES = eslintFlatConfigFilenames;
66

77
export const ESLINT_OLD_CONFIG_FILENAMES = [
88
'.eslintrc',
@@ -40,6 +40,7 @@ export function findFlatConfigFile(
4040
ESLINT_FLAT_CONFIG_FILENAMES
4141
);
4242
if (configFilePath) {
43+
console.log(`Found eslint flat config file at: ${configFilePath}`);
4344
return configFilePath;
4445
}
4546
if (currentDir === workspaceRoot) {
Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
import { Tree } from '@nx/devkit';
22

3+
// todo: add support for eslint.config.mjs,
4+
export const eslintFlatConfigFilenames = [
5+
'eslint.config.js',
6+
'eslint.config.cjs',
7+
];
8+
9+
export function flatConfigEslintFilename(tree: Tree): string {
10+
for (const file of eslintFlatConfigFilenames) {
11+
if (tree.exists(file)) {
12+
return file;
13+
}
14+
}
15+
throw new Error('Could not find flat config file');
16+
}
17+
318
export function useFlatConfig(tree: Tree): boolean {
4-
return tree.exists('eslint.config.js');
19+
try {
20+
return !!flatConfigEslintFilename(tree);
21+
} catch {
22+
return false;
23+
}
524
}

0 commit comments

Comments
 (0)