nx 23.0.0 → 23.0.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.
- package/README.md +1 -2
- package/dist/bin/init-local.js +1 -1
- package/dist/release/changelog-renderer/index.d.ts +1 -0
- package/dist/release/changelog-renderer/index.js +27 -12
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.d.ts +1 -0
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +6 -1
- package/dist/src/command-line/init/init-v2.js +1 -1
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.js +3 -2
- package/dist/src/command-line/migrate/migrate.d.ts +2 -0
- package/dist/src/command-line/migrate/migrate.js +34 -7
- package/dist/src/command-line/migrate/resolve-package-version.js +3 -25
- package/dist/src/command-line/migrate/update-filters.js +2 -1
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.d.ts +1 -1
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +37 -20
- package/dist/src/command-line/release/version/resolve-current-version.js +4 -1
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +30 -11
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/plugins/js/lock-file/bun-parser.js +61 -38
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +1 -3
- package/dist/src/plugins/js/package-json/create-package-json.js +22 -1
- package/dist/src/plugins/js/project-graph/affected/tsconfig-json-changes.js +1 -1
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.d.ts +7 -0
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +26 -1
- package/dist/src/plugins/js/utils/register.d.ts +31 -10
- package/dist/src/plugins/js/utils/register.js +87 -18
- package/dist/src/plugins/package-json/create-nodes.js +5 -3
- package/dist/src/project-graph/operators.d.ts +0 -1
- package/dist/src/project-graph/operators.js +0 -44
- package/dist/src/project-graph/project-graph-builder.js +26 -10
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +23 -6
- package/dist/src/project-graph/utils/project-configuration-utils.js +28 -28
- package/dist/src/tasks-runner/batch/run-batch.js +3 -0
- package/dist/src/tasks-runner/cache.js +6 -0
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -0
- package/dist/src/tasks-runner/pseudo-terminal.js +18 -4
- package/dist/src/tasks-runner/run-command.js +24 -8
- package/dist/src/tasks-runner/utils.d.ts +1 -0
- package/dist/src/tasks-runner/utils.js +4 -0
- package/dist/src/utils/ab-testing.d.ts +9 -0
- package/dist/src/utils/ab-testing.js +18 -4
- package/dist/src/utils/catalog/index.d.ts +7 -0
- package/dist/src/utils/catalog/index.js +31 -0
- package/dist/src/utils/catalog/manager-utils.d.ts +9 -0
- package/dist/src/utils/catalog/manager-utils.js +215 -0
- package/dist/src/utils/catalog/pnpm-manager.js +4 -102
- package/dist/src/utils/catalog/yarn-manager.js +4 -102
- package/dist/src/utils/is-sandbox.js +2 -0
- package/dist/src/utils/min-release-age/behavior/pnpm.d.ts +6 -5
- package/dist/src/utils/min-release-age/behavior/pnpm.js +87 -339
- package/dist/src/utils/package-json.d.ts +1 -0
- package/dist/src/utils/package-manager.d.ts +6 -3
- package/dist/src/utils/package-manager.js +21 -7
- package/dist/src/utils/spinner.d.ts +13 -1
- package/dist/src/utils/spinner.js +20 -4
- package/dist/src/utils/terminal-link.d.ts +16 -0
- package/dist/src/utils/terminal-link.js +87 -0
- package/package.json +19 -15
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.readPnpmPolicy = readPnpmPolicy;
|
|
4
4
|
exports.pickPnpmVersion = pickPnpmVersion;
|
|
5
|
-
const
|
|
6
|
-
const os_1 = require("os");
|
|
7
|
-
const path_1 = require("path");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
8
6
|
const semver_1 = require("semver");
|
|
9
7
|
const constants_1 = require("../constants");
|
|
10
8
|
const errors_1 = require("../errors");
|
|
11
|
-
const npmrc_1 = require("../npmrc");
|
|
12
9
|
const pick_1 = require("../pick");
|
|
13
10
|
// Ordered newest-bound-first so the first matching row applies.
|
|
14
11
|
const PNPM_BEHAVIOR_ROWS = [
|
|
@@ -19,7 +16,6 @@ const PNPM_BEHAVIOR_ROWS = [
|
|
|
19
16
|
strictAutoOnWhenExplicit: true,
|
|
20
17
|
excludeGrammar: 'v2-globs-unions',
|
|
21
18
|
writesExcludes: true,
|
|
22
|
-
uppercaseEnv: true,
|
|
23
19
|
},
|
|
24
20
|
{
|
|
25
21
|
minVersion: '11.1.0',
|
|
@@ -28,7 +24,6 @@ const PNPM_BEHAVIOR_ROWS = [
|
|
|
28
24
|
strictAutoOnWhenExplicit: true,
|
|
29
25
|
excludeGrammar: 'v2-globs-unions',
|
|
30
26
|
writesExcludes: false,
|
|
31
|
-
uppercaseEnv: true,
|
|
32
27
|
},
|
|
33
28
|
{
|
|
34
29
|
minVersion: '11.0.4',
|
|
@@ -37,7 +32,6 @@ const PNPM_BEHAVIOR_ROWS = [
|
|
|
37
32
|
strictAutoOnWhenExplicit: true,
|
|
38
33
|
excludeGrammar: 'v2-globs-unions',
|
|
39
34
|
writesExcludes: false,
|
|
40
|
-
uppercaseEnv: false,
|
|
41
35
|
},
|
|
42
36
|
{
|
|
43
37
|
minVersion: '11.0.0',
|
|
@@ -46,7 +40,6 @@ const PNPM_BEHAVIOR_ROWS = [
|
|
|
46
40
|
strictAutoOnWhenExplicit: false,
|
|
47
41
|
excludeGrammar: 'v2-globs-unions',
|
|
48
42
|
writesExcludes: false,
|
|
49
|
-
uppercaseEnv: false,
|
|
50
43
|
},
|
|
51
44
|
{
|
|
52
45
|
minVersion: '10.19.0',
|
|
@@ -55,7 +48,6 @@ const PNPM_BEHAVIOR_ROWS = [
|
|
|
55
48
|
strictAutoOnWhenExplicit: false,
|
|
56
49
|
excludeGrammar: 'v2-globs-unions',
|
|
57
50
|
writesExcludes: false,
|
|
58
|
-
uppercaseEnv: false,
|
|
59
51
|
},
|
|
60
52
|
{
|
|
61
53
|
minVersion: '10.16.0',
|
|
@@ -64,29 +56,78 @@ const PNPM_BEHAVIOR_ROWS = [
|
|
|
64
56
|
strictAutoOnWhenExplicit: false,
|
|
65
57
|
excludeGrammar: 'v1-exact-names',
|
|
66
58
|
writesExcludes: false,
|
|
67
|
-
uppercaseEnv: false,
|
|
68
59
|
},
|
|
69
60
|
];
|
|
70
61
|
function findBehaviorRow(pmVersion) {
|
|
71
62
|
return PNPM_BEHAVIOR_ROWS.find((row) => (0, semver_1.gte)(pmVersion, row.minVersion));
|
|
72
63
|
}
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
|
|
64
|
+
// Asks pnpm for its own resolved config rather than re-deriving how pnpm layers
|
|
65
|
+
// .npmrc / env / pnpm-workspace.yaml / global config across versions. Returns
|
|
66
|
+
// null if pnpm cannot be run or its output is not parseable JSON, so the caller
|
|
67
|
+
// defers to a real install.
|
|
68
|
+
function readPnpmConfigList(root) {
|
|
69
|
+
let raw;
|
|
70
|
+
try {
|
|
71
|
+
raw = (0, child_process_1.execSync)('pnpm config list --json', {
|
|
72
|
+
cwd: root,
|
|
73
|
+
encoding: 'utf-8',
|
|
74
|
+
windowsHide: true,
|
|
75
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(raw);
|
|
83
|
+
return parsed && typeof parsed === 'object'
|
|
84
|
+
? parsed
|
|
85
|
+
: null;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Extracts the cooldown keys from pnpm's reported config. pnpm reports the
|
|
92
|
+
// kebab-case keys; the exclude list comes back as a JSON array (set in a yaml
|
|
93
|
+
// surface) or a comma-joined string (set via .npmrc / env).
|
|
94
|
+
function parseCooldownConfig(config) {
|
|
76
95
|
return {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
windowExplicit,
|
|
96
|
+
windowMinutes: toNumber(config['minimum-release-age']) ?? undefined,
|
|
97
|
+
excludes: parseExcludeValue(config['minimum-release-age-exclude']),
|
|
98
|
+
strictExplicit: toBoolean(config['minimum-release-age-strict']),
|
|
99
|
+
ignoreMissingTimeExplicit: toBoolean(config['minimum-release-age-ignore-missing-time']),
|
|
82
100
|
};
|
|
83
101
|
}
|
|
102
|
+
function parseExcludeValue(value) {
|
|
103
|
+
const entries = Array.isArray(value)
|
|
104
|
+
? value.map((entry) => String(entry))
|
|
105
|
+
: typeof value === 'string'
|
|
106
|
+
? value.split(',')
|
|
107
|
+
: [];
|
|
108
|
+
return entries
|
|
109
|
+
.map((entry) => entry.trim())
|
|
110
|
+
.filter((entry) => entry.length > 0);
|
|
111
|
+
}
|
|
112
|
+
function toBoolean(value) {
|
|
113
|
+
if (typeof value === 'boolean') {
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
if (value === 'true') {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (value === 'false') {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
84
124
|
/**
|
|
85
|
-
* Reads pnpm's effective cooldown configuration once
|
|
86
|
-
*
|
|
87
|
-
* (
|
|
88
|
-
*
|
|
89
|
-
*
|
|
125
|
+
* Reads pnpm's effective cooldown configuration once by asking pnpm itself
|
|
126
|
+
* (`pnpm config list --json`) instead of re-implementing how it layers config
|
|
127
|
+
* surfaces (a moving target across pnpm versions). The window and excludes come
|
|
128
|
+
* straight from pnpm; the strict default, exclude grammar, and loose-fallback
|
|
129
|
+
* semantics stay version-keyed because pnpm does not report those resolved
|
|
130
|
+
* values.
|
|
90
131
|
*/
|
|
91
132
|
async function readPnpmPolicy(root, pmVersion) {
|
|
92
133
|
// A pnpm major newer than the table knows can behave differently; defer to a
|
|
@@ -101,39 +142,39 @@ async function readPnpmPolicy(root, pmVersion) {
|
|
|
101
142
|
if (!row) {
|
|
102
143
|
return { outcome: 'inactive' };
|
|
103
144
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const read = readV11Surfaces(root, row);
|
|
109
|
-
resolution = read.window;
|
|
110
|
-
strictExplicit = read.strictExplicit;
|
|
111
|
-
ignoreMissingTimeExplicit = read.ignoreMissingTime;
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
resolution = readV10Surfaces(root);
|
|
115
|
-
// v10 strict is hardcoded; no surface toggles it.
|
|
116
|
-
strictExplicit = undefined;
|
|
117
|
-
}
|
|
118
|
-
if (!resolution) {
|
|
119
|
-
return { outcome: 'inactive' };
|
|
120
|
-
}
|
|
121
|
-
if (resolution.kind !== 'ok') {
|
|
122
|
-
return { outcome: 'ambiguous', reason: resolution.reason };
|
|
123
|
-
}
|
|
124
|
-
const { windowMinutes, excludes, sourceDescription, windowExplicit } = resolution;
|
|
125
|
-
if (!Number.isFinite(windowMinutes)) {
|
|
145
|
+
const config = readPnpmConfigList(root);
|
|
146
|
+
if (config === null) {
|
|
147
|
+
// Could not read pnpm's resolved config; defer to a real install rather than
|
|
148
|
+
// guess the policy.
|
|
126
149
|
return {
|
|
127
150
|
outcome: 'ambiguous',
|
|
128
|
-
reason:
|
|
151
|
+
reason: 'Unable to read the pnpm minimum-release-age configuration.',
|
|
129
152
|
};
|
|
130
153
|
}
|
|
154
|
+
const { windowMinutes: explicitWindow, excludes, strictExplicit, ignoreMissingTimeExplicit, } = parseCooldownConfig(config);
|
|
155
|
+
// An explicitly configured window (from whatever surface pnpm honors) wins;
|
|
156
|
+
// otherwise v11 falls back to its built-in 1440-minute (1 day) default, while
|
|
157
|
+
// v10 has no default (no cooldown).
|
|
158
|
+
let windowMinutes;
|
|
159
|
+
let windowExplicit;
|
|
160
|
+
if (explicitWindow !== undefined) {
|
|
161
|
+
windowMinutes = explicitWindow;
|
|
162
|
+
windowExplicit = true;
|
|
163
|
+
}
|
|
164
|
+
else if (row.major === 11) {
|
|
165
|
+
windowMinutes = 1440;
|
|
166
|
+
windowExplicit = false;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
return { outcome: 'inactive' };
|
|
170
|
+
}
|
|
131
171
|
// 0 disables; negatives push the cutoff into the future -> everything passes.
|
|
132
172
|
if (windowMinutes <= 0) {
|
|
133
173
|
return { outcome: 'inactive' };
|
|
134
174
|
}
|
|
135
175
|
const windowMs = windowMinutes * constants_1.MS_PER_MINUTE;
|
|
136
176
|
const cutoffMs = Date.now() - windowMs;
|
|
177
|
+
const sourceDescription = `pnpm minimumReleaseAge (${windowMinutes} min)`;
|
|
137
178
|
const strict = resolveStrict(row, strictExplicit, windowExplicit);
|
|
138
179
|
// v10 always errors on missing time; v11 defaults to skip unless a surface
|
|
139
180
|
// explicitly disabled it.
|
|
@@ -179,269 +220,6 @@ function resolveStrict(row, strictExplicit, windowExplicit) {
|
|
|
179
220
|
// so it stays loose - the normal pnpm 11 state.
|
|
180
221
|
return row.strictAutoOnWhenExplicit && windowExplicit;
|
|
181
222
|
}
|
|
182
|
-
// --- v11 surfaces -----------------------------------------------------------
|
|
183
|
-
function readV11Surfaces(root, row) {
|
|
184
|
-
const env = process.env;
|
|
185
|
-
const keySet = envKeySetForMajor(row);
|
|
186
|
-
const wsRead = readYamlWindow((0, path_1.join)(root, 'pnpm-workspace.yaml'));
|
|
187
|
-
if (wsRead && wsRead.kind === 'invalid') {
|
|
188
|
-
return {
|
|
189
|
-
window: wsRead,
|
|
190
|
-
strictExplicit: undefined,
|
|
191
|
-
ignoreMissingTime: undefined,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
const globalRead = readYamlWindow((0, path_1.join)(getConfigDir(env), 'config.yaml'));
|
|
195
|
-
if (globalRead && globalRead.kind === 'invalid') {
|
|
196
|
-
return {
|
|
197
|
-
window: globalRead,
|
|
198
|
-
strictExplicit: undefined,
|
|
199
|
-
ignoreMissingTime: undefined,
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
const wsYaml = wsRead && wsRead.kind === 'ok' ? wsRead : null;
|
|
203
|
-
const globalYaml = globalRead && globalRead.kind === 'ok' ? globalRead : null;
|
|
204
|
-
// pnpm v11 resolves each cooldown key independently across surfaces:
|
|
205
|
-
// env > pnpm-workspace.yaml > global config.yaml > built-in default.
|
|
206
|
-
const strictExplicit = readEnvBoolean(env, keySet, 'minimum_release_age_strict') ??
|
|
207
|
-
wsYaml?.strict ??
|
|
208
|
-
globalYaml?.strict;
|
|
209
|
-
const ignoreMissingTime = readEnvBoolean(env, keySet, 'minimum_release_age_ignore_missing_time') ??
|
|
210
|
-
wsYaml?.ignoreMissingTime ??
|
|
211
|
-
globalYaml?.ignoreMissingTime;
|
|
212
|
-
const envExcludes = readEnvArray(env, keySet, 'minimum_release_age_exclude');
|
|
213
|
-
if (envExcludes === 'invalid') {
|
|
214
|
-
return {
|
|
215
|
-
window: {
|
|
216
|
-
kind: 'invalid',
|
|
217
|
-
reason: 'Invalid pnpm minimumReleaseAgeExclude entry.',
|
|
218
|
-
},
|
|
219
|
-
strictExplicit: undefined,
|
|
220
|
-
ignoreMissingTime: undefined,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
const excludes = envExcludes ?? wsYaml?.excludes ?? globalYaml?.excludes ?? [];
|
|
224
|
-
const envWindow = readEnvNumber(env, keySet, 'minimum_release_age');
|
|
225
|
-
// pnpm drops a NaN env value rather than erroring; treat 'invalid' as unset
|
|
226
|
-
// and fall through to lower surfaces.
|
|
227
|
-
if (envWindow !== undefined && envWindow !== 'invalid') {
|
|
228
|
-
return {
|
|
229
|
-
window: okWindow(envWindow, excludes, 'env'),
|
|
230
|
-
strictExplicit,
|
|
231
|
-
ignoreMissingTime,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
if (wsYaml && wsYaml.windowMinutes !== undefined) {
|
|
235
|
-
return {
|
|
236
|
-
window: okWindow(wsYaml.windowMinutes, excludes, 'pnpm-workspace.yaml'),
|
|
237
|
-
strictExplicit,
|
|
238
|
-
ignoreMissingTime,
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
if (globalYaml && globalYaml.windowMinutes !== undefined) {
|
|
242
|
-
return {
|
|
243
|
-
window: okWindow(globalYaml.windowMinutes, excludes, 'global config.yaml'),
|
|
244
|
-
strictExplicit,
|
|
245
|
-
ignoreMissingTime,
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
// Built-in 1440-minute (1 day) default, injected programmatically and
|
|
249
|
-
// invisible to `pnpm config get`. Loose unless some surface set strict.
|
|
250
|
-
return {
|
|
251
|
-
window: okWindow(1440, excludes, 'default', false),
|
|
252
|
-
strictExplicit,
|
|
253
|
-
ignoreMissingTime,
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
// --- v10 surfaces -----------------------------------------------------------
|
|
257
|
-
function readV10Surfaces(root) {
|
|
258
|
-
// v10 layers config via @pnpm/npm-conf, per key:
|
|
259
|
-
// workspace yaml > npm_config_* env > project .npmrc > user .npmrc.
|
|
260
|
-
const wsRead = readYamlWindow((0, path_1.join)(root, 'pnpm-workspace.yaml'));
|
|
261
|
-
if (wsRead && wsRead.kind === 'invalid') {
|
|
262
|
-
return wsRead;
|
|
263
|
-
}
|
|
264
|
-
const wsYaml = wsRead && wsRead.kind === 'ok' ? wsRead : null;
|
|
265
|
-
const env = process.env;
|
|
266
|
-
const keySet = { prefix: 'npm_config_', uppercase: false };
|
|
267
|
-
const rawEnvWindow = readEnvNumber(env, keySet, 'minimum_release_age');
|
|
268
|
-
// npm-conf drops values that fail the Number type; treat as unset.
|
|
269
|
-
const envWindow = rawEnvWindow === 'invalid' ? undefined : rawEnvWindow;
|
|
270
|
-
const projectNpmrc = readNpmrcSurface((0, path_1.join)(root, '.npmrc'));
|
|
271
|
-
const userNpmrc = readNpmrcSurface((0, path_1.join)((0, os_1.homedir)(), '.npmrc'));
|
|
272
|
-
// v10 reads npm_config_*, which never JSON-parses, so readEnvArray can only
|
|
273
|
-
// yield a single-entry array or undefined here - never 'invalid'.
|
|
274
|
-
const envExcludes = readEnvArray(env, keySet, 'minimum_release_age_exclude');
|
|
275
|
-
const excludes = wsYaml?.excludes ??
|
|
276
|
-
(envExcludes === 'invalid' ? undefined : envExcludes) ??
|
|
277
|
-
projectNpmrc?.excludes ??
|
|
278
|
-
userNpmrc?.excludes ??
|
|
279
|
-
[];
|
|
280
|
-
if (wsYaml && wsYaml.windowMinutes !== undefined) {
|
|
281
|
-
return okWindow(wsYaml.windowMinutes, excludes, 'pnpm-workspace.yaml');
|
|
282
|
-
}
|
|
283
|
-
if (envWindow !== undefined) {
|
|
284
|
-
return okWindow(envWindow, excludes, 'env');
|
|
285
|
-
}
|
|
286
|
-
for (const npmrc of [projectNpmrc, userNpmrc]) {
|
|
287
|
-
if (npmrc && npmrc.windowMinutes !== undefined) {
|
|
288
|
-
return okWindow(npmrc.windowMinutes, excludes, '.npmrc');
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
function readYamlRaw(path) {
|
|
294
|
-
if (!(0, fs_1.existsSync)(path)) {
|
|
295
|
-
return null;
|
|
296
|
-
}
|
|
297
|
-
try {
|
|
298
|
-
const { load } = require('@zkochan/js-yaml');
|
|
299
|
-
return load((0, fs_1.readFileSync)(path, 'utf-8')) ?? {};
|
|
300
|
-
}
|
|
301
|
-
catch {
|
|
302
|
-
// The file exists but is unparseable. An absent file falls through to lower
|
|
303
|
-
// surfaces; a corrupt one can't be reasoned about, so signal it and let the
|
|
304
|
-
// caller defer to a real install (matching npm/yarn/bun on a read failure).
|
|
305
|
-
return 'invalid';
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
function readYamlWindow(path) {
|
|
309
|
-
const doc = readYamlRaw(path);
|
|
310
|
-
if (doc === 'invalid') {
|
|
311
|
-
return { kind: 'invalid', reason: `Unable to parse ${(0, path_1.basename)(path)}.` };
|
|
312
|
-
}
|
|
313
|
-
if (!doc) {
|
|
314
|
-
return null;
|
|
315
|
-
}
|
|
316
|
-
// Each key is read independently; pnpm merges surfaces per key.
|
|
317
|
-
const excludes = readArrayKey(doc, 'minimumReleaseAgeExclude');
|
|
318
|
-
const strict = readBooleanKey(doc, 'minimumReleaseAgeStrict');
|
|
319
|
-
const ignoreMissingTime = readBooleanKey(doc, 'minimumReleaseAgeIgnoreMissingTime');
|
|
320
|
-
const raw = doc['minimumReleaseAge'];
|
|
321
|
-
if (raw === undefined || raw === null) {
|
|
322
|
-
return { kind: 'ok', excludes, strict, ignoreMissingTime };
|
|
323
|
-
}
|
|
324
|
-
const num = toNumber(raw);
|
|
325
|
-
if (num === null) {
|
|
326
|
-
return {
|
|
327
|
-
kind: 'invalid',
|
|
328
|
-
reason: `Invalid pnpm minimumReleaseAge value: ${String(raw)}.`,
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
return {
|
|
332
|
-
kind: 'ok',
|
|
333
|
-
windowMinutes: num,
|
|
334
|
-
excludes,
|
|
335
|
-
strict,
|
|
336
|
-
ignoreMissingTime,
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
function readNpmrcSurface(path) {
|
|
340
|
-
const entries = (0, npmrc_1.readNpmrcEntries)(path);
|
|
341
|
-
if (entries === null) {
|
|
342
|
-
return null;
|
|
343
|
-
}
|
|
344
|
-
// v10 reads the kebab-case keys via npm-conf; camelCase in .npmrc is never
|
|
345
|
-
// honored. Only the two cooldown keys are relevant here.
|
|
346
|
-
let windowMinutes;
|
|
347
|
-
let excludes;
|
|
348
|
-
for (const { key, value: rawValue } of entries) {
|
|
349
|
-
const value = stripQuotes(rawValue);
|
|
350
|
-
if (key === 'minimum-release-age') {
|
|
351
|
-
const num = toNumber(value);
|
|
352
|
-
if (num !== null) {
|
|
353
|
-
windowMinutes = num;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
else if (key === 'minimum-release-age-exclude') {
|
|
357
|
-
// npm-conf accumulates repeated ini keys into an array.
|
|
358
|
-
(excludes ??= []).push(value);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return { windowMinutes, excludes };
|
|
362
|
-
}
|
|
363
|
-
// pnpm mirrors getConfigDir: XDG_CONFIG_HOME, else per-platform default.
|
|
364
|
-
function getConfigDir(env) {
|
|
365
|
-
if (env.XDG_CONFIG_HOME) {
|
|
366
|
-
return (0, path_1.join)(env.XDG_CONFIG_HOME, 'pnpm');
|
|
367
|
-
}
|
|
368
|
-
if (process.platform === 'darwin') {
|
|
369
|
-
return (0, path_1.join)((0, os_1.homedir)(), 'Library/Preferences/pnpm');
|
|
370
|
-
}
|
|
371
|
-
if (process.platform !== 'win32') {
|
|
372
|
-
return (0, path_1.join)((0, os_1.homedir)(), '.config/pnpm');
|
|
373
|
-
}
|
|
374
|
-
if (env.LOCALAPPDATA) {
|
|
375
|
-
return (0, path_1.join)(env.LOCALAPPDATA, 'pnpm/config');
|
|
376
|
-
}
|
|
377
|
-
return (0, path_1.join)((0, os_1.homedir)(), '.config/pnpm');
|
|
378
|
-
}
|
|
379
|
-
function envKeySetForMajor(row) {
|
|
380
|
-
return row.major === 11
|
|
381
|
-
? { prefix: 'pnpm_config_', uppercase: row.uppercaseEnv }
|
|
382
|
-
: { prefix: 'npm_config_', uppercase: false };
|
|
383
|
-
}
|
|
384
|
-
function envKeys(keySet, suffix) {
|
|
385
|
-
const keys = [`${keySet.prefix}${suffix}`];
|
|
386
|
-
if (keySet.uppercase) {
|
|
387
|
-
keys.push(`${keySet.prefix.toUpperCase()}${suffix.toUpperCase()}`);
|
|
388
|
-
}
|
|
389
|
-
return keys;
|
|
390
|
-
}
|
|
391
|
-
function readEnvRaw(env, keySet, suffix) {
|
|
392
|
-
for (const key of envKeys(keySet, suffix)) {
|
|
393
|
-
if (env[key] !== undefined) {
|
|
394
|
-
return env[key];
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
return undefined;
|
|
398
|
-
}
|
|
399
|
-
function readEnvNumber(env, keySet, suffix) {
|
|
400
|
-
const raw = readEnvRaw(env, keySet, suffix);
|
|
401
|
-
if (raw === undefined) {
|
|
402
|
-
return undefined;
|
|
403
|
-
}
|
|
404
|
-
const num = toNumber(raw);
|
|
405
|
-
// pnpm parses env values via Number(); NaN drops the key.
|
|
406
|
-
return num === null ? 'invalid' : num;
|
|
407
|
-
}
|
|
408
|
-
function readEnvBoolean(env, keySet, suffix) {
|
|
409
|
-
const raw = readEnvRaw(env, keySet, suffix);
|
|
410
|
-
// pnpm's Boolean env schema (config/reader/src/env.ts) yields only true/false
|
|
411
|
-
// for the literals; anything else drops the key, so the value falls through to
|
|
412
|
-
// lower surfaces / defaults instead of coercing to false.
|
|
413
|
-
if (raw === 'true') {
|
|
414
|
-
return true;
|
|
415
|
-
}
|
|
416
|
-
if (raw === 'false') {
|
|
417
|
-
return false;
|
|
418
|
-
}
|
|
419
|
-
return undefined;
|
|
420
|
-
}
|
|
421
|
-
function readEnvArray(env, keySet, suffix) {
|
|
422
|
-
const raw = readEnvRaw(env, keySet, suffix);
|
|
423
|
-
if (raw === undefined) {
|
|
424
|
-
return undefined;
|
|
425
|
-
}
|
|
426
|
-
// pnpm v11's [String, Array] env schema tries a JSON array first, then falls
|
|
427
|
-
// back to the raw value as a single entry. v10 (nopt) never JSON-parses.
|
|
428
|
-
if (keySet.prefix === 'pnpm_config_') {
|
|
429
|
-
try {
|
|
430
|
-
const parsed = JSON.parse(raw);
|
|
431
|
-
if (Array.isArray(parsed)) {
|
|
432
|
-
// pnpm passes the array verbatim, then errors at install
|
|
433
|
-
// (ERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDE) on any non-string
|
|
434
|
-
// element; signal invalid so the caller defers to a real install.
|
|
435
|
-
return parsed.every((e) => typeof e === 'string')
|
|
436
|
-
? parsed
|
|
437
|
-
: 'invalid';
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
catch { }
|
|
441
|
-
}
|
|
442
|
-
return [raw];
|
|
443
|
-
}
|
|
444
|
-
// --- value helpers ----------------------------------------------------------
|
|
445
223
|
function toNumber(value) {
|
|
446
224
|
if (typeof value === 'number') {
|
|
447
225
|
return Number.isFinite(value) ? value : null;
|
|
@@ -456,36 +234,6 @@ function toNumber(value) {
|
|
|
456
234
|
}
|
|
457
235
|
return null;
|
|
458
236
|
}
|
|
459
|
-
function stripQuotes(value) {
|
|
460
|
-
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
461
|
-
(value.startsWith("'") && value.endsWith("'"))) {
|
|
462
|
-
return value.slice(1, -1);
|
|
463
|
-
}
|
|
464
|
-
return value;
|
|
465
|
-
}
|
|
466
|
-
function readArrayKey(doc, key) {
|
|
467
|
-
const value = doc[key];
|
|
468
|
-
if (Array.isArray(value)) {
|
|
469
|
-
return value.map((v) => String(v));
|
|
470
|
-
}
|
|
471
|
-
if (typeof value === 'string') {
|
|
472
|
-
return [value];
|
|
473
|
-
}
|
|
474
|
-
return undefined;
|
|
475
|
-
}
|
|
476
|
-
function readBooleanKey(doc, key) {
|
|
477
|
-
const value = doc[key];
|
|
478
|
-
if (typeof value === 'boolean') {
|
|
479
|
-
return value;
|
|
480
|
-
}
|
|
481
|
-
if (value === 'true') {
|
|
482
|
-
return true;
|
|
483
|
-
}
|
|
484
|
-
if (value === 'false') {
|
|
485
|
-
return false;
|
|
486
|
-
}
|
|
487
|
-
return undefined;
|
|
488
|
-
}
|
|
489
237
|
/**
|
|
490
238
|
* Builds the exclude predicate matching pnpm's version-policy semantics.
|
|
491
239
|
* Returns null when any entry is invalid (pnpm would error on it), so the
|
|
@@ -78,9 +78,12 @@ export declare function modifyYarnRcToFitNewDirectory(contents: string): string;
|
|
|
78
78
|
/**
|
|
79
79
|
* We copy pnpm-workspace.yaml to the temporary directory so the workspace's
|
|
80
80
|
* registry, auth and release-age settings still apply, and so `pnpm add -w`
|
|
81
|
-
* recognizes the directory as a workspace root. `
|
|
82
|
-
*
|
|
83
|
-
*
|
|
81
|
+
* recognizes the directory as a workspace root. `patchedDependencies` (relative
|
|
82
|
+
* patch paths) only resolves in the real workspace, so it is dropped. The
|
|
83
|
+
* `packages` field is always set to a self-reference (`['.']`) - the temp dir is
|
|
84
|
+
* a single-package workspace - whether or not the source had one, since pnpm
|
|
85
|
+
* <10.5 (and corepack's bundled default pnpm) reject a workspace manifest whose
|
|
86
|
+
* `packages` field is missing or empty.
|
|
84
87
|
*
|
|
85
88
|
* Exported for testing - not meant to be used outside of this file.
|
|
86
89
|
*
|
|
@@ -326,9 +326,12 @@ function modifyYarnRcToFitNewDirectory(contents) {
|
|
|
326
326
|
/**
|
|
327
327
|
* We copy pnpm-workspace.yaml to the temporary directory so the workspace's
|
|
328
328
|
* registry, auth and release-age settings still apply, and so `pnpm add -w`
|
|
329
|
-
* recognizes the directory as a workspace root. `
|
|
330
|
-
*
|
|
331
|
-
*
|
|
329
|
+
* recognizes the directory as a workspace root. `patchedDependencies` (relative
|
|
330
|
+
* patch paths) only resolves in the real workspace, so it is dropped. The
|
|
331
|
+
* `packages` field is always set to a self-reference (`['.']`) - the temp dir is
|
|
332
|
+
* a single-package workspace - whether or not the source had one, since pnpm
|
|
333
|
+
* <10.5 (and corepack's bundled default pnpm) reject a workspace manifest whose
|
|
334
|
+
* `packages` field is missing or empty.
|
|
332
335
|
*
|
|
333
336
|
* Exported for testing - not meant to be used outside of this file.
|
|
334
337
|
*
|
|
@@ -337,10 +340,11 @@ function modifyYarnRcToFitNewDirectory(contents) {
|
|
|
337
340
|
*/
|
|
338
341
|
function modifyPnpmWorkspaceYamlToFitNewDirectory(contents) {
|
|
339
342
|
const doc = (0, yaml_1.parseDocument)(contents);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
343
|
+
// Set unconditionally so an empty/comments-only source (null doc.contents)
|
|
344
|
+
// still gets a packages field; doc.set creates the root map.
|
|
345
|
+
doc.set('packages', ['.']);
|
|
346
|
+
// Relative patch paths don't resolve in the temp dir.
|
|
347
|
+
doc.delete('patchedDependencies');
|
|
344
348
|
return doc.toString();
|
|
345
349
|
}
|
|
346
350
|
function copyPackageManagerConfigurationFiles(root, destination) {
|
|
@@ -499,8 +503,15 @@ options) {
|
|
|
499
503
|
// Quote the spec so range operators (e.g. `>=0.0.0`) are not parsed as shell
|
|
500
504
|
// redirections.
|
|
501
505
|
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.
|
|
502
510
|
const { stdout } = await execAsync(`${pm} view "${spec}" ${args}`, {
|
|
503
511
|
windowsHide: true,
|
|
512
|
+
...(pm === 'npm'
|
|
513
|
+
? { env: { ...process.env, npm_config_force: 'true' } }
|
|
514
|
+
: {}),
|
|
504
515
|
});
|
|
505
516
|
return stdout.toString().trim();
|
|
506
517
|
}
|
|
@@ -516,6 +527,9 @@ async function packageRegistryPack(cwd, pkg, version) {
|
|
|
516
527
|
const { stdout } = await execAsync(`${pm} pack ${pkg}@${version}`, {
|
|
517
528
|
cwd,
|
|
518
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' },
|
|
519
533
|
});
|
|
520
534
|
const tarballPath = stdout.trim();
|
|
521
535
|
return { tarballPath };
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
export declare const SHOULD_SHOW_SPINNERS: boolean;
|
|
2
|
+
export interface StartSpinnerOptions {
|
|
3
|
+
/**
|
|
4
|
+
* When `true`, the text passed to `start`, `succeed`, and `fail` is NOT
|
|
5
|
+
* emitted in non-TTY environments. By default (`false`), the text is logged
|
|
6
|
+
* via `console.warn` so progress information isn't lost in non-interactive
|
|
7
|
+
* environments. Set to `true` when completion is reported through a
|
|
8
|
+
* different mechanism (e.g. a batched logger).
|
|
9
|
+
*
|
|
10
|
+
* Defaults to `false`.
|
|
11
|
+
*/
|
|
12
|
+
skipNonTtyLogging?: boolean;
|
|
13
|
+
}
|
|
2
14
|
declare class SpinnerManager {
|
|
3
15
|
#private;
|
|
4
|
-
start(text?: string, prefix?: string): SpinnerManager;
|
|
16
|
+
start(text?: string, prefix?: string, opts?: StartSpinnerOptions): SpinnerManager;
|
|
5
17
|
succeed(text?: string): void;
|
|
6
18
|
stop(): void;
|
|
7
19
|
fail(text?: string): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _SpinnerManager_instances, _SpinnerManager_ora, _SpinnerManager_prefix, _SpinnerManager_createOra;
|
|
2
|
+
var _SpinnerManager_instances, _SpinnerManager_ora, _SpinnerManager_prefix, _SpinnerManager_skipNonTtyLogging, _SpinnerManager_createOra, _SpinnerManager_handleNonTty;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.globalSpinner = exports.SHOULD_SHOW_SPINNERS = void 0;
|
|
5
5
|
const tslib_1 = require("tslib");
|
|
@@ -11,9 +11,11 @@ class SpinnerManager {
|
|
|
11
11
|
_SpinnerManager_instances.add(this);
|
|
12
12
|
_SpinnerManager_ora.set(this, void 0);
|
|
13
13
|
_SpinnerManager_prefix.set(this, void 0);
|
|
14
|
+
_SpinnerManager_skipNonTtyLogging.set(this, false);
|
|
14
15
|
}
|
|
15
|
-
start(text, prefix) {
|
|
16
|
-
|
|
16
|
+
start(text, prefix, opts) {
|
|
17
|
+
tslib_1.__classPrivateFieldSet(this, _SpinnerManager_skipNonTtyLogging, opts?.skipNonTtyLogging ?? false, "f");
|
|
18
|
+
if (tslib_1.__classPrivateFieldGet(this, _SpinnerManager_instances, "m", _SpinnerManager_handleNonTty).call(this, text)) {
|
|
17
19
|
return this;
|
|
18
20
|
}
|
|
19
21
|
if (prefix !== undefined) {
|
|
@@ -30,12 +32,18 @@ class SpinnerManager {
|
|
|
30
32
|
return this;
|
|
31
33
|
}
|
|
32
34
|
succeed(text) {
|
|
35
|
+
if (tslib_1.__classPrivateFieldGet(this, _SpinnerManager_instances, "m", _SpinnerManager_handleNonTty).call(this, text)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
33
38
|
tslib_1.__classPrivateFieldGet(this, _SpinnerManager_ora, "f")?.succeed(text);
|
|
34
39
|
}
|
|
35
40
|
stop() {
|
|
36
41
|
tslib_1.__classPrivateFieldGet(this, _SpinnerManager_ora, "f")?.stop();
|
|
37
42
|
}
|
|
38
43
|
fail(text) {
|
|
44
|
+
if (tslib_1.__classPrivateFieldGet(this, _SpinnerManager_instances, "m", _SpinnerManager_handleNonTty).call(this, text)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
39
47
|
tslib_1.__classPrivateFieldGet(this, _SpinnerManager_ora, "f")?.fail(text);
|
|
40
48
|
}
|
|
41
49
|
updateText(text) {
|
|
@@ -50,12 +58,20 @@ class SpinnerManager {
|
|
|
50
58
|
return tslib_1.__classPrivateFieldGet(this, _SpinnerManager_ora, "f")?.isSpinning ?? false;
|
|
51
59
|
}
|
|
52
60
|
}
|
|
53
|
-
_SpinnerManager_ora = new WeakMap(), _SpinnerManager_prefix = new WeakMap(), _SpinnerManager_instances = new WeakSet(), _SpinnerManager_createOra = function _SpinnerManager_createOra(text) {
|
|
61
|
+
_SpinnerManager_ora = new WeakMap(), _SpinnerManager_prefix = new WeakMap(), _SpinnerManager_skipNonTtyLogging = new WeakMap(), _SpinnerManager_instances = new WeakSet(), _SpinnerManager_createOra = function _SpinnerManager_createOra(text) {
|
|
54
62
|
tslib_1.__classPrivateFieldSet(this, _SpinnerManager_ora, (0, ora_1.default)({
|
|
55
63
|
text: text,
|
|
56
64
|
prefixText: tslib_1.__classPrivateFieldGet(this, _SpinnerManager_prefix, "f"),
|
|
57
65
|
hideCursor: false,
|
|
58
66
|
discardStdin: false,
|
|
59
67
|
}), "f");
|
|
68
|
+
}, _SpinnerManager_handleNonTty = function _SpinnerManager_handleNonTty(text) {
|
|
69
|
+
if (exports.SHOULD_SHOW_SPINNERS) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
if (!tslib_1.__classPrivateFieldGet(this, _SpinnerManager_skipNonTtyLogging, "f") && text) {
|
|
73
|
+
console.warn(text);
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
60
76
|
};
|
|
61
77
|
exports.globalSpinner = new SpinnerManager();
|