@nx/eslint 23.0.0-beta.23 → 23.0.0-beta.25

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.
@@ -0,0 +1,9 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export default function migrateCreateNodesV2ToCreateNodes(tree: Tree): Promise<void>;
3
+ /**
4
+ * Rewrites named imports and re-exports of `createNodesV2` to `createNodes`
5
+ * when they come from one of the given module specifiers. Only the named
6
+ * bindings are touched — the module specifier, the `import`/`export` keyword,
7
+ * any `type` modifier, and any default import are left untouched.
8
+ */
9
+ export declare function rewriteCreateNodesV2Imports(source: string, specifiers: ReadonlySet<string>): string;
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = migrateCreateNodesV2ToCreateNodes;
4
+ exports.rewriteCreateNodesV2Imports = rewriteCreateNodesV2Imports;
5
+ const devkit_1 = require("@nx/devkit");
6
+ const TS_EXTENSIONS = ['.ts', '.tsx', '.cts', '.mts'];
7
+ const DEPRECATED_NAME = 'createNodesV2';
8
+ const CANONICAL_NAME = 'createNodes';
9
+ // Module specifiers from which `@nx/eslint` publicly exposes `createNodesV2`.
10
+ // A named import or re-export of `createNodesV2` from one of these is rewritten
11
+ // to the canonical `createNodes` export.
12
+ const TARGET_SPECIFIERS = new Set(['@nx/eslint/plugin']);
13
+ let ts;
14
+ async function migrateCreateNodesV2ToCreateNodes(tree) {
15
+ let touchedCount = 0;
16
+ (0, devkit_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
17
+ if (!TS_EXTENSIONS.some((ext) => filePath.endsWith(ext))) {
18
+ return;
19
+ }
20
+ const original = tree.read(filePath, 'utf-8');
21
+ if (!original || !original.includes(DEPRECATED_NAME)) {
22
+ return;
23
+ }
24
+ const updated = rewriteCreateNodesV2Imports(original, TARGET_SPECIFIERS);
25
+ if (updated !== original) {
26
+ tree.write(filePath, updated);
27
+ touchedCount += 1;
28
+ }
29
+ });
30
+ if (touchedCount > 0) {
31
+ devkit_1.logger.info(`Renamed \`${DEPRECATED_NAME}\` imports to \`${CANONICAL_NAME}\` in ${touchedCount} file(s).`);
32
+ }
33
+ await (0, devkit_1.formatFiles)(tree);
34
+ }
35
+ /**
36
+ * Rewrites named imports and re-exports of `createNodesV2` to `createNodes`
37
+ * when they come from one of the given module specifiers. Only the named
38
+ * bindings are touched — the module specifier, the `import`/`export` keyword,
39
+ * any `type` modifier, and any default import are left untouched.
40
+ */
41
+ function rewriteCreateNodesV2Imports(source, specifiers) {
42
+ ts ??= (0, devkit_1.ensurePackage)('typescript', '*');
43
+ const sourceFile = ts.createSourceFile('tmp.ts', source, ts.ScriptTarget.Latest,
44
+ /* setParentNodes */ true, ts.ScriptKind.TSX);
45
+ const changes = [];
46
+ for (const stmt of sourceFile.statements) {
47
+ if (ts.isImportDeclaration(stmt)) {
48
+ collectImportRewrite(sourceFile, stmt, specifiers, changes);
49
+ }
50
+ else if (ts.isExportDeclaration(stmt)) {
51
+ collectExportRewrite(sourceFile, stmt, specifiers, changes);
52
+ }
53
+ }
54
+ return changes.length > 0 ? (0, devkit_1.applyChangesToString)(source, changes) : source;
55
+ }
56
+ function isTargetSpecifier(node, specifiers) {
57
+ return ts.isStringLiteral(node) && specifiers.has(node.text);
58
+ }
59
+ function collectImportRewrite(sourceFile, stmt, specifiers, changes) {
60
+ if (!isTargetSpecifier(stmt.moduleSpecifier, specifiers)) {
61
+ return;
62
+ }
63
+ const namedBindings = stmt.importClause?.namedBindings;
64
+ // Only `import { ... }` carries renameable named bindings. `import x`,
65
+ // `import * as ns`, and side-effect imports reference the module wholesale
66
+ // and keep working through the `createNodesV2` runtime alias, so we leave
67
+ // them be. A mixed `import def, { createNodesV2 }` still has its named
68
+ // bindings rewritten below — the default binding is untouched.
69
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) {
70
+ return;
71
+ }
72
+ rewriteNamedBindings(sourceFile, namedBindings, changes);
73
+ }
74
+ function collectExportRewrite(sourceFile, stmt, specifiers, changes) {
75
+ if (!stmt.moduleSpecifier ||
76
+ !isTargetSpecifier(stmt.moduleSpecifier, specifiers)) {
77
+ return;
78
+ }
79
+ // `export { ... } from '...'` can be rewritten; `export * from '...'` has no
80
+ // named bindings to rename.
81
+ if (!stmt.exportClause || !ts.isNamedExports(stmt.exportClause)) {
82
+ return;
83
+ }
84
+ rewriteNamedBindings(sourceFile, stmt.exportClause, changes);
85
+ }
86
+ /**
87
+ * Re-renders the `{ ... }` of a named import/export, renaming any
88
+ * `createNodesV2` specifier to `createNodes`. If renaming would collide with a
89
+ * `createNodes` that is already present (e.g. `{ createNodes, createNodesV2 }`),
90
+ * the duplicate is dropped. Returns without recording a change when the binding
91
+ * list contains no `createNodesV2`.
92
+ */
93
+ function rewriteNamedBindings(sourceFile, namedBindings, changes) {
94
+ const elements = namedBindings.elements;
95
+ const hasDeprecated = elements.some((el) => (el.propertyName ?? el.name).text === DEPRECATED_NAME);
96
+ if (!hasDeprecated) {
97
+ return;
98
+ }
99
+ const seen = new Set();
100
+ const rendered = [];
101
+ for (const el of elements) {
102
+ const text = renderSpecifier(el);
103
+ if (!seen.has(text)) {
104
+ seen.add(text);
105
+ rendered.push(text);
106
+ }
107
+ }
108
+ const start = namedBindings.getStart(sourceFile);
109
+ changes.push({
110
+ type: devkit_1.ChangeType.Delete,
111
+ start,
112
+ length: namedBindings.getEnd() - start,
113
+ }, {
114
+ type: devkit_1.ChangeType.Insert,
115
+ index: start,
116
+ text: `{ ${rendered.join(', ')} }`,
117
+ });
118
+ }
119
+ function renderSpecifier(el) {
120
+ const typePrefix = el.isTypeOnly ? 'type ' : '';
121
+ const rename = (name) => name === DEPRECATED_NAME ? CANONICAL_NAME : name;
122
+ // `{ name }` — no alias, so the local binding follows the rename.
123
+ if (!el.propertyName) {
124
+ return `${typePrefix}${rename(el.name.text)}`;
125
+ }
126
+ // `{ propertyName as name }` — only the imported (left) side is renamed; the
127
+ // local alias is preserved. A now-redundant alias such as
128
+ // `createNodesV2 as createNodes` collapses to `createNodes`.
129
+ const canonicalImported = rename(el.propertyName.text);
130
+ const localName = el.name.text;
131
+ return canonicalImported === localName
132
+ ? `${typePrefix}${localName}`
133
+ : `${typePrefix}${canonicalImported} as ${localName}`;
134
+ }
@@ -0,0 +1,25 @@
1
+ #### Rename `createNodesV2` imports to `createNodes`
2
+
3
+ `@nx/eslint` renamed its primary inferred-plugin export from `createNodesV2` to `createNodes`. The `createNodesV2` name is preserved as a deprecated alias for now, but new code should use `createNodes`.
4
+
5
+ This migration scans every `.ts`, `.tsx`, `.cts`, and `.mts` file in your workspace and rewrites named imports and re-exports of `createNodesV2` from `@nx/eslint/plugin` to `createNodes`.
6
+
7
+ #### Sample Code Changes
8
+
9
+ ##### Before
10
+
11
+ ```ts
12
+ import { createNodesV2 } from '@nx/eslint/plugin';
13
+ ```
14
+
15
+ ##### After
16
+
17
+ ```ts
18
+ import { createNodes } from '@nx/eslint/plugin';
19
+ ```
20
+
21
+ Aliases are preserved (`createNodesV2 as cn` becomes `createNodes as cn`), and if a file already imports both names (`{ createNodes, createNodesV2 }`) the redundant binding is dropped.
22
+
23
+ #### What is not rewritten
24
+
25
+ Only static `import`/`export` named bindings from `@nx/eslint/plugin` are rewritten. Namespace imports, dynamic `import(...)`, `require(...)` destructuring, and property access such as `plugin.createNodesV2` are left untouched — they keep working through the `createNodesV2` runtime alias. Update those by hand if you want to drop the deprecated name everywhere.
package/migrations.json CHANGED
@@ -1,23 +1,5 @@
1
1
  {
2
2
  "generators": {
3
- "update-typescript-eslint-v8.13.0": {
4
- "version": "20.2.0-beta.5",
5
- "description": "Update TypeScript ESLint packages to v8.13.0 if they are already on v8",
6
- "implementation": "./dist/src/migrations/update-20-2-0/update-typescript-eslint-v8-13-0",
7
- "requires": {
8
- "@typescript-eslint/parser": ">=8.0.0"
9
- },
10
- "documentation": "./dist/src/migrations/update-20-2-0/update-typescript-eslint-v8-13-0.md"
11
- },
12
- "add-file-extensions-to-overrides": {
13
- "version": "20.3.0-beta.1",
14
- "description": "Update ESLint flat config to include .cjs, .mjs, .cts, and .mts files in overrides (if needed)",
15
- "implementation": "./dist/src/migrations/update-20-3-0/add-file-extensions-to-overrides",
16
- "requires": {
17
- "eslint": ">=8.57.0"
18
- },
19
- "documentation": "./dist/src/migrations/update-20-3-0/add-file-extensions-to-overrides.md"
20
- },
21
3
  "update-executor-lint-inputs": {
22
4
  "version": "22.7.0-beta.12",
23
5
  "description": "Add missing inputs to @nx/eslint:lint executor target defaults",
@@ -27,81 +9,15 @@
27
9
  "version": "23.0.0-beta.17",
28
10
  "description": "Rewrites `@nx/eslint/src/*` subpath imports now that the `./src/*` subpath is no longer exposed by `@nx/eslint`'s exports map. Named imports/exports of public symbols are routed to `@nx/eslint` and the rest to the new `@nx/eslint/internal` entry; `require`, dynamic `import` and `jest.mock` calls reference the whole module and are routed to `@nx/eslint/internal`.",
29
11
  "implementation": "./dist/src/migrations/update-23-0-0/rewrite-internal-subpath-imports"
12
+ },
13
+ "update-23-0-0-migrate-create-nodes-v2-import": {
14
+ "version": "23.0.0-beta.24",
15
+ "description": "Rename imports of `createNodesV2` from `@nx/eslint/plugin` to the canonical `createNodes` export.",
16
+ "implementation": "./dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes",
17
+ "documentation": "./dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.md"
30
18
  }
31
19
  },
32
20
  "packageJsonUpdates": {
33
- "20.4.0-typescript-eslint": {
34
- "version": "20.4.0-beta.1",
35
- "requires": {
36
- "typescript-eslint": ">8.0.0 <8.19.0"
37
- },
38
- "packages": {
39
- "typescript-eslint": {
40
- "version": "^8.19.0"
41
- },
42
- "@typescript-eslint/eslint-plugin": {
43
- "version": "^8.19.0"
44
- },
45
- "@typescript-eslint/parser": {
46
- "version": "^8.19.0"
47
- },
48
- "@typescript-eslint/utils": {
49
- "version": "^8.19.0"
50
- },
51
- "@typescript-eslint/rule-tester": {
52
- "version": "^8.19.0",
53
- "alwaysAddToPackageJson": false
54
- },
55
- "@typescript-eslint/scope-manager": {
56
- "version": "^8.19.0",
57
- "alwaysAddToPackageJson": false
58
- },
59
- "@typescript-eslint/typescript-estree": {
60
- "version": "^8.19.0",
61
- "alwaysAddToPackageJson": false
62
- }
63
- }
64
- },
65
- "20.4.0-@typescript-eslint": {
66
- "version": "20.4.0-beta.1",
67
- "requires": {
68
- "@typescript-eslint/eslint-plugin": ">8.0.0 <8.19.0"
69
- },
70
- "packages": {
71
- "typescript-eslint": {
72
- "version": "^8.19.0"
73
- },
74
- "@typescript-eslint/eslint-plugin": {
75
- "version": "^8.19.0"
76
- },
77
- "@typescript-eslint/parser": {
78
- "version": "^8.19.0"
79
- },
80
- "@typescript-eslint/utils": {
81
- "version": "^8.19.0"
82
- },
83
- "@typescript-eslint/rule-tester": {
84
- "version": "^8.19.0",
85
- "alwaysAddToPackageJson": false
86
- },
87
- "@typescript-eslint/scope-manager": {
88
- "version": "^8.19.0",
89
- "alwaysAddToPackageJson": false
90
- },
91
- "@typescript-eslint/typescript-estree": {
92
- "version": "^8.19.0",
93
- "alwaysAddToPackageJson": false
94
- }
95
- }
96
- },
97
- "20.7.0": {
98
- "version": "20.7.0-beta.4",
99
- "packages": {
100
- "eslint-config-prettier": {
101
- "version": "^10.0.0"
102
- }
103
- }
104
- },
105
21
  "21.2.0-typescript-eslint": {
106
22
  "version": "21.2.0-beta.0",
107
23
  "requires": {
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@nx/eslint",
3
- "version": "23.0.0-beta.23",
3
+ "version": "23.0.0-beta.25",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
7
7
  "dist",
8
8
  "!dist/tsconfig.tsbuildinfo",
9
- "!dist/spec",
10
9
  "migrations.json",
11
10
  "executors.json",
12
11
  "generators.json"
@@ -45,7 +44,8 @@
45
44
  "homepage": "https://nx.dev",
46
45
  "ng-update": {
47
46
  "requirements": {},
48
- "migrations": "./migrations.json"
47
+ "migrations": "./migrations.json",
48
+ "supportsOptionalUpdates": true
49
49
  },
50
50
  "generators": "./generators.json",
51
51
  "executors": "./executors.json",
@@ -73,17 +73,17 @@
73
73
  "peerDependencies": {
74
74
  "@zkochan/js-yaml": "0.0.7",
75
75
  "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0",
76
- "@nx/jest": "23.0.0-beta.23"
76
+ "@nx/jest": "23.0.0-beta.25"
77
77
  },
78
78
  "dependencies": {
79
79
  "semver": "^7.6.3",
80
80
  "tslib": "^2.3.0",
81
81
  "typescript": "~5.9.2",
82
- "@nx/js": "23.0.0-beta.23",
83
- "@nx/devkit": "23.0.0-beta.23"
82
+ "@nx/devkit": "23.0.0-beta.25",
83
+ "@nx/js": "23.0.0-beta.25"
84
84
  },
85
85
  "devDependencies": {
86
- "nx": "23.0.0-beta.23"
86
+ "nx": "23.0.0-beta.25"
87
87
  },
88
88
  "peerDependenciesMeta": {
89
89
  "@nx/jest": {
@@ -1,2 +0,0 @@
1
- import { type GeneratorCallback, type Tree } from '@nx/devkit';
2
- export default function (tree: Tree): Promise<GeneratorCallback>;
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = default_1;
4
- const devkit_1 = require("@nx/devkit");
5
- const internal_1 = require("@nx/devkit/internal");
6
- const semver_1 = require("semver");
7
- async function default_1(tree) {
8
- const devDependencies = {};
9
- // `@typescript-eslint/parser >=8.0.0` is enforced at the `requires` gate
10
- // in `migrations.json`. The per-package `gte('8.0.0') && lt('8.13.0')`
11
- // check below catches the lockstep-broken case where one of the four
12
- // typescript-eslint packages is at a different major than the parser.
13
- const checkPackageAndMigrate = (pkgName) => {
14
- const pkgVersion = (0, internal_1.getDeclaredPackageVersion)(tree, pkgName);
15
- if (!!pkgVersion && (0, semver_1.gte)(pkgVersion, '8.0.0') && (0, semver_1.lt)(pkgVersion, '8.13.0')) {
16
- devDependencies[pkgName] = '^8.13.0';
17
- }
18
- };
19
- checkPackageAndMigrate('typescript-eslint');
20
- checkPackageAndMigrate('@typescript-eslint/eslint-plugin');
21
- checkPackageAndMigrate('@typescript-eslint/parser');
22
- checkPackageAndMigrate('@typescript-eslint/utils');
23
- if (Object.keys(devDependencies).length > 0) {
24
- return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, devDependencies);
25
- }
26
- return () => { };
27
- }
@@ -1,33 +0,0 @@
1
- #### Update TypeScript ESLint to v8.13.0
2
-
3
- Update TypeScript ESLint packages to v8.13.0 if they are already on v8
4
-
5
- #### Sample Code Changes
6
-
7
- This migration will update `typescript-eslint`, `@typescript-eslint/eslint-plugin`, `@typescript-eslint/parser` and `@typescript-eslint/utils` to `8.13.0` if they are between version `8.0.0` and `8.13.0`.
8
-
9
- ##### Before
10
-
11
- ```json title="package.json"
12
- {
13
- "devDependencies": {
14
- "typescript-eslint": "^8.0.0",
15
- "@typescript-eslint/eslint-plugin": "^8.0.0",
16
- "@typescript-eslint/parser": "^8.0.0",
17
- "@typescript-eslint/utils": "^8.0.0"
18
- }
19
- }
20
- ```
21
-
22
- ##### After
23
-
24
- ```json title="package.json"
25
- {
26
- "devDependencies": {
27
- "typescript-eslint": "^8.13.0",
28
- "@typescript-eslint/eslint-plugin": "^8.13.0",
29
- "@typescript-eslint/parser": "^8.13.0",
30
- "@typescript-eslint/utils": "^8.13.0"
31
- }
32
- }
33
- ```
@@ -1,2 +0,0 @@
1
- import { type Tree } from '@nx/devkit';
2
- export default function (tree: Tree): Promise<void>;
@@ -1,50 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = default_1;
4
- const tslib_1 = require("tslib");
5
- const ts = tslib_1.__importStar(require("typescript"));
6
- const js_1 = require("@nx/js");
7
- async function default_1(tree) {
8
- let rootConfig;
9
- // NOTE: we don't support generating ESM base config currently so they are not handled.
10
- for (const candidate of ['eslint.config.js', 'eslint.config.cjs']) {
11
- if (tree.exists(candidate)) {
12
- rootConfig = candidate;
13
- break;
14
- }
15
- }
16
- if (!rootConfig)
17
- return;
18
- updateOverrideFileExtensions(tree, rootConfig, 'plugin:@nx/typescript', [`'**/*.ts'`, `'**/*.tsx'`], [`'**/*.cts'`, `'**/*.mts'`]);
19
- updateOverrideFileExtensions(tree, rootConfig, 'plugin:@nx/javascript', [`'**/*.js'`, `'**/*.jsx'`], [`'**/*.cjs'`, `'**/*.mjs'`]);
20
- }
21
- function updateOverrideFileExtensions(tree, configFile, plugin, matchingExts, newExts) {
22
- const content = tree.read(configFile, 'utf-8');
23
- const source = ts.createSourceFile('', content, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
24
- let compatNode;
25
- const spreadElementNodes = (0, js_1.findNodes)(source, ts.SyntaxKind.SpreadElement);
26
- for (const a of spreadElementNodes) {
27
- const assignmentNodes = (0, js_1.findNodes)(a, ts.SyntaxKind.PropertyAssignment);
28
- if (assignmentNodes.length === 0)
29
- continue;
30
- for (const b of assignmentNodes) {
31
- if (b.name.getText() === 'extends' &&
32
- b.initializer.getText().includes(plugin)) {
33
- compatNode = a;
34
- break;
35
- }
36
- }
37
- }
38
- if (compatNode) {
39
- const arrayNodes = (0, js_1.findNodes)(compatNode, ts.SyntaxKind.ArrayLiteralExpression);
40
- for (const a of arrayNodes) {
41
- if (matchingExts.every((ext) => a.elements.some((e) => e.getText() === ext))) {
42
- const exts = new Set(a.elements.map((e) => e.getText()));
43
- for (const ext of newExts) {
44
- exts.add(ext);
45
- }
46
- (0, js_1.replaceChange)(tree, source, configFile, a.getStart(a.getSourceFile()), `[${Array.from(exts).join(', ')}]`, a.getText()).getText();
47
- }
48
- }
49
- }
50
- }
@@ -1,83 +0,0 @@
1
- #### Update ESLint Config File Extensions in Overrides
2
-
3
- Update ESLint flat config to include .cjs, .mjs, .cts, and .mts files in overrides (if needed)
4
-
5
- #### Sample Code Changes
6
-
7
- Add `.cjs`, `.mjs`, `.cts`, `.mts` file extensions to overrides converted using `convert-to-flat-config`
8
-
9
- ##### Before
10
-
11
- ```js title="eslint.config.js"
12
- const { FlatCompat } = require('@eslint/eslintrc');
13
- const js = require('@eslint/js');
14
- const nxEslintPlugin = require('@nx/eslint-plugin');
15
-
16
- const compat = new FlatCompat({
17
- baseDirectory: __dirname,
18
- recommendedConfig: js.configs.recommended,
19
- });
20
-
21
- module.exports = [
22
- ...compat
23
- .config({
24
- extends: ['plugin:@nx/typescript'],
25
- })
26
- .map((config) => ({
27
- ...config,
28
- files: ['**/*.ts', '**/*.tsx'],
29
- rules: {
30
- ...config.rules,
31
- },
32
- })),
33
- ...compat
34
- .config({
35
- extends: ['plugin:@nx/javascript'],
36
- })
37
- .map((config) => ({
38
- ...config,
39
- files: ['**/*.js', '**/*.jsx'],
40
- rules: {
41
- ...config.rules,
42
- },
43
- })),
44
- ];
45
- ```
46
-
47
- ##### After
48
-
49
- ```js title="eslint.config.js" {17,28}
50
- const { FlatCompat } = require('@eslint/eslintrc');
51
- const js = require('@eslint/js');
52
- const nxEslintPlugin = require('@nx/eslint-plugin');
53
-
54
- const compat = new FlatCompat({
55
- baseDirectory: __dirname,
56
- recommendedConfig: js.configs.recommended,
57
- });
58
-
59
- module.exports = [
60
- ...compat
61
- .config({
62
- extends: ['plugin:@nx/typescript'],
63
- })
64
- .map((config) => ({
65
- ...config,
66
- files: ['**/*.ts', '**/*.tsx', '**/*.cts', '**/*.mts'],
67
- rules: {
68
- ...config.rules,
69
- },
70
- })),
71
- ...compat
72
- .config({
73
- extends: ['plugin:@nx/javascript'],
74
- })
75
- .map((config) => ({
76
- ...config,
77
- files: ['**/*.js', '**/*.jsx', '**/*.cjs', '**/*.mjs'],
78
- rules: {
79
- ...config.rules,
80
- },
81
- })),
82
- ];
83
- ```