@nx/eslint 0.0.0-pr-22179-271588f
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 +22 -0
- package/README.md +66 -0
- package/executors.json +10 -0
- package/generators.json +28 -0
- package/index.d.ts +4 -0
- package/index.js +14 -0
- package/migrations.json +138 -0
- package/package.json +52 -0
- package/plugin.d.ts +1 -0
- package/plugin.js +5 -0
- package/src/executors/lint/hasher.d.ts +9 -0
- package/src/executors/lint/hasher.js +43 -0
- package/src/executors/lint/lint.impl.d.ts +5 -0
- package/src/executors/lint/lint.impl.js +174 -0
- package/src/executors/lint/schema.d.ts +40 -0
- package/src/executors/lint/schema.json +148 -0
- package/src/executors/lint/utility/eslint-utils.d.ts +6 -0
- package/src/executors/lint/utility/eslint-utils.js +75 -0
- package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +11 -0
- package/src/generators/convert-to-flat-config/converters/json-converter.js +175 -0
- package/src/generators/convert-to-flat-config/generator.d.ts +4 -0
- package/src/generators/convert-to-flat-config/generator.js +139 -0
- package/src/generators/convert-to-flat-config/schema.d.ts +3 -0
- package/src/generators/convert-to-flat-config/schema.json +17 -0
- package/src/generators/init/global-eslint-config.d.ts +29 -0
- package/src/generators/init/global-eslint-config.js +102 -0
- package/src/generators/init/init-migration.d.ts +3 -0
- package/src/generators/init/init-migration.js +137 -0
- package/src/generators/init/init.d.ts +9 -0
- package/src/generators/init/init.js +93 -0
- package/src/generators/init/schema.json +28 -0
- package/src/generators/lint-project/lint-project.d.ts +22 -0
- package/src/generators/lint-project/lint-project.js +227 -0
- package/src/generators/lint-project/setup-root-eslint.d.ts +7 -0
- package/src/generators/lint-project/setup-root-eslint.js +33 -0
- package/src/generators/utils/eslint-file.d.ts +16 -0
- package/src/generators/utils/eslint-file.js +287 -0
- package/src/generators/utils/eslint-targets.d.ts +2 -0
- package/src/generators/utils/eslint-targets.js +18 -0
- package/src/generators/utils/flat-config/ast-utils.d.ts +60 -0
- package/src/generators/utils/flat-config/ast-utils.js +573 -0
- package/src/generators/utils/flat-config/path-utils.d.ts +3 -0
- package/src/generators/utils/flat-config/path-utils.js +28 -0
- package/src/generators/utils/linter.d.ts +4 -0
- package/src/generators/utils/linter.js +8 -0
- package/src/generators/utils/plugin.d.ts +2 -0
- package/src/generators/utils/plugin.js +11 -0
- package/src/generators/workspace-rule/files/__name__.spec.ts__tmpl__ +11 -0
- package/src/generators/workspace-rule/files/__name__.ts__tmpl__ +37 -0
- package/src/generators/workspace-rule/schema.json +26 -0
- package/src/generators/workspace-rule/workspace-rule.d.ts +6 -0
- package/src/generators/workspace-rule/workspace-rule.js +78 -0
- package/src/generators/workspace-rules-project/files/index.ts__tmpl__ +27 -0
- package/src/generators/workspace-rules-project/files/tsconfig.json__tmpl__ +14 -0
- package/src/generators/workspace-rules-project/files/tsconfig.lint.json__tmpl__ +9 -0
- package/src/generators/workspace-rules-project/schema.json +23 -0
- package/src/generators/workspace-rules-project/workspace-rules-project.d.ts +8 -0
- package/src/generators/workspace-rules-project/workspace-rules-project.js +82 -0
- package/src/migrations/update-15-0-0/add-eslint-inputs.d.ts +2 -0
- package/src/migrations/update-15-0-0/add-eslint-inputs.js +27 -0
- package/src/migrations/update-15-7-1/add-eslint-ignore.d.ts +2 -0
- package/src/migrations/update-15-7-1/add-eslint-ignore.js +36 -0
- package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +2 -0
- package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +9 -0
- package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.d.ts +2 -0
- package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.js +44 -0
- package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.d.ts +2 -0
- package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.js +47 -0
- package/src/migrations/update-17-1-0/update-typescript-eslint.d.ts +2 -0
- package/src/migrations/update-17-1-0/update-typescript-eslint.js +74 -0
- package/src/migrations/update-17-2-0/simplify-eslint-patterns.d.ts +2 -0
- package/src/migrations/update-17-2-0/simplify-eslint-patterns.js +46 -0
- package/src/migrations/update-17-2-9/move-options-to-target-defaults.d.ts +2 -0
- package/src/migrations/update-17-2-9/move-options-to-target-defaults.js +107 -0
- package/src/plugins/plugin.d.ts +5 -0
- package/src/plugins/plugin.js +92 -0
- package/src/utils/config-file.d.ts +5 -0
- package/src/utils/config-file.js +35 -0
- package/src/utils/flat-config.d.ts +2 -0
- package/src/utils/flat-config.js +7 -0
- package/src/utils/rules-requiring-type-checking.d.ts +3 -0
- package/src/utils/rules-requiring-type-checking.js +84 -0
- package/src/utils/versions.d.ts +5 -0
- package/src/utils/versions.js +8 -0
- package/src/utils/workspace-lint-rules.d.ts +1 -0
- package/src/utils/workspace-lint-rules.js +5 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGlobalFlatEslintConfiguration = exports.getGlobalEsLintConfiguration = exports.javaScriptOverride = exports.typeScriptOverride = void 0;
|
|
4
|
+
const ast_utils_1 = require("../utils/flat-config/ast-utils");
|
|
5
|
+
/**
|
|
6
|
+
* This configuration is intended to apply to all TypeScript source files.
|
|
7
|
+
* See the eslint-plugin package for what is in the referenced shareable config.
|
|
8
|
+
*/
|
|
9
|
+
exports.typeScriptOverride = {
|
|
10
|
+
files: ['*.ts', '*.tsx'],
|
|
11
|
+
extends: ['plugin:@nx/typescript'],
|
|
12
|
+
/**
|
|
13
|
+
* Having an empty rules object present makes it more obvious to the user where they would
|
|
14
|
+
* extend things from if they needed to
|
|
15
|
+
*/
|
|
16
|
+
rules: {},
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* This configuration is intended to apply to all JavaScript source files.
|
|
20
|
+
* See the eslint-plugin package for what is in the referenced shareable config.
|
|
21
|
+
*/
|
|
22
|
+
exports.javaScriptOverride = {
|
|
23
|
+
files: ['*.js', '*.jsx'],
|
|
24
|
+
extends: ['plugin:@nx/javascript'],
|
|
25
|
+
/**
|
|
26
|
+
* Having an empty rules object present makes it more obvious to the user where they would
|
|
27
|
+
* extend things from if they needed to
|
|
28
|
+
*/
|
|
29
|
+
rules: {},
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* This configuration is intended to apply to all "source code" (but not
|
|
33
|
+
* markup like HTML, or other custom file types like GraphQL)
|
|
34
|
+
*/
|
|
35
|
+
const moduleBoundariesOverride = {
|
|
36
|
+
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
|
|
37
|
+
rules: {
|
|
38
|
+
'@nx/enforce-module-boundaries': [
|
|
39
|
+
'error',
|
|
40
|
+
{
|
|
41
|
+
enforceBuildableLibDependency: true,
|
|
42
|
+
allow: [],
|
|
43
|
+
depConstraints: [{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] }],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* This configuration is intended to apply to all "source code" (but not
|
|
50
|
+
* markup like HTML, or other custom file types like GraphQL)
|
|
51
|
+
*/
|
|
52
|
+
const jestOverride = {
|
|
53
|
+
files: ['*.spec.ts', '*.spec.tsx', '*.spec.js', '*.spec.jsx'],
|
|
54
|
+
env: {
|
|
55
|
+
jest: true,
|
|
56
|
+
},
|
|
57
|
+
rules: {},
|
|
58
|
+
};
|
|
59
|
+
const getGlobalEsLintConfiguration = (unitTestRunner, rootProject) => {
|
|
60
|
+
const config = {
|
|
61
|
+
root: true,
|
|
62
|
+
ignorePatterns: rootProject ? ['!**/*'] : ['**/*'],
|
|
63
|
+
plugins: ['@nx'],
|
|
64
|
+
/**
|
|
65
|
+
* We leverage ESLint's "overrides" capability so that we can set up a root config which will support
|
|
66
|
+
* all permutations of Nx workspaces across all frameworks, libraries and tools.
|
|
67
|
+
*
|
|
68
|
+
* The key point is that we need entirely different ESLint config to apply to different types of files,
|
|
69
|
+
* but we still want to share common config where possible.
|
|
70
|
+
*/
|
|
71
|
+
overrides: [
|
|
72
|
+
...(rootProject ? [] : [moduleBoundariesOverride]),
|
|
73
|
+
exports.typeScriptOverride,
|
|
74
|
+
exports.javaScriptOverride,
|
|
75
|
+
...(unitTestRunner === 'jest' ? [jestOverride] : []),
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
return config;
|
|
79
|
+
};
|
|
80
|
+
exports.getGlobalEsLintConfiguration = getGlobalEsLintConfiguration;
|
|
81
|
+
const getGlobalFlatEslintConfiguration = (unitTestRunner, rootProject) => {
|
|
82
|
+
const nodeList = (0, ast_utils_1.createNodeList)(new Map(), [], true);
|
|
83
|
+
let content = (0, ast_utils_1.stringifyNodeList)(nodeList);
|
|
84
|
+
content = (0, ast_utils_1.addImportToFlatConfig)(content, 'nxPlugin', '@nx/eslint-plugin');
|
|
85
|
+
content = (0, ast_utils_1.addPluginsToExportsBlock)(content, [
|
|
86
|
+
{ name: '@nx', varName: 'nxPlugin', imp: '@nx/eslint-plugin' },
|
|
87
|
+
]);
|
|
88
|
+
if (!rootProject) {
|
|
89
|
+
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(moduleBoundariesOverride));
|
|
90
|
+
}
|
|
91
|
+
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(exports.typeScriptOverride));
|
|
92
|
+
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(exports.javaScriptOverride));
|
|
93
|
+
if (unitTestRunner === 'jest') {
|
|
94
|
+
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateFlatOverride)(jestOverride));
|
|
95
|
+
}
|
|
96
|
+
// add ignore for .nx folder
|
|
97
|
+
content = (0, ast_utils_1.addBlockToFlatConfigExport)(content, (0, ast_utils_1.generateAst)({
|
|
98
|
+
ignores: ['.nx'],
|
|
99
|
+
}));
|
|
100
|
+
return content;
|
|
101
|
+
};
|
|
102
|
+
exports.getGlobalFlatEslintConfiguration = getGlobalFlatEslintConfiguration;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ProjectConfiguration, TargetConfiguration, Tree } from '@nx/devkit';
|
|
2
|
+
export declare function migrateConfigToMonorepoStyle(projects: ProjectConfiguration[], tree: Tree, unitTestRunner: string, keepExistingVersions?: boolean): void;
|
|
3
|
+
export declare function findLintTarget(project: ProjectConfiguration): TargetConfiguration;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findLintTarget = exports.migrateConfigToMonorepoStyle = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const eslint_file_1 = require("../utils/eslint-file");
|
|
7
|
+
const global_eslint_config_1 = require("./global-eslint-config");
|
|
8
|
+
const flat_config_1 = require("../../utils/flat-config");
|
|
9
|
+
const versions_1 = require("../../utils/versions");
|
|
10
|
+
const ast_utils_1 = require("../utils/flat-config/ast-utils");
|
|
11
|
+
const plugin_1 = require("../utils/plugin");
|
|
12
|
+
const config_file_1 = require("../../utils/config-file");
|
|
13
|
+
function migrateConfigToMonorepoStyle(projects, tree, unitTestRunner, keepExistingVersions) {
|
|
14
|
+
const rootEslintConfig = (0, eslint_file_1.findEslintFile)(tree);
|
|
15
|
+
let skipCleanup = false;
|
|
16
|
+
if (rootEslintConfig?.match(/\.base\./) &&
|
|
17
|
+
!projects.some((p) => p.root === '.')) {
|
|
18
|
+
// if the migration has been run already, we need to rename the base config
|
|
19
|
+
// and only update the extends paths
|
|
20
|
+
tree.rename(rootEslintConfig, rootEslintConfig.replace('.base.', '.'));
|
|
21
|
+
skipCleanup = true;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
25
|
+
// we need this for the compat
|
|
26
|
+
(0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
27
|
+
'@eslint/js': versions_1.eslintVersion,
|
|
28
|
+
}, undefined, keepExistingVersions);
|
|
29
|
+
tree.write(tree.exists('eslint.config.js')
|
|
30
|
+
? 'eslint.base.config.js'
|
|
31
|
+
: 'eslint.config.js', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(unitTestRunner));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const eslintFile = (0, eslint_file_1.findEslintFile)(tree, '.');
|
|
35
|
+
(0, devkit_1.writeJson)(tree, eslintFile ? '.eslintrc.base.json' : '.eslintrc.json', (0, global_eslint_config_1.getGlobalEsLintConfiguration)(unitTestRunner));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// update extends in all projects' eslint configs
|
|
39
|
+
projects.forEach((project) => {
|
|
40
|
+
let eslintFile;
|
|
41
|
+
const lintTarget = findLintTarget(project);
|
|
42
|
+
if (lintTarget) {
|
|
43
|
+
// If target is configured in project.json, read file from target options.
|
|
44
|
+
eslintFile =
|
|
45
|
+
lintTarget.options?.eslintConfig || (0, eslint_file_1.findEslintFile)(tree, project.root);
|
|
46
|
+
}
|
|
47
|
+
else if ((0, plugin_1.hasEslintPlugin)(tree)) {
|
|
48
|
+
// Otherwise, if `@nx/eslint/plugin` is used, match any of the known config files.
|
|
49
|
+
for (const f of config_file_1.ESLINT_CONFIG_FILENAMES) {
|
|
50
|
+
if (tree.exists((0, devkit_1.joinPathFragments)(project.root, f))) {
|
|
51
|
+
eslintFile = f;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (eslintFile) {
|
|
57
|
+
const projectEslintPath = (0, devkit_1.joinPathFragments)(project.root, eslintFile);
|
|
58
|
+
if (skipCleanup) {
|
|
59
|
+
const content = tree.read(projectEslintPath, 'utf-8');
|
|
60
|
+
tree.write(projectEslintPath, content.replace(rootEslintConfig, rootEslintConfig.replace('.base.', '.')));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
migrateEslintFile(projectEslintPath, tree);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
exports.migrateConfigToMonorepoStyle = migrateConfigToMonorepoStyle;
|
|
69
|
+
function findLintTarget(project) {
|
|
70
|
+
return Object.values(project.targets ?? {}).find((target) => target.executor === '@nx/eslint:lint' ||
|
|
71
|
+
target.executor === '@nx/linter:eslint' ||
|
|
72
|
+
target.executor === '@nrwl/linter:eslint');
|
|
73
|
+
}
|
|
74
|
+
exports.findLintTarget = findLintTarget;
|
|
75
|
+
function migrateEslintFile(projectEslintPath, tree) {
|
|
76
|
+
const baseFile = (0, eslint_file_1.findEslintFile)(tree);
|
|
77
|
+
if ((0, eslint_file_1.isEslintConfigSupported)(tree)) {
|
|
78
|
+
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
79
|
+
let config = tree.read(projectEslintPath, 'utf-8');
|
|
80
|
+
// remove @nx plugin
|
|
81
|
+
config = (0, ast_utils_1.removePlugin)(config, '@nx', '@nx/eslint-plugin-nx');
|
|
82
|
+
// extend eslint.base.config.js
|
|
83
|
+
config = (0, ast_utils_1.addImportToFlatConfig)(config, 'baseConfig', `${(0, devkit_1.offsetFromRoot)((0, path_1.dirname)(projectEslintPath))}${baseFile}`);
|
|
84
|
+
config = (0, ast_utils_1.addBlockToFlatConfigExport)(config, (0, ast_utils_1.generateSpreadElement)('baseConfig'), { insertAtTheEnd: false });
|
|
85
|
+
// cleanup file extends
|
|
86
|
+
config = (0, ast_utils_1.removeCompatExtends)(config, [
|
|
87
|
+
'plugin:@nx/typescript',
|
|
88
|
+
'plugin:@nx/javascript',
|
|
89
|
+
'plugin:@nrwl/typescript',
|
|
90
|
+
'plugin:@nrwl/javascript',
|
|
91
|
+
]);
|
|
92
|
+
tree.write(projectEslintPath, config);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
(0, devkit_1.updateJson)(tree, projectEslintPath, (json) => {
|
|
96
|
+
// we have a new root now
|
|
97
|
+
delete json.root;
|
|
98
|
+
// remove nrwl/nx plugins
|
|
99
|
+
if (json.plugins) {
|
|
100
|
+
json.plugins = json.plugins.filter((p) => p !== '@nx' && p !== '@nrwl/nx');
|
|
101
|
+
if (json.plugins.length === 0) {
|
|
102
|
+
delete json.plugins;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// add extends
|
|
106
|
+
json.extends = json.extends || [];
|
|
107
|
+
const pathToRootConfig = `${(0, devkit_1.offsetFromRoot)((0, path_1.dirname)(projectEslintPath))}${baseFile}`;
|
|
108
|
+
if (json.extends.indexOf(pathToRootConfig) === -1) {
|
|
109
|
+
json.extends.push(pathToRootConfig);
|
|
110
|
+
}
|
|
111
|
+
// cleanup overrides
|
|
112
|
+
if (json.overrides) {
|
|
113
|
+
json.overrides.forEach((override) => {
|
|
114
|
+
if (override.extends) {
|
|
115
|
+
override.extends = override.extends.filter((ext) => ext !== 'plugin:@nx/typescript' &&
|
|
116
|
+
ext !== 'plugin:@nrwl/nx/typescript' &&
|
|
117
|
+
ext !== 'plugin:@nx/javascript' &&
|
|
118
|
+
ext !== 'plugin:@nrwl/nx/javascript');
|
|
119
|
+
if (override.extends.length === 0) {
|
|
120
|
+
delete override.extends;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return json;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (projectEslintPath.endsWith('.yml') ||
|
|
131
|
+
projectEslintPath.endsWith('.yaml')) {
|
|
132
|
+
console.warn('YAML eslint config is not supported yet for migration');
|
|
133
|
+
}
|
|
134
|
+
if (projectEslintPath.endsWith('.js') || projectEslintPath.endsWith('.cjs')) {
|
|
135
|
+
console.warn('JS eslint config is not supported yet for migration');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
|
2
|
+
export interface LinterInitOptions {
|
|
3
|
+
skipPackageJson?: boolean;
|
|
4
|
+
keepExistingVersions?: boolean;
|
|
5
|
+
updatePackageScripts?: boolean;
|
|
6
|
+
addPlugin?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function initEsLint(tree: Tree, options: LinterInitOptions): Promise<GeneratorCallback>;
|
|
9
|
+
export declare function lintInitGenerator(tree: Tree, options: LinterInitOptions): Promise<GeneratorCallback>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lintInitGenerator = exports.initEsLint = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const update_package_scripts_1 = require("@nx/devkit/src/utils/update-package-scripts");
|
|
6
|
+
const versions_1 = require("../../utils/versions");
|
|
7
|
+
const eslint_file_1 = require("../utils/eslint-file");
|
|
8
|
+
const plugin_1 = require("../../plugins/plugin");
|
|
9
|
+
const plugin_2 = require("../utils/plugin");
|
|
10
|
+
function updateProductionFileset(tree) {
|
|
11
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
12
|
+
const productionFileSet = nxJson.namedInputs?.production;
|
|
13
|
+
if (productionFileSet) {
|
|
14
|
+
productionFileSet.push('!{projectRoot}/.eslintrc.json');
|
|
15
|
+
productionFileSet.push('!{projectRoot}/eslint.config.js');
|
|
16
|
+
// Dedupe and set
|
|
17
|
+
nxJson.namedInputs.production = Array.from(new Set(productionFileSet));
|
|
18
|
+
}
|
|
19
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
20
|
+
}
|
|
21
|
+
function addTargetDefaults(tree) {
|
|
22
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
23
|
+
nxJson.targetDefaults ??= {};
|
|
24
|
+
nxJson.targetDefaults['@nx/eslint:lint'] ??= {};
|
|
25
|
+
nxJson.targetDefaults['@nx/eslint:lint'].cache ??= true;
|
|
26
|
+
nxJson.targetDefaults['@nx/eslint:lint'].inputs ??= [
|
|
27
|
+
'default',
|
|
28
|
+
`{workspaceRoot}/.eslintrc.json`,
|
|
29
|
+
`{workspaceRoot}/.eslintignore`,
|
|
30
|
+
`{workspaceRoot}/eslint.config.js`,
|
|
31
|
+
];
|
|
32
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
33
|
+
}
|
|
34
|
+
function addPlugin(tree) {
|
|
35
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
36
|
+
nxJson.plugins ??= [];
|
|
37
|
+
for (const plugin of nxJson.plugins) {
|
|
38
|
+
if (typeof plugin === 'string'
|
|
39
|
+
? plugin === '@nx/eslint/plugin'
|
|
40
|
+
: plugin.plugin === '@nx/eslint/plugin') {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
nxJson.plugins.push({
|
|
45
|
+
plugin: '@nx/eslint/plugin',
|
|
46
|
+
options: {
|
|
47
|
+
targetName: 'lint',
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
51
|
+
}
|
|
52
|
+
async function initEsLint(tree, options) {
|
|
53
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
54
|
+
const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
55
|
+
nxJson.useInferencePlugins !== false;
|
|
56
|
+
options.addPlugin ??= addPluginDefault;
|
|
57
|
+
const hasPlugin = (0, plugin_2.hasEslintPlugin)(tree);
|
|
58
|
+
const rootEslintFile = (0, eslint_file_1.findEslintFile)(tree);
|
|
59
|
+
if (rootEslintFile && options.addPlugin && !hasPlugin) {
|
|
60
|
+
addPlugin(tree);
|
|
61
|
+
if (options.updatePackageScripts) {
|
|
62
|
+
await (0, update_package_scripts_1.updatePackageScripts)(tree, plugin_1.createNodes);
|
|
63
|
+
}
|
|
64
|
+
return () => { };
|
|
65
|
+
}
|
|
66
|
+
if (rootEslintFile) {
|
|
67
|
+
return () => { };
|
|
68
|
+
}
|
|
69
|
+
updateProductionFileset(tree);
|
|
70
|
+
if (options.addPlugin) {
|
|
71
|
+
addPlugin(tree);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
addTargetDefaults(tree);
|
|
75
|
+
}
|
|
76
|
+
const tasks = [];
|
|
77
|
+
if (!options.skipPackageJson) {
|
|
78
|
+
tasks.push((0, devkit_1.removeDependenciesFromPackageJson)(tree, ['@nx/eslint'], []));
|
|
79
|
+
tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
80
|
+
'@nx/eslint': versions_1.nxVersion,
|
|
81
|
+
eslint: versions_1.eslintVersion,
|
|
82
|
+
}, undefined, options.keepExistingVersions));
|
|
83
|
+
}
|
|
84
|
+
if (options.updatePackageScripts) {
|
|
85
|
+
await (0, update_package_scripts_1.updatePackageScripts)(tree, plugin_1.createNodes);
|
|
86
|
+
}
|
|
87
|
+
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
88
|
+
}
|
|
89
|
+
exports.initEsLint = initEsLint;
|
|
90
|
+
async function lintInitGenerator(tree, options) {
|
|
91
|
+
return await initEsLint(tree, { addPlugin: false, ...options });
|
|
92
|
+
}
|
|
93
|
+
exports.lintInitGenerator = lintInitGenerator;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"cli": "nx",
|
|
4
|
+
"$id": "NxESLintInit",
|
|
5
|
+
"title": "Initialize ESLint Plugin",
|
|
6
|
+
"description": "Set up the ESLint plugin.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"skipPackageJson": {
|
|
10
|
+
"description": "Do not add dependencies to `package.json`.",
|
|
11
|
+
"type": "boolean",
|
|
12
|
+
"default": false
|
|
13
|
+
},
|
|
14
|
+
"keepExistingVersions": {
|
|
15
|
+
"type": "boolean",
|
|
16
|
+
"x-priority": "internal",
|
|
17
|
+
"description": "Keep existing dependencies versions",
|
|
18
|
+
"default": false
|
|
19
|
+
},
|
|
20
|
+
"updatePackageScripts": {
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"x-priority": "internal",
|
|
23
|
+
"description": "Update `package.json` scripts with inferred targets",
|
|
24
|
+
"default": false
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": []
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
|
2
|
+
import { Linter as LinterEnum } from '../utils/linter';
|
|
3
|
+
interface LintProjectOptions {
|
|
4
|
+
project: string;
|
|
5
|
+
linter?: LinterEnum;
|
|
6
|
+
eslintFilePatterns?: string[];
|
|
7
|
+
tsConfigPaths?: string[];
|
|
8
|
+
skipFormat: boolean;
|
|
9
|
+
setParserOptionsProject?: boolean;
|
|
10
|
+
skipPackageJson?: boolean;
|
|
11
|
+
unitTestRunner?: string;
|
|
12
|
+
rootProject?: boolean;
|
|
13
|
+
keepExistingVersions?: boolean;
|
|
14
|
+
addPlugin?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
addExplicitTargets?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function lintProjectGenerator(tree: Tree, options: LintProjectOptions): Promise<GeneratorCallback>;
|
|
21
|
+
export declare function lintProjectGeneratorInternal(tree: Tree, options: LintProjectOptions): Promise<GeneratorCallback>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lintProjectGeneratorInternal = exports.lintProjectGenerator = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const eslint_file_1 = require("../utils/eslint-file");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const init_1 = require("../init/init");
|
|
8
|
+
const init_migration_1 = require("../init/init-migration");
|
|
9
|
+
const project_configuration_1 = require("nx/src/generators/utils/project-configuration");
|
|
10
|
+
const flat_config_1 = require("../../utils/flat-config");
|
|
11
|
+
const ast_utils_1 = require("../utils/flat-config/ast-utils");
|
|
12
|
+
const config_file_1 = require("../../utils/config-file");
|
|
13
|
+
const plugin_1 = require("../utils/plugin");
|
|
14
|
+
const setup_root_eslint_1 = require("./setup-root-eslint");
|
|
15
|
+
function lintProjectGenerator(tree, options) {
|
|
16
|
+
return lintProjectGeneratorInternal(tree, { addPlugin: false, ...options });
|
|
17
|
+
}
|
|
18
|
+
exports.lintProjectGenerator = lintProjectGenerator;
|
|
19
|
+
async function lintProjectGeneratorInternal(tree, options) {
|
|
20
|
+
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
21
|
+
const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' &&
|
|
22
|
+
nxJson.useInferencePlugins !== false;
|
|
23
|
+
options.addPlugin ??= addPluginDefault;
|
|
24
|
+
const tasks = [];
|
|
25
|
+
const initTask = await (0, init_1.lintInitGenerator)(tree, {
|
|
26
|
+
skipPackageJson: options.skipPackageJson,
|
|
27
|
+
addPlugin: options.addPlugin,
|
|
28
|
+
});
|
|
29
|
+
tasks.push(initTask);
|
|
30
|
+
const rootEsLintTask = (0, setup_root_eslint_1.setupRootEsLint)(tree, {
|
|
31
|
+
unitTestRunner: options.unitTestRunner,
|
|
32
|
+
skipPackageJson: options.skipPackageJson,
|
|
33
|
+
rootProject: options.rootProject,
|
|
34
|
+
});
|
|
35
|
+
tasks.push(rootEsLintTask);
|
|
36
|
+
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
37
|
+
let lintFilePatterns = options.eslintFilePatterns;
|
|
38
|
+
if (!lintFilePatterns && options.rootProject && projectConfig.root === '.') {
|
|
39
|
+
lintFilePatterns = ['./src'];
|
|
40
|
+
}
|
|
41
|
+
if (lintFilePatterns &&
|
|
42
|
+
lintFilePatterns.length &&
|
|
43
|
+
!lintFilePatterns.includes('{projectRoot}') &&
|
|
44
|
+
isBuildableLibraryProject(projectConfig)) {
|
|
45
|
+
lintFilePatterns.push(`{projectRoot}/package.json`);
|
|
46
|
+
}
|
|
47
|
+
const hasPlugin = (0, plugin_1.hasEslintPlugin)(tree);
|
|
48
|
+
if (hasPlugin && !options.addExplicitTargets) {
|
|
49
|
+
if (lintFilePatterns &&
|
|
50
|
+
lintFilePatterns.length &&
|
|
51
|
+
lintFilePatterns.some((p) => !['./src', '{projectRoot}', projectConfig.root].includes(p))) {
|
|
52
|
+
projectConfig.targets['lint'] = {
|
|
53
|
+
command: `eslint ${lintFilePatterns
|
|
54
|
+
.join(' ')
|
|
55
|
+
.replace('{projectRoot}', projectConfig.root)}`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
projectConfig.targets['lint'] = {
|
|
61
|
+
executor: '@nx/eslint:lint',
|
|
62
|
+
};
|
|
63
|
+
if (lintFilePatterns && lintFilePatterns.length) {
|
|
64
|
+
// only add lintFilePatterns if they are explicitly defined
|
|
65
|
+
projectConfig.targets['lint'].options = {
|
|
66
|
+
lintFilePatterns,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// we are adding new project which is not the root project or
|
|
71
|
+
// companion e2e app so we should check if migration to
|
|
72
|
+
// monorepo style is needed
|
|
73
|
+
if (!options.rootProject) {
|
|
74
|
+
const projects = {};
|
|
75
|
+
(0, project_configuration_1.getProjects)(tree).forEach((v, k) => (projects[k] = v));
|
|
76
|
+
if (isMigrationToMonorepoNeeded(projects, tree)) {
|
|
77
|
+
// we only migrate project configurations that have been created
|
|
78
|
+
const filteredProjects = [];
|
|
79
|
+
Object.entries(projects).forEach(([name, project]) => {
|
|
80
|
+
if (name !== options.project) {
|
|
81
|
+
filteredProjects.push(project);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
(0, init_migration_1.migrateConfigToMonorepoStyle)(filteredProjects, tree, options.unitTestRunner, options.keepExistingVersions);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// our root `.eslintrc` is already the project config, so we should not override it
|
|
88
|
+
// additionally, the companion e2e app would have `rootProject: true`
|
|
89
|
+
// so we need to check for the root path as well
|
|
90
|
+
if (!options.rootProject || projectConfig.root !== '.') {
|
|
91
|
+
createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject, options.rootProject);
|
|
92
|
+
}
|
|
93
|
+
// Buildable libs need source analysis enabled for linting `package.json`.
|
|
94
|
+
if (isBuildableLibraryProject(projectConfig) &&
|
|
95
|
+
!isJsAnalyzeSourceFilesEnabled(tree)) {
|
|
96
|
+
(0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
|
|
97
|
+
json.pluginsConfig ??= {};
|
|
98
|
+
json.pluginsConfig['@nx/js'] ??= {};
|
|
99
|
+
json.pluginsConfig['@nx/js'].analyzeSourceFiles = true;
|
|
100
|
+
return json;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
(0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
|
|
104
|
+
if (!options.skipFormat) {
|
|
105
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
106
|
+
}
|
|
107
|
+
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
108
|
+
}
|
|
109
|
+
exports.lintProjectGeneratorInternal = lintProjectGeneratorInternal;
|
|
110
|
+
function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject, rootProject) {
|
|
111
|
+
// we are only extending root for non-standalone projects or their complementary e2e apps
|
|
112
|
+
const extendedRootConfig = rootProject ? undefined : (0, eslint_file_1.findEslintFile)(tree);
|
|
113
|
+
const pathToRootConfig = extendedRootConfig
|
|
114
|
+
? `${(0, devkit_1.offsetFromRoot)(projectConfig.root)}${extendedRootConfig}`
|
|
115
|
+
: undefined;
|
|
116
|
+
const addDependencyChecks = isBuildableLibraryProject(projectConfig);
|
|
117
|
+
const overrides = [
|
|
118
|
+
{
|
|
119
|
+
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
|
|
120
|
+
/**
|
|
121
|
+
* NOTE: We no longer set parserOptions.project by default when creating new projects.
|
|
122
|
+
*
|
|
123
|
+
* We have observed that users rarely add rules requiring type-checking to their Nx workspaces, and therefore
|
|
124
|
+
* do not actually need the capabilites which parserOptions.project provides. When specifying parserOptions.project,
|
|
125
|
+
* typescript-eslint needs to create full TypeScript Programs for you. When omitting it, it can perform a simple
|
|
126
|
+
* parse (and AST tranformation) of the source files it encounters during a lint run, which is much faster and much
|
|
127
|
+
* less memory intensive.
|
|
128
|
+
*
|
|
129
|
+
* In the rare case that users attempt to add rules requiring type-checking to their setup later on (and haven't set
|
|
130
|
+
* parserOptions.project), the executor will attempt to look for the particular error typescript-eslint gives you
|
|
131
|
+
* and provide feedback to the user.
|
|
132
|
+
*/
|
|
133
|
+
parserOptions: !setParserOptionsProject
|
|
134
|
+
? undefined
|
|
135
|
+
: {
|
|
136
|
+
project: [`${projectConfig.root}/tsconfig.*?.json`],
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* Having an empty rules object present makes it more obvious to the user where they would
|
|
140
|
+
* extend things from if they needed to
|
|
141
|
+
*/
|
|
142
|
+
rules: {},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
files: ['*.ts', '*.tsx'],
|
|
146
|
+
rules: {},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
files: ['*.js', '*.jsx'],
|
|
150
|
+
rules: {},
|
|
151
|
+
},
|
|
152
|
+
];
|
|
153
|
+
if (isBuildableLibraryProject(projectConfig)) {
|
|
154
|
+
overrides.push({
|
|
155
|
+
files: ['*.json'],
|
|
156
|
+
parser: 'jsonc-eslint-parser',
|
|
157
|
+
rules: {
|
|
158
|
+
'@nx/dependency-checks': 'error',
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if ((0, flat_config_1.useFlatConfig)(tree)) {
|
|
163
|
+
const isCompatNeeded = addDependencyChecks;
|
|
164
|
+
const nodes = [];
|
|
165
|
+
const importMap = new Map();
|
|
166
|
+
if (extendedRootConfig) {
|
|
167
|
+
importMap.set(pathToRootConfig, 'baseConfig');
|
|
168
|
+
nodes.push((0, ast_utils_1.generateSpreadElement)('baseConfig'));
|
|
169
|
+
}
|
|
170
|
+
overrides.forEach((override) => {
|
|
171
|
+
nodes.push((0, ast_utils_1.generateFlatOverride)(override));
|
|
172
|
+
});
|
|
173
|
+
const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes, isCompatNeeded);
|
|
174
|
+
const content = (0, ast_utils_1.stringifyNodeList)(nodeList);
|
|
175
|
+
tree.write((0, path_1.join)(projectConfig.root, 'eslint.config.js'), content);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
(0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
|
|
179
|
+
extends: extendedRootConfig ? [pathToRootConfig] : undefined,
|
|
180
|
+
// Include project files to be linted since the global one excludes all files.
|
|
181
|
+
ignorePatterns: ['!**/*'],
|
|
182
|
+
overrides,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function isJsAnalyzeSourceFilesEnabled(tree) {
|
|
187
|
+
const nxJson = (0, devkit_1.readJson)(tree, 'nx.json');
|
|
188
|
+
const jsPluginConfig = nxJson.pluginsConfig?.['@nx/js'];
|
|
189
|
+
return (jsPluginConfig?.analyzeSourceFiles ??
|
|
190
|
+
nxJson.extends !== 'nx/presets/npm.json');
|
|
191
|
+
}
|
|
192
|
+
function isBuildableLibraryProject(projectConfig) {
|
|
193
|
+
return (projectConfig.projectType === 'library' &&
|
|
194
|
+
projectConfig.targets?.build &&
|
|
195
|
+
!!projectConfig.targets.build);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Detect based on the state of lint target configuration of the root project
|
|
199
|
+
* if we should migrate eslint configs to monorepo style
|
|
200
|
+
*/
|
|
201
|
+
function isMigrationToMonorepoNeeded(projects, tree) {
|
|
202
|
+
// the base config is already created, migration has been done
|
|
203
|
+
if (tree.exists(config_file_1.baseEsLintConfigFile) ||
|
|
204
|
+
tree.exists(config_file_1.baseEsLintFlatConfigFile)) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
const configs = Object.values(projects);
|
|
208
|
+
if (configs.length === 1) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
// get root project
|
|
212
|
+
const rootProject = configs.find((p) => p.root === '.');
|
|
213
|
+
if (!rootProject || !rootProject.targets) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
// check if we're inferring lint target from `@nx/eslint/plugin`
|
|
217
|
+
if ((0, plugin_1.hasEslintPlugin)(tree)) {
|
|
218
|
+
for (const f of config_file_1.ESLINT_CONFIG_FILENAMES) {
|
|
219
|
+
if (tree.exists(f)) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// find if root project has lint target
|
|
225
|
+
const lintTarget = (0, init_migration_1.findLintTarget)(rootProject);
|
|
226
|
+
return !!lintTarget;
|
|
227
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type GeneratorCallback, type Tree } from '@nx/devkit';
|
|
2
|
+
export type SetupRootEsLintOptions = {
|
|
3
|
+
unitTestRunner?: string;
|
|
4
|
+
skipPackageJson?: boolean;
|
|
5
|
+
rootProject?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function setupRootEsLint(tree: Tree, options: SetupRootEsLintOptions): GeneratorCallback;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupRootEsLint = void 0;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const versions_1 = require("../../utils/versions");
|
|
6
|
+
const global_eslint_config_1 = require("../init/global-eslint-config");
|
|
7
|
+
const eslint_file_1 = require("../utils/eslint-file");
|
|
8
|
+
function setupRootEsLint(tree, options) {
|
|
9
|
+
const rootEslintFile = (0, eslint_file_1.findEslintFile)(tree);
|
|
10
|
+
if (rootEslintFile) {
|
|
11
|
+
return () => { };
|
|
12
|
+
}
|
|
13
|
+
(0, devkit_1.writeJson)(tree, '.eslintrc.json', (0, global_eslint_config_1.getGlobalEsLintConfiguration)(options.unitTestRunner, options.rootProject));
|
|
14
|
+
if (tree.exists('.eslintignore')) {
|
|
15
|
+
let content = tree.read('.eslintignore', 'utf-8');
|
|
16
|
+
if (!/^node_modules$/gm.test(content)) {
|
|
17
|
+
content = `${content}\nnode_modules\n`;
|
|
18
|
+
tree.write('.eslintignore', content);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
tree.write('.eslintignore', 'node_modules\n');
|
|
23
|
+
}
|
|
24
|
+
return !options.skipPackageJson
|
|
25
|
+
? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
26
|
+
'@nx/eslint-plugin': versions_1.nxVersion,
|
|
27
|
+
'@typescript-eslint/parser': versions_1.typescriptESLintVersion,
|
|
28
|
+
'@typescript-eslint/eslint-plugin': versions_1.typescriptESLintVersion,
|
|
29
|
+
'eslint-config-prettier': versions_1.eslintConfigPrettierVersion,
|
|
30
|
+
})
|
|
31
|
+
: () => { };
|
|
32
|
+
}
|
|
33
|
+
exports.setupRootEsLint = setupRootEsLint;
|