Skip to content

Match Node's console.table index column header and alignment - #32619

Closed
robobun wants to merge 2 commits into
mainfrom
farm/64abbb39/console-table-node-compat
Closed

robobun wants to merge 2 commits into
mainfrom
farm/64abbb39/console-table-node-compat

Conversation

@robobun

@robobun robobun commented Jun 22, 2026 •

Copy link
Copy Markdown
Collaborator

What

console.table (and node:console's table, plus Bun.inspect.table, which share the native TablePrinter) left the first column header blank and right-aligned that column. Node labels it (index), or (iteration index) for Map/Set, and left-aligns it.

import { table } from "node:console";
table([{ a: 1, b: "Y" }, { a: "Z", b: 2 }]);

Before:

┌───┬───┬───┐
│   │ a │ b │
├───┼───┼───┤
│ 0 │ 1 │ Y │
│ 1 │ Z │ 2 │
└───┴───┴───┘

After (Node's header and alignment):

┌─────────┬───┬───┐
│ (index) │ a │ b │
├─────────┼───┼───┤
│ 0       │ 1 │ Y │
│ 1       │ Z │ 2 │
└─────────┴───┴───┘

Cause

print_table always created the first column named " " (a single space), and print_row right-aligned that column. The blank header was invisible because the column was never wider than its numeric keys; widening it to the real header name also exposed the right-alignment, which Node does not do.

Fix

  • Name the index column (index), or (iteration index) for Map/Set (via the existing JSType::is_map/is_set). The column width already grows to fit the header name.
  • Left-align the index column.

Map/Set also pick up the (iteration index) header:

┌───────────────────┬─────┬────────┐
│ (iteration index) │ Key │ Values │
├───────────────────┼─────┼────────┤
│ 0                 │ a   │ 42     │
└───────────────────┴─────┴────────┘

Scope

Issue #32614 also notes that Node quotes string cell values ('Y' vs Bun's bare Y). Whether to quote/escape string cells is the same user-visible decision already open in #32224 and #29084, which touch the same lines. To avoid competing changes there, this PR is limited to the index column and leaves string-cell rendering unchanged.

Verification

bun bd test test/js/bun/console/console-table.test.ts test/js/bun/console/bun-inspect-table.test.ts

passes. The added console.table / node:console regression tests fail on the current release and pass with this change. Both snapshot files are regenerated; the only diffs are the index column header and its alignment.

Rebase note

Rebased onto main after #32924 ("console.table: invoke each cell getter once") landed and refactored the same TablePrinter (rows are now collected once into CollectedRow, RowKey::Str became a struct variant, and print_row is &self). Re-applied the three changes on top of the new structure:

  • the (index)/(iteration index) header naming,
  • the left-alignment padding swap in print_row,
  • the strict is_map field gating the Map "Key" column and key/value extraction.

Also updated the hardcoded table strings in #32924's new "console.table reads each cell once" tests to the (index) layout, and regenerated both snapshot files. No behavioral interaction with the getter-once change: the cell-collection path is unchanged.

@robobun

robobun commented Jun 22, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 12:00 AM PT - Jun 29th, 2026

❌ @robobun, your commit 71f18b1 has 1 failures in Build #66628 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 32619

That installs a local version of the PR into your bun-32619 executable, so you can run:

bun-32619 --bun

@coderabbitai

coderabbitai Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bc00fb9a-f59d-4cd3-b463-7d0f581b2c63

📥 Commits

Reviewing files that changed from the base of the PR and between 6ad9434 and 71f18b1.

📒 Files selected for processing (1)
  • docs/runtime/utils.mdx

Walkthrough

console.table now distinguishes strict Map from WeakMap, left-aligns the index column, and uses "(index)" or "(iteration index)" headers. Tests and docs were updated to match the revised ASCII table output and weak collection handling.

Changes

console.table Node Compatibility

Layer / File(s) Summary
Map distinction field
src/jsc/ConsoleObject.rs
TablePrinter stores strict Map state in is_map, and TablePrinter::init sets it from jstype == JSType::Map.
Index column rendering
src/jsc/ConsoleObject.rs
update_columns_for_row, print_row, and print_table use the strict Map flag to gate Map-specific columns, left-align the index column, and emit "(iteration index)" or "(index)" as the first header.
Output tests
test/js/bun/console/console-table.test.ts
console.table repeat 50 is updated for the new frame layout, and new subprocess tests assert exact stdout for arrays, plain objects, Map, Set, WeakMap, and WeakSet, including node:console parity and exit codes.
Documentation examples
docs/runtime/utils.mdx
Two Bun.inspect.table example outputs are updated to show the explicit (index) header and the revised table borders and spacing.

Possibly related PRs

  • oven-sh/bun#32924: Also changes src/jsc/ConsoleObject.rs TablePrinter rendering paths around print_row/print_table, including Map/Keys/Values handling and table formatting.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: matching Node's console.table index header and alignment.
Description check ✅ Passed The description covers what changed and how it was verified, even though it uses custom headings instead of the template text.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@test/js/bun/console/console-table.test.ts`:
- Around line 251-257: The test function starting with "table from node:console
matches global console.table" executes two subprocess calls via run() on lines
253-254 but does not verify their exit status. Add assertions to check that both
the fromImport and fromGlobal results include a successful exit code (typically
exitCode === 0 or similar property from the run() return value) to ensure
subprocess failures are properly detected rather than silently masked by
subsequent output comparisons.
🪄 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

Run ID: 56c5aa2b-7fcf-4228-9047-0e77512d4236

📥 Commits

Reviewing files that changed from the base of the PR and between 0672e7d and 41411cc.

⛔ Files ignored due to path filters (2)
  • test/js/bun/console/__snapshots__/bun-inspect-table.test.ts.snap is excluded by !**/*.snap
  • test/js/bun/console/__snapshots__/console-table.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • src/jsc/ConsoleObject.rs
  • test/js/bun/console/console-table.test.ts

Comment thread test/js/bun/console/console-table.test.ts
Comment thread src/jsc/ConsoleObject.rs
Comment thread test/js/bun/console/console-table.test.ts Outdated
Comment thread src/jsc/ConsoleObject.rs Outdated
@mintlify

mintlify Bot commented Jun 22, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
bun 🟢 Ready View Preview Jun 22, 2026, 11:51 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Comment thread src/jsc/ConsoleObject.rs Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — the crash fix in 6ad9434 looks right (all four is_map consumers now share the single strict field), and the remaining MapIterator/SetIterator header nit is cosmetic and non-blocking.

Extended reasoning...

Overview

This PR aligns console.table / Bun.inspect.table / node:console's table with Node's output: the first column is now labeled (index) (or (iteration index) for Map/Set) and left-aligned, instead of blank and right-aligned. Touches:

  • src/jsc/ConsoleObject.rs: ~30 lines — adds a strict is_map: bool field to TablePrinter, swaps padding order in print_row, and names the index column in print_table.
  • Two snapshot files (mechanical regeneration).
  • test/js/bun/console/console-table.test.ts: updated existing literal + new describe.concurrent block with 7 subprocess tests covering arrays, objects, Map, Set, WeakMap/WeakSet, and the WeakMap-with-expando crash case.
  • docs/runtime/utils.mdx: regenerated two example output blocks.

Review history

This PR has been through two prior review rounds from me. Round 1 flagged stale docs, sequential subprocess tests, and the WeakMap/WeakSet header edge case — all fixed in 0e1ff80. Round 2 caught a real crash regression introduced by 0e1ff80 (producer/consumer desync on the Key column for a WeakMap with an own property) — fixed in 6ad9434 by storing a single strict is_map on TablePrinter that all four sites share. I verified the current code: lines 740, 865, 870, 954, 965 all read self.is_map; no loose jstype.is_map() consumers remain. A regression test for the crash case was added. CodeRabbit's exit-code feedback was also addressed in e3a4c0e.

Security risks

None. This is purely cosmetic output formatting of a debugging API (console.table). No untrusted input parsing beyond what already existed, no auth/crypto/permissions, no network or filesystem effects.

Level of scrutiny

Low-to-moderate. The logic change is small and self-contained; the bulk of the diff is regenerated snapshots. The one risky part (the is_map refactor) was caught, fixed, and now has a dedicated crash test. The remaining inline nit (MapIterator/SetIterator getting (index) instead of Node's (iteration index)) is cosmetic-only for an unusual input where Bun's body rendering already diverges from Node, so it doesn't block.

Other factors

Test coverage is good: existing snapshots regenerated, new exact-output subprocess tests for the common cases, plus the WeakMap crash regression test. All prior reviewer comments (mine and CodeRabbit's) are resolved.

Comment thread src/jsc/ConsoleObject.rs
The native TablePrinter (shared by console.table, node:console's table,
and Bun.inspect.table) left the first column header blank and
right-aligned that column. Node labels it "(index)", or
"(iteration index)" for Map and Set, and left-aligns it.

- Name the index column "(index)", or "(iteration index)" for real
  Map/Set. A strict is_map (computed once in init) gates the header,
  the "Key" column, and the Map-entry key/value extraction so the
  producer and consumers can't desync: the loose
  JSType::is_map()/is_set() also match WeakMap/WeakSet, which are not
  iterable and render as plain objects with "(index)" in Node.
- Left-align the index column.

Regenerates the console table snapshots and the two Bun.inspect.table
examples in docs/runtime/utils.mdx, and adds console.table / node:console
regression coverage including WeakMap/WeakSet and a WeakMap with an own
property (which must not take the Map "Key" column path).

Refs #32614

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — all earlier feedback addressed (including the WeakMap-with-own-property crash), and the declined MapIterator header nit is reasonable to defer.

Extended reasoning...

Overview

This PR changes console.table's index column to match Node: the header is now (index) (or (iteration index) for Map/Set) and the column is left-aligned. The Rust change in src/jsc/ConsoleObject.rs is small: a new is_map: bool field on TablePrinter (strict JSType::Map only, computed once in init and shared by the header, the Key-column push, and the row-handling consumer), the header string, and a swap of leading/trailing padding in print_row. The two snapshot files are regenerated mechanically, docs/runtime/utils.mdx example output is updated to match, and console-table.test.ts gains a describe.concurrent block of subprocess tests covering arrays, plain objects, Map, Set, WeakMap/WeakSet, and the WeakMap-with-expando-property regression case.

Security risks

None. This is purely cosmetic output formatting in console.table / Bun.inspect.table — no parsing of untrusted input, no auth/crypto/permissions, no network or filesystem behavior.

Level of scrutiny

Low-to-moderate. The native change is narrow (header text + padding order + a stored boolean), and the single risky interaction — desync between the Key-column producer and its consumers for WeakMap — was caught in review, fixed by hoisting a single is_map source of truth onto the struct, and now has a dedicated "WeakMap with an own property renders as a plain object (no crash)" test. I verified the current ConsoleObject.rs has no remaining jstype.is_map() call sites; all three users gate on self.is_map.

Other factors

Across three review rounds the author addressed every actionable comment: docs example regeneration, describe.concurrent, strict Map/Set vs WeakMap/WeakSet, and the columns[1] index-out-of-bounds crash. The one remaining MapIterator/SetIterator header nit was declined with a coherent rationale (Bun renders those bodies as generic iterables, so widening only the header would be internally inconsistent; full Node parity there needs the iterator-preview path, which is out of scope). Snapshot diffs are large but mechanical, and the new subprocess tests assert exact stdout plus exit code. No outstanding reviewer comments remain.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — all prior feedback addressed and the rebase onto #32924 looks clean.

Extended reasoning...

Overview

This PR changes console.table / Bun.inspect.table / node:console's table to match Node's index-column rendering: the first column is now labelled (index) (or (iteration index) for Map/Set) and left-aligned, instead of a blank header with right alignment. The Rust change in src/jsc/ConsoleObject.rs is small: a new strict is_map: bool field on TablePrinter (computed once in init), the header-name selection in print_table, and a padding swap in print_row. The remaining diff is regenerated snapshots, updated hard-coded table strings in the existing getter-once tests, two doc example blocks, and a new describe.concurrent block of subprocess tests covering arrays, plain objects, Map/Set, WeakMap/WeakSet, and the WeakMap-with-expando case.

Security risks

None. This is purely cosmetic output formatting of a debugging API; no auth, crypto, filesystem, network, or untrusted-input parsing is touched.

Level of scrutiny

Low-to-moderate. The behavioral surface is debug output only, and the change is tightly scoped. The one real risk class — desync between the Key-column producer and its consumers when narrowing Map detection — was caught in an earlier review round, fixed by storing a single is_map field, and is now covered by a regression test (WeakMap with an own property renders as a plain object (no crash)). I re-checked the current ConsoleObject.rs: after the rebase onto #32924, print_row no longer has any Map-specific branching (it reads pre-collected row.cells), and the only remaining Map gates (update_columns_for_row:786, print_table:962/973) all read self.is_map, so producer and consumers cannot diverge.

Other factors

All four of my prior inline comments are resolved: docs regenerated, describe.concurrent applied, strict Map/Set gating, and the WeakMap-expando crash fix. The remaining MapIterator/SetIterator header nit was reasonably declined as out of scope (Bun's body rendering for those already differs from Node, so changing only the header would be inconsistent). CodeRabbit's exit-code suggestion was also applied. The PR was rebased onto main after #32924's TablePrinter refactor and the rebase note accurately describes the re-application; the latest push is just a CI retrigger. No outstanding human review comments.

@robobun

robobun commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

Diff is green; the red CI lanes are unrelated infrastructure/flake, not this change (which only touches console.table formatting).

  • Build 66623: :darwin: 26 aarch64 failed at artifact download ("buildkite-agent artifact download timed out after 120s", never ran a test); :windows: 2019 x64 killed test/bake/dev-and-prod.test.ts with SIGKILL (flaky dev-server suite, unrelated subsystem).
  • Build 66628 (after a ci: retrigger): :alpine: 3.23 x64 and x64-baseline both exited 2 at the post-run no cores found core-dump step with 0 test failures across all files; that alpine shard didn't even include console-table.test.ts.

No console.table / Bun.inspect.table test has failed on any lane. I've used my one retrigger and won't keep pushing empty commits. Ready for a maintainer to merge (or re-run the alpine/darwin lanes).

@robobun

robobun commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Closing as part of a cleanup of stale pull requests. This PR has had no new commits since 2026-06-29, it conflicts with main, and its last CI run failed. This is not a judgment on the fix itself. If the problem still reproduces on a current build, reopen this PR after a rebase or open a new one against main.

@robobun robobun closed this Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant