/** * `each="NAME"` on a `` — render it once per element of a list. * * This is what turns a card holding a list into normalized rows: a customer * with three orders emits three `INSERT INTO orders` lines instead of one line * with the orders comma-joined in a cell. * * The whole mechanism is an OVERLAY registry. `interpolate` resolves names * against a registry, so rendering an element only means handing it a registry * where `NAME` resolves to that element and the two positional built-ins exist. * Nothing in the interpolation path changes. * * Kept apart from render.ts so the splitting and the key arithmetic can be * checked without running a renderer. * Spec: docs/specs/2026-07-19-each-repeating-a-line-per-list-element.md */ import type { PoolTables } from '../sequence/pool.js'; import { type SequenceRegistry, type SequenceSpec } from '../sequence/index.js'; /** 1-based position of the element within its card. */ export declare const ITEM_INDEX = "_item"; /** Key unique across the whole run — the primary key of the child table. */ export declare const ITEM_ID = "_item_id"; /** Built-ins that only mean anything inside an `each` line. */ export declare const EACH_BUILTINS: readonly string[]; /** * Where the element stands among the lines the `each` actually prints, read through the walked * name: `${{Doctors._last}}`, `if="!Doctors._last"`. One set per walked name, so a list inside a * pool record and the pool around it never answer for each other. */ export declare const EACH_POSITIONS: readonly string[]; /** The positional names a line walking `name` publishes — `Doctors._item`, `Doctors._first`, … */ export declare function positionNames(name: string): string[]; /** * Split a card's cell into the elements the loop walks. * * An empty cell is an EMPTY LIST, not a list holding one blank — otherwise * `"".split(",")` would invent a phantom element and emit a row for a customer * with no orders. Same rule the Parquet list path uses. */ export declare function splitElements(cell: string | undefined, separator: string): string[]; /** * The key for element `position` (1-based) of card `card` (1-based). * * Each card owns a block of `stride` keys, and each LIST owns a lane inside * that block starting at `lane`. Both are needed: a config with two repeating * sequences writes both into the same child table, and giving them one shared * counter makes their keys collide. Measured before this shape existed: 3501 * rows produced only 3071 distinct keys. * * Derived from the card index alone, so a row still resolves without knowing * anything about its predecessors — which is what keeps `--jobs` and the * streaming engine working. It leaves gaps when a card holds fewer elements * than its list allows; that is the deliberate trade documented in the spec. * Keys that increase down the file read better in a SQL dump than gap-free * keys that jump around. */ export declare function itemKey(card: number, position: number, lane: number, stride: number): number; /** * A registry for one element: the base registry, with `name` resolving to this * element and the positional built-ins added. * * Shallow — every other sequence still resolves per CARD, which is exactly what * makes the foreign key (`${{Id}}`) point at the right parent on every emitted * row. */ export declare function elementRegistry(base: SequenceRegistry, name: string, element: string, position: number, card: number, lane: number, stride: number): SequenceRegistry; /** What a line needs to know to walk a list and number its elements. */ export interface EachInfo { readonly separator: string; /** Where this list's lane starts inside a card's key block. */ readonly lane: number; /** Keys per card, across ALL lists — so two lists never overlap. */ readonly stride: number; } export declare function buildEachInfo(specs: readonly SequenceSpec[]): Map; /** * The registries one `each` line renders with — one per line it PRINTS. * * The walked name is a list (a `repeat=` sequence) or a pool. A list element overlays the name * itself; a pool record overlays every one of its fields as `Pool.field`, nested records * included (`Doctors.dept.name`), since the pool table publishes them under those paths. * * `keep` is the line's own `if=`, asked of each element with that element in scope — a pool line * that prints only some of its records is the point of a filter there. The positions are then * counted over the elements that were KEPT: `Doctors._last` is the last line printed, which is * what a JSON array needs to know before its comma, whatever the filter dropped after it. */ export declare function eachRegistries(name: string, base: SequenceRegistry, iteration: number, eachInfo: ReadonlyMap | undefined, pools: PoolTables | undefined, keep: (registry: SequenceRegistry) => boolean): SequenceRegistry[]; //# sourceMappingURL=each.d.ts.map