@kubb/plugin-zod 5.0.0-beta.84 → 5.0.0-beta.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./rolldown-runtime-C0LytTxp.js";
2
- import { ast, defineGenerator, definePlugin, defineResolver } from "kubb/kit";
2
+ import { Resolver, ast, createResolver, defineGenerator, definePlugin } from "kubb/kit";
3
3
  import { Const, File, Type, jsxRenderer } from "kubb/jsx";
4
4
  import { Fragment, jsx, jsxs } from "kubb/jsx/jsx-runtime";
5
5
  //#region ../../internals/utils/src/casing.ts
@@ -41,31 +41,6 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
41
41
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
42
42
  }
43
43
  //#endregion
44
- //#region ../../internals/utils/src/fs.ts
45
- /**
46
- * Builds a nested file path from a dotted name. Splits on dots that precede a letter
47
- * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
48
- * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
49
- *
50
- * Empty segments are dropped before joining. They arise when the name starts with a dot
51
- * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
52
- * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
53
- * absolute path, letting generated files escape the configured output directory.
54
- *
55
- * @example Nested path from a dotted name
56
- * `toFilePath('pet.petId') // 'pet/petId'`
57
- *
58
- * @example PascalCase the final segment
59
- * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
60
- *
61
- * @example Suffix applied to the final segment only
62
- * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
63
- */
64
- function toFilePath(name, caseLast = camelCase) {
65
- const parts = name.split(/\.(?=[a-zA-Z])/);
66
- return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
67
- }
68
- //#endregion
69
44
  //#region ../../internals/utils/src/reserved.ts
70
45
  /**
71
46
  * JavaScript and Java reserved words.
@@ -188,6 +163,188 @@ function ensureValidVarName(name) {
188
163
  if (!name || isValidVarName(name)) return name;
189
164
  return `_${name}`;
190
165
  }
166
+ /**
167
+ * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
168
+ *
169
+ * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
170
+ * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
171
+ * deciding whether an object key needs quoting.
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * isIdentifier('name') // true
176
+ * isIdentifier('x-total')// false
177
+ * ```
178
+ */
179
+ function isIdentifier(name) {
180
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
181
+ }
182
+ //#endregion
183
+ //#region ../../internals/utils/src/strings.ts
184
+ /**
185
+ * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
186
+ * any backslash or single quote in the content.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * singleQuote('foo') // "'foo'"
191
+ * singleQuote("o'clock") // "'o\\'clock'"
192
+ * ```
193
+ */
194
+ function singleQuote(value) {
195
+ if (value === void 0 || value === null) return "''";
196
+ return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
197
+ }
198
+ /**
199
+ * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
200
+ * Returns the string unchanged when no balanced quote pair is found.
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * trimQuotes('"hello"') // 'hello'
205
+ * trimQuotes('hello') // 'hello'
206
+ * ```
207
+ */
208
+ function trimQuotes(text) {
209
+ if (text.length >= 2) {
210
+ const first = text[0];
211
+ const last = text[text.length - 1];
212
+ if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
213
+ }
214
+ return text;
215
+ }
216
+ /**
217
+ * Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
218
+ *
219
+ * Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
220
+ * code matches the repo style without a formatter.
221
+ *
222
+ * @example
223
+ * ```ts
224
+ * stringify('hello') // "'hello'"
225
+ * stringify('"hello"') // "'hello'"
226
+ * ```
227
+ */
228
+ function stringify(value) {
229
+ if (value === void 0 || value === null) return "''";
230
+ return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
231
+ }
232
+ /**
233
+ * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
234
+ * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
235
+ * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
236
+ *
237
+ * @example
238
+ * ```ts
239
+ * toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")'
240
+ * toRegExpString('^(?im)foo', null) // '/^foo/im'
241
+ * ```
242
+ */
243
+ function toRegExpString(text, func = "RegExp") {
244
+ const raw = trimQuotes(text);
245
+ const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
246
+ const replacementTarget = match?.[1] ?? "";
247
+ const matchedFlags = match?.[2];
248
+ const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
249
+ const { source, flags } = new RegExp(cleaned, matchedFlags);
250
+ if (func === null) return `/${source}/${flags}`;
251
+ return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
252
+ }
253
+ //#endregion
254
+ //#region ../../internals/utils/src/codegen.ts
255
+ const INDENT = " ";
256
+ /**
257
+ * Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
258
+ */
259
+ function indentLines(text) {
260
+ if (!text) return "";
261
+ return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n");
262
+ }
263
+ /**
264
+ * Renders an object key, quoting it with single quotes only when it is not a valid identifier.
265
+ * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.
266
+ *
267
+ * @example
268
+ * ```ts
269
+ * objectKey('name') // 'name'
270
+ * objectKey('x-total') // "'x-total'"
271
+ * ```
272
+ */
273
+ function objectKey(name) {
274
+ return isIdentifier(name) ? name : singleQuote(name);
275
+ }
276
+ /**
277
+ * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
278
+ * level and closing the brace at column zero. Entries that are themselves multi-line objects indent
279
+ * cumulatively. Each entry ends with a trailing comma to match the formatter's multi-line style.
280
+ *
281
+ * @example
282
+ * ```ts
283
+ * buildObject(['id: z.number()', 'name: z.string()'])
284
+ * // '{\n id: z.number(),\n name: z.string(),\n}'
285
+ * ```
286
+ */
287
+ function buildObject(entries) {
288
+ if (entries.length === 0) return "{}";
289
+ return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`;
290
+ }
291
+ /**
292
+ * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on
293
+ * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented
294
+ * one level with a trailing comma and the closing bracket at column zero. Used for member lists such
295
+ * as `z.union([…])` and `z.array([…])`.
296
+ *
297
+ * @example
298
+ * ```ts
299
+ * buildList(['z.string()', 'z.number()'])
300
+ * // '[z.string(), z.number()]'
301
+ * ```
302
+ */
303
+ function buildList(items, brackets = ["[", "]"]) {
304
+ const [open, close] = brackets;
305
+ if (items.length === 0) return `${open}${close}`;
306
+ if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`;
307
+ return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`;
308
+ }
309
+ /**
310
+ * Emits a lazy getter for a circular-ref property position, `get name() { return body }`. The key
311
+ * is quoted only when it is not a valid identifier. Used by the string printers to defer evaluation
312
+ * of a recursive schema until first access.
313
+ *
314
+ * @example
315
+ * ```ts
316
+ * lazyGetter({ name: 'parent', body: 'z.lazy(() => Pet)' })
317
+ * // "get parent() { return z.lazy(() => Pet) }"
318
+ * ```
319
+ */
320
+ function lazyGetter({ name, body }) {
321
+ return `get ${objectKey(name)}() { return ${body} }`;
322
+ }
323
+ //#endregion
324
+ //#region ../../internals/utils/src/fs.ts
325
+ /**
326
+ * Builds a nested file path from a dotted name. Splits on dots that precede a letter
327
+ * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
328
+ * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
329
+ *
330
+ * Empty segments are dropped before joining. They arise when the name starts with a dot
331
+ * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
332
+ * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
333
+ * absolute path, letting generated files escape the configured output directory.
334
+ *
335
+ * @example Nested path from a dotted name
336
+ * `toFilePath('pet.petId') // 'pet/petId'`
337
+ *
338
+ * @example PascalCase the final segment
339
+ * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
340
+ *
341
+ * @example Suffix applied to the final segment only
342
+ * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
343
+ */
344
+ function toFilePath(name, caseLast = camelCase) {
345
+ const parts = name.split(/\.(?=[a-zA-Z])/);
346
+ return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
347
+ }
191
348
  //#endregion
192
349
  //#region ../../internals/shared/src/params.ts
193
350
  const caseParamsCache = /* @__PURE__ */ new WeakMap();
@@ -453,7 +610,7 @@ function isObjectComposableIntersection(node, cyclicSchemas) {
453
610
  * Objects become `{}`, primitives become their string representation, strings are quoted.
454
611
  */
455
612
  function formatDefault(value) {
456
- if (typeof value === "string") return ast.stringify(value);
613
+ if (typeof value === "string") return stringify(value);
457
614
  if (typeof value === "object" && value !== null) return "{}";
458
615
  return String(value ?? "");
459
616
  }
@@ -489,7 +646,7 @@ function defaultLiteral(node, value) {
489
646
  * Strings are quoted; numbers and booleans are emitted raw.
490
647
  */
491
648
  function formatLiteral(v) {
492
- if (typeof v === "string") return ast.stringify(v);
649
+ if (typeof v === "string") return stringify(v);
493
650
  return String(v);
494
651
  }
495
652
  /**
@@ -531,8 +688,7 @@ function patternKeySchemaMini({ patterns, regexType }) {
531
688
  })}))`;
532
689
  }
533
690
  function patternKeySource({ patterns, regexType }) {
534
- const source = patterns.length === 1 ? patterns[0] : patterns.map((pattern) => `(${pattern})`).join("|");
535
- return ast.toRegExpString(source, regexFunc(regexType));
691
+ return toRegExpString(patterns.length === 1 ? patterns[0] : patterns.map((pattern) => `(${pattern})`).join("|"), regexFunc(regexType));
536
692
  }
537
693
  /**
538
694
  * Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
@@ -555,7 +711,7 @@ function lengthConstraints({ min, max, pattern, regexType }) {
555
711
  return [
556
712
  min !== void 0 ? `.min(${min})` : "",
557
713
  max !== void 0 ? `.max(${max})` : "",
558
- pattern !== void 0 ? `.regex(${ast.toRegExpString(pattern, regexFunc(regexType))})` : ""
714
+ pattern !== void 0 ? `.regex(${toRegExpString(pattern, regexFunc(regexType))})` : ""
559
715
  ].join("");
560
716
  }
561
717
  /**
@@ -577,7 +733,7 @@ function lengthChecksMini({ min, max, pattern, regexType }) {
577
733
  const checks = [];
578
734
  if (min !== void 0) checks.push(`z.minLength(${min})`);
579
735
  if (max !== void 0) checks.push(`z.maxLength(${max})`);
580
- if (pattern !== void 0) checks.push(`z.regex(${ast.toRegExpString(pattern, regexFunc(regexType))})`);
736
+ if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, regexFunc(regexType))})`);
581
737
  return checks.length ? `.check(${checks.join(", ")})` : "";
582
738
  }
583
739
  /**
@@ -593,7 +749,7 @@ function applyModifiers({ value, schema, nullable, optional, nullish, defaultVal
593
749
  })();
594
750
  const literal = defaultValue !== void 0 ? defaultLiteral(schema, defaultValue) : null;
595
751
  const withDefault = literal !== null ? `${withModifier}.default(${literal})` : withModifier;
596
- const withDescription = description ? `${withDefault}.describe(${ast.stringify(description)})` : withDefault;
752
+ const withDescription = description ? `${withDefault}.describe(${stringify(description)})` : withDefault;
597
753
  return examples?.length ? `${withDescription}.meta({ examples: [${examples.map(formatDefault).join(", ")}] })` : withDescription;
598
754
  }
599
755
  function modifierDepth(schema) {
@@ -664,7 +820,7 @@ function buildZodObjectShape(ctx, node) {
664
820
  const objectNode = ast.narrowSchema(node, "object");
665
821
  if (!objectNode) return "{}";
666
822
  const isCyclic = (schema) => ctx.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
667
- const entries = ast.mapSchemaProperties(objectNode, (schema) => {
823
+ return buildObject(ast.mapSchemaProperties(objectNode, (schema) => {
668
824
  const hasSelfRef = isCyclic(schema);
669
825
  const savedCyclicSchemas = ctx.options.cyclicSchemas;
670
826
  if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
@@ -685,12 +841,11 @@ function buildZodObjectShape(ctx, node) {
685
841
  description: descriptionToApply,
686
842
  examples: meta.examples
687
843
  });
688
- return isCyclic(schema) ? ast.lazyGetter({
844
+ return isCyclic(schema) ? lazyGetter({
689
845
  name: propName,
690
846
  body: value
691
- }) : `${ast.objectKey(propName)}: ${value}`;
692
- });
693
- return ast.buildObject(entries);
847
+ }) : `${objectKey(propName)}: ${value}`;
848
+ }));
694
849
  }
695
850
  /**
696
851
  * Zod v4 printer built with `definePrinter`.
@@ -784,7 +939,7 @@ const printerZod = ast.createPrinter((options) => {
784
939
  if (!node.name) return null;
785
940
  const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? ast.extractRefName(node.ref) ?? node.name : node.name;
786
941
  const useInputVariant = node.ref != null && this.options.direction === "input" && containsCodec(node);
787
- const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.resolveInputSchemaName(refName) ?? refName : this.options.resolver?.default(refName, "function") ?? refName : node.name;
942
+ const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.schema.inputName(refName) ?? refName : this.options.resolver?.name(refName) ?? refName : node.name;
788
943
  if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
789
944
  return resolvedName;
790
945
  },
@@ -823,8 +978,7 @@ const printerZod = ast.createPrinter((options) => {
823
978
  return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
824
979
  },
825
980
  tuple(node) {
826
- const items = ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean);
827
- return `z.tuple(${ast.buildList(items)})`;
981
+ return `z.tuple(${buildList(ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
828
982
  },
829
983
  union(node) {
830
984
  const nodeMembers = node.members ?? [];
@@ -832,8 +986,8 @@ const printerZod = ast.createPrinter((options) => {
832
986
  if (members.length === 0) return "";
833
987
  if (members.length === 1) return members[0];
834
988
  const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
835
- if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${ast.stringify(node.discriminatorPropertyName)}, ${ast.buildList(members)})`;
836
- return `z.union(${ast.buildList(members)})`;
989
+ if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
990
+ return `z.union(${buildList(members)})`;
837
991
  },
838
992
  intersection(node) {
839
993
  const members = node.members ?? [];
@@ -905,7 +1059,7 @@ function buildZodMiniObjectShape(ctx, node) {
905
1059
  const objectNode = ast.narrowSchema(node, "object");
906
1060
  if (!objectNode) return "{}";
907
1061
  const isCyclic = (schema) => ctx.options.cyclicSchemas != null && ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
908
- const entries = ast.mapSchemaProperties(objectNode, (schema) => {
1062
+ return buildObject(ast.mapSchemaProperties(objectNode, (schema) => {
909
1063
  const hasSelfRef = isCyclic(schema);
910
1064
  const savedCyclicSchemas = ctx.options.cyclicSchemas;
911
1065
  if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
@@ -923,12 +1077,11 @@ function buildZodMiniObjectShape(ctx, node) {
923
1077
  nullish: schema.nullish,
924
1078
  defaultValue: meta.default
925
1079
  });
926
- return isCyclic(schema) ? ast.lazyGetter({
1080
+ return isCyclic(schema) ? lazyGetter({
927
1081
  name: propName,
928
1082
  body: value
929
- }) : `${ast.objectKey(propName)}: ${value}`;
930
- });
931
- return ast.buildObject(entries);
1083
+ }) : `${objectKey(propName)}: ${value}`;
1084
+ }));
932
1085
  }
933
1086
  /**
934
1087
  * Zod v4 Mini printer built with `definePrinter`.
@@ -1013,7 +1166,7 @@ const printerZodMini = ast.createPrinter((options) => {
1013
1166
  ref(node) {
1014
1167
  if (!node.name) return null;
1015
1168
  const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? ast.extractRefName(node.ref) ?? node.name : node.name;
1016
- const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
1169
+ const resolvedName = node.ref ? this.options.resolver?.name(refName) ?? refName : node.name;
1017
1170
  if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
1018
1171
  return resolvedName;
1019
1172
  },
@@ -1050,8 +1203,7 @@ const printerZodMini = ast.createPrinter((options) => {
1050
1203
  return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
1051
1204
  },
1052
1205
  tuple(node) {
1053
- const items = ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean);
1054
- return `z.tuple(${ast.buildList(items)})`;
1206
+ return `z.tuple(${buildList(ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
1055
1207
  },
1056
1208
  union(node) {
1057
1209
  const nodeMembers = node.members ?? [];
@@ -1059,8 +1211,8 @@ const printerZodMini = ast.createPrinter((options) => {
1059
1211
  if (members.length === 0) return "";
1060
1212
  if (members.length === 1) return members[0];
1061
1213
  const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
1062
- if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${ast.stringify(node.discriminatorPropertyName)}, ${ast.buildList(members)})`;
1063
- return `z.union(${ast.buildList(members)})`;
1214
+ if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
1215
+ return `z.union(${buildList(members)})`;
1064
1216
  },
1065
1217
  intersection(node) {
1066
1218
  const members = node.members ?? [];
@@ -1180,22 +1332,20 @@ const zodGenerator = defineGenerator({
1180
1332
  const hasCodec = !mini && containsCodec(node);
1181
1333
  const codecRefNames = new Set(hasCodec ? collectCodecRefNames(node) : []);
1182
1334
  const importEntries = adapter.getImports(node, (schemaName) => ({
1183
- name: resolver.resolveSchemaName(schemaName),
1184
- path: resolver.resolveFile({
1335
+ name: resolver.name(schemaName),
1336
+ path: resolver.file({
1185
1337
  name: schemaName,
1186
- extname: ".ts"
1187
- }, {
1338
+ extname: ".ts",
1188
1339
  root,
1189
1340
  output,
1190
1341
  group: group ?? void 0
1191
1342
  }).path
1192
1343
  }));
1193
1344
  const inputImportEntries = hasCodec ? [...codecRefNames].map((schemaName) => ({
1194
- name: [resolver.resolveInputSchemaName(schemaName)],
1195
- path: resolver.resolveFile({
1345
+ name: [resolver.schema.inputName(schemaName)],
1346
+ path: resolver.file({
1196
1347
  name: schemaName,
1197
- extname: ".ts"
1198
- }, {
1348
+ extname: ".ts",
1199
1349
  root,
1200
1350
  output,
1201
1351
  group: group ?? void 0
@@ -1209,17 +1359,16 @@ const zodGenerator = defineGenerator({
1209
1359
  return true;
1210
1360
  });
1211
1361
  const meta = {
1212
- name: resolver.resolveSchemaName(node.name),
1213
- file: resolver.resolveFile({
1362
+ name: resolver.name(node.name),
1363
+ file: resolver.file({
1214
1364
  name: node.name,
1215
- extname: ".ts"
1216
- }, {
1365
+ extname: ".ts",
1217
1366
  root,
1218
1367
  output,
1219
1368
  group: group ?? void 0
1220
1369
  })
1221
1370
  };
1222
- const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : null;
1371
+ const inferTypeName = inferred ? resolver.schema.typeName(node.name) : null;
1223
1372
  const nameMapping = adapter.options.nameMapping;
1224
1373
  const stdPrinters = mini ? null : getStdPrinters(resolver, {
1225
1374
  coercion,
@@ -1241,7 +1390,7 @@ const zodGenerator = defineGenerator({
1241
1390
  baseName: meta.file.baseName,
1242
1391
  path: meta.file.path,
1243
1392
  meta: meta.file.meta,
1244
- banner: resolver.resolveBanner(ctx.meta, {
1393
+ banner: resolver.default.banner(ctx.meta, {
1245
1394
  output,
1246
1395
  config,
1247
1396
  file: {
@@ -1249,7 +1398,7 @@ const zodGenerator = defineGenerator({
1249
1398
  baseName: meta.file.baseName
1250
1399
  }
1251
1400
  }),
1252
- footer: resolver.resolveFooter(ctx.meta, {
1401
+ footer: resolver.default.footer(ctx.meta, {
1253
1402
  output,
1254
1403
  config,
1255
1404
  file: {
@@ -1280,10 +1429,10 @@ const zodGenerator = defineGenerator({
1280
1429
  cyclic: cyclicSchemas.has(node.name)
1281
1430
  }),
1282
1431
  hasCodec && stdPrinters && /* @__PURE__ */ jsx(Zod, {
1283
- name: resolver.resolveInputSchemaName(node.name),
1432
+ name: resolver.schema.inputName(node.name),
1284
1433
  node,
1285
1434
  printer: stdPrinters.input,
1286
- inferTypeName: inferred ? resolver.resolveInputSchemaTypeName(node.name) : null,
1435
+ inferTypeName: inferred ? resolver.schema.inputTypeName(node.name) : null,
1287
1436
  cyclic: cyclicSchemas.has(node.name)
1288
1437
  })
1289
1438
  ]
@@ -1296,12 +1445,11 @@ const zodGenerator = defineGenerator({
1296
1445
  const dateType = adapter.options.dateType;
1297
1446
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1298
1447
  const params = caseParams(node.parameters, "camelcase");
1299
- const meta = { file: resolver.resolveFile({
1448
+ const meta = { file: resolver.file({
1300
1449
  name: node.operationId,
1301
1450
  extname: ".ts",
1302
1451
  tag: node.tags[0] ?? "default",
1303
- path: node.path
1304
- }, {
1452
+ path: node.path,
1305
1453
  root,
1306
1454
  output,
1307
1455
  group: group ?? void 0
@@ -1310,14 +1458,13 @@ const zodGenerator = defineGenerator({
1310
1458
  const nameMapping = adapter.options.nameMapping;
1311
1459
  function renderSchemaEntry({ schema, name, keysToOmit, direction = "output" }) {
1312
1460
  if (!schema) return null;
1313
- const inferTypeName = inferred ? resolver.resolveTypeName(name) : null;
1461
+ const inferTypeName = inferred ? resolver.schema.type(name) : null;
1314
1462
  const codecRefNames = direction === "input" && !mini ? new Set(collectCodecRefNames(schema)) : null;
1315
1463
  const imports = adapter.getImports(schema, (schemaName) => ({
1316
- name: codecRefNames?.has(schemaName) ? resolver.resolveInputSchemaName(schemaName) : resolver.resolveSchemaName(schemaName),
1317
- path: resolver.resolveFile({
1464
+ name: codecRefNames?.has(schemaName) ? resolver.schema.inputName(schemaName) : resolver.name(schemaName),
1465
+ path: resolver.file({
1318
1466
  name: schemaName,
1319
- extname: ".ts"
1320
- }, {
1467
+ extname: ".ts",
1321
1468
  root,
1322
1469
  output,
1323
1470
  group: group ?? void 0
@@ -1395,30 +1542,30 @@ const zodGenerator = defineGenerator({
1395
1542
  }
1396
1543
  const paramSchemas = params.map((param) => renderSchemaEntry({
1397
1544
  schema: param.schema,
1398
- name: resolver.resolveParamName(node, param),
1545
+ name: resolver.param.name(node, param),
1399
1546
  direction: "input"
1400
1547
  }));
1401
1548
  const responseSchemas = node.responses.map((res) => {
1402
1549
  const variants = (res.content ?? []).filter((entry) => entry.schema);
1403
- if (variants.length > 1) return buildContentTypeVariants(res.content, resolver.resolveResponseStatusName(node, res.statusCode));
1550
+ if (variants.length > 1) return buildContentTypeVariants(res.content, resolver.response.status(node, res.statusCode));
1404
1551
  const primary = variants[0] ?? res.content?.[0];
1405
1552
  return renderSchemaEntry({
1406
1553
  schema: primary?.schema ?? null,
1407
- name: resolver.resolveResponseStatusName(node, res.statusCode),
1554
+ name: resolver.response.status(node, res.statusCode),
1408
1555
  keysToOmit: primary?.keysToOmit
1409
1556
  });
1410
1557
  });
1411
1558
  const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
1412
1559
  const successResponsesWithSchema = getSuccessResponses(responsesWithSchema);
1413
1560
  const responseUnionSchema = responsesWithSchema.length > 0 ? (() => {
1414
- const responseUnionName = resolver.resolveResponseName(node);
1561
+ const responseUnionName = resolver.response.response(node);
1415
1562
  if (new Set(successResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
1416
- name: resolver.resolveSchemaName(schemaName),
1563
+ name: resolver.name(schemaName),
1417
1564
  path: ""
1418
1565
  })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(responseUnionName)) return null;
1419
1566
  const members = successResponsesWithSchema.map((res) => ast.factory.createSchema({
1420
1567
  type: "ref",
1421
- name: resolver.resolveResponseStatusName(node, res.statusCode)
1568
+ name: resolver.response.status(node, res.statusCode)
1422
1569
  }));
1423
1570
  if (members.length === 0) return renderSchemaEntry({
1424
1571
  schema: ast.factory.createSchema({ type: "unknown" }),
@@ -1434,14 +1581,14 @@ const zodGenerator = defineGenerator({
1434
1581
  })() : null;
1435
1582
  const errorResponsesWithSchema = responsesWithSchema.filter((res) => !isSuccessStatusCode(res.statusCode));
1436
1583
  const errorUnionSchema = errorResponsesWithSchema.length > 0 ? (() => {
1437
- const errorUnionName = resolver.resolveErrorName(node);
1584
+ const errorUnionName = resolver.response.error(node);
1438
1585
  if (new Set(errorResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
1439
- name: resolver.resolveSchemaName(schemaName),
1586
+ name: resolver.name(schemaName),
1440
1587
  path: ""
1441
1588
  })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(errorUnionName)) return null;
1442
1589
  const members = errorResponsesWithSchema.map((res) => ast.factory.createSchema({
1443
1590
  type: "ref",
1444
- name: resolver.resolveResponseStatusName(node, res.statusCode)
1591
+ name: resolver.response.status(node, res.statusCode)
1445
1592
  }));
1446
1593
  return renderSchemaEntry({
1447
1594
  schema: members.length === 1 ? members[0] : ast.factory.createSchema({
@@ -1462,12 +1609,12 @@ const zodGenerator = defineGenerator({
1462
1609
  ...entry.schema,
1463
1610
  description: node.requestBody.description ?? entry.schema.description
1464
1611
  },
1465
- name: resolver.resolveDataName(node),
1612
+ name: resolver.response.body(node),
1466
1613
  keysToOmit: entry.keysToOmit,
1467
1614
  direction: "input"
1468
1615
  });
1469
1616
  }
1470
- return buildContentTypeVariants(requestBodyContent, resolver.resolveDataName(node), (schema) => ({
1617
+ return buildContentTypeVariants(requestBodyContent, resolver.response.body(node), (schema) => ({
1471
1618
  ...schema,
1472
1619
  description: node.requestBody.description ?? schema.description
1473
1620
  }), "input");
@@ -1476,7 +1623,7 @@ const zodGenerator = defineGenerator({
1476
1623
  baseName: meta.file.baseName,
1477
1624
  path: meta.file.path,
1478
1625
  meta: meta.file.meta,
1479
- banner: resolver.resolveBanner(ctx.meta, {
1626
+ banner: resolver.default.banner(ctx.meta, {
1480
1627
  output,
1481
1628
  config,
1482
1629
  file: {
@@ -1484,7 +1631,7 @@ const zodGenerator = defineGenerator({
1484
1631
  baseName: meta.file.baseName
1485
1632
  }
1486
1633
  }),
1487
- footer: resolver.resolveFooter(ctx.meta, {
1634
+ footer: resolver.default.footer(ctx.meta, {
1488
1635
  output,
1489
1636
  config,
1490
1637
  file: {
@@ -1520,64 +1667,63 @@ const zodGenerator = defineGenerator({
1520
1667
  * ```ts
1521
1668
  * import { resolverZod } from '@kubb/plugin-zod'
1522
1669
  *
1523
- * resolverZod.default('list pets', 'function') // 'listPetsSchema'
1524
- * resolverZod.resolveSchemaTypeName('pet') // 'PetSchemaType'
1670
+ * resolverZod.name('list pets') // 'listPetsSchema'
1671
+ * resolverZod.schema.typeName('pet') // 'PetSchemaType'
1525
1672
  * ```
1526
1673
  */
1527
- const resolverZod = defineResolver(() => {
1528
- return {
1529
- name: "default",
1530
- pluginName: "plugin-zod",
1531
- default(name, type) {
1532
- if (type === "file") return toFilePath(name, (part) => camelCase(part, { suffix: "schema" }));
1533
- return ensureValidVarName(camelCase(name, { suffix: type ? "schema" : void 0 }));
1534
- },
1535
- resolveSchemaName(name) {
1536
- return ensureValidVarName(camelCase(name, { suffix: "schema" }));
1537
- },
1538
- resolveSchemaTypeName(name) {
1674
+ const resolverZod = createResolver({
1675
+ pluginName: "plugin-zod",
1676
+ name(name) {
1677
+ return ensureValidVarName(camelCase(name, { suffix: "schema" }));
1678
+ },
1679
+ file: { baseName({ name, extname }) {
1680
+ return `${toFilePath(name, (part) => camelCase(part, { suffix: "schema" }))}${extname}`;
1681
+ } },
1682
+ schema: {
1683
+ typeName(name) {
1539
1684
  return ensureValidVarName(pascalCase(name, { suffix: "schema type" }));
1540
1685
  },
1541
- resolveInputSchemaName(name) {
1542
- return this.resolveSchemaName(`${name} input`);
1543
- },
1544
- resolveInputSchemaTypeName(name) {
1545
- return this.resolveSchemaTypeName(`${name} input`);
1546
- },
1547
- resolveTypeName(name) {
1686
+ type(name) {
1548
1687
  return ensureValidVarName(pascalCase(name, { suffix: "type" }));
1549
1688
  },
1550
- resolvePathName(name, type) {
1551
- return this.default(name, type);
1552
- },
1553
- resolveParamName(node, param) {
1554
- return this.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`);
1689
+ inputName(name) {
1690
+ return this.name(`${name} input`);
1555
1691
  },
1556
- resolveResponseStatusName(node, statusCode) {
1557
- return this.resolveSchemaName(`${node.operationId} Status ${statusCode}`);
1692
+ inputTypeName(name) {
1693
+ return this.schema.typeName(`${name} input`);
1694
+ }
1695
+ },
1696
+ param: {
1697
+ name(node, param) {
1698
+ return this.name(`${node.operationId} ${param.in} ${param.name}`);
1558
1699
  },
1559
- resolveDataName(node) {
1560
- return this.resolveSchemaName(`${node.operationId} Data`);
1700
+ path(node, param) {
1701
+ return this.param.name(node, param);
1561
1702
  },
1562
- resolveResponsesName(node) {
1563
- return this.resolveSchemaName(`${node.operationId} Responses`);
1703
+ query(node, param) {
1704
+ return this.param.name(node, param);
1564
1705
  },
1565
- resolveResponseName(node) {
1566
- return this.resolveSchemaName(`${node.operationId} Response`);
1706
+ headers(node, param) {
1707
+ return this.param.name(node, param);
1708
+ }
1709
+ },
1710
+ response: {
1711
+ status(node, statusCode) {
1712
+ return this.name(`${node.operationId} Status ${statusCode}`);
1567
1713
  },
1568
- resolveErrorName(node) {
1569
- return this.resolveSchemaName(`${node.operationId} Error`);
1714
+ body(node) {
1715
+ return this.name(`${node.operationId} Body`);
1570
1716
  },
1571
- resolvePathParamsName(node, param) {
1572
- return this.resolveParamName(node, param);
1717
+ responses(node) {
1718
+ return this.name(`${node.operationId} Responses`);
1573
1719
  },
1574
- resolveQueryParamsName(node, param) {
1575
- return this.resolveParamName(node, param);
1720
+ response(node) {
1721
+ return this.name(`${node.operationId} Response`);
1576
1722
  },
1577
- resolveHeaderParamsName(node, param) {
1578
- return this.resolveParamName(node, param);
1723
+ error(node) {
1724
+ return this.name(`${node.operationId} Error`);
1579
1725
  }
1580
- };
1726
+ }
1581
1727
  });
1582
1728
  //#endregion
1583
1729
  //#region src/plugin.ts
@@ -1636,10 +1782,7 @@ const pluginZod = definePlugin((options) => {
1636
1782
  mini,
1637
1783
  printer
1638
1784
  });
1639
- ctx.setResolver(userResolver ? {
1640
- ...resolverZod,
1641
- ...userResolver
1642
- } : resolverZod);
1785
+ ctx.setResolver(userResolver ? Resolver.merge(resolverZod, userResolver) : resolverZod);
1643
1786
  if (userMacros?.length) ctx.setMacros(userMacros);
1644
1787
  ctx.addGenerator(zodGenerator);
1645
1788
  } }