@nx/eslint 17.0.0-beta.8

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 (69) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +61 -0
  3. package/executors.json +10 -0
  4. package/generators.json +22 -0
  5. package/index.d.ts +4 -0
  6. package/index.js +14 -0
  7. package/migrations.json +79 -0
  8. package/package.json +51 -0
  9. package/src/executors/lint/hasher.d.ts +9 -0
  10. package/src/executors/lint/hasher.js +43 -0
  11. package/src/executors/lint/lint.impl.d.ts +5 -0
  12. package/src/executors/lint/lint.impl.js +140 -0
  13. package/src/executors/lint/schema.d.ts +39 -0
  14. package/src/executors/lint/schema.json +144 -0
  15. package/src/executors/lint/utility/eslint-utils.d.ts +6 -0
  16. package/src/executors/lint/utility/eslint-utils.js +71 -0
  17. package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +6 -0
  18. package/src/generators/convert-to-flat-config/converters/json-converter.js +180 -0
  19. package/src/generators/convert-to-flat-config/generator.d.ts +4 -0
  20. package/src/generators/convert-to-flat-config/generator.js +83 -0
  21. package/src/generators/convert-to-flat-config/schema.d.ts +3 -0
  22. package/src/generators/convert-to-flat-config/schema.json +17 -0
  23. package/src/generators/init/global-eslint-config.d.ts +29 -0
  24. package/src/generators/init/global-eslint-config.js +98 -0
  25. package/src/generators/init/init-migration.d.ts +3 -0
  26. package/src/generators/init/init-migration.js +103 -0
  27. package/src/generators/init/init.d.ts +9 -0
  28. package/src/generators/init/init.js +65 -0
  29. package/src/generators/lint-project/lint-project.d.ts +16 -0
  30. package/src/generators/lint-project/lint-project.js +191 -0
  31. package/src/generators/utils/eslint-file.d.ts +19 -0
  32. package/src/generators/utils/eslint-file.js +269 -0
  33. package/src/generators/utils/eslint-targets.d.ts +2 -0
  34. package/src/generators/utils/eslint-targets.js +18 -0
  35. package/src/generators/utils/flat-config/ast-utils.d.ts +61 -0
  36. package/src/generators/utils/flat-config/ast-utils.js +581 -0
  37. package/src/generators/utils/flat-config/path-utils.d.ts +2 -0
  38. package/src/generators/utils/flat-config/path-utils.js +31 -0
  39. package/src/generators/utils/linter.d.ts +4 -0
  40. package/src/generators/utils/linter.js +8 -0
  41. package/src/generators/workspace-rule/files/__name__.spec.ts__tmpl__ +11 -0
  42. package/src/generators/workspace-rule/files/__name__.ts__tmpl__ +37 -0
  43. package/src/generators/workspace-rule/schema.json +26 -0
  44. package/src/generators/workspace-rule/workspace-rule.d.ts +6 -0
  45. package/src/generators/workspace-rule/workspace-rule.js +73 -0
  46. package/src/generators/workspace-rules-project/files/index.ts__tmpl__ +27 -0
  47. package/src/generators/workspace-rules-project/files/tsconfig.json__tmpl__ +13 -0
  48. package/src/generators/workspace-rules-project/files/tsconfig.lint.json__tmpl__ +9 -0
  49. package/src/generators/workspace-rules-project/schema.json +23 -0
  50. package/src/generators/workspace-rules-project/workspace-rules-project.d.ts +7 -0
  51. package/src/generators/workspace-rules-project/workspace-rules-project.js +80 -0
  52. package/src/migrations/update-15-0-0/add-eslint-inputs.d.ts +2 -0
  53. package/src/migrations/update-15-0-0/add-eslint-inputs.js +27 -0
  54. package/src/migrations/update-15-7-1/add-eslint-ignore.d.ts +2 -0
  55. package/src/migrations/update-15-7-1/add-eslint-ignore.js +36 -0
  56. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +2 -0
  57. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +9 -0
  58. package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.d.ts +2 -0
  59. package/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.js +44 -0
  60. package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.d.ts +2 -0
  61. package/src/migrations/update-17-0-0-rename-to-eslint/update-17-0-0-rename-to-eslint.js +45 -0
  62. package/src/utils/flat-config.d.ts +2 -0
  63. package/src/utils/flat-config.js +7 -0
  64. package/src/utils/rules-requiring-type-checking.d.ts +3 -0
  65. package/src/utils/rules-requiring-type-checking.js +84 -0
  66. package/src/utils/versions.d.ts +5 -0
  67. package/src/utils/versions.js +8 -0
  68. package/src/utils/workspace-lint-rules.d.ts +1 -0
  69. package/src/utils/workspace-lint-rules.js +5 -0
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveAndInstantiateESLint = void 0;
4
+ async function resolveESLintClass(useFlatConfig = false) {
5
+ try {
6
+ if (!useFlatConfig) {
7
+ return (await Promise.resolve().then(() => require('eslint'))).ESLint;
8
+ }
9
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
10
+ const { FlatESLint } = require('eslint/use-at-your-own-risk');
11
+ return FlatESLint;
12
+ }
13
+ catch {
14
+ throw new Error('Unable to find ESLint. Ensure ESLint is installed.');
15
+ }
16
+ }
17
+ async function resolveAndInstantiateESLint(eslintConfigPath, options, useFlatConfig = false) {
18
+ if (useFlatConfig &&
19
+ eslintConfigPath &&
20
+ !eslintConfigPath?.endsWith('eslint.config.js')) {
21
+ throw new Error('When using the new Flat Config with ESLint, all configs must be named eslint.config.js and .eslintrc files may not be used. See https://eslint.org/docs/latest/use/configure/configuration-files-new');
22
+ }
23
+ const ESLint = await resolveESLintClass(useFlatConfig);
24
+ const eslintOptions = {
25
+ overrideConfigFile: eslintConfigPath,
26
+ fix: !!options.fix,
27
+ cache: !!options.cache,
28
+ cacheLocation: options.cacheLocation || undefined,
29
+ cacheStrategy: options.cacheStrategy || undefined,
30
+ /**
31
+ * Default is `true` and if not overridden the eslint.lintFiles() method will throw an error
32
+ * when no target files are found.
33
+ *
34
+ * We don't want ESLint to throw an error if a user has only just created
35
+ * a project and therefore doesn't necessarily have matching files, for example.
36
+ *
37
+ * Also, the angular generator creates a lint pattern for `html` files, but there may
38
+ * not be any html files in the project, so keeping it true would break linting every time
39
+ */
40
+ errorOnUnmatchedPattern: false,
41
+ reportUnusedDisableDirectives: options.reportUnusedDisableDirectives || undefined,
42
+ };
43
+ if (useFlatConfig) {
44
+ if (typeof options.useEslintrc !== 'undefined') {
45
+ throw new Error('For Flat Config, the `useEslintrc` option is not applicable. See https://eslint.org/docs/latest/use/configure/configuration-files-new');
46
+ }
47
+ if (options.resolvePluginsRelativeTo !== undefined) {
48
+ throw new Error('For Flat Config, ESLint removed `resolvePluginsRelativeTo` and so it is not supported as an option. See https://eslint.org/docs/latest/use/configure/configuration-files-new');
49
+ }
50
+ if (options.ignorePath !== undefined) {
51
+ throw new Error('For Flat Config, ESLint removed `ignorePath` and so it is not supported as an option. See https://eslint.org/docs/latest/use/configure/configuration-files-new');
52
+ }
53
+ }
54
+ else {
55
+ eslintOptions.rulePaths = options.rulesdir || [];
56
+ eslintOptions.resolvePluginsRelativeTo =
57
+ options.resolvePluginsRelativeTo || undefined;
58
+ eslintOptions.ignorePath = options.ignorePath || undefined;
59
+ /**
60
+ * If "noEslintrc" is set to `true` (and therefore here "useEslintrc" will be `false`), then ESLint will not
61
+ * merge the provided config with others it finds automatically.
62
+ */
63
+ eslintOptions.useEslintrc = !options.noEslintrc;
64
+ }
65
+ const eslint = new ESLint(eslintOptions);
66
+ return {
67
+ ESLint,
68
+ eslint,
69
+ };
70
+ }
71
+ exports.resolveAndInstantiateESLint = resolveAndInstantiateESLint;
@@ -0,0 +1,6 @@
1
+ import { Tree } from '@nx/devkit';
2
+ /**
3
+ * Converts an ESLint JSON config to a flat config.
4
+ * Deletes the original file along with .eslintignore if it exists.
5
+ */
6
+ export declare function convertEslintJsonToFlatConfig(tree: Tree, root: string, sourceFile: string, destinationFile: string): void;
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertEslintJsonToFlatConfig = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const path_1 = require("path");
6
+ const ts = require("typescript");
7
+ const versions_1 = require("../../../utils/versions");
8
+ const ast_utils_1 = require("../../utils/flat-config/ast-utils");
9
+ const eslint_file_1 = require("../../utils/eslint-file");
10
+ /**
11
+ * Converts an ESLint JSON config to a flat config.
12
+ * Deletes the original file along with .eslintignore if it exists.
13
+ */
14
+ function convertEslintJsonToFlatConfig(tree, root, sourceFile, destinationFile) {
15
+ const importsMap = new Map();
16
+ const exportElements = [];
17
+ let isFlatCompatNeeded = false;
18
+ let combinedConfig = [];
19
+ let languageOptions = [];
20
+ // read original config
21
+ const config = (0, devkit_1.readJson)(tree, `${root}/${sourceFile}`);
22
+ if (config.extends) {
23
+ isFlatCompatNeeded = addExtends(importsMap, exportElements, config, tree);
24
+ }
25
+ if (config.plugins) {
26
+ addPlugins(importsMap, exportElements, config);
27
+ }
28
+ if (config.parser) {
29
+ const imp = config.parser;
30
+ const parserName = (0, devkit_1.names)(imp).propertyName;
31
+ importsMap.set(imp, parserName);
32
+ languageOptions.push(ts.factory.createPropertyAssignment('parser', ts.factory.createIdentifier(parserName)));
33
+ }
34
+ if (config.parserOptions) {
35
+ languageOptions.push(ts.factory.createPropertyAssignment('parserOptions', (0, ast_utils_1.generateAst)(config.parserOptions)));
36
+ }
37
+ if (config.globals || config.env) {
38
+ if (config.env) {
39
+ importsMap.set('globals', 'globals');
40
+ }
41
+ languageOptions.push(ts.factory.createPropertyAssignment('globals', ts.factory.createObjectLiteralExpression([
42
+ ...Object.keys(config.env || {}).map((env) => ts.factory.createSpreadAssignment(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('globals'), ts.factory.createIdentifier(env)))),
43
+ ...Object.keys(config.globals || {}).map((key) => ts.factory.createPropertyAssignment(key, (0, ast_utils_1.generateAst)(config.globals[key]))),
44
+ ])));
45
+ }
46
+ if (config.settings) {
47
+ combinedConfig.push(ts.factory.createPropertyAssignment('settings', (0, ast_utils_1.generateAst)(config.settings)));
48
+ }
49
+ if (config.noInlineConfig !== undefined ||
50
+ config.reportUnusedDisableDirectives !== undefined) {
51
+ combinedConfig.push(ts.factory.createPropertyAssignment('linterOptions', (0, ast_utils_1.generateAst)({
52
+ noInlineConfig: config.noInlineConfig,
53
+ reportUnusedDisableDirectives: config.reportUnusedDisableDirectives,
54
+ })));
55
+ }
56
+ if (languageOptions.length > 0) {
57
+ combinedConfig.push(ts.factory.createPropertyAssignment('languageOptions', ts.factory.createObjectLiteralExpression(languageOptions, languageOptions.length > 1)));
58
+ }
59
+ if (combinedConfig.length > 0) {
60
+ exportElements.push(ts.factory.createObjectLiteralExpression(combinedConfig, combinedConfig.length > 1));
61
+ }
62
+ if (config.rules) {
63
+ exportElements.push((0, ast_utils_1.generateAst)({ rules: config.rules }));
64
+ }
65
+ if (config.overrides) {
66
+ config.overrides.forEach((override) => {
67
+ if (override.env ||
68
+ override.extends ||
69
+ override.plugins ||
70
+ override.parser) {
71
+ isFlatCompatNeeded = true;
72
+ }
73
+ exportElements.push((0, ast_utils_1.generateFlatOverride)(override, root));
74
+ });
75
+ }
76
+ if (config.ignorePatterns) {
77
+ const patterns = (Array.isArray(config.ignorePatterns)
78
+ ? config.ignorePatterns
79
+ : [config.ignorePatterns]).filter((pattern) => !['**/*', '!**/*', 'node_modules'].includes(pattern)); // these are useless in a flat config
80
+ if (patterns.length > 0) {
81
+ exportElements.push((0, ast_utils_1.generateAst)({
82
+ ignores: patterns.map((path) => (0, ast_utils_1.mapFilePath)(path, root)),
83
+ }));
84
+ }
85
+ }
86
+ if (tree.exists(`${root}/.eslintignore`)) {
87
+ const patterns = tree
88
+ .read(`${root}/.eslintignore`, 'utf-8')
89
+ .split('\n')
90
+ .filter((line) => line.length > 0 && line !== 'node_modules')
91
+ .map((path) => (0, ast_utils_1.mapFilePath)(path, root));
92
+ if (patterns.length > 0) {
93
+ exportElements.push((0, ast_utils_1.generateAst)({ ignores: patterns }));
94
+ }
95
+ }
96
+ tree.delete((0, path_1.join)(root, sourceFile));
97
+ tree.delete((0, path_1.join)(root, '.eslintignore'));
98
+ // create the node list and print it to new file
99
+ const nodeList = (0, ast_utils_1.createNodeList)(importsMap, exportElements, isFlatCompatNeeded);
100
+ const content = (0, ast_utils_1.stringifyNodeList)(nodeList, root, destinationFile);
101
+ tree.write((0, path_1.join)(root, destinationFile), content);
102
+ if (isFlatCompatNeeded) {
103
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
104
+ '@eslint/eslintrc': versions_1.eslintrcVersion,
105
+ });
106
+ }
107
+ }
108
+ exports.convertEslintJsonToFlatConfig = convertEslintJsonToFlatConfig;
109
+ // add parsed extends to export blocks and add import statements
110
+ function addExtends(importsMap, configBlocks, config, tree) {
111
+ let isFlatCompatNeeded = false;
112
+ const extendsConfig = Array.isArray(config.extends)
113
+ ? config.extends
114
+ : [config.extends];
115
+ const eslintrcConfigs = [];
116
+ // add base extends
117
+ extendsConfig
118
+ .filter((imp) => imp.match(/^\.?(\.\/)/))
119
+ .forEach((imp, index) => {
120
+ if (imp.match(/\.eslintrc(.base)?\.json$/)) {
121
+ const localName = index ? `baseConfig${index}` : 'baseConfig';
122
+ configBlocks.push((0, ast_utils_1.generateSpreadElement)(localName));
123
+ const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, '$1eslint$2.config.js');
124
+ importsMap.set(newImport, localName);
125
+ }
126
+ else {
127
+ eslintrcConfigs.push(imp);
128
+ }
129
+ });
130
+ // add plugin extends
131
+ const pluginExtends = extendsConfig.filter((imp) => !imp.match(/^\.?(\.\/)/));
132
+ if (pluginExtends.length) {
133
+ const eslintPluginExtends = pluginExtends.filter((imp) => imp.startsWith('eslint:'));
134
+ pluginExtends.forEach((imp) => {
135
+ if (!imp.startsWith('eslint:')) {
136
+ eslintrcConfigs.push(imp);
137
+ }
138
+ });
139
+ if (eslintPluginExtends.length) {
140
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
141
+ '@eslint/js': versions_1.eslintVersion,
142
+ });
143
+ importsMap.set('@eslint/js', 'js');
144
+ eslintPluginExtends.forEach((plugin) => {
145
+ configBlocks.push(ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('js'), ts.factory.createIdentifier('configs')), ts.factory.createIdentifier(plugin.slice(7)) // strip 'eslint:' prefix
146
+ ));
147
+ });
148
+ }
149
+ }
150
+ if (eslintrcConfigs.length) {
151
+ isFlatCompatNeeded = true;
152
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
153
+ '@eslint/js': versions_1.eslintVersion,
154
+ });
155
+ configBlocks.push((0, ast_utils_1.generatePluginExtendsElement)(eslintrcConfigs));
156
+ }
157
+ return isFlatCompatNeeded;
158
+ }
159
+ function addPlugins(importsMap, configBlocks, config) {
160
+ const mappedPlugins = [];
161
+ config.plugins.forEach((name) => {
162
+ const imp = (0, eslint_file_1.getPluginImport)(name);
163
+ const varName = (0, devkit_1.names)(imp).propertyName;
164
+ mappedPlugins.push({ name, varName, imp });
165
+ });
166
+ mappedPlugins.forEach(({ varName, imp }) => {
167
+ importsMap.set(imp, varName);
168
+ });
169
+ const pluginsAst = ts.factory.createObjectLiteralExpression([
170
+ ts.factory.createPropertyAssignment('plugins', ts.factory.createObjectLiteralExpression(mappedPlugins.map(({ name, varName }) => {
171
+ return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(name), ts.factory.createIdentifier(varName));
172
+ }), mappedPlugins.length > 1)),
173
+ ...(config.processor
174
+ ? [
175
+ ts.factory.createPropertyAssignment('processor', ts.factory.createStringLiteral(config.processor)),
176
+ ]
177
+ : []),
178
+ ], false);
179
+ configBlocks.push(pluginsAst);
180
+ }
@@ -0,0 +1,4 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { ConvertToFlatConfigGeneratorSchema } from './schema';
3
+ export declare function convertToFlatConfigGenerator(tree: Tree, options: ConvertToFlatConfigGeneratorSchema): Promise<void>;
4
+ export default convertToFlatConfigGenerator;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertToFlatConfigGenerator = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const eslint_file_1 = require("../utils/eslint-file");
6
+ const json_converter_1 = require("./converters/json-converter");
7
+ async function convertToFlatConfigGenerator(tree, options) {
8
+ const eslintFile = (0, eslint_file_1.findEslintFile)(tree);
9
+ if (!eslintFile) {
10
+ throw new Error('Could not find root eslint file');
11
+ }
12
+ if (!eslintFile.endsWith('.json')) {
13
+ throw new Error('Only json eslint config files are supported for conversion');
14
+ }
15
+ // rename root eslint config to eslint.config.js
16
+ convertRootToFlatConfig(tree, eslintFile);
17
+ // rename and map files
18
+ const projects = (0, devkit_1.getProjects)(tree);
19
+ for (const [project, projectConfig] of projects) {
20
+ convertProjectToFlatConfig(tree, project, projectConfig, (0, devkit_1.readNxJson)(tree));
21
+ }
22
+ // replace references in nx.json
23
+ updateNxJsonConfig(tree);
24
+ // install missing packages
25
+ if (!options.skipFormat) {
26
+ await (0, devkit_1.formatFiles)(tree);
27
+ }
28
+ }
29
+ exports.convertToFlatConfigGenerator = convertToFlatConfigGenerator;
30
+ exports.default = convertToFlatConfigGenerator;
31
+ function convertRootToFlatConfig(tree, eslintFile) {
32
+ if (eslintFile.endsWith('.base.json')) {
33
+ convertConfigToFlatConfig(tree, '', '.eslintrc.base.json', 'eslint.base.config.js');
34
+ }
35
+ convertConfigToFlatConfig(tree, '', '.eslintrc.json', 'eslint.config.js');
36
+ }
37
+ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson) {
38
+ if (tree.exists(`${projectConfig.root}/.eslintrc.json`)) {
39
+ if (projectConfig.targets) {
40
+ const eslintTargets = Object.keys(projectConfig.targets || {}).filter((t) => projectConfig.targets[t].executor === '@nx/eslint:lint');
41
+ for (const target of eslintTargets) {
42
+ // remove any obsolete `eslintConfig` options pointing to the old config file
43
+ if (projectConfig.targets[target].options?.eslintConfig) {
44
+ delete projectConfig.targets[target].options.eslintConfig;
45
+ }
46
+ (0, devkit_1.updateProjectConfiguration)(tree, project, projectConfig);
47
+ }
48
+ const nxHasLintTargets = Object.keys(nxJson.targetDefaults || {}).some((t) => (t === '@nx/eslint:lint' ||
49
+ nxJson.targetDefaults[t].executor === '@nx/eslint:lint') &&
50
+ projectConfig.targets?.[t]);
51
+ if (nxHasLintTargets || eslintTargets.length > 0) {
52
+ convertConfigToFlatConfig(tree, projectConfig.root, '.eslintrc.json', 'eslint.config.js');
53
+ }
54
+ }
55
+ }
56
+ }
57
+ // update names of eslint files in nx.json
58
+ // and remove eslintignore
59
+ function updateNxJsonConfig(tree) {
60
+ if (tree.exists('nx.json')) {
61
+ (0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
62
+ if (json.targetDefaults?.lint?.inputs) {
63
+ const inputSet = new Set(json.targetDefaults.lint.inputs);
64
+ inputSet.add('{workspaceRoot}/eslint.config.js');
65
+ json.targetDefaults.lint.inputs = Array.from(inputSet);
66
+ }
67
+ if (json.targetDefaults?.['@nx/eslint:lint']?.inputs) {
68
+ const inputSet = new Set(json.targetDefaults['@nx/eslint:lint'].inputs);
69
+ inputSet.add('{workspaceRoot}/eslint.config.js');
70
+ json.targetDefaults['@nx/eslint:lint'].inputs = Array.from(inputSet);
71
+ }
72
+ if (json.namedInputs?.production) {
73
+ const inputSet = new Set(json.namedInputs.production);
74
+ inputSet.add('!{projectRoot}/eslint.config.js');
75
+ json.namedInputs.production = Array.from(inputSet);
76
+ }
77
+ return json;
78
+ });
79
+ }
80
+ }
81
+ function convertConfigToFlatConfig(tree, root, source, target) {
82
+ (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, source, target);
83
+ }
@@ -0,0 +1,3 @@
1
+ export interface ConvertToFlatConfigGeneratorSchema {
2
+ skipFormat?: boolean;
3
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "$id": "ConvertToFlatConfig",
4
+ "cli": "nx",
5
+ "description": "Convert an Nx workspace's ESLint configs to use Flat Config.",
6
+ "type": "object",
7
+ "properties": {
8
+ "skipFormat": {
9
+ "type": "boolean",
10
+ "description": "Skip formatting files.",
11
+ "default": false,
12
+ "x-priority": "internal"
13
+ }
14
+ },
15
+ "additionalProperties": false,
16
+ "required": []
17
+ }
@@ -0,0 +1,29 @@
1
+ import { Linter } from 'eslint';
2
+ /**
3
+ * This configuration is intended to apply to all TypeScript source files.
4
+ * See the eslint-plugin package for what is in the referenced shareable config.
5
+ */
6
+ export declare const typeScriptOverride: {
7
+ files: string[];
8
+ extends: string[];
9
+ /**
10
+ * Having an empty rules object present makes it more obvious to the user where they would
11
+ * extend things from if they needed to
12
+ */
13
+ rules: {};
14
+ };
15
+ /**
16
+ * This configuration is intended to apply to all JavaScript source files.
17
+ * See the eslint-plugin package for what is in the referenced shareable config.
18
+ */
19
+ export declare const javaScriptOverride: {
20
+ files: string[];
21
+ extends: string[];
22
+ /**
23
+ * Having an empty rules object present makes it more obvious to the user where they would
24
+ * extend things from if they needed to
25
+ */
26
+ rules: {};
27
+ };
28
+ export declare const getGlobalEsLintConfiguration: (unitTestRunner?: string, rootProject?: boolean) => Linter.Config;
29
+ export declare const getGlobalFlatEslintConfiguration: (unitTestRunner?: string, rootProject?: boolean) => string;
@@ -0,0 +1,98 @@
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, '', 'eslint.config.js');
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
+ return content;
97
+ };
98
+ 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): void;
3
+ export declare function findLintTarget(project: ProjectConfiguration): TargetConfiguration;
@@ -0,0 +1,103 @@
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
+ function migrateConfigToMonorepoStyle(projects, tree, unitTestRunner) {
12
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
13
+ // we need this for the compat
14
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
15
+ '@eslint/js': versions_1.eslintVersion,
16
+ });
17
+ tree.write('eslint.base.config.js', (0, global_eslint_config_1.getGlobalFlatEslintConfiguration)(unitTestRunner));
18
+ }
19
+ else {
20
+ (0, devkit_1.writeJson)(tree, '.eslintrc.base.json', (0, global_eslint_config_1.getGlobalEsLintConfiguration)(unitTestRunner));
21
+ }
22
+ // update extens in all projects' eslint configs
23
+ projects.forEach((project) => {
24
+ const lintTarget = findLintTarget(project);
25
+ if (lintTarget) {
26
+ const eslintFile = lintTarget.options.eslintConfig || (0, eslint_file_1.findEslintFile)(tree, project.root);
27
+ if (eslintFile) {
28
+ const projectEslintPath = (0, devkit_1.joinPathFragments)(project.root, eslintFile);
29
+ migrateEslintFile(projectEslintPath, tree);
30
+ }
31
+ }
32
+ });
33
+ }
34
+ exports.migrateConfigToMonorepoStyle = migrateConfigToMonorepoStyle;
35
+ function findLintTarget(project) {
36
+ return Object.values(project.targets ?? {}).find((target) => target.executor === '@nx/eslint:lint' ||
37
+ target.executor === '@nx/linter:eslint' ||
38
+ target.executor === '@nrwl/linter:eslint');
39
+ }
40
+ exports.findLintTarget = findLintTarget;
41
+ function migrateEslintFile(projectEslintPath, tree) {
42
+ if ((0, eslint_file_1.isEslintConfigSupported)(tree)) {
43
+ if ((0, flat_config_1.useFlatConfig)(tree)) {
44
+ let config = tree.read(projectEslintPath, 'utf-8');
45
+ // remove @nx plugin
46
+ config = (0, ast_utils_1.removePlugin)(config, '@nx', '@nx/eslint-plugin-nx');
47
+ // extend eslint.base.config.js
48
+ config = (0, ast_utils_1.addImportToFlatConfig)(config, 'baseConfig', `${(0, devkit_1.offsetFromRoot)((0, path_1.dirname)(projectEslintPath))}eslint.base.config.js`);
49
+ config = (0, ast_utils_1.addBlockToFlatConfigExport)(config, (0, ast_utils_1.generateSpreadElement)('baseConfig'), { insertAtTheEnd: false });
50
+ // cleanup file extends
51
+ config = (0, ast_utils_1.removeCompatExtends)(config, [
52
+ 'plugin:@nx/typescript',
53
+ 'plugin:@nx/javascript',
54
+ 'plugin:@nrwl/typescript',
55
+ 'plugin:@nrwl/javascript',
56
+ ]);
57
+ console.warn('Flat eslint config is not supported yet for migration');
58
+ tree.write(projectEslintPath, config);
59
+ }
60
+ else {
61
+ (0, devkit_1.updateJson)(tree, projectEslintPath, (json) => {
62
+ // we have a new root now
63
+ delete json.root;
64
+ // remove nrwl/nx plugins
65
+ if (json.plugins) {
66
+ json.plugins = json.plugins.filter((p) => p !== '@nx' && p !== '@nrwl/nx');
67
+ if (json.plugins.length === 0) {
68
+ delete json.plugins;
69
+ }
70
+ }
71
+ // add extends
72
+ json.extends = json.extends || [];
73
+ const pathToRootConfig = `${(0, devkit_1.offsetFromRoot)((0, path_1.dirname)(projectEslintPath))}.eslintrc.base.json`;
74
+ if (json.extends.indexOf(pathToRootConfig) === -1) {
75
+ json.extends.push(pathToRootConfig);
76
+ }
77
+ // cleanup overrides
78
+ if (json.overrides) {
79
+ json.overrides.forEach((override) => {
80
+ if (override.extends) {
81
+ override.extends = override.extends.filter((ext) => ext !== 'plugin:@nx/typescript' &&
82
+ ext !== 'plugin:@nrwl/nx/typescript' &&
83
+ ext !== 'plugin:@nx/javascript' &&
84
+ ext !== 'plugin:@nrwl/nx/javascript');
85
+ if (override.extends.length === 0) {
86
+ delete override.extends;
87
+ }
88
+ }
89
+ });
90
+ }
91
+ return json;
92
+ });
93
+ }
94
+ return;
95
+ }
96
+ if (projectEslintPath.endsWith('.yml') ||
97
+ projectEslintPath.endsWith('.yaml')) {
98
+ console.warn('YAML eslint config is not supported yet for migration');
99
+ }
100
+ if (projectEslintPath.endsWith('.js') || projectEslintPath.endsWith('.cjs')) {
101
+ console.warn('JS eslint config is not supported yet for migration');
102
+ }
103
+ }
@@ -0,0 +1,9 @@
1
+ import type { GeneratorCallback, Tree } from '@nx/devkit';
2
+ import { Linter } from '../utils/linter';
3
+ export interface LinterInitOptions {
4
+ linter?: Linter;
5
+ unitTestRunner?: string;
6
+ skipPackageJson?: boolean;
7
+ rootProject?: boolean;
8
+ }
9
+ export declare function lintInitGenerator(tree: Tree, options: LinterInitOptions): GeneratorCallback;