pnpm/plans/MULTI_LEVEL_HOISTING.md
nodeLinker: hoisted (multi-level output)Close the last structural gap between pacquet's @yarnpkg/nm hoister port
(pnpm/crates/real-hoist) and upstream: per-importer hoisting roots. Today
nm_hoist runs hoist_into_root against the single virtual . root; upstream
hoistTo recurses into every node marked as a hoist root (workspaces under
hoistingLimits: 'workspaces', direct deps under 'dependencies'), producing a
multi-level tree where each bordered subtree gets its own fixed-point hoist.
hoisted_dep_graph.rs::walk_deps) materializes it there.hoisting_limits set blocks its descendants from hoisting past it
(real-hoist/src/lib.rs::hoist_subtree, under_border).hoist_workspace_packages name-links (v11's hoistedWorkspacePackages) are
a separate, implemented shape — they do not depend on this work.Within a bordered subtree (e.g. a workspace importer under
hoistingLimits: 'workspaces'), upstream still hoists internally: the
importer's transitive deps flatten up to the importer's own node_modules
instead of staying at their natural tree depth. Pacquet leaves them nested.
Nested placement is resolution-correct (Node walks up), so the user-visible
difference is layout/dedupe density, not resolvability — this is why the gap
has been shippable so far.
get_hoisting_limits already emits per-importer border entries for the
'dependencies' mode ("become load-bearing once multi-level hoisting
lands" — package-manager/src/hoisting_limits.rs). Keep that shape.nm_hoist, after the root fixed point, recurse: for each surviving
child that is itself a hoist root (Workspace-kind, or name in a border
set with a per-locator hoisting_limits entry), run hoist_into_root
with that node as the root and its locator's border set. Upstream
reference: hoistTo at yarnpkg-nm/sources/hoist.ts:329 and its
hoistIdents/per-root preference maps.walk_deps) needs no structural change — it already recurses
into Workspace-kind children and places whatever the hoister decided.hoist.test.ts cases for hoistingLimits
('workspaces' and 'dependencies') and the CLI known-failure
partial_install_persists_hoisted_map (pnpm/pacquet#433) which also
depends on re-hoist merging.buildPreferenceMap(rootNode) per hoistTo).