@vltpkg/graph 1.0.0-rc.14 → 1.0.0-rc.15
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/dist/actual/load.d.ts.map +1 -1
- package/dist/actual/load.js +3 -2
- package/dist/actual/load.js.map +1 -1
- package/dist/fixup-added-names.d.ts +4 -1
- package/dist/fixup-added-names.d.ts.map +1 -1
- package/dist/fixup-added-names.js +16 -0
- package/dist/fixup-added-names.js.map +1 -1
- package/dist/graph.d.ts +7 -0
- package/dist/graph.d.ts.map +1 -1
- package/dist/graph.js +7 -0
- package/dist/graph.js.map +1 -1
- package/dist/ideal/append-nodes.d.ts +14 -2
- package/dist/ideal/append-nodes.d.ts.map +1 -1
- package/dist/ideal/append-nodes.js +179 -63
- package/dist/ideal/append-nodes.js.map +1 -1
- package/dist/ideal/build.d.ts.map +1 -1
- package/dist/ideal/build.js +11 -1
- package/dist/ideal/build.js.map +1 -1
- package/dist/ideal/peers.d.ts +70 -7
- package/dist/ideal/peers.d.ts.map +1 -1
- package/dist/ideal/peers.js +350 -170
- package/dist/ideal/peers.js.map +1 -1
- package/dist/ideal/refresh-ideal-graph.d.ts +0 -4
- package/dist/ideal/refresh-ideal-graph.d.ts.map +1 -1
- package/dist/ideal/refresh-ideal-graph.js +2 -24
- package/dist/ideal/refresh-ideal-graph.js.map +1 -1
- package/dist/ideal/sorting.d.ts +46 -0
- package/dist/ideal/sorting.d.ts.map +1 -0
- package/dist/ideal/sorting.js +71 -0
- package/dist/ideal/sorting.js.map +1 -0
- package/dist/ideal/types.d.ts +1 -5
- package/dist/ideal/types.d.ts.map +1 -1
- package/dist/ideal/types.js.map +1 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +12 -0
- package/dist/install.js.map +1 -1
- package/dist/lockfile/load.d.ts.map +1 -1
- package/dist/lockfile/load.js +21 -0
- package/dist/lockfile/load.js.map +1 -1
- package/dist/lockfile/save.d.ts.map +1 -1
- package/dist/lockfile/save.js +2 -2
- package/dist/lockfile/save.js.map +1 -1
- package/dist/lockfile/types.d.ts +6 -0
- package/dist/lockfile/types.d.ts.map +1 -1
- package/dist/lockfile/types.js +6 -0
- package/dist/lockfile/types.js.map +1 -1
- package/dist/reify/index.d.ts +1 -0
- package/dist/reify/index.d.ts.map +1 -1
- package/dist/reify/index.js +2 -1
- package/dist/reify/index.js.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +1 -0
- package/dist/update.js.map +1 -1
- package/package.json +22 -22
- package/dist/ideal/get-ordered-dependencies.d.ts +0 -10
- package/dist/ideal/get-ordered-dependencies.d.ts.map +0 -1
- package/dist/ideal/get-ordered-dependencies.js +0 -42
- package/dist/ideal/get-ordered-dependencies.js.map +0 -1
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { joinDepIDTuple, joinExtra } from '@vltpkg/dep-id';
|
|
2
2
|
import { error } from '@vltpkg/error-cause';
|
|
3
3
|
import { Spec } from '@vltpkg/spec';
|
|
4
|
+
import { satisfies } from '@vltpkg/satisfies';
|
|
4
5
|
import { longDependencyTypes, normalizeManifest } from '@vltpkg/types';
|
|
5
6
|
import { fixupAddedNames } from "../fixup-added-names.js";
|
|
6
7
|
import { shorten } from "../dependencies.js";
|
|
7
8
|
import { removeOptionalSubgraph } from "../remove-optional-subgraph.js";
|
|
8
9
|
import { extractNode } from "../reify/extract-node.js";
|
|
9
10
|
import { checkPeerEdgesCompatible, endPeerPlacement, forkPeerContext, postPlacementPeerCheck, startPeerPlacement, } from "./peers.js";
|
|
11
|
+
import { compareByHasPeerDeps } from "./sorting.js";
|
|
10
12
|
/**
|
|
11
13
|
* Only install devDeps for git dependencies and importers
|
|
12
14
|
* Everything else always gets installed
|
|
@@ -39,18 +41,67 @@ const getFileTypeInfo = (spec, fromNode, scurry) => {
|
|
|
39
41
|
};
|
|
40
42
|
};
|
|
41
43
|
const isStringArray = (a) => Array.isArray(a) && !a.some(b => typeof b !== 'string');
|
|
44
|
+
/**
|
|
45
|
+
* Try to find a compatible resolution for a dependency, checking peer context.
|
|
46
|
+
* If the first resolution candidate is incompatible with the peer context,
|
|
47
|
+
* try other candidates.
|
|
48
|
+
*/
|
|
49
|
+
const findCompatibleResolution = (spec, fromNode, graph, peerContext, queryModifier, _peer) => {
|
|
50
|
+
const candidates = graph.nodesByName.get(spec.final.name);
|
|
51
|
+
let existingNode = graph.findResolution(spec, fromNode, queryModifier);
|
|
52
|
+
let peerCompatResult = existingNode ?
|
|
53
|
+
checkPeerEdgesCompatible(existingNode, fromNode, peerContext, graph)
|
|
54
|
+
: { compatible: true };
|
|
55
|
+
// CANDIDATE FALLBACK: If first candidate is peer-incompatible, try others
|
|
56
|
+
if (existingNode &&
|
|
57
|
+
!peerCompatResult.compatible &&
|
|
58
|
+
candidates &&
|
|
59
|
+
candidates.size > 1) {
|
|
60
|
+
for (const candidate of candidates) {
|
|
61
|
+
if (candidate === existingNode)
|
|
62
|
+
continue;
|
|
63
|
+
if (candidate.detached)
|
|
64
|
+
continue;
|
|
65
|
+
if (!satisfies(candidate.id, spec.final, fromNode.location, graph.projectRoot, graph.monorepo)) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const compat = checkPeerEdgesCompatible(candidate, fromNode, peerContext, graph);
|
|
69
|
+
if (compat.compatible) {
|
|
70
|
+
existingNode = candidate;
|
|
71
|
+
peerCompatResult = compat;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { existingNode, peerCompatResult };
|
|
77
|
+
};
|
|
42
78
|
/**
|
|
43
79
|
* Fetch manifests for dependencies and create placement tasks.
|
|
80
|
+
*
|
|
81
|
+
* This is Phase 1 of the breadth-first graph building process. For each
|
|
82
|
+
* dependency at the current level:
|
|
83
|
+
* 1. Apply any active modifiers (spec swapping)
|
|
84
|
+
* 2. Try to find an existing node to reuse (with peer compatibility check)
|
|
85
|
+
* 3. If no reusable node, start a manifest fetch (in parallel)
|
|
86
|
+
* 4. Create placement tasks for Phase 2
|
|
87
|
+
*
|
|
88
|
+
* The result is sorted to process non-peer-dependent packages first,
|
|
89
|
+
* ensuring peer dependencies can resolve to already-placed siblings.
|
|
90
|
+
*
|
|
91
|
+
* **Read-only**: This function no longer mutates the graph. It returns
|
|
92
|
+
* tasks that will be applied serially in the BFS loop for deterministic ordering.
|
|
44
93
|
*/
|
|
45
94
|
const fetchManifestsForDeps = async (packageInfo, graph, fromNode, deps, scurry, peerContext, modifierRefs, depth = 0) => {
|
|
46
|
-
// Create fetch tasks for all dependencies at this level
|
|
47
95
|
const fetchTasks = [];
|
|
48
96
|
const placementTasks = [];
|
|
97
|
+
const reuseTasks = [];
|
|
98
|
+
const forkRequests = [];
|
|
49
99
|
for (const { spec: originalSpec, type } of deps) {
|
|
50
100
|
let spec = originalSpec;
|
|
51
101
|
const fileTypeInfo = getFileTypeInfo(spec, fromNode, scurry);
|
|
52
102
|
const activeModifier = modifierRefs?.get(spec.name);
|
|
53
|
-
//
|
|
103
|
+
// MODIFIER HANDLING: Swap spec if an edge modifier is fully matched
|
|
104
|
+
// Example: `vlt install --override "react:^19"` changes react's spec
|
|
54
105
|
const queryModifier = activeModifier?.modifier.query;
|
|
55
106
|
const completeModifier = activeModifier &&
|
|
56
107
|
activeModifier.interactiveBreadcrumb.current ===
|
|
@@ -59,35 +110,29 @@ const fetchManifestsForDeps = async (packageInfo, graph, fromNode, deps, scurry,
|
|
|
59
110
|
completeModifier &&
|
|
60
111
|
'spec' in activeModifier.modifier) {
|
|
61
112
|
spec = activeModifier.modifier.spec;
|
|
113
|
+
// bareSpec of '-' means "remove this dependency"
|
|
62
114
|
if (spec.bareSpec === '-') {
|
|
63
115
|
continue;
|
|
64
116
|
}
|
|
65
117
|
}
|
|
66
118
|
const peer = type === 'peer' || type === 'peerOptional';
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const peerCompatResult = existingNode ?
|
|
72
|
-
checkPeerEdgesCompatible(existingNode, fromNode, peerContext, graph)
|
|
73
|
-
: { compatible: true };
|
|
74
|
-
// Fork peer context if incompatible peer edges detected
|
|
75
|
-
let effectivePeerContext = peerContext;
|
|
119
|
+
// NODE REUSE LOGIC with peer compatibility
|
|
120
|
+
const { existingNode, peerCompatResult } = findCompatibleResolution(spec, fromNode, graph, peerContext, queryModifier, peer);
|
|
121
|
+
// Accumulate fork request if incompatible peer edges detected (defer actual fork)
|
|
122
|
+
const effectivePeerContext = peerContext;
|
|
76
123
|
/* c8 ignore start */
|
|
77
124
|
if (!peerCompatResult.compatible && peerCompatResult.forkEntry) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]);
|
|
125
|
+
forkRequests.push(peerCompatResult.forkEntry);
|
|
126
|
+
// All fork entries from this fromNode will be applied together in Phase B
|
|
81
127
|
}
|
|
82
128
|
/* c8 ignore stop */
|
|
83
129
|
// defines what nodes are eligible to be reused
|
|
84
130
|
const validExistingNode = existingNode &&
|
|
85
131
|
!existingNode.detached &&
|
|
86
|
-
// Regular deps can always reuse
|
|
132
|
+
// Regular deps can always reuse.
|
|
133
|
+
// Peer deps can reuse as well if their peer edges are compatible.
|
|
87
134
|
/* c8 ignore start */
|
|
88
|
-
(!peer ||
|
|
89
|
-
// otherwise reusing peer deps only in case of a peerSetHash match
|
|
90
|
-
existingNode.peerSetHash === fromNode.peerSetHash) &&
|
|
135
|
+
(!peer || peerCompatResult.compatible) &&
|
|
91
136
|
// Check if existing node's peer edges are compatible with new parent
|
|
92
137
|
peerCompatResult.compatible;
|
|
93
138
|
/* c8 ignore stop */
|
|
@@ -95,7 +140,10 @@ const fetchManifestsForDeps = async (packageInfo, graph, fromNode, deps, scurry,
|
|
|
95
140
|
// importers are handled at the ./refresh-ideal-graph.ts top-level
|
|
96
141
|
// so we should just skip whenever we find one
|
|
97
142
|
existingNode?.importer) {
|
|
98
|
-
|
|
143
|
+
// Defer edge creation to Phase B for deterministic ordering.
|
|
144
|
+
// Previously added immediately, but this caused race conditions when
|
|
145
|
+
// parallel fetches completed in different orders.
|
|
146
|
+
reuseTasks.push({ type, spec, fromNode, toNode: existingNode });
|
|
99
147
|
continue;
|
|
100
148
|
}
|
|
101
149
|
// is the current edge pointint go an optional dependency?
|
|
@@ -145,34 +193,30 @@ const fetchManifestsForDeps = async (packageInfo, graph, fromNode, deps, scurry,
|
|
|
145
193
|
// so that peer dependencies can easily reuse already placed regular
|
|
146
194
|
// dependencies as part of peer context set resolution also makes sure to
|
|
147
195
|
// sort by the manifest name for deterministic order.
|
|
148
|
-
placementTasks.sort(
|
|
149
|
-
|
|
150
|
-
Object.keys(a.manifest.peerDependencies).length > 0) ?
|
|
151
|
-
1
|
|
152
|
-
: 0;
|
|
153
|
-
const bIsPeer = (b.manifest?.peerDependencies &&
|
|
154
|
-
Object.keys(b.manifest.peerDependencies).length > 0) ?
|
|
155
|
-
1
|
|
156
|
-
: 0;
|
|
157
|
-
// regular dependencies first, peer dependencies last
|
|
158
|
-
if (aIsPeer !== bIsPeer) {
|
|
159
|
-
return aIsPeer - bIsPeer;
|
|
160
|
-
}
|
|
161
|
-
// if both are in the same group,
|
|
162
|
-
// sort alphabetically by manifest name (fallback to spec.name)
|
|
163
|
-
const aName = a.manifest?.name /* c8 ignore next */ || a.fetchTask.spec.name;
|
|
164
|
-
const bName = b.manifest?.name || b.fetchTask.spec.name;
|
|
165
|
-
return aName.localeCompare(bName, 'en');
|
|
166
|
-
});
|
|
167
|
-
return placementTasks;
|
|
196
|
+
placementTasks.sort(compareByHasPeerDeps);
|
|
197
|
+
return { placementTasks, reuseTasks, forkRequests };
|
|
168
198
|
};
|
|
169
199
|
/**
|
|
170
|
-
* Process placement tasks and collect child dependencies
|
|
171
|
-
*
|
|
172
|
-
*
|
|
200
|
+
* Process placement tasks and collect child dependencies.
|
|
201
|
+
*
|
|
202
|
+
* This is Phase 2 of the breadth-first graph building process. For each
|
|
203
|
+
* resolved manifest:
|
|
204
|
+
* 1. Handle missing manifests (optional vs required deps)
|
|
205
|
+
* 2. Start peer placement process (collect sibling context)
|
|
206
|
+
* 3. Place the node in the graph with appropriate flags
|
|
207
|
+
* 4. Trigger early extraction if eligible (performance optimization)
|
|
208
|
+
* 5. Collect child dependencies for the next BFS level
|
|
209
|
+
* 6. End peer placement (setup context update functions)
|
|
210
|
+
*
|
|
211
|
+
* Early extraction: When `actual` graph is provided, nodes destined for the
|
|
212
|
+
* vlt store are extracted immediately (in parallel) instead of waiting for
|
|
213
|
+
* the full ideal graph to be built. This significantly improves install time.
|
|
173
214
|
*/
|
|
174
215
|
const processPlacementTasks = async (graph, options, placementTasks, add, modifiers, scurry, packageInfo, extractPromises, actual, seenExtracted, remover, transientAdd, transientRemove) => {
|
|
175
216
|
const childDepsToProcess = [];
|
|
217
|
+
// Note: placementTasks are already sorted by fetchManifestsForDeps
|
|
218
|
+
// using compareByHasPeerDeps to ensure non-peer deps are processed first.
|
|
219
|
+
// We don't sort again here to preserve that ordering.
|
|
176
220
|
for (const placementTask of placementTasks) {
|
|
177
221
|
const { fetchTask, manifest } = placementTask;
|
|
178
222
|
let { activeModifier, edgeOptional, fileTypeInfo, fromNode, peerContext, queryModifier, spec, type, } = fetchTask;
|
|
@@ -341,22 +385,43 @@ const processPlacementTasks = async (graph, options, placementTasks, add, modifi
|
|
|
341
385
|
* Append new nodes in the given `graph` for dependencies specified at `add`
|
|
342
386
|
* and missing dependencies from the `deps` parameter.
|
|
343
387
|
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
388
|
+
* Uses **breadth-first traversal** (BFS) with **deterministic ordering** to
|
|
389
|
+
* ensure reproducible builds. The algorithm:
|
|
390
|
+
*
|
|
391
|
+
* 1. Process all deps at the current level in parallel
|
|
392
|
+
* 2. After each level, run `postPlacementPeerCheck` to handle peer contexts
|
|
393
|
+
* 3. Collect child deps for the next level
|
|
394
|
+
* 4. Repeat until no more deps to process
|
|
395
|
+
*
|
|
396
|
+
* **Peer Context Isolation**: Each workspace importer gets its own peer context
|
|
397
|
+
* to prevent cross-workspace leakage. Without this, `react@^18` from workspace A
|
|
398
|
+
* could incorrectly satisfy `react@^19` peer deps in workspace B.
|
|
399
|
+
*
|
|
400
|
+
* **Early Extraction**: When `actual` graph is provided, nodes are extracted
|
|
401
|
+
* to the vlt store during graph construction (not after), improving performance.
|
|
346
402
|
*/
|
|
347
403
|
export const appendNodes = async (packageInfo, graph, fromNode, deps, scurry, options, seen, add, modifiers, modifierRefs, extractPromises, actual, seenExtracted, remover, transientAdd, transientRemove) => {
|
|
404
|
+
// Cycle detection: skip if already processed
|
|
348
405
|
/* c8 ignore next */
|
|
349
406
|
if (seen.has(fromNode.id))
|
|
350
407
|
return;
|
|
351
408
|
seen.add(fromNode.id);
|
|
352
|
-
//
|
|
353
|
-
|
|
409
|
+
// PEER CONTEXT ISOLATION: Each workspace importer needs its own context
|
|
410
|
+
// to prevent peer targets from one workspace affecting another.
|
|
411
|
+
// The main importer (index 0) uses the initial context; others get fresh ones.
|
|
412
|
+
let initialPeerContext = graph.peerContexts[0];
|
|
354
413
|
/* c8 ignore start - impossible */
|
|
355
|
-
if (!initialPeerContext)
|
|
414
|
+
if (!initialPeerContext)
|
|
356
415
|
throw error('no initial peer context found in graph');
|
|
357
|
-
}
|
|
358
416
|
/* c8 ignore stop */
|
|
359
|
-
|
|
417
|
+
if (fromNode.importer && fromNode !== graph.mainImporter) {
|
|
418
|
+
// Create isolated peer context for this workspace importer
|
|
419
|
+
const nextPeerContext = new Map();
|
|
420
|
+
nextPeerContext.index = graph.nextPeerContextIndex();
|
|
421
|
+
graph.peerContexts[nextPeerContext.index] = nextPeerContext;
|
|
422
|
+
initialPeerContext = nextPeerContext;
|
|
423
|
+
}
|
|
424
|
+
// BFS queue: process deps level by level for deterministic builds
|
|
360
425
|
let currentLevelDeps = [
|
|
361
426
|
{
|
|
362
427
|
node: fromNode,
|
|
@@ -372,27 +437,78 @@ export const appendNodes = async (packageInfo, graph, fromNode, deps, scurry, op
|
|
|
372
437
|
/* c8 ignore stop */
|
|
373
438
|
},
|
|
374
439
|
];
|
|
440
|
+
// BFS MAIN LOOP: Process level by level until no more deps
|
|
375
441
|
while (currentLevelDeps.length > 0) {
|
|
376
442
|
const nextLevelDeps = [];
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
443
|
+
// ============================================================
|
|
444
|
+
// PHASE A: PARALLEL FETCH (READ-ONLY)
|
|
445
|
+
// ============================================================
|
|
446
|
+
// Fetch all manifests at this level in parallel without mutating the graph.
|
|
447
|
+
// This phase is read-only to avoid race conditions from network timing.
|
|
448
|
+
const fetchResults = await Promise.all(currentLevelDeps.map(async ({ node, deps: nodeDeps, modifierRefs: nodeModifierRefs, peerContext, depth, }) => {
|
|
449
|
+
// Cycle prevention: mark as seen when starting to process
|
|
380
450
|
seen.add(node.id);
|
|
381
|
-
// Fetch manifests
|
|
382
|
-
const
|
|
383
|
-
// Sort
|
|
451
|
+
// Fetch manifests and collect tasks (no graph mutations)
|
|
452
|
+
const result = await fetchManifestsForDeps(packageInfo, graph, node,
|
|
453
|
+
// Sort by name for deterministic ordering (reproducible builds)
|
|
384
454
|
nodeDeps.sort((a, b) => a.spec.name.localeCompare(b.spec.name, 'en')), scurry, peerContext, nodeModifierRefs, depth);
|
|
385
|
-
|
|
386
|
-
|
|
455
|
+
return {
|
|
456
|
+
entry: {
|
|
457
|
+
node,
|
|
458
|
+
deps: nodeDeps,
|
|
459
|
+
modifierRefs: nodeModifierRefs,
|
|
460
|
+
peerContext,
|
|
461
|
+
depth,
|
|
462
|
+
},
|
|
463
|
+
result,
|
|
464
|
+
};
|
|
387
465
|
}));
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
//
|
|
466
|
+
// ============================================================
|
|
467
|
+
// PHASE B: SERIAL MUTATIONS (DETERMINISTIC ORDER)
|
|
468
|
+
// ============================================================
|
|
469
|
+
// Sort results by stable identifiers to ensure deterministic ordering
|
|
470
|
+
// regardless of which manifest fetch completed first
|
|
471
|
+
const sortedResults = fetchResults.sort((a, b) => {
|
|
472
|
+
// Sort by node ID (DepID-based, stable) and depth
|
|
473
|
+
const keyA = `${a.entry.node.id}::${a.entry.depth}`;
|
|
474
|
+
const keyB = `${b.entry.node.id}::${b.entry.depth}`;
|
|
475
|
+
return keyA.localeCompare(keyB, 'en');
|
|
476
|
+
});
|
|
477
|
+
// Apply all mutations serially in deterministic order
|
|
478
|
+
const levelResults = [];
|
|
479
|
+
for (const { entry, result } of sortedResults) {
|
|
480
|
+
// Apply accumulated fork requests if any (from Phase A deferred forks)
|
|
481
|
+
if (result.forkRequests.length > 0) {
|
|
482
|
+
const forkedContext = forkPeerContext(graph, entry.peerContext, result.forkRequests);
|
|
483
|
+
entry.peerContext = forkedContext;
|
|
484
|
+
// Update peer context in all placement tasks to use forked context
|
|
485
|
+
for (const task of result.placementTasks) {
|
|
486
|
+
task.fetchTask.peerContext = forkedContext;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
// Apply reuse edges in deterministic order (before placement)
|
|
490
|
+
// Sort reuse tasks by spec name for stability
|
|
491
|
+
const sortedReuseTasks = result.reuseTasks.sort((a, b) => a.spec.name.localeCompare(b.spec.name, 'en'));
|
|
492
|
+
for (const { type, spec, fromNode, toNode, } of sortedReuseTasks) {
|
|
493
|
+
graph.addEdge(type, spec, fromNode, toNode);
|
|
494
|
+
}
|
|
495
|
+
// Place nodes and collect child deps
|
|
496
|
+
const placed = await processPlacementTasks(graph, options, result.placementTasks, add, modifiers, scurry, packageInfo, extractPromises, actual, seenExtracted, remover, transientAdd, transientRemove);
|
|
497
|
+
levelResults.push(placed);
|
|
498
|
+
}
|
|
499
|
+
// ============================================================
|
|
500
|
+
// PHASE C: POST-PLACEMENT PEER CHECK
|
|
501
|
+
// ============================================================
|
|
502
|
+
// After all nodes at this level are placed, update peer contexts,
|
|
503
|
+
// fork as needed, and resolve peer deps that can be satisfied.
|
|
504
|
+
// This must happen AFTER placement so sibling nodes are available.
|
|
392
505
|
postPlacementPeerCheck(graph, levelResults);
|
|
393
|
-
//
|
|
506
|
+
// ============================================================
|
|
507
|
+
// STEP 3: COLLECT CHILD DEPS FOR NEXT LEVEL
|
|
508
|
+
// ============================================================
|
|
394
509
|
for (const childDepsToProcess of levelResults) {
|
|
395
510
|
for (const childDep of childDepsToProcess) {
|
|
511
|
+
// Skip already-seen nodes (cycle prevention)
|
|
396
512
|
if (!seen.has(childDep.node.id)) {
|
|
397
513
|
/* c8 ignore next */
|
|
398
514
|
const currentDepth = currentLevelDeps[0]?.depth ?? 0;
|
|
@@ -403,7 +519,7 @@ export const appendNodes = async (packageInfo, graph, fromNode, deps, scurry, op
|
|
|
403
519
|
}
|
|
404
520
|
}
|
|
405
521
|
}
|
|
406
|
-
//
|
|
522
|
+
// Advance to next BFS level
|
|
407
523
|
currentLevelDeps = nextLevelDeps;
|
|
408
524
|
}
|
|
409
525
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append-nodes.js","sourceRoot":"","sources":["../../src/ideal/append-nodes.ts"],"names":[],"mappings":"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","sourcesContent":["import { joinDepIDTuple, joinExtra } from '@vltpkg/dep-id'\nimport type { DepID } from '@vltpkg/dep-id'\nimport { error } from '@vltpkg/error-cause'\nimport type { PackageInfoClient } from '@vltpkg/package-info'\nimport { Spec } from '@vltpkg/spec'\nimport type { SpecOptions } from '@vltpkg/spec'\nimport { longDependencyTypes, normalizeManifest } from '@vltpkg/types'\nimport type {\n DependencyTypeLong,\n DependencySaveType,\n Manifest,\n} from '@vltpkg/types'\nimport type { PathScurry } from 'path-scurry'\nimport { fixupAddedNames } from '../fixup-added-names.ts'\nimport { shorten } from '../dependencies.ts'\nimport type { Dependency } from '../dependencies.ts'\nimport type { Graph } from '../graph.ts'\nimport type { Node } from '../node.ts'\nimport { removeOptionalSubgraph } from '../remove-optional-subgraph.ts'\nimport type {\n GraphModifier,\n ModifierActiveEntry,\n} from '../modifiers.ts'\nimport type { ExtractResult } from '../reify/extract-node.ts'\nimport { extractNode } from '../reify/extract-node.ts'\nimport type { RollbackRemove } from '@vltpkg/rollback-remove'\nimport {\n checkPeerEdgesCompatible,\n endPeerPlacement,\n forkPeerContext,\n postPlacementPeerCheck,\n startPeerPlacement,\n} from './peers.ts'\nimport type {\n PeerContext,\n AppendNodeEntry,\n ProcessPlacementResult,\n TransientAddMap,\n TransientRemoveMap,\n} from './types.ts'\n\ntype FileTypeInfo = {\n id: DepID\n path: string\n isDirectory: boolean\n}\n\n/**\n * Only install devDeps for git dependencies and importers\n * Everything else always gets installed\n */\nconst shouldInstallDepType = (\n node: Node,\n depType: DependencyTypeLong,\n) =>\n depType !== 'devDependencies' ||\n node.importer ||\n node.id.startsWith('git')\n\n/**\n * Retrieve the {@link DepID} and location for a `file:` type {@link Node}.\n */\nconst getFileTypeInfo = (\n spec: Spec,\n fromNode: Node,\n scurry: PathScurry,\n): FileTypeInfo | undefined => {\n const f = spec.final\n if (f.type !== 'file') return\n\n /* c8 ignore start - should be impossible */\n if (!f.file) {\n throw error('no path on file specifier', { spec })\n }\n /* c8 ignore stop */\n\n // Given that both linked folders and local tarballs (both defined with\n // usage of the `file:` spec prefix) location needs to be relative to their\n // parents, build the expected path and use it for both location and id\n const target = scurry.cwd.resolve(fromNode.location).resolve(f.file)\n const path = target.relativePosix()\n const id = joinDepIDTuple(['file', path])\n\n return {\n path,\n id,\n isDirectory: !!target.lstatSync()?.isDirectory(),\n }\n}\n\nconst isStringArray = (a: unknown): a is string[] =>\n Array.isArray(a) && !a.some(b => typeof b !== 'string')\n\n/**\n * Represents a manifest fetch operation with all the context needed.\n */\ntype ManifestFetchTask = {\n spec: Spec\n type: DependencySaveType\n fromNode: Node\n fileTypeInfo?: FileTypeInfo\n activeModifier?: ModifierActiveEntry\n queryModifier?: string\n edgeOptional: boolean\n manifestPromise: Promise<Manifest | undefined>\n depth: number\n peerContext: PeerContext\n}\n\n/**\n * Represents a node placement operation that depends on a resolved manifest.\n */\ntype NodePlacementTask = {\n fetchTask: ManifestFetchTask\n manifest: Manifest | undefined\n node?: Node\n childDeps?: Dependency[]\n childModifierRefs?: Map<string, ModifierActiveEntry>\n childPeerContext?: PeerContext\n}\n\n/**\n * Fetch manifests for dependencies and create placement tasks.\n */\nconst fetchManifestsForDeps = async (\n packageInfo: PackageInfoClient,\n graph: Graph,\n fromNode: Node,\n deps: Dependency[],\n scurry: PathScurry,\n peerContext: PeerContext,\n modifierRefs?: Map<string, ModifierActiveEntry>,\n depth = 0,\n): Promise<NodePlacementTask[]> => {\n // Create fetch tasks for all dependencies at this level\n const fetchTasks: ManifestFetchTask[] = []\n const placementTasks: NodePlacementTask[] = []\n\n for (const { spec: originalSpec, type } of deps) {\n let spec = originalSpec\n const fileTypeInfo = getFileTypeInfo(spec, fromNode, scurry)\n const activeModifier = modifierRefs?.get(spec.name)\n\n // here is the place we swap specs if a edge modifier was defined\n const queryModifier = activeModifier?.modifier.query\n const completeModifier =\n activeModifier &&\n activeModifier.interactiveBreadcrumb.current ===\n activeModifier.modifier.breadcrumb.last\n if (\n queryModifier &&\n completeModifier &&\n 'spec' in activeModifier.modifier\n ) {\n spec = activeModifier.modifier.spec\n if (spec.bareSpec === '-') {\n continue\n }\n }\n\n const peer = type === 'peer' || type === 'peerOptional'\n\n // skip reusing nodes for peer deps since their reusability\n // is handled ahead-of-time during its parent's placement\n const existingNode = graph.findResolution(\n spec,\n fromNode,\n queryModifier,\n )\n\n // Check if existing node's peer edges are compatible with new parent\n const peerCompatResult =\n existingNode ?\n checkPeerEdgesCompatible(\n existingNode,\n fromNode,\n peerContext,\n graph,\n )\n : { compatible: true }\n\n // Fork peer context if incompatible peer edges detected\n let effectivePeerContext = peerContext\n /* c8 ignore start */\n if (!peerCompatResult.compatible && peerCompatResult.forkEntry) {\n effectivePeerContext = forkPeerContext(graph, peerContext, [\n peerCompatResult.forkEntry,\n ])\n }\n /* c8 ignore stop */\n\n // defines what nodes are eligible to be reused\n const validExistingNode =\n existingNode &&\n !existingNode.detached &&\n // Regular deps can always reuse\n /* c8 ignore start */\n (!peer ||\n // otherwise reusing peer deps only in case of a peerSetHash match\n existingNode.peerSetHash === fromNode.peerSetHash) &&\n // Check if existing node's peer edges are compatible with new parent\n peerCompatResult.compatible\n /* c8 ignore stop */\n\n if (\n validExistingNode ||\n // importers are handled at the ./refresh-ideal-graph.ts top-level\n // so we should just skip whenever we find one\n existingNode?.importer\n ) {\n graph.addEdge(type, spec, fromNode, existingNode)\n continue\n }\n\n // is the current edge pointint go an optional dependency?\n const edgeOptional =\n type === 'optional' || type === 'peerOptional'\n\n // Start manifest fetch immediately for parallel processing\n const manifestPromise =\n // the \"detached\" node state means that it has already been load as\n // part of a graph (either lockfile or actual) and it has valid manifest\n // data so we shortcut the package info manifest fetch here\n existingNode?.detached ?\n Promise.resolve(existingNode.manifest as Manifest | undefined)\n // this is the entry point to fetch calls to retrieve manifests\n // from the build ideal graph point of view\n : packageInfo\n .manifest(spec, { from: scurry.resolve(fromNode.location) })\n .then(manifest => manifest as Manifest | undefined)\n .catch((er: unknown) => {\n // optional deps ignored if inaccessible\n if (edgeOptional || fromNode.optional) {\n return undefined\n }\n throw er\n })\n\n const fetchTask: ManifestFetchTask = {\n spec,\n type,\n fromNode,\n fileTypeInfo,\n activeModifier,\n queryModifier,\n edgeOptional,\n manifestPromise,\n depth,\n peerContext: effectivePeerContext,\n }\n\n fetchTasks.push(fetchTask)\n }\n\n // Create placement tasks from fetch tasks\n for (const fetchTask of fetchTasks) {\n const manifest = await fetchTask.manifestPromise\n\n placementTasks.push({\n fetchTask,\n manifest,\n })\n }\n\n // sort placement tasks: non-peer dependencies first, then peer dependencies\n // so that peer dependencies can easily reuse already placed regular\n // dependencies as part of peer context set resolution also makes sure to\n // sort by the manifest name for deterministic order.\n placementTasks.sort((a, b) => {\n const aIsPeer =\n (\n a.manifest?.peerDependencies &&\n Object.keys(a.manifest.peerDependencies).length > 0\n ) ?\n 1\n : 0\n const bIsPeer =\n (\n b.manifest?.peerDependencies &&\n Object.keys(b.manifest.peerDependencies).length > 0\n ) ?\n 1\n : 0\n\n // regular dependencies first, peer dependencies last\n if (aIsPeer !== bIsPeer) {\n return aIsPeer - bIsPeer\n }\n\n // if both are in the same group,\n // sort alphabetically by manifest name (fallback to spec.name)\n const aName =\n a.manifest?.name /* c8 ignore next */ || a.fetchTask.spec.name\n const bName = b.manifest?.name || b.fetchTask.spec.name\n return aName.localeCompare(bName, 'en')\n })\n\n return placementTasks\n}\n\n/**\n * Process placement tasks and collect child dependencies, this is the\n * second step of the appendNodes operation after manifest fetching in\n * which the final graph data structure is actually built.\n */\nconst processPlacementTasks = async (\n graph: Graph,\n options: SpecOptions,\n placementTasks: NodePlacementTask[],\n add?: Map<string, Dependency>,\n modifiers?: GraphModifier,\n scurry?: PathScurry,\n packageInfo?: PackageInfoClient,\n extractPromises?: Promise<ExtractResult>[],\n actual?: Graph,\n seenExtracted?: Set<DepID>,\n remover?: RollbackRemove,\n transientAdd?: TransientAddMap,\n transientRemove?: TransientRemoveMap,\n): Promise<ProcessPlacementResult> => {\n const childDepsToProcess: ProcessPlacementResult = []\n\n for (const placementTask of placementTasks) {\n const { fetchTask, manifest } = placementTask\n let {\n activeModifier,\n edgeOptional,\n fileTypeInfo,\n fromNode,\n peerContext,\n queryModifier,\n spec,\n type,\n } = fetchTask\n\n // fix the name in the `add` map when needed. This allows the upcoming\n // reify step to properly update the package.json file dependencies\n // using the correct names retrieved from the manifest data\n const additiveMap =\n fromNode.importer ? add : transientAdd?.get(fromNode.id)\n spec = fixupAddedNames(additiveMap, manifest, options, spec)\n\n // handles missing manifest resolution\n if (!manifest) {\n if (!edgeOptional && fromNode.isOptional()) {\n // failed resolution of a non-optional dep of an optional node\n // have to clean up the dependents\n removeOptionalSubgraph(graph, fromNode)\n continue\n } else if (edgeOptional) {\n // failed resolution of an optional dep, just ignore it,\n // nothing to prune because we never added it in the first place.\n continue\n } else {\n throw error('failed to resolve dependency', {\n spec,\n from: fromNode.location,\n })\n }\n }\n\n // start peer deps placement process, populating the peer context with\n // dependency data; adding the parent node deps and this manifest's\n // peer deps references to the current peer context set\n const peerPlacement = startPeerPlacement(\n peerContext,\n manifest,\n fromNode,\n options,\n )\n const peerSetHash = peerPlacement.peerSetHash\n const queuedEntries = peerPlacement.queuedEntries\n\n // places a new node in the graph representing a newly seen dependency\n const node = graph.placePackage(\n fromNode,\n type,\n spec,\n normalizeManifest(manifest),\n fileTypeInfo?.id,\n joinExtra({ peerSetHash, modifier: queryModifier }),\n )\n\n /* c8 ignore start - not possible, already ensured manifest */\n if (!node) {\n throw error('failed to place package', {\n from: fromNode.location,\n spec,\n })\n }\n /* c8 ignore stop */\n\n // update the node modifier tracker\n if (activeModifier) {\n modifiers?.updateActiveEntry(node, activeModifier)\n }\n\n const eligibleForExtraction =\n type !== 'peer' &&\n type !== 'peerOptional' &&\n remover &&\n extractPromises &&\n actual &&\n scurry &&\n packageInfo &&\n node.inVltStore() &&\n !node.isOptional() &&\n // this fixes an issue with installing `file:pathname` specs\n /* c8 ignore next */ !fileTypeInfo?.isDirectory &&\n !node.importer\n\n // extract the node if it meets the criteria for early extraction\n if (eligibleForExtraction) {\n /* c8 ignore start */\n if (seenExtracted?.has(node.id)) {\n continue\n }\n /* c8 ignore stop */\n seenExtracted?.add(node.id)\n const actualNode = actual.nodes.get(node.id)\n if (!actualNode?.equals(node)) {\n // extract the node without awaiting - push the promise to the array\n const extractPromise = extractNode(\n node,\n scurry,\n remover,\n options,\n packageInfo,\n )\n extractPromises.push(extractPromise)\n }\n }\n\n // updates graph node information\n if (fileTypeInfo?.path && fileTypeInfo.isDirectory) {\n node.location = fileTypeInfo.path\n }\n node.setResolved()\n\n // collect child dependencies for processing in the next level\n const nextPeerDeps = new Map<string, Dependency>()\n\n // compute deps normally\n const bundleDeps = manifest.bundleDependencies\n const bundled = new Set<string>(\n (\n node.id.startsWith('git') ||\n node.importer ||\n !isStringArray(bundleDeps)\n ) ?\n []\n : bundleDeps,\n )\n\n // setup next level to process all child dependencies in the manifest\n const nextDeps: Dependency[] = []\n\n // traverse actual dependency declarations in the manifest\n // creating dependency entries for them\n for (const depTypeName of longDependencyTypes) {\n const depRecord: Record<string, string> | undefined =\n manifest[depTypeName]\n\n if (depRecord && shouldInstallDepType(node, depTypeName)) {\n // Sort Object.entries for deterministic iteration\n const sortedEntries = Object.entries(depRecord).sort(\n ([a], [b]) => a.localeCompare(b, 'en'),\n )\n for (const [name, bareSpec] of sortedEntries) {\n // might need to skip already placed peer deps here\n if (bundled.has(name)) continue\n const dep = {\n type: shorten(depTypeName, name, manifest),\n spec: Spec.parse(name, bareSpec, {\n ...options,\n registry: spec.registry,\n }),\n }\n if (depTypeName === 'peerDependencies') {\n nextPeerDeps.set(name, dep)\n } else {\n nextDeps.push(dep)\n }\n }\n }\n }\n\n // Inject transient dependencies for non-importer nodes (nested folders)\n // These are deps that were added from a nested folder context using\n // relative file: specs that should resolve relative to that folder\n const transientDeps = transientAdd?.get(node.id)\n if (transientDeps) {\n for (const [, dep] of transientDeps) {\n if (dep.type === 'peer' || dep.type === 'peerOptional') {\n nextPeerDeps.set(dep.spec.name, dep)\n continue\n }\n\n // remove the dependency from nextDeps if it already exists\n const index = nextDeps.findIndex(\n d => d.spec.name === dep.spec.name,\n )\n if (index !== -1) {\n nextDeps.splice(index, 1)\n }\n\n nextDeps.push(dep)\n }\n }\n\n // Remove transient removals when needed\n const transientRemovals = transientRemove?.get(node.id)\n if (transientRemovals) {\n for (const depName of transientRemovals) {\n const index = nextDeps.findIndex(\n dep => dep.spec.name === depName,\n )\n if (index !== -1) {\n nextDeps.splice(index, 1)\n continue\n }\n\n if (nextPeerDeps.has(depName)) {\n nextPeerDeps.delete(depName)\n }\n }\n }\n\n // finish peer placement for this node, resolving satisfied peers\n // to seen nodes from the peer context and adding unsatisfied peers\n // to `nextDeps` so they get processed along regular dependencies\n const updateContext = endPeerPlacement(\n peerContext,\n nextDeps,\n nextPeerDeps,\n graph,\n spec,\n fromNode,\n node,\n type,\n queuedEntries,\n )\n\n childDepsToProcess.push({\n node,\n deps: nextDeps,\n modifierRefs: modifiers?.tryDependencies(node, nextDeps),\n peerContext,\n updateContext,\n })\n }\n\n return childDepsToProcess\n}\n\n/**\n * Append new nodes in the given `graph` for dependencies specified at `add`\n * and missing dependencies from the `deps` parameter.\n *\n * It also applies any modifiers that applies to a given node as it processes\n * and builds the graph.\n */\nexport const appendNodes = async (\n packageInfo: PackageInfoClient,\n graph: Graph,\n fromNode: Node,\n deps: Dependency[],\n scurry: PathScurry,\n options: SpecOptions,\n seen: Set<DepID>,\n add?: Map<string, Dependency>,\n modifiers?: GraphModifier,\n modifierRefs?: Map<string, ModifierActiveEntry>,\n extractPromises?: Promise<ExtractResult>[],\n actual?: Graph,\n seenExtracted?: Set<DepID>,\n remover?: RollbackRemove,\n transientAdd?: TransientAddMap,\n transientRemove?: TransientRemoveMap,\n) => {\n /* c8 ignore next */\n if (seen.has(fromNode.id)) return\n seen.add(fromNode.id)\n\n // Get the initial peer context from the graph\n const [initialPeerContext] = graph.peerContexts\n /* c8 ignore start - impossible */\n if (!initialPeerContext) {\n throw error('no initial peer context found in graph')\n }\n /* c8 ignore stop */\n\n // Use a queue for breadth-first processing\n let currentLevelDeps: AppendNodeEntry[] = [\n {\n node: fromNode,\n deps,\n modifierRefs,\n depth: 0,\n peerContext: initialPeerContext,\n /* c8 ignore start */\n updateContext: {\n putEntries: () => undefined,\n resolvePeerDeps: () => {},\n },\n /* c8 ignore stop */\n },\n ]\n\n while (currentLevelDeps.length > 0) {\n const nextLevelDeps: AppendNodeEntry[] = []\n\n // Process all nodes at the current level in parallel\n const levelResults = await Promise.all(\n currentLevelDeps.map(\n async ({\n node,\n deps: nodeDeps,\n modifierRefs: nodeModifierRefs,\n peerContext,\n depth,\n }: AppendNodeEntry) => {\n // Mark node as seen when we start processing its dependencies\n seen.add(node.id)\n\n // Fetch manifests for this node's dependencies\n const placementTasks = await fetchManifestsForDeps(\n packageInfo,\n graph,\n node,\n // Sort dependencies by spec.name for deterministic ordering\n nodeDeps.sort((a, b) =>\n a.spec.name.localeCompare(b.spec.name, 'en'),\n ),\n scurry,\n peerContext,\n nodeModifierRefs,\n depth,\n )\n\n // Process the placement tasks and get child dependencies\n return await processPlacementTasks(\n graph,\n options,\n placementTasks,\n add,\n modifiers,\n scurry,\n packageInfo,\n extractPromises,\n actual,\n seenExtracted,\n remover,\n transientAdd,\n transientRemove,\n )\n },\n ),\n )\n\n // Traverse the queued up children dependencies, adding and tracking\n // dependencies on the peer context set, forking the context as needed\n // and resolving any peer dependency that is able to be resolved using\n // the current peer context set\n postPlacementPeerCheck(graph, levelResults)\n\n // Collect all child dependencies for the next level\n for (const childDepsToProcess of levelResults) {\n for (const childDep of childDepsToProcess) {\n if (!seen.has(childDep.node.id)) {\n /* c8 ignore next */\n const currentDepth = currentLevelDeps[0]?.depth ?? 0\n nextLevelDeps.push({\n ...childDep,\n depth: currentDepth + 1,\n })\n }\n }\n }\n\n // Move to the next level\n currentLevelDeps = nextLevelDeps\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"append-nodes.js","sourceRoot":"","sources":["../../src/ideal/append-nodes.ts"],"names":[],"mappings":"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","sourcesContent":["import { joinDepIDTuple, joinExtra } from '@vltpkg/dep-id'\nimport type { DepID } from '@vltpkg/dep-id'\nimport { error } from '@vltpkg/error-cause'\nimport type { PackageInfoClient } from '@vltpkg/package-info'\nimport { Spec } from '@vltpkg/spec'\nimport type { SpecOptions } from '@vltpkg/spec'\nimport { satisfies } from '@vltpkg/satisfies'\nimport { longDependencyTypes, normalizeManifest } from '@vltpkg/types'\nimport type {\n DependencyTypeLong,\n DependencySaveType,\n Manifest,\n} from '@vltpkg/types'\nimport type { PathScurry } from 'path-scurry'\nimport { fixupAddedNames } from '../fixup-added-names.ts'\nimport { shorten } from '../dependencies.ts'\nimport type { Dependency } from '../dependencies.ts'\nimport type { Graph } from '../graph.ts'\nimport type { Node } from '../node.ts'\nimport { removeOptionalSubgraph } from '../remove-optional-subgraph.ts'\nimport type {\n GraphModifier,\n ModifierActiveEntry,\n} from '../modifiers.ts'\nimport type { ExtractResult } from '../reify/extract-node.ts'\nimport { extractNode } from '../reify/extract-node.ts'\nimport type { RollbackRemove } from '@vltpkg/rollback-remove'\nimport {\n checkPeerEdgesCompatible,\n endPeerPlacement,\n forkPeerContext,\n postPlacementPeerCheck,\n startPeerPlacement,\n} from './peers.ts'\nimport { compareByHasPeerDeps } from './sorting.ts'\nimport type {\n PeerContext,\n PeerContextEntryInput,\n AppendNodeEntry,\n ProcessPlacementResult,\n TransientAddMap,\n TransientRemoveMap,\n} from './types.ts'\n\ntype FileTypeInfo = {\n id: DepID\n path: string\n isDirectory: boolean\n}\n\n/**\n * Task for reusing an existing node (deferred edge creation).\n */\ntype ReuseTask = {\n type: DependencySaveType\n spec: Spec\n fromNode: Node\n toNode: Node\n}\n\n/**\n * Result of fetching manifests for dependencies.\n */\ntype FetchResult = {\n placementTasks: NodePlacementTask[]\n reuseTasks: ReuseTask[]\n forkRequests: PeerContextEntryInput[]\n}\n\n/**\n * Only install devDeps for git dependencies and importers\n * Everything else always gets installed\n */\nconst shouldInstallDepType = (\n node: Node,\n depType: DependencyTypeLong,\n) =>\n depType !== 'devDependencies' ||\n node.importer ||\n node.id.startsWith('git')\n\n/**\n * Retrieve the {@link DepID} and location for a `file:` type {@link Node}.\n */\nconst getFileTypeInfo = (\n spec: Spec,\n fromNode: Node,\n scurry: PathScurry,\n): FileTypeInfo | undefined => {\n const f = spec.final\n if (f.type !== 'file') return\n\n /* c8 ignore start - should be impossible */\n if (!f.file) {\n throw error('no path on file specifier', { spec })\n }\n /* c8 ignore stop */\n\n // Given that both linked folders and local tarballs (both defined with\n // usage of the `file:` spec prefix) location needs to be relative to their\n // parents, build the expected path and use it for both location and id\n const target = scurry.cwd.resolve(fromNode.location).resolve(f.file)\n const path = target.relativePosix()\n const id = joinDepIDTuple(['file', path])\n\n return {\n path,\n id,\n isDirectory: !!target.lstatSync()?.isDirectory(),\n }\n}\n\nconst isStringArray = (a: unknown): a is string[] =>\n Array.isArray(a) && !a.some(b => typeof b !== 'string')\n\n/**\n * Represents a manifest fetch operation with all the context needed.\n */\ntype ManifestFetchTask = {\n spec: Spec\n type: DependencySaveType\n fromNode: Node\n fileTypeInfo?: FileTypeInfo\n activeModifier?: ModifierActiveEntry\n queryModifier?: string\n edgeOptional: boolean\n manifestPromise: Promise<Manifest | undefined>\n depth: number\n peerContext: PeerContext\n}\n\n/**\n * Represents a node placement operation that depends on a resolved manifest.\n */\ntype NodePlacementTask = {\n fetchTask: ManifestFetchTask\n manifest: Manifest | undefined\n node?: Node\n childDeps?: Dependency[]\n childModifierRefs?: Map<string, ModifierActiveEntry>\n childPeerContext?: PeerContext\n}\n\n/**\n * Try to find a compatible resolution for a dependency, checking peer context.\n * If the first resolution candidate is incompatible with the peer context,\n * try other candidates.\n */\nconst findCompatibleResolution = (\n spec: Spec,\n fromNode: Node,\n graph: Graph,\n peerContext: PeerContext,\n queryModifier?: string,\n _peer?: boolean,\n) => {\n const candidates = graph.nodesByName.get(spec.final.name)\n let existingNode = graph.findResolution(\n spec,\n fromNode,\n queryModifier,\n )\n\n let peerCompatResult =\n existingNode ?\n checkPeerEdgesCompatible(\n existingNode,\n fromNode,\n peerContext,\n graph,\n )\n : { compatible: true }\n\n // CANDIDATE FALLBACK: If first candidate is peer-incompatible, try others\n if (\n existingNode &&\n !peerCompatResult.compatible &&\n candidates &&\n candidates.size > 1\n ) {\n for (const candidate of candidates) {\n if (candidate === existingNode) continue\n if (candidate.detached) continue\n if (\n !satisfies(\n candidate.id,\n spec.final,\n fromNode.location,\n graph.projectRoot,\n graph.monorepo,\n )\n ) {\n continue\n }\n\n const compat = checkPeerEdgesCompatible(\n candidate,\n fromNode,\n peerContext,\n graph,\n )\n if (compat.compatible) {\n existingNode = candidate\n peerCompatResult = compat\n break\n }\n }\n }\n\n return { existingNode, peerCompatResult }\n}\n\n/**\n * Fetch manifests for dependencies and create placement tasks.\n *\n * This is Phase 1 of the breadth-first graph building process. For each\n * dependency at the current level:\n * 1. Apply any active modifiers (spec swapping)\n * 2. Try to find an existing node to reuse (with peer compatibility check)\n * 3. If no reusable node, start a manifest fetch (in parallel)\n * 4. Create placement tasks for Phase 2\n *\n * The result is sorted to process non-peer-dependent packages first,\n * ensuring peer dependencies can resolve to already-placed siblings.\n *\n * **Read-only**: This function no longer mutates the graph. It returns\n * tasks that will be applied serially in the BFS loop for deterministic ordering.\n */\nconst fetchManifestsForDeps = async (\n packageInfo: PackageInfoClient,\n graph: Graph,\n fromNode: Node,\n deps: Dependency[],\n scurry: PathScurry,\n peerContext: PeerContext,\n modifierRefs?: Map<string, ModifierActiveEntry>,\n depth = 0,\n): Promise<FetchResult> => {\n const fetchTasks: ManifestFetchTask[] = []\n const placementTasks: NodePlacementTask[] = []\n const reuseTasks: ReuseTask[] = []\n const forkRequests: PeerContextEntryInput[] = []\n\n for (const { spec: originalSpec, type } of deps) {\n let spec = originalSpec\n const fileTypeInfo = getFileTypeInfo(spec, fromNode, scurry)\n const activeModifier = modifierRefs?.get(spec.name)\n\n // MODIFIER HANDLING: Swap spec if an edge modifier is fully matched\n // Example: `vlt install --override \"react:^19\"` changes react's spec\n const queryModifier = activeModifier?.modifier.query\n const completeModifier =\n activeModifier &&\n activeModifier.interactiveBreadcrumb.current ===\n activeModifier.modifier.breadcrumb.last\n if (\n queryModifier &&\n completeModifier &&\n 'spec' in activeModifier.modifier\n ) {\n spec = activeModifier.modifier.spec\n // bareSpec of '-' means \"remove this dependency\"\n if (spec.bareSpec === '-') {\n continue\n }\n }\n\n const peer = type === 'peer' || type === 'peerOptional'\n\n // NODE REUSE LOGIC with peer compatibility\n const { existingNode, peerCompatResult } =\n findCompatibleResolution(\n spec,\n fromNode,\n graph,\n peerContext,\n queryModifier,\n peer,\n )\n\n // Accumulate fork request if incompatible peer edges detected (defer actual fork)\n const effectivePeerContext = peerContext\n /* c8 ignore start */\n if (!peerCompatResult.compatible && peerCompatResult.forkEntry) {\n forkRequests.push(peerCompatResult.forkEntry)\n // All fork entries from this fromNode will be applied together in Phase B\n }\n /* c8 ignore stop */\n\n // defines what nodes are eligible to be reused\n const validExistingNode =\n existingNode &&\n !existingNode.detached &&\n // Regular deps can always reuse.\n // Peer deps can reuse as well if their peer edges are compatible.\n /* c8 ignore start */\n (!peer || peerCompatResult.compatible) &&\n // Check if existing node's peer edges are compatible with new parent\n peerCompatResult.compatible\n /* c8 ignore stop */\n\n if (\n validExistingNode ||\n // importers are handled at the ./refresh-ideal-graph.ts top-level\n // so we should just skip whenever we find one\n existingNode?.importer\n ) {\n // Defer edge creation to Phase B for deterministic ordering.\n // Previously added immediately, but this caused race conditions when\n // parallel fetches completed in different orders.\n reuseTasks.push({ type, spec, fromNode, toNode: existingNode })\n continue\n }\n\n // is the current edge pointint go an optional dependency?\n const edgeOptional =\n type === 'optional' || type === 'peerOptional'\n\n // Start manifest fetch immediately for parallel processing\n const manifestPromise =\n // the \"detached\" node state means that it has already been load as\n // part of a graph (either lockfile or actual) and it has valid manifest\n // data so we shortcut the package info manifest fetch here\n existingNode?.detached ?\n Promise.resolve(existingNode.manifest as Manifest | undefined)\n // this is the entry point to fetch calls to retrieve manifests\n // from the build ideal graph point of view\n : packageInfo\n .manifest(spec, { from: scurry.resolve(fromNode.location) })\n .then(manifest => manifest as Manifest | undefined)\n .catch((er: unknown) => {\n // optional deps ignored if inaccessible\n if (edgeOptional || fromNode.optional) {\n return undefined\n }\n throw er\n })\n\n const fetchTask: ManifestFetchTask = {\n spec,\n type,\n fromNode,\n fileTypeInfo,\n activeModifier,\n queryModifier,\n edgeOptional,\n manifestPromise,\n depth,\n peerContext: effectivePeerContext,\n }\n\n fetchTasks.push(fetchTask)\n }\n\n // Create placement tasks from fetch tasks\n for (const fetchTask of fetchTasks) {\n const manifest = await fetchTask.manifestPromise\n\n placementTasks.push({\n fetchTask,\n manifest,\n })\n }\n\n // sort placement tasks: non-peer dependencies first, then peer dependencies\n // so that peer dependencies can easily reuse already placed regular\n // dependencies as part of peer context set resolution also makes sure to\n // sort by the manifest name for deterministic order.\n placementTasks.sort(compareByHasPeerDeps)\n\n return { placementTasks, reuseTasks, forkRequests }\n}\n\n/**\n * Process placement tasks and collect child dependencies.\n *\n * This is Phase 2 of the breadth-first graph building process. For each\n * resolved manifest:\n * 1. Handle missing manifests (optional vs required deps)\n * 2. Start peer placement process (collect sibling context)\n * 3. Place the node in the graph with appropriate flags\n * 4. Trigger early extraction if eligible (performance optimization)\n * 5. Collect child dependencies for the next BFS level\n * 6. End peer placement (setup context update functions)\n *\n * Early extraction: When `actual` graph is provided, nodes destined for the\n * vlt store are extracted immediately (in parallel) instead of waiting for\n * the full ideal graph to be built. This significantly improves install time.\n */\nconst processPlacementTasks = async (\n graph: Graph,\n options: SpecOptions,\n placementTasks: NodePlacementTask[],\n add?: Map<string, Dependency>,\n modifiers?: GraphModifier,\n scurry?: PathScurry,\n packageInfo?: PackageInfoClient,\n extractPromises?: Promise<ExtractResult>[],\n actual?: Graph,\n seenExtracted?: Set<DepID>,\n remover?: RollbackRemove,\n transientAdd?: TransientAddMap,\n transientRemove?: TransientRemoveMap,\n): Promise<ProcessPlacementResult> => {\n const childDepsToProcess: ProcessPlacementResult = []\n\n // Note: placementTasks are already sorted by fetchManifestsForDeps\n // using compareByHasPeerDeps to ensure non-peer deps are processed first.\n // We don't sort again here to preserve that ordering.\n\n for (const placementTask of placementTasks) {\n const { fetchTask, manifest } = placementTask\n let {\n activeModifier,\n edgeOptional,\n fileTypeInfo,\n fromNode,\n peerContext,\n queryModifier,\n spec,\n type,\n } = fetchTask\n\n // fix the name in the `add` map when needed. This allows the upcoming\n // reify step to properly update the package.json file dependencies\n // using the correct names retrieved from the manifest data\n const additiveMap =\n fromNode.importer ? add : transientAdd?.get(fromNode.id)\n spec = fixupAddedNames(additiveMap, manifest, options, spec)\n\n // handles missing manifest resolution\n if (!manifest) {\n if (!edgeOptional && fromNode.isOptional()) {\n // failed resolution of a non-optional dep of an optional node\n // have to clean up the dependents\n removeOptionalSubgraph(graph, fromNode)\n continue\n } else if (edgeOptional) {\n // failed resolution of an optional dep, just ignore it,\n // nothing to prune because we never added it in the first place.\n continue\n } else {\n throw error('failed to resolve dependency', {\n spec,\n from: fromNode.location,\n })\n }\n }\n\n // start peer deps placement process, populating the peer context with\n // dependency data; adding the parent node deps and this manifest's\n // peer deps references to the current peer context set\n const peerPlacement = startPeerPlacement(\n peerContext,\n manifest,\n fromNode,\n options,\n )\n const peerSetHash = peerPlacement.peerSetHash\n const queuedEntries = peerPlacement.queuedEntries\n\n // places a new node in the graph representing a newly seen dependency\n const node = graph.placePackage(\n fromNode,\n type,\n spec,\n normalizeManifest(manifest),\n fileTypeInfo?.id,\n joinExtra({ peerSetHash, modifier: queryModifier }),\n )\n\n /* c8 ignore start - not possible, already ensured manifest */\n if (!node) {\n throw error('failed to place package', {\n from: fromNode.location,\n spec,\n })\n }\n /* c8 ignore stop */\n\n // update the node modifier tracker\n if (activeModifier) {\n modifiers?.updateActiveEntry(node, activeModifier)\n }\n\n const eligibleForExtraction =\n type !== 'peer' &&\n type !== 'peerOptional' &&\n remover &&\n extractPromises &&\n actual &&\n scurry &&\n packageInfo &&\n node.inVltStore() &&\n !node.isOptional() &&\n // this fixes an issue with installing `file:pathname` specs\n /* c8 ignore next */ !fileTypeInfo?.isDirectory &&\n !node.importer\n\n // extract the node if it meets the criteria for early extraction\n if (eligibleForExtraction) {\n /* c8 ignore start */\n if (seenExtracted?.has(node.id)) {\n continue\n }\n /* c8 ignore stop */\n seenExtracted?.add(node.id)\n const actualNode = actual.nodes.get(node.id)\n if (!actualNode?.equals(node)) {\n // extract the node without awaiting - push the promise to the array\n const extractPromise = extractNode(\n node,\n scurry,\n remover,\n options,\n packageInfo,\n )\n extractPromises.push(extractPromise)\n }\n }\n\n // updates graph node information\n if (fileTypeInfo?.path && fileTypeInfo.isDirectory) {\n node.location = fileTypeInfo.path\n }\n node.setResolved()\n\n // collect child dependencies for processing in the next level\n const nextPeerDeps = new Map<string, Dependency>()\n\n // compute deps normally\n const bundleDeps = manifest.bundleDependencies\n const bundled = new Set<string>(\n (\n node.id.startsWith('git') ||\n node.importer ||\n !isStringArray(bundleDeps)\n ) ?\n []\n : bundleDeps,\n )\n\n // setup next level to process all child dependencies in the manifest\n const nextDeps: Dependency[] = []\n\n // traverse actual dependency declarations in the manifest\n // creating dependency entries for them\n for (const depTypeName of longDependencyTypes) {\n const depRecord: Record<string, string> | undefined =\n manifest[depTypeName]\n\n if (depRecord && shouldInstallDepType(node, depTypeName)) {\n // Sort Object.entries for deterministic iteration\n const sortedEntries = Object.entries(depRecord).sort(\n ([a], [b]) => a.localeCompare(b, 'en'),\n )\n for (const [name, bareSpec] of sortedEntries) {\n // might need to skip already placed peer deps here\n if (bundled.has(name)) continue\n const dep = {\n type: shorten(depTypeName, name, manifest),\n spec: Spec.parse(name, bareSpec, {\n ...options,\n registry: spec.registry,\n }),\n }\n if (depTypeName === 'peerDependencies') {\n nextPeerDeps.set(name, dep)\n } else {\n nextDeps.push(dep)\n }\n }\n }\n }\n\n // Inject transient dependencies for non-importer nodes (nested folders)\n // These are deps that were added from a nested folder context using\n // relative file: specs that should resolve relative to that folder\n const transientDeps = transientAdd?.get(node.id)\n if (transientDeps) {\n for (const [, dep] of transientDeps) {\n if (dep.type === 'peer' || dep.type === 'peerOptional') {\n nextPeerDeps.set(dep.spec.name, dep)\n continue\n }\n\n // remove the dependency from nextDeps if it already exists\n const index = nextDeps.findIndex(\n d => d.spec.name === dep.spec.name,\n )\n if (index !== -1) {\n nextDeps.splice(index, 1)\n }\n\n nextDeps.push(dep)\n }\n }\n\n // Remove transient removals when needed\n const transientRemovals = transientRemove?.get(node.id)\n if (transientRemovals) {\n for (const depName of transientRemovals) {\n const index = nextDeps.findIndex(\n dep => dep.spec.name === depName,\n )\n if (index !== -1) {\n nextDeps.splice(index, 1)\n continue\n }\n\n if (nextPeerDeps.has(depName)) {\n nextPeerDeps.delete(depName)\n }\n }\n }\n\n // finish peer placement for this node, resolving satisfied peers\n // to seen nodes from the peer context and adding unsatisfied peers\n // to `nextDeps` so they get processed along regular dependencies\n const updateContext = endPeerPlacement(\n peerContext,\n nextDeps,\n nextPeerDeps,\n graph,\n spec,\n fromNode,\n node,\n type,\n queuedEntries,\n )\n\n childDepsToProcess.push({\n node,\n deps: nextDeps,\n modifierRefs: modifiers?.tryDependencies(node, nextDeps),\n peerContext,\n updateContext,\n })\n }\n\n return childDepsToProcess\n}\n\n/**\n * Append new nodes in the given `graph` for dependencies specified at `add`\n * and missing dependencies from the `deps` parameter.\n *\n * Uses **breadth-first traversal** (BFS) with **deterministic ordering** to\n * ensure reproducible builds. The algorithm:\n *\n * 1. Process all deps at the current level in parallel\n * 2. After each level, run `postPlacementPeerCheck` to handle peer contexts\n * 3. Collect child deps for the next level\n * 4. Repeat until no more deps to process\n *\n * **Peer Context Isolation**: Each workspace importer gets its own peer context\n * to prevent cross-workspace leakage. Without this, `react@^18` from workspace A\n * could incorrectly satisfy `react@^19` peer deps in workspace B.\n *\n * **Early Extraction**: When `actual` graph is provided, nodes are extracted\n * to the vlt store during graph construction (not after), improving performance.\n */\nexport const appendNodes = async (\n packageInfo: PackageInfoClient,\n graph: Graph,\n fromNode: Node,\n deps: Dependency[],\n scurry: PathScurry,\n options: SpecOptions,\n seen: Set<DepID>,\n add?: Map<string, Dependency>,\n modifiers?: GraphModifier,\n modifierRefs?: Map<string, ModifierActiveEntry>,\n extractPromises?: Promise<ExtractResult>[],\n actual?: Graph,\n seenExtracted?: Set<DepID>,\n remover?: RollbackRemove,\n transientAdd?: TransientAddMap,\n transientRemove?: TransientRemoveMap,\n) => {\n // Cycle detection: skip if already processed\n /* c8 ignore next */\n if (seen.has(fromNode.id)) return\n seen.add(fromNode.id)\n\n // PEER CONTEXT ISOLATION: Each workspace importer needs its own context\n // to prevent peer targets from one workspace affecting another.\n // The main importer (index 0) uses the initial context; others get fresh ones.\n let initialPeerContext = graph.peerContexts[0]\n /* c8 ignore start - impossible */\n if (!initialPeerContext)\n throw error('no initial peer context found in graph')\n /* c8 ignore stop */\n if (fromNode.importer && fromNode !== graph.mainImporter) {\n // Create isolated peer context for this workspace importer\n const nextPeerContext: PeerContext = new Map()\n nextPeerContext.index = graph.nextPeerContextIndex()\n graph.peerContexts[nextPeerContext.index] = nextPeerContext\n initialPeerContext = nextPeerContext\n }\n\n // BFS queue: process deps level by level for deterministic builds\n let currentLevelDeps: AppendNodeEntry[] = [\n {\n node: fromNode,\n deps,\n modifierRefs,\n depth: 0,\n peerContext: initialPeerContext,\n /* c8 ignore start */\n updateContext: {\n putEntries: () => undefined,\n resolvePeerDeps: () => {},\n },\n /* c8 ignore stop */\n },\n ]\n\n // BFS MAIN LOOP: Process level by level until no more deps\n while (currentLevelDeps.length > 0) {\n const nextLevelDeps: AppendNodeEntry[] = []\n\n // ============================================================\n // PHASE A: PARALLEL FETCH (READ-ONLY)\n // ============================================================\n // Fetch all manifests at this level in parallel without mutating the graph.\n // This phase is read-only to avoid race conditions from network timing.\n const fetchResults = await Promise.all(\n currentLevelDeps.map(\n async ({\n node,\n deps: nodeDeps,\n modifierRefs: nodeModifierRefs,\n peerContext,\n depth,\n }: AppendNodeEntry) => {\n // Cycle prevention: mark as seen when starting to process\n seen.add(node.id)\n\n // Fetch manifests and collect tasks (no graph mutations)\n const result = await fetchManifestsForDeps(\n packageInfo,\n graph,\n node,\n // Sort by name for deterministic ordering (reproducible builds)\n nodeDeps.sort((a, b) =>\n a.spec.name.localeCompare(b.spec.name, 'en'),\n ),\n scurry,\n peerContext,\n nodeModifierRefs,\n depth,\n )\n\n return {\n entry: {\n node,\n deps: nodeDeps,\n modifierRefs: nodeModifierRefs,\n peerContext,\n depth,\n },\n result,\n }\n },\n ),\n )\n\n // ============================================================\n // PHASE B: SERIAL MUTATIONS (DETERMINISTIC ORDER)\n // ============================================================\n // Sort results by stable identifiers to ensure deterministic ordering\n // regardless of which manifest fetch completed first\n const sortedResults = fetchResults.sort((a, b) => {\n // Sort by node ID (DepID-based, stable) and depth\n const keyA = `${a.entry.node.id}::${a.entry.depth}`\n const keyB = `${b.entry.node.id}::${b.entry.depth}`\n return keyA.localeCompare(keyB, 'en')\n })\n\n // Apply all mutations serially in deterministic order\n const levelResults: ProcessPlacementResult[] = []\n for (const { entry, result } of sortedResults) {\n // Apply accumulated fork requests if any (from Phase A deferred forks)\n if (result.forkRequests.length > 0) {\n const forkedContext = forkPeerContext(\n graph,\n entry.peerContext,\n result.forkRequests,\n )\n entry.peerContext = forkedContext\n // Update peer context in all placement tasks to use forked context\n for (const task of result.placementTasks) {\n task.fetchTask.peerContext = forkedContext\n }\n }\n\n // Apply reuse edges in deterministic order (before placement)\n // Sort reuse tasks by spec name for stability\n const sortedReuseTasks = result.reuseTasks.sort((a, b) =>\n a.spec.name.localeCompare(b.spec.name, 'en'),\n )\n for (const {\n type,\n spec,\n fromNode,\n toNode,\n } of sortedReuseTasks) {\n graph.addEdge(type, spec, fromNode, toNode)\n }\n\n // Place nodes and collect child deps\n const placed = await processPlacementTasks(\n graph,\n options,\n result.placementTasks,\n add,\n modifiers,\n scurry,\n packageInfo,\n extractPromises,\n actual,\n seenExtracted,\n remover,\n transientAdd,\n transientRemove,\n )\n\n levelResults.push(placed)\n }\n\n // ============================================================\n // PHASE C: POST-PLACEMENT PEER CHECK\n // ============================================================\n // After all nodes at this level are placed, update peer contexts,\n // fork as needed, and resolve peer deps that can be satisfied.\n // This must happen AFTER placement so sibling nodes are available.\n postPlacementPeerCheck(graph, levelResults)\n\n // ============================================================\n // STEP 3: COLLECT CHILD DEPS FOR NEXT LEVEL\n // ============================================================\n for (const childDepsToProcess of levelResults) {\n for (const childDep of childDepsToProcess) {\n // Skip already-seen nodes (cycle prevention)\n if (!seen.has(childDep.node.id)) {\n /* c8 ignore next */\n const currentDepth = currentLevelDeps[0]?.depth ?? 0\n nextLevelDeps.push({\n ...childDep,\n depth: currentDepth + 1,\n })\n }\n }\n }\n\n // Advance to next BFS level\n currentLevelDeps = nextLevelDeps\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/ideal/build.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,KAAK,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,KAAK,EACV,2BAA2B,EAC3B,8BAA8B,EAE/B,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAGxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAK7D,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG;IAClD;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAA;IACd;;;;;OAKG;IACH,GAAG,CAAC,EAAE,2BAA2B,CAAA;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,8BAA8B,CAAA;IACvC;;OAEG;IACH,OAAO,EAAE,cAAc,CAAA;IACvB;;OAEG;IACH,WAAW,EAAE,iBAAiB,CAAA;CAC/B,CAAA;AAmBD;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,YACP,iBAAiB,KACzB,OAAO,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/ideal/build.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,KAAK,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACzE,OAAO,KAAK,EACV,2BAA2B,EAC3B,8BAA8B,EAE/B,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAGxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAK7D,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG;IAClD;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAA;IACd;;;;;OAKG;IACH,GAAG,CAAC,EAAE,2BAA2B,CAAA;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,8BAA8B,CAAA;IACvC;;OAEG;IACH,OAAO,EAAE,cAAc,CAAA;IACvB;;OAEG;IACH,WAAW,EAAE,iBAAiB,CAAA;CAC/B,CAAA;AAmBD;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,YACP,iBAAiB,KACzB,OAAO,CAAC,KAAK,CAgEf,CAAA"}
|
package/dist/ideal/build.js
CHANGED
|
@@ -39,7 +39,17 @@ export const build = async (options) => {
|
|
|
39
39
|
monorepo,
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
-
catch {
|
|
42
|
+
catch (err) {
|
|
43
|
+
// Check if this is a lockfile version mismatch
|
|
44
|
+
const cause = err.cause;
|
|
45
|
+
if (cause?.code === 'ELOCKFILEVERSION') {
|
|
46
|
+
// If lockfile is from a different vlt version, hard fail
|
|
47
|
+
if (typeof cause.found === 'number' &&
|
|
48
|
+
typeof cause.wanted === 'number') {
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
// TODO: add warning to CLI layer via @vltpkg/output when available
|
|
52
|
+
}
|
|
43
53
|
graph = loadActual({
|
|
44
54
|
...options,
|
|
45
55
|
mainManifest,
|
package/dist/ideal/build.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/ideal/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAA;AASlF,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAI3C,MAAM,MAAM,GAAG,CAA0B,CAAK,EAAE,EAAE,CAChD,CAAC,IAAK,IAAI,GAAG,EAAQ,CAAA;AA8BvB;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,CAAC,KAAY,EAAE,EAAS,EAAE,EAAE;IACtD,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC,CAAA;IACnC,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5C,MAAM,KAAK,CACT,6DAA6D,EAC7D,EAAE,IAAI,EAAE,CACT,CAAA;IACH,CAAC;AACH,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,EACxB,OAA0B,EACV,EAAE;IAClB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;IAE/B,yDAAyD;IACzD,iDAAiD;IACjD,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAA;IAC9D,MAAM,YAAY,GAChB,OAAO,CAAC,YAAY,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IAC/D,IAAI,KAAK,CAAA;IACT,IAAI,CAAC;QACH,KAAK,GAAG,WAAW,CAAC;YAClB,GAAG,OAAO;YACV,YAAY;YACZ,QAAQ;SACT,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,UAAU,CAAC;YACjB,GAAG,OAAO;YACV,YAAY;YACZ,QAAQ;SACT,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,2BAA2B,CAAC;QAC5C,GAAG,OAAO;QACV,MAAM;QACN,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;QACxB,KAAK;QACL,WAAW;QACX,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;QAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAA;IACF,IAAI,EAAE,CAAA;IAEN,4DAA4D;IAC5D,sDAAsD;IACtD,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;YACpD,IAAI,KAAK,CAAC,IAAI;gBAAE,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QAClD,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1D,IAAI,KAAK,CAAC,IAAI;gBAAE,mBAAmB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QACrD,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { graphStep } from '@vltpkg/output'\nimport { load as loadActual } from '../actual/load.ts'\nimport { load as loadVirtual } from '../lockfile/load.ts'\nimport { buildIdealFromStartingGraph } from './build-ideal-from-starting-graph.ts'\nimport type { PackageInfoClient } from '@vltpkg/package-info'\nimport type { LoadOptions as LoadActualOptions } from '../actual/load.ts'\nimport type {\n AddImportersDependenciesMap,\n RemoveImportersDependenciesMap,\n Dependency,\n} from '../dependencies.ts'\nimport type { Graph } from '../graph.ts'\nimport { splitDepID } from '@vltpkg/dep-id'\nimport type { DepID } from '@vltpkg/dep-id'\nimport type { RollbackRemove } from '@vltpkg/rollback-remove'\n\nconst getMap = <T extends Map<any, any>>(m?: T) =>\n m ?? (new Map() as T)\n\nexport type BuildIdealOptions = LoadActualOptions & {\n /**\n * An actual graph\n */\n actual?: Graph\n /**\n * A `Map` in which keys are {@link DepID} linking to another `Map` in which\n * keys are the dependency names and values are {@link Dependency}. This\n * structure represents dependencies that need to be added to the importer\n * represented by {@link DepID}.\n */\n add?: AddImportersDependenciesMap\n /**\n * A `Map` object representing nodes to be removed from the ideal graph.\n * Each {@link DepID} key represents an importer node and the `Set` of\n * dependency names to be removed from its dependency list.\n */\n remove?: RemoveImportersDependenciesMap\n /**\n * A {@link RollbackRemove} instance to handle extraction rollbacks\n */\n remover: RollbackRemove\n /**\n * A {@link PackageInfoClient} instance to read manifest info from.\n */\n packageInfo: PackageInfoClient\n}\n\n/**\n * Validates that a file dependency node exists in the graph after\n * a successful graph build. This helps providing an actionable error\n * message in case the current working directory is a linked nested\n * folder that hasn't yet been added as a dependency to an importer\n * in the project.\n */\nconst validateFileDepNode = (graph: Graph, id: DepID) => {\n const [type, path] = splitDepID(id)\n if (type === 'file' && !graph.nodes.get(id)) {\n throw error(\n 'The current working dir is not a dependency of this project',\n { path },\n )\n }\n}\n\n/**\n * Builds an ideal {@link Graph} representing the dependencies that\n * should be present in order to fulfill the requirements defined\n * by the `package.json` and `vlt-lock.json` files using either the\n * virtual or actual graph as a starting point. Also add / remove any\n * dependencies listed in the `add` and `remove` properties.\n */\nexport const build = async (\n options: BuildIdealOptions,\n): Promise<Graph> => {\n const done = graphStep('build')\n\n // Creates the shared instances that are going to be used\n // in both the loader methods and the build graph\n const { packageInfo, packageJson, scurry, monorepo } = options\n const mainManifest =\n options.mainManifest ?? packageJson.read(options.projectRoot)\n let graph\n try {\n graph = loadVirtual({\n ...options,\n mainManifest,\n monorepo,\n })\n } catch {\n graph = loadActual({\n ...options,\n mainManifest,\n monorepo,\n })\n }\n\n const res = await buildIdealFromStartingGraph({\n ...options,\n scurry,\n add: getMap(options.add),\n graph,\n packageInfo,\n remove: getMap(options.remove),\n actual: options.actual,\n })\n done()\n\n // when adding or removing a new dependency from a file dep,\n // validate the receiver node was present in the graph\n if (options.add) {\n for (const [addKey, value] of options.add.entries()) {\n if (value.size) validateFileDepNode(res, addKey)\n }\n }\n if (options.remove) {\n for (const [removeKey, value] of options.remove.entries()) {\n if (value.size) validateFileDepNode(res, removeKey)\n }\n }\n\n return res\n}\n"]}
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/ideal/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport { graphStep } from '@vltpkg/output'\nimport { load as loadActual } from '../actual/load.ts'\nimport { load as loadVirtual } from '../lockfile/load.ts'\nimport { buildIdealFromStartingGraph } from './build-ideal-from-starting-graph.ts'\nimport type { PackageInfoClient } from '@vltpkg/package-info'\nimport type { LoadOptions as LoadActualOptions } from '../actual/load.ts'\nimport type {\n AddImportersDependenciesMap,\n RemoveImportersDependenciesMap,\n Dependency,\n} from '../dependencies.ts'\nimport type { Graph } from '../graph.ts'\nimport { splitDepID } from '@vltpkg/dep-id'\nimport type { DepID } from '@vltpkg/dep-id'\nimport type { RollbackRemove } from '@vltpkg/rollback-remove'\n\nconst getMap = <T extends Map<any, any>>(m?: T) =>\n m ?? (new Map() as T)\n\nexport type BuildIdealOptions = LoadActualOptions & {\n /**\n * An actual graph\n */\n actual?: Graph\n /**\n * A `Map` in which keys are {@link DepID} linking to another `Map` in which\n * keys are the dependency names and values are {@link Dependency}. This\n * structure represents dependencies that need to be added to the importer\n * represented by {@link DepID}.\n */\n add?: AddImportersDependenciesMap\n /**\n * A `Map` object representing nodes to be removed from the ideal graph.\n * Each {@link DepID} key represents an importer node and the `Set` of\n * dependency names to be removed from its dependency list.\n */\n remove?: RemoveImportersDependenciesMap\n /**\n * A {@link RollbackRemove} instance to handle extraction rollbacks\n */\n remover: RollbackRemove\n /**\n * A {@link PackageInfoClient} instance to read manifest info from.\n */\n packageInfo: PackageInfoClient\n}\n\n/**\n * Validates that a file dependency node exists in the graph after\n * a successful graph build. This helps providing an actionable error\n * message in case the current working directory is a linked nested\n * folder that hasn't yet been added as a dependency to an importer\n * in the project.\n */\nconst validateFileDepNode = (graph: Graph, id: DepID) => {\n const [type, path] = splitDepID(id)\n if (type === 'file' && !graph.nodes.get(id)) {\n throw error(\n 'The current working dir is not a dependency of this project',\n { path },\n )\n }\n}\n\n/**\n * Builds an ideal {@link Graph} representing the dependencies that\n * should be present in order to fulfill the requirements defined\n * by the `package.json` and `vlt-lock.json` files using either the\n * virtual or actual graph as a starting point. Also add / remove any\n * dependencies listed in the `add` and `remove` properties.\n */\nexport const build = async (\n options: BuildIdealOptions,\n): Promise<Graph> => {\n const done = graphStep('build')\n\n // Creates the shared instances that are going to be used\n // in both the loader methods and the build graph\n const { packageInfo, packageJson, scurry, monorepo } = options\n const mainManifest =\n options.mainManifest ?? packageJson.read(options.projectRoot)\n let graph\n try {\n graph = loadVirtual({\n ...options,\n mainManifest,\n monorepo,\n })\n } catch (err) {\n // Check if this is a lockfile version mismatch\n const cause = (\n err as Error & {\n cause?: { code?: string; found?: number; wanted?: number }\n }\n ).cause\n if (cause?.code === 'ELOCKFILEVERSION') {\n // If lockfile is from a different vlt version, hard fail\n if (\n typeof cause.found === 'number' &&\n typeof cause.wanted === 'number'\n ) {\n throw err\n }\n // TODO: add warning to CLI layer via @vltpkg/output when available\n }\n graph = loadActual({\n ...options,\n mainManifest,\n monorepo,\n })\n }\n\n const res = await buildIdealFromStartingGraph({\n ...options,\n scurry,\n add: getMap(options.add),\n graph,\n packageInfo,\n remove: getMap(options.remove),\n actual: options.actual,\n })\n done()\n\n // when adding or removing a new dependency from a file dep,\n // validate the receiver node was present in the graph\n if (options.add) {\n for (const [addKey, value] of options.add.entries()) {\n if (value.size) validateFileDepNode(res, addKey)\n }\n }\n if (options.remove) {\n for (const [removeKey, value] of options.remove.entries()) {\n if (value.size) validateFileDepNode(res, removeKey)\n }\n }\n\n return res\n}\n"]}
|