/** * Structural checks for `` — the small table computed before the rows. * * A pool is a miniature ``, so everything INSIDE it (a sequence with no * ``, a mix whose percentages don't add up, a group of one) is checked by * the ordinary env machinery, called on the pool node. Only three things are * specific to the tag itself, and they are here: * * - it must have a name, because a reference names it (TDC222); * - it must have a member count, and the count must mean something (TDC223); * - some tags cannot live inside it (TDC230). * * The last one deserves its reason written down. `` and the fixtures * describe a FILE — where records start, what goes between them. A pool has no * file; it is a table read by other columns. And a `` inside a `` * is refused rather than supported because the honest way to express "doctors * belong to clinics" is a reference from one pool to another, which keeps every * pool a flat table you can print. Nesting would make a pool a tree and every * later feature — uniqueness, filtering, the memory ceiling — would have to ask * "at which depth?". */ import type { Diagnostic } from '../errors/index.js'; import type { OpenCloseElementContext, SelfClosingElementContext } from '../generated/TDCParser.js'; import type { GenPlace } from './gen-type.js'; /** * How many members each pool declares, by name. * * Read from the attribute rather than counted, because that IS the count — a * pool's `count=` is how many members it builds. Wanted by the group checks: a * `` over three references to a pool of two cannot be kept, and that * is provable before a row exists. */ export declare function collectPoolCounts(env: OpenCloseElementContext | undefined): Map; /** * The field names each pool declares, collected before the members are walked. * * A pre-pass rather than a running tally, so a reference is understood wherever * it stands. The engine does need a pool declared above its references (it is * computed first), but a validator that only reported "unknown field" for a * pool written at the bottom of the file would be reporting the wrong problem. */ export declare function collectPoolFields(env: OpenCloseElementContext | undefined): Map; /** * The values each pool field can hold, where the config says them outright. * * A member whose body is one unnamed `` produces * nothing but `A` and `B` — the list is literal, never a file or a pack — so the * set recorded here is a SUPERSET of what the built pool will actually contain * (a pool of two members drawn from three values holds at most two of them). * That direction is what TDC225 needs: a value outside the superset can match no * member, whatever the draw turns out to be. * * `case=`/`mask=` rewrite the value on the way out and `repeat=` makes it a * list, so any of the three and the values stop being knowable — the same rule * the top-level `finiteTextValues` follows, for the same reason. */ export declare function collectPoolFieldValues(env: OpenCloseElementContext | undefined): Map>; /** * Every pool named by a ``, anywhere under ``. * * Collected in one descent rather than tallied during the walk because a * reference may stand above the pool it names, and TDC231 has to know about it * by the time that pool is reached. */ export declare function collectPoolReferences(env: OpenCloseElementContext | undefined): Set; /** * The pools a `` or a `` prints, at any depth — read as surely * as a `` reads one. */ export declare function collectEachPools(block: OpenCloseElementContext | undefined, named?: Set): Set; /** * The pools printed by an `each` anywhere in the output — the block and every fixture. A lookup * table printed once in `` is read as surely as one printed per row. */ export declare function collectPrintedPools(block: OpenCloseElementContext | undefined, env: OpenCloseElementContext | undefined, fixtureNames: readonly string[]): Set; /** * A pool nobody draws from. * * A warning rather than an error, on the same reasoning as TDC234: the config * runs, and every row is exactly what it would have been. What it costs is the * build — a pool is computed in full before the first row and held in memory for * the whole run — so an unread `count="50000"` is paid for and thrown away. It is * also the shape a rename leaves behind, where the reference now points at a new * pool and the old one sits there looking deliberate. */ export declare function checkPoolIsRead(pool: OpenCloseElementContext, referenced: ReadonlySet, diagnostics: Diagnostic[]): void; /** * A member that draws from another pool may only name a pool declared ABOVE. * * The engine builds pools in declaration order, so that is not a style rule: a * pool named below has no table yet when this one is computed, and a pool naming * itself never would. Both used to pass validation and produce a member with no * fields, which surfaced far away as "not a field of Seen" — a message that * blames the line doing the reading for a mistake made in the declaration. * * Declaration order is also the entire cycle check. There is nothing to detect: * a cycle cannot be written down. */ export declare function checkPoolMemberRefs(pool: OpenCloseElementContext, above: readonly string[], diagnostics: Diagnostic[]): void; /** * A name in `filter=` that means two things at once. * * The expression is evaluated in two scopes — a candidate member's fields and * the current row's columns — and a bare name resolves to the member's field * first. When a name exists in both, picking a winner silently would make the * config say something the author cannot see. It is refused instead, and the * fix is spelled out: qualify with the pool's name. * * Identifiers are pulled out with a regexp rather than the expression parser. * A diagnostic that over-reports a name appearing inside a string literal * would be wrong, but the parser cannot be reached from here without dragging * the evaluator into the validator, and the shape of the mistake — the same * word declared twice — is visible in the text either way. */ export declare function checkFilterAmbiguity(gen: OpenCloseElementContext | SelfClosingElementContext, poolFields: readonly string[], declaredColumns: readonly string[], diagnostics: Diagnostic[]): void; /** * A `filter=` put aside, and where its complaint belongs in the report. * * Held back for the same reason an `if=` is: the column a filter compares * against may be declared BELOW the reference, and the run resolves that * happily. Deciding mid-walk would report a problem the author does not have. */ export interface PendingPoolFilter { readonly at: number; readonly gen: OpenCloseElementContext | SelfClosingElementContext; readonly expr: string; readonly pool: string; readonly field: string; /** The other side of the `==`: a column name, or a bare word read as a literal. */ readonly other: string; /** * The pool this filter is written INSIDE, with that pool's own field names. * A pool's members read each other and nothing from the run, so there the * other side is a column only if it is one of those fields, and its values are * that field's. Undefined for a filter at the top level. */ readonly scope?: { readonly pool: string; readonly names: readonly string[]; } | undefined; } /** * Recognise `field == Something`, the one filter shape a check can decide. * * The same shape the engine gives a fast path to, and recognised the same way — * by looking at the text rather than at a parsed tree — so that what the reader * sees and what is checked are the same thing. Anything richer (`price <= * Budget`) compares against a value that only exists once the row is being * built, and stays a run-time refusal. */ export declare function pendingFilterFor(gen: OpenCloseElementContext | SelfClosingElementContext, poolFields: readonly string[], at: number, scope?: PendingPoolFilter['scope']): PendingPoolFilter | undefined; /** * The put-aside filters, decided now that every column is known. * * What can be said before a single value exists: the member's field and the * other side of the `==` each draw from a set the config writes down, and when * those two sets do not overlap the filter can never match — not on some row, on * every row. The run already refuses that, on row one, after building the pool; * saying it at check time costs nothing and names both lists. * * Only DISJOINT sets are reported. A value that is merely rare (`Want` produces * `A` and `Z`, members hold `A`) is a refusal waiting for the row that draws * `Z`, and reporting it here would also refuse `percent="100,0"`, which never * draws that value at all. The run-time message names the value that matched * nobody, which is the honest place to say it. */ export declare function runPendingPoolFilters(pending: readonly PendingPoolFilter[], diagnostics: Diagnostic[], declared: readonly string[], finiteValues: ReadonlyMap, poolFieldValues: ReadonlyMap>): void; /** * Check one `` tag: its own attributes and the tags it may hold. * * What is inside a legal child is NOT checked here — the caller walks the pool * body with the same checks it uses on ``, which is the whole point of the * construct. */ export declare function checkPool(pool: OpenCloseElementContext, diagnostics: Diagnostic[]): void; /** * Teach the rest of the validator about a `` reference. * * It publishes the pool's fields under the sequence's own name, so * `${{Doctor.lastName}}` is a field of `Doctor` exactly as it would be for a * compound. That one registration is what lets TDC134, TDC193 and every other * name check work on a pool while knowing nothing about pools. */ export interface PoolRefContext { readonly poolFields: ReadonlyMap; readonly declaredSequences: string[]; readonly valuelessSequences: string[]; readonly diagnostics: Diagnostic[]; readonly poolReferences: string[]; readonly pendingPoolFilters: PendingPoolFilter[]; /** * The `` being walked, when the reference is one of its members. A * pool's members read each other and nothing from the run, so a filter written * there is checked against that pool's own fields. */ readonly currentPool?: string | undefined; } export declare function registerPoolReference(name: string, gens: readonly (OpenCloseElementContext | SelfClosingElementContext)[], ctx: PoolRefContext): void; /** * A `` anywhere but as a whole ``. * * `if=` came first. A `` carrying `if=` becomes a CONDITIONAL branch, and * the pool resolver only recognises a plain ``. So the reference * registered no `Ref.field` columns at all and `${{Ref.name}}` reached the output * as its own literal text — on EVERY row, including the ones the condition * selected. The config validated clean and the file filled up with * `${{Doctor.name}}`. * * Every other place a `` can stand has the same hole, measured on all five: * the fallback after the `if=` branches and a part of a composed sequence printed * the marker too, and inside a `` or as a compound field the run stopped * with `gen type "pool" not yet supported` after `check` had called it valid. * * Refused rather than implemented: a reference publishes a whole MEMBER as * `Ref.field` columns, and a branch or a part has no column of its own to publish * them under. Giving a row no member at all is what `parent=` already does. */ export declare function checkPoolRefPlace(gen: OpenCloseElementContext | SelfClosingElementContext, place: GenPlace, diagnostics: Diagnostic[]): void; //# sourceMappingURL=pool.d.ts.map