Something went wrong

Thank you for being patient! We're working hard on resolving the issue

Tree Pipeline - Lona Docs Log in

Tree Pipeline

The tree pipeline projects a hydrated Sheet (plus optionally a RenderScene) into a ParsedTree snapshot. Used by snapshot tests, the CLI's tree renderer, and any consumer that needs a text-renderable view of the tree.

Builders

buildHydratedTree(sheet) — rows only

Mirrors the hydrated field of a short-format fixture (TREE-SPEC §2). Walks sheet.tree.roots() + sheet.tree.children and emits one row node per SheetRow.

import { buildHydratedTree } from "@tento-lona/sheets";

const tree = buildHydratedTree(sheet);
// → ParsedTree with kind: "root" / "row" nodes only

buildSceneTree(sheet, scene, options?) — rows + cells

Mirrors §3.4 — same row hierarchy, plus one cell child node per drawn cell. Cell payload comes from the scene's CellNode.content.

import { buildSceneTree, RenderPluginRegistry } from "@tento-lona/sheets";

const tree = buildSceneTree(sheet, scene, {
  registry,                          // optional: enables cellValueFormatter
  formatColumnLabel: (cell) =>
    `Mon ${cell.columnDate.day1}`,   // override default ISO format
});

When registry is supplied, buildSceneTree consults spec.cellValueFormatter for each cell's display string. Without it, the built-in stringifyCellValue switch handles primitive values; complex object cells render as <typename> markers.

Parse / serialize

The same module owns the round-trip pair for short-format text fixtures:

import {
  parseTree, serializeTree,
  parseRendered, serializeRendered, serializeRenderedTreeWithCols,
  diffTree, walkTree, allRows, findRowByType,
} from "@tento-lona/sheets";

const text = serializeTree(tree);
const reparsed = parseTree(text);
diffTree(tree, reparsed);   // empty if round-trip clean

TreeWatcher — reactive bridge

TreeWatcher wraps a Sheet + InvalidationSink and emits TreeDiff on each mutation. The canonical pattern any consumer (CLI, TUI, DOM) wires into its render loop:

import { TreeWatcher, type TreeDiff } from "@tento-lona/sheets";

const watcher = new TreeWatcher(sheet, sheet.invalidation);

watcher.subscribe((diff: TreeDiff) => {
  for (const change of diff.changes) {
    switch (change.kind) {
      case "insert":
      case "update":
      case "remove":
        reconcile(change);
    }
  }
});

// Initial render:
const initial = watcher.snapshot();

TreeWatcher.snapshot() calls buildHydratedTree. For scene-aware snapshots, take the watcher's Sheet reference and call buildSceneTree yourself.

Tree flatten

flatten produces a flat list of subsumed children for adapters that need a single linear sequence:

import { flatten, TreeFlattener } from "@tento-lona/sheets";

const result = flatten(sheet, {
  visit: (row) => /* return true to include, false to subsume */,
});

Pure port of SheetRowTree.visit / markSubsumed / buildFlattened.

See also

  • Scene & Diff — the scene buildSceneTree ingests
  • TREE-SPEC.md — the canonical fixture grammar
  • __architecture/fuzz-harness-tento/tento-lona-js/sheets.md — fuzz coverage for round-trip stability