nx 23.0.0-beta.11 → 23.0.0-beta.13

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 (70) hide show
  1. package/dist/src/command-line/examples.js +1 -1
  2. package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +14 -18
  3. package/dist/src/command-line/init/implementation/utils.d.ts +7 -1
  4. package/dist/src/command-line/init/implementation/utils.js +44 -14
  5. package/dist/src/command-line/migrate/command-object.js +1 -1
  6. package/dist/src/command-line/migrate/migrate.d.ts +23 -5
  7. package/dist/src/command-line/migrate/migrate.js +76 -28
  8. package/dist/src/command-line/migrate/multi-major.d.ts +23 -2
  9. package/dist/src/command-line/migrate/multi-major.js +47 -28
  10. package/dist/src/command-line/migrate/prompt-files.d.ts +12 -0
  11. package/dist/src/command-line/migrate/prompt-files.js +107 -0
  12. package/dist/src/command-line/migrate/version-utils.d.ts +1 -0
  13. package/dist/src/command-line/migrate/version-utils.js +9 -3
  14. package/dist/src/command-line/release/config/config.d.ts +3 -6
  15. package/dist/src/command-line/release/config/config.js +77 -45
  16. package/dist/src/command-line/release/utils/release-graph.js +2 -3
  17. package/dist/src/command-line/release/utils/repository-git-tags.js +1 -1
  18. package/dist/src/command-line/release/version/resolve-current-version.js +1 -1
  19. package/dist/src/command-line/show/show-target/info.js +4 -5
  20. package/dist/src/command-line/watch/command-object.js +24 -4
  21. package/dist/src/command-line/watch/watch.d.ts +7 -0
  22. package/dist/src/command-line/watch/watch.js +1 -1
  23. package/dist/src/config/misc-interfaces.d.ts +3 -1
  24. package/dist/src/config/nx-json.d.ts +43 -56
  25. package/dist/src/core/graph/main.js +1 -1
  26. package/dist/src/daemon/client/client.d.ts +1 -1
  27. package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +1 -1
  28. package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +1 -1
  29. package/dist/src/devkit-exports.d.ts +1 -1
  30. package/dist/src/devkit-internals.d.ts +1 -0
  31. package/dist/src/devkit-internals.js +4 -1
  32. package/dist/src/executors/run-commands/running-tasks.d.ts +7 -0
  33. package/dist/src/executors/run-commands/running-tasks.js +178 -105
  34. package/dist/src/executors/run-script/run-script.impl.js +3 -10
  35. package/dist/src/hasher/task-hasher.js +6 -4
  36. package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +6 -2
  37. package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +20 -4
  38. package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.d.ts +9 -0
  39. package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.js +18 -0
  40. package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.d.ts +25 -0
  41. package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.js +117 -0
  42. package/dist/src/native/index.d.ts +18 -1
  43. package/dist/src/native/native-bindings.js +2 -0
  44. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  45. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  46. package/dist/src/project-graph/plugins/utils.js +13 -7
  47. package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +95 -4
  48. package/dist/src/project-graph/utils/project-configuration/target-defaults.js +515 -68
  49. package/dist/src/project-graph/utils/project-configuration-utils.d.ts +13 -5
  50. package/dist/src/project-graph/utils/project-configuration-utils.js +14 -6
  51. package/dist/src/tasks-runner/forked-process-task-runner.d.ts +1 -1
  52. package/dist/src/tasks-runner/forked-process-task-runner.js +11 -6
  53. package/dist/src/tasks-runner/legacy-depends-on-warning.d.ts +18 -0
  54. package/dist/src/tasks-runner/legacy-depends-on-warning.js +109 -0
  55. package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
  56. package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
  57. package/dist/src/tasks-runner/run-command.js +0 -10
  58. package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +1 -1
  59. package/dist/src/tasks-runner/running-tasks/batch-process.js +3 -5
  60. package/dist/src/tasks-runner/running-tasks/node-child-process.d.ts +2 -2
  61. package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -7
  62. package/dist/src/tasks-runner/task-orchestrator.d.ts +1 -0
  63. package/dist/src/tasks-runner/task-orchestrator.js +33 -24
  64. package/dist/src/tasks-runner/utils.d.ts +6 -4
  65. package/dist/src/tasks-runner/utils.js +26 -7
  66. package/dist/src/utils/installed-nx-version.js +5 -2
  67. package/dist/src/utils/package-json.js +10 -1
  68. package/migrations.json +11 -0
  69. package/package.json +11 -12
  70. package/schemas/nx-schema.json +114 -80
@@ -378,7 +378,7 @@ exports.examples = {
378
378
  description: 'Watch the "app" project and echo the project name and the files that changed',
379
379
  },
380
380
  {
381
- command: 'watch --projects=app1,app2 --includeDependentProjects -- echo \\$NX_PROJECT_NAME',
381
+ command: 'watch --projects=app1,app2 --includeDependencies -- echo \\$NX_PROJECT_NAME',
382
382
  description: 'Watch "app1" and "app2" and echo the project name whenever a specified project or its dependencies change',
383
383
  },
384
384
  {
@@ -54,29 +54,26 @@ function createNxJson(repoRoot, angularJson, cacheableOperations, { eslintProjec
54
54
  : []),
55
55
  ].filter(Boolean),
56
56
  };
57
- nxJson.targetDefaults ??= {};
57
+ const defaults = Array.isArray(nxJson.targetDefaults)
58
+ ? [...nxJson.targetDefaults]
59
+ : [];
58
60
  if (workspaceTargets.includes('build')) {
59
- nxJson.targetDefaults.build = {
60
- ...nxJson.targetDefaults.build,
61
+ (0, utils_1.upsertTargetDefaultEntry)(defaults, 'build', {
61
62
  dependsOn: ['^build'],
62
63
  inputs: ['production', '^production'],
63
- };
64
+ });
64
65
  }
65
66
  if (workspaceTargets.includes('server')) {
66
- nxJson.targetDefaults.server = {
67
- ...nxJson.targetDefaults.server,
67
+ (0, utils_1.upsertTargetDefaultEntry)(defaults, 'server', {
68
68
  inputs: ['production', '^production'],
69
- };
69
+ });
70
70
  }
71
71
  if (workspaceTargets.includes('test')) {
72
72
  const inputs = ['default', '^production'];
73
73
  if ((0, fileutils_1.fileExists)((0, node_path_1.join)(repoRoot, 'karma.conf.js'))) {
74
74
  inputs.push('{workspaceRoot}/karma.conf.js');
75
75
  }
76
- nxJson.targetDefaults.test = {
77
- ...nxJson.targetDefaults.test,
78
- inputs,
79
- };
76
+ (0, utils_1.upsertTargetDefaultEntry)(defaults, 'test', { inputs });
80
77
  }
81
78
  if (workspaceTargets.includes('lint')) {
82
79
  const inputs = ['default'];
@@ -86,16 +83,15 @@ function createNxJson(repoRoot, angularJson, cacheableOperations, { eslintProjec
86
83
  if ((0, fileutils_1.fileExists)((0, node_path_1.join)(repoRoot, 'eslint.config.cjs'))) {
87
84
  inputs.push('{workspaceRoot}/eslint.config.cjs');
88
85
  }
89
- nxJson.targetDefaults.lint = {
90
- ...nxJson.targetDefaults.lint,
91
- inputs,
92
- };
86
+ (0, utils_1.upsertTargetDefaultEntry)(defaults, 'lint', { inputs });
93
87
  }
94
88
  if (workspaceTargets.includes('e2e')) {
95
- nxJson.targetDefaults.e2e = {
96
- ...nxJson.targetDefaults.e2e,
89
+ (0, utils_1.upsertTargetDefaultEntry)(defaults, 'e2e', {
97
90
  inputs: ['default', '^production'],
98
- };
91
+ });
92
+ }
93
+ if (defaults.length > 0) {
94
+ nxJson.targetDefaults = defaults;
99
95
  }
100
96
  (0, fileutils_1.writeJsonFile)((0, node_path_1.join)(repoRoot, 'nx.json'), nxJson);
101
97
  }
@@ -1,9 +1,15 @@
1
- import { NxJsonConfiguration } from '../../../config/nx-json';
1
+ import { NxJsonConfiguration, TargetDefaultEntry } from '../../../config/nx-json';
2
2
  import { PackageJson } from '../../../utils/package-json';
3
3
  import { PackageManagerCommands } from '../../../utils/package-manager';
4
4
  export declare function createNxJsonFile(repoRoot: string, topologicalTargets: string[], cacheableOperations: string[], scriptOutputs: {
5
5
  [name: string]: string;
6
6
  }): void;
7
+ /**
8
+ * Locate-by-target upsert against an in-memory `targetDefaults` array.
9
+ * Used by `nx init` code paths that operate on raw JSON before a Tree
10
+ * exists — generators should use `upsertTargetDefault` from devkit instead.
11
+ */
12
+ export declare function upsertTargetDefaultEntry(entries: TargetDefaultEntry[], target: string, patch: Partial<TargetDefaultEntry>): void;
7
13
  export declare function createNxJsonFromTurboJson(turboJson: Record<string, any>): NxJsonConfiguration;
8
14
  export declare function addDepsToPackageJson(repoRoot: string, additionalPackages?: string[]): void;
9
15
  export declare function updateGitIgnore(root: string): void;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createNxJsonFile = createNxJsonFile;
4
+ exports.upsertTargetDefaultEntry = upsertTargetDefaultEntry;
4
5
  exports.createNxJsonFromTurboJson = createNxJsonFromTurboJson;
5
6
  exports.addDepsToPackageJson = addDepsToPackageJson;
6
7
  exports.updateGitIgnore = updateGitIgnore;
@@ -34,27 +35,37 @@ function createNxJsonFile(repoRoot, topologicalTargets, cacheableOperations, scr
34
35
  }
35
36
  catch { }
36
37
  nxJson.$schema = './node_modules/nx/schemas/nx-schema.json';
37
- nxJson.targetDefaults ??= {};
38
+ const entries = Array.isArray(nxJson.targetDefaults)
39
+ ? [...nxJson.targetDefaults]
40
+ : [];
38
41
  if (topologicalTargets.length > 0) {
39
42
  for (const scriptName of topologicalTargets) {
40
- nxJson.targetDefaults[scriptName] ??= {};
41
- nxJson.targetDefaults[scriptName] = { dependsOn: [`^${scriptName}`] };
43
+ upsertTargetDefaultEntry(entries, scriptName, {
44
+ dependsOn: [`^${scriptName}`],
45
+ });
42
46
  }
43
47
  }
44
48
  for (const [scriptName, output] of Object.entries(scriptOutputs)) {
45
49
  if (!output) {
46
50
  continue;
47
51
  }
48
- nxJson.targetDefaults[scriptName] ??= {};
49
- nxJson.targetDefaults[scriptName].outputs = [`{projectRoot}/${output}`];
52
+ upsertTargetDefaultEntry(entries, scriptName, {
53
+ outputs: [`{projectRoot}/${output}`],
54
+ });
50
55
  }
51
56
  for (const target of cacheableOperations) {
52
- nxJson.targetDefaults[target] ??= {};
53
- nxJson.targetDefaults[target].cache ??= true;
57
+ const existing = findUnfilteredTargetEntry(entries, target);
58
+ if (existing)
59
+ existing.cache ??= true;
60
+ else
61
+ entries.push({ target, cache: true });
54
62
  }
55
- if (Object.keys(nxJson.targetDefaults).length === 0) {
63
+ if (entries.length === 0) {
56
64
  delete nxJson.targetDefaults;
57
65
  }
66
+ else {
67
+ nxJson.targetDefaults = entries;
68
+ }
58
69
  const defaultBase = (0, deduce_default_base_1.deduceDefaultBase)();
59
70
  // Do not add defaultBase if it is inferred to be the Nx default value of main
60
71
  if (defaultBase !== 'main') {
@@ -62,6 +73,21 @@ function createNxJsonFile(repoRoot, topologicalTargets, cacheableOperations, scr
62
73
  }
63
74
  (0, fileutils_1.writeJsonFile)(nxJsonPath, nxJson);
64
75
  }
76
+ /**
77
+ * Locate-by-target upsert against an in-memory `targetDefaults` array.
78
+ * Used by `nx init` code paths that operate on raw JSON before a Tree
79
+ * exists — generators should use `upsertTargetDefault` from devkit instead.
80
+ */
81
+ function upsertTargetDefaultEntry(entries, target, patch) {
82
+ const existing = findUnfilteredTargetEntry(entries, target);
83
+ if (existing)
84
+ Object.assign(existing, patch, { target });
85
+ else
86
+ entries.push({ ...patch, target });
87
+ }
88
+ function findUnfilteredTargetEntry(entries, target) {
89
+ return entries.find((e) => e.target === target && e.projects === undefined && e.plugin === undefined);
90
+ }
65
91
  function createNxJsonFromTurboJson(turboJson) {
66
92
  const nxJson = {
67
93
  $schema: './node_modules/nx/schemas/nx-schema.json',
@@ -88,20 +114,20 @@ function createNxJsonFromTurboJson(turboJson) {
88
114
  }
89
115
  // Handle task configurations
90
116
  if (turboJson.tasks) {
91
- nxJson.targetDefaults = {};
117
+ const entries = [];
92
118
  for (const [taskName, taskConfig] of Object.entries(turboJson.tasks)) {
93
119
  // Skip project-specific tasks (containing #)
94
120
  if (taskName.includes('#'))
95
121
  continue;
96
122
  const config = taskConfig;
97
- nxJson.targetDefaults[taskName] = {};
123
+ const entry = { target: taskName };
98
124
  // Handle dependsOn
99
125
  if (config.dependsOn?.length > 0) {
100
- nxJson.targetDefaults[taskName].dependsOn = config.dependsOn;
126
+ entry.dependsOn = config.dependsOn;
101
127
  }
102
128
  // Handle inputs
103
129
  if (config.inputs?.length > 0) {
104
- nxJson.targetDefaults[taskName].inputs = config.inputs
130
+ entry.inputs = config.inputs
105
131
  .map((input) => {
106
132
  if (input === '$TURBO_DEFAULT$') {
107
133
  return '{projectRoot}/**/*';
@@ -124,7 +150,7 @@ function createNxJsonFromTurboJson(turboJson) {
124
150
  }
125
151
  // Handle outputs
126
152
  if (config.outputs?.length > 0) {
127
- nxJson.targetDefaults[taskName].outputs = config.outputs.map((output) => {
153
+ entry.outputs = config.outputs.map((output) => {
128
154
  // Don't add projectRoot if it's already there
129
155
  if (output.startsWith('{projectRoot}/'))
130
156
  return output;
@@ -136,7 +162,11 @@ function createNxJsonFromTurboJson(turboJson) {
136
162
  });
137
163
  }
138
164
  // Handle cache setting - true by default in Turbo
139
- nxJson.targetDefaults[taskName].cache = config.cache !== false;
165
+ entry.cache = config.cache !== false;
166
+ entries.push(entry);
167
+ }
168
+ if (entries.length > 0) {
169
+ nxJson.targetDefaults = entries;
140
170
  }
141
171
  }
142
172
  /**
@@ -68,7 +68,7 @@ function withMigrationOptions(yargs) {
68
68
  default: false,
69
69
  })
70
70
  .option('mode', {
71
- describe: "Restrict which packages to migrate. Only applies when migrating Nx itself. 'first-party' processes only Nx and its plugins (the target package plus its nx.packageGroup); 'third-party' processes only the third-party dependencies referenced by Nx packageJsonUpdates entries, catching up on any updates that may have been skipped previously; 'all' processes everything. Defaults to 'all' (or prompts in an interactive terminal when targeting Nx).",
71
+ describe: "Restrict which packages to migrate. Only applies when migrating Nx itself. 'first-party' processes only Nx and its plugins (the target package plus its nx.packageGroup); 'third-party' processes only the third-party dependencies referenced by Nx packageJsonUpdates entries, catching up on any updates that may have been skipped previously; 'all' processes everything. When targeting Nx in an interactive terminal, prompts for the value if not provided; otherwise defaults to 'all'.",
72
72
  type: 'string',
73
73
  choices: ['first-party', 'third-party', 'all'],
74
74
  })
@@ -2,11 +2,14 @@ import { MigrationsJson, PackageJsonUpdateForPackage as PackageUpdate } from '..
2
2
  import { NxJsonConfiguration } from '../../config/nx-json';
3
3
  import { FileChange } from '../../generators/tree';
4
4
  import { ArrayPackageGroup, PackageJson } from '../../utils/package-json';
5
+ import { type MultiMajorMode } from './multi-major';
5
6
  import { filterDowngradedUpdates } from './update-filters';
6
7
  import { normalizeVersion } from './version-utils';
7
8
  export { normalizeVersion };
8
9
  export interface ResolvedMigrationConfiguration extends MigrationsJson {
9
10
  packageGroup?: ArrayPackageGroup;
11
+ /** Prompt file contents keyed by the `prompt` value as it appears on the migration entry. */
12
+ resolvedPromptFiles?: Record<string, string>;
10
13
  }
11
14
  type CommandFailure = {
12
15
  message?: string;
@@ -14,6 +17,7 @@ type CommandFailure = {
14
17
  stdout?: string | Buffer;
15
18
  };
16
19
  export declare function formatCommandFailure(command: string, error: CommandFailure): string;
20
+ export type MigrateMode = 'first-party' | 'third-party' | 'all';
17
21
  export interface MigratorOptions {
18
22
  packageJson?: PackageJson;
19
23
  nxInstallation?: NxJsonConfiguration['installation'];
@@ -33,7 +37,7 @@ export interface MigratorOptions {
33
37
  * - 'third-party' keeps only packages NOT in `firstPartyPackages`
34
38
  * - 'all' / undefined keeps all packages (no filtering)
35
39
  */
36
- mode?: 'first-party' | 'third-party' | 'all';
40
+ mode?: MigrateMode;
37
41
  /** First-party package names used by `mode` for filtering. */
38
42
  firstPartyPackages?: ReadonlySet<string>;
39
43
  }
@@ -55,6 +59,8 @@ export declare class Migrator {
55
59
  constructor(opts: MigratorOptions);
56
60
  private fetchMigrationConfig;
57
61
  migrate(targetPackage: string, targetVersion: string): Promise<{
62
+ minVersionWithSkippedUpdates: string;
63
+ promptContents?: Record<string, string>;
58
64
  packageUpdates: Record<string, PackageUpdate>;
59
65
  migrations: {
60
66
  package: string;
@@ -63,9 +69,9 @@ export declare class Migrator {
63
69
  description?: string;
64
70
  implementation?: string;
65
71
  factory?: string;
72
+ prompt?: string;
66
73
  requires?: Record<string, string>;
67
74
  }[];
68
- minVersionWithSkippedUpdates: string;
69
75
  }>;
70
76
  private createMigrateJson;
71
77
  private buildPackageJsonUpdates;
@@ -106,10 +112,10 @@ export declare class Migrator {
106
112
  * walking the cascade.
107
113
  */
108
114
  export declare function resolveCanonicalNxPackage(targetVersion: string): 'nx' | '@nrwl/workspace';
109
- export declare function resolveMode(mode: 'first-party' | 'third-party' | 'all' | undefined, targetPackage: string, targetVersion: string, context?: {
115
+ export declare function resolveMode(mode: MigrateMode | undefined, targetPackage: string, targetVersion: string, context?: {
110
116
  hasFrom: boolean;
111
117
  hasExcludeAppliedMigrations: boolean;
112
- }): Promise<'first-party' | 'third-party' | 'all'>;
118
+ }): Promise<MigrateMode>;
113
119
  type GenerateMigrations = {
114
120
  type: 'generateMigrations';
115
121
  targetPackage: string;
@@ -122,7 +128,19 @@ type GenerateMigrations = {
122
128
  };
123
129
  interactive?: boolean;
124
130
  excludeAppliedMigrations?: boolean;
125
- mode: 'first-party' | 'third-party' | 'all';
131
+ mode: MigrateMode;
132
+ /**
133
+ * Set when multi-major redirected `targetVersion` to an incremental step
134
+ * (gradual mode or the interactive prompt picking a smaller jump). Holds
135
+ * the concrete resolved target so Next Steps can suggest re-running toward
136
+ * it.
137
+ */
138
+ originalTargetVersion?: string;
139
+ /**
140
+ * The `--multi-major-mode` value to propagate to a continuation command,
141
+ * or undefined to omit it. See `MultiMajorResult.gradual` for when it's set.
142
+ */
143
+ multiMajorMode?: MultiMajorMode;
126
144
  };
127
145
  type RunMigrations = {
128
146
  type: 'runMigrations';
@@ -48,6 +48,7 @@ const format_changed_files_with_prettier_if_available_1 = require("../../generat
48
48
  const provenance_1 = require("../../utils/provenance");
49
49
  const catalog_1 = require("../../utils/catalog");
50
50
  const multi_major_1 = require("./multi-major");
51
+ const prompt_files_1 = require("./prompt-files");
51
52
  const update_filters_1 = require("./update-filters");
52
53
  Object.defineProperty(exports, "filterDowngradedUpdates", { enumerable: true, get: function () { return update_filters_1.filterDowngradedUpdates; } });
53
54
  const version_utils_1 = require("./version-utils");
@@ -122,14 +123,16 @@ class Migrator {
122
123
  addToPackageJson: false,
123
124
  });
124
125
  this.applyModeFilter();
125
- const migrations = await this.createMigrateJson();
126
+ const { migrations, promptContents } = await this.createMigrateJson();
126
127
  return {
127
128
  packageUpdates: this.packageUpdates,
128
129
  migrations,
130
+ ...(Object.keys(promptContents).length > 0 ? { promptContents } : {}),
129
131
  minVersionWithSkippedUpdates: this.minVersionWithSkippedUpdates,
130
132
  };
131
133
  }
132
134
  async createMigrateJson() {
135
+ const promptContents = {};
133
136
  const migrations = await Promise.all(Object.keys(this.packageUpdates).map(async (packageName) => {
134
137
  if (this.packageUpdates[packageName].ignoreMigrations) {
135
138
  return [];
@@ -138,10 +141,15 @@ class Migrator {
138
141
  if (currentVersion === null)
139
142
  return [];
140
143
  const { version } = this.packageUpdates[packageName];
141
- const { generators } = await this.fetchMigrationConfig(packageName, version);
142
- if (!generators)
144
+ const { generators: migrationEntries, resolvedPromptFiles } = await this.fetchMigrationConfig(packageName, version);
145
+ if (!migrationEntries)
143
146
  return [];
144
- return Object.entries(generators)
147
+ if (resolvedPromptFiles) {
148
+ for (const [promptPath, content] of Object.entries(resolvedPromptFiles)) {
149
+ promptContents[(0, prompt_files_1.promptContentKey)(packageName, promptPath)] = content;
150
+ }
151
+ }
152
+ return Object.entries(migrationEntries)
145
153
  .filter(([, migration]) => migration.version &&
146
154
  this.gt(migration.version, currentVersion) &&
147
155
  this.lte(migration.version, version) &&
@@ -152,7 +160,7 @@ class Migrator {
152
160
  name: migrationName,
153
161
  }));
154
162
  }));
155
- return migrations.flat();
163
+ return { migrations: migrations.flat(), promptContents };
156
164
  }
157
165
  async buildPackageJsonUpdates(targetPackage, target) {
158
166
  const packagesToCheck = await this.populatePackageJsonUpdatesAndGetPackagesToCheck(targetPackage, target);
@@ -250,7 +258,7 @@ class Migrator {
250
258
  if (ignorePackageGroup) {
251
259
  return [];
252
260
  }
253
- const packageGroup = packageName === '@nrwl/workspace' && (0, semver_1.lt)(targetVersion, '14.0.0-beta.0')
261
+ const packageGroup = packageName === '@nrwl/workspace' && (0, version_utils_1.isLegacyEra)(targetVersion)
254
262
  ? LEGACY_NRWL_PACKAGE_GROUP
255
263
  : (migrationConfig.packageGroup ?? []);
256
264
  let packageGroupOrder = [];
@@ -503,9 +511,7 @@ function resolveFirstPartyPackages(targetPackage, packageGroup) {
503
511
  * walking the cascade.
504
512
  */
505
513
  function resolveCanonicalNxPackage(targetVersion) {
506
- return (0, semver_1.valid)(targetVersion) && (0, semver_1.lt)(targetVersion, '14.0.0-beta.0')
507
- ? '@nrwl/workspace'
508
- : 'nx';
514
+ return (0, version_utils_1.isLegacyEra)(targetVersion) ? '@nrwl/workspace' : 'nx';
509
515
  }
510
516
  async function resolveMode(mode, targetPackage, targetVersion, context = {
511
517
  hasFrom: false,
@@ -588,9 +594,9 @@ async function parseTargetPackageAndVersion(args) {
588
594
  // on the registry
589
595
  const targetVersion = await (0, version_utils_1.normalizeVersionWithTagCheck)('nx', args);
590
596
  const isDistTag = version_utils_1.DIST_TAGS.includes(args);
591
- const targetPackage = !isDistTag && (0, semver_1.lt)(targetVersion, '14.0.0-beta.0')
592
- ? '@nrwl/workspace'
593
- : 'nx';
597
+ const targetPackage = isDistTag
598
+ ? 'nx'
599
+ : resolveCanonicalNxPackage(targetVersion);
594
600
  return { targetPackage, targetVersion };
595
601
  }
596
602
  return { targetPackage: args, targetVersion: 'latest' };
@@ -602,6 +608,9 @@ async function parseMigrationsOptions(options) {
602
608
  if (options.mode && options.runMigrations) {
603
609
  throw new Error(`Error: '--mode' cannot be combined with '--run-migrations'.`);
604
610
  }
611
+ if (options.multiMajorMode && options.runMigrations) {
612
+ throw new Error(`Error: '--multi-major-mode' cannot be combined with '--run-migrations'.`);
613
+ }
605
614
  if (options.runMigrations) {
606
615
  return {
607
616
  type: 'runMigrations',
@@ -625,12 +634,13 @@ async function parseMigrationsOptions(options) {
625
634
  // Spec §10: prompt or warn when crossing more than one major boundary.
626
635
  // Each major's metadata may have pruned migrations from much-older versions,
627
636
  // so jumping multiple majors at once can silently skip migrations.
628
- targetVersion = await (0, multi_major_1.maybePromptOrWarnMultiMajorMigration)({
637
+ const multiMajorResult = await (0, multi_major_1.maybePromptOrWarnMultiMajorMigration)({
629
638
  mode,
630
639
  options,
631
640
  targetPackage,
632
641
  targetVersion,
633
642
  });
643
+ targetVersion = multiMajorResult.chosen;
634
644
  if (mode === 'third-party') {
635
645
  assertThirdPartyTargetBounds({
636
646
  targetPackage,
@@ -648,6 +658,8 @@ async function parseMigrationsOptions(options) {
648
658
  interactive: options.interactive,
649
659
  excludeAppliedMigrations: options.excludeAppliedMigrations,
650
660
  mode,
661
+ originalTargetVersion: multiMajorResult.originalTarget,
662
+ multiMajorMode: multiMajorResult.gradual ? 'gradual' : undefined,
651
663
  };
652
664
  }
653
665
  function assertThirdPartyModeFlagCompatibility(options) {
@@ -708,7 +720,7 @@ async function resolveTargetAndMode(args) {
708
720
  targetVersion = 'latest';
709
721
  }
710
722
  if (options.mode && !(0, version_utils_1.isNxEquivalentTarget)(targetPackage, targetVersion)) {
711
- const isLegacy = (0, semver_1.valid)(targetVersion) && (0, semver_1.lt)(targetVersion, '14.0.0-beta.0');
723
+ const isLegacy = (0, version_utils_1.isLegacyEra)(targetVersion);
712
724
  const validTargets = isLegacy
713
725
  ? `'@nrwl/workspace'`
714
726
  : `'nx' or '@nx/workspace'`;
@@ -767,10 +779,10 @@ function assertThirdPartyTargetBounds(args) {
767
779
  function resolveInstalledCanonical() {
768
780
  const installedNx = (0, installed_nx_version_1.getInstalledNxVersion)();
769
781
  if (installedNx) {
770
- if ((0, semver_1.lt)(installedNx, '14.0.0-beta.0')) {
771
- return { canonical: '@nrwl/workspace', version: installedNx };
772
- }
773
- return { canonical: 'nx', version: installedNx };
782
+ return {
783
+ canonical: resolveCanonicalNxPackage(installedNx),
784
+ version: installedNx,
785
+ };
774
786
  }
775
787
  const installedLegacy = (0, installed_nx_version_1.getInstalledLegacyNrwlWorkspaceVersion)();
776
788
  if (installedLegacy) {
@@ -923,11 +935,22 @@ async function downloadPackageMigrationsFromRegistry(packageName, packageVersion
923
935
  let result;
924
936
  try {
925
937
  const { tarballPath } = await (0, package_manager_1.packageRegistryPack)(dir, packageName, packageVersion);
926
- const migrations = await (0, fileutils_1.extractFileFromTarball)((0, path_1.join)(dir, tarballPath), (0, path_2.joinPathFragments)('package', migrationsFilePath), (0, path_1.join)(dir, migrationsFilePath)).then((path) => (0, fileutils_1.readJsonFile)(path));
927
- result = { ...migrations, packageGroup, version: packageVersion };
928
- }
929
- catch {
930
- throw new Error(`Failed to find migrations file "${migrationsFilePath}" in package "${packageName}@${packageVersion}".`);
938
+ const fullTarballPath = (0, path_1.join)(dir, tarballPath);
939
+ let migrations;
940
+ try {
941
+ migrations = await (0, fileutils_1.extractFileFromTarball)(fullTarballPath, (0, path_2.joinPathFragments)('package', migrationsFilePath), (0, path_1.join)(dir, migrationsFilePath)).then((path) => (0, fileutils_1.readJsonFile)(path));
942
+ }
943
+ catch {
944
+ throw new Error(`Failed to find migrations file "${migrationsFilePath}" in package "${packageName}@${packageVersion}".`);
945
+ }
946
+ (0, prompt_files_1.validateMigrationEntries)(packageName, packageVersion, migrations);
947
+ const resolvedPromptFiles = await (0, prompt_files_1.extractPromptFilesFromTarball)(packageName, packageVersion, migrations, migrationsFilePath, fullTarballPath, dir);
948
+ result = {
949
+ ...migrations,
950
+ packageGroup,
951
+ version: packageVersion,
952
+ ...(resolvedPromptFiles ? { resolvedPromptFiles } : {}),
953
+ };
931
954
  }
932
955
  finally {
933
956
  await cleanup();
@@ -981,10 +1004,18 @@ async function getPackageMigrationsUsingInstallImpl(packageName, packageVersion)
981
1004
  });
982
1005
  const { migrations: migrationsFilePath, packageGroup, packageJson, } = readPackageMigrationConfig(packageName, dir);
983
1006
  let migrations = undefined;
1007
+ let resolvedPromptFiles;
984
1008
  if (migrationsFilePath) {
985
1009
  migrations = (0, fileutils_1.readJsonFile)(migrationsFilePath);
986
- }
987
- result = { ...migrations, packageGroup, version: packageJson.version };
1010
+ (0, prompt_files_1.validateMigrationEntries)(packageName, packageVersion, migrations);
1011
+ resolvedPromptFiles = await (0, prompt_files_1.readPromptFilesFromInstall)(packageName, packageVersion, migrations, migrationsFilePath);
1012
+ }
1013
+ result = {
1014
+ ...migrations,
1015
+ packageGroup,
1016
+ version: packageJson.version,
1017
+ ...(resolvedPromptFiles ? { resolvedPromptFiles } : {}),
1018
+ };
988
1019
  }
989
1020
  catch (e) {
990
1021
  const pmc = (0, package_manager_1.getPackageManagerCommand)((0, package_manager_1.detectPackageManager)(dir), dir);
@@ -1191,8 +1222,7 @@ async function generateMigrationsJsonAndUpdatePackageJson(root, opts) {
1191
1222
  // `LEGACY_NRWL_PACKAGE_GROUP` for that case, and the post-build
1192
1223
  // third-party filter must mirror that set or first-party `@nrwl/*`
1193
1224
  // plugins slip past it.
1194
- const packageGroup = sourcePackage === '@nrwl/workspace' &&
1195
- (0, semver_1.lt)(opts.targetVersion, '14.0.0-beta.0')
1225
+ const packageGroup = sourcePackage === '@nrwl/workspace' && (0, version_utils_1.isLegacyEra)(opts.targetVersion)
1196
1226
  ? LEGACY_NRWL_PACKAGE_GROUP
1197
1227
  : rootMetadata.packageGroup;
1198
1228
  firstPartyPackages = resolveFirstPartyPackages(sourcePackage, packageGroup);
@@ -1210,7 +1240,7 @@ async function generateMigrationsJsonAndUpdatePackageJson(root, opts) {
1210
1240
  mode,
1211
1241
  firstPartyPackages,
1212
1242
  });
1213
- const { migrations, packageUpdates, minVersionWithSkippedUpdates } = await migrator.migrate(walkedTargetPackage, opts.targetVersion);
1243
+ const { migrations, packageUpdates, promptContents, minVersionWithSkippedUpdates, } = await migrator.migrate(walkedTargetPackage, opts.targetVersion);
1214
1244
  // The cascade collects packageJsonUpdates entries against the cascade
1215
1245
  // root's installed version, but inner per-package pins are only gated
1216
1246
  // against the in-flight cascade tally — not against each inner package's
@@ -1221,6 +1251,7 @@ async function generateMigrationsJsonAndUpdatePackageJson(root, opts) {
1221
1251
  const writableUpdates = (0, update_filters_1.filterDowngradedUpdates)(packageUpdates, originalPackageJson, installedPackageVersions);
1222
1252
  const wrotePackageJson = await updatePackageJson(root, writableUpdates);
1223
1253
  const wroteNxJsonInstallation = await updateInstallationDetails(root, writableUpdates);
1254
+ const promptMigrationFiles = (0, prompt_files_1.writePromptMigrationFiles)(root, migrations, promptContents ?? {}, packageUpdates[walkedTargetPackage].version);
1224
1255
  if (migrations.length > 0) {
1225
1256
  await createMigrationsFile(root, [
1226
1257
  ...addSplitConfigurationMigrationIfAvailable(from, writableUpdates),
@@ -1258,6 +1289,11 @@ async function generateMigrationsJsonAndUpdatePackageJson(root, opts) {
1258
1289
  migrations.length > 0
1259
1290
  ? `- migrations.json has been generated.`
1260
1291
  : `- There are no migrations to run, so migrations.json has not been created.`,
1292
+ ...(promptMigrationFiles.length > 0
1293
+ ? [
1294
+ `- ${promptMigrationFiles.length} AI migration prompt(s) have been written to ${prompt_files_1.AI_MIGRATIONS_DIR}/.`,
1295
+ ]
1296
+ : []),
1261
1297
  ],
1262
1298
  });
1263
1299
  try {
@@ -1291,9 +1327,21 @@ async function generateMigrationsJsonAndUpdatePackageJson(root, opts) {
1291
1327
  ]
1292
1328
  : [
1293
1329
  `- Make sure package.json changes make sense and then run '${pmc.install}',`,
1330
+ ...(promptMigrationFiles.length > 0
1331
+ ? [
1332
+ `- Review and tweak the AI migration prompts in ${prompt_files_1.AI_MIGRATIONS_DIR}/ as needed.`,
1333
+ ]
1334
+ : []),
1294
1335
  ...(migrations.length > 0
1295
1336
  ? [`- Run '${pmc.exec} nx migrate --run-migrations'`]
1296
1337
  : []),
1338
+ ...(opts.originalTargetVersion
1339
+ ? [
1340
+ `- After applying these migrations, run '${pmc.exec} nx migrate ${opts.targetPackage}@${opts.originalTargetVersion} --mode=${opts.mode}${opts.multiMajorMode === 'gradual'
1341
+ ? ` ${multi_major_1.MULTI_MAJOR_MODE_FLAG}=gradual`
1342
+ : ''}' to continue toward your original target.`,
1343
+ ]
1344
+ : []),
1297
1345
  ...(opts.interactive && minVersionWithSkippedUpdates
1298
1346
  ? [
1299
1347
  `- You opted out of some migrations for now. Write the following command down somewhere to apply these migrations later:`,
@@ -1,9 +1,30 @@
1
+ import type { MigrateMode } from './migrate';
2
+ export declare const MULTI_MAJOR_MODE_FLAG = "--multi-major-mode";
1
3
  export type MultiMajorMode = 'direct' | 'gradual';
4
+ /**
5
+ * Result of running the multi-major check.
6
+ *
7
+ * - `chosen`: the version to actually migrate to (always concrete semver when
8
+ * the function ran past the dist-tag resolution; otherwise the input value).
9
+ * - `originalTarget`: set only when an actual redirect happened (gradual mode
10
+ * auto-picked a smaller step, OR the interactive prompt returned a version
11
+ * different from the resolved target). Holds the concrete resolved target
12
+ * so callers can suggest re-running toward it.
13
+ * - `gradual`: set only when the redirect came from gradual mode (flag or
14
+ * env). Tells callers it's safe to propagate `--multi-major-mode=gradual`
15
+ * to a continuation command; left unset when the redirect came from the
16
+ * interactive prompt so the user isn't silently locked into gradual.
17
+ */
18
+ export type MultiMajorResult = {
19
+ chosen: string;
20
+ originalTarget?: string;
21
+ gradual?: boolean;
22
+ };
2
23
  export declare function maybePromptOrWarnMultiMajorMigration(args: {
3
- mode: 'first-party' | 'third-party' | 'all';
24
+ mode: MigrateMode;
4
25
  options: {
5
26
  multiMajorMode?: MultiMajorMode;
6
27
  };
7
28
  targetPackage: string;
8
29
  targetVersion: string;
9
- }): Promise<string>;
30
+ }): Promise<MultiMajorResult>;