nx 23.1.0 → 23.1.2

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 (223) hide show
  1. package/dist/bin/nx.js +2 -1
  2. package/dist/release/changelog-renderer/index.js +4 -5
  3. package/dist/release/index.d.ts +1 -1
  4. package/dist/src/ai/configure-ai-agents-disclaimer.d.ts +5 -0
  5. package/dist/src/ai/configure-ai-agents-disclaimer.js +31 -0
  6. package/dist/src/analytics/analytics.d.ts +6 -0
  7. package/dist/src/analytics/analytics.js +16 -8
  8. package/dist/src/analytics/index.d.ts +1 -1
  9. package/dist/src/analytics/index.js +2 -1
  10. package/dist/src/command-line/add/add.js +13 -1
  11. package/dist/src/command-line/affected/affected.js +1 -0
  12. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
  13. package/dist/src/command-line/graph/graph.d.ts +1 -0
  14. package/dist/src/command-line/graph/graph.js +15 -6
  15. package/dist/src/command-line/import/import.js +2 -3
  16. package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
  17. package/dist/src/command-line/init/ai-agent-prompts.js +7 -6
  18. package/dist/src/command-line/init/command-object.js +10 -2
  19. package/dist/src/command-line/init/configure-plugins.js +3 -2
  20. package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +4 -2
  21. package/dist/src/command-line/init/implementation/add-nx-to-nest.js +4 -3
  22. package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +4 -3
  23. package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +4 -3
  24. package/dist/src/command-line/init/implementation/angular/index.js +4 -2
  25. package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
  26. package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
  27. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
  28. package/dist/src/command-line/init/implementation/utils.d.ts +3 -3
  29. package/dist/src/command-line/init/implementation/utils.js +22 -3
  30. package/dist/src/command-line/init/init-v2.js +4 -5
  31. package/dist/src/command-line/migrate/execute-migration.d.ts +72 -0
  32. package/dist/src/command-line/migrate/execute-migration.js +389 -0
  33. package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
  34. package/dist/src/command-line/migrate/migrate.d.ts +5 -45
  35. package/dist/src/command-line/migrate/migrate.js +122 -402
  36. package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +1 -1
  37. package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
  38. package/dist/src/command-line/release/changelog.js +5 -0
  39. package/dist/src/command-line/release/index.d.ts +1 -1
  40. package/dist/src/command-line/release/utils/git.js +7 -3
  41. package/dist/src/command-line/release/utils/release-graph.d.ts +19 -2
  42. package/dist/src/command-line/release/utils/release-graph.js +71 -19
  43. package/dist/src/command-line/release/utils/remote-release-clients/github.js +7 -1
  44. package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +1 -1
  45. package/dist/src/command-line/release/utils/shared.d.ts +2 -2
  46. package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
  47. package/dist/src/command-line/release/version/release-group-processor.js +80 -6
  48. package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
  49. package/dist/src/command-line/release/version/version-actions.js +9 -1
  50. package/dist/src/command-line/release/version.js +9 -5
  51. package/dist/src/command-line/reset/reset.js +6 -1
  52. package/dist/src/command-line/run/run-one.js +1 -0
  53. package/dist/src/command-line/run-many/run-many.js +1 -0
  54. package/dist/src/command-line/show/show-target/info.js +11 -2
  55. package/dist/src/command-line/show/show-target/inputs.js +50 -153
  56. package/dist/src/command-line/show/show-target/outputs.js +48 -173
  57. package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
  58. package/dist/src/command-line/show/show-target/utils.js +83 -3
  59. package/dist/src/command-line/watch/watch.js +13 -0
  60. package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  61. package/dist/src/commands-runner/create-command-graph.js +5 -0
  62. package/dist/src/config/nx-json.d.ts +5 -3
  63. package/dist/src/core/graph/main.js +1 -1
  64. package/dist/src/core/graph/styles.js +1 -1
  65. package/dist/src/daemon/client/client.d.ts +52 -3
  66. package/dist/src/daemon/client/client.js +177 -55
  67. package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
  68. package/dist/src/daemon/client/daemon-environment.js +110 -2
  69. package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
  70. package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
  71. package/dist/src/daemon/message-types/daemon-message.js +25 -0
  72. package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
  73. package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
  74. package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
  75. package/dist/src/daemon/server/latest-nx.js +5 -2
  76. package/dist/src/daemon/server/server.js +31 -4
  77. package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
  78. package/dist/src/daemon/server/shutdown-utils.js +11 -4
  79. package/dist/src/daemon/socket-utils.d.ts +1 -0
  80. package/dist/src/daemon/socket-utils.js +24 -3
  81. package/dist/src/daemon/tmp-dir.d.ts +43 -3
  82. package/dist/src/daemon/tmp-dir.js +437 -15
  83. package/dist/src/devkit-internals.d.ts +96 -3
  84. package/dist/src/devkit-internals.js +200 -4
  85. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
  86. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
  87. package/dist/src/generators/tree.d.ts +4 -2
  88. package/dist/src/generators/utils/nx-json.js +13 -3
  89. package/dist/src/hasher/check-task-files.d.ts +86 -0
  90. package/dist/src/hasher/check-task-files.js +378 -0
  91. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  92. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  93. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  94. package/dist/src/native/index.d.ts +31 -2
  95. package/dist/src/native/index.js +71 -28
  96. package/dist/src/native/native-bindings.js +3 -0
  97. package/dist/src/native/native-file-cache-location.d.ts +17 -1
  98. package/dist/src/native/native-file-cache-location.js +86 -12
  99. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  100. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  101. package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
  102. package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
  103. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  104. package/dist/src/plugins/js/lock-file/npm-parser.js +71 -27
  105. package/dist/src/plugins/js/lock-file/pnpm-parser.js +110 -17
  106. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +15 -9
  107. package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
  108. package/dist/src/plugins/js/lock-file/yarn-parser.js +32 -5
  109. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
  110. package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +14 -4
  111. package/dist/src/plugins/js/utils/register.d.ts +18 -0
  112. package/dist/src/plugins/js/utils/register.js +81 -0
  113. package/dist/src/plugins/js/utils/typescript.d.ts +9 -0
  114. package/dist/src/plugins/js/utils/typescript.js +15 -0
  115. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
  116. package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
  117. package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
  118. package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
  119. package/dist/src/project-graph/build-project-graph.js +7 -1
  120. package/dist/src/project-graph/error-types.d.ts +12 -1
  121. package/dist/src/project-graph/error-types.js +68 -3
  122. package/dist/src/project-graph/file-utils.js +6 -1
  123. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
  124. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +22 -1
  125. package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
  126. package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
  127. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
  128. package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
  129. package/dist/src/project-graph/plugins/transpiler.js +4 -0
  130. package/dist/src/project-graph/project-graph.js +23 -0
  131. package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +10 -12
  132. package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +93 -63
  133. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +5 -8
  134. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +16 -15
  135. package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +12 -5
  136. package/dist/src/project-graph/utils/project-configuration/source-maps.js +21 -7
  137. package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +1 -1
  138. package/dist/src/project-graph/utils/project-configuration/target-defaults.js +26 -27
  139. package/dist/src/project-graph/utils/project-configuration/target-merging.js +50 -8
  140. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +149 -6
  141. package/dist/src/project-graph/utils/project-configuration/utils.d.ts +15 -0
  142. package/dist/src/project-graph/utils/project-configuration/utils.js +42 -6
  143. package/dist/src/project-graph/utils/project-configuration-utils.d.ts +15 -12
  144. package/dist/src/project-graph/utils/project-configuration-utils.js +79 -101
  145. package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +11 -4
  146. package/dist/src/tasks-runner/life-cycles/performance-analysis.js +15 -6
  147. package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
  148. package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +18 -8
  149. package/dist/src/tasks-runner/life-cycles/performance-report.js +66 -29
  150. package/dist/src/tasks-runner/run-command.js +4 -2
  151. package/dist/src/tasks-runner/task-env.d.ts +9 -0
  152. package/dist/src/tasks-runner/task-env.js +31 -4
  153. package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
  154. package/dist/src/tasks-runner/task-orchestrator.js +23 -10
  155. package/dist/src/tasks-runner/utils.js +2 -6
  156. package/dist/src/utils/acknowledge-build-scripts.d.ts +13 -0
  157. package/dist/src/utils/acknowledge-build-scripts.js +102 -0
  158. package/dist/src/utils/analytics-prompt.d.ts +0 -6
  159. package/dist/src/utils/analytics-prompt.js +0 -51
  160. package/dist/src/utils/assert-workspace-validity.js +7 -2
  161. package/dist/src/utils/catalog/manager-utils.d.ts +1 -2
  162. package/dist/src/utils/catalog/manager-utils.js +22 -5
  163. package/dist/src/utils/catalog/pnpm-manager.d.ts +1 -0
  164. package/dist/src/utils/catalog/pnpm-manager.js +3 -15
  165. package/dist/src/utils/catalog/yarn-manager.d.ts +1 -0
  166. package/dist/src/utils/catalog/yarn-manager.js +3 -15
  167. package/dist/src/utils/command-line-utils.js +30 -20
  168. package/dist/src/utils/fileutils.d.ts +5 -0
  169. package/dist/src/utils/fileutils.js +7 -2
  170. package/dist/src/utils/git-revision.d.ts +12 -0
  171. package/dist/src/utils/git-revision.js +25 -0
  172. package/dist/src/utils/git-utils.d.ts +16 -3
  173. package/dist/src/utils/git-utils.js +146 -52
  174. package/dist/src/utils/git-worktrees.d.ts +30 -0
  175. package/dist/src/utils/git-worktrees.js +212 -0
  176. package/dist/src/utils/ignore.d.ts +128 -1
  177. package/dist/src/utils/ignore.js +182 -12
  178. package/dist/src/utils/long-running-target.d.ts +10 -0
  179. package/dist/src/utils/long-running-target.js +19 -0
  180. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  181. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  182. package/dist/src/utils/min-release-age/behavior/pnpm.js +9 -7
  183. package/dist/src/utils/min-release-age/packument.js +1 -1
  184. package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
  185. package/dist/src/utils/nx-tmp-dir.js +40 -0
  186. package/dist/src/utils/owned-private-dir.d.ts +132 -0
  187. package/dist/src/utils/owned-private-dir.js +323 -0
  188. package/dist/src/utils/package-json.js +11 -7
  189. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  190. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  191. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  192. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  193. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  194. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  195. package/dist/src/utils/package-manager.d.ts +23 -2
  196. package/dist/src/utils/package-manager.js +264 -43
  197. package/dist/src/utils/provenance.js +18 -16
  198. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  199. package/dist/src/utils/registry-config/bun.js +257 -0
  200. package/dist/src/utils/registry-config/index.d.ts +13 -0
  201. package/dist/src/utils/registry-config/index.js +102 -0
  202. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  203. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  204. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  205. package/dist/src/utils/registry-config/utils.js +496 -0
  206. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  207. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  208. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  209. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  210. package/dist/src/utils/safe-spawn.d.ts +24 -0
  211. package/dist/src/utils/safe-spawn.js +104 -0
  212. package/dist/src/utils/shell-quoting.d.ts +15 -0
  213. package/dist/src/utils/shell-quoting.js +35 -0
  214. package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
  215. package/dist/src/utils/wait-for-socket-connection.js +14 -8
  216. package/dist/src/utils/workspace-id.d.ts +20 -0
  217. package/dist/src/utils/workspace-id.js +54 -0
  218. package/migrations.json +13 -1
  219. package/package.json +22 -17
  220. package/dist/src/migrations/update-17-3-0/nx-release-path.d.ts +0 -3
  221. package/dist/src/migrations/update-17-3-0/nx-release-path.js +0 -47
  222. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  223. package/dist/src/utils/min-release-age/npmrc.js +0 -45
@@ -7,6 +7,7 @@ node_perf_hooks_1.performance.mark(`plugin worker ${process.pid} code loading --
7
7
  const consume_messages_from_socket_1 = require("../../../utils/consume-messages-from-socket");
8
8
  const logger_1 = require("../../../utils/logger");
9
9
  const serializable_error_1 = require("../../../utils/serializable-error");
10
+ const daemon_message_1 = require("../../../daemon/message-types/daemon-message");
10
11
  const messaging_1 = require("./messaging");
11
12
  const worker_streaming_1 = require("./worker-streaming");
12
13
  const fs_1 = require("fs");
@@ -23,6 +24,19 @@ global.NX_PLUGIN_WORKER = true;
23
24
  let plugin;
24
25
  const socketPath = process.argv[2];
25
26
  const expectedPluginName = process.argv[3];
27
+ // The host's root, passed explicitly rather than re-resolved: a host that set
28
+ // its root at runtime would resolve a different one here and drop every
29
+ // legitimate message as foreign.
30
+ const hostWorkspaceRoot = process.argv[4];
31
+ // Positional, so inserting an argument host-side shifts all of them — and the
32
+ // symptom is silent and total: an undefined hostWorkspaceRoot makes every
33
+ // message look foreign while the host waits out its plugin timeout.
34
+ if (!socketPath || !expectedPluginName || !hostWorkspaceRoot) {
35
+ console.error(`[plugin-worker] started with an incomplete argument list ` +
36
+ `(socketPath=${socketPath}, pluginName=${expectedPluginName}, hostWorkspaceRoot=${hostWorkspaceRoot}). ` +
37
+ `This is an Nx bug — please report it at https://github.com/nrwl/nx/issues.`);
38
+ process.exit(1);
39
+ }
26
40
  const CONNECT_TIMEOUT_MS = 30_000;
27
41
  let connectErrorTimeout = setErrorTimeout(CONNECT_TIMEOUT_MS, `The plugin worker for ${expectedPluginName} is exiting as it was not connected to within ${CONNECT_TIMEOUT_MS / 1000} seconds. ` +
28
42
  'Plugin workers expect to receive a socket connection from the parent process shortly after being started. ' +
@@ -45,6 +59,16 @@ const server = (0, net_1.createServer)((socket) => {
45
59
  if (!(0, messaging_1.isPluginWorkerMessage)(message)) {
46
60
  return;
47
61
  }
62
+ // Same check the daemon applies to its own socket. Dropped rather than thrown:
63
+ // a stray foreign message must not kill a worker serving its host. The daemon
64
+ // has a response channel and surfaces it to the client instead.
65
+ try {
66
+ (0, daemon_message_1.assertNotForeignWorkspaceMessage)(message, hostWorkspaceRoot, `The Nx plugin worker "${expectedPluginName}" (pid: ${process.pid})`);
67
+ }
68
+ catch (e) {
69
+ logger_1.logger.verbose(`[plugin-worker] ignored a "${message.type}" message: ${e instanceof Error ? e.message : e}`);
70
+ return;
71
+ }
48
72
  return (0, messaging_1.consumeMessage)(socket, message, {
49
73
  load: async ({ plugin: pluginConfiguration, root, name, pluginPath, shouldRegisterTSTranspiler, }) => {
50
74
  loadErrorTimeout?.clear();
@@ -104,8 +128,24 @@ const server = (0, net_1.createServer)((socket) => {
104
128
  process.exit(0);
105
129
  });
106
130
  });
107
- server.listen(socketPath);
108
- logger_1.logger.verbose(`[plugin-worker] "${expectedPluginName}" (pid: ${process.pid}) listening on ${socketPath}`);
131
+ server.on('error', (err) => {
132
+ // Without this the host only sees "exited before the connection was
133
+ // established"; the errno distinguishes a denied bind from EADDRINUSE.
134
+ console.error(`[plugin-worker] "${expectedPluginName}" (pid: ${process.pid}) failed to listen on ${socketPath}: ${err.message}`);
135
+ process.exit(1);
136
+ });
137
+ // A worker killed without its 'end' handler leaves the socket behind. Colliding
138
+ // takes a recycled host pid landing on the same counter *and* the same 4 random
139
+ // bytes; the random component is what this unlink rests on, and on Windows it is
140
+ // the only barrier, since the endpoint is a namespace object and the mode never
141
+ // applies. A failed bind surfaces through the error handler above.
142
+ try {
143
+ (0, fs_1.unlinkSync)(socketPath);
144
+ }
145
+ catch { }
146
+ server.listen(socketPath, () => {
147
+ logger_1.logger.verbose(`[plugin-worker] "${expectedPluginName}" (pid: ${process.pid}) listening on ${socketPath}`);
148
+ });
109
149
  async function withErrorHandling(cb) {
110
150
  try {
111
151
  const result = await cb();
@@ -136,15 +176,25 @@ function setErrorTimeout(timeoutMs, errorMessage) {
136
176
  },
137
177
  };
138
178
  }
139
- const exitHandler = (exitCode) => () => {
179
+ const cleanup = () => {
140
180
  server.close();
141
181
  try {
142
182
  (0, fs_1.unlinkSync)(socketPath);
143
183
  }
144
184
  catch (e) { }
145
- process.exit(exitCode);
146
185
  };
147
- const events = ['SIGINT', 'SIGTERM', 'SIGQUIT', 'exit'];
148
- events.forEach((event) => process.once(event, exitHandler(0)));
149
- process.once('uncaughtException', exitHandler(1));
150
- process.once('unhandledRejection', exitHandler(1));
186
+ const events = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
187
+ events.forEach((event) => process.once(event, () => {
188
+ cleanup();
189
+ process.exit(0);
190
+ }));
191
+ // Cleanup only: process.exit() here would override the real exit code.
192
+ process.once('exit', cleanup);
193
+ const fatalHandler = (error) => {
194
+ // Registering this handler suppresses Node's default reporting.
195
+ console.error(error);
196
+ cleanup();
197
+ process.exit(1);
198
+ };
199
+ process.once('uncaughtException', fatalHandler);
200
+ process.once('unhandledRejection', fatalHandler);
@@ -63,6 +63,7 @@ class LoadedNxPlugin {
63
63
  track: true,
64
64
  ...(analytics_1.customDimensions && {
65
65
  [analytics_1.customDimensions.projectCount]: projectCount,
66
+ [analytics_1.customDimensions.sampleRate]: analytics_1.PERF_SPAN_SAMPLE_RATE,
66
67
  }),
67
68
  },
68
69
  });
@@ -25,6 +25,10 @@ function registerPluginTSTranspiler() {
25
25
  if (exports.unregisterPluginTSTranspiler !== null) {
26
26
  return;
27
27
  }
28
+ // Align Node's runtime resolution with the source-first plugin entry so the
29
+ // plugin's transitive workspace imports don't fall through to unbuilt `dist`.
30
+ // A no-op inside a plugin worker/daemon already spawned with `--conditions`.
31
+ (0, register_1.ensureResolveConditionsInjected)((0, typescript_1.getRootTsConfigResolveExportsConditions)(workspace_root_1.workspaceRoot));
28
32
  if ((0, register_1.isNativeStripPreferred)()) {
29
33
  // Native strip handles `.ts` syntax but doesn't rewrite NodeNext-style
30
34
  // `.js` relative specifiers to their `.ts` sources. Patch the CJS resolver
@@ -244,6 +244,7 @@ async function createProjectGraphAndSourceMapsAsync(opts = {
244
244
  track: true,
245
245
  ...(analytics_1.customDimensions && {
246
246
  [analytics_1.customDimensions.projectCount]: Object.keys(currentProjectGraph.nodes).length,
247
+ [analytics_1.customDimensions.sampleRate]: analytics_1.PERF_SPAN_SAMPLE_RATE,
247
248
  }),
248
249
  },
249
250
  });
@@ -310,6 +311,7 @@ async function createProjectGraphAndSourceMapsAsync(opts = {
310
311
  ...(analytics_1.customDimensions && {
311
312
  [analytics_1.customDimensions.projectCount]: Object.keys(res.projectGraph.nodes)
312
313
  .length,
314
+ [analytics_1.customDimensions.sampleRate]: analytics_1.PERF_SPAN_SAMPLE_RATE,
313
315
  }),
314
316
  },
315
317
  });
@@ -333,6 +335,7 @@ async function createProjectGraphAndSourceMapsAsync(opts = {
333
335
  track: true,
334
336
  ...(analytics_1.customDimensions && {
335
337
  [analytics_1.customDimensions.projectCount]: Object.keys(projectGraphAndSourceMaps.projectGraph.nodes).length,
338
+ [analytics_1.customDimensions.sampleRate]: analytics_1.PERF_SPAN_SAMPLE_RATE,
336
339
  }),
337
340
  },
338
341
  });
@@ -351,6 +354,26 @@ async function createProjectGraphAndSourceMapsAsync(opts = {
351
354
  (0, tmp_dir_1.markDaemonAsDisabled)(e.message);
352
355
  return buildProjectGraphAndSourceMapsWithoutDaemon();
353
356
  }
357
+ if (e.daemonPermissionError) {
358
+ // Deliberately not disabled: unlike the inotify limit above, a socket
359
+ // owned by someone else stops being there when it is removed or the
360
+ // machine reboots, and disabling until `nx reset` would outlive the
361
+ // cause and hide the fix from anyone who followed the advice.
362
+ // The first line carries the errno, and it is the one token that tells
363
+ // the two causes apart: EACCES is a socket owned by someone else (delete
364
+ // it), EPERM is a sandbox refusing the connect syscall (allow unix
365
+ // sockets under the Nx socket root). The message hedges between exactly
366
+ // those two because it cannot tell them apart, and this branch does not
367
+ // call writeDaemonLogs, so dropping the line loses the errno for good.
368
+ const [summary, ...details] = e.message.split('\n');
369
+ output_1.output.note({
370
+ title: `${summary} Continuing without the daemon.`,
371
+ // The blank line after the summary separates paragraphs when the
372
+ // message is printed as one blob; as bodyLines it is a leading gap.
373
+ bodyLines: details[0] === '' ? details.slice(1) : details,
374
+ });
375
+ return buildProjectGraphAndSourceMapsWithoutDaemon();
376
+ }
354
377
  if (e.internalDaemonError) {
355
378
  const errorLogFile = (0, tmp_dir_1.writeDaemonLogs)(e.message);
356
379
  output_1.output.warn({
@@ -4,16 +4,13 @@ import { ProjectConfiguration } from '../../../config/workspace-json-project-jso
4
4
  * reference. `RootRef` carries the referenced project's root (resolved
5
5
  * via nameMap lookup); `UsageRef` carries the raw written name (for
6
6
  * forward refs, promoted to `RootRef` in place when the name is
7
- * identified). `parent` + `key` let the final pass write the resolved
8
- * name back; `targetPart` preserves the `:target` suffix from
7
+ * identified). `targetPart` preserves the `:target` suffix from
9
8
  * `dependsOn` strings.
10
9
  */
11
10
  export declare abstract class NameRef {
12
11
  value: string;
13
- parent: unknown;
14
- key: string | undefined;
15
12
  targetPart: string | undefined;
16
- constructor(value: string, parent: unknown, key: string | undefined, targetPart: string | undefined);
13
+ constructor(value: string, targetPart: string | undefined);
17
14
  }
18
15
  export declare class RootRef extends NameRef {
19
16
  }
@@ -27,16 +24,17 @@ export declare function isUsageRef(value: unknown): value is UsageRef;
27
24
  * then resolves them after all merging is done.
28
25
  *
29
26
  * Tracking by array position breaks once `'...'` spreads shuffle indices,
30
- * so each ref becomes a sentinel object. Arrays spread-merge by pushing
31
- * element references, so sentinel identity survives any downstream
32
- * merges — the final pass walks a flat registry and writes the resolved
33
- * name back through each sentinel's `parent` back-reference. Orphaned
34
- * sentinels (from arrays dropped by a full-replace) write harmlessly.
27
+ * so each ref becomes a sentinel object. Merges copy sentinels by
28
+ * reference — one sentinel can end up in many arrays (e.g. a pattern
29
+ * target's dependsOn applied to every matching target) — so the final
30
+ * pass sweeps the merged rootMap and resolves every sentinel where it
31
+ * actually sits. Sentinels in arrays dropped by a full-replace are never
32
+ * visited and vanish with their array.
35
33
  */
36
34
  export declare class ProjectNameInNodePropsManager {
37
35
  private getNameMap;
38
- private allRefs;
39
36
  private pendingByName;
37
+ private nameHistory;
40
38
  constructor(getNameMap?: () => Record<string, ProjectConfiguration>);
41
39
  registerNameRefs(pluginResultProjects?: Record<string, Omit<ProjectConfiguration, 'root'> & Partial<ProjectConfiguration>>): void;
42
40
  private processInputs;
@@ -45,6 +43,6 @@ export declare class ProjectNameInNodePropsManager {
45
43
  private createRef;
46
44
  identifyProjectWithRoot(root: string, name: string): void;
47
45
  applySubstitutions(rootMap: Record<string, ProjectConfiguration>): void;
46
+ private substituteInArray;
48
47
  private resolveFinalName;
49
- private writeReplacement;
50
48
  }
@@ -11,15 +11,12 @@ const split_target_1 = require("../../../utils/split-target");
11
11
  * reference. `RootRef` carries the referenced project's root (resolved
12
12
  * via nameMap lookup); `UsageRef` carries the raw written name (for
13
13
  * forward refs, promoted to `RootRef` in place when the name is
14
- * identified). `parent` + `key` let the final pass write the resolved
15
- * name back; `targetPart` preserves the `:target` suffix from
14
+ * identified). `targetPart` preserves the `:target` suffix from
16
15
  * `dependsOn` strings.
17
16
  */
18
17
  class NameRef {
19
- constructor(value, parent, key, targetPart) {
18
+ constructor(value, targetPart) {
20
19
  this.value = value;
21
- this.parent = parent;
22
- this.key = key;
23
20
  this.targetPart = targetPart;
24
21
  }
25
22
  }
@@ -44,16 +41,19 @@ function isUsageRef(value) {
44
41
  * then resolves them after all merging is done.
45
42
  *
46
43
  * Tracking by array position breaks once `'...'` spreads shuffle indices,
47
- * so each ref becomes a sentinel object. Arrays spread-merge by pushing
48
- * element references, so sentinel identity survives any downstream
49
- * merges — the final pass walks a flat registry and writes the resolved
50
- * name back through each sentinel's `parent` back-reference. Orphaned
51
- * sentinels (from arrays dropped by a full-replace) write harmlessly.
44
+ * so each ref becomes a sentinel object. Merges copy sentinels by
45
+ * reference — one sentinel can end up in many arrays (e.g. a pattern
46
+ * target's dependsOn applied to every matching target) — so the final
47
+ * pass sweeps the merged rootMap and resolves every sentinel where it
48
+ * actually sits. Sentinels in arrays dropped by a full-replace are never
49
+ * visited and vanish with their array.
52
50
  */
53
51
  class ProjectNameInNodePropsManager {
54
52
  constructor(getNameMap) {
55
- this.allRefs = new Set();
56
53
  this.pendingByName = new Map();
54
+ // name → root for every name a project has ever been identified by, so refs
55
+ // to a since-renamed name still bind to the right root (see createRef).
56
+ this.nameHistory = new Map();
57
57
  this.getNameMap = getNameMap ?? (() => ({}));
58
58
  }
59
59
  // Replaces each project-name ref in `inputs`/`dependsOn` with a sentinel.
@@ -82,26 +82,20 @@ class ProjectNameInNodePropsManager {
82
82
  processInputs(inputs) {
83
83
  for (let i = 0; i < inputs.length; i++) {
84
84
  const entry = inputs[i];
85
- // Existing sentinel: spread merges may have copied it out of its
86
- // original array, so rebind parent to this one.
87
- if (isNameRef(entry)) {
88
- entry.parent = inputs;
85
+ if (isNameRef(entry))
89
86
  continue;
90
- }
91
87
  if (!entry || typeof entry !== 'object')
92
88
  continue;
93
89
  if (!('projects' in entry))
94
90
  continue;
95
91
  const element = entry;
96
92
  const projects = element.projects;
97
- if (isNameRef(projects)) {
98
- // Object-parent sentinel — element identity is stable across spread.
93
+ if (isNameRef(projects))
99
94
  continue;
100
- }
101
95
  if (typeof projects === 'string') {
102
96
  if (projects === 'self' || projects === 'dependencies')
103
97
  continue;
104
- element.projects = this.createRef(projects, element, 'projects');
98
+ element.projects = this.createRef(projects);
105
99
  }
106
100
  else if (Array.isArray(projects)) {
107
101
  this.processProjectsArray(projects);
@@ -111,12 +105,8 @@ class ProjectNameInNodePropsManager {
111
105
  processDependsOn(dependsOn, ownerTargets, ownerName) {
112
106
  for (let i = 0; i < dependsOn.length; i++) {
113
107
  const dep = dependsOn[i];
114
- // Existing sentinel: rebind parent to this array in case a spread
115
- // merge copied it out of its original.
116
- if (isNameRef(dep)) {
117
- dep.parent = dependsOn;
108
+ if (isNameRef(dep))
118
109
  continue;
119
- }
120
110
  if (typeof dep === 'string') {
121
111
  // `^target` and same-project targets aren't cross-project refs.
122
112
  if (dep.startsWith('^') || (ownerTargets && dep in ownerTargets)) {
@@ -126,7 +116,7 @@ class ProjectNameInNodePropsManager {
126
116
  if (rest.length === 0)
127
117
  continue;
128
118
  const targetPart = rest.join(':');
129
- dependsOn[i] = this.createRef(maybeProject, dependsOn, undefined, targetPart);
119
+ dependsOn[i] = this.createRef(maybeProject, targetPart);
130
120
  continue;
131
121
  }
132
122
  if (!dep || typeof dep !== 'object' || !('projects' in dep))
@@ -142,7 +132,7 @@ class ProjectNameInNodePropsManager {
142
132
  projects === 'dependencies') {
143
133
  continue;
144
134
  }
145
- element.projects = this.createRef(projects, element, 'projects');
135
+ element.projects = this.createRef(projects);
146
136
  }
147
137
  else if (Array.isArray(projects)) {
148
138
  this.processProjectsArray(projects);
@@ -152,24 +142,26 @@ class ProjectNameInNodePropsManager {
152
142
  processProjectsArray(projects) {
153
143
  for (let j = 0; j < projects.length; j++) {
154
144
  const name = projects[j];
155
- if (isNameRef(name)) {
156
- name.parent = projects;
145
+ if (isNameRef(name))
157
146
  continue;
158
- }
159
147
  if (typeof name !== 'string')
160
148
  continue;
161
149
  if ((0, globs_1.isGlobPattern)(name))
162
150
  continue;
163
- projects[j] = this.createRef(name, projects, undefined);
151
+ projects[j] = this.createRef(name);
164
152
  }
165
153
  }
166
- // Builds a sentinel and registers it.
167
- createRef(referencedName, parent, key, targetPart) {
168
- const referencedRoot = this.getNameMap()[referencedName]?.root;
154
+ // Builds a sentinel and registers it. When `referencedName` isn't in the
155
+ // current name map, fall back to the rename history: a batch may reference a
156
+ // project by a name that a project earlier in the same batch already renamed
157
+ // (refs register after the whole batch merges), and the old name still
158
+ // identifies the same root.
159
+ createRef(referencedName, targetPart) {
160
+ const referencedRoot = this.getNameMap()[referencedName]?.root ??
161
+ this.nameHistory.get(referencedName);
169
162
  const ref = referencedRoot !== undefined
170
- ? new RootRef(referencedRoot, parent, key, targetPart)
171
- : new UsageRef(referencedName, parent, key, targetPart);
172
- this.allRefs.add(ref);
163
+ ? new RootRef(referencedRoot, targetPart)
164
+ : new UsageRef(referencedName, targetPart);
173
165
  if (ref instanceof UsageRef) {
174
166
  let set = this.pendingByName.get(referencedName);
175
167
  if (!set) {
@@ -184,6 +176,11 @@ class ProjectNameInNodePropsManager {
184
176
  // RootRef by prototype swap. Sentinel identity across spread copies means
185
177
  // one promotion updates every array the sentinel reached.
186
178
  identifyProjectWithRoot(root, name) {
179
+ // Every name a root has ever gone by, including pre-rename names. A later
180
+ // ref to a stale name resolves to the root it identified at the time.
181
+ // (If two roots use the same name over a graph construction, the later
182
+ // one wins — matching how the live name map would have resolved it.)
183
+ this.nameHistory.set(name, root);
187
184
  const pending = this.pendingByName.get(name);
188
185
  if (!pending)
189
186
  return;
@@ -195,24 +192,72 @@ class ProjectNameInNodePropsManager {
195
192
  ref.value = root;
196
193
  }
197
194
  }
198
- // Writes each sentinel's current resolved name back into its owning slot.
199
- // Called once after all plugin results have been merged.
195
+ // Resolves every sentinel in the merged rootMap in place. Sweeping the
196
+ // final config (rather than writing through back-references held by the
197
+ // sentinels) covers sentinels that merges copied into arrays other than
198
+ // the one they were created in, e.g. a pattern target's dependsOn applied
199
+ // to every matching target. Called once after all plugin results have
200
+ // been merged.
200
201
  applySubstitutions(rootMap) {
201
202
  const nameByRoot = {};
202
203
  for (const root in rootMap) {
203
204
  nameByRoot[root] = rootMap[root]?.name;
204
205
  }
205
- for (const ref of this.allRefs) {
206
- const finalName = this.resolveFinalName(ref, nameByRoot);
207
- if (finalName === undefined)
208
- continue;
209
- const replacement = ref.targetPart !== undefined
210
- ? `${finalName}:${ref.targetPart}`
211
- : finalName;
212
- this.writeReplacement(ref, replacement);
206
+ for (const root in rootMap) {
207
+ const targets = rootMap[root]?.targets;
208
+ if (!targets)
209
+ continue;
210
+ for (const targetName in targets) {
211
+ const targetConfig = targets[targetName];
212
+ if (!targetConfig || typeof targetConfig !== 'object')
213
+ continue;
214
+ if (Array.isArray(targetConfig.inputs)) {
215
+ this.substituteInArray(targetConfig.inputs, nameByRoot);
216
+ }
217
+ if (Array.isArray(targetConfig.dependsOn)) {
218
+ this.substituteInArray(targetConfig.dependsOn, nameByRoot);
219
+ }
220
+ }
213
221
  }
214
- this.allRefs.clear();
215
222
  this.pendingByName.clear();
223
+ this.nameHistory.clear();
224
+ }
225
+ substituteInArray(entries, nameByRoot) {
226
+ for (let i = 0; i < entries.length; i++) {
227
+ const entry = entries[i];
228
+ if (isNameRef(entry)) {
229
+ const finalName = this.resolveFinalName(entry, nameByRoot);
230
+ if (finalName !== undefined) {
231
+ entries[i] =
232
+ entry.targetPart !== undefined
233
+ ? `${finalName}:${entry.targetPart}`
234
+ : finalName;
235
+ }
236
+ continue;
237
+ }
238
+ if (!entry || typeof entry !== 'object' || !('projects' in entry)) {
239
+ continue;
240
+ }
241
+ const element = entry;
242
+ if (isNameRef(element.projects)) {
243
+ const finalName = this.resolveFinalName(element.projects, nameByRoot);
244
+ if (finalName !== undefined) {
245
+ element.projects = finalName;
246
+ }
247
+ }
248
+ else if (Array.isArray(element.projects)) {
249
+ const projects = element.projects;
250
+ for (let j = 0; j < projects.length; j++) {
251
+ const name = projects[j];
252
+ if (!isNameRef(name))
253
+ continue;
254
+ const finalName = this.resolveFinalName(name, nameByRoot);
255
+ if (finalName !== undefined) {
256
+ projects[j] = finalName;
257
+ }
258
+ }
259
+ }
260
+ }
216
261
  }
217
262
  resolveFinalName(ref, nameByRoot) {
218
263
  if (ref instanceof RootRef) {
@@ -221,20 +266,5 @@ class ProjectNameInNodePropsManager {
221
266
  // Unpromoted forward ref — best effort, fall back to the written name.
222
267
  return this.getNameMap()[ref.value]?.name ?? ref.value;
223
268
  }
224
- writeReplacement(ref, replacement) {
225
- const parent = ref.parent;
226
- if (Array.isArray(parent)) {
227
- // One sentinel may appear at multiple indices (e.g. `[..., ...]`
228
- // pushed the same reference twice via spread), so replace all.
229
- for (let i = 0; i < parent.length; i++) {
230
- if (parent[i] === ref)
231
- parent[i] = replacement;
232
- }
233
- return;
234
- }
235
- if (parent && typeof parent === 'object' && ref.key !== undefined) {
236
- parent[ref.key] = replacement;
237
- }
238
- }
239
269
  }
240
270
  exports.ProjectNameInNodePropsManager = ProjectNameInNodePropsManager;
@@ -28,15 +28,12 @@ export declare class ProjectNodesManager {
28
28
  mergeProjectNode(project: ProjectConfiguration, configurationSourceMaps?: ConfigurationSourceMaps, sourceInformation?: SourceInformation): void;
29
29
  /**
30
30
  * Inserts project-name sentinels into `inputs` and `dependsOn` on the
31
- * merged objects from `mergedRootMap` (defaulting to this manager's
32
- * rootMap). Walking the merged entries matters because a spread-produced
33
- * array is a fresh instance.
34
- *
35
- * Pass a different `mergedRootMap` for the default-plugin intermediate
36
- * pass, then call again with `this.rootMap` after it's applied so
37
- * sentinel parents rebind onto the final arrays.
31
+ * merged objects in this manager's rootMap. Walking the merged entries —
32
+ * not the plugin results — matters because a spread-produced array is a
33
+ * fresh instance, and because sentinels written into plugin-result arrays
34
+ * would corrupt them for any later merge that re-reads the results.
38
35
  */
39
- registerNameRefs(pluginResultProjects?: Record<string, Omit<ProjectConfiguration, 'root'> & Partial<ProjectConfiguration>>, mergedRootMap?: Record<string, ProjectConfiguration>): void;
36
+ registerNameRefs(pluginResultProjects?: Record<string, Omit<ProjectConfiguration, 'root'> & Partial<ProjectConfiguration>>): void;
40
37
  /**
41
38
  * Applies all pending name substitutions. Call once after all plugin
42
39
  * results have been merged.
@@ -7,6 +7,8 @@ exports.createRootMap = createRootMap;
7
7
  const error_types_1 = require("../../error-types");
8
8
  const target_merging_1 = require("./target-merging");
9
9
  const target_normalization_1 = require("./target-normalization");
10
+ const git_worktrees_1 = require("../../../utils/git-worktrees");
11
+ const workspace_root_1 = require("../../../utils/workspace-root");
10
12
  const name_substitution_manager_1 = require("./name-substitution-manager");
11
13
  const source_maps_1 = require("./source-maps");
12
14
  const minimatch_1 = require("minimatch");
@@ -129,10 +131,10 @@ deferSpreadsWithoutBase = true) {
129
131
  // if augmenting an existing target.
130
132
  const target = project.targets?.[targetName];
131
133
  if (sourceMap) {
132
- // A target default stamping fields onto an existing target must not
133
- // steal provenance for the target's existence; real plugins still win
134
- // last. Field-level attribution is handled inside
135
- // `mergeTargetConfigurations`.
134
+ // Claims the node key for a newly-created target (or reclaims it from
135
+ // a weak target-defaults stamp). Whether an *existing* target changes
136
+ // owners is decided inside `mergeTargetConfigurations`, which knows
137
+ // whether this merge changed the target's identity.
136
138
  (0, source_maps_1.recordTargetIdentitySourceMapInfo)(sourceMap, (0, source_maps_1.targetSourceMapKey)(targetName), sourceInformation);
137
139
  }
138
140
  const normalizedTarget = skipTargetNormalization
@@ -194,7 +196,9 @@ function readProjectConfigurationsFromRootMap(projectRootMap) {
194
196
  }
195
197
  }
196
198
  if (conflicts.size > 0) {
197
- throw new error_types_1.MultipleProjectsWithSameNameError(conflicts, projects);
199
+ // Only on the way to throwing, so a workspace without duplicates never
200
+ // pays for reading git's worktree registry.
201
+ throw new error_types_1.MultipleProjectsWithSameNameError(conflicts, projects, (0, git_worktrees_1.analyzeWorktreeConflicts)(workspace_root_1.workspaceRoot, conflicts) ?? undefined);
198
202
  }
199
203
  if (projectRootsWithNoName.length > 0) {
200
204
  throw new error_types_1.ProjectsWithNoNameError(projectRootsWithNoName, projects);
@@ -257,21 +261,18 @@ class ProjectNodesManager {
257
261
  }
258
262
  /**
259
263
  * Inserts project-name sentinels into `inputs` and `dependsOn` on the
260
- * merged objects from `mergedRootMap` (defaulting to this manager's
261
- * rootMap). Walking the merged entries matters because a spread-produced
262
- * array is a fresh instance.
263
- *
264
- * Pass a different `mergedRootMap` for the default-plugin intermediate
265
- * pass, then call again with `this.rootMap` after it's applied so
266
- * sentinel parents rebind onto the final arrays.
264
+ * merged objects in this manager's rootMap. Walking the merged entries —
265
+ * not the plugin results — matters because a spread-produced array is a
266
+ * fresh instance, and because sentinels written into plugin-result arrays
267
+ * would corrupt them for any later merge that re-reads the results.
267
268
  */
268
- registerNameRefs(pluginResultProjects, mergedRootMap = this.rootMap) {
269
+ registerNameRefs(pluginResultProjects) {
269
270
  if (!pluginResultProjects)
270
271
  return;
271
272
  const scoped = {};
272
273
  for (const root in pluginResultProjects) {
273
- if (mergedRootMap[root]) {
274
- scoped[root] = mergedRootMap[root];
274
+ if (this.rootMap[root]) {
275
+ scoped[root] = this.rootMap[root];
275
276
  }
276
277
  }
277
278
  this.nameSubstitutionManager.registerNameRefs(scoped);
@@ -9,12 +9,19 @@ export type SourceInformation = [file: string | null, plugin: string];
9
9
  */
10
10
  export declare const TARGET_DEFAULTS_PLUGIN_NAME = "nx/target-defaults";
11
11
  /**
12
- * Write the source for a target's "identity" key (the target node itself, or
13
- * its executor/command). Real plugins win last; a target-defaults stamp only
14
- * claims the key when no real plugin already recorded it — target defaults
15
- * never bring a target into existence, they only layer fields onto one.
12
+ * Write the source for the target node key (`targets.<name>`). Ownership of a
13
+ * target follows its identity, not the last writer:
14
+ *
15
+ * - An unowned key goes to whoever writes it first (the creator).
16
+ * - A target-defaults stamp is weak — it never authors a target's existence,
17
+ * so any real plugin reclaims the key from it, and it can never take the
18
+ * key from a real plugin.
19
+ * - Between real plugins, the key only changes hands when the merge changed
20
+ * the target's identity (executor/command) — a plugin that merely layers
21
+ * fields (dependsOn, options, …) onto an existing target does not become
22
+ * its owner.
16
23
  */
17
- export declare function recordTargetIdentitySourceMapInfo(sourceMap: Record<string, SourceInformation>, key: string, sourceInfo: SourceInformation): void;
24
+ export declare function recordTargetIdentitySourceMapInfo(sourceMap: Record<string, SourceInformation>, key: string, sourceInfo: SourceInformation, identityChanged?: boolean): void;
18
25
  /** Source map per project root. */
19
26
  export type ConfigurationSourceMaps = Record<string, Record<string, SourceInformation>>;
20
27
  export declare function forEachSourceMapKeyForArray(prefixKey: string, array: unknown[], callback: (key: string, index: number) => void, startIndex?: number): void;
@@ -21,14 +21,28 @@ exports.targetConfigurationsSourceMapKey = targetConfigurationsSourceMapKey;
21
21
  */
22
22
  exports.TARGET_DEFAULTS_PLUGIN_NAME = 'nx/target-defaults';
23
23
  /**
24
- * Write the source for a target's "identity" key (the target node itself, or
25
- * its executor/command). Real plugins win last; a target-defaults stamp only
26
- * claims the key when no real plugin already recorded it — target defaults
27
- * never bring a target into existence, they only layer fields onto one.
24
+ * Write the source for the target node key (`targets.<name>`). Ownership of a
25
+ * target follows its identity, not the last writer:
26
+ *
27
+ * - An unowned key goes to whoever writes it first (the creator).
28
+ * - A target-defaults stamp is weak — it never authors a target's existence,
29
+ * so any real plugin reclaims the key from it, and it can never take the
30
+ * key from a real plugin.
31
+ * - Between real plugins, the key only changes hands when the merge changed
32
+ * the target's identity (executor/command) — a plugin that merely layers
33
+ * fields (dependsOn, options, …) onto an existing target does not become
34
+ * its owner.
28
35
  */
29
- function recordTargetIdentitySourceMapInfo(sourceMap, key, sourceInfo) {
30
- if (sourceInfo[1] !== exports.TARGET_DEFAULTS_PLUGIN_NAME ||
31
- sourceMap[key] === undefined) {
36
+ function recordTargetIdentitySourceMapInfo(sourceMap, key, sourceInfo, identityChanged = false) {
37
+ const existing = sourceMap[key];
38
+ if (existing === undefined) {
39
+ sourceMap[key] = sourceInfo;
40
+ return;
41
+ }
42
+ if (sourceInfo[1] === exports.TARGET_DEFAULTS_PLUGIN_NAME) {
43
+ return;
44
+ }
45
+ if (existing[1] === exports.TARGET_DEFAULTS_PLUGIN_NAME || identityChanged) {
32
46
  sourceMap[key] = sourceInfo;
33
47
  }
34
48
  }
@@ -19,7 +19,7 @@ type CreateNodesResultEntry = readonly [
19
19
  * fly. That's all the matcher needs; the full target merge happens
20
20
  * downstream in the real merge.
21
21
  */
22
- export declare function createTargetDefaultsResults(specifiedPluginRootMap: Record<string, ProjectConfiguration>, defaultPluginRootMap: Record<string, ProjectConfiguration>, nxJsonConfiguration: NxJsonConfiguration, specifiedSourceMaps?: ConfigurationSourceMaps, defaultSourceMaps?: ConfigurationSourceMaps): CreateNodesResultEntry[];
22
+ export declare function createTargetDefaultsResults(specifiedPluginRootMap: Record<string, ProjectConfiguration>, defaultPluginRootMap: Record<string, ProjectConfiguration>, nxJsonConfiguration: NxJsonConfiguration, specifiedSourceMaps?: ConfigurationSourceMaps): CreateNodesResultEntry[];
23
23
  /**
24
24
  * Public reader that resolves the target defaults applying to a given
25
25
  * target. Accepts the nested map shape (a value is either a plain config