import ts from "typescript"; import { type Sentinels } from "./vendor-host-url.js"; type FoldSegment = { text: string; } | { hole: ts.Node; }; export interface Folded { segments: FoldSegment[]; /** Sub-expressions that were not constant, so the walker can still scan them. */ holes: ts.Node[]; } /** * Module-local constant bindings, so `const H = "vendor.invalid"` used by name is * resolved rather than treated as an opaque runtime value. * * Without this, moving the host one `const` away from the URL was enough to turn * a hard-coded endpoint into an "undeterminable host", which the annotation * carve-outs then waved through. Scope is deliberately shallow — a single * assignment to a `const` with a constant initialiser — because anything cleverer * would need a type checker, and the guard should be honest about being a * syntactic tool. */ type ConstantBindings = Map>; export declare function collectConstantBindings(source: ts.SourceFile): ConstantBindings; export declare function fold(node: ts.Node, out: Folded, bindings: ConstantBindings): void; /** Is this node the outermost part of a string-building expression? */ export declare function isFoldRoot(node: ts.Node): boolean; /** * Render a folded expression two ways, because both are values the program can * produce and each hides a different attack: * * - holes as sentinels: keeps `https://s3.${region}.amazonaws.com` readable as * the amazonaws.com host it is, and makes `"https://" + host` visible as a * scheme with an undeterminable authority; * - holes as empty strings: catches a host split by an interpolation that * contributes nothing, e.g. `` `https://ski${""}lls.md` ``. */ export declare function renderFolded(folded: Folded, sentinels: Sentinels): string[]; export {};