@nx/eslint 20.3.0-canary.20241217-ee4de0b → 20.3.0-canary.20241219-2eb5243
Sign up to get free protection for your applications and to get access to all the features.
- package/migrations.json +5 -0
- package/package.json +3 -3
- package/src/generators/convert-to-flat-config/converters/json-converter.js +5 -1
- package/src/generators/convert-to-flat-config/generator.js +8 -8
- package/src/generators/convert-to-inferred/convert-to-inferred.js +1 -1
- package/src/generators/init/global-eslint-config.js +11 -2
- package/src/generators/init/init-migration.js +4 -4
- package/src/generators/init/init.js +2 -2
- package/src/generators/lint-project/lint-project.js +1 -2
- package/src/generators/lint-project/setup-root-eslint.js +1 -1
- package/src/generators/utils/eslint-file.js +70 -8
- package/src/generators/utils/flat-config/ast-utils.js +23 -1
- package/src/migrations/update-20-3-0/add-file-extensions-to-overrides.d.ts +2 -0
- package/src/migrations/update-20-3-0/add-file-extensions-to-overrides.js +49 -0
- package/src/utils/config-file.d.ts +2 -1
- package/src/utils/config-file.js +4 -2
- package/src/utils/flat-config.js +1 -1
package/migrations.json
CHANGED
@@ -24,6 +24,11 @@
|
|
24
24
|
"version": "20.2.0-beta.5",
|
25
25
|
"description": "Update TypeScript ESLint packages to v8.13.0 if they are already on v8",
|
26
26
|
"implementation": "./src/migrations/update-20-2-0/update-typescript-eslint-v8-13-0"
|
27
|
+
},
|
28
|
+
"add-file-extensions-to-overrides": {
|
29
|
+
"version": "20.3.0-beta.1",
|
30
|
+
"description": "Update ESLint flat config to include .cjs, .mjs, .cts, and .mts files in overrides (if needed)",
|
31
|
+
"implementation": "./src/migrations/update-20-3-0/add-file-extensions-to-overrides"
|
27
32
|
}
|
28
33
|
},
|
29
34
|
"packageJsonUpdates": {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@nx/eslint",
|
3
|
-
"version": "20.3.0-canary.
|
3
|
+
"version": "20.3.0-canary.20241219-2eb5243",
|
4
4
|
"private": false,
|
5
5
|
"description": "The ESLint plugin for Nx contains executors, generators and utilities used for linting JavaScript/TypeScript projects within an Nx workspace.",
|
6
6
|
"repository": {
|
@@ -35,8 +35,8 @@
|
|
35
35
|
"eslint": "^8.0.0 || ^9.0.0"
|
36
36
|
},
|
37
37
|
"dependencies": {
|
38
|
-
"@nx/devkit": "20.3.0-canary.
|
39
|
-
"@nx/js": "20.3.0-canary.
|
38
|
+
"@nx/devkit": "20.3.0-canary.20241219-2eb5243",
|
39
|
+
"@nx/js": "20.3.0-canary.20241219-2eb5243",
|
40
40
|
"semver": "^7.5.3",
|
41
41
|
"tslib": "^2.3.0",
|
42
42
|
"typescript": "~5.6.2"
|
@@ -17,6 +17,10 @@ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
|
|
17
17
|
let isESLintJSNeeded = false;
|
18
18
|
let combinedConfig = [];
|
19
19
|
let languageOptions = [];
|
20
|
+
// exclude dist and eslint config from being linted, which matches the default for new workspaces
|
21
|
+
exportElements.push((0, ast_utils_1.generateAst)({
|
22
|
+
ignores: ['**/dist'],
|
23
|
+
}));
|
20
24
|
if (config.extends) {
|
21
25
|
const extendsResult = addExtends(importsMap, exportElements, config);
|
22
26
|
isFlatCompatNeeded = extendsResult.isFlatCompatNeeded;
|
@@ -122,7 +126,7 @@ function addExtends(importsMap, configBlocks, config) {
|
|
122
126
|
if (imp.match(/\.eslintrc(.base)?\.json$/)) {
|
123
127
|
const localName = index ? `baseConfig${index}` : 'baseConfig';
|
124
128
|
configBlocks.push((0, ast_utils_1.generateSpreadElement)(localName));
|
125
|
-
const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, '$1eslint$2.config.
|
129
|
+
const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, '$1eslint$2.config.cjs');
|
126
130
|
importsMap.set(newImport, localName);
|
127
131
|
}
|
128
132
|
else {
|
@@ -15,9 +15,9 @@ async function convertToFlatConfigGenerator(tree, options) {
|
|
15
15
|
throw new Error('Only json and yaml eslint config files are supported for conversion');
|
16
16
|
}
|
17
17
|
const eslintIgnoreFiles = new Set(['.eslintignore']);
|
18
|
-
// convert root eslint config to eslint.config.
|
18
|
+
// convert root eslint config to eslint.config.cjs
|
19
19
|
convertRootToFlatConfig(tree, eslintFile);
|
20
|
-
// convert project eslint files to eslint.config.
|
20
|
+
// convert project eslint files to eslint.config.cjs
|
21
21
|
const projects = (0, devkit_1.getProjects)(tree);
|
22
22
|
for (const [project, projectConfig] of projects) {
|
23
23
|
convertProjectToFlatConfig(tree, project, projectConfig, (0, devkit_1.readNxJson)(tree), eslintIgnoreFiles);
|
@@ -37,9 +37,9 @@ async function convertToFlatConfigGenerator(tree, options) {
|
|
37
37
|
exports.default = convertToFlatConfigGenerator;
|
38
38
|
function convertRootToFlatConfig(tree, eslintFile) {
|
39
39
|
if (/\.base\.(js|json|yml|yaml)$/.test(eslintFile)) {
|
40
|
-
convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.
|
40
|
+
convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.cjs');
|
41
41
|
}
|
42
|
-
convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.
|
42
|
+
convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.cjs');
|
43
43
|
}
|
44
44
|
function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles) {
|
45
45
|
const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
|
@@ -67,7 +67,7 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
|
|
67
67
|
? p === '@nx/eslint/plugin'
|
68
68
|
: p.plugin === '@nx/eslint/plugin');
|
69
69
|
if (nxHasEsLintTargets || nxHasEsLintPlugin || eslintTargets.length > 0) {
|
70
|
-
convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, 'eslint.config.
|
70
|
+
convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, 'eslint.config.cjs', ignorePath);
|
71
71
|
eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
|
72
72
|
if (ignorePath) {
|
73
73
|
eslintIgnoreFiles.add(ignorePath);
|
@@ -83,17 +83,17 @@ function updateNxJsonConfig(tree) {
|
|
83
83
|
(0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
|
84
84
|
if (json.targetDefaults?.lint?.inputs) {
|
85
85
|
const inputSet = new Set(json.targetDefaults.lint.inputs);
|
86
|
-
inputSet.add('{workspaceRoot}/eslint.config.
|
86
|
+
inputSet.add('{workspaceRoot}/eslint.config.cjs');
|
87
87
|
json.targetDefaults.lint.inputs = Array.from(inputSet);
|
88
88
|
}
|
89
89
|
if (json.targetDefaults?.['@nx/eslint:lint']?.inputs) {
|
90
90
|
const inputSet = new Set(json.targetDefaults['@nx/eslint:lint'].inputs);
|
91
|
-
inputSet.add('{workspaceRoot}/eslint.config.
|
91
|
+
inputSet.add('{workspaceRoot}/eslint.config.cjs');
|
92
92
|
json.targetDefaults['@nx/eslint:lint'].inputs = Array.from(inputSet);
|
93
93
|
}
|
94
94
|
if (json.namedInputs?.production) {
|
95
95
|
const inputSet = new Set(json.namedInputs.production);
|
96
|
-
inputSet.add('!{projectRoot}/eslint.config.
|
96
|
+
inputSet.add('!{projectRoot}/eslint.config.cjs');
|
97
97
|
json.namedInputs.production = Array.from(inputSet);
|
98
98
|
}
|
99
99
|
return json;
|
@@ -33,7 +33,7 @@ function postTargetTransformer(target, tree, projectDetails, inferredTargetConfi
|
|
33
33
|
'default',
|
34
34
|
'{workspaceRoot}/.eslintrc.json',
|
35
35
|
'{workspaceRoot}/.eslintignore',
|
36
|
-
'{workspaceRoot}/eslint.config.
|
36
|
+
'{workspaceRoot}/eslint.config.cjs',
|
37
37
|
].includes(input));
|
38
38
|
if (inputs.length === 0) {
|
39
39
|
delete target.inputs;
|
@@ -85,7 +85,9 @@ const getGlobalFlatEslintConfiguration = (rootProject) => {
|
|
85
85
|
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)('flat/base'), { insertAtTheEnd: false });
|
86
86
|
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)('flat/typescript'));
|
87
87
|
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)('flat/javascript'));
|
88
|
-
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
|
88
|
+
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
|
89
|
+
ignores: ['**/dist'],
|
90
|
+
}));
|
89
91
|
if (!rootProject) {
|
90
92
|
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
|
91
93
|
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
|
@@ -108,7 +110,14 @@ const getGlobalFlatEslintConfiguration = (rootProject) => {
|
|
108
110
|
}));
|
109
111
|
}
|
110
112
|
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)({
|
111
|
-
files: [
|
113
|
+
files: [
|
114
|
+
'**/*.ts',
|
115
|
+
'**/*.tsx',
|
116
|
+
'**/*.js',
|
117
|
+
'**/*.jsx',
|
118
|
+
'**/*.cjs',
|
119
|
+
'**/*.mjs',
|
120
|
+
],
|
112
121
|
rules: {},
|
113
122
|
}));
|
114
123
|
return content;
|
@@ -27,9 +27,9 @@ function migrateConfigToMonorepoStyle(projects, tree, unitTestRunner, keepExisti
|
|
27
27
|
(0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
28
28
|
'@eslint/js': versions_1.eslintVersion,
|
29
29
|
}, undefined, keepExistingVersions);
|
30
|
-
tree.write(tree.exists('eslint.config.
|
31
|
-
? 'eslint.base.config.
|
32
|
-
: 'eslint.config.
|
30
|
+
tree.write(tree.exists('eslint.config.cjs')
|
31
|
+
? 'eslint.base.config.cjs'
|
32
|
+
: 'eslint.config.cjs', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)());
|
33
33
|
}
|
34
34
|
else {
|
35
35
|
const eslintFile = (0, eslint_file_1.findEslintFile)(tree, '.');
|
@@ -80,7 +80,7 @@ function migrateEslintFile(projectEslintPath, tree) {
|
|
80
80
|
let config = tree.read(projectEslintPath, 'utf-8');
|
81
81
|
// remove @nx plugin
|
82
82
|
config = (0, ast_utils_1.removePlugin)(config, '@nx', '@nx/eslint-plugin-nx');
|
83
|
-
// extend eslint.base.config.
|
83
|
+
// extend eslint.base.config.cjs
|
84
84
|
config = (0, ast_utils_1.addImportToFlatConfig)(config, 'baseConfig', `${(0, devkit_1.offsetFromRoot)((0, path_1.dirname)(projectEslintPath))}${baseFile}`);
|
85
85
|
config = (0, ast_utils_1.addBlockToFlatConfigExport)(config, (0, ast_utils_1.generateSpreadElement)('baseConfig'), { insertAtTheEnd: false });
|
86
86
|
// cleanup file extends
|
@@ -13,7 +13,7 @@ function updateProductionFileset(tree) {
|
|
13
13
|
const productionFileSet = nxJson.namedInputs?.production;
|
14
14
|
if (productionFileSet) {
|
15
15
|
productionFileSet.push('!{projectRoot}/.eslintrc.json');
|
16
|
-
productionFileSet.push('!{projectRoot}/eslint.config.
|
16
|
+
productionFileSet.push('!{projectRoot}/eslint.config.cjs');
|
17
17
|
// Dedupe and set
|
18
18
|
nxJson.namedInputs.production = Array.from(new Set(productionFileSet));
|
19
19
|
}
|
@@ -28,7 +28,7 @@ function addTargetDefaults(tree) {
|
|
28
28
|
'default',
|
29
29
|
`{workspaceRoot}/.eslintrc.json`,
|
30
30
|
`{workspaceRoot}/.eslintignore`,
|
31
|
-
`{workspaceRoot}/eslint.config.
|
31
|
+
`{workspaceRoot}/eslint.config.cjs`,
|
32
32
|
];
|
33
33
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
34
34
|
}
|
@@ -184,8 +184,7 @@ function createEsLintConfiguration(tree, options, projectConfig, setParserOption
|
|
184
184
|
});
|
185
185
|
const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes);
|
186
186
|
const content = (0, ast_utils_1.stringifyNodeList)(nodeList);
|
187
|
-
|
188
|
-
tree.write((0, path_1.join)(projectConfig.root, `eslint.config${ext}`), content);
|
187
|
+
tree.write((0, path_1.join)(projectConfig.root, `eslint.config.cjs`), content);
|
189
188
|
}
|
190
189
|
else {
|
191
190
|
(0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
|
@@ -38,7 +38,7 @@ function setUpLegacyRootEslintRc(tree, options) {
|
|
38
38
|
: () => { };
|
39
39
|
}
|
40
40
|
function setUpRootFlatConfig(tree, options) {
|
41
|
-
tree.write('eslint.config.
|
41
|
+
tree.write('eslint.config.cjs', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(options.rootProject));
|
42
42
|
return !options.skipPackageJson
|
43
43
|
? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
44
44
|
'@eslint/js': versions_1.eslint9__eslintVersion,
|
@@ -28,6 +28,10 @@ function findEslintFile(tree, projectRoot) {
|
|
28
28
|
if (projectRoot === undefined && tree.exists(config_file_1.baseEsLintFlatConfigFile)) {
|
29
29
|
return config_file_1.baseEsLintFlatConfigFile;
|
30
30
|
}
|
31
|
+
if (projectRoot === undefined &&
|
32
|
+
tree.exists(config_file_1.legacyBaseEsLintFlatConfigFile)) {
|
33
|
+
return config_file_1.legacyBaseEsLintFlatConfigFile;
|
34
|
+
}
|
31
35
|
projectRoot ??= '';
|
32
36
|
for (const file of config_file_1.ESLINT_CONFIG_FILENAMES) {
|
33
37
|
if (tree.exists((0, devkit_1.joinPathFragments)(projectRoot, file))) {
|
@@ -117,7 +121,18 @@ function addOverrideToLintConfig(tree, root, override, options = {
|
|
117
121
|
}) {
|
118
122
|
const isBase = options.checkBaseConfig && findEslintFile(tree, root).includes('.base');
|
119
123
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
120
|
-
|
124
|
+
let fileName;
|
125
|
+
if (isBase) {
|
126
|
+
fileName = (0, devkit_1.joinPathFragments)(root, config_file_1.baseEsLintFlatConfigFile);
|
127
|
+
}
|
128
|
+
else {
|
129
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
130
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
131
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
132
|
+
break;
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
121
136
|
const flatOverride = (0, ast_utils_1.generateFlatOverride)(override);
|
122
137
|
let content = tree.read(fileName, 'utf8');
|
123
138
|
// Check if the provided override using legacy eslintrc properties or plugins, if so we need to add compat
|
@@ -148,7 +163,14 @@ function updateOverrideInLintConfig(tree, rootOrFile, lookup, update) {
|
|
148
163
|
root = (0, posix_1.dirname)(rootOrFile);
|
149
164
|
}
|
150
165
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
151
|
-
|
166
|
+
if (!fileName) {
|
167
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
168
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
169
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
170
|
+
break;
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
152
174
|
let content = tree.read(fileName, 'utf8');
|
153
175
|
content = (0, ast_utils_1.replaceOverride)(content, root, lookup, update);
|
154
176
|
tree.write(fileName, content);
|
@@ -190,8 +212,18 @@ function lintConfigHasOverride(tree, rootOrFile, lookup, checkBaseConfig = false
|
|
190
212
|
const isBase = !fileName &&
|
191
213
|
checkBaseConfig &&
|
192
214
|
findEslintFile(tree, root).includes('.base');
|
215
|
+
if (isBase) {
|
216
|
+
fileName = (0, devkit_1.joinPathFragments)(root, config_file_1.baseEsLintFlatConfigFile);
|
217
|
+
}
|
193
218
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
194
|
-
|
219
|
+
if (!fileName) {
|
220
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
221
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
222
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
223
|
+
break;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
}
|
195
227
|
const content = tree.read(fileName, 'utf8');
|
196
228
|
return (0, ast_utils_1.hasOverride)(content, lookup);
|
197
229
|
}
|
@@ -202,7 +234,13 @@ function lintConfigHasOverride(tree, rootOrFile, lookup, checkBaseConfig = false
|
|
202
234
|
}
|
203
235
|
function replaceOverridesInLintConfig(tree, root, overrides) {
|
204
236
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
205
|
-
|
237
|
+
let fileName;
|
238
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
239
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
240
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
241
|
+
break;
|
242
|
+
}
|
243
|
+
}
|
206
244
|
let content = tree.read(fileName, 'utf8');
|
207
245
|
// Check if any of the provided overrides using legacy eslintrc properties or plugins, if so we need to add compat
|
208
246
|
if (overrides.some(ast_utils_1.overrideNeedsCompat)) {
|
@@ -226,7 +264,13 @@ function replaceOverridesInLintConfig(tree, root, overrides) {
|
|
226
264
|
function addExtendsToLintConfig(tree, root, plugin, insertAtTheEnd = false) {
|
227
265
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
228
266
|
const pluginExtends = [];
|
229
|
-
|
267
|
+
let fileName;
|
268
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
269
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
270
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
271
|
+
break;
|
272
|
+
}
|
273
|
+
}
|
230
274
|
let shouldImportEslintCompat = false;
|
231
275
|
// assume eslint version is 9 if not found, as it's what we'd be generating by default
|
232
276
|
const eslintVersion = (0, version_utils_1.getInstalledEslintVersion)(tree) ?? versions_1.eslint9__eslintVersion;
|
@@ -294,7 +338,13 @@ function addExtendsToLintConfig(tree, root, plugin, insertAtTheEnd = false) {
|
|
294
338
|
function addPredefinedConfigToFlatLintConfig(tree, root, predefinedConfigName, moduleName = 'nx', moduleImportPath = '@nx/eslint-plugin', spread = true, insertAtTheEnd = true) {
|
295
339
|
if (!(0, flat_config_1.useFlatConfig)(tree))
|
296
340
|
throw new Error('Predefined configs can only be used with flat configs');
|
297
|
-
|
341
|
+
let fileName;
|
342
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
343
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
344
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
345
|
+
break;
|
346
|
+
}
|
347
|
+
}
|
298
348
|
let content = tree.read(fileName, 'utf8');
|
299
349
|
content = (0, ast_utils_1.addImportToFlatConfig)(content, moduleName, moduleImportPath);
|
300
350
|
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)(predefinedConfigName, moduleName, spread), { insertAtTheEnd });
|
@@ -303,7 +353,13 @@ function addPredefinedConfigToFlatLintConfig(tree, root, predefinedConfigName, m
|
|
303
353
|
function addPluginsToLintConfig(tree, root, plugin) {
|
304
354
|
const plugins = Array.isArray(plugin) ? plugin : [plugin];
|
305
355
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
306
|
-
|
356
|
+
let fileName;
|
357
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
358
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
359
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
360
|
+
break;
|
361
|
+
}
|
362
|
+
}
|
307
363
|
let content = tree.read(fileName, 'utf8');
|
308
364
|
const mappedPlugins = [];
|
309
365
|
plugins.forEach((name) => {
|
@@ -327,7 +383,13 @@ function addPluginsToLintConfig(tree, root, plugin) {
|
|
327
383
|
}
|
328
384
|
function addIgnoresToLintConfig(tree, root, ignorePatterns) {
|
329
385
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
330
|
-
|
386
|
+
let fileName;
|
387
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
388
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
389
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
390
|
+
break;
|
391
|
+
}
|
392
|
+
}
|
331
393
|
const block = (0, ast_utils_1.generateAst)({
|
332
394
|
ignores: ignorePatterns.map((path) => (0, path_utils_1.mapFilePath)(path)),
|
333
395
|
});
|
@@ -670,10 +670,32 @@ function generateFlatOverride(_override) {
|
|
670
670
|
});
|
671
671
|
}
|
672
672
|
// At this point we are applying the flat config compat tooling to the override
|
673
|
-
|
673
|
+
let { excludedFiles, parser, parserOptions, rules, files, ...rest } = override;
|
674
674
|
const objectLiteralElements = [
|
675
675
|
ts.factory.createSpreadAssignment(ts.factory.createIdentifier('config')),
|
676
676
|
];
|
677
|
+
// If converting the JS rule, then we need to match ESLint default and also include .cjs and .mjs files.
|
678
|
+
if ((Array.isArray(rest.extends) &&
|
679
|
+
rest.extends.includes('plugin:@nx/javascript')) ||
|
680
|
+
rest.extends === 'plugin:@nx/javascript') {
|
681
|
+
const newFiles = new Set(files);
|
682
|
+
newFiles.add('**/*.js');
|
683
|
+
newFiles.add('**/*.jsx');
|
684
|
+
newFiles.add('**/*.cjs');
|
685
|
+
newFiles.add('**/*.mjs');
|
686
|
+
files = Array.from(newFiles);
|
687
|
+
}
|
688
|
+
// If converting the TS rule, then we need to match ESLint default and also include .cts and .mts files.
|
689
|
+
if ((Array.isArray(rest.extends) &&
|
690
|
+
rest.extends.includes('plugin:@nx/typescript')) ||
|
691
|
+
rest.extends === 'plugin:@nx/typescript') {
|
692
|
+
const newFiles = new Set(files);
|
693
|
+
newFiles.add('**/*.ts');
|
694
|
+
newFiles.add('**/*.tsx');
|
695
|
+
newFiles.add('**/*.cts');
|
696
|
+
newFiles.add('**/*.mts');
|
697
|
+
files = Array.from(newFiles);
|
698
|
+
}
|
677
699
|
addTSObjectProperty(objectLiteralElements, 'files', files);
|
678
700
|
addTSObjectProperty(objectLiteralElements, 'excludedFiles', excludedFiles);
|
679
701
|
// Apply rules (and spread ...config.rules into it as the first assignment)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.default = default_1;
|
4
|
+
const ts = require("typescript");
|
5
|
+
const js_1 = require("@nx/js");
|
6
|
+
async function default_1(tree) {
|
7
|
+
let rootConfig;
|
8
|
+
// NOTE: we don't support generating ESM base config currently so they are not handled.
|
9
|
+
for (const candidate of ['eslint.config.js', 'eslint.config.cjs']) {
|
10
|
+
if (tree.exists(candidate)) {
|
11
|
+
rootConfig = candidate;
|
12
|
+
break;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
if (!rootConfig)
|
16
|
+
return;
|
17
|
+
updateOverrideFileExtensions(tree, rootConfig, 'plugin:@nx/typescript', [`'**/*.ts'`, `'**/*.tsx'`], [`'**/*.cts'`, `'**/*.mts'`]);
|
18
|
+
updateOverrideFileExtensions(tree, rootConfig, 'plugin:@nx/javascript', [`'**/*.js'`, `'**/*.jsx'`], [`'**/*.cjs'`, `'**/*.mjs'`]);
|
19
|
+
}
|
20
|
+
function updateOverrideFileExtensions(tree, configFile, plugin, matchingExts, newExts) {
|
21
|
+
const content = tree.read(configFile, 'utf-8');
|
22
|
+
const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
23
|
+
let compatNode;
|
24
|
+
const spreadElementNodes = (0, js_1.findNodes)(source, ts.SyntaxKind.SpreadElement);
|
25
|
+
for (const a of spreadElementNodes) {
|
26
|
+
const assignmentNodes = (0, js_1.findNodes)(a, ts.SyntaxKind.PropertyAssignment);
|
27
|
+
if (assignmentNodes.length === 0)
|
28
|
+
continue;
|
29
|
+
for (const b of assignmentNodes) {
|
30
|
+
if (b.name.getText() === 'extends' &&
|
31
|
+
b.initializer.getText().includes(plugin)) {
|
32
|
+
compatNode = a;
|
33
|
+
break;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
if (compatNode) {
|
38
|
+
const arrayNodes = (0, js_1.findNodes)(compatNode, ts.SyntaxKind.ArrayLiteralExpression);
|
39
|
+
for (const a of arrayNodes) {
|
40
|
+
if (matchingExts.every((ext) => a.elements.some((e) => e.getText() === ext))) {
|
41
|
+
const exts = new Set(a.elements.map((e) => e.getText()));
|
42
|
+
for (const ext of newExts) {
|
43
|
+
exts.add(ext);
|
44
|
+
}
|
45
|
+
(0, js_1.replaceChange)(tree, source, configFile, a.getStart(a.getSourceFile()), `[${Array.from(exts).join(', ')}]`, a.getText()).getText();
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
@@ -2,7 +2,8 @@ export declare const ESLINT_FLAT_CONFIG_FILENAMES: string[];
|
|
2
2
|
export declare const ESLINT_OLD_CONFIG_FILENAMES: string[];
|
3
3
|
export declare const ESLINT_CONFIG_FILENAMES: string[];
|
4
4
|
export declare const baseEsLintConfigFile = ".eslintrc.base.json";
|
5
|
-
export declare const baseEsLintFlatConfigFile = "eslint.base.config.
|
5
|
+
export declare const baseEsLintFlatConfigFile = "eslint.base.config.cjs";
|
6
|
+
export declare const legacyBaseEsLintFlatConfigFile = "eslint.base.config.js";
|
6
7
|
export declare function isFlatConfig(configFilePath: string): boolean;
|
7
8
|
export declare function findFlatConfigFile(directory: string, workspaceRoot: string): string | null;
|
8
9
|
export declare function findOldConfigFile(filePathOrDirectory: string, workspaceRoot: string): string | null;
|
package/src/utils/config-file.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.baseEsLintFlatConfigFile = exports.baseEsLintConfigFile = exports.ESLINT_CONFIG_FILENAMES = exports.ESLINT_OLD_CONFIG_FILENAMES = exports.ESLINT_FLAT_CONFIG_FILENAMES = void 0;
|
3
|
+
exports.legacyBaseEsLintFlatConfigFile = exports.baseEsLintFlatConfigFile = exports.baseEsLintConfigFile = exports.ESLINT_CONFIG_FILENAMES = exports.ESLINT_OLD_CONFIG_FILENAMES = exports.ESLINT_FLAT_CONFIG_FILENAMES = void 0;
|
4
4
|
exports.isFlatConfig = isFlatConfig;
|
5
5
|
exports.findFlatConfigFile = findFlatConfigFile;
|
6
6
|
exports.findOldConfigFile = findOldConfigFile;
|
@@ -21,7 +21,9 @@ exports.ESLINT_CONFIG_FILENAMES = [
|
|
21
21
|
...exports.ESLINT_FLAT_CONFIG_FILENAMES,
|
22
22
|
];
|
23
23
|
exports.baseEsLintConfigFile = '.eslintrc.base.json';
|
24
|
-
exports.baseEsLintFlatConfigFile = 'eslint.base.config.
|
24
|
+
exports.baseEsLintFlatConfigFile = 'eslint.base.config.cjs';
|
25
|
+
// Make sure we can handle previous file extension as well for migrations or custom generators.
|
26
|
+
exports.legacyBaseEsLintFlatConfigFile = 'eslint.base.config.js';
|
25
27
|
function isFlatConfig(configFilePath) {
|
26
28
|
const configFileName = (0, path_1.basename)(configFilePath);
|
27
29
|
return exports.ESLINT_FLAT_CONFIG_FILENAMES.includes(configFileName);
|
package/src/utils/flat-config.js
CHANGED
@@ -6,8 +6,8 @@ exports.useFlatConfig = useFlatConfig;
|
|
6
6
|
const semver_1 = require("semver");
|
7
7
|
// todo: add support for eslint.config.mjs,
|
8
8
|
exports.eslintFlatConfigFilenames = [
|
9
|
-
'eslint.config.js',
|
10
9
|
'eslint.config.cjs',
|
10
|
+
'eslint.config.js',
|
11
11
|
];
|
12
12
|
function getRootESLintFlatConfigFilename(tree) {
|
13
13
|
for (const file of exports.eslintFlatConfigFilenames) {
|