zod-compiler 1.8.0 → 1.9.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.
- package/README.md +3 -2
- package/dist/core/codegen/schemas/discriminated-union.d.ts +43 -0
- package/dist/core/codegen/schemas/discriminated-union.d.ts.map +1 -1
- package/dist/core/codegen/schemas/discriminated-union.js +97 -17
- package/dist/core/codegen/schemas/discriminated-union.js.map +1 -1
- package/dist/core/codegen/schemas/union.d.ts.map +1 -1
- package/dist/core/codegen/schemas/union.js +11 -0
- package/dist/core/codegen/schemas/union.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -530,6 +530,7 @@ compiles; `z.string().transform((s) => s + suffix)` falls back (it captures
|
|
|
530
530
|
| pipe (non-transform) | 8.8M | 5.9M | **16.1M** | — | — | 2.7x |
|
|
531
531
|
| discriminatedUnion (3 variants) | 3.3M | 4.0M | **16.1M** | 15.8M | 8.0M | 4.0x |
|
|
532
532
|
| discriminatedUnion (8 variants, rotating) | 2.7M | 3.5M | **9.6M** | — | — | 2.7x |
|
|
533
|
+
| plain union of 8 tagged objects (auto-discrim.) | 368K | 655K | **8.6M** | — | — | **13x** |
|
|
533
534
|
| strict object (DB row) | 1.8M | 3.2M | **7.3M** | — | — | 2.3x |
|
|
534
535
|
| medium object (valid) | 2.0M | 2.4M | **10.3M** | 11.4M | 7.7M | 4.3x |
|
|
535
536
|
| medium object (invalid) | 536K | 80K | **15.5M** | 2.9M | 7.9M | **194x** |
|
|
@@ -546,7 +547,7 @@ compiles; `z.string().transform((s) => s + suffix)` falls back (it captures
|
|
|
546
547
|
|
|
547
548
|
_ops/s, higher is better. "—" = not supported by the library. Measured with `vitest bench` on Apple M4 Max (zod 4.3.6, zod v3 3.23.8, typia 12, ajv 8)._
|
|
548
549
|
|
|
549
|
-
Performance scales with schema complexity. Nested objects and arrays see the biggest gains because zod-compiler eliminates per-node traversal overhead. Deeply nested schemas (the 243-leaf dashboard row) stay fast because oversized fast-check functions are split into smaller boolean helpers, each kept within V8's optimizing-compiler budget. `discriminatedUnion` uses O(1) `switch` dispatch instead of Zod's sequential trial, and each case validates only its variant's distinctive fields — the object type-guard and the discriminator are checked once before dispatch, never re-checked inside the matched case (a redundancy the engine only elides on unions small enough to inline, so large unions get a measured ~1.5x on the fast check). The invalid-input row is large because failed `safeParse` defers error materialization until `.error` is read. Zero-capture `transform`/`refine` callbacks are compiled (3-19x); schemas with captured callbacks fall back per-field and roughly match Zod.
|
|
550
|
+
Performance scales with schema complexity. Nested objects and arrays see the biggest gains because zod-compiler eliminates per-node traversal overhead. Deeply nested schemas (the 243-leaf dashboard row) stay fast because oversized fast-check functions are split into smaller boolean helpers, each kept within V8's optimizing-compiler budget. `discriminatedUnion` uses O(1) `switch` dispatch instead of Zod's sequential trial, and each case validates only its variant's distinctive fields — the object type-guard and the discriminator are checked once before dispatch, never re-checked inside the matched case (a redundancy the engine only elides on unions small enough to inline, so large unions get a measured ~1.5x on the fast check). A **plain `z.union`** of objects that all pin a shared key to disjoint literals is auto-detected and lowered to the same switch dispatch — so an untagged union written without `discriminatedUnion` still validates in O(1) (13x faster than Zod here), as long as it has enough options to outweigh the switch's setup cost; below that it keeps the fully-inlined `||`-chain. The invalid-input row is large because failed `safeParse` defers error materialization until `.error` is read. Zero-capture `transform`/`refine` callbacks are compiled (3-19x); schemas with captured callbacks fall back per-field and roughly match Zod.
|
|
550
551
|
|
|
551
552
|
`parse()` (throwing API) rides a zero-allocation fast path: medium object 2.3M → 9.7M ops/s (4.1x), large object (100 items) 17K → 1.4M ops/s (79x).
|
|
552
553
|
|
|
@@ -561,7 +562,7 @@ For eligible schemas, zod-compiler generates a **two-phase validator**:
|
|
|
561
562
|
1. **Fast Path** — A single `&&` expression chain that validates the entire input with zero allocations. Valid input returns immediately.
|
|
562
563
|
2. **Slow Path** — Error-collecting validation that only runs when the Fast Path fails.
|
|
563
564
|
|
|
564
|
-
Additional optimizations: check ordering (cheap checks first), pre-compiled regex, Set-based enum lookups, small enum inlining (`===` for up to 5 values),
|
|
565
|
+
Additional optimizations: check ordering (cheap checks first), pre-compiled regex, Set-based enum lookups, small enum inlining (`===` for up to 5 values), discriminated-union cases that skip the now-redundant object-guard and discriminator re-check after `switch` dispatch, and auto-discrimination of plain `z.union`s of tagged objects into the same switch dispatch.
|
|
565
566
|
|
|
566
567
|
Run `npx zod-compiler check --json` to see which schemas qualify for Fast Path.
|
|
567
568
|
|
|
@@ -1,7 +1,50 @@
|
|
|
1
1
|
import type { DiscriminatedUnionIR, SchemaIR } from "../../types.js";
|
|
2
2
|
import type { FastGen, SlowGen } from "../context.js";
|
|
3
|
+
/** One `discriminator value → option index` dispatch entry. */
|
|
4
|
+
type DiscriminatorCase = DiscriminatedUnionIR["cases"][number];
|
|
3
5
|
export declare function slowDiscriminatedUnion(ir: SchemaIR & {
|
|
4
6
|
type: "discriminatedUnion";
|
|
5
7
|
}, g: SlowGen): string;
|
|
8
|
+
/**
|
|
9
|
+
* Emit an O(1) switch-dispatch fast-check for a discriminated union — real
|
|
10
|
+
* (`z.discriminatedUnion`) or one detected inside a plain `z.union`
|
|
11
|
+
* (see {@link detectUnionDiscriminator}). Both share this so the detected case
|
|
12
|
+
* inherits the size-gating and the per-case guard strip.
|
|
13
|
+
*
|
|
14
|
+
* `discSkipKey` tells each object option to drop its own type-guard and
|
|
15
|
+
* discriminator re-check: the caller's guard (`typeof x==="object"&&…` below)
|
|
16
|
+
* already proved object-ness, and the matched switch case has fixed the
|
|
17
|
+
* discriminator value, so re-emitting either is pure redundancy the optimizer
|
|
18
|
+
* only removes when it inlines this helper — which a union large enough to
|
|
19
|
+
* matter won't. Routed through the normal `visit` so size-gated extraction
|
|
20
|
+
* still bounds the switch (the strip survives into any hoisted helper);
|
|
21
|
+
* non-object options ignore the hint and keep their own guard.
|
|
22
|
+
*
|
|
23
|
+
* Returns null if any option is fast-path-ineligible.
|
|
24
|
+
*/
|
|
25
|
+
export declare function emitFastDiscriminatedSwitch(g: FastGen, discriminator: string, cases: readonly DiscriminatorCase[], options: readonly SchemaIR[]): string | null;
|
|
6
26
|
export declare function fastDiscriminatedUnion(ir: DiscriminatedUnionIR, g: FastGen): string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Detect whether a plain (untagged) `z.union` is *structurally* a discriminated
|
|
29
|
+
* union, so its fast path can use O(1) switch dispatch instead of probing every
|
|
30
|
+
* arm. Returns the discriminator + dispatch table, or null to keep the
|
|
31
|
+
* `||`-chain.
|
|
32
|
+
*
|
|
33
|
+
* Requires (proving the switch accepts exactly what the `||`-chain would): every
|
|
34
|
+
* option is a plain object that pins one shared key to a REQUIRED literal
|
|
35
|
+
* (`prop.type === "literal"` — an optional/non-literal key is rejected), and the
|
|
36
|
+
* literal values are pairwise DISJOINT across options. Disjointness is the crux:
|
|
37
|
+
* it guarantees at most one option can accept any given input, so dispatching to
|
|
38
|
+
* that single option is equivalent to trying them all. Any value shared by two
|
|
39
|
+
* options (ambiguous), a non-switchable value (`undefined`/`NaN`), or a
|
|
40
|
+
* non-object option makes detection bail to the safe `||`-chain.
|
|
41
|
+
*
|
|
42
|
+
* Fast-path only: the slow path keeps `z.union`'s sequential trial and its
|
|
43
|
+
* `invalid_union` error shape, so failure output stays byte-identical to Zod.
|
|
44
|
+
*/
|
|
45
|
+
export declare function detectUnionDiscriminator(options: readonly SchemaIR[]): {
|
|
46
|
+
discriminator: string;
|
|
47
|
+
cases: DiscriminatorCase[];
|
|
48
|
+
} | null;
|
|
49
|
+
export {};
|
|
7
50
|
//# sourceMappingURL=discriminated-union.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discriminated-union.d.ts","sourceRoot":"","sources":["../../../../src/core/codegen/schemas/discriminated-union.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"discriminated-union.d.ts","sourceRoot":"","sources":["../../../../src/core/codegen/schemas/discriminated-union.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAY,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAKtD,+DAA+D;AAC/D,KAAK,iBAAiB,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,QAAQ,GAAG;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,EAC7C,CAAC,EAAE,OAAO,GACT,MAAM,CA2BR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,2BAA2B,CACzC,CAAC,EAAE,OAAO,EACV,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,SAAS,iBAAiB,EAAE,EACnC,OAAO,EAAE,SAAS,QAAQ,EAAE,GAC3B,MAAM,GAAG,IAAI,CAuBf;AAED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,oBAAoB,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE1F;AA0BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,QAAQ,EAAE,GAC3B;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,iBAAiB,EAAE,CAAA;CAAE,GAAG,IAAI,CA2B9D"}
|
|
@@ -25,33 +25,113 @@ export function slowDiscriminatedUnion(ir, g) {
|
|
|
25
25
|
}`;
|
|
26
26
|
return `${code}\n`;
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Emit an O(1) switch-dispatch fast-check for a discriminated union — real
|
|
30
|
+
* (`z.discriminatedUnion`) or one detected inside a plain `z.union`
|
|
31
|
+
* (see {@link detectUnionDiscriminator}). Both share this so the detected case
|
|
32
|
+
* inherits the size-gating and the per-case guard strip.
|
|
33
|
+
*
|
|
34
|
+
* `discSkipKey` tells each object option to drop its own type-guard and
|
|
35
|
+
* discriminator re-check: the caller's guard (`typeof x==="object"&&…` below)
|
|
36
|
+
* already proved object-ness, and the matched switch case has fixed the
|
|
37
|
+
* discriminator value, so re-emitting either is pure redundancy the optimizer
|
|
38
|
+
* only removes when it inlines this helper — which a union large enough to
|
|
39
|
+
* matter won't. Routed through the normal `visit` so size-gated extraction
|
|
40
|
+
* still bounds the switch (the strip survives into any hoisted helper);
|
|
41
|
+
* non-object options ignore the hint and keep their own guard.
|
|
42
|
+
*
|
|
43
|
+
* Returns null if any option is fast-path-ineligible.
|
|
44
|
+
*/
|
|
45
|
+
export function emitFastDiscriminatedSwitch(g, discriminator, cases, options) {
|
|
29
46
|
const x = g.input;
|
|
30
|
-
const discKey = escapeString(
|
|
31
|
-
// Generate switch-based dispatch for O(1) discriminator lookup
|
|
47
|
+
const discKey = escapeString(discriminator);
|
|
32
48
|
const helperName = g.temp("du");
|
|
33
49
|
const helperParam = g.temp("dx");
|
|
34
|
-
const
|
|
50
|
+
const caseStrs = [];
|
|
35
51
|
// The switch body is its own function: size-gate the options against the cap
|
|
36
52
|
// in a fresh scope, otherwise many small options accumulate into the caller's
|
|
37
53
|
// scope while this helper itself grows unbounded past the TurboFan budget.
|
|
38
54
|
const body = g.scoped(helperParam);
|
|
39
|
-
for (const { value, option: index } of
|
|
40
|
-
const option =
|
|
41
|
-
|
|
42
|
-
// discriminator re-check: the caller's guard (`typeof x==="object"&&…`
|
|
43
|
-
// below) already proved object-ness, and this switch case has matched the
|
|
44
|
-
// discriminator value, so re-emitting either is pure redundancy the
|
|
45
|
-
// optimizer only removes when it inlines this helper — which a union large
|
|
46
|
-
// enough to matter won't. Routed through the normal `visit` so size-gated
|
|
47
|
-
// extraction still bounds the switch (the strip survives into any hoisted
|
|
48
|
-
// helper); non-object options ignore the hint and keep their own guard.
|
|
49
|
-
const check = body.visit(option, { discSkipKey: ir.discriminator });
|
|
55
|
+
for (const { value, option: index } of cases) {
|
|
56
|
+
const option = options[index];
|
|
57
|
+
const check = body.visit(option, { discSkipKey: discriminator });
|
|
50
58
|
if (check === null)
|
|
51
59
|
return null;
|
|
52
|
-
|
|
60
|
+
caseStrs.push(`case ${literalToJs(value)}:return ${check};`);
|
|
53
61
|
}
|
|
54
|
-
g.ctx.preamble.push(`function ${helperName}(${helperParam}){switch(${helperParam}[${discKey}]){${
|
|
62
|
+
g.ctx.preamble.push(`function ${helperName}(${helperParam}){switch(${helperParam}[${discKey}]){${caseStrs.join("")}default:return false;}}`);
|
|
55
63
|
return `typeof ${x}==="object"&&${x}!==null&&!Array.isArray(${x})&&${helperName}(${x})`;
|
|
56
64
|
}
|
|
65
|
+
export function fastDiscriminatedUnion(ir, g) {
|
|
66
|
+
return emitFastDiscriminatedSwitch(g, ir.discriminator, ir.cases, ir.options);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Minimum option count for rewriting a plain `z.union` to switch dispatch. Below
|
|
70
|
+
* this the switch helper's fixed call overhead loses to a fully-inlined
|
|
71
|
+
* `||`-chain that V8 keeps flat: measured crossover is ~4 options (n=3 can hit
|
|
72
|
+
* 0.6x — a regression — while n=5 is 1.27x and n=32 is 2.34x), so 5 captures the
|
|
73
|
+
* stable wins with margin and never regresses a small union. Real
|
|
74
|
+
* `z.discriminatedUnion` is unaffected — it dispatches via switch by construction
|
|
75
|
+
* regardless of size.
|
|
76
|
+
*/
|
|
77
|
+
const MIN_AUTO_DISCRIMINATE_OPTIONS = 5;
|
|
78
|
+
/** Values that switch correctly under `===` (excludes `undefined` and `NaN`). */
|
|
79
|
+
function isSwitchableDiscriminant(v) {
|
|
80
|
+
return (v === null ||
|
|
81
|
+
typeof v === "string" ||
|
|
82
|
+
typeof v === "boolean" ||
|
|
83
|
+
typeof v === "bigint" ||
|
|
84
|
+
(typeof v === "number" && !Number.isNaN(v)));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Detect whether a plain (untagged) `z.union` is *structurally* a discriminated
|
|
88
|
+
* union, so its fast path can use O(1) switch dispatch instead of probing every
|
|
89
|
+
* arm. Returns the discriminator + dispatch table, or null to keep the
|
|
90
|
+
* `||`-chain.
|
|
91
|
+
*
|
|
92
|
+
* Requires (proving the switch accepts exactly what the `||`-chain would): every
|
|
93
|
+
* option is a plain object that pins one shared key to a REQUIRED literal
|
|
94
|
+
* (`prop.type === "literal"` — an optional/non-literal key is rejected), and the
|
|
95
|
+
* literal values are pairwise DISJOINT across options. Disjointness is the crux:
|
|
96
|
+
* it guarantees at most one option can accept any given input, so dispatching to
|
|
97
|
+
* that single option is equivalent to trying them all. Any value shared by two
|
|
98
|
+
* options (ambiguous), a non-switchable value (`undefined`/`NaN`), or a
|
|
99
|
+
* non-object option makes detection bail to the safe `||`-chain.
|
|
100
|
+
*
|
|
101
|
+
* Fast-path only: the slow path keeps `z.union`'s sequential trial and its
|
|
102
|
+
* `invalid_union` error shape, so failure output stays byte-identical to Zod.
|
|
103
|
+
*/
|
|
104
|
+
export function detectUnionDiscriminator(options) {
|
|
105
|
+
if (options.length < MIN_AUTO_DISCRIMINATE_OPTIONS)
|
|
106
|
+
return null;
|
|
107
|
+
const objects = [];
|
|
108
|
+
for (const option of options) {
|
|
109
|
+
if (option.type !== "object")
|
|
110
|
+
return null;
|
|
111
|
+
objects.push(option);
|
|
112
|
+
}
|
|
113
|
+
const first = objects[0];
|
|
114
|
+
if (first === undefined)
|
|
115
|
+
return null; // unreachable (length checked above)
|
|
116
|
+
// Only keys present in the first option can be shared by all; try each.
|
|
117
|
+
candidate: for (const key of Object.keys(first.properties)) {
|
|
118
|
+
const seen = new Set();
|
|
119
|
+
const cases = [];
|
|
120
|
+
for (const [i, object] of objects.entries()) {
|
|
121
|
+
const prop = object.properties[key];
|
|
122
|
+
if (prop === undefined || prop.type !== "literal")
|
|
123
|
+
continue candidate;
|
|
124
|
+
for (const value of prop.values) {
|
|
125
|
+
if (!isSwitchableDiscriminant(value))
|
|
126
|
+
continue candidate;
|
|
127
|
+
if (seen.has(value))
|
|
128
|
+
continue candidate; // shared value → ambiguous dispatch
|
|
129
|
+
seen.add(value);
|
|
130
|
+
cases.push({ value, option: i });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { discriminator: key, cases };
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
57
137
|
//# sourceMappingURL=discriminated-union.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discriminated-union.js","sourceRoot":"","sources":["../../../../src/core/codegen/schemas/discriminated-union.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"discriminated-union.js","sourceRoot":"","sources":["../../../../src/core/codegen/schemas/discriminated-union.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"union.d.ts","sourceRoot":"","sources":["../../../../src/core/codegen/schemas/union.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"union.d.ts","sourceRoot":"","sources":["../../../../src/core/codegen/schemas/union.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAKtD,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAmF9E;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyBhE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { hasMutation } from "../context.js";
|
|
2
2
|
import { emit } from "../emit.js";
|
|
3
|
+
import { detectUnionDiscriminator, emitFastDiscriminatedSwitch } from "./discriminated-union.js";
|
|
3
4
|
export function slowUnion(ir, g) {
|
|
4
5
|
const resultVar = g.temp("u");
|
|
5
6
|
const errorsVar = g.temp("ue");
|
|
@@ -82,6 +83,16 @@ export function slowUnion(ir, g) {
|
|
|
82
83
|
return `${code}\n`;
|
|
83
84
|
}
|
|
84
85
|
export function fastUnion(ir, g) {
|
|
86
|
+
// A plain `z.union` of objects that all pin a shared key to disjoint literals
|
|
87
|
+
// is structurally a discriminated union: dispatch on that key with an O(1)
|
|
88
|
+
// switch instead of probing every arm in sequence. detectUnionDiscriminator
|
|
89
|
+
// returns non-null only when the switch provably accepts exactly what the
|
|
90
|
+
// ||-chain would (disjoint required literals). The slow path is untouched, so
|
|
91
|
+
// error output stays identical to Zod's plain-union behavior.
|
|
92
|
+
const discriminated = detectUnionDiscriminator(ir.options);
|
|
93
|
+
if (discriminated !== null) {
|
|
94
|
+
return emitFastDiscriminatedSwitch(g, discriminated.discriminator, discriminated.cases, ir.options);
|
|
95
|
+
}
|
|
85
96
|
const optionChecks = [];
|
|
86
97
|
for (const option of ir.options) {
|
|
87
98
|
const check = g.visit(option);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"union.js","sourceRoot":"","sources":["../../../../src/core/codegen/schemas/union.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"union.js","sourceRoot":"","sources":["../../../../src/core/codegen/schemas/union.ts"],"names":[],"mappings":"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"}
|