@kubb/plugin-zod 5.4.9 → 5.4.12

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.js CHANGED
@@ -1,24 +1,6 @@
1
- import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
2
- import { Resolver, addGenerator, ast, containsCircularRef, createResolver, defineExtension, defineGenerator, extractRefName, setMacros, setResolver, syncSchemaRef } from "kubb/kit";
1
+ import { Diagnostics, Resolver, addGenerator, assertPluginOption, ast, containsCircularRef, createResolver, defineExtension, defineGenerator, extractRefName, setMacros, setResolver, syncSchemaRef } from "kubb/kit";
3
2
  import { Const, File, Function, Type, jsxRenderer } from "kubb/jsx";
4
3
  import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
5
- //#region ../../internals/shared/src/params.ts
6
- /**
7
- * Drops parameters that share the same name, keeping the first.
8
- *
9
- * A malformed spec can declare the same parameter name twice within one `in` location. Both would
10
- * resolve to the same output property, so emitting both would yield an object type with a duplicate
11
- * member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
12
- * parameter names flow through unchanged, so no two distinct names ever collide here anymore.
13
- */
14
- function dedupeParams(params) {
15
- const seen = /* @__PURE__ */ new Set();
16
- return params.filter((param) => {
17
- if (seen.has(param.name)) return false;
18
- seen.add(param.name);
19
- return true;
20
- });
21
- }
22
4
  //#endregion
23
5
  //#region ../../internals/shared/src/operation.ts
24
6
  /**
@@ -79,11 +61,19 @@ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
79
61
  function getOperationParameters(node) {
80
62
  const cached = operationParameterGroupsByNode.get(node);
81
63
  if (cached) return cached;
64
+ const group = (location) => {
65
+ const seen = /* @__PURE__ */ new Set();
66
+ return node.parameters.filter((param) => {
67
+ if (param.in !== location || seen.has(param.name)) return false;
68
+ seen.add(param.name);
69
+ return true;
70
+ });
71
+ };
82
72
  const groups = {
83
- path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
84
- query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
85
- header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
86
- cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
73
+ path: group("path"),
74
+ query: group("query"),
75
+ header: group("header"),
76
+ cookie: group("cookie")
87
77
  };
88
78
  operationParameterGroupsByNode.set(node, groups);
89
79
  return groups;
@@ -227,7 +217,13 @@ function getSuccessResponses(responses) {
227
217
  * ```
228
218
  */
229
219
  function getOasAdapter(adapter) {
230
- if (adapter.name !== "oas") throw new Error(`Expected the OpenAPI adapter (adapterOas), but received "${adapter.name}". Configure \`adapter: adapterOas()\` in your Kubb config.`);
220
+ if (adapter.name !== "oas") throw new Diagnostics.Error({
221
+ code: Diagnostics.code.adapterRequired,
222
+ severity: "error",
223
+ message: `Expected the OpenAPI adapter (adapterOas), but received "${adapter.name}".`,
224
+ help: "Set `adapter: adapterOas()` in kubb.config.ts.",
225
+ location: { kind: "config" }
226
+ });
231
227
  return adapter;
232
228
  }
233
229
  //#endregion
@@ -650,20 +646,6 @@ function createCasedFile(caseLast) {
650
646
  } };
651
647
  }
652
648
  //#endregion
653
- //#region ../../internals/shared/src/refs.ts
654
- /**
655
- * Collects the resolved target name of every pointer-carrying ref in a schema tree, in
656
- * first-occurrence order. Use this for name-only checks (e.g. redeclaration detection) where
657
- * `resolver.imports` would resolve file paths that are then discarded.
658
- */
659
- function collectRefNames(schema) {
660
- return ast.collectSync(schema, { schema: (node) => {
661
- const refNode = ast.narrowSchema(node, "ref");
662
- if (!refNode?.ref) return null;
663
- return ast.resolveRefName(refNode);
664
- } });
665
- }
666
- //#endregion
667
649
  //#region ../../internals/shared/src/group.ts
668
650
  /**
669
651
  * Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
@@ -807,13 +789,6 @@ function Zod({ name, node, printer, inferTypeName, typeGuards, isName, assertNam
807
789
  ] });
808
790
  }
809
791
  //#endregion
810
- //#region src/constants.ts
811
- /**
812
- * Import paths that use a namespace import (`import * as z from '...'`).
813
- * All other import paths use a named import (`import { z } from '...'`).
814
- */
815
- const ZOD_NAMESPACE_IMPORTS = /* @__PURE__ */ new Set(["zod", "zod/mini"]);
816
- //#endregion
817
792
  //#region src/utils.ts
818
793
  /**
819
794
  * Returns `true` when the given coercion option enables coercion for the specified type.
@@ -823,8 +798,8 @@ function shouldCoerce(coercion, type) {
823
798
  if (coercion === true) return true;
824
799
  return !!coercion[type];
825
800
  }
826
- function hasPropertyNames(node) {
827
- return "propertyNames" in node && Boolean(node.propertyNames);
801
+ function propertyNamesOf(node) {
802
+ return "propertyNames" in node ? node.propertyNames : void 0;
828
803
  }
829
804
  /**
830
805
  * Whether the schema node represents a closed or finite set of keys (e.g. enum, literal,
@@ -854,7 +829,7 @@ function isPlainInlineObject(node) {
854
829
  if (node.nullable || node.optional || node.nullish) return false;
855
830
  const hasAdditionalProperties = node.additionalProperties !== void 0;
856
831
  const hasPatternProperties = Boolean(node.patternProperties);
857
- return !hasAdditionalProperties && !hasPatternProperties && !hasPropertyNames(node);
832
+ return !hasAdditionalProperties && !hasPatternProperties && !propertyNamesOf(node);
858
833
  }
859
834
  /**
860
835
  * Whether a node renders as a bare Zod object — one that accepts `.extend(…)` and can be a
@@ -869,7 +844,7 @@ function isObjectSchemaNode(node, cyclicSchemas) {
869
844
  const hasProperties = Boolean(node.properties?.length);
870
845
  const hasTypedAdditionalProperties = Boolean(node.additionalProperties && node.additionalProperties !== true);
871
846
  const hasPatternProperties = Boolean(node.patternProperties);
872
- return !(!hasProperties && (hasTypedAdditionalProperties || hasPatternProperties || hasPropertyNames(node)));
847
+ return !(!hasProperties && (hasTypedAdditionalProperties || hasPatternProperties || propertyNamesOf(node)));
873
848
  }
874
849
  if (node.type === "ref") {
875
850
  const refName = ast.resolveRefName(node);
@@ -926,28 +901,20 @@ function defaultLiteral(node, value) {
926
901
  const values = enumNode.namedEnumValues?.map((member) => member.value) ?? enumNode.enumValues ?? [];
927
902
  if (values.length) {
928
903
  const match = values.find((member) => member === value || String(member) === String(value));
929
- return match != null ? formatLiteral(match) : null;
904
+ return match != null ? formatDefault(match) : null;
930
905
  }
931
906
  }
932
907
  return formatDefault(value);
933
908
  }
934
909
  /**
935
- * Format a primitive enum/literal value.
936
- * Strings are quoted; numbers and booleans are emitted raw.
937
- */
938
- function formatLiteral(v) {
939
- if (typeof v === "string") return stringify(v);
940
- return String(v);
941
- }
942
- /**
943
910
  * Build the Zod schema for a set of literal enum values.
944
911
  * `z.enum()` only accepts string members in Zod v4, so a numeric, boolean, or
945
912
  * mixed set is emitted as a single `z.literal(…)` or a `z.union([z.literal(…), …])`.
946
913
  * An all-string set keeps the more compact `z.enum([…])`.
947
914
  */
948
915
  function buildEnum(values) {
949
- if (values.every((v) => typeof v === "string")) return `z.enum([${values.map(formatLiteral).join(", ")}])`;
950
- const literals = values.map((v) => `z.literal(${formatLiteral(v)})`);
916
+ if (values.every((v) => typeof v === "string")) return `z.enum([${values.map((v) => formatDefault(v)).join(", ")}])`;
917
+ const literals = values.map((v) => `z.literal(${formatDefault(v)})`);
951
918
  if (literals.length === 1) return literals[0];
952
919
  return `z.union([${literals.join(", ")}])`;
953
920
  }
@@ -966,33 +933,26 @@ function integerFormatPattern(format) {
966
933
  if (format === "uint64") return "^\\d+$";
967
934
  }
968
935
  /**
969
- * Map a `regexType` to the `func` argument of `toRegExpString`: `'constructor'` emits
970
- * `new RegExp(...)`, while `'literal'` (the default) emits a regex literal.
936
+ * Renders a `pattern` as a regex literal, or as `new RegExp(...)` when `regexType` is `'constructor'`.
971
937
  */
972
- function regexFunc(regexType) {
973
- return regexType === "constructor" ? "RegExp" : null;
938
+ function regexSource(pattern, regexType) {
939
+ return toRegExpString(pattern, regexType === "constructor" ? "RegExp" : null);
940
+ }
941
+ function joinPatterns(patterns) {
942
+ return patterns.length === 1 ? patterns[0] : patterns.map((pattern) => `(${pattern})`).join("|");
974
943
  }
975
944
  /**
976
945
  * Builds a Zod record key schema that enforces the `patternProperties` regexes a plain
977
- * `.catchall()` would drop. Several patterns combine into one alternation (`(^a)|(^b)`).
946
+ * `.catchall()` would drop.
978
947
  */
979
948
  function patternKeySchema({ patterns, regexType }) {
980
- return `z.string().regex(${patternKeySource({
981
- patterns,
982
- regexType
983
- })})`;
949
+ return `z.string().regex(${regexSource(joinPatterns(patterns), regexType)})`;
984
950
  }
985
951
  /**
986
952
  * `zod/mini` variant of {@link patternKeySchema}, wrapping the regex in `.check(z.regex(...))`.
987
953
  */
988
954
  function patternKeySchemaMini({ patterns, regexType }) {
989
- return `z.string().check(z.regex(${patternKeySource({
990
- patterns,
991
- regexType
992
- })}))`;
993
- }
994
- function patternKeySource({ patterns, regexType }) {
995
- return toRegExpString(patterns.length === 1 ? patterns[0] : patterns.map((pattern) => `(${pattern})`).join("|"), regexFunc(regexType));
955
+ return `z.string().check(z.regex(${regexSource(joinPatterns(patterns), regexType)}))`;
996
956
  }
997
957
  /**
998
958
  * Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
@@ -1015,7 +975,7 @@ function lengthConstraints({ min, max, pattern, regexType }) {
1015
975
  return [
1016
976
  min !== void 0 ? `.min(${min})` : "",
1017
977
  max !== void 0 ? `.max(${max})` : "",
1018
- pattern !== void 0 ? `.regex(${toRegExpString(pattern, regexFunc(regexType))})` : ""
978
+ pattern !== void 0 ? `.regex(${regexSource(pattern, regexType)})` : ""
1019
979
  ].join("");
1020
980
  }
1021
981
  /**
@@ -1037,7 +997,7 @@ function lengthChecksMini({ min, max, pattern, regexType }) {
1037
997
  const checks = [];
1038
998
  if (min !== void 0) checks.push(`z.minLength(${min})`);
1039
999
  if (max !== void 0) checks.push(`z.maxLength(${max})`);
1040
- if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, regexFunc(regexType))})`);
1000
+ if (pattern !== void 0) checks.push(`z.regex(${regexSource(pattern, regexType)})`);
1041
1001
  return checks.length ? `.check(${checks.join(", ")})` : "";
1042
1002
  }
1043
1003
  /**
@@ -1091,63 +1051,44 @@ function applyMiniModifiers({ value, schema, nullable, optional, nullish, defaul
1091
1051
  return literal !== null ? `z._default(${withModifier}, ${literal})` : withModifier;
1092
1052
  }
1093
1053
  /**
1094
- * Builds an `object` schema node grouping the given parameter nodes.
1095
- * The `primitive: 'object'` marker ensures the Zod printer emits `z.object(…)` rather than a record.
1054
+ * Calls for string `format`s with a dedicated Zod constructor; a `Map` so `constructor` cannot hit `Object.prototype`.
1096
1055
  */
1097
- function buildGroupedParamsSchema({ params, optional }) {
1098
- return ast.factory.createSchema({
1099
- type: "object",
1100
- optional,
1101
- primitive: "object",
1102
- properties: params.map((param) => ast.factory.createProperty({
1103
- name: param.name,
1104
- required: param.required,
1105
- schema: param.schema
1106
- }))
1107
- });
1108
- }
1109
- //#endregion
1110
- //#region src/printers/printerZod.ts
1056
+ const STRING_FORMAT_CALLS = /* @__PURE__ */ new Map([
1057
+ ["byte", "z.base64()"],
1058
+ ["base64", "z.base64()"],
1059
+ ["base64url", "z.base64url()"],
1060
+ ["jwt", "z.jwt()"],
1061
+ ["ulid", "z.ulid()"],
1062
+ ["iban", "z.iban()"],
1063
+ ["duration", "z.iso.duration()"]
1064
+ ]);
1111
1065
  /**
1112
- * A `oneOf` member that is an inline object is exhaustive, so it prints as a strict object.
1113
- * Marking the node lets `object()` build `z.strictObject(...)` itself; appending `.strict()` to the
1114
- * printed member instead would read `.shape` eagerly and run a self-reference's deferred getter
1115
- * inside the temporal dead zone.
1066
+ * Marks an inline `oneOf` object strict, so `object()` builds `z.strictObject(...)` and no eager `.shape` read hits a deferred getter.
1116
1067
  */
1117
- function strictOneOfNode$1(node) {
1068
+ function strictOneOfNode(node) {
1118
1069
  return node.type === "object" && node.additionalProperties === void 0 ? {
1119
1070
  ...node,
1120
1071
  additionalProperties: false
1121
1072
  } : node;
1122
1073
  }
1123
- __name(strictOneOfNode$1, "strictOneOfNode");
1124
- function strictOneOfMember(member, node, cyclicSchemas) {
1125
- if (node.type === "ref") {
1126
- if (member.startsWith("z.lazy(")) return member;
1127
- const refName = ast.resolveRefName(node);
1128
- if (refName && cyclicSchemas?.has(refName)) return member;
1129
- const schema = syncSchemaRef(node);
1130
- if (schema.nullable || schema.optional || node.nullable || node.optional) return member;
1131
- if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
1132
- }
1133
- return member;
1134
- }
1135
- function getMemberConstraint({ member, regexType }) {
1136
- if (member.primitive === "string") return lengthConstraints({
1074
+ /**
1075
+ * The constraint chain an `allOf` member adds to a bare string, number or array; each printer passes its own renderers.
1076
+ */
1077
+ function getMemberConstraint({ member, regexType, lengths, numbers }) {
1078
+ if (member.primitive === "string") return lengths({
1137
1079
  ...ast.narrowSchema(member, "string") ?? {},
1138
1080
  regexType
1139
1081
  }) || void 0;
1140
- if (member.primitive === "number" || member.primitive === "integer") return numberConstraints(ast.narrowSchema(member, "number") ?? ast.narrowSchema(member, "integer") ?? {}) || void 0;
1141
- if (member.primitive === "array") return lengthConstraints({
1082
+ if (member.primitive === "number" || member.primitive === "integer") return numbers(ast.narrowSchema(member, "number") ?? ast.narrowSchema(member, "integer") ?? {}) || void 0;
1083
+ if (member.primitive === "array") return lengths({
1142
1084
  ...ast.narrowSchema(member, "array") ?? {},
1143
1085
  regexType
1144
1086
  }) || void 0;
1145
1087
  }
1146
1088
  /**
1147
- * Builds the `{ key: value, … }` shape for an object node, shared by the `z.object(...)` and
1148
- * `.extend(...)` renderings so they stay in lockstep.
1089
+ * Builds the `{ key: value, … }` shape shared by the `z.object(...)` and `.extend(...)` renderings.
1149
1090
  */
1150
- function buildZodObjectShape(ctx, node) {
1091
+ function buildObjectShape(ctx, node, modify) {
1151
1092
  const objectNode = ast.narrowSchema(node, "object");
1152
1093
  if (!objectNode) return "{}";
1153
1094
  const isCyclic = (schema) => ctx.options.cyclicSchemas != null && containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
@@ -1160,17 +1101,11 @@ function buildZodObjectShape(ctx, node) {
1160
1101
  return baseOutput;
1161
1102
  }).map(({ name: propName, property, output: baseOutput }) => {
1162
1103
  const { schema } = property;
1163
- const meta = syncSchemaRef(schema);
1164
- const descriptionToApply = schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description;
1165
- const value = applyModifiers({
1104
+ const value = modify({
1166
1105
  value: baseOutput,
1167
1106
  schema,
1168
- nullable: meta.nullable,
1169
- optional: schema.optional || property.required === false,
1170
- nullish: schema.nullish,
1171
- defaultValue: meta.default,
1172
- description: descriptionToApply,
1173
- examples: meta.examples
1107
+ required: property.required,
1108
+ meta: syncSchemaRef(schema)
1174
1109
  });
1175
1110
  return isCyclic(schema) ? lazyGetter({
1176
1111
  name: propName,
@@ -1179,6 +1114,51 @@ function buildZodObjectShape(ctx, node) {
1179
1114
  }));
1180
1115
  }
1181
1116
  /**
1117
+ * Shared `print` body: transforms the node, applies `keysToOmit` as `.omit(...)`, then `modify` adds the modifiers.
1118
+ */
1119
+ function printWithOmit(ctx, node, modify) {
1120
+ const { keysToOmit } = ctx.options;
1121
+ const transformed = ctx.transform(node);
1122
+ if (!transformed) return null;
1123
+ const meta = syncSchemaRef(node);
1124
+ return modify((() => {
1125
+ if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
1126
+ const unwrap = omitUnwrapChain(node);
1127
+ const omit = `.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
1128
+ const lazyMatch = transformed.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
1129
+ if (lazyMatch) return `z.lazy(() => ${lazyMatch[1]}${unwrap}${omit})`;
1130
+ return `${transformed}${unwrap}${omit}`;
1131
+ })(), meta);
1132
+ }
1133
+ //#endregion
1134
+ //#region src/printers/printerZod.ts
1135
+ function strictOneOfMember(member, node, cyclicSchemas) {
1136
+ if (node.type === "ref") {
1137
+ if (member.startsWith("z.lazy(")) return member;
1138
+ const refName = ast.resolveRefName(node);
1139
+ if (refName && cyclicSchemas?.has(refName)) return member;
1140
+ const schema = syncSchemaRef(node);
1141
+ if (schema.nullable || schema.optional || node.nullable || node.optional) return member;
1142
+ if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
1143
+ }
1144
+ return member;
1145
+ }
1146
+ /**
1147
+ * Builds the `{ key: value, … }` shape for an object node with the chainable modifiers.
1148
+ */
1149
+ function buildZodObjectShape(ctx, node) {
1150
+ return buildObjectShape(ctx, node, ({ value, schema, required, meta }) => applyModifiers({
1151
+ value,
1152
+ schema,
1153
+ nullable: meta.nullable,
1154
+ optional: schema.optional || required === false,
1155
+ nullish: schema.nullish,
1156
+ defaultValue: meta.default,
1157
+ description: schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description,
1158
+ examples: meta.examples
1159
+ }));
1160
+ }
1161
+ /**
1182
1162
  * Types the direction probe skips. They delegate to their children rather than reading
1183
1163
  * `direction` themselves, so {@link containsDirectionalNode} walks into the children instead.
1184
1164
  */
@@ -1244,7 +1224,8 @@ function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */
1244
1224
  if ("items" in node && node.items) children.push(...node.items);
1245
1225
  if ("members" in node && node.members) children.push(...node.members);
1246
1226
  if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
1247
- if ("propertyNames" in node && node.propertyNames) children.push(node.propertyNames);
1227
+ const propertyNames = propertyNamesOf(node);
1228
+ if (propertyNames) children.push(propertyNames);
1248
1229
  return children.some((child) => containsDirectionalNode({
1249
1230
  node: child,
1250
1231
  printerOptions,
@@ -1279,32 +1260,11 @@ const scalarNodes = {
1279
1260
  boolean: () => "z.boolean()",
1280
1261
  null: () => "z.null()",
1281
1262
  string(node) {
1282
- if (!shouldCoerce(this.options.coercion, "strings")) {
1283
- if (node.format === "byte" || node.format === "base64") return `z.base64()${lengthConstraints({
1284
- ...node,
1285
- regexType: this.options.regexType
1286
- })}`;
1287
- if (node.format === "base64url") return `z.base64url()${lengthConstraints({
1288
- ...node,
1289
- regexType: this.options.regexType
1290
- })}`;
1291
- if (node.format === "jwt") return `z.jwt()${lengthConstraints({
1292
- ...node,
1293
- regexType: this.options.regexType
1294
- })}`;
1295
- if (node.format === "ulid") return `z.ulid()${lengthConstraints({
1296
- ...node,
1297
- regexType: this.options.regexType
1298
- })}`;
1299
- if (node.format === "iban") return `z.iban()${lengthConstraints({
1300
- ...node,
1301
- regexType: this.options.regexType
1302
- })}`;
1303
- if (node.format === "duration") return `z.iso.duration()${lengthConstraints({
1304
- ...node,
1305
- regexType: this.options.regexType
1306
- })}`;
1307
- }
1263
+ const call = shouldCoerce(this.options.coercion, "strings") ? void 0 : STRING_FORMAT_CALLS.get(node.format);
1264
+ if (call) return `${call}${lengthConstraints({
1265
+ ...node,
1266
+ regexType: this.options.regexType
1267
+ })}`;
1308
1268
  const base = shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()";
1309
1269
  const pattern = node.pattern ?? integerFormatPattern(node.format);
1310
1270
  return `${base}${lengthConstraints({
@@ -1368,7 +1328,7 @@ const scalarNodes = {
1368
1328
  enum(node) {
1369
1329
  const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
1370
1330
  if (node.namedEnumValues?.length) {
1371
- const literals = nonNullValues.map((v) => `z.literal(${formatLiteral(v)})`);
1331
+ const literals = nonNullValues.map((v) => `z.literal(${formatDefault(v)})`);
1372
1332
  if (literals.length === 1) return literals[0];
1373
1333
  return `z.union([${literals.join(", ")}])`;
1374
1334
  }
@@ -1409,7 +1369,7 @@ const printerZod = ast.createPrinter((options) => {
1409
1369
  object(node) {
1410
1370
  const entries = node.properties ?? [];
1411
1371
  const patterns = node.patternProperties ? Object.entries(node.patternProperties) : [];
1412
- const propertyNamesNode = "propertyNames" in node ? node.propertyNames : void 0;
1372
+ const propertyNamesNode = propertyNamesOf(node);
1413
1373
  const propertyNamesKeySchema = propertyNamesNode ? this.transform(propertyNamesNode) : null;
1414
1374
  const isStrict = node.additionalProperties === false && patterns.length === 0;
1415
1375
  const isLoose = node.additionalProperties === true;
@@ -1455,7 +1415,7 @@ const printerZod = ast.createPrinter((options) => {
1455
1415
  },
1456
1416
  union(node) {
1457
1417
  const nodeMembers = node.members ?? [];
1458
- const members = mapSchemaMembers(node, (memberNode) => this.transform(node.strategy === "one" ? strictOneOfNode$1(memberNode) : memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember(output, schema, cyclicSchemaNames) : output).filter(Boolean);
1418
+ const members = mapSchemaMembers(node, (memberNode) => this.transform(node.strategy === "one" ? strictOneOfNode(memberNode) : memberNode)).map(({ schema, output }) => output && node.strategy === "one" ? strictOneOfMember(output, schema, cyclicSchemaNames) : output).filter(Boolean);
1459
1419
  if (members.length === 0) return "";
1460
1420
  if (members.length === 1) return members[0];
1461
1421
  const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
@@ -1473,7 +1433,9 @@ const printerZod = ast.createPrinter((options) => {
1473
1433
  return rest.reduce((acc, member) => {
1474
1434
  const constraint = getMemberConstraint({
1475
1435
  member,
1476
- regexType: this.options.regexType
1436
+ regexType: this.options.regexType,
1437
+ lengths: lengthConstraints,
1438
+ numbers: numberConstraints
1477
1439
  });
1478
1440
  if (constraint) return acc + constraint;
1479
1441
  const transformed = this.transform(member);
@@ -1483,19 +1445,8 @@ const printerZod = ast.createPrinter((options) => {
1483
1445
  },
1484
1446
  overrides: options.nodes,
1485
1447
  print(node) {
1486
- const { keysToOmit } = this.options;
1487
- const transformed = this.transform(node);
1488
- if (!transformed) return null;
1489
- const meta = syncSchemaRef(node);
1490
- return applyModifiers({
1491
- value: (() => {
1492
- if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
1493
- const unwrap = omitUnwrapChain(node);
1494
- const omit = `.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
1495
- const lazyMatch = transformed.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
1496
- if (lazyMatch) return `z.lazy(() => ${lazyMatch[1]}${unwrap}${omit})`;
1497
- return `${transformed}${unwrap}${omit}`;
1498
- })(),
1448
+ return printWithOmit(this, node, (value, meta) => applyModifiers({
1449
+ value,
1499
1450
  schema: node,
1500
1451
  nullable: meta.nullable,
1501
1452
  optional: meta.optional,
@@ -1503,63 +1454,23 @@ const printerZod = ast.createPrinter((options) => {
1503
1454
  defaultValue: meta.default,
1504
1455
  description: meta.description,
1505
1456
  examples: meta.examples
1506
- });
1457
+ }));
1507
1458
  }
1508
1459
  };
1509
1460
  });
1510
1461
  //#endregion
1511
1462
  //#region src/printers/printerZodMini.ts
1512
1463
  /**
1513
- * A `oneOf` member that is an inline object is exhaustive, so it prints as a strict object.
1514
- * Marking the node lets `object()` build `z.strictObject(...)` itself, with no rewrite afterwards.
1515
- */
1516
- function strictOneOfNode(node) {
1517
- return node.type === "object" && node.additionalProperties === void 0 ? {
1518
- ...node,
1519
- additionalProperties: false
1520
- } : node;
1521
- }
1522
- function getMemberConstraintMini({ member, regexType }) {
1523
- if (member.primitive === "string") return lengthChecksMini({
1524
- ...ast.narrowSchema(member, "string") ?? {},
1525
- regexType
1526
- }) || void 0;
1527
- if (member.primitive === "number" || member.primitive === "integer") return numberChecksMini(ast.narrowSchema(member, "number") ?? ast.narrowSchema(member, "integer") ?? {}) || void 0;
1528
- if (member.primitive === "array") return lengthChecksMini({
1529
- ...ast.narrowSchema(member, "array") ?? {},
1530
- regexType
1531
- }) || void 0;
1532
- }
1533
- /**
1534
- * Builds the `{ key: value, … }` shape for an object node with the functional `zod/mini` modifiers,
1535
- * shared by the `z.object(...)` and `z.extend(...)` renderings so they stay in lockstep.
1464
+ * Builds the `{ key: value, … }` shape for an object node with the functional `zod/mini` modifiers.
1536
1465
  */
1537
1466
  function buildZodMiniObjectShape(ctx, node) {
1538
- const objectNode = ast.narrowSchema(node, "object");
1539
- if (!objectNode) return "{}";
1540
- const isCyclic = (schema) => ctx.options.cyclicSchemas != null && containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
1541
- return buildObject(mapSchemaProperties(objectNode, (schema) => {
1542
- const hasSelfRef = isCyclic(schema);
1543
- const savedCyclicSchemas = ctx.options.cyclicSchemas;
1544
- if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
1545
- const baseOutput = ctx.transform(schema) ?? ctx.transform(ast.factory.createSchema({ type: "unknown" }));
1546
- if (hasSelfRef) ctx.options.cyclicSchemas = savedCyclicSchemas;
1547
- return baseOutput;
1548
- }).map(({ name: propName, property, output: baseOutput }) => {
1549
- const { schema } = property;
1550
- const meta = syncSchemaRef(schema);
1551
- const value = applyMiniModifiers({
1552
- value: baseOutput,
1553
- schema,
1554
- nullable: meta.nullable,
1555
- optional: schema.optional || property.required === false,
1556
- nullish: schema.nullish,
1557
- defaultValue: meta.default
1558
- });
1559
- return isCyclic(schema) ? lazyGetter({
1560
- name: propName,
1561
- body: value
1562
- }) : `${objectKey(propName)}: ${value}`;
1467
+ return buildObjectShape(ctx, node, ({ value, schema, required, meta }) => applyMiniModifiers({
1468
+ value,
1469
+ schema,
1470
+ nullable: meta.nullable,
1471
+ optional: schema.optional || required === false,
1472
+ nullish: schema.nullish,
1473
+ defaultValue: meta.default
1563
1474
  }));
1564
1475
  }
1565
1476
  /**
@@ -1588,32 +1499,11 @@ const printerZodMini = ast.createPrinter((options) => {
1588
1499
  null: () => "z.null()",
1589
1500
  string(node) {
1590
1501
  const coerce = shouldCoerce(this.options.coercion, "strings");
1591
- if (!coerce) {
1592
- if (node.format === "byte" || node.format === "base64") return `z.base64()${lengthChecksMini({
1593
- ...node,
1594
- regexType: this.options.regexType
1595
- })}`;
1596
- if (node.format === "base64url") return `z.base64url()${lengthChecksMini({
1597
- ...node,
1598
- regexType: this.options.regexType
1599
- })}`;
1600
- if (node.format === "jwt") return `z.jwt()${lengthChecksMini({
1601
- ...node,
1602
- regexType: this.options.regexType
1603
- })}`;
1604
- if (node.format === "ulid") return `z.ulid()${lengthChecksMini({
1605
- ...node,
1606
- regexType: this.options.regexType
1607
- })}`;
1608
- if (node.format === "iban") return `z.iban()${lengthChecksMini({
1609
- ...node,
1610
- regexType: this.options.regexType
1611
- })}`;
1612
- if (node.format === "duration") return `z.iso.duration()${lengthChecksMini({
1613
- ...node,
1614
- regexType: this.options.regexType
1615
- })}`;
1616
- }
1502
+ const call = coerce ? void 0 : STRING_FORMAT_CALLS.get(node.format);
1503
+ if (call) return `${call}${lengthChecksMini({
1504
+ ...node,
1505
+ regexType: this.options.regexType
1506
+ })}`;
1617
1507
  const base = coerce ? "z.coerce.string()" : "z.string()";
1618
1508
  const pattern = node.pattern ?? integerFormatPattern(node.format);
1619
1509
  return `${base}${lengthChecksMini({
@@ -1669,7 +1559,7 @@ const printerZodMini = ast.createPrinter((options) => {
1669
1559
  enum(node) {
1670
1560
  const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
1671
1561
  if (node.namedEnumValues?.length) {
1672
- const literals = nonNullValues.map((v) => `z.literal(${formatLiteral(v)})`);
1562
+ const literals = nonNullValues.map((v) => `z.literal(${formatDefault(v)})`);
1673
1563
  if (literals.length === 1) return literals[0];
1674
1564
  return `z.union([${literals.join(", ")}])`;
1675
1565
  }
@@ -1686,7 +1576,7 @@ const printerZodMini = ast.createPrinter((options) => {
1686
1576
  object(node) {
1687
1577
  const entries = node.properties ?? [];
1688
1578
  const patterns = node.patternProperties ? Object.entries(node.patternProperties) : [];
1689
- const propertyNamesNode = "propertyNames" in node ? node.propertyNames : void 0;
1579
+ const propertyNamesNode = propertyNamesOf(node);
1690
1580
  const propertyNamesKeySchema = propertyNamesNode ? this.transform(propertyNamesNode) : null;
1691
1581
  const isStrict = node.additionalProperties === false && patterns.length === 0;
1692
1582
  const isLoose = node.additionalProperties === true;
@@ -1743,9 +1633,11 @@ const printerZodMini = ast.createPrinter((options) => {
1743
1633
  if (!firstBase) return "";
1744
1634
  if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return rest.reduce((acc, member) => `z.extend(${acc}, ${buildZodMiniObjectShape(this, member)})`, firstBase);
1745
1635
  return rest.reduce((acc, member) => {
1746
- const constraint = getMemberConstraintMini({
1636
+ const constraint = getMemberConstraint({
1747
1637
  member,
1748
- regexType: this.options.regexType
1638
+ regexType: this.options.regexType,
1639
+ lengths: lengthChecksMini,
1640
+ numbers: numberChecksMini
1749
1641
  });
1750
1642
  if (constraint) return acc + constraint;
1751
1643
  const transformed = this.transform(member);
@@ -1755,25 +1647,14 @@ const printerZodMini = ast.createPrinter((options) => {
1755
1647
  },
1756
1648
  overrides: options.nodes,
1757
1649
  print(node) {
1758
- const { keysToOmit } = this.options;
1759
- const transformed = this.transform(node);
1760
- if (!transformed) return null;
1761
- const meta = syncSchemaRef(node);
1762
- return applyMiniModifiers({
1763
- value: (() => {
1764
- if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
1765
- const unwrap = omitUnwrapChain(node);
1766
- const omit = `.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
1767
- const lazyMatch = transformed.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
1768
- if (lazyMatch) return `z.lazy(() => ${lazyMatch[1]}${unwrap}${omit})`;
1769
- return `${transformed}${unwrap}${omit}`;
1770
- })(),
1650
+ return printWithOmit(this, node, (value, meta) => applyMiniModifiers({
1651
+ value,
1771
1652
  schema: node,
1772
1653
  nullable: meta.nullable,
1773
1654
  optional: meta.optional,
1774
1655
  nullish: meta.nullish,
1775
1656
  defaultValue: meta.default
1776
- });
1657
+ }));
1777
1658
  }
1778
1659
  };
1779
1660
  });
@@ -1845,7 +1726,7 @@ const zodGenerator = defineGenerator({
1845
1726
  const { output, coercion, guidType, regexType, compile, mini, inferred, typeGuards, importPath, group, printer } = ctx.options;
1846
1727
  const dateType = getOasAdapter(adapter).options.dateType;
1847
1728
  if (!node.name) return;
1848
- const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1729
+ const isZodImport = importPath === "zod" || importPath === "zod/mini";
1849
1730
  const cyclicSchemas = new Set(ctx.meta.circularNames);
1850
1731
  const printerOptions = {
1851
1732
  coercion,
@@ -1880,13 +1761,7 @@ const zodGenerator = defineGenerator({
1880
1761
  group: group ?? void 0
1881
1762
  }).path
1882
1763
  })) : [];
1883
- const seenImports = /* @__PURE__ */ new Set();
1884
- const imports = [...importEntries, ...inputImportEntries].filter((imp) => {
1885
- const key = `${Array.isArray(imp.name) ? imp.name.join(",") : imp.name}|${imp.path}`;
1886
- if (seenImports.has(key)) return false;
1887
- seenImports.add(key);
1888
- return true;
1889
- });
1764
+ const imports = [...new Map([...importEntries, ...inputImportEntries].map((imp) => [`${Array.isArray(imp.name) ? imp.name.join(",") : imp.name}|${imp.path}`, imp])).values()];
1890
1765
  const meta = {
1891
1766
  name: resolver.name(node.name),
1892
1767
  file: resolver.file({
@@ -1982,7 +1857,7 @@ const zodGenerator = defineGenerator({
1982
1857
  const { adapter, config, resolver, root } = ctx;
1983
1858
  const { output, coercion, guidType, regexType, compile, mini, inferred, importPath, group, printer } = ctx.options;
1984
1859
  const dateType = getOasAdapter(adapter).options.dateType;
1985
- const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1860
+ const isZodImport = importPath === "zod" || importPath === "zod/mini";
1986
1861
  const meta = { file: resolver.file({
1987
1862
  name: node.operationId,
1988
1863
  extname: ".ts",
@@ -2086,7 +1961,7 @@ const zodGenerator = defineGenerator({
2086
1961
  })] });
2087
1962
  }
2088
1963
  function buildResponseUnion({ responses, name, fallbackUnknown }) {
2089
- if (new Set(responses.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? collectRefNames(entry.schema).map((refName) => resolver.name(refName)) : []))).has(name)) return null;
1964
+ if (new Set(responses.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? ast.collectImportedRefNames(entry.schema).map((refName) => resolver.name(refName)) : []))).has(name)) return null;
2090
1965
  const members = responses.map((res) => ast.factory.createSchema({
2091
1966
  type: "ref",
2092
1967
  name: resolver.response.status(node, res.statusCode)
@@ -2167,7 +2042,15 @@ const zodGenerator = defineGenerator({
2167
2042
  params: header
2168
2043
  }
2169
2044
  ].filter(({ params }) => params.length > 0).map(({ kind, params }) => renderSchemaEntry({
2170
- schema: buildGroupedParamsSchema({ params }),
2045
+ schema: ast.factory.createSchema({
2046
+ type: "object",
2047
+ primitive: "object",
2048
+ properties: params.map((param) => ast.factory.createProperty({
2049
+ name: param.name,
2050
+ required: param.required,
2051
+ schema: param.schema
2052
+ }))
2053
+ }),
2171
2054
  name: resolver.param[kind](node, params[0]),
2172
2055
  direction: "encode"
2173
2056
  })) : [];
@@ -2222,11 +2105,11 @@ const zodGenerator = defineGenerator({
2222
2105
  //#region kubb-extension.json
2223
2106
  var compatibility = {
2224
2107
  "kubb": ">=5.8.3",
2225
- "node": ">=22"
2108
+ "node": ">=22.12"
2226
2109
  };
2227
2110
  //#endregion
2228
2111
  //#region package.json
2229
- var version = "5.4.9";
2112
+ var version = "5.4.12";
2230
2113
  //#endregion
2231
2114
  //#region src/resolvers/resolverZod.ts
2232
2115
  /**
@@ -2326,6 +2209,18 @@ const pluginZod = defineExtension({
2326
2209
  path: "zod",
2327
2210
  barrel: { type: "named" }
2328
2211
  }, group, exclude = [], include, override = [], compile = false, mini = false, guidType = "uuid", regexType = "literal", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, typeGuards = false, printer, resolver: userResolver, macros: userMacros } = options;
2212
+ assertPluginOption({
2213
+ plugin: pluginZodName,
2214
+ option: "guidType",
2215
+ value: guidType,
2216
+ allowed: ["uuid", "guid"]
2217
+ });
2218
+ assertPluginOption({
2219
+ plugin: pluginZodName,
2220
+ option: "regexType",
2221
+ value: regexType,
2222
+ allowed: ["literal", "constructor"]
2223
+ });
2329
2224
  setResolver(userResolver ? Resolver.merge(resolverZod, userResolver) : resolverZod);
2330
2225
  if (userMacros?.length) setMacros(userMacros);
2331
2226
  addGenerator(zodGenerator);