@kubb/plugin-zod 5.9.0 → 5.9.1
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/dist/index.cjs +154 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +154 -75
- package/dist/index.js.map +1 -1
- package/docs/guides/customization.md +7 -6
- package/docs/options.md +13 -7
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -343,7 +343,8 @@ type ResolverZod = Resolver & {
|
|
|
343
343
|
type CompileOptions = {
|
|
344
344
|
/**
|
|
345
345
|
* Throw an error if any part of the schema cannot be compiled into flat JavaScript,
|
|
346
|
-
* preventing silent fallback to the standard interpreter.
|
|
346
|
+
* preventing silent fallback to the standard interpreter. A schema Zod refuses to
|
|
347
|
+
* compile, such as a coerced scalar or a `z.xor`, is left uncompiled.
|
|
347
348
|
*
|
|
348
349
|
* @default false
|
|
349
350
|
*/
|
|
@@ -513,6 +514,7 @@ declare global {
|
|
|
513
514
|
typeName: string;
|
|
514
515
|
type: string;
|
|
515
516
|
zodPrinter: ReturnType<typeof printerZod> | ReturnType<typeof printerZodMini>;
|
|
517
|
+
zodDirectionalNodes: WeakMap<ast.SchemaNode, ast.SchemaNode | null>;
|
|
516
518
|
}
|
|
517
519
|
}
|
|
518
520
|
}
|
|
@@ -571,5 +573,4 @@ export declare const pluginZod: import("@kubb/kit").PluginFactory<PluginZod>;
|
|
|
571
573
|
* ```
|
|
572
574
|
*/
|
|
573
575
|
export declare const resolverZod: ResolverZod;
|
|
574
|
-
export { type CompileOptions, type PluginZod, type PrinterZodFactory, type PrinterZodMiniFactory, type PrinterZodMiniNodes, type PrinterZodMiniOptions, type PrinterZodNodes, type PrinterZodOptions, type ResolverZod, pluginZod as default };
|
|
575
|
-
//# sourceMappingURL=index.d.cts.map
|
|
576
|
+
export { type CompileOptions, type PluginZod, type PrinterZodFactory, type PrinterZodMiniFactory, type PrinterZodMiniNodes, type PrinterZodMiniOptions, type PrinterZodNodes, type PrinterZodOptions, type ResolverZod, pluginZod as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -343,7 +343,8 @@ type ResolverZod = Resolver & {
|
|
|
343
343
|
type CompileOptions = {
|
|
344
344
|
/**
|
|
345
345
|
* Throw an error if any part of the schema cannot be compiled into flat JavaScript,
|
|
346
|
-
* preventing silent fallback to the standard interpreter.
|
|
346
|
+
* preventing silent fallback to the standard interpreter. A schema Zod refuses to
|
|
347
|
+
* compile, such as a coerced scalar or a `z.xor`, is left uncompiled.
|
|
347
348
|
*
|
|
348
349
|
* @default false
|
|
349
350
|
*/
|
|
@@ -513,6 +514,7 @@ declare global {
|
|
|
513
514
|
typeName: string;
|
|
514
515
|
type: string;
|
|
515
516
|
zodPrinter: ReturnType<typeof printerZod> | ReturnType<typeof printerZodMini>;
|
|
517
|
+
zodDirectionalNodes: WeakMap<ast.SchemaNode, ast.SchemaNode | null>;
|
|
516
518
|
}
|
|
517
519
|
}
|
|
518
520
|
}
|
|
@@ -571,5 +573,4 @@ export declare const pluginZod: import("@kubb/kit").PluginFactory<PluginZod>;
|
|
|
571
573
|
* ```
|
|
572
574
|
*/
|
|
573
575
|
export declare const resolverZod: ResolverZod;
|
|
574
|
-
export { type CompileOptions, type PluginZod, type PrinterZodFactory, type PrinterZodMiniFactory, type PrinterZodMiniNodes, type PrinterZodMiniOptions, type PrinterZodNodes, type PrinterZodOptions, type ResolverZod, pluginZod as default };
|
|
575
|
-
//# sourceMappingURL=index.d.ts.map
|
|
576
|
+
export { type CompileOptions, type PluginZod, type PrinterZodFactory, type PrinterZodMiniFactory, type PrinterZodMiniNodes, type PrinterZodMiniOptions, type PrinterZodNodes, type PrinterZodOptions, type ResolverZod, pluginZod as default };
|
package/dist/index.js
CHANGED
|
@@ -767,78 +767,6 @@ function createCasedFile(caseLast) {
|
|
|
767
767
|
function getCircularNames(ctx) {
|
|
768
768
|
return ctx.memo("circularNames:set", () => ast.graph.getCircularNames(ctx.driver.inputNode?.schemas ?? []));
|
|
769
769
|
}
|
|
770
|
-
// src/components/Zod.tsx
|
|
771
|
-
function Zod({ name, node, printer, inferTypeName, inferKind = "infer", typeGuards, isName, assertName, mini, cyclic, compile }) {
|
|
772
|
-
const output = printer.print(node);
|
|
773
|
-
const printerImports = printer.drainImports();
|
|
774
|
-
if (!output) return;
|
|
775
|
-
const needsAnnotation = cyclic && node.type !== "object";
|
|
776
|
-
const isAlias = ast.ref.isAlias(node, printer.options.keysToOmit);
|
|
777
|
-
const isCyclic = Boolean(cyclic || printer.options.cyclicSchemas && ast.graph.containsCircular(node, { circularSchemas: printer.options.cyclicSchemas }));
|
|
778
|
-
const value = Boolean(compile) && !isAlias && !isCyclic ? typeof compile === "object" && compile.strict ? `z.compile(${output}, { strict: true })` : `z.compile(${output})` : output;
|
|
779
|
-
const targetType = inferTypeName ?? `z.infer<typeof ${name}>`;
|
|
780
|
-
const shouldGenerateIs = isName && (typeof typeGuards === "object" ? typeGuards.is ?? true : Boolean(typeGuards));
|
|
781
|
-
const shouldGenerateAssert = assertName && (typeof typeGuards === "object" ? typeGuards.assert ?? true : Boolean(typeGuards));
|
|
782
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
783
|
-
printerImports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
|
|
784
|
-
name: imp.name,
|
|
785
|
-
path: imp.path,
|
|
786
|
-
root: imp.root,
|
|
787
|
-
isTypeOnly: imp.isTypeOnly,
|
|
788
|
-
isNameSpace: imp.isNameSpace
|
|
789
|
-
}, [
|
|
790
|
-
name,
|
|
791
|
-
imp.path,
|
|
792
|
-
imp.name
|
|
793
|
-
].join("-"))),
|
|
794
|
-
/* @__PURE__ */ jsx(File.Source, {
|
|
795
|
-
name,
|
|
796
|
-
isExportable: true,
|
|
797
|
-
isIndexable: true,
|
|
798
|
-
children: /* @__PURE__ */ jsx(Const, {
|
|
799
|
-
export: true,
|
|
800
|
-
name,
|
|
801
|
-
type: needsAnnotation ? mini ? "z.ZodMiniType" : "z.ZodType" : void 0,
|
|
802
|
-
children: value
|
|
803
|
-
})
|
|
804
|
-
}),
|
|
805
|
-
inferTypeName && /* @__PURE__ */ jsx(File.Source, {
|
|
806
|
-
name: inferTypeName,
|
|
807
|
-
isExportable: true,
|
|
808
|
-
isIndexable: true,
|
|
809
|
-
isTypeOnly: true,
|
|
810
|
-
children: /* @__PURE__ */ jsx(Type, {
|
|
811
|
-
export: true,
|
|
812
|
-
name: inferTypeName,
|
|
813
|
-
children: `z.${inferKind}<typeof ${name}>`
|
|
814
|
-
})
|
|
815
|
-
}),
|
|
816
|
-
shouldGenerateIs && /* @__PURE__ */ jsx(File.Source, {
|
|
817
|
-
name: isName,
|
|
818
|
-
isExportable: true,
|
|
819
|
-
isIndexable: true,
|
|
820
|
-
children: /* @__PURE__ */ jsx(Const, {
|
|
821
|
-
export: true,
|
|
822
|
-
name: isName,
|
|
823
|
-
JSDoc: { comments: [`Type guard for {@link ${name}}`] },
|
|
824
|
-
children: mini ? `(data: unknown): data is ${targetType} => z.validate(${name}, data)` : `(data: unknown): data is ${targetType} => ${name}.validate(data)`
|
|
825
|
-
})
|
|
826
|
-
}),
|
|
827
|
-
shouldGenerateAssert && /* @__PURE__ */ jsx(File.Source, {
|
|
828
|
-
name: assertName,
|
|
829
|
-
isExportable: true,
|
|
830
|
-
isIndexable: true,
|
|
831
|
-
children: /* @__PURE__ */ jsx(Function, {
|
|
832
|
-
export: true,
|
|
833
|
-
name: assertName,
|
|
834
|
-
params: "data: unknown",
|
|
835
|
-
returnType: `asserts data is ${targetType}`,
|
|
836
|
-
JSDoc: { comments: [`Asserter for {@link ${name}}`, "@throws {z.ZodError} If data is invalid"] },
|
|
837
|
-
children: mini ? `if (!z.validate(${name}, data)) {\n z.parse(${name}, data)\n}` : `if (!${name}.validate(data)) {\n ${name}.parse(data)\n}`
|
|
838
|
-
})
|
|
839
|
-
})
|
|
840
|
-
] });
|
|
841
|
-
}
|
|
842
770
|
// src/utils.ts
|
|
843
771
|
/**
|
|
844
772
|
* Returns `true` when the given coercion option enables coercion for the specified type.
|
|
@@ -1331,6 +1259,40 @@ function hasCoercedDiscriminator({ member, propertyName, options }) {
|
|
|
1331
1259
|
})?.coerce;
|
|
1332
1260
|
});
|
|
1333
1261
|
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Whether `z.compile(schema, { strict: true })` throws for the node. Zod runs an unsupported schema below an object
|
|
1264
|
+
* property or an array, tuple or record item on its runtime parser, so only a coerced scalar or a `z.xor` that compiles
|
|
1265
|
+
* inline with the root throws: the node itself, or one reached through refs and union or intersection members.
|
|
1266
|
+
* `siblings` resolves a generated ref, which names another schema of the same file and carries no target.
|
|
1267
|
+
*
|
|
1268
|
+
* Mirrors the built-in handlers, so a type with a `printer.nodes` override is judged as if it printed the built-in output.
|
|
1269
|
+
*/
|
|
1270
|
+
function throwsOnStrictCompile({ node, options, siblings, seen = /* @__PURE__ */ new Set() }) {
|
|
1271
|
+
if (!node || seen.has(node)) return false;
|
|
1272
|
+
seen.add(node);
|
|
1273
|
+
const throws = (child) => throwsOnStrictCompile({
|
|
1274
|
+
node: child,
|
|
1275
|
+
options,
|
|
1276
|
+
siblings,
|
|
1277
|
+
seen
|
|
1278
|
+
});
|
|
1279
|
+
switch (node.type) {
|
|
1280
|
+
case ast.schema.types.ref: return throws(node.schema ?? (node.ref || !node.name ? void 0 : siblings?.get(node.name)));
|
|
1281
|
+
case ast.schema.types.union:
|
|
1282
|
+
if (node.strategy === "one" && options.oneOfType === "xor") return true;
|
|
1283
|
+
return !!getLiteralUnion({
|
|
1284
|
+
node,
|
|
1285
|
+
options
|
|
1286
|
+
})?.coerce || (node.members ?? []).some(throws);
|
|
1287
|
+
case ast.schema.types.intersection: return (node.members ?? []).some(throws);
|
|
1288
|
+
case ast.schema.types.bigint: return true;
|
|
1289
|
+
case ast.schema.types.string: return shouldCoerce(options.coercion, "strings");
|
|
1290
|
+
case ast.schema.types.number:
|
|
1291
|
+
case ast.schema.types.integer: return shouldCoerce(options.coercion, "numbers");
|
|
1292
|
+
case ast.schema.types.date: return node.representation === "date" && options.direction !== "encode" && shouldCoerce(options.coercion, "dates");
|
|
1293
|
+
default: return false;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1334
1296
|
function hasPlainDiscriminator({ member, propertyName }) {
|
|
1335
1297
|
const schemas = ast.schema.findProperties({
|
|
1336
1298
|
node: member,
|
|
@@ -1594,6 +1556,111 @@ function withInputChecks(nodes) {
|
|
|
1594
1556
|
};
|
|
1595
1557
|
return Object.fromEntries(Object.values(ast.schema.types).flatMap(wrapHandler));
|
|
1596
1558
|
}
|
|
1559
|
+
// src/components/Zod.tsx
|
|
1560
|
+
/**
|
|
1561
|
+
* Whether the schema reaches a circular schema through its refs. `containsCircular` reads the refs the node holds,
|
|
1562
|
+
* while Zod refuses to compile a cycle anywhere below the root. A generated ref carries no target, so `siblings` resolves it.
|
|
1563
|
+
*/
|
|
1564
|
+
function reachesCycle({ node, siblings, cyclicSchemas, seen = /* @__PURE__ */ new Set() }) {
|
|
1565
|
+
if (!cyclicSchemas?.size || seen.has(node)) return false;
|
|
1566
|
+
seen.add(node);
|
|
1567
|
+
return ast.schema.find(node, {
|
|
1568
|
+
followRefs: true,
|
|
1569
|
+
predicate(schema) {
|
|
1570
|
+
if (schema.type !== ast.schema.types.ref) return false;
|
|
1571
|
+
const name = ast.ref.getName(schema);
|
|
1572
|
+
if (name && cyclicSchemas.has(name)) return true;
|
|
1573
|
+
const sibling = schema.ref || !schema.name ? void 0 : siblings?.get(schema.name);
|
|
1574
|
+
return !!sibling && reachesCycle({
|
|
1575
|
+
node: sibling,
|
|
1576
|
+
siblings,
|
|
1577
|
+
cyclicSchemas,
|
|
1578
|
+
seen
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
}) !== void 0;
|
|
1582
|
+
}
|
|
1583
|
+
function Zod({ name, node, printer, inferTypeName, inferKind = "infer", typeGuards, isName, assertName, mini, cyclic, compile, siblings }) {
|
|
1584
|
+
const output = printer.print(node);
|
|
1585
|
+
const printerImports = printer.drainImports();
|
|
1586
|
+
if (!output) return;
|
|
1587
|
+
const needsAnnotation = cyclic && node.type !== "object";
|
|
1588
|
+
const isAlias = ast.ref.isAlias(node, printer.options.keysToOmit);
|
|
1589
|
+
const isCyclic = Boolean(cyclic || printer.options.cyclicSchemas && ast.graph.containsCircular(node, { circularSchemas: printer.options.cyclicSchemas }));
|
|
1590
|
+
const isStrict = typeof compile === "object" && Boolean(compile.strict);
|
|
1591
|
+
const throwsOnCompile = isStrict && (throwsOnStrictCompile({
|
|
1592
|
+
node,
|
|
1593
|
+
options: printer.options,
|
|
1594
|
+
siblings
|
|
1595
|
+
}) || reachesCycle({
|
|
1596
|
+
node,
|
|
1597
|
+
siblings,
|
|
1598
|
+
cyclicSchemas: printer.options.cyclicSchemas
|
|
1599
|
+
}));
|
|
1600
|
+
const value = Boolean(compile) && !isAlias && !isCyclic && !throwsOnCompile ? isStrict ? `z.compile(${output}, { strict: true })` : `z.compile(${output})` : output;
|
|
1601
|
+
const targetType = inferTypeName ?? `z.infer<typeof ${name}>`;
|
|
1602
|
+
const shouldGenerateIs = isName && (typeof typeGuards === "object" ? typeGuards.is ?? true : Boolean(typeGuards));
|
|
1603
|
+
const shouldGenerateAssert = assertName && (typeof typeGuards === "object" ? typeGuards.assert ?? true : Boolean(typeGuards));
|
|
1604
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1605
|
+
printerImports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
|
|
1606
|
+
name: imp.name,
|
|
1607
|
+
path: imp.path,
|
|
1608
|
+
root: imp.root,
|
|
1609
|
+
isTypeOnly: imp.isTypeOnly,
|
|
1610
|
+
isNameSpace: imp.isNameSpace
|
|
1611
|
+
}, [
|
|
1612
|
+
name,
|
|
1613
|
+
imp.path,
|
|
1614
|
+
imp.name
|
|
1615
|
+
].join("-"))),
|
|
1616
|
+
/* @__PURE__ */ jsx(File.Source, {
|
|
1617
|
+
name,
|
|
1618
|
+
isExportable: true,
|
|
1619
|
+
isIndexable: true,
|
|
1620
|
+
children: /* @__PURE__ */ jsx(Const, {
|
|
1621
|
+
export: true,
|
|
1622
|
+
name,
|
|
1623
|
+
type: needsAnnotation ? mini ? "z.ZodMiniType" : "z.ZodType" : void 0,
|
|
1624
|
+
children: value
|
|
1625
|
+
})
|
|
1626
|
+
}),
|
|
1627
|
+
inferTypeName && /* @__PURE__ */ jsx(File.Source, {
|
|
1628
|
+
name: inferTypeName,
|
|
1629
|
+
isExportable: true,
|
|
1630
|
+
isIndexable: true,
|
|
1631
|
+
isTypeOnly: true,
|
|
1632
|
+
children: /* @__PURE__ */ jsx(Type, {
|
|
1633
|
+
export: true,
|
|
1634
|
+
name: inferTypeName,
|
|
1635
|
+
children: `z.${inferKind}<typeof ${name}>`
|
|
1636
|
+
})
|
|
1637
|
+
}),
|
|
1638
|
+
shouldGenerateIs && /* @__PURE__ */ jsx(File.Source, {
|
|
1639
|
+
name: isName,
|
|
1640
|
+
isExportable: true,
|
|
1641
|
+
isIndexable: true,
|
|
1642
|
+
children: /* @__PURE__ */ jsx(Const, {
|
|
1643
|
+
export: true,
|
|
1644
|
+
name: isName,
|
|
1645
|
+
JSDoc: { comments: [`Type guard for {@link ${name}}`] },
|
|
1646
|
+
children: mini ? `(data: unknown): data is ${targetType} => z.validate(${name}, data)` : `(data: unknown): data is ${targetType} => ${name}.validate(data)`
|
|
1647
|
+
})
|
|
1648
|
+
}),
|
|
1649
|
+
shouldGenerateAssert && /* @__PURE__ */ jsx(File.Source, {
|
|
1650
|
+
name: assertName,
|
|
1651
|
+
isExportable: true,
|
|
1652
|
+
isIndexable: true,
|
|
1653
|
+
children: /* @__PURE__ */ jsx(Function, {
|
|
1654
|
+
export: true,
|
|
1655
|
+
name: assertName,
|
|
1656
|
+
params: "data: unknown",
|
|
1657
|
+
returnType: `asserts data is ${targetType}`,
|
|
1658
|
+
JSDoc: { comments: [`Asserter for {@link ${name}}`, "@throws {z.ZodError} If data is invalid"] },
|
|
1659
|
+
children: mini ? `if (!z.validate(${name}, data)) {\n z.parse(${name}, data)\n}` : `if (!${name}.validate(data)) {\n ${name}.parse(data)\n}`
|
|
1660
|
+
})
|
|
1661
|
+
})
|
|
1662
|
+
] });
|
|
1663
|
+
}
|
|
1597
1664
|
// src/printers/printerZod.ts
|
|
1598
1665
|
function strictOneOfMember(member, node, cyclicSchemas) {
|
|
1599
1666
|
if (node.type === ast.schema.types.ref) {
|
|
@@ -1714,10 +1781,19 @@ function containsDirectionalNode({ node, printerOptions }) {
|
|
|
1714
1781
|
node: schema,
|
|
1715
1782
|
printerOptions
|
|
1716
1783
|
}),
|
|
1717
|
-
followRefs: true
|
|
1784
|
+
followRefs: true,
|
|
1785
|
+
cache: getDirectionalCache(printerOptions)
|
|
1718
1786
|
}) !== void 0;
|
|
1719
1787
|
}
|
|
1720
1788
|
/**
|
|
1789
|
+
* The `find` cache for {@link containsDirectionalNode}, one per plugin per build and per option set
|
|
1790
|
+
* the probe reads. A `printer.nodes` override has no string key, so it searches without a cache.
|
|
1791
|
+
*/
|
|
1792
|
+
function getDirectionalCache({ resolver, nodes, coercion, dateType }) {
|
|
1793
|
+
if (!resolver || nodes) return void 0;
|
|
1794
|
+
return resolver.memo(`zodDirectionalNodes:${shouldCoerce(coercion, "dates")}:${dateType}`, () => /* @__PURE__ */ new WeakMap());
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1721
1797
|
* Names of the `$ref` schemas the generator should route to their input (encode) variant.
|
|
1722
1798
|
*/
|
|
1723
1799
|
function collectDirectionalRefNames({ node, printerOptions }) {
|
|
@@ -2083,8 +2159,10 @@ const zodGenerator = defineGenerator({
|
|
|
2083
2159
|
cyclicSchemas: getCircularNames(ctx),
|
|
2084
2160
|
nodes: printer?.nodes
|
|
2085
2161
|
};
|
|
2162
|
+
const siblings = /* @__PURE__ */ new Map();
|
|
2086
2163
|
function renderSchemaEntry({ schema, name, keysToOmit, direction = "decode" }) {
|
|
2087
2164
|
if (!schema) return null;
|
|
2165
|
+
siblings.set(name, schema);
|
|
2088
2166
|
const directionalRefNames = direction === "encode" && !mini ? new Set(collectDirectionalRefNames({
|
|
2089
2167
|
node: schema,
|
|
2090
2168
|
printerOptions
|
|
@@ -2116,7 +2194,8 @@ const zodGenerator = defineGenerator({
|
|
|
2116
2194
|
inferTypeName: inferred ? resolver.schema.type(name) : null,
|
|
2117
2195
|
inferKind: aliasKind(inferred, direction),
|
|
2118
2196
|
cyclic: false,
|
|
2119
|
-
compile
|
|
2197
|
+
compile,
|
|
2198
|
+
siblings
|
|
2120
2199
|
})] });
|
|
2121
2200
|
}
|
|
2122
2201
|
function buildContentTypeVariants(entries, baseName, decorate, direction) {
|
|
@@ -2297,7 +2376,7 @@ var compatibility = {
|
|
|
2297
2376
|
"node": ">=22.22"
|
|
2298
2377
|
};
|
|
2299
2378
|
// package.json
|
|
2300
|
-
var version = "5.9.
|
|
2379
|
+
var version = "5.9.1";
|
|
2301
2380
|
// src/resolvers/resolverZod.ts
|
|
2302
2381
|
/**
|
|
2303
2382
|
* Default resolver used by `@kubb/plugin-zod`. Decides the names and file
|