fix(arborist): don't load store packages' devDependencies as required edges#9633
Merged
Merged
Conversation
… edges (npm#9626) In continuation of our exploration of using `install-strategy=linked` in the [Gutenberg monorepo](WordPress/gutenberg#75814), which powers the WordPress Block Editor. Under `install-strategy=linked`, `npm sbom` exited non-zero with `ESBOMPROBLEMS`, reporting the devDependencies of transitive packages (e.g. `matcha`, `tape`) as `missing: ... required by ...`. Those dev dependencies are correctly not installed (the same is true under hoisted), yet only the linked strategy treated them as missing-and-required. Hoisted produced a clean SBOM for the same dependency set. A package in the linked strategy's store lives at `node_modules/.store/<key>/node_modules/<pkg>`, which makes it a structural tree top (`isTop`, no parent). `Node._loadDeps` loads devDependencies for every top node, so each store package — a transitive dependency whose devDependencies are never installed — gained required `dev` edges. `npm sbom` reads the filesystem tree via `loadActual`, queries it, and flags every non-optional missing edge, so those spurious dev edges surfaced as `ESBOMPROBLEMS`. Standalone `npm audit` was unaffected because it audits the virtual tree from the lockfile. Hoisted was unaffected because its transitive packages have a real parent, so they are not tops and never load devDependencies. `load-actual.js` now flags a node as `isInStore` when its realpath sits inside a `node_modules/.store/` directory, matching the flag the isolated reifier already sets on ideal-tree store nodes. `Node._loadDeps` excludes store nodes from the devDependency load (`isTop && !globalTop && path && !this.isInStore`), so a store package — a transitive dependency by definition — never gains required dev edges. This makes the linked actual tree's edge semantics match hoisted. Fixes npm#9610 Part of npm#9608
owlstronaut
approved these changes
Jun 24, 2026
owlstronaut
pushed a commit
that referenced
this pull request
Jun 24, 2026
Restores the global 100% coverage gate on `release/v11`, which broke after #9633. `filterLinkedStrategyEdges` in `lib/commands/ls.js` skips dev edges on non-root (store) packages — a guard added in #9095 to suppress false `UNMET DEPENDENCY` output in the linked strategy. #9633 fixed the root cause (store packages no longer load `devDependencies` as required edges), so the test suite no longer produces a store package with a dev edge, leaving that branch unexercised. The guard is kept as defensive (a store package could still carry a dev edge in untested paths) and marked `istanbul ignore`, so behavior is unchanged. The full test suite passes at 100%. This gap is invisible on direct pushes to `release/v11` because the Test matrix only runs on PRs, so it surfaces on the first PR after #9633. ## References Follows up #9633
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.
Backport of #9626 to
release/v11.Under
install-strategy=linked,npm sbomexited withESBOMPROBLEMS, reporting transitive packages' devDependencies as missing/required. A store package lives atnode_modules/.store/<key>/node_modules/<pkg>, which makes it a structural tree top, soNode._loadDepsloaded its devDependencies as required edges.loadActualnow flags such nodesisInStoreand_loadDepsskips devDependencies for them, matching the hoisted strategy.Cherry-picked cleanly except for a test-file context conflict: the unrelated
applies root packageExtensions to a linked actual treetest (not part of this PR and not present onrelease/v11) was dropped from the resolution; only this fix's two regression tests are included.References
Backports #9626