@pnpm/installing.deps-resolver 1100.2.4 → 1100.2.6

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.
@@ -6,6 +6,8 @@ export interface WantedDependency {
6
6
  optional: boolean;
7
7
  injected?: boolean;
8
8
  saveCatalogName?: string;
9
+ /** Whether this dependency's spec should be (re)written to the manifest. */
10
+ updateSpec?: boolean;
9
11
  }
10
12
  type GetNonDevWantedDependenciesManifest = Pick<DependencyManifest, 'bundleDependencies' | 'bundledDependencies' | 'optionalDependencies' | 'dependencies' | 'dependenciesMeta'> & {
11
13
  name?: string;
package/lib/index.js CHANGED
@@ -221,6 +221,7 @@ export async function resolveDependencies(importers, opts) {
221
221
  }
222
222
  }
223
223
  }
224
+ await waitForResolutionFetches(resolvedPkgsById);
224
225
  const newLockfile = updateLockfile({
225
226
  dependenciesGraph,
226
227
  lockfile: opts.wantedLockfile,
@@ -334,6 +335,21 @@ function alignDependencyTypes(manifest, projectSnapshot) {
334
335
  }
335
336
  }
336
337
  }
338
+ /**
339
+ * Waits for fetches that complete resolution data used by the lockfile snapshot and
340
+ * virtual-store paths. Other package fetches are awaited later by `waitTillAllFetchingsFinish`.
341
+ */
342
+ async function waitForResolutionFetches(resolvedPkgsById) {
343
+ const fetches = [];
344
+ for (const pkg of Object.values(resolvedPkgsById)) {
345
+ if (pkg.resolutionNeedsFetch && pkg.fetching != null) {
346
+ fetches.push(pkg.fetching());
347
+ }
348
+ }
349
+ if (fetches.length > 0) {
350
+ await Promise.all(fetches);
351
+ }
352
+ }
337
353
  function getAliasToDependencyTypeMap(manifest) {
338
354
  const depTypesOfAliases = {};
339
355
  for (const depType of DEPENDENCIES_FIELDS) {
@@ -45,6 +45,11 @@ export interface PkgAddressOrLinkBase {
45
45
  optional: boolean;
46
46
  pkg: PackageManifest;
47
47
  pkgId: PkgResolutionId;
48
+ /**
49
+ * The wanted dependency this direct dependency was resolved from, carried so
50
+ * consumers can recover the request directly. See `updateProjectManifest`.
51
+ */
52
+ wantedDependency?: WantedDependency;
48
53
  }
49
54
  export interface LinkedDependency extends PkgAddressOrLinkBase {
50
55
  isLinkedDependency: true;
@@ -201,6 +206,12 @@ export interface ResolvedPackage {
201
206
  dev: boolean;
202
207
  optional: boolean;
203
208
  fetching: () => Promise<PkgRequestFetchResult>;
209
+ /**
210
+ * The resolution can't be completed without awaiting `fetching` (e.g. a registry tarball
211
+ * whose integrity is computed from the downloaded bytes). The lockfile snapshot and the
212
+ * virtual-store paths derived from the integrity must await `fetching` for these first.
213
+ */
214
+ resolutionNeedsFetch?: boolean;
204
215
  filesIndexFile: string;
205
216
  name: string;
206
217
  version: string;
@@ -278,6 +289,15 @@ export declare function resolveDependencies(ctx: ResolutionContext, preferredVer
278
289
  updateDepth?: number;
279
290
  }>, options: ResolvedDependenciesOptions): Promise<ResolvedDependenciesResult>;
280
291
  export declare function createNodeIdForLinkedLocalPkg(lockfileDir: string, pkgDir: string): NodeId;
292
+ export declare function claimChildrenResolution(ctx: ResolutionContext, opts: {
293
+ currentDepth: number;
294
+ parentIds: PkgResolutionId[];
295
+ pkgId: PkgResolutionId;
296
+ }): {
297
+ id: number;
298
+ isOwner: boolean;
299
+ missingPeersOfChildren?: MissingPeersOfChildren;
300
+ };
281
301
  export declare function buildTree(ctx: {
282
302
  childrenByParentId: ChildrenByParentId;
283
303
  dependenciesTree: DependenciesTree<ResolvedPackage>;
@@ -8,6 +8,7 @@ import { nameVerFromPkgSnapshot, pkgSnapshotToResolution, } from '@pnpm/lockfile
8
8
  import { logger } from '@pnpm/logger';
9
9
  import { getPatchInfo } from '@pnpm/patching.config';
10
10
  import { convertEnginesRuntimeToDependencies } from '@pnpm/pkg-manifest.utils';
11
+ import { parseBareSpecifier } from '@pnpm/resolving.npm-resolver';
11
12
  import { DIRECT_DEP_SELECTOR_WEIGHT, } from '@pnpm/resolving.resolver-base';
12
13
  import { lexCompare } from '@pnpm/util.lex-comparator';
13
14
  import normalizePath from 'normalize-path';
@@ -39,7 +40,8 @@ export async function resolveRootDependencies(ctx, importers) {
39
40
  ctx.allPreferredVersions = getPreferredVersionsFromLockfileAndManifests(ctx.wantedLockfile.packages, []);
40
41
  }
41
42
  else if (ctx.hoistPeers) {
42
- ctx.allPreferredVersions = {};
43
+ // Null-prototype: keyed by package names from resolved manifests.
44
+ ctx.allPreferredVersions = Object.create(null);
43
45
  }
44
46
  const { pkgAddressesByImportersWithoutPeers, publishedBy, time } = await resolveDependenciesOfImporters(ctx, importers);
45
47
  if (!ctx.hoistPeers) {
@@ -434,8 +436,14 @@ async function resolveDependenciesOfDependency(ctx, preferredVersions, options,
434
436
  const updateShouldContinue = options.currentDepth <= updateDepth;
435
437
  const updateRequested = updateShouldContinue &&
436
438
  ((options.updateMatching == null) ||
437
- (extendedWantedDep.infoFromLockfile?.name != null &&
438
- options.updateMatching(extendedWantedDep.infoFromLockfile.name, extendedWantedDep.infoFromLockfile.version)));
439
+ (extendedWantedDep.infoFromLockfile?.name != null
440
+ ? options.updateMatching(extendedWantedDep.infoFromLockfile.name, extendedWantedDep.infoFromLockfile.version)
441
+ // A changed specifier forgets the edge's lockfile reference before
442
+ // resolution (e.g. `pnpm audit --fix` widening a vulnerable pin), so
443
+ // the target would otherwise lose its updateRequested status — and
444
+ // keep its seeded lockfile pins — at the very moment it is being
445
+ // updated. Fall back to matching by the wanted dependency itself.
446
+ : wantedDependencyMatchesUpdateTarget(ctx, options.updateMatching, extendedWantedDep.wantedDependency)));
439
447
  const update = updateRequested ||
440
448
  ((extendedWantedDep.infoFromLockfile?.dependencyLockfile) == null) || Boolean((ctx.workspacePackages != null) &&
441
449
  ctx.linkWorkspacePackagesDepth !== -1 &&
@@ -557,6 +565,21 @@ async function resolveDependenciesOfDependency(ctx, preferredVersions, options,
557
565
  },
558
566
  };
559
567
  }
568
+ /**
569
+ * Whether a wanted dependency without a lockfile reference matches the
570
+ * update target by package name. The name is parsed from the bare
571
+ * specifier, so an `npm:` alias matches by the real package name it
572
+ * installs — `foo@npm:bar@^4` matches an update target of `bar`, not
573
+ * `foo`. Exotic specifiers the npm parser rejects fall back to the alias.
574
+ */
575
+ function wantedDependencyMatchesUpdateTarget(ctx, updateMatching, wantedDependency) {
576
+ const { alias, bareSpecifier } = wantedDependency;
577
+ const spec = alias && bareSpecifier
578
+ ? parseBareSpecifier(bareSpecifier, alias, ctx.defaultTag ?? 'latest', ctx.registries.default)
579
+ : null;
580
+ const name = spec?.name ?? alias;
581
+ return name != null && updateMatching(name, undefined);
582
+ }
560
583
  export function createNodeIdForLinkedLocalPkg(lockfileDir, pkgDir) {
561
584
  return `link:${normalizePath(path.relative(lockfileDir, pkgDir))}`;
562
585
  }
@@ -611,7 +634,7 @@ function hasActivePackageResolutionBeforeDepth(ctx, depth) {
611
634
  }
612
635
  return false;
613
636
  }
614
- function claimChildrenResolution(ctx, opts) {
637
+ export function claimChildrenResolution(ctx, opts) {
615
638
  const owner = {
616
639
  depth: opts.currentDepth,
617
640
  importerOrder: ctx.importerResolutionOrder[opts.parentIds[0]] ?? Number.MAX_SAFE_INTEGER,
@@ -657,8 +680,13 @@ function claimChildrenResolution(ctx, opts) {
657
680
  if (ctx.hoistPeers &&
658
681
  !opts.parentIds.includes(opts.pkgId) &&
659
682
  existing.missingPeersOfChildren &&
660
- (existing.owner.depth >= opts.currentDepth ||
661
- existing.missingPeersOfChildren.resolved)) {
683
+ existing.owner.depth >= opts.currentDepth) {
684
+ // Gating reuse on the owner's depth keeps a transitive optional peer's
685
+ // presence in the resolved suffix a function of graph structure, not of
686
+ // which occurrence happened to finish resolving first. A strictly shallower
687
+ // owner is excluded because its promise may still be unsettled here, and
688
+ // awaiting it can deadlock under auto-install-peers
689
+ // (https://github.com/pnpm/pnpm/issues/5454).
662
690
  missingPeersOfChildren = existing.missingPeersOfChildren;
663
691
  }
664
692
  return {
@@ -1097,6 +1125,7 @@ async function resolveDependency(wantedDependency, ctx, options) {
1097
1125
  trustPolicyExclude: ctx.trustPolicyExclude,
1098
1126
  trustPolicyIgnoreAfter: ctx.trustPolicyIgnoreAfter,
1099
1127
  update: options.update,
1128
+ updateRequested: options.updateRequested,
1100
1129
  updateChecksums: options.updateChecksums,
1101
1130
  workspacePackages: ctx.workspacePackages,
1102
1131
  supportedArchitectures: options.supportedArchitectures,
@@ -1158,7 +1187,8 @@ async function resolveDependency(wantedDependency, ctx, options) {
1158
1187
  }
1159
1188
  if (ctx.allPreferredVersions && pkgResponse.body.manifest?.version) {
1160
1189
  if (!ctx.allPreferredVersions[pkgResponse.body.manifest.name]) {
1161
- ctx.allPreferredVersions[pkgResponse.body.manifest.name] = {};
1190
+ // Null-prototype: keyed by versions from the resolved manifest.
1191
+ ctx.allPreferredVersions[pkgResponse.body.manifest.name] = Object.create(null);
1162
1192
  }
1163
1193
  ctx.allPreferredVersions[pkgResponse.body.manifest.name][pkgResponse.body.manifest.version] = 'version';
1164
1194
  }
@@ -1184,6 +1214,7 @@ async function resolveDependency(wantedDependency, ctx, options) {
1184
1214
  version: pkgResponse.body.manifest.version,
1185
1215
  normalizedBareSpecifier: pkgResponse.body.normalizedBareSpecifier,
1186
1216
  pkg: pkgResponse.body.manifest,
1217
+ wantedDependency,
1187
1218
  };
1188
1219
  }
1189
1220
  let prepare;
@@ -1364,6 +1395,7 @@ async function resolveDependency(wantedDependency, ctx, options) {
1364
1395
  resolvedVia: pkgResponse.body.resolvedVia,
1365
1396
  isNew,
1366
1397
  nodeId,
1398
+ wantedDependency,
1367
1399
  normalizedBareSpecifier: pkgResponse.body.normalizedBareSpecifier,
1368
1400
  missingPeersOfChildren,
1369
1401
  childrenResolutionId: childrenResolution.id,
@@ -1433,6 +1465,7 @@ function getResolvedPackage(options) {
1433
1465
  pkgIdWithPatchHash: options.pkgIdWithPatchHash,
1434
1466
  dev: options.wantedDependency.dev,
1435
1467
  fetching: options.pkgResponse.fetching,
1468
+ resolutionNeedsFetch: options.pkgResponse.resolutionNeedsFetch,
1436
1469
  filesIndexFile: options.pkgResponse.filesIndexFile,
1437
1470
  hasBin: options.hasBin,
1438
1471
  hasBundledDependencies: !((options.pkg.bundledDependencies ?? options.pkg.bundleDependencies) == null),
@@ -25,6 +25,11 @@ export interface ResolvedDirectDependency {
25
25
  name: string;
26
26
  catalogLookup?: CatalogLookupMetadata;
27
27
  normalizedBareSpecifier?: string;
28
+ /**
29
+ * The wanted dependency this was resolved from, carried so consumers can
30
+ * recover the request directly. See `updateProjectManifest`.
31
+ */
32
+ wantedDependency?: WantedDependency;
28
33
  }
29
34
  /**
30
35
  * Information related to the catalog entry for this dependency if it was
@@ -164,6 +164,7 @@ export async function resolveDependencyTree(importers, opts) {
164
164
  resolution: resolvedPackage.resolution,
165
165
  version: resolvedPackage.version,
166
166
  normalizedBareSpecifier: dep.normalizedBareSpecifier,
167
+ wantedDependency: dep.wantedDependency,
167
168
  };
168
169
  }),
169
170
  directNodeIdsByAlias: new Map(directNonLinkedDeps.map(({ alias, nodeId }) => [alias, nodeId])),
@@ -3,19 +3,24 @@ export async function updateProjectManifest(importer, opts) {
3
3
  if (!importer.manifest) {
4
4
  throw new Error('Cannot save because no package.json found');
5
5
  }
6
- const specsToUpsert = opts.directDependencies
7
- .filter((rdd, index) => importer.wantedDependencies[index]?.updateSpec)
8
- .map((rdd, index) => {
9
- const wantedDep = importer.wantedDependencies[index];
10
- return {
6
+ const specsToUpsert = [];
7
+ for (const rdd of opts.directDependencies) {
8
+ const wantedDep = rdd.wantedDependency;
9
+ if (wantedDep?.updateSpec !== true)
10
+ continue;
11
+ specsToUpsert.push({
11
12
  alias: rdd.alias,
12
13
  peer: importer.peer,
13
14
  bareSpecifier: getBareSpecifierToSave(wantedDep, rdd, opts.preserveWorkspaceProtocol),
14
15
  resolvedVersion: rdd.version,
15
16
  pinnedVersion: importer.pinnedVersion,
16
17
  saveType: importer.targetDependenciesField,
17
- };
18
- });
18
+ });
19
+ }
20
+ // Re-save a dependency flagged for update that failed to resolve (e.g. a
21
+ // missing optional, hence absent from `directDependencies`) carrying no
22
+ // specifier, so it keeps its existing version under the importer's target
23
+ // field (which is unset for a plain install/update, making this a no-op).
19
24
  for (const pkgToInstall of importer.wantedDependencies) {
20
25
  if (pkgToInstall.updateSpec && pkgToInstall.alias && !specsToUpsert.some(({ alias }) => alias === pkgToInstall.alias)) {
21
26
  specsToUpsert.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/installing.deps-resolver",
3
- "version": "1100.2.4",
3
+ "version": "1100.2.6",
4
4
  "description": "Resolves dependency graph of a package",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -10,9 +10,9 @@
10
10
  "funding": "https://opencollective.com/pnpm",
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "https://github.com/pnpm/pnpm/tree/main/installing/deps-resolver"
13
+ "url": "https://github.com/pnpm/pnpm/tree/main/pnpm11/installing/deps-resolver"
14
14
  },
15
- "homepage": "https://github.com/pnpm/pnpm/tree/main/installing/deps-resolver#readme",
15
+ "homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/installing/deps-resolver#readme",
16
16
  "bugs": {
17
17
  "url": "https://github.com/pnpm/pnpm/issues"
18
18
  },
@@ -43,30 +43,30 @@
43
43
  "semver-range-intersect": "^0.3.1",
44
44
  "validate-npm-package-name": "7.0.2",
45
45
  "version-selector-type": "^3.0.0",
46
+ "@pnpm/catalogs.resolver": "1100.0.0",
47
+ "@pnpm/config.version-policy": "1100.1.6",
48
+ "@pnpm/catalogs.types": "1100.0.0",
46
49
  "@pnpm/constants": "1100.0.0",
47
50
  "@pnpm/core-loggers": "1100.2.1",
48
- "@pnpm/deps.graph-hasher": "1100.2.5",
49
- "@pnpm/error": "1100.0.0",
50
- "@pnpm/fetching.pick-fetcher": "1100.0.12",
51
+ "@pnpm/deps.graph-hasher": "1100.2.7",
51
52
  "@pnpm/deps.peer-range": "1100.0.2",
52
- "@pnpm/hooks.types": "1100.0.12",
53
53
  "@pnpm/deps.path": "1100.0.8",
54
- "@pnpm/config.version-policy": "1100.1.5",
55
- "@pnpm/lockfile.preferred-versions": "1100.0.16",
56
- "@pnpm/lockfile.types": "1100.0.11",
57
- "@pnpm/lockfile.utils": "1100.0.13",
58
- "@pnpm/patching.config": "1100.0.8",
59
- "@pnpm/catalogs.types": "1100.0.0",
60
- "@pnpm/pkg-manifest.reader": "1100.0.8",
61
- "@pnpm/pkg-manifest.utils": "1100.2.5",
62
- "@pnpm/resolving.npm-resolver": "1102.0.1",
63
- "@pnpm/resolving.resolver-base": "1100.4.2",
64
- "@pnpm/store.controller-types": "1100.1.5",
65
- "@pnpm/types": "1101.3.2",
66
- "@pnpm/workspace.spec-parser": "1100.0.0",
54
+ "@pnpm/error": "1100.0.1",
55
+ "@pnpm/hooks.types": "1100.1.1",
56
+ "@pnpm/fetching.pick-fetcher": "1100.0.14",
57
+ "@pnpm/lockfile.preferred-versions": "1100.0.18",
58
+ "@pnpm/lockfile.pruner": "1100.0.13",
59
+ "@pnpm/lockfile.types": "1100.0.13",
60
+ "@pnpm/lockfile.utils": "1100.1.1",
61
+ "@pnpm/patching.config": "1100.0.9",
67
62
  "@pnpm/patching.types": "1100.0.0",
68
- "@pnpm/catalogs.resolver": "1100.0.0",
69
- "@pnpm/lockfile.pruner": "1100.0.11"
63
+ "@pnpm/resolving.npm-resolver": "1102.1.1",
64
+ "@pnpm/pkg-manifest.reader": "1100.0.9",
65
+ "@pnpm/resolving.resolver-base": "1100.5.1",
66
+ "@pnpm/pkg-manifest.utils": "1100.2.6",
67
+ "@pnpm/types": "1101.3.2",
68
+ "@pnpm/store.controller-types": "1100.1.7",
69
+ "@pnpm/workspace.spec-parser": "1100.0.0"
70
70
  },
71
71
  "peerDependencies": {
72
72
  "@pnpm/logger": "^1100.0.0"
@@ -77,8 +77,8 @@
77
77
  "@types/ramda": "0.31.1",
78
78
  "@types/semver": "7.7.1",
79
79
  "@types/validate-npm-package-name": "^4.0.2",
80
- "@pnpm/installing.deps-resolver": "1100.2.4",
81
- "@pnpm/logger": "1100.0.0"
80
+ "@pnpm/logger": "1100.0.0",
81
+ "@pnpm/installing.deps-resolver": "1100.2.6"
82
82
  },
83
83
  "engines": {
84
84
  "node": ">=22.13"