nx 23.3.0-beta.4 → 23.3.0-beta.6

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 (113) hide show
  1. package/dist/nx-cloud-internals.d.ts +1 -0
  2. package/dist/nx-cloud-internals.js +9 -0
  3. package/dist/plugins/package-json.js +1 -1
  4. package/dist/src/command-line/affected/affected.js +51 -9
  5. package/dist/src/command-line/graph/graph.d.ts +31 -0
  6. package/dist/src/command-line/graph/graph.js +71 -17
  7. package/dist/src/command-line/release/publish.js +7 -11
  8. package/dist/src/command-line/release/utils/get-touched-projects-for-group.js +3 -3
  9. package/dist/src/command-line/run/run-one.js +5 -1
  10. package/dist/src/command-line/run-many/run-many.js +6 -12
  11. package/dist/src/command-line/show/projects.js +30 -1
  12. package/dist/src/config/task-graph.d.ts +1 -1
  13. package/dist/src/config/workspace-json-project-json.d.ts +21 -1
  14. package/dist/src/core/graph/main.js +1 -1
  15. package/dist/src/core/graph/runtime.js +1 -1
  16. package/dist/src/core/graph/styles.js +1 -1
  17. package/dist/src/daemon/client/client.d.ts +7 -2
  18. package/dist/src/daemon/client/client.js +15 -2
  19. package/dist/src/daemon/message-types/io-snapshot-version.d.ts +5 -0
  20. package/dist/src/daemon/message-types/io-snapshot-version.js +2 -0
  21. package/dist/src/daemon/message-types/select-affected-tasks.d.ts +18 -0
  22. package/dist/src/daemon/message-types/select-affected-tasks.js +11 -0
  23. package/dist/src/daemon/server/handle-hash-tasks.d.ts +2 -0
  24. package/dist/src/daemon/server/handle-hash-tasks.js +5 -3
  25. package/dist/src/daemon/server/handle-select-affected-tasks.d.ts +3 -0
  26. package/dist/src/daemon/server/handle-select-affected-tasks.js +23 -0
  27. package/dist/src/daemon/server/io-snapshots-state.d.ts +7 -0
  28. package/dist/src/daemon/server/io-snapshots-state.js +35 -0
  29. package/dist/src/daemon/server/planning-context.d.ts +8 -0
  30. package/dist/src/daemon/server/planning-context.js +18 -0
  31. package/dist/src/daemon/server/server.d.ts +1 -0
  32. package/dist/src/daemon/server/server.js +6 -0
  33. package/dist/src/executors/run-commands/run-commands.impl.d.ts +2 -1
  34. package/dist/src/executors/run-commands/run-commands.impl.js +19 -5
  35. package/dist/src/executors/run-commands/running-tasks.d.ts +5 -4
  36. package/dist/src/executors/run-commands/running-tasks.js +13 -13
  37. package/dist/src/hasher/create-task-hasher.d.ts +8 -1
  38. package/dist/src/hasher/create-task-hasher.js +13 -3
  39. package/dist/src/hasher/hash-plan-inspector.js +2 -2
  40. package/dist/src/hasher/hash-task.d.ts +2 -2
  41. package/dist/src/hasher/hash-task.js +7 -1
  42. package/dist/src/hasher/native-task-hasher-impl.d.ts +13 -5
  43. package/dist/src/hasher/native-task-hasher-impl.js +38 -15
  44. package/dist/src/hasher/task-hasher.d.ts +17 -9
  45. package/dist/src/hasher/task-hasher.js +16 -11
  46. package/dist/src/hasher/task-planning-context.d.ts +13 -0
  47. package/dist/src/hasher/task-planning-context.js +12 -0
  48. package/dist/src/io-snapshots/config.d.ts +23 -0
  49. package/dist/src/io-snapshots/config.js +32 -0
  50. package/dist/src/io-snapshots/fetch.d.ts +21 -0
  51. package/dist/src/io-snapshots/fetch.js +43 -0
  52. package/dist/src/io-snapshots/outputs.d.ts +12 -0
  53. package/dist/src/io-snapshots/outputs.js +33 -0
  54. package/dist/src/io-snapshots/overrides.d.ts +12 -0
  55. package/dist/src/io-snapshots/overrides.js +49 -0
  56. package/dist/src/io-snapshots/report.d.ts +13 -0
  57. package/dist/src/io-snapshots/report.js +68 -0
  58. package/dist/src/io-snapshots/store.d.ts +37 -0
  59. package/dist/src/io-snapshots/store.js +162 -0
  60. package/dist/src/native/index.d.ts +264 -2
  61. package/dist/src/native/native-bindings.js +10 -0
  62. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  63. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  64. package/dist/src/native/transform-objects.d.ts +11 -2
  65. package/dist/src/native/transform-objects.js +46 -0
  66. package/dist/src/nx-cloud/update-manager.d.ts +3 -0
  67. package/dist/src/plugins/js/project-graph/affected/lock-file-changes.d.ts +10 -2
  68. package/dist/src/plugins/js/project-graph/affected/lock-file-changes.js +51 -29
  69. package/dist/src/plugins/js/project-graph/affected/npm-packages.d.ts +10 -2
  70. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +32 -11
  71. package/dist/src/plugins/package-json/create-nodes.d.ts +2 -2
  72. package/dist/src/plugins/package-json/create-nodes.js +13 -13
  73. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +14 -0
  74. package/dist/src/project-graph/affected/affected-project-graph.js +5 -18
  75. package/dist/src/project-graph/affected/affected-projects.d.ts +7 -0
  76. package/dist/src/project-graph/affected/affected-projects.js +42 -0
  77. package/dist/src/project-graph/affected/affected-tasks.d.ts +90 -0
  78. package/dist/src/project-graph/affected/affected-tasks.js +214 -0
  79. package/dist/src/project-graph/file-utils.js +6 -2
  80. package/dist/src/project-graph/utils/project-configuration/target-merging.js +67 -0
  81. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +83 -0
  82. package/dist/src/project-graph/utils/project-configuration/utils.d.ts +1 -0
  83. package/dist/src/project-graph/utils/project-configuration/utils.js +1 -0
  84. package/dist/src/tasks-runner/create-task-graph.d.ts +24 -1
  85. package/dist/src/tasks-runner/create-task-graph.js +56 -2
  86. package/dist/src/tasks-runner/forked-process-task-runner.js +3 -3
  87. package/dist/src/tasks-runner/init-tasks-runner.d.ts +7 -2
  88. package/dist/src/tasks-runner/init-tasks-runner.js +17 -6
  89. package/dist/src/tasks-runner/run-command.d.ts +41 -5
  90. package/dist/src/tasks-runner/run-command.js +84 -18
  91. package/dist/src/tasks-runner/task-io-service.d.ts +11 -3
  92. package/dist/src/tasks-runner/task-io-service.js +14 -5
  93. package/dist/src/tasks-runner/task-orchestrator.js +1 -1
  94. package/dist/src/tasks-runner/utils.d.ts +5 -0
  95. package/dist/src/tasks-runner/utils.js +9 -0
  96. package/dist/src/utils/db-connection.d.ts +1 -0
  97. package/dist/src/utils/db-connection.js +1 -0
  98. package/dist/src/utils/json-diff.d.ts +4 -2
  99. package/dist/src/utils/json-diff.js +6 -94
  100. package/dist/src/utils/nx-cloud-utils.d.ts +2 -0
  101. package/dist/src/utils/nx-cloud-utils.js +6 -1
  102. package/dist/src/utils/project-graph-utils.d.ts +2 -0
  103. package/dist/src/utils/project-graph-utils.js +12 -0
  104. package/package.json +22 -13
  105. package/readme-template.md +16 -0
  106. package/schemas/nx-schema.json +34 -0
  107. package/schemas/project-schema.json +31 -0
  108. package/dist/src/project-graph/affected/locators/project-glob-changes.d.ts +0 -2
  109. package/dist/src/project-graph/affected/locators/project-glob-changes.js +0 -40
  110. package/dist/src/project-graph/affected/locators/workspace-json-changes.d.ts +0 -4
  111. package/dist/src/project-graph/affected/locators/workspace-json-changes.js +0 -47
  112. package/dist/src/project-graph/affected/locators/workspace-projects.d.ts +0 -3
  113. package/dist/src/project-graph/affected/locators/workspace-projects.js +0 -74
@@ -0,0 +1 @@
1
+ export { importIoSnapshots, openIoSnapshots } from './src/io-snapshots/store';
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ // Nx internals for the Nx Cloud client, loaded as `nx/nx-cloud-internals`; not
3
+ // a public API. The client probes these exports to tell what this nx supports,
4
+ // so keep them stable.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.openIoSnapshots = exports.importIoSnapshots = void 0;
7
+ var store_1 = require("./src/io-snapshots/store");
8
+ Object.defineProperty(exports, "importIoSnapshots", { enumerable: true, get: function () { return store_1.importIoSnapshots; } });
9
+ Object.defineProperty(exports, "openIoSnapshots", { enumerable: true, get: function () { return store_1.openIoSnapshots; } });
@@ -29,7 +29,7 @@ const plugin = {
29
29
  const patterns = (0, package_json_1.buildPackageJsonPatterns)(context.workspaceRoot, (f) => (0, fileutils_1.readJsonFile)((0, path_1.join)(context.workspaceRoot, f)));
30
30
  const isInPackageJsonWorkspaces = (0, package_json_1.buildPackageJsonWorkspacesMatcher)(patterns);
31
31
  const packageManagerCommand = (0, package_manager_1.getPackageManagerCommand)((0, package_manager_1.detectPackageManager)(context.workspaceRoot), context.workspaceRoot);
32
- const result = (0, plugins_1.createNodesFromFiles)((packageJsonPath) => (0, package_json_1.createNodeFromPackageJson)(packageJsonPath, workspace_root_1.workspaceRoot, cache, isInPackageJsonWorkspaces(packageJsonPath), packageManagerCommand), configFiles, options, context);
32
+ const result = (0, plugins_1.createNodesFromFiles)((packageJsonPath) => (0, package_json_1.createNodeFromPackageJson)(packageJsonPath, workspace_root_1.workspaceRoot, cache, isInPackageJsonWorkspaces(packageJsonPath), packageManagerCommand, context.nxJsonConfiguration), configFiles, options, context);
33
33
  writeCache();
34
34
  return result;
35
35
  },
@@ -14,6 +14,7 @@ const affected_project_graph_1 = require("../../project-graph/affected/affected-
14
14
  const configuration_1 = require("../../config/configuration");
15
15
  const find_matching_projects_1 = require("../../utils/find-matching-projects");
16
16
  const graph_1 = require("../graph/graph");
17
+ const affected_tasks_1 = require("../../project-graph/affected/affected-tasks");
17
18
  async function affected(command, args, extraTargetDependencies = {}, extraOptions = {
18
19
  excludeTaskDependencies: args.excludeTaskDependencies,
19
20
  loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false',
@@ -25,16 +26,47 @@ async function affected(command, args, extraTargetDependencies = {}, extraOption
25
26
  printWarnings: command !== 'print-affected' && !args.plain && args.graph !== 'stdout',
26
27
  }, nxJson);
27
28
  await (0, connect_to_nx_cloud_1.connectToNxCloudIfExplicitlyAsked)(nxArgs);
28
- const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({
29
- exitOnError: true,
30
- });
31
- const projects = await getAffectedGraphNodes(nxArgs, projectGraph);
29
+ // Task selection needs a target to select against, so `nx graph --affected`
30
+ // and the deprecated print-affected stay project-grained.
31
+ const useTasks = (0, affected_tasks_1.selectsAffectedTasks)() &&
32
+ command === 'affected' &&
33
+ !!nxArgs.targets?.length;
34
+ // Outside the try so errors reach handleErrors, as they did from inside runCommand.
35
+ let projectGraph;
36
+ let taskSelection;
37
+ let projects = [];
38
+ if (useTasks) {
39
+ ({ projectGraph, taskSelection } = await (0, affected_tasks_1.computeAffectedTasks)({
40
+ nxJson,
41
+ targets: nxArgs.targets,
42
+ touchedFiles: (0, file_utils_1.calculateFileChanges)((0, command_line_utils_1.parseFiles)(nxArgs).files, nxArgs),
43
+ fileChangeArgs: {
44
+ base: nxArgs.base,
45
+ head: nxArgs.head,
46
+ files: nxArgs.files,
47
+ },
48
+ configuration: nxArgs.configuration,
49
+ overrides,
50
+ extraTargetDependencies,
51
+ excludeTaskDependencies: extraOptions.excludeTaskDependencies,
52
+ exclude: nxArgs.exclude,
53
+ ...(await (0, run_command_1.runnerInputsForSelection)(nxArgs, nxJson)),
54
+ }));
55
+ }
56
+ else {
57
+ projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
58
+ projects = await getAffectedGraphNodes(nxArgs, projectGraph);
59
+ if (command === 'affected' && !nxArgs.graph) {
60
+ taskSelection = (0, run_command_1.selectTasksForProjects)(projectGraph, projectsWithTarget(projects, nxArgs), nxArgs, overrides, extraTargetDependencies, extraOptions.excludeTaskDependencies);
61
+ }
62
+ }
32
63
  try {
33
64
  switch (command) {
34
65
  case 'affected': {
35
- const projectsWithTarget = allProjectsWithTarget(projects, nxArgs);
36
66
  if (nxArgs.graph) {
37
- const projectNames = projectsWithTarget.map((t) => t.name);
67
+ const projectNames = useTasks
68
+ ? initiatingProjects(taskSelection)
69
+ : projectsWithTarget(projects, nxArgs);
38
70
  const file = (0, command_line_utils_1.readGraphFileFromGraphArg)(nxArgs);
39
71
  return await (0, graph_1.generateGraph)({
40
72
  watch: true,
@@ -45,10 +77,13 @@ async function affected(command, args, extraTargetDependencies = {}, extraOption
45
77
  (!nxArgs.projects || nxArgs.projects.length === 0),
46
78
  projects: projectNames,
47
79
  file,
80
+ taskSelection: taskSelection ??
81
+ (() => (0, run_command_1.selectTasksForProjects)(projectGraph, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions.excludeTaskDependencies)),
82
+ configuration: nxArgs.configuration,
48
83
  }, projectNames);
49
84
  }
50
85
  else {
51
- const status = await (0, run_command_1.runCommand)(projectsWithTarget, projectGraph, { nxJson }, nxArgs, overrides, null, extraTargetDependencies, extraOptions);
86
+ const status = await (0, run_command_1.runCommand)(taskSelection, projectGraph, { nxJson }, nxArgs, overrides, null, extraTargetDependencies, extraOptions);
52
87
  await output_1.output.drain();
53
88
  process.exit(status);
54
89
  }
@@ -74,8 +109,15 @@ async function getAffectedGraphNodes(nxArgs, projectGraph) {
74
109
  }
75
110
  return Object.values(affectedGraph.nodes);
76
111
  }
77
- function allProjectsWithTarget(projects, nxArgs) {
78
- return projects.filter((p) => nxArgs.targets.find((target) => (0, project_graph_utils_1.projectHasTarget)(p, target)));
112
+ function initiatingProjects(selection) {
113
+ return [
114
+ ...new Set(selection.initiatingTaskIds.map((id) => selection.taskGraph.tasks[id].target.project)),
115
+ ];
116
+ }
117
+ function projectsWithTarget(projects, nxArgs) {
118
+ return projects
119
+ .filter((p) => nxArgs.targets.find((target) => (0, project_graph_utils_1.projectHasTarget)(p, target)))
120
+ .map((p) => p.name);
79
121
  }
80
122
  function printError(e, verbose) {
81
123
  const bodyLines = [e.message];
@@ -1,5 +1,6 @@
1
1
  import { ProjectFileMap, ProjectGraph, ProjectGraphDependency, ProjectGraphProjectNode } from '../../config/project-graph';
2
2
  import { TaskGraph } from '../../config/task-graph';
3
+ import { type TaskSelection } from '../../tasks-runner/run-command';
3
4
  export interface GraphError {
4
5
  message: string;
5
6
  stack: string;
@@ -49,7 +50,37 @@ export declare function generateGraph(args: {
49
50
  focus?: string;
50
51
  exclude?: string[];
51
52
  affected?: boolean;
53
+ /**
54
+ * What the command would run for `targets`, or how to build it. A builder
55
+ * is only called where an output needs it, so the live graph can still
56
+ * open, and show the error, when the task graph cannot be built.
57
+ */
58
+ taskSelection?: TaskSelection | (() => TaskSelection);
59
+ /** The `-c` the tasks run with; their ids carry it. */
60
+ configuration?: string;
52
61
  }, affectedProjects: string[]): Promise<void>;
62
+ export interface TaskSelectionForGraph {
63
+ targets: string[];
64
+ configuration?: string;
65
+ taskIds: string[];
66
+ }
67
+ /**
68
+ * The selection applies only to a page asking for its exact targets with its configuration
69
+ * or none (the ids carry it); anything else would prune to nothing, so it is shown whole.
70
+ */
71
+ export declare function selectedFor(targets: string[], configuration: string | undefined, selection: TaskSelectionForGraph | undefined): {
72
+ configuration?: string;
73
+ taskIds?: string[];
74
+ };
75
+ /**
76
+ * The task graph to draw: the selection's own when it has one, otherwise built
77
+ * and, given ids, pruned to them. The live graph rebuilds per request, so it
78
+ * passes only ids.
79
+ */
80
+ export declare function taskGraphForSelection(build: () => TaskGraph, selection?: {
81
+ taskGraph?: TaskGraph;
82
+ taskIds?: string[];
83
+ }): TaskGraph;
53
84
  export declare function getExpandedTaskInputs(depGraphClientResponse: ProjectGraphClientResponse, expandedTaskInputsCache: Map<string, Record<string, string[]>>, taskId: string): Promise<Record<string, string[]>>;
54
85
  /**
55
86
  * The data type that `nx graph --file graph.json` or `nx build --graph graph.json` contains
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateGraph = generateGraph;
4
+ exports.selectedFor = selectedFor;
5
+ exports.taskGraphForSelection = taskGraphForSelection;
4
6
  exports.getExpandedTaskInputs = getExpandedTaskInputs;
5
7
  const tslib_1 = require("tslib");
6
8
  const crypto_1 = require("crypto");
@@ -22,6 +24,9 @@ const typescript_1 = require("../../plugins/js/utils/typescript");
22
24
  const operators_1 = require("../../project-graph/operators");
23
25
  const project_graph_1 = require("../../project-graph/project-graph");
24
26
  const create_task_graph_1 = require("../../tasks-runner/create-task-graph");
27
+ const utils_1 = require("../../tasks-runner/utils");
28
+ const run_command_1 = require("../../tasks-runner/run-command");
29
+ const project_graph_utils_1 = require("../../utils/project-graph-utils");
25
30
  const all_file_data_1 = require("../../utils/all-file-data");
26
31
  const command_line_utils_1 = require("../../utils/command-line-utils");
27
32
  const native_1 = require("../../native");
@@ -178,6 +183,17 @@ async function generateGraph(args, affectedProjects) {
178
183
  }
179
184
  }
180
185
  let prunedGraph = (0, operators_1.pruneExternalNodes)(rawGraph);
186
+ // `nx graph --targets` has no command to take a selection from, so it draws
187
+ // the projects' targets.
188
+ const jsonTaskSelection = () => args.targets?.length
189
+ ? (resolveSelection(args.taskSelection) ??
190
+ (0, run_command_1.selectTasksForProjects)(rawGraph, args.projects?.length
191
+ ? args.projects
192
+ : [...(0, project_graph_utils_1.runnableForTarget)(rawGraph.nodes, args.targets)], {
193
+ targets: args.targets,
194
+ configuration: args.configuration,
195
+ }, {}, {}, false))
196
+ : undefined;
181
197
  const projects = Object.values(prunedGraph.nodes);
182
198
  projects.sort((a, b) => {
183
199
  return a.name.localeCompare(b.name);
@@ -231,7 +247,7 @@ async function generateGraph(args, affectedProjects) {
231
247
  let html = (0, node_fs_1.readFileSync)((0, node_path_1.join)(__dirname, '../../core/graph/index.html'), 'utf-8');
232
248
  prunedGraph = filterGraph(prunedGraph, args.focus || null, excludePatterns);
233
249
  if (args.print || args.file === 'stdout') {
234
- console.log(JSON.stringify(await createJsonOutput(prunedGraph, rawGraph, args.projects, args.targets), null, 2));
250
+ console.log(JSON.stringify(await createJsonOutput(prunedGraph, rawGraph, jsonTaskSelection()), null, 2));
235
251
  await output_1.output.drain();
236
252
  await new Promise((res) => setImmediate(res));
237
253
  process.exit(0);
@@ -258,7 +274,7 @@ async function generateGraph(args, affectedProjects) {
258
274
  });
259
275
  const { projectGraphClientResponse } = await createProjectGraphAndSourceMapClientResponse(affectedProjects);
260
276
  const taskGraphClientResponse = args.targets
261
- ? await createTaskGraphForTargetsAndProjects(args.targets, args.projects)
277
+ ? await createTaskGraphForTargetsAndProjects(args.targets, args.projects, args.configuration, args.taskSelection)
262
278
  : await createTaskGraphClientResponse();
263
279
  const taskInputsReponse = await createExpandedTaskInputResponse(taskGraphClientResponse, projectGraphClientResponse);
264
280
  const environmentJs = buildEnvironmentJs(excludePatterns, args.watch, !!args.file && args.file.endsWith('html') ? 'build' : 'serve', projectGraphClientResponse, taskGraphClientResponse, taskInputsReponse, sourceMaps);
@@ -275,7 +291,7 @@ async function generateGraph(args, affectedProjects) {
275
291
  }
276
292
  else if (ext === '.json') {
277
293
  (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(fullFilePath), { recursive: true });
278
- const json = await createJsonOutput(prunedGraph, rawGraph, args.projects, args.targets);
294
+ const json = await createJsonOutput(prunedGraph, rawGraph, jsonTaskSelection());
279
295
  (0, fileutils_1.writeJsonFile)(fullFilePath, json);
280
296
  output_1.output.success({
281
297
  title: `JSON output created in ${fileFolderPath}`,
@@ -297,7 +313,13 @@ async function generateGraph(args, affectedProjects) {
297
313
  let app;
298
314
  let url;
299
315
  try {
300
- const result = await startServer(html, environmentJs, args.host || '127.0.0.1', args.port || 4211, args.watch, affectedProjects, args.focus, args.groupByFolder, excludePatterns);
316
+ const result = await startServer(html, environmentJs, args.host || '127.0.0.1', args.port || 4211, args.watch, affectedProjects, args.focus, args.groupByFolder, excludePatterns, typeof args.taskSelection === 'object' && args.taskSelection.taskIds
317
+ ? {
318
+ targets: args.targets,
319
+ configuration: args.configuration,
320
+ taskIds: args.taskSelection.taskIds,
321
+ }
322
+ : undefined);
301
323
  app = result.app;
302
324
  url = result.url;
303
325
  }
@@ -383,7 +405,7 @@ function findAvailablePort(startPort, host = '127.0.0.1') {
383
405
  });
384
406
  });
385
407
  }
386
- async function startServer(html, environmentJs, host, port = 4211, watchForChanges = true, affected = [], focus = null, groupByFolder = false, exclude = []) {
408
+ async function startServer(html, environmentJs, host, port = 4211, watchForChanges = true, affected = [], focus = null, groupByFolder = false, exclude = [], selection) {
387
409
  let unregisterFileWatcher;
388
410
  if (watchForChanges && !client_1.daemonClient.enabled()) {
389
411
  output_1.output.warn({
@@ -427,14 +449,15 @@ async function startServer(html, environmentJs, host, port = 4211, watchForChang
427
449
  if (sanitizePath === 'task-graph.json') {
428
450
  const projectsParam = parsedUrl.searchParams.get('projects');
429
451
  const targetsParam = parsedUrl.searchParams.get('targets');
430
- const configuration = parsedUrl.searchParams.get('configuration');
452
+ const configuration = parsedUrl.searchParams.get('configuration') || undefined;
431
453
  res.writeHead(200, { 'Content-Type': 'application/json' });
432
454
  if (targetsParam) {
433
455
  const targetNames = targetsParam.split(' ').filter(Boolean);
434
456
  const projectNames = projectsParam
435
457
  ? projectsParam.split(' ').filter(Boolean)
436
458
  : undefined;
437
- return res.end(JSON.stringify(await createTaskGraphForTargetsAndProjects(targetNames, projectNames, configuration)));
459
+ const request = selectedFor(targetNames, configuration, selection);
460
+ return res.end(JSON.stringify(await createTaskGraphForTargetsAndProjects(targetNames, projectNames, request.configuration, { taskIds: request.taskIds })));
438
461
  }
439
462
  // load all task graphs if there's no targets specified
440
463
  return res.end(JSON.stringify(await createTaskGraphClientResponse()));
@@ -726,7 +749,7 @@ async function createTaskGraphClientResponse(pruneExternal = false) {
726
749
  try {
727
750
  const taskGraph = (0, create_task_graph_1.createTaskGraph)(graph, {}, projects, targets, undefined, {});
728
751
  node_perf_hooks_1.performance.mark('task graph generation:end');
729
- const planner = new native_1.HashPlanner(nxJson, (0, native_1.transferProjectGraph)((0, transform_objects_1.transformProjectGraphForRust)(graph)));
752
+ const planner = new native_1.HashPlanner(nxJson, (0, transform_objects_1.transformProjectGraphForRust)(graph));
730
753
  node_perf_hooks_1.performance.mark('task hash plan generation:start');
731
754
  const taskIds = Object.keys(taskGraph.tasks);
732
755
  const plans = taskIds.length > 0 ? planner.getPlans(taskIds, taskGraph) : {};
@@ -774,10 +797,40 @@ function clearTaskGraphCache() {
774
797
  expandedTaskInputsCache.clear();
775
798
  }
776
799
  /**
777
- * Creates a single task graph for multiple projects with multiple targets
778
- * If no projects specified, returns graph for all projects with the targets
800
+ * The selection applies only to a page asking for its exact targets with its configuration
801
+ * or none (the ids carry it); anything else would prune to nothing, so it is shown whole.
802
+ */
803
+ function selectedFor(targets, configuration, selection) {
804
+ const applies = selection &&
805
+ targets.length === selection.targets.length &&
806
+ targets.every((target) => selection.targets.includes(target)) &&
807
+ (configuration === undefined || configuration === selection.configuration);
808
+ return applies
809
+ ? { configuration: selection.configuration, taskIds: selection.taskIds }
810
+ : { configuration };
811
+ }
812
+ function resolveSelection(selection) {
813
+ return typeof selection === 'function' ? selection() : selection;
814
+ }
815
+ /**
816
+ * The task graph to draw: the selection's own when it has one, otherwise built
817
+ * and, given ids, pruned to them. The live graph rebuilds per request, so it
818
+ * passes only ids.
819
+ */
820
+ function taskGraphForSelection(build, selection) {
821
+ if (selection?.taskGraph) {
822
+ return selection.taskGraph;
823
+ }
824
+ const taskGraph = build();
825
+ return selection?.taskIds
826
+ ? (0, utils_1.pruneToSelectedTasks)(taskGraph, selection.taskIds)
827
+ : taskGraph;
828
+ }
829
+ /**
830
+ * The task graph client response for `targetNames`: `selection`'s graph when given,
831
+ * else built for `projectNames` (default: every project with one of the targets).
779
832
  */
780
- async function createTaskGraphForTargetsAndProjects(targetNames, projectNames, configuration) {
833
+ async function createTaskGraphForTargetsAndProjects(targetNames, projectNames, configuration, selection) {
781
834
  // Get project graph
782
835
  let graph;
783
836
  try {
@@ -801,10 +854,11 @@ async function createTaskGraphForTargetsAndProjects(targetNames, projectNames, c
801
854
  .map(([projectName]) => projectName);
802
855
  }
803
856
  try {
804
- // Create single task graph
805
- const taskGraph = (0, create_task_graph_1.createTaskGraph)(graph, {}, projectsToUse, targetNames, configuration, {});
857
+ const taskGraph = taskGraphForSelection(() => (0, create_task_graph_1.createTaskGraph)(graph, {}, projectsToUse, targetNames, configuration, {}),
858
+ // Built in here, so an error is reported in the page like any other.
859
+ resolveSelection(selection));
806
860
  node_perf_hooks_1.performance.mark(`task graph generation:end`);
807
- const planner = new native_1.HashPlanner(nxJson, (0, native_1.transferProjectGraph)((0, transform_objects_1.transformProjectGraphForRust)(graph)));
861
+ const planner = new native_1.HashPlanner(nxJson, (0, transform_objects_1.transformProjectGraphForRust)(graph));
808
862
  node_perf_hooks_1.performance.mark('task hash plan generation:start');
809
863
  const taskIds = Object.keys(taskGraph.tasks);
810
864
  const plans = taskIds.length > 0 ? planner.getPlans(taskIds, taskGraph) : {};
@@ -982,12 +1036,12 @@ function getExpandedWorkspaceRoots(workspaceRootInputs, allWorkspaceFiles) {
982
1036
  workspaceRootsExpanded.sort();
983
1037
  return workspaceRootsExpanded;
984
1038
  }
985
- async function createJsonOutput(prunedGraph, rawGraph, projects, targets) {
1039
+ async function createJsonOutput(prunedGraph, rawGraph, taskSelection) {
986
1040
  const response = {
987
1041
  graph: prunedGraph,
988
1042
  };
989
- if (targets?.length) {
990
- const taskGraph = (0, create_task_graph_1.createTaskGraph)(rawGraph, {}, projects, targets, undefined, {});
1043
+ if (taskSelection) {
1044
+ const taskGraph = taskSelection.taskGraph;
991
1045
  const hasher = (0, create_task_hasher_1.createTaskHasher)(rawGraph, (0, configuration_1.readNxJson)());
992
1046
  let tasks = Object.values(taskGraph.tasks);
993
1047
  // Match the runtime path: each task is hashed against its own env so
@@ -181,6 +181,7 @@ async function runPublishOnProjects(args, projectGraph, nxJson, projectNames, ex
181
181
  targets: [requiredTargetName],
182
182
  projects: projectNamesWithTarget,
183
183
  file,
184
+ taskSelection: () => (0, run_command_1.selectTasksForProjects)(projectGraph, projectNamesWithTarget, { targets: [requiredTargetName] }, overrides, {}, extraOptions.excludeTaskDependencies),
184
185
  }, projectNamesWithTarget);
185
186
  return {};
186
187
  }
@@ -208,24 +209,19 @@ async function runPublishOnProjects(args, projectGraph, nxJson, projectNames, ex
208
209
  */
209
210
  process.env.NX_TUI = 'false';
210
211
  const publishOutputStyle = args.specifiedOutputStyle ?? 'static';
211
- const { taskResults } = await (0, run_command_1.runCommandForTasks)(projectsWithTarget, projectGraph, { nxJson }, {
212
+ const publishArgs = {
212
213
  targets: [requiredTargetName],
213
214
  ...args,
214
- // Everything this command reports — the registry, the tag, the
215
- // package.json diff, the dry-run summary — is printed from inside the
216
- // task, so the failures-only default would swallow all of it (under
217
- // --dry-run every task succeeds by definition). Set after the spread and
218
- // on all three fields: the middleware always writes `resolvedOutputStyle`,
219
- // so a value placed before it would be overwritten on every run, and the
220
- // renderer reads the new fields rather than the deprecated one. A style
221
- // the user actually named still wins, which is what `specifiedOutputStyle`
222
- // being set means.
215
+ // All output is printed from inside the task, so the failures-only default
216
+ // would hide it. Set after the spread, on all three fields: the middleware
217
+ // always writes `resolvedOutputStyle`.
223
218
  outputStyle: publishOutputStyle,
224
219
  specifiedOutputStyle: publishOutputStyle,
225
220
  resolvedOutputStyle: publishOutputStyle,
226
221
  // It is possible for workspaces to have circular dependencies between packages and still release them to a registry
227
222
  nxIgnoreCycles: true,
228
- }, overrides, null, {}, extraOptions);
223
+ };
224
+ const { taskResults } = await (0, run_command_1.runTasksForCommand)((0, run_command_1.selectTasksForProjects)(projectGraph, projectsWithTarget.map((p) => p.name), publishArgs, overrides, {}, extraOptions.excludeTaskDependencies), projectGraph, { nxJson }, publishArgs, overrides, null, {}, extraOptions);
229
225
  const endTime = Date.now();
230
226
  const publishProjectsResult = {};
231
227
  for (const taskData of Object.values(taskResults)) {
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createGetTouchedProjectsForGroup = createGetTouchedProjectsForGroup;
4
- const workspace_projects_1 = require("../../../project-graph/affected/locators/workspace-projects");
4
+ const native_1 = require("../../../native");
5
+ const transform_objects_1 = require("../../../native/transform-objects");
5
6
  const file_utils_1 = require("../../../project-graph/file-utils");
6
7
  const ignore_1 = require("../../../utils/ignore");
7
8
  const output_1 = require("../../../utils/output");
@@ -44,8 +45,7 @@ function createGetTouchedProjectsForGroup(nxArgs, projectGraph, changedFiles, fi
44
45
  touchedProjects = serializedIgnorePatternsToTouchedProjects.get(serializedIgnorePatterns);
45
46
  }
46
47
  else {
47
- // We only care about directly touched projects, not implicitly affected ones etc
48
- const touchedProjectsArr = await (0, workspace_projects_1.getTouchedProjects)((0, file_utils_1.calculateFileChanges)(changedFiles, nxArgs, undefined, ignore), projectGraph.nodes);
48
+ const touchedProjectsArr = (0, native_1.directlyTouchedProjects)((0, transform_objects_1.transformProjectGraphForLocators)(projectGraph), (0, file_utils_1.calculateFileChanges)(changedFiles, nxArgs, undefined, ignore).map((f) => f.file));
49
49
  touchedProjects = touchedProjectsArr.reduce((acc, project) => ({ ...acc, [project]: true }), {});
50
50
  serializedIgnorePatternsToTouchedProjects.set(serializedIgnorePatterns, touchedProjects);
51
51
  }
@@ -37,6 +37,8 @@ async function runOne(cwd, args, extraTargetDependencies = {}, extraOptions = {
37
37
  process.exit(0);
38
38
  }
39
39
  await (0, connect_to_nx_cloud_1.connectToNxCloudIfExplicitlyAsked)(nxArgs);
40
+ // --graph's file output draws this selection; the live graph builds its own.
41
+ const selectTasks = () => (0, run_command_1.selectTasksForProjects)(projectGraph, projects.map((p) => p.name), nxArgs, overrides, extraTargetDependencies, extraOptions.excludeTaskDependencies);
40
42
  if (nxArgs.graph) {
41
43
  const projectNames = projects.map((t) => t.name);
42
44
  const file = (0, command_line_utils_1.readGraphFileFromGraphArg)(nxArgs);
@@ -47,10 +49,12 @@ async function runOne(cwd, args, extraTargetDependencies = {}, extraOptions = {
47
49
  targets: nxArgs.targets,
48
50
  projects: projectNames,
49
51
  file,
52
+ taskSelection: selectTasks,
53
+ configuration: nxArgs.configuration,
50
54
  }, projectNames);
51
55
  }
52
56
  else {
53
- const status = await (0, run_command_1.runCommand)(projects, projectGraph, { nxJson }, nxArgs, overrides, projectName, extraTargetDependencies, extraOptions);
57
+ const status = await (0, run_command_1.runCommand)(selectTasks(), projectGraph, { nxJson }, nxArgs, overrides, projectName, extraTargetDependencies, extraOptions);
54
58
  await output_1.output.drain();
55
59
  process.exit(status);
56
60
  }
@@ -26,6 +26,8 @@ async function runMany(args, extraTargetDependencies = {}, extraOptions = {
26
26
  await (0, connect_to_nx_cloud_1.connectToNxCloudIfExplicitlyAsked)(nxArgs);
27
27
  const projectGraph = await (0, project_graph_1.createProjectGraphAsync)({ exitOnError: true });
28
28
  const projects = projectsToRun(nxArgs, projectGraph);
29
+ // --graph's file output draws this selection; the live graph builds its own.
30
+ const selectTasks = () => (0, run_command_1.selectTasksForProjects)(projectGraph, projects.map((p) => p.name), nxArgs, overrides, extraTargetDependencies, extraOptions.excludeTaskDependencies);
29
31
  if (nxArgs.graph) {
30
32
  const file = (0, command_line_utils_1.readGraphFileFromGraphArg)(nxArgs);
31
33
  const projectNames = projects.map((t) => t.name);
@@ -37,17 +39,19 @@ async function runMany(args, extraTargetDependencies = {}, extraOptions = {
37
39
  targets: nxArgs.targets,
38
40
  projects: projectNames,
39
41
  file,
42
+ taskSelection: selectTasks,
43
+ configuration: nxArgs.configuration,
40
44
  }, projectNames);
41
45
  }
42
46
  else {
43
- const status = await (0, run_command_1.runCommand)(projects, projectGraph, { nxJson }, nxArgs, overrides, null, extraTargetDependencies, extraOptions);
47
+ const status = await (0, run_command_1.runCommand)(selectTasks(), projectGraph, { nxJson }, nxArgs, overrides, null, extraTargetDependencies, extraOptions);
44
48
  await output_1.output.drain();
45
49
  process.exit(status);
46
50
  }
47
51
  }
48
52
  function projectsToRun(nxArgs, projectGraph) {
49
53
  const selectedProjects = {};
50
- const validProjects = runnableForTarget(projectGraph.nodes, nxArgs.targets);
54
+ const validProjects = (0, project_graph_utils_1.runnableForTarget)(projectGraph.nodes, nxArgs.targets);
51
55
  const invalidProjects = [];
52
56
  // --all is default now, if --projects is provided, it'll override the --all
53
57
  if (nxArgs.all && nxArgs.projects.length === 0) {
@@ -78,13 +82,3 @@ function projectsToRun(nxArgs, projectGraph) {
78
82
  }
79
83
  return Object.values(selectedProjects);
80
84
  }
81
- function runnableForTarget(projects, targets) {
82
- const runnable = new Set();
83
- for (let projectName in projects) {
84
- const project = projects[projectName];
85
- if (targets.find((target) => (0, project_graph_utils_1.projectHasTarget)(project, target))) {
86
- runnable.add(projectName);
87
- }
88
- }
89
- return runnable;
90
- }
@@ -4,6 +4,7 @@ exports.showProjectsHandler = showProjectsHandler;
4
4
  const output_1 = require("../../utils/output");
5
5
  const nx_json_1 = require("../../config/nx-json");
6
6
  const affected_project_graph_1 = require("../../project-graph/affected/affected-project-graph");
7
+ const affected_tasks_1 = require("../../project-graph/affected/affected-tasks");
7
8
  const file_utils_1 = require("../../project-graph/file-utils");
8
9
  const operators_1 = require("../../project-graph/operators");
9
10
  const project_graph_1 = require("../../project-graph/project-graph");
@@ -20,7 +21,31 @@ async function showProjectsHandler(args) {
20
21
  // Affected touches dependencies so it needs to be processed first.
21
22
  if (args.affected) {
22
23
  const touchedFiles = await getTouchedFiles(nxArgs);
23
- graph = await getAffectedGraph(touchedFiles, nxJson, graph);
24
+ // With a target, list projects owning an affected task for it, matching `affected -t`.
25
+ if ((0, affected_tasks_1.selectsAffectedTasks)() && args.withTarget?.length && !args.projects) {
26
+ const affectedTasks = await (0, affected_tasks_1.computeAffectedTasks)({
27
+ projectGraph: graph,
28
+ nxJson,
29
+ targets: args.withTarget,
30
+ touchedFiles,
31
+ fileChangeArgs: {
32
+ base: nxArgs.base,
33
+ head: nxArgs.head,
34
+ files: nxArgs.files,
35
+ },
36
+ ...(await runCommandModule().runnerInputsForSelection(nxArgs, nxJson)),
37
+ });
38
+ const { taskGraph, initiatingTaskIds } = affectedTasks.taskSelection;
39
+ const owning = new Set(initiatingTaskIds.map((id) => taskGraph.tasks[id].target.project));
40
+ // The graph selection ran against: with the daemon on, the daemon's, not `graph`.
41
+ graph = {
42
+ ...affectedTasks.projectGraph,
43
+ nodes: Object.fromEntries(Object.entries(affectedTasks.projectGraph.nodes).filter(([name]) => owning.has(name))),
44
+ };
45
+ }
46
+ else {
47
+ graph = await getAffectedGraph(touchedFiles, nxJson, graph);
48
+ }
24
49
  }
25
50
  const filter = (0, operators_1.filterNodes)((node) => {
26
51
  if (args.type && node.type !== args.type) {
@@ -78,3 +103,7 @@ function getAffectedGraph(touchedFiles, nxJson, graph) {
78
103
  async function getTouchedFiles(nxArgs) {
79
104
  return (0, file_utils_1.calculateFileChanges)((0, command_line_utils_1.parseFiles)(nxArgs).files, nxArgs);
80
105
  }
106
+ /** Loaded only when task selection needs it. */
107
+ function runCommandModule() {
108
+ return require('../../tasks-runner/run-command');
109
+ }
@@ -3,4 +3,4 @@
3
3
  * `packages/nx/src/native/tasks/types.rs` and exposed to TypeScript via NAPI.
4
4
  * This file re-exports them so existing imports keep working.
5
5
  */
6
- export type { Task, TaskGraph, TaskTarget, TaskHashDetails } from '../native';
6
+ export type { Task, TaskGraph, TaskTarget, TaskHashDetails, TaskUltracacheConfiguration, } from '../native';
@@ -1,4 +1,4 @@
1
- import type { JsonInput } from '../native';
1
+ import type { JsonInput, TaskUltracacheConfiguration } from '../native';
2
2
  import type { PackageJson } from '../utils/package-json';
3
3
  import type { NxJsonConfiguration, NxReleaseDockerConfiguration, NxReleaseVersionConfiguration } from './nx-json';
4
4
  /**
@@ -147,6 +147,22 @@ export interface TargetMetadata {
147
147
  };
148
148
  };
149
149
  }
150
+ /**
151
+ * Authoring form of a property merged key-by-key: permits the `'...'` spread
152
+ * token alongside the resolved keys. Merging resolves the token, so it never
153
+ * appears on the resolved shape.
154
+ */
155
+ export type Spreadable<T> = T & {
156
+ '...'?: true;
157
+ };
158
+ /**
159
+ * Ultracache configuration for a target's tasks.
160
+ *
161
+ * The resolved shape rides on each Task instance (`Task['ultracache']`), which
162
+ * is why it is shared with the native task definition. Authoring additionally
163
+ * permits `'...'`, which target merging resolves away.
164
+ */
165
+ export type TargetUltracacheConfiguration = Spreadable<TaskUltracacheConfiguration>;
150
166
  export interface TargetDependencyConfig {
151
167
  /**
152
168
  * A list of projects that have `target`.
@@ -244,6 +260,10 @@ export interface TargetConfiguration<T = any> {
244
260
  * Determines if Nx is able to cache a given target.
245
261
  */
246
262
  cache?: boolean;
263
+ /**
264
+ * Configures ultracache for tasks of this target. Nx Cloud only.
265
+ */
266
+ ultracache?: TargetUltracacheConfiguration;
247
267
  /**
248
268
  * Metadata about the target
249
269
  */