Skip to content

fix(jsonview): keep single-column stream tables column-shaped - #207

Open
feiiiiii5 wants to merge 2 commits into
openai:mainfrom
feiiiiii5:fix/jsonview-single-key-stream-rows
Open

feiiiiii5 wants to merge 2 commits into
openai:mainfrom
feiiiiii5:fix/jsonview-single-key-stream-rows

Conversation

@feiiiiii5

Copy link
Copy Markdown

Summary

In the interactive JSON explorer, a row that arrives through the lazy stream loader is rendered differently from the preloaded rows above it whenever the streamed objects share exactly one key: the preloaded rows show the bare value under the key's column, and every lazily loaded row shows {key:"value"} instead.

Problem

TableView.appendItem decided whether a table is column-shaped by counting columns:

if len(tv.columns) > 1 && result.IsObject() {

newArrayOfObjectsTableView builds one column per unique key, so a stream whose items all carry a single key gives a table with one column and columnKeys = ["id"]. That table is column-shaped, but the count check says otherwise, so the appended row falls through to the generic single-cell row and renders the whole object.

Measured with the new test against internal/jsonview/explorer.go from 0169bff:

--- Expected
	([]string) (len=1) { "second" }
+++ Actual
	([]string) (len=1) { "{id:\"second\"}" }

and in raw mode expected []string{"\"second\""} / actual []string{"{\"id\":\"second\"}"}. toggleRaw re-renders the whole table through newArrayOfObjectsTableView, so after pressing r the lazily loaded row snaps back to the bare value — the same cell changes content twice per keypress.

Because the row is also the input to updateColumnWidths, the {key:"value"} cell additionally drives the single column's width off the value widths the rest of the table was laid out for.

Fix

columnKeys is populated only by the array-of-objects constructor, so it — not the column count — says whether a table is column-shaped. One line plus a comment explaining the invariant; a plain array (columnKeys == nil) keeps the single Items cell rendering it already had.

Where this is reachable

pkg/cmd/cmdutil.go:503 hands an auto-paging iterator to jsonview.ExploreJSONStream for --format explore, and the lazy path activates once a collection has more items than the preload count. Every list endpoint I checked returns multi-key items, so on today's API this needs a collection whose items share a single key — I am not claiming a specific public command reproduces it, only that the two row-building paths disagree in the shipped code.

#172 widens this: it projects each item through --transform before it becomes row data, so a projection onto a one-key object lands exactly here. My change is in a different function and shares no lines with that diff, so either order merges cleanly.

Tests

internal/jsonview/explorer_single_key_test.go, three cases:

  • a single-key lazy row renders like the preloaded row, in both formatted and raw mode;
  • a streamed item carrying a key the preloaded items never showed does not widen the table, and the full item stays reachable through rowData (which is what print and navigation read);
  • a scalar array keeps the generic Items column, so the fix is not broader than the column-shaped case.

Validation

go1.25.0 darwin/arm64, on top of 0169bff:

  • the new tests fail against main's explorer.go with the output quoted above, and pass with the fix;
  • go test ./internal/... — every package ok;
  • go test -race -count=3 ./internal/jsonview — ok;
  • go test ./... -run '^$', ./scripts/lint, go vet ./internal/jsonview, gofmt -l internal/jsonview, go mod verify, go mod tidy -diff (no diff) — all clean.

What I did not verify: I did not run ./scripts/test against the Steady mock server (it needs the pinned Deno source install), and I did not drive a real terminal session. The reproduction is at TableView level, driven through JSONViewer.Update with the same tea.KeyMsg the explorer's key handling receives, so it covers the production path up to the TUI renderer.

No generated files, dependencies, or budget/policy files change; internal/jsonview/explorer.go is handwritten.

appendItem picked the row shape from the column count, so a streamed array
whose items share exactly one key appended `{id:"x"}` cells under a column
that already rendered bare values for the preloaded rows. Discriminate on
columnKeys, which only the array-of-objects constructor populates.
@feiiiiii5
feiiiiii5 requested a review from a team as a code owner September 20, 2026 15:59
@feiiiiii5

Copy link
Copy Markdown
Author

Authorship note, for consistency with #208: an AI coding agent produced this change under the account owner's standing instruction for this repo, ran every command quoted above and read its output. No human reviewed the diff before it was opened.

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.

1 participant