import type { AgencyNode, Assignment, Expression, ScopeType, VariableType } from "../../types.js"; import type { AccessChainElement, ValueAccess } from "../../types/access.js"; import type { TsNode } from "../../ir/tsIR.js"; import type { ScopeManager } from "./scopeManager.js"; /** * Callbacks PipeChainEmitter needs from the parent TypeScriptBuilder. * * Pipe lowering recursively delegates back into the main expression / * statement emitter, so we accept the relevant builder methods as * dependencies rather than holding a reference to the whole builder. */ export type PipeChainEmitterDeps = { processNode: (node: AgencyNode) => TsNode; /** * The builder's full ValueAccess lowering. Used to build pipe-stage * receivers correctly — see the doc comment on `processValueAccessPartial`. */ processValueAccess: (node: ValueAccess) => TsNode; buildAssignmentLhs: (scope: ScopeType, varName: string, accessChain?: AccessChainElement[]) => TsNode; buildStateConfig: () => TsNode | undefined; /** * Build a zod validation schema string for a VariableType taken from * user source. Must deep-resolve generic aliases before lowering, just * like the rest of the TS builder does. See `TypeScriptBuilder.zodSchemaFor`. */ zodSchemaFor: (t: VariableType) => string; scopes: ScopeManager; }; /** * Lowers `|>` pipe chains into runner steps. * * A pipe chain `a |> f |> g` is parsed left-associatively as * `(a |> f) |> g`. This emitter flattens that tree into ordered stages * (`[a, f, g]`) and produces one runner step per stage so that interrupts * resume between stages without replaying the earlier ones. * * Public API: * - {@link tryGetChainStages} — flatten an assignment-of-pipe into stages * - {@link expand} — turn an assignment + stages into runner nodes * - {@link bind} — lower a bare `lhs |> rhs` expression */ export declare class PipeChainEmitter { private deps; private counter; constructor(deps: PipeChainEmitterDeps); /** * Walk a left-recursive `|>` tree under an assignment and return * [initial, stage1, stage2, ...] in evaluation order. * Returns null if the node is not an assignment whose value is a pipe chain. */ tryGetChainStages(node: AgencyNode): Expression[] | null; /** * Lower a bare pipe expression `left |> stage` (not an assignment) into * `await __pipeBind(left, async (__pipeArg) => stage(__pipeArg))`. */ bind(leftIR: TsNode, stage: Expression): TsNode; /** * Expand a pipe-chain assignment into one runner node per stage. * * Layout (for `x = a |> f |> g`): * step baseId+0: __pipe_N = a * pipe baseId+1: __pipe_N = await __pipeBind(__pipe_N, lambda(f)) * pipe baseId+2: x = await __pipeBind(__pipe_N, lambda(g)) * * If the assignment is validated (`x!: T = ...`), an extra runner step * wraps the final result in `__validateType`. */ expand(stmt: Assignment, stages: Expression[], baseId: number): TsNode[]; private buildPipeLambda; /** * Build the body expression for a pipe stage (without the outer arrow * function wrapper). Returns `await __call(...)` — the caller wraps this * in an arrow function or `__catchResult(...)`. */ private buildPipeStageBody; /** * Process a ValueAccess up to but not including the last chain element. * Used by pipe lowering to get the receiver for a method call — * the LAST chain element is the pipe stage's method name, which the * caller hands to `__callMethod(receiver, name, …)` directly. * * Delegates to the builder's full `processValueAccess` (via deps) on * a synthetic node with `chain.slice(0, -1)`. This keeps every * subtlety of receiver lowering in one place — awaiting + paren- * wrapping a `functionCall` base, paren-wrapping a non-trivial base, * propagating the `optional` flag through chain elements, handling * the `call` chain-element kind, etc. Previously this method * duplicated the chain-walk and silently dropped all of those * behaviours; see the "pipe receiver precedence" issue for the * shapes that were broken (`getObj().foo.bar |> stage`, `obj?.foo * |> stage`, `factories.makeOne().bar |> stage`, etc.). */ private processValueAccessPartial; }