nx 23.0.0-beta.2 → 23.0.0-beta.21

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 (274) hide show
  1. package/dist/bin/init-local.js +11 -20
  2. package/dist/bin/nx.d.ts +1 -0
  3. package/dist/bin/nx.js +28 -2
  4. package/dist/plugins/package-json.js +4 -2
  5. package/dist/src/adapter/ngcli-adapter.d.ts +2 -1
  6. package/dist/src/adapter/ngcli-adapter.js +25 -2
  7. package/dist/src/ai/clone-ai-config-repo.js +20 -3
  8. package/dist/src/analytics/analytics.js +10 -1
  9. package/dist/src/command-line/add/completion.d.ts +1 -0
  10. package/dist/src/command-line/add/completion.js +15 -0
  11. package/dist/src/command-line/affected/completion.d.ts +1 -0
  12. package/dist/src/command-line/affected/completion.js +15 -0
  13. package/dist/src/command-line/completion/argv-layout.d.ts +6 -0
  14. package/dist/src/command-line/completion/argv-layout.js +19 -0
  15. package/dist/src/command-line/completion/command-completions.d.ts +19 -0
  16. package/dist/src/command-line/completion/command-completions.js +120 -0
  17. package/dist/src/command-line/completion/command-handlers.d.ts +30 -0
  18. package/dist/src/command-line/completion/command-handlers.js +69 -0
  19. package/dist/src/command-line/completion/command-object.d.ts +10 -0
  20. package/dist/src/command-line/completion/command-object.js +95 -0
  21. package/dist/src/command-line/completion/completion-providers.d.ts +21 -0
  22. package/dist/src/command-line/completion/completion-providers.js +194 -0
  23. package/dist/src/command-line/completion/infix-targets.d.ts +1 -0
  24. package/dist/src/command-line/completion/infix-targets.js +48 -0
  25. package/dist/src/command-line/completion/metadata.d.ts +22 -0
  26. package/dist/src/command-line/completion/metadata.js +71 -0
  27. package/dist/src/command-line/completion/registrations.d.ts +9 -0
  28. package/dist/src/command-line/completion/registrations.js +16 -0
  29. package/dist/src/command-line/completion/scripts/bash.sh +51 -0
  30. package/dist/src/command-line/completion/scripts/fish.fish +47 -0
  31. package/dist/src/command-line/completion/scripts/powershell.ps1 +52 -0
  32. package/dist/src/command-line/completion/scripts/zsh.zsh +69 -0
  33. package/dist/src/command-line/completion/scripts.d.ts +18 -0
  34. package/dist/src/command-line/completion/scripts.js +140 -0
  35. package/dist/src/command-line/completion/trigger.d.ts +3 -0
  36. package/dist/src/command-line/completion/trigger.js +21 -0
  37. package/dist/src/command-line/completion/value-completions.d.ts +3 -0
  38. package/dist/src/command-line/completion/value-completions.js +21 -0
  39. package/dist/src/command-line/examples.js +1 -1
  40. package/dist/src/command-line/format/format.js +15 -5
  41. package/dist/src/command-line/generate/completion.d.ts +1 -0
  42. package/dist/src/command-line/generate/completion.js +9 -0
  43. package/dist/src/command-line/graph/completion.d.ts +1 -0
  44. package/dist/src/command-line/graph/completion.js +13 -0
  45. package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +14 -18
  46. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +1 -0
  47. package/dist/src/command-line/init/implementation/utils.d.ts +7 -1
  48. package/dist/src/command-line/init/implementation/utils.js +51 -14
  49. package/dist/src/command-line/migrate/agentic/capture-generator-output.d.ts +22 -0
  50. package/dist/src/command-line/migrate/agentic/capture-generator-output.js +100 -0
  51. package/dist/src/command-line/migrate/agentic/cli-args.d.ts +12 -0
  52. package/dist/src/command-line/migrate/agentic/cli-args.js +38 -0
  53. package/dist/src/command-line/migrate/agentic/definitions.d.ts +6 -0
  54. package/dist/src/command-line/migrate/agentic/definitions.js +98 -0
  55. package/dist/src/command-line/migrate/agentic/detect-installed.d.ts +10 -0
  56. package/dist/src/command-line/migrate/agentic/detect-installed.js +68 -0
  57. package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +46 -0
  58. package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +87 -0
  59. package/dist/src/command-line/migrate/agentic/handoff.d.ts +63 -0
  60. package/dist/src/command-line/migrate/agentic/handoff.js +183 -0
  61. package/dist/src/command-line/migrate/agentic/inception.d.ts +9 -0
  62. package/dist/src/command-line/migrate/agentic/inception.js +15 -0
  63. package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.d.ts +22 -0
  64. package/dist/src/command-line/migrate/agentic/print-dropped-agent-context.js +50 -0
  65. package/dist/src/command-line/migrate/agentic/prompts/generic-validation.d.ts +51 -0
  66. package/dist/src/command-line/migrate/agentic/prompts/generic-validation.js +65 -0
  67. package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.d.ts +44 -0
  68. package/dist/src/command-line/migrate/agentic/prompts/hybrid-prompt-migration.js +52 -0
  69. package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.d.ts +21 -0
  70. package/dist/src/command-line/migrate/agentic/prompts/prompt-migration.js +26 -0
  71. package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.d.ts +18 -0
  72. package/dist/src/command-line/migrate/agentic/prompts/shared-rendering.js +130 -0
  73. package/dist/src/command-line/migrate/agentic/prompts/system-prompt.d.ts +46 -0
  74. package/dist/src/command-line/migrate/agentic/prompts/system-prompt.js +88 -0
  75. package/dist/src/command-line/migrate/agentic/run-step.d.ts +51 -0
  76. package/dist/src/command-line/migrate/agentic/run-step.js +121 -0
  77. package/dist/src/command-line/migrate/agentic/runner.d.ts +33 -0
  78. package/dist/src/command-line/migrate/agentic/runner.js +442 -0
  79. package/dist/src/command-line/migrate/agentic/select.d.ts +14 -0
  80. package/dist/src/command-line/migrate/agentic/select.js +150 -0
  81. package/dist/src/command-line/migrate/agentic/types.d.ts +102 -0
  82. package/dist/src/command-line/migrate/agentic/types.js +2 -0
  83. package/dist/src/command-line/migrate/command-object.d.ts +1 -0
  84. package/dist/src/command-line/migrate/command-object.js +32 -7
  85. package/dist/src/command-line/migrate/migrate-commits.d.ts +50 -0
  86. package/dist/src/command-line/migrate/migrate-commits.js +102 -0
  87. package/dist/src/command-line/migrate/migrate-output.d.ts +180 -0
  88. package/dist/src/command-line/migrate/migrate-output.js +258 -0
  89. package/dist/src/command-line/migrate/migrate.d.ts +122 -12
  90. package/dist/src/command-line/migrate/migrate.js +1036 -217
  91. package/dist/src/command-line/migrate/migration-shape.d.ts +8 -0
  92. package/dist/src/command-line/migrate/migration-shape.js +13 -0
  93. package/dist/src/command-line/migrate/multi-major.d.ts +30 -0
  94. package/dist/src/command-line/migrate/multi-major.js +185 -0
  95. package/dist/src/command-line/migrate/prompt-files.d.ts +31 -0
  96. package/dist/src/command-line/migrate/prompt-files.js +141 -0
  97. package/dist/src/command-line/migrate/run-migration-process.js +28 -6
  98. package/dist/src/command-line/migrate/safe-prompt.d.ts +28 -0
  99. package/dist/src/command-line/migrate/safe-prompt.js +49 -0
  100. package/dist/src/command-line/migrate/update-filters.d.ts +11 -0
  101. package/dist/src/command-line/migrate/update-filters.js +44 -0
  102. package/dist/src/command-line/migrate/version-utils.d.ts +6 -0
  103. package/dist/src/command-line/migrate/version-utils.js +59 -0
  104. package/dist/src/command-line/nx-commands.js +9 -0
  105. package/dist/src/command-line/release/config/config.d.ts +3 -6
  106. package/dist/src/command-line/release/config/config.js +77 -45
  107. package/dist/src/command-line/release/config/use-legacy-versioning.d.ts +2 -0
  108. package/dist/src/command-line/release/config/use-legacy-versioning.js +8 -0
  109. package/dist/src/command-line/release/utils/release-graph.js +2 -3
  110. package/dist/src/command-line/release/utils/repository-git-tags.js +1 -1
  111. package/dist/src/command-line/release/utils/resolve-changelog-renderer.js +7 -19
  112. package/dist/src/command-line/release/version/resolve-current-version.js +1 -1
  113. package/dist/src/command-line/release/version/version-actions.js +3 -7
  114. package/dist/src/command-line/report/report.js +2 -2
  115. package/dist/src/command-line/run/completion.d.ts +1 -0
  116. package/dist/src/command-line/run/completion.js +7 -0
  117. package/dist/src/command-line/run-many/completion.d.ts +1 -0
  118. package/dist/src/command-line/run-many/completion.js +13 -0
  119. package/dist/src/command-line/show/completion.d.ts +1 -0
  120. package/dist/src/command-line/show/completion.js +27 -0
  121. package/dist/src/command-line/show/show-target/info.d.ts +1 -0
  122. package/dist/src/command-line/show/show-target/info.js +100 -19
  123. package/dist/src/command-line/watch/command-object.js +24 -4
  124. package/dist/src/command-line/watch/completion.d.ts +1 -0
  125. package/dist/src/command-line/watch/completion.js +10 -0
  126. package/dist/src/command-line/watch/watch.d.ts +7 -0
  127. package/dist/src/command-line/watch/watch.js +1 -1
  128. package/dist/src/config/misc-interfaces.d.ts +25 -2
  129. package/dist/src/config/nx-json.d.ts +43 -56
  130. package/dist/src/config/schema-utils.d.ts +21 -0
  131. package/dist/src/config/schema-utils.js +92 -18
  132. package/dist/src/config/task-graph.d.ts +4 -107
  133. package/dist/src/core/graph/main.js +1 -1
  134. package/dist/src/core/graph/styles.css +2 -3
  135. package/dist/src/core/graph/styles.js +1 -1
  136. package/dist/src/daemon/client/client.d.ts +1 -1
  137. package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +1 -1
  138. package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +1 -1
  139. package/dist/src/daemon/server/file-watching/route-workspace-changes.d.ts +9 -0
  140. package/dist/src/daemon/server/file-watching/route-workspace-changes.js +76 -0
  141. package/dist/src/daemon/server/project-graph-incremental-recomputation.js +45 -11
  142. package/dist/src/daemon/server/server.js +4 -43
  143. package/dist/src/daemon/server/start.d.ts +1 -1
  144. package/dist/src/daemon/server/start.js +2 -0
  145. package/dist/src/devkit-exports.d.ts +2 -2
  146. package/dist/src/devkit-internals.d.ts +5 -1
  147. package/dist/src/devkit-internals.js +17 -1
  148. package/dist/src/executors/run-commands/running-tasks.d.ts +7 -0
  149. package/dist/src/executors/run-commands/running-tasks.js +178 -105
  150. package/dist/src/executors/run-script/run-script.impl.js +3 -10
  151. package/dist/src/executors/utils/convert-nx-executor.js +1 -1
  152. package/dist/src/hasher/hash-plan-inspector.d.ts +1 -1
  153. package/dist/src/hasher/task-hasher.js +6 -4
  154. package/dist/src/index.d.ts +1 -1
  155. package/dist/src/index.js +0 -3
  156. package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +6 -2
  157. package/dist/src/migrations/update-17-0-0/move-cache-directory.md +31 -0
  158. package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +20 -4
  159. package/dist/src/migrations/update-20-0-0/move-use-daemon-process.md +27 -0
  160. package/dist/src/migrations/update-20-0-1/use-legacy-cache.md +24 -0
  161. package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.md +49 -0
  162. package/dist/src/migrations/update-21-0-0/release-version-config-changes.md +54 -0
  163. package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.md +28 -0
  164. package/dist/src/migrations/update-21-0-0/remove-legacy-cache.md +22 -0
  165. package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.md +11 -0
  166. package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.d.ts +2 -0
  167. package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +16 -0
  168. package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.d.ts +9 -0
  169. package/dist/src/migrations/update-23-0-0/consolidate-release-tag-config.js +18 -0
  170. package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.d.ts +35 -0
  171. package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.js +139 -0
  172. package/dist/src/migrations/update-23-0-0/convert-target-defaults-to-array.md +66 -0
  173. package/dist/src/native/index.d.ts +79 -2
  174. package/dist/src/native/native-bindings.js +3 -0
  175. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  176. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  177. package/dist/src/plugins/js/lock-file/npm-parser.js +37 -19
  178. package/dist/src/plugins/js/lock-file/pnpm-parser.js +51 -4
  179. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +12 -4
  180. package/dist/src/plugins/js/utils/packages.js +1 -1
  181. package/dist/src/plugins/js/utils/register.d.ts +103 -14
  182. package/dist/src/plugins/js/utils/register.js +434 -39
  183. package/dist/src/plugins/js/utils/typescript.d.ts +7 -0
  184. package/dist/src/plugins/js/utils/typescript.js +39 -0
  185. package/dist/src/plugins/package-json/create-nodes.d.ts +3 -2
  186. package/dist/src/plugins/package-json/create-nodes.js +7 -5
  187. package/dist/src/project-graph/affected/locators/project-glob-changes.js +2 -1
  188. package/dist/src/project-graph/build-project-graph.d.ts +5 -0
  189. package/dist/src/project-graph/build-project-graph.js +6 -2
  190. package/dist/src/project-graph/file-map-utils.d.ts +5 -0
  191. package/dist/src/project-graph/file-map-utils.js +10 -1
  192. package/dist/src/project-graph/plugins/get-plugins.d.ts +7 -2
  193. package/dist/src/project-graph/plugins/get-plugins.js +8 -5
  194. package/dist/src/project-graph/plugins/isolation/plugin-worker.d.ts +1 -0
  195. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +2 -0
  196. package/dist/src/project-graph/plugins/resolve-plugin.d.ts +7 -4
  197. package/dist/src/project-graph/plugins/resolve-plugin.js +152 -33
  198. package/dist/src/project-graph/plugins/tasks-execution-hooks.js +4 -2
  199. package/dist/src/project-graph/plugins/transpiler.d.ts +12 -0
  200. package/dist/src/project-graph/plugins/transpiler.js +37 -0
  201. package/dist/src/project-graph/plugins/utils.js +13 -7
  202. package/dist/src/project-graph/project-graph.js +1 -1
  203. package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +95 -4
  204. package/dist/src/project-graph/utils/project-configuration/target-defaults.js +515 -68
  205. package/dist/src/project-graph/utils/project-configuration-utils.d.ts +13 -5
  206. package/dist/src/project-graph/utils/project-configuration-utils.js +14 -6
  207. package/dist/src/project-graph/utils/retrieve-workspace-files.js +1 -1
  208. package/dist/src/tasks-runner/create-task-graph.d.ts +4 -4
  209. package/dist/src/tasks-runner/create-task-graph.js +1 -1
  210. package/dist/src/tasks-runner/default-tasks-runner.d.ts +0 -2
  211. package/dist/src/tasks-runner/forked-process-task-runner.d.ts +1 -1
  212. package/dist/src/tasks-runner/forked-process-task-runner.js +11 -6
  213. package/dist/src/tasks-runner/init-tasks-runner.d.ts +0 -15
  214. package/dist/src/tasks-runner/init-tasks-runner.js +0 -63
  215. package/dist/src/tasks-runner/legacy-depends-on-warning.d.ts +18 -0
  216. package/dist/src/tasks-runner/legacy-depends-on-warning.js +109 -0
  217. package/dist/src/tasks-runner/life-cycle.d.ts +7 -8
  218. package/dist/src/tasks-runner/life-cycles/invoke-runner-terminal-output-life-cycle.js +6 -6
  219. package/dist/src/tasks-runner/life-cycles/task-history-life-cycle-old.js +13 -2
  220. package/dist/src/tasks-runner/life-cycles/task-history-life-cycle.js +16 -5
  221. package/dist/src/tasks-runner/life-cycles/tui-summary-life-cycle.js +11 -2
  222. package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
  223. package/dist/src/tasks-runner/pseudo-terminal.js +22 -10
  224. package/dist/src/tasks-runner/run-command.js +8 -11
  225. package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +1 -1
  226. package/dist/src/tasks-runner/running-tasks/batch-process.js +3 -5
  227. package/dist/src/tasks-runner/running-tasks/node-child-process.d.ts +2 -2
  228. package/dist/src/tasks-runner/running-tasks/node-child-process.js +5 -7
  229. package/dist/src/tasks-runner/task-env.d.ts +1 -1
  230. package/dist/src/tasks-runner/task-env.js +6 -1
  231. package/dist/src/tasks-runner/task-orchestrator.d.ts +11 -1
  232. package/dist/src/tasks-runner/task-orchestrator.js +112 -38
  233. package/dist/src/tasks-runner/tasks-schedule.js +3 -3
  234. package/dist/src/tasks-runner/utils.d.ts +7 -8
  235. package/dist/src/tasks-runner/utils.js +23 -27
  236. package/dist/src/utils/child-process.js +2 -2
  237. package/dist/src/utils/compile-cache.d.ts +24 -0
  238. package/dist/src/utils/compile-cache.js +49 -0
  239. package/dist/src/utils/enable-compile-cache.d.ts +1 -0
  240. package/dist/src/utils/enable-compile-cache.js +7 -0
  241. package/dist/src/utils/fileutils.d.ts +0 -8
  242. package/dist/src/utils/fileutils.js +0 -40
  243. package/dist/src/utils/git-utils.d.ts +15 -0
  244. package/dist/src/utils/git-utils.js +138 -0
  245. package/dist/src/utils/handle-import.d.ts +4 -1
  246. package/dist/src/utils/handle-import.js +56 -2
  247. package/dist/src/utils/has-nx-js-plugin.d.ts +9 -0
  248. package/dist/src/utils/has-nx-js-plugin.js +24 -0
  249. package/dist/src/utils/installed-nx-version.d.ts +14 -4
  250. package/dist/src/utils/installed-nx-version.js +54 -7
  251. package/dist/src/utils/logger.d.ts +12 -1
  252. package/dist/src/utils/logger.js +57 -36
  253. package/dist/src/utils/nx-key.d.ts +0 -1
  254. package/dist/src/utils/nx-key.js +20 -23
  255. package/dist/src/utils/nx-package-group.d.ts +8 -0
  256. package/dist/src/utils/nx-package-group.js +15 -0
  257. package/dist/src/utils/output.d.ts +3 -2
  258. package/dist/src/utils/output.js +29 -28
  259. package/dist/src/utils/package-json.d.ts +14 -1
  260. package/dist/src/utils/package-json.js +20 -21
  261. package/dist/src/utils/perf-logging.js +3 -1
  262. package/dist/src/utils/plugin-cache-utils.d.ts +13 -4
  263. package/dist/src/utils/plugin-cache-utils.js +23 -13
  264. package/dist/src/utils/plugins/local-plugins.d.ts +18 -0
  265. package/dist/src/utils/plugins/local-plugins.js +30 -0
  266. package/dist/src/utils/tar.d.ts +8 -0
  267. package/dist/src/utils/tar.js +44 -0
  268. package/migrations.json +16 -0
  269. package/package.json +28 -28
  270. package/schemas/nx-schema.json +114 -80
  271. package/dist/src/plugins/js/project-graph/build-dependencies/strip-source-code.d.ts +0 -7
  272. package/dist/src/plugins/js/project-graph/build-dependencies/strip-source-code.js +0 -155
  273. package/dist/src/plugins/js/project-graph/build-dependencies/typescript-import-locator.d.ts +0 -16
  274. package/dist/src/plugins/js/project-graph/build-dependencies/typescript-import-locator.js +0 -121
@@ -2,19 +2,51 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createTargetDefaultsResults = createTargetDefaultsResults;
4
4
  exports.readTargetDefaultsForTarget = readTargetDefaultsForTarget;
5
+ exports.findBestTargetDefault = findBestTargetDefault;
6
+ exports.normalizeTargetDefaults = normalizeTargetDefaults;
7
+ exports.normalizeTargetDefaultsAgainstRootMaps = normalizeTargetDefaultsAgainstRootMaps;
8
+ const tslib_1 = require("tslib");
5
9
  const minimatch_1 = require("minimatch");
10
+ const find_matching_projects_1 = require("../../../utils/find-matching-projects");
6
11
  const globs_1 = require("../../../utils/globs");
12
+ const source_maps_1 = require("./source-maps");
7
13
  const target_merging_1 = require("./target-merging");
8
14
  const utils_1 = require("./utils");
15
+ const os_1 = require("os");
16
+ const pc = tslib_1.__importStar(require("picocolors"));
9
17
  /**
10
18
  * Builds a synthetic plugin result from nx.json's `targetDefaults`, layered
11
19
  * between specified-plugin and default-plugin results during merging.
20
+ *
21
+ * Synthesis sees the two layers separately to avoid re-merging specified
22
+ * results into a parallel rootMap — for each (root, target) where both
23
+ * layers contribute, it computes the eventual executor/command on the
24
+ * fly. That's all the matcher needs; the full target merge happens
25
+ * downstream in the real merge.
12
26
  */
13
- function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMap, nxJsonConfiguration) {
27
+ function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMap, nxJsonConfiguration, specifiedSourceMaps, defaultSourceMaps) {
14
28
  const targetDefaultsConfig = nxJsonConfiguration.targetDefaults;
15
29
  if (!targetDefaultsConfig) {
16
30
  return [];
17
31
  }
32
+ // Disambiguate `:`-shaped record keys against the actual targets and
33
+ // executors present in the rootMaps. This is the same idea the v23
34
+ // `convert-target-defaults-to-array` migration uses against the project
35
+ // graph — we just consult the rootMaps directly here since we don't have
36
+ // a graph yet during construction.
37
+ const entries = normalizeTargetDefaultsAgainstRootMaps(targetDefaultsConfig, specifiedPluginRootMap, defaultPluginRootMap);
38
+ if (entries.length === 0) {
39
+ return [];
40
+ }
41
+ // `projectNodesByName` and `rootToName` are only consulted when an entry
42
+ // has a `projects:` filter — that's the only matcher branch that needs
43
+ // either the project name or its node. Source-plugin attribution is
44
+ // root-keyed via `resolveSourcePlugin`, not name-keyed, so it doesn't
45
+ // need either map. Skip both builds in the common no-filter path.
46
+ const needsProjectNodes = entries.some((e) => e.projects !== undefined);
47
+ const projectNodes = needsProjectNodes
48
+ ? buildProjectNodesAndRootToName(specifiedPluginRootMap, defaultPluginRootMap)
49
+ : undefined;
18
50
  const syntheticProjects = {};
19
51
  const allRoots = new Set([
20
52
  ...Object.keys(specifiedPluginRootMap),
@@ -23,8 +55,16 @@ function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMa
23
55
  for (const root of allRoots) {
24
56
  const specifiedTargets = specifiedPluginRootMap[root]?.targets ?? {};
25
57
  const defaultTargets = defaultPluginRootMap[root]?.targets ?? {};
58
+ const projectName = projectNodes?.rootToName.get(root);
59
+ const projectNode = projectName
60
+ ? projectNodes.projectNodesByName[projectName]
61
+ : undefined;
26
62
  for (const targetName of (0, utils_1.uniqueKeysInObjects)(specifiedTargets, defaultTargets)) {
27
- const syntheticTarget = buildSyntheticTargetForRoot(targetName, root, specifiedTargets[targetName], defaultTargets[targetName], targetDefaultsConfig);
63
+ const effective = effectiveTargetForLookup(specifiedTargets[targetName], defaultTargets[targetName], root);
64
+ if (!effective)
65
+ continue;
66
+ const sourcePlugin = resolveSourcePlugin(root, targetName, specifiedSourceMaps, defaultSourceMaps);
67
+ const syntheticTarget = buildSyntheticTargetForRoot(targetName, root, effective, entries, projectName, projectNode, sourcePlugin);
28
68
  if (!syntheticTarget)
29
69
  continue;
30
70
  syntheticProjects[root] ??= { root, targets: {} };
@@ -44,92 +84,499 @@ function createTargetDefaultsResults(specifiedPluginRootMap, defaultPluginRootMa
44
84
  ],
45
85
  ];
46
86
  }
47
- // Returns the synthetic defaults target to insert for `targetName` at
48
- // `root`, or undefined if no defaults apply.
49
- // Layering: specified plugins < target defaults < default plugins.
50
- function buildSyntheticTargetForRoot(targetName, root, specifiedTarget, defaultTarget, targetDefaultsConfig) {
87
+ // Returns the (executor, command) pair the real merge will land on at
88
+ // `(root, targetName)` only the fields the matcher needs. Incompatible
89
+ // pairs wholesale-replace specified with default; compatible pairs let
90
+ // the default's executor win, otherwise the specified's.
91
+ function effectiveTargetForLookup(specifiedTarget, defaultTarget, root) {
51
92
  const resolvedSpecified = specifiedTarget
52
93
  ? (0, target_merging_1.resolveCommandSyntacticSugar)(specifiedTarget, root)
53
94
  : undefined;
54
95
  const resolvedDefault = defaultTarget
55
96
  ? (0, target_merging_1.resolveCommandSyntacticSugar)(defaultTarget, root)
56
97
  : undefined;
57
- // Specified-only: layer defaults on top, but only when the resulting
58
- // synthetic is compatible with the specified target. An incompatible
59
- // synthetic (e.g. `targetDefaults['test-native'] = { executor:
60
- // '@monodon/rust:test' }` while a polyglot plugin infers `test-native`
61
- // with `nx:run-commands`) would otherwise replace the specified target
62
- // wholesale during the downstream merge.
63
- if (resolvedSpecified && !resolvedDefault) {
64
- const targetDefaults = readAndPrepareTargetDefaults(targetName, resolvedSpecified.executor, root, targetDefaultsConfig);
65
- if (targetDefaults &&
66
- !(0, target_merging_1.isCompatibleTarget)(resolvedSpecified, targetDefaults)) {
67
- return undefined;
98
+ if (resolvedSpecified && resolvedDefault) {
99
+ if (!(0, target_merging_1.isCompatibleTarget)(resolvedSpecified, resolvedDefault)) {
100
+ return {
101
+ executor: resolvedDefault.executor,
102
+ command: resolvedDefault.command,
103
+ };
68
104
  }
69
- return targetDefaults;
70
- }
71
- // Default-only.
72
- if (resolvedDefault && !resolvedSpecified) {
73
- return readAndPrepareTargetDefaults(targetName, resolvedDefault.executor, root, targetDefaultsConfig);
105
+ return {
106
+ executor: resolvedDefault.executor ?? resolvedSpecified.executor,
107
+ command: resolvedDefault.command ?? resolvedSpecified.command,
108
+ };
74
109
  }
75
- if (!resolvedSpecified || !resolvedDefault)
76
- return undefined;
77
- // Both compatible: use the default plugin's executor for the lookup.
78
- // The same incompatibility check applies — a project.json `{}` entry
79
- // asks defaults to fill in the target, but the lookup can still fall
80
- // back to a target-name keyed default with a foreign executor that
81
- // would replace the inferred target. Skip the synthetic in that case.
82
- if ((0, target_merging_1.isCompatibleTarget)(resolvedSpecified, resolvedDefault)) {
83
- const targetDefaults = readAndPrepareTargetDefaults(targetName, resolvedDefault.executor || resolvedSpecified.executor, root, targetDefaultsConfig);
84
- if (targetDefaults &&
85
- !(0, target_merging_1.isCompatibleTarget)(resolvedSpecified, targetDefaults)) {
86
- return undefined;
87
- }
88
- return targetDefaults;
110
+ if (resolvedSpecified) {
111
+ return {
112
+ executor: resolvedSpecified.executor,
113
+ command: resolvedSpecified.command,
114
+ };
89
115
  }
90
- // Incompatible: default plugin will replace specified; only defaults
91
- // matching the default plugin's executor are useful.
92
- const targetDefaults = readAndPrepareTargetDefaults(targetName, resolvedDefault.executor, root, targetDefaultsConfig);
93
- if (targetDefaults && (0, target_merging_1.isCompatibleTarget)(resolvedDefault, targetDefaults)) {
94
- // Stamp executor/command so the default layer merges cleanly on top.
116
+ if (resolvedDefault) {
95
117
  return {
96
- ...targetDefaults,
97
118
  executor: resolvedDefault.executor,
98
119
  command: resolvedDefault.command,
99
120
  };
100
121
  }
101
122
  return undefined;
102
123
  }
103
- function readAndPrepareTargetDefaults(targetName, executor, root, targetDefaultsConfig) {
104
- const rawTargetDefaults = readTargetDefaultsForTarget(targetName, targetDefaultsConfig, executor);
124
+ /**
125
+ * Returns the synthetic defaults target to insert for `targetName` at
126
+ * `root`, or undefined if no defaults apply. The synthetic stamps the
127
+ * effective executor/command so neither merge neighbor can
128
+ * incompatible-replace it and drop its contributions.
129
+ *
130
+ * @param effective The `(executor, command)` shape the real merge will
131
+ * land on. Used both to pick the highest-ranked compatible default
132
+ * (falling back to less-specific matches if the best one would be
133
+ * incompatible) and as the locked shape stamped onto the synthetic.
134
+ */
135
+ function buildSyntheticTargetForRoot(targetName, root, effective, targetDefaults, projectName, projectNode, sourcePlugin) {
136
+ const rawTargetDefaults = findBestTargetDefault(targetName, effective.executor, projectName, projectNode, sourcePlugin, targetDefaults, effective.command, (candidate) => (0, target_merging_1.isCompatibleTarget)({ executor: effective.executor, command: effective.command }, candidate));
105
137
  if (!rawTargetDefaults)
106
138
  return undefined;
107
- return (0, target_merging_1.resolveCommandSyntacticSugar)((0, target_merging_1.deepClone)(rawTargetDefaults), root);
108
- }
109
- function readTargetDefaultsForTarget(targetName, targetDefaults, executor) {
110
- if (executor && targetDefaults?.[executor]) {
111
- // If an executor is defined in project.json, defaults should be read
112
- // from the most specific key that matches that executor.
113
- // e.g. If executor === run-commands, and the target is named build:
114
- // Use, use nx:run-commands if it is present
115
- // If not, use build if it is present.
116
- return targetDefaults?.[executor];
117
- }
118
- else if (targetDefaults?.[targetName]) {
119
- // If the executor is not defined, the only key we have is the target name.
120
- return targetDefaults?.[targetName];
121
- }
122
- let matchingTargetDefaultKey = null;
123
- for (const key in targetDefaults ?? {}) {
124
- if ((0, globs_1.isGlobPattern)(key) && (0, minimatch_1.minimatch)(targetName, key)) {
125
- if (!matchingTargetDefaultKey ||
126
- matchingTargetDefaultKey.length < key.length) {
127
- matchingTargetDefaultKey = key;
139
+ const synthetic = (0, target_merging_1.resolveCommandSyntacticSugar)((0, target_merging_1.deepClone)(rawTargetDefaults), root);
140
+ // Pre-stamp executor/command from the effective shape so the
141
+ // synthetic can't be incompatible-replaced during the real merge.
142
+ if (effective.executor !== undefined)
143
+ synthetic.executor = effective.executor;
144
+ if (effective.command !== undefined)
145
+ synthetic.command = effective.command;
146
+ return synthetic;
147
+ }
148
+ /**
149
+ * Public, backwards-compatible reader that looks up the most-specific
150
+ * target default for a given target. Accepts either the new array shape
151
+ * or the legacy record shape (devkit support).
152
+ *
153
+ * When called without project context, entries that require a `projects`
154
+ * filter or a `plugin` filter are skipped.
155
+ *
156
+ * The normalized entries are cached per `targetDefaults` reference so
157
+ * repeated reads against the same nx.json don't re-normalize (and don't
158
+ * re-fire the legacy-record-shape warning).
159
+ */
160
+ function readTargetDefaultsForTarget(targetName, targetDefaults, executor, opts) {
161
+ if (!targetDefaults)
162
+ return null;
163
+ return findBestTargetDefault(targetName, executor, opts?.projectName, opts?.projectNode, opts?.sourcePlugin, getCachedNormalizedEntries(targetDefaults), opts?.command);
164
+ }
165
+ const normalizedEntriesCache = new WeakMap();
166
+ function getCachedNormalizedEntries(targetDefaults) {
167
+ // WeakMap keys must be objects — both array and record forms are objects,
168
+ // so this is safe regardless of shape.
169
+ const key = targetDefaults;
170
+ let entries = normalizedEntriesCache.get(key);
171
+ if (!entries) {
172
+ entries = normalizeTargetDefaults(targetDefaults);
173
+ normalizedEntriesCache.set(key, entries);
174
+ }
175
+ return entries;
176
+ }
177
+ /**
178
+ * Find the highest-specificity `targetDefaults` entry that applies to the
179
+ * given (target, project, sourcePlugin) tuple. Ties are broken by match
180
+ * kind, then by later array index. Returns the config slice with filter
181
+ * keys (`target`, `projects`, `plugin`) stripped.
182
+ *
183
+ * Tier = (1 if a target/executor locator matched, else 0) + 1 per
184
+ * applied filter (`projects`, `plugin`). So locator-bearing entries:
185
+ * - tier 3: target/executor + projects + plugin
186
+ * - tier 2: target/executor + projects, or target/executor + plugin
187
+ * - tier 1: target/executor alone
188
+ * And filter-only entries (no `target` and no `executor`):
189
+ * - tier 2: projects + plugin
190
+ * - tier 1: projects alone, or plugin alone
191
+ *
192
+ * `executor` matching contributes to matchKind only, not to tier — it's
193
+ * not a filter, it's a refinement of the match. Within the same tier,
194
+ * tie-break order (highest first):
195
+ * targetAndExecutor > executorOnly > exactTarget > globTarget > filterOnly
196
+ *
197
+ * `filterOnly` ranks below every locator-bearing kind, so a filter-only
198
+ * entry can never tie-break ahead of one that names a target or executor
199
+ * at the same tier.
200
+ *
201
+ * `executor` only acts as an "injector" (matches a target with neither
202
+ * executor nor command) when the entry also sets `target`. Executor-only
203
+ * entries require the workspace target to actually have an executor.
204
+ *
205
+ * When `predicate` is provided, ranked candidates are iterated and the
206
+ * first one that satisfies the predicate is returned. This lets synthesis
207
+ * fall back to a less-specific compatible default when the most-specific
208
+ * match would be incompatible with the target it's being applied to.
209
+ * Without a predicate, the highest-ranked candidate is returned directly.
210
+ */
211
+ function findBestTargetDefault(targetName, executor, projectName, projectNode, sourcePlugin, entries, targetCommand, predicate) {
212
+ if (!entries?.length)
213
+ return null;
214
+ // Single greedy best-so-far loop in both the predicate and no-predicate
215
+ // paths. With a predicate, we filter candidates as they appear and only
216
+ // promote one to `best` when it passes — equivalent to the previous
217
+ // "collect-all + sort + first-passing" approach because `beats` is a
218
+ // total order, but without the sort allocation.
219
+ let best = null;
220
+ for (let i = 0; i < entries.length; i++) {
221
+ const candidate = matchEntry(entries[i], i, targetName, executor, projectName, projectNode, sourcePlugin, targetCommand);
222
+ if (!candidate)
223
+ continue;
224
+ if (predicate && !predicate(candidate.config))
225
+ continue;
226
+ if (!best || beats(candidate, best)) {
227
+ best = candidate;
228
+ }
229
+ }
230
+ return best ? best.config : null;
231
+ }
232
+ /**
233
+ * Classify the runtime intent of an entry's `projects:` value:
234
+ * - `none`: filter is absent — the entry is unscoped on the projects axis.
235
+ * - `empty`: filter is `[]` — matches no project, so the whole entry is
236
+ * dead. Treated as a never-match by the matcher rather than allowing
237
+ * the entry to silently apply nowhere (which is almost always a bug).
238
+ * - `wildcard`: filter is exactly `'*'` or `['*']` (or any combination of
239
+ * pure-wildcard patterns) — matches every project, equivalent to no
240
+ * filter at all. Doesn't count toward the broadcast guard or the
241
+ * specificity tier so the entry doesn't outrank a real, narrower one.
242
+ * - `filter`: a real pattern set the matcher needs to evaluate.
243
+ */
244
+ function classifyProjectsFilter(projects) {
245
+ if (projects === undefined)
246
+ return 'none';
247
+ const arr = Array.isArray(projects) ? projects : [projects];
248
+ if (arr.length === 0)
249
+ return 'empty';
250
+ if (arr.every((p) => p === '*'))
251
+ return 'wildcard';
252
+ return 'filter';
253
+ }
254
+ /**
255
+ * Test a single `targetDefaults` entry against the (target, executor,
256
+ * project, plugin, command) tuple of the target being resolved. Returns
257
+ * a `Candidate` with its tier and match kind, or null when the entry
258
+ * doesn't apply.
259
+ *
260
+ * The match facts (`targetName`, `executor`, `projectName`, `projectNode`,
261
+ * `sourcePlugin`, `targetCommand`) are passed in instead of being read
262
+ * from the graph node here because callers — `findBestTargetDefault` and
263
+ * `buildSyntheticTargetForRoot` — work in different graph contexts. The
264
+ * synthetic builder, in particular, evaluates against the *effective*
265
+ * executor/command (what the merge will land on), which doesn't always
266
+ * equal the node's current executor; threading the values explicitly
267
+ * keeps that asymmetry visible at the call sites.
268
+ */
269
+ function matchEntry(entry, index, targetName, executor, projectName, projectNode, sourcePlugin, targetCommand) {
270
+ if (!entry)
271
+ return null;
272
+ // `normalizeTargetDefaults` already drops entries with neither locator
273
+ // nor real filter. Empty-array `projects:` is an explicit never-match
274
+ // shape — kept by the normalizer because it's named, rejected here.
275
+ const projectsKind = classifyProjectsFilter(entry.projects);
276
+ if (projectsKind === 'empty')
277
+ return null;
278
+ let targetKind = null;
279
+ if (entry.target !== undefined) {
280
+ if (entry.target === targetName)
281
+ targetKind = 'exact';
282
+ else if ((0, globs_1.isGlobPattern)(entry.target) && (0, minimatch_1.minimatch)(targetName, entry.target))
283
+ targetKind = 'glob';
284
+ else
285
+ return null;
286
+ }
287
+ let executorMatched = false;
288
+ if (entry.executor !== undefined) {
289
+ if (executor && executor === entry.executor) {
290
+ executorMatched = true;
291
+ }
292
+ else if (targetKind !== null && !executor && !targetCommand) {
293
+ // Bare target with no executor — safe to inject the entry's
294
+ // executor because the target locator has already narrowed the match.
295
+ executorMatched = true;
296
+ }
297
+ else {
298
+ return null;
299
+ }
300
+ }
301
+ // Locator-bearing entries get a base tier of 1 (the locator match);
302
+ // filter-only entries start at 0 so a single filter doesn't tie a
303
+ // single locator. Filters then add 1 each — with the matchKind
304
+ // tie-break below, filter-only always loses to locator-bearing at
305
+ // the same final tier.
306
+ const hasLocator = targetKind !== null || executorMatched;
307
+ let tier = hasLocator ? 1 : 0;
308
+ if (projectsKind === 'filter') {
309
+ if (!projectName || !projectNode)
310
+ return null;
311
+ // Copy — `findMatchingProjects` prepends `*` for a leading negation
312
+ // and would otherwise mutate the shared nxJson entry.
313
+ const patterns = Array.isArray(entry.projects)
314
+ ? [...entry.projects]
315
+ : [entry.projects];
316
+ const matched = (0, find_matching_projects_1.findMatchingProjects)(patterns, {
317
+ [projectName]: projectNode,
318
+ });
319
+ if (!matched.includes(projectName))
320
+ return null;
321
+ tier++;
322
+ }
323
+ if (entry.plugin !== undefined) {
324
+ if (entry.plugin !== sourcePlugin)
325
+ return null;
326
+ tier++;
327
+ }
328
+ // Safety net for callers (e.g. direct unit-test calls) that bypass
329
+ // `normalizeTargetDefaults`: an entry with no locator and no real
330
+ // filter has tier 0 after processing — it would broadcast to every
331
+ // (root, target) in the workspace.
332
+ if (!hasLocator && tier === 0)
333
+ return null;
334
+ const matchKind = targetKind !== null && executorMatched
335
+ ? 'targetAndExecutor'
336
+ : executorMatched
337
+ ? 'executorOnly'
338
+ : targetKind === 'exact'
339
+ ? 'exactTarget'
340
+ : targetKind === 'glob'
341
+ ? 'globTarget'
342
+ : 'filterOnly';
343
+ return {
344
+ config: stripFilterKeys(entry),
345
+ tier,
346
+ matchKind,
347
+ index,
348
+ };
349
+ }
350
+ /**
351
+ * Specificity ordering for two candidate matches. Higher specificity
352
+ * wins because the more specific entry is the one the user most likely
353
+ * wrote to override a broader rule.
354
+ *
355
+ * 1. Tier — entries with `projects` or `plugin` filters are scoped
356
+ * narrower than unfiltered entries, so they outrank.
357
+ * 2. Match kind — within the same tier, more locator slots is more
358
+ * specific: `target+executor` > `executor-only` > `exactTarget` >
359
+ * `globTarget` > `filterOnly`. Note `executor-only` outranks
360
+ * `exactTarget`: a workspace-wide rule keyed on a specific executor
361
+ * is treated as more intentional than a target-name rule that might
362
+ * accidentally catch unrelated executors. `filterOnly` (no `target`
363
+ * and no `executor`, just `projects` and/or `plugin`) sits at the
364
+ * bottom — it's the explicit "least specific" tier that lets a bare
365
+ * `plugin: '@nx/jest/plugin'` apply to every jest-attributed target
366
+ * while still losing to any entry that names the target or executor.
367
+ * 3. Tie-break — later array index wins, so users can append an entry
368
+ * to override earlier ones without rewriting them.
369
+ */
370
+ function beats(a, b) {
371
+ if (a.tier !== b.tier)
372
+ return a.tier > b.tier;
373
+ const aRank = matchKindRank(a.matchKind);
374
+ const bRank = matchKindRank(b.matchKind);
375
+ if (aRank !== bRank)
376
+ return aRank > bRank;
377
+ return a.index > b.index;
378
+ }
379
+ function matchKindRank(kind) {
380
+ switch (kind) {
381
+ case 'targetAndExecutor':
382
+ return 4;
383
+ case 'executorOnly':
384
+ return 3;
385
+ case 'exactTarget':
386
+ return 2;
387
+ case 'globTarget':
388
+ return 1;
389
+ case 'filterOnly':
390
+ return 0;
391
+ }
392
+ }
393
+ /** Removes keys used only for locating the defaults, leaving the merge payload. */
394
+ function stripFilterKeys(entry) {
395
+ const { target, projects, plugin, ...rest } = entry;
396
+ return rest;
397
+ }
398
+ let hasWarnedAboutLegacyRecordShape = false;
399
+ /**
400
+ * Accept either the new array shape or the legacy record shape and return
401
+ * a normalized array. Record entries become `{ target: key, ...value }`
402
+ * — except executor-shaped keys (e.g. `@nx/vite:test`, `nx:run-commands`)
403
+ * which become `{ executor: key, ...value }` so the matcher treats them
404
+ * as executor matches rather than target-name matches.
405
+ *
406
+ * Disambiguation here is purely syntactic — `:` in a record key is
407
+ * genuinely ambiguous (target names can contain `:`). Callers that have
408
+ * access to the workspace's targets (the graph-construction path, the
409
+ * v23 migration) should prefer
410
+ * {@link normalizeTargetDefaultsAgainstRootMaps} or the migration's
411
+ * graph-based classifier so that ambiguous keys get classified by what
412
+ * the workspace actually contains. The warning below points end-users
413
+ * at `nx repair`, which runs the migration that durably resolves the
414
+ * ambiguity in nx.json on disk.
415
+ */
416
+ function normalizeTargetDefaults(raw) {
417
+ if (!raw)
418
+ return [];
419
+ const entries = Array.isArray(raw) ? raw : recordToEntries(raw);
420
+ return entries.filter(isWellFormedEntry);
421
+ }
422
+ function recordToEntries(raw) {
423
+ warnAboutLegacyRecordShapeOnce();
424
+ const out = [];
425
+ for (const key of Object.keys(raw)) {
426
+ const value = raw[key] ?? {};
427
+ out.push(...syntacticallyClassifyLegacyKey(key, value));
428
+ }
429
+ return out;
430
+ }
431
+ /**
432
+ * An entry is well-formed when it has at least one locator (`target` /
433
+ * `executor`) or a real filter (`projects` resolving to something other
434
+ * than empty/wildcard, or `plugin`). Pre-filtering here lets the matcher
435
+ * trust its inputs and skip the per-entry broadcast guard.
436
+ */
437
+ function isWellFormedEntry(entry) {
438
+ if (entry.target !== undefined)
439
+ return true;
440
+ if (entry.executor !== undefined)
441
+ return true;
442
+ if (entry.plugin !== undefined)
443
+ return true;
444
+ return classifyProjectsFilter(entry.projects) === 'filter';
445
+ }
446
+ /**
447
+ * Same shape contract as {@link normalizeTargetDefaults}, but classifies
448
+ * `:`-shaped record keys against the targets and executors actually
449
+ * present in the supplied rootMaps. When a key matches a target name in
450
+ * the workspace, it becomes a `target:` entry; when it matches an
451
+ * executor, an `executor:` entry; when it matches both, both entries are
452
+ * emitted (matching the v23 migration's "duplicate rather than guess"
453
+ * behavior so neither side of the match silently drops). Falls back to
454
+ * the syntactic heuristic when there's no evidence either way.
455
+ */
456
+ function normalizeTargetDefaultsAgainstRootMaps(raw, ...rootMaps) {
457
+ if (!raw)
458
+ return [];
459
+ if (Array.isArray(raw))
460
+ return raw;
461
+ warnAboutLegacyRecordShapeOnce();
462
+ const targetNames = new Set();
463
+ const executors = new Set();
464
+ for (const map of rootMaps) {
465
+ for (const cfg of Object.values(map)) {
466
+ const targets = cfg?.targets;
467
+ if (!targets)
468
+ continue;
469
+ for (const [name, target] of Object.entries(targets)) {
470
+ targetNames.add(name);
471
+ if (target?.executor)
472
+ executors.add(target.executor);
128
473
  }
129
474
  }
130
475
  }
131
- if (matchingTargetDefaultKey) {
132
- return targetDefaults[matchingTargetDefaultKey];
476
+ const out = [];
477
+ for (const key of Object.keys(raw)) {
478
+ const value = raw[key] ?? {};
479
+ if ((0, globs_1.isGlobPattern)(key)) {
480
+ out.push({ ...value, target: key });
481
+ continue;
482
+ }
483
+ const matchesTarget = targetNames.has(key);
484
+ const matchesExecutor = executors.has(key);
485
+ if (matchesTarget && matchesExecutor) {
486
+ out.push({ ...value, target: key }, { ...value, executor: key });
487
+ }
488
+ else if (matchesExecutor) {
489
+ out.push({ ...value, executor: key });
490
+ }
491
+ else if (matchesTarget) {
492
+ out.push({ ...value, target: key });
493
+ }
494
+ else {
495
+ out.push(...syntacticallyClassifyLegacyKey(key, value));
496
+ }
497
+ }
498
+ return out;
499
+ }
500
+ function syntacticallyClassifyLegacyKey(key, value) {
501
+ return [
502
+ key.includes(':') && !(0, globs_1.isGlobPattern)(key)
503
+ ? { ...value, executor: key }
504
+ : { ...value, target: key },
505
+ ];
506
+ }
507
+ function warnAboutLegacyRecordShapeOnce() {
508
+ if (hasWarnedAboutLegacyRecordShape)
509
+ return;
510
+ hasWarnedAboutLegacyRecordShape = true;
511
+ // Written to stderr (not stdout) so commands with structured stdout —
512
+ // e.g. `nx show project --json` — remain parseable.
513
+ const title = pc.yellow('NX nx.json uses the legacy record-shape `targetDefaults`');
514
+ const bodyLines = [
515
+ 'The object/record form of `targetDefaults` is deprecated. Nx still reads it for now, but the array form is required to use the new `projects` and `plugin` filters.',
516
+ 'Run `nx repair` to automatically convert `targetDefaults` to the array shape.',
517
+ ];
518
+ process.stderr.write(`${os_1.EOL}${title}${os_1.EOL}${os_1.EOL}${bodyLines
519
+ .map((l) => ` ${l}`)
520
+ .join(os_1.EOL)}${os_1.EOL}${os_1.EOL}`);
521
+ }
522
+ function resolveSourcePlugin(root, targetName, specifiedSourceMaps, defaultSourceMaps) {
523
+ // Default-plugin attribution overrides specified-plugin attribution in
524
+ // the merge, so we check it first. Only the executor/command keys are
525
+ // reliable — the top-level `targets.<name>` key tracks the last writer.
526
+ const executorKey = (0, source_maps_1.targetOptionSourceMapKey)(targetName, 'executor');
527
+ const commandKey = (0, source_maps_1.targetOptionSourceMapKey)(targetName, 'command');
528
+ const candidates = [
529
+ pluginFromSourceMap(defaultSourceMaps, root, executorKey),
530
+ pluginFromSourceMap(defaultSourceMaps, root, commandKey),
531
+ pluginFromSourceMap(specifiedSourceMaps, root, executorKey),
532
+ pluginFromSourceMap(specifiedSourceMaps, root, commandKey),
533
+ ];
534
+ for (const candidate of candidates) {
535
+ if (candidate && candidate !== 'nx/target-defaults')
536
+ return candidate;
133
537
  }
134
- return null;
538
+ return undefined;
539
+ }
540
+ function pluginFromSourceMap(maps, root, key) {
541
+ const entry = maps?.[root]?.[key];
542
+ return entry?.[1];
543
+ }
544
+ // Walks both layered rootMaps and produces a name → ProjectGraphProjectNode
545
+ // view for `findMatchingProjects` to consult. Default-plugin-only
546
+ // projects are included — they're the bulk of typical workspaces and
547
+ // `projects:` filters need to apply to them too. Tags are unioned across
548
+ // layers so tag-based filters see all contributions.
549
+ //
550
+ // We don't reuse `mergeProjectConfigurationIntoRootMap` here: it does a
551
+ // full project-config merge (targets, named inputs, source maps, ...)
552
+ // keyed by root, while this function only needs name + tags keyed by
553
+ // name. The full merge would be substantial wasted work on every graph
554
+ // build.
555
+ function buildProjectNodesAndRootToName(specifiedPluginRootMap, defaultPluginRootMap) {
556
+ const projectNodesByName = {};
557
+ const rootToName = new Map();
558
+ const addFromMap = (map) => {
559
+ for (const root of Object.keys(map)) {
560
+ const cfg = map[root];
561
+ const name = cfg?.name;
562
+ if (!name)
563
+ continue;
564
+ if (projectNodesByName[name]) {
565
+ const existingTags = projectNodesByName[name].data.tags ?? [];
566
+ const newTags = cfg.tags ?? [];
567
+ projectNodesByName[name].data.tags = Array.from(new Set([...existingTags, ...newTags]));
568
+ }
569
+ else {
570
+ projectNodesByName[name] = {
571
+ name,
572
+ type: cfg.projectType === 'application' ? 'app' : 'lib',
573
+ data: { root, tags: cfg.tags ?? [] },
574
+ };
575
+ rootToName.set(root, name);
576
+ }
577
+ }
578
+ };
579
+ addFromMap(specifiedPluginRootMap);
580
+ addFromMap(defaultPluginRootMap);
581
+ return { projectNodesByName, rootToName };
135
582
  }
@@ -60,11 +60,19 @@ export type MergeError = AggregateCreateNodesError | MergeNodesError | ProjectsW
60
60
  /**
61
61
  * Merges create nodes results into a single rootMap.
62
62
  *
63
- * Default plugin results are merged twice: first into an intermediate
64
- * rootMap with unresolved spread sentinels preserved, so target
65
- * defaults selection sees the real merged shape of defaults; then
66
- * applied as a single layer onto the main rootMap where the preserved
67
- * spreads resolve against the specified + target-defaults base.
63
+ * Specified plugin results are merged once into the manager. Default
64
+ * plugin results are first staged into an intermediate rootMap (with
65
+ * `'...'` spreads deferred) so that synthesis can read each layer's
66
+ * contribution without re-running the merge. The synthetic result from
67
+ * `createTargetDefaultsResults` is then merged into the manager, and
68
+ * the staged intermediate is replayed on top — that replay is where
69
+ * deferred spreads expand against the final (specified + synth) base.
70
+ *
71
+ * Synthesis itself doesn't materialize a second rootMap. Per
72
+ * (root, target) it does an on-the-fly merge of the two layered
73
+ * contributions to learn the eventual executor/command, then matches
74
+ * defaults against that merged shape. This keeps specified-plugin
75
+ * merge work to a single pass.
68
76
  */
69
77
  export declare function mergeCreateNodesResults(specifiedResults: CreateNodesResultEntry[][], defaultResults: CreateNodesResultEntry[][], nxJsonConfiguration: NxJsonConfiguration, workspaceRoot: string, errors: MergeError[]): {
70
78
  projectRootMap: Record<string, ProjectConfiguration>;