@kubb/plugin-zod 5.0.0-beta.99 → 5.0.0

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
@@ -12,6 +12,179 @@ var __name = (target, value) => __defProp(target, "name", {
12
12
  let kubb_kit = require("kubb/kit");
13
13
  let kubb_jsx = require("kubb/jsx");
14
14
  let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
15
+ //#region ../../internals/shared/src/params.ts
16
+ /**
17
+ * Drops parameters that share the same name, keeping the first.
18
+ *
19
+ * A malformed spec can declare the same parameter name twice within one `in` location. Both would
20
+ * resolve to the same output property, so emitting both would yield an object type with a duplicate
21
+ * member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
22
+ * parameter names flow through unchanged, so no two distinct names ever collide here anymore.
23
+ */
24
+ function dedupeParams(params) {
25
+ const seen = /* @__PURE__ */ new Set();
26
+ return params.filter((param) => {
27
+ if (seen.has(param.name)) return false;
28
+ seen.add(param.name);
29
+ return true;
30
+ });
31
+ }
32
+ //#endregion
33
+ //#region ../../internals/shared/src/operation.ts
34
+ /**
35
+ * Maps a content type to the PascalCase suffix used to name per-content-type variants
36
+ * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
37
+ */
38
+ function getContentTypeSuffix(contentType) {
39
+ const baseType = contentType.split(";")[0].trim();
40
+ if (baseType === "application/json") return "Json";
41
+ if (baseType === "multipart/form-data") return "FormData";
42
+ if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
43
+ const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
44
+ if (parts.length === 0) return "Unknown";
45
+ return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
46
+ }
47
+ /**
48
+ * Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
49
+ * (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
50
+ */
51
+ function getPerContentTypeName(baseName, suffix) {
52
+ if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
53
+ return baseName + suffix;
54
+ }
55
+ /**
56
+ * Resolves per-content-type variant names for a set of content entries, deduplicating suffix
57
+ * collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is
58
+ * the final (possibly counter-augmented) value, so callers can derive parallel names in another
59
+ * namespace (e.g. plugin-faker deriving the matching plugin-ts type name).
60
+ */
61
+ function resolveContentTypeVariants(entries, baseName) {
62
+ const usedNames = /* @__PURE__ */ new Set();
63
+ return entries.filter((entry) => entry.schema).map((entry) => {
64
+ const baseSuffix = getContentTypeSuffix(entry.contentType);
65
+ let suffix = baseSuffix;
66
+ let name = getPerContentTypeName(baseName, suffix);
67
+ let counter = 2;
68
+ while (usedNames.has(name)) {
69
+ suffix = `${baseSuffix}${counter++}`;
70
+ name = getPerContentTypeName(baseName, suffix);
71
+ }
72
+ usedNames.add(name);
73
+ return {
74
+ name,
75
+ suffix,
76
+ schema: entry.schema,
77
+ keysToOmit: entry.keysToOmit,
78
+ contentType: entry.contentType
79
+ };
80
+ });
81
+ }
82
+ const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
83
+ /**
84
+ * Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
85
+ * group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
86
+ * (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
87
+ * same parameters once per plugin.
88
+ */
89
+ function getOperationParameters(node) {
90
+ const cached = operationParameterGroupsByNode.get(node);
91
+ if (cached) return cached;
92
+ const groups = {
93
+ path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
94
+ query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
95
+ header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
96
+ cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
97
+ };
98
+ operationParameterGroupsByNode.set(node, groups);
99
+ return groups;
100
+ }
101
+ /**
102
+ * Builds the combined `{ body, path, query, headers }` options object schema for an operation,
103
+ * referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s
104
+ * `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same
105
+ * shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
106
+ * printer to emit `z.object(…)` rather than a record.
107
+ */
108
+ function buildOptionsSchema(node, resolver) {
109
+ const { path, query, header } = getOperationParameters(node);
110
+ const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
111
+ const createNever = () => kubb_kit.ast.factory.createSchema({
112
+ type: "never",
113
+ primitive: void 0,
114
+ optional: true
115
+ });
116
+ const groups = [
117
+ {
118
+ name: "path",
119
+ params: path,
120
+ resolve: resolver.param.path
121
+ },
122
+ {
123
+ name: "query",
124
+ params: query,
125
+ resolve: resolver.param.query
126
+ },
127
+ {
128
+ name: "headers",
129
+ params: header,
130
+ resolve: resolver.param.headers
131
+ }
132
+ ];
133
+ return kubb_kit.ast.factory.createSchema({
134
+ type: "object",
135
+ primitive: "object",
136
+ deprecated: node.deprecated,
137
+ properties: [kubb_kit.ast.factory.createProperty({
138
+ name: "body",
139
+ required: hasBody,
140
+ schema: hasBody ? kubb_kit.ast.factory.createSchema({
141
+ type: "ref",
142
+ name: resolver.response.body(node)
143
+ }) : createNever()
144
+ }), ...groups.map(({ name, params, resolve }) => {
145
+ const required = params.some((param) => param.required);
146
+ return kubb_kit.ast.factory.createProperty({
147
+ name,
148
+ required,
149
+ schema: params.length > 0 ? kubb_kit.ast.factory.createSchema({
150
+ type: "ref",
151
+ name: resolve.call(resolver.param, node, params[0]),
152
+ optional: !required
153
+ }) : createNever()
154
+ });
155
+ })]
156
+ });
157
+ }
158
+ function getStatusCodeNumber(statusCode) {
159
+ const code = Number(statusCode);
160
+ return Number.isNaN(code) ? null : code;
161
+ }
162
+ function isSuccessStatusCode(statusCode) {
163
+ const code = getStatusCodeNumber(statusCode);
164
+ return code !== null && code >= 200 && code < 300;
165
+ }
166
+ function getSuccessResponses(responses) {
167
+ return responses.filter((response) => isSuccessStatusCode(response.statusCode));
168
+ }
169
+ //#endregion
170
+ //#region ../../internals/shared/src/adapter.ts
171
+ /**
172
+ * Narrows the generic `Adapter` from a generator context to the OpenAPI adapter,
173
+ * so OAS-only options (`dateType`, `enums`) and the parsed `document` are typed.
174
+ *
175
+ * Throws when a non-OAS adapter is configured, turning a silently wrong cast into a
176
+ * clear, actionable error at the point of use.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * const { dateType } = getOasAdapter(ctx.adapter).options
181
+ * ```
182
+ */
183
+ function getOasAdapter(adapter) {
184
+ if (adapter.name !== "oas") throw new Error(`Expected the OpenAPI adapter (adapterOas), but received "${adapter.name}". Configure \`adapter: adapterOas()\` in your Kubb config.`);
185
+ return adapter;
186
+ }
187
+ //#endregion
15
188
  //#region ../../internals/utils/src/casing.ts
16
189
  /**
17
190
  * Shared implementation for camelCase and PascalCase conversion.
@@ -356,85 +529,6 @@ function toFilePath(name, caseLast = camelCase) {
356
529
  return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
357
530
  }
358
531
  //#endregion
359
- //#region ../../internals/shared/src/operation.ts
360
- /**
361
- * Maps a content type to the PascalCase suffix used to name per-content-type variants
362
- * (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
363
- */
364
- function getContentTypeSuffix(contentType) {
365
- const baseType = contentType.split(";")[0].trim();
366
- if (baseType === "application/json") return "Json";
367
- if (baseType === "multipart/form-data") return "FormData";
368
- if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
369
- const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
370
- if (parts.length === 0) return "Unknown";
371
- return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
372
- }
373
- /**
374
- * Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
375
- * (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
376
- */
377
- function getPerContentTypeName(baseName, suffix) {
378
- if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
379
- return baseName + suffix;
380
- }
381
- /**
382
- * Resolves per-content-type variant names for a set of content entries, deduplicating suffix
383
- * collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is
384
- * the final (possibly counter-augmented) value, so callers can derive parallel names in another
385
- * namespace (e.g. plugin-faker deriving the matching plugin-ts type name).
386
- */
387
- function resolveContentTypeVariants(entries, baseName) {
388
- const usedNames = /* @__PURE__ */ new Set();
389
- return entries.filter((entry) => entry.schema).map((entry) => {
390
- const baseSuffix = getContentTypeSuffix(entry.contentType);
391
- let suffix = baseSuffix;
392
- let name = getPerContentTypeName(baseName, suffix);
393
- let counter = 2;
394
- while (usedNames.has(name)) {
395
- suffix = `${baseSuffix}${counter++}`;
396
- name = getPerContentTypeName(baseName, suffix);
397
- }
398
- usedNames.add(name);
399
- return {
400
- name,
401
- suffix,
402
- schema: entry.schema,
403
- keysToOmit: entry.keysToOmit,
404
- contentType: entry.contentType
405
- };
406
- });
407
- }
408
- function getStatusCodeNumber(statusCode) {
409
- const code = Number(statusCode);
410
- return Number.isNaN(code) ? null : code;
411
- }
412
- function isSuccessStatusCode(statusCode) {
413
- const code = getStatusCodeNumber(statusCode);
414
- return code !== null && code >= 200 && code < 300;
415
- }
416
- function getSuccessResponses(responses) {
417
- return responses.filter((response) => isSuccessStatusCode(response.statusCode));
418
- }
419
- //#endregion
420
- //#region ../../internals/shared/src/adapter.ts
421
- /**
422
- * Narrows the generic `Adapter` from a generator context to the OpenAPI adapter,
423
- * so OAS-only options (`dateType`, `enums`) and the parsed `document` are typed.
424
- *
425
- * Throws when a non-OAS adapter is configured, turning a silently wrong cast into a
426
- * clear, actionable error at the point of use.
427
- *
428
- * @example
429
- * ```ts
430
- * const { dateType } = getOasAdapter(ctx.adapter).options
431
- * ```
432
- */
433
- function getOasAdapter(adapter) {
434
- if (adapter.name !== "oas") throw new Error(`Expected the OpenAPI adapter (adapterOas), but received "${adapter.name}". Configure \`adapter: adapterOas()\` in your Kubb config.`);
435
- return adapter;
436
- }
437
- //#endregion
438
532
  //#region ../../internals/shared/src/resolver.ts
439
533
  /**
440
534
  * Resolves a single operation parameter name with the
@@ -447,6 +541,29 @@ function operationParamName(node, param) {
447
541
  return this.name(`${node.operationId} ${param.in} ${param.name}`);
448
542
  }
449
543
  /**
544
+ * Builds the shared `param` namespace. Spread the result into `createResolver`
545
+ * and override individual methods next to it when a plugin deviates.
546
+ *
547
+ * @example
548
+ * ```ts
549
+ * createResolver<PluginTs>({ param: createOperationParamResolver(), ... })
550
+ * ```
551
+ */
552
+ function createOperationParamResolver() {
553
+ return {
554
+ name: operationParamName,
555
+ path(node) {
556
+ return this.name(`${node.operationId} Path`);
557
+ },
558
+ query(node) {
559
+ return this.name(`${node.operationId} Query`);
560
+ },
561
+ headers(node) {
562
+ return this.name(`${node.operationId} Headers`);
563
+ }
564
+ };
565
+ }
566
+ /**
450
567
  * Builds the shared `response` namespace. Spread the result into
451
568
  * `createResolver` and add plugin-specific methods (`options`, `error`) next
452
569
  * to it.
@@ -494,7 +611,7 @@ function createCasedFile(caseLast) {
494
611
  * `resolver.imports` would resolve file paths that are then discarded.
495
612
  */
496
613
  function collectRefNames(schema) {
497
- return kubb_kit.ast.collect(schema, { schema: (node) => {
614
+ return kubb_kit.ast.collectSync(schema, { schema: (node) => {
498
615
  const refNode = kubb_kit.ast.narrowSchema(node, "ref");
499
616
  if (!refNode?.ref) return null;
500
617
  return kubb_kit.ast.resolveRefName(refNode);
@@ -654,12 +771,12 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
654
771
  if (hasCodec(node)) return true;
655
772
  if (node.type === "ref") {
656
773
  if (!node.ref) return false;
657
- const refName = kubb_kit.ast.extractRefName(node.ref);
774
+ const refName = (0, kubb_kit.extractRefName)(node.ref);
658
775
  if (refName) {
659
776
  if (seen.has(refName)) return false;
660
777
  seen.add(refName);
661
778
  }
662
- const resolved = kubb_kit.ast.syncSchemaRef(node);
779
+ const resolved = (0, kubb_kit.syncSchemaRef)(node);
663
780
  if (resolved.type === "ref") return false;
664
781
  return containsCodec(resolved, seen);
665
782
  }
@@ -675,7 +792,7 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
675
792
  * them to their input (encode) variant.
676
793
  */
677
794
  function collectCodecRefNames(node) {
678
- return kubb_kit.ast.collect(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? kubb_kit.ast.resolveRefName(n) ?? void 0 : void 0 });
795
+ return kubb_kit.ast.collectSync(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? kubb_kit.ast.resolveRefName(n) ?? void 0 : void 0 });
679
796
  }
680
797
  /**
681
798
  * Whether the node is a plain inline object whose shape can be lifted into an `.extend({ … })`
@@ -698,7 +815,7 @@ function isObjectSchemaNode(node, cyclicSchemas) {
698
815
  if (node.type === "ref") {
699
816
  const refName = kubb_kit.ast.resolveRefName(node);
700
817
  if (refName && cyclicSchemas?.has(refName)) return false;
701
- const resolved = kubb_kit.ast.syncSchemaRef(node);
818
+ const resolved = (0, kubb_kit.syncSchemaRef)(node);
702
819
  return resolved.type === "ref" || isObjectSchemaNode(resolved, cyclicSchemas);
703
820
  }
704
821
  if (node.type === "union") {
@@ -774,6 +891,20 @@ function buildEnum(values) {
774
891
  return `z.union([${literals.join(", ")}])`;
775
892
  }
776
893
  /**
894
+ * Digit pattern for a `type: 'string'` schema that carries an integer `format`, the way ProtoJSON
895
+ * encodes 64-bit integers. Returns `undefined` for every other format, and a `pattern` from the
896
+ * spec takes precedence over this fallback.
897
+ *
898
+ * @example
899
+ * ```ts
900
+ * integerFormatPattern('uint64') // '^\\d+$'
901
+ * ```
902
+ */
903
+ function integerFormatPattern(format) {
904
+ if (format === "int32" || format === "int64") return "^-?\\d+$";
905
+ if (format === "uint64") return "^\\d+$";
906
+ }
907
+ /**
777
908
  * Map a `regexType` to the `func` argument of `toRegExpString`: `'constructor'` emits
778
909
  * `new RegExp(...)`, while `'literal'` (the default) emits a regex literal.
779
910
  */
@@ -898,6 +1029,22 @@ function applyMiniModifiers({ value, schema, nullable, optional, nullish, defaul
898
1029
  const literal = defaultValue !== void 0 ? defaultLiteral(schema, defaultValue) : null;
899
1030
  return literal !== null ? `z._default(${withModifier}, ${literal})` : withModifier;
900
1031
  }
1032
+ /**
1033
+ * Builds an `object` schema node grouping the given parameter nodes.
1034
+ * The `primitive: 'object'` marker ensures the Zod printer emits `z.object(…)` rather than a record.
1035
+ */
1036
+ function buildGroupedParamsSchema({ params, optional }) {
1037
+ return kubb_kit.ast.factory.createSchema({
1038
+ type: "object",
1039
+ optional,
1040
+ primitive: "object",
1041
+ properties: params.map((param) => kubb_kit.ast.factory.createProperty({
1042
+ name: param.name,
1043
+ required: param.required,
1044
+ schema: param.schema
1045
+ }))
1046
+ });
1047
+ }
901
1048
  //#endregion
902
1049
  //#region src/printers/printerZod.ts
903
1050
  function strictOneOfMember$1(member, node, cyclicSchemas) {
@@ -906,7 +1053,7 @@ function strictOneOfMember$1(member, node, cyclicSchemas) {
906
1053
  if (member.startsWith("z.lazy(")) return member;
907
1054
  const refName = kubb_kit.ast.resolveRefName(node);
908
1055
  if (refName && cyclicSchemas?.has(refName)) return member;
909
- const schema = kubb_kit.ast.syncSchemaRef(node);
1056
+ const schema = (0, kubb_kit.syncSchemaRef)(node);
910
1057
  if (schema.nullable || schema.optional || node.nullable || node.optional) return member;
911
1058
  if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
912
1059
  }
@@ -931,7 +1078,7 @@ function getMemberConstraint({ member, regexType }) {
931
1078
  function buildZodObjectShape(ctx, node) {
932
1079
  const objectNode = kubb_kit.ast.narrowSchema(node, "object");
933
1080
  if (!objectNode) return "{}";
934
- const isCyclic = (schema) => ctx.options.cyclicSchemas != null && kubb_kit.ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
1081
+ const isCyclic = (schema) => ctx.options.cyclicSchemas != null && (0, kubb_kit.containsCircularRef)(schema, { circularSchemas: ctx.options.cyclicSchemas });
935
1082
  return buildObject(mapSchemaProperties(objectNode, (schema) => {
936
1083
  const hasSelfRef = isCyclic(schema);
937
1084
  const savedCyclicSchemas = ctx.options.cyclicSchemas;
@@ -941,7 +1088,7 @@ function buildZodObjectShape(ctx, node) {
941
1088
  return baseOutput;
942
1089
  }).map(({ name: propName, property, output: baseOutput }) => {
943
1090
  const { schema } = property;
944
- const meta = kubb_kit.ast.syncSchemaRef(schema);
1091
+ const meta = (0, kubb_kit.syncSchemaRef)(schema);
945
1092
  const descriptionToApply = schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description;
946
1093
  const value = applyModifiers({
947
1094
  value: baseOutput,
@@ -984,8 +1131,11 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
984
1131
  boolean: () => "z.boolean()",
985
1132
  null: () => "z.null()",
986
1133
  string(node) {
987
- return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints({
1134
+ const base = shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()";
1135
+ const pattern = node.pattern ?? integerFormatPattern(node.format);
1136
+ return `${base}${lengthConstraints({
988
1137
  ...node,
1138
+ pattern,
989
1139
  regexType: this.options.regexType
990
1140
  })}`;
991
1141
  },
@@ -1126,7 +1276,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
1126
1276
  const { keysToOmit } = this.options;
1127
1277
  const transformed = this.transform(node);
1128
1278
  if (!transformed) return null;
1129
- const meta = kubb_kit.ast.syncSchemaRef(node);
1279
+ const meta = (0, kubb_kit.syncSchemaRef)(node);
1130
1280
  return applyModifiers({
1131
1281
  value: (() => {
1132
1282
  if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
@@ -1171,7 +1321,7 @@ function getMemberConstraintMini({ member, regexType }) {
1171
1321
  function buildZodMiniObjectShape(ctx, node) {
1172
1322
  const objectNode = kubb_kit.ast.narrowSchema(node, "object");
1173
1323
  if (!objectNode) return "{}";
1174
- const isCyclic = (schema) => ctx.options.cyclicSchemas != null && kubb_kit.ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
1324
+ const isCyclic = (schema) => ctx.options.cyclicSchemas != null && (0, kubb_kit.containsCircularRef)(schema, { circularSchemas: ctx.options.cyclicSchemas });
1175
1325
  return buildObject(mapSchemaProperties(objectNode, (schema) => {
1176
1326
  const hasSelfRef = isCyclic(schema);
1177
1327
  const savedCyclicSchemas = ctx.options.cyclicSchemas;
@@ -1181,7 +1331,7 @@ function buildZodMiniObjectShape(ctx, node) {
1181
1331
  return baseOutput;
1182
1332
  }).map(({ name: propName, property, output: baseOutput }) => {
1183
1333
  const { schema } = property;
1184
- const meta = kubb_kit.ast.syncSchemaRef(schema);
1334
+ const meta = (0, kubb_kit.syncSchemaRef)(schema);
1185
1335
  const value = applyMiniModifiers({
1186
1336
  value: baseOutput,
1187
1337
  schema,
@@ -1221,8 +1371,10 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1221
1371
  boolean: () => "z.boolean()",
1222
1372
  null: () => "z.null()",
1223
1373
  string(node) {
1374
+ const pattern = node.pattern ?? integerFormatPattern(node.format);
1224
1375
  return `z.string()${lengthChecksMini({
1225
1376
  ...node,
1377
+ pattern,
1226
1378
  regexType: this.options.regexType
1227
1379
  })}`;
1228
1380
  },
@@ -1352,7 +1504,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1352
1504
  const { keysToOmit } = this.options;
1353
1505
  const transformed = this.transform(node);
1354
1506
  if (!transformed) return null;
1355
- const meta = kubb_kit.ast.syncSchemaRef(node);
1507
+ const meta = (0, kubb_kit.syncSchemaRef)(node);
1356
1508
  return applyMiniModifiers({
1357
1509
  value: (() => {
1358
1510
  if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
@@ -1703,6 +1855,30 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1703
1855
  description: node.requestBody.description ?? schema.description
1704
1856
  }), "input");
1705
1857
  })();
1858
+ const { path, query, header } = getOperationParameters(node);
1859
+ const paramGroupSchemas = inferred ? [
1860
+ {
1861
+ kind: "path",
1862
+ params: path
1863
+ },
1864
+ {
1865
+ kind: "query",
1866
+ params: query
1867
+ },
1868
+ {
1869
+ kind: "headers",
1870
+ params: header
1871
+ }
1872
+ ].filter(({ params }) => params.length > 0).map(({ kind, params }) => renderSchemaEntry({
1873
+ schema: buildGroupedParamsSchema({ params }),
1874
+ name: resolver.param[kind](node, params[0]),
1875
+ direction: "input"
1876
+ })) : [];
1877
+ const optionsSchema = inferred ? renderSchemaEntry({
1878
+ schema: buildOptionsSchema(node, resolver),
1879
+ name: resolver.name(`${node.operationId} Options`),
1880
+ direction: "input"
1881
+ }) : null;
1706
1882
  return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
1707
1883
  baseName: meta.file.baseName,
1708
1884
  path: meta.file.path,
@@ -1733,7 +1909,9 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1733
1909
  responseSchemas,
1734
1910
  responseUnionSchema,
1735
1911
  errorUnionSchema,
1736
- requestSchema
1912
+ requestSchema,
1913
+ paramGroupSchemas,
1914
+ optionsSchema
1737
1915
  ]
1738
1916
  });
1739
1917
  }
@@ -1775,22 +1953,14 @@ const resolverZod = (0, kubb_kit.createResolver)({
1775
1953
  return this.schema.typeName(`${name} input`);
1776
1954
  }
1777
1955
  },
1778
- param: {
1779
- name: operationParamName,
1780
- path(node, param) {
1781
- return this.param.name(node, param);
1782
- },
1783
- query(node, param) {
1784
- return this.param.name(node, param);
1785
- },
1786
- headers(node, param) {
1787
- return this.param.name(node, param);
1788
- }
1789
- },
1956
+ param: createOperationParamResolver(),
1790
1957
  response: {
1791
1958
  ...createOperationResponseResolver(),
1792
1959
  error(node) {
1793
1960
  return this.name(`${node.operationId} Error`);
1961
+ },
1962
+ options(node) {
1963
+ return this.schema.type(this.name(`${node.operationId} Options`));
1794
1964
  }
1795
1965
  }
1796
1966
  });