@nx/eslint 0.0.0-pr-31222-862e973 → 0.0.0-pr-31313-387cdca
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/LICENSE +1 -1
- package/README.md +1 -1
- package/migrations.json +69 -112
- package/package.json +6 -7
- package/src/executors/lint/utility/eslint-utils.js +6 -0
- package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +1 -1
- package/src/generators/convert-to-flat-config/converters/json-converter.js +10 -18
- package/src/generators/convert-to-flat-config/generator.js +18 -17
- package/src/generators/convert-to-flat-config/schema.d.ts +2 -0
- package/src/generators/convert-to-inferred/convert-to-inferred.js +2 -1
- package/src/generators/init/global-eslint-config.d.ts +1 -1
- package/src/generators/init/global-eslint-config.js +17 -6
- package/src/generators/init/init-migration.d.ts +1 -1
- package/src/generators/init/init-migration.js +18 -13
- package/src/generators/init/init.d.ts +1 -0
- package/src/generators/init/init.js +31 -6
- package/src/generators/lint-project/lint-project.d.ts +1 -0
- package/src/generators/lint-project/lint-project.js +37 -15
- package/src/generators/lint-project/setup-root-eslint.d.ts +1 -0
- package/src/generators/lint-project/setup-root-eslint.js +2 -1
- package/src/generators/utils/eslint-file.d.ts +3 -2
- package/src/generators/utils/eslint-file.js +160 -28
- package/src/generators/utils/flat-config/ast-utils.d.ts +12 -4
- package/src/generators/utils/flat-config/ast-utils.js +412 -63
- package/src/generators/utils/linter.d.ts +3 -0
- package/src/generators/utils/linter.js +2 -2
- package/src/generators/workspace-rule/files/__name__.spec.ts__tmpl__ +11 -2
- package/src/generators/workspace-rule/workspace-rule.d.ts +2 -2
- package/src/generators/workspace-rule/workspace-rule.js +11 -3
- package/src/generators/workspace-rules-project/workspace-rules-project.js +4 -1
- package/src/migrations/update-20-2-0/update-typescript-eslint-v8-13-0.d.ts +2 -0
- package/src/migrations/update-20-2-0/update-typescript-eslint-v8-13-0.js +23 -0
- 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/plugins/plugin.js +21 -10
- package/src/utils/config-file.d.ts +3 -1
- package/src/utils/config-file.js +5 -2
- package/src/utils/flat-config.d.ts +1 -0
- package/src/utils/flat-config.js +9 -3
- package/src/utils/version-utils.d.ts +1 -0
- package/src/utils/version-utils.js +13 -9
- package/src/utils/versions.d.ts +3 -2
- package/src/utils/versions.js +4 -3
- package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +0 -2
- package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +0 -9
- package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.d.ts +0 -2
- package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.js +0 -44
- package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.d.ts +0 -2
- package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.js +0 -47
- package/src/migrations/update-17-1-0/update-typescript-eslint.d.ts +0 -2
- package/src/migrations/update-17-1-0/update-typescript-eslint.js +0 -74
- package/src/migrations/update-17-2-0/simplify-eslint-patterns.d.ts +0 -2
- package/src/migrations/update-17-2-0/simplify-eslint-patterns.js +0 -46
- package/src/migrations/update-17-2-9/move-options-to-target-defaults.d.ts +0 -2
- package/src/migrations/update-17-2-9/move-options-to-target-defaults.js +0 -107
|
@@ -4,6 +4,7 @@ export interface LinterInitOptions {
|
|
|
4
4
|
keepExistingVersions?: boolean;
|
|
5
5
|
updatePackageScripts?: boolean;
|
|
6
6
|
addPlugin?: boolean;
|
|
7
|
+
eslintConfigFormat?: 'mjs' | 'cjs';
|
|
7
8
|
}
|
|
8
9
|
export declare function initEsLint(tree: Tree, options: LinterInitOptions): Promise<GeneratorCallback>;
|
|
9
10
|
export declare function lintInitGenerator(tree: Tree, options: LinterInitOptions): Promise<GeneratorCallback>;
|
|
@@ -8,18 +8,19 @@ const versions_1 = require("../../utils/versions");
|
|
|
8
8
|
const eslint_file_1 = require("../utils/eslint-file");
|
|
9
9
|
const plugin_1 = require("../../plugins/plugin");
|
|
10
10
|
const plugin_2 = require("../utils/plugin");
|
|
11
|
-
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
function updateProductionFileset(tree, format = 'mjs') {
|
|
12
13
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
13
14
|
const productionFileSet = nxJson.namedInputs?.production;
|
|
14
15
|
if (productionFileSet) {
|
|
15
16
|
productionFileSet.push('!{projectRoot}/.eslintrc.json');
|
|
16
|
-
productionFileSet.push(
|
|
17
|
+
productionFileSet.push(`!{projectRoot}/eslint.config.${format}`);
|
|
17
18
|
// Dedupe and set
|
|
18
19
|
nxJson.namedInputs.production = Array.from(new Set(productionFileSet));
|
|
19
20
|
}
|
|
20
21
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
21
22
|
}
|
|
22
|
-
function addTargetDefaults(tree) {
|
|
23
|
+
function addTargetDefaults(tree, format) {
|
|
23
24
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
24
25
|
nxJson.targetDefaults ??= {};
|
|
25
26
|
nxJson.targetDefaults['@nx/eslint:lint'] ??= {};
|
|
@@ -28,17 +29,40 @@ function addTargetDefaults(tree) {
|
|
|
28
29
|
'default',
|
|
29
30
|
`{workspaceRoot}/.eslintrc.json`,
|
|
30
31
|
`{workspaceRoot}/.eslintignore`,
|
|
31
|
-
`{workspaceRoot}/eslint.config
|
|
32
|
+
`{workspaceRoot}/eslint.config.${format}`,
|
|
32
33
|
];
|
|
33
34
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
34
35
|
}
|
|
36
|
+
function updateVsCodeRecommendedExtensions(host) {
|
|
37
|
+
if (!host.exists('.vscode/extensions.json')) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
(0, devkit_1.updateJson)(host, '.vscode/extensions.json', (json) => {
|
|
41
|
+
json.recommendations = json.recommendations || [];
|
|
42
|
+
const extension = 'dbaeumer.vscode-eslint';
|
|
43
|
+
if (!json.recommendations.includes(extension)) {
|
|
44
|
+
json.recommendations.push(extension);
|
|
45
|
+
}
|
|
46
|
+
return json;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
35
49
|
async function initEsLint(tree, options) {
|
|
36
50
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
37
51
|
const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
38
52
|
nxJson.useInferencePlugins !== false;
|
|
39
53
|
options.addPlugin ??= addPluginDefault;
|
|
54
|
+
options.eslintConfigFormat ??= 'mjs';
|
|
40
55
|
const hasPlugin = (0, plugin_2.hasEslintPlugin)(tree);
|
|
41
56
|
const rootEslintFile = (0, eslint_file_1.findEslintFile)(tree);
|
|
57
|
+
if (rootEslintFile) {
|
|
58
|
+
const fileExtension = (0, path_1.extname)(rootEslintFile);
|
|
59
|
+
if (fileExtension === '.mjs' || fileExtension === '.cjs') {
|
|
60
|
+
options.eslintConfigFormat = fileExtension.slice(1);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
options.eslintConfigFormat = (0, eslint_file_1.determineEslintConfigFormat)(tree.read(rootEslintFile, 'utf-8'));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
42
66
|
const graph = await (0, devkit_1.createProjectGraphAsync)();
|
|
43
67
|
const lintTargetNames = [
|
|
44
68
|
'lint',
|
|
@@ -57,14 +81,15 @@ async function initEsLint(tree, options) {
|
|
|
57
81
|
if (rootEslintFile) {
|
|
58
82
|
return () => { };
|
|
59
83
|
}
|
|
60
|
-
updateProductionFileset(tree);
|
|
84
|
+
updateProductionFileset(tree, options.eslintConfigFormat);
|
|
85
|
+
updateVsCodeRecommendedExtensions(tree);
|
|
61
86
|
if (options.addPlugin) {
|
|
62
87
|
await (0, add_plugin_1.addPlugin)(tree, graph, '@nx/eslint/plugin', plugin_1.createNodesV2, {
|
|
63
88
|
targetName: lintTargetNames,
|
|
64
89
|
}, options.updatePackageScripts);
|
|
65
90
|
}
|
|
66
91
|
else {
|
|
67
|
-
addTargetDefaults(tree);
|
|
92
|
+
addTargetDefaults(tree, options.eslintConfigFormat);
|
|
68
93
|
}
|
|
69
94
|
const tasks = [];
|
|
70
95
|
if (!options.skipPackageJson) {
|
|
@@ -12,12 +12,15 @@ const flat_config_1 = require("../../utils/flat-config");
|
|
|
12
12
|
const ast_utils_1 = require("../utils/flat-config/ast-utils");
|
|
13
13
|
const config_file_1 = require("../../utils/config-file");
|
|
14
14
|
const plugin_1 = require("../utils/plugin");
|
|
15
|
+
const versions_1 = require("../../utils/versions");
|
|
15
16
|
const setup_root_eslint_1 = require("./setup-root-eslint");
|
|
17
|
+
const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
|
|
16
18
|
function lintProjectGenerator(tree, options) {
|
|
17
19
|
return lintProjectGeneratorInternal(tree, { addPlugin: false, ...options });
|
|
18
20
|
}
|
|
19
21
|
async function lintProjectGeneratorInternal(tree, options) {
|
|
20
22
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
23
|
+
options.eslintConfigFormat ??= 'mjs';
|
|
21
24
|
const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
22
25
|
nxJson.useInferencePlugins !== false;
|
|
23
26
|
options.addPlugin ??= addPluginDefault;
|
|
@@ -25,12 +28,14 @@ async function lintProjectGeneratorInternal(tree, options) {
|
|
|
25
28
|
const initTask = await (0, init_1.lintInitGenerator)(tree, {
|
|
26
29
|
skipPackageJson: options.skipPackageJson,
|
|
27
30
|
addPlugin: options.addPlugin,
|
|
31
|
+
eslintConfigFormat: options.eslintConfigFormat,
|
|
28
32
|
});
|
|
29
33
|
tasks.push(initTask);
|
|
30
34
|
const rootEsLintTask = (0, setup_root_eslint_1.setupRootEsLint)(tree, {
|
|
31
35
|
unitTestRunner: options.unitTestRunner,
|
|
32
36
|
skipPackageJson: options.skipPackageJson,
|
|
33
37
|
rootProject: options.rootProject,
|
|
38
|
+
eslintConfigFormat: options.eslintConfigFormat,
|
|
34
39
|
});
|
|
35
40
|
tasks.push(rootEsLintTask);
|
|
36
41
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
@@ -41,7 +46,7 @@ async function lintProjectGeneratorInternal(tree, options) {
|
|
|
41
46
|
if (lintFilePatterns &&
|
|
42
47
|
lintFilePatterns.length &&
|
|
43
48
|
!lintFilePatterns.includes('{projectRoot}') &&
|
|
44
|
-
isBuildableLibraryProject(projectConfig)) {
|
|
49
|
+
isBuildableLibraryProject(tree, projectConfig)) {
|
|
45
50
|
lintFilePatterns.push(`{projectRoot}/package.json`);
|
|
46
51
|
}
|
|
47
52
|
const hasPlugin = (0, plugin_1.hasEslintPlugin)(tree);
|
|
@@ -49,6 +54,7 @@ async function lintProjectGeneratorInternal(tree, options) {
|
|
|
49
54
|
if (lintFilePatterns &&
|
|
50
55
|
lintFilePatterns.length &&
|
|
51
56
|
lintFilePatterns.some((p) => !['./src', '{projectRoot}', projectConfig.root].includes(p))) {
|
|
57
|
+
projectConfig.targets ??= {};
|
|
52
58
|
projectConfig.targets['lint'] = {
|
|
53
59
|
command: `eslint ${lintFilePatterns
|
|
54
60
|
.join(' ')
|
|
@@ -57,6 +63,7 @@ async function lintProjectGeneratorInternal(tree, options) {
|
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
else {
|
|
66
|
+
projectConfig.targets ??= {};
|
|
60
67
|
projectConfig.targets['lint'] = {
|
|
61
68
|
executor: '@nx/eslint:lint',
|
|
62
69
|
};
|
|
@@ -82,7 +89,7 @@ async function lintProjectGeneratorInternal(tree, options) {
|
|
|
82
89
|
filteredProjects.push(project);
|
|
83
90
|
}
|
|
84
91
|
});
|
|
85
|
-
const migrateTask = (0, init_migration_1.migrateConfigToMonorepoStyle)(filteredProjects, tree, options.unitTestRunner, options.keepExistingVersions);
|
|
92
|
+
const migrateTask = (0, init_migration_1.migrateConfigToMonorepoStyle)(filteredProjects, tree, options.unitTestRunner, options.eslintConfigFormat, options.keepExistingVersions);
|
|
86
93
|
tasks.push(migrateTask);
|
|
87
94
|
}
|
|
88
95
|
}
|
|
@@ -90,10 +97,15 @@ async function lintProjectGeneratorInternal(tree, options) {
|
|
|
90
97
|
// additionally, the companion e2e app would have `rootProject: true`
|
|
91
98
|
// so we need to check for the root path as well
|
|
92
99
|
if (!options.rootProject || projectConfig.root !== '.') {
|
|
93
|
-
|
|
100
|
+
const addDependencyChecks = options.addPackageJsonDependencyChecks ||
|
|
101
|
+
isBuildableLibraryProject(tree, projectConfig);
|
|
102
|
+
createEsLintConfiguration(tree, options, projectConfig, options.setParserOptionsProject, options.rootProject, addDependencyChecks);
|
|
103
|
+
if (addDependencyChecks) {
|
|
104
|
+
tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, { 'jsonc-eslint-parser': versions_1.jsoncEslintParserVersion }, undefined, true));
|
|
105
|
+
}
|
|
94
106
|
}
|
|
95
107
|
// Buildable libs need source analysis enabled for linting `package.json`.
|
|
96
|
-
if (isBuildableLibraryProject(projectConfig) &&
|
|
108
|
+
if (isBuildableLibraryProject(tree, projectConfig) &&
|
|
97
109
|
!isJsAnalyzeSourceFilesEnabled(tree)) {
|
|
98
110
|
(0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
|
|
99
111
|
json.pluginsConfig ??= {};
|
|
@@ -108,14 +120,24 @@ async function lintProjectGeneratorInternal(tree, options) {
|
|
|
108
120
|
}
|
|
109
121
|
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
110
122
|
}
|
|
111
|
-
function createEsLintConfiguration(tree, options, projectConfig, setParserOptionsProject, rootProject) {
|
|
123
|
+
function createEsLintConfiguration(tree, options, projectConfig, setParserOptionsProject, rootProject, addDependencyChecks) {
|
|
112
124
|
// we are only extending root for non-standalone projects or their complementary e2e apps
|
|
113
125
|
const extendedRootConfig = rootProject ? undefined : (0, eslint_file_1.findEslintFile)(tree);
|
|
114
126
|
const pathToRootConfig = extendedRootConfig
|
|
115
127
|
? `${(0, devkit_1.offsetFromRoot)(projectConfig.root)}${extendedRootConfig}`
|
|
116
128
|
: undefined;
|
|
117
|
-
|
|
118
|
-
|
|
129
|
+
if (extendedRootConfig) {
|
|
130
|
+
// We do not want to mix the formats
|
|
131
|
+
// if the base file extension is `.mjs` we should use `mjs` for the new file
|
|
132
|
+
// or if base the file extension is `.cjs` then the format should be `cjs`
|
|
133
|
+
const fileExtension = (0, path_1.extname)(extendedRootConfig);
|
|
134
|
+
if (fileExtension === '.mjs' || fileExtension === '.cjs') {
|
|
135
|
+
options.eslintConfigFormat = fileExtension.slice(1);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
options.eslintConfigFormat = (0, eslint_file_1.determineEslintConfigFormat)(tree.read(extendedRootConfig, 'utf-8'));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
119
141
|
const overrides = (0, flat_config_1.useFlatConfig)(tree)
|
|
120
142
|
? // For flat configs, we don't need to generate different overrides for each file. Users should add their own overrides as needed.
|
|
121
143
|
[]
|
|
@@ -178,11 +200,11 @@ function createEsLintConfiguration(tree, options, projectConfig, setParserOption
|
|
|
178
200
|
nodes.push((0, ast_utils_1.generateSpreadElement)('baseConfig'));
|
|
179
201
|
}
|
|
180
202
|
overrides.forEach((override) => {
|
|
181
|
-
nodes.push((0, ast_utils_1.generateFlatOverride)(override));
|
|
203
|
+
nodes.push((0, ast_utils_1.generateFlatOverride)(override, options.eslintConfigFormat));
|
|
182
204
|
});
|
|
183
|
-
const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes);
|
|
205
|
+
const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes, options.eslintConfigFormat);
|
|
184
206
|
const content = (0, ast_utils_1.stringifyNodeList)(nodeList);
|
|
185
|
-
tree.write((0, path_1.join)(projectConfig.root,
|
|
207
|
+
tree.write((0, path_1.join)(projectConfig.root, `eslint.config.${options.eslintConfigFormat}`), content);
|
|
186
208
|
}
|
|
187
209
|
else {
|
|
188
210
|
(0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
|
|
@@ -199,8 +221,9 @@ function isJsAnalyzeSourceFilesEnabled(tree) {
|
|
|
199
221
|
return (jsPluginConfig?.analyzeSourceFiles ??
|
|
200
222
|
nxJson.extends !== 'nx/presets/npm.json');
|
|
201
223
|
}
|
|
202
|
-
function isBuildableLibraryProject(projectConfig) {
|
|
203
|
-
return (projectConfig.projectType ===
|
|
224
|
+
function isBuildableLibraryProject(tree, projectConfig) {
|
|
225
|
+
return ((0, ts_solution_setup_1.getProjectType)(tree, projectConfig.root, projectConfig.projectType) ===
|
|
226
|
+
'library' &&
|
|
204
227
|
projectConfig.targets?.build &&
|
|
205
228
|
!!projectConfig.targets.build);
|
|
206
229
|
}
|
|
@@ -210,8 +233,7 @@ function isBuildableLibraryProject(projectConfig) {
|
|
|
210
233
|
*/
|
|
211
234
|
function isMigrationToMonorepoNeeded(tree, graph) {
|
|
212
235
|
// the base config is already created, migration has been done
|
|
213
|
-
if (tree.exists(
|
|
214
|
-
tree.exists(config_file_1.baseEsLintFlatConfigFile)) {
|
|
236
|
+
if ([config_file_1.baseEsLintConfigFile, ...config_file_1.BASE_ESLINT_CONFIG_FILENAMES].some((f) => tree.exists(f))) {
|
|
215
237
|
return false;
|
|
216
238
|
}
|
|
217
239
|
const nodes = Object.values(graph.nodes);
|
|
@@ -221,7 +243,7 @@ function isMigrationToMonorepoNeeded(tree, graph) {
|
|
|
221
243
|
return false;
|
|
222
244
|
}
|
|
223
245
|
for (const targetConfig of Object.values(rootProject.data.targets ?? {})) {
|
|
224
|
-
if (['@nx/eslint:lint', '@
|
|
246
|
+
if (['@nx/eslint:lint', '@nx/linter:eslint'].includes(targetConfig.executor) ||
|
|
225
247
|
(targetConfig.executor === 'nx:run-commands' &&
|
|
226
248
|
targetConfig.options?.command &&
|
|
227
249
|
targetConfig.options?.command.startsWith('eslint '))) {
|
|
@@ -11,6 +11,7 @@ function setupRootEsLint(tree, options) {
|
|
|
11
11
|
if (rootEslintFile) {
|
|
12
12
|
return () => { };
|
|
13
13
|
}
|
|
14
|
+
options.eslintConfigFormat ??= 'mjs';
|
|
14
15
|
if (!(0, flat_config_1.useFlatConfig)(tree)) {
|
|
15
16
|
return setUpLegacyRootEslintRc(tree, options);
|
|
16
17
|
}
|
|
@@ -38,7 +39,7 @@ function setUpLegacyRootEslintRc(tree, options) {
|
|
|
38
39
|
: () => { };
|
|
39
40
|
}
|
|
40
41
|
function setUpRootFlatConfig(tree, options) {
|
|
41
|
-
tree.write(
|
|
42
|
+
tree.write(`eslint.config.${options.eslintConfigFormat}`, (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(options.eslintConfigFormat, options.rootProject));
|
|
42
43
|
return !options.skipPackageJson
|
|
43
44
|
? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
44
45
|
'@eslint/js': versions_1.eslint9__eslintVersion,
|
|
@@ -3,12 +3,13 @@ import type { Linter } from 'eslint';
|
|
|
3
3
|
export declare function findEslintFile(tree: Tree, projectRoot?: string): string | null;
|
|
4
4
|
export declare function isEslintConfigSupported(tree: Tree, projectRoot?: string): boolean;
|
|
5
5
|
export declare function updateRelativePathsInConfig(tree: Tree, sourcePath: string, destinationPath: string): void;
|
|
6
|
+
export declare function determineEslintConfigFormat(content: string): 'mjs' | 'cjs';
|
|
6
7
|
export declare function addOverrideToLintConfig(tree: Tree, root: string, override: Partial<Linter.ConfigOverride<Linter.RulesRecord>>, options?: {
|
|
7
8
|
insertAtTheEnd?: boolean;
|
|
8
9
|
checkBaseConfig?: boolean;
|
|
9
10
|
}): void;
|
|
10
|
-
export declare function updateOverrideInLintConfig(tree: Tree,
|
|
11
|
-
export declare function lintConfigHasOverride(tree: Tree,
|
|
11
|
+
export declare function updateOverrideInLintConfig(tree: Tree, rootOrFile: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean, update: (override: Linter.ConfigOverride<Linter.RulesRecord>) => Linter.ConfigOverride<Linter.RulesRecord>): void;
|
|
12
|
+
export declare function lintConfigHasOverride(tree: Tree, rootOrFile: string, lookup: (override: Linter.ConfigOverride<Linter.RulesRecord>) => boolean, checkBaseConfig?: boolean): boolean;
|
|
12
13
|
export declare function replaceOverridesInLintConfig(tree: Tree, root: string, overrides: Linter.ConfigOverride<Linter.RulesRecord>[]): void;
|
|
13
14
|
export declare function addExtendsToLintConfig(tree: Tree, root: string, plugin: string | {
|
|
14
15
|
name: string;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.findEslintFile = findEslintFile;
|
|
4
4
|
exports.isEslintConfigSupported = isEslintConfigSupported;
|
|
5
5
|
exports.updateRelativePathsInConfig = updateRelativePathsInConfig;
|
|
6
|
+
exports.determineEslintConfigFormat = determineEslintConfigFormat;
|
|
6
7
|
exports.addOverrideToLintConfig = addOverrideToLintConfig;
|
|
7
8
|
exports.updateOverrideInLintConfig = updateOverrideInLintConfig;
|
|
8
9
|
exports.lintConfigHasOverride = lintConfigHasOverride;
|
|
@@ -20,12 +21,18 @@ const version_utils_1 = require("../../utils/version-utils");
|
|
|
20
21
|
const versions_1 = require("../../utils/versions");
|
|
21
22
|
const ast_utils_1 = require("./flat-config/ast-utils");
|
|
22
23
|
const path_utils_1 = require("./flat-config/path-utils");
|
|
24
|
+
const ts = require("typescript");
|
|
25
|
+
const posix_1 = require("node:path/posix");
|
|
23
26
|
function findEslintFile(tree, projectRoot) {
|
|
24
|
-
if (projectRoot === undefined
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
if (projectRoot === undefined) {
|
|
28
|
+
for (const file of [
|
|
29
|
+
config_file_1.baseEsLintConfigFile,
|
|
30
|
+
...config_file_1.BASE_ESLINT_CONFIG_FILENAMES,
|
|
31
|
+
]) {
|
|
32
|
+
if (tree.exists(file)) {
|
|
33
|
+
return file;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
29
36
|
}
|
|
30
37
|
projectRoot ??= '';
|
|
31
38
|
for (const file of config_file_1.ESLINT_CONFIG_FILENAMES) {
|
|
@@ -40,7 +47,10 @@ function isEslintConfigSupported(tree, projectRoot = '') {
|
|
|
40
47
|
if (!eslintFile) {
|
|
41
48
|
return false;
|
|
42
49
|
}
|
|
43
|
-
return eslintFile.endsWith('.json') ||
|
|
50
|
+
return (eslintFile.endsWith('.json') ||
|
|
51
|
+
eslintFile.endsWith('.config.js') ||
|
|
52
|
+
eslintFile.endsWith('.config.cjs') ||
|
|
53
|
+
eslintFile.endsWith('.config.mjs'));
|
|
44
54
|
}
|
|
45
55
|
function updateRelativePathsInConfig(tree, sourcePath, destinationPath) {
|
|
46
56
|
if (sourcePath === destinationPath ||
|
|
@@ -84,6 +94,17 @@ function replaceFlatConfigPaths(config, sourceRoot, offset, destinationRoot, tre
|
|
|
84
94
|
`require('${newPath}')` +
|
|
85
95
|
newConfig.slice(match.index + match[0].length);
|
|
86
96
|
}
|
|
97
|
+
// Handle import statements
|
|
98
|
+
const importRegex = RegExp(/import\s+.*?\s+from\s+['"](.*)['"]/g);
|
|
99
|
+
while ((match = importRegex.exec(newConfig)) !== null) {
|
|
100
|
+
const oldPath = match[1];
|
|
101
|
+
const newPath = offsetFilePath(sourceRoot, oldPath, offset, tree);
|
|
102
|
+
// Replace the old path with the updated path
|
|
103
|
+
newConfig =
|
|
104
|
+
newConfig.slice(0, match.index + match[0].indexOf(oldPath)) +
|
|
105
|
+
newPath +
|
|
106
|
+
newConfig.slice(match.index + match[0].indexOf(oldPath) + oldPath.length);
|
|
107
|
+
}
|
|
87
108
|
// replace projects
|
|
88
109
|
const projectRegex = RegExp(/project:\s?\[?['"](.*)['"]\]?/g);
|
|
89
110
|
while ((match = projectRegex.exec(newConfig)) !== null) {
|
|
@@ -109,14 +130,37 @@ function offsetFilePath(projectRoot, pathToFile, offset, tree) {
|
|
|
109
130
|
}
|
|
110
131
|
return (0, devkit_1.joinPathFragments)(offset, projectRoot, pathToFile);
|
|
111
132
|
}
|
|
133
|
+
function determineEslintConfigFormat(content) {
|
|
134
|
+
const sourceFile = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true);
|
|
135
|
+
// Check if there's an `export default` in the AST
|
|
136
|
+
const hasExportDefault = sourceFile.statements.some((statement) => ts.isExportAssignment(statement) && !statement.isExportEquals);
|
|
137
|
+
return hasExportDefault ? 'mjs' : 'cjs';
|
|
138
|
+
}
|
|
112
139
|
function addOverrideToLintConfig(tree, root, override, options = {
|
|
113
140
|
insertAtTheEnd: true,
|
|
114
141
|
}) {
|
|
115
142
|
const isBase = options.checkBaseConfig && findEslintFile(tree, root).includes('.base');
|
|
116
143
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
117
|
-
|
|
118
|
-
|
|
144
|
+
let fileName;
|
|
145
|
+
if (isBase) {
|
|
146
|
+
for (const file of config_file_1.BASE_ESLINT_CONFIG_FILENAMES) {
|
|
147
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, file))) {
|
|
148
|
+
fileName = (0, devkit_1.joinPathFragments)(root, file);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
|
155
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
|
156
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
119
161
|
let content = tree.read(fileName, 'utf8');
|
|
162
|
+
const format = content.includes('export default') ? 'mjs' : 'cjs';
|
|
163
|
+
const flatOverride = (0, ast_utils_1.generateFlatOverride)(override, format);
|
|
120
164
|
// Check if the provided override using legacy eslintrc properties or plugins, if so we need to add compat
|
|
121
165
|
if ((0, ast_utils_1.overrideNeedsCompat)(override)) {
|
|
122
166
|
content = (0, ast_utils_1.addFlatCompatToFlatConfig)(content);
|
|
@@ -137,15 +181,28 @@ function addOverrideToLintConfig(tree, root, override, options = {
|
|
|
137
181
|
});
|
|
138
182
|
}
|
|
139
183
|
}
|
|
140
|
-
function updateOverrideInLintConfig(tree,
|
|
184
|
+
function updateOverrideInLintConfig(tree, rootOrFile, lookup, update) {
|
|
185
|
+
let fileName;
|
|
186
|
+
let root = rootOrFile;
|
|
187
|
+
if (tree.exists(rootOrFile) && tree.isFile(rootOrFile)) {
|
|
188
|
+
fileName = rootOrFile;
|
|
189
|
+
root = (0, posix_1.dirname)(rootOrFile);
|
|
190
|
+
}
|
|
141
191
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
142
|
-
|
|
192
|
+
if (!fileName) {
|
|
193
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
|
194
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
|
195
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
143
200
|
let content = tree.read(fileName, 'utf8');
|
|
144
201
|
content = (0, ast_utils_1.replaceOverride)(content, root, lookup, update);
|
|
145
202
|
tree.write(fileName, content);
|
|
146
203
|
}
|
|
147
204
|
else {
|
|
148
|
-
|
|
205
|
+
fileName ??= (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
|
|
149
206
|
if (!tree.exists(fileName)) {
|
|
150
207
|
return;
|
|
151
208
|
}
|
|
@@ -168,32 +225,62 @@ function updateOverrideInLintConfig(tree, root, lookup, update) {
|
|
|
168
225
|
});
|
|
169
226
|
}
|
|
170
227
|
}
|
|
171
|
-
function lintConfigHasOverride(tree,
|
|
172
|
-
|
|
228
|
+
function lintConfigHasOverride(tree, rootOrFile, lookup, checkBaseConfig = false) {
|
|
229
|
+
let fileName;
|
|
230
|
+
let root = rootOrFile;
|
|
231
|
+
if (tree.exists(rootOrFile) && tree.isFile(rootOrFile)) {
|
|
232
|
+
fileName = rootOrFile;
|
|
233
|
+
root = (0, posix_1.dirname)(rootOrFile);
|
|
234
|
+
}
|
|
235
|
+
if (!fileName && !isEslintConfigSupported(tree, root)) {
|
|
173
236
|
return false;
|
|
174
237
|
}
|
|
175
|
-
const isBase =
|
|
238
|
+
const isBase = !fileName &&
|
|
239
|
+
checkBaseConfig &&
|
|
240
|
+
findEslintFile(tree, root).includes('.base');
|
|
241
|
+
if (isBase) {
|
|
242
|
+
for (const file of config_file_1.BASE_ESLINT_CONFIG_FILENAMES) {
|
|
243
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, file))) {
|
|
244
|
+
fileName = (0, devkit_1.joinPathFragments)(root, file);
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
176
249
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
177
|
-
|
|
250
|
+
if (!fileName) {
|
|
251
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
|
252
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
|
253
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
178
258
|
const content = tree.read(fileName, 'utf8');
|
|
179
259
|
return (0, ast_utils_1.hasOverride)(content, lookup);
|
|
180
260
|
}
|
|
181
261
|
else {
|
|
182
|
-
|
|
262
|
+
fileName ??= (0, devkit_1.joinPathFragments)(root, isBase ? config_file_1.baseEsLintConfigFile : '.eslintrc.json');
|
|
183
263
|
return (0, devkit_1.readJson)(tree, fileName).overrides?.some(lookup) || false;
|
|
184
264
|
}
|
|
185
265
|
}
|
|
186
266
|
function replaceOverridesInLintConfig(tree, root, overrides) {
|
|
187
267
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
188
|
-
|
|
268
|
+
let fileName;
|
|
269
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
|
270
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
|
271
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
189
275
|
let content = tree.read(fileName, 'utf8');
|
|
276
|
+
const format = content.includes('export default') ? 'mjs' : 'cjs';
|
|
190
277
|
// Check if any of the provided overrides using legacy eslintrc properties or plugins, if so we need to add compat
|
|
191
278
|
if (overrides.some(ast_utils_1.overrideNeedsCompat)) {
|
|
192
279
|
content = (0, ast_utils_1.addFlatCompatToFlatConfig)(content);
|
|
193
280
|
}
|
|
194
281
|
content = (0, ast_utils_1.removeOverridesFromLintConfig)(content);
|
|
195
282
|
overrides.forEach((override) => {
|
|
196
|
-
const flatOverride = (0, ast_utils_1.generateFlatOverride)(override);
|
|
283
|
+
const flatOverride = (0, ast_utils_1.generateFlatOverride)(override, format);
|
|
197
284
|
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, flatOverride);
|
|
198
285
|
});
|
|
199
286
|
tree.write(fileName, content);
|
|
@@ -209,7 +296,21 @@ function replaceOverridesInLintConfig(tree, root, overrides) {
|
|
|
209
296
|
function addExtendsToLintConfig(tree, root, plugin, insertAtTheEnd = false) {
|
|
210
297
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
211
298
|
const pluginExtends = [];
|
|
212
|
-
|
|
299
|
+
let fileName;
|
|
300
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
|
301
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
|
302
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Check the file extension to determine the format of the config if it is .js we look for the export
|
|
307
|
+
const eslintConfigFormat = fileName.endsWith('.mjs')
|
|
308
|
+
? 'mjs'
|
|
309
|
+
: fileName.endsWith('.cjs')
|
|
310
|
+
? 'cjs'
|
|
311
|
+
: tree.read(fileName, 'utf-8').includes('module.exports')
|
|
312
|
+
? 'cjs'
|
|
313
|
+
: 'mjs';
|
|
213
314
|
let shouldImportEslintCompat = false;
|
|
214
315
|
// assume eslint version is 9 if not found, as it's what we'd be generating by default
|
|
215
316
|
const eslintVersion = (0, version_utils_1.getInstalledEslintVersion)(tree) ?? versions_1.eslint9__eslintVersion;
|
|
@@ -256,9 +357,9 @@ function addExtendsToLintConfig(tree, root, plugin, insertAtTheEnd = false) {
|
|
|
256
357
|
}
|
|
257
358
|
tree.write(fileName, content);
|
|
258
359
|
if (shouldImportEslintCompat) {
|
|
259
|
-
return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@eslint/compat': versions_1.eslintCompat }, undefined, true);
|
|
360
|
+
return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@eslint/compat': versions_1.eslintCompat, '@eslint/eslintrc': versions_1.eslintrcVersion }, undefined, true);
|
|
260
361
|
}
|
|
261
|
-
return ()
|
|
362
|
+
return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@eslint/eslintrc': versions_1.eslintrcVersion }, undefined, true);
|
|
262
363
|
}
|
|
263
364
|
else {
|
|
264
365
|
const plugins = (Array.isArray(plugin) ? plugin : [plugin]).map((p) => typeof p === 'string' ? p : p.name);
|
|
@@ -277,7 +378,13 @@ function addExtendsToLintConfig(tree, root, plugin, insertAtTheEnd = false) {
|
|
|
277
378
|
function addPredefinedConfigToFlatLintConfig(tree, root, predefinedConfigName, moduleName = 'nx', moduleImportPath = '@nx/eslint-plugin', spread = true, insertAtTheEnd = true) {
|
|
278
379
|
if (!(0, flat_config_1.useFlatConfig)(tree))
|
|
279
380
|
throw new Error('Predefined configs can only be used with flat configs');
|
|
280
|
-
|
|
381
|
+
let fileName;
|
|
382
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
|
383
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
|
384
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
281
388
|
let content = tree.read(fileName, 'utf8');
|
|
282
389
|
content = (0, ast_utils_1.addImportToFlatConfig)(content, moduleName, moduleImportPath);
|
|
283
390
|
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatPredefinedConfig)(predefinedConfigName, moduleName, spread), { insertAtTheEnd });
|
|
@@ -286,7 +393,13 @@ function addPredefinedConfigToFlatLintConfig(tree, root, predefinedConfigName, m
|
|
|
286
393
|
function addPluginsToLintConfig(tree, root, plugin) {
|
|
287
394
|
const plugins = Array.isArray(plugin) ? plugin : [plugin];
|
|
288
395
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
289
|
-
|
|
396
|
+
let fileName;
|
|
397
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
|
398
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
|
399
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
290
403
|
let content = tree.read(fileName, 'utf8');
|
|
291
404
|
const mappedPlugins = [];
|
|
292
405
|
plugins.forEach((name) => {
|
|
@@ -310,14 +423,33 @@ function addPluginsToLintConfig(tree, root, plugin) {
|
|
|
310
423
|
}
|
|
311
424
|
function addIgnoresToLintConfig(tree, root, ignorePatterns) {
|
|
312
425
|
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
313
|
-
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
426
|
+
let fileName;
|
|
427
|
+
for (const f of flat_config_1.eslintFlatConfigFilenames) {
|
|
428
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(root, f))) {
|
|
429
|
+
fileName = (0, devkit_1.joinPathFragments)(root, f);
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (!fileName) {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
let content = tree.read(fileName, 'utf8');
|
|
437
|
+
if ((0, ast_utils_1.hasFlatConfigIgnoresBlock)(content)) {
|
|
438
|
+
content = (0, ast_utils_1.addPatternsToFlatConfigIgnoresBlock)(content, ignorePatterns);
|
|
439
|
+
tree.write(fileName, content);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
const block = (0, ast_utils_1.generateAst)({
|
|
443
|
+
ignores: ignorePatterns.map((path) => (0, path_utils_1.mapFilePath)(path)),
|
|
444
|
+
});
|
|
445
|
+
tree.write(fileName, (0, ast_utils_1.addBlockToFlatConfigExport)(content, block));
|
|
446
|
+
}
|
|
318
447
|
}
|
|
319
448
|
else {
|
|
320
449
|
const fileName = (0, devkit_1.joinPathFragments)(root, '.eslintrc.json');
|
|
450
|
+
if (!tree.exists(fileName)) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
321
453
|
(0, devkit_1.updateJson)(tree, fileName, (json) => {
|
|
322
454
|
const ignoreSet = new Set([
|
|
323
455
|
...(json.ignorePatterns ?? []),
|