nx 23.0.0-rc.3 → 23.0.0

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 (30) hide show
  1. package/dist/src/command-line/completion/command-object.js +31 -19
  2. package/dist/src/command-line/configure-ai-agents/command-object.js +18 -6
  3. package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +18 -14
  4. package/dist/src/command-line/init/implementation/utils.d.ts +1 -7
  5. package/dist/src/command-line/init/implementation/utils.js +14 -44
  6. package/dist/src/command-line/show/show-target/info.js +5 -4
  7. package/dist/src/config/nx-json.d.ts +1 -37
  8. package/dist/src/core/graph/main.js +1 -1
  9. package/dist/src/devkit-exports.d.ts +1 -1
  10. package/dist/src/devkit-internals.d.ts +0 -1
  11. package/dist/src/devkit-internals.js +1 -4
  12. package/dist/src/hasher/task-hasher.js +4 -6
  13. package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +2 -6
  14. package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +4 -20
  15. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  16. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  17. package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +4 -95
  18. package/dist/src/project-graph/utils/project-configuration/target-defaults.js +68 -515
  19. package/dist/src/project-graph/utils/project-configuration-utils.d.ts +5 -13
  20. package/dist/src/project-graph/utils/project-configuration-utils.js +6 -14
  21. package/dist/src/tasks-runner/run-command.js +10 -0
  22. package/dist/src/tasks-runner/task-orchestrator.js +29 -13
  23. package/dist/src/tasks-runner/utils.js +0 -3
  24. package/dist/src/utils/package-json.js +1 -10
  25. package/migrations.json +0 -7
  26. package/package.json +11 -11
  27. package/schemas/nx-schema.json +5 -101
  28. package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.d.ts +0 -35
  29. package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.js +0 -139
  30. package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.md +0 -66
@@ -10,25 +10,16 @@ const SHELL_CHOICES = ['bash', 'zsh', 'fish', 'powershell'];
10
10
  exports.yargsCompletionCommand = {
11
11
  command: 'completion [shell]',
12
12
  describe: 'Install shell completion for bash, zsh, fish, or powershell. Omit the shell to pick interactively.',
13
- builder: (yargs) => yargs
14
- .positional('shell', {
15
- type: 'string',
16
- choices: SHELL_CHOICES,
17
- describe: 'Shell to install completion for.',
18
- })
19
- .option('force', {
20
- type: 'boolean',
21
- default: false,
22
- describe: 'Install the completion script even if `nx` is not found on PATH.',
23
- })
24
- .option('stdout', {
25
- type: 'boolean',
26
- default: false,
27
- describe: 'Print the completion script to stdout instead of writing to the shell rc file.',
28
- })
29
- .example('$0 completion bash', 'Install bash completion to ~/.bashrc')
30
- .example('$0 completion', 'Pick shells interactively and install completion for each')
31
- .example('$0 completion bash --stdout >> ~/.bash_profile', 'Print to stdout for a custom rc location'),
13
+ builder: (yargs) => {
14
+ const y = withCompletionOptions(yargs);
15
+ // Yargs' built-in help is disabled (see nx-commands.ts) and this command
16
+ // skips initLocal's --help handling, so handle it in the builder like init.
17
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
18
+ y.showHelp();
19
+ process.exit(0);
20
+ }
21
+ return y;
22
+ },
32
23
  handler: async (args) => {
33
24
  const scripts = await (0, handle_import_1.handleImport)('./scripts.js', __dirname);
34
25
  const shells = args.shell ? [args.shell] : await pickShellsInteractively();
@@ -51,6 +42,27 @@ exports.yargsCompletionCommand = {
51
42
  process.exit(0);
52
43
  },
53
44
  };
45
+ function withCompletionOptions(yargs) {
46
+ return yargs
47
+ .positional('shell', {
48
+ type: 'string',
49
+ choices: SHELL_CHOICES,
50
+ describe: 'Shell to install completion for.',
51
+ })
52
+ .option('force', {
53
+ type: 'boolean',
54
+ default: false,
55
+ describe: 'Install the completion script even if `nx` is not found on PATH.',
56
+ })
57
+ .option('stdout', {
58
+ type: 'boolean',
59
+ default: false,
60
+ describe: 'Print the completion script to stdout instead of writing to the shell rc file.',
61
+ })
62
+ .example('$0 completion bash', 'Install bash completion to ~/.bashrc')
63
+ .example('$0 completion', 'Pick shells interactively and install completion for each')
64
+ .example('$0 completion bash --stdout >> ~/.bash_profile', 'Print to stdout for a custom rc location');
65
+ }
54
66
  async function pickShellsInteractively() {
55
67
  if (!process.stdin.isTTY || !process.stderr.isTTY) {
56
68
  console.warn('nx: please specify a shell — `nx completion <bash|zsh|fish|powershell>`.');
@@ -6,7 +6,22 @@ const handle_import_1 = require("../../utils/handle-import");
6
6
  exports.yargsConfigureAiAgentsCommand = {
7
7
  command: 'configure-ai-agents',
8
8
  describe: 'Configure and update AI agent configurations for your workspace.',
9
- builder: (yargs) => (0, shared_options_1.withVerbose)(yargs)
9
+ builder: (yargs) => {
10
+ const y = withConfigureAiAgentsOptions(yargs);
11
+ // Yargs' built-in help is disabled (see nx-commands.ts) and this command
12
+ // skips initLocal's --help handling, so handle it in the builder like init.
13
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
14
+ y.showHelp();
15
+ process.exit(0);
16
+ }
17
+ return y;
18
+ },
19
+ handler: async (args) => {
20
+ await (await (0, handle_import_1.handleImport)('./configure-ai-agents.js', __dirname)).configureAiAgentsHandler(args);
21
+ },
22
+ };
23
+ function withConfigureAiAgentsOptions(yargs) {
24
+ return (0, shared_options_1.withVerbose)(yargs)
10
25
  .option('agents', {
11
26
  type: 'array',
12
27
  string: true,
@@ -40,8 +55,5 @@ exports.yargsConfigureAiAgentsCommand = {
40
55
  .example('$0 configure-ai-agents --agents claude gemini', 'Prompts for updates and and configuration of Claude and Gemini AI agents')
41
56
  .example('$0 configure-ai-agents --check', 'Checks if any configured agents are out of date and need to be updated')
42
57
  .example('$0 configure-ai-agents --check=all', 'Checks if any agents are not configured, out of date or partially configured')
43
- .example('$0 configure-ai-agents --agents claude gemini --no-interactive', 'Configures and updates Claude and Gemini AI agents without prompts'), // because of the coerce function
44
- handler: async (args) => {
45
- await (await (0, handle_import_1.handleImport)('./configure-ai-agents.js', __dirname)).configureAiAgentsHandler(args);
46
- },
47
- };
58
+ .example('$0 configure-ai-agents --agents claude gemini --no-interactive', 'Configures and updates Claude and Gemini AI agents without prompts'); // because of the coerce function
59
+ }
@@ -54,26 +54,29 @@ function createNxJson(repoRoot, angularJson, cacheableOperations, { eslintProjec
54
54
  : []),
55
55
  ].filter(Boolean),
56
56
  };
57
- const defaults = Array.isArray(nxJson.targetDefaults)
58
- ? [...nxJson.targetDefaults]
59
- : [];
57
+ nxJson.targetDefaults ??= {};
60
58
  if (workspaceTargets.includes('build')) {
61
- (0, utils_1.upsertTargetDefaultEntry)(defaults, 'build', {
59
+ nxJson.targetDefaults.build = {
60
+ ...nxJson.targetDefaults.build,
62
61
  dependsOn: ['^build'],
63
62
  inputs: ['production', '^production'],
64
- });
63
+ };
65
64
  }
66
65
  if (workspaceTargets.includes('server')) {
67
- (0, utils_1.upsertTargetDefaultEntry)(defaults, 'server', {
66
+ nxJson.targetDefaults.server = {
67
+ ...nxJson.targetDefaults.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
- (0, utils_1.upsertTargetDefaultEntry)(defaults, 'test', { inputs });
76
+ nxJson.targetDefaults.test = {
77
+ ...nxJson.targetDefaults.test,
78
+ inputs,
79
+ };
77
80
  }
78
81
  if (workspaceTargets.includes('lint')) {
79
82
  const inputs = ['default'];
@@ -83,15 +86,16 @@ function createNxJson(repoRoot, angularJson, cacheableOperations, { eslintProjec
83
86
  if ((0, fileutils_1.fileExists)((0, node_path_1.join)(repoRoot, 'eslint.config.cjs'))) {
84
87
  inputs.push('{workspaceRoot}/eslint.config.cjs');
85
88
  }
86
- (0, utils_1.upsertTargetDefaultEntry)(defaults, 'lint', { inputs });
89
+ nxJson.targetDefaults.lint = {
90
+ ...nxJson.targetDefaults.lint,
91
+ inputs,
92
+ };
87
93
  }
88
94
  if (workspaceTargets.includes('e2e')) {
89
- (0, utils_1.upsertTargetDefaultEntry)(defaults, 'e2e', {
95
+ nxJson.targetDefaults.e2e = {
96
+ ...nxJson.targetDefaults.e2e,
90
97
  inputs: ['default', '^production'],
91
- });
92
- }
93
- if (defaults.length > 0) {
94
- nxJson.targetDefaults = defaults;
98
+ };
95
99
  }
96
100
  (0, fileutils_1.writeJsonFile)((0, node_path_1.join)(repoRoot, 'nx.json'), nxJson);
97
101
  }
@@ -1,15 +1,9 @@
1
- import { NxJsonConfiguration, TargetDefaultEntry } from '../../../config/nx-json';
1
+ import { NxJsonConfiguration } 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;
13
7
  export declare function createNxJsonFromTurboJson(turboJson: Record<string, any>): NxJsonConfiguration;
14
8
  export declare function addDepsToPackageJson(repoRoot: string, additionalPackages?: string[]): void;
15
9
  export declare function updateGitIgnore(root: string): void;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createNxJsonFile = createNxJsonFile;
4
- exports.upsertTargetDefaultEntry = upsertTargetDefaultEntry;
5
4
  exports.createNxJsonFromTurboJson = createNxJsonFromTurboJson;
6
5
  exports.addDepsToPackageJson = addDepsToPackageJson;
7
6
  exports.updateGitIgnore = updateGitIgnore;
@@ -35,37 +34,27 @@ function createNxJsonFile(repoRoot, topologicalTargets, cacheableOperations, scr
35
34
  }
36
35
  catch { }
37
36
  nxJson.$schema = './node_modules/nx/schemas/nx-schema.json';
38
- const entries = Array.isArray(nxJson.targetDefaults)
39
- ? [...nxJson.targetDefaults]
40
- : [];
37
+ nxJson.targetDefaults ??= {};
41
38
  if (topologicalTargets.length > 0) {
42
39
  for (const scriptName of topologicalTargets) {
43
- upsertTargetDefaultEntry(entries, scriptName, {
44
- dependsOn: [`^${scriptName}`],
45
- });
40
+ nxJson.targetDefaults[scriptName] ??= {};
41
+ nxJson.targetDefaults[scriptName] = { dependsOn: [`^${scriptName}`] };
46
42
  }
47
43
  }
48
44
  for (const [scriptName, output] of Object.entries(scriptOutputs)) {
49
45
  if (!output) {
50
46
  continue;
51
47
  }
52
- upsertTargetDefaultEntry(entries, scriptName, {
53
- outputs: [`{projectRoot}/${output}`],
54
- });
48
+ nxJson.targetDefaults[scriptName] ??= {};
49
+ nxJson.targetDefaults[scriptName].outputs = [`{projectRoot}/${output}`];
55
50
  }
56
51
  for (const target of cacheableOperations) {
57
- const existing = findUnfilteredTargetEntry(entries, target);
58
- if (existing)
59
- existing.cache ??= true;
60
- else
61
- entries.push({ target, cache: true });
52
+ nxJson.targetDefaults[target] ??= {};
53
+ nxJson.targetDefaults[target].cache ??= true;
62
54
  }
63
- if (entries.length === 0) {
55
+ if (Object.keys(nxJson.targetDefaults).length === 0) {
64
56
  delete nxJson.targetDefaults;
65
57
  }
66
- else {
67
- nxJson.targetDefaults = entries;
68
- }
69
58
  const defaultBase = (0, deduce_default_base_1.deduceDefaultBase)();
70
59
  // Do not add defaultBase if it is inferred to be the Nx default value of main
71
60
  if (defaultBase !== 'main') {
@@ -73,21 +62,6 @@ function createNxJsonFile(repoRoot, topologicalTargets, cacheableOperations, scr
73
62
  }
74
63
  (0, fileutils_1.writeJsonFile)(nxJsonPath, nxJson);
75
64
  }
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
- }
91
65
  function createNxJsonFromTurboJson(turboJson) {
92
66
  const nxJson = {
93
67
  $schema: './node_modules/nx/schemas/nx-schema.json',
@@ -114,20 +88,20 @@ function createNxJsonFromTurboJson(turboJson) {
114
88
  }
115
89
  // Handle task configurations
116
90
  if (turboJson.tasks) {
117
- const entries = [];
91
+ nxJson.targetDefaults = {};
118
92
  for (const [taskName, taskConfig] of Object.entries(turboJson.tasks)) {
119
93
  // Skip project-specific tasks (containing #)
120
94
  if (taskName.includes('#'))
121
95
  continue;
122
96
  const config = taskConfig;
123
- const entry = { target: taskName };
97
+ nxJson.targetDefaults[taskName] = {};
124
98
  // Handle dependsOn
125
99
  if (config.dependsOn?.length > 0) {
126
- entry.dependsOn = config.dependsOn;
100
+ nxJson.targetDefaults[taskName].dependsOn = config.dependsOn;
127
101
  }
128
102
  // Handle inputs
129
103
  if (config.inputs?.length > 0) {
130
- entry.inputs = config.inputs
104
+ nxJson.targetDefaults[taskName].inputs = config.inputs
131
105
  .map((input) => {
132
106
  if (input === '$TURBO_DEFAULT$') {
133
107
  return '{projectRoot}/**/*';
@@ -150,7 +124,7 @@ function createNxJsonFromTurboJson(turboJson) {
150
124
  }
151
125
  // Handle outputs
152
126
  if (config.outputs?.length > 0) {
153
- entry.outputs = config.outputs.map((output) => {
127
+ nxJson.targetDefaults[taskName].outputs = config.outputs.map((output) => {
154
128
  // Don't add projectRoot if it's already there
155
129
  if (output.startsWith('{projectRoot}/'))
156
130
  return output;
@@ -162,11 +136,7 @@ function createNxJsonFromTurboJson(turboJson) {
162
136
  });
163
137
  }
164
138
  // Handle cache setting - true by default in Turbo
165
- entry.cache = config.cache !== false;
166
- entries.push(entry);
167
- }
168
- if (entries.length > 0) {
169
- nxJson.targetDefaults = entries;
139
+ nxJson.targetDefaults[taskName].cache = config.cache !== false;
170
140
  }
171
141
  }
172
142
  /**
@@ -20,9 +20,10 @@ function resolveTargetInfoData(t) {
20
20
  allTargetNames.add(name);
21
21
  }
22
22
  }
23
- const depConfigs = (0, utils_1.getDependencyConfigs)({ project: projectName, target: targetName },
24
- // no programmatic extras — `dependsOn` is already merged into the graph node
25
- {}, graph, [...allTargetNames]) ?? [];
23
+ const extraTargetDeps = Object.fromEntries(Object.entries(nxJson.targetDefaults ?? {})
24
+ .filter(([, config]) => config.dependsOn)
25
+ .map(([name, config]) => [name, config.dependsOn]));
26
+ const depConfigs = (0, utils_1.getDependencyConfigs)({ project: projectName, target: targetName }, extraTargetDeps, graph, [...allTargetNames]) ?? [];
26
27
  // Determine the hoisted command value and which option key it came from
27
28
  let command;
28
29
  let commandSourceKey;
@@ -43,7 +44,7 @@ function resolveTargetInfoData(t) {
43
44
  command = targetConfig.options.script;
44
45
  commandSourceKey = 'options.script';
45
46
  }
46
- const { dependsOn, depSourceIndices, transitiveTasks } = resolveTaskGraphDependencies(graph, {}, projectName, targetName, configuration, depConfigs);
47
+ const { dependsOn, depSourceIndices, transitiveTasks } = resolveTaskGraphDependencies(graph, extraTargetDeps, projectName, targetName, configuration, depConfigs);
47
48
  const configurations = Object.keys(targetConfig.configurations ?? {});
48
49
  const targetSourceMap = extractTargetSourceMap(node.data.root, targetName, sourceMaps);
49
50
  const usesCustomHasher = (0, utils_2.hasCustomHasher)(projectName, targetName, graph);
@@ -20,43 +20,7 @@ export interface NxAffectedConfig {
20
20
  */
21
21
  defaultBase?: string;
22
22
  }
23
- /**
24
- * A single entry in the array-shaped `targetDefaults` configuration.
25
- * Supports filtering the default's applicability by project set and/or the
26
- * plugin that originated the target.
27
- *
28
- * Either `target` or `executor` must be set. An entry with both narrows
29
- * the match further (target name AND executor must agree).
30
- */
31
- export type TargetDefaultEntry = {
32
- /**
33
- * Target name or glob pattern (e.g. `build`, `e2e-ci--*`). When omitted,
34
- * the entry matches by `executor` alone.
35
- */
36
- target?: string;
37
- /**
38
- * Restrict the default to a subset of projects. Accepts any pattern
39
- * supported by `findMatchingProjects` (project names, globs, `tag:foo`,
40
- * directory globs, negation with `!`).
41
- */
42
- projects?: string | string[];
43
- /**
44
- * Restrict the default to targets originated by a specific plugin
45
- * (e.g. `@nx/vite`). Matches against the plugin that wrote the target's
46
- * `executor` or `command`.
47
- */
48
- plugin?: string;
49
- } & Partial<TargetConfiguration>;
50
- /**
51
- * @deprecated Use the array-shaped {@link TargetDefaultEntry}[] form instead.
52
- * Retained so devkit helpers can still read nx.json files that predate the
53
- * migration.
54
- * @todo(v24) Remove this type and all branches that read it.
55
- */
56
- export type TargetDefaultsRecord = Record<string, Partial<TargetConfiguration>>;
57
- export type TargetDefaults = TargetDefaultEntry[] | TargetDefaultsRecord;
58
- /** Internal-only: the post-normalization shape consumed by the nx core matcher. */
59
- export type NormalizedTargetDefaults = TargetDefaultEntry[];
23
+ export type TargetDefaults = Record<string, Partial<TargetConfiguration>>;
60
24
  export type TargetDependencies = Record<string, (TargetDependencyConfig | string)[]>;
61
25
  export interface NrwlJsPluginConfig {
62
26
  analyzeSourceFiles?: boolean;