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,612 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getYarnBerrySpawnRegistryEnv = getYarnBerrySpawnRegistryEnv;
4
+ const fs_1 = require("fs");
5
+ const minimatch_1 = require("minimatch");
6
+ const os_1 = require("os");
7
+ const path_1 = require("path");
8
+ const semver_1 = require("semver");
9
+ const fileutils_1 = require("../fileutils");
10
+ const logger_1 = require("../logger");
11
+ const npmrc_1 = require("../package-manager-config/npmrc");
12
+ const utils_1 = require("./utils");
13
+ /*
14
+ * yarn berry (2/3/4) registry resolution (verified on 2.4.2, 3.8.7, 4.16.0):
15
+ *
16
+ * - Sources, highest first: YARN_* env vars > project .yarnrc.yml > ancestor
17
+ * .yarnrc.yml files (closer dir wins) > ~/.yarnrc.yml > defaults
18
+ * (first-writer-wins for scalars; npmScopes/npmRegistries merge per entry).
19
+ * See https://github.com/yarnpkg/berry/blob/a26895a80d2784a5be92c54d5e7622bc9b0864a5/packages/yarnpkg-core/sources/Configuration.ts#L1424
20
+ * - Fetch registry for @scope/pkg: npmScopes.<scope-without-@>.npmRegistryServer,
21
+ * else npmRegistryServer (default https://registry.yarnpkg.com).
22
+ * - .npmrc files are completely ignored.
23
+ *
24
+ * Because npm-visible surfaces are irrelevant to berry, the resolved values
25
+ * are always injected (default and, for scoped targets, the scoped key), so a
26
+ * stray .npmrc cannot steer the spawned npm away from what berry would do.
27
+ *
28
+ * Auth (npmAuthToken/npmAuthIdent at scope > npmRegistries[registry] > global)
29
+ * lives in .yarnrc.yml, which npm cannot read; it is translated to nerf-darted
30
+ * npm keys. TLS: caFilePath (v2/3) / httpsCaFilePath (v4), the
31
+ * httpsCertFilePath/httpsKeyFilePath client-certificate pair (3.2.0 on),
32
+ * per-host networkSettings (hostname globs, longest key first), enableStrictSsl
33
+ * (global only). A matching networkSettings entry is read before the global
34
+ * value of the same key, so for those keys alone it outranks the env vars too.
35
+ * enableNetwork is resolved the same way but has no npm counterpart, so a host
36
+ * berry refuses to reach is reported rather than reproduced.
37
+ */
38
+ const BERRY_DEFAULT_REGISTRY = 'https://registry.yarnpkg.com';
39
+ // Berry rewrote its env-var expander in 4.13.0, tightening the variable-name
40
+ // class from [\d\w_]+ (a leading _ or digit is valid) to [a-zA-Z]\w*.
41
+ const BERRY_ENV_PARSER_REWRITE = '4.13.0';
42
+ // httpsCertFilePath/httpsKeyFilePath landed in 3.2.0, as an rc setting and
43
+ // inside networkSettings at once. Below it berry aborts on the setting, so
44
+ // there is no resolution left to reproduce.
45
+ const BERRY_CLIENT_CERT_SETTINGS = '3.2.0';
46
+ const JSR_REGISTRY = 'https://npm.jsr.io';
47
+ function getYarnBerrySpawnRegistryEnv(packageName, root, yarnVersion) {
48
+ const env = {};
49
+ const scope = (0, utils_1.getPackageScope)(packageName);
50
+ const rcFiles = collectRcFiles(root);
51
+ // berry v4 deep-merges map settings (npmScopes/npmRegistries/networkSettings)
52
+ // per sub-key across rc files; v2/v3 take the whole entry from the highest-
53
+ // priority file that defines the key, omitted sub-keys included as their
54
+ // defaults.
55
+ const deepMerge = (0, semver_1.major)(yarnVersion) >= 4;
56
+ const resolveMapEntry = (pick) => {
57
+ if (!deepMerge) {
58
+ return firstDefinedIn(rcFiles, pick);
59
+ }
60
+ const merged = {};
61
+ let any = false;
62
+ for (const key of [
63
+ 'npmRegistryServer',
64
+ 'npmAuthToken',
65
+ 'npmAuthIdent',
66
+ 'npmAlwaysAuth',
67
+ ]) {
68
+ const value = firstDefinedIn(rcFiles, (c) => pick(c)?.[key]);
69
+ if (value !== undefined) {
70
+ merged[key] = value;
71
+ any = true;
72
+ }
73
+ }
74
+ return any ? merged : undefined;
75
+ };
76
+ // Berry expands env vars in every string setting at parse time, so expand
77
+ // before the URL parse and nerf-dart. An unexpanded
78
+ // `npmRegistryServer: "${MY_REGISTRY}"` has no parseable host, so its auth
79
+ // and TLS keys are never emitted.
80
+ const legacy = (0, semver_1.lt)(yarnVersion, BERRY_ENV_PARSER_REWRITE);
81
+ const defaultRegistry = expandBerryEnvVars(process.env['YARN_NPM_REGISTRY_SERVER'] ??
82
+ firstDefinedIn(rcFiles, (c) => c.npmRegistryServer) ??
83
+ BERRY_DEFAULT_REGISTRY, legacy);
84
+ // npmScopes keys are scope names without the leading @.
85
+ const scopeName = scope?.slice(1);
86
+ const scopeEntry = scopeName
87
+ ? resolveMapEntry((c) => c.npmScopes?.[scopeName])
88
+ : undefined;
89
+ // A scope configured in npmScopes (even auth-only or empty) with no
90
+ // npmRegistryServer routes to berry's shape default (registry.yarnpkg.com),
91
+ // not the top-level npmRegistryServer. Berry seeds the scope entry with that
92
+ // default and returns it directly.
93
+ const scopeConfigured = scopeName !== undefined &&
94
+ rcFiles.some((f) => f.config.npmScopes !== undefined &&
95
+ // Own keys only: the parsed-YAML object carries Object.prototype, and a
96
+ // scope named after one of its members (@constructor) is not configured.
97
+ Object.hasOwn(f.config.npmScopes, scopeName));
98
+ const jsrDefault = scopeName === 'jsr' && !scopeConfigured && (0, semver_1.gte)(yarnVersion, '4.9.0');
99
+ const effectiveRegistry = scopeConfigured
100
+ ? expandBerryEnvVars(scopeEntry?.npmRegistryServer ?? BERRY_DEFAULT_REGISTRY, legacy)
101
+ : jsrDefault
102
+ ? JSR_REGISTRY
103
+ : defaultRegistry;
104
+ (0, utils_1.setRegistry)(env, defaultRegistry);
105
+ if (scope) {
106
+ (0, utils_1.setScopedRegistry)(env, scope, effectiveRegistry);
107
+ }
108
+ // berry's getAuthConfiguration picks ONE config object by specificity and
109
+ // reads token-then-ident from that object alone, so the tiers never mix. A
110
+ // present-but-credential-less npmRegistries entry therefore emits no auth
111
+ // rather than falling back to the global or env credentials.
112
+ const registryKey = selectNpmRegistriesKey(rcFiles, effectiveRegistry);
113
+ let authToken;
114
+ let authIdent;
115
+ let alwaysAuth = false;
116
+ if (scopeEntry?.npmAuthToken !== undefined ||
117
+ scopeEntry?.npmAuthIdent !== undefined) {
118
+ authToken = scopeEntry.npmAuthToken;
119
+ authIdent = scopeEntry.npmAuthIdent;
120
+ alwaysAuth = isBerryTrueBoolean(scopeEntry.npmAlwaysAuth);
121
+ }
122
+ else if (registryKey !== undefined) {
123
+ const registryEntry = resolveMapEntry((c) => c.npmRegistries?.[registryKey]);
124
+ authToken = registryEntry?.npmAuthToken;
125
+ authIdent = registryEntry?.npmAuthIdent;
126
+ alwaysAuth = isBerryTrueBoolean(registryEntry?.npmAlwaysAuth);
127
+ }
128
+ else {
129
+ // berry's getAuthConfiguration ends on the merged configuration with no
130
+ // source-tier tracking, so a global npmAuthToken/npmAuthIdent (any file
131
+ // tier, the home rc included, or env) authenticates whichever registry the
132
+ // other tiers selected. Reproduced deliberately for parity.
133
+ authToken =
134
+ process.env['YARN_NPM_AUTH_TOKEN'] ??
135
+ firstDefinedIn(rcFiles, (c) => c.npmAuthToken);
136
+ authIdent =
137
+ process.env['YARN_NPM_AUTH_IDENT'] ??
138
+ firstDefinedIn(rcFiles, (c) => c.npmAuthIdent);
139
+ alwaysAuth = isBerryTrueBoolean(process.env['YARN_NPM_ALWAYS_AUTH'] ??
140
+ firstDefinedIn(rcFiles, (c) => c.npmAlwaysAuth));
141
+ }
142
+ // Expand ${VAR} before use so the npmAuthIdent base64 decision and the
143
+ // bridged value are computed on the real credentials, matching berry.
144
+ // Env-sourced values are literal (no-op).
145
+ authToken = expandBerryValue(authToken, legacy);
146
+ authIdent = expandBerryValue(authIdent, legacy);
147
+ // A scoped fetch authenticates (berry forces BEST_EFFORT); an unscoped fetch
148
+ // only when npmAlwaysAuth is set on the selected config (npm view/pack leaves
149
+ // berry's authType at CONFIGURATION).
150
+ if (scope || alwaysAuth) {
151
+ if (authToken) {
152
+ (0, utils_1.setAuthToken)(env, effectiveRegistry, authToken);
153
+ }
154
+ else if (authIdent) {
155
+ (0, utils_1.setAuthIdent)(env, effectiveRegistry, encodeIdent(authIdent, yarnVersion));
156
+ }
157
+ }
158
+ applyTls(env, rcFiles, effectiveRegistry, yarnVersion);
159
+ // Unlike yarn classic there is no gate to consult here. Everything berry
160
+ // would send is already in the overlay, which the warning checks against, so
161
+ // it runs once the last of it (the client certificate) is in. The dart is the
162
+ // one npm resolves for a request to this registry, since the overlay writes
163
+ // there and the check climbs from it.
164
+ const dart = (0, utils_1.requestNerfDart)(effectiveRegistry);
165
+ if (dart) {
166
+ (0, utils_1.warnNativeCredential)(env, dart, 'yarn', 'Remove that credential from .npmrc if npm should not authenticate there; yarn never reads that file.', npmrcReader(root));
167
+ }
168
+ // Berry's expander consumes the backslash that escapes a reference, so what
169
+ // it resolves can hold a `${VAR}` npm would go on to resolve for itself,
170
+ // sending a credential berry keeps literal. Escaping every value it produced
171
+ // hands npm the same text back. Keys are left as they are: a reference can
172
+ // only reach one through a registry host, which is not a host berry resolves
173
+ // either.
174
+ for (const [key, value] of Object.entries(env)) {
175
+ env[key] = (0, utils_1.escapeNpmEnvExpr)(value);
176
+ }
177
+ return env;
178
+ }
179
+ /**
180
+ * Reads a key the way the spawned npm would from the .npmrc files berry ignores.
181
+ * The env tier is left out on purpose: berry never reads npm_config_*, so the
182
+ * spawn strips every bridged ambient one (mergeNpmConfigEnv), the nerf-darted
183
+ * keys this reader is probed with are all bridged, and what berry does send
184
+ * is in the overlay the warning checks separately. npm also reads a
185
+ * <globalPrefix>/etc npmrc and its own builtin one, which are not enumerated
186
+ * here: missing one only means the warning stays silent. The maps are read once
187
+ * because the caller probes dozens of keys walking npm's credential ladder.
188
+ */
189
+ function npmrcReader(root) {
190
+ const maps = [(0, path_1.join)(root, '.npmrc'), (0, path_1.join)((0, os_1.homedir)(), '.npmrc')].map((path) => {
191
+ const map = (0, npmrc_1.readNpmrcMap)(path);
192
+ // npm silently treats an .npmrc it cannot read as absent; this reader only
193
+ // mirrors npm's own view, so an unreadable file keeps the warning silent.
194
+ return map === 'unreadable' ? null : map;
195
+ });
196
+ return (key) => {
197
+ for (const map of maps) {
198
+ const value = map && (0, utils_1.readExpandedKey)(map, key, utils_1.expandNpmEnvVars);
199
+ if (value !== undefined) {
200
+ return value;
201
+ }
202
+ }
203
+ return undefined;
204
+ };
205
+ }
206
+ function collectRcFiles(root) {
207
+ // YARN_RC_FILENAME renames the files berry finds by walking up, but not the
208
+ // home one: findFolderRcFile reads the constant instead of the setting.
209
+ const rcName = process.env['YARN_RC_FILENAME'] ?? '.yarnrc.yml';
210
+ // berry looks the project and ancestor files up before reading them but opens
211
+ // the home one outright, so a symlink loop is absent in the first group and
212
+ // aborts yarn in the last (measured on 4.10.3).
213
+ const paths = [
214
+ { path: (0, path_1.join)(root, rcName), lookedUp: true },
215
+ ...(0, utils_1.ancestorDirectories)(root).map((dir) => ({
216
+ path: (0, path_1.join)(dir, rcName),
217
+ lookedUp: true,
218
+ })),
219
+ { path: (0, path_1.join)((0, os_1.homedir)(), '.yarnrc.yml'), lookedUp: false },
220
+ ];
221
+ const files = [];
222
+ for (const { path, lookedUp } of paths) {
223
+ if (lookedUp && !(0, fs_1.existsSync)(path)) {
224
+ continue;
225
+ }
226
+ // An unreadable, corrupt or non-mapping rc file aborts yarn itself, so there
227
+ // is no resolution left to reproduce. Every shape propagates to the caller's
228
+ // fall-open; dropping the file instead would resolve to berry's default
229
+ // registry while still bridging the credentials the other files declare.
230
+ let config;
231
+ try {
232
+ // berry loads its rc files through @yarnpkg/parsers, which calls js-yaml
233
+ // with the failsafe schema and json: true. That combination is what makes
234
+ // `npmAuthToken: 12345` a string and a repeated key last-wins rather than
235
+ // an error, so read them the same way instead of re-typing the scalars.
236
+ config = (0, fileutils_1.readYamlFile)(path, { json: true, failsafe: true });
237
+ }
238
+ catch (e) {
239
+ // Nothing looked this one up, so an absent file surfaces as the read's
240
+ // own ENOENT rather than as a missed lookup.
241
+ if (!lookedUp && e?.code === 'ENOENT') {
242
+ continue;
243
+ }
244
+ // The parse error quotes the lines around the fault, which in an rc file
245
+ // is credential material, and the caller logs whatever reaches it.
246
+ throw new Error(`The yarn rc file at ${path} could not be read.`);
247
+ }
248
+ // An empty or comment-only file is a valid rc that declares nothing.
249
+ if (config === undefined || config === null) {
250
+ continue;
251
+ }
252
+ if (typeof config !== 'object' || Array.isArray(config)) {
253
+ throw new Error(`The yarn rc file at ${path} is not a settings mapping.`);
254
+ }
255
+ normalizeMapSettings(config, path);
256
+ files.push({ path, config });
257
+ }
258
+ return files;
259
+ }
260
+ /**
261
+ * Berry types npmScopes/npmRegistries/networkSettings and their entries, and
262
+ * rejects the wrong shape before it resolves anything: a null is tolerated (that
263
+ * level keeps its defaults) but any other non-object aborts yarn with "must be
264
+ * an object". Reproduce both, so a config berry refuses to run on never reads as
265
+ * if berry had accepted it. Verified on 3.8.7 and 4.15.0.
266
+ */
267
+ function normalizeMapSettings(config, path) {
268
+ config.npmScopes = normalizeMapSetting(config.npmScopes, 'npmScopes', path);
269
+ // npmRegistries is declared with normalizeKeys, so berry strips the trailing
270
+ // slash off each key as it loads the map, and lets a colliding key win last
271
+ // the way berry's Map does.
272
+ const registries = normalizeMapSetting(config.npmRegistries, 'npmRegistries', path);
273
+ config.npmRegistries = registries
274
+ ? Object.fromEntries(Object.entries(registries).map(([key, entry]) => [
275
+ normalizeRegistryKey(key),
276
+ entry,
277
+ ]))
278
+ : undefined;
279
+ config.networkSettings = normalizeMapSetting(config.networkSettings, 'networkSettings', path);
280
+ }
281
+ function normalizeMapSetting(map, setting, path) {
282
+ const entries = asBerryObject(map, setting, path);
283
+ if (!entries) {
284
+ return undefined;
285
+ }
286
+ for (const key of Object.keys(entries)) {
287
+ // A null entry is still a configured key, with every sub-setting defaulted.
288
+ entries[key] =
289
+ asBerryObject(entries[key], `${setting}["${key}"]`, path) ?? {};
290
+ }
291
+ return entries;
292
+ }
293
+ function asBerryObject(value, setting, path) {
294
+ if (value === undefined || value === null) {
295
+ return undefined;
296
+ }
297
+ if (typeof value !== 'object' || Array.isArray(value)) {
298
+ throw new Error(`The yarn setting "${setting}" in ${path} is not an object.`);
299
+ }
300
+ return value;
301
+ }
302
+ /**
303
+ * Berry looks the effective registry up in its merged npmRegistries map by exact
304
+ * key first and only then with the scheme stripped, so the key has to be picked
305
+ * across every rc file before any entry is read: an exact key in the home rc
306
+ * still beats a scheme-less one in the project rc.
307
+ */
308
+ function selectNpmRegistriesKey(rcFiles, registry) {
309
+ const exact = normalizeRegistryKey(registry);
310
+ // berry strips any scheme (not just http/https) for the second lookup.
311
+ for (const key of [exact, exact.replace(/^[a-z]+:/, '')]) {
312
+ if (rcFiles.some((f) => f.config.npmRegistries?.[key] !== undefined)) {
313
+ return key;
314
+ }
315
+ }
316
+ return undefined;
317
+ }
318
+ /** Berry's normalizeRegistry, which it also applies to every npmRegistries key. */
319
+ function normalizeRegistryKey(registry) {
320
+ return registry.replace(/\/$/, '');
321
+ }
322
+ /**
323
+ * npm's `_auth` is base64(user:pass). Berry v2 stores npmAuthIdent already
324
+ * base64-encoded; v3/v4 accept both and base64-encode at request time only
325
+ * when the value still contains a `:`.
326
+ */
327
+ function encodeIdent(ident, yarnVersion) {
328
+ if ((0, semver_1.major)(yarnVersion) >= 3 && ident.includes(':')) {
329
+ return Buffer.from(ident).toString('base64');
330
+ }
331
+ return ident;
332
+ }
333
+ function applyTls(env, rcFiles, effectiveRegistry, yarnVersion) {
334
+ const legacy = (0, semver_1.lt)(yarnVersion, BERRY_ENV_PARSER_REWRITE);
335
+ const v4 = (0, semver_1.major)(yarnVersion) >= 4;
336
+ // The other major's CA-setting name aborts berry, as an rc setting and as a
337
+ // YARN_* env var alike, so only the name the running major accepts has
338
+ // anything left to reproduce.
339
+ const caKey = v4 ? 'httpsCaFilePath' : 'caFilePath';
340
+ const caEnvKey = v4 ? 'YARN_HTTPS_CA_FILE_PATH' : 'YARN_CA_FILE_PATH';
341
+ let host;
342
+ try {
343
+ host = new URL(effectiveRegistry).hostname;
344
+ }
345
+ catch { }
346
+ // Berry's getNetworkSettings falls back to a global setting only after the
347
+ // matching per-host entries, so a per-host value outranks the YARN_* env vars
348
+ // while those still outrank the rc files.
349
+ const network = resolveNetworkSettings(rcFiles, host, v4);
350
+ // Berry expands env vars in path settings, then resolves an rc-sourced path
351
+ // relative to that rc file's directory and an env-sourced one relative to the
352
+ // directory yarn was invoked from.
353
+ const resolvePath = (key, envKey) => {
354
+ const path = network[key] ?? envPath(process.env[envKey]) ?? firstPathIn(rcFiles, key);
355
+ return path
356
+ ? (0, path_1.resolve)(path.baseDir, expandBerryEnvVars(path.value, legacy))
357
+ : undefined;
358
+ };
359
+ const cafile = resolvePath(caKey, caEnvKey);
360
+ if (cafile) {
361
+ (0, utils_1.setCafile)(env, cafile);
362
+ }
363
+ if ((0, semver_1.gte)(yarnVersion, BERRY_CLIENT_CERT_SETTINGS)) {
364
+ // Berry sets cert and key independently (httpUtils has no joint gate); a
365
+ // lone half only fails there because Node cannot present a certificate
366
+ // without its key, so it stays out of the overlay.
367
+ const certfile = resolvePath('httpsCertFilePath', 'YARN_HTTPS_CERT_FILE_PATH');
368
+ const keyfile = resolvePath('httpsKeyFilePath', 'YARN_HTTPS_KEY_FILE_PATH');
369
+ if (certfile && keyfile) {
370
+ (0, utils_1.setClientCertificate)(env, effectiveRegistry, certfile, keyfile);
371
+ }
372
+ }
373
+ const enableNetwork = network.enableNetwork ??
374
+ process.env['YARN_ENABLE_NETWORK'] ??
375
+ firstDefinedIn(rcFiles, (c) => c.enableNetwork);
376
+ if (host &&
377
+ enableNetwork !== undefined &&
378
+ isBerryFalseBoolean(enableNetwork)) {
379
+ warnDisabledNetwork(host);
380
+ }
381
+ const strictSsl = process.env['YARN_ENABLE_STRICT_SSL'] ??
382
+ firstDefinedIn(rcFiles, (c) => c.enableStrictSsl);
383
+ if (strictSsl !== undefined) {
384
+ (0, utils_1.setStrictSsl)(env, !isBerryFalseBoolean(strictSsl));
385
+ }
386
+ (0, utils_1.setProxies)(env, {
387
+ httpProxy: expandBerryValue(network.httpProxy ??
388
+ process.env['YARN_HTTP_PROXY'] ??
389
+ firstDefinedIn(rcFiles, (c) => c.httpProxy), legacy),
390
+ httpsProxy: expandBerryValue(network.httpsProxy ??
391
+ process.env['YARN_HTTPS_PROXY'] ??
392
+ firstDefinedIn(rcFiles, (c) => c.httpsProxy), legacy),
393
+ });
394
+ }
395
+ let warnedDisabledNetwork = false;
396
+ /**
397
+ * Berry refuses to reach a host it has enableNetwork off for and exits (verified
398
+ * on 4.15.0: the registry is never contacted). The spawned npm has no such
399
+ * setting and will make the request, so say so once rather than reproducing a
400
+ * refusal that would leave the workspace un-migrated.
401
+ */
402
+ function warnDisabledNetwork(host) {
403
+ if (warnedDisabledNetwork) {
404
+ return;
405
+ }
406
+ warnedDisabledNetwork = true;
407
+ logger_1.logger.warn(`yarn is configured not to use the network for ${host} (enableNetwork is false), so yarn itself would refuse to fetch from it. Packages will still be fetched from that registry.`);
408
+ }
409
+ function envPath(value) {
410
+ return value ? { value, baseDir: process.cwd() } : undefined;
411
+ }
412
+ function firstPathIn(rcFiles, key) {
413
+ for (const file of rcFiles) {
414
+ const value = file.config[key];
415
+ if (value) {
416
+ return { value, baseDir: (0, path_1.dirname)(file.path) };
417
+ }
418
+ }
419
+ return undefined;
420
+ }
421
+ const BERRY_PATH_KEYS = [
422
+ 'caFilePath',
423
+ 'httpsCaFilePath',
424
+ 'httpsCertFilePath',
425
+ 'httpsKeyFilePath',
426
+ ];
427
+ // Reproduces berry getNetworkSettings. Berry builds the merged map lowest
428
+ // priority first and its sort is stable, so two globs of equal length are
429
+ // consulted in that same order.
430
+ function resolveNetworkSettings(rcFiles, host, deepMerge) {
431
+ const result = {};
432
+ if (!host) {
433
+ return result;
434
+ }
435
+ const merged = new Map();
436
+ for (const file of [...rcFiles].reverse()) {
437
+ const settings = file.config.networkSettings;
438
+ if (!settings) {
439
+ continue;
440
+ }
441
+ const baseDir = (0, path_1.dirname)(file.path);
442
+ for (const [hostKey, entry] of Object.entries(settings)) {
443
+ // Walking lowest priority first, a later file is the higher-priority one:
444
+ // under v4 each sub-key it defines wins, and under v2/v3 it owns the whole
445
+ // entry, so a lower file never contributes a missing sub-key there.
446
+ const m = (deepMerge && merged.get(hostKey)) || {};
447
+ for (const key of BERRY_PATH_KEYS) {
448
+ if (entry[key] != null) {
449
+ m[key] = { value: entry[key], baseDir };
450
+ }
451
+ }
452
+ if (entry.enableNetwork != null) {
453
+ m.enableNetwork = entry.enableNetwork;
454
+ }
455
+ if (entry.httpProxy != null) {
456
+ m.httpProxy = entry.httpProxy;
457
+ }
458
+ if (entry.httpsProxy != null) {
459
+ m.httpsProxy = entry.httpsProxy;
460
+ }
461
+ merged.set(hostKey, m);
462
+ }
463
+ }
464
+ const matching = [...merged.entries()]
465
+ .filter(([key]) => matchesHostGlob(host, key))
466
+ .sort((a, b) => b[0].length - a[0].length)
467
+ .map(([, m]) => m);
468
+ for (const m of matching) {
469
+ for (const key of BERRY_PATH_KEYS) {
470
+ result[key] ??= m[key];
471
+ }
472
+ result.enableNetwork ??= m.enableNetwork;
473
+ result.httpProxy ??= m.httpProxy;
474
+ result.httpsProxy ??= m.httpsProxy;
475
+ }
476
+ return result;
477
+ }
478
+ /**
479
+ * Berry matches a networkSettings key against the hostname with micromatch,
480
+ * which parses two forms differently from minimatch: a bare `(a|b)` is an
481
+ * extglob alternation rather than literal parentheses, and a leading `!` negates
482
+ * the pattern only when it is not the start of a `!(...)` extglob. Left to
483
+ * minimatch a `!(...)` key matches nearly every host, which would hand one
484
+ * host's CA and proxy to the registry.
485
+ */
486
+ function matchesHostGlob(host, key) {
487
+ return (0, minimatch_1.minimatch)(host, key.replace(/(^|[^\\@!+*?])\(/g, '$1@('), {
488
+ nonegate: key.startsWith('!('),
489
+ });
490
+ }
491
+ // Berry's miscUtils.replaceEnvVariables, applied to every string setting:
492
+ // ${VAR}, ${VAR-default} (default when unset) and ${VAR:-default} (default when
493
+ // unset or empty). Berry throws on an undefined bare ${VAR}, which aborts berry
494
+ // itself, so a working workspace never has one; we leave the reference literal
495
+ // rather than failing the migrate.
496
+ // see https://github.com/yarnpkg/berry/blob/c5857bdee5737425b879492db5e2732a5e6e14f2/packages/yarnpkg-core/sources/miscUtils.ts#L473
497
+ function expandBerryEnvVars(value, legacy, env = process.env) {
498
+ return legacy
499
+ ? expandBerryEnvVarsLegacy(value, env)
500
+ : scanBerryEnv(value, 0, env, false).text;
501
+ }
502
+ // Berry's pre-4.13 miscUtils.replaceEnvVariables.
503
+ // See https://github.com/yarnpkg/berry/blob/%40yarnpkg/cli/4.12.0/packages/yarnpkg-core/sources/miscUtils.ts
504
+ function expandBerryEnvVarsLegacy(value, env) {
505
+ return value.replace(/\\?\$\{(?<variableName>[\d\w_]+)(?<colon>:)?(?:-(?<fallback>[^}]*))?\}/g, (match, ...args) => {
506
+ if (match.startsWith('\\')) {
507
+ return match.slice(1);
508
+ }
509
+ const { variableName, colon, fallback } = args[args.length - 1];
510
+ const resolved = env[variableName];
511
+ if (resolved || (Object.hasOwn(env, variableName) && !colon)) {
512
+ return resolved;
513
+ }
514
+ return fallback ?? match;
515
+ });
516
+ }
517
+ // Scans from `start`, expanding env-var references. When `nested` is set the
518
+ // scan also stops just after the unescaped `}` that closes an enclosing default.
519
+ function scanBerryEnv(input, start, env, nested) {
520
+ let text = '';
521
+ let i = start;
522
+ while (i < input.length) {
523
+ const c = input[i];
524
+ if (c === '\\' && i + 1 < input.length && '\\$}'.includes(input[i + 1])) {
525
+ text += input[i + 1];
526
+ i += 2;
527
+ }
528
+ else if (nested && c === '}') {
529
+ return { text, end: i + 1 };
530
+ }
531
+ else if (c === '$' && input[i + 1] === '{') {
532
+ const ref = parseBerryRef(input, i, env);
533
+ if (ref) {
534
+ text += ref.text;
535
+ i = ref.end;
536
+ }
537
+ else {
538
+ // Malformed `${...` (berry would throw); emit it literally and continue.
539
+ text += '${';
540
+ i += 2;
541
+ }
542
+ }
543
+ else {
544
+ text += c;
545
+ i += 1;
546
+ }
547
+ }
548
+ return { text, end: i };
549
+ }
550
+ // Parses one ${NAME} / ${NAME-default} / ${NAME:-default} at `start`, which
551
+ // must be the `${`. The default is scanned brace-balanced so a nested ${...} is
552
+ // captured whole.
553
+ function parseBerryRef(input, start, env) {
554
+ const nameMatch = input.slice(start + 2).match(/^[a-zA-Z]\w*/);
555
+ if (!nameMatch) {
556
+ return null;
557
+ }
558
+ const name = nameMatch[0];
559
+ let i = start + 2 + name.length;
560
+ const value = env[name];
561
+ if (input[i] === '}') {
562
+ // ${NAME}: an undefined value aborts berry; leave the reference literal.
563
+ return {
564
+ text: value !== undefined ? value : input.slice(start, i + 1),
565
+ end: i + 1,
566
+ };
567
+ }
568
+ let emptyIsUnset = false;
569
+ if (input[i] === ':' && input[i + 1] === '-') {
570
+ emptyIsUnset = true;
571
+ i += 2;
572
+ }
573
+ else if (input[i] === '-') {
574
+ i += 1;
575
+ }
576
+ else {
577
+ return null;
578
+ }
579
+ // Parse (and expand) the default region even when the value wins, so `end`
580
+ // skips past the matching close brace.
581
+ const fallback = scanBerryEnv(input, i, env, true);
582
+ const useValue = emptyIsUnset
583
+ ? value !== undefined && value !== ''
584
+ : value !== undefined;
585
+ return {
586
+ text: useValue ? value : fallback.text,
587
+ end: fallback.end,
588
+ };
589
+ }
590
+ // Berry's miscUtils.parseBoolean false set for SettingsType.BOOLEAN.
591
+ function isBerryFalseBoolean(value) {
592
+ return value === false || value === 0 || value === 'false' || value === '0';
593
+ }
594
+ // Its true set. Berry throws on a value in neither, which aborts berry itself,
595
+ // so each side keeps the tolerance that is safe for its setting: an unparseable
596
+ // enableStrictSsl keeps TLS verification on, an unparseable npmAlwaysAuth leaves
597
+ // an unscoped fetch unauthenticated.
598
+ function isBerryTrueBoolean(value) {
599
+ return value === true || value === 1 || value === 'true' || value === '1';
600
+ }
601
+ function expandBerryValue(value, legacy) {
602
+ return value === undefined ? undefined : expandBerryEnvVars(value, legacy);
603
+ }
604
+ function firstDefinedIn(rcFiles, read) {
605
+ for (const file of rcFiles) {
606
+ const value = read(file.config);
607
+ if (value !== undefined) {
608
+ return value;
609
+ }
610
+ }
611
+ return undefined;
612
+ }
@@ -0,0 +1,2 @@
1
+ import { type NpmConfigEnv } from './utils';
2
+ export declare function getYarnClassicSpawnRegistryEnv(packageName: string, root: string): NpmConfigEnv;