Files
pnpm/installing
David Barratt 29a496ac7c fix: make peer-dependent deduplication deterministic (#12179)
* fix(deps-resolver): make peer-dependent deduplication deterministic

When a peer-suffixed package variant is a subset of two or more mutually
incompatible larger variants, `deduplicateDepPaths` chose which one to
collapse it into based on the order dep paths were inserted into the
per-pkgId set, which reflects importer/resolution order and varies between
platforms. The same workspace could then resolve to different lockfiles on
different machines, making `pnpm dedupe --check` alternate between pass and
fail.

The depth-count sorter `nodeDepsCount(a) - nodeDepsCount(b)` is not a total
order, so equal-count variants keep their (order-dependent) relative
position. Tie-break on the dep path string to give a deterministic winner
regardless of insertion order.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(deps-resolver): assert resolved depPath is defined before order check

The order-invariance assertion compared two undefined values, which would
pass silently if the depPath never resolved. Assert both are defined first.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(pacquet): port dedupePeerDependents collapse

Port pnpm's `dedupePeerDependents` pass (resolvePeers tail block +
`deduplicateAll` / `deduplicateDepPaths` / `nodeDepsCount` /
`isCompatibleAndHasMoreDeps`) into pacquet, carrying the pnpm/pnpm#12179
determinism fix: the collapse target is chosen by a total order over
`(dep count, dep path)` so it no longer depends on importer/resolution
order.

Runs in `resolve_peers_workspace` after `dedupe_injected_deps`, gated on
`config.dedupe_peer_dependents` (default true) threaded through
`WorkspaceResolveOptions`. Duplicate variant groups are reconstructed by
grouping the finished graph on `resolved_package_id` instead of threading
pnpm's `depPathsByPkgId` through the walk. Since pacquet has no unified
post-resolve lockfile pruner, the pass reuses
`dedupe_injected_deps::prune_unreachable` to drop collapsed orphans so
they don't surface in the lockfile.

Both unit tests from pnpm's dedupeDepPaths.test.ts are ported (the
version-mismatch collapse and the importer-order determinism case),
plus end-to-end remap+prune and incompatible-variant coverage.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-06-08 12:44:55 +02:00
..
2026-06-05 08:27:41 +02:00
2026-06-05 08:27:41 +02:00
2026-06-05 08:27:41 +02:00
2026-06-05 08:27:41 +02:00
2026-06-05 08:27:41 +02:00