Skip to content

console: left-align Console#table cells to match Node - #33453

Open
robobun wants to merge 2 commits into
mainfrom
farm/82216bbc/console-table-left-align
Open

robobun wants to merge 2 commits into
mainfrom
farm/82216bbc/console-table-left-align

Conversation

@robobun

@robobun robobun commented Jul 6, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • new Console(stream).table(...) from node:console centers every cell. Node v26.3.0 pads each cell on the right only. The frame, column widths and quoting already match, so the outputs differ in the padding alone.
  • The cause is renderRow (src/js/builtins/ConsoleObject.ts:198). It writes half of the spare width on each side of the cell, as Node did up to v20.10 and v21.1.

Fix

  • renderRow writes the cell and then the whole spare width as spaces, as Node's lib/internal/cli_table.js does.
  • Correct because Node documents this layout and Bun reports process.version v26.3.0.
  • Verified: test/js/node/console/console.test.ts (5 new tests) and console-table-iterators.test.ts. Stock Bun 1.4.3 fails 6 of the 13 tests in those two files. Also all of test/js/node/console/ and test/js/bun/console/.

Background

  • Bun has two table renderers. The Console class of node:console is a JS builtin that cites Node v20.6.1 as its source. The global console.table is native code with its own format. This PR changes only the first.
  • Node changed the padding in lib: align console.table row to the left nodejs/node#50135 (v20.11.0, v21.2.0). Bun's copy predates it.
  • Considered a call from Console#table into the native printer, to keep one renderer. That printer prints no (index) header and no quotes, so it differs more from Node.

Downsides

Notes

Repro

import { Console } from "node:console";
import { Writable } from "node:stream";

let out = "";
const sink = () => new Writable({ decodeStrings: false, write(c, e, cb) { out += c; cb(); } });
new Console({ stdout: sink(), stderr: sink() }).table([{ aaaaa: 1, b: "x" }, { aaaaa: 22222, c: true }]);
process.stdout.write(out);
node v26.3.0, and this branch           bun 1.4.3 (367d939d9)
┌─────────┬───────┬─────┬──────┐        ┌─────────┬───────┬─────┬──────┐
│ (index) │ aaaaa │ b   │ c    │        │ (index) │ aaaaa │  b  │  c   │
├─────────┼───────┼─────┼──────┤        ├─────────┼───────┼─────┼──────┤
│ 0       │ 1     │ 'x' │      │        │    0    │   1   │ 'x' │      │
│ 1       │ 22222 │     │ true │        │    1    │ 22222 │     │ true │
└─────────┴───────┴─────┴──────┘        └─────────┴───────┴─────┴──────┘

Which Node versions pad on the right. lib/internal/cli_table.js line 43 at each release tag:

tag line 43
v18.20.8, v20.9.0, v20.10.0, v21.0.0, v21.1.0 const needed = (columnWidths[i] - len) / 2;
v20.11.0, v20.19.5, v21.2.0, v22.0.0, v24.0.0, v26.3.0 const needed = (columnWidths[i] - len);

The Node commit is nodejs/node@14af167209 (2023-10-28). Bun's file cites nodejs/node@d2c7c367 (v20.6.1, 2023-09-07), which still centers. An earlier revision of this description said that Node pads on the right since v18. That was wrong.

The tests. Each expected table in console.test.ts is the output of node v26.3.0 for the same call. A script with the same calls, plus a Set iterator, prints 4106 identical bytes under node v26.3.0 and under this branch. The snapshot in console-table-iterators.test.ts recorded the centered padding. Only its padding changes. Its first table is Bun's layout for a Map iterator, not Node's, and a comment above the snapshot says so.

Node's own test. test/parallel/test-console-table.js at v26.3.0 has 33 cases. With each case in its own try, stock Bun 1.4.3 passes 8 and this branch passes 31. Node passes 33 with the same wrapper. The 2 cases that remain are not about padding:

The file cannot be added to test/js/node/test/parallel/ verbatim until those two land.

Other PRs on this renderer. #33452 and #42359 add snapshots with the centered padding to the same two test files. The PR that lands later needs its snapshots updated.

Also run on the debug build. test/js/node/console/ and test/js/bun/console/: 104 pass, 1 skip (a test that this PR does not touch), 0 fail. The vendored test-console-with-frozen-intrinsics.js, test-console-instance.js, test-console-methods.js, test-console-group.js, test-console-tty-colors.js, test-console-tty-colors-per-stream.js and test-console-formatTime.js exit 0. bun x tsc --noEmit -p src/js/tsconfig.json reports no error.

Binary size. The CI size report of build 123479 shows +0.0 KB on eleven targets and +0.5 KB on bun-windows-aarch64.

History. The stale sweep closed this PR on 2026-10-05 with no review. renderRow on main was unchanged, so the branch is rebased onto 13a98b0 and the PR is open again.


[human-review] gate passed · iteration 4 · 3 files touched

fails on main (without fix)
ASAN without fix: 6 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/pr_gate.xml" test/js/node/console/console-table-iterators.test.ts test/js/node/console/console.test.ts
bun test v1.4.3 (367d939d9)

test/js/node/console/console-table-iterators.test.ts:
22 | 
23 |   if (exitCode !== 0) {
24 |     expect(stderr).toBe("");
25 |   }
26 |   // Known gap: Node splits the Map iterator into `Key` and `Values` columns (https://github.com/oven-sh/bun/pull/42359).
27 |   expect(stdout).toMatchInlineSnapshot(`
                      ^
error: expect(received).toMatchInlineSnapshot(expected)

  
  "┌───────────────────┬────────────┐
- │ (iteration index) │ Values     │
+ │ (iteration index) │   Values   │
  ├───────────────────┼────────────┤
- │ 0                 │ [ 'a', 1 ] │
- │ 1                 │ [ 'b', 2 ] │
+ │         0         │ [ 'a', 1 ] │
+ │         1         │ [ 'b', 2 ] │
  └───────────────────┴───
... (truncated)

release without fix: 6 FAILED
bun test v1.4.3-canary.1 (367d939d9)

test/js/node/console/console-table-iterators.test.ts:
22 | 
23 |   if (exitCode !== 0) {
24 |     expect(stderr).toBe("");
25 |   }
26 |   // Known gap: Node splits the Map iterator into `Key` and `Values` columns (https://github.com/oven-sh/bun/pull/42359).
27 |   expect(stdout).toMatchInlineSnapshot(`
                      ^
error: expect(received).toMatchInlineSnapshot(expected)

  
  "┌───────────────────┬────────────┐
- │ (iteration index) │ Values     │
+ │ (iteration index) │   Values   │
  ├───────────────────┼────────────┤
- │ 0                 │ [ 'a', 1 ] │
- │ 1                 │ [ 'b', 2 ] │
+ │         0         │ [ 'a', 1 ] │
+ │         1         │ [ 'b', 2 ] │
  └───────────────────┴────────────┘
  ┌───────────────────┬────────┐
  │ (iteration index) │ Values │
  ├───────────────
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/pr_gate.xml" test/js/node/console/console-table-iterators.test.ts test/js/node/console/console.test.ts
bun test v1.4.3 (367d939d9)

test/js/node/console/console-table-iterators.test.ts:
(pass) console.Console#table renders Map and Set iterators [1754.04ms]

test/js/node/console/console.test.ts:
(pass) console.Console > global instanceof Console [5.12ms]
(pass) console.Console > new Console instanceof Console [47.55ms]

(pass) console.Console > it can write to a stream [218.32ms]
(pass) console.Console > can enable colors [27.71ms]
(pass) console.Console > stderr and stdout are separate [20.12ms]
(pass) console.Console > table pads cells on the right > array of objects with absent cells [68.72ms]
(pass) console.Console > table pads cells on the right > object of primitives [33.90ms]
(pass) console.Console > table pads cells on the right > Map [36.81ms]
(pass) console.Console > table pads cells on the right > properties filter [18.98ms]
(pass) console.Console > table pads cells on the right > cells wider than their string length [21.80ms]
(pass) conso
... (truncated)

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 1309ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[1/139] gen JS modules (bundle-modules)
Preprocess modules (12267ms)
Bundle modules (113ms)
Postprocesss modules (55ms)
Bundle Functions (699ms)
Generate Code (51ms)

[13.20s] Bundled "src/js" for production
  2613 kb
  198 internal modules
  13 native modules
  50 internal functions across 16 files
[2/6] link bun-profile
ld.lld: warning: Linking two modules of different target triples: 'obj/codegen/GeneratedSSLConfig.cpp.o' is 'x86_64-pc-linux-gnu' whereas 'rust-target/x86_64-unknown-linux-gnu/deps/libbun_jsc-3687dde034820260.rlib(bun_jsc-3687dde034820260.bun_jsc.a197853160ed3415-cgu.0.rcgu.o at 222462)' is 'x86_64-unknown-linux-gnu'


ld.lld: warning: Linking two modules of different target triples: 'obj/codegen/GeneratedSocketConfig.cpp.o' is 'x86_64-pc-linux-gnu' whereas 'rust-target/x86_64-unknown-linux-gnu/deps/libbun_jsc-3687dde034820260.rlib(bun_jsc-3687dde034820260.bun_jsc.a197853160ed3415-cgu.0.rcgu.o at 222462)' is 'x86_64-unknown-linux-gnu'


ld.lld: warning: Linking two modules of different t
... (truncated)
diff hotspot
src/js/builtins/ConsoleObject.ts                   |  8 +--
 .../node/console/console-table-iterators.test.ts   | 11 +--
 test/js/node/console/console.test.ts               | 83 ++++++++++++++++++++++
 3 files changed, 92 insertions(+), 10 deletions(-)

gate history · 1 passed · 0 rejected · iteration 4

evidence per changed file
file                                                  reads  edits  tests
src/js/builtins/ConsoleObject.ts                          3      2     19
test/js/node/console/console-table-iterators.test.ts      2      3     13
test/js/node/console/console.test.ts                      2      3     15

@coderabbitai

coderabbitai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: oven-sh/bun/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Essentials
  • Run ID: 819ef2c2-a227-4679-abf6-0e10db8315d6
📥 Commits

Reviewing files that changed from the base of the PR and between 13a98b0 and 7d86567.

📒 Files selected for processing (3)
  • src/js/builtins/ConsoleObject.ts
  • test/js/node/console/console-table-iterators.test.ts
  • test/js/node/console/console.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.


Walkthrough

Console.table now left-aligns cells by placing remaining column padding after each cell. Tests update iterator snapshots and add coverage for arrays, objects, Maps, property filters, and mixed-width strings.

Changes

Console.table output

Layer / File(s) Summary
Render and validate table alignment
src/js/builtins/ConsoleObject.ts, test/js/node/console/console.test.ts, test/js/node/console/console-table-iterators.test.ts
The renderer now places all remaining column-width padding after each cell. Tests update Map and Set iterator snapshots and add snapshots for absent array cells, primitive-valued objects, Maps, property filtering, and mixed-width strings. The renderer comment links to Node’s cli_table.js.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to 7d865

No actionable issue remains in the supplied review evidence; this change is mergeable after normal checks.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly summarizes the main change: left-aligning Console#table cells to match Node.
Description check ✅ Passed The description explains the problem, the fix, and how the author verified it. Although it does not use the template headings, it provides the required information and includes detailed test results.
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@github-actions github-actions Bot added the claude label Jul 6, 2026
@robobun

robobun commented Jul 6, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 6:47 PM PT - Oct 5th, 2026

❌ @robobun, your commit e598b01 has 2 failures in Build #123479 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 33453

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

bun-33453 --bun

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. Match Node's console.table index column header and alignment #32619 - Both fix console.table cell alignment to be left-aligned matching Node.js; Match Node's console.table index column header and alignment #32619 targets the Rust-side native renderer while this PR targets the TypeScript-side Console class renderer

🤖 Generated with Claude Code

@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 — straightforward Node compat fix switching cell padding from centered to left-aligned.

Extended reasoning...

Overview

This PR changes two lines in renderRow in src/js/builtins/ConsoleObject.ts so that Console#table (the node:console constructor path) left-aligns cell content instead of centering it, matching Node.js behavior since v18. It updates one existing inline snapshot in console-table-iterators.test.ts and adds two new snapshot tests in console.test.ts covering mixed columns, absent cells, object-keyed index rows, and wide-character (CJK) width handling.

Security risks

None. This is pure output-formatting logic in a builtin JS module — no parsing of untrusted input, no I/O, no auth/crypto/permissions surface. needed = columnWidths[i] - len is guaranteed non-negative because columnWidths[i] is computed as the max of all cell widths in that column, so String.prototype.repeat cannot throw.

Level of scrutiny

Low. The source change is a 2-line mechanical replacement that mirrors Node's lib/internal/cli_table.js implementation verbatim (minus the vestigial MathCeil). The PR description cites the upstream source, provides a byte-for-byte diff against Node v26.3.0, and confirms the tests fail without the fix. This only affects the new Console(...) path; the global console.table native renderer is untouched.

Other factors

No CODEOWNERS on these paths, no outstanding reviewer comments, and the bug hunter found nothing. The updated snapshot in console-table-iterators.test.ts is a necessary consequence of the fix (it was recording the old centered output). Test coverage is solid and the expected outputs were transcribed from Node rather than captured from Bun.

@robobun

robobun commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

Not a duplicate of #32619, though they are adjacent. Bun has two independent console.table renderers, and each needs its own fix:

renderer reached by this PR #32619
native src/jsc/ConsoleObject.rs (TablePrinter) global console.table, Bun.inspect.table x
builtin src/js/builtins/ConsoleObject.ts (renderRow) new Console(...).table(...) from node:console x

There is no file overlap between the two diffs, so they can land in either order.

The two also fix different things. #32619 changes the native renderer's index column (header text and alignment); its data cells were already left-aligned. This PR changes the builtin renderer's cell padding from centered to right-padded, which affects every cell including the header row. Today the builtin path is the only one that centers:

new Console(...).table(...)     global console.table        node v26.3.0
┌─────────┬───────┬─────┐       ┌───┬───────┬─────┐         ┌─────────┬───────┬─────┐
│ (index) │ aaaaa │  b  │       │   │ aaaaa │ b   │         │ (index) │ aaaaa │ b   │
├─────────┼───────┼─────┤       ├───┼───────┼─────┤         ├─────────┼───────┼─────┤
│    0    │   1   │ 'x' │       │ 0 │ 1     │ x   │         │ 0       │ 1     │ 'x' │
└─────────┴───────┴─────┘       └───┴───────┴─────┘         └─────────┴───────┴─────┘

@robobun
robobun force-pushed the farm/82216bbc/console-table-left-align branch from 202a9cd to 276e34d Compare July 6, 2026 14:21

@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 — straightforward Node compat fix; the cookie-map.test.ts CI failure is unrelated to this change.

Extended reasoning...

Overview

This PR changes two lines in renderRow (src/js/builtins/ConsoleObject.ts) to right-pad table cells instead of centering them, matching Node's lib/internal/cli_table.js since v18. It updates one existing inline snapshot and adds two new snapshot tests in test/js/node/console/ covering mixed-width columns, absent cells, string-keyed indexes, and CJK width handling.

Security risks

None. This is pure output-formatting logic for a debugging utility (Console#table). No user input parsing beyond what already existed, no I/O, no auth/crypto/permissions surface.

Level of scrutiny

Low. The functional diff is a two-line arithmetic simplification: (columnWidths[i] - len) / 2 split across two .repeat() calls becomes a single trailing .repeat(columnWidths[i] - len). columnWidths[i] is computed as the max of getStringWidth over the header and every cell in that column, so needed is a non-negative integer and .repeat(needed) cannot throw. The total padding (and therefore column width / box borders) is unchanged — only the position of the whitespace moves. The expected snapshots were transcribed from Node v26.3.0 rather than captured from Bun, which is the right verification methodology for a compat fix.

Other factors

  • No CODEOWNERS entry covers src/js/builtins/ConsoleObject.ts.
  • Grepping test/ for (index) / (iteration index) table snapshots turns up only the two files already updated in this PR, so no other snapshots will break.
  • The single CI failure is test/js/bun/cookie/cookie-map.test.ts, which this PR does not touch; it's the IMF-fixdate assertion issue addressed by #33425 on main and is unrelated.
  • The bug-hunting pass found no issues.
  • The PR description already clarifies the non-overlap with #32619 (native renderer vs. builtin node:console renderer).

@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 — straightforward Node compat fix with matching snapshot tests.

Extended reasoning...

Overview

This PR changes 3 lines in renderRow inside src/js/builtins/ConsoleObject.ts to right-pad table cells instead of centering them, matching Node's lib/internal/cli_table.js behavior since v18. It updates one existing inline snapshot in console-table-iterators.test.ts (which was recording the old centered output) and adds two new snapshot tests in console.test.ts covering mixed-width columns, absent cells, object-keyed index columns, and CJK wide-character width handling.

Security risks

None. This is pure output-formatting code for node:console's Console#table — no parsing of untrusted input, no auth/crypto/permissions, no filesystem or network access. needed = columnWidths[i] - len is guaranteed non-negative because columnWidths[i] is computed as the max of header width and every cell's getStringWidth, so String.prototype.repeat cannot receive a negative count.

Level of scrutiny

Low. The source change is a mechanical one-liner that mirrors upstream Node's implementation verbatim (the PR description quotes the Node source). It only affects the JS-side new Console(...) path, not the native global console.table renderer. The updated snapshot and new tests were transcribed from Node v26.3.0 output rather than captured from Bun, so they act as a real Node-compat regression check.

Other factors

The bug-hunting system found no issues. There are no outstanding human review comments — timeline activity is all bot noise (CodeRabbit rate-limit notice, build status, duplicate-PR detector which the author already addressed). The change follows existing file conventions (StringPrototypeRepeat.$call). Given the tiny surface area, clear upstream reference, and solid test coverage, this is safe to approve without human review.

@robobun

robobun commented Jul 6, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status

The fix is ready for review. The diff is green. CI is red because of two jobs, and neither failure comes from this diff.

CI (build 123479, e598b01). The build is finished: 179 jobs passed and 2 failed.

  • :windows: 11 aarch64 - test-bun ran no test. It did not get the build artifact: buildkite-agent artifact download timed out after 120s for step 'windows-aarch64-build-bun'. ci: retry a timed out artifact download and bound the darwin guest warmup installs #40500 is the open PR for that timeout.
  • :debian: 13 x64-asan - test-bun failed on test/js/bun/spawn/spawn.test.ts, in the test an idle reader stopped at the highwater mark does not keep the process alive (saturating writer). The test expects an empty stderr from a child process. It got a LeakSanitizer warning: WARNING: ptrace appears to be blocked (is seccomp enabled?). LeakSanitizer may hang. The same test passed on main at the base commit (build 123448). This PR changes only renderRow of Console#table, and that test does not call it.
  • Eight other tests that this PR does not touch failed and then passed on a retry.
  • The new tests ran and passed. On :debian: 13 x64: console.test.ts 12 pass, console-table-iterators.test.ts 1 pass. All jobs passed on the six other Linux lanes, on :windows: 2019 x64 and on both macOS lanes.

A maintainer can run the two failed jobs again, or merge without them.

How to reproduce. Run this script under Node and under Bun:

import { Console } from "node:console";
import { Writable } from "node:stream";

let out = "";
const sink = () => new Writable({ decodeStrings: false, write(c, e, cb) { out += c; cb(); } });
new Console({ stdout: sink(), stderr: sink() }).table([{ aaaaa: 1, b: "x" }, { aaaaa: 22222, c: true }]);
process.stdout.write(out);

Node v26.3.0 pads each cell on the right. Bun 1.4.3 (367d939) centers each cell. This branch prints the same bytes as Node.

How it is verified.

  • bun bd test test/js/node/console/console.test.ts test/js/node/console/console-table-iterators.test.ts: 13 pass, 0 fail.
  • The same two files with stock Bun 1.4.3 (USE_SYSTEM_BUN=1 bun test ...): 6 fail, and each diff shows only the padding.

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Closing this PR because it has been inactive for more than 90 days.

@github-actions github-actions Bot closed this Oct 5, 2026
The Console class's renderRow split the leftover width across both sides
of the cell, which centers it. That is Node's behavior up to v20.10 and
v21.1. Node has padded only on the right since v20.11.0 and v21.2.0
(nodejs/node#50135), and Bun reports a newer Node version than that.

Every other part of the output (box frame, column widths, quoting)
already matched, so a byte comparison of Console#table output against
Node differed in the padding alone.
@robobun robobun reopened this Oct 6, 2026
@robobun
robobun force-pushed the farm/82216bbc/console-table-left-align branch from 379dfce to 7d86567 Compare October 6, 2026 00:55
@robobun

robobun commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

Reopened. The stale sweep closed this PR before a review, and the bug still reproduces on main (13a98b0): renderRow in src/js/builtins/ConsoleObject.ts is unchanged there.

Changes since the last push:

  • The branch is rebased onto main. It is one commit again.
  • The tests cover five table shapes. Each expected table is the output of node v26.3.0 for the same call.
  • The source has a permalink to Node's lib/internal/cli_table.js, which this code is copied from.
  • The description is rewritten. The old one said that Node pads on the right since v18. That was wrong: the change shipped in v20.11.0 and v21.2.0 (lib: align console.table row to the left nodejs/node#50135).

Node's own test/parallel/test-console-table.js goes from 8 to 31 passing cases out of 33 with this change. #42359 and #33452 cover the last two.

@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.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Additional findings (outside the current diff — GitHub can't attach inline comments there):

  • 🟣 test/js/node/console/console-table-iterators.test.ts:32 — Users passing a Map iterator to Console#table still get a single 'Values' column of [key, value] pairs after merging, while Node prints separate 'Key' and 'Values' columns; the rewritten snapshot now certifies that divergence under a PR titled as Node parity. The mapIter branch that would split keys and values is dead because previewEntries is commented out at src/js/builtins/ConsoleObject.ts:666-670, so isKeyValue stays false and the iterator falls into the setlike path at src/js/builtins/ConsoleObject.ts:695-703. Fix: wire the Map-iterator path to Node's Key/Values layout (or document the exclusion) and update this snapshot to Node's three-column output instead of re-recording the wrong one.

    Why this was flagged

    Trigger: any caller doing new Console(...).table(map.entries()) or table(mapSymbol.iterator), the exact input this test exercises at test/js/node/console/console-table-iterators.test.ts:14. In src/js/builtins/ConsoleObject.ts:663 mapIter is true, but the previewEntries call at lines 666-670 is commented out, so isKeyValue never becomes true and the keys/values split at lines 676-681 is unreachable; the iterator is consumed by the setlike loop at lines 699-702 and each entry is rendered as the inspected array [ 'a', 1 ]. Node's cli_table path renders (iteration index) | Key | Values for the same input. The base branch already behaved this way, but this PR rewrote the inline snapshot at lines 27-32 to the new padding while keeping the single-column layout, which per the repo rules certifies the bug in a PR whose stated goal is byte-identical Node output. Remedy: implement the Key/Values split for Map iterators (previewEntries equivalent) and record Node's actual output.

    Verification: pre-existing. Trigger: any caller passing a Map iterator to new Console(...).table(). In src/js/builtins/ConsoleObject.ts lines 666-670 are commented out, so the key/value split at 676-681 is unreachable and line 695 routes the Map iterator into the loop at 699-702, yielding a single Values column. The base snapshot already pinned the identical structure; the diff only changes padding whitespace.

Node prints a Map iterator with Key and Values columns. Bun prints the
pairs in one Values column. The snapshot records Bun's layout, so say
that it is not Node's.
@robobun

robobun commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

On the Map iterator finding: it is correct, and it is older than this PR.

For new Console(...).table(new Map([["a", 1], ["b", 2]]).entries()):

node v26.3.0                              this branch (and main, with centered cells)
┌───────────────────┬─────┬────────┐      ┌───────────────────┬────────────┐
│ (iteration index) │ Key │ Values │      │ (iteration index) │ Values     │
├───────────────────┼─────┼────────┤      ├───────────────────┼────────────┤
│ 0                 │ 'a' │ 1      │      │ 0                 │ [ 'a', 1 ] │
│ 1                 │ 'b' │ 2      │      │ 1                 │ [ 'b', 2 ] │
└───────────────────┴─────┴────────┘      └───────────────────┴────────────┘

The cause is in Console#table (src/js/builtins/ConsoleObject.ts:669-700). Nothing sets isKeyValue for a Map iterator, so the iterator takes the Set path and each pair becomes one cell. This PR changes only the padding in renderRow, so the layout is the same before and after.

#42359 is the open PR for that layout. It reads the iterator entries natively and replaces this snapshot with Node's three columns. The description of this PR lists the gap under Downsides.

The snapshot must not read as Node's layout, so e598b01 adds one comment above it. The comment names the gap and links #42359.

@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 — a small, self-contained padding change in Console#table that matches Node's current cli_table.js, with snapshot coverage.

What was reviewed:

  • renderRow in src/js/builtins/ConsoleObject.ts: needed is max(header width, every cell width) - cell width, so it is always a non-negative integer and String.prototype.repeat cannot throw; the as any cast was only needed for the old fractional value.
  • The new Map snapshot in console.test.ts does not contradict the "known gap" note: a plain Map takes the $isMap branch and already gets Key/Values columns; the gap is only for Map iterators, which the sibling test still covers with the single Values column.
  • Checked the CJK snapshot arithmetic ('日本語' width 8, divider 10) and grepped the suite for other assertions on the old centered layout — the only ones are the two files updated here; test/js/bun/console/ exercises the native global console.table, which this PR does not touch.
Extended reasoning...

The diff changes three lines in the renderRow helper of the node:console Console class builtin (src/js/builtins/ConsoleObject.ts) to pad each table cell on the right instead of centering it, adds a Node source permalink, updates one existing inline snapshot, and adds five new inline-snapshot tests following the file's existing writable() helper pattern. It touches no security-sensitive surface (no parsing of untrusted input, no auth or crypto), keeps the $call primordial-safe style, and the padding arithmetic is provably non-negative from the columnWidths computation a few lines above. No CODEOWNERS entry covers these paths, the hunt ran dry with zero findings, and the second commit since the last review only adds an explanatory comment to a test, so the change is simple enough to approve without a human pass.

This branch has not been deployed

No deployments
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