Repository navigation
feat(pm): add --json flag to bun pm ls and bun list - #35251
khaled4vokalz wants to merge 1 commit into
Conversation
WalkthroughChanges
Package listing JSON output
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/runtime/cli/package_manager_command.rs`:
- Around line 506-512: Update the json_output branch in the package-manager
command before print_ls_json and Global::exit to detect when --trusted is also
present and emit a warning to stderr that trusted-only filtering is unsupported
for JSON output and the flag is ignored; preserve the existing JSON listing
behavior and exit flow.
- Around line 924-961: Update build_dep_info to derive dep_info.path from the
resolved node_modules placement data used by installation, rather than joining
cwd, node_modules, and dep.name. Reuse the dependency’s actual
node_modules-folder/store location so isolated and hoisted layouts resolve the
correct package directory for the selected resolution.
- Around line 861-880: Update print_ls_json’s --all transitiveDependencies
construction to walk every node_modules tree via the same tree::Iterator-based
directory traversal used by non-JSON --all output, rather than relying on
lockfile.buffers.hoisted_dependencies. Preserve dependency filtering,
resolution, naming, and deduplication while including nested or shadowed
packages visible at any depth.
In `@test/cli/install/bun-pm.test.ts`:
- Around line 973-1146: Extend the “bun pm ls --json separates dependencies and
devDependencies” coverage with non-empty optionalDependencies and
peerDependencies entries, install them through the existing dummy registry
setup, and assert the JSON output places each package in its corresponding
optionalDependencies and peerDependencies bucket while excluding them from
unrelated buckets. Keep the existing dependency/devDependency assertions intact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 35932a2b-170f-42b1-9591-9550219a2355
📒 Files selected for processing (3)
src/install/PackageManager.rssrc/runtime/cli/package_manager_command.rstest/cli/install/bun-pm.test.ts
ce74217 to
70d5591
Compare
Add a `--json` flag to `bun pm ls` (and its `bun list` alias) that emits
the dependency tree as JSON instead of the human-readable tree, in a
pnpm-compatible shape for easy scripting.
The output is a single root object with:
- `name`, `version`, `path` for the current project
- `dependencies`, `devDependencies`, `optionalDependencies`,
`peerDependencies` buckets, each keyed by package name with
`{ from, version, path }` entries
- `transitiveDependencies` (only with `--all`)
The four direct-dependency buckets are always emitted (empty object when a
bucket has no members) so consumers get a stable schema.
`transitiveDependencies` is omitted unless `--all` is passed.
Also documents `--json` in the `bun pm`/`bun list` help output and fixes
the alignment of the `bun list` header line, which was two columns short
of its siblings.
This is a port of the original Zig implementation (oven-sh#26223), which was
closed after Bun's package manager was rewritten to Rust. Filtering
support is intentionally deferred to a follow-up.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
70d5591 to
32599e6
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/runtime/cli/package_manager_command.rs`:
- Around line 880-902: Update the transitive dependency emission in the show_all
branch around transitive_deps.put so duplicate package names are handled
explicitly instead of silently replacing prior entries. Preserve every
same-named package from different node_modules locations by aggregating their
dependency objects under one name, or reject duplicates deterministically; do
not emit a single non-representative value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 0cf7d3d7-8d36-418e-b3c0-0045ea495790
📒 Files selected for processing (3)
src/install/PackageManager.rssrc/runtime/cli/package_manager_command.rstest/cli/install/bun-pm.test.ts
| // Transitive deps (only with --all). Sourced from the same tree walk that | ||
| // produced `dep_folders`, so every edge carries its real install path. | ||
| if show_all { | ||
| let mut sorted_transitive: Vec<DependencyID> = dep_folders | ||
| .keys() | ||
| .copied() | ||
| .filter(|id| !direct_dep_ids.contains(id)) | ||
| .collect(); | ||
| sorted_transitive.sort_unstable_by(|a, b| by_name.cmp(*a, *b)); | ||
|
|
||
| for &dependency_id in &sorted_transitive { | ||
| let package_id = resolutions_buf[dependency_id as usize]; | ||
| if package_id as usize >= lockfile.packages.len() { | ||
| continue; | ||
| } | ||
| let dep = &dependencies[dependency_id as usize]; | ||
| let folder_rel = dep_folders.get(&dependency_id).copied().unwrap_or(b"node_modules"); | ||
| let dep_expr = | ||
| build_dep_info(dep, &resolutions[package_id as usize], string_bytes, cwd, folder_rel)?; | ||
| let name = crate::cli::cli_dupe(dep.name.slice(string_bytes)); | ||
| transitive_deps.put(bump, name, dep_expr)?; | ||
| } | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect E::Object::put semantics for duplicate keys
rg -nP 'fn put\b' src/ast -A20
# Check how print_json handles an object with repeated property keys
rg -nP 'EObject|properties' src/js_printer/lib.rs -n | head -40Repository: oven-sh/bun
Length of output: 7605
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- package_manager_command context ---\n'
sed -n '820,915p' src/runtime/cli/package_manager_command.rs
printf '\n--- E::Object put implementation ---\n'
sed -n '1300,1355p' src/ast/e.rs
printf '\n--- as_property implementation ---\n'
sed -n '1180,1305p' src/ast/e.rs
printf '\n--- JSON printer object handling ---\n'
rg -n 'EObjectJSON|EObject|properties' src/js_printer src/runtime -g '*.rs' -A6 -B3 | head -200Repository: oven-sh/bun
Length of output: 240
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- package_manager_command context ---'
sed -n '820,915p' src/runtime/cli/package_manager_command.rs
echo
echo '--- E::Object put implementation ---'
sed -n '1300,1355p' src/ast/e.rs
echo
echo '--- as_property implementation ---'
sed -n '1180,1305p' src/ast/e.rs
echo
echo '--- JSON printer object handling ---'
rg -n 'EObjectJSON|EObject|properties' src/js_printer src/runtime -g '*.rs' -A6 -B3 | head -200Repository: oven-sh/bun
Length of output: 24092
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- JSON printer object property iteration ---'
sed -n '3612,3655p' src/js_printer/lib.rs
echo
echo '--- JS printer object property iteration ---'
sed -n '4340,4575p' src/js_printer/lib.rs
echo
echo '--- package manager command tests around nested paths / duplicate names ---'
sed -n '1,220p' src/runtime/cli/package_manager_command.rs | rg -n 'nested|duplicate|transitive|package|name|node_modules|Conflict|diamond' -A5 -B5 || true
find . -path '*/tests/*' -o -path '*/test/*' -o -name '*package_command*test*' -o -name '*PackageCmd*' | head -50
rg -n 'transitiveDependencies|transitive deps|package_manager_command|nested' . -g '*.rs' -g '*.test.*' -g '*.spec.*' -A6 -B3 | head -240Repository: oven-sh/bun
Length of output: 20337
Avoid one-value-over-one-value merging in transitiveDependencies.
E::Object::put replaces an existing same-named property, so installing the same transitive package in multiple node_modules locations yields a non-deterministic surviving entry. Either report multiple values under each name (for example [{ path: "...", ... }, { path: "...", ... }]) or reject duplicate names deterministically rather than emitting JSON with a single non-representative nested package.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/runtime/cli/package_manager_command.rs` around lines 880 - 902, Update
the transitive dependency emission in the show_all branch around
transitive_deps.put so duplicate package names are handled explicitly instead of
silently replacing prior entries. Preserve every same-named package from
different node_modules locations by aggregating their dependency objects under
one name, or reject duplicates deterministically; do not emit a single
non-representative value.
|
Thank you for this PR, and for porting it from the Zig version after the rewrite.
Three differences from this PR: the document is an array with the root as its only element, as Closing this PR in favor of #40045. The grouped text output that #8283 also asks for is still open for discussion on that issue. |
What does this PR do?
Add a
--jsonflag tobun pm ls(and itsbun listalias) that emitsthe dependency tree as JSON instead of the human-readable tree, in a
pnpm-compatible shape for easy scripting.
The output is a single root object with:
name,version,pathfor the current projectdependencies,devDependencies,optionalDependencies,peerDependenciesbuckets, each keyed by package name with{ from, version, path }entriestransitiveDependencies(only with--all)The four direct-dependency buckets are always emitted (empty object when a
bucket has no members) so consumers get a stable schema.
transitiveDependenciesis omitted unless--allis passed.Also documents
--jsonin thebun pm/bun listhelp output and fixesthe alignment of the
bun listheader line, which was two columns shortof its siblings.
This is a port of the original Zig implementation (#26223), which was
closed after Bun's package manager was rewritten to Rust. Filtering
support is intentionally deferred to a follow-up.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Closes #26222
How did you verify your code works?
Added unit tests
Testing the debug build in my local gives the below output (heroku cli):
$ BUN_DEBUG_QUIET_LOGS=1 ../bun/build/debug/bun-debug list --json { "path": "/my/personal/workspace/cli", "dependencies": { "heroku": { "from": "heroku", "version": "workspace:packages/cli", "path": "/my/personal/workspace/cli/node_modules/heroku" } }, "devDependencies": { "@actions/core": { "from": "@actions/core", "version": "1.11.1", "path": "/my/personal/workspace/cli/node_modules/@actions/core" }, ... "tmp": { "from": "tmp", "version": "0.2.5", "path": "/my/personal/workspace/cli/node_modules/tmp" } } }and with
--allflag the output is:$ BUN_DEBUG_QUIET_LOGS=1 ../bun/build/debug/bun-debug list --json --all { "path": "/my/personal/workspace/cli", "dependencies": { "heroku": { "from": "heroku", "version": "workspace:packages/cli", "path": "/my/personal/workspace/cli/node_modules/heroku" } }, "devDependencies": { "@actions/core": { "from": "@actions/core", "version": "1.11.1", "path": "/my/personal/workspace/cli/node_modules/@actions/core" }, ... "tmp": { "from": "tmp", "version": "0.2.5", "path": "/my/personal/workspace/cli/node_modules/tmp" } }, "transitiveDependencies": { "@actions/exec": { "from": "@actions/exec", "version": "1.1.1", "path": "/my/personal/workspace/cli/node_modules/@actions/exec" }, ... "@aws-sdk/region-config-resolver": { "from": "@aws-sdk/region-config-resolver", "version": "3.969.0", "path": "/my/personal/workspace/cli/node_modules/@aws-sdk/region-config-resolver" }, ... "acorn": { "from": "acorn", "version": "8.15.0", "path": "/my/personal/workspace/cli/node_modules/acorn" }, ... "zod-to-json-schema": { "from": "zod-to-json-schema", "version": "3.25.1", "path": "/my/personal/workspace/cli/node_modules/zod-to-json-schema" } } }