@kubb/plugin-zod 5.0.0-alpha.8 → 5.0.0-beta.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.
Files changed (45) hide show
  1. package/LICENSE +17 -10
  2. package/README.md +1 -3
  3. package/dist/index.cjs +1061 -105
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +369 -4
  6. package/dist/index.js +1053 -104
  7. package/dist/index.js.map +1 -1
  8. package/package.json +44 -70
  9. package/src/components/Operations.tsx +25 -18
  10. package/src/components/Zod.tsx +21 -121
  11. package/src/constants.ts +5 -0
  12. package/src/generators/zodGenerator.tsx +174 -160
  13. package/src/index.ts +11 -2
  14. package/src/plugin.ts +67 -156
  15. package/src/printers/printerZod.ts +339 -0
  16. package/src/printers/printerZodMini.ts +295 -0
  17. package/src/resolvers/resolverZod.ts +57 -0
  18. package/src/types.ts +130 -115
  19. package/src/utils.ts +222 -0
  20. package/dist/components-B7zUFnAm.cjs +0 -890
  21. package/dist/components-B7zUFnAm.cjs.map +0 -1
  22. package/dist/components-eECfXVou.js +0 -842
  23. package/dist/components-eECfXVou.js.map +0 -1
  24. package/dist/components.cjs +0 -4
  25. package/dist/components.d.ts +0 -56
  26. package/dist/components.js +0 -2
  27. package/dist/generators-BjPDdJUz.cjs +0 -301
  28. package/dist/generators-BjPDdJUz.cjs.map +0 -1
  29. package/dist/generators-lTWPS6oN.js +0 -290
  30. package/dist/generators-lTWPS6oN.js.map +0 -1
  31. package/dist/generators.cjs +0 -4
  32. package/dist/generators.d.ts +0 -479
  33. package/dist/generators.js +0 -2
  34. package/dist/templates/ToZod.source.cjs +0 -7
  35. package/dist/templates/ToZod.source.cjs.map +0 -1
  36. package/dist/templates/ToZod.source.d.ts +0 -7
  37. package/dist/templates/ToZod.source.js +0 -6
  38. package/dist/templates/ToZod.source.js.map +0 -1
  39. package/dist/types-CoCoOc2u.d.ts +0 -172
  40. package/src/components/index.ts +0 -2
  41. package/src/generators/index.ts +0 -2
  42. package/src/generators/operationsGenerator.tsx +0 -50
  43. package/src/parser.ts +0 -909
  44. package/src/templates/ToZod.source.ts +0 -4
  45. package/templates/ToZod.ts +0 -61
package/dist/index.cjs CHANGED
@@ -1,12 +1,11 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_components = require("./components-B7zUFnAm.cjs");
3
- const require_generators = require("./generators-BjPDdJUz.cjs");
4
- const require_templates_ToZod_source = require("./templates/ToZod.source.cjs");
5
- let node_path = require("node:path");
6
- node_path = require_components.__toESM(node_path);
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ //#endregion
7
6
  let _kubb_core = require("@kubb/core");
8
- let _kubb_plugin_oas = require("@kubb/plugin-oas");
9
- let _kubb_plugin_ts = require("@kubb/plugin-ts");
7
+ let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
8
+ let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
10
9
  //#region ../../internals/utils/src/casing.ts
11
10
  /**
12
11
  * Shared implementation for camelCase and PascalCase conversion.
@@ -26,9 +25,12 @@ function toCamelOrPascal(text, pascal) {
26
25
  * Splits `text` on `.` and applies `transformPart` to each segment.
27
26
  * The last segment receives `isLast = true`, all earlier segments receive `false`.
28
27
  * Segments are joined with `/` to form a file path.
28
+ *
29
+ * Only splits on dots followed by a letter so that version numbers
30
+ * embedded in operationIds (e.g. `v2025.0`) are kept intact.
29
31
  */
30
32
  function applyToFileParts(text, transformPart) {
31
- const parts = text.split(".");
33
+ const parts = text.split(/\.(?=[a-zA-Z])/);
32
34
  return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
33
35
  }
34
36
  /**
@@ -62,117 +64,1071 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
62
64
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
63
65
  }
64
66
  //#endregion
67
+ //#region ../../internals/utils/src/string.ts
68
+ /**
69
+ * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
70
+ * Returns the string unchanged when no balanced quote pair is found.
71
+ *
72
+ * @example
73
+ * trimQuotes('"hello"') // 'hello'
74
+ * trimQuotes('hello') // 'hello'
75
+ */
76
+ function trimQuotes(text) {
77
+ if (text.length >= 2) {
78
+ const first = text[0];
79
+ const last = text[text.length - 1];
80
+ if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
81
+ }
82
+ return text;
83
+ }
84
+ //#endregion
85
+ //#region ../../internals/utils/src/object.ts
86
+ /**
87
+ * Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.
88
+ *
89
+ * @example
90
+ * stringify('hello') // '"hello"'
91
+ * stringify('"hello"') // '"hello"'
92
+ */
93
+ function stringify(value) {
94
+ if (value === void 0 || value === null) return "\"\"";
95
+ return JSON.stringify(trimQuotes(value.toString()));
96
+ }
97
+ /**
98
+ * Converts a plain object into a multiline key-value string suitable for embedding in generated code.
99
+ * Nested objects are recursively stringified with indentation.
100
+ *
101
+ * @example
102
+ * stringifyObject({ foo: 'bar', nested: { a: 1 } })
103
+ * // 'foo: bar,\nnested: {\n a: 1\n }'
104
+ */
105
+ function stringifyObject(value) {
106
+ return Object.entries(value).map(([key, val]) => {
107
+ if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`;
108
+ return `${key}: ${val}`;
109
+ }).filter(Boolean).join(",\n");
110
+ }
111
+ //#endregion
112
+ //#region ../../internals/utils/src/regexp.ts
113
+ /**
114
+ * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
115
+ * Inline flags expressed as `^(?im)` prefixes are extracted and applied to the resulting expression.
116
+ * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
117
+ *
118
+ * @example
119
+ * toRegExpString('^(?im)foo') // → 'new RegExp("foo", "im")'
120
+ * toRegExpString('^(?im)foo', null) // → '/foo/im'
121
+ */
122
+ function toRegExpString(text, func = "RegExp") {
123
+ const raw = trimQuotes(text);
124
+ const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
125
+ const replacementTarget = match?.[1] ?? "";
126
+ const matchedFlags = match?.[2];
127
+ const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
128
+ const { source, flags } = new RegExp(cleaned, matchedFlags);
129
+ if (func === null) return `/${source}/${flags}`;
130
+ return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
131
+ }
132
+ //#endregion
133
+ //#region src/components/Operations.tsx
134
+ function Operations({ name, operations }) {
135
+ const operationsJSON = operations.reduce((prev, acc) => {
136
+ prev[`"${acc.node.operationId}"`] = acc.data;
137
+ return prev;
138
+ }, {});
139
+ const pathsJSON = operations.reduce((prev, acc) => {
140
+ prev[`"${acc.node.path}"`] = {
141
+ ...prev[`"${acc.node.path}"`] ?? {},
142
+ [acc.node.method]: `operations["${acc.node.operationId}"]`
143
+ };
144
+ return prev;
145
+ }, {});
146
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
147
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
148
+ name: "OperationSchema",
149
+ isExportable: true,
150
+ isIndexable: true,
151
+ children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Type, {
152
+ name: "OperationSchema",
153
+ export: true,
154
+ children: `{
155
+ readonly request: z.ZodTypeAny | undefined;
156
+ readonly parameters: {
157
+ readonly path: z.ZodTypeAny | undefined;
158
+ readonly query: z.ZodTypeAny | undefined;
159
+ readonly header: z.ZodTypeAny | undefined;
160
+ };
161
+ readonly responses: {
162
+ readonly [status: number]: z.ZodTypeAny;
163
+ readonly default: z.ZodTypeAny;
164
+ };
165
+ readonly errors: {
166
+ readonly [status: number]: z.ZodTypeAny;
167
+ };
168
+ }`
169
+ })
170
+ }),
171
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
172
+ name: "OperationsMap",
173
+ isExportable: true,
174
+ isIndexable: true,
175
+ children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Type, {
176
+ name: "OperationsMap",
177
+ export: true,
178
+ children: "Record<string, OperationSchema>"
179
+ })
180
+ }),
181
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
182
+ name,
183
+ isExportable: true,
184
+ isIndexable: true,
185
+ children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
186
+ export: true,
187
+ name,
188
+ asConst: true,
189
+ children: `{${stringifyObject(operationsJSON)}}`
190
+ })
191
+ }),
192
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
193
+ name: "paths",
194
+ isExportable: true,
195
+ isIndexable: true,
196
+ children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
197
+ export: true,
198
+ name: "paths",
199
+ asConst: true,
200
+ children: `{${stringifyObject(pathsJSON)}}`
201
+ })
202
+ })
203
+ ] });
204
+ }
205
+ //#endregion
206
+ //#region src/components/Zod.tsx
207
+ function Zod({ name, node, printer, inferTypeName }) {
208
+ const output = printer.print(node);
209
+ if (!output) return;
210
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
211
+ name,
212
+ isExportable: true,
213
+ isIndexable: true,
214
+ children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
215
+ export: true,
216
+ name,
217
+ children: output
218
+ })
219
+ }), inferTypeName && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
220
+ name: inferTypeName,
221
+ isExportable: true,
222
+ isIndexable: true,
223
+ isTypeOnly: true,
224
+ children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Type, {
225
+ export: true,
226
+ name: inferTypeName,
227
+ children: `z.infer<typeof ${name}>`
228
+ })
229
+ })] });
230
+ }
231
+ //#endregion
232
+ //#region src/constants.ts
233
+ /**
234
+ * Import paths that use a namespace import (`import * as z from '...'`).
235
+ * All other import paths use a named import (`import { z } from '...'`).
236
+ */
237
+ const ZOD_NAMESPACE_IMPORTS = new Set(["zod", "zod/mini"]);
238
+ //#endregion
239
+ //#region src/utils.ts
240
+ /**
241
+ * Returns `true` when the given coercion option enables coercion for the specified type.
242
+ */
243
+ function shouldCoerce(coercion, type) {
244
+ if (coercion === void 0 || coercion === false) return false;
245
+ if (coercion === true) return true;
246
+ return !!coercion[type];
247
+ }
248
+ /**
249
+ * Collects all resolved schema names for an operation's parameters and responses
250
+ * into a single lookup object, useful for building imports and type references.
251
+ */
252
+ function buildSchemaNames(node, { params, resolver }) {
253
+ const pathParam = params.find((p) => p.in === "path");
254
+ const queryParam = params.find((p) => p.in === "query");
255
+ const headerParam = params.find((p) => p.in === "header");
256
+ const responses = {};
257
+ const errors = {};
258
+ for (const res of node.responses) {
259
+ const name = resolver.resolveResponseStatusName(node, res.statusCode);
260
+ const statusNum = Number(res.statusCode);
261
+ if (!Number.isNaN(statusNum)) {
262
+ responses[statusNum] = name;
263
+ if (statusNum >= 400) errors[statusNum] = name;
264
+ }
265
+ }
266
+ responses["default"] = resolver.resolveResponseName(node);
267
+ return {
268
+ request: node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : void 0,
269
+ parameters: {
270
+ path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : void 0,
271
+ query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : void 0,
272
+ header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : void 0
273
+ },
274
+ responses,
275
+ errors
276
+ };
277
+ }
278
+ /**
279
+ * Format a default value as a code-level literal.
280
+ * Objects become `{}`, primitives become their string representation, strings are quoted.
281
+ */
282
+ function formatDefault(value) {
283
+ if (typeof value === "string") return stringify(value);
284
+ if (typeof value === "object" && value !== null) return "{}";
285
+ return String(value ?? "");
286
+ }
287
+ /**
288
+ * Format a primitive enum/literal value.
289
+ * Strings are quoted; numbers and booleans are emitted raw.
290
+ */
291
+ function formatLiteral(v) {
292
+ if (typeof v === "string") return stringify(v);
293
+ return String(v);
294
+ }
295
+ /**
296
+ * Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
297
+ * using the standard chainable Zod v4 API.
298
+ */
299
+ function numberConstraints({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }) {
300
+ return [
301
+ min !== void 0 ? `.min(${min})` : "",
302
+ max !== void 0 ? `.max(${max})` : "",
303
+ exclusiveMinimum !== void 0 ? `.gt(${exclusiveMinimum})` : "",
304
+ exclusiveMaximum !== void 0 ? `.lt(${exclusiveMaximum})` : "",
305
+ multipleOf !== void 0 ? `.multipleOf(${multipleOf})` : ""
306
+ ].join("");
307
+ }
308
+ /**
309
+ * Build `.min()` / `.max()` / `.regex()` chains for strings/arrays
310
+ * using the standard chainable Zod v4 API.
311
+ */
312
+ function lengthConstraints({ min, max, pattern }) {
313
+ return [
314
+ min !== void 0 ? `.min(${min})` : "",
315
+ max !== void 0 ? `.max(${max})` : "",
316
+ pattern !== void 0 ? `.regex(${toRegExpString(pattern, null)})` : ""
317
+ ].join("");
318
+ }
319
+ /**
320
+ * Build `.check(z.minimum(), z.maximum())` for `zod/mini` numeric constraints.
321
+ */
322
+ function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }) {
323
+ const checks = [];
324
+ if (min !== void 0) checks.push(`z.minimum(${min})`);
325
+ if (max !== void 0) checks.push(`z.maximum(${max})`);
326
+ if (exclusiveMinimum !== void 0) checks.push(`z.minimum(${exclusiveMinimum}, { exclusive: true })`);
327
+ if (exclusiveMaximum !== void 0) checks.push(`z.maximum(${exclusiveMaximum}, { exclusive: true })`);
328
+ if (multipleOf !== void 0) checks.push(`z.multipleOf(${multipleOf})`);
329
+ return checks.length ? `.check(${checks.join(", ")})` : "";
330
+ }
331
+ /**
332
+ * Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
333
+ */
334
+ function lengthChecksMini({ min, max, pattern }) {
335
+ const checks = [];
336
+ if (min !== void 0) checks.push(`z.minLength(${min})`);
337
+ if (max !== void 0) checks.push(`z.maxLength(${max})`);
338
+ if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, null)})`);
339
+ return checks.length ? `.check(${checks.join(", ")})` : "";
340
+ }
341
+ /**
342
+ * Apply nullable / optional / nullish modifiers and an optional `.describe()` call
343
+ * to a schema value string using the chainable Zod v4 API.
344
+ */
345
+ function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }) {
346
+ let result = value;
347
+ if (nullish || nullable && optional) result = `${result}.nullish()`;
348
+ else if (optional) result = `${result}.optional()`;
349
+ else if (nullable) result = `${result}.nullable()`;
350
+ if (defaultValue !== void 0) result = `${result}.default(${formatDefault(defaultValue)})`;
351
+ if (description) result = `${result}.describe(${stringify(description)})`;
352
+ return result;
353
+ }
354
+ /**
355
+ * Apply nullable / optional / nullish modifiers using the functional `zod/mini` API
356
+ * (`z.nullable()`, `z.optional()`, `z.nullish()`).
357
+ */
358
+ function applyMiniModifiers({ value, nullable, optional, nullish, defaultValue }) {
359
+ let result = value;
360
+ if (nullish) result = `z.nullish(${result})`;
361
+ else {
362
+ if (nullable) result = `z.nullable(${result})`;
363
+ if (optional) result = `z.optional(${result})`;
364
+ }
365
+ if (defaultValue !== void 0) result = `z._default(${result}, ${formatDefault(defaultValue)})`;
366
+ return result;
367
+ }
368
+ //#endregion
369
+ //#region src/printers/printerZod.ts
370
+ /**
371
+ * Zod v4 printer built with `definePrinter`.
372
+ *
373
+ * Converts a `SchemaNode` AST into a Zod v4 code string using the chainable API
374
+ * (`.optional()`, `.nullable()`, `.omit()`, etc.). For improved tree-shaking, see {@link printerZodMini}.
375
+ *
376
+ * @example Chainable API
377
+ * ```ts
378
+ * const printer = printerZod({ coercion: false })
379
+ * const code = printer.print(stringNode) // "z.string()"
380
+ * ```
381
+ */
382
+ const printerZod = _kubb_core.ast.definePrinter((options) => {
383
+ return {
384
+ name: "zod",
385
+ options,
386
+ nodes: {
387
+ any: () => "z.any()",
388
+ unknown: () => "z.unknown()",
389
+ void: () => "z.void()",
390
+ never: () => "z.never()",
391
+ boolean: () => "z.boolean()",
392
+ null: () => "z.null()",
393
+ string(node) {
394
+ return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints(node)}`;
395
+ },
396
+ number(node) {
397
+ return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number()" : "z.number()"}${numberConstraints(node)}`;
398
+ },
399
+ integer(node) {
400
+ return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number().int()" : "z.int()"}${numberConstraints(node)}`;
401
+ },
402
+ bigint() {
403
+ return shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.bigint()" : "z.bigint()";
404
+ },
405
+ date(node) {
406
+ if (node.representation === "string") return "z.iso.date()";
407
+ return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
408
+ },
409
+ datetime(node) {
410
+ const offset = node.offset || this.options.dateType === "stringOffset";
411
+ const local = node.local || this.options.dateType === "stringLocal";
412
+ if (offset) return "z.iso.datetime({ offset: true })";
413
+ if (local) return "z.iso.datetime({ local: true })";
414
+ return "z.iso.datetime()";
415
+ },
416
+ time(node) {
417
+ if (node.representation === "string") return "z.iso.time()";
418
+ return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
419
+ },
420
+ uuid(node) {
421
+ return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints(node)}`;
422
+ },
423
+ email(node) {
424
+ return `z.email()${lengthConstraints(node)}`;
425
+ },
426
+ url(node) {
427
+ return `z.url()${lengthConstraints(node)}`;
428
+ },
429
+ ipv4: () => "z.ipv4()",
430
+ ipv6: () => "z.ipv6()",
431
+ blob: () => "z.instanceof(File)",
432
+ enum(node) {
433
+ const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
434
+ if (node.namedEnumValues?.length) {
435
+ const literals = nonNullValues.map((v) => `z.literal(${formatLiteral(v)})`);
436
+ if (literals.length === 1) return literals[0];
437
+ return `z.union([${literals.join(", ")}])`;
438
+ }
439
+ return `z.enum([${nonNullValues.map(formatLiteral).join(", ")}])`;
440
+ },
441
+ ref(node) {
442
+ if (!node.name) return void 0;
443
+ const refName = node.ref ? _kubb_core.ast.extractRefName(node.ref) ?? node.name : node.name;
444
+ const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
445
+ if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
446
+ return resolvedName;
447
+ },
448
+ object(node) {
449
+ let result = `z.object({\n ${node.properties.map((prop) => {
450
+ const { name: propName, schema } = prop;
451
+ const meta = _kubb_core.ast.syncSchemaRef(schema);
452
+ const isNullable = meta.nullable;
453
+ const isOptional = schema.optional;
454
+ const isNullish = schema.nullish;
455
+ const hasSelfRef = this.options.cyclicSchemas != null && _kubb_core.ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
456
+ if (hasSelfRef) this.options.cyclicSchemas = void 0;
457
+ const baseOutput = this.transform(schema) ?? this.transform(_kubb_core.ast.createSchema({ type: "unknown" }));
458
+ if (hasSelfRef) this.options.cyclicSchemas = options.cyclicSchemas;
459
+ const wrappedOutput = this.options.wrapOutput ? this.options.wrapOutput({
460
+ output: baseOutput,
461
+ schema
462
+ }) || baseOutput : baseOutput;
463
+ let descriptionToApply = meta.description;
464
+ if (schema.type !== "ref" && meta.type === "ref") descriptionToApply = void 0;
465
+ const value = applyModifiers({
466
+ value: wrappedOutput,
467
+ nullable: isNullable,
468
+ optional: isOptional,
469
+ nullish: isNullish,
470
+ defaultValue: meta.default,
471
+ description: descriptionToApply
472
+ });
473
+ if (hasSelfRef) return `get "${propName}"() { return ${value} }`;
474
+ return `"${propName}": ${value}`;
475
+ }).join(",\n ")}\n })`;
476
+ if (node.additionalProperties && node.additionalProperties !== true) {
477
+ const catchallType = this.transform(node.additionalProperties);
478
+ if (catchallType) result += `.catchall(${catchallType})`;
479
+ } else if (node.additionalProperties === true) result += `.catchall(${this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})`;
480
+ else if (node.additionalProperties === false) result += ".strict()";
481
+ return result;
482
+ },
483
+ array(node) {
484
+ let result = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})${lengthConstraints(node)}`;
485
+ if (node.unique) result += `.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`;
486
+ return result;
487
+ },
488
+ tuple(node) {
489
+ return `z.tuple([${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ")}])`;
490
+ },
491
+ union(node) {
492
+ const nodeMembers = node.members ?? [];
493
+ const members = nodeMembers.map((m) => this.transform(m)).filter(Boolean);
494
+ if (members.length === 0) return "";
495
+ if (members.length === 1) return members[0];
496
+ if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, [${members.join(", ")}])`;
497
+ return `z.union([${members.join(", ")}])`;
498
+ },
499
+ intersection(node) {
500
+ const members = node.members ?? [];
501
+ if (members.length === 0) return "";
502
+ const [first, ...rest] = members;
503
+ if (!first) return "";
504
+ let base = this.transform(first);
505
+ if (!base) return "";
506
+ for (const member of rest) {
507
+ if (member.primitive === "string") {
508
+ const c = lengthConstraints(_kubb_core.ast.narrowSchema(member, "string") ?? {});
509
+ if (c) {
510
+ base += c;
511
+ continue;
512
+ }
513
+ } else if (member.primitive === "number" || member.primitive === "integer") {
514
+ const c = numberConstraints(_kubb_core.ast.narrowSchema(member, "number") ?? _kubb_core.ast.narrowSchema(member, "integer") ?? {});
515
+ if (c) {
516
+ base += c;
517
+ continue;
518
+ }
519
+ } else if (member.primitive === "array") {
520
+ const c = lengthConstraints(_kubb_core.ast.narrowSchema(member, "array") ?? {});
521
+ if (c) {
522
+ base += c;
523
+ continue;
524
+ }
525
+ }
526
+ const transformed = this.transform(member);
527
+ if (transformed) base = `${base}.and(${transformed})`;
528
+ }
529
+ return base;
530
+ },
531
+ ...options.nodes
532
+ },
533
+ print(node) {
534
+ const { keysToOmit } = this.options;
535
+ let base = this.transform(node);
536
+ if (!base) return null;
537
+ const meta = _kubb_core.ast.syncSchemaRef(node);
538
+ if (keysToOmit?.length && meta.primitive === "object" && !(meta.type === "union" && meta.discriminatorPropertyName)) {
539
+ const lazyMatch = base.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
540
+ if (lazyMatch) base = `z.lazy(() => ${lazyMatch[1]}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }))`;
541
+ else base = `${base}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
542
+ }
543
+ return applyModifiers({
544
+ value: base,
545
+ nullable: meta.nullable,
546
+ optional: meta.optional,
547
+ nullish: meta.nullish,
548
+ defaultValue: meta.default,
549
+ description: meta.description
550
+ });
551
+ }
552
+ };
553
+ });
554
+ //#endregion
555
+ //#region src/printers/printerZodMini.ts
556
+ /**
557
+ * Zod v4 **Mini** printer built with `definePrinter`.
558
+ *
559
+ * Converts a `SchemaNode` AST into a Zod v4 code string using the functional API
560
+ * (`z.optional(z.string())`) for improved tree-shaking. See {@link printerZod} for the chainable API.
561
+ *
562
+ * @example Functional Mini API
563
+ * ```ts
564
+ * const printer = printerZodMini({})
565
+ * const code = printer.print(optionalStringNode) // "z.optional(z.string())"
566
+ * ```
567
+ */
568
+ const printerZodMini = _kubb_core.ast.definePrinter((options) => {
569
+ return {
570
+ name: "zod-mini",
571
+ options,
572
+ nodes: {
573
+ any: () => "z.any()",
574
+ unknown: () => "z.unknown()",
575
+ void: () => "z.void()",
576
+ never: () => "z.never()",
577
+ boolean: () => "z.boolean()",
578
+ null: () => "z.null()",
579
+ string(node) {
580
+ return `z.string()${lengthChecksMini(node)}`;
581
+ },
582
+ number(node) {
583
+ return `z.number()${numberChecksMini(node)}`;
584
+ },
585
+ integer(node) {
586
+ return `z.int()${numberChecksMini(node)}`;
587
+ },
588
+ bigint(node) {
589
+ return `z.bigint()${numberChecksMini(node)}`;
590
+ },
591
+ date(node) {
592
+ if (node.representation === "string") return "z.iso.date()";
593
+ return "z.date()";
594
+ },
595
+ datetime() {
596
+ return "z.string()";
597
+ },
598
+ time(node) {
599
+ if (node.representation === "string") return "z.iso.time()";
600
+ return "z.date()";
601
+ },
602
+ uuid(node) {
603
+ return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthChecksMini(node)}`;
604
+ },
605
+ email(node) {
606
+ return `z.email()${lengthChecksMini(node)}`;
607
+ },
608
+ url(node) {
609
+ return `z.url()${lengthChecksMini(node)}`;
610
+ },
611
+ ipv4: () => "z.ipv4()",
612
+ ipv6: () => "z.ipv6()",
613
+ blob: () => "z.instanceof(File)",
614
+ enum(node) {
615
+ const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
616
+ if (node.namedEnumValues?.length) {
617
+ const literals = nonNullValues.map((v) => `z.literal(${formatLiteral(v)})`);
618
+ if (literals.length === 1) return literals[0];
619
+ return `z.union([${literals.join(", ")}])`;
620
+ }
621
+ return `z.enum([${nonNullValues.map(formatLiteral).join(", ")}])`;
622
+ },
623
+ ref(node) {
624
+ if (!node.name) return void 0;
625
+ const refName = node.ref ? _kubb_core.ast.extractRefName(node.ref) ?? node.name : node.name;
626
+ const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
627
+ if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
628
+ return resolvedName;
629
+ },
630
+ object(node) {
631
+ return `z.object({\n ${node.properties.map((prop) => {
632
+ const { name: propName, schema } = prop;
633
+ const meta = _kubb_core.ast.syncSchemaRef(schema);
634
+ const isNullable = meta.nullable;
635
+ const isOptional = schema.optional;
636
+ const isNullish = schema.nullish;
637
+ const hasSelfRef = this.options.cyclicSchemas != null && _kubb_core.ast.containsCircularRef(schema, { circularSchemas: this.options.cyclicSchemas });
638
+ if (hasSelfRef) this.options.cyclicSchemas = void 0;
639
+ const baseOutput = this.transform(schema) ?? this.transform(_kubb_core.ast.createSchema({ type: "unknown" }));
640
+ if (hasSelfRef) this.options.cyclicSchemas = options.cyclicSchemas;
641
+ const value = applyMiniModifiers({
642
+ value: this.options.wrapOutput ? this.options.wrapOutput({
643
+ output: baseOutput,
644
+ schema
645
+ }) || baseOutput : baseOutput,
646
+ nullable: isNullable,
647
+ optional: isOptional,
648
+ nullish: isNullish,
649
+ defaultValue: meta.default
650
+ });
651
+ if (hasSelfRef) return `get "${propName}"() { return ${value} }`;
652
+ return `"${propName}": ${value}`;
653
+ }).join(",\n ")}\n })`;
654
+ },
655
+ array(node) {
656
+ let result = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(_kubb_core.ast.createSchema({ type: "unknown" }))})${lengthChecksMini(node)}`;
657
+ if (node.unique) result += `.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`;
658
+ return result;
659
+ },
660
+ tuple(node) {
661
+ return `z.tuple([${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ")}])`;
662
+ },
663
+ union(node) {
664
+ const nodeMembers = node.members ?? [];
665
+ const members = nodeMembers.map((m) => this.transform(m)).filter(Boolean);
666
+ if (members.length === 0) return "";
667
+ if (members.length === 1) return members[0];
668
+ if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, [${members.join(", ")}])`;
669
+ return `z.union([${members.join(", ")}])`;
670
+ },
671
+ intersection(node) {
672
+ const members = node.members ?? [];
673
+ if (members.length === 0) return "";
674
+ const [first, ...rest] = members;
675
+ if (!first) return "";
676
+ let base = this.transform(first);
677
+ if (!base) return "";
678
+ for (const member of rest) {
679
+ if (member.primitive === "string") {
680
+ const c = lengthChecksMini(_kubb_core.ast.narrowSchema(member, "string") ?? {});
681
+ if (c) {
682
+ base += c;
683
+ continue;
684
+ }
685
+ } else if (member.primitive === "number" || member.primitive === "integer") {
686
+ const c = numberChecksMini(_kubb_core.ast.narrowSchema(member, "number") ?? _kubb_core.ast.narrowSchema(member, "integer") ?? {});
687
+ if (c) {
688
+ base += c;
689
+ continue;
690
+ }
691
+ } else if (member.primitive === "array") {
692
+ const c = lengthChecksMini(_kubb_core.ast.narrowSchema(member, "array") ?? {});
693
+ if (c) {
694
+ base += c;
695
+ continue;
696
+ }
697
+ }
698
+ const transformed = this.transform(member);
699
+ if (transformed) base = `z.intersection(${base}, ${transformed})`;
700
+ }
701
+ return base;
702
+ },
703
+ ...options.nodes
704
+ },
705
+ print(node) {
706
+ const { keysToOmit } = this.options;
707
+ let base = this.transform(node);
708
+ if (!base) return null;
709
+ const meta = _kubb_core.ast.syncSchemaRef(node);
710
+ if (keysToOmit?.length && meta.primitive === "object" && !(meta.type === "union" && meta.discriminatorPropertyName)) {
711
+ const lazyMatch = base.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
712
+ if (lazyMatch) base = `z.lazy(() => ${lazyMatch[1]}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }))`;
713
+ else base = `${base}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
714
+ }
715
+ return applyMiniModifiers({
716
+ value: base,
717
+ nullable: meta.nullable,
718
+ optional: meta.optional,
719
+ nullish: meta.nullish,
720
+ defaultValue: meta.default
721
+ });
722
+ }
723
+ };
724
+ });
725
+ //#endregion
726
+ //#region src/generators/zodGenerator.tsx
727
+ const zodGenerator = (0, _kubb_core.defineGenerator)({
728
+ name: "zod",
729
+ renderer: _kubb_renderer_jsx.jsxRenderer,
730
+ schema(node, ctx) {
731
+ const { adapter, config, resolver, root } = ctx;
732
+ const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
733
+ const dateType = adapter.options.dateType;
734
+ if (!node.name) return;
735
+ const mode = ctx.getMode(output);
736
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
737
+ const imports = adapter.getImports(node, (schemaName) => ({
738
+ name: resolver.resolveSchemaName(schemaName),
739
+ path: resolver.resolveFile({
740
+ name: schemaName,
741
+ extname: ".ts"
742
+ }, {
743
+ root,
744
+ output,
745
+ group
746
+ }).path
747
+ }));
748
+ const meta = {
749
+ name: resolver.resolveSchemaName(node.name),
750
+ file: resolver.resolveFile({
751
+ name: node.name,
752
+ extname: ".ts"
753
+ }, {
754
+ root,
755
+ output,
756
+ group
757
+ })
758
+ };
759
+ const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : void 0;
760
+ const cyclicSchemas = adapter.inputNode ? _kubb_core.ast.findCircularSchemas(adapter.inputNode.schemas) : void 0;
761
+ const schemaPrinter = mini ? printerZodMini({
762
+ guidType,
763
+ wrapOutput,
764
+ resolver,
765
+ cyclicSchemas,
766
+ nodes: printer?.nodes
767
+ }) : printerZod({
768
+ coercion,
769
+ guidType,
770
+ dateType,
771
+ wrapOutput,
772
+ resolver,
773
+ cyclicSchemas,
774
+ nodes: printer?.nodes
775
+ });
776
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
777
+ baseName: meta.file.baseName,
778
+ path: meta.file.path,
779
+ meta: meta.file.meta,
780
+ banner: resolver.resolveBanner(adapter.inputNode, {
781
+ output,
782
+ config
783
+ }),
784
+ footer: resolver.resolveFooter(adapter.inputNode, {
785
+ output,
786
+ config
787
+ }),
788
+ children: [
789
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
790
+ name: isZodImport ? "z" : ["z"],
791
+ path: importPath,
792
+ isNameSpace: isZodImport
793
+ }),
794
+ mode === "split" && imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
795
+ root: meta.file.path,
796
+ path: imp.path,
797
+ name: imp.name
798
+ }, [node.name, imp.path].join("-"))),
799
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Zod, {
800
+ name: meta.name,
801
+ node,
802
+ printer: schemaPrinter,
803
+ inferTypeName
804
+ })
805
+ ]
806
+ });
807
+ },
808
+ operation(node, ctx) {
809
+ const { adapter, config, resolver, root } = ctx;
810
+ const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, printer } = ctx.options;
811
+ const dateType = adapter.options.dateType;
812
+ const mode = ctx.getMode(output);
813
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
814
+ const params = _kubb_core.ast.caseParams(node.parameters, paramsCasing);
815
+ const meta = { file: resolver.resolveFile({
816
+ name: node.operationId,
817
+ extname: ".ts",
818
+ tag: node.tags[0] ?? "default",
819
+ path: node.path
820
+ }, {
821
+ root,
822
+ output,
823
+ group
824
+ }) };
825
+ const cyclicSchemas = adapter.inputNode ? _kubb_core.ast.findCircularSchemas(adapter.inputNode.schemas) : void 0;
826
+ function renderSchemaEntry({ schema, name, keysToOmit }) {
827
+ if (!schema) return null;
828
+ const inferTypeName = inferred ? resolver.resolveTypeName(name) : void 0;
829
+ const imports = adapter.getImports(schema, (schemaName) => ({
830
+ name: resolver.resolveSchemaName(schemaName),
831
+ path: resolver.resolveFile({
832
+ name: schemaName,
833
+ extname: ".ts"
834
+ }, {
835
+ root,
836
+ output,
837
+ group
838
+ }).path
839
+ }));
840
+ const schemaPrinter = mini ? printerZodMini({
841
+ guidType,
842
+ wrapOutput,
843
+ resolver,
844
+ keysToOmit,
845
+ cyclicSchemas,
846
+ nodes: printer?.nodes
847
+ }) : printerZod({
848
+ coercion,
849
+ guidType,
850
+ dateType,
851
+ wrapOutput,
852
+ resolver,
853
+ keysToOmit,
854
+ cyclicSchemas,
855
+ nodes: printer?.nodes
856
+ });
857
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
858
+ root: meta.file.path,
859
+ path: imp.path,
860
+ name: imp.name
861
+ }, [
862
+ name,
863
+ imp.path,
864
+ imp.name
865
+ ].join("-"))), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Zod, {
866
+ name,
867
+ node: schema,
868
+ printer: schemaPrinter,
869
+ inferTypeName
870
+ })] });
871
+ }
872
+ const paramSchemas = params.map((param) => renderSchemaEntry({
873
+ schema: param.schema,
874
+ name: resolver.resolveParamName(node, param)
875
+ }));
876
+ const responseSchemas = node.responses.map((res) => renderSchemaEntry({
877
+ schema: res.schema,
878
+ name: resolver.resolveResponseStatusName(node, res.statusCode),
879
+ keysToOmit: res.keysToOmit
880
+ }));
881
+ const responsesWithSchema = node.responses.filter((res) => res.schema);
882
+ const responseUnionSchema = responsesWithSchema.length > 0 ? (() => {
883
+ const responseUnionName = resolver.resolveResponseName(node);
884
+ if (new Set(responsesWithSchema.flatMap((res) => res.schema ? adapter.getImports(res.schema, (schemaName) => ({
885
+ name: resolver.resolveSchemaName(schemaName),
886
+ path: ""
887
+ })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : [])).has(responseUnionName)) return null;
888
+ const members = responsesWithSchema.map((res) => _kubb_core.ast.createSchema({
889
+ type: "ref",
890
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
891
+ }));
892
+ return renderSchemaEntry({
893
+ schema: members.length === 1 ? members[0] : _kubb_core.ast.createSchema({
894
+ type: "union",
895
+ members
896
+ }),
897
+ name: responseUnionName
898
+ });
899
+ })() : null;
900
+ const requestSchema = node.requestBody?.content?.[0]?.schema ? renderSchemaEntry({
901
+ schema: {
902
+ ...node.requestBody.content[0].schema,
903
+ description: node.requestBody.description ?? node.requestBody.content[0].schema.description
904
+ },
905
+ name: resolver.resolveDataName(node),
906
+ keysToOmit: node.requestBody.content[0].keysToOmit
907
+ }) : null;
908
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
909
+ baseName: meta.file.baseName,
910
+ path: meta.file.path,
911
+ meta: meta.file.meta,
912
+ banner: resolver.resolveBanner(adapter.inputNode, {
913
+ output,
914
+ config
915
+ }),
916
+ footer: resolver.resolveFooter(adapter.inputNode, {
917
+ output,
918
+ config
919
+ }),
920
+ children: [
921
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
922
+ name: isZodImport ? "z" : ["z"],
923
+ path: importPath,
924
+ isNameSpace: isZodImport
925
+ }),
926
+ paramSchemas,
927
+ responseSchemas,
928
+ responseUnionSchema,
929
+ requestSchema
930
+ ]
931
+ });
932
+ },
933
+ operations(nodes, ctx) {
934
+ const { adapter, config, resolver, root } = ctx;
935
+ const { output, importPath, group, operations, paramsCasing } = ctx.options;
936
+ if (!operations) return;
937
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
938
+ const meta = { file: resolver.resolveFile({
939
+ name: "operations",
940
+ extname: ".ts"
941
+ }, {
942
+ root,
943
+ output,
944
+ group
945
+ }) };
946
+ const transformedOperations = nodes.map((node) => {
947
+ return {
948
+ node,
949
+ data: buildSchemaNames(node, {
950
+ params: _kubb_core.ast.caseParams(node.parameters, paramsCasing),
951
+ resolver
952
+ })
953
+ };
954
+ });
955
+ const imports = transformedOperations.flatMap(({ node, data }) => {
956
+ const names = [
957
+ data.request,
958
+ ...Object.values(data.responses),
959
+ ...Object.values(data.parameters)
960
+ ].filter(Boolean);
961
+ const opFile = resolver.resolveFile({
962
+ name: node.operationId,
963
+ extname: ".ts",
964
+ tag: node.tags[0] ?? "default",
965
+ path: node.path
966
+ }, {
967
+ root,
968
+ output,
969
+ group
970
+ });
971
+ return names.map((name) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
972
+ name: [name],
973
+ root: meta.file.path,
974
+ path: opFile.path
975
+ }, [name, opFile.path].join("-")));
976
+ });
977
+ return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
978
+ baseName: meta.file.baseName,
979
+ path: meta.file.path,
980
+ meta: meta.file.meta,
981
+ banner: resolver.resolveBanner(adapter.inputNode, {
982
+ output,
983
+ config
984
+ }),
985
+ footer: resolver.resolveFooter(adapter.inputNode, {
986
+ output,
987
+ config
988
+ }),
989
+ children: [
990
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
991
+ isTypeOnly: true,
992
+ name: isZodImport ? "z" : ["z"],
993
+ path: importPath,
994
+ isNameSpace: isZodImport
995
+ }),
996
+ imports,
997
+ /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Operations, {
998
+ name: "operations",
999
+ operations: transformedOperations
1000
+ })
1001
+ ]
1002
+ });
1003
+ }
1004
+ });
1005
+ //#endregion
1006
+ //#region src/resolvers/resolverZod.ts
1007
+ /**
1008
+ * Naming convention resolver for Zod plugin.
1009
+ *
1010
+ * Provides default naming helpers using camelCase with a `Schema` suffix for schemas.
1011
+ *
1012
+ * @example
1013
+ * `resolverZod.default('list pets', 'function') // → 'listPetsSchema'`
1014
+ */
1015
+ const resolverZod = (0, _kubb_core.defineResolver)((ctx) => {
1016
+ return {
1017
+ name: "default",
1018
+ pluginName: "plugin-zod",
1019
+ default(name, type) {
1020
+ return camelCase(name, {
1021
+ isFile: type === "file",
1022
+ suffix: type ? "schema" : void 0
1023
+ });
1024
+ },
1025
+ resolveSchemaName(name) {
1026
+ return camelCase(name, { suffix: "schema" });
1027
+ },
1028
+ resolveSchemaTypeName(name) {
1029
+ return pascalCase(name, { suffix: "schema" });
1030
+ },
1031
+ resolveTypeName(name) {
1032
+ return pascalCase(name);
1033
+ },
1034
+ resolvePathName(name, type) {
1035
+ return ctx.default(name, type);
1036
+ },
1037
+ resolveParamName(node, param) {
1038
+ return ctx.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`);
1039
+ },
1040
+ resolveResponseStatusName(node, statusCode) {
1041
+ return ctx.resolveSchemaName(`${node.operationId} Status ${statusCode}`);
1042
+ },
1043
+ resolveDataName(node) {
1044
+ return ctx.resolveSchemaName(`${node.operationId} Data`);
1045
+ },
1046
+ resolveResponsesName(node) {
1047
+ return ctx.resolveSchemaName(`${node.operationId} Responses`);
1048
+ },
1049
+ resolveResponseName(node) {
1050
+ return ctx.resolveSchemaName(`${node.operationId} Response`);
1051
+ },
1052
+ resolvePathParamsName(node, param) {
1053
+ return ctx.resolveParamName(node, param);
1054
+ },
1055
+ resolveQueryParamsName(node, param) {
1056
+ return ctx.resolveParamName(node, param);
1057
+ },
1058
+ resolveHeaderParamsName(node, param) {
1059
+ return ctx.resolveParamName(node, param);
1060
+ }
1061
+ };
1062
+ });
1063
+ //#endregion
65
1064
  //#region src/plugin.ts
1065
+ /**
1066
+ * Canonical plugin name for `@kubb/plugin-zod`, used in driver lookups and warnings.
1067
+ */
66
1068
  const pluginZodName = "plugin-zod";
67
- const pluginZod = (0, _kubb_core.createPlugin)((options) => {
1069
+ /**
1070
+ * Generates Zod validation schemas from an OpenAPI specification.
1071
+ * Walks schemas and operations, delegates to generators, and writes barrel files
1072
+ * based on the configured `barrelType`.
1073
+ *
1074
+ * @example Zod schema generator
1075
+ * ```ts
1076
+ * import pluginZod from '@kubb/plugin-zod'
1077
+ * export default defineConfig({
1078
+ * plugins: [pluginZod({ output: { path: 'zod' } })]
1079
+ * })
1080
+ * ```
1081
+ */
1082
+ const pluginZod = (0, _kubb_core.definePlugin)((options) => {
68
1083
  const { output = {
69
1084
  path: "zod",
70
1085
  barrelType: "named"
71
- }, group, exclude = [], include, override = [], transformers = {}, dateType = "string", unknownType = "any", emptySchemaType = unknownType, integerType = "number", typed = false, mapper = {}, operations = false, mini = false, version = mini ? "4" : new _kubb_core.PackageManager().isValidSync("zod", ">=4") ? "4" : "3", guidType = "uuid", importPath = mini ? "zod/mini" : version === "4" ? "zod/v4" : "zod", coercion = false, inferred = false, generators = [require_generators.zodGenerator, operations ? require_generators.operationsGenerator : void 0].filter(Boolean), wrapOutput = void 0, contentType } = options;
1086
+ }, group, exclude = [], include, override = [], typed = false, operations = false, mini = false, guidType = "uuid", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, wrapOutput = void 0, paramsCasing, printer, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
1087
+ const groupConfig = group ? {
1088
+ ...group,
1089
+ name: (ctx) => {
1090
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
1091
+ return `${camelCase(ctx.group)}Controller`;
1092
+ }
1093
+ } : void 0;
72
1094
  return {
73
1095
  name: pluginZodName,
74
- options: {
75
- output,
76
- transformers,
77
- include,
78
- exclude,
79
- override,
80
- typed,
81
- dateType,
82
- unknownType,
83
- emptySchemaType,
84
- integerType,
85
- mapper,
86
- importPath,
87
- coercion,
88
- operations,
89
- inferred,
90
- group,
91
- wrapOutput,
92
- version,
93
- guidType,
94
- mini,
95
- usedEnumNames: {}
96
- },
97
- pre: [_kubb_plugin_oas.pluginOasName, typed ? _kubb_plugin_ts.pluginTsName : void 0].filter(Boolean),
98
- resolvePath(baseName, pathMode, options) {
99
- const root = node_path.default.resolve(this.config.root, this.config.output.path);
100
- if ((pathMode ?? (0, _kubb_core.getMode)(node_path.default.resolve(root, output.path))) === "single")
101
- /**
102
- * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend
103
- * Other plugins then need to call addOrAppend instead of just add from the fileManager class
104
- */
105
- return node_path.default.resolve(root, output.path);
106
- if (group && (options?.group?.path || options?.group?.tag)) {
107
- const groupName = group?.name ? group.name : (ctx) => {
108
- if (group?.type === "path") return `${ctx.group.split("/")[1]}`;
109
- return `${camelCase(ctx.group)}Controller`;
110
- };
111
- return node_path.default.resolve(root, output.path, groupName({ group: group.type === "path" ? options.group.path : options.group.tag }), baseName);
112
- }
113
- return node_path.default.resolve(root, output.path, baseName);
114
- },
115
- resolveName(name, type) {
116
- let resolvedName = camelCase(name, {
117
- suffix: type ? "schema" : void 0,
118
- isFile: type === "file"
119
- });
120
- if (type === "type") resolvedName = pascalCase(resolvedName);
121
- if (type) return transformers?.name?.(resolvedName, type) || resolvedName;
122
- return resolvedName;
123
- },
124
- async install() {
125
- const root = node_path.default.resolve(this.config.root, this.config.output.path);
126
- const mode = (0, _kubb_core.getMode)(node_path.default.resolve(root, output.path));
127
- const oas = await this.getOas();
128
- if (this.plugin.options.typed && this.plugin.options.version === "3") await this.addFile({
129
- baseName: "ToZod.ts",
130
- path: node_path.default.resolve(root, ".kubb/ToZod.ts"),
131
- sources: [{
132
- name: "ToZod",
133
- value: require_templates_ToZod_source.source
134
- }],
135
- imports: [],
136
- exports: []
137
- });
138
- const schemaFiles = await new _kubb_plugin_oas.SchemaGenerator(this.plugin.options, {
139
- fabric: this.fabric,
140
- oas,
141
- driver: this.driver,
142
- events: this.events,
143
- plugin: this.plugin,
144
- contentType,
145
- include: void 0,
146
- override,
147
- mode,
148
- output: output.path
149
- }).build(...generators);
150
- await this.upsertFile(...schemaFiles);
151
- const operationFiles = await new _kubb_plugin_oas.OperationGenerator(this.plugin.options, {
152
- fabric: this.fabric,
153
- oas,
154
- driver: this.driver,
155
- events: this.events,
156
- plugin: this.plugin,
157
- contentType,
1096
+ options,
1097
+ hooks: { "kubb:plugin:setup"(ctx) {
1098
+ ctx.setOptions({
1099
+ output,
158
1100
  exclude,
159
1101
  include,
160
1102
  override,
161
- mode
162
- }).build(...generators);
163
- await this.upsertFile(...operationFiles);
164
- const barrelFiles = await (0, _kubb_core.getBarrelFiles)(this.fabric.files, {
165
- type: output.barrelType ?? "named",
166
- root,
167
- output,
168
- meta: { pluginName: this.plugin.name }
1103
+ group: groupConfig,
1104
+ typed,
1105
+ importPath,
1106
+ coercion,
1107
+ operations,
1108
+ inferred,
1109
+ guidType,
1110
+ mini,
1111
+ wrapOutput,
1112
+ paramsCasing,
1113
+ printer
169
1114
  });
170
- await this.upsertFile(...barrelFiles);
171
- }
1115
+ ctx.setResolver(userResolver ? {
1116
+ ...resolverZod,
1117
+ ...userResolver
1118
+ } : resolverZod);
1119
+ if (userTransformer) ctx.setTransformer(userTransformer);
1120
+ ctx.addGenerator(zodGenerator);
1121
+ for (const gen of userGenerators) ctx.addGenerator(gen);
1122
+ } }
172
1123
  };
173
1124
  });
174
1125
  //#endregion
1126
+ exports.default = pluginZod;
175
1127
  exports.pluginZod = pluginZod;
176
1128
  exports.pluginZodName = pluginZodName;
1129
+ exports.printerZod = printerZod;
1130
+ exports.printerZodMini = printerZodMini;
1131
+ exports.resolverZod = resolverZod;
1132
+ exports.zodGenerator = zodGenerator;
177
1133
 
178
1134
  //# sourceMappingURL=index.cjs.map