import type { Scope, TypeAliasEntry, VariableType } from "../../types.js"; import type { CompilationUnit } from "../../compilationUnit.js"; /** * Owns the lexical scope stack and answers scope-related queries. * * The TypeScriptBuilder pushes a new scope every time it descends into a * function, graph node, or block body, and pops on exit. This class * centralises that bookkeeping plus the read-only queries that depend on * the current scope (return type, visible type aliases, scope-key for * symbol lookups, …) so callers can use a declarative API instead of * touching a raw array. * * `inDestructiveFunction` is tracked here because destructiveness is a * property of the function currently being emitted, which conceptually * belongs to the scope stack. */ export declare class ScopeManager { private readonly compilationUnit; private stack; private _inDestructiveFunction; constructor(compilationUnit: CompilationUnit); push(scope: Scope): void; pop(): void; current(): Scope; /** Stable string key for the current scope (used for symbol/type-alias lookups). */ currentKey(): string; /** Function, node, or block name; empty string for global. */ currentName(): string; /** * Resolve a relative block depth to the frame binding to read through. * * `depth` counts block scopes outward from the innermost block: 0 = the * current block, 1 = its enclosing block, etc. Depth 0 returns * `undefined` so callers keep emitting the existing `__bstack` alias * (no fixture churn for non-nested blocks). Depth > 0 returns the * unique `__bframe_` binding that the block-setup template * declares for the owning block, which is in lexical closure scope. */ blockFrameVar(depth: number): string | undefined; get inDestructiveFunction(): boolean; set inDestructiveFunction(value: boolean); visibleTypeAliases(): Record; /** * Full TypeAliasEntry-form alias registry for callers (resolveTypeDeep) * that need type-parameter metadata to substitute user-defined generic * aliases. */ visibleTypeAliasesFull(): Record; /** * Declared return type of the currently-executing function or graph node, * or `undefined` for global scope, a function with no annotation, or a * block scope. * * Block scopes (`fork(...) as item { ... }`, `guard(cost: $X) as { ... }`, * any `as { ... }` body) currently return `undefined` because we don't * carry the block's declared return type onto `Scope.block`. The only * caller that matters is `processLlmCall` for a `return llm(...)` inside * a block — and `processLlmCall` already defaults `undefined` to * `string` for structured-output inference. So today, a bare * `return llm(...)` from a block is always typed as `string`. * * Propagating the block's declared return type (from the enclosing * function's block-parameter signature) into the builder would require * either threading the parameter type through every `scopes.push({ * type: "block", ... })` site or looking it up via the typechecker — * both substantial. Documented in docs/site/guide/llm.md as a known * limitation; users who want a non-string structured type should * assign the call: `const x: Foo = llm(...); return x`. */ returnType(): VariableType | undefined; /** * Declared return type of the nearest enclosing scope that has an * ANSWER: a guard block whose result the user annotated `Result` * (its stamped yield, #580), else — walking outward past unstamped * blocks — the nearest function or node's declared return. Unlike * `returnType()`, which answers for the CURRENT scope (and answers * `undefined` for blocks), this is the saveDraft tool's schema key * (partials-ergonomics spec Part 2): the block owning the draft * slot answers exactly when the user named its type. */ enclosingDeclaredReturnType(): VariableType | undefined; /** Whether the surrounding function/node opted-in to runtime return-type validation. */ returnTypeValidated(): boolean; }