@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/dist/index.cjs CHANGED
@@ -10,8 +10,8 @@ var __name = (target, value) => __defProp(target, "name", {
10
10
  });
11
11
  //#endregion
12
12
  let _kubb_core = require("@kubb/core");
13
- let _kubb_ast_utils = require("@kubb/ast/utils");
14
13
  let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
14
+ let _kubb_ast_utils = require("@kubb/ast/utils");
15
15
  let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
16
16
  //#region ../../internals/utils/src/casing.ts
17
17
  /**
@@ -200,6 +200,27 @@ function ensureValidVarName(name) {
200
200
  return `_${name}`;
201
201
  }
202
202
  //#endregion
203
+ //#region ../../internals/shared/src/params.ts
204
+ const caseParamsCache = /* @__PURE__ */ new WeakMap();
205
+ /**
206
+ * Applies camelCase to parameter names and returns a new array without mutating the input.
207
+ *
208
+ * Run it before handing parameters to schema builders so output property keys get the right casing
209
+ * while `OperationNode.parameters` stays intact for other consumers. When `casing` is unset, the
210
+ * original array is returned unchanged. Results are cached per input array.
211
+ */
212
+ function caseParams(params, casing) {
213
+ if (!casing) return params;
214
+ const cached = caseParamsCache.get(params);
215
+ if (cached) return cached;
216
+ const result = params.map((param) => ({
217
+ ...param,
218
+ name: camelCase(param.name)
219
+ }));
220
+ caseParamsCache.set(params, result);
221
+ return result;
222
+ }
223
+ //#endregion
203
224
  //#region ../../internals/shared/src/operation.ts
204
225
  /**
205
226
  * Maps a content type to the PascalCase suffix used to name per-content-type variants
@@ -249,6 +270,17 @@ function resolveContentTypeVariants(entries, baseName) {
249
270
  };
250
271
  });
251
272
  }
273
+ function getStatusCodeNumber(statusCode) {
274
+ const code = Number(statusCode);
275
+ return Number.isNaN(code) ? null : code;
276
+ }
277
+ function isSuccessStatusCode(statusCode) {
278
+ const code = getStatusCodeNumber(statusCode);
279
+ return code !== null && code >= 200 && code < 300;
280
+ }
281
+ function getSuccessResponses(responses) {
282
+ return responses.filter((response) => isSuccessStatusCode(response.statusCode));
283
+ }
252
284
  //#endregion
253
285
  //#region ../../internals/shared/src/group.ts
254
286
  /**
@@ -441,7 +473,7 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
441
473
  if (seen.has(refName)) return false;
442
474
  seen.add(refName);
443
475
  }
444
- const resolved = _kubb_core.ast.syncSchemaRef(node);
476
+ const resolved = (0, _kubb_ast_utils.syncSchemaRef)(node);
445
477
  if (resolved.type === "ref") return false;
446
478
  return containsCodec(resolved, seen);
447
479
  }
@@ -453,6 +485,13 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
453
485
  return children.some((child) => containsCodec(child, seen));
454
486
  }
455
487
  /**
488
+ * Collects the names of `$ref` schemas that transitively contain a codec, so the generator can route
489
+ * them to their input (encode) variant.
490
+ */
491
+ function collectCodecRefNames(node) {
492
+ return _kubb_core.ast.collect(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? (0, _kubb_ast_utils.extractRefName)(n.ref) ?? void 0 : void 0 });
493
+ }
494
+ /**
456
495
  * Collects all resolved schema names for an operation's parameters and responses
457
496
  * into a single lookup object, useful for building imports and type references.
458
497
  */
@@ -500,6 +539,13 @@ function formatLiteral(v) {
500
539
  return String(v);
501
540
  }
502
541
  /**
542
+ * Map a `regexType` to the `func` argument of `toRegExpString`: `'constructor'` emits
543
+ * `new RegExp(...)`, while `'literal'` (the default) emits a regex literal.
544
+ */
545
+ function regexFunc(regexType) {
546
+ return regexType === "constructor" ? "RegExp" : null;
547
+ }
548
+ /**
503
549
  * Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
504
550
  * using the standard chainable Zod v4 API.
505
551
  */
@@ -516,11 +562,11 @@ function numberConstraints({ min, max, exclusiveMinimum, exclusiveMaximum, multi
516
562
  * Build `.min()` / `.max()` / `.regex()` chains for strings/arrays
517
563
  * using the standard chainable Zod v4 API.
518
564
  */
519
- function lengthConstraints({ min, max, pattern }) {
565
+ function lengthConstraints({ min, max, pattern, regexType }) {
520
566
  return [
521
567
  min !== void 0 ? `.min(${min})` : "",
522
568
  max !== void 0 ? `.max(${max})` : "",
523
- pattern !== void 0 ? `.regex(${(0, _kubb_ast_utils.toRegExpString)(pattern, null)})` : ""
569
+ pattern !== void 0 ? `.regex(${(0, _kubb_ast_utils.toRegExpString)(pattern, regexFunc(regexType))})` : ""
524
570
  ].join("");
525
571
  }
526
572
  /**
@@ -538,18 +584,18 @@ function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multip
538
584
  /**
539
585
  * Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
540
586
  */
541
- function lengthChecksMini({ min, max, pattern }) {
587
+ function lengthChecksMini({ min, max, pattern, regexType }) {
542
588
  const checks = [];
543
589
  if (min !== void 0) checks.push(`z.minLength(${min})`);
544
590
  if (max !== void 0) checks.push(`z.maxLength(${max})`);
545
- if (pattern !== void 0) checks.push(`z.regex(${(0, _kubb_ast_utils.toRegExpString)(pattern, null)})`);
591
+ if (pattern !== void 0) checks.push(`z.regex(${(0, _kubb_ast_utils.toRegExpString)(pattern, regexFunc(regexType))})`);
546
592
  return checks.length ? `.check(${checks.join(", ")})` : "";
547
593
  }
548
594
  /**
549
- * Apply nullable / optional / nullish modifiers and an optional `.describe()` call
550
- * to a schema value string using the chainable Zod v4 API.
595
+ * Apply nullable / optional / nullish modifiers, an optional `.describe()` call, and an
596
+ * optional `.meta({ examples })` call to a schema value string using the chainable Zod v4 API.
551
597
  */
552
- function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }) {
598
+ function applyModifiers({ value, nullable, optional, nullish, defaultValue, description, examples }) {
553
599
  const withModifier = (() => {
554
600
  if (nullish || nullable && optional) return `${value}.nullish()`;
555
601
  if (optional) return `${value}.optional()`;
@@ -557,7 +603,8 @@ function applyModifiers({ value, nullable, optional, nullish, defaultValue, desc
557
603
  return value;
558
604
  })();
559
605
  const withDefault = defaultValue !== void 0 ? `${withModifier}.default(${formatDefault(defaultValue)})` : withModifier;
560
- return description ? `${withDefault}.describe(${(0, _kubb_ast_utils.stringify)(description)})` : withDefault;
606
+ const withDescription = description ? `${withDefault}.describe(${(0, _kubb_ast_utils.stringify)(description)})` : withDefault;
607
+ return examples?.length ? `${withDescription}.meta({ examples: [${examples.map(formatDefault).join(", ")}] })` : withDescription;
561
608
  }
562
609
  /**
563
610
  * Apply nullable / optional / nullish modifiers using the functional `zod/mini` API
@@ -577,16 +624,22 @@ function strictOneOfMember$1(member, node) {
577
624
  if (node.type === "object" && node.additionalProperties === void 0) return `${member}.strict()`;
578
625
  if (node.type === "ref") {
579
626
  if (member.startsWith("z.lazy(")) return member;
580
- const schema = _kubb_core.ast.syncSchemaRef(node);
627
+ const schema = (0, _kubb_ast_utils.syncSchemaRef)(node);
581
628
  if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
582
629
  }
583
630
  return member;
584
631
  }
585
632
  __name(strictOneOfMember$1, "strictOneOfMember");
586
- function getMemberConstraint(member) {
587
- if (member.primitive === "string") return lengthConstraints(_kubb_core.ast.narrowSchema(member, "string") ?? {}) || void 0;
633
+ function getMemberConstraint({ member, regexType }) {
634
+ if (member.primitive === "string") return lengthConstraints({
635
+ ..._kubb_core.ast.narrowSchema(member, "string") ?? {},
636
+ regexType
637
+ }) || void 0;
588
638
  if (member.primitive === "number" || member.primitive === "integer") return numberConstraints(_kubb_core.ast.narrowSchema(member, "number") ?? _kubb_core.ast.narrowSchema(member, "integer") ?? {}) || void 0;
589
- if (member.primitive === "array") return lengthConstraints(_kubb_core.ast.narrowSchema(member, "array") ?? {}) || void 0;
639
+ if (member.primitive === "array") return lengthConstraints({
640
+ ..._kubb_core.ast.narrowSchema(member, "array") ?? {},
641
+ regexType
642
+ }) || void 0;
590
643
  }
591
644
  /**
592
645
  * Zod v4 printer built with `definePrinter`.
@@ -600,7 +653,7 @@ function getMemberConstraint(member) {
600
653
  * const code = printer.print(stringNode) // "z.string()"
601
654
  * ```
602
655
  */
603
- const printerZod = _kubb_core.ast.definePrinter((options) => {
656
+ const printerZod = _kubb_core.ast.createPrinter((options) => {
604
657
  return {
605
658
  name: "zod",
606
659
  options,
@@ -612,7 +665,10 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
612
665
  boolean: () => "z.boolean()",
613
666
  null: () => "z.null()",
614
667
  string(node) {
615
- return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints(node)}`;
668
+ return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints({
669
+ ...node,
670
+ regexType: this.options.regexType
671
+ })}`;
616
672
  },
617
673
  number(node) {
618
674
  return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number()" : "z.number()"}${numberConstraints(node)}`;
@@ -640,13 +696,22 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
640
696
  return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
641
697
  },
642
698
  uuid(node) {
643
- return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints(node)}`;
699
+ return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints({
700
+ ...node,
701
+ regexType: this.options.regexType
702
+ })}`;
644
703
  },
645
704
  email(node) {
646
- return `z.email()${lengthConstraints(node)}`;
705
+ return `z.email()${lengthConstraints({
706
+ ...node,
707
+ regexType: this.options.regexType
708
+ })}`;
647
709
  },
648
710
  url(node) {
649
- return `z.url()${lengthConstraints(node)}`;
711
+ return `z.url()${lengthConstraints({
712
+ ...node,
713
+ regexType: this.options.regexType
714
+ })}`;
650
715
  },
651
716
  ipv4: () => "z.ipv4()",
652
717
  ipv6: () => "z.ipv6()",
@@ -669,17 +734,17 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
669
734
  return resolvedName;
670
735
  },
671
736
  object(node) {
672
- const objectBase = `z.object(${(0, _kubb_ast_utils.buildObject)(node.properties.map((prop) => {
673
- const { name: propName, schema } = prop;
674
- const meta = _kubb_core.ast.syncSchemaRef(schema);
675
- const isNullable = meta.nullable;
676
- const isOptional = schema.optional;
677
- const isNullish = schema.nullish;
678
- const hasSelfRef = this.options.cyclicSchemas != null && _kubb_core.ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
737
+ const isCyclic = (schema) => this.options.cyclicSchemas != null && (0, _kubb_ast_utils.containsCircularRef)(schema, { circularSchemas: this.options.cyclicSchemas });
738
+ const objectBase = `z.object(${(0, _kubb_ast_utils.buildObject)((0, _kubb_ast_utils.mapSchemaProperties)(node, (schema) => {
739
+ const hasSelfRef = isCyclic(schema);
679
740
  const savedCyclicSchemas = this.options.cyclicSchemas;
680
741
  if (hasSelfRef) this.options.cyclicSchemas = void 0;
681
- const baseOutput = this.transform(schema) ?? this.transform(_kubb_core.ast.createSchema({ type: "unknown" }));
742
+ const baseOutput = this.transform(schema) ?? this.transform(_kubb_core.ast.factory.createSchema({ type: "unknown" }));
682
743
  if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas;
744
+ return baseOutput;
745
+ }).map(({ name: propName, property, output: baseOutput }) => {
746
+ const { schema } = property;
747
+ const meta = (0, _kubb_ast_utils.syncSchemaRef)(schema);
683
748
  const wrappedOutput = this.options.wrapOutput ? this.options.wrapOutput({
684
749
  output: baseOutput,
685
750
  schema
@@ -687,38 +752,41 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
687
752
  const descriptionToApply = schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description;
688
753
  const value = applyModifiers({
689
754
  value: wrappedOutput,
690
- nullable: isNullable,
691
- optional: isOptional,
692
- nullish: isNullish,
755
+ nullable: meta.nullable,
756
+ optional: schema.optional || property.required === false,
757
+ nullish: schema.nullish,
693
758
  defaultValue: meta.default,
694
- description: descriptionToApply
759
+ description: descriptionToApply,
760
+ examples: meta.examples
695
761
  });
696
- if (hasSelfRef) return `get ${(0, _kubb_ast_utils.objectKey)(propName)}() { return ${value} }`;
697
- return `${(0, _kubb_ast_utils.objectKey)(propName)}: ${value}`;
762
+ return isCyclic(schema) ? (0, _kubb_ast_utils.lazyGetter)({
763
+ name: propName,
764
+ body: value
765
+ }) : `${(0, _kubb_ast_utils.objectKey)(propName)}: ${value}`;
698
766
  }))})`;
699
767
  return (() => {
700
768
  if (node.additionalProperties && node.additionalProperties !== true) {
701
769
  const catchallType = this.transform(node.additionalProperties);
702
770
  return catchallType ? `${objectBase}.catchall(${catchallType})` : objectBase;
703
771
  }
704
- if (node.additionalProperties === true) return `${objectBase}.catchall(${this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})`;
772
+ if (node.additionalProperties === true) return `${objectBase}.catchall(${this.transform(_kubb_core.ast.factory.createSchema({ type: "unknown" }))})`;
705
773
  if (node.additionalProperties === false) return `${objectBase}.strict()`;
706
774
  return objectBase;
707
775
  })();
708
776
  },
709
777
  array(node) {
710
- const base = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})${lengthConstraints(node)}`;
778
+ const base = `z.array(${(0, _kubb_ast_utils.mapSchemaItems)(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.factory.createSchema({ type: "unknown" }))})${lengthConstraints({
779
+ ...node,
780
+ regexType: this.options.regexType
781
+ })}`;
711
782
  return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
712
783
  },
713
784
  tuple(node) {
714
- return `z.tuple(${(0, _kubb_ast_utils.buildList)((node.items ?? []).map((item) => this.transform(item)).filter(Boolean))})`;
785
+ return `z.tuple(${(0, _kubb_ast_utils.buildList)((0, _kubb_ast_utils.mapSchemaItems)(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
715
786
  },
716
787
  union(node) {
717
788
  const nodeMembers = node.members ?? [];
718
- const members = nodeMembers.map((memberNode) => {
719
- const member = this.transform(memberNode);
720
- return member && node.strategy === "one" ? strictOneOfMember$1(member, memberNode) : member;
721
- }).filter(Boolean);
789
+ const members = (0, _kubb_ast_utils.mapSchemaMembers)(node, (memberNode) => this.transform(memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember$1(output, schema) : output).filter(Boolean);
722
790
  if (members.length === 0) return "";
723
791
  if (members.length === 1) return members[0];
724
792
  if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${(0, _kubb_ast_utils.stringify)(node.discriminatorPropertyName)}, ${(0, _kubb_ast_utils.buildList)(members)})`;
@@ -732,7 +800,10 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
732
800
  const firstBase = this.transform(first);
733
801
  if (!firstBase) return "";
734
802
  return rest.reduce((acc, member) => {
735
- const constraint = getMemberConstraint(member);
803
+ const constraint = getMemberConstraint({
804
+ member,
805
+ regexType: this.options.regexType
806
+ });
736
807
  if (constraint) return acc + constraint;
737
808
  const transformed = this.transform(member);
738
809
  return transformed ? `${acc}.and(${transformed})` : acc;
@@ -744,7 +815,7 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
744
815
  const { keysToOmit } = this.options;
745
816
  const transformed = this.transform(node);
746
817
  if (!transformed) return null;
747
- const meta = _kubb_core.ast.syncSchemaRef(node);
818
+ const meta = (0, _kubb_ast_utils.syncSchemaRef)(node);
748
819
  return applyModifiers({
749
820
  value: (() => {
750
821
  if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
@@ -756,7 +827,8 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
756
827
  optional: meta.optional,
757
828
  nullish: meta.nullish,
758
829
  defaultValue: meta.default,
759
- description: meta.description
830
+ description: meta.description,
831
+ examples: meta.examples
760
832
  });
761
833
  }
762
834
  };
@@ -767,10 +839,16 @@ function strictOneOfMember(member, node) {
767
839
  if (node.type === "object" && (node.additionalProperties === void 0 || node.additionalProperties === false)) return member.replace(/^z\.object\(/, "z.strictObject(");
768
840
  return member;
769
841
  }
770
- function getMemberConstraintMini(member) {
771
- if (member.primitive === "string") return lengthChecksMini(_kubb_core.ast.narrowSchema(member, "string") ?? {}) || void 0;
842
+ function getMemberConstraintMini({ member, regexType }) {
843
+ if (member.primitive === "string") return lengthChecksMini({
844
+ ..._kubb_core.ast.narrowSchema(member, "string") ?? {},
845
+ regexType
846
+ }) || void 0;
772
847
  if (member.primitive === "number" || member.primitive === "integer") return numberChecksMini(_kubb_core.ast.narrowSchema(member, "number") ?? _kubb_core.ast.narrowSchema(member, "integer") ?? {}) || void 0;
773
- if (member.primitive === "array") return lengthChecksMini(_kubb_core.ast.narrowSchema(member, "array") ?? {}) || void 0;
848
+ if (member.primitive === "array") return lengthChecksMini({
849
+ ..._kubb_core.ast.narrowSchema(member, "array") ?? {},
850
+ regexType
851
+ }) || void 0;
774
852
  }
775
853
  /**
776
854
  * Zod v4 **Mini** printer built with `definePrinter`.
@@ -784,7 +862,7 @@ function getMemberConstraintMini(member) {
784
862
  * const code = printer.print(optionalStringNode) // "z.optional(z.string())"
785
863
  * ```
786
864
  */
787
- const printerZodMini = _kubb_core.ast.definePrinter((options) => {
865
+ const printerZodMini = _kubb_core.ast.createPrinter((options) => {
788
866
  return {
789
867
  name: "zod-mini",
790
868
  options,
@@ -796,7 +874,10 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
796
874
  boolean: () => "z.boolean()",
797
875
  null: () => "z.null()",
798
876
  string(node) {
799
- return `z.string()${lengthChecksMini(node)}`;
877
+ return `z.string()${lengthChecksMini({
878
+ ...node,
879
+ regexType: this.options.regexType
880
+ })}`;
800
881
  },
801
882
  number(node) {
802
883
  return `z.number()${numberChecksMini(node)}`;
@@ -819,13 +900,22 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
819
900
  return "z.date()";
820
901
  },
821
902
  uuid(node) {
822
- return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthChecksMini(node)}`;
903
+ return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthChecksMini({
904
+ ...node,
905
+ regexType: this.options.regexType
906
+ })}`;
823
907
  },
824
908
  email(node) {
825
- return `z.email()${lengthChecksMini(node)}`;
909
+ return `z.email()${lengthChecksMini({
910
+ ...node,
911
+ regexType: this.options.regexType
912
+ })}`;
826
913
  },
827
914
  url(node) {
828
- return `z.url()${lengthChecksMini(node)}`;
915
+ return `z.url()${lengthChecksMini({
916
+ ...node,
917
+ regexType: this.options.regexType
918
+ })}`;
829
919
  },
830
920
  ipv4: () => "z.ipv4()",
831
921
  ipv6: () => "z.ipv6()",
@@ -847,44 +937,46 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
847
937
  return resolvedName;
848
938
  },
849
939
  object(node) {
850
- return `z.object(${(0, _kubb_ast_utils.buildObject)(node.properties.map((prop) => {
851
- const { name: propName, schema } = prop;
852
- const meta = _kubb_core.ast.syncSchemaRef(schema);
853
- const isNullable = meta.nullable;
854
- const isOptional = schema.optional;
855
- const isNullish = schema.nullish;
856
- const hasSelfRef = this.options.cyclicSchemas != null && _kubb_core.ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
940
+ const isCyclic = (schema) => this.options.cyclicSchemas != null && (0, _kubb_ast_utils.containsCircularRef)(schema, { circularSchemas: this.options.cyclicSchemas });
941
+ return `z.object(${(0, _kubb_ast_utils.buildObject)((0, _kubb_ast_utils.mapSchemaProperties)(node, (schema) => {
942
+ const hasSelfRef = isCyclic(schema);
857
943
  const savedCyclicSchemas = this.options.cyclicSchemas;
858
944
  if (hasSelfRef) this.options.cyclicSchemas = void 0;
859
- const baseOutput = this.transform(schema) ?? this.transform(_kubb_core.ast.createSchema({ type: "unknown" }));
945
+ const baseOutput = this.transform(schema) ?? this.transform(_kubb_core.ast.factory.createSchema({ type: "unknown" }));
860
946
  if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas;
947
+ return baseOutput;
948
+ }).map(({ name: propName, property, output: baseOutput }) => {
949
+ const { schema } = property;
950
+ const meta = (0, _kubb_ast_utils.syncSchemaRef)(schema);
861
951
  const value = applyMiniModifiers({
862
952
  value: this.options.wrapOutput ? this.options.wrapOutput({
863
953
  output: baseOutput,
864
954
  schema
865
955
  }) || baseOutput : baseOutput,
866
- nullable: isNullable,
867
- optional: isOptional,
868
- nullish: isNullish,
956
+ nullable: meta.nullable,
957
+ optional: schema.optional || property.required === false,
958
+ nullish: schema.nullish,
869
959
  defaultValue: meta.default
870
960
  });
871
- if (hasSelfRef) return `get ${(0, _kubb_ast_utils.objectKey)(propName)}() { return ${value} }`;
872
- return `${(0, _kubb_ast_utils.objectKey)(propName)}: ${value}`;
961
+ return isCyclic(schema) ? (0, _kubb_ast_utils.lazyGetter)({
962
+ name: propName,
963
+ body: value
964
+ }) : `${(0, _kubb_ast_utils.objectKey)(propName)}: ${value}`;
873
965
  }))})`;
874
966
  },
875
967
  array(node) {
876
- const base = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})${lengthChecksMini(node)}`;
968
+ const base = `z.array(${(0, _kubb_ast_utils.mapSchemaItems)(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.factory.createSchema({ type: "unknown" }))})${lengthChecksMini({
969
+ ...node,
970
+ regexType: this.options.regexType
971
+ })}`;
877
972
  return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
878
973
  },
879
974
  tuple(node) {
880
- return `z.tuple(${(0, _kubb_ast_utils.buildList)((node.items ?? []).map((item) => this.transform(item)).filter(Boolean))})`;
975
+ return `z.tuple(${(0, _kubb_ast_utils.buildList)((0, _kubb_ast_utils.mapSchemaItems)(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
881
976
  },
882
977
  union(node) {
883
978
  const nodeMembers = node.members ?? [];
884
- const members = nodeMembers.map((memberNode) => {
885
- const member = this.transform(memberNode);
886
- return member && node.strategy === "one" ? strictOneOfMember(member, memberNode) : member;
887
- }).filter(Boolean);
979
+ const members = (0, _kubb_ast_utils.mapSchemaMembers)(node, (memberNode) => this.transform(memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember(output, schema) : output).filter(Boolean);
888
980
  if (members.length === 0) return "";
889
981
  if (members.length === 1) return members[0];
890
982
  if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${(0, _kubb_ast_utils.stringify)(node.discriminatorPropertyName)}, ${(0, _kubb_ast_utils.buildList)(members)})`;
@@ -898,7 +990,10 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
898
990
  const firstBase = this.transform(first);
899
991
  if (!firstBase) return "";
900
992
  return rest.reduce((acc, member) => {
901
- const constraint = getMemberConstraintMini(member);
993
+ const constraint = getMemberConstraintMini({
994
+ member,
995
+ regexType: this.options.regexType
996
+ });
902
997
  if (constraint) return acc + constraint;
903
998
  const transformed = this.transform(member);
904
999
  return transformed ? `z.intersection(${acc}, ${transformed})` : acc;
@@ -910,7 +1005,7 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
910
1005
  const { keysToOmit } = this.options;
911
1006
  const transformed = this.transform(node);
912
1007
  if (!transformed) return null;
913
- const meta = _kubb_core.ast.syncSchemaRef(node);
1008
+ const meta = (0, _kubb_ast_utils.syncSchemaRef)(node);
914
1009
  return applyMiniModifiers({
915
1010
  value: (() => {
916
1011
  if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
@@ -937,7 +1032,7 @@ const zodMiniPrinterCache = /* @__PURE__ */ new WeakMap();
937
1032
  */
938
1033
  function getStdPrinters(resolver, params) {
939
1034
  const cached = zodPrinterCache.get(resolver);
940
- if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.dateType === params.dateType) return {
1035
+ if (cached && cached.coercion === params.coercion && cached.guidType === params.guidType && cached.regexType === params.regexType && cached.dateType === params.dateType) return {
941
1036
  output: cached.output,
942
1037
  input: cached.input
943
1038
  };
@@ -958,6 +1053,7 @@ function getStdPrinters(resolver, params) {
958
1053
  input,
959
1054
  coercion: params.coercion,
960
1055
  guidType: params.guidType,
1056
+ regexType: params.regexType,
961
1057
  dateType: params.dateType
962
1058
  });
963
1059
  return {
@@ -967,14 +1063,15 @@ function getStdPrinters(resolver, params) {
967
1063
  }
968
1064
  function getMiniPrinter(resolver, params) {
969
1065
  const cached = zodMiniPrinterCache.get(resolver);
970
- if (cached && cached.guidType === params.guidType) return cached.printer;
1066
+ if (cached && cached.guidType === params.guidType && cached.regexType === params.regexType) return cached.printer;
971
1067
  const p = printerZodMini({
972
1068
  ...params,
973
1069
  resolver
974
1070
  });
975
1071
  zodMiniPrinterCache.set(resolver, {
976
1072
  printer: p,
977
- guidType: params.guidType
1073
+ guidType: params.guidType,
1074
+ regexType: params.regexType
978
1075
  });
979
1076
  return p;
980
1077
  }
@@ -989,13 +1086,13 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
989
1086
  renderer: _kubb_renderer_jsx.jsxRenderer,
990
1087
  schema(node, ctx) {
991
1088
  const { adapter, config, resolver, root } = ctx;
992
- const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
1089
+ const { output, coercion, guidType, regexType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
993
1090
  const dateType = adapter.options.dateType;
994
1091
  if (!node.name) return;
995
1092
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
996
1093
  const cyclicSchemas = new Set(ctx.meta.circularNames);
997
1094
  const hasCodec = !mini && containsCodec(node);
998
- const codecRefNames = new Set(hasCodec ? _kubb_core.ast.collect(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? (0, _kubb_ast_utils.extractRefName)(n.ref) ?? void 0 : void 0 }) : []);
1095
+ const codecRefNames = new Set(hasCodec ? collectCodecRefNames(node) : []);
999
1096
  const importEntries = adapter.getImports(node, (schemaName) => ({
1000
1097
  name: resolver.resolveSchemaName(schemaName),
1001
1098
  path: resolver.resolveFile({
@@ -1040,6 +1137,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1040
1137
  const stdPrinters = mini ? null : getStdPrinters(resolver, {
1041
1138
  coercion,
1042
1139
  guidType,
1140
+ regexType,
1043
1141
  dateType,
1044
1142
  wrapOutput,
1045
1143
  cyclicSchemas,
@@ -1047,6 +1145,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1047
1145
  });
1048
1146
  const schemaPrinter = mini ? getMiniPrinter(resolver, {
1049
1147
  guidType,
1148
+ regexType,
1050
1149
  wrapOutput,
1051
1150
  cyclicSchemas,
1052
1151
  nodes: printer?.nodes
@@ -1104,10 +1203,10 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1104
1203
  operation(node, ctx) {
1105
1204
  if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
1106
1205
  const { adapter, config, resolver, root } = ctx;
1107
- const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, printer } = ctx.options;
1206
+ const { output, coercion, guidType, regexType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
1108
1207
  const dateType = adapter.options.dateType;
1109
1208
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1110
- const params = _kubb_core.ast.caseParams(node.parameters, paramsCasing);
1209
+ const params = caseParams(node.parameters, "camelcase");
1111
1210
  const meta = { file: resolver.resolveFile({
1112
1211
  name: node.operationId,
1113
1212
  extname: ".ts",
@@ -1122,7 +1221,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1122
1221
  function renderSchemaEntry({ schema, name, keysToOmit, direction = "output" }) {
1123
1222
  if (!schema) return null;
1124
1223
  const inferTypeName = inferred ? resolver.resolveTypeName(name) : null;
1125
- const codecRefNames = direction === "input" && !mini ? new Set(_kubb_core.ast.collect(schema, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? (0, _kubb_ast_utils.extractRefName)(n.ref) ?? void 0 : void 0 })) : null;
1224
+ const codecRefNames = direction === "input" && !mini ? new Set(collectCodecRefNames(schema)) : null;
1126
1225
  const imports = adapter.getImports(schema, (schemaName) => ({
1127
1226
  name: codecRefNames?.has(schemaName) ? resolver.resolveInputSchemaName(schemaName) : resolver.resolveSchemaName(schemaName),
1128
1227
  path: resolver.resolveFile({
@@ -1136,6 +1235,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1136
1235
  }));
1137
1236
  const schemaPrinter = mini ? keysToOmit?.length ? printerZodMini({
1138
1237
  guidType,
1238
+ regexType,
1139
1239
  wrapOutput,
1140
1240
  resolver,
1141
1241
  keysToOmit,
@@ -1143,12 +1243,14 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1143
1243
  nodes: printer?.nodes
1144
1244
  }) : getMiniPrinter(resolver, {
1145
1245
  guidType,
1246
+ regexType,
1146
1247
  wrapOutput,
1147
1248
  cyclicSchemas,
1148
1249
  nodes: printer?.nodes
1149
1250
  }) : keysToOmit?.length ? printerZod({
1150
1251
  coercion,
1151
1252
  guidType,
1253
+ regexType,
1152
1254
  dateType,
1153
1255
  wrapOutput,
1154
1256
  resolver,
@@ -1159,6 +1261,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1159
1261
  }) : getStdPrinters(resolver, {
1160
1262
  coercion,
1161
1263
  guidType,
1264
+ regexType,
1162
1265
  dateType,
1163
1266
  wrapOutput,
1164
1267
  cyclicSchemas,
@@ -1181,9 +1284,9 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1181
1284
  }
1182
1285
  function buildContentTypeVariants(entries, baseName, decorate, direction) {
1183
1286
  const variants = resolveContentTypeVariants(entries, baseName);
1184
- const unionSchema = _kubb_core.ast.createSchema({
1287
+ const unionSchema = _kubb_core.ast.factory.createSchema({
1185
1288
  type: "union",
1186
- members: variants.map((variant) => _kubb_core.ast.createSchema({
1289
+ members: variants.map((variant) => _kubb_core.ast.factory.createSchema({
1187
1290
  type: "ref",
1188
1291
  name: variant.name
1189
1292
  }))
@@ -1215,18 +1318,23 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1215
1318
  });
1216
1319
  });
1217
1320
  const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
1321
+ const successResponsesWithSchema = getSuccessResponses(responsesWithSchema);
1218
1322
  const responseUnionSchema = responsesWithSchema.length > 0 ? (() => {
1219
1323
  const responseUnionName = resolver.resolveResponseName(node);
1220
- if (new Set(responsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
1324
+ if (new Set(successResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
1221
1325
  name: resolver.resolveSchemaName(schemaName),
1222
1326
  path: ""
1223
1327
  })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(responseUnionName)) return null;
1224
- const members = responsesWithSchema.map((res) => _kubb_core.ast.createSchema({
1328
+ const members = successResponsesWithSchema.map((res) => _kubb_core.ast.factory.createSchema({
1225
1329
  type: "ref",
1226
1330
  name: resolver.resolveResponseStatusName(node, res.statusCode)
1227
1331
  }));
1332
+ if (members.length === 0) return renderSchemaEntry({
1333
+ schema: _kubb_core.ast.factory.createSchema({ type: "unknown" }),
1334
+ name: responseUnionName
1335
+ });
1228
1336
  return renderSchemaEntry({
1229
- schema: members.length === 1 ? members[0] : _kubb_core.ast.createSchema({
1337
+ schema: members.length === 1 ? members[0] : _kubb_core.ast.factory.createSchema({
1230
1338
  type: "union",
1231
1339
  members
1232
1340
  }),
@@ -1289,7 +1397,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1289
1397
  },
1290
1398
  operations(nodes, ctx) {
1291
1399
  const { config, resolver, root } = ctx;
1292
- const { output, importPath, group, operations, paramsCasing } = ctx.options;
1400
+ const { output, importPath, group, operations } = ctx.options;
1293
1401
  if (!operations) return;
1294
1402
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1295
1403
  const meta = { file: resolver.resolveFile({
@@ -1304,7 +1412,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1304
1412
  return {
1305
1413
  node,
1306
1414
  data: buildSchemaNames(node, {
1307
- params: _kubb_core.ast.caseParams(node.parameters, paramsCasing),
1415
+ params: caseParams(node.parameters, "camelcase"),
1308
1416
  resolver
1309
1417
  })
1310
1418
  };
@@ -1446,8 +1554,9 @@ const pluginZodName = "plugin-zod";
1446
1554
  /**
1447
1555
  * Generates Zod v4 schemas from an OpenAPI spec. Use them to validate API
1448
1556
  * responses at runtime, build form schemas, or feed back into router libraries
1449
- * that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-client` and
1450
- * set the client's `parser: 'zod'` to validate every response automatically.
1557
+ * that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-axios` or
1558
+ * `@kubb/plugin-fetch` and set the client's `parser: 'zod'` to validate every response
1559
+ * automatically.
1451
1560
  *
1452
1561
  * @example
1453
1562
  * ```ts
@@ -1472,7 +1581,7 @@ const pluginZod = (0, _kubb_core.definePlugin)((options) => {
1472
1581
  const { output = {
1473
1582
  path: "zod",
1474
1583
  barrel: { type: "named" }
1475
- }, group, exclude = [], include, override = [], typed = false, operations = false, mini = false, guidType = "uuid", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, wrapOutput = void 0, paramsCasing, printer, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
1584
+ }, 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;
1476
1585
  const groupConfig = createGroupConfig(group);
1477
1586
  return {
1478
1587
  name: pluginZodName,
@@ -1490,18 +1599,17 @@ const pluginZod = (0, _kubb_core.definePlugin)((options) => {
1490
1599
  operations,
1491
1600
  inferred,
1492
1601
  guidType,
1602
+ regexType,
1493
1603
  mini,
1494
1604
  wrapOutput,
1495
- paramsCasing,
1496
1605
  printer
1497
1606
  });
1498
1607
  ctx.setResolver(userResolver ? {
1499
1608
  ...resolverZod,
1500
1609
  ...userResolver
1501
1610
  } : resolverZod);
1502
- if (userTransformer) ctx.setTransformer(userTransformer);
1611
+ if (userMacros?.length) ctx.setMacros(userMacros);
1503
1612
  ctx.addGenerator(zodGenerator);
1504
- for (const gen of userGenerators) ctx.addGenerator(gen);
1505
1613
  } }
1506
1614
  };
1507
1615
  });