@nx/devkit 23.0.0-beta.22 → 23.0.0-beta.24

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.
@@ -1,5 +1,5 @@
1
1
  import type { ProjectConfiguration } from 'nx/src/config/workspace-json-project-json';
2
- import { type CreateNodesV2, type NxJsonConfiguration, type ProjectGraph, type TargetConfiguration, type Tree } from 'nx/src/devkit-exports';
2
+ import { type CreateNodes, type NxJsonConfiguration, type ProjectGraph, type TargetConfiguration, type Tree } from 'nx/src/devkit-exports';
3
3
  import { logger as devkitLogger } from 'nx/src/devkit-exports';
4
4
  export type InferredTargetConfiguration = TargetConfiguration & {
5
5
  name: string;
@@ -14,14 +14,14 @@ export declare class NoTargetsToMigrateError extends Error {
14
14
  constructor();
15
15
  }
16
16
  export declare function readTargetDefaultsForExecutor(executor: string, targetDefaults: NxJsonConfiguration['targetDefaults'] | undefined): Partial<TargetConfiguration> | undefined;
17
- export declare function migrateProjectExecutorsToPlugin<T>(tree: Tree, projectGraph: ProjectGraph, pluginPath: string, createNodesV2: CreateNodesV2<T>, defaultPluginOptions: T, migrations: Array<{
17
+ export declare function migrateProjectExecutorsToPlugin<T>(tree: Tree, projectGraph: ProjectGraph, pluginPath: string, createNodesV2: CreateNodes<T>, defaultPluginOptions: T, migrations: Array<{
18
18
  executors: string[];
19
19
  targetPluginOptionMapper: (targetName: string) => Partial<T>;
20
20
  postTargetTransformer: PostTargetTransformer;
21
21
  skipProjectFilter?: SkipProjectFilter;
22
22
  skipTargetFilter?: SkipTargetFilter;
23
23
  }>, specificProjectToMigrate?: string, logger?: typeof devkitLogger): Promise<Map<string, Record<string, string>>>;
24
- export declare function migrateProjectExecutorsToPluginV1<T>(tree: Tree, projectGraph: ProjectGraph, pluginPath: string, createNodes: CreateNodesV2<T>, defaultPluginOptions: T, migrations: Array<{
24
+ export declare function migrateProjectExecutorsToPluginV1<T>(tree: Tree, projectGraph: ProjectGraph, pluginPath: string, createNodes: CreateNodes<T>, defaultPluginOptions: T, migrations: Array<{
25
25
  executors: string[];
26
26
  targetPluginOptionMapper: (targetName: string) => Partial<T>;
27
27
  postTargetTransformer: PostTargetTransformer;
@@ -7,6 +7,7 @@ exports.addBuildTargetDefaults = addBuildTargetDefaults;
7
7
  exports.addE2eCiTargetDefaults = addE2eCiTargetDefaults;
8
8
  const devkit_exports_1 = require("nx/src/devkit-exports");
9
9
  const devkit_internals_1 = require("nx/src/devkit-internals");
10
+ const minimatch_1 = require("minimatch");
10
11
  const semver_1 = require("semver");
11
12
  const package_json_1 = require("../utils/package-json");
12
13
  const normalize_target_defaults_1 = require("../utils/normalize-target-defaults");
@@ -183,7 +184,12 @@ async function addE2eCiTargetDefaults(tree, e2ePlugin, buildTarget, pathToE2ECon
183
184
  return;
184
185
  }
185
186
  const resolvedE2ePlugin = await import(e2ePlugin);
186
- const e2ePluginGlob = resolvedE2ePlugin.createNodesV2?.[0] ?? resolvedE2ePlugin.createNodes?.[0];
187
+ const e2ePluginGlob = resolvedE2ePlugin.createNodes?.[0] ?? resolvedE2ePlugin.createNodesV2?.[0];
188
+ // The e2e config file must be one this plugin actually processes (its path
189
+ // matches the plugin's createNodes glob) before the registration's
190
+ // include/exclude filters are applied.
191
+ const e2eConfigMatchesPluginGlob = !e2ePluginGlob ||
192
+ (0, minimatch_1.minimatch)(pathToE2EConfigFile, e2ePluginGlob, { dot: true });
187
193
  let foundPluginForApplication;
188
194
  for (let i = 0; i < e2ePluginRegistrations.length; i++) {
189
195
  let candidatePluginForApplication = e2ePluginRegistrations[i];
@@ -191,7 +197,9 @@ async function addE2eCiTargetDefaults(tree, e2ePlugin, buildTarget, pathToE2ECon
191
197
  foundPluginForApplication = candidatePluginForApplication;
192
198
  break;
193
199
  }
194
- const matchingConfigFiles = (0, devkit_internals_1.findMatchingConfigFiles)([pathToE2EConfigFile], e2ePluginGlob, candidatePluginForApplication.include, candidatePluginForApplication.exclude);
200
+ const matchingConfigFiles = e2eConfigMatchesPluginGlob
201
+ ? (0, devkit_internals_1.findMatchingConfigFiles)([pathToE2EConfigFile], candidatePluginForApplication.include, candidatePluginForApplication.exclude)
202
+ : [];
195
203
  if (matchingConfigFiles.length) {
196
204
  foundPluginForApplication = candidatePluginForApplication;
197
205
  break;
@@ -0,0 +1,10 @@
1
+ import { type Tree } from 'nx/src/devkit-exports';
2
+ export declare const CREATE_NODES_V2_TYPE_RENAMES: ReadonlyMap<string, string>;
3
+ export default function renameCreateNodesV2Types(tree: Tree): Promise<void>;
4
+ /**
5
+ * Rewrites named imports and re-exports of the deprecated `*V2` plugin types
6
+ * from `@nx/devkit` to their canonical names. Only the named bindings are
7
+ * touched — the module specifier, the `import`/`export` keyword, any `type`
8
+ * modifier, and any default import are left untouched.
9
+ */
10
+ export declare function rewriteCreateNodesV2Types(source: string): string;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CREATE_NODES_V2_TYPE_RENAMES = void 0;
4
+ exports.default = renameCreateNodesV2Types;
5
+ exports.rewriteCreateNodesV2Types = rewriteCreateNodesV2Types;
6
+ const devkit_exports_1 = require("nx/src/devkit-exports");
7
+ const format_files_1 = require("../../generators/format-files");
8
+ const visit_not_ignored_files_1 = require("../../generators/visit-not-ignored-files");
9
+ const package_json_1 = require("../../utils/package-json");
10
+ const string_change_1 = require("../../utils/string-change");
11
+ const versions_1 = require("../../utils/versions");
12
+ const TS_EXTENSIONS = ['.ts', '.tsx', '.cts', '.mts'];
13
+ const DEVKIT_SPECIFIER = '@nx/devkit';
14
+ // The `*V2` plugin types were renamed to their canonical un-suffixed names in
15
+ // Nx 23. The `V2` names remain as `@deprecated` aliases, so this migration only
16
+ // moves callers onto the canonical names. (`CreateNodesResultV2` is renamed to
17
+ // `CreateNodesResultArray`, not `CreateNodesResult`, which is an unrelated type.)
18
+ exports.CREATE_NODES_V2_TYPE_RENAMES = new Map([
19
+ ['CreateNodesV2', 'CreateNodes'],
20
+ ['CreateNodesContextV2', 'CreateNodesContext'],
21
+ ['CreateNodesResultV2', 'CreateNodesResultArray'],
22
+ ['CreateNodesFunctionV2', 'CreateNodesFunction'],
23
+ ['NxPluginV2', 'NxPlugin'],
24
+ ]);
25
+ let ts;
26
+ async function renameCreateNodesV2Types(tree) {
27
+ let touchedCount = 0;
28
+ (0, visit_not_ignored_files_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
29
+ if (!TS_EXTENSIONS.some((ext) => filePath.endsWith(ext))) {
30
+ return;
31
+ }
32
+ const original = tree.read(filePath, 'utf-8');
33
+ if (!original || !original.includes('V2')) {
34
+ return;
35
+ }
36
+ const updated = rewriteCreateNodesV2Types(original);
37
+ if (updated !== original) {
38
+ tree.write(filePath, updated);
39
+ touchedCount += 1;
40
+ }
41
+ });
42
+ if (touchedCount > 0) {
43
+ devkit_exports_1.logger.info(`Renamed deprecated CreateNodes V2 type imports from @nx/devkit in ${touchedCount} file(s).`);
44
+ }
45
+ await (0, format_files_1.formatFiles)(tree);
46
+ }
47
+ /**
48
+ * Rewrites named imports and re-exports of the deprecated `*V2` plugin types
49
+ * from `@nx/devkit` to their canonical names. Only the named bindings are
50
+ * touched — the module specifier, the `import`/`export` keyword, any `type`
51
+ * modifier, and any default import are left untouched.
52
+ */
53
+ function rewriteCreateNodesV2Types(source) {
54
+ ts ??= (0, package_json_1.ensurePackage)('typescript', versions_1.typescriptVersion);
55
+ const sourceFile = ts.createSourceFile('tmp.ts', source, ts.ScriptTarget.Latest,
56
+ /* setParentNodes */ true, ts.ScriptKind.TSX);
57
+ const changes = [];
58
+ for (const stmt of sourceFile.statements) {
59
+ if (ts.isImportDeclaration(stmt)) {
60
+ collectImportRewrite(sourceFile, stmt, changes);
61
+ }
62
+ else if (ts.isExportDeclaration(stmt)) {
63
+ collectExportRewrite(sourceFile, stmt, changes);
64
+ }
65
+ }
66
+ return changes.length > 0 ? (0, string_change_1.applyChangesToString)(source, changes) : source;
67
+ }
68
+ function isDevkitSpecifier(node) {
69
+ return ts.isStringLiteral(node) && node.text === DEVKIT_SPECIFIER;
70
+ }
71
+ function collectImportRewrite(sourceFile, stmt, changes) {
72
+ if (!isDevkitSpecifier(stmt.moduleSpecifier)) {
73
+ return;
74
+ }
75
+ const namedBindings = stmt.importClause?.namedBindings;
76
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) {
77
+ return;
78
+ }
79
+ rewriteNamedBindings(sourceFile, namedBindings, changes);
80
+ }
81
+ function collectExportRewrite(sourceFile, stmt, changes) {
82
+ if (!stmt.moduleSpecifier || !isDevkitSpecifier(stmt.moduleSpecifier)) {
83
+ return;
84
+ }
85
+ if (!stmt.exportClause || !ts.isNamedExports(stmt.exportClause)) {
86
+ return;
87
+ }
88
+ rewriteNamedBindings(sourceFile, stmt.exportClause, changes);
89
+ }
90
+ /**
91
+ * Re-renders the `{ ... }` of a named import/export, renaming any deprecated
92
+ * `*V2` type to its canonical name. If renaming would collide with a canonical
93
+ * name that is already present, the duplicate is dropped. Returns without
94
+ * recording a change when the binding list contains none of the renamed types.
95
+ */
96
+ function rewriteNamedBindings(sourceFile, namedBindings, changes) {
97
+ const elements = namedBindings.elements;
98
+ const hasRenamed = elements.some((el) => exports.CREATE_NODES_V2_TYPE_RENAMES.has((el.propertyName ?? el.name).text));
99
+ if (!hasRenamed) {
100
+ return;
101
+ }
102
+ const seen = new Set();
103
+ const rendered = [];
104
+ for (const el of elements) {
105
+ const text = renderSpecifier(el);
106
+ if (!seen.has(text)) {
107
+ seen.add(text);
108
+ rendered.push(text);
109
+ }
110
+ }
111
+ const start = namedBindings.getStart(sourceFile);
112
+ changes.push({
113
+ type: string_change_1.ChangeType.Delete,
114
+ start,
115
+ length: namedBindings.getEnd() - start,
116
+ }, {
117
+ type: string_change_1.ChangeType.Insert,
118
+ index: start,
119
+ text: `{ ${rendered.join(', ')} }`,
120
+ });
121
+ }
122
+ function renderSpecifier(el) {
123
+ const typePrefix = el.isTypeOnly ? 'type ' : '';
124
+ const rename = (name) => exports.CREATE_NODES_V2_TYPE_RENAMES.get(name) ?? name;
125
+ // `{ name }` — no alias, so the local binding follows the rename.
126
+ if (!el.propertyName) {
127
+ return `${typePrefix}${rename(el.name.text)}`;
128
+ }
129
+ // `{ propertyName as name }` — only the imported (left) side is renamed; the
130
+ // local alias is preserved. A now-redundant alias such as
131
+ // `CreateNodesV2 as CreateNodes` collapses to `CreateNodes`.
132
+ const canonicalImported = rename(el.propertyName.text);
133
+ const localName = el.name.text;
134
+ return canonicalImported === localName
135
+ ? `${typePrefix}${localName}`
136
+ : `${typePrefix}${canonicalImported} as ${localName}`;
137
+ }
@@ -0,0 +1,29 @@
1
+ #### Rename deprecated CreateNodes `V2` types from `@nx/devkit`
2
+
3
+ The canonical plugin API types lost their `V2` suffix in Nx 23. The `V2` names are kept as `@deprecated` aliases, but new code should use the canonical names:
4
+
5
+ | Deprecated (`@nx/devkit`) | Canonical |
6
+ | ------------------------- | ------------------------ |
7
+ | `CreateNodesV2` | `CreateNodes` |
8
+ | `CreateNodesContextV2` | `CreateNodesContext` |
9
+ | `CreateNodesResultV2` | `CreateNodesResultArray` |
10
+ | `CreateNodesFunctionV2` | `CreateNodesFunction` |
11
+ | `NxPluginV2` | `NxPlugin` |
12
+
13
+ This migration scans every `.ts`, `.tsx`, `.cts`, and `.mts` file in your workspace and rewrites named imports and re-exports of these types from `@nx/devkit` to their canonical names.
14
+
15
+ #### Sample Code Changes
16
+
17
+ ##### Before
18
+
19
+ ```ts
20
+ import type { CreateNodesV2, CreateNodesContextV2 } from '@nx/devkit';
21
+ ```
22
+
23
+ ##### After
24
+
25
+ ```ts
26
+ import type { CreateNodes, CreateNodesContext } from '@nx/devkit';
27
+ ```
28
+
29
+ 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. The unrelated `CreateNodesResult` type is left untouched.
@@ -1,13 +1,13 @@
1
- import { CreateNodesV2, ProjectGraph, Tree } from 'nx/src/devkit-exports';
1
+ import { CreateNodes, ProjectGraph, Tree } from 'nx/src/devkit-exports';
2
2
  /**
3
3
  * Iterates through various forms of plugin options to find the one which does not conflict with the current graph
4
4
 
5
5
  */
6
- export declare function addPlugin<PluginOptions>(tree: Tree, graph: ProjectGraph, pluginName: string, createNodesTuple: CreateNodesV2<PluginOptions>, options: Partial<Record<keyof PluginOptions, PluginOptions[keyof PluginOptions][]>>, shouldUpdatePackageJsonScripts: boolean): Promise<void>;
6
+ export declare function addPlugin<PluginOptions>(tree: Tree, graph: ProjectGraph, pluginName: string, createNodesTuple: CreateNodes<PluginOptions>, options: Partial<Record<keyof PluginOptions, PluginOptions[keyof PluginOptions][]>>, shouldUpdatePackageJsonScripts: boolean): Promise<void>;
7
7
  /**
8
8
  * @deprecated Use `addPlugin` instead
9
9
  * Iterates through various forms of plugin options to find the one which does not conflict with the current graph
10
10
 
11
11
  */
12
- export declare function addPluginV1<PluginOptions>(tree: Tree, graph: ProjectGraph, pluginName: string, createNodesTuple: CreateNodesV2<PluginOptions>, options: Partial<Record<keyof PluginOptions, PluginOptions[keyof PluginOptions][]>>, shouldUpdatePackageJsonScripts: boolean): Promise<void>;
12
+ export declare function addPluginV1<PluginOptions>(tree: Tree, graph: ProjectGraph, pluginName: string, createNodesTuple: CreateNodes<PluginOptions>, options: Partial<Record<keyof PluginOptions, PluginOptions[keyof PluginOptions][]>>, shouldUpdatePackageJsonScripts: boolean): Promise<void>;
13
13
  export declare function generateCombinations<T>(input: Record<string, T[]>): Record<string, T>[];
@@ -14,7 +14,7 @@ const devkit_internals_1 = require("nx/src/devkit-internals");
14
14
  async function addPlugin(tree, graph, pluginName, createNodesTuple, options, shouldUpdatePackageJsonScripts) {
15
15
  return _addPluginInternal(tree, graph, pluginName, (pluginOptions) => new devkit_internals_1.LoadedNxPlugin({
16
16
  name: pluginName,
17
- createNodesV2: createNodesTuple,
17
+ createNodes: createNodesTuple,
18
18
  }, {
19
19
  plugin: pluginName,
20
20
  options: pluginOptions,
@@ -1,8 +1,8 @@
1
- import { CreateNodesContextV2 } from 'nx/src/devkit-exports';
1
+ import { CreateNodesContext } from 'nx/src/devkit-exports';
2
2
  /**
3
3
  * @deprecated Use {@link calculateHashesForCreateNodes} instead, which batches
4
4
  * workspace-context hashing across multiple project roots in a single call.
5
5
  * This will be removed in Nx 24.
6
6
  */
7
- export declare function calculateHashForCreateNodes(projectRoot: string, options: object, context: CreateNodesContextV2, additionalGlobs?: string[]): Promise<string>;
8
- export declare function calculateHashesForCreateNodes(projectRoots: string[], options: object, context: CreateNodesContextV2, additionalGlobs?: string[][]): Promise<string[]>;
7
+ export declare function calculateHashForCreateNodes(projectRoot: string, options: object, context: CreateNodesContext, additionalGlobs?: string[]): Promise<string>;
8
+ export declare function calculateHashesForCreateNodes(projectRoots: string[], options: object, context: CreateNodesContext, additionalGlobs?: string[][]): Promise<string[]>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findPluginForConfigFile = findPluginForConfigFile;
4
4
  const devkit_exports_1 = require("nx/src/devkit-exports");
5
5
  const devkit_internals_1 = require("nx/src/devkit-internals");
6
+ const minimatch_1 = require("minimatch");
6
7
  async function findPluginForConfigFile(tree, pluginName, pathToConfigFile) {
7
8
  const nxJson = (0, devkit_exports_1.readNxJson)(tree);
8
9
  if (!nxJson.plugins) {
@@ -18,8 +19,13 @@ async function findPluginForConfigFile(tree, pluginName, pathToConfigFile) {
18
19
  }
19
20
  if (plugin.include || plugin.exclude) {
20
21
  const resolvedPlugin = await import(pluginName);
21
- const pluginGlob = resolvedPlugin.createNodesV2?.[0] ?? resolvedPlugin.createNodes?.[0];
22
- const matchingConfigFile = (0, devkit_internals_1.findMatchingConfigFiles)([pathToConfigFile], pluginGlob, plugin.include, plugin.exclude);
22
+ const pluginGlob = resolvedPlugin.createNodes?.[0] ?? resolvedPlugin.createNodesV2?.[0];
23
+ // The file must be one this plugin actually processes (its path matches
24
+ // the plugin's createNodes glob) before the registration's include/exclude
25
+ // filters are applied.
26
+ const matchingConfigFile = !pluginGlob || (0, minimatch_1.minimatch)(pathToConfigFile, pluginGlob, { dot: true })
27
+ ? (0, devkit_internals_1.findMatchingConfigFiles)([pathToConfigFile], plugin.include, plugin.exclude)
28
+ : [];
23
29
  if (matchingConfigFile.length) {
24
30
  return plugin;
25
31
  }
@@ -1,8 +1,8 @@
1
1
  import type { InputDefinition } from 'nx/src/config/workspace-json-project-json';
2
- import { CreateNodesContextV2 } from 'nx/src/devkit-exports';
2
+ import { CreateNodesContext } from 'nx/src/devkit-exports';
3
3
  /**
4
4
  * Get the named inputs available for a directory
5
5
  */
6
- export declare function getNamedInputs(directory: string, context: CreateNodesContextV2): {
6
+ export declare function getNamedInputs(directory: string, context: CreateNodesContext): {
7
7
  [inputName: string]: (string | InputDefinition)[];
8
8
  };
@@ -456,7 +456,7 @@ function ensurePackage(pkgOrTree, requiredVersionOrPackage, maybeRequiredVersion
456
456
  if (process.env.NX_DRY_RUN && process.env.NX_DRY_RUN !== 'false') {
457
457
  throw new Error('NOTE: This generator does not support --dry-run. If you are running this in Nx Console, it should execute fine once you hit the "Generate" button.\n');
458
458
  }
459
- const { tempDir } = (0, devkit_internals_1.installPackageToTmp)(pkg, requiredVersion);
459
+ const { tempDir } = (0, devkit_internals_1.installPackageToTmp)(pkg, requiredVersion, (0, devkit_exports_1.detectPackageManager)(devkit_exports_1.workspaceRoot));
460
460
  addToNodePath((0, path_1.join)(devkit_exports_1.workspaceRoot, 'node_modules'));
461
461
  addToNodePath((0, path_1.join)(tempDir, 'node_modules'));
462
462
  // Re-initialize the added paths into require
@@ -1,2 +1,2 @@
1
- import { CreateNodesV2, Tree } from 'nx/src/devkit-exports';
2
- export declare function replaceProjectConfigurationsWithPlugin<T = unknown>(tree: Tree, rootMappings: Map<string, string>, pluginPath: string, createNodes: CreateNodesV2<T>, pluginOptions: T): Promise<void>;
1
+ import { CreateNodes, Tree } from 'nx/src/devkit-exports';
2
+ export declare function replaceProjectConfigurationsWithPlugin<T = unknown>(tree: Tree, rootMappings: Map<string, string>, pluginPath: string, createNodes: CreateNodes<T>, pluginOptions: T): Promise<void>;
package/migrations.json CHANGED
@@ -5,6 +5,12 @@
5
5
  "description": "Rewrite imports from `@nx/devkit/src/...` to `@nx/devkit` (for public symbols) or `@nx/devkit/internal` (for the rest), since deep imports are no longer reachable through the package's `exports` map.",
6
6
  "implementation": "./dist/src/migrations/update-23-0-0/update-deep-imports",
7
7
  "documentation": "./dist/src/migrations/update-23-0-0/update-deep-imports.md"
8
+ },
9
+ "update-23-0-0-rename-create-nodes-v2-types": {
10
+ "version": "23.0.0-beta.24",
11
+ "description": "Rename deprecated CreateNodes `V2` type imports (CreateNodesV2, CreateNodesContextV2, CreateNodesResultV2, CreateNodesFunctionV2, NxPluginV2) from `@nx/devkit` to their canonical names.",
12
+ "implementation": "./dist/src/migrations/update-23-0-0/rename-create-nodes-v2-types",
13
+ "documentation": "./dist/src/migrations/update-23-0-0/rename-create-nodes-v2-types.md"
8
14
  }
9
15
  },
10
16
  "packageJsonUpdates": {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/devkit",
3
- "version": "23.0.0-beta.22",
3
+ "version": "23.0.0-beta.24",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "devDependencies": {
62
62
  "jest": "30.3.0",
63
- "nx": "23.0.0-beta.22"
63
+ "nx": "23.0.0-beta.24"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "nx": ">= 22 <= 24 || ^23.0.0-0"