nx 23.1.1 → 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 (128) hide show
  1. package/dist/release/changelog-renderer/index.js +4 -5
  2. package/dist/release/index.d.ts +1 -1
  3. package/dist/src/command-line/add/add.js +5 -0
  4. package/dist/src/command-line/affected/affected.js +1 -0
  5. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
  6. package/dist/src/command-line/import/import.js +1 -2
  7. package/dist/src/command-line/init/init-v2.js +4 -5
  8. package/dist/src/command-line/migrate/migrate.d.ts +4 -0
  9. package/dist/src/command-line/migrate/migrate.js +89 -26
  10. package/dist/src/command-line/release/changelog.js +5 -0
  11. package/dist/src/command-line/release/index.d.ts +1 -1
  12. package/dist/src/command-line/release/utils/git.js +1 -1
  13. package/dist/src/command-line/release/utils/release-graph.d.ts +17 -0
  14. package/dist/src/command-line/release/utils/release-graph.js +71 -19
  15. package/dist/src/command-line/release/utils/remote-release-clients/github.js +6 -0
  16. package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
  17. package/dist/src/command-line/release/version/release-group-processor.js +80 -6
  18. package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
  19. package/dist/src/command-line/release/version/version-actions.js +9 -1
  20. package/dist/src/command-line/release/version.js +9 -5
  21. package/dist/src/command-line/reset/reset.js +6 -1
  22. package/dist/src/command-line/run/run-one.js +1 -0
  23. package/dist/src/command-line/run-many/run-many.js +1 -0
  24. package/dist/src/command-line/watch/watch.js +13 -0
  25. package/dist/src/core/graph/main.js +1 -1
  26. package/dist/src/core/graph/styles.js +1 -1
  27. package/dist/src/daemon/client/client.d.ts +52 -1
  28. package/dist/src/daemon/client/client.js +160 -36
  29. package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
  30. package/dist/src/daemon/client/daemon-environment.js +110 -2
  31. package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
  32. package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
  33. package/dist/src/daemon/message-types/daemon-message.js +25 -0
  34. package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
  35. package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
  36. package/dist/src/daemon/server/latest-nx.js +5 -2
  37. package/dist/src/daemon/server/server.js +24 -0
  38. package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
  39. package/dist/src/daemon/server/shutdown-utils.js +11 -4
  40. package/dist/src/daemon/socket-utils.d.ts +1 -0
  41. package/dist/src/daemon/socket-utils.js +24 -3
  42. package/dist/src/daemon/tmp-dir.d.ts +43 -3
  43. package/dist/src/daemon/tmp-dir.js +437 -15
  44. package/dist/src/devkit-internals.d.ts +93 -3
  45. package/dist/src/devkit-internals.js +192 -5
  46. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
  47. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
  48. package/dist/src/generators/tree.d.ts +4 -2
  49. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  50. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  51. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  52. package/dist/src/native/index.d.ts +10 -0
  53. package/dist/src/native/index.js +71 -28
  54. package/dist/src/native/native-bindings.js +1 -0
  55. package/dist/src/native/native-file-cache-location.d.ts +17 -1
  56. package/dist/src/native/native-file-cache-location.js +86 -12
  57. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  58. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  59. package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
  60. package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
  61. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  62. package/dist/src/plugins/js/lock-file/pnpm-parser.js +60 -0
  63. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +14 -8
  64. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
  65. package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +2 -0
  66. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
  67. package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
  68. package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
  69. package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
  70. package/dist/src/project-graph/error-types.d.ts +12 -1
  71. package/dist/src/project-graph/error-types.js +27 -2
  72. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
  73. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
  74. package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
  75. package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
  76. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
  77. package/dist/src/project-graph/project-graph.js +20 -0
  78. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +5 -1
  79. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +133 -3
  80. package/dist/src/tasks-runner/task-env.js +5 -2
  81. package/dist/src/tasks-runner/utils.js +2 -6
  82. package/dist/src/utils/assert-workspace-validity.js +7 -2
  83. package/dist/src/utils/fileutils.d.ts +5 -0
  84. package/dist/src/utils/fileutils.js +7 -2
  85. package/dist/src/utils/git-worktrees.d.ts +30 -0
  86. package/dist/src/utils/git-worktrees.js +212 -0
  87. package/dist/src/utils/ignore.d.ts +128 -1
  88. package/dist/src/utils/ignore.js +182 -12
  89. package/dist/src/utils/long-running-target.d.ts +10 -0
  90. package/dist/src/utils/long-running-target.js +19 -0
  91. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  92. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  93. package/dist/src/utils/min-release-age/packument.js +1 -1
  94. package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
  95. package/dist/src/utils/nx-tmp-dir.js +40 -0
  96. package/dist/src/utils/owned-private-dir.d.ts +132 -0
  97. package/dist/src/utils/owned-private-dir.js +323 -0
  98. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  99. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  100. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  101. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  102. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  103. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  104. package/dist/src/utils/package-manager.d.ts +21 -2
  105. package/dist/src/utils/package-manager.js +244 -47
  106. package/dist/src/utils/provenance.js +6 -14
  107. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  108. package/dist/src/utils/registry-config/bun.js +257 -0
  109. package/dist/src/utils/registry-config/index.d.ts +13 -0
  110. package/dist/src/utils/registry-config/index.js +102 -0
  111. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  112. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  113. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  114. package/dist/src/utils/registry-config/utils.js +496 -0
  115. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  116. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  117. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  118. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  119. package/dist/src/utils/safe-spawn.d.ts +24 -0
  120. package/dist/src/utils/safe-spawn.js +104 -0
  121. package/dist/src/utils/shell-quoting.d.ts +15 -0
  122. package/dist/src/utils/shell-quoting.js +35 -0
  123. package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
  124. package/dist/src/utils/wait-for-socket-connection.js +14 -8
  125. package/migrations.json +6 -0
  126. package/package.json +12 -12
  127. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  128. package/dist/src/utils/min-release-age/npmrc.js +0 -45
@@ -0,0 +1,496 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPackageScope = getPackageScope;
4
+ exports.nerfDart = nerfDart;
5
+ exports.requestNerfDart = requestNerfDart;
6
+ exports.normalizeNpmConfigKey = normalizeNpmConfigKey;
7
+ exports.readNpmConfigEnv = readNpmConfigEnv;
8
+ exports.mergeNpmConfigEnv = mergeNpmConfigEnv;
9
+ exports.ignoresNpmConfigEnv = ignoresNpmConfigEnv;
10
+ exports.setRegistry = setRegistry;
11
+ exports.setScopedRegistry = setScopedRegistry;
12
+ exports.setAuthToken = setAuthToken;
13
+ exports.setAuthIdent = setAuthIdent;
14
+ exports.setClientCertificate = setClientCertificate;
15
+ exports.setCafile = setCafile;
16
+ exports.setStrictSsl = setStrictSsl;
17
+ exports.setProxies = setProxies;
18
+ exports.ancestorDirectories = ancestorDirectories;
19
+ exports.expandNpmEnvVars = expandNpmEnvVars;
20
+ exports.escapeNpmEnvExpr = escapeNpmEnvExpr;
21
+ exports.expandEnvVars = expandEnvVars;
22
+ exports.expandYarnEnvVars = expandYarnEnvVars;
23
+ exports.expandPnpmEnvVars = expandPnpmEnvVars;
24
+ exports.bridgePnpmEnvVars = bridgePnpmEnvVars;
25
+ exports.unresolvedPnpmEnvVars = unresolvedPnpmEnvVars;
26
+ exports.pnpmEnvVarsResolve = pnpmEnvVarsResolve;
27
+ exports.readEnvVar = readEnvVar;
28
+ exports.readExpandedKey = readExpandedKey;
29
+ exports.registryKeysFor = registryKeysFor;
30
+ exports.hasCredentialFor = hasCredentialFor;
31
+ exports.warnNativeCredential = warnNativeCredential;
32
+ const path_1 = require("path");
33
+ const semver_1 = require("semver");
34
+ const logger_1 = require("../logger");
35
+ function getPackageScope(packageName) {
36
+ if (packageName.startsWith('@')) {
37
+ const slash = packageName.indexOf('/');
38
+ if (slash > 0) {
39
+ return packageName.slice(0, slash);
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ /**
45
+ * Converts a registry URL into npm's nerf-dart key prefix (host + directory
46
+ * path), e.g. `https://r.example.com/npm/` -> `//r.example.com/npm/`.
47
+ * See https://github.com/npm/cli/blob/bb056c85059cfb39514614e31abba09f20ac1612/workspaces/config/lib/nerf-dart.js#L12-L17
48
+ */
49
+ function nerfDart(registryUrl) {
50
+ try {
51
+ const url = new URL(registryUrl);
52
+ const dir = url.pathname.endsWith('/')
53
+ ? url.pathname
54
+ : url.pathname.slice(0, url.pathname.lastIndexOf('/') + 1);
55
+ return `//${url.host}${dir}`;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ /**
62
+ * Where npm and pnpm both begin a lookup for `registry`, and what
63
+ * registryKeysFor climbs from. Both append the trailing slash a registry path is
64
+ * missing before darting (npm darts the request URI; pnpm does it in
65
+ * getAuthHeaderByURI and pickSettingByUrl), so the walk starts at the request's
66
+ * own directory and still reaches a setting pinned to `//h/api/npm/` for a
67
+ * request to `https://h/api/npm`, which the plain dart begins above.
68
+ *
69
+ * A registry URL carrying a query or a fragment lands back on the plain dart:
70
+ * npm builds its request URI by concatenation, so the package name joins the
71
+ * query rather than the path, and its walk never reaches the deeper directory.
72
+ */
73
+ function requestNerfDart(registry) {
74
+ return nerfDart(registry.endsWith('/') ? registry : `${registry}/`);
75
+ }
76
+ /**
77
+ * The setting name npm resolves an environment key to, null for a key npm does
78
+ * not read.
79
+ * See https://github.com/npm/cli/blob/bb056c85059cfb39514614e31abba09f20ac1612/workspaces/config/lib/index.js#L345-L356
80
+ */
81
+ function npmConfigSetting(envKey) {
82
+ if (!/^npm_config_/i.test(envKey)) {
83
+ return null;
84
+ }
85
+ const key = envKey.slice('npm_config_'.length);
86
+ return key.startsWith('//') ? key : normalizeNpmConfigKey(key);
87
+ }
88
+ /** npm's key rewrite: non-leading `_` to `-`, then lowercased. */
89
+ function normalizeNpmConfigKey(key) {
90
+ return key.replace(/(?!^)_/g, '-').toLowerCase();
91
+ }
92
+ /**
93
+ * The value npm resolves for `setting` out of an environment: the last non-empty
94
+ * `npm_config_*` spelling wins (loadEnv). `setting` is the name npm looks the
95
+ * value up under, so a scope npm rewrites (`@my_scope`) finds nothing.
96
+ */
97
+ function readNpmConfigEnv(env, setting) {
98
+ let value;
99
+ for (const [key, candidate] of Object.entries(env)) {
100
+ if (candidate && npmConfigSetting(key) === setting) {
101
+ value = candidate;
102
+ }
103
+ }
104
+ return value;
105
+ }
106
+ const BRIDGED_SETTINGS = new Set([
107
+ 'registry',
108
+ 'ca',
109
+ 'cafile',
110
+ 'cert',
111
+ 'key',
112
+ 'strict-ssl',
113
+ 'proxy',
114
+ 'https-proxy',
115
+ 'noproxy',
116
+ ]);
117
+ /**
118
+ * Whether `setting` is one this module resolves on the package manager's behalf.
119
+ * `userconfig` is deliberately absent: it selects npm's own config file rather
120
+ * than a value the package manager resolves, and npm reading its own .npmrc is
121
+ * outside what the overlay reproduces.
122
+ */
123
+ function isBridgedSetting(setting) {
124
+ return (setting.startsWith('//') ||
125
+ setting.endsWith(':registry') ||
126
+ BRIDGED_SETTINGS.has(setting));
127
+ }
128
+ /**
129
+ * Merges an npm_config_* overlay into the environment for a spawned npm, leaving
130
+ * one non-empty spelling per setting: the overlay's where it carries the setting,
131
+ * otherwise the ambient one npm itself would resolve. npm reads its env tier
132
+ * last-write-wins over the received key order, and both macOS `/bin/sh` and npm's
133
+ * own shell launcher rebuild that order, so a setting left spelled two ways
134
+ * (`NPM_CONFIG_REGISTRY` beside `npm_config_registry`) goes to whichever one they
135
+ * emit last instead of to the value resolved here.
136
+ *
137
+ * `managerIgnoresEnv` says which settings the package manager resolves without
138
+ * reading `npm_config_*`. Bridged settings it answers true for are dropped even
139
+ * where the overlay claims nothing: npm's env tier sits above every file, so
140
+ * leaving one in place stops npm from reaching the .npmrc chain the package
141
+ * manager itself resolved from. Settings outside the bridged set stay ambient
142
+ * either way.
143
+ */
144
+ function mergeNpmConfigEnv(baseEnv, overlay, managerIgnoresEnv = IGNORES_NONE) {
145
+ const overlaid = new Set(Object.keys(overlay).map(npmConfigSetting).filter(Boolean));
146
+ const merged = {};
147
+ const keptSpelling = new Map();
148
+ for (const [key, value] of Object.entries(baseEnv)) {
149
+ const setting = npmConfigSetting(key);
150
+ if (setting === null) {
151
+ merged[key] = value;
152
+ continue;
153
+ }
154
+ // Even an empty ambient entry goes when the overlay carries the setting: a
155
+ // Windows environment is case-insensitive, and only the first spelling in
156
+ // it reaches the child, which would be this one rather than the overlay's.
157
+ if (overlaid.has(setting)) {
158
+ continue;
159
+ }
160
+ if (managerIgnoresEnv(setting) && isBridgedSetting(setting)) {
161
+ continue;
162
+ }
163
+ // npm skips an empty value, so it neither overrides nor competes.
164
+ if (!value) {
165
+ merged[key] = value;
166
+ continue;
167
+ }
168
+ const superseded = keptSpelling.get(setting);
169
+ if (superseded !== undefined) {
170
+ delete merged[superseded];
171
+ }
172
+ keptSpelling.set(setting, key);
173
+ merged[key] = value;
174
+ }
175
+ return { ...merged, ...overlay };
176
+ }
177
+ const IGNORES_NONE = () => false;
178
+ const IGNORES_ALL = () => true;
179
+ // pnpm 11.6.0's readUrlScopedEnvConfig reads a `p?npm_config_//<dart>:<key>`
180
+ // entry from the environment again, except `:tokenHelper`, which it refuses to
181
+ // take from there. Named settings stay on pnpm's own `PNPM_CONFIG_*` prefix.
182
+ const IGNORES_ALL_BUT_URL_SCOPED = (setting) => !setting.startsWith('//') || setting.endsWith(':tokenHelper');
183
+ /**
184
+ * The settings the package manager resolves without reading `npm_config_*`, as
185
+ * a predicate over setting names. A bridged setting it returns true for is one
186
+ * the spawned npm never receives from the ambient environment; settings outside
187
+ * the bridged set it has no say over. pnpm reads them all up to 10.x and stops at 11.0.0,
188
+ * which switched to its own `PNPM_CONFIG_*` prefix, except that 11.6.0 restored
189
+ * the URL-scoped credential keys; yarn berry has never read any; npm reads them by
190
+ * definition, and bun reads them for the settings this module bridges.
191
+ *
192
+ * An undetermined or unparseable version answers false for every setting:
193
+ * bridging is skipped or falls open there anyway, so the ambient environment
194
+ * stays as it is.
195
+ */
196
+ function ignoresNpmConfigEnv(packageManager, packageManagerVersion) {
197
+ const version = packageManagerVersion ? (0, semver_1.parse)(packageManagerVersion) : null;
198
+ if (!version) {
199
+ return IGNORES_NONE;
200
+ }
201
+ switch (packageManager) {
202
+ case 'npm':
203
+ case 'bun':
204
+ return IGNORES_NONE;
205
+ case 'pnpm':
206
+ if (version.major < 11) {
207
+ return IGNORES_NONE;
208
+ }
209
+ return (0, semver_1.gte)(version, '11.6.0') ? IGNORES_ALL_BUT_URL_SCOPED : IGNORES_ALL;
210
+ case 'yarn':
211
+ return version.major >= 2 ? IGNORES_ALL : IGNORES_NONE;
212
+ default: {
213
+ // A new PackageManager member fails typecheck here until classified above;
214
+ // callers outside a fall-open catch keep the ambient env instead of throwing.
215
+ const _exhaustive = packageManager;
216
+ return IGNORES_NONE;
217
+ }
218
+ }
219
+ }
220
+ function setRegistry(env, url) {
221
+ env['npm_config_registry'] = url;
222
+ }
223
+ function setScopedRegistry(env, scope, url) {
224
+ env[`npm_config_${scope}:registry`] = url;
225
+ }
226
+ /**
227
+ * Keyed on the registry's own directory rather than the parent a path missing
228
+ * its trailing slash darts to, so two registries under one parent keep separate
229
+ * keys instead of handing each other's credential out. The same holds for the
230
+ * two sinks below.
231
+ */
232
+ function setAuthToken(env, registryUrl, token) {
233
+ const dart = requestNerfDart(registryUrl);
234
+ if (dart) {
235
+ env[`npm_config_${dart}:_authToken`] = token;
236
+ }
237
+ }
238
+ /** `_auth` carries base64(user:pass). */
239
+ function setAuthIdent(env, registryUrl, base64Ident) {
240
+ const dart = requestNerfDart(registryUrl);
241
+ if (dart) {
242
+ env[`npm_config_${dart}:_auth`] = base64Ident;
243
+ }
244
+ }
245
+ /**
246
+ * npm presents a client certificate only when both halves are configured, so
247
+ * they are set together; each is a path, not the material itself.
248
+ * See https://github.com/npm/npm-registry-fetch/blob/v19.1.1/lib/auth.js#L170
249
+ */
250
+ function setClientCertificate(env, registryUrl, certfile, keyfile) {
251
+ const dart = requestNerfDart(registryUrl);
252
+ if (dart) {
253
+ env[`npm_config_${dart}:certfile`] = certfile;
254
+ env[`npm_config_${dart}:keyfile`] = keyfile;
255
+ }
256
+ }
257
+ function setCafile(env, path) {
258
+ env['npm_config_cafile'] = path;
259
+ }
260
+ function setStrictSsl(env, value) {
261
+ env['npm_config_strict_ssl'] = String(value);
262
+ }
263
+ function setProxies(env, proxies) {
264
+ if (proxies.httpProxy) {
265
+ env['npm_config_proxy'] = proxies.httpProxy;
266
+ }
267
+ if (proxies.httpsProxy) {
268
+ env['npm_config_https_proxy'] = proxies.httpsProxy;
269
+ }
270
+ if (proxies.noProxy) {
271
+ env['npm_config_noproxy'] = proxies.noProxy;
272
+ }
273
+ }
274
+ /**
275
+ * Directories above `root` (exclusive), nearest first. yarn classic and berry
276
+ * both read rc files from ancestor directories, which npm never sees because
277
+ * its project-config walk stops at the first package.json.
278
+ */
279
+ function ancestorDirectories(root) {
280
+ const dirs = [];
281
+ let current = (0, path_1.dirname)(root);
282
+ while (true) {
283
+ dirs.push(current);
284
+ const parent = (0, path_1.dirname)(current);
285
+ if (parent === current) {
286
+ break;
287
+ }
288
+ current = parent;
289
+ }
290
+ return dirs;
291
+ }
292
+ const ENV_EXPR = /(?<!\\)(\\*)\$\{([^${}]+)\}/g;
293
+ function replaceEnvExpr(value, resolve, { keepEscaped = false } = {}) {
294
+ return value.replace(ENV_EXPR, (orig, esc, name) => {
295
+ if (esc.length % 2) {
296
+ return keepEscaped ? orig : orig.slice((esc.length + 1) / 2);
297
+ }
298
+ return esc.slice(esc.length / 2) + (resolve(name) ?? `$\{${name}}`);
299
+ });
300
+ }
301
+ const NPM_ENV_EXPR = /(?<!\\)(\\*)\$\{([^${}?]+)(\?)?\}/g;
302
+ /**
303
+ * Resolves `${VAR}` references to the value npm itself ends up with, escapes
304
+ * consumed and the `${VAR?}` form falling back to an empty string. Use it to
305
+ * predict what a value npm reads for itself becomes, not to produce one for it:
306
+ * a bridged value goes through npm's own pass, which expandEnvVars accounts for.
307
+ * The `${VAR?}` form only landed in npm 11.6.0, so against an older spawned npm
308
+ * the prediction resolves a reference that npm itself would leave verbatim.
309
+ * See https://github.com/npm/cli/blob/v11.16.0/workspaces/config/lib/env-replace.js
310
+ */
311
+ function expandNpmEnvVars(value, env = process.env) {
312
+ return value.replace(NPM_ENV_EXPR, (orig, esc, name, optional) => {
313
+ if (esc.length % 2) {
314
+ return orig.slice((esc.length + 1) / 2);
315
+ }
316
+ const fallback = optional ? '' : `$\{${name}}`;
317
+ return esc.slice(esc.length / 2) + (env[name] ?? fallback);
318
+ });
319
+ }
320
+ /**
321
+ * The value to bridge so that npm's own expansion produces `value`, for a
322
+ * resolution that consumed the package manager's escapes rather than leaving
323
+ * them for npm (a literal a reader never expanded, or an expander whose escape
324
+ * rule is not npm's). Each reference gets an odd run of backslashes, which npm
325
+ * halves back to what it started as. Only what npm's reader would act on is
326
+ * escaped, so a `${` it leaves alone is not turned into a literal backslash.
327
+ */
328
+ function escapeNpmEnvExpr(value) {
329
+ return value.replace(NPM_ENV_EXPR, (_orig, esc, name, optional) => `${'\\'.repeat(esc.length * 2 + 1)}$\{${name}${optional ?? ''}}`);
330
+ }
331
+ /**
332
+ * Expands `${VAR}` references from the environment the way npm/bun ini readers
333
+ * do. Unknown variables are left verbatim. The result is bridged, so an escaped
334
+ * reference keeps its escape for the spawned npm to consume.
335
+ */
336
+ function expandEnvVars(value, env = process.env) {
337
+ return replaceEnvExpr(value, (name) => env[name], { keepEscaped: true });
338
+ }
339
+ const YARN_ENV_EXPR = /(\\*)\$\{([^}]+)\}/g;
340
+ /**
341
+ * Expands `${VAR}` the way yarn classic's own envReplace does, which parts from
342
+ * npm's on both halves of its escape rule: an odd run of backslashes keeps
343
+ * every one of them along with the reference, and an even one drops all of them
344
+ * rather than half. A reference it resolves nothing for aborts yarn, so it
345
+ * throws here into the caller's fall-open.
346
+ * See https://github.com/yarnpkg/yarn/blob/v1.22.22/src/registries/npm-registry.js
347
+ */
348
+ function expandYarnEnvVars(value, env = process.env) {
349
+ return value.replace(YARN_ENV_EXPR, (orig, esc, name) => {
350
+ if (esc.length % 2) {
351
+ return orig;
352
+ }
353
+ const resolved = env[name];
354
+ if (resolved === undefined) {
355
+ throw new Error(`Failed to replace env in config: ${orig}`);
356
+ }
357
+ return resolved;
358
+ });
359
+ }
360
+ const PNPM_ENV_DEFAULT = /([^:-]+)(:?)-(.+)/;
361
+ /**
362
+ * One `${...}` reference as pnpm's getEnvValue resolves it: the variable, or the
363
+ * `${VAR-default}` fallback and its `${VAR:-default}` form, which falls back for
364
+ * an empty value too and not just an unset one. Undefined for a reference pnpm
365
+ * finds nothing for, which is what its two readers part ways over.
366
+ */
367
+ function resolvePnpmEnvValue(name, env) {
368
+ const matched = name.match(PNPM_ENV_DEFAULT);
369
+ if (!matched) {
370
+ return env[name];
371
+ }
372
+ const [, variableName, colon, fallback] = matched;
373
+ const resolved = env[variableName];
374
+ if (resolved === undefined) {
375
+ return fallback;
376
+ }
377
+ return !resolved && colon ? fallback : resolved;
378
+ }
379
+ /**
380
+ * Expands `${VAR}` the way pnpm's @pnpm/config.env-replace does. A reference
381
+ * that resolves to nothing becomes an empty string, matching the envReplaceLossy
382
+ * reader pnpm takes its config through from 11.0.0; keeping it verbatim would
383
+ * put a literal `${VAR}` on the wire as if it were a credential. Below 11 the
384
+ * reader throws instead and the whole file goes with it (readPnpmNpmrcMap), so
385
+ * on that line nothing reaching this carries an unresolvable reference.
386
+ *
387
+ * This is what pnpm itself ends up with, escapes consumed. Use it for a key,
388
+ * which nothing expands a second time, and for a value compared against pnpm's
389
+ * own resolution; a value handed to the spawned npm goes through
390
+ * bridgePnpmEnvVars instead.
391
+ */
392
+ function expandPnpmEnvVars(value, env = process.env) {
393
+ return replaceEnvExpr(value, (name) => resolvePnpmEnvValue(name, env) ?? '');
394
+ }
395
+ /**
396
+ * The same expansion in the form to hand the spawned npm: every `${VAR}` left in
397
+ * what pnpm resolved is escaped, so npm reproduces it instead of expanding a
398
+ * reference pnpm would have sent literally, whether that reference is one pnpm
399
+ * kept escaped or one a variable's own value carries.
400
+ *
401
+ * The escaping runs over pnpm's whole result rather than per reference, because
402
+ * a resolved value ending in a backslash joins the escape run of the reference
403
+ * behind it. Escaping each piece on its own leaves npm reading the merged run,
404
+ * whose parity says expand where pnpm's said keep.
405
+ */
406
+ function bridgePnpmEnvVars(value, env = process.env) {
407
+ return escapeNpmEnvExpr(expandPnpmEnvVars(value, env));
408
+ }
409
+ /** The `${VAR}` references in `value` that pnpm's throwing reader dies on. */
410
+ function unresolvedPnpmEnvVars(value, env = process.env) {
411
+ const unresolved = [];
412
+ replaceEnvExpr(value, (name) => {
413
+ const resolved = resolvePnpmEnvValue(name, env);
414
+ if (resolved === undefined) {
415
+ unresolved.push(`$\{${name}}`);
416
+ }
417
+ return resolved ?? '';
418
+ });
419
+ return unresolved;
420
+ }
421
+ /** Whether every `${VAR}` in `value` is one pnpm's throwing reader gets past. */
422
+ function pnpmEnvVarsResolve(value, env = process.env) {
423
+ return unresolvedPnpmEnvVars(value, env).length === 0;
424
+ }
425
+ function readEnvVar(env, name) {
426
+ return env[name] ?? env[name.toLowerCase()] ?? env[name.toUpperCase()];
427
+ }
428
+ /**
429
+ * Reads `map` under `setting`, matching how npm and pnpm both expand a `${VAR}`
430
+ * in an .npmrc key before they look a value up under it; `setting` is already
431
+ * the resolved form to match. Both readers assign in file order, so the last key
432
+ * that `expand` turns into `setting` wins, a literal one included.
433
+ */
434
+ function readExpandedKey(map, setting, expand) {
435
+ let matched;
436
+ for (const [rawKey, value] of map) {
437
+ const expanded = rawKey.includes('${') ? expand(rawKey) : rawKey;
438
+ if (expanded === setting) {
439
+ matched = value;
440
+ }
441
+ }
442
+ return matched;
443
+ }
444
+ /**
445
+ * The registry keys npm looks a setting up under for `dart`, nearest first: it
446
+ * strips one path segment at a time until only the host is left, which covers
447
+ * the key spelled with and without its trailing slash.
448
+ * See https://github.com/npm/npm-registry-fetch/blob/v18.0.2/lib/auth.js#L16-L26
449
+ */
450
+ function registryKeysFor(dart) {
451
+ const keys = [];
452
+ let regKey = dart;
453
+ while (regKey.length > '//'.length) {
454
+ keys.push(regKey);
455
+ regKey = regKey.replace(/([^/]+|\/)$/, '');
456
+ }
457
+ return keys;
458
+ }
459
+ /**
460
+ * Whether npm would find a credential for `dart` among the values `read`
461
+ * exposes, at the dart or at any parent of it.
462
+ * See https://github.com/npm/npm-registry-fetch/blob/v18.0.2/lib/auth.js#L34-L49
463
+ */
464
+ function hasCredentialFor(dart, read) {
465
+ return registryKeysFor(dart).some((regKey) => read(`${regKey}:_authToken`) ||
466
+ read(`${regKey}:_auth`) ||
467
+ (read(`${regKey}:username`) && read(`${regKey}:_password`)) ||
468
+ (read(`${regKey}:certfile`) && read(`${regKey}:keyfile`)));
469
+ }
470
+ const warnedNativeCredentials = new Set();
471
+ /**
472
+ * npm reads the user's own .npmrc chain and the overlay cannot switch that off,
473
+ * so npm can authenticate on a registry the package manager resolved but would
474
+ * have queried anonymously. The fetch still succeeds, so nothing else reports it.
475
+ * Warn only where the overlay is what sent npm to that registry: left to itself
476
+ * npm would have used its own resolution and the same credentials, which is what
477
+ * the user gets from npm anywhere else.
478
+ *
479
+ * `remediation` closes the message, because what the user can safely do about it
480
+ * depends on whether the package manager reads .npmrc at all.
481
+ */
482
+ function warnNativeCredential(env, dart, packageManager, remediation, npmVisible) {
483
+ // Per registry: one migrate resolves several packages, and a scoped one can
484
+ // send npm to a registry no earlier package reached.
485
+ const warned = `${packageManager}\0${dart}`;
486
+ if (warnedNativeCredentials.has(warned) ||
487
+ env['npm_config_registry'] === undefined ||
488
+ // A credential the overlay carries is the package manager's own and
489
+ // outranks the file, so npm sending it reproduces rather than diverges.
490
+ hasCredentialFor(dart, (key) => env[`npm_config_${key}`]) ||
491
+ !hasCredentialFor(dart, npmVisible)) {
492
+ return;
493
+ }
494
+ warnedNativeCredentials.add(warned);
495
+ logger_1.logger.warn(`npm will send the credential your .npmrc holds for ${dart} when fetching packages. ${packageManager} would not send it for this request. ${remediation}`);
496
+ }
@@ -0,0 +1,2 @@
1
+ import { type NpmConfigEnv } from './utils';
2
+ export declare function getYarnBerrySpawnRegistryEnv(packageName: string, root: string, yarnVersion: string): NpmConfigEnv;