@kubb/plugin-zod 5.0.0-beta.80 → 5.0.0-beta.84
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 +212 -157
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +34 -40
- package/dist/index.js +170 -115
- package/dist/index.js.map +1 -1
- package/package.json +3 -7
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
|
|
2
|
-
import { ast, defineGenerator, definePlugin, defineResolver } from "
|
|
3
|
-
import { Const, File, Type, jsxRenderer } from "
|
|
4
|
-
import { Fragment, jsx, jsxs } from "
|
|
5
|
-
import { buildList, buildObject, containsCircularRef, extractRefName, lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, objectKey, stringify, syncSchemaRef, toRegExpString } from "@kubb/ast/utils";
|
|
2
|
+
import { ast, defineGenerator, definePlugin, defineResolver } from "kubb/kit";
|
|
3
|
+
import { Const, File, Type, jsxRenderer } from "kubb/jsx";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
|
|
6
5
|
//#region ../../internals/utils/src/casing.ts
|
|
7
6
|
/**
|
|
8
7
|
* Shared implementation for camelCase and PascalCase conversion.
|
|
@@ -386,12 +385,12 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
|
|
|
386
385
|
if (hasCodec(node)) return true;
|
|
387
386
|
if (node.type === "ref") {
|
|
388
387
|
if (!node.ref) return false;
|
|
389
|
-
const refName = extractRefName(node.ref);
|
|
388
|
+
const refName = ast.extractRefName(node.ref);
|
|
390
389
|
if (refName) {
|
|
391
390
|
if (seen.has(refName)) return false;
|
|
392
391
|
seen.add(refName);
|
|
393
392
|
}
|
|
394
|
-
const resolved = syncSchemaRef(node);
|
|
393
|
+
const resolved = ast.syncSchemaRef(node);
|
|
395
394
|
if (resolved.type === "ref") return false;
|
|
396
395
|
return containsCodec(resolved, seen);
|
|
397
396
|
}
|
|
@@ -407,14 +406,54 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
|
|
|
407
406
|
* them to their input (encode) variant.
|
|
408
407
|
*/
|
|
409
408
|
function collectCodecRefNames(node) {
|
|
410
|
-
return ast.collect(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? extractRefName(n.ref) ?? void 0 : void 0 });
|
|
409
|
+
return ast.collect(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? ast.extractRefName(n.ref) ?? void 0 : void 0 });
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Whether the node is a plain inline object whose shape can be lifted into an `.extend({ … })`
|
|
413
|
+
* argument. A catchall, `patternProperties`, or a nullable/optional wrapper cannot, so those stay
|
|
414
|
+
* on `.and(…)`.
|
|
415
|
+
*/
|
|
416
|
+
function isPlainInlineObject(node) {
|
|
417
|
+
return node.type === "object" && !node.nullable && !node.optional && !node.nullish && node.additionalProperties === void 0 && !node.patternProperties;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Whether a node renders as a bare Zod object — one that accepts `.extend(…)` and can be a
|
|
421
|
+
* `z.discriminatedUnion` option. Covers object nodes, `$ref`s that resolve to (or are still
|
|
422
|
+
* unresolved) objects, single-member unions of an object, and object-composable `allOf`.
|
|
423
|
+
*
|
|
424
|
+
* `cyclicSchemas` bounds the recursion: a ref into a cycle renders as `z.lazy(…)`, not an object.
|
|
425
|
+
*/
|
|
426
|
+
function isObjectSchemaNode(node, cyclicSchemas) {
|
|
427
|
+
if (node.nullable || node.optional || node.nullish) return false;
|
|
428
|
+
if (node.type === "object") return true;
|
|
429
|
+
if (node.type === "ref") {
|
|
430
|
+
const refName = (node.ref ? ast.extractRefName(node.ref) : void 0) ?? node.name;
|
|
431
|
+
if (refName && cyclicSchemas?.has(refName)) return false;
|
|
432
|
+
const resolved = ast.syncSchemaRef(node);
|
|
433
|
+
return resolved.type === "ref" || isObjectSchemaNode(resolved, cyclicSchemas);
|
|
434
|
+
}
|
|
435
|
+
if (node.type === "union") {
|
|
436
|
+
const members = node.members ?? [];
|
|
437
|
+
return members.length === 1 && isObjectSchemaNode(members[0], cyclicSchemas);
|
|
438
|
+
}
|
|
439
|
+
return isObjectComposableIntersection(node, cyclicSchemas);
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Whether an `allOf` is a pure object composition — an object base plus inline object members whose
|
|
443
|
+
* shapes merge with `.extend(…)`. These stay a Zod object instead of a `ZodIntersection`, which
|
|
444
|
+
* `z.discriminatedUnion` rejects.
|
|
445
|
+
*/
|
|
446
|
+
function isObjectComposableIntersection(node, cyclicSchemas) {
|
|
447
|
+
if (node.type !== "intersection") return false;
|
|
448
|
+
const [first, ...rest] = node.members ?? [];
|
|
449
|
+
return !!first && isObjectSchemaNode(first, cyclicSchemas) && rest.every(isPlainInlineObject);
|
|
411
450
|
}
|
|
412
451
|
/**
|
|
413
452
|
* Format a default value as a code-level literal.
|
|
414
453
|
* Objects become `{}`, primitives become their string representation, strings are quoted.
|
|
415
454
|
*/
|
|
416
455
|
function formatDefault(value) {
|
|
417
|
-
if (typeof value === "string") return stringify(value);
|
|
456
|
+
if (typeof value === "string") return ast.stringify(value);
|
|
418
457
|
if (typeof value === "object" && value !== null) return "{}";
|
|
419
458
|
return String(value ?? "");
|
|
420
459
|
}
|
|
@@ -450,7 +489,7 @@ function defaultLiteral(node, value) {
|
|
|
450
489
|
* Strings are quoted; numbers and booleans are emitted raw.
|
|
451
490
|
*/
|
|
452
491
|
function formatLiteral(v) {
|
|
453
|
-
if (typeof v === "string") return stringify(v);
|
|
492
|
+
if (typeof v === "string") return ast.stringify(v);
|
|
454
493
|
return String(v);
|
|
455
494
|
}
|
|
456
495
|
/**
|
|
@@ -492,7 +531,8 @@ function patternKeySchemaMini({ patterns, regexType }) {
|
|
|
492
531
|
})}))`;
|
|
493
532
|
}
|
|
494
533
|
function patternKeySource({ patterns, regexType }) {
|
|
495
|
-
|
|
534
|
+
const source = patterns.length === 1 ? patterns[0] : patterns.map((pattern) => `(${pattern})`).join("|");
|
|
535
|
+
return ast.toRegExpString(source, regexFunc(regexType));
|
|
496
536
|
}
|
|
497
537
|
/**
|
|
498
538
|
* Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
|
|
@@ -515,7 +555,7 @@ function lengthConstraints({ min, max, pattern, regexType }) {
|
|
|
515
555
|
return [
|
|
516
556
|
min !== void 0 ? `.min(${min})` : "",
|
|
517
557
|
max !== void 0 ? `.max(${max})` : "",
|
|
518
|
-
pattern !== void 0 ? `.regex(${toRegExpString(pattern, regexFunc(regexType))})` : ""
|
|
558
|
+
pattern !== void 0 ? `.regex(${ast.toRegExpString(pattern, regexFunc(regexType))})` : ""
|
|
519
559
|
].join("");
|
|
520
560
|
}
|
|
521
561
|
/**
|
|
@@ -537,7 +577,7 @@ function lengthChecksMini({ min, max, pattern, regexType }) {
|
|
|
537
577
|
const checks = [];
|
|
538
578
|
if (min !== void 0) checks.push(`z.minLength(${min})`);
|
|
539
579
|
if (max !== void 0) checks.push(`z.maxLength(${max})`);
|
|
540
|
-
if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, regexFunc(regexType))})`);
|
|
580
|
+
if (pattern !== void 0) checks.push(`z.regex(${ast.toRegExpString(pattern, regexFunc(regexType))})`);
|
|
541
581
|
return checks.length ? `.check(${checks.join(", ")})` : "";
|
|
542
582
|
}
|
|
543
583
|
/**
|
|
@@ -553,7 +593,7 @@ function applyModifiers({ value, schema, nullable, optional, nullish, defaultVal
|
|
|
553
593
|
})();
|
|
554
594
|
const literal = defaultValue !== void 0 ? defaultLiteral(schema, defaultValue) : null;
|
|
555
595
|
const withDefault = literal !== null ? `${withModifier}.default(${literal})` : withModifier;
|
|
556
|
-
const withDescription = description ? `${withDefault}.describe(${stringify(description)})` : withDefault;
|
|
596
|
+
const withDescription = description ? `${withDefault}.describe(${ast.stringify(description)})` : withDefault;
|
|
557
597
|
return examples?.length ? `${withDescription}.meta({ examples: [${examples.map(formatDefault).join(", ")}] })` : withDescription;
|
|
558
598
|
}
|
|
559
599
|
function modifierDepth(schema) {
|
|
@@ -596,9 +636,9 @@ function strictOneOfMember$1(member, node, cyclicSchemas) {
|
|
|
596
636
|
if (node.type === "object" && node.additionalProperties === void 0) return `${member}.strict()`;
|
|
597
637
|
if (node.type === "ref") {
|
|
598
638
|
if (member.startsWith("z.lazy(")) return member;
|
|
599
|
-
const refName = (node.ref ? extractRefName(node.ref) : void 0) ?? node.name;
|
|
639
|
+
const refName = (node.ref ? ast.extractRefName(node.ref) : void 0) ?? node.name;
|
|
600
640
|
if (refName && cyclicSchemas?.has(refName)) return member;
|
|
601
|
-
const schema = syncSchemaRef(node);
|
|
641
|
+
const schema = ast.syncSchemaRef(node);
|
|
602
642
|
if (schema.nullable || schema.optional || node.nullable || node.optional) return member;
|
|
603
643
|
if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
|
|
604
644
|
}
|
|
@@ -617,6 +657,42 @@ function getMemberConstraint({ member, regexType }) {
|
|
|
617
657
|
}) || void 0;
|
|
618
658
|
}
|
|
619
659
|
/**
|
|
660
|
+
* Builds the `{ key: value, … }` shape for an object node, shared by the `z.object(...)` and
|
|
661
|
+
* `.extend(...)` renderings so they stay in lockstep.
|
|
662
|
+
*/
|
|
663
|
+
function buildZodObjectShape(ctx, node) {
|
|
664
|
+
const objectNode = ast.narrowSchema(node, "object");
|
|
665
|
+
if (!objectNode) return "{}";
|
|
666
|
+
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
|
|
667
|
+
const entries = ast.mapSchemaProperties(objectNode, (schema) => {
|
|
668
|
+
const hasSelfRef = isCyclic(schema);
|
|
669
|
+
const savedCyclicSchemas = ctx.options.cyclicSchemas;
|
|
670
|
+
if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
|
|
671
|
+
const baseOutput = ctx.transform(schema) ?? ctx.transform(ast.factory.createSchema({ type: "unknown" }));
|
|
672
|
+
if (hasSelfRef) ctx.options.cyclicSchemas = savedCyclicSchemas;
|
|
673
|
+
return baseOutput;
|
|
674
|
+
}).map(({ name: propName, property, output: baseOutput }) => {
|
|
675
|
+
const { schema } = property;
|
|
676
|
+
const meta = ast.syncSchemaRef(schema);
|
|
677
|
+
const descriptionToApply = schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description;
|
|
678
|
+
const value = applyModifiers({
|
|
679
|
+
value: baseOutput,
|
|
680
|
+
schema,
|
|
681
|
+
nullable: meta.nullable,
|
|
682
|
+
optional: schema.optional || property.required === false,
|
|
683
|
+
nullish: schema.nullish,
|
|
684
|
+
defaultValue: meta.default,
|
|
685
|
+
description: descriptionToApply,
|
|
686
|
+
examples: meta.examples
|
|
687
|
+
});
|
|
688
|
+
return isCyclic(schema) ? ast.lazyGetter({
|
|
689
|
+
name: propName,
|
|
690
|
+
body: value
|
|
691
|
+
}) : `${ast.objectKey(propName)}: ${value}`;
|
|
692
|
+
});
|
|
693
|
+
return ast.buildObject(entries);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
620
696
|
* Zod v4 printer built with `definePrinter`.
|
|
621
697
|
*
|
|
622
698
|
* Converts a `SchemaNode` AST into a Zod v4 code string using the chainable API
|
|
@@ -657,7 +733,10 @@ const printerZod = ast.createPrinter((options) => {
|
|
|
657
733
|
},
|
|
658
734
|
date(node) {
|
|
659
735
|
const codec = getCodec(node);
|
|
660
|
-
if (codec)
|
|
736
|
+
if (codec) {
|
|
737
|
+
if (this.options.direction === "input") return codec.encode(node);
|
|
738
|
+
return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : codec.decode(node);
|
|
739
|
+
}
|
|
661
740
|
return "z.iso.date()";
|
|
662
741
|
},
|
|
663
742
|
datetime(node) {
|
|
@@ -703,45 +782,15 @@ const printerZod = ast.createPrinter((options) => {
|
|
|
703
782
|
},
|
|
704
783
|
ref(node) {
|
|
705
784
|
if (!node.name) return null;
|
|
706
|
-
const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? extractRefName(node.ref) ?? node.name : node.name;
|
|
785
|
+
const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? ast.extractRefName(node.ref) ?? node.name : node.name;
|
|
707
786
|
const useInputVariant = node.ref != null && this.options.direction === "input" && containsCodec(node);
|
|
708
787
|
const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.resolveInputSchemaName(refName) ?? refName : this.options.resolver?.default(refName, "function") ?? refName : node.name;
|
|
709
788
|
if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
|
|
710
789
|
return resolvedName;
|
|
711
790
|
},
|
|
712
791
|
object(node) {
|
|
713
|
-
const
|
|
714
|
-
const
|
|
715
|
-
const hasSelfRef = isCyclic(schema);
|
|
716
|
-
const savedCyclicSchemas = this.options.cyclicSchemas;
|
|
717
|
-
if (hasSelfRef) this.options.cyclicSchemas = void 0;
|
|
718
|
-
const baseOutput = this.transform(schema) ?? this.transform(ast.factory.createSchema({ type: "unknown" }));
|
|
719
|
-
if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas;
|
|
720
|
-
return baseOutput;
|
|
721
|
-
}).map(({ name: propName, property, output: baseOutput }) => {
|
|
722
|
-
const { schema } = property;
|
|
723
|
-
const meta = syncSchemaRef(schema);
|
|
724
|
-
const wrappedOutput = this.options.wrapOutput ? this.options.wrapOutput({
|
|
725
|
-
output: baseOutput,
|
|
726
|
-
schema
|
|
727
|
-
}) || baseOutput : baseOutput;
|
|
728
|
-
const descriptionToApply = schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description;
|
|
729
|
-
const value = applyModifiers({
|
|
730
|
-
value: wrappedOutput,
|
|
731
|
-
schema,
|
|
732
|
-
nullable: meta.nullable,
|
|
733
|
-
optional: schema.optional || property.required === false,
|
|
734
|
-
nullish: schema.nullish,
|
|
735
|
-
defaultValue: meta.default,
|
|
736
|
-
description: descriptionToApply,
|
|
737
|
-
examples: meta.examples
|
|
738
|
-
});
|
|
739
|
-
return isCyclic(schema) ? lazyGetter({
|
|
740
|
-
name: propName,
|
|
741
|
-
body: value
|
|
742
|
-
}) : `${objectKey(propName)}: ${value}`;
|
|
743
|
-
});
|
|
744
|
-
const objectBase = `z.object(${buildObject(entries)})`;
|
|
792
|
+
const entries = node.properties ?? [];
|
|
793
|
+
const objectBase = `z.object(${buildZodObjectShape(this, node)})`;
|
|
745
794
|
return (() => {
|
|
746
795
|
const patterns = node.patternProperties ? Object.entries(node.patternProperties) : [];
|
|
747
796
|
if (node.additionalProperties && node.additionalProperties !== true) {
|
|
@@ -767,23 +816,24 @@ const printerZod = ast.createPrinter((options) => {
|
|
|
767
816
|
})();
|
|
768
817
|
},
|
|
769
818
|
array(node) {
|
|
770
|
-
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthConstraints({
|
|
819
|
+
const base = `z.array(${ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthConstraints({
|
|
771
820
|
...node,
|
|
772
821
|
regexType: this.options.regexType
|
|
773
822
|
})}`;
|
|
774
823
|
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
|
|
775
824
|
},
|
|
776
825
|
tuple(node) {
|
|
777
|
-
|
|
826
|
+
const items = ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean);
|
|
827
|
+
return `z.tuple(${ast.buildList(items)})`;
|
|
778
828
|
},
|
|
779
829
|
union(node) {
|
|
780
830
|
const nodeMembers = node.members ?? [];
|
|
781
|
-
const members = mapSchemaMembers(node, (memberNode) => this.transform(memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember$1(output, schema, cyclicSchemaNames) : output).filter(Boolean);
|
|
831
|
+
const members = ast.mapSchemaMembers(node, (memberNode) => this.transform(memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember$1(output, schema, cyclicSchemaNames) : output).filter(Boolean);
|
|
782
832
|
if (members.length === 0) return "";
|
|
783
833
|
if (members.length === 1) return members[0];
|
|
784
|
-
const allDiscriminable = nodeMembers.every((m) => (m
|
|
785
|
-
if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
|
|
786
|
-
return `z.union(${buildList(members)})`;
|
|
834
|
+
const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
|
|
835
|
+
if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${ast.stringify(node.discriminatorPropertyName)}, ${ast.buildList(members)})`;
|
|
836
|
+
return `z.union(${ast.buildList(members)})`;
|
|
787
837
|
},
|
|
788
838
|
intersection(node) {
|
|
789
839
|
const members = node.members ?? [];
|
|
@@ -792,6 +842,7 @@ const printerZod = ast.createPrinter((options) => {
|
|
|
792
842
|
if (!first) return "";
|
|
793
843
|
const firstBase = this.transform(first);
|
|
794
844
|
if (!firstBase) return "";
|
|
845
|
+
if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return rest.reduce((acc, member) => `${acc}.extend(${buildZodObjectShape(this, member)})`, firstBase);
|
|
795
846
|
return rest.reduce((acc, member) => {
|
|
796
847
|
const constraint = getMemberConstraint({
|
|
797
848
|
member,
|
|
@@ -801,14 +852,14 @@ const printerZod = ast.createPrinter((options) => {
|
|
|
801
852
|
const transformed = this.transform(member);
|
|
802
853
|
return transformed ? `${acc}.and(${transformed})` : acc;
|
|
803
854
|
}, firstBase);
|
|
804
|
-
}
|
|
805
|
-
...options.nodes
|
|
855
|
+
}
|
|
806
856
|
},
|
|
857
|
+
overrides: options.nodes,
|
|
807
858
|
print(node) {
|
|
808
859
|
const { keysToOmit } = this.options;
|
|
809
860
|
const transformed = this.transform(node);
|
|
810
861
|
if (!transformed) return null;
|
|
811
|
-
const meta = syncSchemaRef(node);
|
|
862
|
+
const meta = ast.syncSchemaRef(node);
|
|
812
863
|
return applyModifiers({
|
|
813
864
|
value: (() => {
|
|
814
865
|
if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
|
|
@@ -847,7 +898,40 @@ function getMemberConstraintMini({ member, regexType }) {
|
|
|
847
898
|
}) || void 0;
|
|
848
899
|
}
|
|
849
900
|
/**
|
|
850
|
-
*
|
|
901
|
+
* Builds the `{ key: value, … }` shape for an object node with the functional `zod/mini` modifiers,
|
|
902
|
+
* shared by the `z.object(...)` and `z.extend(...)` renderings so they stay in lockstep.
|
|
903
|
+
*/
|
|
904
|
+
function buildZodMiniObjectShape(ctx, node) {
|
|
905
|
+
const objectNode = ast.narrowSchema(node, "object");
|
|
906
|
+
if (!objectNode) return "{}";
|
|
907
|
+
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
|
|
908
|
+
const entries = ast.mapSchemaProperties(objectNode, (schema) => {
|
|
909
|
+
const hasSelfRef = isCyclic(schema);
|
|
910
|
+
const savedCyclicSchemas = ctx.options.cyclicSchemas;
|
|
911
|
+
if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
|
|
912
|
+
const baseOutput = ctx.transform(schema) ?? ctx.transform(ast.factory.createSchema({ type: "unknown" }));
|
|
913
|
+
if (hasSelfRef) ctx.options.cyclicSchemas = savedCyclicSchemas;
|
|
914
|
+
return baseOutput;
|
|
915
|
+
}).map(({ name: propName, property, output: baseOutput }) => {
|
|
916
|
+
const { schema } = property;
|
|
917
|
+
const meta = ast.syncSchemaRef(schema);
|
|
918
|
+
const value = applyMiniModifiers({
|
|
919
|
+
value: baseOutput,
|
|
920
|
+
schema,
|
|
921
|
+
nullable: meta.nullable,
|
|
922
|
+
optional: schema.optional || property.required === false,
|
|
923
|
+
nullish: schema.nullish,
|
|
924
|
+
defaultValue: meta.default
|
|
925
|
+
});
|
|
926
|
+
return isCyclic(schema) ? ast.lazyGetter({
|
|
927
|
+
name: propName,
|
|
928
|
+
body: value
|
|
929
|
+
}) : `${ast.objectKey(propName)}: ${value}`;
|
|
930
|
+
});
|
|
931
|
+
return ast.buildObject(entries);
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Zod v4 Mini printer built with `definePrinter`.
|
|
851
935
|
*
|
|
852
936
|
* Converts a `SchemaNode` AST into a Zod v4 code string using the functional API
|
|
853
937
|
* (`z.optional(z.string())`) for improved tree-shaking. See {@link printerZod} for the chainable API.
|
|
@@ -859,6 +943,7 @@ function getMemberConstraintMini({ member, regexType }) {
|
|
|
859
943
|
* ```
|
|
860
944
|
*/
|
|
861
945
|
const printerZodMini = ast.createPrinter((options) => {
|
|
946
|
+
const cyclicSchemaNames = options.cyclicSchemas;
|
|
862
947
|
return {
|
|
863
948
|
name: "zod-mini",
|
|
864
949
|
options,
|
|
@@ -927,40 +1012,14 @@ const printerZodMini = ast.createPrinter((options) => {
|
|
|
927
1012
|
},
|
|
928
1013
|
ref(node) {
|
|
929
1014
|
if (!node.name) return null;
|
|
930
|
-
const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? extractRefName(node.ref) ?? node.name : node.name;
|
|
1015
|
+
const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? ast.extractRefName(node.ref) ?? node.name : node.name;
|
|
931
1016
|
const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
|
|
932
1017
|
if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
|
|
933
1018
|
return resolvedName;
|
|
934
1019
|
},
|
|
935
1020
|
object(node) {
|
|
936
|
-
const
|
|
937
|
-
const
|
|
938
|
-
const hasSelfRef = isCyclic(schema);
|
|
939
|
-
const savedCyclicSchemas = this.options.cyclicSchemas;
|
|
940
|
-
if (hasSelfRef) this.options.cyclicSchemas = void 0;
|
|
941
|
-
const baseOutput = this.transform(schema) ?? this.transform(ast.factory.createSchema({ type: "unknown" }));
|
|
942
|
-
if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas;
|
|
943
|
-
return baseOutput;
|
|
944
|
-
}).map(({ name: propName, property, output: baseOutput }) => {
|
|
945
|
-
const { schema } = property;
|
|
946
|
-
const meta = syncSchemaRef(schema);
|
|
947
|
-
const value = applyMiniModifiers({
|
|
948
|
-
value: this.options.wrapOutput ? this.options.wrapOutput({
|
|
949
|
-
output: baseOutput,
|
|
950
|
-
schema
|
|
951
|
-
}) || baseOutput : baseOutput,
|
|
952
|
-
schema,
|
|
953
|
-
nullable: meta.nullable,
|
|
954
|
-
optional: schema.optional || property.required === false,
|
|
955
|
-
nullish: schema.nullish,
|
|
956
|
-
defaultValue: meta.default
|
|
957
|
-
});
|
|
958
|
-
return isCyclic(schema) ? lazyGetter({
|
|
959
|
-
name: propName,
|
|
960
|
-
body: value
|
|
961
|
-
}) : `${objectKey(propName)}: ${value}`;
|
|
962
|
-
});
|
|
963
|
-
const objectBase = `z.object(${buildObject(entries)})`;
|
|
1021
|
+
const entries = node.properties ?? [];
|
|
1022
|
+
const objectBase = `z.object(${buildZodMiniObjectShape(this, node)})`;
|
|
964
1023
|
const patterns = node.patternProperties ? Object.entries(node.patternProperties) : [];
|
|
965
1024
|
if (node.additionalProperties && node.additionalProperties !== true) {
|
|
966
1025
|
const catchallType = this.transform(node.additionalProperties);
|
|
@@ -984,23 +1043,24 @@ const printerZodMini = ast.createPrinter((options) => {
|
|
|
984
1043
|
return objectBase;
|
|
985
1044
|
},
|
|
986
1045
|
array(node) {
|
|
987
|
-
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthChecksMini({
|
|
1046
|
+
const base = `z.array(${ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthChecksMini({
|
|
988
1047
|
...node,
|
|
989
1048
|
regexType: this.options.regexType
|
|
990
1049
|
})}`;
|
|
991
1050
|
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
|
|
992
1051
|
},
|
|
993
1052
|
tuple(node) {
|
|
994
|
-
|
|
1053
|
+
const items = ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean);
|
|
1054
|
+
return `z.tuple(${ast.buildList(items)})`;
|
|
995
1055
|
},
|
|
996
1056
|
union(node) {
|
|
997
1057
|
const nodeMembers = node.members ?? [];
|
|
998
|
-
const members = mapSchemaMembers(node, (memberNode) => this.transform(memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember(output, schema) : output).filter(Boolean);
|
|
1058
|
+
const members = ast.mapSchemaMembers(node, (memberNode) => this.transform(memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember(output, schema) : output).filter(Boolean);
|
|
999
1059
|
if (members.length === 0) return "";
|
|
1000
1060
|
if (members.length === 1) return members[0];
|
|
1001
|
-
const allDiscriminable = nodeMembers.every((m) => (m
|
|
1002
|
-
if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
|
|
1003
|
-
return `z.union(${buildList(members)})`;
|
|
1061
|
+
const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
|
|
1062
|
+
if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${ast.stringify(node.discriminatorPropertyName)}, ${ast.buildList(members)})`;
|
|
1063
|
+
return `z.union(${ast.buildList(members)})`;
|
|
1004
1064
|
},
|
|
1005
1065
|
intersection(node) {
|
|
1006
1066
|
const members = node.members ?? [];
|
|
@@ -1009,6 +1069,7 @@ const printerZodMini = ast.createPrinter((options) => {
|
|
|
1009
1069
|
if (!first) return "";
|
|
1010
1070
|
const firstBase = this.transform(first);
|
|
1011
1071
|
if (!firstBase) return "";
|
|
1072
|
+
if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return rest.reduce((acc, member) => `z.extend(${acc}, ${buildZodMiniObjectShape(this, member)})`, firstBase);
|
|
1012
1073
|
return rest.reduce((acc, member) => {
|
|
1013
1074
|
const constraint = getMemberConstraintMini({
|
|
1014
1075
|
member,
|
|
@@ -1018,14 +1079,14 @@ const printerZodMini = ast.createPrinter((options) => {
|
|
|
1018
1079
|
const transformed = this.transform(member);
|
|
1019
1080
|
return transformed ? `z.intersection(${acc}, ${transformed})` : acc;
|
|
1020
1081
|
}, firstBase);
|
|
1021
|
-
}
|
|
1022
|
-
...options.nodes
|
|
1082
|
+
}
|
|
1023
1083
|
},
|
|
1084
|
+
overrides: options.nodes,
|
|
1024
1085
|
print(node) {
|
|
1025
1086
|
const { keysToOmit } = this.options;
|
|
1026
1087
|
const transformed = this.transform(node);
|
|
1027
1088
|
if (!transformed) return null;
|
|
1028
|
-
const meta = syncSchemaRef(node);
|
|
1089
|
+
const meta = ast.syncSchemaRef(node);
|
|
1029
1090
|
return applyMiniModifiers({
|
|
1030
1091
|
value: (() => {
|
|
1031
1092
|
if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
|
|
@@ -1050,12 +1111,12 @@ const zodPrinterCache = /* @__PURE__ */ new WeakMap();
|
|
|
1050
1111
|
const zodMiniPrinterCache = /* @__PURE__ */ new WeakMap();
|
|
1051
1112
|
/**
|
|
1052
1113
|
* Returns the cached `output`/`input` direction printers for a resolver, building them on
|
|
1053
|
-
* first use. The `input` printer encodes `Date → string` for request bodies
|
|
1114
|
+
* first use. The `input` printer encodes `Date → string` for request bodies, and `output` decodes
|
|
1054
1115
|
* `string → Date` for responses. Schemas without `dateType: 'date'` fields print identically.
|
|
1055
1116
|
*/
|
|
1056
1117
|
function getStdPrinters(resolver, params) {
|
|
1057
1118
|
const cached = zodPrinterCache.get(resolver);
|
|
1058
|
-
if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.regexType === params.regexType && cached.dateType === params.dateType) return {
|
|
1119
|
+
if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.regexType === params.regexType && cached.dateType === params.dateType && cached.nodes === params.nodes) return {
|
|
1059
1120
|
output: cached.output,
|
|
1060
1121
|
input: cached.input
|
|
1061
1122
|
};
|
|
@@ -1077,7 +1138,8 @@ function getStdPrinters(resolver, params) {
|
|
|
1077
1138
|
coercion: params.coercion,
|
|
1078
1139
|
guidType: params.guidType,
|
|
1079
1140
|
regexType: params.regexType,
|
|
1080
|
-
dateType: params.dateType
|
|
1141
|
+
dateType: params.dateType,
|
|
1142
|
+
nodes: params.nodes
|
|
1081
1143
|
});
|
|
1082
1144
|
return {
|
|
1083
1145
|
output,
|
|
@@ -1086,7 +1148,7 @@ function getStdPrinters(resolver, params) {
|
|
|
1086
1148
|
}
|
|
1087
1149
|
function getMiniPrinter(resolver, params) {
|
|
1088
1150
|
const cached = zodMiniPrinterCache.get(resolver);
|
|
1089
|
-
if (cached && cached.guidType === params.guidType && cached.regexType === params.regexType) return cached.printer;
|
|
1151
|
+
if (cached && cached.guidType === params.guidType && cached.regexType === params.regexType && cached.nodes === params.nodes) return cached.printer;
|
|
1090
1152
|
const p = printerZodMini({
|
|
1091
1153
|
...params,
|
|
1092
1154
|
resolver
|
|
@@ -1094,7 +1156,8 @@ function getMiniPrinter(resolver, params) {
|
|
|
1094
1156
|
zodMiniPrinterCache.set(resolver, {
|
|
1095
1157
|
printer: p,
|
|
1096
1158
|
guidType: params.guidType,
|
|
1097
|
-
regexType: params.regexType
|
|
1159
|
+
regexType: params.regexType,
|
|
1160
|
+
nodes: params.nodes
|
|
1098
1161
|
});
|
|
1099
1162
|
return p;
|
|
1100
1163
|
}
|
|
@@ -1109,7 +1172,7 @@ const zodGenerator = defineGenerator({
|
|
|
1109
1172
|
renderer: jsxRenderer,
|
|
1110
1173
|
schema(node, ctx) {
|
|
1111
1174
|
const { adapter, config, resolver, root } = ctx;
|
|
1112
|
-
const { output, coercion, guidType, regexType, mini,
|
|
1175
|
+
const { output, coercion, guidType, regexType, mini, inferred, importPath, group, printer } = ctx.options;
|
|
1113
1176
|
const dateType = adapter.options.dateType;
|
|
1114
1177
|
if (!node.name) return;
|
|
1115
1178
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
@@ -1163,7 +1226,6 @@ const zodGenerator = defineGenerator({
|
|
|
1163
1226
|
guidType,
|
|
1164
1227
|
regexType,
|
|
1165
1228
|
dateType,
|
|
1166
|
-
wrapOutput,
|
|
1167
1229
|
cyclicSchemas,
|
|
1168
1230
|
nameMapping,
|
|
1169
1231
|
nodes: printer?.nodes
|
|
@@ -1171,7 +1233,6 @@ const zodGenerator = defineGenerator({
|
|
|
1171
1233
|
const schemaPrinter = mini ? getMiniPrinter(resolver, {
|
|
1172
1234
|
guidType,
|
|
1173
1235
|
regexType,
|
|
1174
|
-
wrapOutput,
|
|
1175
1236
|
cyclicSchemas,
|
|
1176
1237
|
nameMapping,
|
|
1177
1238
|
nodes: printer?.nodes
|
|
@@ -1231,7 +1292,7 @@ const zodGenerator = defineGenerator({
|
|
|
1231
1292
|
operation(node, ctx) {
|
|
1232
1293
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1233
1294
|
const { adapter, config, resolver, root } = ctx;
|
|
1234
|
-
const { output, coercion, guidType, regexType, mini,
|
|
1295
|
+
const { output, coercion, guidType, regexType, mini, inferred, importPath, group, printer } = ctx.options;
|
|
1235
1296
|
const dateType = adapter.options.dateType;
|
|
1236
1297
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
1237
1298
|
const params = caseParams(node.parameters, "camelcase");
|
|
@@ -1265,7 +1326,6 @@ const zodGenerator = defineGenerator({
|
|
|
1265
1326
|
const schemaPrinter = mini ? keysToOmit?.length ? printerZodMini({
|
|
1266
1327
|
guidType,
|
|
1267
1328
|
regexType,
|
|
1268
|
-
wrapOutput,
|
|
1269
1329
|
resolver,
|
|
1270
1330
|
keysToOmit,
|
|
1271
1331
|
cyclicSchemas,
|
|
@@ -1274,7 +1334,6 @@ const zodGenerator = defineGenerator({
|
|
|
1274
1334
|
}) : getMiniPrinter(resolver, {
|
|
1275
1335
|
guidType,
|
|
1276
1336
|
regexType,
|
|
1277
|
-
wrapOutput,
|
|
1278
1337
|
cyclicSchemas,
|
|
1279
1338
|
nameMapping,
|
|
1280
1339
|
nodes: printer?.nodes
|
|
@@ -1283,7 +1342,6 @@ const zodGenerator = defineGenerator({
|
|
|
1283
1342
|
guidType,
|
|
1284
1343
|
regexType,
|
|
1285
1344
|
dateType,
|
|
1286
|
-
wrapOutput,
|
|
1287
1345
|
resolver,
|
|
1288
1346
|
keysToOmit,
|
|
1289
1347
|
cyclicSchemas,
|
|
@@ -1295,7 +1353,6 @@ const zodGenerator = defineGenerator({
|
|
|
1295
1353
|
guidType,
|
|
1296
1354
|
regexType,
|
|
1297
1355
|
dateType,
|
|
1298
|
-
wrapOutput,
|
|
1299
1356
|
cyclicSchemas,
|
|
1300
1357
|
nameMapping,
|
|
1301
1358
|
nodes: printer?.nodes
|
|
@@ -1538,7 +1595,7 @@ const pluginZodName = "plugin-zod";
|
|
|
1538
1595
|
*
|
|
1539
1596
|
* @example
|
|
1540
1597
|
* ```ts
|
|
1541
|
-
* import { defineConfig } from 'kubb'
|
|
1598
|
+
* import { defineConfig } from 'kubb/config'
|
|
1542
1599
|
* import { pluginTs } from '@kubb/plugin-ts'
|
|
1543
1600
|
* import { pluginZod } from '@kubb/plugin-zod'
|
|
1544
1601
|
*
|
|
@@ -1549,7 +1606,7 @@ const pluginZodName = "plugin-zod";
|
|
|
1549
1606
|
* pluginTs(),
|
|
1550
1607
|
* pluginZod({
|
|
1551
1608
|
* output: { path: './zod' },
|
|
1552
|
-
*
|
|
1609
|
+
* inferred: true,
|
|
1553
1610
|
* }),
|
|
1554
1611
|
* ],
|
|
1555
1612
|
* })
|
|
@@ -1559,7 +1616,7 @@ const pluginZod = definePlugin((options) => {
|
|
|
1559
1616
|
const { output = {
|
|
1560
1617
|
path: "zod",
|
|
1561
1618
|
barrel: { type: "named" }
|
|
1562
|
-
}, group, exclude = [], include, override = [],
|
|
1619
|
+
}, group, exclude = [], include, override = [], mini = false, guidType = "uuid", regexType = "literal", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, printer, resolver: userResolver, macros: userMacros } = options;
|
|
1563
1620
|
const groupConfig = createGroupConfig(group);
|
|
1564
1621
|
return {
|
|
1565
1622
|
name: pluginZodName,
|
|
@@ -1571,14 +1628,12 @@ const pluginZod = definePlugin((options) => {
|
|
|
1571
1628
|
include,
|
|
1572
1629
|
override,
|
|
1573
1630
|
group: groupConfig,
|
|
1574
|
-
typed,
|
|
1575
1631
|
importPath,
|
|
1576
1632
|
coercion,
|
|
1577
1633
|
inferred,
|
|
1578
1634
|
guidType,
|
|
1579
1635
|
regexType,
|
|
1580
1636
|
mini,
|
|
1581
|
-
wrapOutput,
|
|
1582
1637
|
printer
|
|
1583
1638
|
});
|
|
1584
1639
|
ctx.setResolver(userResolver ? {
|