@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,1182 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { matchCatalogResolveResult } from '@pnpm/catalogs.resolver';
|
|
3
|
+
import { deprecationLogger, progressLogger, skippedOptionalDependencyLogger, } from '@pnpm/core-loggers';
|
|
4
|
+
import * as dp from '@pnpm/deps.path';
|
|
5
|
+
import { PnpmError } from '@pnpm/error';
|
|
6
|
+
import { getPreferredVersionsFromLockfileAndManifests } from '@pnpm/lockfile.preferred-versions';
|
|
7
|
+
import { nameVerFromPkgSnapshot, pkgSnapshotToResolution, } from '@pnpm/lockfile.utils';
|
|
8
|
+
import { logger } from '@pnpm/logger';
|
|
9
|
+
import { getPatchInfo } from '@pnpm/patching.config';
|
|
10
|
+
import { convertEnginesRuntimeToDependencies } from '@pnpm/pkg-manifest.utils';
|
|
11
|
+
import { DIRECT_DEP_SELECTOR_WEIGHT, } from '@pnpm/resolving.resolver-base';
|
|
12
|
+
import normalizePath from 'normalize-path';
|
|
13
|
+
import pDefer from 'p-defer';
|
|
14
|
+
import { pathExists } from 'path-exists';
|
|
15
|
+
import { pShare } from 'promise-share';
|
|
16
|
+
import { omit, pickBy, zipWith } from 'ramda';
|
|
17
|
+
import semver from 'semver';
|
|
18
|
+
import { getExactSinglePreferredVersions } from './getExactSinglePreferredVersions.js';
|
|
19
|
+
import { getNonDevWantedDependencies } from './getNonDevWantedDependencies.js';
|
|
20
|
+
import { getHoistableOptionalPeers, hoistPeers } from './hoistPeers.js';
|
|
21
|
+
import { safeIntersect } from './mergePeers.js';
|
|
22
|
+
import { nextNodeId } from './nextNodeId.js';
|
|
23
|
+
import { parentIdsContainSequence } from './parentIdsContainSequence.js';
|
|
24
|
+
import { replaceVersionInBareSpecifier } from './replaceVersionInBareSpecifier.js';
|
|
25
|
+
import { wantedDepIsLocallyAvailable } from './wantedDepIsLocallyAvailable.js';
|
|
26
|
+
const dependencyResolvedLogger = logger('_dependency_resolved');
|
|
27
|
+
const omitDepsFields = omit(['dependencies', 'optionalDependencies', 'peerDependencies', 'peerDependenciesMeta']);
|
|
28
|
+
export function getPkgsInfoFromIds(ids, resolvedPkgsById) {
|
|
29
|
+
return ids
|
|
30
|
+
.slice(1)
|
|
31
|
+
.map((id) => {
|
|
32
|
+
const { name, version } = resolvedPkgsById[id];
|
|
33
|
+
return { id, name, version };
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export async function resolveRootDependencies(ctx, importers) {
|
|
37
|
+
if (ctx.autoInstallPeers) {
|
|
38
|
+
ctx.allPreferredVersions = getPreferredVersionsFromLockfileAndManifests(ctx.wantedLockfile.packages, []);
|
|
39
|
+
}
|
|
40
|
+
else if (ctx.hoistPeers) {
|
|
41
|
+
ctx.allPreferredVersions = {};
|
|
42
|
+
}
|
|
43
|
+
const { pkgAddressesByImportersWithoutPeers, publishedBy, time } = await resolveDependenciesOfImporters(ctx, importers);
|
|
44
|
+
if (!ctx.hoistPeers) {
|
|
45
|
+
return {
|
|
46
|
+
pkgAddressesByImporters: pkgAddressesByImportersWithoutPeers.map(({ pkgAddresses }) => pkgAddresses),
|
|
47
|
+
time,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
let workspaceRootDeps;
|
|
51
|
+
if (ctx.resolvePeersFromWorkspaceRoot) {
|
|
52
|
+
const rootImporterIndex = importers.findIndex(({ options }) => options.parentIds[0] === '.');
|
|
53
|
+
workspaceRootDeps = pkgAddressesByImportersWithoutPeers[rootImporterIndex]?.pkgAddresses ?? [];
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
workspaceRootDeps = [];
|
|
57
|
+
}
|
|
58
|
+
const _hoistPeers = hoistPeers.bind(null, {
|
|
59
|
+
autoInstallPeers: ctx.autoInstallPeers,
|
|
60
|
+
allPreferredVersions: ctx.allPreferredVersions,
|
|
61
|
+
workspaceRootDeps,
|
|
62
|
+
});
|
|
63
|
+
/* eslint-disable no-await-in-loop */
|
|
64
|
+
while (true) {
|
|
65
|
+
const allMissingOptionalPeersByImporters = await Promise.all(pkgAddressesByImportersWithoutPeers.map(async (importerResolutionResult, index) => {
|
|
66
|
+
const { parentPkgAliases, preferredVersions, options } = importers[index];
|
|
67
|
+
const allMissingOptionalPeers = {};
|
|
68
|
+
while (true) {
|
|
69
|
+
for (const pkgAddress of importerResolutionResult.pkgAddresses) {
|
|
70
|
+
parentPkgAliases[pkgAddress.alias] = true;
|
|
71
|
+
}
|
|
72
|
+
const missingOptionalPeers = [];
|
|
73
|
+
const missingRequiredPeers = [];
|
|
74
|
+
for (const [peerName, peerInfo] of Object.entries(importerResolutionResult.missingPeers ?? {})) {
|
|
75
|
+
if (peerInfo.optional) {
|
|
76
|
+
missingOptionalPeers.push([peerName, peerInfo]);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
missingRequiredPeers.push([peerName, peerInfo]);
|
|
80
|
+
parentPkgAliases[peerName] = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (ctx.autoInstallPeers) {
|
|
84
|
+
// All the missing peers should get installed in the root.
|
|
85
|
+
// Otherwise, pending nodes will not work.
|
|
86
|
+
// even those peers should be hoisted that are not autoinstalled
|
|
87
|
+
for (const [resolvedPeerName, resolvedPeerAddress] of Object.entries(importerResolutionResult.resolvedPeers ?? {})) {
|
|
88
|
+
if (!parentPkgAliases[resolvedPeerName]) {
|
|
89
|
+
importerResolutionResult.pkgAddresses.push(resolvedPeerAddress);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const [missingOptionalPeerName, { range: missingOptionalPeerRange }] of missingOptionalPeers) {
|
|
94
|
+
if (!allMissingOptionalPeers[missingOptionalPeerName]) {
|
|
95
|
+
allMissingOptionalPeers[missingOptionalPeerName] = [missingOptionalPeerRange];
|
|
96
|
+
}
|
|
97
|
+
else if (!allMissingOptionalPeers[missingOptionalPeerName].includes(missingOptionalPeerRange)) {
|
|
98
|
+
allMissingOptionalPeers[missingOptionalPeerName].push(missingOptionalPeerRange);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!missingRequiredPeers.length)
|
|
102
|
+
break;
|
|
103
|
+
const dependencies = _hoistPeers(missingRequiredPeers);
|
|
104
|
+
if (!Object.keys(dependencies).length)
|
|
105
|
+
break;
|
|
106
|
+
const wantedDependencies = getNonDevWantedDependencies({ dependencies });
|
|
107
|
+
const resolveDependenciesResult = await resolveDependencies(ctx, preferredVersions, wantedDependencies, {
|
|
108
|
+
...options,
|
|
109
|
+
parentPkgAliases,
|
|
110
|
+
publishedBy,
|
|
111
|
+
updateToLatest: false,
|
|
112
|
+
});
|
|
113
|
+
importerResolutionResult.pkgAddresses.push(...resolveDependenciesResult.pkgAddresses);
|
|
114
|
+
Object.assign(importerResolutionResult, filterMissingPeers(await resolveDependenciesResult.resolvingPeers, parentPkgAliases));
|
|
115
|
+
}
|
|
116
|
+
return allMissingOptionalPeers;
|
|
117
|
+
}));
|
|
118
|
+
let hasNewMissingPeers = false;
|
|
119
|
+
await Promise.all(allMissingOptionalPeersByImporters.map(async (allMissingOptionalPeers, index) => {
|
|
120
|
+
const { preferredVersions, parentPkgAliases, options } = importers[index];
|
|
121
|
+
if (Object.keys(allMissingOptionalPeers).length && ctx.allPreferredVersions) {
|
|
122
|
+
const optionalDependencies = getHoistableOptionalPeers(allMissingOptionalPeers, ctx.allPreferredVersions);
|
|
123
|
+
if (Object.keys(optionalDependencies).length) {
|
|
124
|
+
hasNewMissingPeers = true;
|
|
125
|
+
const wantedDependencies = getNonDevWantedDependencies({ optionalDependencies });
|
|
126
|
+
const resolveDependenciesResult = await resolveDependencies(ctx, preferredVersions, wantedDependencies, {
|
|
127
|
+
...options,
|
|
128
|
+
parentPkgAliases,
|
|
129
|
+
publishedBy,
|
|
130
|
+
updateToLatest: false,
|
|
131
|
+
});
|
|
132
|
+
pkgAddressesByImportersWithoutPeers[index].pkgAddresses.push(...resolveDependenciesResult.pkgAddresses);
|
|
133
|
+
Object.assign(pkgAddressesByImportersWithoutPeers[index], filterMissingPeers(await resolveDependenciesResult.resolvingPeers, parentPkgAliases));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}));
|
|
137
|
+
if (!hasNewMissingPeers)
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
/* eslint-enable no-await-in-loop */
|
|
141
|
+
return {
|
|
142
|
+
pkgAddressesByImporters: pkgAddressesByImportersWithoutPeers.map(({ pkgAddresses }) => pkgAddresses),
|
|
143
|
+
time,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async function resolveDependenciesOfImporters(ctx, importers) {
|
|
147
|
+
const pickLowestVersion = ctx.resolutionMode === 'time-based' || ctx.resolutionMode === 'lowest-direct';
|
|
148
|
+
const resolveResults = await Promise.all(importers.map(async (importer) => {
|
|
149
|
+
const extendedWantedDeps = getDepsToResolve(importer.wantedDependencies, ctx.wantedLockfile, {
|
|
150
|
+
preferredDependencies: importer.options.preferredDependencies,
|
|
151
|
+
prefix: importer.options.prefix,
|
|
152
|
+
proceed: importer.options.proceed || ctx.forceFullResolution,
|
|
153
|
+
registries: ctx.registries,
|
|
154
|
+
resolvedDependencies: importer.options.resolvedDependencies,
|
|
155
|
+
});
|
|
156
|
+
const postponedResolutionsQueue = [];
|
|
157
|
+
const postponedPeersResolutionQueue = [];
|
|
158
|
+
const pkgAddresses = [];
|
|
159
|
+
const resolveDependenciesOfImporterWantedDep = resolveDependenciesOfImporterDependency.bind(null, {
|
|
160
|
+
ctx,
|
|
161
|
+
importer,
|
|
162
|
+
pickLowestVersion,
|
|
163
|
+
});
|
|
164
|
+
const resolvedDependenciesOfImporter = await Promise.all(extendedWantedDeps.map(resolveDependenciesOfImporterWantedDep));
|
|
165
|
+
for (const { resolveDependencyResult, postponedPeersResolution, postponedResolution } of resolvedDependenciesOfImporter) {
|
|
166
|
+
if (resolveDependencyResult) {
|
|
167
|
+
pkgAddresses.push(resolveDependencyResult);
|
|
168
|
+
}
|
|
169
|
+
if (postponedResolution) {
|
|
170
|
+
postponedResolutionsQueue.push(postponedResolution);
|
|
171
|
+
}
|
|
172
|
+
if (postponedPeersResolution) {
|
|
173
|
+
postponedPeersResolutionQueue.push(postponedPeersResolution);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return { pkgAddresses, postponedResolutionsQueue, postponedPeersResolutionQueue };
|
|
177
|
+
}));
|
|
178
|
+
let publishedBy;
|
|
179
|
+
let time;
|
|
180
|
+
if (ctx.resolutionMode === 'time-based') {
|
|
181
|
+
const result = getPublishedByDate(resolveResults.map(({ pkgAddresses }) => pkgAddresses).flat(), ctx.wantedLockfile.time);
|
|
182
|
+
if (result.publishedBy) {
|
|
183
|
+
publishedBy = new Date(result.publishedBy.getTime() + 60 * 60 * 1000); // adding 1 hour delta
|
|
184
|
+
time = result.newTime;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (ctx.maximumPublishedBy && (publishedBy == null || publishedBy > ctx.maximumPublishedBy)) {
|
|
188
|
+
publishedBy = ctx.maximumPublishedBy;
|
|
189
|
+
}
|
|
190
|
+
const pkgAddressesByImportersWithoutPeers = await Promise.all(zipWith(async (importer, { pkgAddresses, postponedResolutionsQueue, postponedPeersResolutionQueue }) => {
|
|
191
|
+
const newPreferredVersions = Object.create(importer.preferredVersions);
|
|
192
|
+
const currentParentPkgAliases = {};
|
|
193
|
+
for (const pkgAddress of pkgAddresses) {
|
|
194
|
+
if (currentParentPkgAliases[pkgAddress.alias] !== true) {
|
|
195
|
+
currentParentPkgAliases[pkgAddress.alias] = pkgAddress;
|
|
196
|
+
}
|
|
197
|
+
if (pkgAddress.updated) {
|
|
198
|
+
ctx.updatedSet.add(pkgAddress.alias);
|
|
199
|
+
}
|
|
200
|
+
const resolvedPackage = ctx.resolvedPkgsById[pkgAddress.pkgId];
|
|
201
|
+
if (!resolvedPackage)
|
|
202
|
+
continue; // This will happen only with linked dependencies
|
|
203
|
+
if (!Object.hasOwn(newPreferredVersions, resolvedPackage.name)) {
|
|
204
|
+
newPreferredVersions[resolvedPackage.name] = { ...importer.preferredVersions[resolvedPackage.name] };
|
|
205
|
+
}
|
|
206
|
+
if (!newPreferredVersions[resolvedPackage.name][resolvedPackage.version]) {
|
|
207
|
+
newPreferredVersions[resolvedPackage.name][resolvedPackage.version] = {
|
|
208
|
+
selectorType: 'version',
|
|
209
|
+
weight: DIRECT_DEP_SELECTOR_WEIGHT,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const newParentPkgAliases = { ...importer.parentPkgAliases, ...currentParentPkgAliases };
|
|
214
|
+
const postponedResolutionOpts = {
|
|
215
|
+
preferredVersions: newPreferredVersions,
|
|
216
|
+
parentPkgAliases: newParentPkgAliases,
|
|
217
|
+
publishedBy,
|
|
218
|
+
};
|
|
219
|
+
const childrenResults = await Promise.all(postponedResolutionsQueue.map((postponedResolution) => postponedResolution(postponedResolutionOpts)));
|
|
220
|
+
if (!ctx.hoistPeers) {
|
|
221
|
+
return {
|
|
222
|
+
missingPeers: {},
|
|
223
|
+
pkgAddresses,
|
|
224
|
+
resolvedPeers: {},
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const postponedPeersResolution = await Promise.all(postponedPeersResolutionQueue.map((postponedMissingPeers) => postponedMissingPeers(postponedResolutionOpts.parentPkgAliases)));
|
|
228
|
+
const resolvedPeers = [...childrenResults, ...postponedPeersResolution].reduce((acc, { resolvedPeers }) => Object.assign(acc, resolvedPeers), {});
|
|
229
|
+
const allMissingPeers = mergePkgsDeps([
|
|
230
|
+
...filterMissingPeersFromPkgAddresses(pkgAddresses, currentParentPkgAliases, resolvedPeers),
|
|
231
|
+
...childrenResults,
|
|
232
|
+
...postponedPeersResolution,
|
|
233
|
+
].map(({ missingPeers }) => missingPeers).filter(Boolean), {
|
|
234
|
+
autoInstallPeersFromHighestMatch: ctx.autoInstallPeersFromHighestMatch,
|
|
235
|
+
});
|
|
236
|
+
return {
|
|
237
|
+
missingPeers: allMissingPeers,
|
|
238
|
+
pkgAddresses,
|
|
239
|
+
resolvedPeers,
|
|
240
|
+
};
|
|
241
|
+
}, importers, resolveResults));
|
|
242
|
+
return {
|
|
243
|
+
pkgAddressesByImportersWithoutPeers,
|
|
244
|
+
publishedBy,
|
|
245
|
+
time,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
async function resolveDependenciesOfImporterDependency({ ctx, importer, pickLowestVersion }, extendedWantedDep) {
|
|
249
|
+
// The catalog protocol is only usable in importers (i.e. packages in the
|
|
250
|
+
// workspace. Replacing catalog protocol while resolving importers here before
|
|
251
|
+
// resolving dependencies of packages outside of the workspace/monorepo.
|
|
252
|
+
const catalogLookup = matchCatalogResolveResult(ctx.catalogResolver(extendedWantedDep.wantedDependency), {
|
|
253
|
+
found: (result) => result.resolution,
|
|
254
|
+
unused: () => undefined,
|
|
255
|
+
misconfiguration: (result) => {
|
|
256
|
+
throw result.error;
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
const originalBareSpecifier = extendedWantedDep.wantedDependency.bareSpecifier;
|
|
260
|
+
// The lockfile from a previous installation may have already resolved this
|
|
261
|
+
// cataloged dependency. Reuse the exact version in the lockfile catalog
|
|
262
|
+
// snapshot to ensure all projects using the same cataloged dependency get the
|
|
263
|
+
// same version.
|
|
264
|
+
if (catalogLookup != null) {
|
|
265
|
+
extendedWantedDep.wantedDependency.bareSpecifier = catalogLookup.specifier;
|
|
266
|
+
extendedWantedDep.preferredVersion = getCatalogExistingVersionFromSnapshot(catalogLookup, ctx.wantedLockfile, extendedWantedDep.wantedDependency);
|
|
267
|
+
}
|
|
268
|
+
const result = await resolveDependenciesOfDependency(ctx, importer.preferredVersions, {
|
|
269
|
+
...importer.options,
|
|
270
|
+
parentPkgAliases: importer.parentPkgAliases,
|
|
271
|
+
pickLowestVersion: pickLowestVersion && !importer.updatePackageManifest,
|
|
272
|
+
pinnedVersion: importer.pinnedVersion,
|
|
273
|
+
publishedBy: ctx.maximumPublishedBy,
|
|
274
|
+
}, extendedWantedDep);
|
|
275
|
+
// If the catalog protocol was used, store metadata about the catalog
|
|
276
|
+
// lookup to use in the lockfile.
|
|
277
|
+
if (result.resolveDependencyResult != null && catalogLookup != null) {
|
|
278
|
+
result.resolveDependencyResult.catalogLookup = {
|
|
279
|
+
...catalogLookup,
|
|
280
|
+
userSpecifiedBareSpecifier: originalBareSpecifier,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
function filterMissingPeersFromPkgAddresses(pkgAddresses, currentParentPkgAliases, resolvedPeers) {
|
|
286
|
+
return pkgAddresses.map((pkgAddress) => ({
|
|
287
|
+
...pkgAddress,
|
|
288
|
+
missingPeers: pickBy((_, peerName) => {
|
|
289
|
+
if (!currentParentPkgAliases[peerName])
|
|
290
|
+
return true;
|
|
291
|
+
if (currentParentPkgAliases[peerName] !== true) {
|
|
292
|
+
resolvedPeers[peerName] = currentParentPkgAliases[peerName];
|
|
293
|
+
}
|
|
294
|
+
return false;
|
|
295
|
+
}, pkgAddress.missingPeers ?? {}),
|
|
296
|
+
}));
|
|
297
|
+
}
|
|
298
|
+
function getPublishedByDate(pkgAddresses, timeFromLockfile = {}) {
|
|
299
|
+
const newTime = {};
|
|
300
|
+
for (const pkgAddress of pkgAddresses) {
|
|
301
|
+
if (pkgAddress.publishedAt) {
|
|
302
|
+
newTime[pkgAddress.pkgId] = pkgAddress.publishedAt;
|
|
303
|
+
}
|
|
304
|
+
else if (timeFromLockfile[pkgAddress.pkgId]) {
|
|
305
|
+
newTime[pkgAddress.pkgId] = timeFromLockfile[pkgAddress.pkgId];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const sortedDates = Object.values(newTime)
|
|
309
|
+
.map((publishedAt) => new Date(publishedAt))
|
|
310
|
+
.sort((d1, d2) => d1.getTime() - d2.getTime());
|
|
311
|
+
return { publishedBy: sortedDates[sortedDates.length - 1], newTime };
|
|
312
|
+
}
|
|
313
|
+
export async function resolveDependencies(ctx, preferredVersions, wantedDependencies, options) {
|
|
314
|
+
const extendedWantedDeps = getDepsToResolve(wantedDependencies, ctx.wantedLockfile, {
|
|
315
|
+
preferredDependencies: options.preferredDependencies,
|
|
316
|
+
prefix: options.prefix,
|
|
317
|
+
proceed: options.proceed || ctx.forceFullResolution,
|
|
318
|
+
registries: ctx.registries,
|
|
319
|
+
resolvedDependencies: options.resolvedDependencies,
|
|
320
|
+
});
|
|
321
|
+
const postponedResolutionsQueue = [];
|
|
322
|
+
const postponedPeersResolutionQueue = [];
|
|
323
|
+
const pkgAddresses = [];
|
|
324
|
+
await Promise.all(extendedWantedDeps.map(async (extendedWantedDep) => {
|
|
325
|
+
const { resolveDependencyResult, postponedResolution, postponedPeersResolution, } = await resolveDependenciesOfDependency(ctx, preferredVersions, options, extendedWantedDep);
|
|
326
|
+
if (resolveDependencyResult) {
|
|
327
|
+
pkgAddresses.push(resolveDependencyResult);
|
|
328
|
+
}
|
|
329
|
+
if (postponedResolution) {
|
|
330
|
+
postponedResolutionsQueue.push(postponedResolution);
|
|
331
|
+
}
|
|
332
|
+
if (postponedPeersResolution) {
|
|
333
|
+
postponedPeersResolutionQueue.push(postponedPeersResolution);
|
|
334
|
+
}
|
|
335
|
+
}));
|
|
336
|
+
const newPreferredVersions = Object.create(preferredVersions);
|
|
337
|
+
const currentParentPkgAliases = {};
|
|
338
|
+
for (const pkgAddress of pkgAddresses) {
|
|
339
|
+
if (currentParentPkgAliases[pkgAddress.alias] !== true) {
|
|
340
|
+
currentParentPkgAliases[pkgAddress.alias] = pkgAddress;
|
|
341
|
+
}
|
|
342
|
+
if (pkgAddress.updated) {
|
|
343
|
+
ctx.updatedSet.add(pkgAddress.alias);
|
|
344
|
+
}
|
|
345
|
+
const resolvedPackage = ctx.resolvedPkgsById[pkgAddress.pkgId];
|
|
346
|
+
if (!resolvedPackage)
|
|
347
|
+
continue; // This will happen only with linked dependencies
|
|
348
|
+
if (!Object.hasOwn(newPreferredVersions, resolvedPackage.name)) {
|
|
349
|
+
newPreferredVersions[resolvedPackage.name] = { ...preferredVersions[resolvedPackage.name] };
|
|
350
|
+
}
|
|
351
|
+
if (!newPreferredVersions[resolvedPackage.name][resolvedPackage.version]) {
|
|
352
|
+
newPreferredVersions[resolvedPackage.name][resolvedPackage.version] = 'version';
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const newParentPkgAliases = {
|
|
356
|
+
...options.parentPkgAliases,
|
|
357
|
+
...currentParentPkgAliases,
|
|
358
|
+
};
|
|
359
|
+
const postponedResolutionOpts = {
|
|
360
|
+
preferredVersions: newPreferredVersions,
|
|
361
|
+
parentPkgAliases: newParentPkgAliases,
|
|
362
|
+
publishedBy: options.publishedBy,
|
|
363
|
+
};
|
|
364
|
+
const childrenResults = await Promise.all(postponedResolutionsQueue.map((postponedResolution) => postponedResolution(postponedResolutionOpts)));
|
|
365
|
+
if (!ctx.hoistPeers) {
|
|
366
|
+
return {
|
|
367
|
+
resolvingPeers: Promise.resolve({
|
|
368
|
+
missingPeers: {},
|
|
369
|
+
resolvedPeers: {},
|
|
370
|
+
}),
|
|
371
|
+
pkgAddresses,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
pkgAddresses,
|
|
376
|
+
resolvingPeers: startResolvingPeers({
|
|
377
|
+
childrenResults,
|
|
378
|
+
pkgAddresses,
|
|
379
|
+
parentPkgAliases: options.parentPkgAliases,
|
|
380
|
+
currentParentPkgAliases,
|
|
381
|
+
postponedPeersResolutionQueue,
|
|
382
|
+
autoInstallPeersFromHighestMatch: ctx.autoInstallPeersFromHighestMatch,
|
|
383
|
+
}),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
async function startResolvingPeers({ childrenResults, currentParentPkgAliases, parentPkgAliases, pkgAddresses, postponedPeersResolutionQueue, autoInstallPeersFromHighestMatch, }) {
|
|
387
|
+
const results = await Promise.all(postponedPeersResolutionQueue.map((postponedPeersResolution) => postponedPeersResolution(parentPkgAliases)));
|
|
388
|
+
const resolvedPeers = [...childrenResults, ...results].reduce((acc, { resolvedPeers }) => Object.assign(acc, resolvedPeers), {});
|
|
389
|
+
const allMissingPeers = mergePkgsDeps([
|
|
390
|
+
...filterMissingPeersFromPkgAddresses(pkgAddresses, currentParentPkgAliases, resolvedPeers),
|
|
391
|
+
...childrenResults,
|
|
392
|
+
...results,
|
|
393
|
+
].map(({ missingPeers }) => missingPeers).filter(Boolean), { autoInstallPeersFromHighestMatch });
|
|
394
|
+
return {
|
|
395
|
+
missingPeers: allMissingPeers,
|
|
396
|
+
resolvedPeers,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function mergePkgsDeps(pkgsDeps, opts) {
|
|
400
|
+
const groupedRanges = {};
|
|
401
|
+
for (const deps of pkgsDeps) {
|
|
402
|
+
for (const [name, { range, optional }] of Object.entries(deps)) {
|
|
403
|
+
if (!groupedRanges[name]) {
|
|
404
|
+
groupedRanges[name] = { ranges: [], optional };
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
groupedRanges[name].optional &&= optional;
|
|
408
|
+
}
|
|
409
|
+
groupedRanges[name].ranges.push(range);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const mergedPkgDeps = {};
|
|
413
|
+
for (const [name, { ranges, optional }] of Object.entries(groupedRanges)) {
|
|
414
|
+
const intersection = safeIntersect(ranges);
|
|
415
|
+
if (intersection) {
|
|
416
|
+
mergedPkgDeps[name] = { range: intersection, optional };
|
|
417
|
+
}
|
|
418
|
+
else if (opts.autoInstallPeersFromHighestMatch) {
|
|
419
|
+
mergedPkgDeps[name] = { range: ranges.join(' || '), optional };
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return mergedPkgDeps;
|
|
423
|
+
}
|
|
424
|
+
async function resolveDependenciesOfDependency(ctx, preferredVersions, options, extendedWantedDep) {
|
|
425
|
+
const updateDepth = typeof extendedWantedDep.wantedDependency.updateDepth === 'number'
|
|
426
|
+
? extendedWantedDep.wantedDependency.updateDepth
|
|
427
|
+
: options.updateDepth;
|
|
428
|
+
const updateShouldContinue = options.currentDepth <= updateDepth;
|
|
429
|
+
const updateRequested = updateShouldContinue &&
|
|
430
|
+
((options.updateMatching == null) ||
|
|
431
|
+
(extendedWantedDep.infoFromLockfile?.name != null &&
|
|
432
|
+
options.updateMatching(extendedWantedDep.infoFromLockfile.name, extendedWantedDep.infoFromLockfile.version)));
|
|
433
|
+
const update = updateRequested ||
|
|
434
|
+
((extendedWantedDep.infoFromLockfile?.dependencyLockfile) == null) || Boolean((ctx.workspacePackages != null) &&
|
|
435
|
+
ctx.linkWorkspacePackagesDepth !== -1 &&
|
|
436
|
+
wantedDepIsLocallyAvailable(ctx.workspacePackages, extendedWantedDep.wantedDependency, { defaultTag: ctx.defaultTag, registry: ctx.registries.default })) || ctx.updatedSet.has(extendedWantedDep.infoFromLockfile.name);
|
|
437
|
+
const resolveDependencyOpts = {
|
|
438
|
+
currentDepth: options.currentDepth,
|
|
439
|
+
parentPkg: options.parentPkg,
|
|
440
|
+
parentPkgAliases: options.parentPkgAliases,
|
|
441
|
+
preferredVersions,
|
|
442
|
+
currentPkg: extendedWantedDep.infoFromLockfile ?? undefined,
|
|
443
|
+
preferredVersion: extendedWantedDep.preferredVersion,
|
|
444
|
+
pickLowestVersion: options.pickLowestVersion,
|
|
445
|
+
prefix: options.prefix,
|
|
446
|
+
proceed: extendedWantedDep.proceed || updateShouldContinue || ctx.updatedSet.size > 0,
|
|
447
|
+
publishedBy: options.publishedBy,
|
|
448
|
+
update: update ? options.updateToLatest ? 'latest' : 'compatible' : false,
|
|
449
|
+
updateDepth,
|
|
450
|
+
updateRequested,
|
|
451
|
+
supportedArchitectures: options.supportedArchitectures,
|
|
452
|
+
parentIds: options.parentIds,
|
|
453
|
+
pinnedVersion: options.pinnedVersion,
|
|
454
|
+
};
|
|
455
|
+
// The catalog protocol is normally replaced when resolving the dependencies
|
|
456
|
+
// of importers. However, when a workspace package is "injected", it becomes a
|
|
457
|
+
// "file:" dependency and is no longer an "importer" from the perspective of
|
|
458
|
+
// pnpm.
|
|
459
|
+
//
|
|
460
|
+
// To allow the catalog protocol to still be used for injected workspace
|
|
461
|
+
// packages, it's necessary to check if the parent package was an injected
|
|
462
|
+
// workspace package and replace the catalog: protocol for the current package.
|
|
463
|
+
const isInjectedWorkspacePackage = options.parentPkg.resolvedVia === 'workspace' &&
|
|
464
|
+
options.parentPkg.pkgId.startsWith('file:');
|
|
465
|
+
if (isInjectedWorkspacePackage) {
|
|
466
|
+
const catalogLookup = matchCatalogResolveResult(ctx.catalogResolver(extendedWantedDep.wantedDependency), {
|
|
467
|
+
found: (result) => result.resolution,
|
|
468
|
+
unused: () => undefined,
|
|
469
|
+
misconfiguration: (result) => {
|
|
470
|
+
throw result.error;
|
|
471
|
+
},
|
|
472
|
+
});
|
|
473
|
+
// The standard process for replacing the catalog protocol when resolving
|
|
474
|
+
// the dependencies of "importers" stores the catalog lookup in the
|
|
475
|
+
// dependency resolution result. This allows the catalogs snapshot section
|
|
476
|
+
// of the wanted lockfile to be kept up to date.
|
|
477
|
+
//
|
|
478
|
+
// We can do a simple replacement here instead and discard the catalog
|
|
479
|
+
// lookup object. It's not necessary to store this information for injected
|
|
480
|
+
// workspace packages. The injected workspace package will still be resolved
|
|
481
|
+
// as an importer separately, and we can rely on that process keeping the
|
|
482
|
+
// importers lockfile catalog snapshots up to date.
|
|
483
|
+
if (catalogLookup != null) {
|
|
484
|
+
extendedWantedDep.wantedDependency.bareSpecifier = catalogLookup.specifier;
|
|
485
|
+
extendedWantedDep.preferredVersion = getCatalogExistingVersionFromSnapshot(catalogLookup, ctx.wantedLockfile, extendedWantedDep.wantedDependency);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const resolveDependencyResult = await resolveDependency(extendedWantedDep.wantedDependency, ctx, resolveDependencyOpts);
|
|
489
|
+
if (resolveDependencyResult == null)
|
|
490
|
+
return { resolveDependencyResult: null };
|
|
491
|
+
if (resolveDependencyResult.isLinkedDependency) {
|
|
492
|
+
ctx.dependenciesTree.set(createNodeIdForLinkedLocalPkg(ctx.lockfileDir, resolveDependencyResult.resolution.directory), {
|
|
493
|
+
children: {},
|
|
494
|
+
depth: -1,
|
|
495
|
+
installable: true,
|
|
496
|
+
resolvedPackage: {
|
|
497
|
+
name: resolveDependencyResult.name,
|
|
498
|
+
version: resolveDependencyResult.version,
|
|
499
|
+
},
|
|
500
|
+
});
|
|
501
|
+
return { resolveDependencyResult };
|
|
502
|
+
}
|
|
503
|
+
if (!resolveDependencyResult.isNew) {
|
|
504
|
+
return {
|
|
505
|
+
resolveDependencyResult,
|
|
506
|
+
postponedPeersResolution: resolveDependencyResult.missingPeersOfChildren != null
|
|
507
|
+
? async (parentPkgAliases) => {
|
|
508
|
+
const missingPeers = await resolveDependencyResult.missingPeersOfChildren.get();
|
|
509
|
+
return filterMissingPeers({ missingPeers, resolvedPeers: {} }, parentPkgAliases);
|
|
510
|
+
}
|
|
511
|
+
: undefined,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
const postponedResolution = resolveChildren.bind(null, ctx, {
|
|
515
|
+
parentPkg: resolveDependencyResult,
|
|
516
|
+
dependencyLockfile: extendedWantedDep.infoFromLockfile?.dependencyLockfile,
|
|
517
|
+
parentDepth: options.currentDepth,
|
|
518
|
+
parentIds: [...options.parentIds, resolveDependencyResult.pkgId],
|
|
519
|
+
updateDepth,
|
|
520
|
+
prefix: options.prefix,
|
|
521
|
+
updateMatching: options.updateMatching,
|
|
522
|
+
supportedArchitectures: options.supportedArchitectures,
|
|
523
|
+
updateToLatest: options.updateToLatest,
|
|
524
|
+
});
|
|
525
|
+
return {
|
|
526
|
+
resolveDependencyResult,
|
|
527
|
+
postponedResolution: async (postponedResolutionOpts) => {
|
|
528
|
+
const { missingPeers, resolvedPeers } = await postponedResolution(postponedResolutionOpts);
|
|
529
|
+
if (resolveDependencyResult.missingPeersOfChildren) {
|
|
530
|
+
resolveDependencyResult.missingPeersOfChildren.resolved = true;
|
|
531
|
+
resolveDependencyResult.missingPeersOfChildren.resolve(missingPeers);
|
|
532
|
+
}
|
|
533
|
+
return filterMissingPeers({ missingPeers, resolvedPeers }, postponedResolutionOpts.parentPkgAliases);
|
|
534
|
+
},
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
export function createNodeIdForLinkedLocalPkg(lockfileDir, pkgDir) {
|
|
538
|
+
return `link:${normalizePath(path.relative(lockfileDir, pkgDir))}`;
|
|
539
|
+
}
|
|
540
|
+
function filterMissingPeers({ missingPeers, resolvedPeers }, parentPkgAliases) {
|
|
541
|
+
const newMissing = {};
|
|
542
|
+
for (const [peerName, peerVersion] of Object.entries(missingPeers)) {
|
|
543
|
+
if (parentPkgAliases[peerName]) {
|
|
544
|
+
if (parentPkgAliases[peerName] !== true) {
|
|
545
|
+
resolvedPeers[peerName] = parentPkgAliases[peerName];
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
newMissing[peerName] = peerVersion;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return {
|
|
553
|
+
resolvedPeers,
|
|
554
|
+
missingPeers: newMissing,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
async function resolveChildren(ctx, { parentPkg, parentIds, dependencyLockfile, parentDepth, updateDepth, updateMatching, prefix, supportedArchitectures, }, { parentPkgAliases, preferredVersions, publishedBy, }) {
|
|
558
|
+
const currentResolvedDependencies = (dependencyLockfile != null)
|
|
559
|
+
? {
|
|
560
|
+
...dependencyLockfile.dependencies,
|
|
561
|
+
...dependencyLockfile.optionalDependencies,
|
|
562
|
+
}
|
|
563
|
+
: undefined;
|
|
564
|
+
const resolvedDependencies = parentPkg.updated
|
|
565
|
+
? undefined
|
|
566
|
+
: currentResolvedDependencies;
|
|
567
|
+
const parentDependsOnPeer = Boolean(Object.keys(dependencyLockfile?.peerDependencies ??
|
|
568
|
+
parentPkg.pkg.peerDependencies ??
|
|
569
|
+
{}).length);
|
|
570
|
+
const wantedDependencies = getNonDevWantedDependencies(parentPkg.pkg);
|
|
571
|
+
const { pkgAddresses, resolvingPeers, } = await resolveDependencies(ctx, preferredVersions, wantedDependencies, {
|
|
572
|
+
currentDepth: parentDepth + 1,
|
|
573
|
+
parentPkg,
|
|
574
|
+
parentPkgAliases,
|
|
575
|
+
preferredDependencies: currentResolvedDependencies,
|
|
576
|
+
prefix,
|
|
577
|
+
// If the package is not linked, we should also gather information about its dependencies.
|
|
578
|
+
// After linking the package we'll need to symlink its dependencies.
|
|
579
|
+
proceed: !parentPkg.depIsLinked || parentDependsOnPeer,
|
|
580
|
+
publishedBy,
|
|
581
|
+
resolvedDependencies,
|
|
582
|
+
updateDepth,
|
|
583
|
+
updateMatching,
|
|
584
|
+
supportedArchitectures,
|
|
585
|
+
parentIds,
|
|
586
|
+
});
|
|
587
|
+
ctx.childrenByParentId[parentPkg.pkgId] = pkgAddresses.map((child) => ({
|
|
588
|
+
alias: child.alias,
|
|
589
|
+
id: child.pkgId,
|
|
590
|
+
}));
|
|
591
|
+
ctx.dependenciesTree.set(parentPkg.nodeId, {
|
|
592
|
+
children: pkgAddresses.reduce((chn, child) => {
|
|
593
|
+
chn[child.alias] = child.nodeId ?? child.pkgId;
|
|
594
|
+
return chn;
|
|
595
|
+
}, {}),
|
|
596
|
+
depth: parentDepth,
|
|
597
|
+
installable: parentPkg.installable,
|
|
598
|
+
resolvedPackage: ctx.resolvedPkgsById[parentPkg.pkgId],
|
|
599
|
+
});
|
|
600
|
+
return resolvingPeers;
|
|
601
|
+
}
|
|
602
|
+
function getDepsToResolve(wantedDependencies, wantedLockfile, options) {
|
|
603
|
+
const resolvedDependencies = options.resolvedDependencies ?? {};
|
|
604
|
+
const preferredDependencies = options.preferredDependencies ?? {};
|
|
605
|
+
const extendedWantedDeps = [];
|
|
606
|
+
// The only reason we resolve children in case the package depends on peers
|
|
607
|
+
// is to get information about the existing dependencies, so that they can
|
|
608
|
+
// be merged with the resolved peers.
|
|
609
|
+
let proceedAll = options.proceed;
|
|
610
|
+
const satisfiesWanted2Args = referenceSatisfiesWantedSpec.bind(null, {
|
|
611
|
+
lockfile: wantedLockfile,
|
|
612
|
+
prefix: options.prefix,
|
|
613
|
+
});
|
|
614
|
+
for (const wantedDependency of wantedDependencies) {
|
|
615
|
+
let reference = undefined;
|
|
616
|
+
let proceed = proceedAll;
|
|
617
|
+
if (wantedDependency.alias) {
|
|
618
|
+
const satisfiesWanted = satisfiesWanted2Args.bind(null, wantedDependency);
|
|
619
|
+
if (resolvedDependencies[wantedDependency.alias] &&
|
|
620
|
+
(satisfiesWanted(resolvedDependencies[wantedDependency.alias]) || resolvedDependencies[wantedDependency.alias].startsWith('file:'))) {
|
|
621
|
+
reference = resolvedDependencies[wantedDependency.alias];
|
|
622
|
+
}
|
|
623
|
+
else if (
|
|
624
|
+
// If dependencies that were used by the previous version of the package
|
|
625
|
+
// satisfy the newer version's requirements, then pnpm tries to keep
|
|
626
|
+
// the previous dependency.
|
|
627
|
+
// So for example, if foo@1.0.0 had bar@1.0.0 as a dependency
|
|
628
|
+
// and foo was updated to 1.1.0 which depends on bar ^1.0.0
|
|
629
|
+
// then bar@1.0.0 can be reused for foo@1.1.0
|
|
630
|
+
semver.validRange(wantedDependency.bareSpecifier) !== null &&
|
|
631
|
+
preferredDependencies[wantedDependency.alias] &&
|
|
632
|
+
satisfiesWanted(preferredDependencies[wantedDependency.alias])) {
|
|
633
|
+
proceed = true;
|
|
634
|
+
reference = preferredDependencies[wantedDependency.alias];
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
const infoFromLockfile = getInfoFromLockfile(wantedLockfile, options.registries, reference, wantedDependency.alias);
|
|
638
|
+
if (!proceedAll &&
|
|
639
|
+
((infoFromLockfile == null) ||
|
|
640
|
+
infoFromLockfile.dependencyLockfile != null && (infoFromLockfile.dependencyLockfile.peerDependencies != null ||
|
|
641
|
+
infoFromLockfile.dependencyLockfile.transitivePeerDependencies?.length))) {
|
|
642
|
+
proceed = true;
|
|
643
|
+
proceedAll = true;
|
|
644
|
+
for (const extendedWantedDep of extendedWantedDeps) {
|
|
645
|
+
if (!extendedWantedDep.proceed) {
|
|
646
|
+
extendedWantedDep.proceed = true;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
extendedWantedDeps.push({
|
|
651
|
+
infoFromLockfile,
|
|
652
|
+
proceed,
|
|
653
|
+
wantedDependency,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
return extendedWantedDeps;
|
|
657
|
+
}
|
|
658
|
+
function referenceSatisfiesWantedSpec(opts, wantedDep, preferredRef) {
|
|
659
|
+
const depPath = dp.refToRelative(preferredRef, wantedDep.alias);
|
|
660
|
+
if (depPath === null)
|
|
661
|
+
return false;
|
|
662
|
+
const pkgSnapshot = opts.lockfile.packages?.[depPath];
|
|
663
|
+
if (pkgSnapshot == null) {
|
|
664
|
+
logger.warn({
|
|
665
|
+
message: `Could not find preferred package ${depPath} in lockfile`,
|
|
666
|
+
prefix: opts.prefix,
|
|
667
|
+
});
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
const { version } = nameVerFromPkgSnapshot(depPath, pkgSnapshot);
|
|
671
|
+
if (!semver.validRange(wantedDep.bareSpecifier) && Object.values(opts.lockfile.importers).filter(importer => importer.specifiers[wantedDep.alias] === wantedDep.bareSpecifier).length) {
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
return semver.satisfies(version, wantedDep.bareSpecifier, true);
|
|
675
|
+
}
|
|
676
|
+
function getInfoFromLockfile(lockfile, registries, reference, alias) {
|
|
677
|
+
if (!reference || !alias) {
|
|
678
|
+
return undefined;
|
|
679
|
+
}
|
|
680
|
+
const depPath = dp.refToRelative(reference, alias);
|
|
681
|
+
if (!depPath) {
|
|
682
|
+
return undefined;
|
|
683
|
+
}
|
|
684
|
+
let dependencyLockfile = lockfile.packages?.[depPath];
|
|
685
|
+
if (dependencyLockfile != null) {
|
|
686
|
+
if ((dependencyLockfile.peerDependencies != null) && (dependencyLockfile.dependencies != null)) {
|
|
687
|
+
// This is done to guarantee that the dependency will be relinked with the
|
|
688
|
+
// up-to-date peer dependencies
|
|
689
|
+
// Covered by test: "peer dependency is grouped with dependency when peer is resolved not from a top dependency"
|
|
690
|
+
const dependencies = {};
|
|
691
|
+
for (const [depName, ref] of Object.entries(dependencyLockfile.dependencies ?? {})) {
|
|
692
|
+
if (dependencyLockfile.peerDependencies[depName])
|
|
693
|
+
continue;
|
|
694
|
+
dependencies[depName] = ref;
|
|
695
|
+
}
|
|
696
|
+
dependencyLockfile = {
|
|
697
|
+
...dependencyLockfile,
|
|
698
|
+
dependencies,
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
const { name, version, nonSemverVersion } = nameVerFromPkgSnapshot(depPath, dependencyLockfile);
|
|
702
|
+
return {
|
|
703
|
+
name,
|
|
704
|
+
version,
|
|
705
|
+
dependencyLockfile,
|
|
706
|
+
pkgId: nonSemverVersion ?? `${name}@${version}`,
|
|
707
|
+
// resolution may not exist if lockfile is broken, and an unexpected error will be thrown
|
|
708
|
+
// if resolution does not exist, return undefined so it can be autofixed later
|
|
709
|
+
resolution: dependencyLockfile.resolution && pkgSnapshotToResolution(depPath, dependencyLockfile, registries),
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
else {
|
|
713
|
+
const parsed = dp.parse(depPath);
|
|
714
|
+
return {
|
|
715
|
+
pkgId: parsed.nonSemverVersion ?? (parsed.name && parsed.version ? `${parsed.name}@${parsed.version}` : depPath), // Does it make sense to set pkgId when we're not sure?
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
async function resolveDependency(wantedDependency, ctx, options) {
|
|
720
|
+
const currentPkg = options.currentPkg ?? {};
|
|
721
|
+
const currentLockfileContainsTheDep = currentPkg.depPath
|
|
722
|
+
? Boolean(ctx.currentLockfile.packages?.[currentPkg.depPath])
|
|
723
|
+
: undefined;
|
|
724
|
+
const depIsLinked = Boolean(
|
|
725
|
+
// if package is not in `node_modules/.pnpm-lock.yaml`
|
|
726
|
+
// we can safely assume that it doesn't exist in `node_modules`
|
|
727
|
+
currentLockfileContainsTheDep &&
|
|
728
|
+
currentPkg.depPath &&
|
|
729
|
+
currentPkg.dependencyLockfile &&
|
|
730
|
+
currentPkg.name &&
|
|
731
|
+
await pathExists(path.join(ctx.virtualStoreDir, dp.depPathToFilename(currentPkg.depPath, ctx.virtualStoreDirMaxLength), 'node_modules', currentPkg.name, 'package.json')));
|
|
732
|
+
if (!options.update && !options.proceed && (currentPkg.resolution != null) && depIsLinked) {
|
|
733
|
+
return null;
|
|
734
|
+
}
|
|
735
|
+
let pkgResponse;
|
|
736
|
+
if (!options.parentPkg.installable) {
|
|
737
|
+
wantedDependency = {
|
|
738
|
+
...wantedDependency,
|
|
739
|
+
optional: true,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
// Normalize the `preferredVersion` (singular) and `preferredVersions`
|
|
743
|
+
// (plural) options. If the singular option is passed through, it'll be used
|
|
744
|
+
// instead of the plural option.
|
|
745
|
+
const preferredVersions = !options.updateRequested && options.preferredVersion != null
|
|
746
|
+
? getExactSinglePreferredVersions(wantedDependency, options.preferredVersion)
|
|
747
|
+
: options.preferredVersions;
|
|
748
|
+
try {
|
|
749
|
+
const calcSpecifier = options.currentDepth === 0;
|
|
750
|
+
if (!options.update && currentPkg.version && currentPkg.pkgId?.endsWith(`@${currentPkg.version}`) && !calcSpecifier) {
|
|
751
|
+
wantedDependency.bareSpecifier = replaceVersionInBareSpecifier(wantedDependency.bareSpecifier, currentPkg.version);
|
|
752
|
+
}
|
|
753
|
+
pkgResponse = await ctx.storeController.requestPackage(wantedDependency, {
|
|
754
|
+
allowBuild: ctx.allowBuild,
|
|
755
|
+
alwaysTryWorkspacePackages: ctx.linkWorkspacePackagesDepth >= options.currentDepth,
|
|
756
|
+
currentPkg: currentPkg
|
|
757
|
+
? {
|
|
758
|
+
id: currentPkg.pkgId,
|
|
759
|
+
name: currentPkg.name,
|
|
760
|
+
resolution: currentPkg.resolution,
|
|
761
|
+
version: currentPkg.version,
|
|
762
|
+
}
|
|
763
|
+
: undefined,
|
|
764
|
+
expectedPkg: currentPkg,
|
|
765
|
+
defaultTag: ctx.defaultTag,
|
|
766
|
+
ignoreScripts: ctx.ignoreScripts,
|
|
767
|
+
publishedBy: options.publishedBy,
|
|
768
|
+
publishedByExclude: ctx.publishedByExclude,
|
|
769
|
+
pickLowestVersion: options.pickLowestVersion,
|
|
770
|
+
downloadPriority: -options.currentDepth,
|
|
771
|
+
lockfileDir: ctx.lockfileDir,
|
|
772
|
+
preferredVersions,
|
|
773
|
+
preferWorkspacePackages: ctx.preferWorkspacePackages,
|
|
774
|
+
projectDir: (options.currentDepth > 0 &&
|
|
775
|
+
!wantedDependency.bareSpecifier.startsWith('file:'))
|
|
776
|
+
? ctx.lockfileDir
|
|
777
|
+
: options.parentPkg.rootDir,
|
|
778
|
+
skipFetch: ctx.dryRun,
|
|
779
|
+
trustPolicy: ctx.trustPolicy,
|
|
780
|
+
trustPolicyExclude: ctx.trustPolicyExclude,
|
|
781
|
+
trustPolicyIgnoreAfter: ctx.trustPolicyIgnoreAfter,
|
|
782
|
+
update: options.update,
|
|
783
|
+
workspacePackages: ctx.workspacePackages,
|
|
784
|
+
supportedArchitectures: options.supportedArchitectures,
|
|
785
|
+
onFetchError: (err) => {
|
|
786
|
+
err.prefix = options.prefix;
|
|
787
|
+
err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
|
|
788
|
+
return err;
|
|
789
|
+
},
|
|
790
|
+
injectWorkspacePackages: ctx.injectWorkspacePackages,
|
|
791
|
+
calcSpecifier,
|
|
792
|
+
pinnedVersion: options.pinnedVersion,
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
catch (err) { // eslint-disable-line
|
|
796
|
+
const wantedDependencyDetails = {
|
|
797
|
+
name: wantedDependency.alias,
|
|
798
|
+
bareSpecifier: wantedDependency.bareSpecifier,
|
|
799
|
+
version: wantedDependency.alias ? wantedDependency.bareSpecifier : undefined,
|
|
800
|
+
};
|
|
801
|
+
if (wantedDependency.optional && err.code !== 'ERR_PNPM_TRUST_DOWNGRADE' && err.code !== 'ERR_PNPM_NO_MATURE_MATCHING_VERSION') {
|
|
802
|
+
skippedOptionalDependencyLogger.debug({
|
|
803
|
+
details: err.toString(),
|
|
804
|
+
package: wantedDependencyDetails,
|
|
805
|
+
parents: getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById),
|
|
806
|
+
prefix: options.prefix,
|
|
807
|
+
reason: 'resolution_failure',
|
|
808
|
+
});
|
|
809
|
+
return null;
|
|
810
|
+
}
|
|
811
|
+
err.package = wantedDependencyDetails;
|
|
812
|
+
err.prefix = options.prefix;
|
|
813
|
+
err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
|
|
814
|
+
throw err;
|
|
815
|
+
}
|
|
816
|
+
dependencyResolvedLogger.debug({
|
|
817
|
+
resolution: pkgResponse.body.id,
|
|
818
|
+
wanted: {
|
|
819
|
+
dependentId: options.parentPkg.pkgId,
|
|
820
|
+
name: wantedDependency.alias,
|
|
821
|
+
rawSpec: wantedDependency.bareSpecifier,
|
|
822
|
+
},
|
|
823
|
+
});
|
|
824
|
+
// Check if exotic dependencies are disallowed in subdependencies
|
|
825
|
+
if (ctx.blockExoticSubdeps &&
|
|
826
|
+
options.currentDepth > 0 &&
|
|
827
|
+
pkgResponse.body.resolvedVia != null && // This is already coming from the lockfile, we skip the check in this case for now. Should be fixed later.
|
|
828
|
+
isExoticDep(pkgResponse.body.resolvedVia)) {
|
|
829
|
+
const error = new PnpmError('EXOTIC_SUBDEP', `Exotic dependency "${wantedDependency.alias ?? wantedDependency.bareSpecifier}" (resolved via ${pkgResponse.body.resolvedVia}) is not allowed in subdependencies when blockExoticSubdeps is enabled`);
|
|
830
|
+
error.prefix = options.prefix;
|
|
831
|
+
error.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
|
|
832
|
+
throw error;
|
|
833
|
+
}
|
|
834
|
+
if (ctx.allPreferredVersions && pkgResponse.body.manifest?.version) {
|
|
835
|
+
if (!ctx.allPreferredVersions[pkgResponse.body.manifest.name]) {
|
|
836
|
+
ctx.allPreferredVersions[pkgResponse.body.manifest.name] = {};
|
|
837
|
+
}
|
|
838
|
+
ctx.allPreferredVersions[pkgResponse.body.manifest.name][pkgResponse.body.manifest.version] = 'version';
|
|
839
|
+
}
|
|
840
|
+
if (!pkgResponse.body.updated &&
|
|
841
|
+
options.currentDepth === Math.max(0, options.updateDepth) &&
|
|
842
|
+
depIsLinked && !ctx.force && !options.proceed) {
|
|
843
|
+
return null;
|
|
844
|
+
}
|
|
845
|
+
if (pkgResponse.body.isLocal) {
|
|
846
|
+
if (!pkgResponse.body.manifest) {
|
|
847
|
+
// This should actually never happen because the local-resolver returns a manifest
|
|
848
|
+
// even if no real manifest exists in the filesystem.
|
|
849
|
+
throw new PnpmError('MISSING_PACKAGE_JSON', `Can't install ${wantedDependency.bareSpecifier}: Missing package.json file`);
|
|
850
|
+
}
|
|
851
|
+
return {
|
|
852
|
+
alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkgResponse.body.manifest.name ?? path.basename(pkgResponse.body.resolution.directory),
|
|
853
|
+
dev: wantedDependency.dev,
|
|
854
|
+
isLinkedDependency: true,
|
|
855
|
+
name: pkgResponse.body.manifest.name,
|
|
856
|
+
optional: wantedDependency.optional,
|
|
857
|
+
pkgId: pkgResponse.body.id,
|
|
858
|
+
resolution: pkgResponse.body.resolution,
|
|
859
|
+
version: pkgResponse.body.manifest.version,
|
|
860
|
+
normalizedBareSpecifier: pkgResponse.body.normalizedBareSpecifier,
|
|
861
|
+
pkg: pkgResponse.body.manifest,
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
let prepare;
|
|
865
|
+
let hasBin;
|
|
866
|
+
let pkg = getManifestFromResponse(pkgResponse, wantedDependency, currentPkg);
|
|
867
|
+
if (!pkg.dependencies) {
|
|
868
|
+
pkg.dependencies = {};
|
|
869
|
+
}
|
|
870
|
+
if (ctx.readPackageHook != null) {
|
|
871
|
+
pkg = await ctx.readPackageHook(pkg);
|
|
872
|
+
}
|
|
873
|
+
if (pkg.peerDependencies && pkg.dependencies) {
|
|
874
|
+
if (ctx.autoInstallPeers) {
|
|
875
|
+
pkg = {
|
|
876
|
+
...pkg,
|
|
877
|
+
dependencies: omit(Object.keys(pkg.peerDependencies), pkg.dependencies),
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
pkg = {
|
|
882
|
+
...pkg,
|
|
883
|
+
dependencies: omit(Object.keys(pkg.peerDependencies).filter((peerDep) => options.parentPkgAliases[peerDep]), pkg.dependencies),
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
if (pkg.engines?.runtime != null) {
|
|
888
|
+
convertEnginesRuntimeToDependencies(pkg, 'engines', 'dependencies');
|
|
889
|
+
}
|
|
890
|
+
if (!pkg.name) { // TODO: don't fail on optional dependencies
|
|
891
|
+
throw new PnpmError('MISSING_PACKAGE_NAME', `Can't install ${wantedDependency.bareSpecifier}: Missing package name`);
|
|
892
|
+
}
|
|
893
|
+
let pkgIdWithPatchHash = (pkgResponse.body.id.startsWith(`${pkg.name}@`) ? pkgResponse.body.id : `${pkg.name}@${pkgResponse.body.id}`);
|
|
894
|
+
const patch = getPatchInfo(ctx.patchedDependencies, pkg.name, pkg.version);
|
|
895
|
+
if (patch) {
|
|
896
|
+
ctx.appliedPatches.add(patch.key);
|
|
897
|
+
pkgIdWithPatchHash = `${pkgIdWithPatchHash}(patch_hash=${patch.hash})`;
|
|
898
|
+
}
|
|
899
|
+
// We are building the dependency tree only until there are new packages
|
|
900
|
+
// or the packages repeat in a unique order.
|
|
901
|
+
// This is needed later during peer dependencies resolution.
|
|
902
|
+
//
|
|
903
|
+
// So we resolve foo > bar > qar > foo
|
|
904
|
+
// But we stop on foo > bar > qar > foo > qar
|
|
905
|
+
// In the second example, there's no reason to walk qar again
|
|
906
|
+
// when qar is included the first time, the dependencies of foo
|
|
907
|
+
// are already resolved and included as parent dependencies of qar.
|
|
908
|
+
// So during peers resolution, qar cannot possibly get any new or different
|
|
909
|
+
// peers resolved, after the first occurrence.
|
|
910
|
+
//
|
|
911
|
+
// However, in the next example we would analyze the second qar as well,
|
|
912
|
+
// because zoo is a new parent package:
|
|
913
|
+
// foo > bar > qar > zoo > qar
|
|
914
|
+
if (parentIdsContainSequence(options.parentIds, options.parentPkg.pkgId, pkgResponse.body.id) || pkgResponse.body.id === options.parentPkg.pkgId) {
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
if (!options.update && (currentPkg.dependencyLockfile != null) && currentPkg.depPath &&
|
|
918
|
+
!pkgResponse.body.updated &&
|
|
919
|
+
// peerDependencies field is also used for transitive peer dependencies which should not be linked
|
|
920
|
+
// That's why we cannot omit reading package.json of such dependencies.
|
|
921
|
+
// This can be removed if we implement something like peerDependenciesMeta.transitive: true
|
|
922
|
+
(currentPkg.dependencyLockfile.peerDependencies == null)) {
|
|
923
|
+
hasBin = currentPkg.dependencyLockfile.hasBin === true;
|
|
924
|
+
pkg = {
|
|
925
|
+
...nameVerFromPkgSnapshot(currentPkg.depPath, currentPkg.dependencyLockfile),
|
|
926
|
+
...omitDepsFields(currentPkg.dependencyLockfile),
|
|
927
|
+
...pkg,
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
prepare = Boolean(pkgResponse.body.resolvedVia === 'git-repository' &&
|
|
932
|
+
typeof pkg.scripts?.prepare === 'string');
|
|
933
|
+
if (currentPkg.dependencyLockfile?.deprecated &&
|
|
934
|
+
!pkgResponse.body.updated && !pkg.deprecated) {
|
|
935
|
+
pkg.deprecated = currentPkg.dependencyLockfile.deprecated;
|
|
936
|
+
}
|
|
937
|
+
hasBin = (currentPkg.dependencyLockfile?.hasBin != null && !pkg.bin)
|
|
938
|
+
? currentPkg.dependencyLockfile.hasBin
|
|
939
|
+
: Boolean((pkg.bin && !(pkg.bin === '' || Object.keys(pkg.bin).length === 0)) ?? pkg.directories?.bin);
|
|
940
|
+
}
|
|
941
|
+
if (options.currentDepth === 0 && pkgResponse.body.latest && pkgResponse.body.latest !== pkg.version) {
|
|
942
|
+
ctx.outdatedDependencies[pkgResponse.body.id] = pkgResponse.body.latest;
|
|
943
|
+
}
|
|
944
|
+
if (pkg.peerDependencies != null) {
|
|
945
|
+
for (const name in pkg.peerDependencies) {
|
|
946
|
+
ctx.allPeerDepNames.add(name);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
if (pkg.peerDependenciesMeta != null) {
|
|
950
|
+
for (const name in pkg.peerDependenciesMeta) {
|
|
951
|
+
ctx.allPeerDepNames.add(name);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
// In case of leaf dependencies (dependencies that have no prod deps or peer deps),
|
|
955
|
+
// we only ever need to analyze one leaf dep in a graph, so the nodeId can be short and stateless.
|
|
956
|
+
const nodeId = pkgIsLeaf(pkg) ? pkgResponse.body.id : nextNodeId();
|
|
957
|
+
const parentIsInstallable = options.parentPkg.installable === undefined || options.parentPkg.installable;
|
|
958
|
+
const installable = parentIsInstallable && pkgResponse.body.isInstallable !== false;
|
|
959
|
+
const isNew = !ctx.resolvedPkgsById[pkgResponse.body.id];
|
|
960
|
+
const parentImporterId = options.parentIds[0];
|
|
961
|
+
const currentIsOptional = wantedDependency.optional || options.parentPkg.optional;
|
|
962
|
+
if (isNew) {
|
|
963
|
+
if (pkg.deprecated &&
|
|
964
|
+
(!ctx.allowedDeprecatedVersions[pkg.name] || !semver.satisfies(pkg.version, ctx.allowedDeprecatedVersions[pkg.name]))) {
|
|
965
|
+
// Report deprecated packages only on first occurrence.
|
|
966
|
+
deprecationLogger.debug({
|
|
967
|
+
deprecated: pkg.deprecated,
|
|
968
|
+
depth: options.currentDepth,
|
|
969
|
+
pkgId: pkgResponse.body.id,
|
|
970
|
+
pkgName: pkg.name,
|
|
971
|
+
pkgVersion: pkg.version,
|
|
972
|
+
prefix: options.prefix,
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
if (pkgResponse.body.isInstallable === false || !parentIsInstallable) {
|
|
976
|
+
ctx.skipped.add(pkgResponse.body.id);
|
|
977
|
+
}
|
|
978
|
+
progressLogger.debug({
|
|
979
|
+
packageId: pkgResponse.body.id,
|
|
980
|
+
requester: ctx.lockfileDir,
|
|
981
|
+
status: 'resolved',
|
|
982
|
+
});
|
|
983
|
+
// WARN: It is very important to keep this sync
|
|
984
|
+
// Otherwise, deprecation messages for the same package might get written several times
|
|
985
|
+
ctx.resolvedPkgsById[pkgResponse.body.id] = getResolvedPackage({
|
|
986
|
+
dependencyLockfile: currentPkg.dependencyLockfile,
|
|
987
|
+
pkgIdWithPatchHash,
|
|
988
|
+
force: ctx.force,
|
|
989
|
+
hasBin,
|
|
990
|
+
patch,
|
|
991
|
+
pkg,
|
|
992
|
+
pkgResponse,
|
|
993
|
+
prepare,
|
|
994
|
+
wantedDependency,
|
|
995
|
+
parentImporterId,
|
|
996
|
+
optional: currentIsOptional,
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
else {
|
|
1000
|
+
ctx.resolvedPkgsById[pkgResponse.body.id].prod = ctx.resolvedPkgsById[pkgResponse.body.id].prod || !wantedDependency.dev && !wantedDependency.optional;
|
|
1001
|
+
ctx.resolvedPkgsById[pkgResponse.body.id].dev = ctx.resolvedPkgsById[pkgResponse.body.id].dev || wantedDependency.dev;
|
|
1002
|
+
ctx.resolvedPkgsById[pkgResponse.body.id].optional = ctx.resolvedPkgsById[pkgResponse.body.id].optional && currentIsOptional;
|
|
1003
|
+
if (ctx.resolvedPkgsById[pkgResponse.body.id].fetching == null && pkgResponse.fetching != null) {
|
|
1004
|
+
ctx.resolvedPkgsById[pkgResponse.body.id].fetching = pkgResponse.fetching;
|
|
1005
|
+
ctx.resolvedPkgsById[pkgResponse.body.id].filesIndexFile = pkgResponse.filesIndexFile;
|
|
1006
|
+
}
|
|
1007
|
+
if (ctx.dependenciesTree.has(nodeId)) {
|
|
1008
|
+
ctx.dependenciesTree.get(nodeId).depth = Math.min(ctx.dependenciesTree.get(nodeId).depth, options.currentDepth);
|
|
1009
|
+
}
|
|
1010
|
+
else {
|
|
1011
|
+
ctx.pendingNodes.push({
|
|
1012
|
+
alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkg.name,
|
|
1013
|
+
depth: options.currentDepth,
|
|
1014
|
+
parentIds: options.parentIds,
|
|
1015
|
+
installable,
|
|
1016
|
+
nodeId,
|
|
1017
|
+
resolvedPackage: ctx.resolvedPkgsById[pkgResponse.body.id],
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
const rootDir = pkgResponse.body.resolution.type === 'directory'
|
|
1022
|
+
? path.resolve(ctx.lockfileDir, pkgResponse.body.resolution.directory)
|
|
1023
|
+
: options.prefix;
|
|
1024
|
+
let missingPeersOfChildren;
|
|
1025
|
+
if (ctx.hoistPeers && !options.parentIds.includes(pkgResponse.body.id)) {
|
|
1026
|
+
if (ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id]) {
|
|
1027
|
+
// This if condition is used to avoid a dead lock.
|
|
1028
|
+
// There might be a better way to hoist peer dependencies during resolution
|
|
1029
|
+
// but it would probably require a big rewrite of the resolution algorithm.
|
|
1030
|
+
if (ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id].depth >= options.currentDepth ||
|
|
1031
|
+
ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id].missingPeersOfChildren.resolved) {
|
|
1032
|
+
missingPeersOfChildren = ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id].missingPeersOfChildren;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
else {
|
|
1036
|
+
const p = pDefer();
|
|
1037
|
+
missingPeersOfChildren = {
|
|
1038
|
+
resolve: p.resolve,
|
|
1039
|
+
reject: p.reject,
|
|
1040
|
+
get: pShare(p.promise),
|
|
1041
|
+
};
|
|
1042
|
+
ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id] = {
|
|
1043
|
+
depth: options.currentDepth,
|
|
1044
|
+
missingPeersOfChildren,
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
const resolvedPkg = ctx.resolvedPkgsById[pkgResponse.body.id];
|
|
1049
|
+
return {
|
|
1050
|
+
alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkg.name,
|
|
1051
|
+
depIsLinked,
|
|
1052
|
+
resolvedVia: pkgResponse.body.resolvedVia,
|
|
1053
|
+
isNew,
|
|
1054
|
+
nodeId,
|
|
1055
|
+
normalizedBareSpecifier: pkgResponse.body.normalizedBareSpecifier,
|
|
1056
|
+
missingPeersOfChildren,
|
|
1057
|
+
pkgId: pkgResponse.body.id,
|
|
1058
|
+
rootDir,
|
|
1059
|
+
missingPeers: getMissingPeers(pkg),
|
|
1060
|
+
optional: resolvedPkg.optional,
|
|
1061
|
+
version: resolvedPkg.version,
|
|
1062
|
+
saveCatalogName: wantedDependency.saveCatalogName,
|
|
1063
|
+
// Next fields are actually only needed when isNew = true
|
|
1064
|
+
installable,
|
|
1065
|
+
isLinkedDependency: undefined,
|
|
1066
|
+
pkg,
|
|
1067
|
+
updated: pkgResponse.body.updated,
|
|
1068
|
+
publishedAt: pkgResponse.body.publishedAt,
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
export function getManifestFromResponse(pkgResponse, wantedDependency, currentPkg) {
|
|
1072
|
+
if (pkgResponse.body.manifest)
|
|
1073
|
+
return pkgResponse.body.manifest;
|
|
1074
|
+
if (currentPkg?.name && currentPkg?.version) {
|
|
1075
|
+
return {
|
|
1076
|
+
name: currentPkg.name,
|
|
1077
|
+
version: currentPkg.version,
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
return {
|
|
1081
|
+
name: wantedDependency.alias ? wantedDependency.alias : wantedDependency.bareSpecifier.split('/').pop(),
|
|
1082
|
+
version: '0.0.0',
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
function getMissingPeers(pkg) {
|
|
1086
|
+
const missingPeers = {};
|
|
1087
|
+
for (const [peerName, peerVersion] of Object.entries(pkg.peerDependencies ?? {})) {
|
|
1088
|
+
missingPeers[peerName] = {
|
|
1089
|
+
range: peerVersion,
|
|
1090
|
+
optional: pkg.peerDependenciesMeta?.[peerName]?.optional === true,
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
return missingPeers;
|
|
1094
|
+
}
|
|
1095
|
+
function pkgIsLeaf(pkg) {
|
|
1096
|
+
return Object.keys(pkg.dependencies ?? {}).length === 0 &&
|
|
1097
|
+
Object.keys(pkg.optionalDependencies ?? {}).length === 0 &&
|
|
1098
|
+
Object.keys(pkg.peerDependencies ?? {}).length === 0 &&
|
|
1099
|
+
// Package manifests can declare peerDependenciesMeta without declaring
|
|
1100
|
+
// peerDependencies. peerDependenciesMeta implies the later.
|
|
1101
|
+
Object.keys(pkg.peerDependenciesMeta ?? {}).length === 0;
|
|
1102
|
+
}
|
|
1103
|
+
function getResolvedPackage(options) {
|
|
1104
|
+
const peerDependencies = peerDependenciesWithoutOwn(options.pkg);
|
|
1105
|
+
return {
|
|
1106
|
+
additionalInfo: {
|
|
1107
|
+
bundledDependencies: options.pkg.bundledDependencies,
|
|
1108
|
+
bundleDependencies: options.pkg.bundleDependencies,
|
|
1109
|
+
cpu: options.pkg.cpu,
|
|
1110
|
+
deprecated: options.pkg.deprecated,
|
|
1111
|
+
engines: options.pkg.engines,
|
|
1112
|
+
os: options.pkg.os,
|
|
1113
|
+
libc: options.pkg.libc,
|
|
1114
|
+
},
|
|
1115
|
+
isLeaf: pkgIsLeaf(options.pkg),
|
|
1116
|
+
pkgIdWithPatchHash: options.pkgIdWithPatchHash,
|
|
1117
|
+
dev: options.wantedDependency.dev,
|
|
1118
|
+
fetching: options.pkgResponse.fetching,
|
|
1119
|
+
filesIndexFile: options.pkgResponse.filesIndexFile,
|
|
1120
|
+
hasBin: options.hasBin,
|
|
1121
|
+
hasBundledDependencies: !((options.pkg.bundledDependencies ?? options.pkg.bundleDependencies) == null),
|
|
1122
|
+
id: options.pkgResponse.body.id,
|
|
1123
|
+
name: options.pkg.name,
|
|
1124
|
+
optional: options.optional,
|
|
1125
|
+
optionalDependencies: new Set(Object.keys(options.pkg.optionalDependencies ?? {})),
|
|
1126
|
+
patch: options.patch,
|
|
1127
|
+
peerDependencies,
|
|
1128
|
+
prepare: options.prepare,
|
|
1129
|
+
prod: !options.wantedDependency.dev && !options.wantedDependency.optional,
|
|
1130
|
+
resolution: options.pkgResponse.body.resolution,
|
|
1131
|
+
version: options.pkg.version,
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
function peerDependenciesWithoutOwn(pkg) {
|
|
1135
|
+
if ((pkg.peerDependencies == null) && (pkg.peerDependenciesMeta == null))
|
|
1136
|
+
return {};
|
|
1137
|
+
const ownDeps = new Set([
|
|
1138
|
+
pkg.name,
|
|
1139
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
1140
|
+
...Object.keys(pkg.optionalDependencies ?? {}),
|
|
1141
|
+
]);
|
|
1142
|
+
const result = {};
|
|
1143
|
+
if (pkg.peerDependencies != null) {
|
|
1144
|
+
for (const [peerName, peerRange] of Object.entries(pkg.peerDependencies)) {
|
|
1145
|
+
if (ownDeps.has(peerName))
|
|
1146
|
+
continue;
|
|
1147
|
+
result[peerName] = {
|
|
1148
|
+
version: peerRange,
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
if (pkg.peerDependenciesMeta != null) {
|
|
1153
|
+
for (const [peerName, peerMeta] of Object.entries(pkg.peerDependenciesMeta)) {
|
|
1154
|
+
if (ownDeps.has(peerName) || peerMeta.optional !== true)
|
|
1155
|
+
continue;
|
|
1156
|
+
if (!result[peerName])
|
|
1157
|
+
result[peerName] = { version: '*' };
|
|
1158
|
+
result[peerName].optional = true;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
return result;
|
|
1162
|
+
}
|
|
1163
|
+
function getCatalogExistingVersionFromSnapshot(catalogLookup, wantedLockfile, wantedDependency) {
|
|
1164
|
+
const existingCatalogResolution = wantedLockfile.catalogs?.[catalogLookup.catalogName]?.[wantedDependency.alias];
|
|
1165
|
+
return existingCatalogResolution?.specifier === catalogLookup.specifier
|
|
1166
|
+
? existingCatalogResolution.version
|
|
1167
|
+
: undefined;
|
|
1168
|
+
}
|
|
1169
|
+
const NON_EXOTIC_RESOLVED_VIA = new Set([
|
|
1170
|
+
'custom-resolver',
|
|
1171
|
+
'github.com/denoland/deno',
|
|
1172
|
+
'github.com/oven-sh/bun',
|
|
1173
|
+
'jsr-registry',
|
|
1174
|
+
'local-filesystem',
|
|
1175
|
+
'nodejs.org',
|
|
1176
|
+
'npm-registry',
|
|
1177
|
+
'workspace',
|
|
1178
|
+
]);
|
|
1179
|
+
function isExoticDep(resolvedVia) {
|
|
1180
|
+
return !NON_EXOTIC_RESOLVED_VIA.has(resolvedVia);
|
|
1181
|
+
}
|
|
1182
|
+
//# sourceMappingURL=resolveDependencies.js.map
|