1/**
2 * Installs runtime-generated schema decoders without changing SchemaParser's
3 * public interface. Operations are compiled lazily. Import the separate
4 * `SchemaJITCompiler/enable` module to enable compilation globally.
5 *
6 * @stability unstable
7 * @since 4.0.0
8 */
9import { type DecoderOperation, generate, shouldCompileParser } from "../internal/schema/codegen.ts"
10import * as Registry from "../internal/schema/compilerRegistry.ts"
11import type * as SchemaAST from "../SchemaAST.ts"
12import type { CompiledDecoder } from "./SchemaCompiler.ts"
13import { runtime } from "./SchemaCompiler/runtime.ts"
14
15let checked: FunctionConstructor | undefined
16let supported = false
17
18/**
19 * @internal
20 */
21export const compiler: Registry.CompileSource = (ast, resolve) => {
22 if (!shouldCompileParser(ast)) return undefined
23 if (checked !== globalThis.Function) {
24 checked = globalThis.Function
25 try {
26 checked("return true")
27 supported = true
28 } catch {
29 supported = false
30 }
31 }
32 if (!supported) return undefined
33 let decodeFailed = false
34 const operation = (key: DecoderOperation) => {
35 const isConstruction = key === "make" || key === "makeEffect"
36 if (isConstruction || !decodeFailed) {
37 try {
38 const source = generate(ast, key)
39 if (source === undefined) return undefined
40 return globalThis.Function("ast", "R", "resolve", source)(ast, runtime, resolve)
41 } catch {
42 // Only code generation and initialization are inside this catch.
43 if (!isConstruction) decodeFailed = true
44 }
45 }
46 return key === "decodeEffect"
47 ? runtime.decode(ast, resolve)
48 : key === "makeEffect"
49 ? runtime.make(ast, resolve)
50 : undefined
51 }
52 return {
53 get is() {
54 return operation("is")
55 },
56 get decode() {
57 return operation("decode")
58 },
59 get make() {
60 return operation("make")
61 },
62 get decodeEffect() {
63 return operation("decodeEffect")
64 },
65 get makeEffect() {
66 return operation("makeEffect")
67 }
68 } satisfies CompiledDecoder
69}
70
71/**
72 * Enables lazy JIT compilation for an AST and its parsing dependencies.
73 *
74 * **Details**
75 *
76 * Uses the same registry as `SchemaCompiler.set`. Compilation failures, including
77 * environments that block `new Function`, retain interpreted parsing. Errors
78 * thrown while parsing are not retried. No checks, transformations or defaults
79 * execute during installation.
80 *
81 * **Gotchas**
82 *
83 * Enable before first use to optimize every consumer. Functions that already
84 * captured an entry keep it. Enable type-side and flipped ASTs separately when
85 * they differ from the supplied AST.
86 *
87 * @stability unstable
88 * @category compilation
89 * @since 4.0.0
90 */
91export function enable(ast: SchemaAST.AST): void {
92 Registry.enable(ast, compiler)
93}