@kubb/plugin-zod 5.0.0-beta.56 → 5.0.0-beta.73
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 +2 -2
- package/dist/index.cjs +201 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +78 -18
- package/dist/index.js +202 -94
- package/dist/index.js.map +1 -1
- package/package.json +9 -11
- package/src/components/Operations.tsx +0 -78
- package/src/components/Zod.tsx +0 -42
- package/src/constants.ts +0 -5
- package/src/generators/zodGenerator.tsx +0 -367
- package/src/index.ts +0 -11
- package/src/plugin.ts +0 -97
- package/src/printers/printerZod.ts +0 -360
- package/src/printers/printerZodMini.ts +0 -290
- package/src/resolvers/resolverZod.ts +0 -71
- package/src/types.ts +0 -219
- package/src/utils.ts +0 -299
- /package/dist/{chunk-C0LytTxp.js → rolldown-runtime-C0LytTxp.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as __name } from "./
|
|
1
|
+
import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
|
|
2
2
|
import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
|
|
3
|
-
import { buildList, buildObject, extractRefName, objectKey, stringify, stringifyObject, toRegExpString } from "@kubb/ast/utils";
|
|
4
3
|
import { Const, File, Type, jsxRenderer } from "@kubb/renderer-jsx";
|
|
4
|
+
import { buildList, buildObject, containsCircularRef, extractRefName, lazyGetter, mapSchemaItems, mapSchemaMembers, mapSchemaProperties, objectKey, stringify, stringifyObject, syncSchemaRef, toRegExpString } from "@kubb/ast/utils";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
|
|
6
6
|
//#region ../../internals/utils/src/casing.ts
|
|
7
7
|
/**
|
|
@@ -190,6 +190,27 @@ function ensureValidVarName(name) {
|
|
|
190
190
|
return `_${name}`;
|
|
191
191
|
}
|
|
192
192
|
//#endregion
|
|
193
|
+
//#region ../../internals/shared/src/params.ts
|
|
194
|
+
const caseParamsCache = /* @__PURE__ */ new WeakMap();
|
|
195
|
+
/**
|
|
196
|
+
* Applies camelCase to parameter names and returns a new array without mutating the input.
|
|
197
|
+
*
|
|
198
|
+
* Run it before handing parameters to schema builders so output property keys get the right casing
|
|
199
|
+
* while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
|
|
200
|
+
* original array is returned unchanged. Results are cached per input array.
|
|
201
|
+
*/
|
|
202
|
+
function caseParams(params, casing) {
|
|
203
|
+
if (!casing) return params;
|
|
204
|
+
const cached = caseParamsCache.get(params);
|
|
205
|
+
if (cached) return cached;
|
|
206
|
+
const result = params.map((param) => ({
|
|
207
|
+
...param,
|
|
208
|
+
name: camelCase(param.name)
|
|
209
|
+
}));
|
|
210
|
+
caseParamsCache.set(params, result);
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
//#endregion
|
|
193
214
|
//#region ../../internals/shared/src/operation.ts
|
|
194
215
|
/**
|
|
195
216
|
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
@@ -239,6 +260,17 @@ function resolveContentTypeVariants(entries, baseName) {
|
|
|
239
260
|
};
|
|
240
261
|
});
|
|
241
262
|
}
|
|
263
|
+
function getStatusCodeNumber(statusCode) {
|
|
264
|
+
const code = Number(statusCode);
|
|
265
|
+
return Number.isNaN(code) ? null : code;
|
|
266
|
+
}
|
|
267
|
+
function isSuccessStatusCode(statusCode) {
|
|
268
|
+
const code = getStatusCodeNumber(statusCode);
|
|
269
|
+
return code !== null && code >= 200 && code < 300;
|
|
270
|
+
}
|
|
271
|
+
function getSuccessResponses(responses) {
|
|
272
|
+
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
273
|
+
}
|
|
242
274
|
//#endregion
|
|
243
275
|
//#region ../../internals/shared/src/group.ts
|
|
244
276
|
/**
|
|
@@ -431,7 +463,7 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
|
|
|
431
463
|
if (seen.has(refName)) return false;
|
|
432
464
|
seen.add(refName);
|
|
433
465
|
}
|
|
434
|
-
const resolved =
|
|
466
|
+
const resolved = syncSchemaRef(node);
|
|
435
467
|
if (resolved.type === "ref") return false;
|
|
436
468
|
return containsCodec(resolved, seen);
|
|
437
469
|
}
|
|
@@ -443,6 +475,13 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
|
|
|
443
475
|
return children.some((child) => containsCodec(child, seen));
|
|
444
476
|
}
|
|
445
477
|
/**
|
|
478
|
+
* Collects the names of `$ref` schemas that transitively contain a codec, so the generator can route
|
|
479
|
+
* them to their input (encode) variant.
|
|
480
|
+
*/
|
|
481
|
+
function collectCodecRefNames(node) {
|
|
482
|
+
return ast.collect(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? extractRefName(n.ref) ?? void 0 : void 0 });
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
446
485
|
* Collects all resolved schema names for an operation's parameters and responses
|
|
447
486
|
* into a single lookup object, useful for building imports and type references.
|
|
448
487
|
*/
|
|
@@ -490,6 +529,13 @@ function formatLiteral(v) {
|
|
|
490
529
|
return String(v);
|
|
491
530
|
}
|
|
492
531
|
/**
|
|
532
|
+
* Map a `regexType` to the `func` argument of `toRegExpString`: `'constructor'` emits
|
|
533
|
+
* `new RegExp(...)`, while `'literal'` (the default) emits a regex literal.
|
|
534
|
+
*/
|
|
535
|
+
function regexFunc(regexType) {
|
|
536
|
+
return regexType === "constructor" ? "RegExp" : null;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
493
539
|
* Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
|
|
494
540
|
* using the standard chainable Zod v4 API.
|
|
495
541
|
*/
|
|
@@ -506,11 +552,11 @@ function numberConstraints({ min, max, exclusiveMinimum, exclusiveMaximum, multi
|
|
|
506
552
|
* Build `.min()` / `.max()` / `.regex()` chains for strings/arrays
|
|
507
553
|
* using the standard chainable Zod v4 API.
|
|
508
554
|
*/
|
|
509
|
-
function lengthConstraints({ min, max, pattern }) {
|
|
555
|
+
function lengthConstraints({ min, max, pattern, regexType }) {
|
|
510
556
|
return [
|
|
511
557
|
min !== void 0 ? `.min(${min})` : "",
|
|
512
558
|
max !== void 0 ? `.max(${max})` : "",
|
|
513
|
-
pattern !== void 0 ? `.regex(${toRegExpString(pattern,
|
|
559
|
+
pattern !== void 0 ? `.regex(${toRegExpString(pattern, regexFunc(regexType))})` : ""
|
|
514
560
|
].join("");
|
|
515
561
|
}
|
|
516
562
|
/**
|
|
@@ -528,18 +574,18 @@ function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multip
|
|
|
528
574
|
/**
|
|
529
575
|
* Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
|
|
530
576
|
*/
|
|
531
|
-
function lengthChecksMini({ min, max, pattern }) {
|
|
577
|
+
function lengthChecksMini({ min, max, pattern, regexType }) {
|
|
532
578
|
const checks = [];
|
|
533
579
|
if (min !== void 0) checks.push(`z.minLength(${min})`);
|
|
534
580
|
if (max !== void 0) checks.push(`z.maxLength(${max})`);
|
|
535
|
-
if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern,
|
|
581
|
+
if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, regexFunc(regexType))})`);
|
|
536
582
|
return checks.length ? `.check(${checks.join(", ")})` : "";
|
|
537
583
|
}
|
|
538
584
|
/**
|
|
539
|
-
* Apply nullable / optional / nullish modifiers
|
|
540
|
-
* to a schema value string using the chainable Zod v4 API.
|
|
585
|
+
* Apply nullable / optional / nullish modifiers, an optional `.describe()` call, and an
|
|
586
|
+
* optional `.meta({ examples })` call to a schema value string using the chainable Zod v4 API.
|
|
541
587
|
*/
|
|
542
|
-
function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }) {
|
|
588
|
+
function applyModifiers({ value, nullable, optional, nullish, defaultValue, description, examples }) {
|
|
543
589
|
const withModifier = (() => {
|
|
544
590
|
if (nullish || nullable && optional) return `${value}.nullish()`;
|
|
545
591
|
if (optional) return `${value}.optional()`;
|
|
@@ -547,7 +593,8 @@ function applyModifiers({ value, nullable, optional, nullish, defaultValue, desc
|
|
|
547
593
|
return value;
|
|
548
594
|
})();
|
|
549
595
|
const withDefault = defaultValue !== void 0 ? `${withModifier}.default(${formatDefault(defaultValue)})` : withModifier;
|
|
550
|
-
|
|
596
|
+
const withDescription = description ? `${withDefault}.describe(${stringify(description)})` : withDefault;
|
|
597
|
+
return examples?.length ? `${withDescription}.meta({ examples: [${examples.map(formatDefault).join(", ")}] })` : withDescription;
|
|
551
598
|
}
|
|
552
599
|
/**
|
|
553
600
|
* Apply nullable / optional / nullish modifiers using the functional `zod/mini` API
|
|
@@ -567,16 +614,22 @@ function strictOneOfMember$1(member, node) {
|
|
|
567
614
|
if (node.type === "object" && node.additionalProperties === void 0) return `${member}.strict()`;
|
|
568
615
|
if (node.type === "ref") {
|
|
569
616
|
if (member.startsWith("z.lazy(")) return member;
|
|
570
|
-
const schema =
|
|
617
|
+
const schema = syncSchemaRef(node);
|
|
571
618
|
if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
|
|
572
619
|
}
|
|
573
620
|
return member;
|
|
574
621
|
}
|
|
575
622
|
__name(strictOneOfMember$1, "strictOneOfMember");
|
|
576
|
-
function getMemberConstraint(member) {
|
|
577
|
-
if (member.primitive === "string") return lengthConstraints(
|
|
623
|
+
function getMemberConstraint({ member, regexType }) {
|
|
624
|
+
if (member.primitive === "string") return lengthConstraints({
|
|
625
|
+
...ast.narrowSchema(member, "string") ?? {},
|
|
626
|
+
regexType
|
|
627
|
+
}) || void 0;
|
|
578
628
|
if (member.primitive === "number" || member.primitive === "integer") return numberConstraints(ast.narrowSchema(member, "number") ?? ast.narrowSchema(member, "integer") ?? {}) || void 0;
|
|
579
|
-
if (member.primitive === "array") return lengthConstraints(
|
|
629
|
+
if (member.primitive === "array") return lengthConstraints({
|
|
630
|
+
...ast.narrowSchema(member, "array") ?? {},
|
|
631
|
+
regexType
|
|
632
|
+
}) || void 0;
|
|
580
633
|
}
|
|
581
634
|
/**
|
|
582
635
|
* Zod v4 printer built with `definePrinter`.
|
|
@@ -590,7 +643,7 @@ function getMemberConstraint(member) {
|
|
|
590
643
|
* const code = printer.print(stringNode) // "z.string()"
|
|
591
644
|
* ```
|
|
592
645
|
*/
|
|
593
|
-
const printerZod = ast.
|
|
646
|
+
const printerZod = ast.createPrinter((options) => {
|
|
594
647
|
return {
|
|
595
648
|
name: "zod",
|
|
596
649
|
options,
|
|
@@ -602,7 +655,10 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
602
655
|
boolean: () => "z.boolean()",
|
|
603
656
|
null: () => "z.null()",
|
|
604
657
|
string(node) {
|
|
605
|
-
return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints(
|
|
658
|
+
return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints({
|
|
659
|
+
...node,
|
|
660
|
+
regexType: this.options.regexType
|
|
661
|
+
})}`;
|
|
606
662
|
},
|
|
607
663
|
number(node) {
|
|
608
664
|
return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number()" : "z.number()"}${numberConstraints(node)}`;
|
|
@@ -630,13 +686,22 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
630
686
|
return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
|
|
631
687
|
},
|
|
632
688
|
uuid(node) {
|
|
633
|
-
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints(
|
|
689
|
+
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints({
|
|
690
|
+
...node,
|
|
691
|
+
regexType: this.options.regexType
|
|
692
|
+
})}`;
|
|
634
693
|
},
|
|
635
694
|
email(node) {
|
|
636
|
-
return `z.email()${lengthConstraints(
|
|
695
|
+
return `z.email()${lengthConstraints({
|
|
696
|
+
...node,
|
|
697
|
+
regexType: this.options.regexType
|
|
698
|
+
})}`;
|
|
637
699
|
},
|
|
638
700
|
url(node) {
|
|
639
|
-
return `z.url()${lengthConstraints(
|
|
701
|
+
return `z.url()${lengthConstraints({
|
|
702
|
+
...node,
|
|
703
|
+
regexType: this.options.regexType
|
|
704
|
+
})}`;
|
|
640
705
|
},
|
|
641
706
|
ipv4: () => "z.ipv4()",
|
|
642
707
|
ipv6: () => "z.ipv6()",
|
|
@@ -659,17 +724,17 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
659
724
|
return resolvedName;
|
|
660
725
|
},
|
|
661
726
|
object(node) {
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
const
|
|
665
|
-
const isNullable = meta.nullable;
|
|
666
|
-
const isOptional = schema.optional;
|
|
667
|
-
const isNullish = schema.nullish;
|
|
668
|
-
const hasSelfRef = this.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
|
|
727
|
+
const isCyclic = (schema) => this.options.cyclicSchemas != null && containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
|
|
728
|
+
const objectBase = `z.object(${buildObject(mapSchemaProperties(node, (schema) => {
|
|
729
|
+
const hasSelfRef = isCyclic(schema);
|
|
669
730
|
const savedCyclicSchemas = this.options.cyclicSchemas;
|
|
670
731
|
if (hasSelfRef) this.options.cyclicSchemas = void 0;
|
|
671
|
-
const baseOutput = this.transform(schema) ?? this.transform(ast.createSchema({ type: "unknown" }));
|
|
732
|
+
const baseOutput = this.transform(schema) ?? this.transform(ast.factory.createSchema({ type: "unknown" }));
|
|
672
733
|
if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas;
|
|
734
|
+
return baseOutput;
|
|
735
|
+
}).map(({ name: propName, property, output: baseOutput }) => {
|
|
736
|
+
const { schema } = property;
|
|
737
|
+
const meta = syncSchemaRef(schema);
|
|
673
738
|
const wrappedOutput = this.options.wrapOutput ? this.options.wrapOutput({
|
|
674
739
|
output: baseOutput,
|
|
675
740
|
schema
|
|
@@ -677,38 +742,41 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
677
742
|
const descriptionToApply = schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description;
|
|
678
743
|
const value = applyModifiers({
|
|
679
744
|
value: wrappedOutput,
|
|
680
|
-
nullable:
|
|
681
|
-
optional:
|
|
682
|
-
nullish:
|
|
745
|
+
nullable: meta.nullable,
|
|
746
|
+
optional: schema.optional || property.required === false,
|
|
747
|
+
nullish: schema.nullish,
|
|
683
748
|
defaultValue: meta.default,
|
|
684
|
-
description: descriptionToApply
|
|
749
|
+
description: descriptionToApply,
|
|
750
|
+
examples: meta.examples
|
|
685
751
|
});
|
|
686
|
-
|
|
687
|
-
|
|
752
|
+
return isCyclic(schema) ? lazyGetter({
|
|
753
|
+
name: propName,
|
|
754
|
+
body: value
|
|
755
|
+
}) : `${objectKey(propName)}: ${value}`;
|
|
688
756
|
}))})`;
|
|
689
757
|
return (() => {
|
|
690
758
|
if (node.additionalProperties && node.additionalProperties !== true) {
|
|
691
759
|
const catchallType = this.transform(node.additionalProperties);
|
|
692
760
|
return catchallType ? `${objectBase}.catchall(${catchallType})` : objectBase;
|
|
693
761
|
}
|
|
694
|
-
if (node.additionalProperties === true) return `${objectBase}.catchall(${this.transform(ast.createSchema({ type: "unknown" }))})`;
|
|
762
|
+
if (node.additionalProperties === true) return `${objectBase}.catchall(${this.transform(ast.factory.createSchema({ type: "unknown" }))})`;
|
|
695
763
|
if (node.additionalProperties === false) return `${objectBase}.strict()`;
|
|
696
764
|
return objectBase;
|
|
697
765
|
})();
|
|
698
766
|
},
|
|
699
767
|
array(node) {
|
|
700
|
-
const base = `z.array(${(node
|
|
768
|
+
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthConstraints({
|
|
769
|
+
...node,
|
|
770
|
+
regexType: this.options.regexType
|
|
771
|
+
})}`;
|
|
701
772
|
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
|
|
702
773
|
},
|
|
703
774
|
tuple(node) {
|
|
704
|
-
return `z.tuple(${buildList((node
|
|
775
|
+
return `z.tuple(${buildList(mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
|
|
705
776
|
},
|
|
706
777
|
union(node) {
|
|
707
778
|
const nodeMembers = node.members ?? [];
|
|
708
|
-
const members =
|
|
709
|
-
const member = this.transform(memberNode);
|
|
710
|
-
return member && node.strategy === "one" ? strictOneOfMember$1(member, memberNode) : member;
|
|
711
|
-
}).filter(Boolean);
|
|
779
|
+
const members = mapSchemaMembers(node, (memberNode) => this.transform(memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember$1(output, schema) : output).filter(Boolean);
|
|
712
780
|
if (members.length === 0) return "";
|
|
713
781
|
if (members.length === 1) return members[0];
|
|
714
782
|
if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
|
|
@@ -722,7 +790,10 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
722
790
|
const firstBase = this.transform(first);
|
|
723
791
|
if (!firstBase) return "";
|
|
724
792
|
return rest.reduce((acc, member) => {
|
|
725
|
-
const constraint = getMemberConstraint(
|
|
793
|
+
const constraint = getMemberConstraint({
|
|
794
|
+
member,
|
|
795
|
+
regexType: this.options.regexType
|
|
796
|
+
});
|
|
726
797
|
if (constraint) return acc + constraint;
|
|
727
798
|
const transformed = this.transform(member);
|
|
728
799
|
return transformed ? `${acc}.and(${transformed})` : acc;
|
|
@@ -734,7 +805,7 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
734
805
|
const { keysToOmit } = this.options;
|
|
735
806
|
const transformed = this.transform(node);
|
|
736
807
|
if (!transformed) return null;
|
|
737
|
-
const meta =
|
|
808
|
+
const meta = syncSchemaRef(node);
|
|
738
809
|
return applyModifiers({
|
|
739
810
|
value: (() => {
|
|
740
811
|
if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
|
|
@@ -746,7 +817,8 @@ const printerZod = ast.definePrinter((options) => {
|
|
|
746
817
|
optional: meta.optional,
|
|
747
818
|
nullish: meta.nullish,
|
|
748
819
|
defaultValue: meta.default,
|
|
749
|
-
description: meta.description
|
|
820
|
+
description: meta.description,
|
|
821
|
+
examples: meta.examples
|
|
750
822
|
});
|
|
751
823
|
}
|
|
752
824
|
};
|
|
@@ -757,10 +829,16 @@ function strictOneOfMember(member, node) {
|
|
|
757
829
|
if (node.type === "object" && (node.additionalProperties === void 0 || node.additionalProperties === false)) return member.replace(/^z\.object\(/, "z.strictObject(");
|
|
758
830
|
return member;
|
|
759
831
|
}
|
|
760
|
-
function getMemberConstraintMini(member) {
|
|
761
|
-
if (member.primitive === "string") return lengthChecksMini(
|
|
832
|
+
function getMemberConstraintMini({ member, regexType }) {
|
|
833
|
+
if (member.primitive === "string") return lengthChecksMini({
|
|
834
|
+
...ast.narrowSchema(member, "string") ?? {},
|
|
835
|
+
regexType
|
|
836
|
+
}) || void 0;
|
|
762
837
|
if (member.primitive === "number" || member.primitive === "integer") return numberChecksMini(ast.narrowSchema(member, "number") ?? ast.narrowSchema(member, "integer") ?? {}) || void 0;
|
|
763
|
-
if (member.primitive === "array") return lengthChecksMini(
|
|
838
|
+
if (member.primitive === "array") return lengthChecksMini({
|
|
839
|
+
...ast.narrowSchema(member, "array") ?? {},
|
|
840
|
+
regexType
|
|
841
|
+
}) || void 0;
|
|
764
842
|
}
|
|
765
843
|
/**
|
|
766
844
|
* Zod v4 **Mini** printer built with `definePrinter`.
|
|
@@ -774,7 +852,7 @@ function getMemberConstraintMini(member) {
|
|
|
774
852
|
* const code = printer.print(optionalStringNode) // "z.optional(z.string())"
|
|
775
853
|
* ```
|
|
776
854
|
*/
|
|
777
|
-
const printerZodMini = ast.
|
|
855
|
+
const printerZodMini = ast.createPrinter((options) => {
|
|
778
856
|
return {
|
|
779
857
|
name: "zod-mini",
|
|
780
858
|
options,
|
|
@@ -786,7 +864,10 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
786
864
|
boolean: () => "z.boolean()",
|
|
787
865
|
null: () => "z.null()",
|
|
788
866
|
string(node) {
|
|
789
|
-
return `z.string()${lengthChecksMini(
|
|
867
|
+
return `z.string()${lengthChecksMini({
|
|
868
|
+
...node,
|
|
869
|
+
regexType: this.options.regexType
|
|
870
|
+
})}`;
|
|
790
871
|
},
|
|
791
872
|
number(node) {
|
|
792
873
|
return `z.number()${numberChecksMini(node)}`;
|
|
@@ -809,13 +890,22 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
809
890
|
return "z.date()";
|
|
810
891
|
},
|
|
811
892
|
uuid(node) {
|
|
812
|
-
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthChecksMini(
|
|
893
|
+
return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthChecksMini({
|
|
894
|
+
...node,
|
|
895
|
+
regexType: this.options.regexType
|
|
896
|
+
})}`;
|
|
813
897
|
},
|
|
814
898
|
email(node) {
|
|
815
|
-
return `z.email()${lengthChecksMini(
|
|
899
|
+
return `z.email()${lengthChecksMini({
|
|
900
|
+
...node,
|
|
901
|
+
regexType: this.options.regexType
|
|
902
|
+
})}`;
|
|
816
903
|
},
|
|
817
904
|
url(node) {
|
|
818
|
-
return `z.url()${lengthChecksMini(
|
|
905
|
+
return `z.url()${lengthChecksMini({
|
|
906
|
+
...node,
|
|
907
|
+
regexType: this.options.regexType
|
|
908
|
+
})}`;
|
|
819
909
|
},
|
|
820
910
|
ipv4: () => "z.ipv4()",
|
|
821
911
|
ipv6: () => "z.ipv6()",
|
|
@@ -837,44 +927,46 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
837
927
|
return resolvedName;
|
|
838
928
|
},
|
|
839
929
|
object(node) {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
const
|
|
843
|
-
const isNullable = meta.nullable;
|
|
844
|
-
const isOptional = schema.optional;
|
|
845
|
-
const isNullish = schema.nullish;
|
|
846
|
-
const hasSelfRef = this.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
|
|
930
|
+
const isCyclic = (schema) => this.options.cyclicSchemas != null && containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
|
|
931
|
+
return `z.object(${buildObject(mapSchemaProperties(node, (schema) => {
|
|
932
|
+
const hasSelfRef = isCyclic(schema);
|
|
847
933
|
const savedCyclicSchemas = this.options.cyclicSchemas;
|
|
848
934
|
if (hasSelfRef) this.options.cyclicSchemas = void 0;
|
|
849
|
-
const baseOutput = this.transform(schema) ?? this.transform(ast.createSchema({ type: "unknown" }));
|
|
935
|
+
const baseOutput = this.transform(schema) ?? this.transform(ast.factory.createSchema({ type: "unknown" }));
|
|
850
936
|
if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas;
|
|
937
|
+
return baseOutput;
|
|
938
|
+
}).map(({ name: propName, property, output: baseOutput }) => {
|
|
939
|
+
const { schema } = property;
|
|
940
|
+
const meta = syncSchemaRef(schema);
|
|
851
941
|
const value = applyMiniModifiers({
|
|
852
942
|
value: this.options.wrapOutput ? this.options.wrapOutput({
|
|
853
943
|
output: baseOutput,
|
|
854
944
|
schema
|
|
855
945
|
}) || baseOutput : baseOutput,
|
|
856
|
-
nullable:
|
|
857
|
-
optional:
|
|
858
|
-
nullish:
|
|
946
|
+
nullable: meta.nullable,
|
|
947
|
+
optional: schema.optional || property.required === false,
|
|
948
|
+
nullish: schema.nullish,
|
|
859
949
|
defaultValue: meta.default
|
|
860
950
|
});
|
|
861
|
-
|
|
862
|
-
|
|
951
|
+
return isCyclic(schema) ? lazyGetter({
|
|
952
|
+
name: propName,
|
|
953
|
+
body: value
|
|
954
|
+
}) : `${objectKey(propName)}: ${value}`;
|
|
863
955
|
}))})`;
|
|
864
956
|
},
|
|
865
957
|
array(node) {
|
|
866
|
-
const base = `z.array(${(node
|
|
958
|
+
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(ast.factory.createSchema({ type: "unknown" }))})${lengthChecksMini({
|
|
959
|
+
...node,
|
|
960
|
+
regexType: this.options.regexType
|
|
961
|
+
})}`;
|
|
867
962
|
return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
|
|
868
963
|
},
|
|
869
964
|
tuple(node) {
|
|
870
|
-
return `z.tuple(${buildList((node
|
|
965
|
+
return `z.tuple(${buildList(mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
|
|
871
966
|
},
|
|
872
967
|
union(node) {
|
|
873
968
|
const nodeMembers = node.members ?? [];
|
|
874
|
-
const members =
|
|
875
|
-
const member = this.transform(memberNode);
|
|
876
|
-
return member && node.strategy === "one" ? strictOneOfMember(member, memberNode) : member;
|
|
877
|
-
}).filter(Boolean);
|
|
969
|
+
const members = mapSchemaMembers(node, (memberNode) => this.transform(memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember(output, schema) : output).filter(Boolean);
|
|
878
970
|
if (members.length === 0) return "";
|
|
879
971
|
if (members.length === 1) return members[0];
|
|
880
972
|
if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
|
|
@@ -888,7 +980,10 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
888
980
|
const firstBase = this.transform(first);
|
|
889
981
|
if (!firstBase) return "";
|
|
890
982
|
return rest.reduce((acc, member) => {
|
|
891
|
-
const constraint = getMemberConstraintMini(
|
|
983
|
+
const constraint = getMemberConstraintMini({
|
|
984
|
+
member,
|
|
985
|
+
regexType: this.options.regexType
|
|
986
|
+
});
|
|
892
987
|
if (constraint) return acc + constraint;
|
|
893
988
|
const transformed = this.transform(member);
|
|
894
989
|
return transformed ? `z.intersection(${acc}, ${transformed})` : acc;
|
|
@@ -900,7 +995,7 @@ const printerZodMini = ast.definePrinter((options) => {
|
|
|
900
995
|
const { keysToOmit } = this.options;
|
|
901
996
|
const transformed = this.transform(node);
|
|
902
997
|
if (!transformed) return null;
|
|
903
|
-
const meta =
|
|
998
|
+
const meta = syncSchemaRef(node);
|
|
904
999
|
return applyMiniModifiers({
|
|
905
1000
|
value: (() => {
|
|
906
1001
|
if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
|
|
@@ -927,7 +1022,7 @@ const zodMiniPrinterCache = /* @__PURE__ */ new WeakMap();
|
|
|
927
1022
|
*/
|
|
928
1023
|
function getStdPrinters(resolver, params) {
|
|
929
1024
|
const cached = zodPrinterCache.get(resolver);
|
|
930
|
-
if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.dateType === params.dateType) return {
|
|
1025
|
+
if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.regexType === params.regexType && cached.dateType === params.dateType) return {
|
|
931
1026
|
output: cached.output,
|
|
932
1027
|
input: cached.input
|
|
933
1028
|
};
|
|
@@ -948,6 +1043,7 @@ function getStdPrinters(resolver, params) {
|
|
|
948
1043
|
input,
|
|
949
1044
|
coercion: params.coercion,
|
|
950
1045
|
guidType: params.guidType,
|
|
1046
|
+
regexType: params.regexType,
|
|
951
1047
|
dateType: params.dateType
|
|
952
1048
|
});
|
|
953
1049
|
return {
|
|
@@ -957,14 +1053,15 @@ function getStdPrinters(resolver, params) {
|
|
|
957
1053
|
}
|
|
958
1054
|
function getMiniPrinter(resolver, params) {
|
|
959
1055
|
const cached = zodMiniPrinterCache.get(resolver);
|
|
960
|
-
if (cached && cached.guidType === params.guidType) return cached.printer;
|
|
1056
|
+
if (cached && cached.guidType === params.guidType && cached.regexType === params.regexType) return cached.printer;
|
|
961
1057
|
const p = printerZodMini({
|
|
962
1058
|
...params,
|
|
963
1059
|
resolver
|
|
964
1060
|
});
|
|
965
1061
|
zodMiniPrinterCache.set(resolver, {
|
|
966
1062
|
printer: p,
|
|
967
|
-
guidType: params.guidType
|
|
1063
|
+
guidType: params.guidType,
|
|
1064
|
+
regexType: params.regexType
|
|
968
1065
|
});
|
|
969
1066
|
return p;
|
|
970
1067
|
}
|
|
@@ -979,13 +1076,13 @@ const zodGenerator = defineGenerator({
|
|
|
979
1076
|
renderer: jsxRenderer,
|
|
980
1077
|
schema(node, ctx) {
|
|
981
1078
|
const { adapter, config, resolver, root } = ctx;
|
|
982
|
-
const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
|
|
1079
|
+
const { output, coercion, guidType, regexType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
|
|
983
1080
|
const dateType = adapter.options.dateType;
|
|
984
1081
|
if (!node.name) return;
|
|
985
1082
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
986
1083
|
const cyclicSchemas = new Set(ctx.meta.circularNames);
|
|
987
1084
|
const hasCodec = !mini && containsCodec(node);
|
|
988
|
-
const codecRefNames = new Set(hasCodec ?
|
|
1085
|
+
const codecRefNames = new Set(hasCodec ? collectCodecRefNames(node) : []);
|
|
989
1086
|
const importEntries = adapter.getImports(node, (schemaName) => ({
|
|
990
1087
|
name: resolver.resolveSchemaName(schemaName),
|
|
991
1088
|
path: resolver.resolveFile({
|
|
@@ -1030,6 +1127,7 @@ const zodGenerator = defineGenerator({
|
|
|
1030
1127
|
const stdPrinters = mini ? null : getStdPrinters(resolver, {
|
|
1031
1128
|
coercion,
|
|
1032
1129
|
guidType,
|
|
1130
|
+
regexType,
|
|
1033
1131
|
dateType,
|
|
1034
1132
|
wrapOutput,
|
|
1035
1133
|
cyclicSchemas,
|
|
@@ -1037,6 +1135,7 @@ const zodGenerator = defineGenerator({
|
|
|
1037
1135
|
});
|
|
1038
1136
|
const schemaPrinter = mini ? getMiniPrinter(resolver, {
|
|
1039
1137
|
guidType,
|
|
1138
|
+
regexType,
|
|
1040
1139
|
wrapOutput,
|
|
1041
1140
|
cyclicSchemas,
|
|
1042
1141
|
nodes: printer?.nodes
|
|
@@ -1094,10 +1193,10 @@ const zodGenerator = defineGenerator({
|
|
|
1094
1193
|
operation(node, ctx) {
|
|
1095
1194
|
if (!ast.isHttpOperationNode(node)) return null;
|
|
1096
1195
|
const { adapter, config, resolver, root } = ctx;
|
|
1097
|
-
const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group,
|
|
1196
|
+
const { output, coercion, guidType, regexType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
|
|
1098
1197
|
const dateType = adapter.options.dateType;
|
|
1099
1198
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
1100
|
-
const params =
|
|
1199
|
+
const params = caseParams(node.parameters, "camelcase");
|
|
1101
1200
|
const meta = { file: resolver.resolveFile({
|
|
1102
1201
|
name: node.operationId,
|
|
1103
1202
|
extname: ".ts",
|
|
@@ -1112,7 +1211,7 @@ const zodGenerator = defineGenerator({
|
|
|
1112
1211
|
function renderSchemaEntry({ schema, name, keysToOmit, direction = "output" }) {
|
|
1113
1212
|
if (!schema) return null;
|
|
1114
1213
|
const inferTypeName = inferred ? resolver.resolveTypeName(name) : null;
|
|
1115
|
-
const codecRefNames = direction === "input" && !mini ? new Set(
|
|
1214
|
+
const codecRefNames = direction === "input" && !mini ? new Set(collectCodecRefNames(schema)) : null;
|
|
1116
1215
|
const imports = adapter.getImports(schema, (schemaName) => ({
|
|
1117
1216
|
name: codecRefNames?.has(schemaName) ? resolver.resolveInputSchemaName(schemaName) : resolver.resolveSchemaName(schemaName),
|
|
1118
1217
|
path: resolver.resolveFile({
|
|
@@ -1126,6 +1225,7 @@ const zodGenerator = defineGenerator({
|
|
|
1126
1225
|
}));
|
|
1127
1226
|
const schemaPrinter = mini ? keysToOmit?.length ? printerZodMini({
|
|
1128
1227
|
guidType,
|
|
1228
|
+
regexType,
|
|
1129
1229
|
wrapOutput,
|
|
1130
1230
|
resolver,
|
|
1131
1231
|
keysToOmit,
|
|
@@ -1133,12 +1233,14 @@ const zodGenerator = defineGenerator({
|
|
|
1133
1233
|
nodes: printer?.nodes
|
|
1134
1234
|
}) : getMiniPrinter(resolver, {
|
|
1135
1235
|
guidType,
|
|
1236
|
+
regexType,
|
|
1136
1237
|
wrapOutput,
|
|
1137
1238
|
cyclicSchemas,
|
|
1138
1239
|
nodes: printer?.nodes
|
|
1139
1240
|
}) : keysToOmit?.length ? printerZod({
|
|
1140
1241
|
coercion,
|
|
1141
1242
|
guidType,
|
|
1243
|
+
regexType,
|
|
1142
1244
|
dateType,
|
|
1143
1245
|
wrapOutput,
|
|
1144
1246
|
resolver,
|
|
@@ -1149,6 +1251,7 @@ const zodGenerator = defineGenerator({
|
|
|
1149
1251
|
}) : getStdPrinters(resolver, {
|
|
1150
1252
|
coercion,
|
|
1151
1253
|
guidType,
|
|
1254
|
+
regexType,
|
|
1152
1255
|
dateType,
|
|
1153
1256
|
wrapOutput,
|
|
1154
1257
|
cyclicSchemas,
|
|
@@ -1171,9 +1274,9 @@ const zodGenerator = defineGenerator({
|
|
|
1171
1274
|
}
|
|
1172
1275
|
function buildContentTypeVariants(entries, baseName, decorate, direction) {
|
|
1173
1276
|
const variants = resolveContentTypeVariants(entries, baseName);
|
|
1174
|
-
const unionSchema = ast.createSchema({
|
|
1277
|
+
const unionSchema = ast.factory.createSchema({
|
|
1175
1278
|
type: "union",
|
|
1176
|
-
members: variants.map((variant) => ast.createSchema({
|
|
1279
|
+
members: variants.map((variant) => ast.factory.createSchema({
|
|
1177
1280
|
type: "ref",
|
|
1178
1281
|
name: variant.name
|
|
1179
1282
|
}))
|
|
@@ -1205,18 +1308,23 @@ const zodGenerator = defineGenerator({
|
|
|
1205
1308
|
});
|
|
1206
1309
|
});
|
|
1207
1310
|
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
|
|
1311
|
+
const successResponsesWithSchema = getSuccessResponses(responsesWithSchema);
|
|
1208
1312
|
const responseUnionSchema = responsesWithSchema.length > 0 ? (() => {
|
|
1209
1313
|
const responseUnionName = resolver.resolveResponseName(node);
|
|
1210
|
-
if (new Set(
|
|
1314
|
+
if (new Set(successResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
|
|
1211
1315
|
name: resolver.resolveSchemaName(schemaName),
|
|
1212
1316
|
path: ""
|
|
1213
1317
|
})).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(responseUnionName)) return null;
|
|
1214
|
-
const members =
|
|
1318
|
+
const members = successResponsesWithSchema.map((res) => ast.factory.createSchema({
|
|
1215
1319
|
type: "ref",
|
|
1216
1320
|
name: resolver.resolveResponseStatusName(node, res.statusCode)
|
|
1217
1321
|
}));
|
|
1322
|
+
if (members.length === 0) return renderSchemaEntry({
|
|
1323
|
+
schema: ast.factory.createSchema({ type: "unknown" }),
|
|
1324
|
+
name: responseUnionName
|
|
1325
|
+
});
|
|
1218
1326
|
return renderSchemaEntry({
|
|
1219
|
-
schema: members.length === 1 ? members[0] : ast.createSchema({
|
|
1327
|
+
schema: members.length === 1 ? members[0] : ast.factory.createSchema({
|
|
1220
1328
|
type: "union",
|
|
1221
1329
|
members
|
|
1222
1330
|
}),
|
|
@@ -1279,7 +1387,7 @@ const zodGenerator = defineGenerator({
|
|
|
1279
1387
|
},
|
|
1280
1388
|
operations(nodes, ctx) {
|
|
1281
1389
|
const { config, resolver, root } = ctx;
|
|
1282
|
-
const { output, importPath, group, operations
|
|
1390
|
+
const { output, importPath, group, operations } = ctx.options;
|
|
1283
1391
|
if (!operations) return;
|
|
1284
1392
|
const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
|
|
1285
1393
|
const meta = { file: resolver.resolveFile({
|
|
@@ -1294,7 +1402,7 @@ const zodGenerator = defineGenerator({
|
|
|
1294
1402
|
return {
|
|
1295
1403
|
node,
|
|
1296
1404
|
data: buildSchemaNames(node, {
|
|
1297
|
-
params:
|
|
1405
|
+
params: caseParams(node.parameters, "camelcase"),
|
|
1298
1406
|
resolver
|
|
1299
1407
|
})
|
|
1300
1408
|
};
|
|
@@ -1436,8 +1544,9 @@ const pluginZodName = "plugin-zod";
|
|
|
1436
1544
|
/**
|
|
1437
1545
|
* Generates Zod v4 schemas from an OpenAPI spec. Use them to validate API
|
|
1438
1546
|
* responses at runtime, build form schemas, or feed back into router libraries
|
|
1439
|
-
* that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-
|
|
1440
|
-
* set the client's `parser: 'zod'` to validate every response
|
|
1547
|
+
* that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-axios` or
|
|
1548
|
+
* `@kubb/plugin-fetch` and set the client's `parser: 'zod'` to validate every response
|
|
1549
|
+
* automatically.
|
|
1441
1550
|
*
|
|
1442
1551
|
* @example
|
|
1443
1552
|
* ```ts
|
|
@@ -1462,7 +1571,7 @@ const pluginZod = definePlugin((options) => {
|
|
|
1462
1571
|
const { output = {
|
|
1463
1572
|
path: "zod",
|
|
1464
1573
|
barrel: { type: "named" }
|
|
1465
|
-
}, group, exclude = [], include, override = [], typed = false, operations = false, mini = false, guidType = "uuid", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, wrapOutput = void 0,
|
|
1574
|
+
}, group, exclude = [], include, override = [], typed = false, operations = false, mini = false, guidType = "uuid", regexType = "literal", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, wrapOutput = void 0, printer, resolver: userResolver, macros: userMacros } = options;
|
|
1466
1575
|
const groupConfig = createGroupConfig(group);
|
|
1467
1576
|
return {
|
|
1468
1577
|
name: pluginZodName,
|
|
@@ -1480,18 +1589,17 @@ const pluginZod = definePlugin((options) => {
|
|
|
1480
1589
|
operations,
|
|
1481
1590
|
inferred,
|
|
1482
1591
|
guidType,
|
|
1592
|
+
regexType,
|
|
1483
1593
|
mini,
|
|
1484
1594
|
wrapOutput,
|
|
1485
|
-
paramsCasing,
|
|
1486
1595
|
printer
|
|
1487
1596
|
});
|
|
1488
1597
|
ctx.setResolver(userResolver ? {
|
|
1489
1598
|
...resolverZod,
|
|
1490
1599
|
...userResolver
|
|
1491
1600
|
} : resolverZod);
|
|
1492
|
-
if (
|
|
1601
|
+
if (userMacros?.length) ctx.setMacros(userMacros);
|
|
1493
1602
|
ctx.addGenerator(zodGenerator);
|
|
1494
|
-
for (const gen of userGenerators) ctx.addGenerator(gen);
|
|
1495
1603
|
} }
|
|
1496
1604
|
};
|
|
1497
1605
|
});
|