@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.
Files changed (86) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +66 -0
  3. package/executors.json +10 -0
  4. package/generators.json +28 -0
  5. package/index.d.ts +4 -0
  6. package/index.js +14 -0
  7. package/migrations.json +138 -0
  8. package/package.json +52 -0
  9. package/plugin.d.ts +1 -0
  10. package/plugin.js +5 -0
  11. package/src/executors/lint/hasher.d.ts +9 -0
  12. package/src/executors/lint/hasher.js +43 -0
  13. package/src/executors/lint/lint.impl.d.ts +5 -0
  14. package/src/executors/lint/lint.impl.js +174 -0
  15. package/src/executors/lint/schema.d.ts +40 -0
  16. package/src/executors/lint/schema.json +148 -0
  17. package/src/executors/lint/utility/eslint-utils.d.ts +6 -0
  18. package/src/executors/lint/utility/eslint-utils.js +75 -0
  19. package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +11 -0
  20. package/src/generators/convert-to-flat-config/converters/json-converter.js +175 -0
  21. package/src/generators/convert-to-flat-config/generator.d.ts +4 -0
  22. package/src/generators/convert-to-flat-config/generator.js +139 -0
  23. package/src/generators/convert-to-flat-config/schema.d.ts +3 -0
  24. package/src/generators/convert-to-flat-config/schema.json +17 -0
  25. package/src/generators/init/global-eslint-config.d.ts +29 -0
  26. package/src/generators/init/global-eslint-config.js +102 -0
  27. package/src/generators/init/init-migration.d.ts +3 -0
  28. package/src/generators/init/init-migration.js +137 -0
  29. package/src/generators/init/init.d.ts +9 -0
  30. package/src/generators/init/init.js +93 -0
  31. package/src/generators/init/schema.json +28 -0
  32. package/src/generators/lint-project/lint-project.d.ts +22 -0
  33. package/src/generators/lint-project/lint-project.js +227 -0
  34. package/src/generators/lint-project/setup-root-eslint.d.ts +7 -0
  35. package/src/generators/lint-project/setup-root-eslint.js +33 -0
  36. package/src/generators/utils/eslint-file.d.ts +16 -0
  37. package/src/generators/utils/eslint-file.js +287 -0
  38. package/src/generators/utils/eslint-targets.d.ts +2 -0
  39. package/src/generators/utils/eslint-targets.js +18 -0
  40. package/src/generators/utils/flat-config/ast-utils.d.ts +60 -0
  41. package/src/generators/utils/flat-config/ast-utils.js +573 -0
  42. package/src/generators/utils/flat-config/path-utils.d.ts +3 -0
  43. package/src/generators/utils/flat-config/path-utils.js +28 -0
  44. package/src/generators/utils/linter.d.ts +4 -0
  45. package/src/generators/utils/linter.js +8 -0
  46. package/src/generators/utils/plugin.d.ts +2 -0
  47. package/src/generators/utils/plugin.js +11 -0
  48. package/src/generators/workspace-rule/files/__name__.spec.ts__tmpl__ +11 -0
  49. package/src/generators/workspace-rule/files/__name__.ts__tmpl__ +37 -0
  50. package/src/generators/workspace-rule/schema.json +26 -0
  51. package/src/generators/workspace-rule/workspace-rule.d.ts +6 -0
  52. package/src/generators/workspace-rule/workspace-rule.js +78 -0
  53. package/src/generators/workspace-rules-project/files/index.ts__tmpl__ +27 -0
  54. package/src/generators/workspace-rules-project/files/tsconfig.json__tmpl__ +14 -0
  55. package/src/generators/workspace-rules-project/files/tsconfig.lint.json__tmpl__ +9 -0
  56. package/src/generators/workspace-rules-project/schema.json +23 -0
  57. package/src/generators/workspace-rules-project/workspace-rules-project.d.ts +8 -0
  58. package/src/generators/workspace-rules-project/workspace-rules-project.js +82 -0
  59. package/src/migrations/update-15-0-0/add-eslint-inputs.d.ts +2 -0
  60. package/src/migrations/update-15-0-0/add-eslint-inputs.js +27 -0
  61. package/src/migrations/update-15-7-1/add-eslint-ignore.d.ts +2 -0
  62. package/src/migrations/update-15-7-1/add-eslint-ignore.js +36 -0
  63. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +2 -0
  64. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +9 -0
  65. package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.d.ts +2 -0
  66. package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.js +44 -0
  67. package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.d.ts +2 -0
  68. package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.js +47 -0
  69. package/src/migrations/update-17-1-0/update-typescript-eslint.d.ts +2 -0
  70. package/src/migrations/update-17-1-0/update-typescript-eslint.js +74 -0
  71. package/src/migrations/update-17-2-0/simplify-eslint-patterns.d.ts +2 -0
  72. package/src/migrations/update-17-2-0/simplify-eslint-patterns.js +46 -0
  73. package/src/migrations/update-17-2-9/move-options-to-target-defaults.d.ts +2 -0
  74. package/src/migrations/update-17-2-9/move-options-to-target-defaults.js +107 -0
  75. package/src/plugins/plugin.d.ts +5 -0
  76. package/src/plugins/plugin.js +92 -0
  77. package/src/utils/config-file.d.ts +5 -0
  78. package/src/utils/config-file.js +35 -0
  79. package/src/utils/flat-config.d.ts +2 -0
  80. package/src/utils/flat-config.js +7 -0
  81. package/src/utils/rules-requiring-type-checking.d.ts +3 -0
  82. package/src/utils/rules-requiring-type-checking.js +84 -0
  83. package/src/utils/versions.d.ts +5 -0
  84. package/src/utils/versions.js +8 -0
  85. package/src/utils/workspace-lint-rules.d.ts +1 -0
  86. 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;