@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,148 @@
1
+ {
2
+ "version": 2,
3
+ "outputCapture": "direct-nodejs",
4
+ "$schema": "https://json-schema.org/schema",
5
+ "title": "ESLint Lint Target",
6
+ "description": "ESLint Lint Target.",
7
+ "cli": "nx",
8
+ "type": "object",
9
+ "properties": {
10
+ "eslintConfig": {
11
+ "type": "string",
12
+ "description": "The name of the ESLint configuration file.",
13
+ "x-completion-type": "file",
14
+ "x-completion-glob": ".eslintrc?(.json)",
15
+ "x-priority": "important"
16
+ },
17
+ "lintFilePatterns": {
18
+ "type": "array",
19
+ "description": "One or more files/dirs/globs to pass directly to ESLint's `lintFiles()` method.",
20
+ "default": ["{projectRoot}"],
21
+ "items": {
22
+ "type": "string"
23
+ }
24
+ },
25
+ "format": {
26
+ "type": "string",
27
+ "description": "ESLint Output formatter (https://eslint.org/docs/user-guide/formatters).",
28
+ "default": "stylish",
29
+ "anyOf": [
30
+ {
31
+ "enum": [
32
+ "stylish",
33
+ "compact",
34
+ "codeframe",
35
+ "unix",
36
+ "visualstudio",
37
+ "table",
38
+ "checkstyle",
39
+ "html",
40
+ "jslint-xml",
41
+ "json",
42
+ "json-with-metadata",
43
+ "junit",
44
+ "tap"
45
+ ]
46
+ },
47
+ {
48
+ "minLength": 1
49
+ }
50
+ ],
51
+ "x-priority": "important"
52
+ },
53
+ "force": {
54
+ "type": "boolean",
55
+ "description": "Succeeds even if there was linting errors.",
56
+ "default": false
57
+ },
58
+ "silent": {
59
+ "type": "boolean",
60
+ "description": "Hide output text.",
61
+ "default": false
62
+ },
63
+ "fix": {
64
+ "type": "boolean",
65
+ "description": "Fixes linting errors (may overwrite linted files).",
66
+ "default": false,
67
+ "x-priority": "important"
68
+ },
69
+ "cache": {
70
+ "type": "boolean",
71
+ "description": "Only check changed files.",
72
+ "default": false
73
+ },
74
+ "cacheLocation": {
75
+ "type": "string",
76
+ "description": "Path to the cache file or directory.",
77
+ "x-completion-type": "directory",
78
+ "x-completion-glob": "tsconfig.*.json"
79
+ },
80
+ "outputFile": {
81
+ "type": "string",
82
+ "description": "File to write report to.",
83
+ "x-completion-type": "file"
84
+ },
85
+ "maxWarnings": {
86
+ "type": "number",
87
+ "description": "Number of warnings to trigger nonzero exit code - default: `-1`.",
88
+ "default": -1
89
+ },
90
+ "quiet": {
91
+ "type": "boolean",
92
+ "description": "Report errors only - default: `false`.",
93
+ "default": false,
94
+ "x-priority": "important"
95
+ },
96
+ "ignorePath": {
97
+ "type": "string",
98
+ "description": "The path of the `.eslintignore` file. Not supported for Flat Config.",
99
+ "x-completion-type": "file",
100
+ "x-completion-glob": ".eslintignore"
101
+ },
102
+ "noEslintrc": {
103
+ "type": "boolean",
104
+ "description": "The equivalent of the `--no-eslintrc` flag on the ESLint CLI, it is `false` by default.",
105
+ "default": false
106
+ },
107
+ "hasTypeAwareRules": {
108
+ "type": "boolean",
109
+ "description": "When set to `true`, the linter will invalidate its cache when any of its dependencies changes."
110
+ },
111
+ "cacheStrategy": {
112
+ "type": "string",
113
+ "description": "Strategy to use for detecting changed files in the cache.",
114
+ "default": "metadata",
115
+ "enum": ["metadata", "content"]
116
+ },
117
+ "rulesdir": {
118
+ "type": "array",
119
+ "description": "The equivalent of the `--rulesdir` flag on the ESLint CLI.",
120
+ "default": [],
121
+ "items": {
122
+ "type": "string",
123
+ "x-completion-type": "directory"
124
+ }
125
+ },
126
+ "resolvePluginsRelativeTo": {
127
+ "type": "string",
128
+ "description": "The equivalent of the `--resolve-plugins-relative-to` flag on the ESLint CLI. Not supported for Flat Config.",
129
+ "x-completion-type": "directory"
130
+ },
131
+ "reportUnusedDisableDirectives": {
132
+ "type": "string",
133
+ "enum": ["off", "warn", "error"],
134
+ "description": "The equivalent of the `--report-unused-disable-directives` flag on the ESLint CLI."
135
+ },
136
+ "printConfig": {
137
+ "type": "string",
138
+ "description": "The equivalent of the `--print-config` flag on the ESLint CLI.",
139
+ "x-completion-type": "file"
140
+ },
141
+ "errorOnUnmatchedPattern": {
142
+ "type": "boolean",
143
+ "description": "When set to false, equivalent of the `--no-error-on-unmatched-pattern` flag on the ESLint CLI.",
144
+ "default": true
145
+ }
146
+ },
147
+ "examplesFile": "../../../docs/eslint-examples.md"
148
+ }
@@ -0,0 +1,6 @@
1
+ import type { ESLint } from 'eslint';
2
+ import type { Schema } from '../schema';
3
+ export declare function resolveAndInstantiateESLint(eslintConfigPath: string | undefined, options: Schema, useFlatConfig?: boolean): Promise<{
4
+ ESLint: typeof import("eslint").ESLint;
5
+ eslint: ESLint;
6
+ }>;
@@ -0,0 +1,75 @@
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
+ };
42
+ if (useFlatConfig) {
43
+ if (typeof options.useEslintrc !== 'undefined') {
44
+ throw new Error('For Flat Config, the `useEslintrc` option is not applicable. See https://eslint.org/docs/latest/use/configure/configuration-files-new');
45
+ }
46
+ if (options.resolvePluginsRelativeTo !== undefined) {
47
+ 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');
48
+ }
49
+ if (options.ignorePath !== undefined) {
50
+ 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');
51
+ }
52
+ if (options.reportUnusedDisableDirectives) {
53
+ throw new Error('For Flat Config, ESLint removed `reportedUnusedDisableDirectives` and so it is not supported as an option. See https://eslint.org/docs/latest/use/configure/configuration-files-new');
54
+ }
55
+ }
56
+ else {
57
+ eslintOptions.rulePaths = options.rulesdir || [];
58
+ eslintOptions.resolvePluginsRelativeTo =
59
+ options.resolvePluginsRelativeTo || undefined;
60
+ eslintOptions.ignorePath = options.ignorePath || undefined;
61
+ /**
62
+ * If "noEslintrc" is set to `true` (and therefore here "useEslintrc" will be `false`), then ESLint will not
63
+ * merge the provided config with others it finds automatically.
64
+ */
65
+ eslintOptions.useEslintrc = !options.noEslintrc;
66
+ eslintOptions.reportUnusedDisableDirectives =
67
+ options.reportUnusedDisableDirectives || undefined;
68
+ }
69
+ const eslint = new ESLint(eslintOptions);
70
+ return {
71
+ ESLint,
72
+ eslint,
73
+ };
74
+ }
75
+ exports.resolveAndInstantiateESLint = resolveAndInstantiateESLint;
@@ -0,0 +1,11 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { ESLint } from 'eslint';
3
+ /**
4
+ * Converts an ESLint JSON config to a flat config.
5
+ * Deletes the original file along with .eslintignore if it exists.
6
+ */
7
+ export declare function convertEslintJsonToFlatConfig(tree: Tree, root: string, config: ESLint.ConfigData, ignorePaths: string[]): {
8
+ content: string;
9
+ addESLintRC: boolean;
10
+ addESLintJS: boolean;
11
+ };
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertEslintJsonToFlatConfig = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const ts = require("typescript");
6
+ const ast_utils_1 = require("../../utils/flat-config/ast-utils");
7
+ const eslint_file_1 = require("../../utils/eslint-file");
8
+ const path_utils_1 = require("../../utils/flat-config/path-utils");
9
+ /**
10
+ * Converts an ESLint JSON config to a flat config.
11
+ * Deletes the original file along with .eslintignore if it exists.
12
+ */
13
+ function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
14
+ const importsMap = new Map();
15
+ const exportElements = [];
16
+ let isFlatCompatNeeded = false;
17
+ let isESLintJSNeeded = false;
18
+ let combinedConfig = [];
19
+ let languageOptions = [];
20
+ if (config.extends) {
21
+ const extendsResult = addExtends(importsMap, exportElements, config);
22
+ isFlatCompatNeeded = extendsResult.isFlatCompatNeeded;
23
+ isESLintJSNeeded = extendsResult.isESLintJSNeeded;
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));
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, path_utils_1.mapFilePath)(path)),
83
+ }));
84
+ }
85
+ }
86
+ for (const ignorePath of ignorePaths) {
87
+ if (tree.exists(ignorePath)) {
88
+ const patterns = tree
89
+ .read(ignorePath, 'utf-8')
90
+ .split('\n')
91
+ .filter((line) => line.length > 0 && line !== 'node_modules')
92
+ .map((path) => (0, path_utils_1.mapFilePath)(path));
93
+ if (patterns.length > 0) {
94
+ exportElements.push((0, ast_utils_1.generateAst)({ ignores: patterns }));
95
+ }
96
+ }
97
+ }
98
+ // create the node list and print it to new file
99
+ const nodeList = (0, ast_utils_1.createNodeList)(importsMap, exportElements, isFlatCompatNeeded);
100
+ return {
101
+ content: (0, ast_utils_1.stringifyNodeList)(nodeList),
102
+ addESLintRC: isFlatCompatNeeded,
103
+ addESLintJS: isESLintJSNeeded,
104
+ };
105
+ }
106
+ exports.convertEslintJsonToFlatConfig = convertEslintJsonToFlatConfig;
107
+ // add parsed extends to export blocks and add import statements
108
+ function addExtends(importsMap, configBlocks, config) {
109
+ let isFlatCompatNeeded = false;
110
+ let isESLintJSNeeded = false;
111
+ const extendsConfig = Array.isArray(config.extends)
112
+ ? config.extends
113
+ : [config.extends];
114
+ const eslintrcConfigs = [];
115
+ // add base extends
116
+ extendsConfig
117
+ .filter((imp) => imp.match(/^\.?(\.\/)/))
118
+ .forEach((imp, index) => {
119
+ if (imp.match(/\.eslintrc(.base)?\.json$/)) {
120
+ const localName = index ? `baseConfig${index}` : 'baseConfig';
121
+ configBlocks.push((0, ast_utils_1.generateSpreadElement)(localName));
122
+ const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, '$1eslint$2.config.js');
123
+ importsMap.set(newImport, localName);
124
+ }
125
+ else {
126
+ eslintrcConfigs.push(imp);
127
+ }
128
+ });
129
+ // add plugin extends
130
+ const pluginExtends = extendsConfig.filter((imp) => !imp.match(/^\.?(\.\/)/));
131
+ if (pluginExtends.length) {
132
+ const eslintPluginExtends = pluginExtends.filter((imp) => imp.startsWith('eslint:'));
133
+ pluginExtends.forEach((imp) => {
134
+ if (!imp.startsWith('eslint:')) {
135
+ eslintrcConfigs.push(imp);
136
+ }
137
+ });
138
+ if (eslintPluginExtends.length) {
139
+ isESLintJSNeeded = true;
140
+ importsMap.set('@eslint/js', 'js');
141
+ eslintPluginExtends.forEach((plugin) => {
142
+ 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
143
+ ));
144
+ });
145
+ }
146
+ }
147
+ if (eslintrcConfigs.length) {
148
+ isFlatCompatNeeded = true;
149
+ isESLintJSNeeded = true;
150
+ configBlocks.push((0, ast_utils_1.generatePluginExtendsElement)(eslintrcConfigs));
151
+ }
152
+ return { isFlatCompatNeeded, isESLintJSNeeded };
153
+ }
154
+ function addPlugins(importsMap, configBlocks, config) {
155
+ const mappedPlugins = [];
156
+ config.plugins.forEach((name) => {
157
+ const imp = (0, eslint_file_1.getPluginImport)(name);
158
+ const varName = (0, devkit_1.names)(imp).propertyName;
159
+ mappedPlugins.push({ name, varName, imp });
160
+ });
161
+ mappedPlugins.forEach(({ varName, imp }) => {
162
+ importsMap.set(imp, varName);
163
+ });
164
+ const pluginsAst = ts.factory.createObjectLiteralExpression([
165
+ ts.factory.createPropertyAssignment('plugins', ts.factory.createObjectLiteralExpression(mappedPlugins.map(({ name, varName }) => {
166
+ return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(name), ts.factory.createIdentifier(varName));
167
+ }), mappedPlugins.length > 1)),
168
+ ...(config.processor
169
+ ? [
170
+ ts.factory.createPropertyAssignment('processor', ts.factory.createStringLiteral(config.processor)),
171
+ ]
172
+ : []),
173
+ ], false);
174
+ configBlocks.push(pluginsAst);
175
+ }
@@ -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,139 @@
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 path_1 = require("path");
7
+ const versions_1 = require("../../utils/versions");
8
+ const json_converter_1 = require("./converters/json-converter");
9
+ const js_yaml_1 = require("js-yaml");
10
+ async function convertToFlatConfigGenerator(tree, options) {
11
+ const eslintFile = (0, eslint_file_1.findEslintFile)(tree);
12
+ if (!eslintFile) {
13
+ throw new Error('Could not find root eslint file');
14
+ }
15
+ if (eslintFile.endsWith('.js')) {
16
+ throw new Error('Only json and yaml eslint config files are supported for conversion');
17
+ }
18
+ const eslintIgnoreFiles = new Set(['.eslintignore']);
19
+ // convert root eslint config to eslint.config.js
20
+ convertRootToFlatConfig(tree, eslintFile);
21
+ // convert project eslint files to eslint.config.js
22
+ const projects = (0, devkit_1.getProjects)(tree);
23
+ for (const [project, projectConfig] of projects) {
24
+ convertProjectToFlatConfig(tree, project, projectConfig, (0, devkit_1.readNxJson)(tree), eslintIgnoreFiles);
25
+ }
26
+ // delete all .eslintignore files
27
+ for (const ignoreFile of eslintIgnoreFiles) {
28
+ tree.delete(ignoreFile);
29
+ }
30
+ // replace references in nx.json
31
+ updateNxJsonConfig(tree);
32
+ // install missing packages
33
+ if (!options.skipFormat) {
34
+ await (0, devkit_1.formatFiles)(tree);
35
+ }
36
+ }
37
+ exports.convertToFlatConfigGenerator = convertToFlatConfigGenerator;
38
+ exports.default = convertToFlatConfigGenerator;
39
+ function convertRootToFlatConfig(tree, eslintFile) {
40
+ if (/\.base\.(js|json|yml|yaml)$/.test(eslintFile)) {
41
+ convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.js');
42
+ }
43
+ convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.js');
44
+ }
45
+ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles) {
46
+ const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
47
+ if (eslintFile && !eslintFile.endsWith('.js')) {
48
+ if (projectConfig.targets) {
49
+ const eslintTargets = Object.keys(projectConfig.targets || {}).filter((t) => projectConfig.targets[t].executor === '@nx/eslint:lint' ||
50
+ projectConfig.targets[t].command?.includes('eslint'));
51
+ let ignorePath;
52
+ for (const target of eslintTargets) {
53
+ // remove any obsolete `eslintConfig` options pointing to the old config file
54
+ if (projectConfig.targets[target].options?.eslintConfig) {
55
+ delete projectConfig.targets[target].options.eslintConfig;
56
+ }
57
+ if (projectConfig.targets[target].options?.ignorePath) {
58
+ ignorePath = projectConfig.targets[target].options.ignorePath;
59
+ delete projectConfig.targets[target].options.ignorePath;
60
+ }
61
+ (0, devkit_1.updateProjectConfiguration)(tree, project, projectConfig);
62
+ }
63
+ const nxHasEsLintTargets = Object.keys(nxJson.targetDefaults || {}).some((t) => (t === '@nx/eslint:lint' ||
64
+ nxJson.targetDefaults[t].executor === '@nx/eslint:lint' ||
65
+ nxJson.targetDefaults[t].command?.includes('eslint')) &&
66
+ projectConfig.targets?.[t]);
67
+ const nxHasEsLintPlugin = (nxJson.plugins || []).some((p) => typeof p === 'string'
68
+ ? p === '@nx/eslint/plugin'
69
+ : p.plugin === '@nx/eslint/plugin');
70
+ if (nxHasEsLintTargets || nxHasEsLintPlugin || eslintTargets.length > 0) {
71
+ convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, 'eslint.config.js', ignorePath);
72
+ eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
73
+ if (ignorePath) {
74
+ eslintIgnoreFiles.add(ignorePath);
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ // update names of eslint files in nx.json
81
+ // and remove eslintignore
82
+ function updateNxJsonConfig(tree) {
83
+ if (tree.exists('nx.json')) {
84
+ (0, devkit_1.updateJson)(tree, 'nx.json', (json) => {
85
+ if (json.targetDefaults?.lint?.inputs) {
86
+ const inputSet = new Set(json.targetDefaults.lint.inputs);
87
+ inputSet.add('{workspaceRoot}/eslint.config.js');
88
+ json.targetDefaults.lint.inputs = Array.from(inputSet);
89
+ }
90
+ if (json.targetDefaults?.['@nx/eslint:lint']?.inputs) {
91
+ const inputSet = new Set(json.targetDefaults['@nx/eslint:lint'].inputs);
92
+ inputSet.add('{workspaceRoot}/eslint.config.js');
93
+ json.targetDefaults['@nx/eslint:lint'].inputs = Array.from(inputSet);
94
+ }
95
+ if (json.namedInputs?.production) {
96
+ const inputSet = new Set(json.namedInputs.production);
97
+ inputSet.add('!{projectRoot}/eslint.config.js');
98
+ json.namedInputs.production = Array.from(inputSet);
99
+ }
100
+ return json;
101
+ });
102
+ }
103
+ }
104
+ function convertConfigToFlatConfig(tree, root, source, target, ignorePath) {
105
+ const ignorePaths = ignorePath
106
+ ? [ignorePath, `${root}/.eslintignore`]
107
+ : [`${root}/.eslintignore`];
108
+ if (source.endsWith('.json')) {
109
+ const config = (0, devkit_1.readJson)(tree, `${root}/${source}`);
110
+ const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths);
111
+ return processConvertedConfig(tree, root, source, target, conversionResult);
112
+ }
113
+ if (source.endsWith('.yaml') || source.endsWith('.yml')) {
114
+ const originalContent = tree.read(`${root}/${source}`, 'utf-8');
115
+ const config = (0, js_yaml_1.load)(originalContent, {
116
+ json: true,
117
+ filename: source,
118
+ });
119
+ const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths);
120
+ return processConvertedConfig(tree, root, source, target, conversionResult);
121
+ }
122
+ }
123
+ function processConvertedConfig(tree, root, source, target, { content, addESLintRC, addESLintJS, }) {
124
+ // remove original config file
125
+ tree.delete((0, path_1.join)(root, source));
126
+ // save new
127
+ tree.write((0, path_1.join)(root, target), content);
128
+ // add missing packages
129
+ if (addESLintRC) {
130
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
131
+ '@eslint/eslintrc': versions_1.eslintrcVersion,
132
+ });
133
+ }
134
+ if (addESLintJS) {
135
+ (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
136
+ '@eslint/js': versions_1.eslintVersion,
137
+ });
138
+ }
139
+ }
@@ -0,0 +1,3 @@
1
+ export interface ConvertToFlatConfigGeneratorSchema {
2
+ skipFormat?: boolean;
3
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://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;