install: make `bun outdated` and `bun update -i` read dependency ranges from package.json
Closed
RO
1mo ago+567+567+012345678901234567890123456789-440-440-012345678901234567890123456789
Problem
bun outdatedandbun update -icompute the "Update" / "Target" column from the dependency range stored in bun.lock, not from package.json. Change"no-deps": "1.0.0"to"^1.0.0"without a reinstall and both still print1.0.0. A dependency removed from package.json stays listed (as #34262 reports).- The cause:
print_outdated_info_table(src/runtime/cli/outdated_command.rs:365) and its copyget_outdated_packages(update_interactive_command.rs:847) walk the lockfile's dependency rows, which keep the names, groups and ranges of the lastbun install.
Fix
- Add
DeclaredDependenciestobun_install. It parses the root and each selected workspace package.json the waybun installdoes and joins each declared npm dependency, by name and group, with the package bun.lock installed for it. Both commands iterate it. - Correct because
bun installmakes the same split: it diffs a fresh package.json parse against the lockfile, which records what is installed, not what is wanted. - Self-reviewed: 6 concerns raised, 6 addressed (the first draft fixed
bun outdatedalone). - Verified: new cases in
test/cli/install/bun-install-registry.test.tsandtest/cli/update_interactive_formatting.test.ts, both failing on stock bun, plus every otheroutdatedandupdate -itest.
Background
- Both commands print, per direct dependency,
Current(installed),Update/Target(best version in the declared range) andLatest(latestdist-tag). - bun.lock stores, per workspace package, a copy of its package.json dependency list at the last install, next to the resolved package of each entry.
ScratchManifests(workspace_manifests.rs) parses package.json files into a throw-awayLockfile, asbun add --filteralready does.DeclaredDependenciesis a public facade over it.
Notes
- Repro without the tests:
echo '{"name":"app","dependencies":{"pkg":"1.0.0"}}' > package.json && bun install, change"1.0.0"to"^1.0.0", runbun outdated. Before:Update 1.0.0, whilenpm outdatedprints the new wanted version for the same tree. A no-opbun installrefreshes the lockfile copy and the nextbun outdatedis right, which shows where the range came from. - The
bun outdatedtest ("reads dependency ranges from package.json, not bun.lock") covers four cases in one table: a changed root range (~1.0.0), a changed catalog range used by a member (catalog:), a member dependency that changed range and moved todevDependencies, and a root dependency removed from package.json. It also checks that bun.lockb is byte-identical afterwards. Theupdate -itest ("should offer what package.json declares now, not what bun.lock recorded") covers a widened range, a moved group and a removed dependency, and checks bun.lock is untouched. WorkspaceTarget::of_lockfile_packageis the former privatetarget_forofaudit_fix/package_json_edits.rs.same_rowis the former private helper ofpackage_json_write_back.rs. Both move next toScratchManifestsso each has one copy.DeclaredDependenciesusessame_rowto match a declared dependency to its lockfile row, and falls back to a same-name row when the dependency moved to another group.- A dependency that is in package.json but has no lockfile row yet (added, never installed) is still not listed, as before. npm prints
MISSINGfor it. Left for a follow-up. - A workspace whose package.json cannot be read now fails the command with
failed to read/parse package.json for workspace '<name>', the messagebun add --filteruses. Before, its stale lockfile rows were printed. Plainbun outdated(no--filter/-r) only reads the root and the current workspace, whichbun installalready requires. bun update -i's "Checked N dependencies" line now counts declared npm dependencies that are installed. It no longer countsworkspace:links or git dependencies, which it never offered anyway.bun update(non-interactive) already excluded workspace links.- The root parse uses
Features::main(), so it walks theworkspacesglobs like an install. That keeps fidelity: a root dependency that names a workspace member by version becomes aworkspace:dependency only through that walk. - #38813 touches the same file for pack/publish. This PR keeps
ScratchManifestscrate-private behind a public facade, the shape #38813 uses, and the samecrash(log, err, what)helper, so either order rebases cleanly. - Also in the first pass of
bun outdated: the installed version is now formatted with the lockfile string buffer in the two fallback branches (it was formatted with the manifest buffer, which mis-sizes the column for a pre-release current version). #38649 changes the same two lines. - Other suites run locally:
bun-update-transitive.test.ts(all 174),bun-add-filter.test.ts,bun-audit.test.ts -t fix,update_interactive_install.test.ts,update_interactive_snapshots.test.ts, theoutdatedtests inbun-update.test.tsandminimum-release-age.test.ts.
no test proof · iteration 0 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/cli/update_interactive_formatting.test.ts, test/cli/install/bun-install-registry.test.ts