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
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readNpmrcEntries = readNpmrcEntries;
4
+ exports.parseNpmrcContent = parseNpmrcContent;
5
+ exports.readNpmrcMap = readNpmrcMap;
6
+ exports.npmrcEntriesToMap = npmrcEntriesToMap;
7
+ const fs_1 = require("fs");
8
+ /**
9
+ * Parses an .npmrc file into its `key = value` entries the way npm/yarn/pnpm do
10
+ * (via the `ini` package). Returns null when the file is missing, and
11
+ * 'unreadable' when it exists but cannot be read (permissions, a directory):
12
+ * package managers diverge on that state, so each caller decides whether to
13
+ * skip, warn, or abort rather than having it collapsed into "absent" here.
14
+ */
15
+ function readNpmrcEntries(path) {
16
+ let raw;
17
+ try {
18
+ raw = (0, fs_1.readFileSync)(path, 'utf-8');
19
+ }
20
+ catch (e) {
21
+ // ENOTDIR (a path through a non-directory) is another shape of absent, not an
22
+ // unreadable file.
23
+ return e?.code === 'ENOENT' || e?.code === 'ENOTDIR' ? null : 'unreadable';
24
+ }
25
+ return parseNpmrcContent(raw);
26
+ }
27
+ function parseNpmrcContent(raw) {
28
+ const entries = [];
29
+ // ini breaks lines on any run of CR/LF, so splitting on `\r?\n` here would
30
+ // hide everything after a bare CR that npm still reads.
31
+ for (const line of raw.split(/[\r\n]+/)) {
32
+ const trimmed = line.trim();
33
+ if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith(';')) {
34
+ continue;
35
+ }
36
+ // ini matches the header on the raw line, so an indented one stays a literal
37
+ // bare-flag key. Everything after a header nests under it, out of npm's flat
38
+ // lookup, so stop here.
39
+ if (/^\[[^\]]*\]\s*$/.test(line)) {
40
+ break;
41
+ }
42
+ // ini reads a valueless line as the flag `true`; dropping it would lose a bare
43
+ // `always-auth`/`strict-ssl` and flip the credential/TLS decision built on it.
44
+ const eq = trimmed.indexOf('=');
45
+ const rawKey = iniUnsafe(eq === -1 ? trimmed : trimmed.slice(0, eq));
46
+ const value = eq === -1 ? 'true' : iniUnsafe(trimmed.slice(eq + 1));
47
+ // ini enables bracketedArray by default, so a `key[]` suffix appends under the
48
+ // bare key instead of making a literal `key[]` entry.
49
+ if (rawKey.length > 2 && rawKey.endsWith('[]')) {
50
+ entries.push({ key: rawKey.slice(0, -2), value, array: true });
51
+ }
52
+ else {
53
+ entries.push({ key: rawKey, value });
54
+ }
55
+ }
56
+ return entries;
57
+ }
58
+ /**
59
+ * Reads an .npmrc-format file into a map with ini's semantics for repeated
60
+ * keys: scalars last-write-wins, `key[]` values joined. Null and 'unreadable'
61
+ * pass through from {@link readNpmrcEntries}.
62
+ */
63
+ function readNpmrcMap(path) {
64
+ const entries = readNpmrcEntries(path);
65
+ return Array.isArray(entries) ? npmrcEntriesToMap(entries) : entries;
66
+ }
67
+ /** Those entries under ini's semantics for repeated keys. */
68
+ function npmrcEntriesToMap(entries) {
69
+ const map = new Map();
70
+ for (const { key, value, array } of entries) {
71
+ // ini collects repeated `key[]` values into an array under the bare key, and
72
+ // npm rebuilds a config array from the env by splitting on a blank line, so
73
+ // join them that way.
74
+ const existing = map.get(key);
75
+ map.set(key, array && existing !== undefined ? `${existing}\n\n${value}` : value);
76
+ }
77
+ return map;
78
+ }
79
+ function isQuoted(val) {
80
+ return (val.length >= 2 &&
81
+ ((val.startsWith('"') && val.endsWith('"')) ||
82
+ (val.startsWith("'") && val.endsWith("'"))));
83
+ }
84
+ /**
85
+ * Mirrors the `ini` package's `unsafe()`, except that ini JSON-decodes a
86
+ * single-quoted value's contents and we keep them verbatim; that only differs
87
+ * when the contents are valid JSON, never true for a registry, token, or path.
88
+ * See https://github.com/isaacs/ini/blob/a0c72fe9e335a3f949d734fb5ef13371a850bbe3/lib/ini.js#L230
89
+ */
90
+ function iniUnsafe(raw) {
91
+ const val = raw.trim();
92
+ if (isQuoted(val)) {
93
+ if (val.startsWith("'")) {
94
+ return val.slice(1, -1);
95
+ }
96
+ try {
97
+ return JSON.parse(val);
98
+ }
99
+ catch {
100
+ return val;
101
+ }
102
+ }
103
+ let esc = false;
104
+ let unesc = '';
105
+ for (const c of val) {
106
+ if (esc) {
107
+ unesc += '\\;#'.includes(c) ? c : `\\${c}`;
108
+ esc = false;
109
+ }
110
+ else if (c === ';' || c === '#') {
111
+ break;
112
+ }
113
+ else if (c === '\\') {
114
+ esc = true;
115
+ }
116
+ else {
117
+ unesc += c;
118
+ }
119
+ }
120
+ if (esc) {
121
+ unesc += '\\';
122
+ }
123
+ return unesc.trim();
124
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Mirrors pnpm's getConfigDir. Hosts pnpm's global config.yaml and (v11+)
3
+ * auth.ini.
4
+ * See https://github.com/pnpm/pnpm/blob/b7195db5c8469c80908d625c648302b26c2f9977/config/reader/src/dirs.ts#L73-L92
5
+ */
6
+ export declare function getPnpmConfigDir(env: NodeJS.ProcessEnv): string;
7
+ /**
8
+ * Reads a pnpm YAML config file (pnpm-workspace.yaml or the global
9
+ * config.yaml). An absent file returns null so callers can fall through to
10
+ * lower surfaces; everything else returns 'unusable', which every caller turns
11
+ * into a throw. pnpm's own reader tolerates ENOENT alone and rethrows the rest,
12
+ * and it dies the same way on a document it cannot parse or that is not a
13
+ * mapping, so the two failures need no separate states. Requiring an object
14
+ * also keeps the sentinel out of the success domain: a returned string can only
15
+ * ever mean unusable.
16
+ */
17
+ export declare function readPnpmYamlConfig(path: string): Record<string, unknown> | 'unusable' | null;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPnpmConfigDir = getPnpmConfigDir;
4
+ exports.readPnpmYamlConfig = readPnpmYamlConfig;
5
+ const os_1 = require("os");
6
+ const path_1 = require("path");
7
+ const fileutils_1 = require("../fileutils");
8
+ /**
9
+ * Mirrors pnpm's getConfigDir. Hosts pnpm's global config.yaml and (v11+)
10
+ * auth.ini.
11
+ * See https://github.com/pnpm/pnpm/blob/b7195db5c8469c80908d625c648302b26c2f9977/config/reader/src/dirs.ts#L73-L92
12
+ */
13
+ function getPnpmConfigDir(env) {
14
+ if (env.XDG_CONFIG_HOME) {
15
+ return (0, path_1.join)(env.XDG_CONFIG_HOME, 'pnpm');
16
+ }
17
+ if (process.platform === 'darwin') {
18
+ return (0, path_1.join)((0, os_1.homedir)(), 'Library/Preferences/pnpm');
19
+ }
20
+ if (process.platform !== 'win32') {
21
+ return (0, path_1.join)((0, os_1.homedir)(), '.config/pnpm');
22
+ }
23
+ if (env.LOCALAPPDATA) {
24
+ return (0, path_1.join)(env.LOCALAPPDATA, 'pnpm/config');
25
+ }
26
+ return (0, path_1.join)((0, os_1.homedir)(), '.config/pnpm');
27
+ }
28
+ /**
29
+ * Reads a pnpm YAML config file (pnpm-workspace.yaml or the global
30
+ * config.yaml). An absent file returns null so callers can fall through to
31
+ * lower surfaces; everything else returns 'unusable', which every caller turns
32
+ * into a throw. pnpm's own reader tolerates ENOENT alone and rethrows the rest,
33
+ * and it dies the same way on a document it cannot parse or that is not a
34
+ * mapping, so the two failures need no separate states. Requiring an object
35
+ * also keeps the sentinel out of the success domain: a returned string can only
36
+ * ever mean unusable.
37
+ */
38
+ function readPnpmYamlConfig(path) {
39
+ let doc;
40
+ try {
41
+ doc = (0, fileutils_1.readYamlFile)(path);
42
+ }
43
+ catch (e) {
44
+ // Only ENOENT resolves on, so a path through a non-directory or a file that
45
+ // will not open is fatal here. Callers whose pnpm counterpart looks the file
46
+ // up before reading it widen "absent" themselves.
47
+ if (e?.code === 'ENOENT') {
48
+ return null;
49
+ }
50
+ return 'unusable';
51
+ }
52
+ // An empty file declares nothing; pnpm accepts it.
53
+ if (doc === null || doc === undefined) {
54
+ return {};
55
+ }
56
+ if (typeof doc !== 'object' || Array.isArray(doc)) {
57
+ return 'unusable';
58
+ }
59
+ return doc;
60
+ }
@@ -118,12 +118,33 @@ export declare function resolvePackageVersionUsingRegistry(packageName: string,
118
118
  * package.json.
119
119
  */
120
120
  export declare function resolvePackageVersionUsingInstallation(packageName: string, version: string): Promise<string>;
121
- export declare function packageRegistryView(pkg: string, version: string, args: string, options?: {
121
+ /**
122
+ * The registry the fetch for `pkg` went to, with its userinfo masked because a
123
+ * registry URL can carry a bare token. The lookup is spawned the way
124
+ * `packageRegistryView` spawns the fetch this describes (same manager, same
125
+ * environment), so a registry the package manager keeps outside the .npmrc
126
+ * chain and a scope resolved for itself both land on the value that fetch used.
127
+ * Null where the manager yields no usable registry URL; throws where it cannot be run.
128
+ */
129
+ export declare function getWorkspaceRegistryUrlForDisplay(pkg: string): string | null;
130
+ export declare function packageRegistryView(pkg: string, version: string, args: string[], options?: {
122
131
  forceNpm?: boolean;
123
132
  }): Promise<string>;
124
- export declare function packageRegistryPack(cwd: string, pkg: string, version: string): Promise<{
133
+ /**
134
+ * Only `npm pack` supports downloading a tarball of a specified remote
135
+ * package. `yarn` packs the active workspace, `pnpm pack` only packs
136
+ * the local project, and `bun` doesn't support pack.
137
+ *
138
+ * @param packDestination Directory passed to npm's `--pack-destination`, where
139
+ * the `.tgz` is written.
140
+ * @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
141
+ */
142
+ export declare function packageRegistryPack(packDestination: string, pkg: string, version: string, options?: {
143
+ bypassMinReleaseAge?: boolean;
144
+ }): Promise<{
125
145
  tarballPath: string;
126
146
  }>;
147
+ export declare function clearPackageManagerVersionCache(): void;
127
148
  /**
128
149
  * Gets the workspaces defined in the package manager configuration.
129
150
  * @returns workspaces defined in the package manager configuration, empty array if none are defined
@@ -13,8 +13,10 @@ exports.copyPackageManagerConfigurationFiles = copyPackageManagerConfigurationFi
13
13
  exports.createTempNpmDirectory = createTempNpmDirectory;
14
14
  exports.resolvePackageVersionUsingRegistry = resolvePackageVersionUsingRegistry;
15
15
  exports.resolvePackageVersionUsingInstallation = resolvePackageVersionUsingInstallation;
16
+ exports.getWorkspaceRegistryUrlForDisplay = getWorkspaceRegistryUrlForDisplay;
16
17
  exports.packageRegistryView = packageRegistryView;
17
18
  exports.packageRegistryPack = packageRegistryPack;
19
+ exports.clearPackageManagerVersionCache = clearPackageManagerVersionCache;
18
20
  exports.getPackageWorkspaces = getPackageWorkspaces;
19
21
  exports.addPackagePathToWorkspaces = addPackagePathToWorkspaces;
20
22
  const child_process_1 = require("child_process");
@@ -30,9 +32,36 @@ const file_utils_1 = require("../project-graph/file-utils");
30
32
  const catalog_1 = require("./catalog");
31
33
  const fileutils_1 = require("./fileutils");
32
34
  const installation_directory_1 = require("./installation-directory");
35
+ const logger_1 = require("./logger");
33
36
  const package_json_1 = require("./package-json");
37
+ const shell_quoting_1 = require("./shell-quoting");
34
38
  const workspace_root_1 = require("./workspace-root");
35
39
  const execAsync = (0, util_1.promisify)(child_process_1.exec);
40
+ const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
41
+ /**
42
+ * Shell-less spawn for the registry-bridged fetches: `exec` goes through
43
+ * /bin/sh, which is dash on Debian-family systems, and dash drops environment
44
+ * names that are not valid shell identifiers, i.e. every `//...:_authToken`
45
+ * credential and `@scope:registry` entry the overlay carries. Windows stays on
46
+ * `exec`, with every argument quoted, because Node refuses to execFile the
47
+ * package manager's `.cmd` shim without a shell.
48
+ *
49
+ * That quoting is the whole defence on Windows, so it goes through
50
+ * quoteShellArg, which throws on the one argument it cannot make safe.
51
+ */
52
+ function execPackageManagerAsync(pm, args, options) {
53
+ if (process.platform === 'win32') {
54
+ return execAsync([pm, ...args].map(shell_quoting_1.quoteShellArg).join(' '), options);
55
+ }
56
+ return execFileAsync(pm, args, options);
57
+ }
58
+ /** Same split, and the same quoting, for a blocking caller. */
59
+ function execPackageManagerSync(pm, args, options) {
60
+ if (process.platform === 'win32') {
61
+ return (0, child_process_1.execSync)([pm, ...args].map(shell_quoting_1.quoteShellArg).join(' '), options);
62
+ }
63
+ return (0, child_process_1.execFileSync)(pm, args, options);
64
+ }
36
65
  /**
37
66
  * Detects which package manager is used in the workspace based on the lock file.
38
67
  */
@@ -165,8 +194,12 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
165
194
  install: 'pnpm install --no-frozen-lockfile', // explicitly disable in case of CI
166
195
  ciInstall: 'pnpm install --frozen-lockfile',
167
196
  updateLockFile: 'pnpm install --lockfile-only',
168
- add: isPnpmWorkspace ? 'pnpm add -w' : 'pnpm add',
169
- addDev: isPnpmWorkspace ? 'pnpm add -Dw' : 'pnpm add -D',
197
+ add: isPnpmWorkspace
198
+ ? 'pnpm add -w --config.frozen-lockfile=false'
199
+ : 'pnpm add --config.frozen-lockfile=false',
200
+ addDev: isPnpmWorkspace
201
+ ? 'pnpm add -Dw --config.frozen-lockfile=false'
202
+ : 'pnpm add -D --config.frozen-lockfile=false',
170
203
  rm: 'pnpm rm',
171
204
  exec: modernPnpm ? 'pnpm exec' : 'pnpx',
172
205
  dlx: modernPnpm ? 'pnpm dlx' : 'pnpx',
@@ -345,6 +378,20 @@ function modifyPnpmWorkspaceYamlToFitNewDirectory(contents) {
345
378
  doc.set('packages', ['.']);
346
379
  // Relative patch paths don't resolve in the temp dir.
347
380
  doc.delete('patchedDependencies');
381
+ // link:/file: overrides (e.g. written by `pnpm link`) point at paths that
382
+ // don't exist in the temp dir, and an override would hijack an exact-version
383
+ // add (`pnpm add pkg@x.y.z` would install the linked dir instead).
384
+ const overrides = doc.toJS()?.overrides;
385
+ if (overrides && typeof overrides === 'object') {
386
+ for (const [name, spec] of Object.entries(overrides)) {
387
+ if (typeof spec === 'string' && /^(link|file):/.test(spec)) {
388
+ doc.deleteIn(['overrides', name]);
389
+ }
390
+ }
391
+ if (Object.keys(doc.toJS()?.overrides ?? {}).length === 0) {
392
+ doc.delete('overrides');
393
+ }
394
+ }
348
395
  return doc.toString();
349
396
  }
350
397
  function copyPackageManagerConfigurationFiles(root, destination) {
@@ -390,6 +437,27 @@ function copyPackageManagerConfigurationFiles(root, destination) {
390
437
  }
391
438
  }
392
439
  }
440
+ /**
441
+ * A non-JS workspace has no root package.json and keeps its package manager
442
+ * files under the Nx installation directory instead.
443
+ */
444
+ function getPackageManagerConfigRoot() {
445
+ if ((0, fs_1.existsSync)((0, path_1.join)(workspace_root_1.workspaceRoot, 'package.json'))) {
446
+ return workspace_root_1.workspaceRoot;
447
+ }
448
+ const installationPath = (0, installation_directory_1.getNxInstallationPath)(workspace_root_1.workspaceRoot);
449
+ // The installation directory can be missing or not a directory, and spawning
450
+ // with such a cwd fails outright (ENOENT/ENOTDIR).
451
+ try {
452
+ return (0, fs_1.statSync)(installationPath).isDirectory()
453
+ ? installationPath
454
+ : workspace_root_1.workspaceRoot;
455
+ }
456
+ catch (e) {
457
+ logger_1.logger.verbose(`Failed to stat the Nx installation directory at "${installationPath}".`, e);
458
+ return workspace_root_1.workspaceRoot;
459
+ }
460
+ }
393
461
  /**
394
462
  * Creates a temporary directory where you can run package manager commands safely.
395
463
  *
@@ -406,8 +474,7 @@ function createTempNpmDirectory(skipCopy = false) {
406
474
  // A package.json is needed for pnpm pack and for .npmrc to resolve
407
475
  (0, fileutils_1.writeJsonFile)(`${dir}/package.json`, {});
408
476
  if (!skipCopy) {
409
- const isNonJs = !(0, fs_1.existsSync)((0, path_1.join)(workspace_root_1.workspaceRoot, 'package.json'));
410
- copyPackageManagerConfigurationFiles(isNonJs ? (0, installation_directory_1.getNxInstallationPath)(workspace_root_1.workspaceRoot) : workspace_root_1.workspaceRoot, dir);
477
+ copyPackageManagerConfigurationFiles(getPackageManagerConfigRoot(), dir);
411
478
  }
412
479
  const cleanup = async () => {
413
480
  try {
@@ -426,7 +493,9 @@ function createTempNpmDirectory(skipCopy = false) {
426
493
  async function resolvePackageVersionUsingRegistry(packageName, version) {
427
494
  try {
428
495
  const resolvedVersion = (0, catalog_1.resolveCatalogReferenceIfNeeded)(packageName, version);
429
- const result = await packageRegistryView(packageName, resolvedVersion, 'version');
496
+ const result = await packageRegistryView(packageName, resolvedVersion, [
497
+ 'version',
498
+ ]);
430
499
  if (!result) {
431
500
  throw new Error(`Unable to resolve version ${packageName}@${resolvedVersion}.`);
432
501
  }
@@ -448,9 +517,29 @@ async function resolvePackageVersionUsingRegistry(packageName, version) {
448
517
  .replace(/'/g, '');
449
518
  return finalResolvedVersion;
450
519
  }
451
- catch {
452
- throw new Error(`Unable to resolve version ${packageName}@${version}.`);
520
+ catch (e) {
521
+ // npm masks a URL credential only in the password position, so a bare token
522
+ // in the registry URL survives into the error kept as the cause.
523
+ throw new Error(`Unable to resolve version ${packageName}@${version}.`, {
524
+ cause: redactErrorCause(e),
525
+ });
526
+ }
527
+ }
528
+ // Masks the userinfo in a URL: `user`, `user:pass`, or a bare token.
529
+ function redactUrlCredentials(text) {
530
+ return text.replace(/([a-z][a-z0-9+.-]*:\/\/)[^/@\s]+@/gi, '$1***@');
531
+ }
532
+ function redactErrorCause(error) {
533
+ if (error && typeof error === 'object') {
534
+ const e = error;
535
+ // An exec error carries the command and both output streams as fields.
536
+ for (const field of ['message', 'stack', 'stderr', 'stdout', 'cmd']) {
537
+ if (typeof e[field] === 'string') {
538
+ e[field] = redactUrlCredentials(e[field]);
539
+ }
540
+ }
453
541
  }
542
+ return error;
454
543
  }
455
544
  /**
456
545
  * Return the resolved version for a given package and version tag using by
@@ -480,12 +569,86 @@ async function resolvePackageVersionUsingInstallation(packageName, version) {
480
569
  await cleanup();
481
570
  }
482
571
  }
483
- async function packageRegistryView(pkg, version, args,
484
- // `forceNpm` runs the view through npm even in a pnpm workspace: npm projects
485
- // a field across every matched version, whereas `pnpm view <pkg>@<range>`
486
- // collapses to the single highest match (breaks per-version field queries).
487
- options) {
488
- let pm = detectPackageManager();
572
+ /**
573
+ * What every registry-bound npm spawn resolves the same way: where npm runs,
574
+ * and an environment reproducing the workspace package manager's own registry,
575
+ * auth and TLS resolution for `pkg`. `buildEnv` adds the caller's own entries.
576
+ */
577
+ function createRegistrySpawnContext(pkg) {
578
+ // Deferred so the registry resolvers load only for the commands that spawn
579
+ // npm, not with every package-manager.ts import.
580
+ const { getNpmSpawnRegistryEnv, getPackageScope, ignoresNpmConfigEnv, mergeNpmConfigEnv, } = require('./registry-config');
581
+ const workspacePm = detectPackageManager();
582
+ const configRoot = getPackageManagerConfigRoot();
583
+ const workspacePmVersion = getPackageManagerVersionSafe(workspacePm, configRoot);
584
+ return {
585
+ workspacePm,
586
+ workspacePmVersion,
587
+ configRoot,
588
+ scope: getPackageScope(pkg),
589
+ buildEnv: (extra) => mergeNpmConfigEnv(process.env, {
590
+ ...getNpmSpawnRegistryEnv(pkg, configRoot, workspacePm, workspacePmVersion),
591
+ ...extra,
592
+ }, ignoresNpmConfigEnv(workspacePm, workspacePmVersion)),
593
+ };
594
+ }
595
+ /**
596
+ * The registry the fetch for `pkg` went to, with its userinfo masked because a
597
+ * registry URL can carry a bare token. The lookup is spawned the way
598
+ * `packageRegistryView` spawns the fetch this describes (same manager, same
599
+ * environment), so a registry the package manager keeps outside the .npmrc
600
+ * chain and a scope resolved for itself both land on the value that fetch used.
601
+ * Null where the manager yields no usable registry URL; throws where it cannot be run.
602
+ */
603
+ function getWorkspaceRegistryUrlForDisplay(pkg) {
604
+ const { workspacePm, workspacePmVersion, configRoot, scope, buildEnv } = createRegistrySpawnContext(pkg);
605
+ const { pm, env, usesNativePnpm } = resolveRegistrySpawnTarget(workspacePm, workspacePmVersion, buildEnv);
606
+ // Ask for the package scope first. Native pnpm can keep the workspace
607
+ // `registries.default` separate from the flat `registry`, so it is queried
608
+ // in between.
609
+ const keys = scope ? [`${scope}:registry`] : [];
610
+ if (usesNativePnpm) {
611
+ keys.push('registries.default');
612
+ }
613
+ keys.push('registry');
614
+ for (const key of keys) {
615
+ const value = execPackageManagerSync(pm, ['config', 'get', key], {
616
+ cwd: configRoot,
617
+ timeout: 5000,
618
+ windowsHide: true,
619
+ encoding: 'utf-8',
620
+ // The downgraded pin warns on stderr, which is noise on a path that only
621
+ // decorates an error message.
622
+ stdio: ['ignore', 'pipe', 'ignore'],
623
+ env,
624
+ }).trim();
625
+ if (!value || value === 'undefined' || value === 'null') {
626
+ continue;
627
+ }
628
+ // A present but unusable answer (a `registries:` map with a non-string
629
+ // default serializes as JSON; a non-HTTP(S) scheme) also aborted the fetch
630
+ // this describes, so a key below it was never contacted either.
631
+ if (!URL.canParse(value)) {
632
+ return null;
633
+ }
634
+ const protocol = new URL(value).protocol;
635
+ if (protocol !== 'http:' && protocol !== 'https:') {
636
+ return null;
637
+ }
638
+ return redactUrlCredentials(value);
639
+ }
640
+ return null;
641
+ }
642
+ /**
643
+ * Which manager answers a registry read for this workspace, and the environment
644
+ * it reads under. pnpm 11 reimplemented `view` natively, resolving registry and
645
+ * credentials (tokenHelper included) itself, so it runs on the untouched
646
+ * environment; pnpm 10 passed `view` through to the npm CLI, which needs the
647
+ * overlay. Shared so a lookup describing a fetch cannot resolve against a
648
+ * different environment than the fetch used.
649
+ */
650
+ function resolveRegistrySpawnTarget(workspacePm, workspacePmVersion, buildEnv, options) {
651
+ let pm = workspacePm;
489
652
  if (options?.forceNpm || pm === 'yarn' || pm === 'bun') {
490
653
  /**
491
654
  * yarn has `yarn info` but it behaves differently than (p)npm,
@@ -499,40 +662,98 @@ options) {
499
662
  */
500
663
  pm = 'npm';
501
664
  }
665
+ if (pm === 'pnpm' && ((0, semver_1.parse)(workspacePmVersion)?.major ?? 0) >= 11) {
666
+ return { pm, env: process.env, usesNativePnpm: true };
667
+ }
668
+ // npm_config_force downgrades npm's `devEngines.packageManager` enforcement,
669
+ // which otherwise aborts even a read-only lookup when the pin sets
670
+ // `onFail: error`. Only set for npm so a pnpm spawn is untouched.
671
+ return {
672
+ pm,
673
+ env: buildEnv(pm === 'npm' ? { npm_config_force: 'true' } : {}),
674
+ usesNativePnpm: false,
675
+ };
676
+ }
677
+ async function packageRegistryView(pkg, version, args,
678
+ // `forceNpm` runs the view through npm even in a pnpm workspace: npm projects
679
+ // a field across every matched version, whereas `pnpm view <pkg>@<range>`
680
+ // collapses to the single highest match (breaks per-version field queries).
681
+ options) {
682
+ const { workspacePm, workspacePmVersion, configRoot, buildEnv } = createRegistrySpawnContext(pkg);
683
+ const { pm, env } = resolveRegistrySpawnTarget(workspacePm, workspacePmVersion, buildEnv, options);
502
684
  // An empty version means we want the full packument; omit the trailing `@`.
503
- // Quote the spec so range operators (e.g. `>=0.0.0`) are not parsed as shell
504
- // redirections.
505
685
  const spec = version ? `${pkg}@${version}` : pkg;
506
- // npm enforces `devEngines.packageManager` on every command, even a read-only
507
- // `view`; in a yarn/bun workspace we run npm, so a non-npm pin with
508
- // `onFail: error` aborts the lookup. force downgrades that to a warning.
509
- // Scoped to npm so a `pnpm view` spawn is left untouched.
510
- const { stdout } = await execAsync(`${pm} view "${spec}" ${args}`, {
511
- windowsHide: true,
512
- ...(pm === 'npm'
513
- ? { env: { ...process.env, npm_config_force: 'true' } }
514
- : {}),
515
- });
516
- return stdout.toString().trim();
686
+ try {
687
+ const { stdout } = await execPackageManagerAsync(pm, ['view', spec, ...args], {
688
+ windowsHide: true,
689
+ cwd: configRoot,
690
+ env,
691
+ });
692
+ return stdout.toString().trim();
693
+ }
694
+ catch (e) {
695
+ throw redactErrorCause(e);
696
+ }
517
697
  }
518
- async function packageRegistryPack(cwd, pkg, version) {
519
- /**
520
- * Only `npm pack` supports downloading a tarball of a specified remote
521
- * package. `yarn` packs the active workspace, `pnpm pack` only packs
522
- * the local project, and `bun` doesn't support pack.
523
- *
524
- * @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
525
- */
698
+ /**
699
+ * Only `npm pack` supports downloading a tarball of a specified remote
700
+ * package. `yarn` packs the active workspace, `pnpm pack` only packs
701
+ * the local project, and `bun` doesn't support pack.
702
+ *
703
+ * @param packDestination Directory passed to npm's `--pack-destination`, where
704
+ * the `.tgz` is written.
705
+ * @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
706
+ */
707
+ async function packageRegistryPack(packDestination, pkg, version, options) {
526
708
  const pm = 'npm';
527
- const { stdout } = await execAsync(`${pm} pack ${pkg}@${version}`, {
528
- cwd,
529
- windowsHide: true,
530
- // npm enforces `devEngines.packageManager` even on `pack`; force keeps the
531
- // download working in workspaces that pin a non-npm manager (onFail: error).
532
- env: { ...process.env, npm_config_force: 'true' },
533
- });
534
- const tarballPath = stdout.trim();
535
- return { tarballPath };
709
+ const { configRoot, buildEnv } = createRegistrySpawnContext(pkg);
710
+ // Run from the config root, not the temp dir, so npm reads the workspace
711
+ // .npmrc natively; --pack-destination still writes the tarball to the temp
712
+ // dir. npm prints the tarball basename to stdout.
713
+ try {
714
+ const { stdout } = await execPackageManagerAsync(pm, ['pack', `${pkg}@${version}`, '--pack-destination', packDestination], {
715
+ cwd: configRoot,
716
+ windowsHide: true,
717
+ env: buildEnv({
718
+ // downgrade npm's devEngines.packageManager enforcement (onFail:
719
+ // error) to a warning so pack still runs in a non-npm workspace
720
+ npm_config_force: 'true',
721
+ ...(options?.bypassMinReleaseAge
722
+ ? { npm_config_min_release_age: '0' }
723
+ : {}),
724
+ }),
725
+ });
726
+ const tarballPath = stdout.trim();
727
+ return { tarballPath };
728
+ }
729
+ catch (e) {
730
+ throw redactErrorCause(e);
731
+ }
732
+ }
733
+ // The version probe shells out when the packageManager field is absent, and
734
+ // packageRegistryView/packageRegistryPack run in tight resolution loops.
735
+ const packageManagerVersionCache = new Map();
736
+ /**
737
+ * A null version is tolerated per package manager: pnpm and yarn skip bridging,
738
+ * bun assumes a current version.
739
+ */
740
+ function getPackageManagerVersionSafe(packageManager, root) {
741
+ const key = `${packageManager}:${root}`;
742
+ if (!packageManagerVersionCache.has(key)) {
743
+ let version = null;
744
+ try {
745
+ version = getPackageManagerVersion(packageManager, root);
746
+ }
747
+ catch (e) {
748
+ logger_1.logger.verbose(`Failed to determine the ${packageManager} version in "${root}".`, e);
749
+ }
750
+ packageManagerVersionCache.set(key, version);
751
+ }
752
+ return packageManagerVersionCache.get(key);
753
+ }
754
+ // Test-only: production never re-resolves a version mid-run.
755
+ function clearPackageManagerVersionCache() {
756
+ packageManagerVersionCache.clear();
536
757
  }
537
758
  /**
538
759
  * Gets the workspaces defined in the package manager configuration.