@nx/eslint 20.3.0-canary.20241218-fb40366 → 20.3.0-canary.20241219-2eb5243
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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) {
|