import type { AgencyConfig } from "../../config.js"; import type { AgencyProgram } from "../../types.js"; import type { SpliceDiagnostic, SpliceResult } from "./types.js"; import type { SymbolTable } from "../../symbolTable.js"; /** * Working out which module supplies a splice's generator, and deciding * whether that generator may run. * * Two rules gate it: a generator may not contain a splice of its own, and * its imports must stay inside Agency. See `checkGeneratorEligible`. * * Effects are not checked here. A generator that reaches a dangerous * operation is stopped while running instead, because compilation installs * no interrupt handlers and the operation cannot complete without one. */ /** * A path to an Agency source file, relative or absolute. * * Absolute paths and `../` escapes out of the project both qualify, which * is deliberate rather than incidental: anything this accepts is still * Agency source, so it still gets walked and checked by everything here. * The name says "file path" rather than "relative" so it does not promise * a narrowness it has never had. */ export declare function isAgencyFilePath(specifier: string): boolean; /** Every import edge declared by one file, unfiltered. */ export declare function importEdgesOf(program: AgencyProgram): string[]; /** Through the shared parse cache, like every other closure walker in the * codebase. These files get parsed several times per splice: once per * check, plus again for the cache fingerprint. */ export declare function parseFileOrNull(absPath: string, config: AgencyConfig): AgencyProgram | null; /** * Every file a generator can reach through relative `.agency` imports, * entry first. * * Three checks and the cache need this same set and ask different * questions of it, so the walk lives here once. `std::` modules are not * followed, or every check would drag in most of the standard library. * * A file that does not exist or does not parse is skipped. Whether that * matters is the caller's business. */ export declare function closureFiles(entryPath: string, config?: AgencyConfig): string[]; /** * The first import that leaves Agency code, or null when every edge is * allowed. * * This is what makes the safety story mean anything. Dangerous operations * raise interrupts, compilation installs no handlers, so an operation * cannot complete. That reasoning holds only for Agency code. JavaScript * raises nothing, so a generator that reaches an npm package is neither * checked before it runs nor stopped while running. * * Transitive is the operative word. A local `.agency` file the generator * imports can pull in `zod` one level down while the generator itself * looks spotless. * * Users who need a generator to reach JavaScript can turn this off with * `allowNonAgencyGenerators` in their config. */ export declare function checkImportGraph(entryPath: string, generatorName: string, config?: AgencyConfig): SpliceDiagnostic | null; /** * Refuse a generator whose own file contains a splice. * * Running a generator compiles it, which expands any splice it contains, * which runs another generator. That recursion has no floor. Template * Haskell forbids the same thing for the same reason. * * Only the generator's own file is scanned. This exists to stop runaway * recursion, and one level is enough: a file one import away gets the same * check when it is itself used as a generator. */ export declare function checkNoNestedSplice(generatorPath: string, generatorName: string, config?: AgencyConfig): SpliceDiagnostic | null; /** * Everything that gates a generator before it runs. * * Two rules. A generator may not contain a splice of its own, or running * it would recurse without a floor. And its imports must stay inside * Agency, unless the user opts out. * * There is deliberately no static effect check here. The * unhandled-interrupt backstop already stops an effectful generator, and * a static version cannot be precise while issue #680 stands, because * effects do not propagate across a module boundary. To fail closed it * would have to refuse a generator whenever any export anywhere in its * closure raised, which rejects a generator that uses one harmless helper * from a file that happens to contain an effectful one. Tracked as #691. */ export declare function checkGeneratorEligible(generatorPath: string, generatorName: string, config?: AgencyConfig, symbolTable?: SymbolTable): SpliceDiagnostic | null; /** * Which module supplies a splice's generator, and under what name. * * A generator must be imported from another file. It has to be compiled * before the file that splices it, so no order works if they share a file. * Template Haskell calls this the stage restriction. * * Returns the module's original exported name, so an aliased import * resolves to what the module exports rather than the local spelling. */ export declare function resolveGeneratorModule(program: AgencyProgram, localName: string, hostPath: string): SpliceResult<{ modulePath: string; exportedName: string; }>; /** One name the host file imports, and where it comes from. */ export type ImportSource = { /** The specifier as written: `./data.agency` or `std::math`. */ specifier: string; /** Absolute path for a file specifier, null for `std::`. */ modulePath: string | null; exportedName: string; localName: string; }; /** Where a name in the host file comes from, or null when nothing imports it. */ export declare function resolveImportedName(program: AgencyProgram, localName: string, hostPath: string): ImportSource | null;