fix(linter): update allowed ESLint config file extensions (#30127)

ESLint added experimental support for typescript config files since
[9.9.0](https://eslint.org/blog/2024/08/eslint-v9.9.0-released/#experimental-typescript-configuration-files),
and as of
[9.18.0](https://eslint.org/blog/2025/01/eslint-v9.18.0-released/#stable-typescript-configuration-file-support)
that support is stable. This PR add ts/mts/cts to the list of known
eslint config files, and adds the same extensions to config file
generators

## Current Behavior
When using the eslint executor with a ts file, returns error "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"

When using the eslint plugin, the inferred task is not created for
projects that do not have a non-ts eslint config.

### Workarounds
- Compiling ts rules/configs in a project. Introduces other issues
- Using jiti or comparable
- For plugin users, having a fake eslint.config.js at the root allows
the inferred task to be created. ESLint will still use the ts config.
  - Cache targets are wrong
  - Complications in non-monorepo workspaces

## Expected Behavior
When using the eslint executor with a ts file, no error is thrown.

When using the eslint plugin with a ts file, the inferred task is
created.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->
No issues, but addresses [this
discussion](https://github.com/nrwl/nx/discussions/29710#discussion-7856165)

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
This commit is contained in:
Torin 2025-06-09 07:29:19 -06:00 committed by GitHub
parent f9c427a80b
commit f1c090b640
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 21 additions and 10 deletions

View File

@ -137,7 +137,7 @@ describe('addLinting generator', () => {
"error", "error",
{ {
ignoredFiles: [ ignoredFiles: [
"{projectRoot}/eslint.config.{js,cjs,mjs}" "{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}"
] ]
} }
] ]
@ -206,7 +206,7 @@ describe('addLinting generator', () => {
{ {
enforceBuildableLibDependency: true, enforceBuildableLibDependency: true,
allow: [ allow: [
"^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?js$" "^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?[jt]s$"
], ],
depConstraints: [ depConstraints: [
{ {

View File

@ -137,7 +137,7 @@ export const getGlobalFlatEslintConfiguration = (
allow: [ allow: [
// This allows a root project to be present without causing lint errors // This allows a root project to be present without causing lint errors
// since all projects will depend on this base file. // since all projects will depend on this base file.
'^.*/eslint(\\.base)?\\.config\\.[cm]?js$', '^.*/eslint(\\.base)?\\.config\\.[cm]?[jt]s$',
], ],
depConstraints: [ depConstraints: [
{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] }, { sourceTag: '*', onlyDependOnLibsWithTags: ['*'] },

View File

@ -308,7 +308,7 @@ describe('@nx/eslint:lint-project', () => {
{ {
enforceBuildableLibDependency: true, enforceBuildableLibDependency: true,
allow: [ allow: [
"^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?js$" "^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?[jt]s$"
], ],
depConstraints: [ depConstraints: [
{ {
@ -379,7 +379,7 @@ describe('@nx/eslint:lint-project', () => {
{ {
enforceBuildableLibDependency: true, enforceBuildableLibDependency: true,
allow: [ allow: [
"^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?js$" "^.*/eslint(\\\\.base)?\\\\.config\\\\.[cm]?[jt]s$"
], ],
depConstraints: [ depConstraints: [
{ {
@ -495,7 +495,9 @@ describe('@nx/eslint:lint-project', () => {
"@nx/dependency-checks": [ "@nx/dependency-checks": [
"error", "error",
{ {
"ignoredFiles": ["{projectRoot}/eslint.config.{js,cjs,mjs}"] "ignoredFiles": [
"{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}"
]
} }
] ]
} }

View File

@ -293,8 +293,10 @@ function createEsLintConfiguration(
'@nx/dependency-checks': [ '@nx/dependency-checks': [
'error', 'error',
{ {
// With flat configs, we don't want to include imports in the eslint js/cjs/mjs files to be checked // With flat configs, we don't want to include imports in the eslint js/cjs/mjs/ts/cts/mts files to be checked
ignoredFiles: ['{projectRoot}/eslint.config.{js,cjs,mjs}'], ignoredFiles: [
'{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
],
}, },
], ],
}, },

View File

@ -5,13 +5,20 @@ export const eslintFlatConfigFilenames = [
'eslint.config.cjs', 'eslint.config.cjs',
'eslint.config.js', 'eslint.config.js',
'eslint.config.mjs', 'eslint.config.mjs',
'eslint.config.cts',
'eslint.config.ts',
'eslint.config.mts',
]; ];
export const baseEslintConfigFilenames = [ export const baseEslintConfigFilenames = [
'eslint.base.js', 'eslint.base.js',
'eslint.base.ts',
'eslint.base.config.cjs', 'eslint.base.config.cjs',
'eslint.base.config.js', 'eslint.base.config.js',
'eslint.base.config.mjs', 'eslint.base.config.mjs',
'eslint.base.config.cts',
'eslint.base.config.ts',
'eslint.base.config.mts',
]; ];
export function getRootESLintFlatConfigFilename(tree: Tree): string { export function getRootESLintFlatConfigFilename(tree: Tree): string {

View File

@ -159,7 +159,7 @@ describe('lint-checks generator', () => {
"error", "error",
{ {
"ignoredFiles": [ "ignoredFiles": [
"{projectRoot}/eslint.config.{js,cjs,mjs}", "{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}",
], ],
}, },
], ],

View File

@ -296,7 +296,7 @@ describe('@nx/vite:configuration', () => {
'error', 'error',
{ {
ignoredFiles: [ ignoredFiles: [
'{projectRoot}/eslint.config.{js,cjs,mjs}', '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
'{projectRoot}/vite.config.{js,ts,mjs,mts}', '{projectRoot}/vite.config.{js,ts,mjs,mts}',
], ],
}, },