Conversation
iamstarkov
reviewed
Nov 4, 2016
| // TODO: implement | ||
| }) | ||
|
|
||
| test('should reinstall package to the store if it is not in the store.yml', async function (t) { |
iamstarkov
approved these changes
Nov 4, 2016
pull Bot
pushed a commit
to dwongdev/pnpm
that referenced
this pull request
May 14, 2026
…slice 3 close-out) (pnpm#465) Closes out the Slice 3 hoist-algorithm port. Two additions on top of slice 3c's peer-aware hoist: 1. **Multi-round convergence.** The DFS runs in a fixed-point loop — a peer-shadow refusal in one round can be reconsidered in a later round once the blocking ident has moved out of the ancestor chain (or a previously-empty root slot has been filled with a compatible version). Bounded by O(N) rounds since every move is one-way. 2. **`hoistingLimits` enforcement.** The upfront `UnsupportedHoistingLimits` guard is gone; the algorithm now reads `opts.hoisting_limits[root_locator]` and refuses to hoist names listed there. New `AbsorbDecision::Border` variant alongside `Free` / `SameNode` / `Conflict` / `PeerShadow`. Plus a backfill of behavior-pinning tests ported from `@yarnpkg/nm/tests/hoist.test.ts`. ## How multi-round works - `hoist_subtree` returns `bool` for whether it moved any node in the current round. - `hoist_into_root` wraps it in a `loop` that resets `visited` each iteration and exits when a round makes no moves. - Mirrors upstream `hoistTo`'s `do { hoistGraph(); } while (anotherRoundNeeded)` without the per-candidate `dependsOn` bookkeeping; pacquet's coarse re-walk catches the same unlock cases at the cost of revisiting unchanged nodes. Canonical case (`multi_round_unlocks_peer_friendly_hoist_after_blocker_moves`): `root → app → {widget(peer: x), x@1}` with root carrying no `x`. - **Round 1.** Alphabetical iteration visits `widget` first. App supplies `x@1`, root has no `x` → mismatch → `PeerShadow`, widget stays at app. Then `x` is evaluated: `Free`, hoist to root. - **Round 2.** Reconsider widget. App no longer has `x`; root has `x@1`. No ancestor disagreement → `Free`. Widget hoists. - **Round 3.** No moves; loop exits. ## How hoistingLimits works - Computed locator: `"{ident_name}@{reference}"` — for the wrapper's root that's `".@"`, matching pnpm's keying convention. - Border-name set: `opts.hoisting_limits.get(root_locator)`, defaulting to empty when absent. - New `AbsorbDecision::Border` is layered between the basic decision and the peer check. Names in the set never hoist; they stay where the lockfile placed them. - Mirrors upstream's `isHoistBorder` flag set during `cloneTree`. ## Upstream test ports From `yarnpkg/berry@4287909fa6` `packages/yarnpkg-nm/tests/hoist.test.ts`, expressed via lockfile fixtures so they exercise the wrapper too: - **`hoisting_limits_keeps_blocked_name_at_parent`** — `should not hoist packages past hoist boundary`. - **`hoisting_limits_blocks_multiple_names`** — `should not hoist multiple package past nohoist root`. - **`hoisting_limits_keyed_on_unrelated_importer_is_inert`** — non-interference sanity check. - **`self_dependency_does_not_loop`** — `should tolerate self-dependencies`. - **`basic_cyclic_dependency_terminates`** — `should support basic cyclic dependencies`. ## Documented gaps The `nm_hoist` doc-comment now lists what's deferred *intentionally* rather than "not done yet": - **Popularity-based ident preference.** Upstream's `buildPreferenceMap` picks the ident with more incoming references when two distinct deps share an alias; pacquet picks the first-visited. Affects the handful of upstream test cases that exercise the tie-break (`should honor package popularity when hoisting`, etc.). - **Multi-importer workspace hoist trees.** Still guarded upfront by `HoistError::UnsupportedWorkspace`. Workspace-aware hoisting needs per-importer roots and a different output shape. - **`ExternalSoftLink` descendants.** The wrapper only creates soft-links as zero-children placeholders, so upstream's "only-hoist-when-all-descendants-hoist" rule has nothing to delay today. Tests for `should not hoist portal with unhoistable dependencies` and similar were skipped. ## Upstream reference Aligned with `yarnpkg/berry@4287909fa6`: - [`hoist.ts:109-119`](https://github.com/yarnpkg/berry/blob/4287909fa6a0a1ec976a55776bff606864b31990/packages/yarnpkg-nm/sources/hoist.ts#L109-L119) — outer round loop in `hoist`. - [`hoist.ts:352-367`](https://github.com/yarnpkg/berry/blob/4287909fa6a0a1ec976a55776bff606864b31990/packages/yarnpkg-nm/sources/hoist.ts#L352-L367) — inner round loop in `hoistTo`. - [`hoist.ts:707`](https://github.com/yarnpkg/berry/blob/4287909fa6a0a1ec976a55776bff606864b31990/packages/yarnpkg-nm/sources/hoist.ts#L707) — `isHoistBorder` flag during `cloneTree`.
github-actions Bot
pushed a commit
to Eyalm321/pnpm
that referenced
this pull request
May 18, 2026
…slice 3 close-out) (pnpm#465) Closes out the Slice 3 hoist-algorithm port. Two additions on top of slice 3c's peer-aware hoist: 1. **Multi-round convergence.** The DFS runs in a fixed-point loop — a peer-shadow refusal in one round can be reconsidered in a later round once the blocking ident has moved out of the ancestor chain (or a previously-empty root slot has been filled with a compatible version). Bounded by O(N) rounds since every move is one-way. 2. **`hoistingLimits` enforcement.** The upfront `UnsupportedHoistingLimits` guard is gone; the algorithm now reads `opts.hoisting_limits[root_locator]` and refuses to hoist names listed there. New `AbsorbDecision::Border` variant alongside `Free` / `SameNode` / `Conflict` / `PeerShadow`. Plus a backfill of behavior-pinning tests ported from `@yarnpkg/nm/tests/hoist.test.ts`. ## How multi-round works - `hoist_subtree` returns `bool` for whether it moved any node in the current round. - `hoist_into_root` wraps it in a `loop` that resets `visited` each iteration and exits when a round makes no moves. - Mirrors upstream `hoistTo`'s `do { hoistGraph(); } while (anotherRoundNeeded)` without the per-candidate `dependsOn` bookkeeping; pacquet's coarse re-walk catches the same unlock cases at the cost of revisiting unchanged nodes. Canonical case (`multi_round_unlocks_peer_friendly_hoist_after_blocker_moves`): `root → app → {widget(peer: x), x@1}` with root carrying no `x`. - **Round 1.** Alphabetical iteration visits `widget` first. App supplies `x@1`, root has no `x` → mismatch → `PeerShadow`, widget stays at app. Then `x` is evaluated: `Free`, hoist to root. - **Round 2.** Reconsider widget. App no longer has `x`; root has `x@1`. No ancestor disagreement → `Free`. Widget hoists. - **Round 3.** No moves; loop exits. ## How hoistingLimits works - Computed locator: `"{ident_name}@{reference}"` — for the wrapper's root that's `".@"`, matching pnpm's keying convention. - Border-name set: `opts.hoisting_limits.get(root_locator)`, defaulting to empty when absent. - New `AbsorbDecision::Border` is layered between the basic decision and the peer check. Names in the set never hoist; they stay where the lockfile placed them. - Mirrors upstream's `isHoistBorder` flag set during `cloneTree`. ## Upstream test ports From `yarnpkg/berry@4287909fa6` `packages/yarnpkg-nm/tests/hoist.test.ts`, expressed via lockfile fixtures so they exercise the wrapper too: - **`hoisting_limits_keeps_blocked_name_at_parent`** — `should not hoist packages past hoist boundary`. - **`hoisting_limits_blocks_multiple_names`** — `should not hoist multiple package past nohoist root`. - **`hoisting_limits_keyed_on_unrelated_importer_is_inert`** — non-interference sanity check. - **`self_dependency_does_not_loop`** — `should tolerate self-dependencies`. - **`basic_cyclic_dependency_terminates`** — `should support basic cyclic dependencies`. ## Documented gaps The `nm_hoist` doc-comment now lists what's deferred *intentionally* rather than "not done yet": - **Popularity-based ident preference.** Upstream's `buildPreferenceMap` picks the ident with more incoming references when two distinct deps share an alias; pacquet picks the first-visited. Affects the handful of upstream test cases that exercise the tie-break (`should honor package popularity when hoisting`, etc.). - **Multi-importer workspace hoist trees.** Still guarded upfront by `HoistError::UnsupportedWorkspace`. Workspace-aware hoisting needs per-importer roots and a different output shape. - **`ExternalSoftLink` descendants.** The wrapper only creates soft-links as zero-children placeholders, so upstream's "only-hoist-when-all-descendants-hoist" rule has nothing to delay today. Tests for `should not hoist portal with unhoistable dependencies` and similar were skipped. ## Upstream reference Aligned with `yarnpkg/berry@4287909fa6`: - [`hoist.ts:109-119`](https://github.com/yarnpkg/berry/blob/4287909fa6a0a1ec976a55776bff606864b31990/packages/yarnpkg-nm/sources/hoist.ts#L109-L119) — outer round loop in `hoist`. - [`hoist.ts:352-367`](https://github.com/yarnpkg/berry/blob/4287909fa6a0a1ec976a55776bff606864b31990/packages/yarnpkg-nm/sources/hoist.ts#L352-L367) — inner round loop in `hoistTo`. - [`hoist.ts:707`](https://github.com/yarnpkg/berry/blob/4287909fa6a0a1ec976a55776bff606864b31990/packages/yarnpkg-nm/sources/hoist.ts#L707) — `isHoistBorder` flag during `cloneTree`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Close #462