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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -51,31 +51,6 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
51
51
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
52
52
  }
53
53
  //#endregion
54
- //#region ../../internals/utils/src/fs.ts
55
- /**
56
- * Builds a nested file path from a dotted name. Splits on dots that precede a letter
57
- * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
58
- * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
59
- *
60
- * Empty segments are dropped before joining. They arise when the name starts with a dot
61
- * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
62
- * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
63
- * absolute path, letting generated files escape the configured output directory.
64
- *
65
- * @example Nested path from a dotted name
66
- * `toFilePath('pet.petId') // 'pet/petId'`
67
- *
68
- * @example PascalCase the final segment
69
- * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
70
- *
71
- * @example Suffix applied to the final segment only
72
- * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
73
- */
74
- function toFilePath(name, caseLast = camelCase) {
75
- const parts = name.split(/\.(?=[a-zA-Z])/);
76
- return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
77
- }
78
- //#endregion
79
54
  //#region ../../internals/utils/src/reserved.ts
80
55
  /**
81
56
  * JavaScript and Java reserved words.
@@ -176,7 +151,7 @@ const reservedWords = /* @__PURE__ */ new Set([
176
151
  */
177
152
  function isValidVarName(name) {
178
153
  if (!name || reservedWords.has(name)) return false;
179
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
154
+ return isIdentifier(name);
180
155
  }
181
156
  /**
182
157
  * Returns `name` when it's a syntactically valid JavaScript variable name,
@@ -198,6 +173,188 @@ function ensureValidVarName(name) {
198
173
  if (!name || isValidVarName(name)) return name;
199
174
  return `_${name}`;
200
175
  }
176
+ /**
177
+ * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
178
+ *
179
+ * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
180
+ * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
181
+ * deciding whether an object key needs quoting.
182
+ *
183
+ * @example
184
+ * ```ts
185
+ * isIdentifier('name') // true
186
+ * isIdentifier('x-total')// false
187
+ * ```
188
+ */
189
+ function isIdentifier(name) {
190
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
191
+ }
192
+ //#endregion
193
+ //#region ../../internals/utils/src/strings.ts
194
+ /**
195
+ * Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
196
+ * any backslash or single quote in the content.
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * singleQuote('foo') // "'foo'"
201
+ * singleQuote("o'clock") // "'o\\'clock'"
202
+ * ```
203
+ */
204
+ function singleQuote(value) {
205
+ if (value === void 0 || value === null) return "''";
206
+ return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
207
+ }
208
+ /**
209
+ * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
210
+ * Returns the string unchanged when no balanced quote pair is found.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * trimQuotes('"hello"') // 'hello'
215
+ * trimQuotes('hello') // 'hello'
216
+ * ```
217
+ */
218
+ function trimQuotes(text) {
219
+ if (text.length >= 2) {
220
+ const first = text[0];
221
+ const last = text[text.length - 1];
222
+ if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
223
+ }
224
+ return text;
225
+ }
226
+ /**
227
+ * Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
228
+ *
229
+ * Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
230
+ * code matches the repo style without a formatter.
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * stringify('hello') // "'hello'"
235
+ * stringify('"hello"') // "'hello'"
236
+ * ```
237
+ */
238
+ function stringify(value) {
239
+ if (value === void 0 || value === null) return "''";
240
+ return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
241
+ }
242
+ /**
243
+ * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
244
+ * Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
245
+ * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
246
+ *
247
+ * @example
248
+ * ```ts
249
+ * toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")'
250
+ * toRegExpString('^(?im)foo', null) // '/^foo/im'
251
+ * ```
252
+ */
253
+ function toRegExpString(text, func = "RegExp") {
254
+ const raw = trimQuotes(text);
255
+ const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
256
+ const replacementTarget = match?.[1] ?? "";
257
+ const matchedFlags = match?.[2];
258
+ const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
259
+ const { source, flags } = new RegExp(cleaned, matchedFlags);
260
+ if (func === null) return `/${source}/${flags}`;
261
+ return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
262
+ }
263
+ //#endregion
264
+ //#region ../../internals/utils/src/codegen.ts
265
+ const INDENT = " ";
266
+ /**
267
+ * Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
268
+ */
269
+ function indentLines(text) {
270
+ if (!text) return "";
271
+ return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n");
272
+ }
273
+ /**
274
+ * Renders an object key, quoting it with single quotes only when it is not a valid identifier.
275
+ * Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.
276
+ *
277
+ * @example
278
+ * ```ts
279
+ * objectKey('name') // 'name'
280
+ * objectKey('x-total') // "'x-total'"
281
+ * ```
282
+ */
283
+ function objectKey(name) {
284
+ return isIdentifier(name) ? name : singleQuote(name);
285
+ }
286
+ /**
287
+ * Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
288
+ * level and closing the brace at column zero. Entries that are themselves multi-line objects indent
289
+ * cumulatively. Each entry ends with a trailing comma to match the formatter's multi-line style.
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * buildObject(['id: z.number()', 'name: z.string()'])
294
+ * // '{\n id: z.number(),\n name: z.string(),\n}'
295
+ * ```
296
+ */
297
+ function buildObject(entries) {
298
+ if (entries.length === 0) return "{}";
299
+ return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`;
300
+ }
301
+ /**
302
+ * Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on
303
+ * one line when no item spans multiple lines, and otherwise puts each item on its own line, indented
304
+ * one level with a trailing comma and the closing bracket at column zero. Used for member lists such
305
+ * as `z.union([…])` and `z.array([…])`.
306
+ *
307
+ * @example
308
+ * ```ts
309
+ * buildList(['z.string()', 'z.number()'])
310
+ * // '[z.string(), z.number()]'
311
+ * ```
312
+ */
313
+ function buildList(items, brackets = ["[", "]"]) {
314
+ const [open, close] = brackets;
315
+ if (items.length === 0) return `${open}${close}`;
316
+ if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`;
317
+ return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`;
318
+ }
319
+ /**
320
+ * Emits a lazy getter for a circular-ref property position, `get name() { return body }`. The key
321
+ * is quoted only when it is not a valid identifier. Used by the string printers to defer evaluation
322
+ * of a recursive schema until first access.
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * lazyGetter({ name: 'parent', body: 'z.lazy(() => Pet)' })
327
+ * // "get parent() { return z.lazy(() => Pet) }"
328
+ * ```
329
+ */
330
+ function lazyGetter({ name, body }) {
331
+ return `get ${objectKey(name)}() { return ${body} }`;
332
+ }
333
+ //#endregion
334
+ //#region ../../internals/utils/src/fs.ts
335
+ /**
336
+ * Builds a nested file path from a dotted name. Splits on dots that precede a letter
337
+ * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
338
+ * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
339
+ *
340
+ * Empty segments are dropped before joining. They arise when the name starts with a dot
341
+ * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
342
+ * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
343
+ * absolute path, letting generated files escape the configured output directory.
344
+ *
345
+ * @example Nested path from a dotted name
346
+ * `toFilePath('pet.petId') // 'pet/petId'`
347
+ *
348
+ * @example PascalCase the final segment
349
+ * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
350
+ *
351
+ * @example Suffix applied to the final segment only
352
+ * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
353
+ */
354
+ function toFilePath(name, caseLast = camelCase) {
355
+ const parts = name.split(/\.(?=[a-zA-Z])/);
356
+ return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
357
+ }
201
358
  //#endregion
202
359
  //#region ../../internals/shared/src/params.ts
203
360
  const caseParamsCache = /* @__PURE__ */ new WeakMap();
@@ -463,7 +620,7 @@ function isObjectComposableIntersection(node, cyclicSchemas) {
463
620
  * Objects become `{}`, primitives become their string representation, strings are quoted.
464
621
  */
465
622
  function formatDefault(value) {
466
- if (typeof value === "string") return kubb_kit.ast.stringify(value);
623
+ if (typeof value === "string") return stringify(value);
467
624
  if (typeof value === "object" && value !== null) return "{}";
468
625
  return String(value ?? "");
469
626
  }
@@ -499,7 +656,7 @@ function defaultLiteral(node, value) {
499
656
  * Strings are quoted; numbers and booleans are emitted raw.
500
657
  */
501
658
  function formatLiteral(v) {
502
- if (typeof v === "string") return kubb_kit.ast.stringify(v);
659
+ if (typeof v === "string") return stringify(v);
503
660
  return String(v);
504
661
  }
505
662
  /**
@@ -541,8 +698,7 @@ function patternKeySchemaMini({ patterns, regexType }) {
541
698
  })}))`;
542
699
  }
543
700
  function patternKeySource({ patterns, regexType }) {
544
- const source = patterns.length === 1 ? patterns[0] : patterns.map((pattern) => `(${pattern})`).join("|");
545
- return kubb_kit.ast.toRegExpString(source, regexFunc(regexType));
701
+ return toRegExpString(patterns.length === 1 ? patterns[0] : patterns.map((pattern) => `(${pattern})`).join("|"), regexFunc(regexType));
546
702
  }
547
703
  /**
548
704
  * Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
@@ -565,7 +721,7 @@ function lengthConstraints({ min, max, pattern, regexType }) {
565
721
  return [
566
722
  min !== void 0 ? `.min(${min})` : "",
567
723
  max !== void 0 ? `.max(${max})` : "",
568
- pattern !== void 0 ? `.regex(${kubb_kit.ast.toRegExpString(pattern, regexFunc(regexType))})` : ""
724
+ pattern !== void 0 ? `.regex(${toRegExpString(pattern, regexFunc(regexType))})` : ""
569
725
  ].join("");
570
726
  }
571
727
  /**
@@ -587,7 +743,7 @@ function lengthChecksMini({ min, max, pattern, regexType }) {
587
743
  const checks = [];
588
744
  if (min !== void 0) checks.push(`z.minLength(${min})`);
589
745
  if (max !== void 0) checks.push(`z.maxLength(${max})`);
590
- if (pattern !== void 0) checks.push(`z.regex(${kubb_kit.ast.toRegExpString(pattern, regexFunc(regexType))})`);
746
+ if (pattern !== void 0) checks.push(`z.regex(${toRegExpString(pattern, regexFunc(regexType))})`);
591
747
  return checks.length ? `.check(${checks.join(", ")})` : "";
592
748
  }
593
749
  /**
@@ -603,7 +759,7 @@ function applyModifiers({ value, schema, nullable, optional, nullish, defaultVal
603
759
  })();
604
760
  const literal = defaultValue !== void 0 ? defaultLiteral(schema, defaultValue) : null;
605
761
  const withDefault = literal !== null ? `${withModifier}.default(${literal})` : withModifier;
606
- const withDescription = description ? `${withDefault}.describe(${kubb_kit.ast.stringify(description)})` : withDefault;
762
+ const withDescription = description ? `${withDefault}.describe(${stringify(description)})` : withDefault;
607
763
  return examples?.length ? `${withDescription}.meta({ examples: [${examples.map(formatDefault).join(", ")}] })` : withDescription;
608
764
  }
609
765
  function modifierDepth(schema) {
@@ -674,7 +830,7 @@ function buildZodObjectShape(ctx, node) {
674
830
  const objectNode = kubb_kit.ast.narrowSchema(node, "object");
675
831
  if (!objectNode) return "{}";
676
832
  const isCyclic = (schema) => ctx.options.cyclicSchemas != null && kubb_kit.ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
677
- const entries = kubb_kit.ast.mapSchemaProperties(objectNode, (schema) => {
833
+ return buildObject(kubb_kit.ast.mapSchemaProperties(objectNode, (schema) => {
678
834
  const hasSelfRef = isCyclic(schema);
679
835
  const savedCyclicSchemas = ctx.options.cyclicSchemas;
680
836
  if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
@@ -695,12 +851,11 @@ function buildZodObjectShape(ctx, node) {
695
851
  description: descriptionToApply,
696
852
  examples: meta.examples
697
853
  });
698
- return isCyclic(schema) ? kubb_kit.ast.lazyGetter({
854
+ return isCyclic(schema) ? lazyGetter({
699
855
  name: propName,
700
856
  body: value
701
- }) : `${kubb_kit.ast.objectKey(propName)}: ${value}`;
702
- });
703
- return kubb_kit.ast.buildObject(entries);
857
+ }) : `${objectKey(propName)}: ${value}`;
858
+ }));
704
859
  }
705
860
  /**
706
861
  * Zod v4 printer built with `definePrinter`.
@@ -794,7 +949,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
794
949
  if (!node.name) return null;
795
950
  const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? kubb_kit.ast.extractRefName(node.ref) ?? node.name : node.name;
796
951
  const useInputVariant = node.ref != null && this.options.direction === "input" && containsCodec(node);
797
- const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.resolveInputSchemaName(refName) ?? refName : this.options.resolver?.default(refName, "function") ?? refName : node.name;
952
+ const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.schema.inputName(refName) ?? refName : this.options.resolver?.name(refName) ?? refName : node.name;
798
953
  if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
799
954
  return resolvedName;
800
955
  },
@@ -833,8 +988,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
833
988
  return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
834
989
  },
835
990
  tuple(node) {
836
- const items = kubb_kit.ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean);
837
- return `z.tuple(${kubb_kit.ast.buildList(items)})`;
991
+ return `z.tuple(${buildList(kubb_kit.ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
838
992
  },
839
993
  union(node) {
840
994
  const nodeMembers = node.members ?? [];
@@ -842,8 +996,8 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
842
996
  if (members.length === 0) return "";
843
997
  if (members.length === 1) return members[0];
844
998
  const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
845
- if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${kubb_kit.ast.stringify(node.discriminatorPropertyName)}, ${kubb_kit.ast.buildList(members)})`;
846
- return `z.union(${kubb_kit.ast.buildList(members)})`;
999
+ if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
1000
+ return `z.union(${buildList(members)})`;
847
1001
  },
848
1002
  intersection(node) {
849
1003
  const members = node.members ?? [];
@@ -915,7 +1069,7 @@ function buildZodMiniObjectShape(ctx, node) {
915
1069
  const objectNode = kubb_kit.ast.narrowSchema(node, "object");
916
1070
  if (!objectNode) return "{}";
917
1071
  const isCyclic = (schema) => ctx.options.cyclicSchemas != null && kubb_kit.ast.containsCircularRef(schema, { circularSchemas: ctx.options.cyclicSchemas });
918
- const entries = kubb_kit.ast.mapSchemaProperties(objectNode, (schema) => {
1072
+ return buildObject(kubb_kit.ast.mapSchemaProperties(objectNode, (schema) => {
919
1073
  const hasSelfRef = isCyclic(schema);
920
1074
  const savedCyclicSchemas = ctx.options.cyclicSchemas;
921
1075
  if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
@@ -933,12 +1087,11 @@ function buildZodMiniObjectShape(ctx, node) {
933
1087
  nullish: schema.nullish,
934
1088
  defaultValue: meta.default
935
1089
  });
936
- return isCyclic(schema) ? kubb_kit.ast.lazyGetter({
1090
+ return isCyclic(schema) ? lazyGetter({
937
1091
  name: propName,
938
1092
  body: value
939
- }) : `${kubb_kit.ast.objectKey(propName)}: ${value}`;
940
- });
941
- return kubb_kit.ast.buildObject(entries);
1093
+ }) : `${objectKey(propName)}: ${value}`;
1094
+ }));
942
1095
  }
943
1096
  /**
944
1097
  * Zod v4 Mini printer built with `definePrinter`.
@@ -1023,7 +1176,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1023
1176
  ref(node) {
1024
1177
  if (!node.name) return null;
1025
1178
  const refName = node.ref ? this.options.nameMapping?.get(node.ref) ?? kubb_kit.ast.extractRefName(node.ref) ?? node.name : node.name;
1026
- const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
1179
+ const resolvedName = node.ref ? this.options.resolver?.name(refName) ?? refName : node.name;
1027
1180
  if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
1028
1181
  return resolvedName;
1029
1182
  },
@@ -1060,8 +1213,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1060
1213
  return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
1061
1214
  },
1062
1215
  tuple(node) {
1063
- const items = kubb_kit.ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean);
1064
- return `z.tuple(${kubb_kit.ast.buildList(items)})`;
1216
+ return `z.tuple(${buildList(kubb_kit.ast.mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean))})`;
1065
1217
  },
1066
1218
  union(node) {
1067
1219
  const nodeMembers = node.members ?? [];
@@ -1069,8 +1221,8 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
1069
1221
  if (members.length === 0) return "";
1070
1222
  if (members.length === 1) return members[0];
1071
1223
  const allDiscriminable = nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
1072
- if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${kubb_kit.ast.stringify(node.discriminatorPropertyName)}, ${kubb_kit.ast.buildList(members)})`;
1073
- return `z.union(${kubb_kit.ast.buildList(members)})`;
1224
+ if (node.discriminatorPropertyName && allDiscriminable) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
1225
+ return `z.union(${buildList(members)})`;
1074
1226
  },
1075
1227
  intersection(node) {
1076
1228
  const members = node.members ?? [];
@@ -1190,22 +1342,20 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1190
1342
  const hasCodec = !mini && containsCodec(node);
1191
1343
  const codecRefNames = new Set(hasCodec ? collectCodecRefNames(node) : []);
1192
1344
  const importEntries = adapter.getImports(node, (schemaName) => ({
1193
- name: resolver.resolveSchemaName(schemaName),
1194
- path: resolver.resolveFile({
1345
+ name: resolver.name(schemaName),
1346
+ path: resolver.file({
1195
1347
  name: schemaName,
1196
- extname: ".ts"
1197
- }, {
1348
+ extname: ".ts",
1198
1349
  root,
1199
1350
  output,
1200
1351
  group: group ?? void 0
1201
1352
  }).path
1202
1353
  }));
1203
1354
  const inputImportEntries = hasCodec ? [...codecRefNames].map((schemaName) => ({
1204
- name: [resolver.resolveInputSchemaName(schemaName)],
1205
- path: resolver.resolveFile({
1355
+ name: [resolver.schema.inputName(schemaName)],
1356
+ path: resolver.file({
1206
1357
  name: schemaName,
1207
- extname: ".ts"
1208
- }, {
1358
+ extname: ".ts",
1209
1359
  root,
1210
1360
  output,
1211
1361
  group: group ?? void 0
@@ -1219,17 +1369,16 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1219
1369
  return true;
1220
1370
  });
1221
1371
  const meta = {
1222
- name: resolver.resolveSchemaName(node.name),
1223
- file: resolver.resolveFile({
1372
+ name: resolver.name(node.name),
1373
+ file: resolver.file({
1224
1374
  name: node.name,
1225
- extname: ".ts"
1226
- }, {
1375
+ extname: ".ts",
1227
1376
  root,
1228
1377
  output,
1229
1378
  group: group ?? void 0
1230
1379
  })
1231
1380
  };
1232
- const inferTypeName = inferred ? resolver.resolveSchemaTypeName(node.name) : null;
1381
+ const inferTypeName = inferred ? resolver.schema.typeName(node.name) : null;
1233
1382
  const nameMapping = adapter.options.nameMapping;
1234
1383
  const stdPrinters = mini ? null : getStdPrinters(resolver, {
1235
1384
  coercion,
@@ -1251,7 +1400,7 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1251
1400
  baseName: meta.file.baseName,
1252
1401
  path: meta.file.path,
1253
1402
  meta: meta.file.meta,
1254
- banner: resolver.resolveBanner(ctx.meta, {
1403
+ banner: resolver.default.banner(ctx.meta, {
1255
1404
  output,
1256
1405
  config,
1257
1406
  file: {
@@ -1259,7 +1408,7 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1259
1408
  baseName: meta.file.baseName
1260
1409
  }
1261
1410
  }),
1262
- footer: resolver.resolveFooter(ctx.meta, {
1411
+ footer: resolver.default.footer(ctx.meta, {
1263
1412
  output,
1264
1413
  config,
1265
1414
  file: {
@@ -1290,10 +1439,10 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1290
1439
  cyclic: cyclicSchemas.has(node.name)
1291
1440
  }),
1292
1441
  hasCodec && stdPrinters && /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Zod, {
1293
- name: resolver.resolveInputSchemaName(node.name),
1442
+ name: resolver.schema.inputName(node.name),
1294
1443
  node,
1295
1444
  printer: stdPrinters.input,
1296
- inferTypeName: inferred ? resolver.resolveInputSchemaTypeName(node.name) : null,
1445
+ inferTypeName: inferred ? resolver.schema.inputTypeName(node.name) : null,
1297
1446
  cyclic: cyclicSchemas.has(node.name)
1298
1447
  })
1299
1448
  ]
@@ -1306,12 +1455,11 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1306
1455
  const dateType = adapter.options.dateType;
1307
1456
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1308
1457
  const params = caseParams(node.parameters, "camelcase");
1309
- const meta = { file: resolver.resolveFile({
1458
+ const meta = { file: resolver.file({
1310
1459
  name: node.operationId,
1311
1460
  extname: ".ts",
1312
1461
  tag: node.tags[0] ?? "default",
1313
- path: node.path
1314
- }, {
1462
+ path: node.path,
1315
1463
  root,
1316
1464
  output,
1317
1465
  group: group ?? void 0
@@ -1320,14 +1468,13 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1320
1468
  const nameMapping = adapter.options.nameMapping;
1321
1469
  function renderSchemaEntry({ schema, name, keysToOmit, direction = "output" }) {
1322
1470
  if (!schema) return null;
1323
- const inferTypeName = inferred ? resolver.resolveTypeName(name) : null;
1471
+ const inferTypeName = inferred ? resolver.schema.type(name) : null;
1324
1472
  const codecRefNames = direction === "input" && !mini ? new Set(collectCodecRefNames(schema)) : null;
1325
1473
  const imports = adapter.getImports(schema, (schemaName) => ({
1326
- name: codecRefNames?.has(schemaName) ? resolver.resolveInputSchemaName(schemaName) : resolver.resolveSchemaName(schemaName),
1327
- path: resolver.resolveFile({
1474
+ name: codecRefNames?.has(schemaName) ? resolver.schema.inputName(schemaName) : resolver.name(schemaName),
1475
+ path: resolver.file({
1328
1476
  name: schemaName,
1329
- extname: ".ts"
1330
- }, {
1477
+ extname: ".ts",
1331
1478
  root,
1332
1479
  output,
1333
1480
  group: group ?? void 0
@@ -1403,64 +1550,55 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1403
1550
  direction
1404
1551
  })] });
1405
1552
  }
1553
+ function buildResponseUnion({ responses, name, fallbackUnknown }) {
1554
+ if (new Set(responses.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
1555
+ name: resolver.name(schemaName),
1556
+ path: ""
1557
+ })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(name)) return null;
1558
+ const members = responses.map((res) => kubb_kit.ast.factory.createSchema({
1559
+ type: "ref",
1560
+ name: resolver.response.status(node, res.statusCode)
1561
+ }));
1562
+ if (fallbackUnknown && members.length === 0) return renderSchemaEntry({
1563
+ schema: kubb_kit.ast.factory.createSchema({ type: "unknown" }),
1564
+ name
1565
+ });
1566
+ return renderSchemaEntry({
1567
+ schema: members.length === 1 ? members[0] : kubb_kit.ast.factory.createSchema({
1568
+ type: "union",
1569
+ members
1570
+ }),
1571
+ name
1572
+ });
1573
+ }
1406
1574
  const paramSchemas = params.map((param) => renderSchemaEntry({
1407
1575
  schema: param.schema,
1408
- name: resolver.resolveParamName(node, param),
1576
+ name: resolver.param.name(node, param),
1409
1577
  direction: "input"
1410
1578
  }));
1411
1579
  const responseSchemas = node.responses.map((res) => {
1412
1580
  const variants = (res.content ?? []).filter((entry) => entry.schema);
1413
- if (variants.length > 1) return buildContentTypeVariants(res.content, resolver.resolveResponseStatusName(node, res.statusCode));
1581
+ if (variants.length > 1) return buildContentTypeVariants(res.content, resolver.response.status(node, res.statusCode));
1414
1582
  const primary = variants[0] ?? res.content?.[0];
1415
1583
  return renderSchemaEntry({
1416
1584
  schema: primary?.schema ?? null,
1417
- name: resolver.resolveResponseStatusName(node, res.statusCode),
1585
+ name: resolver.response.status(node, res.statusCode),
1418
1586
  keysToOmit: primary?.keysToOmit
1419
1587
  });
1420
1588
  });
1421
1589
  const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
1422
1590
  const successResponsesWithSchema = getSuccessResponses(responsesWithSchema);
1423
- const responseUnionSchema = responsesWithSchema.length > 0 ? (() => {
1424
- const responseUnionName = resolver.resolveResponseName(node);
1425
- if (new Set(successResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
1426
- name: resolver.resolveSchemaName(schemaName),
1427
- path: ""
1428
- })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(responseUnionName)) return null;
1429
- const members = successResponsesWithSchema.map((res) => kubb_kit.ast.factory.createSchema({
1430
- type: "ref",
1431
- name: resolver.resolveResponseStatusName(node, res.statusCode)
1432
- }));
1433
- if (members.length === 0) return renderSchemaEntry({
1434
- schema: kubb_kit.ast.factory.createSchema({ type: "unknown" }),
1435
- name: responseUnionName
1436
- });
1437
- return renderSchemaEntry({
1438
- schema: members.length === 1 ? members[0] : kubb_kit.ast.factory.createSchema({
1439
- type: "union",
1440
- members
1441
- }),
1442
- name: responseUnionName
1443
- });
1444
- })() : null;
1591
+ const responseUnionSchema = responsesWithSchema.length > 0 ? buildResponseUnion({
1592
+ responses: successResponsesWithSchema,
1593
+ name: resolver.response.response(node),
1594
+ fallbackUnknown: true
1595
+ }) : null;
1445
1596
  const errorResponsesWithSchema = responsesWithSchema.filter((res) => !isSuccessStatusCode(res.statusCode));
1446
- const errorUnionSchema = errorResponsesWithSchema.length > 0 ? (() => {
1447
- const errorUnionName = resolver.resolveErrorName(node);
1448
- if (new Set(errorResponsesWithSchema.flatMap((res) => (res.content ?? []).flatMap((entry) => entry.schema ? adapter.getImports(entry.schema, (schemaName) => ({
1449
- name: resolver.resolveSchemaName(schemaName),
1450
- path: ""
1451
- })).flatMap((imp) => Array.isArray(imp.name) ? imp.name : [imp.name]) : []))).has(errorUnionName)) return null;
1452
- const members = errorResponsesWithSchema.map((res) => kubb_kit.ast.factory.createSchema({
1453
- type: "ref",
1454
- name: resolver.resolveResponseStatusName(node, res.statusCode)
1455
- }));
1456
- return renderSchemaEntry({
1457
- schema: members.length === 1 ? members[0] : kubb_kit.ast.factory.createSchema({
1458
- type: "union",
1459
- members
1460
- }),
1461
- name: errorUnionName
1462
- });
1463
- })() : null;
1597
+ const errorUnionSchema = errorResponsesWithSchema.length > 0 ? buildResponseUnion({
1598
+ responses: errorResponsesWithSchema,
1599
+ name: resolver.response.error(node),
1600
+ fallbackUnknown: false
1601
+ }) : null;
1464
1602
  const requestBodyContent = node.requestBody?.content ?? [];
1465
1603
  const requestSchema = (() => {
1466
1604
  if (requestBodyContent.length === 0) return null;
@@ -1472,12 +1610,12 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1472
1610
  ...entry.schema,
1473
1611
  description: node.requestBody.description ?? entry.schema.description
1474
1612
  },
1475
- name: resolver.resolveDataName(node),
1613
+ name: resolver.response.body(node),
1476
1614
  keysToOmit: entry.keysToOmit,
1477
1615
  direction: "input"
1478
1616
  });
1479
1617
  }
1480
- return buildContentTypeVariants(requestBodyContent, resolver.resolveDataName(node), (schema) => ({
1618
+ return buildContentTypeVariants(requestBodyContent, resolver.response.body(node), (schema) => ({
1481
1619
  ...schema,
1482
1620
  description: node.requestBody.description ?? schema.description
1483
1621
  }), "input");
@@ -1486,7 +1624,7 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1486
1624
  baseName: meta.file.baseName,
1487
1625
  path: meta.file.path,
1488
1626
  meta: meta.file.meta,
1489
- banner: resolver.resolveBanner(ctx.meta, {
1627
+ banner: resolver.default.banner(ctx.meta, {
1490
1628
  output,
1491
1629
  config,
1492
1630
  file: {
@@ -1494,7 +1632,7 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1494
1632
  baseName: meta.file.baseName
1495
1633
  }
1496
1634
  }),
1497
- footer: resolver.resolveFooter(ctx.meta, {
1635
+ footer: resolver.default.footer(ctx.meta, {
1498
1636
  output,
1499
1637
  config,
1500
1638
  file: {
@@ -1530,64 +1668,63 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
1530
1668
  * ```ts
1531
1669
  * import { resolverZod } from '@kubb/plugin-zod'
1532
1670
  *
1533
- * resolverZod.default('list pets', 'function') // 'listPetsSchema'
1534
- * resolverZod.resolveSchemaTypeName('pet') // 'PetSchemaType'
1671
+ * resolverZod.name('list pets') // 'listPetsSchema'
1672
+ * resolverZod.schema.typeName('pet') // 'PetSchemaType'
1535
1673
  * ```
1536
1674
  */
1537
- const resolverZod = (0, kubb_kit.defineResolver)(() => {
1538
- return {
1539
- name: "default",
1540
- pluginName: "plugin-zod",
1541
- default(name, type) {
1542
- if (type === "file") return toFilePath(name, (part) => camelCase(part, { suffix: "schema" }));
1543
- return ensureValidVarName(camelCase(name, { suffix: type ? "schema" : void 0 }));
1544
- },
1545
- resolveSchemaName(name) {
1546
- return ensureValidVarName(camelCase(name, { suffix: "schema" }));
1547
- },
1548
- resolveSchemaTypeName(name) {
1675
+ const resolverZod = (0, kubb_kit.createResolver)({
1676
+ pluginName: "plugin-zod",
1677
+ name(name) {
1678
+ return ensureValidVarName(camelCase(name, { suffix: "schema" }));
1679
+ },
1680
+ file: { baseName({ name, extname }) {
1681
+ return `${toFilePath(name, (part) => camelCase(part, { suffix: "schema" }))}${extname}`;
1682
+ } },
1683
+ schema: {
1684
+ typeName(name) {
1549
1685
  return ensureValidVarName(pascalCase(name, { suffix: "schema type" }));
1550
1686
  },
1551
- resolveInputSchemaName(name) {
1552
- return this.resolveSchemaName(`${name} input`);
1553
- },
1554
- resolveInputSchemaTypeName(name) {
1555
- return this.resolveSchemaTypeName(`${name} input`);
1556
- },
1557
- resolveTypeName(name) {
1687
+ type(name) {
1558
1688
  return ensureValidVarName(pascalCase(name, { suffix: "type" }));
1559
1689
  },
1560
- resolvePathName(name, type) {
1561
- return this.default(name, type);
1690
+ inputName(name) {
1691
+ return this.name(`${name} input`);
1562
1692
  },
1563
- resolveParamName(node, param) {
1564
- return this.resolveSchemaName(`${node.operationId} ${param.in} ${param.name}`);
1565
- },
1566
- resolveResponseStatusName(node, statusCode) {
1567
- return this.resolveSchemaName(`${node.operationId} Status ${statusCode}`);
1693
+ inputTypeName(name) {
1694
+ return this.schema.typeName(`${name} input`);
1695
+ }
1696
+ },
1697
+ param: {
1698
+ name(node, param) {
1699
+ return this.name(`${node.operationId} ${param.in} ${param.name}`);
1568
1700
  },
1569
- resolveDataName(node) {
1570
- return this.resolveSchemaName(`${node.operationId} Data`);
1701
+ path(node, param) {
1702
+ return this.param.name(node, param);
1571
1703
  },
1572
- resolveResponsesName(node) {
1573
- return this.resolveSchemaName(`${node.operationId} Responses`);
1704
+ query(node, param) {
1705
+ return this.param.name(node, param);
1574
1706
  },
1575
- resolveResponseName(node) {
1576
- return this.resolveSchemaName(`${node.operationId} Response`);
1707
+ headers(node, param) {
1708
+ return this.param.name(node, param);
1709
+ }
1710
+ },
1711
+ response: {
1712
+ status(node, statusCode) {
1713
+ return this.name(`${node.operationId} Status ${statusCode}`);
1577
1714
  },
1578
- resolveErrorName(node) {
1579
- return this.resolveSchemaName(`${node.operationId} Error`);
1715
+ body(node) {
1716
+ return this.name(`${node.operationId} Body`);
1580
1717
  },
1581
- resolvePathParamsName(node, param) {
1582
- return this.resolveParamName(node, param);
1718
+ responses(node) {
1719
+ return this.name(`${node.operationId} Responses`);
1583
1720
  },
1584
- resolveQueryParamsName(node, param) {
1585
- return this.resolveParamName(node, param);
1721
+ response(node) {
1722
+ return this.name(`${node.operationId} Response`);
1586
1723
  },
1587
- resolveHeaderParamsName(node, param) {
1588
- return this.resolveParamName(node, param);
1724
+ error(node) {
1725
+ return this.name(`${node.operationId} Error`);
1589
1726
  }
1590
- };
1727
+ }
1591
1728
  });
1592
1729
  //#endregion
1593
1730
  //#region src/plugin.ts
@@ -1646,10 +1783,7 @@ const pluginZod = (0, kubb_kit.definePlugin)((options) => {
1646
1783
  mini,
1647
1784
  printer
1648
1785
  });
1649
- ctx.setResolver(userResolver ? {
1650
- ...resolverZod,
1651
- ...userResolver
1652
- } : resolverZod);
1786
+ ctx.setResolver(userResolver ? kubb_kit.Resolver.merge(resolverZod, userResolver) : resolverZod);
1653
1787
  if (userMacros?.length) ctx.setMacros(userMacros);
1654
1788
  ctx.addGenerator(zodGenerator);
1655
1789
  } }