import { Edit, Insertion } from "./edits.js"; //#region src/unplugin/hoist.d.ts /** * Hoist Zod schema construction out of functions to module scope — * equivalent of babel-plugin-zod-hoist. * * Schemas built inside function bodies are re-constructed on every call: * * function getSchema() { * return z.object({ name: z.string() }); // rebuilt per call * } * * becomes * * const _zh_94b7f5c1 = z.object({ name: z.string() }); * function getSchema() { * return _zh_94b7f5c1; // built once * } * * Safety rules (babel-plugin-zod-hoist's `canSafelyHoist`, hardened for * lexical analysis): * - A free identifier must be an import or a KNOWN_GLOBALS member, and must * never be bound anywhere in the file (function params, locals, catch * clauses, class names, module-level const/let/var — hoisting above those * would change meaning or hit the TDZ). The babel plugin additionally * allows arbitrary unbound identifiers because it has real scope * information; this port's binding collector is lexical, so an unknown * bare name is treated as a possibly-missed binding rather than a global * (a wrong guess crashes at module load with a ReferenceError). * `this`/`super` disqualify anywhere. Eager `await`/`yield` also * disqualify (stricter than the babel plugin, which never encounters * them: hoisting one would emit top-level await / orphaned yield). * - Eligible roots: any binding imported from zod, an imported identifier * matching /ZodSchema$/, or an imported identifier whose chain contains * an inline z.* reference (e.g. `Base.extend({ a: z.string() })`). * - Nesting (babel's `isNestedInZodCall`): the interior of a zod-rooted * chain never hoists separately — it goes with the outer schema or not at * all. Chains rooted elsewhere (`sql.type(...)`, `api.get(...)`) do NOT * suppress their arguments: when the outer chain is rejected, an inner * `z.object({...})` still hoists on its own. * - Declarations are inserted at the top of the module (after shebang and * directive prologue). Imports are initialized before module code runs, * so referencing them from above their textual position is safe. * - Names are content-hashed, so identical schemas dedupe to one binding. * * The source is TypeScript, which acorn cannot fully parse — candidates are * located with a string/comment/depth-aware scanner and extracted with * parseExpressionAt (the same technique as the autoDiscover rewrite). * Anything unparseable (TS generics, `as` casts) is skipped: a miss leaves * the schema unhoisted, never breaks the code. */ /** * Imported identifiers matching this pattern are treated as schema roots. * * The default must keep implying a "Zod" substring: it is one of the three * triggers the transform hook's `code` filter (ZOD_MENTION in transform.ts) * is a superset of. A default that matched, say, `/Schema$/` would make * hoistable files without any "zod" mention invisible to bundlers with native * hook filters. (A *user-supplied* pattern is handled — it drops the filter.) */ declare const SCHEMA_NAME_PATTERN: RegExp; /** * Module specifiers whose bindings count as the zod namespace. Every entry * must contain "zod" for the same reason as SCHEMA_NAME_PATTERN above; both * are pinned by `describe("code filter soundness")` in the transform tests. */ declare const ZOD_MODULES: Set; /** How an imported local binding maps onto its source module. */ interface ImportDetail { /** Module specifier (`"zod"`, `"./shapes"`). */ specifier: string; /** Exported name the binding refers to; `"*"` for namespace imports, `"default"` for default imports. */ imported: string; } interface ImportBindings { /** Every runtime (non-type) imported binding name. */ all: Set; /** Bindings imported from a zod module (usually just `z`). */ zod: Set; /** Local binding name → source module/export, for build-time evaluation. */ details: Map; } /** * Collect runtime import bindings with a regex over import statements. * Type-only imports and `type` specifiers are excluded — they cannot be * referenced at runtime, so excluding them keeps the capture rule sound. */ declare function collectImportBindings(code: string): ImportBindings; interface HoistOptions { /** * Imported identifiers matching this pattern are treated as schema chain * roots even without an inline z.* reference. A string is compiled as a * RegExp source; null disables name-based matching. * @default /ZodSchema$/ */ schemaNamePattern?: RegExp | string | null | undefined; /** * Fired when the file has hoist-relevant roots and the full source scan * actually runs — i.e., real parse-level work happened (as opposed to the * microsecond import-collection bail). The disk cache uses this to decide * that even a null transform result is worth persisting: re-deriving * "nothing to hoist" costs a full scan per zod-importing file per run. */ onScan?: (() => void) | undefined; } /** * Free-variable analysis of a hoisted expression's source text, for the * build-time compile step. Returns null when the text does not parse (it * always should — it was extracted by this module). */ declare function analyzeHoistedExpression(text: string): { eagerFree: Set; deferredFree: Set; } | null; /** A schema construction hoisted to module scope. */ interface HoistedSchema { /** Module-scope binding name (`_zh_`). */ name: string; /** Source text of the hoisted construction expression. */ text: string; } interface HoistResult { /** The rewritten source. */ code: string; /** One entry per hoisted declaration, in declaration order. */ schemas: HoistedSchema[]; /** * The splices (input coordinates) that produced `code`, for sourcemap * generation: expression → `_zh_*` replacements plus the declaration-block * insertion. `code === applyEdits(input, edits, insert)` by construction. */ edits: Edit[]; insert: Insertion; } /** * Hoist eligible Zod schema expressions to module scope. * Returns the rewritten source, or null when nothing was hoisted. */ declare function hoistZodSchemas(code: string, options?: HoistOptions): string | null; /** * hoistZodSchemas + metadata about each hoisted declaration, so the * transform can compile the hoisted schemas into optimized validators. */ declare function hoistZodSchemasMeta(code: string, options?: HoistOptions): HoistResult | null; //#endregion export { HoistOptions, HoistResult, HoistedSchema, ImportDetail, SCHEMA_NAME_PATTERN, ZOD_MODULES, analyzeHoistedExpression, collectImportBindings, hoistZodSchemas, hoistZodSchemasMeta }; //# sourceMappingURL=hoist.d.ts.map