/** * `` — a column computed from the other columns of its row. * * The engine already had a full expression language, with its own mathematics * agreeing bit for bit across five implementations. It could only ever answer a * yes/no question, though: `if=` and `filter=` consume the boolean and the value * behind it was thrown away. This generator keeps the value. * * * * That is the whole feature. Everything a formula can do — fractional * arithmetic, a division with a remainder you can print, a column correlated * with another one, a derived measure, a unit conversion — is the expression * language doing what it already did, now with somewhere to put the answer. * * ## It reads its OWN row, and that is the point * * Row i is computed from row i and nothing else, so a formula preserves the * property the streaming engines are built on: any row can be produced without * producing the rows before it. `running` (a cell of memory) and `stat` (the * whole run) are the two constructs that genuinely cannot, and they say so. * * That is not a theoretical nicety — it is why a formula RUNS on the streaming * engine, resolved lazily in `stream-build.ts` beside ``, which had * been reading siblings that way all along. Measured: 20,000,000 rows in 9.5 s * to a 291 MB file, peak memory 1.3× what a millionth of that used. * * ## Which layer to reach for * * `` stays the language of CHECK DIGITS — integer by design, because * mod-11 and Luhn need exactness that a double cannot promise. A formula is the * language of MATHEMATICS. The split is safe rather than merely advised, * because whole numbers stay whole in an expression: `1000000 * 1000000` is * exact here, and so is 10¹⁸ + 1. A formula only becomes approximate when the * config asked for something inexact. */ import type { Sequence, SequenceSpec } from './types.js'; /** A value that reads as a number: the expression language's own idea of one. */ /** A cell that reads as a number. Shared with the distribution parameters. */ export declare const NUMERIC: RegExp; /** Raised when a formula cannot produce a value; surfaced as a run refusal. */ export declare class FormulaError extends Error { constructor(message: string); } /** The expression a formula evaluates, or `''` when the generator did not say. */ export declare function formulaExpr(spec: SequenceSpec): string; /** `decimals=`, or undefined when the answer is printed at full precision. */ export declare function formulaDecimals(attrs: Record): number | undefined; /** * One evaluated answer, as the text that goes in the cell. * * The rendering rule is `stat`'s, deliberately and not by coincidence: without * `decimals=` the full value is printed, with it `toFixed` rounds. The same * question deserves the same answer in both places, and `stat`'s version is * already pinned across five implementations by shared fixtures. * * A whole number is printed from the bigint it still is. Going through a double * to print it would undo the exactness the expression language worked to keep. */ export declare function renderFormulaValue(value: unknown, decimals: number | undefined, read?: ColumnsRead): string; /** * Publish the formula column. * * Reads the registry rather than drawing anything: a formula consumes no * randomness at all, which is why adding one leaves every other column exactly * where it was. * * Registered in DECLARATION ORDER, like `running`, `stat` and a date offset — * which is also why a name inside `expr=` has to belong to a sequence declared * above it. The validator says so; here the column is simply not there yet. */ export declare function registerFormula(spec: SequenceSpec, registry: Record, count: number, sequential?: true): void; /** * What one row's evaluation actually read — filled in by the scope as it goes. * * Two things are worth knowing after the fact and cannot be known before it: * whether a column this row does not have was touched, and whether a column * holding text was handed to arithmetic. Both turn a silent wrong answer into a * refusal that names its cause. */ export interface ColumnsRead { /** A referenced column was empty on this row. */ empty?: boolean; /** The first non-numeric column value the expression read. */ text?: { name: string; value: string; }; } /** * How a name inside `expr=` is resolved: this row's value of that column. * * `_count` is the 1-based row number, spelled the same way it is in `if=` — one * expression language, one set of built-ins, so a condition and a formula * cannot come to mean different things by the same words. */ export declare function rowScope(registry: Record, iteration: number, read?: ColumnsRead): (name: string) => string | undefined; /** * The same scope over any reader of the row's columns — the registry above, or the * `valueAt` a branch is handed when the formula sits inside a `` or an `if=`. * * `hasColumn` is asked separately because the two answers `undefined` could mean * must stay apart: a column that is empty on this row, and a word that is no * column at all, which the expression language reads as text. */ export declare function columnScope(row: number, hasColumn: (name: string) => boolean, valueOf: (name: string) => string | undefined, read?: ColumnsRead): (name: string) => string | undefined; /** * The formula column as a LAZY sequence, for the streaming engine. * * The same evaluation as `registerFormula`, one row at a time. `rowScope` needs * no streaming variant: it reads through `sequenceValueAt`, which already calls * a lazy column's own `resolve(i)` instead of indexing an array it does not * have. One evaluator, one set of rules, two ways of getting the value. */ export declare function lazyFormula(spec: SequenceSpec, registry: Record): Sequence; //# sourceMappingURL=formula.d.ts.map