import { AgencyConfig } from "../config.js"; import type { CompilationUnit, ImportedFunctionSignature } from "../compilationUnit.js"; import { AgencyNode, AgencyProgram, FunctionCall, FunctionDefinition, IfElse, WhileLoop } from "../types.js"; import { MessageThread } from "../types/messageThread.js"; export declare class TypescriptPreprocessor { program: AgencyProgram; protected config: AgencyConfig; protected functionDefinitions: Record; protected importedFunctions: Record; protected graphNodeDefinitions: Record; constructor(program: AgencyProgram, config?: AgencyConfig, info?: CompilationUnit); /** * Move standalone `tag` nodes onto the next attach-target node * (function / graphNode / assignment / functionCall / typeAlias). * Public so consumers like the doc generator can run the same * tag-attachment that the full `preprocess()` pipeline runs without * also running every downstream transform. */ attachTags(): void; attachDocComments(): void; /** * Look up the BlockType for a function's block parameter by function name. * Checks both local function definitions and imported function signatures. */ private findBlockType; /** * Copy type annotations from a BlockType onto block params that lack them. */ private applyBlockType; /** * Walk the AST and propagate block type annotations from function definitions * onto direct block arguments that lack type annotations. * e.g. map([1,2,3]) as x { ... } — copies param types from map's block type onto x. * * Note: blocks inside named args (e.g. fn.partial(func: \x -> x)) are not yet * handled — the preprocessor would need valueAccess chain resolution to find * the receiver function. The builder falls back to 'any' for untyped block params. */ propagateBlockTypes(): void; preprocess(): AgencyProgram; /** * Walk every function and graph-node body and desugar `parallel { ... }` * blocks into the existing `fork` primitive. Also inlines any `seq { ... }` * blocks that appear outside a parallel block (where they have no runtime * effect). See lib/preprocessors/parallelDesugar.ts. */ protected desugarParallelBlocks(): void; protected isVarUsedInBody(variableName: string, nodeToExclude: AgencyNode, body: AgencyNode[]): boolean; protected getFunctionDefinitions(): void; protected getGraphNodeDefinitions(): void; protected collectSkills(): void; protected collectSkillsInFunction(body: AgencyNode[]): void; protected findChildren(body: AgencyNode[], type: string): AgencyNode[]; protected isBuiltinFunction(functionName: string): boolean; private prettifyName; renderMermaid(): string[]; protected extractFunctionCalls(body: AgencyNode[]): FunctionCall[]; protected groupCallsByAsync(calls: FunctionCall[]): { type: "sync" | "async"; calls: FunctionCall[]; }[]; protected topologicalSortFunctions(): FunctionDefinition[]; protected addAwaitPendingCalls(): void; protected _addAwaitPendingCalls(body: AgencyNode[]): AgencyNode[]; /** * Recursively collect all async variables defined in this body and nested non-function bodies. * Does not descend into function or graphNode bodies as they have their own scope. */ protected _collectAsyncVariablesInScope(body: AgencyNode[], asyncVarToAssignment: Record): void; /** * Find the first usage of a variable in this scope (across all bodies). * Returns the path to the body and the index within that body. */ protected _findFirstUsageInScope(body: AgencyNode[], varName: string, assignmentNode: AgencyNode, bodyPath?: number[]): { bodyPath: number[]; indexInBody: number; } | null; /** * Check if a node uses a variable directly (not in nested bodies). */ protected _nodeUsesVariableDirectly(node: AgencyNode, varName: string): boolean; /** * Insert awaitPending calls at the appropriate locations in the body. */ protected _insertAwaitPendingCalls(body: AgencyNode[], locationToVars: Record, currentPath?: number[]): AgencyNode[]; protected nodeHasBody(node: AgencyNode): node is FunctionDefinition | AgencyNode | IfElse | WhileLoop | MessageThread; protected _nodeUsesVariable(node: AgencyNode, varName: string): boolean; /** * Validate that no async function calls appear inside loops. * Async calls inside loops can't be properly serialized for interrupt * resumption because multiple iterations share the same step block, * causing branch key collisions. */ protected validateNoAsyncInLoops(): void; /** * Get the scope name for a function-like node (function or graphNode). */ private getScopeName; /** * Resolve variable scopes by annotating AST nodes with their scope. * After this pass, every VariableNameLiteral, InterpolationSegment, and Assignment * will have a `scope` property indicating whether the variable is global, local, or args. */ /** * Resolve variable scopes inside block bodies with full lexical nesting. * * Each block in the function/node body gets a frame of declared names * (params -> "blockArgs", let/const + implicit locals -> "block"). A * reference resolves innermost-first across the block chain; the relative * distance to the owning block is recorded as `blockDepth` (0 = current * block). Names not owned by any block fall back to `lookupScope` * (node-local/global/imported) or are left unscoped for the node-body * pass / final imported pass. * * Blocks are identified by their `BlockArgument` AST-node identity, and a * node's block-ancestor chain (outermost-first) is read from the * `blockArgument` entries in its `walkNodes` ancestor list. */ private resolveBlockScopes; protected resolveVariableScopes(): void; }