@vltpkg/graph 1.0.0-rc.31 → 1.0.0-rc.33
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/dependencies.js +3 -1
- package/dist/graph.d.ts +6 -0
- package/dist/graph.js +11 -2
- package/dist/ideal/append-nodes.js +16 -1
- package/dist/ideal/get-importer-specs.js +13 -1
- package/dist/ideal/peers.js +3 -3
- package/dist/ideal/refresh-ideal-graph.js +3 -1
- package/dist/install.d.ts +2 -0
- package/dist/install.js +5 -1
- package/dist/lockfile/load-edges.js +8 -0
- package/dist/lockfile/load.js +85 -1
- package/dist/lockfile/save.d.ts +1 -1
- package/dist/lockfile/save.js +10 -5
- package/dist/reify/calculate-save-value.d.ts +1 -1
- package/dist/reify/calculate-save-value.js +5 -4
- package/dist/reify/check-needed-build.js +1 -1
- package/dist/reify/index.d.ts +2 -0
- package/dist/reify/index.js +22 -2
- package/dist/reify/update-importers-package-json.d.ts +11 -1
- package/dist/reify/update-importers-package-json.js +4 -4
- package/dist/transfer-data/load.js +4 -3
- package/package.json +29 -22
package/dist/dependencies.js
CHANGED
|
@@ -100,7 +100,9 @@ export const getDependencies = (node, options) => {
|
|
|
100
100
|
const depType = shorten(type, name, node.manifest);
|
|
101
101
|
const spec = Spec.parse(name, bareSpec, {
|
|
102
102
|
...options,
|
|
103
|
-
|
|
103
|
+
// fall back to options.registry so deps don't lose the configured
|
|
104
|
+
// registry when the node itself has none. see vltpkg/vltpkg#1580.
|
|
105
|
+
registry: node.registry ?? options.registry,
|
|
104
106
|
});
|
|
105
107
|
res.set(name, {
|
|
106
108
|
spec,
|
package/dist/graph.d.ts
CHANGED
|
@@ -85,6 +85,12 @@ export declare class Graph implements GraphLike {
|
|
|
85
85
|
* Key format is internal and constructed in `ideal/peers.ts`.
|
|
86
86
|
*/
|
|
87
87
|
peerContextForkCache: Map<string, PeerContext>;
|
|
88
|
+
/**
|
|
89
|
+
* Whether the options used to create this graph differ from the
|
|
90
|
+
* options stored in the lockfile it was loaded from. When true,
|
|
91
|
+
* the ideal builder must reset edges and rebuild the graph.
|
|
92
|
+
*/
|
|
93
|
+
optionsChanged: boolean;
|
|
88
94
|
/**
|
|
89
95
|
* Tracks the current peer context index.
|
|
90
96
|
*/
|
package/dist/graph.js
CHANGED
|
@@ -23,9 +23,12 @@ const getResolutionCacheKey = (spec, location, extra) => {
|
|
|
23
23
|
const fromPrefix = f.type === 'file' ? location + ' : ' : '';
|
|
24
24
|
// the unique key should also precise what is the type of the spec,
|
|
25
25
|
// and in the case of a registry, what registry it is from.
|
|
26
|
-
const typePrecisionKey = f.registry ?
|
|
26
|
+
const typePrecisionKey = f.registry || f.type === 'registry' ?
|
|
27
|
+
// registry-type specs always get a registry segment, even when
|
|
28
|
+
// no registry is configured, since findResolution trusts cache
|
|
29
|
+
// hits without re-running satisfies()
|
|
27
30
|
`${cacheKeySeparator}registry` +
|
|
28
|
-
`${cacheKeySeparator}${f.registry}`
|
|
31
|
+
`${cacheKeySeparator}${f.registry ?? '<none>'}`
|
|
29
32
|
: f.gitRemote ?
|
|
30
33
|
`${cacheKeySeparator}git` + `${cacheKeySeparator}${f.gitRemote}`
|
|
31
34
|
: `${cacheKeySeparator}${f.type}`;
|
|
@@ -93,6 +96,12 @@ export class Graph {
|
|
|
93
96
|
* Key format is internal and constructed in `ideal/peers.ts`.
|
|
94
97
|
*/
|
|
95
98
|
peerContextForkCache = new Map();
|
|
99
|
+
/**
|
|
100
|
+
* Whether the options used to create this graph differ from the
|
|
101
|
+
* options stored in the lockfile it was loaded from. When true,
|
|
102
|
+
* the ideal builder must reset edges and rebuild the graph.
|
|
103
|
+
*/
|
|
104
|
+
optionsChanged = false;
|
|
96
105
|
/**
|
|
97
106
|
* Tracks the current peer context index.
|
|
98
107
|
*/
|
|
@@ -175,6 +175,19 @@ const fetchManifestsForDeps = async (packageInfo, graph, fromNode, deps, scurry,
|
|
|
175
175
|
reuseTasks.push({ type, spec, fromNode, toNode: existingNode });
|
|
176
176
|
continue;
|
|
177
177
|
}
|
|
178
|
+
// workspace: specs can only resolve to local workspace packages.
|
|
179
|
+
// If we didn't find a matching workspace node above, it means either
|
|
180
|
+
// the workspace doesn't exist or its version doesn't satisfy the range.
|
|
181
|
+
if (spec.final.type === 'workspace') {
|
|
182
|
+
const wsVersion = graph.nodesByName
|
|
183
|
+
.get(spec.name)
|
|
184
|
+
?.values()
|
|
185
|
+
.next().value?.version;
|
|
186
|
+
throw error(wsVersion ?
|
|
187
|
+
`workspace dependency ${spec} does not match the ` +
|
|
188
|
+
`local workspace version (${wsVersion})`
|
|
189
|
+
: `no workspace found matching ${spec}`, { spec });
|
|
190
|
+
}
|
|
178
191
|
// is the current edge pointint go an optional dependency?
|
|
179
192
|
const edgeOptional = type === 'optional' || type === 'peerOptional';
|
|
180
193
|
// Start manifest fetch immediately for parallel processing
|
|
@@ -358,7 +371,9 @@ const processPlacementTasks = async (graph, options, placementTasks, add, modifi
|
|
|
358
371
|
type: shorten(depTypeName, name, manifest),
|
|
359
372
|
spec: Spec.parse(name, bareSpec, {
|
|
360
373
|
...options,
|
|
361
|
-
|
|
374
|
+
// git/file/remote parents have no spec.registry, so fall
|
|
375
|
+
// back to the configured one. see vltpkg/vltpkg#1580.
|
|
376
|
+
registry: spec.registry ?? options.registry,
|
|
362
377
|
}),
|
|
363
378
|
};
|
|
364
379
|
if (depTypeName === 'peerDependencies') {
|
|
@@ -49,8 +49,20 @@ export const getImporterSpecs = (options) => {
|
|
|
49
49
|
// skip if the edge exists and already uses the same spec
|
|
50
50
|
if (edge?.to && depSpec === edge.spec.bareSpec)
|
|
51
51
|
continue;
|
|
52
|
+
const spec = Spec.parse(depName, depSpec, options);
|
|
53
|
+
// if a workspace dep references a workspace that no longer exists
|
|
54
|
+
// (folder was removed), mark it for removal instead of trying to
|
|
55
|
+
// resolve it — the workspace can't be satisfied
|
|
56
|
+
if (spec.type === 'workspace' && !edge?.to) {
|
|
57
|
+
const wsExists = [...graph.importers].some(n => n.name === depName);
|
|
58
|
+
if (!wsExists) {
|
|
59
|
+
removeDeps.add(depName);
|
|
60
|
+
removeResult.modifiedDependencies = true;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
52
64
|
const dependency = asDependency({
|
|
53
|
-
spec
|
|
65
|
+
spec,
|
|
54
66
|
type: shorten(depType, depName, importer.manifest),
|
|
55
67
|
});
|
|
56
68
|
addDeps.set(depName, dependency);
|
package/dist/ideal/peers.js
CHANGED
|
@@ -27,7 +27,7 @@ const nodeSatisfiesSpec = (node, spec, fromNode, graph) => satisfies(node.id, sp
|
|
|
27
27
|
*/
|
|
28
28
|
const parseSpec = (name, bareSpec, fromNode, graph) => Spec.parse(name, bareSpec, {
|
|
29
29
|
...graph.mainImporter.options,
|
|
30
|
-
registry: fromNode.registry,
|
|
30
|
+
registry: fromNode.registry ?? graph.mainImporter.options.registry,
|
|
31
31
|
});
|
|
32
32
|
/**
|
|
33
33
|
* Generate a unique cache key for a peer context fork operation.
|
|
@@ -127,7 +127,7 @@ export const checkPeerEdgesCompatible = (existingNode, fromNode, peerContext, gr
|
|
|
127
127
|
// Per-call memoization: avoid repeated satisfies() calls with identical args
|
|
128
128
|
const parseOpts = {
|
|
129
129
|
...graph.mainImporter.options,
|
|
130
|
-
registry: fromNode.registry,
|
|
130
|
+
registry: fromNode.registry ?? graph.mainImporter.options.registry,
|
|
131
131
|
};
|
|
132
132
|
const fromLocation = fromNode.location;
|
|
133
133
|
const projectRoot = fromNode.projectRoot;
|
|
@@ -481,7 +481,7 @@ export const startPeerPlacement = (peerContext, manifest, fromNode, options) =>
|
|
|
481
481
|
// parent node that might have not been parsed yet
|
|
482
482
|
const siblingDeps = getDependencies(fromNode, {
|
|
483
483
|
...options,
|
|
484
|
-
registry: fromNode.registry,
|
|
484
|
+
registry: fromNode.registry ?? options.registry,
|
|
485
485
|
});
|
|
486
486
|
for (const [depName, dep] of siblingDeps) {
|
|
487
487
|
queueMap.set(depName, dep);
|
|
@@ -32,7 +32,9 @@ export const refreshIdealGraph = async ({ add, graph, modifiers, packageInfo, sc
|
|
|
32
32
|
depsPerImporter.set(importer, deps);
|
|
33
33
|
}
|
|
34
34
|
// removes all edges to start recalculating the graph
|
|
35
|
-
if (add.modifiedDependencies ||
|
|
35
|
+
if (add.modifiedDependencies ||
|
|
36
|
+
remove.modifiedDependencies ||
|
|
37
|
+
graph.optionsChanged) {
|
|
36
38
|
graph.resetEdges();
|
|
37
39
|
}
|
|
38
40
|
// iterates on the list of dependencies per importer updating
|
package/dist/install.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export type InstallOptions = LoadOptions & {
|
|
|
7
7
|
packageInfo: PackageInfoClient;
|
|
8
8
|
cleanInstall?: boolean;
|
|
9
9
|
allowScripts: string;
|
|
10
|
+
saveExact?: boolean;
|
|
11
|
+
savePrefix?: string;
|
|
10
12
|
};
|
|
11
13
|
export declare const install: (options: InstallOptions, add?: AddImportersDependenciesMap) => Promise<{
|
|
12
14
|
graph: Graph;
|
package/dist/install.js
CHANGED
|
@@ -94,8 +94,12 @@ export const install = async (options, add) => {
|
|
|
94
94
|
}
|
|
95
95
|
if (importerSpecs.add.modifiedDependencies ||
|
|
96
96
|
importerSpecs.remove.modifiedDependencies ||
|
|
97
|
-
specChanges.length > 0
|
|
97
|
+
specChanges.length > 0 ||
|
|
98
|
+
lockfileGraph.optionsChanged) {
|
|
98
99
|
const details = [];
|
|
100
|
+
if (lockfileGraph.optionsChanged) {
|
|
101
|
+
details.push(' Configuration options have changed (e.g. modifiers, registries, catalogs)');
|
|
102
|
+
}
|
|
99
103
|
if (specChanges.length > 0) {
|
|
100
104
|
details.push(...specChanges);
|
|
101
105
|
}
|
|
@@ -7,6 +7,11 @@ import { isDependencyTypeShort } from "../dependencies.js";
|
|
|
7
7
|
const retrieveNodeFromGraph = (key, value, graph, fromId, seenNodes) => {
|
|
8
8
|
const foundNode = graph.nodes.get(asDepID(fromId));
|
|
9
9
|
if (!foundNode) {
|
|
10
|
+
// workspace or file nodes may be missing if the folder was removed
|
|
11
|
+
// while still referenced in the lockfile — skip gracefully
|
|
12
|
+
if (fromId.startsWith('workspace') || fromId.startsWith('file')) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
10
15
|
throw error('Edge info missing its `from` node', {
|
|
11
16
|
found: {
|
|
12
17
|
nodes: [...graph.nodes].map(([id]) => id),
|
|
@@ -59,6 +64,9 @@ export const loadEdges = (graph, edges, options) => {
|
|
|
59
64
|
else {
|
|
60
65
|
fromNode = retrieveNodeFromGraph(key, value, graph, fromId);
|
|
61
66
|
}
|
|
67
|
+
// skip edges from workspace nodes that no longer exist
|
|
68
|
+
if (!fromNode)
|
|
69
|
+
continue;
|
|
62
70
|
const toId = valRest.substring(vrSplit + 1);
|
|
63
71
|
let toNode = undefined;
|
|
64
72
|
if (toId !== 'MISSING') {
|
package/dist/lockfile/load.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { error } from '@vltpkg/error-cause';
|
|
2
2
|
import { PackageJson } from '@vltpkg/package-json';
|
|
3
|
+
import { defaultGitHostArchives, defaultGitHosts, defaultJsrRegistries, defaultRegistries, defaultRegistryName, defaultScopeRegistries, } from '@vltpkg/spec';
|
|
4
|
+
import { isRecordStringString } from '@vltpkg/types';
|
|
3
5
|
import { Monorepo } from '@vltpkg/workspaces';
|
|
4
6
|
import { readFileSync } from 'node:fs';
|
|
5
7
|
import { resolve } from 'node:path';
|
|
@@ -20,6 +22,79 @@ export const loadHidden = (options) => {
|
|
|
20
22
|
options.throwOnMissingManifest = true;
|
|
21
23
|
return loadObject(options, loadLockfile(projectRoot, 'node_modules/.vlt-lock.json'));
|
|
22
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Removes entries from `items` that match the corresponding
|
|
27
|
+
* entry in `defaultItems`, returning only non-default values.
|
|
28
|
+
*/
|
|
29
|
+
const removeDefaultItems = (defaultItems, items) => {
|
|
30
|
+
const res = {};
|
|
31
|
+
for (const [key, value] of Object.entries(items)) {
|
|
32
|
+
if (!defaultItems[key] || defaultItems[key] !== value) {
|
|
33
|
+
res[key] = value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return res;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Builds a normalized options object from the current runtime config
|
|
40
|
+
* using the same cleaning logic as `lockfile/save.ts` so that it can
|
|
41
|
+
* be compared directly against the options stored in a lockfile.
|
|
42
|
+
*/
|
|
43
|
+
const buildCurrentOptions = (options) => {
|
|
44
|
+
const hasItems = (o) => o && Object.keys(o).length > 0;
|
|
45
|
+
const cleanModifiers = (options.modifiers &&
|
|
46
|
+
isRecordStringString(options.modifiers.config)) ?
|
|
47
|
+
options.modifiers.config
|
|
48
|
+
: undefined;
|
|
49
|
+
const cleanRegistries = isRecordStringString(options.registries) ?
|
|
50
|
+
removeDefaultItems(defaultRegistries, options.registries)
|
|
51
|
+
: undefined;
|
|
52
|
+
const cleanScopeRegistries = isRecordStringString(options['scoped-registries']) ?
|
|
53
|
+
removeDefaultItems(defaultScopeRegistries, options['scoped-registries'])
|
|
54
|
+
: undefined;
|
|
55
|
+
const cleanJsrRegistries = isRecordStringString(options['jsr-registries']) ?
|
|
56
|
+
removeDefaultItems(defaultJsrRegistries, options['jsr-registries'])
|
|
57
|
+
: undefined;
|
|
58
|
+
const cleanGitHosts = isRecordStringString(options['git-hosts']) ?
|
|
59
|
+
removeDefaultItems(defaultGitHosts, options['git-hosts'])
|
|
60
|
+
: undefined;
|
|
61
|
+
const cleanGitHostArchives = isRecordStringString(options['git-host-archives']) ?
|
|
62
|
+
removeDefaultItems(defaultGitHostArchives, options['git-host-archives'])
|
|
63
|
+
: undefined;
|
|
64
|
+
return {
|
|
65
|
+
...(hasItems(cleanModifiers) ?
|
|
66
|
+
{ modifiers: cleanModifiers }
|
|
67
|
+
: {}),
|
|
68
|
+
...(hasItems(options.catalog) ?
|
|
69
|
+
{ catalog: options.catalog }
|
|
70
|
+
: {}),
|
|
71
|
+
...(hasItems(options.catalogs) ?
|
|
72
|
+
{ catalogs: options.catalogs }
|
|
73
|
+
: {}),
|
|
74
|
+
...(hasItems(cleanScopeRegistries) ?
|
|
75
|
+
{ 'scoped-registries': cleanScopeRegistries }
|
|
76
|
+
: undefined),
|
|
77
|
+
...(hasItems(cleanJsrRegistries) ?
|
|
78
|
+
{ 'jsr-registries': cleanJsrRegistries }
|
|
79
|
+
: undefined),
|
|
80
|
+
...(options.registry !== undefined ?
|
|
81
|
+
{ registry: options.registry }
|
|
82
|
+
: undefined),
|
|
83
|
+
...((options['default-registry-alias'] !== undefined &&
|
|
84
|
+
options['default-registry-alias'] !== defaultRegistryName) ?
|
|
85
|
+
{ 'default-registry-alias': options['default-registry-alias'] }
|
|
86
|
+
: undefined),
|
|
87
|
+
...(hasItems(cleanRegistries) ?
|
|
88
|
+
{ registries: cleanRegistries }
|
|
89
|
+
: undefined),
|
|
90
|
+
...(hasItems(cleanGitHosts) ?
|
|
91
|
+
{ 'git-hosts': cleanGitHosts }
|
|
92
|
+
: undefined),
|
|
93
|
+
...(hasItems(cleanGitHostArchives) ?
|
|
94
|
+
{ 'git-host-archives': cleanGitHostArchives }
|
|
95
|
+
: undefined),
|
|
96
|
+
};
|
|
97
|
+
};
|
|
23
98
|
export const loadObject = (options, lockfileData) => {
|
|
24
99
|
const version = lockfileData.lockfileVersion;
|
|
25
100
|
// Lockfile version is required, likely a corrupted lockfile if missing
|
|
@@ -44,12 +119,19 @@ export const loadObject = (options, lockfileData) => {
|
|
|
44
119
|
const packageJson = options.packageJson ?? new PackageJson();
|
|
45
120
|
const monorepo = options.monorepo ??
|
|
46
121
|
Monorepo.maybeLoad(options.projectRoot, { packageJson, scurry });
|
|
47
|
-
const { catalog = {}, catalogs = {}, 'scoped-registries': scopedRegistriesOption, registry, registries, 'git-hosts': gitHosts, 'git-host-archives': gitHostArchives,
|
|
122
|
+
const { catalog = {}, catalogs = {}, 'scoped-registries': scopedRegistriesOption, registry, registries, 'default-registry-alias': defaultRegistryAlias, 'git-hosts': gitHosts, 'git-host-archives': gitHostArchives,
|
|
48
123
|
/* c8 ignore next */
|
|
49
124
|
} = lockfileData.options ?? {};
|
|
50
125
|
// backwards-compat: legacy lockfiles wrote this field as `scope-registries`
|
|
51
126
|
const scopeRegistries = scopedRegistriesOption ??
|
|
52
127
|
lockfileData.options['scope-registries'];
|
|
128
|
+
// Detect whether the current config options differ from those
|
|
129
|
+
// stored in the lockfile. When they do the ideal builder must
|
|
130
|
+
// reset edges and rebuild the graph.
|
|
131
|
+
const currentOptions = buildCurrentOptions(options);
|
|
132
|
+
/* c8 ignore next */
|
|
133
|
+
const lockfileOptions = lockfileData.options ?? {};
|
|
134
|
+
const optionsChanged = JSON.stringify(currentOptions) !== JSON.stringify(lockfileOptions);
|
|
53
135
|
// Optimize options merging - only create new objects when needed
|
|
54
136
|
const mergedOptions = {
|
|
55
137
|
...options,
|
|
@@ -59,6 +141,7 @@ export const loadObject = (options, lockfileData) => {
|
|
|
59
141
|
{ ...options['scoped-registries'], ...scopeRegistries }
|
|
60
142
|
: options['scoped-registries'],
|
|
61
143
|
registry: registry ?? options.registry,
|
|
144
|
+
'default-registry-alias': defaultRegistryAlias ?? options['default-registry-alias'],
|
|
62
145
|
registries: registries ?
|
|
63
146
|
{ ...options.registries, ...registries }
|
|
64
147
|
: options.registries,
|
|
@@ -74,6 +157,7 @@ export const loadObject = (options, lockfileData) => {
|
|
|
74
157
|
mainManifest,
|
|
75
158
|
monorepo,
|
|
76
159
|
});
|
|
160
|
+
graph.optionsChanged = optionsChanged;
|
|
77
161
|
loadNodes(graph, lockfileData.nodes, mergedOptions, options.actual, options.throwOnMissingManifest);
|
|
78
162
|
loadEdges(graph, lockfileData.edges, mergedOptions);
|
|
79
163
|
// hydrate missing node-level registry data
|
package/dist/lockfile/save.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export type SaveOptions = SpecOptions & {
|
|
|
24
24
|
*/
|
|
25
25
|
throwOnMissingManifest?: boolean;
|
|
26
26
|
};
|
|
27
|
-
export declare const lockfileData: ({ graph, catalog, catalogs, "git-hosts": gitHosts, "git-host-archives": gitHostArchives, modifiers, registry, registries, saveManifests, saveBuildData, "scoped-registries": scopeRegistries, "jsr-registries": jsrRegistries, throwOnMissingManifest, }: SaveOptions) => LockfileData;
|
|
27
|
+
export declare const lockfileData: ({ graph, catalog, catalogs, "git-hosts": gitHosts, "git-host-archives": gitHostArchives, modifiers, registry, registries, "default-registry-alias": defaultRegistryAlias, saveManifests, saveBuildData, "scoped-registries": scopeRegistries, "jsr-registries": jsrRegistries, throwOnMissingManifest, }: SaveOptions) => LockfileData;
|
|
28
28
|
export declare const saveData: (data: LockfileData, fileName: string, saveManifests?: boolean) => void;
|
|
29
29
|
export declare const save: (options: Omit<SaveOptions, "saveManifests">) => void;
|
|
30
30
|
export declare const saveHidden: (options: Omit<SaveOptions, "saveManifests" | "saveBuildData">) => void;
|
package/dist/lockfile/save.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expandNormalizedManifestSymbols, isRecordStringString, } from '@vltpkg/types';
|
|
2
|
-
import { defaultGitHostArchives, defaultGitHosts, defaultJsrRegistries, defaultRegistries,
|
|
2
|
+
import { defaultGitHostArchives, defaultGitHosts, defaultJsrRegistries, defaultRegistries, defaultRegistryName, defaultScopeRegistries, } from '@vltpkg/spec';
|
|
3
3
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { dirname, resolve } from 'node:path';
|
|
5
5
|
import { getFlagNumFromNode, getBuildStateFromNode, LOCKFILE_VERSION, } from "./types.js";
|
|
@@ -12,7 +12,10 @@ const formatNodes = (nodes, saveManifests, saveBuildData, registry, throwOnMissi
|
|
|
12
12
|
const orderedNodes = arr.sort((a, b) => a.id.localeCompare(b.id, 'en'));
|
|
13
13
|
const res = {};
|
|
14
14
|
for (const node of orderedNodes) {
|
|
15
|
-
|
|
15
|
+
// when no registry is configured, nothing can be reconstructed on
|
|
16
|
+
// load, so every resolved value has to be persisted
|
|
17
|
+
const customRegistry = node.resolved &&
|
|
18
|
+
(!registry || !node.resolved.startsWith(registry));
|
|
16
19
|
const resolved = customRegistry ? node.resolved : undefined;
|
|
17
20
|
// if it's in a location other than the default, stash that
|
|
18
21
|
const location = node.id.startsWith('file') || node.inVltStore() ?
|
|
@@ -82,7 +85,7 @@ const removeDefaultItems = (defaultItems, items) => {
|
|
|
82
85
|
}
|
|
83
86
|
return res;
|
|
84
87
|
};
|
|
85
|
-
export const lockfileData = ({ graph, catalog, catalogs, 'git-hosts': gitHosts, 'git-host-archives': gitHostArchives, modifiers, registry, registries, saveManifests, saveBuildData, 'scoped-registries': scopeRegistries, 'jsr-registries': jsrRegistries, throwOnMissingManifest, }) => {
|
|
88
|
+
export const lockfileData = ({ graph, catalog, catalogs, 'git-hosts': gitHosts, 'git-host-archives': gitHostArchives, modifiers, registry, registries, 'default-registry-alias': defaultRegistryAlias, saveManifests, saveBuildData, 'scoped-registries': scopeRegistries, 'jsr-registries': jsrRegistries, throwOnMissingManifest, }) => {
|
|
86
89
|
const cleanGitHosts = isRecordStringString(gitHosts) ?
|
|
87
90
|
removeDefaultItems(defaultGitHosts, gitHosts)
|
|
88
91
|
: undefined;
|
|
@@ -116,8 +119,10 @@ export const lockfileData = ({ graph, catalog, catalogs, 'git-hosts': gitHosts,
|
|
|
116
119
|
...(hasItems(cleanJsrRegistries) ?
|
|
117
120
|
{ 'jsr-registries': cleanJsrRegistries }
|
|
118
121
|
: undefined),
|
|
119
|
-
...(registry !== undefined
|
|
120
|
-
|
|
122
|
+
...(registry !== undefined ? { registry } : undefined),
|
|
123
|
+
...((defaultRegistryAlias !== undefined &&
|
|
124
|
+
defaultRegistryAlias !== defaultRegistryName) ?
|
|
125
|
+
{ 'default-registry-alias': defaultRegistryAlias }
|
|
121
126
|
: undefined),
|
|
122
127
|
...(hasItems(cleanRegistries) ?
|
|
123
128
|
{ registries: cleanRegistries }
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { Spec } from '@vltpkg/spec';
|
|
2
|
-
export declare const calculateSaveValue: (nodeType: string, spec: Spec, existing: string | undefined, nodeVersion: string | undefined) => string;
|
|
2
|
+
export declare const calculateSaveValue: (nodeType: string, spec: Spec, existing: string | undefined, nodeVersion: string | undefined, saveExact?: boolean, savePrefix?: string) => string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const
|
|
2
|
-
export const calculateSaveValue = (nodeType, spec, existing, nodeVersion) => {
|
|
1
|
+
const DEFAULT_SAVE_PREFIX = '^';
|
|
2
|
+
export const calculateSaveValue = (nodeType, spec, existing, nodeVersion, saveExact, savePrefix) => {
|
|
3
3
|
// Catalog specs should always be preserved as-is in package.json.
|
|
4
4
|
// The catalog reference (e.g. "catalog:dev") is the user's intent;
|
|
5
5
|
// the resolved version is tracked in the lockfile.
|
|
@@ -25,8 +25,9 @@ export const calculateSaveValue = (nodeType, spec, existing, nodeVersion) => {
|
|
|
25
25
|
return existing;
|
|
26
26
|
}
|
|
27
27
|
else {
|
|
28
|
-
const
|
|
29
|
-
|
|
28
|
+
const prefix = saveExact ? '' : (savePrefix ?? DEFAULT_SAVE_PREFIX);
|
|
29
|
+
const finalRange = (spec.final.semver && !saveExact && spec.final.bareSpec) ||
|
|
30
|
+
`${prefix}${nodeVersion}`;
|
|
30
31
|
// didn't have dep previously, or depended on a different thing
|
|
31
32
|
// than what was requested. Update with the ^ range based on
|
|
32
33
|
// the node that landed in the graph, but preserve alias prefix
|
|
@@ -43,7 +43,7 @@ const nodeNeedsBuild = (node, scurry, packageJson) => {
|
|
|
43
43
|
return true;
|
|
44
44
|
// Check for prepare scripts on importers or git dependencies
|
|
45
45
|
const prepable = node.id.startsWith('git') || node.importer || !node.inVltStore();
|
|
46
|
-
const runPrepare = !!(
|
|
46
|
+
const runPrepare = !!(scripts.prepare || scripts.preprepare || scripts.postprepare
|
|
47
47
|
/* c8 ignore next 2 */
|
|
48
48
|
) && prepable;
|
|
49
49
|
if (runPrepare)
|
package/dist/reify/index.d.ts
CHANGED
package/dist/reify/index.js
CHANGED
|
@@ -70,7 +70,25 @@ export const reify = async (options) => {
|
|
|
70
70
|
const skippable = skipOptionalOnly && !options.update;
|
|
71
71
|
const res = { diff };
|
|
72
72
|
if (!diff.hasChanges() || skippable) {
|
|
73
|
-
//
|
|
73
|
+
// Even when there are no changes to reify, ensure lockfiles
|
|
74
|
+
// exist on disk. This handles the case where a project has no
|
|
75
|
+
// dependencies (or only workspace importers) but still needs
|
|
76
|
+
// lockfiles written on the first install.
|
|
77
|
+
if (!scurry.lstatSync('vlt-lock.json') ||
|
|
78
|
+
!scurry.lstatSync('node_modules/.vlt-lock.json')) {
|
|
79
|
+
saveHidden(options);
|
|
80
|
+
const lfData = lockfileData(options);
|
|
81
|
+
saveData(lfData, scurry.resolve('vlt-lock.json'), false);
|
|
82
|
+
}
|
|
83
|
+
// Even with no reify changes, report nodes that still need building.
|
|
84
|
+
// Build state is persisted in the hidden lockfile and loaded into the
|
|
85
|
+
// actual graph, so check there for pending builds.
|
|
86
|
+
const pending = [...actual.nodes.values()]
|
|
87
|
+
.filter(n => n.buildState === 'needed')
|
|
88
|
+
.map(n => n.id);
|
|
89
|
+
if (pending.length) {
|
|
90
|
+
res.buildQueue = pending;
|
|
91
|
+
}
|
|
74
92
|
done();
|
|
75
93
|
return res;
|
|
76
94
|
}
|
|
@@ -93,7 +111,7 @@ export const reify = async (options) => {
|
|
|
93
111
|
};
|
|
94
112
|
const reify_ = async (options, diff, remover) => {
|
|
95
113
|
const res = {};
|
|
96
|
-
const { add, remove, packageInfo, packageJson, scurry, allowScripts, } = options;
|
|
114
|
+
const { add, remove, packageInfo, packageJson, scurry, allowScripts, saveExact, savePrefix, } = options;
|
|
97
115
|
const saveImportersPackageJson =
|
|
98
116
|
/* c8 ignore next */
|
|
99
117
|
add?.modifiedDependencies || remove?.modifiedDependencies ?
|
|
@@ -102,6 +120,8 @@ const reify_ = async (options, diff, remover) => {
|
|
|
102
120
|
remove,
|
|
103
121
|
graph: options.graph,
|
|
104
122
|
packageJson,
|
|
123
|
+
saveExact,
|
|
124
|
+
savePrefix,
|
|
105
125
|
})
|
|
106
126
|
: undefined;
|
|
107
127
|
// before anything else happens, grab the ideal tree as it was resolved
|
|
@@ -27,9 +27,19 @@ export type UpdatePackageJsonOptions = {
|
|
|
27
27
|
* instance used to load these `package.json` files previously.
|
|
28
28
|
*/
|
|
29
29
|
packageJson: PackageJson;
|
|
30
|
+
/**
|
|
31
|
+
* When true, save dependencies with exact versions (e.g. `1.2.3`)
|
|
32
|
+
* instead of the default semver range operator (e.g. `^1.2.3`).
|
|
33
|
+
*/
|
|
34
|
+
saveExact?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The prefix to use when saving dependency versions (e.g. `^`, `~`, `>=`, ``).
|
|
37
|
+
* Defaults to `^` if not specified. Ignored when `saveExact` is true.
|
|
38
|
+
*/
|
|
39
|
+
savePrefix?: string;
|
|
30
40
|
};
|
|
31
41
|
/**
|
|
32
42
|
* Updates nodes of a provided {@link Graph} accordingly to the
|
|
33
43
|
* provided add or remove arguments.
|
|
34
44
|
*/
|
|
35
|
-
export declare const updatePackageJson: ({ add, graph, packageJson, remove, }: UpdatePackageJsonOptions) => () => void;
|
|
45
|
+
export declare const updatePackageJson: ({ add, graph, packageJson, remove, saveExact, savePrefix, }: UpdatePackageJsonOptions) => () => void;
|
|
@@ -10,7 +10,7 @@ const depTypesMap = new Map([
|
|
|
10
10
|
['peerOptional', 'peerDependencies'],
|
|
11
11
|
['optional', 'optionalDependencies'],
|
|
12
12
|
]);
|
|
13
|
-
const addOrRemoveDeps = (nodeId, graph, addOrRemove) => {
|
|
13
|
+
const addOrRemoveDeps = (nodeId, graph, addOrRemove, saveExact, savePrefix) => {
|
|
14
14
|
const node = graph.nodes.get(nodeId);
|
|
15
15
|
if (!node) {
|
|
16
16
|
throw error('Failed to retrieve node', {
|
|
@@ -86,7 +86,7 @@ const addOrRemoveDeps = (nodeId, graph, addOrRemove) => {
|
|
|
86
86
|
// If the manifest does not contain anything, then update it.
|
|
87
87
|
// Only for registry dependencies
|
|
88
88
|
const existing = dependencies[name];
|
|
89
|
-
const saveValue = calculateSaveValue(nodeType, dep.spec, existing, n.version);
|
|
89
|
+
const saveValue = calculateSaveValue(nodeType, dep.spec, existing, n.version, saveExact, savePrefix);
|
|
90
90
|
dependencies[name] = saveValue;
|
|
91
91
|
manifestChanged = manifestChanged || saveValue !== existing;
|
|
92
92
|
}
|
|
@@ -97,7 +97,7 @@ const addOrRemoveDeps = (nodeId, graph, addOrRemove) => {
|
|
|
97
97
|
* Updates nodes of a provided {@link Graph} accordingly to the
|
|
98
98
|
* provided add or remove arguments.
|
|
99
99
|
*/
|
|
100
|
-
export const updatePackageJson = ({ add, graph, packageJson, remove, }) => {
|
|
100
|
+
export const updatePackageJson = ({ add, graph, packageJson, remove, saveExact, savePrefix, }) => {
|
|
101
101
|
const manifestsToUpdate = new Set();
|
|
102
102
|
const operations = new Set([add, remove]);
|
|
103
103
|
for (const operation of operations) {
|
|
@@ -106,7 +106,7 @@ export const updatePackageJson = ({ add, graph, packageJson, remove, }) => {
|
|
|
106
106
|
// that are nested folders from which the user can also add new
|
|
107
107
|
// dependencies to
|
|
108
108
|
for (const nodeId of operation.keys()) {
|
|
109
|
-
const manifest = addOrRemoveDeps(nodeId, graph, operation);
|
|
109
|
+
const manifest = addOrRemoveDeps(nodeId, graph, operation, saveExact, savePrefix);
|
|
110
110
|
if (manifest) {
|
|
111
111
|
manifestsToUpdate.add(manifest);
|
|
112
112
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { error } from '@vltpkg/error-cause';
|
|
2
2
|
import { SecurityArchive } from '@vltpkg/security-archive/browser';
|
|
3
|
-
import { defaultGitHostArchives, defaultGitHosts, defaultRegistries,
|
|
3
|
+
import { defaultGitHostArchives, defaultGitHosts, defaultRegistries, defaultRegistryName, defaultScopeRegistries, } from '@vltpkg/spec/browser';
|
|
4
4
|
import { stringifyNode } from "../stringify-node.js";
|
|
5
5
|
import { loadEdges } from "../lockfile/load-edges.js";
|
|
6
6
|
import { loadNodes } from "../lockfile/load-nodes.js";
|
|
7
7
|
const loadSpecOptions = (lockfile) => {
|
|
8
|
-
const { catalog = {}, catalogs = {}, registries, registry, 'git-hosts': gitHosts, 'git-host-archives': gitHostArchives, 'scoped-registries': scopedRegistriesOption, 'jsr-registries': jsrRegistries, } = lockfile.options;
|
|
8
|
+
const { catalog = {}, catalogs = {}, registries, registry, 'default-registry-alias': defaultRegistryAlias, 'git-hosts': gitHosts, 'git-host-archives': gitHostArchives, 'scoped-registries': scopedRegistriesOption, 'jsr-registries': jsrRegistries, } = lockfile.options;
|
|
9
9
|
// backwards-compat: legacy lockfiles wrote this field as `scope-registries`
|
|
10
10
|
const scopeRegistries = scopedRegistriesOption ??
|
|
11
11
|
lockfile.options['scope-registries'];
|
|
@@ -13,7 +13,8 @@ const loadSpecOptions = (lockfile) => {
|
|
|
13
13
|
catalog,
|
|
14
14
|
catalogs,
|
|
15
15
|
registries: { ...defaultRegistries, ...registries },
|
|
16
|
-
registry
|
|
16
|
+
registry,
|
|
17
|
+
'default-registry-alias': defaultRegistryAlias ?? defaultRegistryName,
|
|
17
18
|
'jsr-registries': { ...jsrRegistries },
|
|
18
19
|
'git-hosts': { ...defaultGitHosts, ...gitHosts },
|
|
19
20
|
'git-host-archives': {
|
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.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.33",
|
|
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.0.0-rc.
|
|
17
|
-
"@vltpkg/dep-id": "1.0.0-rc.
|
|
18
|
-
"@vltpkg/dss-breadcrumb": "1.0.0-rc.
|
|
19
|
-
"@vltpkg/error-cause": "1.0.0-rc.
|
|
20
|
-
"@vltpkg/fast-split": "1.0.0-rc.
|
|
21
|
-
"@vltpkg/graph-run": "1.0.0-rc.
|
|
22
|
-
"@vltpkg/init": "1.0.0-rc.
|
|
23
|
-
"@vltpkg/output": "1.0.0-rc.
|
|
24
|
-
"@vltpkg/package-info": "1.0.0-rc.
|
|
25
|
-
"@vltpkg/package-json": "1.0.0-rc.
|
|
26
|
-
"@vltpkg/pick-manifest": "1.0.0-rc.
|
|
27
|
-
"@vltpkg/query": "1.0.0-rc.
|
|
28
|
-
"@vltpkg/rollback-remove": "1.0.0-rc.
|
|
29
|
-
"@vltpkg/run": "1.0.0-rc.
|
|
30
|
-
"@vltpkg/satisfies": "1.0.0-rc.
|
|
31
|
-
"@vltpkg/security-archive": "1.0.0-rc.
|
|
32
|
-
"@vltpkg/spec": "1.0.0-rc.
|
|
33
|
-
"@vltpkg/types": "1.0.0-rc.
|
|
34
|
-
"@vltpkg/vlt-json": "1.0.0-rc.
|
|
35
|
-
"@vltpkg/workspaces": "1.0.0-rc.
|
|
16
|
+
"@vltpkg/cmd-shim": "1.0.0-rc.33",
|
|
17
|
+
"@vltpkg/dep-id": "1.0.0-rc.33",
|
|
18
|
+
"@vltpkg/dss-breadcrumb": "1.0.0-rc.33",
|
|
19
|
+
"@vltpkg/error-cause": "1.0.0-rc.33",
|
|
20
|
+
"@vltpkg/fast-split": "1.0.0-rc.33",
|
|
21
|
+
"@vltpkg/graph-run": "1.0.0-rc.33",
|
|
22
|
+
"@vltpkg/init": "1.0.0-rc.33",
|
|
23
|
+
"@vltpkg/output": "1.0.0-rc.33",
|
|
24
|
+
"@vltpkg/package-info": "1.0.0-rc.33",
|
|
25
|
+
"@vltpkg/package-json": "1.0.0-rc.33",
|
|
26
|
+
"@vltpkg/pick-manifest": "1.0.0-rc.33",
|
|
27
|
+
"@vltpkg/query": "1.0.0-rc.33",
|
|
28
|
+
"@vltpkg/rollback-remove": "1.0.0-rc.33",
|
|
29
|
+
"@vltpkg/run": "1.0.0-rc.33",
|
|
30
|
+
"@vltpkg/satisfies": "1.0.0-rc.33",
|
|
31
|
+
"@vltpkg/security-archive": "1.0.0-rc.33",
|
|
32
|
+
"@vltpkg/spec": "1.0.0-rc.33",
|
|
33
|
+
"@vltpkg/types": "1.0.0-rc.33",
|
|
34
|
+
"@vltpkg/vlt-json": "1.0.0-rc.33",
|
|
35
|
+
"@vltpkg/workspaces": "1.0.0-rc.33",
|
|
36
36
|
"path-scurry": "^2.0.1",
|
|
37
37
|
"promise-call-limit": "^3.0.2"
|
|
38
38
|
},
|
|
@@ -83,5 +83,12 @@
|
|
|
83
83
|
},
|
|
84
84
|
"files": [
|
|
85
85
|
"dist"
|
|
86
|
-
]
|
|
86
|
+
],
|
|
87
|
+
"bugs": [
|
|
88
|
+
{
|
|
89
|
+
"type": "link",
|
|
90
|
+
"url": "https://github.com/vltpkg/vltpkg/issues"
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"homepage": "https://github.com/vltpkg/vltpkg/tree/main/src/graph#readme"
|
|
87
94
|
}
|