zz_

app/engine/ladderRender.ts

zzmq.dev@gmail.com/zz / app / engine / ladderRender.ts @ cdba25ef Download
Ladder Summary
  • file This module resolves a Ladder definition stored as Git‑notes into a single fully‑materialized tree (`ResolvedRung`), tracks how many rungs and notes were processed, and provides utilities to render that tree as plain text. It exports the resolution logic (`resolveLadderTree`), a convenience wrapper that reads from a local repository (`collectLadder`), a text‑renderer (`renderText`), a combined collect‑and‑render helper (`renderLadder`), and the `ResolvedRung` and `RenderStats` interfaces.
 // Renders a Ladder to flat, indented plain text for a human to read in one
 // place. Reads from git notes the same way the engine would, not from any
 // cache; this is a materialized view, not a second source of truth.
 import { readAnchor, isRef, type EmbeddedRung } from "./ladderNotes.js";
 import { REPO_RUNG_PATH } from "./ladder.js";
 
 export interface RenderStats {
  rungs: number;
  notes: number;
 }
 
 export async function renderLadder(repoDir: string, stateDir: string): Promise<{ text: string; stats: RenderStats }> {
  const stats: RenderStats = { rungs: 0, notes: 0 };
 
  function renderOwnFields(rung: EmbeddedRung, depth: number): string {
  stats.rungs += 1;
  const indent = " ".repeat(depth);
  const lines = [`${indent}[${rung.kind}] ${rung.path}`, `${indent} ${rung.summary}`];
  if (rung.sources.length) {
  lines.push(`${indent} sources:`);
  for (const s of rung.sources) {
  lines.push(`${indent} - ${s.kind} ${s.ref} (${s.at}) ${s.author}: ${s.title}`);
  }
  }
  if (rung.touches?.length) {
  lines.push(`${indent} touches: ${rung.touches.join(", ")}`);
  }
  return lines.join("\n");
  }
 
  // Walks one already-loaded subtree, re-reading from git notes (another
  // note) whenever a child is a reference rather than embedded content.
  async function renderNode(rung: EmbeddedRung, depth: number): Promise<string> {
  const lines = [renderOwnFields(rung, depth)];
  for (const child of rung.children) {
  if (isRef(child)) {
  const anchor = await readAnchor(repoDir, stateDir, child.ref);
  stats.notes += 1;
  lines.push(anchor ? await renderNode(anchor, depth + 1) : `${" ".repeat(depth + 1)}[missing] ${child.ref}`);
  } else {
  lines.push(await renderNode(child, depth + 1));
  }
  }
  return lines.join("\n");
  }
 
  const root = await readAnchor(repoDir, stateDir, REPO_RUNG_PATH);
  stats.notes += 1;
  const text = root ? await renderNode(root, 0) : `[missing] ${REPO_RUNG_PATH}`;
  return { text, stats };
 }