nx 23.2.0-beta.7 → 23.2.0-beta.9

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 (188) hide show
  1. package/dist/bin/init-local.js +3 -5
  2. package/dist/release/changelog-renderer/index.js +4 -5
  3. package/dist/src/adapter/ngcli-adapter.js +60 -1
  4. package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +2 -2
  5. package/dist/src/command-line/completion/command-object.js +7 -12
  6. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +17 -23
  7. package/dist/src/command-line/format/format.js +84 -101
  8. package/dist/src/command-line/generate/generate.js +35 -35
  9. package/dist/src/command-line/import/import.js +30 -40
  10. package/dist/src/command-line/init/ai-agent-prompts.js +5 -11
  11. package/dist/src/command-line/init/command-object.js +4 -2
  12. package/dist/src/command-line/init/configure-plugins.js +4 -1
  13. package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +12 -32
  14. package/dist/src/command-line/init/implementation/add-nx-to-nest.js +17 -21
  15. package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +8 -21
  16. package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +3 -17
  17. package/dist/src/command-line/init/implementation/angular/index.js +10 -15
  18. package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +2 -0
  19. package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +8 -2
  20. package/dist/src/command-line/init/implementation/check-compatible-with-plugins.js +2 -0
  21. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +5 -0
  22. package/dist/src/command-line/init/implementation/format.d.ts +18 -0
  23. package/dist/src/command-line/init/implementation/format.js +114 -0
  24. package/dist/src/command-line/init/implementation/utils.js +8 -0
  25. package/dist/src/command-line/init/init-v1.js +15 -18
  26. package/dist/src/command-line/init/init-v2.js +37 -56
  27. package/dist/src/command-line/migrate/agentic/definitions.js +35 -8
  28. package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +22 -3
  29. package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +13 -10
  30. package/dist/src/command-line/migrate/agentic/handoff.d.ts +3 -1
  31. package/dist/src/command-line/migrate/agentic/handoff.js +4 -2
  32. package/dist/src/command-line/migrate/agentic/run-step.js +1 -0
  33. package/dist/src/command-line/migrate/agentic/runner.js +24 -24
  34. package/dist/src/command-line/migrate/agentic/select.js +20 -30
  35. package/dist/src/command-line/migrate/agentic/types.d.ts +19 -3
  36. package/dist/src/command-line/migrate/agentic/types.js +13 -4
  37. package/dist/src/command-line/migrate/command-object.d.ts +3 -0
  38. package/dist/src/command-line/migrate/command-object.js +13 -0
  39. package/dist/src/command-line/migrate/execute-migration.d.ts +14 -0
  40. package/dist/src/command-line/migrate/execute-migration.js +30 -9
  41. package/dist/src/command-line/migrate/migrate-analytics.d.ts +28 -0
  42. package/dist/src/command-line/migrate/migrate-analytics.js +51 -1
  43. package/dist/src/command-line/migrate/migrate-commits.d.ts +8 -2
  44. package/dist/src/command-line/migrate/migrate-commits.js +66 -19
  45. package/dist/src/command-line/migrate/migrate-config.d.ts +4 -2
  46. package/dist/src/command-line/migrate/migrate-config.js +12 -4
  47. package/dist/src/command-line/migrate/migrate.d.ts +13 -2
  48. package/dist/src/command-line/migrate/migrate.js +243 -80
  49. package/dist/src/command-line/migrate/multi-major.js +7 -10
  50. package/dist/src/command-line/migrate/resolve-package-version.js +4 -8
  51. package/dist/src/command-line/migrate/run/agent-output.d.ts +20 -0
  52. package/dist/src/command-line/migrate/run/agent-output.js +65 -0
  53. package/dist/src/command-line/migrate/run/index.d.ts +7 -0
  54. package/dist/src/command-line/migrate/run/index.js +19 -1
  55. package/dist/src/command-line/migrate/run/orchestrator.d.ts +20 -0
  56. package/dist/src/command-line/migrate/run/orchestrator.js +1200 -0
  57. package/dist/src/command-line/migrate/run/run-id.d.ts +16 -0
  58. package/dist/src/command-line/migrate/run/run-id.js +56 -0
  59. package/dist/src/command-line/migrate/run/run-state.d.ts +157 -0
  60. package/dist/src/command-line/migrate/run/run-state.js +438 -0
  61. package/dist/src/command-line/migrate/run/state-lock.d.ts +25 -0
  62. package/dist/src/command-line/migrate/run/state-lock.js +76 -0
  63. package/dist/src/command-line/migrate/run/state-machine.d.ts +84 -0
  64. package/dist/src/command-line/migrate/run/state-machine.js +315 -0
  65. package/dist/src/command-line/migrate/run/util.d.ts +58 -0
  66. package/dist/src/command-line/migrate/run/util.js +139 -7
  67. package/dist/src/command-line/migrate/run/worker.d.ts +1 -0
  68. package/dist/src/command-line/migrate/run/worker.js +308 -45
  69. package/dist/src/command-line/migrate/safe-prompt.d.ts +14 -26
  70. package/dist/src/command-line/migrate/safe-prompt.js +32 -43
  71. package/dist/src/command-line/migrate/step-actions.d.ts +5 -0
  72. package/dist/src/command-line/migrate/step-actions.js +12 -0
  73. package/dist/src/command-line/migrate/text.d.ts +18 -0
  74. package/dist/src/command-line/migrate/text.js +26 -0
  75. package/dist/src/command-line/migrate/version-skew-guard.d.ts +6 -4
  76. package/dist/src/command-line/migrate/version-skew-guard.js +34 -14
  77. package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +16 -20
  78. package/dist/src/command-line/release/changelog.js +6 -17
  79. package/dist/src/command-line/release/plan.js +15 -28
  80. package/dist/src/command-line/release/release.js +6 -17
  81. package/dist/src/command-line/release/utils/remote-release-clients/github.js +16 -22
  82. package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +13 -22
  83. package/dist/src/command-line/release/utils/resolve-semver-specifier.js +19 -41
  84. package/dist/src/command-line/release/version/resolve-current-version.js +7 -10
  85. package/dist/src/command-line/release/version.js +2 -2
  86. package/dist/src/core/graph/main.js +1 -1
  87. package/dist/src/daemon/client/client.js +11 -2
  88. package/dist/src/devkit-internals.d.ts +7 -2
  89. package/dist/src/devkit-internals.js +22 -6
  90. package/dist/src/generators/internal-utils/{format-changed-files-with-prettier-if-available.d.ts → format-changed-files.d.ts} +6 -6
  91. package/dist/src/generators/internal-utils/format-changed-files.js +163 -0
  92. package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.d.ts +15 -0
  93. package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.js +21 -3
  94. package/dist/src/migrations/update-15-0-0/prefix-outputs.js +2 -2
  95. package/dist/src/migrations/update-16-0-0/remove-nrwl-cli.js +2 -2
  96. package/dist/src/migrations/update-16-0-0/update-depends-on-to-tokens.js +2 -2
  97. package/dist/src/migrations/update-16-0-0/update-nx-cloud-runner.js +2 -2
  98. package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +2 -2
  99. package/dist/src/migrations/update-17-0-0/rm-default-collection-npm-scope.js +2 -2
  100. package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +2 -2
  101. package/dist/src/migrations/update-17-2-0/move-default-base.js +2 -2
  102. package/dist/src/migrations/update-18-0-0/disable-crystal-for-existing-workspaces.js +2 -2
  103. package/dist/src/migrations/update-19-2-4/set-project-name.js +2 -2
  104. package/dist/src/migrations/update-20-0-0/move-use-daemon-process.js +2 -2
  105. package/dist/src/migrations/update-20-0-1/use-legacy-cache.js +2 -2
  106. package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.js +2 -2
  107. package/dist/src/migrations/update-21-0-0/release-version-config-changes.js +2 -2
  108. package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.js +2 -2
  109. package/dist/src/migrations/update-21-0-0/remove-legacy-cache.js +2 -2
  110. package/dist/src/migrations/update-22-0-0/consolidate-release-tag-config.js +2 -2
  111. package/dist/src/migrations/update-22-0-0/release-version-config-changes.js +2 -2
  112. package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.js +2 -2
  113. package/dist/src/migrations/update-22-6-0/add-claude-settings-local-to-git-ignore.js +2 -2
  114. package/dist/src/migrations/update-22-6-0/add-claude-worktrees-to-git-ignore.js +2 -2
  115. package/dist/src/migrations/update-22-7-0/add-polygraph-to-git-ignore.js +2 -2
  116. package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +2 -2
  117. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  118. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  119. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  120. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  121. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  122. package/dist/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +3 -3
  123. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  124. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +128 -2
  125. package/dist/src/tasks-runner/run-command.js +17 -32
  126. package/dist/src/tasks-runner/task-env.js +5 -2
  127. package/dist/src/tasks-runner/utils.js +2 -6
  128. package/dist/src/utils/analytics-prompt.js +4 -7
  129. package/dist/src/utils/chunkify.d.ts +7 -1
  130. package/dist/src/utils/chunkify.js +10 -3
  131. package/dist/src/utils/exit-codes.d.ts +9 -0
  132. package/dist/src/utils/exit-codes.js +19 -0
  133. package/dist/src/utils/fileutils.d.ts +5 -0
  134. package/dist/src/utils/fileutils.js +7 -2
  135. package/dist/src/utils/formatters/index.d.ts +13 -0
  136. package/dist/src/utils/formatters/index.js +74 -0
  137. package/dist/src/utils/formatters/oxfmt.d.ts +32 -0
  138. package/dist/src/utils/formatters/oxfmt.js +764 -0
  139. package/dist/src/utils/formatters/prettier.d.ts +26 -0
  140. package/dist/src/utils/formatters/prettier.js +201 -0
  141. package/dist/src/utils/formatters/shared.d.ts +5 -0
  142. package/dist/src/utils/formatters/shared.js +8 -0
  143. package/dist/src/utils/git-utils.d.ts +33 -2
  144. package/dist/src/utils/git-utils.js +156 -8
  145. package/dist/src/utils/ignore.d.ts +47 -5
  146. package/dist/src/utils/ignore.js +93 -11
  147. package/dist/src/utils/long-running-target.d.ts +10 -0
  148. package/dist/src/utils/long-running-target.js +19 -0
  149. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  150. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  151. package/dist/src/utils/min-release-age/packument.js +1 -1
  152. package/dist/src/utils/nx-console-prompt.js +3 -6
  153. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  154. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  155. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  156. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  157. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  158. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  159. package/dist/src/utils/package-manager.d.ts +21 -2
  160. package/dist/src/utils/package-manager.js +244 -47
  161. package/dist/src/utils/params.d.ts +7 -1
  162. package/dist/src/utils/params.js +64 -6
  163. package/dist/src/utils/prompt-helpers.d.ts +53 -0
  164. package/dist/src/utils/prompt-helpers.js +111 -0
  165. package/dist/src/utils/provenance.js +6 -14
  166. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  167. package/dist/src/utils/registry-config/bun.js +257 -0
  168. package/dist/src/utils/registry-config/index.d.ts +13 -0
  169. package/dist/src/utils/registry-config/index.js +102 -0
  170. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  171. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  172. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  173. package/dist/src/utils/registry-config/utils.js +496 -0
  174. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  175. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  176. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  177. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  178. package/dist/src/utils/safe-spawn.d.ts +24 -0
  179. package/dist/src/utils/safe-spawn.js +104 -0
  180. package/dist/src/utils/write-formatted-json-file.d.ts +3 -2
  181. package/dist/src/utils/write-formatted-json-file.js +5 -4
  182. package/migrations.json +6 -0
  183. package/package.json +17 -13
  184. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +0 -88
  185. package/dist/src/utils/is-using-prettier.d.ts +0 -3
  186. package/dist/src/utils/is-using-prettier.js +0 -62
  187. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  188. package/dist/src/utils/min-release-age/npmrc.js +0 -45
@@ -5,6 +5,8 @@ exports.normalizeTarget = normalizeTarget;
5
5
  exports.validateAndNormalizeProjectRootMap = validateAndNormalizeProjectRootMap;
6
6
  const executor_utils_1 = require("../../../command-line/run/executor-utils");
7
7
  const fileutils_1 = require("../../../utils/fileutils");
8
+ const long_running_target_1 = require("../../../utils/long-running-target");
9
+ const output_1 = require("../../../utils/output");
8
10
  const to_project_name_1 = require("../../../config/to-project-name");
9
11
  const error_types_1 = require("../../error-types");
10
12
  const target_merging_1 = require("./target-merging");
@@ -65,15 +67,137 @@ function normalizeTarget(target, project, workspaceRoot, projectsMap, errorMsgKe
65
67
  }
66
68
  return target;
67
69
  }
70
+ // TODO(v24): remove the legacy target-name cache fallback and its warning.
71
+ // Removal needs a second mechanism for plugin-inferred targets, which the
72
+ // accompanying migration cannot reach.
73
+ /**
74
+ * Whether `target` is cacheable only by way of the legacy name-based fallback:
75
+ * the exact target-name key of `targetDefaults` declares `cache: true`, but an
76
+ * executor key won target-default resolution instead, so the merged target never
77
+ * received it.
78
+ *
79
+ * A `true` result means the user's `cache: true` silently lost, so this doubles
80
+ * as the condition for warning them that the name key is being shadowed.
81
+ */
82
+ function isLegacyCachedTarget(targetName, targetDefaults, target) {
83
+ // Resolution already decided `cache`, so the name key isn't shadowed.
84
+ if (target.cache !== undefined) {
85
+ return false;
86
+ }
87
+ if (isLongRunningTarget(targetName, target)) {
88
+ return false;
89
+ }
90
+ // Restricted to shadowing, which is narrower than what pre-23 restored: that
91
+ // derivation matched on target name alone, so a name key dropped as
92
+ // incompatible (its entry declared a foreign executor) was cacheable too.
93
+ // Restoring that as well would mean writing `cache` with no key to name in
94
+ // the warning, and no migration able to retire it. Deliberately not covered.
95
+ if (!findShadowingTargetDefaultKey(targetDefaults, target)) {
96
+ return false;
97
+ }
98
+ return declaresCacheTrue(targetDefaults?.[targetName]);
99
+ }
100
+ /**
101
+ * Whether the name key declares `cache: true` on an entry that always applies.
102
+ *
103
+ * Filters are deliberately not evaluated. They cannot express a pre-23 config
104
+ * (the filtered array shape postdates the behavior being restored), and a
105
+ * filtered entry declaring `cache` may or may not apply to this project — so
106
+ * rather than guess, a filtered `cache` declares the value unknowable and
107
+ * nothing is restored. Among unfiltered entries the last wins, matching the
108
+ * in-key merge order.
109
+ */
110
+ function declaresCacheTrue(value) {
111
+ if (!value) {
112
+ return false;
113
+ }
114
+ const entries = Array.isArray(value) ? value : [value];
115
+ let declared;
116
+ for (const entry of entries) {
117
+ // `nx.json` is hand-edited; a null or scalar entry would throw here.
118
+ if (!entry || typeof entry !== 'object')
119
+ continue;
120
+ if (entry.cache === undefined)
121
+ continue;
122
+ if (entry.filter)
123
+ return false;
124
+ declared = entry.cache;
125
+ }
126
+ return declared === true;
127
+ }
128
+ /**
129
+ * The normalization-time half of the pre-23 `longRunningTask` guard, which kept
130
+ * `cacheableOperations` from ever making these cacheable. Its remaining clause
131
+ * — `task.overrides['watch']` — is a runtime invocation override with no target
132
+ * equivalent, so it has no counterpart here.
133
+ */
134
+ function isLongRunningTarget(targetName, target) {
135
+ return !!target.continuous || (0, long_running_target_1.isLongRunningTargetName)(targetName);
136
+ }
137
+ /**
138
+ * The `targetDefaults` key that beat the target-name key for `target`. Only an
139
+ * executor key can: key precedence puts the exact target name ahead of every
140
+ * glob, so nothing else outranks it. Undefined when the name key lost for
141
+ * another reason (e.g. its entry declared a foreign executor and was dropped as
142
+ * incompatible) — see {@link isLegacyCachedTarget} for why that case is left
143
+ * alone even though pre-23 restored it.
144
+ *
145
+ * `hasOwnProperty` rather than a lookup: an executor named `__proto__` resolves
146
+ * through the prototype chain to a truthy object, which would report a key the
147
+ * user never wrote.
148
+ */
149
+ function findShadowingTargetDefaultKey(targetDefaults, target) {
150
+ return target.executor &&
151
+ targetDefaults &&
152
+ Object.prototype.hasOwnProperty.call(targetDefaults, target.executor)
153
+ ? target.executor
154
+ : undefined;
155
+ }
156
+ /**
157
+ * Emits a single grouped warning for every (shadowing key, target-name key)
158
+ * pair that relied on the deprecated fallback. Grouping matters because the
159
+ * same pair recurs in every affected project — a per-target warning would
160
+ * print hundreds of identical lines in a large workspace.
161
+ */
162
+ function warnAboutLegacyCachedTargets(legacyCacheReads) {
163
+ if (legacyCacheReads.size === 0) {
164
+ return;
165
+ }
166
+ const bodyLines = [];
167
+ for (const [shadowingKey, targetKeys] of legacyCacheReads) {
168
+ for (const targetKey of targetKeys) {
169
+ bodyLines.push(` - "${shadowingKey}" does not set "cache", so it was read from "${targetKey}"`);
170
+ }
171
+ }
172
+ bodyLines.push('', 'An executor key applies to every target that resolves through it, so exclude any continuous target before setting "cache" on one — a target that is both cacheable and continuous is rejected.', 'Target defaults resolve to a single key rather than merging, so an executor key hides the target name key entirely.', 'Set "cache" on the executor key to keep these targets cacheable — reading it from the target name key is deprecated and will be removed in Nx 24.');
173
+ output_1.output.warn({
174
+ title: 'Some targets are only cacheable through a deprecated fallback.',
175
+ bodyLines,
176
+ });
177
+ }
68
178
  function normalizeTargets(project, sourceMaps, nxJsonConfiguration, workspaceRoot,
69
179
  /**
70
180
  * Project configurations keyed by project name
71
181
  */
72
- projects) {
182
+ projects,
183
+ /**
184
+ * Shadowing `targetDefaults` key -> target name keys its `cache` was read
185
+ * from. Accumulated across projects so the deprecation warns once per pair.
186
+ */
187
+ legacyCacheReads) {
73
188
  const targetErrorMessage = [];
74
189
  for (const targetName in project.targets) {
75
190
  project.targets[targetName] = normalizeTarget(project.targets[targetName], project, workspaceRoot, projects, [project.root, targetName].join(':'));
76
191
  const target = project.targets[targetName];
192
+ const targetDefaults = nxJsonConfiguration.targetDefaults;
193
+ if (isLegacyCachedTarget(targetName, targetDefaults, target)) {
194
+ target.cache = true;
195
+ // Always defined: `isLegacyCachedTarget` returns false without it.
196
+ const shadowingKey = findShadowingTargetDefaultKey(targetDefaults, target);
197
+ const targetKeys = legacyCacheReads.get(shadowingKey) ?? new Set();
198
+ targetKeys.add(targetName);
199
+ legacyCacheReads.set(shadowingKey, targetKeys);
200
+ }
77
201
  if (
78
202
  // If the target has no executor or command, it doesn't do anything
79
203
  !target.executor &&
@@ -106,6 +230,7 @@ function validateAndNormalizeProjectRootMap(workspaceRoot, projectRootMap, nxJso
106
230
  const conflicts = new Map();
107
231
  const projectRootsWithNoName = [];
108
232
  const validityErrors = [];
233
+ const legacyCacheReads = new Map();
109
234
  for (const root in projectRootMap) {
110
235
  const project = projectRootMap[root];
111
236
  // We're setting `// targets` as a comment `targets` is empty due to Project Crystal.
@@ -155,7 +280,7 @@ function validateAndNormalizeProjectRootMap(workspaceRoot, projectRootMap, nxJso
155
280
  for (const root in projectRootMap) {
156
281
  const project = projectRootMap[root];
157
282
  try {
158
- normalizeTargets(project, sourceMaps, nxJsonConfiguration, workspaceRoot, projects);
283
+ normalizeTargets(project, sourceMaps, nxJsonConfiguration, workspaceRoot, projects, legacyCacheReads);
159
284
  }
160
285
  catch (e) {
161
286
  if (e instanceof error_types_1.WorkspaceValidityError) {
@@ -166,6 +291,7 @@ function validateAndNormalizeProjectRootMap(workspaceRoot, projectRootMap, nxJso
166
291
  }
167
292
  }
168
293
  }
294
+ warnAboutLegacyCachedTargets(legacyCacheReads);
169
295
  const errors = [];
170
296
  if (conflicts.size > 0) {
171
297
  errors.push(new error_types_1.MultipleProjectsWithSameNameError(conflicts, projects));
@@ -8,7 +8,7 @@ exports.constructLifeCycles = constructLifeCycles;
8
8
  exports.getRunner = getRunner;
9
9
  exports.getRunnerOptions = getRunnerOptions;
10
10
  const tslib_1 = require("tslib");
11
- const enquirer_1 = require("enquirer");
11
+ const prompt_helpers_1 = require("../utils/prompt-helpers");
12
12
  const node_util_1 = require("node:util");
13
13
  const nx_json_1 = require("../config/nx-json");
14
14
  const client_1 = require("../daemon/client/client");
@@ -599,23 +599,19 @@ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, project
599
599
  }
600
600
  async function promptForApplyingSyncGeneratorChanges() {
601
601
  try {
602
- const promptConfig = {
603
- name: 'applyChanges',
604
- type: 'autocomplete',
605
- message: 'Would you like to sync the identified changes to get your workspace up to date?',
602
+ // No footer slot, so the opt-out note is part of the message.
603
+ const applyChanges = await (0, prompt_helpers_1.selectPrompt)({
604
+ message: `Would you like to sync the identified changes to get your workspace up to date?${pc.dim('\nYou can skip this prompt by setting the `sync.applyChanges` option to `true` in your `nx.json`.\nFor more information, refer to the docs: https://nx.dev/concepts/sync-generators.')}`,
606
605
  choices: [
606
+ { value: 'yes', label: 'Yes, sync the changes and run the tasks' },
607
607
  {
608
- name: 'yes',
609
- message: 'Yes, sync the changes and run the tasks',
610
- },
611
- {
612
- name: 'no',
613
- message: 'No, run the tasks without syncing the changes',
608
+ value: 'no',
609
+ label: 'No, run the tasks without syncing the changes',
614
610
  },
615
611
  ],
616
- footer: () => pc.dim('\nYou can skip this prompt by setting the `sync.applyChanges` option to `true` in your `nx.json`.\nFor more information, refer to the docs: https://nx.dev/concepts/sync-generators.'),
617
- };
618
- return await (0, enquirer_1.prompt)([promptConfig]).then(({ applyChanges }) => applyChanges === 'yes');
612
+ onCancel: () => process.exit(1),
613
+ });
614
+ return applyChanges === 'yes';
619
615
  }
620
616
  catch {
621
617
  process.exit(1);
@@ -623,26 +619,15 @@ async function promptForApplyingSyncGeneratorChanges() {
623
619
  }
624
620
  async function confirmRunningTasksWithSyncFailures() {
625
621
  try {
626
- const promptConfig = {
627
- name: 'runTasks',
628
- type: 'autocomplete',
629
- message: 'Would you like to ignore the sync failures and continue running the tasks?',
622
+ const runTasks = await (0, prompt_helpers_1.selectPrompt)({
623
+ message: `Would you like to ignore the sync failures and continue running the tasks?${pc.dim(`\nWhen running in CI and there are sync failures, the tasks won't run. Addressing the errors above is highly recommended to prevent failures in CI.`)}`,
630
624
  choices: [
631
- {
632
- name: 'yes',
633
- message: 'Yes, ignore the failures and run the tasks',
634
- },
635
- {
636
- name: 'no',
637
- message: `No, don't run the tasks`,
638
- },
625
+ { value: 'yes', label: 'Yes, ignore the failures and run the tasks' },
626
+ { value: 'no', label: `No, don't run the tasks` },
639
627
  ],
640
- footer: () => pc.dim(`\nWhen running in CI and there are sync failures, the tasks won't run. Addressing the errors above is highly recommended to prevent failures in CI.`),
641
- };
642
- const runTasks = await (0, enquirer_1.prompt)([
643
- promptConfig,
644
- ]).then(({ runTasks }) => runTasks === 'yes');
645
- if (!runTasks) {
628
+ onCancel: () => process.exit(1),
629
+ });
630
+ if (runTasks !== 'yes') {
646
631
  process.exit(1);
647
632
  }
648
633
  }
@@ -166,10 +166,13 @@ function getOwnerTargetForTask(task, graph) {
166
166
  for (const targets of Object.values(project.data.metadata.targetGroups)) {
167
167
  if (targets.includes(task.target.target)) {
168
168
  for (const target of targets) {
169
- if (project.data.targets[target].metadata?.nonAtomizedTarget) {
169
+ // a target group can name a target the project does not define —
170
+ // inference plugins build the group and the targets separately, so
171
+ // the two can disagree. skip the phantom rather than dereferencing it.
172
+ if (project.data.targets[target]?.metadata?.nonAtomizedTarget) {
170
173
  return [
171
174
  target,
172
- project.data.targets[target].metadata?.nonAtomizedTarget,
175
+ project.data.targets[target]?.metadata?.nonAtomizedTarget,
173
176
  ];
174
177
  }
175
178
  }
@@ -36,6 +36,7 @@ const fileutils_1 = require("../utils/fileutils");
36
36
  const find_matching_projects_1 = require("../utils/find-matching-projects");
37
37
  const legacy_depends_on_warning_1 = require("./legacy-depends-on-warning");
38
38
  const globs_1 = require("../utils/globs");
39
+ const long_running_target_1 = require("../utils/long-running-target");
39
40
  const path_1 = require("../utils/path");
40
41
  const serialize_overrides_into_command_line_1 = require("../utils/serialize-overrides-into-command-line");
41
42
  const split_target_1 = require("../utils/split-target");
@@ -429,14 +430,9 @@ function isCacheableTask(task) {
429
430
  return task.cache;
430
431
  }
431
432
  function longRunningTask(task) {
432
- const t = task.target.target;
433
433
  return (task.continuous ||
434
434
  (!!task.overrides['watch'] && task.overrides['watch'] !== 'false') ||
435
- t.endsWith(':watch') ||
436
- t.endsWith('-watch') ||
437
- t === 'serve' ||
438
- t === 'dev' ||
439
- t === 'start');
435
+ (0, long_running_target_1.isLongRunningTargetName)(task.target.target));
440
436
  }
441
437
  // TODO: vsavkin remove when nx-cloud doesn't depend on it
442
438
  function unparse(options) {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ensureAnalyticsPreferenceSet = ensureAnalyticsPreferenceSet;
4
4
  exports.promptForAnalyticsPreference = promptForAnalyticsPreference;
5
5
  const fs_1 = require("fs");
6
- const enquirer_1 = require("enquirer");
6
+ const prompt_helpers_1 = require("./prompt-helpers");
7
7
  const path_1 = require("path");
8
8
  const output_1 = require("./output");
9
9
  const is_ci_1 = require("./is-ci");
@@ -47,16 +47,13 @@ async function promptForAnalyticsPreference() {
47
47
  'Learn more: https://cloud.nx.app/privacy',
48
48
  ],
49
49
  });
50
- const { enableAnalytics } = await (0, enquirer_1.prompt)({
51
- type: 'confirm',
52
- name: 'enableAnalytics',
50
+ return await (0, prompt_helpers_1.confirmationPrompt)({
53
51
  message: 'Share usage data with the Nx team?',
54
- initial: true,
52
+ // Cancelling is a decline, not a failure.
53
+ onCancel: () => false,
55
54
  });
56
- return enableAnalytics;
57
55
  }
58
56
  catch {
59
- // User cancelled - default to false
60
57
  return false;
61
58
  }
62
59
  }
@@ -1,4 +1,10 @@
1
- export declare function chunkify(target: string[], maxChunkLength?: number): string[][];
1
+ export declare function chunkify(target: string[], maxChunkLength?: number,
2
+ /**
3
+ * How long each entry will be once it reaches the command line. Callers that
4
+ * quote or escape afterwards pass that transformation's length here, so the
5
+ * chunk is sized against what is actually spawned rather than the raw string.
6
+ */
7
+ measure?: (item: string) => number): string[][];
2
8
  /**
3
9
  * Get the maximum length of a command-line argument string based on current platform
4
10
  *
@@ -3,22 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.chunkify = chunkify;
4
4
  exports.getMaxArgLength = getMaxArgLength;
5
5
  const TERMINAL_SIZE = getMaxArgLength();
6
- function chunkify(target, maxChunkLength = TERMINAL_SIZE - 500) {
6
+ function chunkify(target, maxChunkLength = TERMINAL_SIZE - 500,
7
+ /**
8
+ * How long each entry will be once it reaches the command line. Callers that
9
+ * quote or escape afterwards pass that transformation's length here, so the
10
+ * chunk is sized against what is actually spawned rather than the raw string.
11
+ */
12
+ measure = (item) => item.length) {
7
13
  const chunks = [];
8
14
  let currentChunk = [];
9
15
  let currentChunkLength = 0;
10
16
  for (const file of target) {
17
+ const length = measure(file);
11
18
  if (
12
19
  // Prevent empty chunk if first file path is longer than maxChunkLength
13
20
  currentChunk.length &&
14
21
  // +1 accounts for the space between file names
15
- currentChunkLength + file.length + 1 >= maxChunkLength) {
22
+ currentChunkLength + length + 1 >= maxChunkLength) {
16
23
  chunks.push(currentChunk);
17
24
  currentChunk = [];
18
25
  currentChunkLength = 0;
19
26
  }
20
27
  currentChunk.push(file);
21
- currentChunkLength += file.length + 1;
28
+ currentChunkLength += length + 1;
22
29
  }
23
30
  chunks.push(currentChunk);
24
31
  return chunks;
@@ -13,3 +13,12 @@ export declare const EXPECTED_TERMINATION_SIGNALS: Set<number>;
13
13
  * Handles both Linux exact-match and macOS strsignal formats (e.g. "Terminated by Hangup: 1").
14
14
  */
15
15
  export declare function messageToCode(message: string): number;
16
+ /**
17
+ * Ends the process the way an interrupted process ends: by SIGINT, not by
18
+ * exiting with its conventional code.
19
+ *
20
+ * A shell reports 130 either way, but a parent using waitpid sees
21
+ * `signal: 'SIGINT'` rather than `code: 130`, which is what tools wrapping nx
22
+ * check to tell "the user pressed Ctrl+C" from "the command failed".
23
+ */
24
+ export declare function exitAsInterrupted(): never;
@@ -4,6 +4,7 @@ exports.EXPECTED_TERMINATION_SIGNALS = void 0;
4
4
  exports.signalToCode = signalToCode;
5
5
  exports.codeToSignal = codeToSignal;
6
6
  exports.messageToCode = messageToCode;
7
+ exports.exitAsInterrupted = exitAsInterrupted;
7
8
  /**
8
9
  * Translates NodeJS signals to numeric exit code
9
10
  * @param signal
@@ -73,3 +74,21 @@ function messageToCode(message) {
73
74
  return 1;
74
75
  }
75
76
  }
77
+ /**
78
+ * Ends the process the way an interrupted process ends: by SIGINT, not by
79
+ * exiting with its conventional code.
80
+ *
81
+ * A shell reports 130 either way, but a parent using waitpid sees
82
+ * `signal: 'SIGINT'` rather than `code: 130`, which is what tools wrapping nx
83
+ * check to tell "the user pressed Ctrl+C" from "the command failed".
84
+ */
85
+ function exitAsInterrupted() {
86
+ // Windows has no signal disposition to inherit - `process.kill` there
87
+ // terminates with an arbitrary code - so keep the 128+SIGINT convention.
88
+ if (process.platform !== 'win32') {
89
+ // Any listener would swallow this; the default action is what terminates.
90
+ process.removeAllListeners('SIGINT');
91
+ process.kill(process.pid, 'SIGINT');
92
+ }
93
+ process.exit(130);
94
+ }
@@ -27,6 +27,11 @@ interface YamlReadOptions {
27
27
  * Compatibility with JSON.parse behaviour. If true, then duplicate keys in a mapping will override values rather than throwing an error.
28
28
  */
29
29
  json?: boolean;
30
+ /**
31
+ * Resolves only the tags every YAML parser must support, so every scalar stays
32
+ * a string instead of `true` or `12`.
33
+ */
34
+ failsafe?: boolean;
30
35
  }
31
36
  /**
32
37
  * Reads a YAML file and returns the object the YAML content represents.
@@ -41,8 +41,13 @@ function readJsonFile(path, options) {
41
41
  */
42
42
  function readYamlFile(path, options) {
43
43
  const content = (0, node_fs_1.readFileSync)(path, 'utf-8');
44
- const { load } = require('@zkochan/js-yaml');
45
- return load(content, { ...options, filename: path });
44
+ const { load, FAILSAFE_SCHEMA } = require('@zkochan/js-yaml');
45
+ const { failsafe, ...loadOptions } = options ?? {};
46
+ return load(content, {
47
+ ...loadOptions,
48
+ ...(failsafe ? { schema: FAILSAFE_SCHEMA } : {}),
49
+ filename: path,
50
+ });
46
51
  }
47
52
  /**
48
53
  * Serializes the given data to JSON and writes it to a file.
@@ -0,0 +1,13 @@
1
+ import type { Tree } from '../../generators/tree';
2
+ /**
3
+ * Adding a member here does NOT reliably break compilation: the repo builds
4
+ * with `strict: false`, so a `switch` that omits one is not an error. The
5
+ * `never` assertions and type-keyed tables that do catch it fail immediately
6
+ * inside `packages/nx`, but the ones in devkit and `@nx/js` read the type from
7
+ * its emitted declarations, so those only fail once it has been rebuilt.
8
+ */
9
+ export type FormatterType = 'prettier' | 'oxfmt';
10
+ /** Test-only: the warn-once flag is module state and would leak between cases. */
11
+ export declare function resetFormatterWarningsForTesting(): void;
12
+ export declare function detectFormatter(root: string): FormatterType | null;
13
+ export declare function detectFormatterInTree(tree: Tree): FormatterType | null;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resetFormatterWarningsForTesting = resetFormatterWarningsForTesting;
4
+ exports.detectFormatter = detectFormatter;
5
+ exports.detectFormatterInTree = detectFormatterInTree;
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ const json_1 = require("../../generators/utils/json");
9
+ const fileutils_1 = require("../fileutils");
10
+ const oxfmt_1 = require("./oxfmt");
11
+ const prettier_1 = require("./prettier");
12
+ const logger_1 = require("../logger");
13
+ // Once per process: detection runs on every one of 200+ `formatFiles` call sites.
14
+ let warnedBothConfigured = false;
15
+ function warnBothConfigured() {
16
+ warnedBothConfigured = true;
17
+ logger_1.logger.warn('Both an oxfmt and a prettier config were found. Nx is formatting with ' +
18
+ 'oxfmt. Delete the config you are not using to make the choice ' +
19
+ 'explicit: https://nx.dev/docs/reference/code-formatting');
20
+ }
21
+ /** Test-only: the warn-once flag is module state and would leak between cases. */
22
+ function resetFormatterWarningsForTesting() {
23
+ warnedBothConfigured = false;
24
+ }
25
+ function detectFormatter(root) {
26
+ if ((0, oxfmt_1.isUsingOxfmt)(root)) {
27
+ // Flag first, so the lookup stops repeating once we have warned.
28
+ if (!warnedBothConfigured && (0, prettier_1.isUsingPrettier)(root)) {
29
+ warnBothConfigured();
30
+ }
31
+ return 'oxfmt';
32
+ }
33
+ if ((0, prettier_1.isUsingPrettier)(root)) {
34
+ return 'prettier';
35
+ }
36
+ // Neither is configured. Both formatters run on their defaults, so a
37
+ // dependency declared in the root package.json is the only statement of
38
+ // intent an unconfigured workspace gives. #30426 ruled out treating prettier
39
+ // as *resolvable in node_modules*, which a declared dependency is not.
40
+ const packageJsonPath = (0, node_path_1.join)(root, 'package.json');
41
+ if ((0, node_fs_1.existsSync)(packageJsonPath)) {
42
+ return detectFormatterFromDependencies((0, fileutils_1.readJsonFile)(packageJsonPath));
43
+ }
44
+ return null;
45
+ }
46
+ function detectFormatterInTree(tree) {
47
+ if ((0, oxfmt_1.isUsingOxfmtInTree)(tree)) {
48
+ if (!warnedBothConfigured && (0, prettier_1.isUsingPrettierInTree)(tree)) {
49
+ warnBothConfigured();
50
+ }
51
+ return 'oxfmt';
52
+ }
53
+ if ((0, prettier_1.isUsingPrettierInTree)(tree)) {
54
+ return 'prettier';
55
+ }
56
+ // See detectFormatter: a declared dependency is the fallback for both.
57
+ if (tree.exists('package.json')) {
58
+ return detectFormatterFromDependencies((0, json_1.readJson)(tree, 'package.json'));
59
+ }
60
+ return null;
61
+ }
62
+ /** oxfmt first, matching the precedence the config files already have. */
63
+ function detectFormatterFromDependencies(packageJson) {
64
+ if (hasDependency(packageJson, 'oxfmt')) {
65
+ return 'oxfmt';
66
+ }
67
+ if (hasDependency(packageJson, 'prettier')) {
68
+ return 'prettier';
69
+ }
70
+ return null;
71
+ }
72
+ function hasDependency(packageJson, name) {
73
+ return Boolean(packageJson.dependencies?.[name] ?? packageJson.devDependencies?.[name]);
74
+ }
@@ -0,0 +1,32 @@
1
+ import type { Tree } from '../../generators/tree';
2
+ /**
3
+ * Config filenames oxfmt *discovers* - narrower than the set `-c` accepts.
4
+ * Measured against 0.60.0: `oxfmt.config.{js,cjs,mjs,cts}` load when named
5
+ * but are never searched for, so treating one as config would format on
6
+ * options oxfmt ignores. No precedence order - oxfmt fails with
7
+ * "Both '<a>' and '<b>' found in <dir>" when a directory holds two.
8
+ */
9
+ export declare const oxfmtConfigFiles: string[];
10
+ export declare function isUsingOxfmt(root: string): boolean;
11
+ export declare function isUsingOxfmtInTree(tree: Tree): boolean;
12
+ export declare function getOxfmtBinPath(): string;
13
+ export declare function writeWithOxfmt(patterns: string[], cwd?: string): void;
14
+ export declare function checkWithOxfmt(patterns: string[]): Promise<string[]>;
15
+ /**
16
+ * Nothing is written to disk: staging files inside the workspace would race the
17
+ * daemon's watcher and the project graph mid-generator.
18
+ *
19
+ * A path is absent from the result when oxfmt has no parser for it, an ignore
20
+ * file covers it, or it is already formatted. One unparseable file fails only
21
+ * itself; the rest of the batch still applies.
22
+ */
23
+ export declare function formatFilesWithOxfmt(files: {
24
+ path: string;
25
+ content: string;
26
+ }[], workspaceRoot: string, seedConfig?: {
27
+ name: string;
28
+ content: string;
29
+ }, rootConfigNames?: readonly string[], read?: (relativePath: string) => string | null | undefined): Promise<{
30
+ formatted: Map<string, string>;
31
+ errors?: string[];
32
+ }>;