/** * Render-tree assembly for the A2UI renderer — the bridge between the pure-TS * processor (`a2ui-validate.ts`, plain Maps) and the recursive Svelte dispatcher * (`A2UINode.svelte`). Pure TS, no Svelte, so `A2UINode` and `A2UIView` share * one typed contract (the house pattern of `md-context.ts`, deliberately not a * Svelte context — the tree is private and explicit prop flow keeps it * inspectable). * * `buildRenderTree` walks the component graph from `root` into a fully-expanded, * BOUNDED node tree: child/children references resolved, list templates expanded * over the data model, dangling references marked, and the depth/node/cycle * limits enforced in ONE place so the Svelte layer can never recurse without * bound regardless of payload. Graph-level ISSUES (the reportable faults) are * still produced by `collectGraphIssues` in `a2ui-validate.ts`; this walk only * shapes what renders. */ import type { Component, Snippet } from 'svelte'; import type { IconComponent } from '../../../icons/index.js'; import type { MarkdownUrlPolicy } from '../markdown/types.js'; import type { A2uiActionEvent, A2uiValidationIssue } from './a2ui.types.js'; import type { A2uiComponentInstance, A2uiSurfaceState } from './a2ui-validate.js'; /** Default traversal bounds — mirror `collectGraphIssues` so the tree and the issue list agree. */ export declare const A2UI_MAX_DEPTH = 32; export declare const A2UI_MAX_NODES = 512; /** * One node of the assembled render tree. `instance === null` marks a dangling * reference (a child id that was never defined) — rendered as a streaming * placeholder or, once settled, a fault chip. `children` are pre-expanded and * ordered; `key` is stable across incremental rebuilds so keyed `{#each}` keeps * component identity (and input focus) through a keystroke-triggered rebuild. */ export interface A2uiRenderNode { key: string; id: string; instance: A2uiComponentInstance | null; /** Template-item scope for relative-path resolution and two-way write-back. */ scopePrefix: string | undefined; children: A2uiRenderNode[]; /** flex-grow, present only when this node is a direct Row/Column child with a finite `weight`. */ weight?: number; /** * The parent prop this child came from (e.g. Card `header`/`footer`/`child`). * Lets a dispatcher with several named childId slots pick the right child by * name instead of position; single-slot / list components ignore it. */ slot?: string; } /** Static text labels threaded to the node dispatcher (i18n comes from A2UIView props). */ export interface A2uiRenderLabels { unsupported: string; blockedImage: string; pending: string; } /** * The single context object each `A2UINode` receives. Carries resolved slot * classes, the icon map, the data-binding resolver, the two-way write-back * callbacks, the action sink and rendering flags. Rebuilt per version bump so a * live data-model edit propagates fresh resolved values without remounting. */ export interface A2uiRenderContext { /** Resolved class string per slot (tv() + slotClasses + unstyled already applied). */ classes: Readonly>; urlPolicy: MarkdownUrlPolicy | undefined; /** Dangling refs render placeholders while true; fault chips once false. */ streaming: boolean; /** True inside a Button label (Text renders as an inline plain span). */ inline: boolean; /** * The view's `unstyled`, relayed to every catalog component the dispatcher * renders. `classes` above already answers it for the view's OWN slots; a * dispatched `