Skip to content

refactor(output): normalize AstNode dump key casing; name the Span tuple #535

@dekobon

Description

@dekobon

Decided (2026-06-05): AST keys → snake_case type/value/span/field_name/children; Span → flat {start_row,start_col,end_row,end_col} named struct (still Option). See the resolved-decisions comment.

Summary

The bca dump/AST JSON output uses PascalCase keys while every other
serialized type in the library is lowercase, and the AST span is an unnamed
4-tuple.

Evidence

  • AstNode hand-serializes Type / TextValue / Span / FieldName /
    Children (src/ast.rs, the impl Serialize), and renames the value field
    to TextValue. Compare SpaceKind's #[serde(rename_all = "lowercase")]
    (src/spaces.rs) and the lowercase CodeMetrics keys.
  • pub type Span = Option<(usize, usize, usize, usize)> (src/ast.rs:26) — a
    bare tuple alias as public API; the four positions (start_row, start_col,
    end_row, end_col) have no names on the wire.

Why 2.0-worthy

The #510/#511 horizon normalizes metric output keys but does not cover the AST
dump keys, so without action the AST dump stays a permanent casing inconsistency.
Renaming serialized keys and changing Span to a named struct are both breaking
→ 2.0.

Proposed change

At 2.0: bring AstNode keys into the same lowercase scheme as the rest of the
output (type/value/span/field_name/children), and promote Span to a
named struct (Span { start_row, start_col, end_row, end_col }) so the AST dump
is self-documenting.

Acceptance

  • bca dump -O json keys match the rest of the serialized surface's casing.
  • Span serializes as a named object; 2.0 CHANGELOG records the shape change.

Part of the pre-2.0 review (#505).

Resolution

Implemented on branch fix/issue-535 (commit ab030f87).

  • AST dump keys are now snake_case: type / value / span /
    field_name / children. TextValuevalue; the hand-written
    serialize_struct("Node", ...) impl was replaced with
    #[derive(Serialize)] + #[serde(rename_all = "snake_case")].
  • Span is now a named struct Span { start_row, start_col, end_row, end_col }, still wrapped in Option. Field order maps 1:1 to the
    former tuple (spos_row+1, spos_column+1, epos_row+1, epos_column+1);
    values are unchanged (1-based tree-sitter rows/cols). Span derives
    Deserialize for wire round-trip parity.
  • Updated call sites: src/alterator.rs::get_text_span, the web
    /ast integration tests, the book AST-traversal example test, and
    the book doc page.
  • (breaking) — serialized AST shape; lands with the 2.0 schema
    cluster. CHANGELOG entry is consolidated by the orchestrator.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions