npm Parser: Resolutions and Overrides as Honestly-Scoped Pins
June 27, 2026 · View on GitHub
Summary
The npm package.json parser now emits Yarn resolutions and npm overrides
entries as dependency rows, distinctly scoped ("resolutions" and
"overrides") and flagged as pins (is_pinned = true) while leaving the
intent booleans (is_runtime, is_optional, is_direct) unset.
Previously these blocks were stored opaquely in extra_data and never surfaced
as dependencies, so projects that pin transitive versions exclusively through
resolutions/overrides under-reported their declared dependency surface.
Behavior difference vs the Python reference
The Python reference maps Yarn resolutions to dependencies but forces
is_runtime = true, is_optional = false, and is_direct = true on them, and
it does not surface npm overrides as dependencies at all.
Provenant diverges deliberately on both points:
- Resolutions/overrides are transitive-graph version overrides, not declared
direct runtime dependencies. They prove a pin — a concrete version
constraint the project asserts — but they do not prove runtime-vs-dev,
optional-vs-required, or direct-vs-transitive intent. Per the project's
"honest unknowns over guessed compatibility defaults" guardrail, Provenant
sets
is_pinned = trueand leaves the intent booleans unset rather than asserting semantics the datasource does not establish. overridesis surfaced too. npm'soverridesis the npm-native equivalent of Yarnresolutions; omitting it under-reports the pinned dependency surface for npm-managed projects.
Distinct scopes let downstream consumers separate override pins from real declared dependency edges.
Supported shapes
- Yarn
resolutions:- plain
"pkg": "range"entries - glob-scoped keys such as
**/@scope/pkgandparent/**/pkg(the trailing package selector is used to build the purl) npm:name@rangealiased requirements (unwrapped to the real package name, matching the other npm scopes)
- plain
- npm
overrides:- plain
"pkg": "version"entries - the
name@rangekeyed form (the@rangequalifier is stripped for the purl while a scoped package's leading@is preserved) - nested objects with the
.self-reference (pins the parent package itself) and immediate child overrides
- plain
Scope boundary
npm overrides can nest arbitrarily deep to express path-specific transitive
scoping. The parser expands the top level plus the immediate children of a
nested object; deeper nesting is intentionally not recursively expanded, to
keep parsing bounded and avoid guessing transitive-scoping semantics that the
flat dependency model cannot faithfully represent.
Coverage
Parser unit tests cover plain entries, glob/alias resolutions, the name@range
override key form, and the nested . self-reference. A parser golden locks the
full emitted shape, and a Layer-3 scan/assembly contract test verifies the pins
hoist to top-level dependencies with the expected scope and is_pinned flag
while declared dependencies retain their existing intent semantics.