Skip to content

fix(install): use includePrerelease semantics for peer dep validation#27085

Closed
ramonclaudio wants to merge 2 commits into
oven-sh:mainfrom
ramonclaudio:fix/peer-dep-prerelease-semver
Closed

fix(install): use includePrerelease semantics for peer dep validation#27085
ramonclaudio wants to merge 2 commits into
oven-sh:mainfrom
ramonclaudio:fix/peer-dep-prerelease-semver

Conversation

@ramonclaudio

@ramonclaudio ramonclaudio commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #29444.

Bun warns incorrect peer dependency for any prerelease version validated against a peer range with no prerelease comparator on the same major.minor.patch. Hits every package on a -canary/-rc/-next channel: expo canary, react-native nightlies, anything shipping prereleases to users.

List.satisfiesPre in src/semver/SemverQuery.zig gates on a pre_matched flag that only flips when a range comparator carries a prerelease tag on the same major.minor.patch. 56.0.0-canary fails against >=14.0.4 because the range has no prerelease comparator, even though 56 > 14. Same for * (desugars to >=0.0.0).

yarn v1 fixed this in 2017 (satisfiesWithPrereleases, yarnpkg/yarn#3361). node-semver has { includePrerelease: true } built in. npm/rfcs#397 open since 2021. Bun auto-installs peer deps, so users hit this with no escape hatch.

Fix adds List.satisfiesIncludePrerelease and Group.satisfiesIncludePrerelease alongside the existing satisfiesPre, skipping the pre_matched gate. resolutionSatisfiesDependency switches to the new method. Existing satisfiesPre signature is untouched, strict semver resolution path is unchanged.

Scope check: resolutionSatisfiesDependency has two callers, both inside if (install_peer and behavior.isPeer()). Change is confined to peer-dep validation. Regular version resolution stays strict.

before:

$ bun install
warn: incorrect peer dependency "react@19.3.0-canary-3e319a94-20260126"

after:

$ bun install
(no warnings)

How did you verify your code works?

  • New integration test in test/cli/install/bun-install-registry.test.ts: a local package declares peerDependencies: { "prereleases-3": ">=1.0.0" }, installs alongside prereleases-3@5.0.0-alpha.150. Asserts the warning does not fire.
  • Regression assertions in test/cli/install/semver.test.ts: locks Bun.semver.satisfies to strict semver so the fix does not leak includePrerelease semantics into general resolution.
  • A/B tested on a fresh oven-sh/bun clone: baseline binary reproduces the warning, patched binary does not. Same test file, same test runner, only the binary differs.
  • Real-world A/B: bun add expo@canary react-native@nightly react@19.3.0-canary-3e319a94-20260126 fires 21 incorrect peer dependency warnings on oven-sh/bun@main, 0 with this patch applied.
  • All 29 existing peer-dep install tests in bun-install-registry.test.ts pass unchanged.

Relates to #26076, #15711.

@coderabbitai

coderabbitai Bot commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds include-prerelease satisfaction logic to enable prerelease versions to satisfy version ranges without prerelease tags. Modifies npm/npm dependency satisfaction in PackageManagerEnqueue and introduces two new satisfiesIncludePrerelease methods in SemverQuery for List and Group.

Changes

Cohort / File(s) Summary
PackageManager Enqueue Updates
src/install/PackageManager/PackageManagerEnqueue.zig
Modified npm/npm dependency satisfaction to use satisfiesIncludePrerelease instead of satisfies, enabling prerelease versions to satisfy ranges without prerelease tags.
Semver Query Prerelease Methods
src/semver/SemverQuery.zig
Added satisfiesIncludePrerelease methods to List and Group structs to enable prerelease versions to match version ranges even when comparators lack prerelease tags.
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: using includePrerelease semantics for peer dependency validation, which directly addresses the main issue in the changeset.
Description check ✅ Passed The PR description comprehensively covers both required template sections with detailed context and verification methods.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ramonclaudio ramonclaudio force-pushed the fix/peer-dep-prerelease-semver branch from ef50df4 to 2f70d05 Compare February 17, 2026 14:26
@claude

claude Bot commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

Newest first

016c3 — Looks good!

Reviewed 2 files across src/semver/ and src/install/: Fixes false peer dependency warnings for prerelease versions (e.g., '56.0.0-canary') by using includePrerelease semantics in semver validation.

Previous reviews

Code Review

Newest first

2f70d — Looks good!

Reviewed 4 files across src/semver/ and src/install/: Fixes false peer dependency warnings for prerelease versions by adding includePrerelease semantics to semver validation so that prerelease versions like 2.1.0-alpha.1 satisfy ranges like ^2.0.0.


Powered by Claude Code Review

Prerelease versions like `56.0.0-canary-20260212-4f61309` incorrectly
trigger "incorrect peer dependency" warnings when checked against ranges
like `>=14.0.4` or `*`. The strict semver `pre_matched` gate in
`List.satisfiesPre` requires comparators to share the same
major.minor.patch with a prerelease tag, which fails for ranges without
prerelease comparators.

Yarn v1 fixed the same issue in 2017 (yarnpkg/yarn#3361) via
`satisfiesWithPrereleases`. node-semver exposes
`{ includePrerelease: true }` as a built-in option. npm/rfcs#397 has
been open since 2021 proposing similar semantics.

Add `satisfiesIncludePrerelease` methods to `List` and `Group` in
`SemverQuery.zig` that skip the `pre_matched` gate, then call from
`resolutionSatisfiesDependency` which is exclusively used for peer
dependency validation. Strict semver resolution path stays strict.

Fixes oven-sh#29444
Relates to oven-sh#26076, oven-sh#15711
@ramonclaudio ramonclaudio force-pushed the fix/peer-dep-prerelease-semver branch from 8341f70 to bb637d7 Compare April 18, 2026 13:01
ramonclaudio added a commit to ramonclaudio/bun-fork that referenced this pull request May 14, 2026
… versions

Removes the install_peer && behavior.is_peer() block from get_or_put_resolved_package
(PackageManagerEnqueue.rs) and the resolution_satisfies_dependency helper that only
that block called. Peers now flow through findBestVersion; dedup and the
'incorrect peer dependency' warning live in Tree::hoist_dependency where placement
is deterministic.

Adds satisfies_include_prerelease on Group and List in SemverQuery.rs — the
strict-semver siblings of satisfies_pre without the pre_matched gate. Wired into
the peer paths in Tree::hoist_dependency so prerelease resolutions like
5.0.0-alpha.150 are accepted against ranges like >=1.0.0 (node-semver
includePrerelease / yarn v1 satisfiesWithPrereleases semantics). The strict
resolver path is untouched; Bun.semver.satisfies() keeps current behavior.

Combines oven-sh#29804 (Dylan Conway, Zig-era refactor) with oven-sh#27085 (prerelease semver
fix). Both were stuck pre-rewrite and don't apply to the Rust tree. Fixes oven-sh#29444.
ramonclaudio added a commit to ramonclaudio/bun-fork that referenced this pull request May 15, 2026
… versions

Removes the install_peer && behavior.is_peer() block from
get_or_put_resolved_package (PackageManagerEnqueue.rs) and the
resolution_satisfies_dependency helper that only that block called. Peers
now flow through findBestVersion. Dedup and the "incorrect peer
dependency" warning live in Tree::hoist_dependency where placement is
deterministic.

Adds satisfies_include_prerelease on Group and List in SemverQuery.rs,
the strict-semver siblings of satisfies_pre without the pre_matched
gate. Wired into the peer paths in Tree::hoist_dependency so prerelease
resolutions like 5.0.0-alpha.150 are accepted against ranges like
>=1.0.0 (node-semver includePrerelease, yarn v1 satisfiesWithPrereleases
semantics). The strict resolver path is untouched. Bun.semver.satisfies()
keeps current behavior.

Combines oven-sh#29804 (Dylan Conway, Zig-era refactor) with oven-sh#27085 (prerelease
semver fix). Both were stuck pre-rewrite and don't apply to the Rust
tree. Fixes oven-sh#29444.
ramonclaudio added a commit to ramonclaudio/bun-fork that referenced this pull request May 15, 2026
… versions

Removes the install_peer && behavior.is_peer() block from
get_or_put_resolved_package (PackageManagerEnqueue.rs) and the
resolution_satisfies_dependency helper that only that block called. Peers
now flow through findBestVersion. Dedup and the "incorrect peer
dependency" warning live in Tree::hoist_dependency where placement is
deterministic.

Adds satisfies_include_prerelease on Group and List in SemverQuery.rs,
the strict-semver siblings of satisfies_pre without the pre_matched
gate. Wired into the peer paths in Tree::hoist_dependency so prerelease
resolutions like 5.0.0-alpha.150 are accepted against ranges like
>=1.0.0 (node-semver includePrerelease, yarn v1 satisfiesWithPrereleases
semantics). The strict resolver path is untouched. Bun.semver.satisfies()
keeps current behavior.

Combines oven-sh#29804 (Dylan Conway, Zig-era refactor) with oven-sh#27085 (prerelease
semver fix). Both were stuck pre-rewrite and don't apply to the Rust
tree. Fixes oven-sh#29444.
ramonclaudio added a commit to ramonclaudio/bun-fork that referenced this pull request May 15, 2026
… versions

Removes the install_peer && behavior.is_peer() block from
get_or_put_resolved_package (PackageManagerEnqueue.rs) and the
resolution_satisfies_dependency helper that only that block called. Peers
now flow through findBestVersion. Dedup and the "incorrect peer
dependency" warning live in Tree::hoist_dependency where placement is
deterministic.

Adds satisfies_include_prerelease on Group and List in SemverQuery.rs,
the strict-semver siblings of satisfies_pre without the pre_matched
gate. Wired into the peer paths in Tree::hoist_dependency so prerelease
resolutions like 5.0.0-alpha.150 are accepted against ranges like
>=1.0.0 (node-semver includePrerelease, yarn v1 satisfiesWithPrereleases
semantics). The strict resolver path is untouched. Bun.semver.satisfies()
keeps current behavior.

Combines oven-sh#29804 (Dylan Conway, Zig-era refactor) with oven-sh#27085 (prerelease
semver fix). Both were stuck pre-rewrite and don't apply to the Rust
tree. Fixes oven-sh#29444.
ramonclaudio added a commit to ramonclaudio/bun-fork that referenced this pull request May 15, 2026
… versions

Removes the install_peer && behavior.is_peer() block from
get_or_put_resolved_package (PackageManagerEnqueue.rs) and the
resolution_satisfies_dependency helper that only that block called. Peers
now flow through findBestVersion. Dedup and the "incorrect peer
dependency" warning live in Tree::hoist_dependency where placement is
deterministic.

Adds satisfies_include_prerelease on Group and List in SemverQuery.rs,
the strict-semver siblings of satisfies_pre without the pre_matched
gate. Wired into the peer paths in Tree::hoist_dependency so prerelease
resolutions like 5.0.0-alpha.150 are accepted against ranges like
>=1.0.0 (node-semver includePrerelease, yarn v1 satisfiesWithPrereleases
semantics). The strict resolver path is untouched. Bun.semver.satisfies()
keeps current behavior.

Combines oven-sh#29804 (Dylan Conway, Zig-era refactor) with oven-sh#27085 (prerelease
semver fix). Both were stuck pre-rewrite and don't apply to the Rust
tree. Fixes oven-sh#29444.
ramonclaudio added a commit to ramonclaudio/bun-fork that referenced this pull request May 15, 2026
… versions

Removes the install_peer && behavior.is_peer() block from
get_or_put_resolved_package (PackageManagerEnqueue.rs) and the
resolution_satisfies_dependency helper that only that block called. Peers
now flow through findBestVersion. Dedup and the "incorrect peer
dependency" warning live in Tree::hoist_dependency where placement is
deterministic.

Adds satisfies_include_prerelease on Group and List in SemverQuery.rs,
the strict-semver siblings of satisfies_pre without the pre_matched
gate. Wired into the peer paths in Tree::hoist_dependency so prerelease
resolutions like 5.0.0-alpha.150 are accepted against ranges like
>=1.0.0 (node-semver includePrerelease, yarn v1 satisfiesWithPrereleases
semantics). The strict resolver path is untouched. Bun.semver.satisfies()
keeps current behavior.

Combines oven-sh#29804 (Dylan Conway, Zig-era refactor) with oven-sh#27085 (prerelease
semver fix). Both were stuck pre-rewrite and don't apply to the Rust
tree. Fixes oven-sh#29444.
ramonclaudio added a commit to ramonclaudio/bun-fork that referenced this pull request May 15, 2026
… versions

Removes the install_peer && behavior.is_peer() block from
get_or_put_resolved_package (PackageManagerEnqueue.rs) and the
resolution_satisfies_dependency helper that only that block called. Peers
now flow through findBestVersion. Dedup and the "incorrect peer
dependency" warning live in Tree::hoist_dependency where placement is
deterministic.

Adds satisfies_include_prerelease on Group and List in SemverQuery.rs,
the strict-semver siblings of satisfies_pre without the pre_matched
gate. Wired into the peer paths in Tree::hoist_dependency so prerelease
resolutions like 5.0.0-alpha.150 are accepted against ranges like
>=1.0.0 (node-semver includePrerelease, yarn v1 satisfiesWithPrereleases
semantics). The strict resolver path is untouched. Bun.semver.satisfies()
keeps current behavior.

Combines oven-sh#29804 (Dylan Conway, Zig-era refactor) with oven-sh#27085 (prerelease
semver fix). Both were stuck pre-rewrite and don't apply to the Rust
tree. Fixes oven-sh#29444.
ramonclaudio added a commit to ramonclaudio/bun-fork that referenced this pull request May 15, 2026
… versions

Removes the install_peer && behavior.is_peer() block from
get_or_put_resolved_package (PackageManagerEnqueue.rs) and the
resolution_satisfies_dependency helper that only that block called. Peers
now flow through findBestVersion. Dedup and the "incorrect peer
dependency" warning live in Tree::hoist_dependency where placement is
deterministic.

Adds satisfies_include_prerelease on Group and List in SemverQuery.rs,
the strict-semver siblings of satisfies_pre without the pre_matched
gate. Wired into the peer paths in Tree::hoist_dependency so prerelease
resolutions like 5.0.0-alpha.150 are accepted against ranges like
>=1.0.0 (node-semver includePrerelease, yarn v1 satisfiesWithPrereleases
semantics). The strict resolver path is untouched. Bun.semver.satisfies()
keeps current behavior.

Combines oven-sh#29804 (Dylan Conway, Zig-era refactor) with oven-sh#27085 (prerelease
semver fix). Both were stuck pre-rewrite and don't apply to the Rust
tree. Fixes oven-sh#29444.
@ramonclaudio

Copy link
Copy Markdown
Contributor Author

Superseded by the Rust port. The order-determinism half (Dylan's #29804) is in #30855, and the prerelease-semver fix that originally lived here follows in a separate Rust PR once that lands. The fix code is preserved on fix/install-peer-dep-prerelease on my fork. Closing here since the Zig base files are reference-only post-#30412.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bun install warns on valid prereleases in peer deps

1 participant