@vltpkg/graph 1.3.7 → 1.4.0
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.js +4 -0
- package/dist/graph.d.ts +11 -3
- package/dist/graph.js +33 -3
- package/dist/ideal/append-nodes.js +8 -0
- package/dist/ideal/build-ideal-from-starting-graph.js +9 -0
- package/dist/ideal/get-importer-specs.d.ts +1 -0
- package/dist/ideal/get-importer-specs.js +10 -0
- package/dist/ideal/refresh-ideal-graph.js +6 -1
- package/dist/install.js +22 -0
- package/dist/lockfile/load-edges.js +0 -2
- package/dist/modifiers.d.ts +7 -0
- package/dist/modifiers.js +24 -0
- package/dist/reify/index.js +8 -3
- package/dist/uninstall.js +10 -0
- package/dist/update.js +41 -1
- package/package.json +21 -21
package/dist/actual/load.js
CHANGED
|
@@ -246,6 +246,10 @@ const parseDir = (options, scurry, packageJson, depsFound, graph, fromNode, curr
|
|
|
246
246
|
});
|
|
247
247
|
// Check for active modifiers and replace spec for missing dependencies
|
|
248
248
|
const { spec: modifiedSpec, queryModifier } = maybeApplyModifierToSpec(spec, name, modifierRefs);
|
|
249
|
+
// a `-` modifier removes the dependency, so it is not missing
|
|
250
|
+
if (modifiedSpec !== spec && modifiedSpec.bareSpec === '-') {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
249
253
|
spec = modifiedSpec;
|
|
250
254
|
graph.placePackage(fromNode, depType, spec, undefined, undefined, joinExtra({ modifier: queryModifier }));
|
|
251
255
|
}
|
package/dist/graph.d.ts
CHANGED
|
@@ -100,9 +100,10 @@ export declare class Graph implements GraphLike {
|
|
|
100
100
|
/**
|
|
101
101
|
* Whether the lockfile on disk no longer matches this graph even
|
|
102
102
|
* though no node changed, e.g. an importer edge spec was rewritten to
|
|
103
|
-
* the value saved to `package.json`,
|
|
104
|
-
*
|
|
105
|
-
*
|
|
103
|
+
* the value saved to `package.json`, a node dev/optional flag was
|
|
104
|
+
* re-derived, or the config options the graph was built with differ
|
|
105
|
+
* from the ones stored in the lockfile. Reify saves the lockfiles
|
|
106
|
+
* from its no-diff early return when set.
|
|
106
107
|
*/
|
|
107
108
|
lockfileStale: boolean;
|
|
108
109
|
/**
|
|
@@ -126,6 +127,13 @@ export declare class Graph implements GraphLike {
|
|
|
126
127
|
* Get the next peer context index.
|
|
127
128
|
*/
|
|
128
129
|
nextPeerContextIndex(): number;
|
|
130
|
+
/**
|
|
131
|
+
* Re-derive node `dev`/`optional` flags: a node is dev/optional only
|
|
132
|
+
* when every importer path crosses a dev/optional edge. Placement only
|
|
133
|
+
* ever lowers these flags, so removed or retyped edges leave them
|
|
134
|
+
* stale. Sets `lockfileStale` when any flag changes.
|
|
135
|
+
*/
|
|
136
|
+
recomputeFlags(): void;
|
|
129
137
|
/**
|
|
130
138
|
* Delete all nodes and edges that are unreachable from the importers.
|
|
131
139
|
* The collection of deleted nodes is returned.
|
package/dist/graph.js
CHANGED
|
@@ -110,9 +110,10 @@ export class Graph {
|
|
|
110
110
|
/**
|
|
111
111
|
* Whether the lockfile on disk no longer matches this graph even
|
|
112
112
|
* though no node changed, e.g. an importer edge spec was rewritten to
|
|
113
|
-
* the value saved to `package.json`,
|
|
114
|
-
*
|
|
115
|
-
*
|
|
113
|
+
* the value saved to `package.json`, a node dev/optional flag was
|
|
114
|
+
* re-derived, or the config options the graph was built with differ
|
|
115
|
+
* from the ones stored in the lockfile. Reify saves the lockfiles
|
|
116
|
+
* from its no-diff early return when set.
|
|
116
117
|
*/
|
|
117
118
|
lockfileStale = false;
|
|
118
119
|
/**
|
|
@@ -195,6 +196,35 @@ export class Graph {
|
|
|
195
196
|
nextPeerContextIndex() {
|
|
196
197
|
return ++this.currentPeerContextIndex;
|
|
197
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Re-derive node `dev`/`optional` flags: a node is dev/optional only
|
|
201
|
+
* when every importer path crosses a dev/optional edge. Placement only
|
|
202
|
+
* ever lowers these flags, so removed or retyped edges leave them
|
|
203
|
+
* stale. Sets `lockfileStale` when any flag changes.
|
|
204
|
+
*/
|
|
205
|
+
recomputeFlags() {
|
|
206
|
+
const reach = (skip) => {
|
|
207
|
+
const seen = new Set(this.importers);
|
|
208
|
+
for (const node of seen) {
|
|
209
|
+
for (const edge of node.edgesOut.values()) {
|
|
210
|
+
if (edge.to && !skip(edge))
|
|
211
|
+
seen.add(edge.to);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return seen;
|
|
215
|
+
};
|
|
216
|
+
const nonDev = reach(edge => edge.dev);
|
|
217
|
+
const nonOptional = reach(edge => edge.optional);
|
|
218
|
+
for (const node of this.nodes.values()) {
|
|
219
|
+
const dev = !nonDev.has(node);
|
|
220
|
+
const optional = !nonOptional.has(node);
|
|
221
|
+
if (node.dev !== dev || node.optional !== optional) {
|
|
222
|
+
node.dev = dev;
|
|
223
|
+
node.optional = optional;
|
|
224
|
+
this.lockfileStale = true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
198
228
|
/**
|
|
199
229
|
* Delete all nodes and edges that are unreachable from the importers.
|
|
200
230
|
* The collection of deleted nodes is returned.
|
|
@@ -228,6 +228,10 @@ const fetchManifestsForDeps = async (packageInfo, graph, fromNode, deps, scurry,
|
|
|
228
228
|
spec = activeModifier.modifier.spec;
|
|
229
229
|
// bareSpec of '-' means "remove this dependency"
|
|
230
230
|
if (spec.bareSpec === '-') {
|
|
231
|
+
// nothing to install or save for an explicit request
|
|
232
|
+
if (isExplicit) {
|
|
233
|
+
throw error(`Cannot add ${originalSpec.name}: it is removed by a graph modifier`, { code: 'ECONFIG', found: queryModifier });
|
|
234
|
+
}
|
|
231
235
|
continue;
|
|
232
236
|
}
|
|
233
237
|
}
|
|
@@ -366,6 +370,8 @@ const fetchManifestsForDeps = async (packageInfo, graph, fromNode, deps, scurry,
|
|
|
366
370
|
}
|
|
367
371
|
throw er;
|
|
368
372
|
});
|
|
373
|
+
// awaited below; a throw before that must not leave it unhandled
|
|
374
|
+
manifestPromise.catch(() => { });
|
|
369
375
|
const fetchTask = {
|
|
370
376
|
spec,
|
|
371
377
|
type,
|
|
@@ -380,6 +386,8 @@ const fetchManifestsForDeps = async (packageInfo, graph, fromNode, deps, scurry,
|
|
|
380
386
|
};
|
|
381
387
|
fetchTasks.push(fetchTask);
|
|
382
388
|
}
|
|
389
|
+
// fail on the first rejection, not once the ones before it settle
|
|
390
|
+
await Promise.all(fetchTasks.map(t => t.manifestPromise));
|
|
383
391
|
// Create placement tasks from fetch tasks
|
|
384
392
|
for (const fetchTask of fetchTasks) {
|
|
385
393
|
const manifest = await fetchTask.manifestPromise;
|
|
@@ -79,6 +79,14 @@ export const buildIdealFromStartingGraph = async (options) => {
|
|
|
79
79
|
if (importerSpecs.staleSpecs.size) {
|
|
80
80
|
options.graph.lockfileStale = true;
|
|
81
81
|
}
|
|
82
|
+
// importer edges a `-` modifier now removes: drop them, gc() takes
|
|
83
|
+
// whatever only they reached
|
|
84
|
+
for (const edge of importerSpecs.removedEdges) {
|
|
85
|
+
edge.from.edgesOut.delete(edge.name);
|
|
86
|
+
edge.to?.edgesIn.delete(edge);
|
|
87
|
+
options.graph.edges.delete(edge);
|
|
88
|
+
options.graph.lockfileStale = true;
|
|
89
|
+
}
|
|
82
90
|
// refreshs the current graph adding the nodes marked for addition
|
|
83
91
|
// and removing the ones marked for removal, while also recalculating
|
|
84
92
|
// peer dependencies and default locations
|
|
@@ -93,5 +101,6 @@ export const buildIdealFromStartingGraph = async (options) => {
|
|
|
93
101
|
hasProvisionalPeerIds(options.graph)) {
|
|
94
102
|
await movePeerStoreDirs(canonicalizePeerIds(options.graph), options);
|
|
95
103
|
}
|
|
104
|
+
options.graph.recomputeFlags();
|
|
96
105
|
return options.graph;
|
|
97
106
|
};
|
|
@@ -18,6 +18,7 @@ export type GetImporterSpecsOptions = BuildIdealAddOptions & BuildIdealFromGraph
|
|
|
18
18
|
export declare const getImporterSpecs: (options: GetImporterSpecsOptions) => {
|
|
19
19
|
add: AddImportersDependenciesMap;
|
|
20
20
|
remove: RemoveImportersDependenciesMap;
|
|
21
|
+
removedEdges: Set<Edge>;
|
|
21
22
|
staleSpecs: Map<Edge, Dependency>;
|
|
22
23
|
transientAdd: TransientAddMap;
|
|
23
24
|
transientRemove: TransientRemoveMap;
|
|
@@ -25,6 +25,8 @@ export const getImporterSpecs = (options) => {
|
|
|
25
25
|
const { add, graph, remove } = options;
|
|
26
26
|
const addResult = new AddImportersDependenciesMapImpl();
|
|
27
27
|
const removeResult = new RemoveImportersDependenciesMapImpl();
|
|
28
|
+
// importer edges a `-` modifier now removes, package.json keeps them
|
|
29
|
+
const removedEdges = new Set();
|
|
28
30
|
// traverse the list of importers in the starting graph
|
|
29
31
|
for (const importer of graph.importers) {
|
|
30
32
|
// uses a Map keying to the spec.name in order to easily make sure there's
|
|
@@ -71,6 +73,13 @@ export const getImporterSpecs = (options) => {
|
|
|
71
73
|
continue;
|
|
72
74
|
}
|
|
73
75
|
const spec = Spec.parse(depName, depSpec, options);
|
|
76
|
+
// a `-` modifier removes this dependency, nothing to place; an
|
|
77
|
+
// edge from before (e.g. a qualifier now matching) has to go
|
|
78
|
+
if (options.modifiers?.removesImporterEdge(importer, spec)) {
|
|
79
|
+
if (edge)
|
|
80
|
+
removedEdges.add(edge);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
74
83
|
// if a workspace dep references a workspace that no longer exists
|
|
75
84
|
// (folder was removed), mark it for removal instead of trying to
|
|
76
85
|
// resolve it — the workspace can't be satisfied
|
|
@@ -212,6 +221,7 @@ export const getImporterSpecs = (options) => {
|
|
|
212
221
|
return {
|
|
213
222
|
add: addResult,
|
|
214
223
|
remove: removeResult,
|
|
224
|
+
removedEdges,
|
|
215
225
|
staleSpecs,
|
|
216
226
|
transientAdd,
|
|
217
227
|
transientRemove,
|
|
@@ -99,7 +99,12 @@ export const refreshIdealGraph = async ({ add, graph, modifiers, packageInfo, sc
|
|
|
99
99
|
const modifierRefs = modifiers?.tryDependencies(importer, deps);
|
|
100
100
|
// Add new nodes for packages defined in the dependencies list fetching
|
|
101
101
|
// metadata from the registry manifests and updating the graph
|
|
102
|
-
await appendNodes(packageInfo, graph, importer, deps, scurry, specOptions, seen, addedDeps, modifiers, modifierRefs, extractPromises, actual, seenExtracted, remover, transientAdd, transientRemove, explicit)
|
|
102
|
+
await appendNodes(packageInfo, graph, importer, deps, scurry, specOptions, seen, addedDeps, modifiers, modifierRefs, extractPromises, actual, seenExtracted, remover, transientAdd, transientRemove, explicit).catch((er) => {
|
|
103
|
+
// extractions still in flight are moot now
|
|
104
|
+
for (const p of extractPromises ?? [])
|
|
105
|
+
p.catch(() => { });
|
|
106
|
+
throw er;
|
|
107
|
+
});
|
|
103
108
|
}
|
|
104
109
|
// locked resolutions only apply to the rebuild that captured them
|
|
105
110
|
graph.lockedResolutions = undefined;
|
package/dist/install.js
CHANGED
|
@@ -7,6 +7,7 @@ import { error } from '@vltpkg/error-cause';
|
|
|
7
7
|
import { asError } from '@vltpkg/types';
|
|
8
8
|
import { getDependencies } from "./dependencies.js";
|
|
9
9
|
import { RollbackRemove } from '@vltpkg/rollback-remove';
|
|
10
|
+
import { joinDepIDTuple } from '@vltpkg/dep-id';
|
|
10
11
|
import { existsSync, rmSync } from 'node:fs';
|
|
11
12
|
import { resolve } from 'node:path';
|
|
12
13
|
import { load as loadVirtual, loadData } from "./lockfile/load.js";
|
|
@@ -109,6 +110,7 @@ export const install = async (options, add) => {
|
|
|
109
110
|
}
|
|
110
111
|
if (importerSpecs.add.modifiedDependencies ||
|
|
111
112
|
importerSpecs.remove.modifiedDependencies ||
|
|
113
|
+
importerSpecs.removedEdges.size > 0 ||
|
|
112
114
|
specChanges.length > 0 ||
|
|
113
115
|
lockfileGraph.optionsChanged) {
|
|
114
116
|
const details = [];
|
|
@@ -141,6 +143,9 @@ export const install = async (options, add) => {
|
|
|
141
143
|
details.push(` ${location}: ${deps.size} ${depLabelRemove} to remove (${depNames.join(', ')})`);
|
|
142
144
|
}
|
|
143
145
|
}
|
|
146
|
+
for (const edge of importerSpecs.removedEdges) {
|
|
147
|
+
details.push(` ${edge.from.location}: ${edge.name} is removed by a graph modifier`);
|
|
148
|
+
}
|
|
144
149
|
const lockfilePath = resolve(options.projectRoot, 'vlt-lock.json');
|
|
145
150
|
throw error('Lockfile is out of sync with package.json. Run "vlt install" to update.\n' +
|
|
146
151
|
details.join('\n'), {
|
|
@@ -148,6 +153,23 @@ export const install = async (options, add) => {
|
|
|
148
153
|
});
|
|
149
154
|
}
|
|
150
155
|
}
|
|
156
|
+
// an explicit add of a dep a `-` modifier removes fails before
|
|
157
|
+
// anything on disk is touched
|
|
158
|
+
if (modifiers && add?.modifiedDependencies) {
|
|
159
|
+
const wsIds = new Set([...(fullMonorepo?.values() ?? [])].map(ws => ws.id));
|
|
160
|
+
for (const [id, deps] of add) {
|
|
161
|
+
const mainImporter = id === joinDepIDTuple(['file', '.']);
|
|
162
|
+
// nested folders are no importers, appendNodes checks those
|
|
163
|
+
if (!mainImporter && !wsIds.has(id))
|
|
164
|
+
continue;
|
|
165
|
+
for (const { spec } of deps.values()) {
|
|
166
|
+
const found = modifiers.removesImporterEdge({ importer: true, mainImporter }, spec);
|
|
167
|
+
if (found) {
|
|
168
|
+
throw error(`Cannot add ${spec.name}: it is removed by a graph modifier`, { code: 'ECONFIG', found });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
151
173
|
const remover = new RollbackRemove();
|
|
152
174
|
if (options.cleanInstall) {
|
|
153
175
|
const nodeModulesPath = resolve(options.projectRoot, 'node_modules');
|
|
@@ -52,11 +52,9 @@ export const loadEdges = (graph, edges, options, cache) => {
|
|
|
52
52
|
const [depType, valRest] = fastSplit(value, ' ', 2);
|
|
53
53
|
const vrSplit = valRest?.lastIndexOf(' ') ?? -1;
|
|
54
54
|
// not a valid edge record
|
|
55
|
-
/* c8 ignore start */
|
|
56
55
|
if (!valRest || !depType || !fromId || !specName || vrSplit < 1) {
|
|
57
56
|
continue;
|
|
58
57
|
}
|
|
59
|
-
/* c8 ignore stop */
|
|
60
58
|
// Validate dependency type early
|
|
61
59
|
if (!isDependencyTypeShort(depType)) {
|
|
62
60
|
throw error('Found unsupported dependency type in lockfile', {
|
package/dist/modifiers.d.ts
CHANGED
|
@@ -126,6 +126,13 @@ export declare class GraphModifier {
|
|
|
126
126
|
* root's own b edge is still the manifest's to validate and heal.
|
|
127
127
|
*/
|
|
128
128
|
targetsImporterEdge(importer: Node, spec: Spec): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Selector of the modifier that wins the direct `importer -> spec.name`
|
|
131
|
+
* edge, if it removes it (value `-`). Same pick as tryNewDependency:
|
|
132
|
+
* complete entries whose qualifier accepts the spec, highest
|
|
133
|
+
* specificity, importer-anchored before lone on ties.
|
|
134
|
+
*/
|
|
135
|
+
removesImporterEdge(importer: Pick<Node, 'importer' | 'mainImporter'>, spec: Spec): string | undefined;
|
|
129
136
|
/**
|
|
130
137
|
* Loads the modifiers defined in `vlt.json` into memory.
|
|
131
138
|
*/
|
package/dist/modifiers.js
CHANGED
|
@@ -115,6 +115,30 @@ export class GraphModifier {
|
|
|
115
115
|
}
|
|
116
116
|
return false;
|
|
117
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Selector of the modifier that wins the direct `importer -> spec.name`
|
|
120
|
+
* edge, if it removes it (value `-`). Same pick as tryNewDependency:
|
|
121
|
+
* complete entries whose qualifier accepts the spec, highest
|
|
122
|
+
* specificity, importer-anchored before lone on ties.
|
|
123
|
+
*/
|
|
124
|
+
removesImporterEdge(importer, spec) {
|
|
125
|
+
const anchored = [];
|
|
126
|
+
const lone = [];
|
|
127
|
+
for (const mod of this.#modifiers) {
|
|
128
|
+
const { last } = mod.breadcrumb;
|
|
129
|
+
if (last.name !== spec.name || !matchesQualifier(last, spec))
|
|
130
|
+
continue;
|
|
131
|
+
const { prev } = last;
|
|
132
|
+
if (!prev)
|
|
133
|
+
lone.push(mod);
|
|
134
|
+
else if (!prev.prev && matchesImporter(prev, importer))
|
|
135
|
+
anchored.push(mod);
|
|
136
|
+
}
|
|
137
|
+
const all = [...anchored, ...lone];
|
|
138
|
+
const [winner] = specificitySort(all.map(m => m.breadcrumb));
|
|
139
|
+
const mod = all.find(m => m.breadcrumb === winner);
|
|
140
|
+
return mod?.value === '-' ? mod.query : undefined;
|
|
141
|
+
}
|
|
118
142
|
/**
|
|
119
143
|
* Loads the modifiers defined in `vlt.json` into memory.
|
|
120
144
|
*/
|
package/dist/reify/index.js
CHANGED
|
@@ -89,15 +89,20 @@ export const reify = async (options) => {
|
|
|
89
89
|
// Otherwise a first install of an optional-only tree would never extract.
|
|
90
90
|
const hasLockfiles = !!scurry.lstatSync('vlt-lock.json') &&
|
|
91
91
|
!!scurry.lstatSync('node_modules/.vlt-lock.json');
|
|
92
|
-
|
|
92
|
+
// a removal is never optional-only: deleting is what reify is for
|
|
93
|
+
const skipOptionalOnly = noModifiedDependencies &&
|
|
94
|
+
diff.optionalOnly &&
|
|
95
|
+
!diff.nodes.delete.size &&
|
|
96
|
+
!diff.edges.delete.size;
|
|
93
97
|
const skippable = skipOptionalOnly && !options.update && hasLockfiles;
|
|
94
98
|
const res = { diff };
|
|
95
99
|
if (!diff.hasChanges() || skippable) {
|
|
96
100
|
// Even when there are no changes to reify, ensure lockfiles
|
|
97
101
|
// exist on disk. This handles the case where a project has no
|
|
98
102
|
// dependencies (or only workspace importers) but still needs
|
|
99
|
-
// lockfiles written on the first install. A stale flag means
|
|
100
|
-
//
|
|
103
|
+
// lockfiles written on the first install. A stale flag means
|
|
104
|
+
// lockfile data changed w/o a node diff (edge spec/type, options,
|
|
105
|
+
// dev/optional flags), which the lockfiles have to carry.
|
|
101
106
|
if (!hasLockfiles || graph.lockfileStale) {
|
|
102
107
|
// with no diff at all the ideal graph is the actual graph, so the
|
|
103
108
|
// hidden lockfile can be written from it; an optional-only diff
|
package/dist/uninstall.js
CHANGED
|
@@ -5,12 +5,18 @@ import { reify } from "./reify/index.js";
|
|
|
5
5
|
import { lockfile } from "./index.js";
|
|
6
6
|
import { updatePackageJson } from "./reify/update-importers-package-json.js";
|
|
7
7
|
import { RollbackRemove } from '@vltpkg/rollback-remove';
|
|
8
|
+
import { Monorepo } from '@vltpkg/workspaces';
|
|
8
9
|
import { existsSync, rmSync } from 'node:fs';
|
|
9
10
|
import { resolve } from 'node:path';
|
|
10
11
|
export const uninstall = async (options, remove) => {
|
|
11
12
|
const mainManifest = options.packageJson.read(options.projectRoot);
|
|
12
13
|
const modifiers = GraphModifier.maybeLoad(options);
|
|
13
14
|
const remover = new RollbackRemove();
|
|
15
|
+
// graph spans every workspace; -w only picks the `remove` targets
|
|
16
|
+
const monorepo = Monorepo.maybeLoad(options.projectRoot, {
|
|
17
|
+
packageJson: options.packageJson,
|
|
18
|
+
scurry: options.scurry,
|
|
19
|
+
});
|
|
14
20
|
try {
|
|
15
21
|
// Load the actual graph before building the ideal graph so that
|
|
16
22
|
// manifest data from installed packages can be used to hydrate
|
|
@@ -20,16 +26,19 @@ export const uninstall = async (options, remove) => {
|
|
|
20
26
|
// due to throwOnMissingManifest and leaving stale entries behind.
|
|
21
27
|
const act = actualLoad({
|
|
22
28
|
...options,
|
|
29
|
+
monorepo,
|
|
23
30
|
modifiers: undefined,
|
|
24
31
|
mainManifest,
|
|
25
32
|
loadManifests: true,
|
|
26
33
|
});
|
|
27
34
|
const graph = await idealBuild({
|
|
28
35
|
...options,
|
|
36
|
+
monorepo,
|
|
29
37
|
actual: act,
|
|
30
38
|
remove,
|
|
31
39
|
mainManifest,
|
|
32
40
|
loadManifests: true,
|
|
41
|
+
modifiers,
|
|
33
42
|
remover,
|
|
34
43
|
});
|
|
35
44
|
// If lockfileOnly is enabled, skip reify and only save the lockfile
|
|
@@ -59,6 +68,7 @@ export const uninstall = async (options, remove) => {
|
|
|
59
68
|
actual: act,
|
|
60
69
|
graph,
|
|
61
70
|
loadManifests: true,
|
|
71
|
+
modifiers,
|
|
62
72
|
remover,
|
|
63
73
|
});
|
|
64
74
|
return { graph, diff };
|
package/dist/update.js
CHANGED
|
@@ -5,10 +5,45 @@ import { GraphModifier } from "./modifiers.js";
|
|
|
5
5
|
import { init } from '@vltpkg/init';
|
|
6
6
|
import { asError } from '@vltpkg/types';
|
|
7
7
|
import { Graph } from "./graph.js";
|
|
8
|
+
import { load as loadVirtual } from "./lockfile/load.js";
|
|
9
|
+
import { isPathSecurityError } from "./path-security-error.js";
|
|
8
10
|
import { graphStep } from '@vltpkg/output';
|
|
9
11
|
import { RollbackRemove } from '@vltpkg/rollback-remove';
|
|
12
|
+
import { Monorepo } from '@vltpkg/workspaces';
|
|
10
13
|
import { existsSync, rmSync } from 'node:fs';
|
|
11
14
|
import { resolve } from 'node:path';
|
|
15
|
+
/**
|
|
16
|
+
* Graph to update from. `-w` filtered: the lockfile (else installed)
|
|
17
|
+
* graph minus the selected workspaces' deps, so only those re-resolve
|
|
18
|
+
* (deps shared with other workspaces stay locked). Else: empty.
|
|
19
|
+
*/
|
|
20
|
+
const startingGraph = (options, monorepo) => {
|
|
21
|
+
const fresh = () => new Graph({ ...options, monorepo });
|
|
22
|
+
if (!options.monorepo || !monorepo)
|
|
23
|
+
return fresh();
|
|
24
|
+
const selected = new Set([...options.monorepo.values()].map(ws => ws.id));
|
|
25
|
+
if (selected.size === monorepo.size)
|
|
26
|
+
return fresh();
|
|
27
|
+
let graph;
|
|
28
|
+
try {
|
|
29
|
+
graph = loadVirtual({ ...options, monorepo });
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
if (isPathSecurityError(err))
|
|
33
|
+
throw err;
|
|
34
|
+
graph = actualLoad({ ...options, monorepo, loadManifests: true });
|
|
35
|
+
}
|
|
36
|
+
for (const importer of graph.importers) {
|
|
37
|
+
if (!selected.has(importer.id))
|
|
38
|
+
continue;
|
|
39
|
+
for (const edge of importer.edgesOut.values()) {
|
|
40
|
+
edge.to?.edgesIn.delete(edge);
|
|
41
|
+
}
|
|
42
|
+
importer.edgesOut.clear();
|
|
43
|
+
}
|
|
44
|
+
graph.gc();
|
|
45
|
+
return graph;
|
|
46
|
+
};
|
|
12
47
|
export const update = async (options) => {
|
|
13
48
|
let mainManifest = undefined;
|
|
14
49
|
try {
|
|
@@ -27,6 +62,10 @@ export const update = async (options) => {
|
|
|
27
62
|
}
|
|
28
63
|
const modifiers = GraphModifier.maybeLoad(options);
|
|
29
64
|
const remover = new RollbackRemove();
|
|
65
|
+
const monorepo = Monorepo.maybeLoad(options.projectRoot, {
|
|
66
|
+
packageJson: options.packageJson,
|
|
67
|
+
scurry: options.scurry,
|
|
68
|
+
});
|
|
30
69
|
try {
|
|
31
70
|
const done = graphStep('build');
|
|
32
71
|
const graph = await buildIdealFromStartingGraph({
|
|
@@ -35,13 +74,14 @@ export const update = async (options) => {
|
|
|
35
74
|
remove: Object.assign(new Map(), {
|
|
36
75
|
modifiedDependencies: false,
|
|
37
76
|
}),
|
|
38
|
-
graph:
|
|
77
|
+
graph: startingGraph({ ...options, mainManifest, modifiers }, monorepo),
|
|
39
78
|
modifiers,
|
|
40
79
|
remover,
|
|
41
80
|
});
|
|
42
81
|
done();
|
|
43
82
|
const act = actualLoad({
|
|
44
83
|
...options,
|
|
84
|
+
monorepo,
|
|
45
85
|
mainManifest,
|
|
46
86
|
loadManifests: true,
|
|
47
87
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vltpkg/graph",
|
|
3
3
|
"description": "A library that helps understanding & expressing what happens on an install",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -13,26 +13,26 @@
|
|
|
13
13
|
"url": "http://vlt.sh"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@vltpkg/cmd-shim": "1.
|
|
17
|
-
"@vltpkg/dep-id": "1.
|
|
18
|
-
"@vltpkg/dss-breadcrumb": "1.
|
|
19
|
-
"@vltpkg/error-cause": "1.
|
|
20
|
-
"@vltpkg/fast-split": "1.
|
|
21
|
-
"@vltpkg/graph-run": "1.
|
|
22
|
-
"@vltpkg/init": "1.
|
|
23
|
-
"@vltpkg/output": "1.
|
|
24
|
-
"@vltpkg/package-info": "1.
|
|
25
|
-
"@vltpkg/package-json": "1.
|
|
26
|
-
"@vltpkg/pick-manifest": "1.
|
|
27
|
-
"@vltpkg/query": "1.
|
|
28
|
-
"@vltpkg/rollback-remove": "1.
|
|
29
|
-
"@vltpkg/run": "1.
|
|
30
|
-
"@vltpkg/satisfies": "1.
|
|
31
|
-
"@vltpkg/security-archive": "1.
|
|
32
|
-
"@vltpkg/spec": "1.
|
|
33
|
-
"@vltpkg/types": "1.
|
|
34
|
-
"@vltpkg/vlt-json": "1.
|
|
35
|
-
"@vltpkg/workspaces": "1.
|
|
16
|
+
"@vltpkg/cmd-shim": "1.4.0",
|
|
17
|
+
"@vltpkg/dep-id": "1.4.0",
|
|
18
|
+
"@vltpkg/dss-breadcrumb": "1.4.0",
|
|
19
|
+
"@vltpkg/error-cause": "1.4.0",
|
|
20
|
+
"@vltpkg/fast-split": "1.4.0",
|
|
21
|
+
"@vltpkg/graph-run": "1.4.0",
|
|
22
|
+
"@vltpkg/init": "1.4.0",
|
|
23
|
+
"@vltpkg/output": "1.4.0",
|
|
24
|
+
"@vltpkg/package-info": "1.4.0",
|
|
25
|
+
"@vltpkg/package-json": "1.4.0",
|
|
26
|
+
"@vltpkg/pick-manifest": "1.4.0",
|
|
27
|
+
"@vltpkg/query": "1.4.0",
|
|
28
|
+
"@vltpkg/rollback-remove": "1.4.0",
|
|
29
|
+
"@vltpkg/run": "1.4.0",
|
|
30
|
+
"@vltpkg/satisfies": "1.4.0",
|
|
31
|
+
"@vltpkg/security-archive": "1.4.0",
|
|
32
|
+
"@vltpkg/spec": "1.4.0",
|
|
33
|
+
"@vltpkg/types": "1.4.0",
|
|
34
|
+
"@vltpkg/vlt-json": "1.4.0",
|
|
35
|
+
"@vltpkg/workspaces": "1.4.0",
|
|
36
36
|
"path-scurry": "^2.0.1",
|
|
37
37
|
"promise-call-limit": "^3.0.2"
|
|
38
38
|
},
|