zod-compiler 1.23.8 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"transform.js","names":[],"sources":["../../src/unplugin/transform.ts"],"sourcesContent":["import remapping from \"@jridgewell/remapping\";\nimport { parseExpressionAt } from \"acorn\";\nimport MagicString from \"magic-string\";\nimport picomatch from \"picomatch\";\nimport type { CodegenMode } from \"../core/codegen/context.js\";\nimport { SHARED_BLOCK_MARKER } from \"../core/codegen/dedupe.js\";\nimport {\n FAIL_CLASS_DECL,\n FAILZ_CLASS_DECL,\n FIN_DECL,\n FIN_DEFERRED_DECL,\n FINZ_DECL,\n generateIIFE,\n MK_VALIDATOR_DECL,\n ZOD_CONFIG_IMPORT,\n ZOD_MSG_DECLARATION,\n} from \"../core/iife.js\";\nimport { aggregateUsedHelpers, type CompiledSchemaInfo, compileSchemas } from \"../core/pipeline.js\";\nimport type { DiscoveredSchema } from \"../core/types.js\";\nimport { discoverSchemas } from \"../discovery.js\";\nimport { ProcessExitDuringLoadError } from \"../loader.js\";\nimport { mayExportSchemas } from \"../static-filter.js\";\nimport { applyEdits, type Edit, type Insertion } from \"./edits.js\";\nimport { hoistZodSchemasMeta } from \"./hoist.js\";\nimport { compileHoistedSchemas } from \"./hoist-compile.js\";\nimport type { TransformOptions, ZodCompilerPluginOptions } from \"./types.js\";\nimport { VIRTUAL_RUNTIME_ID } from \"./virtual.js\";\n\n/** JSON shape of the composed sourcemap returned alongside transformed code. */\nexport interface TransformSourceMap {\n version: number;\n sources: (string | null)[];\n sourcesContent?: (string | null)[];\n names: string[];\n mappings: string;\n file?: string | null;\n}\n\n/**\n * The transform pipeline as a chain of edit batches. Each batch is applied\n * to the CURRENT text through a MagicString (one stage map per batch); the\n * final original→output map is the remapping-composed chain. Deriving the\n * output string and the map from the same edit list makes divergence\n * impossible.\n */\nclass StagedTransform {\n current: string;\n private readonly source: string;\n private readonly maps: unknown[] = [];\n\n constructor(original: string, source: string) {\n this.current = original;\n this.source = source;\n }\n\n apply(edits: readonly Edit[], insert?: Insertion): void {\n this.applyThen(edits, insert === undefined ? undefined : () => insert);\n }\n\n /**\n * Apply `edits`, then let `deferred` derive one more insertion from the\n * resulting text — both inside ONE stage.\n *\n * The head injection (runtime import + shared dedup block) has to be decided\n * from the REWRITTEN source, because `computeRuntimePrefix` probes it for\n * already-present markers. Staging it separately made a whole second\n * `generateMap` over the full generated output — for what is only a prepend at\n * offset 0 — and then forced `remapping` to compose the two. Together those\n * were the dominant cost of a transform: on a 320-schema project they ran to\n * 64% of total wall time, more than discovery and codegen combined. Deferring\n * the insertion into the same MagicString buys byte-identical output and an\n * equivalent map for one generation and no composition — 1.6x (small schemas)\n * to 3.4x (large ones) on the transform, scaling with how much code a file\n * emits, since that is what both costs are proportional to.\n */\n applyThen(edits: readonly Edit[], deferred?: (rewritten: string) => Insertion | undefined): void {\n const s = new MagicString(this.current);\n for (const e of edits) {\n if (e.start === e.end) {\n s.appendLeft(e.start, e.text);\n } else {\n s.overwrite(e.start, e.end, e.text);\n }\n }\n // `toString()` is the only way to show the deferred step what the rewrite\n // produced; it measured well under 1% of a transform.\n const insert = deferred?.(edits.length === 0 ? this.current : s.toString());\n if (insert !== undefined) {\n s.appendLeft(insert.offset, insert.text);\n }\n if (edits.length === 0 && insert === undefined) return;\n this.current = s.toString();\n // `hires: \"boundary\"` is load-bearing, not a tuning knob: without it every\n // mapping collapses to column 0, so a stack frame or debugger breakpoint in\n // untouched user code below a compiled schema lands at the start of its line\n // instead of the right column (tests/unplugin/sourcemap.test.ts pins it). It\n // is also the most expensive thing here, which is why the stage COUNT is\n // what to economize on.\n this.maps.push(s.generateMap({ source: this.source, hires: \"boundary\", includeContent: true }));\n }\n\n /** Composed original→current map, or null when nothing was applied. */\n map(): TransformSourceMap | null {\n if (this.maps.length === 0) return null;\n // A single stage needs no composition: `remapping` over a one-map chain\n // reproduces that map, and it is expensive on generated-code-sized input.\n const [only] = this.maps;\n if (this.maps.length === 1) return only as TransformSourceMap;\n const chain = [...this.maps].reverse();\n return remapping(\n chain as Parameters<typeof remapping>[0],\n () => null,\n ) as unknown as TransformSourceMap;\n }\n}\n\n/**\n * Matches a runtime (non-type-only) import from \"zod\".\n *\n * One of the three triggers ZOD_MENTION (the transform hook's `code` filter)\n * must remain a superset of — widening this to a specifier that does not\n * contain \"zod\" silently strips those files from every bundler with native\n * hook filters. `describe(\"code filter soundness\")` fails if it drifts.\n */\nexport const HAS_RUNTIME_ZOD_IMPORT = /import\\s+(?!type\\s)[^;]*from\\s+[\"']zod(?:\\/v\\d+)?[\"']/;\n\n/**\n * Opt-in phase timing (ZOD_COMPILER_TIMING=1): accumulates per-phase wall time\n * across all transform calls and prints a summary on process exit. Used to\n * attribute plugin overhead in real builds/test runs.\n */\nconst TIMING = process.env[\"ZOD_COMPILER_TIMING\"] === \"1\";\n\n/** A single file's discovery exceeding this is worth an actionable warning. */\nconst SLOW_DISCOVERY_WARN_MS = 5_000;\nconst phaseTotals = new Map<string, { ms: number; calls: number }>();\nlet timingHookInstalled = false;\n\n/** Dedupes the process.exit-during-discovery warning to one per process. */\nlet warnedProcessExit = false;\n\nfunction timePhase<T>(phase: string, fn: () => T): T {\n if (!TIMING) return fn();\n const t0 = performance.now();\n const done = (): void => {\n const dt = performance.now() - t0;\n const agg = phaseTotals.get(phase) ?? { ms: 0, calls: 0 };\n agg.ms += dt;\n agg.calls++;\n phaseTotals.set(phase, agg);\n };\n if (!timingHookInstalled) {\n timingHookInstalled = true;\n process.on(\"exit\", () => {\n const rows = [...phaseTotals.entries()].sort((a, b) => b[1].ms - a[1].ms);\n for (const [name, { ms, calls }] of rows) {\n log(`timing ${name}: ${ms.toFixed(1)}ms over ${calls} call(s)`);\n }\n });\n }\n const r = fn();\n if (r instanceof Promise) {\n return r.finally(done) as T;\n }\n done();\n return r;\n}\n\n/**\n * Check if a file should be transformed by the plugin.\n */\nexport function shouldTransform(id: string, options?: ZodCompilerPluginOptions): boolean {\n if (!/\\.[cm]?[jt]sx?$/.test(id)) return false;\n if (id.includes(\"node_modules\")) return false;\n if (id.endsWith(\".d.ts\")) return false;\n if (id.endsWith(\".compiled.ts\") || id.endsWith(\".compiled.js\")) return false;\n\n if (options?.exclude?.some((pattern) => picomatch.isMatch(id, pattern, { contains: true })))\n return false;\n if (\n options?.include &&\n !options.include.some((pattern) => picomatch.isMatch(id, pattern, { contains: true }))\n )\n return false;\n\n return true;\n}\n\n/**\n * `id` half of the transform hook filter: the option-independent checks of\n * shouldTransform(), restated as patterns the bundler can evaluate itself.\n * Rolldown, Vite and Rollup 4.40+ apply hook filters natively, so a rejected\n * module never crosses into JS; unplugin applies the same patterns in JS for\n * the rest (webpack/rspack skip installing the transform loader entirely).\n *\n * The `include`/`exclude` options stay out of the filter on purpose: they are\n * matched with picomatch's `contains: true` semantics, which the native glob\n * support (patterns resolved against cwd, matched whole) would silently\n * narrow — shouldTransform() keeps applying them inside the handler.\n */\nexport const TRANSFORM_ID_FILTER: { exclude: RegExp[]; include: RegExp[] } = {\n exclude: [/node_modules/, /\\.d\\.ts$/, /\\.compiled\\.[jt]s$/],\n include: [/\\.[cm]?[jt]sx?$/],\n};\n\n/**\n * Every transform path that can change a file needs the substring \"zod\" (or\n * \"Zod\") somewhere in the source. There are exactly three triggers, and each\n * one is pinned by `describe(\"code filter soundness\")` in the transform tests:\n *\n * 1. auto-discovery — HAS_RUNTIME_ZOD_IMPORT (above), which only matches\n * specifiers spelled \"zod…\";\n * 2. `schemas: \"explicit\"` — an import from \"zod-compiler\" (the package name);\n * 3. hoisting — a root imported from ZOD_MODULES or an identifier matching\n * SCHEMA_NAME_PATTERN (both in hoist.ts; a *custom* pattern drops this\n * filter entirely, see transformCodeFilter).\n *\n * Adding a fourth trigger that can fire without a \"zod\" mention MUST widen\n * this pattern, or those files are silently skipped on every bundler with\n * native hook filters — no error, schemas just quietly stay uncompiled.\n *\n * Spelled as a character class rather than an `i` flag: native filters\n * recompile these patterns outside JS, where flag support is narrower.\n */\nconst ZOD_MENTION = /[Zz]od/;\n\n/**\n * `code` half of the transform hook filter, or undefined when no sound filter\n * exists. A custom `hoist.schemaNamePattern` promotes arbitrary imported\n * identifiers to schema roots (`UserModel`), so nothing in such a file is\n * guaranteed to mention zod — those setups keep the unfiltered behavior.\n */\nexport function transformCodeFilter(options?: ZodCompilerPluginOptions): RegExp | undefined {\n const namePattern = typeof options?.hoist === \"object\" ? options.hoist.schemaNamePattern : null;\n // `null` disables name matching and `undefined` keeps the default\n // /ZodSchema$/ — both leave a \"zod\" mention as the only way in.\n return namePattern === null || namePattern === undefined ? ZOD_MENTION : undefined;\n}\n\nexport function log(msg: string): void {\n // oxlint-disable-next-line no-console -- build output\n console.log(`[zod-compiler] ${msg}`);\n}\n\nfunction warn(msg: string): void {\n // oxlint-disable-next-line no-console -- build output\n console.warn(`[zod-compiler] ${msg}`);\n}\n\nexport interface TransformOutput {\n code: string;\n map: TransformSourceMap | null;\n}\n\n/**\n * Transform source code by replacing compile() calls with optimized validators.\n * Returns the transformed code or null if no transformation was needed.\n * Compatibility wrapper over transformCodeWithMap() — discards the map.\n */\nexport async function transformCode(\n code: string,\n id: string,\n options: TransformOptions,\n): Promise<string | null> {\n const result = await transformCodeWithMap(code, id, options);\n return result === null ? null : result.code;\n}\n\n/**\n * transformCode + a composed sourcemap (original → output). Stack traces in\n * transformed files shift by prepended declarations and expanded IIFEs\n * without it — a vitest assertion can be reported dozens of lines off.\n */\nexport async function transformCodeWithMap(\n code: string,\n id: string,\n options: TransformOptions,\n): Promise<TransformOutput | null> {\n const verbose = options.verbose === true;\n const autoDiscover = options.autoDiscover === true;\n const mode = options.mode;\n const staged = new StagedTransform(code, id);\n\n // Hoist Zod schema construction out of function bodies to module scope\n // (babel-plugin-zod-hoist equivalent). Mode-independent: inline schemas\n // live exactly in the files that export none. hoistZodSchemasMeta() bails\n // in microseconds when no eligible imports exist.\n let hoistedSchemas: ReturnType<typeof hoistZodSchemasMeta> = null;\n if (options.hoist !== false && code.includes(\"import\")) {\n hoistedSchemas = timePhase(\"hoist\", () =>\n hoistZodSchemasMeta(code, {\n ...(typeof options.hoist === \"object\" ? options.hoist : undefined),\n onScan: options.onSubstantialWork,\n }),\n );\n if (hoistedSchemas !== null) {\n staged.apply(hoistedSchemas.edits, hoistedSchemas.insert);\n if (verbose) {\n log(`Hoisted inline Zod schemas in ${id}`);\n }\n }\n }\n\n // Compile the hoisted schemas (autoDiscover only — compiling anonymous\n // schemas is auto-discovery of unexported module-scope schemas). Each\n // hoisted `const _zh_x = z.object({...});` whose construction is\n // deterministic (eager refs are zod bindings only) is evaluated at build\n // time and its initializer replaced with the compiled validator IIFE;\n // anything ineligible stays a plain hoist.\n const hoistHelpers = new Set<string>();\n let hoistCompiledCount = 0;\n if (autoDiscover && hoistedSchemas !== null && hoistedSchemas.schemas.length > 0) {\n const hoistCompiled = await timePhase(\"hoist-compile\", () =>\n compileHoistedSchemas(hoistedSchemas.schemas, code, id, mode),\n );\n const spliceEdits: Edit[] = [];\n for (const h of hoistCompiled) {\n const decl = `const ${h.name} = ${h.text};`;\n const at = staged.current.indexOf(decl);\n if (at === -1) continue;\n const iife = generateIIFE(h.text, h.info, { zodCompat: options.zodCompat });\n spliceEdits.push({ start: at, end: at + decl.length, text: `const ${h.name} = ${iife};` });\n hoistCompiledCount++;\n for (const helper of h.info.codegenResult.usedHelpers) {\n hoistHelpers.add(helper);\n }\n if (verbose) {\n log(` ✓ ${h.name} (hoisted schema compiled)`);\n }\n }\n staged.apply(spliceEdits);\n if (hoistCompiledCount > 0) {\n hoistHelpers.add(\"__zcMkv\");\n hoistHelpers.add(\"__zcFin\");\n }\n }\n\n // When only hoisting (± hoisted-schema compilation) changed the file, that\n // is still a transform result — with runtime helpers injected if any\n // hoisted schema compiled.\n const finishHoistOnly = (): TransformOutput | null => {\n if (staged.current === code) return null;\n if (hoistCompiledCount > 0) {\n options.onBuildStats?.({\n files: 1,\n schemas: hoistedSchemas?.schemas.length ?? 0,\n optimized: hoistCompiledCount,\n failed: 0,\n });\n const prefix = computeRuntimePrefix(staged.current, hoistHelpers, mode, options.runtimeId);\n if (prefix !== null) {\n staged.apply([], { offset: 0, text: prefix });\n }\n }\n return { code: staged.current, map: staged.map() };\n };\n\n // Quick bail-out check. Both gates are also encoded in the transform hook's\n // `code` filter (ZOD_MENTION) so bundlers can skip the hook call entirely —\n // relaxing either one here without widening that pattern makes the bundler\n // drop those files before this code ever runs.\n if (autoDiscover) {\n // autoDiscover: any file with a runtime Zod import is a candidate.\n // Skip `import type` — these files have no runtime schemas.\n if (!HAS_RUNTIME_ZOD_IMPORT.test(staged.current)) return finishHoistOnly();\n } else {\n // Legacy mode: require compile() from zod-compiler. The word-boundary\n // check matters: the package name itself contains the substring\n // \"compile\", so a plain includes(\"compile\") would match every import of\n // \"zod-compiler\" — \\bcompile\\b does not match inside \"zod-compiler\"\n // (no boundary between \"e\" and \"r\") but matches compile( / { compile }.\n if (!staged.current.includes(\"zod-compiler\") || !/\\bcompile\\b/.test(staged.current))\n return finishHoistOnly();\n }\n\n // Static pre-filter: skip files whose exports provably cannot be schemas\n // (functions, components, constants, type-only modules) without executing\n // them. Conservative — anything ambiguous stays a candidate. The filter\n // transpiles + parses the file, so its outcome is worth persisting even\n // when the eventual result is null.\n options.onSubstantialWork?.();\n if (!(await timePhase(\"static-filter\", () => mayExportSchemas(staged.current, id))))\n return finishHoistOnly();\n\n // Discover schemas by executing the file. Module executions are cached in\n // the shared loader; watch/HMR changes invalidate via invalidateModuleCache().\n options.onDiscovery?.();\n let schemas: DiscoveredSchema[];\n const discoverStart = performance.now();\n try {\n schemas = await timePhase(\"discover\", () => discoverSchemas(id, { autoDiscover }));\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n // A module in the import graph called process.exit() during discovery —\n // typically an env-validation guard in a CI build where secrets are\n // intentionally absent. The loader converts that exit into a catchable\n // error so the build survives; the affected files just fall back to\n // runtime Zod. Handle it in both modes (never crash on a build-time exit)\n // and surface the cooperative remedy once.\n if (e instanceof ProcessExitDuringLoadError) {\n // The result reflects missing secrets, not file content — never persist\n // it to the content-hashed disk cache (a later secret-ful build would be\n // served this stale \"nothing compiled\" entry).\n options.onUncacheableResult?.();\n if (!warnedProcessExit) {\n warnedProcessExit = true;\n warn(\n `${id} (or a module it imports) called process.exit during build-time schema ` +\n `discovery — those files fall back to runtime Zod instead of crashing the build. ` +\n `This is usually an env-validation guard; wrap it in ` +\n `\\`if (!process.env.ZOD_COMPILER) { ... }\\` to keep these schemas compiled, or set ` +\n `schemas:\"explicit\" / use include to scope discovery.`,\n );\n }\n return finishHoistOnly();\n }\n // In autoDiscover mode, files that can't be loaded (JSX components,\n // unresolved path aliases, etc.) are expected — warn and skip.\n if (autoDiscover) {\n if (verbose) {\n warn(`Skipping ${id}: ${msg}`);\n }\n return finishHoistOnly();\n }\n throw new Error(`[zod-compiler] Failed to load schemas from ${id}: ${msg}`);\n }\n const discoverMs = performance.now() - discoverStart;\n if (discoverMs >= SLOW_DISCOVERY_WARN_MS) {\n // Discovery executes the file's whole first-party import graph inside\n // the bundler's single-threaded process — on saturated CI hosts a large\n // graph can stall the event loop long enough to trip test timeouts.\n // Surface the cost with the two effective remedies.\n warn(\n `Discovery of ${id} took ${(discoverMs / 1000).toFixed(1)}s executing its import graph ` +\n `in the bundler process. Persist node_modules/.cache/zod-compiler across CI runs to pay ` +\n `this once, or narrow autoDiscover/include for test runs (see README \"Large projects ` +\n `and CI\"). ZOD_COMPILER_TIMING=1 prints a per-phase breakdown.`,\n );\n }\n if (schemas.length === 0) return finishHoistOnly();\n\n // Lean mode (every bundler in VIRTUAL_MODULE_FRAMEWORKS — Vite/Rollup/webpack/rspack/etc.)\n // imports shared helpers from a runtime module for cross-file dedup: virtual:zod-compiler/runtime\n // on virtual-friendly bundlers, the __zod-compiler-runtime__ bare specifier on webpack/rspack.\n // Inline mode (CLI emitter, and any bundler not in VIRTUAL_MODULE_FRAMEWORKS) emits self-contained\n // file-level helpers.\n let failedCount = 0;\n const { schemas: compiled, shared } = timePhase(\"compile\", () =>\n compileSchemas(schemas, {\n mode,\n compact: options.compact,\n onError(exportName, error) {\n failedCount++;\n warn(\n `Failed to compile \"${exportName}\" in ${id}: ${error.message}. Keeping original${autoDiscover ? \"\" : \" compile()\"} call.`,\n );\n },\n }),\n );\n\n if (verbose) {\n if (autoDiscover) {\n log(\n `Auto-discovering: ${id} (${schemas.length} Zod export${schemas.length > 1 ? \"s\" : \"\"} found)`,\n );\n }\n for (const s of compiled) {\n const rfCount = s.refEntries.length;\n const rfSuffix = rfCount > 0 ? ` (${rfCount} ref${rfCount > 1 ? \"s\" : \"\"})` : \"\";\n log(` ✓ ${s.exportName}${rfSuffix}`);\n }\n if (failedCount > 0) {\n log(` ✗ ${failedCount} schema(s) failed`);\n }\n }\n\n if (compiled.length === 0) return finishHoistOnly();\n\n // Report build stats only when at least one schema was compiled\n // (hoisted-schema compiles count alongside export schemas).\n options.onBuildStats?.({\n files: 1,\n schemas: schemas.length + (hoistedSchemas?.schemas.length ?? 0),\n optimized: compiled.length + hoistCompiledCount,\n failed: failedCount,\n });\n\n // __zcMkv and __zcFin are always needed (they wrap every IIFE). Helpers used\n // by compiled hoisted schemas ride along in the same injection.\n const usedHelpers = aggregateUsedHelpers(compiled);\n usedHelpers.add(\"__zcMkv\");\n usedHelpers.add(\"__zcFin\");\n for (const helper of hoistHelpers) {\n usedHelpers.add(helper);\n }\n // Shared dedup validators ride the same runtime import.\n for (const helper of shared.usedHelpers) {\n usedHelpers.add(helper);\n }\n\n // Two-pass rewrite: separate compile() schemas from autoDiscover schemas.\n // Both passes collect edits against the same pristine stage input — their\n // target regions are disjoint (compile() assignments vs plain exported\n // declarations of OTHER names), so one batched application is equivalent\n // to the historical sequential rewrites.\n let rewriteEdits: readonly Edit[];\n if (autoDiscover) {\n // Detect compile() schemas by checking source code patterns\n const compileExportNames = new Set<string>();\n for (const s of compiled) {\n const pattern = new RegExp(`\\\\b${s.exportName}\\\\s*=\\\\s*compile[\\\\s<(]`);\n if (pattern.test(staged.current)) {\n compileExportNames.add(s.exportName);\n }\n }\n const compileSchemaInfos = compiled.filter((s) => compileExportNames.has(s.exportName));\n const autoDiscoverSchemaInfos = compiled.filter((s) => !compileExportNames.has(s.exportName));\n\n const edits: Edit[] = [];\n // Pass 1: compile() schemas (includes compile-import removal — only when\n // compile() schemas were actually rewritten, mirroring the historical\n // conditional rewriteSource call)\n if (compileSchemaInfos.length > 0) {\n edits.push(\n ...collectCompileRewriteEdits(staged.current, compileSchemaInfos, {\n zodCompat: options.zodCompat,\n }),\n );\n }\n // Pass 2: plain exported schemas\n if (autoDiscoverSchemaInfos.length > 0) {\n edits.push(\n ...collectAutoDiscoverEdits(staged.current, autoDiscoverSchemaInfos, {\n zodCompat: options.zodCompat,\n }),\n );\n }\n rewriteEdits = edits;\n } else {\n rewriteEdits = collectCompileRewriteEdits(staged.current, compiled, {\n zodCompat: options.zodCompat,\n });\n }\n\n // Head = runtime helpers/import, then the file-level shared dedup block, then\n // the rewritten source. The shared `__zcSw_N` functions live at module scope\n // so every IIFE closes over them; they must follow the runtime import (lean)\n // and the helper decls (inline) that they reference. Guard against\n // double-injection on watch/HMR re-runs the same way computeRuntimePrefix\n // does — a second copy would redeclare every `__zcSw_N`.\n //\n // Deferred into the rewrite's own stage rather than staged after it: both\n // decisions read the REWRITTEN text, and giving a bare prepend its own stage\n // doubled the sourcemap work and added a composition pass (see applyThen).\n staged.applyThen(rewriteEdits, (rewritten) => {\n const prefix = computeRuntimePrefix(rewritten, usedHelpers, mode, options.runtimeId);\n const needsShared = shared.code !== \"\" && !rewritten.includes(SHARED_BLOCK_MARKER);\n const head = (prefix ?? \"\") + (needsShared ? `${shared.code}\\n` : \"\");\n return head === \"\" ? undefined : { offset: 0, text: head };\n });\n return { code: staged.current, map: staged.map() };\n}\n\n/**\n * Prepend the runtime helpers required by the rewritten source.\n *\n * Lean mode emits a single `import { ... } from \"<runtimeId>\";` line —\n * bundlers whose resolveId hook intercepts the specifier dedup helpers across\n * every transformed file into one shared virtual module.\n *\n * Inline mode prepends file-level `function __zcMkv` / `function __zcFin`\n * declarations directly so the file is self-contained.\n *\n * Idempotent: if the file already contains the relevant marker (re-run during\n * watch/HMR), we skip re-injection.\n */\n/** The runtime-helper text to prepend, or null when nothing is needed. */\nfunction computeRuntimePrefix(\n code: string,\n usedHelpers: Set<string>,\n mode: CodegenMode,\n runtimeId: string = VIRTUAL_RUNTIME_ID,\n): string | null {\n if (mode === \"lean\") {\n if (usedHelpers.size === 0) return null;\n if (code.includes(runtimeId)) return null;\n const names = [...usedHelpers].sort().join(\", \");\n return `import { ${names} } from \"${runtimeId}\";\\n`;\n }\n // Inline mode (CLI emitter, and any bundler not in VIRTUAL_MODULE_FRAMEWORKS):\n // ship file-level helper declarations instead of a virtual import.\n // Codegen emits per-IIFE issue literals + per-IIFE `__re_*` decls,\n // so we only need __zcMkv / __zcFin (plus __zcMsg via the zod config import).\n if (!code.includes(\"__zcMkv\")) return null;\n const prefix: string[] = [];\n if (!code.includes(\"__zodCompilerConfig\")) {\n prefix.push(ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION);\n }\n if (!code.includes(\"function __zcMkv(\")) {\n prefix.push(MK_VALIDATOR_DECL);\n }\n // __zcFin and __zcFinD both construct __ZcFail; declare it once before either,\n // guarding against a header already shipped earlier in the same module.\n const needsFin = !code.includes(\"function __zcFin(\");\n const needsFinD = code.includes(\"__zcFinD(\") && !code.includes(\"function __zcFinD(\");\n if ((needsFin || needsFinD) && !code.includes(\"function __ZcFail(\")) {\n prefix.push(FAIL_CLASS_DECL);\n }\n if (needsFin) {\n prefix.push(FIN_DECL);\n }\n if (needsFinD) {\n prefix.push(FIN_DEFERRED_DECL);\n }\n // Compact mode (output: \"compact\") delegates cold errors to zod via __zcFinZ,\n // which constructs its own __ZcFailZ (distinct from __ZcFail).\n const needsFinZ = code.includes(\"__zcFinZ(\") && !code.includes(\"function __zcFinZ(\");\n if (needsFinZ && !code.includes(\"function __ZcFailZ(\")) {\n prefix.push(FAILZ_CLASS_DECL);\n }\n if (needsFinZ) {\n prefix.push(FINZ_DECL);\n }\n return prefix.length > 0 ? `${prefix.join(\"\\n\")}\\n` : null;\n}\n\n/**\n * Find the matching closing parenthesis for a compile() call,\n * handling nested parentheses like compile(z.object({...})).\n * Returns the index of the closing ')' or -1 if not found.\n */\nfunction findMatchingParen(code: string, openIndex: number): number {\n let depth = 1;\n for (let i = openIndex + 1; i < code.length; i++) {\n if (code[i] === \"(\") depth++;\n else if (code[i] === \")\") {\n depth--;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\n/**\n * Rewrite source code by replacing compile() calls with IIFE-wrapped optimized validators.\n */\nexport function rewriteSource(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): string {\n return applyEdits(code, collectCompileRewriteEdits(code, schemas, options));\n}\n\n/**\n * Edits for rewriteSource (compile() call replacements + compile-import\n * removal), collected against pristine `code`. Each schema's declaration is\n * a distinct region and the import statement is distinct from all of them,\n * so the batch is non-overlapping and order-independent.\n */\nfunction collectCompileRewriteEdits(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): Edit[] {\n const edits: Edit[] = [];\n for (const schema of schemas) {\n // Match: <exportName> = compile<...>( with word boundary to prevent substring matches\n const prefixPattern = new RegExp(\n `(\\\\b${schema.exportName}\\\\s*=\\\\s*)compile\\\\s*(?:<[^>]*(?:<[^>]*>[^>]*)?>)?\\\\s*\\\\(`,\n );\n const match = prefixPattern.exec(code);\n if (!match) continue;\n\n // Find the matching closing paren (handles nested parens)\n const openParenIndex = match.index + match[0].length - 1;\n const closeParenIndex = findMatchingParen(code, openParenIndex);\n if (closeParenIndex === -1) continue;\n\n const schemaArgName = code\n .slice(openParenIndex + 1, closeParenIndex)\n .trim()\n .replace(/,\\s*$/, \"\");\n const prefix = match[1] ?? \"\";\n edits.push({\n start: match.index,\n end: closeParenIndex + 1,\n text: prefix + generateIIFE(schemaArgName, schema, options),\n });\n }\n edits.push(...collectRemoveCompileImportEdits(code));\n return edits;\n}\n\n/**\n * Find the end position of a JavaScript expression starting at `start` using acorn.\n * Returns the end offset, or -1 if the expression cannot be parsed.\n */\nexport function findExpressionEnd(code: string, start: number): number {\n try {\n const node = parseExpressionAt(code, start, {\n ecmaVersion: \"latest\",\n sourceType: \"module\",\n });\n return node.end;\n } catch {\n return -1;\n }\n}\n\n/**\n * Rewrite source code by replacing plain Zod schema exports with IIFE-wrapped optimized validators.\n * Used by autoDiscover mode (no compile() wrappers needed).\n */\nexport function rewriteSourceAutoDiscover(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): string {\n return applyEdits(code, collectAutoDiscoverEdits(code, schemas, options));\n}\n\n/** Edits for rewriteSourceAutoDiscover, collected against pristine `code`. */\nfunction collectAutoDiscoverEdits(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): Edit[] {\n const edits: Edit[] = [];\n for (const schema of schemas) {\n const escapedName = schema.exportName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n // Match: export? (const|let|var) ExportName[: TypeAnnotation] = <expr>\n const assignPattern = new RegExp(\n `((?:export\\\\s+)?(?:const|let|var)\\\\s+${escapedName}(?:\\\\s*:[^=]*)?\\\\s*=\\\\s*)`,\n );\n const match = assignPattern.exec(code);\n if (!match) continue;\n\n const rhsStart = match.index + match[0].length;\n const rhsEnd = findExpressionEnd(code, rhsStart);\n if (rhsEnd === -1) continue;\n\n const originalExpr = code.slice(rhsStart, rhsEnd).trim();\n edits.push({\n start: rhsStart,\n end: rhsEnd,\n text: generateIIFE(originalExpr, schema, options),\n });\n }\n return edits;\n}\n\n/**\n * Remove the `compile` binding from `import { compile, ... } from \"zod-compiler\"` statements.\n * If `compile` is the only import, the entire import line is removed.\n */\nexport function removeCompileImport(code: string): string {\n return applyEdits(code, collectRemoveCompileImportEdits(code));\n}\n\n/** Edits stripping the `compile` binding from zod-compiler import statements. */\nfunction collectRemoveCompileImportEdits(code: string): Edit[] {\n // Match: import { ... } from \"zod-compiler\" or 'zod-compiler'\n const importPattern = /import\\s*\\{([^}]*)\\}\\s*from\\s*[\"']zod-compiler[\"'];?/g;\n const edits: Edit[] = [];\n for (const match of code.matchAll(importPattern)) {\n const imports = match[1] ?? \"\";\n const names = imports\n .split(\",\")\n .map((n) => n.trim())\n .filter(Boolean);\n const remaining = names.filter((n) => n !== \"compile\");\n const text =\n remaining.length === 0 ? \"\" : `import { ${remaining.join(\", \")} } from \"zod-compiler\";`;\n if (text !== match[0]) {\n edits.push({ start: match.index, end: match.index + match[0].length, text });\n }\n }\n return edits;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"transform.js","names":[],"sources":["../../src/unplugin/transform.ts"],"sourcesContent":["import remapping from \"@jridgewell/remapping\";\nimport { parseExpressionAt } from \"acorn\";\nimport MagicString from \"magic-string\";\nimport picomatch from \"picomatch\";\nimport type { CodegenMode } from \"../core/codegen/context.js\";\nimport { SHARED_BLOCK_MARKER } from \"../core/codegen/dedupe.js\";\nimport {\n FAIL_CLASS_DECL,\n FAILZ_CLASS_DECL,\n FIN_DECL,\n FIN_DEFERRED_DECL,\n FINZ_DECL,\n generateIIFE,\n MK_VALIDATOR_DECL,\n ZOD_CONFIG_IMPORT,\n ZOD_MSG_DECLARATION,\n} from \"../core/iife.js\";\nimport { aggregateUsedHelpers, type CompiledSchemaInfo, compileSchemas } from \"../core/pipeline.js\";\nimport type { DiscoveredSchema } from \"../core/types.js\";\nimport { discoverSchemas } from \"../discovery.js\";\nimport { ProcessExitDuringLoadError } from \"../loader.js\";\nimport { mayExportSchemas } from \"../static-filter.js\";\nimport { applyEdits, type Edit, type Insertion, moduleHeadOffset } from \"./edits.js\";\nimport { hoistZodSchemasMeta } from \"./hoist.js\";\nimport { compileHoistedSchemas } from \"./hoist-compile.js\";\nimport type { TransformOptions, ZodCompilerPluginOptions } from \"./types.js\";\nimport { VIRTUAL_RUNTIME_ID } from \"./virtual.js\";\n\n/** JSON shape of the composed sourcemap returned alongside transformed code. */\nexport interface TransformSourceMap {\n version: number;\n sources: (string | null)[];\n sourcesContent?: (string | null)[];\n names: string[];\n mappings: string;\n file?: string | null;\n}\n\n/**\n * The transform pipeline as a chain of edit batches. Each batch is applied\n * to the CURRENT text through a MagicString (one stage map per batch); the\n * final original→output map is the remapping-composed chain. Deriving the\n * output string and the map from the same edit list makes divergence\n * impossible.\n */\nclass StagedTransform {\n current: string;\n private readonly source: string;\n private readonly maps: unknown[] = [];\n\n constructor(original: string, source: string) {\n this.current = original;\n this.source = source;\n }\n\n apply(edits: readonly Edit[], insert?: Insertion): void {\n this.stage(edits, (s) => {\n if (insert === undefined) return false;\n s.appendLeft(insert.offset, insert.text);\n return true;\n });\n }\n\n /**\n * Apply `edits`, then prepend `deferred`'s text to the module head — both\n * inside ONE stage.\n *\n * The head injection (runtime import + shared dedup block) has to be decided\n * from the REWRITTEN source, because `computeRuntimePrefix` probes it for\n * already-present markers. Staging it separately made a whole second\n * `generateMap` over the full generated output — for what is only a prepend at\n * the module head — and then forced `remapping` to compose the two. Together\n * those were the dominant cost of a transform: on a 320-schema project they ran\n * to 64% of total wall time, more than discovery and codegen combined. Deferring\n * the insertion into the same MagicString buys byte-identical output and an\n * equivalent map for one generation and no composition — 1.6x (small schemas)\n * to 3.4x (large ones) on the transform, scaling with how much code a file\n * emits, since that is what both costs are proportional to.\n *\n * `deferred` returns TEXT, not an `Insertion`: `appendLeft` resolves offsets\n * against the PRE-edit text while `deferred` is shown the POST-edit text, so a\n * callback-supplied offset would be in the wrong coordinate system. Deriving it\n * here from `this.current` keeps the two in step by construction.\n */\n applyThen(edits: readonly Edit[], deferred?: (rewritten: string) => string | undefined): void {\n this.stage(edits, (s, rewritten) => {\n // `?.()` short-circuits its arguments, so a stage with no deferred step\n // never materializes the rewritten text.\n const head = deferred?.(rewritten());\n if (head === undefined) return false;\n s.appendLeft(moduleHeadOffset(this.current), head);\n return true;\n });\n }\n\n /**\n * One stage: apply `edits` to a fresh MagicString, let `inject` add at most\n * one insertion, then commit the text and its map. `inject` reports whether\n * it inserted, so a no-op stage can be skipped entirely.\n *\n * `rewritten` is a thunk, not a string: materializing it costs a full\n * `toString()` over generated-code-sized input, and the injectors that do not\n * read it (every `apply()` call) must not pay for it.\n */\n private stage(\n edits: readonly Edit[],\n inject: (s: MagicString, rewritten: () => string) => boolean,\n ): void {\n const s = new MagicString(this.current);\n for (const e of edits) {\n if (e.start === e.end) {\n s.appendLeft(e.start, e.text);\n } else {\n s.overwrite(e.start, e.end, e.text);\n }\n }\n // `toString()` is the only way to show the deferred step what the rewrite\n // produced; it measured well under 1% of a transform.\n const inserted = inject(s, () => (edits.length === 0 ? this.current : s.toString()));\n if (edits.length === 0 && !inserted) return;\n this.current = s.toString();\n // `hires: \"boundary\"` is load-bearing, not a tuning knob: without it every\n // mapping collapses to column 0, so a stack frame or debugger breakpoint in\n // untouched user code below a compiled schema lands at the start of its line\n // instead of the right column (tests/unplugin/sourcemap.test.ts pins it). It\n // is also the most expensive thing here, which is why the stage COUNT is\n // what to economize on.\n this.maps.push(s.generateMap({ source: this.source, hires: \"boundary\", includeContent: true }));\n }\n\n /** Composed original→current map, or null when nothing was applied. */\n map(): TransformSourceMap | null {\n if (this.maps.length === 0) return null;\n // A single stage needs no composition: `remapping` over a one-map chain\n // reproduces that map, and it is expensive on generated-code-sized input.\n const [only] = this.maps;\n if (this.maps.length === 1) return only as TransformSourceMap;\n const chain = [...this.maps].reverse();\n return remapping(\n chain as Parameters<typeof remapping>[0],\n () => null,\n ) as unknown as TransformSourceMap;\n }\n}\n\n/**\n * Matches a runtime (non-type-only) import from \"zod\".\n *\n * One of the three triggers ZOD_MENTION (the transform hook's `code` filter)\n * must remain a superset of — widening this to a specifier that does not\n * contain \"zod\" silently strips those files from every bundler with native\n * hook filters. `describe(\"code filter soundness\")` fails if it drifts.\n */\nexport const HAS_RUNTIME_ZOD_IMPORT = /import\\s+(?!type\\s)[^;]*from\\s+[\"']zod(?:\\/v\\d+)?[\"']/;\n\n/**\n * Opt-in phase timing (ZOD_COMPILER_TIMING=1): accumulates per-phase wall time\n * across all transform calls and prints a summary on process exit. Used to\n * attribute plugin overhead in real builds/test runs.\n */\nconst TIMING = process.env[\"ZOD_COMPILER_TIMING\"] === \"1\";\n\n/** A single file's discovery exceeding this is worth an actionable warning. */\nconst SLOW_DISCOVERY_WARN_MS = 5_000;\nconst phaseTotals = new Map<string, { ms: number; calls: number }>();\nlet timingHookInstalled = false;\n\n/** Dedupes the process.exit-during-discovery warning to one per process. */\nlet warnedProcessExit = false;\n\nfunction timePhase<T>(phase: string, fn: () => T): T {\n if (!TIMING) return fn();\n const t0 = performance.now();\n const done = (): void => {\n const dt = performance.now() - t0;\n const agg = phaseTotals.get(phase) ?? { ms: 0, calls: 0 };\n agg.ms += dt;\n agg.calls++;\n phaseTotals.set(phase, agg);\n };\n if (!timingHookInstalled) {\n timingHookInstalled = true;\n process.on(\"exit\", () => {\n const rows = [...phaseTotals.entries()].sort((a, b) => b[1].ms - a[1].ms);\n for (const [name, { ms, calls }] of rows) {\n log(`timing ${name}: ${ms.toFixed(1)}ms over ${calls} call(s)`);\n }\n });\n }\n const r = fn();\n if (r instanceof Promise) {\n return r.finally(done) as T;\n }\n done();\n return r;\n}\n\n/**\n * Check if a file should be transformed by the plugin.\n */\nexport function shouldTransform(id: string, options?: ZodCompilerPluginOptions): boolean {\n if (!/\\.[cm]?[jt]sx?$/.test(id)) return false;\n if (id.includes(\"node_modules\")) return false;\n if (id.endsWith(\".d.ts\")) return false;\n if (id.endsWith(\".compiled.ts\") || id.endsWith(\".compiled.js\")) return false;\n\n if (options?.exclude?.some((pattern) => picomatch.isMatch(id, pattern, { contains: true })))\n return false;\n if (\n options?.include &&\n !options.include.some((pattern) => picomatch.isMatch(id, pattern, { contains: true }))\n )\n return false;\n\n return true;\n}\n\n/**\n * `id` half of the transform hook filter: the option-independent checks of\n * shouldTransform(), restated as patterns the bundler can evaluate itself.\n * Rolldown, Vite and Rollup 4.40+ apply hook filters natively, so a rejected\n * module never crosses into JS; unplugin applies the same patterns in JS for\n * the rest (webpack/rspack skip installing the transform loader entirely).\n *\n * The `include`/`exclude` options stay out of the filter on purpose: they are\n * matched with picomatch's `contains: true` semantics, which the native glob\n * support (patterns resolved against cwd, matched whole) would silently\n * narrow — shouldTransform() keeps applying them inside the handler.\n */\nexport const TRANSFORM_ID_FILTER: { exclude: RegExp[]; include: RegExp[] } = {\n exclude: [/node_modules/, /\\.d\\.ts$/, /\\.compiled\\.[jt]s$/],\n include: [/\\.[cm]?[jt]sx?$/],\n};\n\n/**\n * Every transform path that can change a file needs the substring \"zod\" (or\n * \"Zod\") somewhere in the source. There are exactly three triggers, and each\n * one is pinned by `describe(\"code filter soundness\")` in the transform tests:\n *\n * 1. auto-discovery — HAS_RUNTIME_ZOD_IMPORT (above), which only matches\n * specifiers spelled \"zod…\";\n * 2. `schemas: \"explicit\"` — an import from \"zod-compiler\" (the package name);\n * 3. hoisting — a root imported from ZOD_MODULES or an identifier matching\n * SCHEMA_NAME_PATTERN (both in hoist.ts; a *custom* pattern drops this\n * filter entirely, see transformCodeFilter).\n *\n * Adding a fourth trigger that can fire without a \"zod\" mention MUST widen\n * this pattern, or those files are silently skipped on every bundler with\n * native hook filters — no error, schemas just quietly stay uncompiled.\n *\n * Spelled as a character class rather than an `i` flag: native filters\n * recompile these patterns outside JS, where flag support is narrower.\n */\nconst ZOD_MENTION = /[Zz]od/;\n\n/**\n * `code` half of the transform hook filter, or undefined when no sound filter\n * exists. A custom `hoist.schemaNamePattern` promotes arbitrary imported\n * identifiers to schema roots (`UserModel`), so nothing in such a file is\n * guaranteed to mention zod — those setups keep the unfiltered behavior.\n */\nexport function transformCodeFilter(options?: ZodCompilerPluginOptions): RegExp | undefined {\n const namePattern = typeof options?.hoist === \"object\" ? options.hoist.schemaNamePattern : null;\n // `null` disables name matching and `undefined` keeps the default\n // /ZodSchema$/ — both leave a \"zod\" mention as the only way in.\n return namePattern === null || namePattern === undefined ? ZOD_MENTION : undefined;\n}\n\nexport function log(msg: string): void {\n // oxlint-disable-next-line no-console -- build output\n console.log(`[zod-compiler] ${msg}`);\n}\n\nfunction warn(msg: string): void {\n // oxlint-disable-next-line no-console -- build output\n console.warn(`[zod-compiler] ${msg}`);\n}\n\nexport interface TransformOutput {\n code: string;\n map: TransformSourceMap | null;\n}\n\n/**\n * Transform source code by replacing compile() calls with optimized validators.\n * Returns the transformed code or null if no transformation was needed.\n * Compatibility wrapper over transformCodeWithMap() — discards the map.\n */\nexport async function transformCode(\n code: string,\n id: string,\n options: TransformOptions,\n): Promise<string | null> {\n const result = await transformCodeWithMap(code, id, options);\n return result === null ? null : result.code;\n}\n\n/**\n * transformCode + a composed sourcemap (original → output). Stack traces in\n * transformed files shift by prepended declarations and expanded IIFEs\n * without it — a vitest assertion can be reported dozens of lines off.\n */\nexport async function transformCodeWithMap(\n code: string,\n id: string,\n options: TransformOptions,\n): Promise<TransformOutput | null> {\n const verbose = options.verbose === true;\n const autoDiscover = options.autoDiscover === true;\n const mode = options.mode;\n const staged = new StagedTransform(code, id);\n\n // Hoist Zod schema construction out of function bodies to module scope\n // (babel-plugin-zod-hoist equivalent). Mode-independent: inline schemas\n // live exactly in the files that export none. hoistZodSchemasMeta() bails\n // in microseconds when no eligible imports exist.\n let hoistedSchemas: ReturnType<typeof hoistZodSchemasMeta> = null;\n if (options.hoist !== false && code.includes(\"import\")) {\n hoistedSchemas = timePhase(\"hoist\", () =>\n hoistZodSchemasMeta(code, {\n ...(typeof options.hoist === \"object\" ? options.hoist : undefined),\n onScan: options.onSubstantialWork,\n }),\n );\n if (hoistedSchemas !== null) {\n staged.apply(hoistedSchemas.edits, hoistedSchemas.insert);\n if (verbose) {\n log(`Hoisted inline Zod schemas in ${id}`);\n }\n }\n }\n\n // Compile the hoisted schemas (autoDiscover only — compiling anonymous\n // schemas is auto-discovery of unexported module-scope schemas). Each\n // hoisted `const _zh_x = z.object({...});` whose construction is\n // deterministic (eager refs are zod bindings only) is evaluated at build\n // time and its initializer replaced with the compiled validator IIFE;\n // anything ineligible stays a plain hoist.\n const hoistHelpers = new Set<string>();\n let hoistCompiledCount = 0;\n if (autoDiscover && hoistedSchemas !== null && hoistedSchemas.schemas.length > 0) {\n const hoistCompiled = await timePhase(\"hoist-compile\", () =>\n compileHoistedSchemas(hoistedSchemas.schemas, code, id, mode),\n );\n const spliceEdits: Edit[] = [];\n for (const h of hoistCompiled) {\n const decl = `const ${h.name} = ${h.text};`;\n const at = staged.current.indexOf(decl);\n if (at === -1) continue;\n const iife = generateIIFE(h.text, h.info, { zodCompat: options.zodCompat });\n spliceEdits.push({ start: at, end: at + decl.length, text: `const ${h.name} = ${iife};` });\n hoistCompiledCount++;\n for (const helper of h.info.codegenResult.usedHelpers) {\n hoistHelpers.add(helper);\n }\n if (verbose) {\n log(` ✓ ${h.name} (hoisted schema compiled)`);\n }\n }\n staged.apply(spliceEdits);\n if (hoistCompiledCount > 0) {\n hoistHelpers.add(\"__zcMkv\");\n hoistHelpers.add(\"__zcFin\");\n }\n }\n\n // When only hoisting (± hoisted-schema compilation) changed the file, that\n // is still a transform result — with runtime helpers injected if any\n // hoisted schema compiled.\n const finishHoistOnly = (): TransformOutput | null => {\n if (staged.current === code) return null;\n if (hoistCompiledCount > 0) {\n options.onBuildStats?.({\n files: 1,\n schemas: hoistedSchemas?.schemas.length ?? 0,\n optimized: hoistCompiledCount,\n failed: 0,\n });\n const prefix = computeRuntimePrefix(staged.current, hoistHelpers, mode, options.runtimeId);\n if (prefix !== null) {\n staged.applyThen([], () => prefix);\n }\n }\n return { code: staged.current, map: staged.map() };\n };\n\n // Quick bail-out check. Both gates are also encoded in the transform hook's\n // `code` filter (ZOD_MENTION) so bundlers can skip the hook call entirely —\n // relaxing either one here without widening that pattern makes the bundler\n // drop those files before this code ever runs.\n if (autoDiscover) {\n // autoDiscover: any file with a runtime Zod import is a candidate.\n // Skip `import type` — these files have no runtime schemas.\n if (!HAS_RUNTIME_ZOD_IMPORT.test(staged.current)) return finishHoistOnly();\n } else {\n // Legacy mode: require compile() from zod-compiler. The word-boundary\n // check matters: the package name itself contains the substring\n // \"compile\", so a plain includes(\"compile\") would match every import of\n // \"zod-compiler\" — \\bcompile\\b does not match inside \"zod-compiler\"\n // (no boundary between \"e\" and \"r\") but matches compile( / { compile }.\n if (!staged.current.includes(\"zod-compiler\") || !/\\bcompile\\b/.test(staged.current))\n return finishHoistOnly();\n }\n\n // Static pre-filter: skip files whose exports provably cannot be schemas\n // (functions, components, constants, type-only modules) without executing\n // them. Conservative — anything ambiguous stays a candidate. The filter\n // transpiles + parses the file, so its outcome is worth persisting even\n // when the eventual result is null.\n options.onSubstantialWork?.();\n if (!(await timePhase(\"static-filter\", () => mayExportSchemas(staged.current, id))))\n return finishHoistOnly();\n\n // Discover schemas by executing the file. Module executions are cached in\n // the shared loader; watch/HMR changes invalidate via invalidateModuleCache().\n options.onDiscovery?.();\n let schemas: DiscoveredSchema[];\n const discoverStart = performance.now();\n try {\n schemas = await timePhase(\"discover\", () => discoverSchemas(id, { autoDiscover }));\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n // A module in the import graph called process.exit() during discovery —\n // typically an env-validation guard in a CI build where secrets are\n // intentionally absent. The loader converts that exit into a catchable\n // error so the build survives; the affected files just fall back to\n // runtime Zod. Handle it in both modes (never crash on a build-time exit)\n // and surface the cooperative remedy once.\n if (e instanceof ProcessExitDuringLoadError) {\n // The result reflects missing secrets, not file content — never persist\n // it to the content-hashed disk cache (a later secret-ful build would be\n // served this stale \"nothing compiled\" entry).\n options.onUncacheableResult?.();\n if (!warnedProcessExit) {\n warnedProcessExit = true;\n warn(\n `${id} (or a module it imports) called process.exit during build-time schema ` +\n `discovery — those files fall back to runtime Zod instead of crashing the build. ` +\n `This is usually an env-validation guard; wrap it in ` +\n `\\`if (!process.env.ZOD_COMPILER) { ... }\\` to keep these schemas compiled, or set ` +\n `schemas:\"explicit\" / use include to scope discovery.`,\n );\n }\n return finishHoistOnly();\n }\n // In autoDiscover mode, files that can't be loaded (JSX components,\n // unresolved path aliases, etc.) are expected — warn and skip.\n if (autoDiscover) {\n if (verbose) {\n warn(`Skipping ${id}: ${msg}`);\n }\n return finishHoistOnly();\n }\n throw new Error(`[zod-compiler] Failed to load schemas from ${id}: ${msg}`);\n }\n const discoverMs = performance.now() - discoverStart;\n if (discoverMs >= SLOW_DISCOVERY_WARN_MS) {\n // Discovery executes the file's whole first-party import graph inside\n // the bundler's single-threaded process — on saturated CI hosts a large\n // graph can stall the event loop long enough to trip test timeouts.\n // Surface the cost with the two effective remedies.\n warn(\n `Discovery of ${id} took ${(discoverMs / 1000).toFixed(1)}s executing its import graph ` +\n `in the bundler process. Persist node_modules/.cache/zod-compiler across CI runs to pay ` +\n `this once, or narrow autoDiscover/include for test runs (see README \"Large projects ` +\n `and CI\"). ZOD_COMPILER_TIMING=1 prints a per-phase breakdown.`,\n );\n }\n if (schemas.length === 0) return finishHoistOnly();\n\n // Lean mode (every bundler in VIRTUAL_MODULE_FRAMEWORKS — Vite/Rollup/webpack/rspack/etc.)\n // imports shared helpers from a runtime module for cross-file dedup: virtual:zod-compiler/runtime\n // on virtual-friendly bundlers, the __zod-compiler-runtime__ bare specifier on webpack/rspack.\n // Inline mode (CLI emitter, and any bundler not in VIRTUAL_MODULE_FRAMEWORKS) emits self-contained\n // file-level helpers.\n let failedCount = 0;\n const { schemas: compiled, shared } = timePhase(\"compile\", () =>\n compileSchemas(schemas, {\n mode,\n compact: options.compact,\n onError(exportName, error) {\n failedCount++;\n warn(\n `Failed to compile \"${exportName}\" in ${id}: ${error.message}. Keeping original${autoDiscover ? \"\" : \" compile()\"} call.`,\n );\n },\n }),\n );\n\n if (verbose) {\n if (autoDiscover) {\n log(\n `Auto-discovering: ${id} (${schemas.length} Zod export${schemas.length > 1 ? \"s\" : \"\"} found)`,\n );\n }\n for (const s of compiled) {\n const rfCount = s.refEntries.length;\n const rfSuffix = rfCount > 0 ? ` (${rfCount} ref${rfCount > 1 ? \"s\" : \"\"})` : \"\";\n log(` ✓ ${s.exportName}${rfSuffix}`);\n }\n if (failedCount > 0) {\n log(` ✗ ${failedCount} schema(s) failed`);\n }\n }\n\n if (compiled.length === 0) return finishHoistOnly();\n\n // Report build stats only when at least one schema was compiled\n // (hoisted-schema compiles count alongside export schemas).\n options.onBuildStats?.({\n files: 1,\n schemas: schemas.length + (hoistedSchemas?.schemas.length ?? 0),\n optimized: compiled.length + hoistCompiledCount,\n failed: failedCount,\n });\n\n // __zcMkv and __zcFin are always needed (they wrap every IIFE). Helpers used\n // by compiled hoisted schemas ride along in the same injection.\n const usedHelpers = aggregateUsedHelpers(compiled);\n usedHelpers.add(\"__zcMkv\");\n usedHelpers.add(\"__zcFin\");\n for (const helper of hoistHelpers) {\n usedHelpers.add(helper);\n }\n // Shared dedup validators ride the same runtime import.\n for (const helper of shared.usedHelpers) {\n usedHelpers.add(helper);\n }\n\n // Two-pass rewrite: separate compile() schemas from autoDiscover schemas.\n // Both passes collect edits against the same pristine stage input — their\n // target regions are disjoint (compile() assignments vs plain exported\n // declarations of OTHER names), so one batched application is equivalent\n // to the historical sequential rewrites.\n let rewriteEdits: readonly Edit[];\n if (autoDiscover) {\n // Detect compile() schemas by checking source code patterns\n const compileExportNames = new Set<string>();\n for (const s of compiled) {\n const pattern = new RegExp(`\\\\b${s.exportName}\\\\s*=\\\\s*compile[\\\\s<(]`);\n if (pattern.test(staged.current)) {\n compileExportNames.add(s.exportName);\n }\n }\n const compileSchemaInfos = compiled.filter((s) => compileExportNames.has(s.exportName));\n const autoDiscoverSchemaInfos = compiled.filter((s) => !compileExportNames.has(s.exportName));\n\n const edits: Edit[] = [];\n // Pass 1: compile() schemas (includes compile-import removal — only when\n // compile() schemas were actually rewritten, mirroring the historical\n // conditional rewriteSource call)\n if (compileSchemaInfos.length > 0) {\n edits.push(\n ...collectCompileRewriteEdits(staged.current, compileSchemaInfos, {\n zodCompat: options.zodCompat,\n }),\n );\n }\n // Pass 2: plain exported schemas\n if (autoDiscoverSchemaInfos.length > 0) {\n edits.push(\n ...collectAutoDiscoverEdits(staged.current, autoDiscoverSchemaInfos, {\n zodCompat: options.zodCompat,\n }),\n );\n }\n rewriteEdits = edits;\n } else {\n rewriteEdits = collectCompileRewriteEdits(staged.current, compiled, {\n zodCompat: options.zodCompat,\n });\n }\n\n // Head = runtime helpers/import, then the file-level shared dedup block, then\n // the rewritten source. The shared `__zcSw_N` functions live at module scope\n // so every IIFE closes over them; they must follow the runtime import (lean)\n // and the helper decls (inline) that they reference. Guard against\n // double-injection on watch/HMR re-runs the same way computeRuntimePrefix\n // does — a second copy would redeclare every `__zcSw_N`.\n //\n // Deferred into the rewrite's own stage rather than staged after it: both\n // decisions read the REWRITTEN text, and giving a bare prepend its own stage\n // doubled the sourcemap work and added a composition pass (see applyThen).\n staged.applyThen(rewriteEdits, (rewritten) => {\n const prefix = computeRuntimePrefix(rewritten, usedHelpers, mode, options.runtimeId);\n const needsShared = shared.code !== \"\" && !rewritten.includes(SHARED_BLOCK_MARKER);\n const head = (prefix ?? \"\") + (needsShared ? `${shared.code}\\n` : \"\");\n return head === \"\" ? undefined : head;\n });\n return { code: staged.current, map: staged.map() };\n}\n\n/**\n * Prepend the runtime helpers required by the rewritten source.\n *\n * Lean mode emits a single `import { ... } from \"<runtimeId>\";` line —\n * bundlers whose resolveId hook intercepts the specifier dedup helpers across\n * every transformed file into one shared virtual module.\n *\n * Inline mode prepends file-level `function __zcMkv` / `function __zcFin`\n * declarations directly so the file is self-contained.\n *\n * Idempotent: if the file already contains the relevant marker (re-run during\n * watch/HMR), we skip re-injection.\n */\n/** The runtime-helper text to prepend, or null when nothing is needed. */\nfunction computeRuntimePrefix(\n code: string,\n usedHelpers: Set<string>,\n mode: CodegenMode,\n runtimeId: string = VIRTUAL_RUNTIME_ID,\n): string | null {\n if (mode === \"lean\") {\n if (usedHelpers.size === 0) return null;\n // Match the import STATEMENT, not the bare id. `zod-compiler/runtime` is a\n // plain package specifier and a substring of `virtual:zod-compiler/runtime`,\n // so a file merely mentioning either — a comment, a docs snippet — would\n // suppress the import while codegen still emits calls to the helpers.\n if (code.includes(`from \"${runtimeId}\"`)) return null;\n const names = [...usedHelpers].sort().join(\", \");\n return `import { ${names} } from \"${runtimeId}\";\\n`;\n }\n // Inline mode (CLI emitter, and any bundler not in VIRTUAL_MODULE_FRAMEWORKS):\n // ship file-level helper declarations instead of a virtual import.\n // Codegen emits per-IIFE issue literals + per-IIFE `__re_*` decls,\n // so we only need __zcMkv / __zcFin (plus __zcMsg via the zod config import).\n if (!code.includes(\"__zcMkv\")) return null;\n const prefix: string[] = [];\n if (!code.includes(\"__zodCompilerConfig\")) {\n prefix.push(ZOD_CONFIG_IMPORT, ZOD_MSG_DECLARATION);\n }\n if (!code.includes(\"function __zcMkv(\")) {\n prefix.push(MK_VALIDATOR_DECL);\n }\n // __zcFin and __zcFinD both construct __ZcFail; declare it once before either,\n // guarding against a header already shipped earlier in the same module.\n const needsFin = !code.includes(\"function __zcFin(\");\n const needsFinD = code.includes(\"__zcFinD(\") && !code.includes(\"function __zcFinD(\");\n if ((needsFin || needsFinD) && !code.includes(\"function __ZcFail(\")) {\n prefix.push(FAIL_CLASS_DECL);\n }\n if (needsFin) {\n prefix.push(FIN_DECL);\n }\n if (needsFinD) {\n prefix.push(FIN_DEFERRED_DECL);\n }\n // Compact mode (output: \"compact\") delegates cold errors to zod via __zcFinZ,\n // which constructs its own __ZcFailZ (distinct from __ZcFail).\n const needsFinZ = code.includes(\"__zcFinZ(\") && !code.includes(\"function __zcFinZ(\");\n if (needsFinZ && !code.includes(\"function __ZcFailZ(\")) {\n prefix.push(FAILZ_CLASS_DECL);\n }\n if (needsFinZ) {\n prefix.push(FINZ_DECL);\n }\n return prefix.length > 0 ? `${prefix.join(\"\\n\")}\\n` : null;\n}\n\n/**\n * Find the matching closing parenthesis for a compile() call,\n * handling nested parentheses like compile(z.object({...})).\n * Returns the index of the closing ')' or -1 if not found.\n */\nfunction findMatchingParen(code: string, openIndex: number): number {\n let depth = 1;\n for (let i = openIndex + 1; i < code.length; i++) {\n if (code[i] === \"(\") depth++;\n else if (code[i] === \")\") {\n depth--;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n\n/**\n * Rewrite source code by replacing compile() calls with IIFE-wrapped optimized validators.\n */\nexport function rewriteSource(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): string {\n return applyEdits(code, collectCompileRewriteEdits(code, schemas, options));\n}\n\n/**\n * Edits for rewriteSource (compile() call replacements + compile-import\n * removal), collected against pristine `code`. Each schema's declaration is\n * a distinct region and the import statement is distinct from all of them,\n * so the batch is non-overlapping and order-independent.\n */\nfunction collectCompileRewriteEdits(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): Edit[] {\n const edits: Edit[] = [];\n for (const schema of schemas) {\n // Match: <exportName> = compile<...>( with word boundary to prevent substring matches\n const prefixPattern = new RegExp(\n `(\\\\b${schema.exportName}\\\\s*=\\\\s*)compile\\\\s*(?:<[^>]*(?:<[^>]*>[^>]*)?>)?\\\\s*\\\\(`,\n );\n const match = prefixPattern.exec(code);\n if (!match) continue;\n\n // Find the matching closing paren (handles nested parens)\n const openParenIndex = match.index + match[0].length - 1;\n const closeParenIndex = findMatchingParen(code, openParenIndex);\n if (closeParenIndex === -1) continue;\n\n const schemaArgName = code\n .slice(openParenIndex + 1, closeParenIndex)\n .trim()\n .replace(/,\\s*$/, \"\");\n const prefix = match[1] ?? \"\";\n edits.push({\n start: match.index,\n end: closeParenIndex + 1,\n text: prefix + generateIIFE(schemaArgName, schema, options),\n });\n }\n edits.push(...collectRemoveCompileImportEdits(code));\n return edits;\n}\n\n/**\n * Find the end position of a JavaScript expression starting at `start` using acorn.\n * Returns the end offset, or -1 if the expression cannot be parsed.\n */\nexport function findExpressionEnd(code: string, start: number): number {\n try {\n const node = parseExpressionAt(code, start, {\n ecmaVersion: \"latest\",\n sourceType: \"module\",\n });\n return node.end;\n } catch {\n return -1;\n }\n}\n\n/**\n * Rewrite source code by replacing plain Zod schema exports with IIFE-wrapped optimized validators.\n * Used by autoDiscover mode (no compile() wrappers needed).\n */\nexport function rewriteSourceAutoDiscover(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): string {\n return applyEdits(code, collectAutoDiscoverEdits(code, schemas, options));\n}\n\n/** Edits for rewriteSourceAutoDiscover, collected against pristine `code`. */\nfunction collectAutoDiscoverEdits(\n code: string,\n schemas: CompiledSchemaInfo[],\n options?: { zodCompat?: boolean | undefined },\n): Edit[] {\n const edits: Edit[] = [];\n for (const schema of schemas) {\n const escapedName = schema.exportName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n // Match: export? (const|let|var) ExportName[: TypeAnnotation] = <expr>\n const assignPattern = new RegExp(\n `((?:export\\\\s+)?(?:const|let|var)\\\\s+${escapedName}(?:\\\\s*:[^=]*)?\\\\s*=\\\\s*)`,\n );\n const match = assignPattern.exec(code);\n if (!match) continue;\n\n const rhsStart = match.index + match[0].length;\n const rhsEnd = findExpressionEnd(code, rhsStart);\n if (rhsEnd === -1) continue;\n\n const originalExpr = code.slice(rhsStart, rhsEnd).trim();\n edits.push({\n start: rhsStart,\n end: rhsEnd,\n text: generateIIFE(originalExpr, schema, options),\n });\n }\n return edits;\n}\n\n/**\n * Remove the `compile` binding from `import { compile, ... } from \"zod-compiler\"` statements.\n * If `compile` is the only import, the entire import line is removed.\n */\nexport function removeCompileImport(code: string): string {\n return applyEdits(code, collectRemoveCompileImportEdits(code));\n}\n\n/** Edits stripping the `compile` binding from zod-compiler import statements. */\nfunction collectRemoveCompileImportEdits(code: string): Edit[] {\n // Match: import { ... } from \"zod-compiler\" or 'zod-compiler'\n const importPattern = /import\\s*\\{([^}]*)\\}\\s*from\\s*[\"']zod-compiler[\"'];?/g;\n const edits: Edit[] = [];\n for (const match of code.matchAll(importPattern)) {\n const imports = match[1] ?? \"\";\n const names = imports\n .split(\",\")\n .map((n) => n.trim())\n .filter(Boolean);\n const remaining = names.filter((n) => n !== \"compile\");\n const text =\n remaining.length === 0 ? \"\" : `import { ${remaining.join(\", \")} } from \"zod-compiler\";`;\n if (text !== match[0]) {\n edits.push({ start: match.index, end: match.index + match[0].length, text });\n }\n }\n return edits;\n}\n"],"mappings":"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"}
@@ -16,8 +16,35 @@
16
16
  declare const VIRTUAL_RUNTIME_ID = "virtual:zod-compiler/runtime";
17
17
  /** Bare-specifier alias for webpack/rspack, which reject the `virtual:` URI scheme. */
18
18
  declare const WP_RUNTIME_ID = "__zod-compiler-runtime__";
19
+ /**
20
+ * Real package subpath, shipped as `dist/runtime.js` (emitted at build time from
21
+ * RUNTIME_SOURCE — see the `emit-runtime` plugin in vite.config.ts).
22
+ *
23
+ * The ids above only resolve inside a host that runs zod-compiler's resolveId
24
+ * hook. A webpack loader has none, so lean mode was unavailable to it: the
25
+ * specifier would survive into the output unresolved. This one needs no hook —
26
+ * plain node resolution finds it — which is what lets a loader host dedup
27
+ * helpers across files.
28
+ *
29
+ * Deliberately NOT intercepted by resolveVirtualId, unlike the two ids above.
30
+ * They resolve to nothing without the hook, so answering them is free. This one
31
+ * already resolves, and to a SPECIFIC copy: intercepting would override a
32
+ * nested or newer zod-compiler whose runtime exports helpers this version has
33
+ * never heard of, turning a working build into an unresolvable-import error
34
+ * naming an id the user never wrote. A build that ends up with both this file
35
+ * and the virtual module carries two copies of the helpers, which is wasteful
36
+ * but correct — every result crosses module boundaries structurally, never by
37
+ * identity.
38
+ */
39
+ declare const RUNTIME_PACKAGE_ID = "zod-compiler/runtime";
19
40
  /** Resolved id (Rollup convention: leading null byte hides the module from other plugins). */
20
41
  declare const RESOLVED_RUNTIME_ID = "\0zod-compiler-runtime";
42
+ /**
43
+ * The runtime module's ESM source. Exported because the package build writes it
44
+ * to `dist/runtime.js` — the file and the virtual module must be the same bytes,
45
+ * so there is exactly one producer.
46
+ */
47
+ declare const RUNTIME_SOURCE: string;
21
48
  /** `id` filter for the resolveId hook: the runtime module's public specifiers. */
22
49
  declare const RUNTIME_SPECIFIER_FILTER: RegExp[];
23
50
  /** `id` filter for the load hook: the resolved (`\0`-prefixed) runtime id. */
@@ -27,5 +54,5 @@ declare function loadVirtual(id: string): string | null;
27
54
  /** Names of all helpers exported by the virtual module. */
28
55
  declare const ALL_HELPER_NAMES: readonly string[];
29
56
  //#endregion
30
- export { ALL_HELPER_NAMES, RESOLVED_RUNTIME_ID, RESOLVED_RUNTIME_ID_FILTER, RUNTIME_SPECIFIER_FILTER, VIRTUAL_RUNTIME_ID, WP_RUNTIME_ID, loadVirtual, resolveVirtualId };
57
+ export { ALL_HELPER_NAMES, RESOLVED_RUNTIME_ID, RESOLVED_RUNTIME_ID_FILTER, RUNTIME_PACKAGE_ID, RUNTIME_SOURCE, RUNTIME_SPECIFIER_FILTER, VIRTUAL_RUNTIME_ID, WP_RUNTIME_ID, loadVirtual, resolveVirtualId };
31
58
  //# sourceMappingURL=virtual.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtual.d.ts","names":[],"sources":["../../src/unplugin/virtual.ts"],"mappings":";;;;;;;;;;;;;;;cA4Ba;;cAEA;;cAEA;;cAwDA,0BAA0B;;cAM1B,4BAA4B;iBAEzB,iBAAiB;iBAKjB,YAAY;;cAMf"}
1
+ {"version":3,"file":"virtual.d.ts","names":[],"sources":["../../src/unplugin/virtual.ts"],"mappings":";;;;;;;;;;;;;;;cA4Ba;;cAEA;;;;;;;;;;;;;;;;;;;;;cAqBA;;cAEA;;;;;;cA8CA;;cAeA,0BAA0B;;cAM1B,4BAA4B;iBAEzB,iBAAiB;iBAKjB,YAAY;;cAMf"}
@@ -19,6 +19,27 @@ import { ISSUE_DECLS, RUNTIME_HELPER_DECLS, ZC_SR_RUN_DECL } from "../core/codeg
19
19
  const VIRTUAL_RUNTIME_ID = "virtual:zod-compiler/runtime";
20
20
  /** Bare-specifier alias for webpack/rspack, which reject the `virtual:` URI scheme. */
21
21
  const WP_RUNTIME_ID = "__zod-compiler-runtime__";
22
+ /**
23
+ * Real package subpath, shipped as `dist/runtime.js` (emitted at build time from
24
+ * RUNTIME_SOURCE — see the `emit-runtime` plugin in vite.config.ts).
25
+ *
26
+ * The ids above only resolve inside a host that runs zod-compiler's resolveId
27
+ * hook. A webpack loader has none, so lean mode was unavailable to it: the
28
+ * specifier would survive into the output unresolved. This one needs no hook —
29
+ * plain node resolution finds it — which is what lets a loader host dedup
30
+ * helpers across files.
31
+ *
32
+ * Deliberately NOT intercepted by resolveVirtualId, unlike the two ids above.
33
+ * They resolve to nothing without the hook, so answering them is free. This one
34
+ * already resolves, and to a SPECIFIC copy: intercepting would override a
35
+ * nested or newer zod-compiler whose runtime exports helpers this version has
36
+ * never heard of, turning a working build into an unresolvable-import error
37
+ * naming an id the user never wrote. A build that ends up with both this file
38
+ * and the virtual module carries two copies of the helpers, which is wasteful
39
+ * but correct — every result crosses module boundaries structurally, never by
40
+ * identity.
41
+ */
42
+ const RUNTIME_PACKAGE_ID = "zod-compiler/runtime";
22
43
  /** Resolved id (Rollup convention: leading null byte hides the module from other plugins). */
23
44
  const RESOLVED_RUNTIME_ID = "\0zod-compiler-runtime";
24
45
  function buildRuntimeSource() {
@@ -42,6 +63,11 @@ function buildRuntimeSource() {
42
63
  }
43
64
  return parts.join("\n");
44
65
  }
66
+ /**
67
+ * The runtime module's ESM source. Exported because the package build writes it
68
+ * to `dist/runtime.js` — the file and the virtual module must be the same bytes,
69
+ * so there is exactly one producer.
70
+ */
45
71
  const RUNTIME_SOURCE = buildRuntimeSource();
46
72
  /**
47
73
  * Anchored, literal-safe pattern for an exact id match. Hook filters take
@@ -77,6 +103,6 @@ const ALL_HELPER_NAMES = [
77
103
  ...WELL_KNOWN_REGEXES.flatMap((r) => fastTestSource(r.source) !== null ? [r.name, `${r.name}Src`] : [r.name])
78
104
  ];
79
105
  //#endregion
80
- export { ALL_HELPER_NAMES, RESOLVED_RUNTIME_ID, RESOLVED_RUNTIME_ID_FILTER, RUNTIME_SPECIFIER_FILTER, VIRTUAL_RUNTIME_ID, WP_RUNTIME_ID, loadVirtual, resolveVirtualId };
106
+ export { ALL_HELPER_NAMES, RESOLVED_RUNTIME_ID, RESOLVED_RUNTIME_ID_FILTER, RUNTIME_PACKAGE_ID, RUNTIME_SOURCE, RUNTIME_SPECIFIER_FILTER, VIRTUAL_RUNTIME_ID, WP_RUNTIME_ID, loadVirtual, resolveVirtualId };
81
107
 
82
108
  //# sourceMappingURL=virtual.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtual.js","names":[],"sources":["../../src/unplugin/virtual.ts"],"sourcesContent":["/**\n * Virtual module \"virtual:zod-compiler/runtime\".\n *\n * Hosts shared helpers and well-known regexes so that lean-mode generated code\n * (emitted by the unplugin transform) can `import { __zcMkv, __zcTS, __zcReEmail }`\n * instead of inlining these declarations per IIFE.\n *\n * Bundlers tree-shake unused exports during minification, so the virtual module\n * never bloats the final bundle with helpers that no schema actually references.\n *\n * The virtual module is rebuilt on each plugin instantiation but its content is\n * static (no per-build state), so caching the source string is safe.\n */\n\nimport { ISSUE_DECLS, RUNTIME_HELPER_DECLS, ZC_SR_RUN_DECL } from \"../core/codegen/issue-decls.js\";\nimport { fastTestSource, WELL_KNOWN_REGEXES } from \"../core/codegen/well-known-regex.js\";\nimport {\n FAIL_CLASS_DECL,\n FAILZ_CLASS_DECL,\n FIN_DECL,\n FIN_DEFERRED_DECL,\n FINZ_DECL,\n MK_VALIDATOR_DECL,\n ZOD_CONFIG_IMPORT,\n ZOD_MSG_DECLARATION,\n} from \"../core/iife.js\";\n\n/** Public virtual module ID used by Vite / Rollup / esbuild and other `virtual:`-compatible bundlers. */\nexport const VIRTUAL_RUNTIME_ID = \"virtual:zod-compiler/runtime\";\n/** Bare-specifier alias for webpack/rspack, which reject the `virtual:` URI scheme. */\nexport const WP_RUNTIME_ID = \"__zod-compiler-runtime__\";\n/** Resolved id (Rollup convention: leading null byte hides the module from other plugins). */\nexport const RESOLVED_RUNTIME_ID = \"\\0zod-compiler-runtime\";\n\nfunction buildRuntimeSource(): string {\n // ISSUE_DECLS / RUNTIME_HELPER_DECLS registries are the single source of\n // truth — never enumerate individual decl constants here. A decl present in\n // the registry (and therefore in ALL_HELPER_NAMES and in codegen's\n // usedHelpers imports) but missing from this source is a build-breaking\n // MISSING_EXPORT in every consumer bundle (field incident: __zcUK).\n const parts: string[] = [\n ZOD_CONFIG_IMPORT,\n ZOD_MSG_DECLARATION,\n // Module-local (never imported by generated code) — __zcFin/__zcFinD below\n // construct it. Must precede them; both reference __ZcFail by closure.\n FAIL_CLASS_DECL,\n // Module-local (never imported by generated code) — __zcFinZ constructs it.\n FAILZ_CLASS_DECL,\n `export ${MK_VALIDATOR_DECL}`,\n `export ${FIN_DECL}`,\n `export ${FIN_DEFERRED_DECL}`,\n `export ${FINZ_DECL}`,\n // Module-local (never imported by generated code) — __zcSr/__zcSrOk call it.\n ZC_SR_RUN_DECL,\n ...Object.values(ISSUE_DECLS).map((decl) => `export ${decl}`),\n ...Object.values(RUNTIME_HELPER_DECLS).map((decl) => `export ${decl}`),\n ];\n for (const r of WELL_KNOWN_REGEXES) {\n // fastTestSource is a behavior-equivalent faster pattern used for the\n // runtime regex (table rewrite and/or repeat unrolling); issue sites\n // reference the paired `<name>Src` string so reported patterns stay\n // byte-identical to zod's (single bundle-wide copy of each). It is the same\n // function emitRegex consults, so the virtual module and inline mode can\n // never disagree about which pattern a format actually runs.\n const testSource = fastTestSource(r.source);\n parts.push(`export const ${r.name}=new RegExp(${JSON.stringify(testSource ?? r.source)});`);\n if (testSource !== null) {\n parts.push(`export const ${r.name}Src=${JSON.stringify(`/${r.source}/`)};`);\n }\n }\n return parts.join(\"\\n\");\n}\n\nconst RUNTIME_SOURCE = buildRuntimeSource();\n\n/**\n * Anchored, literal-safe pattern for an exact id match. Hook filters take\n * globs or regexes, and a bare string is treated as a glob resolved against\n * cwd — which never matches a `virtual:` specifier — so the ids are escaped\n * into patterns instead. NUL is written as `\\x00` because the pattern is\n * recompiled outside JS by bundlers with native filters (Rolldown).\n */\nfunction exactIdPattern(id: string): RegExp {\n const escaped = id.replace(/[$()*+.?[\\\\\\]^{|}]/g, \"\\\\$&\").replaceAll(\"\\0\", \"\\\\x00\");\n return new RegExp(`^${escaped}$`);\n}\n\n/** `id` filter for the resolveId hook: the runtime module's public specifiers. */\nexport const RUNTIME_SPECIFIER_FILTER: RegExp[] = [\n exactIdPattern(VIRTUAL_RUNTIME_ID),\n exactIdPattern(WP_RUNTIME_ID),\n];\n\n/** `id` filter for the load hook: the resolved (`\\0`-prefixed) runtime id. */\nexport const RESOLVED_RUNTIME_ID_FILTER: RegExp = exactIdPattern(RESOLVED_RUNTIME_ID);\n\nexport function resolveVirtualId(id: string): string | null {\n if (id === VIRTUAL_RUNTIME_ID || id === WP_RUNTIME_ID) return RESOLVED_RUNTIME_ID;\n return null;\n}\n\nexport function loadVirtual(id: string): string | null {\n if (id === RESOLVED_RUNTIME_ID) return RUNTIME_SOURCE;\n return null;\n}\n\n/** Names of all helpers exported by the virtual module. */\nexport const ALL_HELPER_NAMES: readonly string[] = [\n \"__zcMkv\",\n \"__zcFin\",\n \"__zcFinD\",\n \"__zcFinZ\",\n ...Object.keys(ISSUE_DECLS),\n ...Object.keys(RUNTIME_HELPER_DECLS),\n ...WELL_KNOWN_REGEXES.flatMap((r) =>\n fastTestSource(r.source) !== null ? [r.name, `${r.name}Src`] : [r.name],\n ),\n];\n"],"mappings":";;;;;;;;;;;;;;;;;;AA4BA,MAAa,qBAAqB;;AAElC,MAAa,gBAAgB;;AAE7B,MAAa,sBAAsB;AAEnC,SAAS,qBAA6B;CAMpC,MAAM,QAAkB;EACtB;EACA;EAGA;EAEA;EACA,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EAEV;EACA,GAAG,OAAO,OAAO,WAAW,CAAC,CAAC,KAAK,SAAS,UAAU,MAAM;EAC5D,GAAG,OAAO,OAAO,oBAAoB,CAAC,CAAC,KAAK,SAAS,UAAU,MAAM;CACvE;CACA,KAAK,MAAM,KAAK,oBAAoB;EAOlC,MAAM,aAAa,eAAe,EAAE,MAAM;EAC1C,MAAM,KAAK,gBAAgB,EAAE,KAAK,cAAc,KAAK,UAAU,cAAc,EAAE,MAAM,EAAE,GAAG;EAC1F,IAAI,eAAe,MACjB,MAAM,KAAK,gBAAgB,EAAE,KAAK,MAAM,KAAK,UAAU,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;CAE9E;CACA,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,MAAM,iBAAiB,mBAAmB;;;;;;;;AAS1C,SAAS,eAAe,IAAoB;CAC1C,MAAM,UAAU,GAAG,QAAQ,uBAAuB,MAAM,CAAC,CAAC,WAAW,MAAM,OAAO;CAClF,OAAO,IAAI,OAAO,IAAI,QAAQ,EAAE;AAClC;;AAGA,MAAa,2BAAqC,CAChD,eAAe,kBAAkB,GACjC,eAAe,aAAa,CAC9B;;AAGA,MAAa,6BAAqC,eAAe,mBAAmB;AAEpF,SAAgB,iBAAiB,IAA2B;CAC1D,IAAI,OAAA,kCAA6B,OAAA,4BAAsB,OAAO;CAC9D,OAAO;AACT;AAEA,SAAgB,YAAY,IAA2B;CACrD,IAAI,OAAA,0BAA4B,OAAO;CACvC,OAAO;AACT;;AAGA,MAAa,mBAAsC;CACjD;CACA;CACA;CACA;CACA,GAAG,OAAO,KAAK,WAAW;CAC1B,GAAG,OAAO,KAAK,oBAAoB;CACnC,GAAG,mBAAmB,SAAS,MAC7B,eAAe,EAAE,MAAM,MAAM,OAAO,CAAC,EAAE,MAAM,GAAG,EAAE,KAAK,IAAI,IAAI,CAAC,EAAE,IAAI,CACxE;AACF"}
1
+ {"version":3,"file":"virtual.js","names":[],"sources":["../../src/unplugin/virtual.ts"],"sourcesContent":["/**\n * Virtual module \"virtual:zod-compiler/runtime\".\n *\n * Hosts shared helpers and well-known regexes so that lean-mode generated code\n * (emitted by the unplugin transform) can `import { __zcMkv, __zcTS, __zcReEmail }`\n * instead of inlining these declarations per IIFE.\n *\n * Bundlers tree-shake unused exports during minification, so the virtual module\n * never bloats the final bundle with helpers that no schema actually references.\n *\n * The virtual module is rebuilt on each plugin instantiation but its content is\n * static (no per-build state), so caching the source string is safe.\n */\n\nimport { ISSUE_DECLS, RUNTIME_HELPER_DECLS, ZC_SR_RUN_DECL } from \"../core/codegen/issue-decls.js\";\nimport { fastTestSource, WELL_KNOWN_REGEXES } from \"../core/codegen/well-known-regex.js\";\nimport {\n FAIL_CLASS_DECL,\n FAILZ_CLASS_DECL,\n FIN_DECL,\n FIN_DEFERRED_DECL,\n FINZ_DECL,\n MK_VALIDATOR_DECL,\n ZOD_CONFIG_IMPORT,\n ZOD_MSG_DECLARATION,\n} from \"../core/iife.js\";\n\n/** Public virtual module ID used by Vite / Rollup / esbuild and other `virtual:`-compatible bundlers. */\nexport const VIRTUAL_RUNTIME_ID = \"virtual:zod-compiler/runtime\";\n/** Bare-specifier alias for webpack/rspack, which reject the `virtual:` URI scheme. */\nexport const WP_RUNTIME_ID = \"__zod-compiler-runtime__\";\n/**\n * Real package subpath, shipped as `dist/runtime.js` (emitted at build time from\n * RUNTIME_SOURCE — see the `emit-runtime` plugin in vite.config.ts).\n *\n * The ids above only resolve inside a host that runs zod-compiler's resolveId\n * hook. A webpack loader has none, so lean mode was unavailable to it: the\n * specifier would survive into the output unresolved. This one needs no hook —\n * plain node resolution finds it — which is what lets a loader host dedup\n * helpers across files.\n *\n * Deliberately NOT intercepted by resolveVirtualId, unlike the two ids above.\n * They resolve to nothing without the hook, so answering them is free. This one\n * already resolves, and to a SPECIFIC copy: intercepting would override a\n * nested or newer zod-compiler whose runtime exports helpers this version has\n * never heard of, turning a working build into an unresolvable-import error\n * naming an id the user never wrote. A build that ends up with both this file\n * and the virtual module carries two copies of the helpers, which is wasteful\n * but correct — every result crosses module boundaries structurally, never by\n * identity.\n */\nexport const RUNTIME_PACKAGE_ID = \"zod-compiler/runtime\";\n/** Resolved id (Rollup convention: leading null byte hides the module from other plugins). */\nexport const RESOLVED_RUNTIME_ID = \"\\0zod-compiler-runtime\";\n\nfunction buildRuntimeSource(): string {\n // ISSUE_DECLS / RUNTIME_HELPER_DECLS registries are the single source of\n // truth — never enumerate individual decl constants here. A decl present in\n // the registry (and therefore in ALL_HELPER_NAMES and in codegen's\n // usedHelpers imports) but missing from this source is a build-breaking\n // MISSING_EXPORT in every consumer bundle (field incident: __zcUK).\n const parts: string[] = [\n ZOD_CONFIG_IMPORT,\n ZOD_MSG_DECLARATION,\n // Module-local (never imported by generated code) — __zcFin/__zcFinD below\n // construct it. Must precede them; both reference __ZcFail by closure.\n FAIL_CLASS_DECL,\n // Module-local (never imported by generated code) — __zcFinZ constructs it.\n FAILZ_CLASS_DECL,\n `export ${MK_VALIDATOR_DECL}`,\n `export ${FIN_DECL}`,\n `export ${FIN_DEFERRED_DECL}`,\n `export ${FINZ_DECL}`,\n // Module-local (never imported by generated code) — __zcSr/__zcSrOk call it.\n ZC_SR_RUN_DECL,\n ...Object.values(ISSUE_DECLS).map((decl) => `export ${decl}`),\n ...Object.values(RUNTIME_HELPER_DECLS).map((decl) => `export ${decl}`),\n ];\n for (const r of WELL_KNOWN_REGEXES) {\n // fastTestSource is a behavior-equivalent faster pattern used for the\n // runtime regex (table rewrite and/or repeat unrolling); issue sites\n // reference the paired `<name>Src` string so reported patterns stay\n // byte-identical to zod's (single bundle-wide copy of each). It is the same\n // function emitRegex consults, so the virtual module and inline mode can\n // never disagree about which pattern a format actually runs.\n const testSource = fastTestSource(r.source);\n parts.push(`export const ${r.name}=new RegExp(${JSON.stringify(testSource ?? r.source)});`);\n if (testSource !== null) {\n parts.push(`export const ${r.name}Src=${JSON.stringify(`/${r.source}/`)};`);\n }\n }\n return parts.join(\"\\n\");\n}\n\n/**\n * The runtime module's ESM source. Exported because the package build writes it\n * to `dist/runtime.js` — the file and the virtual module must be the same bytes,\n * so there is exactly one producer.\n */\nexport const RUNTIME_SOURCE = buildRuntimeSource();\n\n/**\n * Anchored, literal-safe pattern for an exact id match. Hook filters take\n * globs or regexes, and a bare string is treated as a glob resolved against\n * cwd — which never matches a `virtual:` specifier — so the ids are escaped\n * into patterns instead. NUL is written as `\\x00` because the pattern is\n * recompiled outside JS by bundlers with native filters (Rolldown).\n */\nfunction exactIdPattern(id: string): RegExp {\n const escaped = id.replace(/[$()*+.?[\\\\\\]^{|}]/g, \"\\\\$&\").replaceAll(\"\\0\", \"\\\\x00\");\n return new RegExp(`^${escaped}$`);\n}\n\n/** `id` filter for the resolveId hook: the runtime module's public specifiers. */\nexport const RUNTIME_SPECIFIER_FILTER: RegExp[] = [\n exactIdPattern(VIRTUAL_RUNTIME_ID),\n exactIdPattern(WP_RUNTIME_ID),\n];\n\n/** `id` filter for the load hook: the resolved (`\\0`-prefixed) runtime id. */\nexport const RESOLVED_RUNTIME_ID_FILTER: RegExp = exactIdPattern(RESOLVED_RUNTIME_ID);\n\nexport function resolveVirtualId(id: string): string | null {\n if (id === VIRTUAL_RUNTIME_ID || id === WP_RUNTIME_ID) return RESOLVED_RUNTIME_ID;\n return null;\n}\n\nexport function loadVirtual(id: string): string | null {\n if (id === RESOLVED_RUNTIME_ID) return RUNTIME_SOURCE;\n return null;\n}\n\n/** Names of all helpers exported by the virtual module. */\nexport const ALL_HELPER_NAMES: readonly string[] = [\n \"__zcMkv\",\n \"__zcFin\",\n \"__zcFinD\",\n \"__zcFinZ\",\n ...Object.keys(ISSUE_DECLS),\n ...Object.keys(RUNTIME_HELPER_DECLS),\n ...WELL_KNOWN_REGEXES.flatMap((r) =>\n fastTestSource(r.source) !== null ? [r.name, `${r.name}Src`] : [r.name],\n ),\n];\n"],"mappings":";;;;;;;;;;;;;;;;;;AA4BA,MAAa,qBAAqB;;AAElC,MAAa,gBAAgB;;;;;;;;;;;;;;;;;;;;;AAqB7B,MAAa,qBAAqB;;AAElC,MAAa,sBAAsB;AAEnC,SAAS,qBAA6B;CAMpC,MAAM,QAAkB;EACtB;EACA;EAGA;EAEA;EACA,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU;EAEV;EACA,GAAG,OAAO,OAAO,WAAW,CAAC,CAAC,KAAK,SAAS,UAAU,MAAM;EAC5D,GAAG,OAAO,OAAO,oBAAoB,CAAC,CAAC,KAAK,SAAS,UAAU,MAAM;CACvE;CACA,KAAK,MAAM,KAAK,oBAAoB;EAOlC,MAAM,aAAa,eAAe,EAAE,MAAM;EAC1C,MAAM,KAAK,gBAAgB,EAAE,KAAK,cAAc,KAAK,UAAU,cAAc,EAAE,MAAM,EAAE,GAAG;EAC1F,IAAI,eAAe,MACjB,MAAM,KAAK,gBAAgB,EAAE,KAAK,MAAM,KAAK,UAAU,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;CAE9E;CACA,OAAO,MAAM,KAAK,IAAI;AACxB;;;;;;AAOA,MAAa,iBAAiB,mBAAmB;;;;;;;;AASjD,SAAS,eAAe,IAAoB;CAC1C,MAAM,UAAU,GAAG,QAAQ,uBAAuB,MAAM,CAAC,CAAC,WAAW,MAAM,OAAO;CAClF,OAAO,IAAI,OAAO,IAAI,QAAQ,EAAE;AAClC;;AAGA,MAAa,2BAAqC,CAChD,eAAe,kBAAkB,GACjC,eAAe,aAAa,CAC9B;;AAGA,MAAa,6BAAqC,eAAe,mBAAmB;AAEpF,SAAgB,iBAAiB,IAA2B;CAC1D,IAAI,OAAA,kCAA6B,OAAA,4BAAsB,OAAO;CAC9D,OAAO;AACT;AAEA,SAAgB,YAAY,IAA2B;CACrD,IAAI,OAAA,0BAA4B,OAAO;CACvC,OAAO;AACT;;AAGA,MAAa,mBAAsC;CACjD;CACA;CACA;CACA;CACA,GAAG,OAAO,KAAK,WAAW;CAC1B,GAAG,OAAO,KAAK,oBAAoB;CACnC,GAAG,mBAAmB,SAAS,MAC7B,eAAe,EAAE,MAAM,MAAM,OAAO,CAAC,EAAE,MAAM,GAAG,EAAE,KAAK,IAAI,IAAI,CAAC,EAAE,IAAI,CACxE;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-compiler",
3
- "version": "1.23.8",
3
+ "version": "1.24.0",
4
4
  "description": "Compile Zod schemas into zero-overhead validation functions",
5
5
  "keywords": [
6
6
  "aot",
@@ -98,6 +98,17 @@
98
98
  "source": "./src/swc.ts",
99
99
  "import": "./dist/swc.js",
100
100
  "default": "./dist/swc.js"
101
+ },
102
+ "./runtime": {
103
+ "types": "./dist/runtime.d.ts",
104
+ "import": "./dist/runtime.js",
105
+ "default": "./dist/runtime.js"
106
+ },
107
+ "./turbopack": {
108
+ "types": "./dist/turbopack.d.ts",
109
+ "source": "./src/turbopack.ts",
110
+ "import": "./dist/turbopack.js",
111
+ "default": "./dist/turbopack.js"
101
112
  }
102
113
  },
103
114
  "scripts": {