@pnpm/installing.deps-resolver 1008.3.1
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/LICENSE +22 -0
- package/README.md +17 -0
- package/lib/dedupeInjectedDeps.d.ts +14 -0
- package/lib/dedupeInjectedDeps.js +72 -0
- package/lib/depPathToRef.d.ts +4 -0
- package/lib/depPathToRef.js +7 -0
- package/lib/getCatalogSnapshots.d.ts +4 -0
- package/lib/getCatalogSnapshots.js +21 -0
- package/lib/getExactSinglePreferredVersions.d.ts +6 -0
- package/lib/getExactSinglePreferredVersions.js +11 -0
- package/lib/getNonDevWantedDependencies.d.ts +12 -0
- package/lib/getNonDevWantedDependencies.js +29 -0
- package/lib/getWantedDependencies.d.ts +14 -0
- package/lib/getWantedDependencies.js +45 -0
- package/lib/hoistPeers.d.ts +10 -0
- package/lib/hoistPeers.js +75 -0
- package/lib/index.d.ts +53 -0
- package/lib/index.js +335 -0
- package/lib/mergePeers.d.ts +7 -0
- package/lib/mergePeers.js +30 -0
- package/lib/nextNodeId.d.ts +6 -0
- package/lib/nextNodeId.js +5 -0
- package/lib/parentIdsContainSequence.d.ts +2 -0
- package/lib/parentIdsContainSequence.js +9 -0
- package/lib/replaceVersionInBareSpecifier.d.ts +1 -0
- package/lib/replaceVersionInBareSpecifier.js +15 -0
- package/lib/resolveDependencies.d.ts +248 -0
- package/lib/resolveDependencies.js +1182 -0
- package/lib/resolveDependencyTree.d.ts +122 -0
- package/lib/resolveDependencyTree.js +228 -0
- package/lib/resolvePeers.d.ts +59 -0
- package/lib/resolvePeers.js +702 -0
- package/lib/safeIsInnerLink.d.ts +6 -0
- package/lib/safeIsInnerLink.js +31 -0
- package/lib/toResolveImporter.d.ts +22 -0
- package/lib/toResolveImporter.js +117 -0
- package/lib/unwrapPackageName.d.ts +23 -0
- package/lib/unwrapPackageName.js +39 -0
- package/lib/updateLockfile.d.ts +10 -0
- package/lib/updateLockfile.js +121 -0
- package/lib/updateProjectManifest.d.ts +8 -0
- package/lib/updateProjectManifest.js +34 -0
- package/lib/validatePeerDependencies.d.ts +6 -0
- package/lib/validatePeerDependencies.js +15 -0
- package/lib/wantedDepIsLocallyAvailable.d.ts +6 -0
- package/lib/wantedDepIsLocallyAvailable.js +23 -0
- package/package.json +91 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { createPeerDepGraphHash, depPathToFilename } from '@pnpm/deps.path';
|
|
3
|
+
import * as semverUtils from '@yarnpkg/core/semverUtils';
|
|
4
|
+
import filenamify from 'filenamify';
|
|
5
|
+
import { analyzeGraph } from 'graph-cycles';
|
|
6
|
+
import pDefer, {} from 'p-defer';
|
|
7
|
+
import { partition, pick } from 'ramda';
|
|
8
|
+
import semver from 'semver';
|
|
9
|
+
import { dedupeInjectedDeps } from './dedupeInjectedDeps.js';
|
|
10
|
+
import { mergePeers } from './mergePeers.js';
|
|
11
|
+
export async function resolvePeers(opts) {
|
|
12
|
+
const depGraph = {};
|
|
13
|
+
const pathsByNodeId = new Map();
|
|
14
|
+
const pathsByNodeIdPromises = new Map();
|
|
15
|
+
const depPathsByPkgId = new Map();
|
|
16
|
+
const _createPkgsByName = createPkgsByName.bind(null, opts.dependenciesTree);
|
|
17
|
+
const rootPkgsByName = opts.resolvePeersFromWorkspaceRoot ? getRootPkgsByName(opts.dependenciesTree, opts.projects) : {};
|
|
18
|
+
const peerDependencyIssuesByProjects = {};
|
|
19
|
+
const finishingList = [];
|
|
20
|
+
const peersCache = new Map();
|
|
21
|
+
const purePkgs = new Set();
|
|
22
|
+
for (const { directNodeIdsByAlias, topParents, rootDir, id } of opts.projects) {
|
|
23
|
+
const peerDependencyIssues = { bad: {}, missing: {} };
|
|
24
|
+
const pkgsByName = Object.fromEntries(Object.entries({
|
|
25
|
+
...rootPkgsByName,
|
|
26
|
+
..._createPkgsByName({ directNodeIdsByAlias, topParents }),
|
|
27
|
+
}).filter(([peerName]) => opts.allPeerDepNames.has(peerName)));
|
|
28
|
+
for (const { nodeId } of Object.values(pkgsByName)) {
|
|
29
|
+
if (nodeId && !pathsByNodeIdPromises.has(nodeId)) {
|
|
30
|
+
pathsByNodeIdPromises.set(nodeId, pDefer());
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// eslint-disable-next-line no-await-in-loop
|
|
34
|
+
const { finishing } = await resolvePeersOfChildren(Object.fromEntries(directNodeIdsByAlias.entries()), pkgsByName, {
|
|
35
|
+
allPeerDepNames: opts.allPeerDepNames,
|
|
36
|
+
parentPkgsOfNode: new Map(),
|
|
37
|
+
dependenciesTree: opts.dependenciesTree,
|
|
38
|
+
depGraph,
|
|
39
|
+
lockfileDir: opts.lockfileDir,
|
|
40
|
+
parentNodeIds: [],
|
|
41
|
+
parentDepPathsChain: [],
|
|
42
|
+
pathsByNodeId,
|
|
43
|
+
pathsByNodeIdPromises,
|
|
44
|
+
depPathsByPkgId,
|
|
45
|
+
peersCache,
|
|
46
|
+
peerDependencyIssues,
|
|
47
|
+
purePkgs,
|
|
48
|
+
peersSuffixMaxLength: opts.peersSuffixMaxLength,
|
|
49
|
+
rootDir,
|
|
50
|
+
virtualStoreDir: opts.virtualStoreDir,
|
|
51
|
+
virtualStoreDirMaxLength: opts.virtualStoreDirMaxLength,
|
|
52
|
+
});
|
|
53
|
+
if (finishing) {
|
|
54
|
+
finishingList.push(finishing);
|
|
55
|
+
}
|
|
56
|
+
if (Object.keys(peerDependencyIssues.bad).length > 0 || Object.keys(peerDependencyIssues.missing).length > 0) {
|
|
57
|
+
peerDependencyIssuesByProjects[id] = {
|
|
58
|
+
...peerDependencyIssues,
|
|
59
|
+
...mergePeers(peerDependencyIssues.missing),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
await Promise.all(finishingList);
|
|
64
|
+
const depGraphWithResolvedChildren = resolveChildren(depGraph);
|
|
65
|
+
function resolveChildren(depGraph) {
|
|
66
|
+
for (const node of Object.values(depGraph)) {
|
|
67
|
+
node.children = {};
|
|
68
|
+
for (const [alias, childNodeId] of Object.entries(node.childrenNodeIds)) {
|
|
69
|
+
node.children[alias] = pathsByNodeId.get(childNodeId) ?? childNodeId;
|
|
70
|
+
}
|
|
71
|
+
delete node.childrenNodeIds;
|
|
72
|
+
}
|
|
73
|
+
return depGraph;
|
|
74
|
+
}
|
|
75
|
+
const dependenciesByProjectId = {};
|
|
76
|
+
for (const { directNodeIdsByAlias, id } of opts.projects) {
|
|
77
|
+
dependenciesByProjectId[id] = new Map();
|
|
78
|
+
for (const [alias, nodeId] of directNodeIdsByAlias.entries()) {
|
|
79
|
+
dependenciesByProjectId[id].set(alias, pathsByNodeId.get(nodeId));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (opts.dedupeInjectedDeps) {
|
|
83
|
+
dedupeInjectedDeps({
|
|
84
|
+
dependenciesByProjectId,
|
|
85
|
+
projects: opts.projects,
|
|
86
|
+
depGraph: depGraphWithResolvedChildren,
|
|
87
|
+
pathsByNodeId,
|
|
88
|
+
lockfileDir: opts.lockfileDir,
|
|
89
|
+
resolvedImporters: opts.resolvedImporters,
|
|
90
|
+
workspaceProjectIds: opts.workspaceProjectIds,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (opts.dedupePeerDependents) {
|
|
94
|
+
const duplicates = Array.from(depPathsByPkgId.values()).filter((item) => item.size > 1);
|
|
95
|
+
const allDepPathsMap = deduplicateAll(depGraphWithResolvedChildren, duplicates);
|
|
96
|
+
for (const { id } of opts.projects) {
|
|
97
|
+
for (const [alias, depPath] of dependenciesByProjectId[id].entries()) {
|
|
98
|
+
dependenciesByProjectId[id].set(alias, allDepPathsMap[depPath] ?? depPath);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
dependenciesGraph: depGraphWithResolvedChildren,
|
|
104
|
+
dependenciesByProjectId,
|
|
105
|
+
peerDependencyIssuesByProjects,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function nodeDepsCount(node) {
|
|
109
|
+
return Object.keys(node.children).length + node.resolvedPeerNames.size;
|
|
110
|
+
}
|
|
111
|
+
function deduplicateAll(depGraph, duplicates) {
|
|
112
|
+
const { depPathsMap, remainingDuplicates } = deduplicateDepPaths(duplicates, depGraph);
|
|
113
|
+
if (remainingDuplicates.length === duplicates.length) {
|
|
114
|
+
return depPathsMap;
|
|
115
|
+
}
|
|
116
|
+
for (const node of Object.values(depGraph)) {
|
|
117
|
+
for (const [alias, childDepPath] of Object.entries(node.children)) {
|
|
118
|
+
if (depPathsMap[childDepPath]) {
|
|
119
|
+
node.children[alias] = depPathsMap[childDepPath];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (Object.keys(depPathsMap).length > 0) {
|
|
124
|
+
return {
|
|
125
|
+
...depPathsMap,
|
|
126
|
+
...deduplicateAll(depGraph, remainingDuplicates),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return depPathsMap;
|
|
130
|
+
}
|
|
131
|
+
function deduplicateDepPaths(duplicates, depGraph) {
|
|
132
|
+
const depCountSorter = (depPath1, depPath2) => nodeDepsCount(depGraph[depPath1]) - nodeDepsCount(depGraph[depPath2]);
|
|
133
|
+
const depPathsMap = {};
|
|
134
|
+
const remainingDuplicates = [];
|
|
135
|
+
for (const depPaths of duplicates) {
|
|
136
|
+
const unresolvedDepPaths = new Set(depPaths.values());
|
|
137
|
+
let currentDepPaths = [...depPaths].sort(depCountSorter);
|
|
138
|
+
while (currentDepPaths.length) {
|
|
139
|
+
const depPath1 = currentDepPaths.pop();
|
|
140
|
+
const nextDepPaths = [];
|
|
141
|
+
while (currentDepPaths.length) {
|
|
142
|
+
const depPath2 = currentDepPaths.pop();
|
|
143
|
+
if (isCompatibleAndHasMoreDeps(depGraph, depPath1, depPath2)) {
|
|
144
|
+
depPathsMap[depPath2] = depPath1;
|
|
145
|
+
unresolvedDepPaths.delete(depPath1);
|
|
146
|
+
unresolvedDepPaths.delete(depPath2);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
nextDepPaths.push(depPath2);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
nextDepPaths.push(...currentDepPaths);
|
|
153
|
+
currentDepPaths = nextDepPaths.sort(depCountSorter);
|
|
154
|
+
}
|
|
155
|
+
if (unresolvedDepPaths.size) {
|
|
156
|
+
remainingDuplicates.push(unresolvedDepPaths);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
depPathsMap,
|
|
161
|
+
remainingDuplicates,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function isCompatibleAndHasMoreDeps(depGraph, depPath1, depPath2) {
|
|
165
|
+
const node1 = depGraph[depPath1];
|
|
166
|
+
const node2 = depGraph[depPath2];
|
|
167
|
+
if (nodeDepsCount(node1) < nodeDepsCount(node2))
|
|
168
|
+
return false;
|
|
169
|
+
const node1DepPathsSet = new Set(Object.values(node1.children));
|
|
170
|
+
const node2DepPaths = Object.values(node2.children);
|
|
171
|
+
if (!node2DepPaths.every((depPath) => node1DepPathsSet.has(depPath)))
|
|
172
|
+
return false;
|
|
173
|
+
for (const depPath of node2.resolvedPeerNames) {
|
|
174
|
+
if (!node1.resolvedPeerNames.has(depPath))
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
function getRootPkgsByName(dependenciesTree, projects) {
|
|
180
|
+
const rootProject = projects.length > 1 ? projects.find(({ id }) => id === '.') : null;
|
|
181
|
+
return rootProject == null ? {} : createPkgsByName(dependenciesTree, rootProject);
|
|
182
|
+
}
|
|
183
|
+
function createPkgsByName(dependenciesTree, { directNodeIdsByAlias, topParents }) {
|
|
184
|
+
const parentRefs = toPkgByName(Array.from(directNodeIdsByAlias.entries())
|
|
185
|
+
.map(([alias, nodeId]) => ({
|
|
186
|
+
alias,
|
|
187
|
+
node: dependenciesTree.get(nodeId),
|
|
188
|
+
nodeId,
|
|
189
|
+
parentNodeIds: [],
|
|
190
|
+
})));
|
|
191
|
+
const _updateParentRefs = updateParentRefs.bind(null, parentRefs);
|
|
192
|
+
for (const { name, version, alias, linkedDir } of topParents) {
|
|
193
|
+
const pkg = {
|
|
194
|
+
occurrence: 0,
|
|
195
|
+
alias,
|
|
196
|
+
depth: 0,
|
|
197
|
+
version,
|
|
198
|
+
nodeId: linkedDir,
|
|
199
|
+
parentNodeIds: [],
|
|
200
|
+
};
|
|
201
|
+
_updateParentRefs(name, pkg);
|
|
202
|
+
if (alias && alias !== name) {
|
|
203
|
+
_updateParentRefs(alias, pkg);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return parentRefs;
|
|
207
|
+
}
|
|
208
|
+
async function resolvePeersOfNode(currentAlias, nodeId, parentParentPkgs, ctx) {
|
|
209
|
+
const node = ctx.dependenciesTree.get(nodeId);
|
|
210
|
+
if (node.depth === -1)
|
|
211
|
+
return { resolvedPeers: new Map(), missingPeers: new Map() };
|
|
212
|
+
const resolvedPackage = node.resolvedPackage;
|
|
213
|
+
if (ctx.purePkgs.has(resolvedPackage.pkgIdWithPatchHash) &&
|
|
214
|
+
ctx.depGraph[resolvedPackage.pkgIdWithPatchHash].depth <= node.depth &&
|
|
215
|
+
Object.keys(resolvedPackage.peerDependencies).length === 0) {
|
|
216
|
+
ctx.pathsByNodeId.set(nodeId, resolvedPackage.pkgIdWithPatchHash);
|
|
217
|
+
ctx.pathsByNodeIdPromises.get(nodeId).resolve(resolvedPackage.pkgIdWithPatchHash);
|
|
218
|
+
return { resolvedPeers: new Map(), missingPeers: new Map() };
|
|
219
|
+
}
|
|
220
|
+
if (typeof node.children === 'function') {
|
|
221
|
+
node.children = node.children();
|
|
222
|
+
}
|
|
223
|
+
const parentNodeIds = [...ctx.parentNodeIds, nodeId];
|
|
224
|
+
const children = node.children;
|
|
225
|
+
let parentPkgs;
|
|
226
|
+
if (Object.keys(children).length === 0) {
|
|
227
|
+
parentPkgs = parentParentPkgs;
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
parentPkgs = { ...parentParentPkgs };
|
|
231
|
+
const parentPkgNodes = [];
|
|
232
|
+
for (const [alias, nodeId] of Object.entries(children)) {
|
|
233
|
+
if (ctx.allPeerDepNames.has(alias)) {
|
|
234
|
+
parentPkgNodes.push({
|
|
235
|
+
alias,
|
|
236
|
+
node: ctx.dependenciesTree.get(nodeId),
|
|
237
|
+
nodeId,
|
|
238
|
+
parentNodeIds,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const newParentPkgs = toPkgByName(parentPkgNodes);
|
|
243
|
+
const _parentPkgsMatch = parentPkgsMatch.bind(null, ctx.dependenciesTree);
|
|
244
|
+
for (const [newParentPkgName, newParentPkg] of Object.entries(newParentPkgs)) {
|
|
245
|
+
if (parentPkgs[newParentPkgName]) {
|
|
246
|
+
if (!_parentPkgsMatch(parentPkgs[newParentPkgName], newParentPkg)) {
|
|
247
|
+
newParentPkg.occurrence = parentPkgs[newParentPkgName].occurrence + 1;
|
|
248
|
+
parentPkgs[newParentPkgName] = newParentPkg;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
parentPkgs[newParentPkgName] = newParentPkg;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const hit = findHit(ctx, parentPkgs, resolvedPackage.pkgIdWithPatchHash);
|
|
257
|
+
if (hit != null) {
|
|
258
|
+
for (const [peerName, { range: wantedRange, optional }] of hit.missingPeers.entries()) {
|
|
259
|
+
if (ctx.peerDependencyIssues.missing[peerName] == null) {
|
|
260
|
+
ctx.peerDependencyIssues.missing[peerName] = [];
|
|
261
|
+
}
|
|
262
|
+
const { parents } = getLocationFromParentNodeIds({
|
|
263
|
+
dependenciesTree: ctx.dependenciesTree,
|
|
264
|
+
parentNodeIds,
|
|
265
|
+
});
|
|
266
|
+
ctx.peerDependencyIssues.missing[peerName].push({
|
|
267
|
+
optional,
|
|
268
|
+
parents,
|
|
269
|
+
wantedRange,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
missingPeers: hit.missingPeers,
|
|
274
|
+
finishing: (async () => {
|
|
275
|
+
const depPath = await hit.depPath.promise;
|
|
276
|
+
ctx.pathsByNodeId.set(nodeId, depPath);
|
|
277
|
+
ctx.depGraph[depPath].depth = Math.min(ctx.depGraph[depPath].depth, node.depth);
|
|
278
|
+
ctx.pathsByNodeIdPromises.get(nodeId).resolve(depPath);
|
|
279
|
+
})(),
|
|
280
|
+
resolvedPeers: hit.resolvedPeers,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const { resolvedPeers: unknownResolvedPeersOfChildren, missingPeers: missingPeersOfChildren, finishing, } = await resolvePeersOfChildren(children, parentPkgs, {
|
|
284
|
+
...ctx,
|
|
285
|
+
parentNodeIds,
|
|
286
|
+
parentDepPathsChain: ctx.parentDepPathsChain.includes(resolvedPackage.pkgIdWithPatchHash) ? ctx.parentDepPathsChain : [...ctx.parentDepPathsChain, resolvedPackage.pkgIdWithPatchHash],
|
|
287
|
+
});
|
|
288
|
+
const { resolvedPeers, missingPeers } = Object.keys(resolvedPackage.peerDependencies).length === 0
|
|
289
|
+
? { resolvedPeers: new Map(), missingPeers: new Map() }
|
|
290
|
+
: _resolvePeers({
|
|
291
|
+
currentDepth: node.depth,
|
|
292
|
+
dependenciesTree: ctx.dependenciesTree,
|
|
293
|
+
lockfileDir: ctx.lockfileDir,
|
|
294
|
+
nodeId,
|
|
295
|
+
parentPkgs,
|
|
296
|
+
peerDependencyIssues: ctx.peerDependencyIssues,
|
|
297
|
+
resolvedPackage,
|
|
298
|
+
rootDir: ctx.rootDir,
|
|
299
|
+
parentNodeIds,
|
|
300
|
+
});
|
|
301
|
+
const allResolvedPeers = unknownResolvedPeersOfChildren;
|
|
302
|
+
for (const [k, v] of resolvedPeers) {
|
|
303
|
+
allResolvedPeers.set(k, v);
|
|
304
|
+
}
|
|
305
|
+
allResolvedPeers.delete(node.resolvedPackage.name);
|
|
306
|
+
const allMissingPeers = new Map();
|
|
307
|
+
for (const [peer, range] of missingPeersOfChildren.entries()) {
|
|
308
|
+
allMissingPeers.set(peer, range);
|
|
309
|
+
}
|
|
310
|
+
for (const [peer, range] of missingPeers.entries()) {
|
|
311
|
+
allMissingPeers.set(peer, range);
|
|
312
|
+
}
|
|
313
|
+
let cache;
|
|
314
|
+
const isPure = allResolvedPeers.size === 0 && allMissingPeers.size === 0;
|
|
315
|
+
if (isPure) {
|
|
316
|
+
ctx.purePkgs.add(resolvedPackage.pkgIdWithPatchHash);
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
cache = {
|
|
320
|
+
missingPeers: allMissingPeers,
|
|
321
|
+
depPath: pDefer(),
|
|
322
|
+
resolvedPeers: allResolvedPeers,
|
|
323
|
+
};
|
|
324
|
+
if (ctx.peersCache.has(resolvedPackage.pkgIdWithPatchHash)) {
|
|
325
|
+
ctx.peersCache.get(resolvedPackage.pkgIdWithPatchHash).push(cache);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
ctx.peersCache.set(resolvedPackage.pkgIdWithPatchHash, [cache]);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
let calculateDepPathIfNeeded;
|
|
332
|
+
if (allResolvedPeers.size === 0) {
|
|
333
|
+
addDepPathToGraph(resolvedPackage.pkgIdWithPatchHash);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
const peerIds = [];
|
|
337
|
+
const pendingPeers = [];
|
|
338
|
+
for (const [alias, peerNodeId] of allResolvedPeers.entries()) {
|
|
339
|
+
if (typeof peerNodeId === 'string' && peerNodeId.startsWith('link:')) {
|
|
340
|
+
const linkedDir = peerNodeId.slice(5);
|
|
341
|
+
peerIds.push({
|
|
342
|
+
name: alias,
|
|
343
|
+
version: filenamify(linkedDir, { replacement: '+' }),
|
|
344
|
+
});
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
const peerDepPath = ctx.pathsByNodeId.get(peerNodeId);
|
|
348
|
+
if (peerDepPath) {
|
|
349
|
+
peerIds.push(peerDepPath);
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
pendingPeers.push({ alias, nodeId: peerNodeId });
|
|
353
|
+
}
|
|
354
|
+
if (pendingPeers.length === 0) {
|
|
355
|
+
const peerDepGraphHash = createPeerDepGraphHash(peerIds, ctx.peersSuffixMaxLength);
|
|
356
|
+
addDepPathToGraph(`${resolvedPackage.pkgIdWithPatchHash}${peerDepGraphHash}`);
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
calculateDepPathIfNeeded = calculateDepPath.bind(null, peerIds, pendingPeers);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
resolvedPeers: allResolvedPeers,
|
|
364
|
+
missingPeers: allMissingPeers,
|
|
365
|
+
calculateDepPath: calculateDepPathIfNeeded,
|
|
366
|
+
finishing,
|
|
367
|
+
};
|
|
368
|
+
async function calculateDepPath(peerIds, pendingPeerNodes, cycles) {
|
|
369
|
+
const cyclicPeerAliases = new Set();
|
|
370
|
+
for (const cycle of cycles) {
|
|
371
|
+
if (cycle.includes(currentAlias)) {
|
|
372
|
+
for (const peerAlias of cycle) {
|
|
373
|
+
cyclicPeerAliases.add(peerAlias);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const peerDepGraphHash = createPeerDepGraphHash([
|
|
378
|
+
...peerIds,
|
|
379
|
+
...await Promise.all(pendingPeerNodes
|
|
380
|
+
.map(async (pendingPeer) => {
|
|
381
|
+
if (cyclicPeerAliases.has(pendingPeer.alias)) {
|
|
382
|
+
const { name, version } = ctx.dependenciesTree.get(pendingPeer.nodeId)?.resolvedPackage;
|
|
383
|
+
const id = `${name}@${version}`;
|
|
384
|
+
ctx.pathsByNodeIdPromises.get(pendingPeer.nodeId)?.resolve(id);
|
|
385
|
+
return id;
|
|
386
|
+
}
|
|
387
|
+
return ctx.pathsByNodeIdPromises.get(pendingPeer.nodeId).promise;
|
|
388
|
+
})),
|
|
389
|
+
], ctx.peersSuffixMaxLength);
|
|
390
|
+
addDepPathToGraph(`${resolvedPackage.pkgIdWithPatchHash}${peerDepGraphHash}`);
|
|
391
|
+
}
|
|
392
|
+
function addDepPathToGraph(depPath) {
|
|
393
|
+
cache?.depPath.resolve(depPath);
|
|
394
|
+
ctx.pathsByNodeId.set(nodeId, depPath);
|
|
395
|
+
ctx.pathsByNodeIdPromises.get(nodeId).resolve(depPath);
|
|
396
|
+
if (ctx.depPathsByPkgId != null) {
|
|
397
|
+
if (!ctx.depPathsByPkgId.has(resolvedPackage.pkgIdWithPatchHash)) {
|
|
398
|
+
ctx.depPathsByPkgId.set(resolvedPackage.pkgIdWithPatchHash, new Set([depPath]));
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
ctx.depPathsByPkgId.get(resolvedPackage.pkgIdWithPatchHash).add(depPath);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
const peerDependencies = { ...resolvedPackage.peerDependencies };
|
|
405
|
+
if (!ctx.depGraph[depPath] || ctx.depGraph[depPath].depth > node.depth) {
|
|
406
|
+
const modules = path.join(ctx.virtualStoreDir, depPathToFilename(depPath, ctx.virtualStoreDirMaxLength), 'node_modules');
|
|
407
|
+
const dir = path.join(modules, resolvedPackage.name);
|
|
408
|
+
const transitivePeerDependencies = new Set();
|
|
409
|
+
for (const unknownPeer of allResolvedPeers.keys()) {
|
|
410
|
+
if (!peerDependencies[unknownPeer]) {
|
|
411
|
+
transitivePeerDependencies.add(unknownPeer);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
for (const unknownPeer of missingPeersOfChildren.keys()) {
|
|
415
|
+
if (!peerDependencies[unknownPeer]) {
|
|
416
|
+
transitivePeerDependencies.add(unknownPeer);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
ctx.depGraph[depPath] = {
|
|
420
|
+
...node.resolvedPackage,
|
|
421
|
+
childrenNodeIds: Object.assign(getPreviouslyResolvedChildren(ctx, node.resolvedPackage.pkgIdWithPatchHash), children, Object.fromEntries(resolvedPeers.entries())),
|
|
422
|
+
depPath,
|
|
423
|
+
depth: node.depth,
|
|
424
|
+
dir,
|
|
425
|
+
installable: node.installable,
|
|
426
|
+
isPure,
|
|
427
|
+
modules,
|
|
428
|
+
peerDependencies,
|
|
429
|
+
transitivePeerDependencies,
|
|
430
|
+
resolvedPeerNames: new Set(allResolvedPeers.keys()),
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function parentPkgsMatch(dependenciesTree, currentParentPkg, newParentPkg) {
|
|
436
|
+
if (currentParentPkg.version !== newParentPkg.version ||
|
|
437
|
+
currentParentPkg.alias !== newParentPkg.alias) {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
const currentParentResolvedPkg = currentParentPkg.nodeId && dependenciesTree.get(currentParentPkg.nodeId)?.resolvedPackage;
|
|
441
|
+
if (currentParentResolvedPkg == null)
|
|
442
|
+
return true;
|
|
443
|
+
const newParentResolvedPkg = newParentPkg.nodeId && dependenciesTree.get(newParentPkg.nodeId)?.resolvedPackage;
|
|
444
|
+
if (newParentResolvedPkg == null)
|
|
445
|
+
return true;
|
|
446
|
+
return currentParentResolvedPkg.name === newParentResolvedPkg.name;
|
|
447
|
+
}
|
|
448
|
+
function findHit(ctx, parentPkgs, pkgIdWithPatchHash) {
|
|
449
|
+
const cacheItems = ctx.peersCache.get(pkgIdWithPatchHash);
|
|
450
|
+
if (!cacheItems)
|
|
451
|
+
return undefined;
|
|
452
|
+
return cacheItems.find((cache) => {
|
|
453
|
+
for (const [name, cachedNodeId] of cache.resolvedPeers) {
|
|
454
|
+
const parentPkgNodeId = parentPkgs[name]?.nodeId;
|
|
455
|
+
if (Boolean(parentPkgNodeId) !== Boolean(cachedNodeId))
|
|
456
|
+
return false;
|
|
457
|
+
if (parentPkgNodeId === cachedNodeId)
|
|
458
|
+
continue;
|
|
459
|
+
if (!parentPkgNodeId)
|
|
460
|
+
return false;
|
|
461
|
+
if (ctx.pathsByNodeId.has(cachedNodeId) &&
|
|
462
|
+
ctx.pathsByNodeId.get(cachedNodeId) === ctx.pathsByNodeId.get(parentPkgNodeId))
|
|
463
|
+
continue;
|
|
464
|
+
if (!ctx.dependenciesTree.has(parentPkgNodeId) && typeof parentPkgNodeId === 'string' && parentPkgNodeId.startsWith('link:')) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
const parentPkgId = ctx.dependenciesTree.get(parentPkgNodeId).resolvedPackage.pkgIdWithPatchHash;
|
|
468
|
+
const cachedPkgId = ctx.dependenciesTree.get(cachedNodeId).resolvedPackage.pkgIdWithPatchHash;
|
|
469
|
+
if (parentPkgId !== cachedPkgId) {
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
if (!ctx.purePkgs.has(parentPkgId) &&
|
|
473
|
+
!parentPackagesMatch(ctx, cachedNodeId, parentPkgNodeId)) {
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
for (const missingPeer of cache.missingPeers.keys()) {
|
|
478
|
+
if (parentPkgs[missingPeer])
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
return true;
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
function parentPackagesMatch(ctx, cachedNodeId, checkedNodeId) {
|
|
485
|
+
const cachedParentPkgs = ctx.parentPkgsOfNode.get(cachedNodeId);
|
|
486
|
+
if (!cachedParentPkgs)
|
|
487
|
+
return false;
|
|
488
|
+
const checkedParentPkgs = ctx.parentPkgsOfNode.get(checkedNodeId);
|
|
489
|
+
if (!checkedParentPkgs)
|
|
490
|
+
return false;
|
|
491
|
+
if (Object.keys(cachedParentPkgs).length !== Object.keys(checkedParentPkgs).length)
|
|
492
|
+
return false;
|
|
493
|
+
const maxDepth = Object.values(checkedParentPkgs)
|
|
494
|
+
.reduce((maxDepth, { depth }) => Math.max(depth ?? 0, maxDepth), 0);
|
|
495
|
+
const peerDepsAreNotShadowed = parentPkgsHaveSingleOccurrence(cachedParentPkgs) &&
|
|
496
|
+
parentPkgsHaveSingleOccurrence(checkedParentPkgs);
|
|
497
|
+
return (Object.entries(cachedParentPkgs).every(([name, { version, pkgIdWithPatchHash }]) => {
|
|
498
|
+
if (checkedParentPkgs[name] == null)
|
|
499
|
+
return false;
|
|
500
|
+
if (version && checkedParentPkgs[name].version) {
|
|
501
|
+
return version === checkedParentPkgs[name].version;
|
|
502
|
+
}
|
|
503
|
+
return pkgIdWithPatchHash != null &&
|
|
504
|
+
(pkgIdWithPatchHash === checkedParentPkgs[name].pkgIdWithPatchHash) &&
|
|
505
|
+
(peerDepsAreNotShadowed ||
|
|
506
|
+
// Peer dependencies that appear last we can consider valid.
|
|
507
|
+
// If they do depend on other peer dependencies then they must be those that we will check further.
|
|
508
|
+
checkedParentPkgs[name].depth === maxDepth ||
|
|
509
|
+
ctx.purePkgs.has(pkgIdWithPatchHash));
|
|
510
|
+
}));
|
|
511
|
+
}
|
|
512
|
+
function parentPkgsHaveSingleOccurrence(parentPkgs) {
|
|
513
|
+
return Object.values(parentPkgs).every(({ occurrence }) => occurrence === 0 || occurrence == null);
|
|
514
|
+
}
|
|
515
|
+
// When a package has itself in the subdependencies, so there's a cycle,
|
|
516
|
+
// pnpm will break the cycle, when it first repeats itself.
|
|
517
|
+
// However, when the cycle is broken up, the last repeated package is removed
|
|
518
|
+
// from the dependencies of the parent package.
|
|
519
|
+
// So we need to merge all the children of all the parent packages with same ID as the resolved package.
|
|
520
|
+
// This way we get all the children that were removed, when ending cycles.
|
|
521
|
+
function getPreviouslyResolvedChildren({ parentNodeIds, parentDepPathsChain, dependenciesTree, }, currentDepPath) {
|
|
522
|
+
const allChildren = {};
|
|
523
|
+
if (!currentDepPath || !parentDepPathsChain.includes(currentDepPath))
|
|
524
|
+
return allChildren;
|
|
525
|
+
for (let i = parentNodeIds.length - 1; i >= 0; i--) {
|
|
526
|
+
const parentNode = dependenciesTree.get(parentNodeIds[i]);
|
|
527
|
+
if (parentNode.resolvedPackage.pkgIdWithPatchHash === currentDepPath) {
|
|
528
|
+
if (typeof parentNode.children === 'function') {
|
|
529
|
+
parentNode.children = parentNode.children();
|
|
530
|
+
}
|
|
531
|
+
Object.assign(allChildren, parentNode.children);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return allChildren;
|
|
535
|
+
}
|
|
536
|
+
async function resolvePeersOfChildren(children, parentPkgs, ctx) {
|
|
537
|
+
const allResolvedPeers = new Map();
|
|
538
|
+
const allMissingPeers = new Map();
|
|
539
|
+
// Partition children based on whether they're repeated in parentPkgs.
|
|
540
|
+
// This impacts the efficiency of graph traversal and prevents potential out-of-memory errors.
|
|
541
|
+
// We check repeated first as the peers resolution of those probably are cached already.
|
|
542
|
+
const [repeated, notRepeated] = partition(([alias]) => parentPkgs[alias] != null, Object.entries(children));
|
|
543
|
+
const nodeIds = Array.from(new Set([...repeated, ...notRepeated].map(([, nodeId]) => nodeId)));
|
|
544
|
+
const aliasByNodeId = Object.fromEntries(Object.entries(children).map(([alias, nodeId]) => [nodeId, alias]));
|
|
545
|
+
for (const nodeId of nodeIds) {
|
|
546
|
+
if (!ctx.pathsByNodeIdPromises.has(nodeId)) {
|
|
547
|
+
ctx.pathsByNodeIdPromises.set(nodeId, pDefer());
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// Resolving non-repeated nodes before repeated nodes proved to be slightly faster.
|
|
551
|
+
const calculateDepPaths = [];
|
|
552
|
+
const graph = new Map();
|
|
553
|
+
const finishingList = [];
|
|
554
|
+
const parentDepPaths = {};
|
|
555
|
+
for (const [name, parentPkg] of Object.entries(parentPkgs)) {
|
|
556
|
+
if (!ctx.allPeerDepNames.has(name))
|
|
557
|
+
continue;
|
|
558
|
+
if (parentPkg.nodeId && (typeof parentPkg.nodeId === 'number' || !parentPkg.nodeId.startsWith('link:'))) {
|
|
559
|
+
parentDepPaths[name] = {
|
|
560
|
+
pkgIdWithPatchHash: ctx.dependenciesTree.get(parentPkg.nodeId).resolvedPackage.pkgIdWithPatchHash,
|
|
561
|
+
depth: parentPkg.depth,
|
|
562
|
+
occurrence: parentPkg.occurrence,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
parentDepPaths[name] = { version: parentPkg.version };
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
for (const childNodeId of nodeIds) {
|
|
570
|
+
ctx.parentPkgsOfNode.set(childNodeId, parentDepPaths);
|
|
571
|
+
}
|
|
572
|
+
for (const childNodeId of nodeIds) {
|
|
573
|
+
const currentAlias = aliasByNodeId[childNodeId];
|
|
574
|
+
const { resolvedPeers, missingPeers, calculateDepPath, finishing, } = await resolvePeersOfNode(currentAlias, childNodeId, parentPkgs, ctx); // eslint-disable-line no-await-in-loop
|
|
575
|
+
if (finishing) {
|
|
576
|
+
finishingList.push(finishing);
|
|
577
|
+
}
|
|
578
|
+
if (calculateDepPath) {
|
|
579
|
+
calculateDepPaths.push(calculateDepPath);
|
|
580
|
+
}
|
|
581
|
+
const edges = [];
|
|
582
|
+
for (const [peerName, peerNodeId] of resolvedPeers) {
|
|
583
|
+
allResolvedPeers.set(peerName, peerNodeId);
|
|
584
|
+
edges.push(peerName);
|
|
585
|
+
}
|
|
586
|
+
addEdgesToGraph(currentAlias, edges);
|
|
587
|
+
const node = ctx.dependenciesTree.get(childNodeId);
|
|
588
|
+
// We resolve peer dependencies via both the alias and the real name of the package.
|
|
589
|
+
// That's why we need to detect circular graphs via both the alias and the real name.
|
|
590
|
+
if (currentAlias !== node.resolvedPackage.name) {
|
|
591
|
+
addEdgesToGraph(node.resolvedPackage.name, edges);
|
|
592
|
+
}
|
|
593
|
+
for (const [missingPeer, range] of missingPeers.entries()) {
|
|
594
|
+
allMissingPeers.set(missingPeer, range);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
function addEdgesToGraph(pkgName, edges) {
|
|
598
|
+
const existingEdges = graph.get(pkgName);
|
|
599
|
+
if (existingEdges == null) {
|
|
600
|
+
graph.set(pkgName, edges);
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
existingEdges.push(...edges);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (calculateDepPaths.length) {
|
|
607
|
+
const { cycles } = analyzeGraph(Array.from(graph.entries()));
|
|
608
|
+
finishingList.push(...calculateDepPaths.map((calculateDepPath) => calculateDepPath(cycles)));
|
|
609
|
+
}
|
|
610
|
+
const finishing = Promise.all(finishingList).then(() => { });
|
|
611
|
+
const unknownResolvedPeersOfChildren = new Map();
|
|
612
|
+
for (const [alias, v] of allResolvedPeers) {
|
|
613
|
+
if (!children[alias]) {
|
|
614
|
+
unknownResolvedPeersOfChildren.set(alias, v);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return { resolvedPeers: unknownResolvedPeersOfChildren, missingPeers: allMissingPeers, finishing };
|
|
618
|
+
}
|
|
619
|
+
function _resolvePeers(ctx) {
|
|
620
|
+
const resolvedPeers = new Map();
|
|
621
|
+
const missingPeers = new Map();
|
|
622
|
+
for (const [peerName, { version, optional }] of Object.entries(ctx.resolvedPackage.peerDependencies)) {
|
|
623
|
+
const peerVersionRange = version.replace(/^workspace:/, '');
|
|
624
|
+
const resolved = ctx.parentPkgs[peerName];
|
|
625
|
+
const optionalPeer = optional === true;
|
|
626
|
+
if (!resolved) {
|
|
627
|
+
missingPeers.set(peerName, { range: version, optional: optionalPeer });
|
|
628
|
+
const location = getLocationFromParentNodeIds(ctx);
|
|
629
|
+
if (!ctx.peerDependencyIssues.missing[peerName]) {
|
|
630
|
+
ctx.peerDependencyIssues.missing[peerName] = [];
|
|
631
|
+
}
|
|
632
|
+
ctx.peerDependencyIssues.missing[peerName].push({
|
|
633
|
+
parents: location.parents,
|
|
634
|
+
optional: optionalPeer,
|
|
635
|
+
wantedRange: peerVersionRange,
|
|
636
|
+
});
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if (!semverUtils.satisfiesWithPrereleases(resolved.version, peerVersionRange, true)) {
|
|
640
|
+
const location = getLocationFromParentNodeIds(ctx);
|
|
641
|
+
if (!ctx.peerDependencyIssues.bad[peerName]) {
|
|
642
|
+
ctx.peerDependencyIssues.bad[peerName] = [];
|
|
643
|
+
}
|
|
644
|
+
const peerLocation = resolved.nodeId == null
|
|
645
|
+
? []
|
|
646
|
+
: getLocationFromParentNodeIds({
|
|
647
|
+
dependenciesTree: ctx.dependenciesTree,
|
|
648
|
+
parentNodeIds: resolved.parentNodeIds,
|
|
649
|
+
}).parents;
|
|
650
|
+
ctx.peerDependencyIssues.bad[peerName].push({
|
|
651
|
+
foundVersion: resolved.version,
|
|
652
|
+
resolvedFrom: peerLocation,
|
|
653
|
+
parents: location.parents,
|
|
654
|
+
optional: optionalPeer,
|
|
655
|
+
wantedRange: peerVersionRange,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
if (resolved?.nodeId)
|
|
659
|
+
resolvedPeers.set(peerName, resolved.nodeId);
|
|
660
|
+
}
|
|
661
|
+
return { resolvedPeers, missingPeers };
|
|
662
|
+
}
|
|
663
|
+
function getLocationFromParentNodeIds({ dependenciesTree, parentNodeIds, }) {
|
|
664
|
+
const parents = parentNodeIds
|
|
665
|
+
.map((nid) => pick(['name', 'version'], dependenciesTree.get(nid).resolvedPackage));
|
|
666
|
+
return {
|
|
667
|
+
projectId: '.',
|
|
668
|
+
parents,
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
function toPkgByName(nodes) {
|
|
672
|
+
const pkgsByName = {};
|
|
673
|
+
const _updateParentRefs = updateParentRefs.bind(null, pkgsByName);
|
|
674
|
+
for (const { alias, node, nodeId, parentNodeIds } of nodes) {
|
|
675
|
+
const pkg = {
|
|
676
|
+
alias,
|
|
677
|
+
depth: node.depth,
|
|
678
|
+
nodeId,
|
|
679
|
+
version: node.resolvedPackage.version,
|
|
680
|
+
occurrence: 0,
|
|
681
|
+
parentNodeIds,
|
|
682
|
+
};
|
|
683
|
+
_updateParentRefs(alias, pkg);
|
|
684
|
+
if (alias !== node.resolvedPackage.name) {
|
|
685
|
+
_updateParentRefs(node.resolvedPackage.name, pkg);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
return pkgsByName;
|
|
689
|
+
}
|
|
690
|
+
function updateParentRefs(parentRefs, newAlias, pkg) {
|
|
691
|
+
const existing = parentRefs[newAlias];
|
|
692
|
+
if (existing) {
|
|
693
|
+
const existingHasAlias = existing.alias != null && existing.alias !== newAlias;
|
|
694
|
+
if (!existingHasAlias)
|
|
695
|
+
return;
|
|
696
|
+
const newHasAlias = pkg.alias != null && pkg.alias !== newAlias;
|
|
697
|
+
if (newHasAlias && semver.gte(existing.version, pkg.version))
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
parentRefs[newAlias] = pkg;
|
|
701
|
+
}
|
|
702
|
+
//# sourceMappingURL=resolvePeers.js.map
|