/** * Sequence types. * * The sequence engine materializes, for every named sequence declared * in ``, an array of length `count` whose i-th entry is the value * that sequence produces for card `i`. Filtered (parent-constrained) * sequences store `undefined` in rows where the parent filter did not * match, so the row's cells can decide whether to emit content. * * See docs/vision/02-sequences.md for the domain model. */ import type { OpenCloseElementContext } from '../generated/TDCParser.js'; import type { AttrMap } from '../processor/attrs.js'; /** * Spec extracted from a `` tag in the DSL. * * Two shapes, distinguished by how the `` children look: * * - **Simple** — one unnamed `` child. The sequence is registered * under its `name` and accessed via `${{Name}}`. * - **Compound** — two or more `` children. Each field * is registered with a dotted key `${parentName}.${fieldName}` and * accessed via `${{Parent.Field}}`. All fields of a compound share * the same `parent` filter (if any) and thus materialize on exactly * the same rows. * - **Mix** — a `` distribution. The sequence itself is scalar, but * the value is assembled from the selected ``'s ``, * ``, and nested `` content, chosen by percentage. * * Which variant is in play is determined at extraction time — the * `gens` array being non-empty with named gens triggers "compound". */ export interface SequenceSpec { readonly name: string; /** * Parent reference in `Name.Value` dotnotation, e.g. `Gender.Male`. * When present, the sequence only materializes values in rows where * the named parent produced the given value. When absent, the * sequence applies to every row (root sequence). * * A bare `Name` without a `.Value` suffix is allowed for symmetry * but behaves exactly like "no filter" at this phase — future * compound/filtered-by-any semantics may attach richer meaning. */ readonly parent?: string; /** * Simple-sequence variant: a single anonymous ``. Present iff * `gens` is absent. */ readonly gen?: GenSpec; /** * Compound-sequence variant: an ordered list of named `` * children. Present iff `gen` is absent. Field order is preserved * from the DSL — important because each field consumes PRNG bits * when materialized, and the order of consumption is part of the * deterministic contract. */ readonly gens?: readonly CompoundField[]; /** * Composed-sequence variant: the body read as ONE ordered list. * * A `` whose children are not all named ``s composes its own * value: every unnamed `` and every `` literal is concatenated, in * declaration order, into `${{Name}}`; a named `` is a field, reachable * as `${{Name.Field}}` and contributing nothing to the concatenation. * * One list rather than two, because a sequence's `` children draw in * declaration order and that order is part of the cross-language contract. * Splitting the body into "fields" and "parts" would make the draw order a * thing to remember instead of a thing the shape guarantees. * * Present iff the body holds a `` element or an unnamed `` beside * anything else — a body of nothing but named ``s stays `gens` and the * lone unnamed one stays `gen`, so no config that was valid before takes this * path. */ readonly items?: readonly SequenceItem[]; /** * Mix-sequence variant: a `` distribution whose selected case * produces the scalar value for this sequence. A `` is a standalone, * env-level named construct (sibling of ``) — it distributes its * `` branches across the rows by `percent` (Hamilton method). */ readonly mixSpec?: MixSpec; /** * Switch-sequence variant: a standalone env-level `` that * deterministically picks a value by matching the subject sequence's value * against per-entry keys (a lookup table). Present iff the sequence comes * from a `` tag. */ readonly switchSpec?: SwitchSpec; /** * Conditional-sequence variant: an ordered list of `` branches. * The FIRST branch whose `if` is truthy — or a branch with no `if` (the * fallback / "else") — produces the sequence's scalar value. If none match, * the sequence is empty on that row. Present iff the sequence's `` * children carry `if` conditions. This keeps the branching logic in `` * (e.g. male-vs-female name) instead of leaking it into the output block. */ readonly conditional?: readonly CondBranch[]; /** * Compute-sequence variant: a `` element that derives this * sequence's scalar value from other values (spec §3). The compute tree is * pure — it consumes no PRNG state — and reads other sequences via * `` with the same visibility as `${{…}}`. Present iff the * sequence's sole producer is a ``. */ readonly compute?: ComputeSpec; /** * `` groups on a compound sequence. Each inner array holds the * field names that must produce **different** values from each other * within one row. Only meaningful alongside `gens`. Absent when the * sequence declares no `` wrapper. */ readonly distinctGroups?: readonly (readonly string[])[]; /** * `uniq="true"` on a compound sequence: the tuple of all fields must be * **unique across every row** (the across-rows twin of ``). * Enforced by rearranging the materialized field columns; infeasible * configs error before output. Only meaningful alongside `gens`. */ readonly uniq?: boolean; } /** A `` producer: the element whose tree is evaluated per row. */ export interface ComputeSpec { readonly node: OpenCloseElementContext; } /** * One item of a composed sequence's body, in source order. * * A named gen is a field; an unnamed gen and a literal are parts of the * sequence's own value. */ export type SequenceItem = { readonly kind: 'field'; readonly name: string; readonly gen: GenSpec; } | { readonly kind: 'gen'; readonly gen: GenSpec; } | { readonly kind: 'text'; readonly text: string; } /** * A named `F` — a constant field. * * The only way to add a column without disturbing the run: a * `` yields the same value and still takes a draw * per row, so inserting one shifts every column after it. */ | { readonly kind: 'constant'; readonly name: string; readonly text: string; }; /** A single named field inside a compound sequence. */ export interface CompoundField { readonly name: string; readonly gen: GenSpec; } /** One branch of a conditional sequence: a gen, optionally gated by an `if`. */ export interface CondBranch { /** The `if` expression. Absent → this branch is the fallback ("else"). */ readonly cond?: string; readonly gen: GenSpec; } /** Spec extracted from a `` tag inside a ``. */ export interface GenSpec { readonly type: string; readonly attrs: AttrMap; } export interface MixSpec { readonly attrs: AttrMap; readonly cases: readonly CaseSpec[]; } /** * A standalone env-level `` — deterministic selection by * looking the subject sequence's value up in a table of keys. Each entry maps * one or more keys to a value-producer (a `` body, or a literal `` * for compact `` rows). An optional `fallback` (from ``) supplies * the value when no key matches; without it, an unmatched row is empty. */ export interface SwitchSpec { /** Name of the subject sequence whose per-row value is looked up. */ readonly on: string; /** Key→value entries, in document order (map rows first, then s). */ readonly entries: readonly SwitchEntry[]; /** `` value-producer used when no entry key matches. */ readonly fallback?: CaseSpec; } /** One `` entry: a value-producer keyed by one or more match values. */ export interface SwitchEntry { /** Match keys (multi-key via `|`, e.g. `US|CA|MX`). Any match selects it. */ readonly keys: readonly string[]; /** How to produce the value when a key matches (literal for `` rows). */ readonly value: CaseSpec; } export interface CaseSpec { readonly parts: readonly CasePart[]; /** * `` — this branch is declared anomalous, so a * `` companion column marks the rows that chose it. Purely * a label: it injects nothing, the branch's own gen produces the outlier. */ readonly anomaly?: boolean; } export type CasePart = { readonly kind: 'data'; readonly text: string; } | { readonly kind: 'gen'; readonly gen: GenSpec; } | { readonly kind: 'mix'; readonly mixSpec: MixSpec; } /** * A `` written inside a ``. It contributes a value only — it has * no `name`, so nothing can interpolate it — and it looks its subject up over * the rows of the branch it sits in, not over the run. */ | { readonly kind: 'switch'; readonly switchSpec: SwitchSpec; }; /** A materialized sequence ready for per-iteration lookup. */ export interface Sequence { readonly name: string; readonly values: readonly (string | undefined)[]; /** * Streaming (Engine 2) resolver: compute row `i`'s value on demand. When * present it is used INSTEAD of `values` (which stays empty), so memory is * O(1) per sequence instead of O(count). See `sequenceValueAt`. */ readonly resolve?: (i: number) => string | undefined; /** * The REAL value behind the text, for a date column another column measures * from — epoch milliseconds, row by row. * * `values[i]` holds a date's PRESENTATION: `02/03/2026` in an en locale, * `03.02.2026` in a ru one, `March 2` under `format="MMMM D"`. Reading a date * back out of that text is guesswork at best and impossible at worst — the * last form has thrown the year away. So the column that produced it keeps * what it actually generated, and an offset measures from THAT: the variable * holds the value, the cell shows a rendering of it. * * Present only when some `` names this column, so a * config that uses no offset pays nothing. Everything else — a date read from * a file or a pack, or built by a construct this does not reach yet — has no * instant, and the offset falls back to reading ISO text. */ readonly instants?: readonly (number | undefined)[]; } /** Read a sequence's value for row `i` — lazy resolver if present, else array. */ export declare function sequenceValueAt(seq: Sequence, i: number): string | undefined; /** The instant behind row `i`'s text, when this column kept one. */ export declare function sequenceInstantAt(seq: Sequence, i: number): number | undefined; /** Map of materialized sequences, keyed by sequence name. */ export type SequenceRegistry = Readonly>; //# sourceMappingURL=types.d.ts.map