@kubb/plugin-zod 5.7.2 → 5.7.3

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,11 +2,10 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- //#endregion
6
5
  let kubb_kit = require("kubb/kit");
7
6
  let kubb_jsx = require("kubb/jsx");
8
7
  let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
9
- //#region ../../internals/shared/src/operation.ts
8
+ // ../../internals/shared/src/operation.ts
10
9
  /**
11
10
  * Maps a content type to the PascalCase suffix used to name per-content-type variants
12
11
  * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
@@ -89,7 +88,10 @@ function getOperationParameters(node) {
89
88
  * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
90
89
  * printer to emit `z.object(…)` rather than a record.
91
90
  */
92
- function buildOptionsSchema(node, resolver) {
91
+ function hasRequestContentTypeChoice(node) {
92
+ return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1;
93
+ }
94
+ function buildOptionsSchema(node, resolver, { pairContentTypes = false } = {}) {
93
95
  const { path, query, header } = getOperationParameters(node);
94
96
  const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
95
97
  const createNever = () => kubb_kit.ast.factory.createSchema({
@@ -114,29 +116,57 @@ function buildOptionsSchema(node, resolver) {
114
116
  resolve: resolver.param.headers
115
117
  }
116
118
  ];
117
- return kubb_kit.ast.factory.createSchema({
119
+ const createOptions = (body, extra = []) => kubb_kit.ast.factory.createSchema({
118
120
  type: "object",
119
121
  primitive: "object",
120
122
  deprecated: node.deprecated,
121
- properties: [kubb_kit.ast.factory.createProperty({
122
- name: "body",
123
- required: hasBody,
124
- schema: hasBody ? kubb_kit.ast.factory.createSchema({
125
- type: "ref",
126
- name: resolver.response.body(node)
127
- }) : createNever()
128
- }), ...groups.map(({ name, params, resolve }) => {
129
- const required = params.some((param) => param.required);
130
- return kubb_kit.ast.factory.createProperty({
131
- name,
132
- required,
133
- schema: params.length > 0 ? kubb_kit.ast.factory.createSchema({
134
- type: "ref",
135
- name: resolve.call(resolver.param, node, params[0]),
136
- optional: !required
137
- }) : createNever()
138
- });
139
- })]
123
+ properties: [
124
+ kubb_kit.ast.factory.createProperty({
125
+ name: "body",
126
+ required: hasBody,
127
+ schema: body
128
+ }),
129
+ ...groups.map(({ name, params, resolve }) => {
130
+ const required = params.some((param) => param.required);
131
+ return kubb_kit.ast.factory.createProperty({
132
+ name,
133
+ required,
134
+ schema: params.length > 0 ? kubb_kit.ast.factory.createSchema({
135
+ type: "ref",
136
+ name: resolve.call(resolver.param, node, params[0]),
137
+ optional: !required
138
+ }) : createNever()
139
+ });
140
+ }),
141
+ ...extra
142
+ ]
143
+ });
144
+ const variants = pairContentTypes && hasRequestContentTypeChoice(node) ? resolveContentTypeVariants(node.requestBody?.content ?? [], resolver.response.body(node)) : [];
145
+ if (variants.length < 2) return createOptions(hasBody ? kubb_kit.ast.factory.createSchema({
146
+ type: "ref",
147
+ name: resolver.response.body(node)
148
+ }) : createNever());
149
+ return kubb_kit.ast.factory.createSchema({
150
+ type: "union",
151
+ members: variants.map((variant, index) => createOptions(kubb_kit.ast.factory.createSchema({
152
+ type: "ref",
153
+ name: variant.name
154
+ }), [kubb_kit.ast.factory.createProperty({
155
+ name: "contentType",
156
+ required: index > 0,
157
+ schema: kubb_kit.ast.factory.createSchema({
158
+ type: "object",
159
+ primitive: "object",
160
+ properties: [kubb_kit.ast.factory.createProperty({
161
+ name: "request",
162
+ required: true,
163
+ schema: kubb_kit.ast.factory.createSchema({
164
+ type: "enum",
165
+ enumValues: [variant.contentType]
166
+ })
167
+ })]
168
+ })
169
+ })]))
140
170
  });
141
171
  }
142
172
  /**
@@ -206,8 +236,7 @@ function isSuccessStatusCode(statusCode) {
206
236
  function getSuccessResponses(responses) {
207
237
  return responses.filter((response) => isSuccessStatusCode(response.statusCode));
208
238
  }
209
- //#endregion
210
- //#region ../../internals/shared/src/adapter.ts
239
+ // ../../internals/shared/src/adapter.ts
211
240
  /**
212
241
  * Narrows the generic `Adapter` from a generator context to the OpenAPI adapter,
213
242
  * so OAS-only options (`dateType`, `enums`) and the parsed `document` are typed.
@@ -230,8 +259,7 @@ function getOasAdapter(adapter) {
230
259
  });
231
260
  return adapter;
232
261
  }
233
- //#endregion
234
- //#region ../../internals/utils/src/casing.ts
262
+ // ../../internals/utils/src/casing.ts
235
263
  /**
236
264
  * Shared implementation for camelCase and PascalCase conversion.
237
265
  * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
@@ -280,8 +308,7 @@ function camelCase(text, { prefix = "", suffix = "" } = {}) {
280
308
  function pascalCase(text, { prefix = "", suffix = "" } = {}) {
281
309
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
282
310
  }
283
- //#endregion
284
- //#region ../../internals/utils/src/reserved.ts
311
+ // ../../internals/utils/src/reserved.ts
285
312
  /**
286
313
  * JavaScript and Java reserved words.
287
314
  * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
@@ -289,6 +316,7 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
289
316
  const reservedWords = /* @__PURE__ */ new Set([
290
317
  "abstract",
291
318
  "arguments",
319
+ "await",
292
320
  "boolean",
293
321
  "break",
294
322
  "byte",
@@ -419,8 +447,7 @@ function ensureValidVarName(name) {
419
447
  function isIdentifier(name) {
420
448
  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
421
449
  }
422
- //#endregion
423
- //#region ../../internals/utils/src/strings.ts
450
+ // ../../internals/utils/src/strings.ts
424
451
  /**
425
452
  * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
426
453
  * any backslash or single quote in the content.
@@ -469,6 +496,34 @@ function stringify(value) {
469
496
  if (value === void 0 || value === null) return "''";
470
497
  return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
471
498
  }
499
+ const NEEDS_UNICODE = /(?<!\\)(?:\\\\)*\\[pPu]\{|[\u{10000}-\u{10FFFF}]/u;
500
+ const KEPT_ESCAPE = /[A-Za-z0-9^$\\.*+?()[\]{}|/]/;
501
+ /**
502
+ * Drops the backslash from escapes that the `u` flag rejects: an escaped punctuation character that is
503
+ * not a syntax character, and `\-` outside a class. Both match the same character without the backslash.
504
+ */
505
+ function dropIdentityEscapes(pattern) {
506
+ let inClass = false;
507
+ return pattern.replace(/\\(.)|[[\]]/gs, (match, escaped) => {
508
+ if (escaped === void 0) {
509
+ inClass = match === "[";
510
+ return match;
511
+ }
512
+ return KEPT_ESCAPE.test(escaped) || escaped === "-" && inClass ? match : escaped;
513
+ });
514
+ }
515
+ /**
516
+ * Builds the `RegExp` for a pattern, adding the `u` flag when it uses `\p{...}`, `\P{...}` or `\u{...}`, or
517
+ * holds a character outside the BMP. A pattern that is not valid under `u` keeps the flags it came with.
518
+ */
519
+ function toRegExp(pattern, flags) {
520
+ if (flags?.includes("u") || !NEEDS_UNICODE.test(pattern)) return new RegExp(pattern, flags);
521
+ try {
522
+ return new RegExp(dropIdentityEscapes(pattern), `${flags ?? ""}u`);
523
+ } catch {
524
+ return new RegExp(pattern, flags);
525
+ }
526
+ }
472
527
  /**
473
528
  * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
474
529
  * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
@@ -485,13 +540,11 @@ function toRegExpString(text, func = "RegExp") {
485
540
  const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
486
541
  const replacementTarget = match?.[1] ?? "";
487
542
  const matchedFlags = match?.[2];
488
- const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
489
- const { source, flags } = new RegExp(cleaned, matchedFlags);
543
+ const { source, flags } = toRegExp(raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""), matchedFlags);
490
544
  if (func === null) return `/${source}/${flags}`;
491
545
  return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
492
546
  }
493
- //#endregion
494
- //#region ../../internals/utils/src/codegen.ts
547
+ // ../../internals/utils/src/codegen.ts
495
548
  const INDENT = " ";
496
549
  /**
497
550
  * Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
@@ -560,8 +613,7 @@ function buildList(items, brackets = ["[", "]"]) {
560
613
  function lazyGetter({ name, body }) {
561
614
  return `get ${objectKey(name)}() { return ${body} }`;
562
615
  }
563
- //#endregion
564
- //#region ../../internals/utils/src/fs.ts
616
+ // ../../internals/utils/src/fs.ts
565
617
  /**
566
618
  * Builds a nested file path from a dotted name. Splits on dots that precede a letter
567
619
  * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
@@ -585,17 +637,24 @@ function toFilePath(name, caseLast = camelCase) {
585
637
  const parts = name.split(/\.(?=[a-zA-Z])/);
586
638
  return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
587
639
  }
588
- //#endregion
589
- //#region ../../internals/shared/src/resolver.ts
640
+ // ../../internals/shared/src/resolver.ts
590
641
  /**
591
- * Resolves a single operation parameter name with the
592
- * `<operationId> <in> <name>` template.
642
+ * Builds the allocation key for a declaration an operation owns. `scope` names which declaration
643
+ * it is, so two of them never share an allocation even when a custom resolver gives both the same
644
+ * name. Leave `scope` empty for the operation's own declaration.
593
645
  *
594
646
  * @example
595
- * `operationParamName.call(resolver, node, param) // → 'DeletePetPathPetId'`
647
+ * ```ts
648
+ * resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
649
+ * ```
596
650
  */
597
- function operationParamName(node, param) {
598
- return this.name(`${node.operationId} ${param.in} ${param.name}`);
651
+ function operationKey(node, ...scope) {
652
+ return [
653
+ "operation",
654
+ node.method,
655
+ node.path,
656
+ ...scope.map(String)
657
+ ];
599
658
  }
600
659
  /**
601
660
  * Builds the shared `param` namespace. Spread the result into `createResolver`
@@ -608,15 +667,33 @@ function operationParamName(node, param) {
608
667
  */
609
668
  function createOperationParamResolver() {
610
669
  return {
611
- name: operationParamName,
670
+ name(node, param) {
671
+ const name = this.name(`${node.operationId} ${param.in} ${param.name}`);
672
+ return this.resolveName({
673
+ key: operationKey(node, "param", "name", param.in, param.name),
674
+ name
675
+ });
676
+ },
612
677
  path(node) {
613
- return this.name(`${node.operationId} Path`);
678
+ const name = this.name(`${node.operationId} Path`);
679
+ return this.resolveName({
680
+ key: operationKey(node, "param", "path"),
681
+ name
682
+ });
614
683
  },
615
684
  query(node) {
616
- return this.name(`${node.operationId} Query`);
685
+ const name = this.name(`${node.operationId} Query`);
686
+ return this.resolveName({
687
+ key: operationKey(node, "param", "query"),
688
+ name
689
+ });
617
690
  },
618
691
  headers(node) {
619
- return this.name(`${node.operationId} Headers`);
692
+ const name = this.name(`${node.operationId} Headers`);
693
+ return this.resolveName({
694
+ key: operationKey(node, "param", "headers"),
695
+ name
696
+ });
620
697
  }
621
698
  };
622
699
  }
@@ -633,16 +710,32 @@ function createOperationParamResolver() {
633
710
  function createOperationResponseResolver() {
634
711
  return {
635
712
  status(node, statusCode) {
636
- return this.name(`${node.operationId} Status ${statusCode}`);
713
+ const name = this.name(`${node.operationId} Status ${statusCode}`);
714
+ return this.resolveName({
715
+ key: operationKey(node, "response", "status", statusCode),
716
+ name
717
+ });
637
718
  },
638
719
  body(node) {
639
- return this.name(`${node.operationId} Body`);
720
+ const name = this.name(`${node.operationId} Body`);
721
+ return this.resolveName({
722
+ key: operationKey(node, "response", "body"),
723
+ name
724
+ });
640
725
  },
641
726
  responses(node) {
642
- return this.name(`${node.operationId} Responses`);
727
+ const name = this.name(`${node.operationId} Responses`);
728
+ return this.resolveName({
729
+ key: operationKey(node, "response", "responses"),
730
+ name
731
+ });
643
732
  },
644
733
  response(node) {
645
- return this.name(`${node.operationId} Response`);
734
+ const name = this.name(`${node.operationId} Response`);
735
+ return this.resolveName({
736
+ key: operationKey(node, "response", "response"),
737
+ name
738
+ });
646
739
  }
647
740
  };
648
741
  }
@@ -660,8 +753,7 @@ function createCasedFile(caseLast) {
660
753
  return `${toFilePath(name, caseLast)}${extname}`;
661
754
  } };
662
755
  }
663
- //#endregion
664
- //#region ../../internals/shared/src/group.ts
756
+ // ../../internals/shared/src/group.ts
665
757
  /**
666
758
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
667
759
  * shared default naming so every plugin groups output consistently:
@@ -691,8 +783,7 @@ function createGroupConfig(group) {
691
783
  name: group.name ? group.name : defaultName
692
784
  };
693
785
  }
694
- //#endregion
695
- //#region ../../internals/shared/src/schemaTraversal.ts
786
+ // ../../internals/shared/src/schemaTraversal.ts
696
787
  /**
697
788
  * Maps each property of an object schema to its transformed output. Pairs every result with the
698
789
  * original property so the printer keeps full control over modifiers, getters, and key syntax.
@@ -730,8 +821,7 @@ function mapSchemaItems(node, transform) {
730
821
  output: transform(schema)
731
822
  }));
732
823
  }
733
- //#endregion
734
- //#region src/components/Zod.tsx
824
+ // src/components/Zod.tsx
735
825
  function Zod({ name, node, printer, inferTypeName, inferKind = "infer", typeGuards, isName, assertName, mini, cyclic, compile }) {
736
826
  const output = printer.print(node);
737
827
  const printerImports = printer.drainImports();
@@ -803,8 +893,7 @@ function Zod({ name, node, printer, inferTypeName, inferKind = "infer", typeGuar
803
893
  })
804
894
  ] });
805
895
  }
806
- //#endregion
807
- //#region src/utils.ts
896
+ // src/utils.ts
808
897
  /**
809
898
  * Returns `true` when the given coercion option enables coercion for the specified type.
810
899
  */
@@ -833,11 +922,12 @@ function isClosedKeySchema(node) {
833
922
  }
834
923
  /**
835
924
  * Whether the node is a plain inline object whose shape can be lifted into an `.extend({ … })`
836
- * argument. A catchall, `patternProperties`, or a nullable/optional wrapper cannot, so those stay
925
+ * argument. Property counts, a catchall, `patternProperties`, or a nullable/optional wrapper cannot, so those stay
837
926
  * on `.and(…)`.
838
927
  */
839
928
  function isPlainInlineObject(node) {
840
929
  if (node.type !== "object") return false;
930
+ if (node.minProperties !== void 0 || node.maxProperties !== void 0) return false;
841
931
  if (node.nullable || node.optional || node.nullish) return false;
842
932
  const hasAdditionalProperties = node.additionalProperties !== void 0;
843
933
  const hasPatternProperties = Boolean(node.patternProperties);
@@ -848,11 +938,12 @@ function isPlainInlineObject(node) {
848
938
  * `z.discriminatedUnion` option. Covers object nodes, `$ref`s that resolve to (or are still
849
939
  * unresolved) objects, single-member unions of an object, and object-composable `allOf`.
850
940
  *
851
- * `cyclicSchemas` bounds the recursion: a ref into a cycle renders as `z.lazy(…)`, not an object.
941
+ * Property counts render as a pipe. A ref into `cyclicSchemas` renders as `z.lazy(…)`.
852
942
  */
853
943
  function isObjectSchemaNode(node, cyclicSchemas) {
854
944
  if (node.nullable || node.optional || node.nullish) return false;
855
945
  if (node.type === "object") {
946
+ if (node.minProperties !== void 0 || node.maxProperties !== void 0) return false;
856
947
  const hasProperties = Boolean(node.properties?.length);
857
948
  const hasTypedAdditionalProperties = Boolean(node.additionalProperties && node.additionalProperties !== true);
858
949
  const hasPatternProperties = Boolean(node.patternProperties);
@@ -880,6 +971,49 @@ function isObjectComposableIntersection(node, cyclicSchemas) {
880
971
  const [first, ...rest] = node.members ?? [];
881
972
  return !!first && isObjectSchemaNode(first, cyclicSchemas) && rest.every(isPlainInlineObject);
882
973
  }
974
+ function preserveRequiredProperties(members) {
975
+ const hasRequiredProperty = ({ node, propertyName, seen = /* @__PURE__ */ new Set() }) => {
976
+ if (seen.has(node)) return false;
977
+ seen.add(node);
978
+ const resolved = (0, kubb_kit.syncSchemaRef)(node);
979
+ const composition = kubb_kit.ast.narrowSchema(resolved, kubb_kit.ast.schemaTypes.intersection) ?? kubb_kit.ast.narrowSchema(resolved, kubb_kit.ast.schemaTypes.union);
980
+ if (composition) {
981
+ if (composition.type === kubb_kit.ast.schemaTypes.union && composition.members?.length !== 1) return false;
982
+ return composition.members?.some((child) => hasRequiredProperty({
983
+ node: child,
984
+ propertyName,
985
+ seen
986
+ })) ?? false;
987
+ }
988
+ return kubb_kit.ast.resolveSchemaProperties({
989
+ node: resolved,
990
+ propertyName
991
+ }).some((property) => property.required !== false && !property.schema.optional && !property.schema.nullish);
992
+ };
993
+ return members.map((member, index) => {
994
+ const object = kubb_kit.ast.narrowSchema(member, kubb_kit.ast.schemaTypes.object);
995
+ if (!object || index === 0) return member;
996
+ return {
997
+ ...object,
998
+ properties: object.properties.map((property) => {
999
+ if (!members.slice(0, index).some((base) => hasRequiredProperty({
1000
+ node: base,
1001
+ propertyName: property.name
1002
+ }))) return property;
1003
+ return {
1004
+ ...property,
1005
+ required: true,
1006
+ schema: {
1007
+ ...property.schema,
1008
+ optional: false,
1009
+ nullish: false,
1010
+ nullable: property.schema.nullable || property.schema.nullish
1011
+ }
1012
+ };
1013
+ })
1014
+ };
1015
+ });
1016
+ }
883
1017
  /**
884
1018
  * Format a default value as a code-level literal.
885
1019
  * Arrays and objects keep their contents as a JSON literal, primitives become their string
@@ -926,11 +1060,20 @@ function defaultLiteral(node, value) {
926
1060
  */
927
1061
  function buildEnum(values) {
928
1062
  if (values.every((v) => typeof v === "string")) return `z.enum([${values.map((v) => formatDefault(v)).join(", ")}])`;
929
- const literals = values.map((v) => `z.literal(${formatDefault(v)})`);
1063
+ const literals = values.map((value) => buildLiteral(value));
930
1064
  if (literals.length === 1) return literals[0];
931
1065
  return `z.union([${literals.join(", ")}])`;
932
1066
  }
933
1067
  /**
1068
+ * Preserves the structure of JSON const values in both Zod APIs.
1069
+ */
1070
+ function buildLiteral(value) {
1071
+ if (value === null) return "z.null()";
1072
+ if (Array.isArray(value)) return `z.tuple([${value.map((item) => buildLiteral(item)).join(", ")}])`;
1073
+ if (typeof value === "object") return `z.strictObject({${Object.entries(value).map(([name, item]) => `${JSON.stringify(name)}: ${buildLiteral(item)}`).join(", ")}})`;
1074
+ return `z.literal(${formatDefault(value)})`;
1075
+ }
1076
+ /**
934
1077
  * Digit pattern for a `type: 'string'` schema that carries an integer `format`, the way ProtoJSON
935
1078
  * encodes 64-bit integers. Returns `undefined` for every other format, and a `pattern` from the
936
1079
  * spec takes precedence over this fallback.
@@ -1013,6 +1156,17 @@ function lengthChecksMini({ min, max, pattern, regexType }) {
1013
1156
  return checks.length ? `.check(${checks.join(", ")})` : "";
1014
1157
  }
1015
1158
  /**
1159
+ * Checks property counts before object parsing strips unknown keys or inserts defaults.
1160
+ */
1161
+ function objectConstraints({ value, node }) {
1162
+ if (node.type !== "object") return value;
1163
+ const checks = [];
1164
+ const skip = "typeof value !== \"object\" || value === null || Array.isArray(value)";
1165
+ if (node.minProperties !== void 0) checks.push(`z.refine(value => ${skip} || Object.keys(value).length >= ${node.minProperties}, { message: "Object must have at least ${node.minProperties} properties" })`);
1166
+ if (node.maxProperties !== void 0) checks.push(`z.refine(value => ${skip} || Object.keys(value).length <= ${node.maxProperties}, { message: "Object must have at most ${node.maxProperties} properties" })`);
1167
+ return checks.length ? `z.pipe(z.unknown().check(${checks.join(", ")}), ${value})` : value;
1168
+ }
1169
+ /**
1016
1170
  * Apply nullable / optional / nullish modifiers, an optional `.describe()` call, and an
1017
1171
  * optional `.meta({ examples })` call to a schema value string using the chainable Zod v4 API.
1018
1172
  */
@@ -1102,7 +1256,7 @@ function getMemberConstraint({ member, regexType, lengths, numbers }) {
1102
1256
  /**
1103
1257
  * Builds the `{ key: value, … }` shape shared by the `z.object(...)` and `.extend(...)` renderings.
1104
1258
  */
1105
- function buildObjectShape(ctx, node, modify) {
1259
+ function buildObjectShape(ctx, node, renderProperty) {
1106
1260
  const objectNode = kubb_kit.ast.narrowSchema(node, "object");
1107
1261
  if (!objectNode) return "{}";
1108
1262
  const isCyclic = (schema) => ctx.options.cyclicSchemas != null && (0, kubb_kit.containsCircularRef)(schema, { circularSchemas: ctx.options.cyclicSchemas });
@@ -1113,18 +1267,16 @@ function buildObjectShape(ctx, node, modify) {
1113
1267
  const baseOutput = ctx.transform(schema) ?? ctx.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }));
1114
1268
  if (hasSelfRef) ctx.options.cyclicSchemas = savedCyclicSchemas;
1115
1269
  return baseOutput;
1116
- }).map(({ name: propName, property, output: baseOutput }) => {
1270
+ }).map(({ name, property, output: value }) => {
1117
1271
  const { schema } = property;
1118
- const value = modify({
1119
- value: baseOutput,
1272
+ return renderProperty({
1273
+ name,
1274
+ value,
1120
1275
  schema,
1121
1276
  required: property.required,
1122
- meta: (0, kubb_kit.syncSchemaRef)(schema)
1277
+ meta: (0, kubb_kit.syncSchemaRef)(schema),
1278
+ cyclic: isCyclic(schema)
1123
1279
  });
1124
- return isCyclic(schema) ? lazyGetter({
1125
- name: propName,
1126
- body: value
1127
- }) : `${objectKey(propName)}: ${value}`;
1128
1280
  }));
1129
1281
  }
1130
1282
  /**
@@ -1139,22 +1291,28 @@ function printWithOmit(ctx, node, modify, mini = false) {
1139
1291
  if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
1140
1292
  const unwrap = omitUnwrapChain(node, mini ? "._zod.def.innerType" : ".unwrap()");
1141
1293
  const mask = `{ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }`;
1142
- const omit = (target) => mini ? `z.omit(${target}${unwrap}, ${mask})` : `${target}${unwrap}.omit(${mask})`;
1294
+ const omit = (target) => {
1295
+ const inner = `${target}${unwrap}`;
1296
+ const hasObjectConstraints = meta.type === "object" && (meta.minProperties !== void 0 || meta.maxProperties !== void 0);
1297
+ const pipe = mini ? `${inner}._zod.def` : inner;
1298
+ const object = hasObjectConstraints ? `${pipe}.out` : inner;
1299
+ const omitted = mini ? `z.omit(${object}, ${mask})` : `${object}.omit(${mask})`;
1300
+ return hasObjectConstraints ? `z.pipe(${pipe}.in, ${omitted})` : omitted;
1301
+ };
1143
1302
  const lazyMatch = transformed.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
1144
1303
  if (lazyMatch) return `z.lazy(() => ${omit(lazyMatch[1])})`;
1145
1304
  return omit(transformed);
1146
1305
  })(), meta);
1147
1306
  }
1148
- //#endregion
1149
- //#region src/printers/printerZod.ts
1307
+ // src/printers/printerZod.ts
1150
1308
  function strictOneOfMember(member, node, cyclicSchemas) {
1151
- if (node.type === "ref") {
1309
+ if (node.type === kubb_kit.ast.schemaTypes.ref) {
1152
1310
  if (member.startsWith("z.lazy(")) return member;
1153
1311
  const refName = kubb_kit.ast.resolveRefName(node);
1154
1312
  if (refName && cyclicSchemas?.has(refName)) return member;
1155
1313
  const schema = (0, kubb_kit.syncSchemaRef)(node);
1156
1314
  if (schema.nullable || schema.optional || node.nullable || node.optional) return member;
1157
- if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
1315
+ if (schema.type === kubb_kit.ast.schemaTypes.object && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
1158
1316
  }
1159
1317
  return member;
1160
1318
  }
@@ -1162,28 +1320,70 @@ function strictOneOfMember(member, node, cyclicSchemas) {
1162
1320
  * Builds the `{ key: value, … }` shape for an object node with the chainable modifiers.
1163
1321
  */
1164
1322
  function buildZodObjectShape(ctx, node) {
1165
- return buildObjectShape(ctx, node, ({ value, schema, required, meta }) => applyModifiers({
1166
- value,
1167
- schema,
1168
- nullable: meta.nullable,
1169
- optional: schema.optional || required === false,
1170
- nullish: schema.nullish,
1171
- defaultValue: meta.default,
1172
- description: schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description,
1173
- examples: meta.examples
1174
- }));
1323
+ return buildObjectShape(ctx, node, ({ name, value, schema, required, meta, cyclic }) => {
1324
+ const body = applyModifiers({
1325
+ value,
1326
+ schema,
1327
+ nullable: meta.nullable,
1328
+ optional: schema.optional || required === false,
1329
+ nullish: schema.nullish,
1330
+ defaultValue: meta.default,
1331
+ description: schema.type !== kubb_kit.ast.schemaTypes.ref && meta.type === kubb_kit.ast.schemaTypes.ref ? void 0 : meta.description,
1332
+ examples: meta.examples
1333
+ });
1334
+ if (!cyclic) return `${objectKey(name)}: ${body}`;
1335
+ const returnType = recursiveGetterType({
1336
+ ctx,
1337
+ schema,
1338
+ required
1339
+ });
1340
+ return returnType ? `get ${objectKey(name)}(): ${returnType} { return ${body} }` : lazyGetter({
1341
+ name,
1342
+ body
1343
+ });
1344
+ });
1345
+ }
1346
+ /**
1347
+ * Breaks getter inference cycles without widening recursive refs and arrays to `z.ZodType`.
1348
+ */
1349
+ function recursiveGetterType({ ctx, schema, required }) {
1350
+ function baseType(schema) {
1351
+ if (ctx.options.nodes?.[schema.type]) return void 0;
1352
+ if (schema.type === kubb_kit.ast.schemaTypes.ref) {
1353
+ const saved = ctx.options.cyclicSchemas;
1354
+ ctx.options.cyclicSchemas = void 0;
1355
+ const name = ctx.transform(schema);
1356
+ ctx.options.cyclicSchemas = saved;
1357
+ return name ? `typeof ${name}` : void 0;
1358
+ }
1359
+ if (schema.type === kubb_kit.ast.schemaTypes.array && schema.items?.length === 1) {
1360
+ const item = baseType(schema.items[0]);
1361
+ return item ? `z.ZodArray<${item}>` : void 0;
1362
+ }
1363
+ }
1364
+ const base = baseType(schema);
1365
+ if (!base) return void 0;
1366
+ const meta = (0, kubb_kit.syncSchemaRef)(schema);
1367
+ const optional = schema.optional || required === false;
1368
+ const wrapped = (() => {
1369
+ if (schema.nullish || meta.nullable && optional) return `z.ZodOptional<z.ZodNullable<${base}>>`;
1370
+ if (optional) return `z.ZodOptional<${base}>`;
1371
+ if (meta.nullable) return `z.ZodNullable<${base}>`;
1372
+ return base;
1373
+ })();
1374
+ return meta.default !== void 0 && defaultLiteral(schema, meta.default) !== null ? `z.ZodDefault<${wrapped}>` : wrapped;
1175
1375
  }
1176
1376
  /**
1177
1377
  * Types the direction probe skips. They delegate to their children rather than reading
1178
1378
  * `direction` themselves, so {@link containsDirectionalNode} walks into the children instead.
1179
1379
  */
1180
1380
  const CONTAINER_TYPES = /* @__PURE__ */ new Set([
1181
- "object",
1182
- "array",
1183
- "tuple",
1184
- "union",
1185
- "intersection",
1186
- "ref"
1381
+ kubb_kit.ast.schemaTypes.object,
1382
+ kubb_kit.ast.schemaTypes.array,
1383
+ kubb_kit.ast.schemaTypes.tuple,
1384
+ kubb_kit.ast.schemaTypes.union,
1385
+ kubb_kit.ast.schemaTypes.intersection,
1386
+ kubb_kit.ast.schemaTypes.ref
1187
1387
  ]);
1188
1388
  /**
1189
1389
  * Runs the node's effective handler (a `printer.nodes` override, else the built-in) once per
@@ -1215,7 +1415,7 @@ function variesByDirection({ node, printerOptions }) {
1215
1415
  */
1216
1416
  function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */ new Set() }) {
1217
1417
  if (!node) return false;
1218
- if (node.type === "ref") {
1418
+ if (node.type === kubb_kit.ast.schemaTypes.ref) {
1219
1419
  if (!node.ref) return false;
1220
1420
  const refName = (0, kubb_kit.extractRefName)(node.ref);
1221
1421
  if (refName) {
@@ -1223,7 +1423,7 @@ function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */
1223
1423
  seen.add(refName);
1224
1424
  }
1225
1425
  const resolved = (0, kubb_kit.syncSchemaRef)(node);
1226
- if (resolved.type === "ref") return false;
1426
+ if (resolved.type === kubb_kit.ast.schemaTypes.ref) return false;
1227
1427
  return containsDirectionalNode({
1228
1428
  node: resolved,
1229
1429
  printerOptions,
@@ -1239,7 +1439,7 @@ function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */
1239
1439
  if ("items" in node && node.items) children.push(...node.items);
1240
1440
  if ("members" in node && node.members) children.push(...node.members);
1241
1441
  if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
1242
- const propertyNames = node.type === "object" ? node.propertyNames : void 0;
1442
+ const propertyNames = node.type === kubb_kit.ast.schemaTypes.object ? node.propertyNames : void 0;
1243
1443
  if (propertyNames) children.push(propertyNames);
1244
1444
  return children.some((child) => containsDirectionalNode({
1245
1445
  node: child,
@@ -1251,7 +1451,7 @@ function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */
1251
1451
  * Names of the `$ref` schemas the generator should route to their input (encode) variant.
1252
1452
  */
1253
1453
  function collectDirectionalRefNames({ node, printerOptions }) {
1254
- return kubb_kit.ast.collectSync(node, { schema: (n) => n.type === "ref" && n.ref && containsDirectionalNode({
1454
+ return kubb_kit.ast.collectSync(node, { schema: (n) => n.type === kubb_kit.ast.schemaTypes.ref && n.ref && containsDirectionalNode({
1255
1455
  node: n,
1256
1456
  printerOptions
1257
1457
  }) ? kubb_kit.ast.resolveRefName(n) ?? void 0 : void 0 });
@@ -1343,7 +1543,7 @@ const scalarNodes = {
1343
1543
  enum(node) {
1344
1544
  const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
1345
1545
  if (node.namedEnumValues?.length) {
1346
- const literals = nonNullValues.map((v) => `z.literal(${formatDefault(v)})`);
1546
+ const literals = nonNullValues.map((v) => buildLiteral(v));
1347
1547
  if (literals.length === 1) return literals[0];
1348
1548
  return `z.union([${literals.join(", ")}])`;
1349
1549
  }
@@ -1364,6 +1564,7 @@ const scalarNodes = {
1364
1564
  */
1365
1565
  const printerZod = kubb_kit.ast.createPrinter((options) => {
1366
1566
  const cyclicSchemaNames = options.cyclicSchemas;
1567
+ const unionsWithSiblings = /* @__PURE__ */ new WeakSet();
1367
1568
  return {
1368
1569
  name: "zod",
1369
1570
  options,
@@ -1389,37 +1590,40 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
1389
1590
  const isStrict = node.additionalProperties === false && patterns.length === 0;
1390
1591
  const isLoose = node.additionalProperties === true;
1391
1592
  const objectBase = `${isStrict ? "z.strictObject" : isLoose ? "z.looseObject" : "z.object"}(${buildZodObjectShape(this, node)})`;
1392
- return (() => {
1393
- const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
1394
- if (node.additionalProperties && node.additionalProperties !== true) {
1395
- const catchallType = this.transform(node.additionalProperties);
1396
- if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
1397
- return catchallType ? `${objectBase}.catchall(${catchallType})` : objectBase;
1398
- }
1399
- if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) {
1400
- const unknownType = this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }));
1401
- return `${recordFn}(${propertyNamesKeySchema}, ${unknownType})`;
1402
- }
1403
- if (node.additionalProperties === true) return objectBase;
1404
- if (isStrict) return objectBase;
1405
- if (patterns.length > 0) {
1406
- const values = patterns.map(([, valueSchema]) => {
1407
- const valueType = this.transform(valueSchema) ?? this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }));
1408
- return valueSchema.nullable ? `${valueType}.nullable()` : valueType;
1409
- });
1410
- const distinct = [...new Set(values)];
1411
- const value = distinct.length === 1 ? distinct[0] : `z.union([${distinct.join(", ")}])`;
1412
- if (entries.length > 0) return `${objectBase}.catchall(${value})`;
1413
- return `z.record(${patternKeySchema({
1414
- patterns: patterns.map(([pattern]) => pattern),
1415
- regexType: this.options.regexType
1416
- })}, ${value})`;
1417
- }
1418
- return objectBase;
1419
- })();
1593
+ return objectConstraints({
1594
+ value: (() => {
1595
+ const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
1596
+ if (node.additionalProperties && node.additionalProperties !== true) {
1597
+ const catchallType = this.transform(node.additionalProperties);
1598
+ if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
1599
+ return catchallType ? `${objectBase}.catchall(${catchallType})` : objectBase;
1600
+ }
1601
+ if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) {
1602
+ const unknownType = this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }));
1603
+ return `${recordFn}(${propertyNamesKeySchema}, ${unknownType})`;
1604
+ }
1605
+ if (node.additionalProperties === true) return objectBase;
1606
+ if (isStrict) return objectBase;
1607
+ if (patterns.length > 0) {
1608
+ const values = patterns.map(([, valueSchema]) => {
1609
+ const valueType = this.transform(valueSchema) ?? this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }));
1610
+ return valueSchema.nullable ? `${valueType}.nullable()` : valueType;
1611
+ });
1612
+ const distinct = [...new Set(values)];
1613
+ const value = distinct.length === 1 ? distinct[0] : `z.union([${distinct.join(", ")}])`;
1614
+ if (entries.length > 0) return `${objectBase}.catchall(${value})`;
1615
+ return `z.record(${patternKeySchema({
1616
+ patterns: patterns.map(([pattern]) => pattern),
1617
+ regexType: this.options.regexType
1618
+ })}, ${value})`;
1619
+ }
1620
+ return objectBase;
1621
+ })(),
1622
+ node
1623
+ });
1420
1624
  },
1421
1625
  array(node) {
1422
- const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }))})${lengthConstraints({
1626
+ const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }))})${lengthConstraints({
1423
1627
  ...node,
1424
1628
  regexType: this.options.regexType
1425
1629
  })}`;
@@ -1432,7 +1636,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
1432
1636
  const nodeMembers = node.members ?? [];
1433
1637
  const isDiscriminated = !!node.discriminatorPropertyName && nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
1434
1638
  const isXor = node.strategy === "one" && !isDiscriminated && this.options.oneOfType === "xor";
1435
- const isStrict = node.strategy === "one" && !isXor;
1639
+ const isStrict = node.strategy === "one" && !isXor && !unionsWithSiblings.has(node);
1436
1640
  const members = mapSchemaMembers(node, (memberNode) => this.transform(isStrict ? strictOneOfNode(memberNode) : memberNode)).map(({ schema, output }) => output && isStrict ? strictOneOfMember(output, schema, cyclicSchemaNames) : output).filter(Boolean);
1437
1641
  if (members.length === 0) return "";
1438
1642
  if (members.length === 1) return members[0];
@@ -1443,11 +1647,21 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
1443
1647
  intersection(node) {
1444
1648
  const members = node.members ?? [];
1445
1649
  if (members.length === 0) return "";
1650
+ const hasSiblingProperties = members.some((member) => member.type === kubb_kit.ast.schemaTypes.object && member.properties.length > 0);
1651
+ const transform = (member) => {
1652
+ if (!hasSiblingProperties) return this.transform(member);
1653
+ unionsWithSiblings.add(member);
1654
+ try {
1655
+ return this.transform(member);
1656
+ } finally {
1657
+ unionsWithSiblings.delete(member);
1658
+ }
1659
+ };
1446
1660
  const [first, ...rest] = members;
1447
1661
  if (!first) return "";
1448
- const firstBase = this.transform(first);
1662
+ const firstBase = transform(first);
1449
1663
  if (!firstBase) return "";
1450
- if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return rest.reduce((acc, member) => `${acc}.extend(${buildZodObjectShape(this, member)})`, firstBase);
1664
+ if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return preserveRequiredProperties(members).slice(1).reduce((acc, member) => `${acc}.extend(${buildZodObjectShape(this, member)})`, firstBase);
1451
1665
  return rest.reduce((acc, member) => {
1452
1666
  const constraint = getMemberConstraint({
1453
1667
  member,
@@ -1456,7 +1670,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
1456
1670
  numbers: numberConstraints
1457
1671
  });
1458
1672
  if (constraint) return acc + constraint;
1459
- const transformed = this.transform(member);
1673
+ const transformed = transform(member);
1460
1674
  return transformed ? `${acc}.and(${transformed})` : acc;
1461
1675
  }, firstBase);
1462
1676
  }
@@ -1476,20 +1690,25 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
1476
1690
  }
1477
1691
  };
1478
1692
  });
1479
- //#endregion
1480
- //#region src/printers/printerZodMini.ts
1693
+ // src/printers/printerZodMini.ts
1481
1694
  /**
1482
1695
  * Builds the `{ key: value, … }` shape for an object node with the functional `zod/mini` modifiers.
1483
1696
  */
1484
1697
  function buildZodMiniObjectShape(ctx, node) {
1485
- return buildObjectShape(ctx, node, ({ value, schema, required, meta }) => applyMiniModifiers({
1486
- value,
1487
- schema,
1488
- nullable: meta.nullable,
1489
- optional: schema.optional || required === false,
1490
- nullish: schema.nullish,
1491
- defaultValue: meta.default
1492
- }));
1698
+ return buildObjectShape(ctx, node, ({ name, value, schema, required, meta, cyclic }) => {
1699
+ const body = applyMiniModifiers({
1700
+ value,
1701
+ schema,
1702
+ nullable: meta.nullable,
1703
+ optional: schema.optional || required === false,
1704
+ nullish: schema.nullish,
1705
+ defaultValue: meta.default
1706
+ });
1707
+ return cyclic ? lazyGetter({
1708
+ name,
1709
+ body
1710
+ }) : `${objectKey(name)}: ${body}`;
1711
+ });
1493
1712
  }
1494
1713
  /**
1495
1714
  * Zod v4 Mini printer built with `definePrinter`.
@@ -1505,6 +1724,7 @@ function buildZodMiniObjectShape(ctx, node) {
1505
1724
  */
1506
1725
  const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1507
1726
  const cyclicSchemaNames = options.cyclicSchemas;
1727
+ const unionsWithSiblings = /* @__PURE__ */ new WeakSet();
1508
1728
  return {
1509
1729
  name: "zod-mini",
1510
1730
  options,
@@ -1577,7 +1797,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1577
1797
  enum(node) {
1578
1798
  const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
1579
1799
  if (node.namedEnumValues?.length) {
1580
- const literals = nonNullValues.map((v) => `z.literal(${formatDefault(v)})`);
1800
+ const literals = nonNullValues.map((v) => buildLiteral(v));
1581
1801
  if (literals.length === 1) return literals[0];
1582
1802
  return `z.union([${literals.join(", ")}])`;
1583
1803
  }
@@ -1599,32 +1819,40 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1599
1819
  const isStrict = node.additionalProperties === false && patterns.length === 0;
1600
1820
  const isLoose = node.additionalProperties === true;
1601
1821
  const objectBase = `${isStrict ? "z.strictObject" : isLoose ? "z.looseObject" : "z.object"}(${buildZodMiniObjectShape(this, node)})`;
1602
- const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
1603
- if (node.additionalProperties && node.additionalProperties !== true) {
1604
- const catchallType = this.transform(node.additionalProperties);
1605
- if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
1606
- return catchallType ? `z.catchall(${objectBase}, ${catchallType})` : objectBase;
1607
- }
1608
- if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) return `${recordFn}(${propertyNamesKeySchema}, ${this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }))})`;
1609
- if (node.additionalProperties === true) return objectBase;
1610
- if (isStrict) return objectBase;
1611
- if (patterns.length > 0) {
1612
- const values = patterns.map(([, valueSchema]) => {
1613
- const valueType = this.transform(valueSchema) ?? this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }));
1614
- return valueSchema.nullable ? `z.nullable(${valueType})` : valueType;
1615
- });
1616
- const distinct = [...new Set(values)];
1617
- const value = distinct.length === 1 ? distinct[0] : `z.union([${distinct.join(", ")}])`;
1618
- if (entries.length > 0) return `z.catchall(${objectBase}, ${value})`;
1619
- return `z.record(${patternKeySchemaMini({
1620
- patterns: patterns.map(([pattern]) => pattern),
1621
- regexType: this.options.regexType
1622
- })}, ${value})`;
1623
- }
1624
- return objectBase;
1822
+ return objectConstraints({
1823
+ value: (() => {
1824
+ const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
1825
+ if (node.additionalProperties && node.additionalProperties !== true) {
1826
+ const catchallType = this.transform(node.additionalProperties);
1827
+ if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
1828
+ return catchallType ? `z.catchall(${objectBase}, ${catchallType})` : objectBase;
1829
+ }
1830
+ if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) {
1831
+ const unknownType = this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }));
1832
+ return `${recordFn}(${propertyNamesKeySchema}, ${unknownType})`;
1833
+ }
1834
+ if (node.additionalProperties === true) return objectBase;
1835
+ if (isStrict) return objectBase;
1836
+ if (patterns.length > 0) {
1837
+ const values = patterns.map(([, valueSchema]) => {
1838
+ const valueType = this.transform(valueSchema) ?? this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }));
1839
+ return valueSchema.nullable ? `z.nullable(${valueType})` : valueType;
1840
+ });
1841
+ const distinct = [...new Set(values)];
1842
+ const value = distinct.length === 1 ? distinct[0] : `z.union([${distinct.join(", ")}])`;
1843
+ if (entries.length > 0) return `z.catchall(${objectBase}, ${value})`;
1844
+ return `z.record(${patternKeySchemaMini({
1845
+ patterns: patterns.map(([pattern]) => pattern),
1846
+ regexType: this.options.regexType
1847
+ })}, ${value})`;
1848
+ }
1849
+ return objectBase;
1850
+ })(),
1851
+ node
1852
+ });
1625
1853
  },
1626
1854
  array(node) {
1627
- const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }))})${lengthChecksMini({
1855
+ const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }))})${lengthChecksMini({
1628
1856
  ...node,
1629
1857
  regexType: this.options.regexType
1630
1858
  })}`;
@@ -1637,7 +1865,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1637
1865
  const nodeMembers = node.members ?? [];
1638
1866
  const isDiscriminated = !!node.discriminatorPropertyName && nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
1639
1867
  const isXor = node.strategy === "one" && !isDiscriminated && this.options.oneOfType === "xor";
1640
- const isStrict = node.strategy === "one" && !isXor;
1868
+ const isStrict = node.strategy === "one" && !isXor && !unionsWithSiblings.has(node);
1641
1869
  const members = mapSchemaMembers(node, (memberNode) => this.transform(isStrict ? strictOneOfNode(memberNode) : memberNode)).map(({ output }) => output).filter(Boolean);
1642
1870
  if (members.length === 0) return "";
1643
1871
  if (members.length === 1) return members[0];
@@ -1648,11 +1876,21 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1648
1876
  intersection(node) {
1649
1877
  const members = node.members ?? [];
1650
1878
  if (members.length === 0) return "";
1879
+ const hasSiblingProperties = members.some((member) => member.type === kubb_kit.ast.schemaTypes.object && member.properties.length > 0);
1880
+ const transform = (member) => {
1881
+ if (!hasSiblingProperties) return this.transform(member);
1882
+ unionsWithSiblings.add(member);
1883
+ try {
1884
+ return this.transform(member);
1885
+ } finally {
1886
+ unionsWithSiblings.delete(member);
1887
+ }
1888
+ };
1651
1889
  const [first, ...rest] = members;
1652
1890
  if (!first) return "";
1653
- const firstBase = this.transform(first);
1891
+ const firstBase = transform(first);
1654
1892
  if (!firstBase) return "";
1655
- if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return rest.reduce((acc, member) => `z.extend(${acc}, ${buildZodMiniObjectShape(this, member)})`, firstBase);
1893
+ if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return preserveRequiredProperties(members).slice(1).reduce((acc, member) => `z.extend(${acc}, ${buildZodMiniObjectShape(this, member)})`, firstBase);
1656
1894
  return rest.reduce((acc, member) => {
1657
1895
  const constraint = getMemberConstraint({
1658
1896
  member,
@@ -1661,7 +1899,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1661
1899
  numbers: numberChecksMini
1662
1900
  });
1663
1901
  if (constraint) return acc + constraint;
1664
- const transformed = this.transform(member);
1902
+ const transformed = transform(member);
1665
1903
  return transformed ? `z.intersection(${acc}, ${transformed})` : acc;
1666
1904
  }, firstBase);
1667
1905
  }
@@ -1679,8 +1917,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1679
1917
  }
1680
1918
  };
1681
1919
  });
1682
- //#endregion
1683
- //#region src/generators/zodGenerator.tsx
1920
+ // src/generators/zodGenerator.tsx
1684
1921
  /**
1685
1922
  * The helper an inferred alias is printed with. `'codec'` reads a request (encode) schema from its
1686
1923
  * input and a response (decode) schema from its output; `true` keeps `z.infer` for both.
@@ -2141,17 +2378,14 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
2141
2378
  });
2142
2379
  }
2143
2380
  });
2144
- //#endregion
2145
- //#region kubb-extension.json
2381
+ // kubb-extension.json
2146
2382
  var compatibility = {
2147
- "kubb": ">=5.8.3",
2383
+ "kubb": ">=5.14.6",
2148
2384
  "node": ">=22.22"
2149
2385
  };
2150
- //#endregion
2151
- //#region package.json
2152
- var version = "5.7.2";
2153
- //#endregion
2154
- //#region src/resolvers/resolverZod.ts
2386
+ // package.json
2387
+ var version = "5.7.3";
2388
+ // src/resolvers/resolverZod.ts
2155
2389
  /**
2156
2390
  * Default resolver used by `@kubb/plugin-zod`. Decides the names and file
2157
2391
  * paths for every generated Zod schema. Schemas use camelCase with a
@@ -2197,15 +2431,22 @@ const resolverZod = (0, kubb_kit.createResolver)({
2197
2431
  response: {
2198
2432
  ...createOperationResponseResolver(),
2199
2433
  error(node) {
2200
- return this.name(`${node.operationId} Error`);
2434
+ const name = this.name(`${node.operationId} Error`);
2435
+ return this.resolveName({
2436
+ key: operationKey(node, "response", "error"),
2437
+ name
2438
+ });
2201
2439
  },
2202
2440
  options(node) {
2203
- return this.schema.type(this.name(`${node.operationId} Options`));
2441
+ const name = this.schema.type(this.name(`${node.operationId} Options`));
2442
+ return this.resolveName({
2443
+ key: operationKey(node, "response", "options"),
2444
+ name
2445
+ });
2204
2446
  }
2205
2447
  }
2206
2448
  });
2207
- //#endregion
2208
- //#region src/plugin.ts
2449
+ // src/plugin.ts
2209
2450
  /**
2210
2451
  * Canonical plugin name for `@kubb/plugin-zod`. Used for driver lookups and
2211
2452
  * cross-plugin dependency references.
@@ -2271,7 +2512,6 @@ const pluginZod = (0, kubb_kit.defineExtension)({
2271
2512
  };
2272
2513
  }
2273
2514
  });
2274
- //#endregion
2275
2515
  exports.default = pluginZod;
2276
2516
  exports.pluginZod = pluginZod;
2277
2517
  exports.pluginZodName = pluginZodName;