@kubb/plugin-zod 5.0.0-alpha.24 → 5.0.0-alpha.25

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 (47) hide show
  1. package/dist/index.cjs +1673 -88
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +317 -2
  4. package/dist/index.js +1646 -88
  5. package/dist/index.js.map +1 -1
  6. package/package.json +5 -33
  7. package/src/components/Operations.tsx +22 -15
  8. package/src/components/Zod.tsx +18 -118
  9. package/src/components/ZodMini.tsx +41 -0
  10. package/src/constants.ts +5 -0
  11. package/src/generators/zodGenerator.tsx +165 -158
  12. package/src/generators/zodGeneratorLegacy.tsx +401 -0
  13. package/src/index.ts +11 -1
  14. package/src/plugin.ts +105 -129
  15. package/src/presets.ts +25 -0
  16. package/src/printers/printerZod.ts +271 -0
  17. package/src/printers/printerZodMini.ts +246 -0
  18. package/src/resolvers/resolverZod.ts +71 -0
  19. package/src/resolvers/resolverZodLegacy.ts +60 -0
  20. package/src/types.ts +121 -92
  21. package/src/utils.ts +248 -0
  22. package/dist/components-DW4Q2yVq.js +0 -868
  23. package/dist/components-DW4Q2yVq.js.map +0 -1
  24. package/dist/components-qFUGs0vU.cjs +0 -916
  25. package/dist/components-qFUGs0vU.cjs.map +0 -1
  26. package/dist/components.cjs +0 -4
  27. package/dist/components.d.ts +0 -56
  28. package/dist/components.js +0 -2
  29. package/dist/generators-C9BCTLXg.cjs +0 -301
  30. package/dist/generators-C9BCTLXg.cjs.map +0 -1
  31. package/dist/generators-maqx12yN.js +0 -290
  32. package/dist/generators-maqx12yN.js.map +0 -1
  33. package/dist/generators.cjs +0 -4
  34. package/dist/generators.d.ts +0 -12
  35. package/dist/generators.js +0 -2
  36. package/dist/templates/ToZod.source.cjs +0 -7
  37. package/dist/templates/ToZod.source.cjs.map +0 -1
  38. package/dist/templates/ToZod.source.d.ts +0 -7
  39. package/dist/templates/ToZod.source.js +0 -6
  40. package/dist/templates/ToZod.source.js.map +0 -1
  41. package/dist/types-CClg-ikj.d.ts +0 -172
  42. package/src/components/index.ts +0 -2
  43. package/src/generators/index.ts +0 -2
  44. package/src/generators/operationsGenerator.tsx +0 -50
  45. package/src/parser.ts +0 -952
  46. package/src/templates/ToZod.source.ts +0 -4
  47. package/templates/ToZod.ts +0 -61
package/dist/index.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import "./chunk--u3MIqq1.js";
2
- import { n as operationsGenerator, t as zodGenerator } from "./generators-maqx12yN.js";
3
- import { source } from "./templates/ToZod.source.js";
4
2
  import path from "node:path";
5
- import { createPlugin, getBarrelFiles, getMode, satisfiesDependency } from "@kubb/core";
6
- import { OperationGenerator, SchemaGenerator, pluginOasName } from "@kubb/plugin-oas";
7
- import { pluginTsName } from "@kubb/plugin-ts";
3
+ import { caseParams, composeTransformers, createProperty, createSchema, extractRefName, narrowSchema, syncSchemaRef, transform, walk } from "@kubb/ast";
4
+ import { createPlugin, defineGenerator, definePresets, definePrinter, defineResolver, getBarrelFiles, getMode, getPreset, runGeneratorOperation, runGeneratorOperations, runGeneratorSchema } from "@kubb/core";
5
+ import { Const, File, Type } from "@kubb/react-fabric";
6
+ import { Fragment, jsx, jsxs } from "@kubb/react-fabric/jsx-runtime";
8
7
  //#region ../../internals/utils/src/casing.ts
9
8
  /**
10
9
  * Shared implementation for camelCase and PascalCase conversion.
@@ -63,105 +62,1664 @@ function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
63
62
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
64
63
  }
65
64
  //#endregion
65
+ //#region ../../internals/utils/src/string.ts
66
+ /**
67
+ * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
68
+ * Returns the string unchanged when no balanced quote pair is found.
69
+ *
70
+ * @example
71
+ * trimQuotes('"hello"') // 'hello'
72
+ * trimQuotes('hello') // 'hello'
73
+ */
74
+ function trimQuotes(text) {
75
+ if (text.length >= 2) {
76
+ const first = text[0];
77
+ const last = text[text.length - 1];
78
+ if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
79
+ }
80
+ return text;
81
+ }
82
+ //#endregion
83
+ //#region ../../internals/utils/src/object.ts
84
+ /**
85
+ * Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.
86
+ *
87
+ * @example
88
+ * stringify('hello') // '"hello"'
89
+ * stringify('"hello"') // '"hello"'
90
+ */
91
+ function stringify(value) {
92
+ if (value === void 0 || value === null) return "\"\"";
93
+ return JSON.stringify(trimQuotes(value.toString()));
94
+ }
95
+ /**
96
+ * Converts a plain object into a multiline key-value string suitable for embedding in generated code.
97
+ * Nested objects are recursively stringified with indentation.
98
+ *
99
+ * @example
100
+ * stringifyObject({ foo: 'bar', nested: { a: 1 } })
101
+ * // 'foo: bar,\nnested: {\n a: 1\n }'
102
+ */
103
+ function stringifyObject(value) {
104
+ return Object.entries(value).map(([key, val]) => {
105
+ if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`;
106
+ return `${key}: ${val}`;
107
+ }).filter(Boolean).join(",\n");
108
+ }
109
+ //#endregion
110
+ //#region ../../internals/utils/src/regexp.ts
111
+ /**
112
+ * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
113
+ * Inline flags expressed as `^(?im)` prefixes are extracted and applied to the resulting expression.
114
+ * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
115
+ *
116
+ * @example
117
+ * toRegExpString('^(?im)foo') // → 'new RegExp("foo", "im")'
118
+ * toRegExpString('^(?im)foo', null) // → '/foo/im'
119
+ */
120
+ function toRegExpString(text, func = "RegExp") {
121
+ const raw = trimQuotes(text);
122
+ const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
123
+ const replacementTarget = match?.[1] ?? "";
124
+ const matchedFlags = match?.[2];
125
+ const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
126
+ const { source, flags } = new RegExp(cleaned, matchedFlags);
127
+ if (func === null) return `/${source}/${flags}`;
128
+ return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
129
+ }
130
+ //#endregion
131
+ //#region src/components/Operations.tsx
132
+ function Operations({ name, operations }) {
133
+ const operationsJSON = operations.reduce((prev, acc) => {
134
+ prev[`"${acc.node.operationId}"`] = acc.data;
135
+ return prev;
136
+ }, {});
137
+ const pathsJSON = operations.reduce((prev, acc) => {
138
+ prev[`"${acc.node.path}"`] = {
139
+ ...prev[`"${acc.node.path}"`] ?? {},
140
+ [acc.node.method]: `operations["${acc.node.operationId}"]`
141
+ };
142
+ return prev;
143
+ }, {});
144
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
145
+ /* @__PURE__ */ jsx(File.Source, {
146
+ name: "OperationSchema",
147
+ isExportable: true,
148
+ isIndexable: true,
149
+ children: /* @__PURE__ */ jsx(Type, {
150
+ name: "OperationSchema",
151
+ export: true,
152
+ children: `{
153
+ readonly request: z.ZodTypeAny | undefined;
154
+ readonly parameters: {
155
+ readonly path: z.ZodTypeAny | undefined;
156
+ readonly query: z.ZodTypeAny | undefined;
157
+ readonly header: z.ZodTypeAny | undefined;
158
+ };
159
+ readonly responses: {
160
+ readonly [status: number]: z.ZodTypeAny;
161
+ readonly default: z.ZodTypeAny;
162
+ };
163
+ readonly errors: {
164
+ readonly [status: number]: z.ZodTypeAny;
165
+ };
166
+ }`
167
+ })
168
+ }),
169
+ /* @__PURE__ */ jsx(File.Source, {
170
+ name: "OperationsMap",
171
+ isExportable: true,
172
+ isIndexable: true,
173
+ children: /* @__PURE__ */ jsx(Type, {
174
+ name: "OperationsMap",
175
+ export: true,
176
+ children: "Record<string, OperationSchema>"
177
+ })
178
+ }),
179
+ /* @__PURE__ */ jsx(File.Source, {
180
+ name,
181
+ isExportable: true,
182
+ isIndexable: true,
183
+ children: /* @__PURE__ */ jsx(Const, {
184
+ export: true,
185
+ name,
186
+ asConst: true,
187
+ children: `{${stringifyObject(operationsJSON)}}`
188
+ })
189
+ }),
190
+ /* @__PURE__ */ jsx(File.Source, {
191
+ name: "paths",
192
+ isExportable: true,
193
+ isIndexable: true,
194
+ children: /* @__PURE__ */ jsx(Const, {
195
+ export: true,
196
+ name: "paths",
197
+ asConst: true,
198
+ children: `{${stringifyObject(pathsJSON)}}`
199
+ })
200
+ })
201
+ ] });
202
+ }
203
+ //#endregion
204
+ //#region src/utils.ts
205
+ /**
206
+ * Returns `true` when the given coercion option enables coercion for the specified type.
207
+ */
208
+ function shouldCoerce(coercion, type) {
209
+ if (coercion === void 0 || coercion === false) return false;
210
+ if (coercion === true) return true;
211
+ return !!coercion[type];
212
+ }
213
+ /**
214
+ * Collects all resolved schema names for an operation's parameters and responses
215
+ * into a single lookup object, useful for building imports and type references.
216
+ */
217
+ function buildSchemaNames(node, { params, resolver }) {
218
+ const pathParam = params.find((p) => p.in === "path");
219
+ const queryParam = params.find((p) => p.in === "query");
220
+ const headerParam = params.find((p) => p.in === "header");
221
+ const responses = {};
222
+ const errors = {};
223
+ for (const res of node.responses) {
224
+ const name = resolver.resolveResponseStatusName(node, res.statusCode);
225
+ const statusNum = Number(res.statusCode);
226
+ if (!Number.isNaN(statusNum)) {
227
+ responses[statusNum] = name;
228
+ if (statusNum >= 400) errors[statusNum] = name;
229
+ }
230
+ }
231
+ responses["default"] = resolver.resolveResponseName(node);
232
+ return {
233
+ request: node.requestBody?.schema ? resolver.resolveDataName(node) : void 0,
234
+ parameters: {
235
+ path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : void 0,
236
+ query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : void 0,
237
+ header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : void 0
238
+ },
239
+ responses,
240
+ errors
241
+ };
242
+ }
243
+ /**
244
+ * Format a default value as a code-level literal.
245
+ * Objects become `{}`, primitives become their string representation, strings are quoted.
246
+ */
247
+ function formatDefault(value) {
248
+ if (typeof value === "string") return stringify(value);
249
+ if (typeof value === "object" && value !== null) return "{}";
250
+ return String(value ?? "");
251
+ }
252
+ /**
253
+ * Format a primitive enum/literal value.
254
+ * Strings are quoted; numbers and booleans are emitted raw.
255
+ */
256
+ function formatLiteral(v) {
257
+ if (typeof v === "string") return stringify(v);
258
+ return String(v);
259
+ }
260
+ /**
261
+ * Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
262
+ * using the standard chainable Zod v4 API.
263
+ */
264
+ function numberConstraints({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }) {
265
+ return [
266
+ min !== void 0 ? `.min(${min})` : "",
267
+ max !== void 0 ? `.max(${max})` : "",
268
+ exclusiveMinimum !== void 0 ? `.gt(${exclusiveMinimum})` : "",
269
+ exclusiveMaximum !== void 0 ? `.lt(${exclusiveMaximum})` : "",
270
+ multipleOf !== void 0 ? `.multipleOf(${multipleOf})` : ""
271
+ ].join("");
272
+ }
273
+ /**
274
+ * Build `.min()` / `.max()` / `.regex()` chains for strings/arrays
275
+ * using the standard chainable Zod v4 API.
276
+ */
277
+ function lengthConstraints({ min, max, pattern }) {
278
+ return [
279
+ min !== void 0 ? `.min(${min})` : "",
280
+ max !== void 0 ? `.max(${max})` : "",
281
+ pattern !== void 0 ? `.regex(${toRegExpString(pattern, null)})` : ""
282
+ ].join("");
283
+ }
284
+ /**
285
+ * Build `.check(z.minimum(), z.maximum())` for `zod/mini` numeric constraints.
286
+ */
287
+ function numberChecksMini({ min, max, exclusiveMinimum, exclusiveMaximum, multipleOf }) {
288
+ const checks = [];
289
+ if (min !== void 0) checks.push(`z.minimum(${min})`);
290
+ if (max !== void 0) checks.push(`z.maximum(${max})`);
291
+ if (exclusiveMinimum !== void 0) checks.push(`z.minimum(${exclusiveMinimum}, { exclusive: true })`);
292
+ if (exclusiveMaximum !== void 0) checks.push(`z.maximum(${exclusiveMaximum}, { exclusive: true })`);
293
+ if (multipleOf !== void 0) checks.push(`z.multipleOf(${multipleOf})`);
294
+ return checks.length ? `.check(${checks.join(", ")})` : "";
295
+ }
296
+ /**
297
+ * Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
298
+ */
299
+ function lengthChecksMini({ min, max, pattern }) {
300
+ const checks = [];
301
+ if (min !== void 0) checks.push(`z.minLength(${min})`);
302
+ if (max !== void 0) checks.push(`z.maxLength(${max})`);
303
+ if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, null)})`);
304
+ return checks.length ? `.check(${checks.join(", ")})` : "";
305
+ }
306
+ /**
307
+ * Apply nullable / optional / nullish modifiers and an optional `.describe()` call
308
+ * to a schema value string using the chainable Zod v4 API.
309
+ */
310
+ function applyModifiers({ value, nullable, optional, nullish, defaultValue, description }) {
311
+ let result = value;
312
+ if (nullish || nullable && optional) result = `${result}.nullish()`;
313
+ else if (optional) result = `${result}.optional()`;
314
+ else if (nullable) result = `${result}.nullable()`;
315
+ if (defaultValue !== void 0) result = `${result}.default(${formatDefault(defaultValue)})`;
316
+ if (description) result = `${result}.describe(${stringify(description)})`;
317
+ return result;
318
+ }
319
+ /**
320
+ * Apply nullable / optional / nullish modifiers using the functional `zod/mini` API
321
+ * (`z.nullable()`, `z.optional()`, `z.nullish()`).
322
+ */
323
+ function applyMiniModifiers({ value, nullable, optional, nullish, defaultValue }) {
324
+ let result = value;
325
+ if (nullish) result = `z.nullish(${result})`;
326
+ else {
327
+ if (nullable) result = `z.nullable(${result})`;
328
+ if (optional) result = `z.optional(${result})`;
329
+ }
330
+ if (defaultValue !== void 0) result = `z._default(${result}, ${formatDefault(defaultValue)})`;
331
+ return result;
332
+ }
333
+ /**
334
+ * Returns true when the schema tree contains a self-referential `$ref`
335
+ * whose resolved name matches `schemaName`.
336
+ *
337
+ * A `visited` set prevents infinite recursion on circular schema graphs.
338
+ */
339
+ function containsSelfRef(node, { schemaName, resolver, visited = /* @__PURE__ */ new Set() }) {
340
+ if (visited.has(node)) return false;
341
+ visited.add(node);
342
+ if (node.type === "ref" && node.ref) {
343
+ const rawName = extractRefName(node.ref) ?? node.name;
344
+ return (rawName ? resolver?.default(rawName, "function") ?? rawName : node.name) === schemaName;
345
+ }
346
+ if (node.type === "object") {
347
+ if (node.properties?.some((p) => containsSelfRef(p.schema, {
348
+ schemaName,
349
+ resolver,
350
+ visited
351
+ }))) return true;
352
+ if (node.additionalProperties && node.additionalProperties !== true) return containsSelfRef(node.additionalProperties, {
353
+ schemaName,
354
+ resolver,
355
+ visited
356
+ });
357
+ return false;
358
+ }
359
+ if (node.type === "array" || node.type === "tuple") return node.items?.some((item) => containsSelfRef(item, {
360
+ schemaName,
361
+ resolver,
362
+ visited
363
+ })) ?? false;
364
+ if (node.type === "union" || node.type === "intersection") return node.members?.some((m) => containsSelfRef(m, {
365
+ schemaName,
366
+ resolver,
367
+ visited
368
+ })) ?? false;
369
+ return false;
370
+ }
371
+ //#endregion
372
+ //#region src/printers/printerZod.ts
373
+ /**
374
+ * Zod v4 printer built with `definePrinter`.
375
+ *
376
+ * Converts a `SchemaNode` AST into a **standard** Zod v4 code string
377
+ * using the chainable method API (`.optional()`, `.nullable()`, etc.).
378
+ *
379
+ * For the `zod/mini` functional API, see {@link printerZodMini}.
380
+ *
381
+ * @example
382
+ * ```ts
383
+ * const printer = printerZod({ coercion: false })
384
+ * const code = printer.print(stringSchemaNode) // "z.string()"
385
+ * ```
386
+ */
387
+ const printerZod = definePrinter((options) => {
388
+ return {
389
+ name: "zod",
390
+ options,
391
+ nodes: {
392
+ any: () => "z.any()",
393
+ unknown: () => "z.unknown()",
394
+ void: () => "z.void()",
395
+ never: () => "z.never()",
396
+ boolean: () => "z.boolean()",
397
+ null: () => "z.null()",
398
+ string(node) {
399
+ return `${shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()"}${lengthConstraints(node)}`;
400
+ },
401
+ number(node) {
402
+ return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number()" : "z.number()"}${numberConstraints(node)}`;
403
+ },
404
+ integer(node) {
405
+ return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number().int()" : "z.int()"}${numberConstraints(node)}`;
406
+ },
407
+ bigint() {
408
+ return shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.bigint()" : "z.bigint()";
409
+ },
410
+ date(node) {
411
+ if (node.representation === "string") return "z.iso.date()";
412
+ return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
413
+ },
414
+ datetime(node) {
415
+ if (node.offset) return "z.iso.datetime({ offset: true })";
416
+ if (node.local) return "z.iso.datetime({ local: true })";
417
+ return "z.iso.datetime()";
418
+ },
419
+ time(node) {
420
+ if (node.representation === "string") return "z.iso.time()";
421
+ return shouldCoerce(this.options.coercion, "dates") ? "z.coerce.date()" : "z.date()";
422
+ },
423
+ uuid(node) {
424
+ return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthConstraints(node)}`;
425
+ },
426
+ email(node) {
427
+ return `z.email()${lengthConstraints(node)}`;
428
+ },
429
+ url(node) {
430
+ return `z.url()${lengthConstraints(node)}`;
431
+ },
432
+ ipv4: () => "z.ipv4()",
433
+ ipv6: () => "z.ipv6()",
434
+ blob: () => "z.instanceof(File)",
435
+ enum(node) {
436
+ const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
437
+ if (node.namedEnumValues?.length) {
438
+ const literals = nonNullValues.map((v) => `z.literal(${formatLiteral(v)})`);
439
+ if (literals.length === 1) return literals[0];
440
+ return `z.union([${literals.join(", ")}])`;
441
+ }
442
+ return `z.enum([${nonNullValues.map(formatLiteral).join(", ")}])`;
443
+ },
444
+ ref(node) {
445
+ if (!node.name) return void 0;
446
+ const refName = node.ref ? extractRefName(node.ref) ?? node.name : node.name;
447
+ const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
448
+ if (node.ref && this.options.schemaName != null && resolvedName === this.options.schemaName) return `z.lazy(() => ${resolvedName})`;
449
+ return resolvedName;
450
+ },
451
+ object(node) {
452
+ let result = `z.object({\n ${node.properties.map((prop) => {
453
+ const { name: propName, schema } = prop;
454
+ const meta = syncSchemaRef(schema);
455
+ const isNullable = meta.nullable;
456
+ const isOptional = schema.optional;
457
+ const isNullish = schema.nullish;
458
+ const hasSelfRef = this.options.schemaName != null && containsSelfRef(schema, {
459
+ schemaName: this.options.schemaName,
460
+ resolver: this.options.resolver
461
+ });
462
+ const baseOutput = this.transform(schema) ?? this.transform(createSchema({ type: "unknown" }));
463
+ const resolvedOutput = hasSelfRef ? baseOutput.replaceAll(`z.lazy(() => ${this.options.schemaName})`, this.options.schemaName) : baseOutput;
464
+ const value = applyModifiers({
465
+ value: this.options.wrapOutput ? this.options.wrapOutput({
466
+ output: resolvedOutput,
467
+ schema
468
+ }) || resolvedOutput : resolvedOutput,
469
+ nullable: isNullable,
470
+ optional: isOptional,
471
+ nullish: isNullish,
472
+ defaultValue: meta.default,
473
+ description: meta.description
474
+ });
475
+ if (hasSelfRef) return `get "${propName}"() { return ${value} }`;
476
+ return `"${propName}": ${value}`;
477
+ }).join(",\n ")}\n })`;
478
+ if (node.additionalProperties && node.additionalProperties !== true) {
479
+ const catchallType = this.transform(node.additionalProperties);
480
+ if (catchallType) result += `.catchall(${catchallType})`;
481
+ } else if (node.additionalProperties === true) result += `.catchall(${this.transform(createSchema({ type: "unknown" }))})`;
482
+ else if (node.additionalProperties === false) result += ".strict()";
483
+ return result;
484
+ },
485
+ array(node) {
486
+ let result = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(createSchema({ type: "unknown" }))})${lengthConstraints(node)}`;
487
+ if (node.unique) result += `.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`;
488
+ return result;
489
+ },
490
+ tuple(node) {
491
+ return `z.tuple([${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ")}])`;
492
+ },
493
+ union(node) {
494
+ const nodeMembers = node.members ?? [];
495
+ const members = nodeMembers.map((m) => this.transform(m)).filter(Boolean);
496
+ if (members.length === 0) return "";
497
+ if (members.length === 1) return members[0];
498
+ if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, [${members.join(", ")}])`;
499
+ return `z.union([${members.join(", ")}])`;
500
+ },
501
+ intersection(node) {
502
+ const members = node.members ?? [];
503
+ if (members.length === 0) return "";
504
+ const [first, ...rest] = members;
505
+ if (!first) return "";
506
+ let base = this.transform(first);
507
+ if (!base) return "";
508
+ for (const member of rest) {
509
+ if (member.primitive === "string") {
510
+ const c = lengthConstraints(narrowSchema(member, "string") ?? {});
511
+ if (c) {
512
+ base += c;
513
+ continue;
514
+ }
515
+ } else if (member.primitive === "number" || member.primitive === "integer") {
516
+ const c = numberConstraints(narrowSchema(member, "number") ?? narrowSchema(member, "integer") ?? {});
517
+ if (c) {
518
+ base += c;
519
+ continue;
520
+ }
521
+ } else if (member.primitive === "array") {
522
+ const c = lengthConstraints(narrowSchema(member, "array") ?? {});
523
+ if (c) {
524
+ base += c;
525
+ continue;
526
+ }
527
+ }
528
+ const transformed = this.transform(member);
529
+ if (transformed) base = `${base}.and(${transformed})`;
530
+ }
531
+ return base;
532
+ }
533
+ },
534
+ print(node) {
535
+ const { keysToOmit } = this.options;
536
+ let base = this.transform(node);
537
+ if (!base) return null;
538
+ const meta = syncSchemaRef(node);
539
+ if (keysToOmit?.length && meta.primitive === "object" && !(meta.type === "union" && meta.discriminatorPropertyName)) base = `${base}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
540
+ return applyModifiers({
541
+ value: base,
542
+ nullable: meta.nullable,
543
+ optional: meta.optional,
544
+ nullish: meta.nullish,
545
+ defaultValue: meta.default,
546
+ description: meta.description
547
+ });
548
+ }
549
+ };
550
+ });
551
+ //#endregion
552
+ //#region src/components/Zod.tsx
553
+ function Zod({ name, node, coercion, guidType, wrapOutput, inferTypeName, resolver, keysToOmit }) {
554
+ const output = printerZod({
555
+ coercion,
556
+ guidType,
557
+ wrapOutput,
558
+ resolver,
559
+ schemaName: name,
560
+ keysToOmit
561
+ }).print(node);
562
+ if (!output) return;
563
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Source, {
564
+ name,
565
+ isExportable: true,
566
+ isIndexable: true,
567
+ children: /* @__PURE__ */ jsx(Const, {
568
+ export: true,
569
+ name,
570
+ children: output
571
+ })
572
+ }), inferTypeName && /* @__PURE__ */ jsx(File.Source, {
573
+ name: inferTypeName,
574
+ isExportable: true,
575
+ isIndexable: true,
576
+ isTypeOnly: true,
577
+ children: /* @__PURE__ */ jsx(Type, {
578
+ export: true,
579
+ name: inferTypeName,
580
+ children: `z.infer<typeof ${name}>`
581
+ })
582
+ })] });
583
+ }
584
+ //#endregion
585
+ //#region src/printers/printerZodMini.ts
586
+ /**
587
+ * Zod v4 **Mini** printer built with `definePrinter`.
588
+ *
589
+ * Converts a `SchemaNode` AST into a Zod v4 Mini code string using the
590
+ * functional API (`z.optional(z.string())`) for better tree-shaking.
591
+ *
592
+ * For the standard chainable API, see {@link printerZod}.
593
+ *
594
+ * @example
595
+ * ```ts
596
+ * const printer = printerZodMini({})
597
+ * const code = printer.print(optionalStringNode) // "z.optional(z.string())"
598
+ * ```
599
+ */
600
+ const printerZodMini = definePrinter((options) => {
601
+ return {
602
+ name: "zod-mini",
603
+ options,
604
+ nodes: {
605
+ any: () => "z.any()",
606
+ unknown: () => "z.unknown()",
607
+ void: () => "z.void()",
608
+ never: () => "z.never()",
609
+ boolean: () => "z.boolean()",
610
+ null: () => "z.null()",
611
+ string(node) {
612
+ return `z.string()${lengthChecksMini(node)}`;
613
+ },
614
+ number(node) {
615
+ return `z.number()${numberChecksMini(node)}`;
616
+ },
617
+ integer(node) {
618
+ return `z.int()${numberChecksMini(node)}`;
619
+ },
620
+ bigint(node) {
621
+ return `z.bigint()${numberChecksMini(node)}`;
622
+ },
623
+ date(node) {
624
+ if (node.representation === "string") return "z.iso.date()";
625
+ return "z.date()";
626
+ },
627
+ datetime() {
628
+ return "z.string()";
629
+ },
630
+ time(node) {
631
+ if (node.representation === "string") return "z.iso.time()";
632
+ return "z.date()";
633
+ },
634
+ uuid(node) {
635
+ return `${this.options.guidType === "guid" ? "z.guid()" : "z.uuid()"}${lengthChecksMini(node)}`;
636
+ },
637
+ email(node) {
638
+ return `z.email()${lengthChecksMini(node)}`;
639
+ },
640
+ url(node) {
641
+ return `z.url()${lengthChecksMini(node)}`;
642
+ },
643
+ ipv4: () => "z.ipv4()",
644
+ ipv6: () => "z.ipv6()",
645
+ blob: () => "z.instanceof(File)",
646
+ enum(node) {
647
+ const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
648
+ if (node.namedEnumValues?.length) {
649
+ const literals = nonNullValues.map((v) => `z.literal(${formatLiteral(v)})`);
650
+ if (literals.length === 1) return literals[0];
651
+ return `z.union([${literals.join(", ")}])`;
652
+ }
653
+ return `z.enum([${nonNullValues.map(formatLiteral).join(", ")}])`;
654
+ },
655
+ ref(node) {
656
+ if (!node.name) return void 0;
657
+ const refName = node.ref ? extractRefName(node.ref) ?? node.name : node.name;
658
+ const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
659
+ if (node.ref && this.options.schemaName != null && resolvedName === this.options.schemaName) return `z.lazy(() => ${resolvedName})`;
660
+ return resolvedName;
661
+ },
662
+ object(node) {
663
+ return `z.object({\n ${node.properties.map((prop) => {
664
+ const { name: propName, schema } = prop;
665
+ const meta = syncSchemaRef(schema);
666
+ const isNullable = meta.nullable;
667
+ const isOptional = schema.optional;
668
+ const isNullish = schema.nullish;
669
+ const hasSelfRef = this.options.schemaName != null && containsSelfRef(schema, {
670
+ schemaName: this.options.schemaName,
671
+ resolver: this.options.resolver
672
+ });
673
+ const baseOutput = this.transform(schema) ?? this.transform(createSchema({ type: "unknown" }));
674
+ const resolvedOutput = hasSelfRef ? baseOutput.replaceAll(`z.lazy(() => ${this.options.schemaName})`, this.options.schemaName) : baseOutput;
675
+ const value = applyMiniModifiers({
676
+ value: this.options.wrapOutput ? this.options.wrapOutput({
677
+ output: resolvedOutput,
678
+ schema
679
+ }) || resolvedOutput : resolvedOutput,
680
+ nullable: isNullable,
681
+ optional: isOptional,
682
+ nullish: isNullish,
683
+ defaultValue: meta.default
684
+ });
685
+ if (hasSelfRef) return `get "${propName}"() { return ${value} }`;
686
+ return `"${propName}": ${value}`;
687
+ }).join(",\n ")}\n })`;
688
+ },
689
+ array(node) {
690
+ let result = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(createSchema({ type: "unknown" }))})${lengthChecksMini(node)}`;
691
+ if (node.unique) result += `.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`;
692
+ return result;
693
+ },
694
+ tuple(node) {
695
+ return `z.tuple([${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ")}])`;
696
+ },
697
+ union(node) {
698
+ const nodeMembers = node.members ?? [];
699
+ const members = nodeMembers.map((m) => this.transform(m)).filter(Boolean);
700
+ if (members.length === 0) return "";
701
+ if (members.length === 1) return members[0];
702
+ if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, [${members.join(", ")}])`;
703
+ return `z.union([${members.join(", ")}])`;
704
+ },
705
+ intersection(node) {
706
+ const members = node.members ?? [];
707
+ if (members.length === 0) return "";
708
+ const [first, ...rest] = members;
709
+ if (!first) return "";
710
+ let base = this.transform(first);
711
+ if (!base) return "";
712
+ for (const member of rest) {
713
+ if (member.primitive === "string") {
714
+ const c = lengthChecksMini(narrowSchema(member, "string") ?? {});
715
+ if (c) {
716
+ base += c;
717
+ continue;
718
+ }
719
+ } else if (member.primitive === "number" || member.primitive === "integer") {
720
+ const c = numberChecksMini(narrowSchema(member, "number") ?? narrowSchema(member, "integer") ?? {});
721
+ if (c) {
722
+ base += c;
723
+ continue;
724
+ }
725
+ } else if (member.primitive === "array") {
726
+ const c = lengthChecksMini(narrowSchema(member, "array") ?? {});
727
+ if (c) {
728
+ base += c;
729
+ continue;
730
+ }
731
+ }
732
+ const transformed = this.transform(member);
733
+ if (transformed) base = `z.intersection(${base}, ${transformed})`;
734
+ }
735
+ return base;
736
+ }
737
+ },
738
+ print(node) {
739
+ const { keysToOmit } = this.options;
740
+ let base = this.transform(node);
741
+ if (!base) return null;
742
+ const meta = syncSchemaRef(node);
743
+ if (keysToOmit?.length && meta.primitive === "object" && !(meta.type === "union" && meta.discriminatorPropertyName)) base = `${base}.omit({ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} })`;
744
+ return applyMiniModifiers({
745
+ value: base,
746
+ nullable: meta.nullable,
747
+ optional: meta.optional,
748
+ nullish: meta.nullish,
749
+ defaultValue: meta.default
750
+ });
751
+ }
752
+ };
753
+ });
754
+ //#endregion
755
+ //#region src/components/ZodMini.tsx
756
+ function ZodMini({ name, node, guidType, wrapOutput, inferTypeName, resolver, keysToOmit }) {
757
+ const output = printerZodMini({
758
+ guidType,
759
+ wrapOutput,
760
+ resolver,
761
+ schemaName: name,
762
+ keysToOmit
763
+ }).print(node);
764
+ if (!output) return;
765
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(File.Source, {
766
+ name,
767
+ isExportable: true,
768
+ isIndexable: true,
769
+ children: /* @__PURE__ */ jsx(Const, {
770
+ export: true,
771
+ name,
772
+ children: output
773
+ })
774
+ }), inferTypeName && /* @__PURE__ */ jsx(File.Source, {
775
+ name: inferTypeName,
776
+ isExportable: true,
777
+ isIndexable: true,
778
+ isTypeOnly: true,
779
+ children: /* @__PURE__ */ jsx(Type, {
780
+ export: true,
781
+ name: inferTypeName,
782
+ children: `z.infer<typeof ${name}>`
783
+ })
784
+ })] });
785
+ }
786
+ //#endregion
787
+ //#region src/constants.ts
788
+ /**
789
+ * Import paths that use a namespace import (`import * as z from '...'`).
790
+ * All other import paths use a named import (`import { z } from '...'`).
791
+ */
792
+ const ZOD_NAMESPACE_IMPORTS = new Set(["zod", "zod/mini"]);
793
+ //#endregion
794
+ //#region src/generators/zodGenerator.tsx
795
+ const zodGenerator = defineGenerator({
796
+ name: "zod",
797
+ type: "react",
798
+ Schema({ node, adapter, options, config, resolver }) {
799
+ const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, transformers = [] } = options;
800
+ const transformedNode = transform(node, composeTransformers(...transformers));
801
+ if (!transformedNode.name) return;
802
+ const root = path.resolve(config.root, config.output.path);
803
+ const mode = getMode(path.resolve(root, output.path));
804
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
805
+ const imports = adapter.getImports(transformedNode, (schemaName) => ({
806
+ name: resolver.default(schemaName, "function"),
807
+ path: resolver.resolveFile({
808
+ name: schemaName,
809
+ extname: ".ts"
810
+ }, {
811
+ root,
812
+ output,
813
+ group
814
+ }).path
815
+ }));
816
+ const inferTypeName = inferred ? resolver.resolveInferName(resolver.resolveName(transformedNode.name)) : void 0;
817
+ const meta = {
818
+ name: resolver.default(transformedNode.name, "function"),
819
+ file: resolver.resolveFile({
820
+ name: transformedNode.name,
821
+ extname: ".ts"
822
+ }, {
823
+ root,
824
+ output,
825
+ group
826
+ })
827
+ };
828
+ return /* @__PURE__ */ jsxs(File, {
829
+ baseName: meta.file.baseName,
830
+ path: meta.file.path,
831
+ meta: meta.file.meta,
832
+ banner: resolver.resolveBanner(adapter.rootNode, {
833
+ output,
834
+ config
835
+ }),
836
+ footer: resolver.resolveFooter(adapter.rootNode, {
837
+ output,
838
+ config
839
+ }),
840
+ children: [
841
+ /* @__PURE__ */ jsx(File.Import, {
842
+ name: isZodImport ? "z" : ["z"],
843
+ path: importPath,
844
+ isNameSpace: isZodImport
845
+ }),
846
+ mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
847
+ root: meta.file.path,
848
+ path: imp.path,
849
+ name: imp.name
850
+ }, [transformedNode.name, imp.path].join("-"))),
851
+ mini ? /* @__PURE__ */ jsx(ZodMini, {
852
+ name: meta.name,
853
+ node: transformedNode,
854
+ guidType,
855
+ wrapOutput,
856
+ inferTypeName,
857
+ resolver
858
+ }) : /* @__PURE__ */ jsx(Zod, {
859
+ name: meta.name,
860
+ node: transformedNode,
861
+ coercion,
862
+ guidType,
863
+ wrapOutput,
864
+ inferTypeName,
865
+ resolver
866
+ })
867
+ ]
868
+ });
869
+ },
870
+ Operation({ node, adapter, options, config, resolver }) {
871
+ const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, transformers } = options;
872
+ const transformedNode = transform(node, composeTransformers(...transformers));
873
+ const root = path.resolve(config.root, config.output.path);
874
+ const mode = getMode(path.resolve(root, output.path));
875
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
876
+ const params = caseParams(transformedNode.parameters, paramsCasing);
877
+ const meta = { file: resolver.resolveFile({
878
+ name: transformedNode.operationId,
879
+ extname: ".ts",
880
+ tag: transformedNode.tags[0] ?? "default",
881
+ path: transformedNode.path
882
+ }, {
883
+ root,
884
+ output,
885
+ group
886
+ }) };
887
+ function renderSchemaEntry({ schema, name, keysToOmit }) {
888
+ if (!schema) return null;
889
+ const inferTypeName = inferred ? resolver.resolveInferName(name) : void 0;
890
+ const imports = adapter.getImports(schema, (schemaName) => ({
891
+ name: resolver.default(schemaName, "function"),
892
+ path: resolver.resolveFile({
893
+ name: schemaName,
894
+ extname: ".ts"
895
+ }, {
896
+ root,
897
+ output,
898
+ group
899
+ }).path
900
+ }));
901
+ return /* @__PURE__ */ jsxs(Fragment, { children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
902
+ root: meta.file.path,
903
+ path: imp.path,
904
+ name: imp.name
905
+ }, [
906
+ name,
907
+ imp.path,
908
+ imp.name
909
+ ].join("-"))), mini ? /* @__PURE__ */ jsx(ZodMini, {
910
+ name,
911
+ node: schema,
912
+ guidType,
913
+ wrapOutput,
914
+ inferTypeName,
915
+ resolver,
916
+ keysToOmit
917
+ }) : /* @__PURE__ */ jsx(Zod, {
918
+ name,
919
+ node: schema,
920
+ coercion,
921
+ guidType,
922
+ wrapOutput,
923
+ inferTypeName,
924
+ resolver,
925
+ keysToOmit
926
+ })] });
927
+ }
928
+ const paramSchemas = params.map((param) => renderSchemaEntry({
929
+ schema: param.schema,
930
+ name: resolver.resolveParamName(node, param)
931
+ }));
932
+ const responseSchemas = transformedNode.responses.map((res) => renderSchemaEntry({
933
+ schema: res.schema,
934
+ name: resolver.resolveResponseStatusName(transformedNode, res.statusCode),
935
+ keysToOmit: res.keysToOmit
936
+ }));
937
+ const requestSchema = transformedNode.requestBody?.schema ? renderSchemaEntry({
938
+ schema: {
939
+ ...transformedNode.requestBody.schema,
940
+ description: transformedNode.requestBody.description ?? transformedNode.requestBody.schema.description
941
+ },
942
+ name: resolver.resolveDataName(transformedNode),
943
+ keysToOmit: transformedNode.requestBody.keysToOmit
944
+ }) : null;
945
+ return /* @__PURE__ */ jsxs(File, {
946
+ baseName: meta.file.baseName,
947
+ path: meta.file.path,
948
+ meta: meta.file.meta,
949
+ banner: resolver.resolveBanner(adapter.rootNode, {
950
+ output,
951
+ config
952
+ }),
953
+ footer: resolver.resolveFooter(adapter.rootNode, {
954
+ output,
955
+ config
956
+ }),
957
+ children: [
958
+ /* @__PURE__ */ jsx(File.Import, {
959
+ name: isZodImport ? "z" : ["z"],
960
+ path: importPath,
961
+ isNameSpace: isZodImport
962
+ }),
963
+ paramSchemas,
964
+ responseSchemas,
965
+ requestSchema
966
+ ]
967
+ });
968
+ },
969
+ Operations({ nodes, adapter, options, config, resolver }) {
970
+ const { output, importPath, group, operations, paramsCasing, transformers } = options;
971
+ if (!operations) return;
972
+ const root = path.resolve(config.root, config.output.path);
973
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
974
+ const meta = { file: resolver.resolveFile({
975
+ name: "operations",
976
+ extname: ".ts"
977
+ }, {
978
+ root,
979
+ output,
980
+ group
981
+ }) };
982
+ const transformedOperations = nodes.map((node) => {
983
+ const transformedNode = transform(node, composeTransformers(...transformers));
984
+ return {
985
+ node: transformedNode,
986
+ data: buildSchemaNames(transformedNode, {
987
+ params: caseParams(transformedNode.parameters, paramsCasing),
988
+ resolver
989
+ })
990
+ };
991
+ });
992
+ const imports = transformedOperations.flatMap(({ node, data }) => {
993
+ const names = [
994
+ data.request,
995
+ ...Object.values(data.responses),
996
+ ...Object.values(data.parameters)
997
+ ].filter(Boolean);
998
+ const opFile = resolver.resolveFile({
999
+ name: node.operationId,
1000
+ extname: ".ts",
1001
+ tag: node.tags[0] ?? "default",
1002
+ path: node.path
1003
+ }, {
1004
+ root,
1005
+ output,
1006
+ group
1007
+ });
1008
+ return names.map((name) => /* @__PURE__ */ jsx(File.Import, {
1009
+ name: [name],
1010
+ root: meta.file.path,
1011
+ path: opFile.path
1012
+ }, [name, opFile.path].join("-")));
1013
+ });
1014
+ return /* @__PURE__ */ jsxs(File, {
1015
+ baseName: meta.file.baseName,
1016
+ path: meta.file.path,
1017
+ meta: meta.file.meta,
1018
+ banner: resolver.resolveBanner(adapter.rootNode, {
1019
+ output,
1020
+ config
1021
+ }),
1022
+ footer: resolver.resolveFooter(adapter.rootNode, {
1023
+ output,
1024
+ config
1025
+ }),
1026
+ children: [
1027
+ /* @__PURE__ */ jsx(File.Import, {
1028
+ isTypeOnly: true,
1029
+ name: isZodImport ? "z" : ["z"],
1030
+ path: importPath,
1031
+ isNameSpace: isZodImport
1032
+ }),
1033
+ imports,
1034
+ /* @__PURE__ */ jsx(Operations, {
1035
+ name: "operations",
1036
+ operations: transformedOperations
1037
+ })
1038
+ ]
1039
+ });
1040
+ }
1041
+ });
1042
+ //#endregion
1043
+ //#region src/generators/zodGeneratorLegacy.tsx
1044
+ function buildGroupedParamsSchema({ params, optional }) {
1045
+ return createSchema({
1046
+ type: "object",
1047
+ optional,
1048
+ primitive: "object",
1049
+ properties: params.map((param) => {
1050
+ return createProperty({
1051
+ name: param.name,
1052
+ required: param.required,
1053
+ schema: param.schema
1054
+ });
1055
+ })
1056
+ });
1057
+ }
1058
+ function buildLegacyResponsesSchemaNode(node, { resolver }) {
1059
+ const isGet = node.method.toLowerCase() === "get";
1060
+ const successResponses = node.responses.filter((res) => {
1061
+ const code = Number(res.statusCode);
1062
+ return !Number.isNaN(code) && code >= 200 && code < 300;
1063
+ });
1064
+ const errorResponses = node.responses.filter((res) => res.statusCode === "default" || Number(res.statusCode) >= 400);
1065
+ const responseSchema = successResponses.length > 0 ? successResponses.length === 1 ? createSchema({
1066
+ type: "ref",
1067
+ name: resolver.resolveResponseStatusName(node, successResponses[0].statusCode)
1068
+ }) : createSchema({
1069
+ type: "union",
1070
+ members: successResponses.map((res) => createSchema({
1071
+ type: "ref",
1072
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
1073
+ }))
1074
+ }) : createSchema({ type: "any" });
1075
+ const errorsSchema = errorResponses.length > 0 ? errorResponses.length === 1 ? createSchema({
1076
+ type: "ref",
1077
+ name: resolver.resolveResponseStatusName(node, errorResponses[0].statusCode)
1078
+ }) : createSchema({
1079
+ type: "union",
1080
+ members: errorResponses.map((res) => createSchema({
1081
+ type: "ref",
1082
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
1083
+ }))
1084
+ }) : createSchema({ type: "any" });
1085
+ const properties = [createProperty({
1086
+ name: "Response",
1087
+ required: true,
1088
+ schema: responseSchema
1089
+ })];
1090
+ if (!isGet && node.requestBody?.schema) properties.push(createProperty({
1091
+ name: "Request",
1092
+ required: true,
1093
+ schema: createSchema({
1094
+ type: "ref",
1095
+ name: resolver.resolveDataName(node)
1096
+ })
1097
+ }));
1098
+ const queryParam = node.parameters.find((p) => p.in === "query");
1099
+ if (queryParam) properties.push(createProperty({
1100
+ name: "QueryParams",
1101
+ required: true,
1102
+ schema: createSchema({
1103
+ type: "ref",
1104
+ name: resolver.resolveQueryParamsName(node, queryParam)
1105
+ })
1106
+ }));
1107
+ const pathParam = node.parameters.find((p) => p.in === "path");
1108
+ if (pathParam) properties.push(createProperty({
1109
+ name: "PathParams",
1110
+ required: true,
1111
+ schema: createSchema({
1112
+ type: "ref",
1113
+ name: resolver.resolvePathParamsName(node, pathParam)
1114
+ })
1115
+ }));
1116
+ const headerParam = node.parameters.find((p) => p.in === "header");
1117
+ if (headerParam) properties.push(createProperty({
1118
+ name: "HeaderParams",
1119
+ required: true,
1120
+ schema: createSchema({
1121
+ type: "ref",
1122
+ name: resolver.resolveHeaderParamsName(node, headerParam)
1123
+ })
1124
+ }));
1125
+ properties.push(createProperty({
1126
+ name: "Errors",
1127
+ required: true,
1128
+ schema: errorsSchema
1129
+ }));
1130
+ return createSchema({
1131
+ type: "object",
1132
+ primitive: "object",
1133
+ properties
1134
+ });
1135
+ }
1136
+ function buildLegacyResponseUnionSchemaNode(node, { resolver }) {
1137
+ const successResponses = node.responses.filter((res) => {
1138
+ const code = Number(res.statusCode);
1139
+ return !Number.isNaN(code) && code >= 200 && code < 300;
1140
+ });
1141
+ if (successResponses.length === 0) return createSchema({ type: "any" });
1142
+ if (successResponses.length === 1) return createSchema({
1143
+ type: "ref",
1144
+ name: resolver.resolveResponseStatusName(node, successResponses[0].statusCode)
1145
+ });
1146
+ return createSchema({
1147
+ type: "union",
1148
+ members: successResponses.map((res) => createSchema({
1149
+ type: "ref",
1150
+ name: resolver.resolveResponseStatusName(node, res.statusCode)
1151
+ }))
1152
+ });
1153
+ }
1154
+ function buildLegacySchemaNames(node, params, resolver) {
1155
+ const pathParam = params.find((p) => p.in === "path");
1156
+ const queryParam = params.find((p) => p.in === "query");
1157
+ const headerParam = params.find((p) => p.in === "header");
1158
+ const responses = {};
1159
+ const errors = {};
1160
+ for (const res of node.responses) {
1161
+ const name = resolver.resolveResponseStatusName(node, res.statusCode);
1162
+ const statusNum = Number(res.statusCode);
1163
+ if (!Number.isNaN(statusNum)) {
1164
+ responses[statusNum] = name;
1165
+ if (statusNum >= 400) errors[statusNum] = name;
1166
+ }
1167
+ }
1168
+ responses["default"] = resolver.resolveResponseName(node);
1169
+ return {
1170
+ request: node.requestBody?.schema ? resolver.resolveDataName(node) : void 0,
1171
+ parameters: {
1172
+ path: pathParam ? resolver.resolvePathParamsName(node, pathParam) : void 0,
1173
+ query: queryParam ? resolver.resolveQueryParamsName(node, queryParam) : void 0,
1174
+ header: headerParam ? resolver.resolveHeaderParamsName(node, headerParam) : void 0
1175
+ },
1176
+ responses,
1177
+ errors
1178
+ };
1179
+ }
1180
+ const zodGeneratorLegacy = defineGenerator({
1181
+ name: "zod-legacy",
1182
+ type: "react",
1183
+ Schema({ node, adapter, options, config, resolver }) {
1184
+ const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, transformers = [] } = options;
1185
+ const transformedNode = transform(node, composeTransformers(...transformers));
1186
+ if (!transformedNode.name) return;
1187
+ const root = path.resolve(config.root, config.output.path);
1188
+ const mode = getMode(path.resolve(root, output.path));
1189
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1190
+ const imports = adapter.getImports(transformedNode, (schemaName) => ({
1191
+ name: resolver.default(schemaName, "function"),
1192
+ path: resolver.resolveFile({
1193
+ name: schemaName,
1194
+ extname: ".ts"
1195
+ }, {
1196
+ root,
1197
+ output,
1198
+ group
1199
+ }).path
1200
+ }));
1201
+ const inferTypeName = inferred ? resolver.resolveInferName(resolver.resolveName(transformedNode.name)) : void 0;
1202
+ const meta = {
1203
+ name: resolver.default(transformedNode.name, "function"),
1204
+ file: resolver.resolveFile({
1205
+ name: transformedNode.name,
1206
+ extname: ".ts"
1207
+ }, {
1208
+ root,
1209
+ output,
1210
+ group
1211
+ })
1212
+ };
1213
+ return /* @__PURE__ */ jsxs(File, {
1214
+ baseName: meta.file.baseName,
1215
+ path: meta.file.path,
1216
+ meta: meta.file.meta,
1217
+ banner: resolver.resolveBanner(adapter.rootNode, {
1218
+ output,
1219
+ config
1220
+ }),
1221
+ footer: resolver.resolveFooter(adapter.rootNode, {
1222
+ output,
1223
+ config
1224
+ }),
1225
+ children: [
1226
+ /* @__PURE__ */ jsx(File.Import, {
1227
+ name: isZodImport ? "z" : ["z"],
1228
+ path: importPath,
1229
+ isNameSpace: isZodImport
1230
+ }),
1231
+ mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1232
+ root: meta.file.path,
1233
+ path: imp.path,
1234
+ name: imp.name
1235
+ }, [transformedNode.name, imp.path].join("-"))),
1236
+ mini ? /* @__PURE__ */ jsx(ZodMini, {
1237
+ name: meta.name,
1238
+ node: transformedNode,
1239
+ guidType,
1240
+ wrapOutput,
1241
+ inferTypeName,
1242
+ resolver
1243
+ }) : /* @__PURE__ */ jsx(Zod, {
1244
+ name: meta.name,
1245
+ node: transformedNode,
1246
+ coercion,
1247
+ guidType,
1248
+ wrapOutput,
1249
+ inferTypeName,
1250
+ resolver
1251
+ })
1252
+ ]
1253
+ });
1254
+ },
1255
+ Operation({ node, adapter, options, config, resolver }) {
1256
+ const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, transformers } = options;
1257
+ const transformedNode = transform(node, composeTransformers(...transformers));
1258
+ const root = path.resolve(config.root, config.output.path);
1259
+ const mode = getMode(path.resolve(root, output.path));
1260
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1261
+ const params = caseParams(transformedNode.parameters, paramsCasing);
1262
+ const meta = { file: resolver.resolveFile({
1263
+ name: transformedNode.operationId,
1264
+ extname: ".ts",
1265
+ tag: transformedNode.tags[0] ?? "default",
1266
+ path: transformedNode.path
1267
+ }, {
1268
+ root,
1269
+ output,
1270
+ group
1271
+ }) };
1272
+ function renderSchemaEntry({ schema, name, keysToOmit }) {
1273
+ if (!schema) return null;
1274
+ const inferTypeName = inferred ? resolver.resolveInferName(name) : void 0;
1275
+ const imports = adapter.getImports(schema, (schemaName) => ({
1276
+ name: resolver.default(schemaName, "function"),
1277
+ path: resolver.resolveFile({
1278
+ name: schemaName,
1279
+ extname: ".ts"
1280
+ }, {
1281
+ root,
1282
+ output,
1283
+ group
1284
+ }).path
1285
+ }));
1286
+ return /* @__PURE__ */ jsxs(Fragment, { children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1287
+ root: meta.file.path,
1288
+ path: imp.path,
1289
+ name: imp.name
1290
+ }, [
1291
+ name,
1292
+ imp.path,
1293
+ imp.name
1294
+ ].join("-"))), mini ? /* @__PURE__ */ jsx(ZodMini, {
1295
+ name,
1296
+ node: schema,
1297
+ guidType,
1298
+ wrapOutput,
1299
+ inferTypeName,
1300
+ resolver,
1301
+ keysToOmit
1302
+ }) : /* @__PURE__ */ jsx(Zod, {
1303
+ name,
1304
+ node: schema,
1305
+ coercion,
1306
+ guidType,
1307
+ wrapOutput,
1308
+ inferTypeName,
1309
+ resolver,
1310
+ keysToOmit
1311
+ })] });
1312
+ }
1313
+ const pathParams = params.filter((p) => p.in === "path");
1314
+ const queryParams = params.filter((p) => p.in === "query");
1315
+ const headerParams = params.filter((p) => p.in === "header");
1316
+ const responseSchemas = transformedNode.responses.map((res) => {
1317
+ const responseName = resolver.resolveResponseStatusName(transformedNode, res.statusCode);
1318
+ return renderSchemaEntry({
1319
+ schema: {
1320
+ ...res.schema,
1321
+ description: res.description ?? res.schema.description
1322
+ },
1323
+ name: responseName,
1324
+ keysToOmit: res.keysToOmit
1325
+ });
1326
+ });
1327
+ const requestSchema = transformedNode.requestBody?.schema ? renderSchemaEntry({
1328
+ schema: {
1329
+ ...transformedNode.requestBody.schema,
1330
+ description: transformedNode.requestBody.description ?? transformedNode.requestBody.schema.description
1331
+ },
1332
+ name: resolver.resolveDataName(transformedNode),
1333
+ keysToOmit: transformedNode.requestBody.keysToOmit
1334
+ }) : null;
1335
+ const legacyParamTypes = [
1336
+ pathParams.length > 0 ? renderSchemaEntry({
1337
+ schema: buildGroupedParamsSchema({
1338
+ params: pathParams,
1339
+ optional: pathParams.every((p) => !p.required)
1340
+ }),
1341
+ name: resolver.resolvePathParamsName(transformedNode, pathParams[0])
1342
+ }) : null,
1343
+ queryParams.length > 0 ? renderSchemaEntry({
1344
+ schema: buildGroupedParamsSchema({
1345
+ params: queryParams,
1346
+ optional: queryParams.every((p) => !p.required)
1347
+ }),
1348
+ name: resolver.resolveQueryParamsName(transformedNode, queryParams[0])
1349
+ }) : null,
1350
+ headerParams.length > 0 ? renderSchemaEntry({
1351
+ schema: buildGroupedParamsSchema({
1352
+ params: headerParams,
1353
+ optional: headerParams.every((p) => !p.required)
1354
+ }),
1355
+ name: resolver.resolveHeaderParamsName(transformedNode, headerParams[0])
1356
+ }) : null
1357
+ ];
1358
+ const legacyResponsesSchema = renderSchemaEntry({
1359
+ schema: buildLegacyResponsesSchemaNode(transformedNode, { resolver }),
1360
+ name: resolver.resolveResponsesName(transformedNode)
1361
+ });
1362
+ const legacyResponseSchema = renderSchemaEntry({
1363
+ schema: buildLegacyResponseUnionSchemaNode(transformedNode, { resolver }),
1364
+ name: resolver.resolveResponseName(transformedNode)
1365
+ });
1366
+ return /* @__PURE__ */ jsxs(File, {
1367
+ baseName: meta.file.baseName,
1368
+ path: meta.file.path,
1369
+ meta: meta.file.meta,
1370
+ banner: resolver.resolveBanner(adapter.rootNode, {
1371
+ output,
1372
+ config
1373
+ }),
1374
+ footer: resolver.resolveFooter(adapter.rootNode, {
1375
+ output,
1376
+ config
1377
+ }),
1378
+ children: [
1379
+ /* @__PURE__ */ jsx(File.Import, {
1380
+ name: isZodImport ? "z" : ["z"],
1381
+ path: importPath,
1382
+ isNameSpace: isZodImport
1383
+ }),
1384
+ legacyParamTypes,
1385
+ responseSchemas,
1386
+ requestSchema,
1387
+ legacyResponseSchema,
1388
+ legacyResponsesSchema
1389
+ ]
1390
+ });
1391
+ },
1392
+ Operations({ nodes, adapter, options, config, resolver }) {
1393
+ const { output, importPath, group, operations, paramsCasing, transformers } = options;
1394
+ if (!operations) return;
1395
+ const root = path.resolve(config.root, config.output.path);
1396
+ const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1397
+ const meta = { file: resolver.resolveFile({
1398
+ name: "operations",
1399
+ extname: ".ts"
1400
+ }, {
1401
+ root,
1402
+ output,
1403
+ group
1404
+ }) };
1405
+ const transformedOperations = nodes.map((node) => {
1406
+ const transformedNode = transform(node, composeTransformers(...transformers));
1407
+ return {
1408
+ node: transformedNode,
1409
+ data: buildLegacySchemaNames(transformedNode, caseParams(transformedNode.parameters, paramsCasing), resolver)
1410
+ };
1411
+ });
1412
+ const imports = transformedOperations.flatMap(({ node, data }) => {
1413
+ const names = [
1414
+ data.request,
1415
+ ...Object.values(data.responses),
1416
+ ...Object.values(data.parameters)
1417
+ ].filter(Boolean);
1418
+ const opFile = resolver.resolveFile({
1419
+ name: node.operationId,
1420
+ extname: ".ts",
1421
+ tag: node.tags[0] ?? "default",
1422
+ path: node.path
1423
+ }, {
1424
+ root,
1425
+ output,
1426
+ group
1427
+ });
1428
+ return names.map((name) => /* @__PURE__ */ jsx(File.Import, {
1429
+ name: [name],
1430
+ root: meta.file.path,
1431
+ path: opFile.path
1432
+ }, [name, opFile.path].join("-")));
1433
+ });
1434
+ return /* @__PURE__ */ jsxs(File, {
1435
+ baseName: meta.file.baseName,
1436
+ path: meta.file.path,
1437
+ meta: meta.file.meta,
1438
+ banner: resolver.resolveBanner(adapter.rootNode, {
1439
+ output,
1440
+ config
1441
+ }),
1442
+ footer: resolver.resolveFooter(adapter.rootNode, {
1443
+ output,
1444
+ config
1445
+ }),
1446
+ children: [
1447
+ /* @__PURE__ */ jsx(File.Import, {
1448
+ isTypeOnly: true,
1449
+ name: isZodImport ? "z" : ["z"],
1450
+ path: importPath,
1451
+ isNameSpace: isZodImport
1452
+ }),
1453
+ imports,
1454
+ /* @__PURE__ */ jsx(Operations, {
1455
+ name: "operations",
1456
+ operations: transformedOperations
1457
+ })
1458
+ ]
1459
+ });
1460
+ }
1461
+ });
1462
+ //#endregion
1463
+ //#region src/resolvers/resolverZod.ts
1464
+ function toSchemaName(name, type) {
1465
+ const resolved = camelCase(name, {
1466
+ suffix: type ? "schema" : void 0,
1467
+ isFile: type === "file"
1468
+ });
1469
+ if (type === "type") return pascalCase(resolved);
1470
+ return resolved;
1471
+ }
1472
+ /**
1473
+ * Default resolver for `@kubb/plugin-zod`.
1474
+ *
1475
+ * Uses `camelCase` naming with a `Schema` suffix for function/type/const names.
1476
+ *
1477
+ * @example
1478
+ * ```ts
1479
+ * resolverZod.default('list pets', 'function') // → 'listPetsSchema'
1480
+ * resolverZod.default('Pet', 'file') // → 'pet'
1481
+ * resolverZod.resolveName('list pets') // → 'listPetsSchema'
1482
+ * ```
1483
+ */
1484
+ const resolverZod = defineResolver(() => {
1485
+ return {
1486
+ name: "default",
1487
+ pluginName: "plugin-zod",
1488
+ default(name, type) {
1489
+ return toSchemaName(name, type);
1490
+ },
1491
+ resolveName(name) {
1492
+ return this.default(name, "function");
1493
+ },
1494
+ resolveInferName(name) {
1495
+ return pascalCase(name);
1496
+ },
1497
+ resolvePathName(name, type) {
1498
+ return this.default(name, type);
1499
+ },
1500
+ resolveParamName(node, param) {
1501
+ return this.resolveName(`${node.operationId} ${param.in} ${param.name}`);
1502
+ },
1503
+ resolveResponseStatusName(node, statusCode) {
1504
+ return this.resolveName(`${node.operationId} Status ${statusCode}`);
1505
+ },
1506
+ resolveDataName(node) {
1507
+ return this.resolveName(`${node.operationId} Data`);
1508
+ },
1509
+ resolveResponsesName(node) {
1510
+ return this.resolveName(`${node.operationId} Responses`);
1511
+ },
1512
+ resolveResponseName(node) {
1513
+ return this.resolveName(`${node.operationId} Response`);
1514
+ },
1515
+ resolvePathParamsName(node, param) {
1516
+ return this.resolveParamName(node, param);
1517
+ },
1518
+ resolveQueryParamsName(node, param) {
1519
+ return this.resolveParamName(node, param);
1520
+ },
1521
+ resolveHeaderParamsName(node, param) {
1522
+ return this.resolveParamName(node, param);
1523
+ }
1524
+ };
1525
+ });
1526
+ //#endregion
1527
+ //#region src/resolvers/resolverZodLegacy.ts
1528
+ /**
1529
+ * Legacy resolver for `@kubb/plugin-zod` that reproduces the naming conventions
1530
+ * used in Kubb v4. Enable via `compatibilityPreset: 'kubbV4'`
1531
+ * (or by composing this resolver manually).
1532
+ *
1533
+ * Key differences from the default resolver:
1534
+ * - Response status types: `<operationId><StatusCode>Schema` (e.g. `createPets201Schema`) instead of `<operationId>Status201Schema`
1535
+ * - Default/error responses: `<operationId>ErrorSchema` instead of `<operationId>StatusDefaultSchema`
1536
+ * - Request body: `<operationId>MutationRequestSchema` (non-GET) / `<operationId>QueryRequestSchema` (GET)
1537
+ * - Combined responses type: `<operationId>MutationSchema` / `<operationId>QuerySchema`
1538
+ * - Response union: `<operationId>MutationResponseSchema` / `<operationId>QueryResponseSchema`
1539
+ *
1540
+ * @example
1541
+ * ```ts
1542
+ * import { resolverZodLegacy } from '@kubb/plugin-zod'
1543
+ *
1544
+ * resolverZodLegacy.resolveResponseStatusName(node, 201) // → 'createPets201Schema'
1545
+ * resolverZodLegacy.resolveResponseStatusName(node, 'default') // → 'createPetsErrorSchema'
1546
+ * resolverZodLegacy.resolveDataName(node) // → 'createPetsMutationRequestSchema' (POST)
1547
+ * resolverZodLegacy.resolveResponsesName(node) // → 'createPetsMutationSchema' (POST)
1548
+ * resolverZodLegacy.resolveResponseName(node) // → 'createPetsMutationResponseSchema' (POST)
1549
+ * ```
1550
+ */
1551
+ const resolverZodLegacy = defineResolver(() => {
1552
+ return {
1553
+ ...resolverZod,
1554
+ pluginName: "plugin-zod",
1555
+ resolveResponseStatusName(node, statusCode) {
1556
+ if (statusCode === "default") return this.resolveName(`${node.operationId} Error`);
1557
+ return this.resolveName(`${node.operationId} ${statusCode}`);
1558
+ },
1559
+ resolveDataName(node) {
1560
+ const suffix = node.method === "GET" ? "QueryRequest" : "MutationRequest";
1561
+ return this.resolveName(`${node.operationId} ${suffix}`);
1562
+ },
1563
+ resolveResponsesName(node) {
1564
+ const suffix = node.method === "GET" ? "Query" : "Mutation";
1565
+ return this.resolveName(`${node.operationId} ${suffix}`);
1566
+ },
1567
+ resolveResponseName(node) {
1568
+ const suffix = node.method === "GET" ? "QueryResponse" : "MutationResponse";
1569
+ return this.resolveName(`${node.operationId} ${suffix}`);
1570
+ },
1571
+ resolvePathParamsName(node, _param) {
1572
+ return this.resolveName(`${node.operationId} PathParams`);
1573
+ },
1574
+ resolveQueryParamsName(node, _param) {
1575
+ return this.resolveName(`${node.operationId} QueryParams`);
1576
+ },
1577
+ resolveHeaderParamsName(node, _param) {
1578
+ return this.resolveName(`${node.operationId} HeaderParams`);
1579
+ }
1580
+ };
1581
+ });
1582
+ //#endregion
1583
+ //#region src/presets.ts
1584
+ /**
1585
+ * Built-in preset registry for `@kubb/plugin-zod`.
1586
+ *
1587
+ * - `default` — uses `resolverZod` and `zodGenerator` (current naming conventions).
1588
+ * - `kubbV4` — uses `resolverZodLegacy` and `zodGeneratorLegacy` (Kubb v4 naming conventions).
1589
+ */
1590
+ const presets = definePresets({
1591
+ default: {
1592
+ name: "default",
1593
+ resolvers: [resolverZod],
1594
+ generators: [zodGenerator]
1595
+ },
1596
+ kubbV4: {
1597
+ name: "kubbV4",
1598
+ resolvers: [resolverZodLegacy],
1599
+ generators: [zodGeneratorLegacy]
1600
+ }
1601
+ });
1602
+ //#endregion
66
1603
  //#region src/plugin.ts
1604
+ /**
1605
+ * Canonical plugin name for `@kubb/plugin-zod`, used to identify the plugin in driver lookups and warnings.
1606
+ */
67
1607
  const pluginZodName = "plugin-zod";
1608
+ /**
1609
+ * The `@kubb/plugin-zod` plugin factory.
1610
+ *
1611
+ * Generates Zod validation schemas from an OpenAPI/AST `RootNode`.
1612
+ * Walks schemas and operations, delegates rendering to the active generators,
1613
+ * and writes barrel files based on `output.barrelType`.
1614
+ *
1615
+ * @example
1616
+ * ```ts
1617
+ * import { pluginZod } from '@kubb/plugin-zod'
1618
+ *
1619
+ * export default defineConfig({
1620
+ * plugins: [pluginZod({ output: { path: 'zod' } })],
1621
+ * })
1622
+ * ```
1623
+ */
68
1624
  const pluginZod = createPlugin((options) => {
69
1625
  const { output = {
70
1626
  path: "zod",
71
1627
  barrelType: "named"
72
- }, group, exclude = [], include, override = [], transformers = {}, dateType = "string", unknownType = "any", emptySchemaType = unknownType, integerType = "number", typed = false, mapper = {}, operations = false, mini = false, version = mini ? "4" : satisfiesDependency("zod", ">=4") ? "4" : "3", guidType = "uuid", importPath = mini ? "zod/mini" : version === "4" ? "zod/v4" : "zod", coercion = false, inferred = false, generators = [zodGenerator, operations ? operationsGenerator : void 0].filter(Boolean), wrapOutput = void 0, contentType } = options;
1628
+ }, group, exclude = [], include, override = [], dateType = "string", typed = false, operations = false, mini = false, guidType = "uuid", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, wrapOutput = void 0, paramsCasing, compatibilityPreset = "default", resolvers: userResolvers = [], transformers: userTransformers = [], generators: userGenerators = [] } = options;
1629
+ const preset = getPreset({
1630
+ preset: compatibilityPreset,
1631
+ presets,
1632
+ resolvers: userResolvers,
1633
+ transformers: userTransformers,
1634
+ generators: userGenerators
1635
+ });
1636
+ let resolveNameWarning = false;
1637
+ let resolvePathWarning = false;
73
1638
  return {
74
1639
  name: pluginZodName,
75
- options: {
76
- output,
77
- transformers,
78
- include,
79
- exclude,
80
- override,
81
- typed,
82
- dateType,
83
- unknownType,
84
- emptySchemaType,
85
- integerType,
86
- mapper,
87
- importPath,
88
- coercion,
89
- operations,
90
- inferred,
91
- group,
92
- wrapOutput,
93
- version,
94
- guidType,
95
- mini,
96
- usedEnumNames: {}
97
- },
98
- pre: [pluginOasName, typed ? pluginTsName : void 0].filter(Boolean),
1640
+ get resolver() {
1641
+ return preset.resolver;
1642
+ },
1643
+ get options() {
1644
+ return {
1645
+ output,
1646
+ group: group ? {
1647
+ ...group,
1648
+ name: (ctx) => {
1649
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
1650
+ return `${camelCase(ctx.group)}Controller`;
1651
+ }
1652
+ } : void 0,
1653
+ dateType,
1654
+ typed,
1655
+ importPath,
1656
+ coercion,
1657
+ operations,
1658
+ inferred,
1659
+ guidType,
1660
+ mini,
1661
+ wrapOutput,
1662
+ paramsCasing,
1663
+ transformers: preset.transformers
1664
+ };
1665
+ },
99
1666
  resolvePath(baseName, pathMode, options) {
100
- const root = path.resolve(this.config.root, this.config.output.path);
101
- if ((pathMode ?? getMode(path.resolve(root, output.path))) === "single")
102
- /**
103
- * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend
104
- * Other plugins then need to call addOrAppend instead of just add from the fileManager class
105
- */
106
- return path.resolve(root, output.path);
107
- if (group && (options?.group?.path || options?.group?.tag)) {
108
- const groupName = group?.name ? group.name : (ctx) => {
109
- if (group?.type === "path") return `${ctx.group.split("/")[1]}`;
110
- return `${camelCase(ctx.group)}Controller`;
111
- };
112
- return path.resolve(root, output.path, groupName({ group: group.type === "path" ? options.group.path : options.group.tag }), baseName);
1667
+ if (!resolvePathWarning) {
1668
+ this.events.emit("warn", "Do not use resolvePath for pluginZod, use resolverZod.resolvePath instead");
1669
+ resolvePathWarning = true;
113
1670
  }
114
- return path.resolve(root, output.path, baseName);
1671
+ return this.plugin.resolver.resolvePath({
1672
+ baseName,
1673
+ pathMode,
1674
+ tag: options?.group?.tag,
1675
+ path: options?.group?.path
1676
+ }, {
1677
+ root: path.resolve(this.config.root, this.config.output.path),
1678
+ output,
1679
+ group: this.plugin.options.group
1680
+ });
115
1681
  },
116
1682
  resolveName(name, type) {
117
- let resolvedName = camelCase(name, {
118
- suffix: type ? "schema" : void 0,
119
- isFile: type === "file"
120
- });
121
- if (type === "type") resolvedName = pascalCase(resolvedName);
122
- if (type) return transformers?.name?.(resolvedName, type) || resolvedName;
123
- return resolvedName;
1683
+ if (!resolveNameWarning) {
1684
+ this.events.emit("warn", "Do not use resolveName for pluginZod, use resolverZod.default instead");
1685
+ resolveNameWarning = true;
1686
+ }
1687
+ return this.plugin.resolver.default(name, type);
124
1688
  },
125
1689
  async install() {
126
- const root = path.resolve(this.config.root, this.config.output.path);
127
- const mode = getMode(path.resolve(root, output.path));
128
- const oas = await this.getOas();
129
- if (this.plugin.options.typed && this.plugin.options.version === "3") await this.addFile({
130
- baseName: "ToZod.ts",
131
- path: path.resolve(root, ".kubb/ToZod.ts"),
132
- sources: [{
133
- name: "ToZod",
134
- value: source
135
- }],
136
- imports: [],
137
- exports: []
138
- });
139
- const schemaFiles = await new SchemaGenerator(this.plugin.options, {
140
- fabric: this.fabric,
141
- oas,
142
- driver: this.driver,
143
- events: this.events,
144
- plugin: this.plugin,
145
- contentType,
146
- include: void 0,
147
- override,
148
- mode,
149
- output: output.path
150
- }).build(...generators);
151
- await this.upsertFile(...schemaFiles);
152
- const operationFiles = await new OperationGenerator(this.plugin.options, {
153
- fabric: this.fabric,
154
- oas,
155
- driver: this.driver,
156
- events: this.events,
157
- plugin: this.plugin,
158
- contentType,
1690
+ const { config, fabric, plugin, adapter, rootNode, driver, openInStudio, resolver } = this;
1691
+ const root = path.resolve(config.root, config.output.path);
1692
+ if (!adapter) throw new Error(`[${pluginZodName}] No adapter found. Add an OAS adapter (e.g. pluginOas()) before this plugin in your Kubb config.`);
1693
+ await openInStudio({ ast: true });
1694
+ const collectedOperations = [];
1695
+ const generatorContext = {
1696
+ generators: preset.generators,
1697
+ plugin,
1698
+ resolver,
159
1699
  exclude,
160
1700
  include,
161
1701
  override,
162
- mode
163
- }).build(...generators);
164
- await this.upsertFile(...operationFiles);
1702
+ fabric,
1703
+ adapter,
1704
+ config,
1705
+ driver
1706
+ };
1707
+ await walk(rootNode, {
1708
+ depth: "shallow",
1709
+ async schema(schemaNode) {
1710
+ await runGeneratorSchema(schemaNode, generatorContext);
1711
+ },
1712
+ async operation(operationNode) {
1713
+ if (resolver.resolveOptions(operationNode, {
1714
+ options: plugin.options,
1715
+ exclude,
1716
+ include,
1717
+ override
1718
+ }) !== null) collectedOperations.push(operationNode);
1719
+ await runGeneratorOperation(operationNode, generatorContext);
1720
+ }
1721
+ });
1722
+ await runGeneratorOperations(collectedOperations, generatorContext);
165
1723
  const barrelFiles = await getBarrelFiles(this.fabric.files, {
166
1724
  type: output.barrelType ?? "named",
167
1725
  root,
@@ -173,6 +1731,6 @@ const pluginZod = createPlugin((options) => {
173
1731
  };
174
1732
  });
175
1733
  //#endregion
176
- export { pluginZod, pluginZodName };
1734
+ export { pluginZod, pluginZodName, printerZod, printerZodMini, resolverZod, resolverZodLegacy, zodGenerator, zodGeneratorLegacy };
177
1735
 
178
1736
  //# sourceMappingURL=index.js.map