@kubb/plugin-zod 5.0.0-beta.3 → 5.0.0-beta.30

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
@@ -2,6 +2,12 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
+ //#region \0rolldown/runtime.js
6
+ var __defProp = Object.defineProperty;
7
+ var __name = (target, value) => __defProp(target, "name", {
8
+ value,
9
+ configurable: true
10
+ });
5
11
  //#endregion
6
12
  let _kubb_core = require("@kubb/core");
7
13
  let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
@@ -130,6 +136,129 @@ function toRegExpString(text, func = "RegExp") {
130
136
  return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
131
137
  }
132
138
  //#endregion
139
+ //#region ../../internals/utils/src/reserved.ts
140
+ /**
141
+ * JavaScript and Java reserved words.
142
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
143
+ */
144
+ const reservedWords = new Set([
145
+ "abstract",
146
+ "arguments",
147
+ "boolean",
148
+ "break",
149
+ "byte",
150
+ "case",
151
+ "catch",
152
+ "char",
153
+ "class",
154
+ "const",
155
+ "continue",
156
+ "debugger",
157
+ "default",
158
+ "delete",
159
+ "do",
160
+ "double",
161
+ "else",
162
+ "enum",
163
+ "eval",
164
+ "export",
165
+ "extends",
166
+ "false",
167
+ "final",
168
+ "finally",
169
+ "float",
170
+ "for",
171
+ "function",
172
+ "goto",
173
+ "if",
174
+ "implements",
175
+ "import",
176
+ "in",
177
+ "instanceof",
178
+ "int",
179
+ "interface",
180
+ "let",
181
+ "long",
182
+ "native",
183
+ "new",
184
+ "null",
185
+ "package",
186
+ "private",
187
+ "protected",
188
+ "public",
189
+ "return",
190
+ "short",
191
+ "static",
192
+ "super",
193
+ "switch",
194
+ "synchronized",
195
+ "this",
196
+ "throw",
197
+ "throws",
198
+ "transient",
199
+ "true",
200
+ "try",
201
+ "typeof",
202
+ "var",
203
+ "void",
204
+ "volatile",
205
+ "while",
206
+ "with",
207
+ "yield",
208
+ "Array",
209
+ "Date",
210
+ "hasOwnProperty",
211
+ "Infinity",
212
+ "isFinite",
213
+ "isNaN",
214
+ "isPrototypeOf",
215
+ "length",
216
+ "Math",
217
+ "name",
218
+ "NaN",
219
+ "Number",
220
+ "Object",
221
+ "prototype",
222
+ "String",
223
+ "toString",
224
+ "undefined",
225
+ "valueOf"
226
+ ]);
227
+ /**
228
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * isValidVarName('status') // true
233
+ * isValidVarName('class') // false (reserved word)
234
+ * isValidVarName('42foo') // false (starts with digit)
235
+ * ```
236
+ */
237
+ function isValidVarName(name) {
238
+ if (!name || reservedWords.has(name)) return false;
239
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
240
+ }
241
+ /**
242
+ * Returns `name` when it's a syntactically valid JavaScript variable name,
243
+ * otherwise prefixes it with `_` so the result is a valid identifier.
244
+ *
245
+ * Useful for sanitizing OpenAPI schema names or operation IDs that start with
246
+ * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
247
+ * variable, type, or function names.
248
+ *
249
+ * @example
250
+ * ```ts
251
+ * ensureValidVarName('409') // '_409'
252
+ * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
253
+ * ensureValidVarName('Pet') // 'Pet'
254
+ * ensureValidVarName('class') // '_class'
255
+ * ```
256
+ */
257
+ function ensureValidVarName(name) {
258
+ if (!name || isValidVarName(name)) return name;
259
+ return `_${name}`;
260
+ }
261
+ //#endregion
133
262
  //#region src/components/Operations.tsx
134
263
  function Operations({ name, operations }) {
135
264
  const operationsJSON = operations.reduce((prev, acc) => {
@@ -265,11 +394,11 @@ function buildSchemaNames(node, { params, resolver }) {
265
394
  }
266
395
  responses["default"] = resolver.resolveResponseName(node);
267
396
  return {
268
- request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : void 0,
397
+ request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null,
269
398
  parameters: {
270
- path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : void 0,
271
- query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : void 0,
272
- header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : void 0
399
+ path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : null,
400
+ query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : null,
401
+ header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : null
273
402
  },
274
403
  responses,
275
404
  errors
@@ -343,30 +472,44 @@ function lengthChecksMini({ min, max, pattern }) {
343
472
  * to a schema value string using the chainable Zod v4 API.
344
473
  */
345
474
  function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }) {
346
- let result = value;
347
- if (nullish || nullable && optional) result = `${result}.nullish()`;
348
- else if (optional) result = `${result}.optional()`;
349
- else if (nullable) result = `${result}.nullable()`;
350
- if (defaultValue !== void 0) result = `${result}.default(${formatDefault(defaultValue)})`;
351
- if (description) result = `${result}.describe(${stringify(description)})`;
352
- return result;
475
+ const withModifier = (() => {
476
+ if (nullish || nullable && optional) return `${value}.nullish()`;
477
+ if (optional) return `${value}.optional()`;
478
+ if (nullable) return `${value}.nullable()`;
479
+ return value;
480
+ })();
481
+ const withDefault = defaultValue !== void 0 ? `${withModifier}.default(${formatDefault(defaultValue)})` : withModifier;
482
+ return description ? `${withDefault}.describe(${stringify(description)})` : withDefault;
353
483
  }
354
484
  /**
355
485
  * Apply nullable / optional / nullish modifiers using the functional `zod/mini` API
356
486
  * (`z.nullable()`, `z.optional()`, `z.nullish()`).
357
487
  */
358
488
  function applyMiniModifiers({ value, nullable, optional, nullish, defaultValue }) {
359
- let result = value;
360
- if (nullish) result = `z.nullish(${result})`;
361
- else {
362
- if (nullable) result = `z.nullable(${result})`;
363
- if (optional) result = `z.optional(${result})`;
364
- }
365
- if (defaultValue !== void 0) result = `z._default(${result}, ${formatDefault(defaultValue)})`;
366
- return result;
489
+ const withModifier = (() => {
490
+ if (nullish) return `z.nullish(${value})`;
491
+ const withNullable = nullable ? `z.nullable(${value})` : value;
492
+ return optional ? `z.optional(${withNullable})` : withNullable;
493
+ })();
494
+ return defaultValue !== void 0 ? `z._default(${withModifier}, ${formatDefault(defaultValue)})` : withModifier;
367
495
  }
368
496
  //#endregion
369
497
  //#region src/printers/printerZod.ts
498
+ function strictOneOfMember$1(member, node) {
499
+ if (node.type === "object" && node.additionalProperties === void 0) return `${member}.strict()`;
500
+ if (node.type === "ref") {
501
+ if (member.startsWith("z.lazy(")) return member;
502
+ const schema = _kubb_core.ast.syncSchemaRef(node);
503
+ if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
504
+ }
505
+ return member;
506
+ }
507
+ __name(strictOneOfMember$1, "strictOneOfMember");
508
+ function getMemberConstraint(member) {
509
+ if (member.primitive === "string") return lengthConstraints(_kubb_core.ast.narrowSchema(member, "string") ?? {}) || void 0;
510
+ if (member.primitive === "number" || member.primitive === "integer") return numberConstraints(_kubb_core.ast.narrowSchema(member, "number") ?? _kubb_core.ast.narrowSchema(member, "integer") ?? {}) || void 0;
511
+ if (member.primitive === "array") return lengthConstraints(_kubb_core.ast.narrowSchema(member, "array") ?? {}) || void 0;
512
+ }
370
513
  /**
371
514
  * Zod v4 printer built with `definePrinter`.
372
515
  *
@@ -439,29 +582,29 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
439
582
  return `z.enum([${nonNullValues.map(formatLiteral).join(", ")}])`;
440
583
  },
441
584
  ref(node) {
442
- if (!node.name) return void 0;
585
+ if (!node.name) return null;
443
586
  const refName = node.ref ? _kubb_core.ast.extractRefName(node.ref) ?? node.name : node.name;
444
587
  const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
445
588
  if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
446
589
  return resolvedName;
447
590
  },
448
591
  object(node) {
449
- let result = `z.object({\n ${node.properties.map((prop) => {
592
+ const objectBase = `z.object({\n ${node.properties.map((prop) => {
450
593
  const { name: propName, schema } = prop;
451
594
  const meta = _kubb_core.ast.syncSchemaRef(schema);
452
595
  const isNullable = meta.nullable;
453
596
  const isOptional = schema.optional;
454
597
  const isNullish = schema.nullish;
455
598
  const hasSelfRef = this.options.cyclicSchemas != null && _kubb_core.ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
599
+ const savedCyclicSchemas = this.options.cyclicSchemas;
456
600
  if (hasSelfRef) this.options.cyclicSchemas = void 0;
457
601
  const baseOutput = this.transform(schema) ?? this.transform(_kubb_core.ast.createSchema({ type: "unknown" }));
458
- if (hasSelfRef) this.options.cyclicSchemas = options.cyclicSchemas;
602
+ if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas;
459
603
  const wrappedOutput = this.options.wrapOutput ? this.options.wrapOutput({
460
604
  output: baseOutput,
461
605
  schema
462
606
  }) || baseOutput : baseOutput;
463
- let descriptionToApply = meta.description;
464
- if (schema.type !== "ref" && meta.type === "ref") descriptionToApply = void 0;
607
+ const descriptionToApply = schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description;
465
608
  const value = applyModifiers({
466
609
  value: wrappedOutput,
467
610
  nullable: isNullable,
@@ -473,24 +616,29 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
473
616
  if (hasSelfRef) return `get "${propName}"() { return ${value} }`;
474
617
  return `"${propName}": ${value}`;
475
618
  }).join(",\n ")}\n })`;
476
- if (node.additionalProperties && node.additionalProperties !== true) {
477
- const catchallType = this.transform(node.additionalProperties);
478
- if (catchallType) result += `.catchall(${catchallType})`;
479
- } else if (node.additionalProperties === true) result += `.catchall(${this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})`;
480
- else if (node.additionalProperties === false) result += ".strict()";
481
- return result;
619
+ return (() => {
620
+ if (node.additionalProperties && node.additionalProperties !== true) {
621
+ const catchallType = this.transform(node.additionalProperties);
622
+ return catchallType ? `${objectBase}.catchall(${catchallType})` : objectBase;
623
+ }
624
+ if (node.additionalProperties === true) return `${objectBase}.catchall(${this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})`;
625
+ if (node.additionalProperties === false) return `${objectBase}.strict()`;
626
+ return objectBase;
627
+ })();
482
628
  },
483
629
  array(node) {
484
- let result = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})${lengthConstraints(node)}`;
485
- if (node.unique) result += `.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`;
486
- return result;
630
+ const base = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})${lengthConstraints(node)}`;
631
+ return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
487
632
  },
488
633
  tuple(node) {
489
634
  return `z.tuple([${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ")}])`;
490
635
  },
491
636
  union(node) {
492
637
  const nodeMembers = node.members ?? [];
493
- const members = nodeMembers.map((m) => this.transform(m)).filter(Boolean);
638
+ const members = nodeMembers.map((memberNode) => {
639
+ const member = this.transform(memberNode);
640
+ return member && node.strategy === "one" ? strictOneOfMember$1(member, memberNode) : member;
641
+ }).filter(Boolean);
494
642
  if (members.length === 0) return "";
495
643
  if (members.length === 1) return members[0];
496
644
  if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, [${members.join(", ")}])`;
@@ -501,47 +649,29 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
501
649
  if (members.length === 0) return "";
502
650
  const [first, ...rest] = members;
503
651
  if (!first) return "";
504
- let base = this.transform(first);
505
- if (!base) return "";
506
- for (const member of rest) {
507
- if (member.primitive === "string") {
508
- const c = lengthConstraints(_kubb_core.ast.narrowSchema(member, "string") ?? {});
509
- if (c) {
510
- base += c;
511
- continue;
512
- }
513
- } else if (member.primitive === "number" || member.primitive === "integer") {
514
- const c = numberConstraints(_kubb_core.ast.narrowSchema(member, "number") ?? _kubb_core.ast.narrowSchema(member, "integer") ?? {});
515
- if (c) {
516
- base += c;
517
- continue;
518
- }
519
- } else if (member.primitive === "array") {
520
- const c = lengthConstraints(_kubb_core.ast.narrowSchema(member, "array") ?? {});
521
- if (c) {
522
- base += c;
523
- continue;
524
- }
525
- }
652
+ const firstBase = this.transform(first);
653
+ if (!firstBase) return "";
654
+ return rest.reduce((acc, member) => {
655
+ const constraint = getMemberConstraint(member);
656
+ if (constraint) return acc + constraint;
526
657
  const transformed = this.transform(member);
527
- if (transformed) base = `${base}.and(${transformed})`;
528
- }
529
- return base;
658
+ return transformed ? `${acc}.and(${transformed})` : acc;
659
+ }, firstBase);
530
660
  },
531
661
  ...options.nodes
532
662
  },
533
663
  print(node) {
534
664
  const { keysToOmit } = this.options;
535
- let base = this.transform(node);
536
- if (!base) return null;
665
+ const transformed = this.transform(node);
666
+ if (!transformed) return null;
537
667
  const meta = _kubb_core.ast.syncSchemaRef(node);
538
- if (keysToOmit?.length && meta.primitive === "object" && !(meta.type === "union" && meta.discriminatorPropertyName)) {
539
- const lazyMatch = base.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
540
- if (lazyMatch) base = `z.lazy(() => ${lazyMatch[1]}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }))`;
541
- else base = `${base}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
542
- }
543
668
  return applyModifiers({
544
- value: base,
669
+ value: (() => {
670
+ if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
671
+ const lazyMatch = transformed.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
672
+ if (lazyMatch) return `z.lazy(() => ${lazyMatch[1]}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }))`;
673
+ return `${transformed}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
674
+ })(),
545
675
  nullable: meta.nullable,
546
676
  optional: meta.optional,
547
677
  nullish: meta.nullish,
@@ -553,6 +683,15 @@ const printerZod = _kubb_core.ast.definePrinter((options) => {
553
683
  });
554
684
  //#endregion
555
685
  //#region src/printers/printerZodMini.ts
686
+ function strictOneOfMember(member, node) {
687
+ if (node.type === "object" && (node.additionalProperties === void 0 || node.additionalProperties === false)) return member.replace(/^z\.object\(/, "z.strictObject(");
688
+ return member;
689
+ }
690
+ function getMemberConstraintMini(member) {
691
+ if (member.primitive === "string") return lengthChecksMini(_kubb_core.ast.narrowSchema(member, "string") ?? {}) || void 0;
692
+ if (member.primitive === "number" || member.primitive === "integer") return numberChecksMini(_kubb_core.ast.narrowSchema(member, "number") ?? _kubb_core.ast.narrowSchema(member, "integer") ?? {}) || void 0;
693
+ if (member.primitive === "array") return lengthChecksMini(_kubb_core.ast.narrowSchema(member, "array") ?? {}) || void 0;
694
+ }
556
695
  /**
557
696
  * Zod v4 **Mini** printer built with `definePrinter`.
558
697
  *
@@ -621,7 +760,7 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
621
760
  return `z.enum([${nonNullValues.map(formatLiteral).join(", ")}])`;
622
761
  },
623
762
  ref(node) {
624
- if (!node.name) return void 0;
763
+ if (!node.name) return null;
625
764
  const refName = node.ref ? _kubb_core.ast.extractRefName(node.ref) ?? node.name : node.name;
626
765
  const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
627
766
  if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
@@ -635,9 +774,10 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
635
774
  const isOptional = schema.optional;
636
775
  const isNullish = schema.nullish;
637
776
  const hasSelfRef = this.options.cyclicSchemas != null && _kubb_core.ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
777
+ const savedCyclicSchemas = this.options.cyclicSchemas;
638
778
  if (hasSelfRef) this.options.cyclicSchemas = void 0;
639
779
  const baseOutput = this.transform(schema) ?? this.transform(_kubb_core.ast.createSchema({ type: "unknown" }));
640
- if (hasSelfRef) this.options.cyclicSchemas = options.cyclicSchemas;
780
+ if (hasSelfRef) this.options.cyclicSchemas = savedCyclicSchemas;
641
781
  const value = applyMiniModifiers({
642
782
  value: this.options.wrapOutput ? this.options.wrapOutput({
643
783
  output: baseOutput,
@@ -653,16 +793,18 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
653
793
  }).join(",\n ")}\n })`;
654
794
  },
655
795
  array(node) {
656
- let result = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})${lengthChecksMini(node)}`;
657
- if (node.unique) result += `.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`;
658
- return result;
796
+ const base = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})${lengthChecksMini(node)}`;
797
+ return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
659
798
  },
660
799
  tuple(node) {
661
800
  return `z.tuple([${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ")}])`;
662
801
  },
663
802
  union(node) {
664
803
  const nodeMembers = node.members ?? [];
665
- const members = nodeMembers.map((m) => this.transform(m)).filter(Boolean);
804
+ const members = nodeMembers.map((memberNode) => {
805
+ const member = this.transform(memberNode);
806
+ return member && node.strategy === "one" ? strictOneOfMember(member, memberNode) : member;
807
+ }).filter(Boolean);
666
808
  if (members.length === 0) return "";
667
809
  if (members.length === 1) return members[0];
668
810
  if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, [${members.join(", ")}])`;
@@ -673,47 +815,29 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
673
815
  if (members.length === 0) return "";
674
816
  const [first, ...rest] = members;
675
817
  if (!first) return "";
676
- let base = this.transform(first);
677
- if (!base) return "";
678
- for (const member of rest) {
679
- if (member.primitive === "string") {
680
- const c = lengthChecksMini(_kubb_core.ast.narrowSchema(member, "string") ?? {});
681
- if (c) {
682
- base += c;
683
- continue;
684
- }
685
- } else if (member.primitive === "number" || member.primitive === "integer") {
686
- const c = numberChecksMini(_kubb_core.ast.narrowSchema(member, "number") ?? _kubb_core.ast.narrowSchema(member, "integer") ?? {});
687
- if (c) {
688
- base += c;
689
- continue;
690
- }
691
- } else if (member.primitive === "array") {
692
- const c = lengthChecksMini(_kubb_core.ast.narrowSchema(member, "array") ?? {});
693
- if (c) {
694
- base += c;
695
- continue;
696
- }
697
- }
818
+ const firstBase = this.transform(first);
819
+ if (!firstBase) return "";
820
+ return rest.reduce((acc, member) => {
821
+ const constraint = getMemberConstraintMini(member);
822
+ if (constraint) return acc + constraint;
698
823
  const transformed = this.transform(member);
699
- if (transformed) base = `z.intersection(${base}, ${transformed})`;
700
- }
701
- return base;
824
+ return transformed ? `z.intersection(${acc}, ${transformed})` : acc;
825
+ }, firstBase);
702
826
  },
703
827
  ...options.nodes
704
828
  },
705
829
  print(node) {
706
830
  const { keysToOmit } = this.options;
707
- let base = this.transform(node);
708
- if (!base) return null;
831
+ const transformed = this.transform(node);
832
+ if (!transformed) return null;
709
833
  const meta = _kubb_core.ast.syncSchemaRef(node);
710
- if (keysToOmit?.length && meta.primitive === "object" && !(meta.type === "union" && meta.discriminatorPropertyName)) {
711
- const lazyMatch = base.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
712
- if (lazyMatch) base = `z.lazy(() => ${lazyMatch[1]}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }))`;
713
- else base = `${base}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
714
- }
715
834
  return applyMiniModifiers({
716
- value: base,
835
+ value: (() => {
836
+ if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
837
+ const lazyMatch = transformed.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
838
+ if (lazyMatch) return `z.lazy(() => ${lazyMatch[1]}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }))`;
839
+ return `${transformed}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
840
+ })(),
717
841
  nullable: meta.nullable,
718
842
  optional: meta.optional,
719
843
  nullish: meta.nullish,
@@ -724,9 +848,17 @@ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
724
848
  });
725
849
  //#endregion
726
850
  //#region src/generators/zodGenerator.tsx
851
+ const zodPrinterCache = /* @__PURE__ */ new WeakMap();
852
+ const zodMiniPrinterCache = /* @__PURE__ */ new WeakMap();
853
+ /**
854
+ * Built-in generator for `@kubb/plugin-zod`. Emits one Zod schema per
855
+ * schema in the spec plus per-operation request/response/parameter schemas.
856
+ * When `mini: true`, schemas use the Zod Mini functional API instead of
857
+ * chainable methods.
858
+ */
727
859
  const zodGenerator = (0, _kubb_core.defineGenerator)({
728
860
  name: "zod",
729
- renderer: _kubb_renderer_jsx.jsxRenderer,
861
+ renderer: _kubb_renderer_jsx.jsxRendererSync,
730
862
  schema(node, ctx) {
731
863
  const { adapter, config, resolver, root } = ctx;
732
864
  const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
@@ -742,7 +874,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
742
874
  }, {
743
875
  root,
744
876
  output,
745
- group
877
+ group: group ?? void 0
746
878
  }).path
747
879
  }));
748
880
  const meta = {
@@ -753,37 +885,67 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
753
885
  }, {
754
886
  root,
755
887
  output,
756
- group
888
+ group: group ?? void 0
757
889
  })
758
890
  };
759
- const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : void 0;
760
- const cyclicSchemas = adapter.inputNode ? _kubb_core.ast.findCircularSchemas(adapter.inputNode.schemas) : void 0;
761
- const schemaPrinter = mini ? printerZodMini({
762
- guidType,
763
- wrapOutput,
764
- resolver,
765
- cyclicSchemas,
766
- nodes: printer?.nodes
767
- }) : printerZod({
768
- coercion,
769
- guidType,
770
- dateType,
771
- wrapOutput,
772
- resolver,
773
- cyclicSchemas,
774
- nodes: printer?.nodes
775
- });
891
+ const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : null;
892
+ const cyclicSchemas = new Set(ctx.meta.circularNames);
893
+ const schemaPrinter = mini ? getCachedMiniPrinter() : getCachedStdPrinter();
894
+ function getCachedStdPrinter() {
895
+ const cached = zodPrinterCache.get(resolver);
896
+ if (cached && cached.coercion === coercion && cached.guidType === guidType && cached.dateType === dateType) return cached.printer;
897
+ const p = printerZod({
898
+ coercion,
899
+ guidType,
900
+ dateType,
901
+ wrapOutput,
902
+ resolver,
903
+ cyclicSchemas,
904
+ nodes: printer?.nodes
905
+ });
906
+ zodPrinterCache.set(resolver, {
907
+ printer: p,
908
+ coercion,
909
+ guidType,
910
+ dateType
911
+ });
912
+ return p;
913
+ }
914
+ function getCachedMiniPrinter() {
915
+ const cached = zodMiniPrinterCache.get(resolver);
916
+ if (cached && cached.guidType === guidType) return cached.printer;
917
+ const p = printerZodMini({
918
+ guidType,
919
+ wrapOutput,
920
+ resolver,
921
+ cyclicSchemas,
922
+ nodes: printer?.nodes
923
+ });
924
+ zodMiniPrinterCache.set(resolver, {
925
+ printer: p,
926
+ guidType
927
+ });
928
+ return p;
929
+ }
776
930
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
777
931
  baseName: meta.file.baseName,
778
932
  path: meta.file.path,
779
933
  meta: meta.file.meta,
780
- banner: resolver.resolveBanner(adapter.inputNode, {
934
+ banner: resolver.resolveBanner(ctx.meta, {
781
935
  output,
782
- config
936
+ config,
937
+ file: {
938
+ path: meta.file.path,
939
+ baseName: meta.file.baseName
940
+ }
783
941
  }),
784
- footer: resolver.resolveFooter(adapter.inputNode, {
942
+ footer: resolver.resolveFooter(ctx.meta, {
785
943
  output,
786
- config
944
+ config,
945
+ file: {
946
+ path: meta.file.path,
947
+ baseName: meta.file.baseName
948
+ }
787
949
  }),
788
950
  children: [
789
951
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
@@ -820,12 +982,12 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
820
982
  }, {
821
983
  root,
822
984
  output,
823
- group
985
+ group: group ?? void 0
824
986
  }) };
825
- const cyclicSchemas = adapter.inputNode ? _kubb_core.ast.findCircularSchemas(adapter.inputNode.schemas) : void 0;
987
+ const cyclicSchemas = new Set(ctx.meta.circularNames);
826
988
  function renderSchemaEntry({ schema, name, keysToOmit }) {
827
989
  if (!schema) return null;
828
- const inferTypeName = inferred ? resolver.resolveTypeName(name) : void 0;
990
+ const inferTypeName = inferred ? resolver.resolveTypeName(name) : null;
829
991
  const imports = adapter.getImports(schema, (schemaName) => ({
830
992
  name: resolver.resolveSchemaName(schemaName),
831
993
  path: resolver.resolveFile({
@@ -834,17 +996,25 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
834
996
  }, {
835
997
  root,
836
998
  output,
837
- group
999
+ group: group ?? void 0
838
1000
  }).path
839
1001
  }));
840
- const schemaPrinter = mini ? printerZodMini({
1002
+ const cachedStd = zodPrinterCache.get(resolver);
1003
+ const cachedMini = zodMiniPrinterCache.get(resolver);
1004
+ const schemaPrinter = mini ? keysToOmit?.length ? printerZodMini({
841
1005
  guidType,
842
1006
  wrapOutput,
843
1007
  resolver,
844
1008
  keysToOmit,
845
1009
  cyclicSchemas,
846
1010
  nodes: printer?.nodes
847
- }) : printerZod({
1011
+ }) : cachedMini?.guidType === guidType ? cachedMini.printer : printerZodMini({
1012
+ guidType,
1013
+ wrapOutput,
1014
+ resolver,
1015
+ cyclicSchemas,
1016
+ nodes: printer?.nodes
1017
+ }) : keysToOmit?.length ? printerZod({
848
1018
  coercion,
849
1019
  guidType,
850
1020
  dateType,
@@ -853,6 +1023,14 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
853
1023
  keysToOmit,
854
1024
  cyclicSchemas,
855
1025
  nodes: printer?.nodes
1026
+ }) : cachedStd?.coercion === coercion && cachedStd?.guidType === guidType && cachedStd?.dateType === dateType ? cachedStd.printer : printerZod({
1027
+ coercion,
1028
+ guidType,
1029
+ dateType,
1030
+ wrapOutput,
1031
+ resolver,
1032
+ cyclicSchemas,
1033
+ nodes: printer?.nodes
856
1034
  });
857
1035
  return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
858
1036
  root: meta.file.path,
@@ -874,14 +1052,14 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
874
1052
  name: resolver.resolveParamName(node, param)
875
1053
  }));
876
1054
  const responseSchemas = node.responses.map((res) => renderSchemaEntry({
877
- schema: res.schema,
1055
+ schema: res.content?.[0]?.schema ?? null,
878
1056
  name: resolver.resolveResponseStatusName(node, res.statusCode),
879
- keysToOmit: res.keysToOmit
1057
+ keysToOmit: res.content?.[0]?.keysToOmit
880
1058
  }));
881
- const responsesWithSchema = node.responses.filter((res) => res.schema);
1059
+ const responsesWithSchema = node.responses.filter((res) => res.content?.[0]?.schema);
882
1060
  const responseUnionSchema = responsesWithSchema.length > 0 ? (() => {
883
1061
  const responseUnionName = resolver.resolveResponseName(node);
884
- if (new Set(responsesWithSchema.flatMap((res) => res.schema ? adapter.getImports(res.schema, (schemaName) => ({
1062
+ if (new Set(responsesWithSchema.flatMap((res) => res.content?.[0]?.schema ? adapter.getImports(res.content[0].schema, (schemaName) => ({
885
1063
  name: resolver.resolveSchemaName(schemaName),
886
1064
  path: ""
887
1065
  })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : [])).has(responseUnionName)) return null;
@@ -909,13 +1087,21 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
909
1087
  baseName: meta.file.baseName,
910
1088
  path: meta.file.path,
911
1089
  meta: meta.file.meta,
912
- banner: resolver.resolveBanner(adapter.inputNode, {
1090
+ banner: resolver.resolveBanner(ctx.meta, {
913
1091
  output,
914
- config
1092
+ config,
1093
+ file: {
1094
+ path: meta.file.path,
1095
+ baseName: meta.file.baseName
1096
+ }
915
1097
  }),
916
- footer: resolver.resolveFooter(adapter.inputNode, {
1098
+ footer: resolver.resolveFooter(ctx.meta, {
917
1099
  output,
918
- config
1100
+ config,
1101
+ file: {
1102
+ path: meta.file.path,
1103
+ baseName: meta.file.baseName
1104
+ }
919
1105
  }),
920
1106
  children: [
921
1107
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
@@ -931,7 +1117,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
931
1117
  });
932
1118
  },
933
1119
  operations(nodes, ctx) {
934
- const { adapter, config, resolver, root } = ctx;
1120
+ const { config, resolver, root } = ctx;
935
1121
  const { output, importPath, group, operations, paramsCasing } = ctx.options;
936
1122
  if (!operations) return;
937
1123
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
@@ -941,7 +1127,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
941
1127
  }, {
942
1128
  root,
943
1129
  output,
944
- group
1130
+ group: group ?? void 0
945
1131
  }) };
946
1132
  const transformedOperations = nodes.map((node) => {
947
1133
  return {
@@ -966,7 +1152,7 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
966
1152
  }, {
967
1153
  root,
968
1154
  output,
969
- group
1155
+ group: group ?? void 0
970
1156
  });
971
1157
  return names.map((name) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
972
1158
  name: [name],
@@ -978,13 +1164,21 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
978
1164
  baseName: meta.file.baseName,
979
1165
  path: meta.file.path,
980
1166
  meta: meta.file.meta,
981
- banner: resolver.resolveBanner(adapter.inputNode, {
1167
+ banner: resolver.resolveBanner(ctx.meta, {
982
1168
  output,
983
- config
1169
+ config,
1170
+ file: {
1171
+ path: meta.file.path,
1172
+ baseName: meta.file.baseName
1173
+ }
984
1174
  }),
985
- footer: resolver.resolveFooter(adapter.inputNode, {
1175
+ footer: resolver.resolveFooter(ctx.meta, {
986
1176
  output,
987
- config
1177
+ config,
1178
+ file: {
1179
+ path: meta.file.path,
1180
+ baseName: meta.file.baseName
1181
+ }
988
1182
  }),
989
1183
  children: [
990
1184
  /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
@@ -1005,77 +1199,96 @@ const zodGenerator = (0, _kubb_core.defineGenerator)({
1005
1199
  //#endregion
1006
1200
  //#region src/resolvers/resolverZod.ts
1007
1201
  /**
1008
- * Naming convention resolver for Zod plugin.
1202
+ * Default resolver used by `@kubb/plugin-zod`. Decides the names and file
1203
+ * paths for every generated Zod schema. Schemas use camelCase with a
1204
+ * `Schema` suffix (`listPetsSchema`); their inferred types use PascalCase.
1009
1205
  *
1010
- * Provides default naming helpers using camelCase with a `Schema` suffix for schemas.
1206
+ * @example Resolve schema and type names
1207
+ * ```ts
1208
+ * import { resolverZod } from '@kubb/plugin-zod'
1011
1209
  *
1012
- * @example
1013
- * `resolverZod.default('list pets', 'function') // 'listPetsSchema'`
1210
+ * resolverZod.default('list pets', 'function') // 'listPetsSchema'
1211
+ * resolverZod.resolveSchemaTypeName('pet') // 'PetSchema'
1212
+ * ```
1014
1213
  */
1015
- const resolverZod = (0, _kubb_core.defineResolver)((ctx) => {
1214
+ const resolverZod = (0, _kubb_core.defineResolver)(() => {
1016
1215
  return {
1017
1216
  name: "default",
1018
1217
  pluginName: "plugin-zod",
1019
1218
  default(name, type) {
1020
- return camelCase(name, {
1219
+ const resolved = camelCase(name, {
1021
1220
  isFile: type === "file",
1022
1221
  suffix: type ? "schema" : void 0
1023
1222
  });
1223
+ return type === "file" ? resolved : ensureValidVarName(resolved);
1024
1224
  },
1025
1225
  resolveSchemaName(name) {
1026
- return camelCase(name, { suffix: "schema" });
1226
+ return ensureValidVarName(camelCase(name, { suffix: "schema" }));
1027
1227
  },
1028
1228
  resolveSchemaTypeName(name) {
1029
- return pascalCase(name, { suffix: "schema" });
1229
+ return ensureValidVarName(pascalCase(name, { suffix: "schema" }));
1030
1230
  },
1031
1231
  resolveTypeName(name) {
1032
- return pascalCase(name);
1232
+ return ensureValidVarName(pascalCase(name));
1033
1233
  },
1034
1234
  resolvePathName(name, type) {
1035
- return ctx.default(name, type);
1235
+ return this.default(name, type);
1036
1236
  },
1037
1237
  resolveParamName(node, param) {
1038
- return ctx.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`);
1238
+ return this.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`);
1039
1239
  },
1040
1240
  resolveResponseStatusName(node, statusCode) {
1041
- return ctx.resolveSchemaName(`${node.operationId} Status ${statusCode}`);
1241
+ return this.resolveSchemaName(`${node.operationId} Status ${statusCode}`);
1042
1242
  },
1043
1243
  resolveDataName(node) {
1044
- return ctx.resolveSchemaName(`${node.operationId} Data`);
1244
+ return this.resolveSchemaName(`${node.operationId} Data`);
1045
1245
  },
1046
1246
  resolveResponsesName(node) {
1047
- return ctx.resolveSchemaName(`${node.operationId} Responses`);
1247
+ return this.resolveSchemaName(`${node.operationId} Responses`);
1048
1248
  },
1049
1249
  resolveResponseName(node) {
1050
- return ctx.resolveSchemaName(`${node.operationId} Response`);
1250
+ return this.resolveSchemaName(`${node.operationId} Response`);
1051
1251
  },
1052
1252
  resolvePathParamsName(node, param) {
1053
- return ctx.resolveParamName(node, param);
1253
+ return this.resolveParamName(node, param);
1054
1254
  },
1055
1255
  resolveQueryParamsName(node, param) {
1056
- return ctx.resolveParamName(node, param);
1256
+ return this.resolveParamName(node, param);
1057
1257
  },
1058
1258
  resolveHeaderParamsName(node, param) {
1059
- return ctx.resolveParamName(node, param);
1259
+ return this.resolveParamName(node, param);
1060
1260
  }
1061
1261
  };
1062
1262
  });
1063
1263
  //#endregion
1064
1264
  //#region src/plugin.ts
1065
1265
  /**
1066
- * Canonical plugin name for `@kubb/plugin-zod`, used in driver lookups and warnings.
1266
+ * Canonical plugin name for `@kubb/plugin-zod`. Used for driver lookups and
1267
+ * cross-plugin dependency references.
1067
1268
  */
1068
1269
  const pluginZodName = "plugin-zod";
1069
1270
  /**
1070
- * Generates Zod validation schemas from an OpenAPI specification.
1071
- * Walks schemas and operations, delegates to generators, and writes barrel files
1072
- * based on the configured `barrelType`.
1271
+ * Generates Zod v4 schemas from an OpenAPI spec. Use them to validate API
1272
+ * responses at runtime, build form schemas, or feed back into router libraries
1273
+ * that consume Zod (tRPC, Hono, Elysia). Pair with `@kubb/plugin-client` and
1274
+ * set the client's `parser: 'zod'` to validate every response automatically.
1073
1275
  *
1074
- * @example Zod schema generator
1276
+ * @example
1075
1277
  * ```ts
1076
- * import pluginZod from '@kubb/plugin-zod'
1278
+ * import { defineConfig } from 'kubb'
1279
+ * import { pluginTs } from '@kubb/plugin-ts'
1280
+ * import { pluginZod } from '@kubb/plugin-zod'
1281
+ *
1077
1282
  * export default defineConfig({
1078
- * plugins: [pluginZod({ output: { path: 'zod' } })]
1283
+ * input: { path: './petStore.yaml' },
1284
+ * output: { path: './src/gen' },
1285
+ * plugins: [
1286
+ * pluginTs(),
1287
+ * pluginZod({
1288
+ * output: { path: './zod' },
1289
+ * typed: true,
1290
+ * }),
1291
+ * ],
1079
1292
  * })
1080
1293
  * ```
1081
1294
  */
@@ -1090,7 +1303,7 @@ const pluginZod = (0, _kubb_core.definePlugin)((options) => {
1090
1303
  if (group.type === "path") return `${ctx.group.split("/")[1]}`;
1091
1304
  return `${camelCase(ctx.group)}Controller`;
1092
1305
  }
1093
- } : void 0;
1306
+ } : null;
1094
1307
  return {
1095
1308
  name: pluginZodName,
1096
1309
  options,