@kubb/plugin-zod 5.0.0-beta.42 → 5.0.0-beta.56

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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./chunk-C0LytTxp.js";
2
- import { Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
2
+ import { Exclude, Generator, Group, Include, Output, OutputOptions, Override, PluginFactoryOptions, Resolver, ast } from "@kubb/core";
3
3
  import { AdapterOas } from "@kubb/adapter-oas";
4
4
 
5
5
  //#region src/printers/printerZod.d.ts
@@ -171,7 +171,7 @@ type ResolverZod = Resolver & ast.OperationParamsResolver & {
171
171
  * Resolves the schema type name (inferred type from schema).
172
172
  *
173
173
  * @example Schema type names
174
- * `resolver.resolveSchemaTypeName('pet') // → 'Pet'`
174
+ * `resolver.resolveSchemaTypeName('pet') // → 'PetSchemaType'`
175
175
  */
176
176
  resolveSchemaTypeName(this: ResolverZod, name: string): string;
177
177
  /**
@@ -186,14 +186,14 @@ type ResolverZod = Resolver & ast.OperationParamsResolver & {
186
186
  * Resolves the inferred type name for the request (input) direction variant.
187
187
  *
188
188
  * @example Input schema type names
189
- * `resolver.resolveInputSchemaTypeName('order') // → 'OrderInputSchema'`
189
+ * `resolver.resolveInputSchemaTypeName('order') // → 'OrderInputSchemaType'`
190
190
  */
191
191
  resolveInputSchemaTypeName(this: ResolverZod, name: string): string;
192
192
  /**
193
193
  * Resolves the generated type name from the schema.
194
194
  *
195
195
  * @example Type names
196
- * `resolver.resolveTypeName('pet') // → 'Pet'`
196
+ * `resolver.resolveTypeName('petSchema') // → 'PetSchemaType'`
197
197
  */
198
198
  resolveTypeName(this: ResolverZod, name: string): string;
199
199
  /**
@@ -243,17 +243,13 @@ type ResolverZod = Resolver & ast.OperationParamsResolver & {
243
243
  */
244
244
  resolveHeaderParamsName(this: ResolverZod, node: ast.OperationNode, param: ast.ParameterNode): string;
245
245
  };
246
- type Options = {
247
- /**
248
- * Where the generated Zod schemas are written and how they are exported.
249
- *
250
- * @default { path: 'zod', barrel: { type: 'named' } }
251
- */
252
- output?: Output;
253
- /**
254
- * Split generated files into subfolders based on the operation's tag.
255
- */
256
- group?: Group;
246
+ /**
247
+ * Where the generated Zod schemas are written and how they are exported, plus the optional
248
+ * `group` strategy. The `group` option organizes `output.mode: 'directory'` output into per-tag or per-path subdirectories.
249
+ *
250
+ * @default { path: 'zod', barrel: { type: 'named' } }
251
+ */
252
+ type Options = OutputOptions & {
257
253
  /**
258
254
  * Skip operations matching at least one entry in the list.
259
255
  */
@@ -270,7 +266,7 @@ type Options = {
270
266
  * Module specifier used in the `import { z } from '...'` statement.
271
267
  * Use `'zod/mini'` for the tree-shakeable bundle.
272
268
  *
273
- * @default 'zod'
269
+ * @default mini ? 'zod/mini' : 'zod'
274
270
  */
275
271
  importPath?: 'zod' | 'zod/mini' | (string & {});
276
272
  /**
@@ -427,14 +423,16 @@ declare const pluginZod: (options?: Options | undefined) => import("@kubb/core")
427
423
  /**
428
424
  * Default resolver used by `@kubb/plugin-zod`. Decides the names and file
429
425
  * paths for every generated Zod schema. Schemas use camelCase with a
430
- * `Schema` suffix (`listPetsSchema`); their inferred types use PascalCase.
426
+ * `Schema` suffix (`listPetsSchema`); their inferred types use PascalCase
427
+ * with a `SchemaType` suffix (`PetSchemaType`), so the value and the type
428
+ * never share an identifier even when the schema name is all-uppercase.
431
429
  *
432
430
  * @example Resolve schema and type names
433
431
  * ```ts
434
432
  * import { resolverZod } from '@kubb/plugin-zod'
435
433
  *
436
434
  * resolverZod.default('list pets', 'function') // 'listPetsSchema'
437
- * resolverZod.resolveSchemaTypeName('pet') // 'PetSchema'
435
+ * resolverZod.resolveSchemaTypeName('pet') // 'PetSchemaType'
438
436
  * ```
439
437
  */
440
438
  declare const resolverZod: ResolverZod;
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { t as __name } from "./chunk-C0LytTxp.js";
2
2
  import { ast, defineGenerator, definePlugin, defineResolver } from "@kubb/core";
3
- import { Const, File, Type, jsxRendererSync } from "@kubb/renderer-jsx";
3
+ import { buildList, buildObject, extractRefName, objectKey, stringify, stringifyObject, toRegExpString } from "@kubb/ast/utils";
4
+ import { Const, File, Type, jsxRenderer } from "@kubb/renderer-jsx";
4
5
  import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
5
6
  //#region ../../internals/utils/src/casing.ts
6
7
  /**
@@ -13,117 +14,57 @@ import { Fragment, jsx, jsxs } from "@kubb/renderer-jsx/jsx-runtime";
13
14
  function toCamelOrPascal(text, pascal) {
14
15
  return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
15
16
  if (word.length > 1 && word === word.toUpperCase()) return word;
16
- if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1);
17
- return word.charAt(0).toUpperCase() + word.slice(1);
17
+ return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
18
18
  }).join("").replace(/[^a-zA-Z0-9]/g, "");
19
19
  }
20
20
  /**
21
- * Splits `text` on `.` and applies `transformPart` to each segment.
22
- * The last segment receives `isLast = true`, all earlier segments receive `false`.
23
- * Segments are joined with `/` to form a file path.
24
- *
25
- * Only splits on dots followed by a letter so that version numbers
26
- * embedded in operationIds (e.g. `v2025.0`) are kept intact.
27
- */
28
- function applyToFileParts(text, transformPart) {
29
- const parts = text.split(/\.(?=[a-zA-Z])/);
30
- return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join("/");
31
- }
32
- /**
33
21
  * Converts `text` to camelCase.
34
- * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.
35
22
  *
36
- * @example
37
- * camelCase('hello-world') // 'helloWorld'
38
- * camelCase('pet.petId', { isFile: true }) // 'pet/petId'
23
+ * @example Word boundaries
24
+ * `camelCase('hello-world') // 'helloWorld'`
25
+ *
26
+ * @example With a prefix
27
+ * `camelCase('tag', { prefix: 'create' }) // 'createTag'`
39
28
  */
40
- function camelCase(text, { isFile, prefix = "", suffix = "" } = {}) {
41
- if (isFile) return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? {
42
- prefix,
43
- suffix
44
- } : {}));
29
+ function camelCase(text, { prefix = "", suffix = "" } = {}) {
45
30
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
46
31
  }
47
32
  /**
48
33
  * Converts `text` to PascalCase.
49
- * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.
50
34
  *
51
- * @example
52
- * pascalCase('hello-world') // 'HelloWorld'
53
- * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'
35
+ * @example Word boundaries
36
+ * `pascalCase('hello-world') // 'HelloWorld'`
37
+ *
38
+ * @example With a suffix
39
+ * `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
54
40
  */
55
- function pascalCase(text, { isFile, prefix = "", suffix = "" } = {}) {
56
- if (isFile) return applyToFileParts(text, (part, isLast) => isLast ? pascalCase(part, {
57
- prefix,
58
- suffix
59
- }) : camelCase(part));
41
+ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
60
42
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
61
43
  }
62
44
  //#endregion
63
- //#region ../../internals/utils/src/string.ts
45
+ //#region ../../internals/utils/src/fs.ts
64
46
  /**
65
- * Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
66
- * Returns the string unchanged when no balanced quote pair is found.
47
+ * Builds a nested file path from a dotted name. Splits on dots that precede a letter
48
+ * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
49
+ * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
67
50
  *
68
- * @example
69
- * trimQuotes('"hello"') // 'hello'
70
- * trimQuotes('hello') // 'hello'
71
- */
72
- function trimQuotes(text) {
73
- if (text.length >= 2) {
74
- const first = text[0];
75
- const last = text[text.length - 1];
76
- if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
77
- }
78
- return text;
79
- }
80
- //#endregion
81
- //#region ../../internals/utils/src/object.ts
82
- /**
83
- * Serializes a primitive value to a JSON string literal, stripping any surrounding quote characters first.
51
+ * Empty segments are dropped before joining. They arise when the name starts with a dot
52
+ * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
53
+ * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
54
+ * absolute path, letting generated files escape the configured output directory.
84
55
  *
85
- * @example
86
- * stringify('hello') // '"hello"'
87
- * stringify('"hello"') // '"hello"'
88
- */
89
- function stringify(value) {
90
- if (value === void 0 || value === null) return "\"\"";
91
- return JSON.stringify(trimQuotes(value.toString()));
92
- }
93
- /**
94
- * Converts a plain object into a multiline key-value string suitable for embedding in generated code.
95
- * Nested objects are recursively stringified with indentation.
56
+ * @example Nested path from a dotted name
57
+ * `toFilePath('pet.petId') // 'pet/petId'`
96
58
  *
97
- * @example
98
- * stringifyObject({ foo: 'bar', nested: { a: 1 } })
99
- * // 'foo: bar,\nnested: {\n a: 1\n }'
100
- */
101
- function stringifyObject(value) {
102
- return Object.entries(value).map(([key, val]) => {
103
- if (val !== null && typeof val === "object") return `${key}: {\n ${stringifyObject(val)}\n }`;
104
- return `${key}: ${val}`;
105
- }).filter(Boolean).join(",\n");
106
- }
107
- //#endregion
108
- //#region ../../internals/utils/src/regexp.ts
109
- /**
110
- * Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
111
- * Inline flags expressed as `^(?im)` prefixes are extracted and applied to the resulting expression.
112
- * Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
59
+ * @example PascalCase the final segment
60
+ * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
113
61
  *
114
- * @example
115
- * toRegExpString('^(?im)foo') // 'new RegExp("foo", "im")'
116
- * toRegExpString('^(?im)foo', null) // → '/foo/im'
62
+ * @example Suffix applied to the final segment only
63
+ * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
117
64
  */
118
- function toRegExpString(text, func = "RegExp") {
119
- const raw = trimQuotes(text);
120
- const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
121
- const replacementTarget = match?.[1] ?? "";
122
- const matchedFlags = match?.[2];
123
- const cleaned = raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, "");
124
- const { source, flags } = new RegExp(cleaned, matchedFlags);
125
- if (func === null) return `/${source}/${flags}`;
126
- return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
65
+ function toFilePath(name, caseLast = camelCase) {
66
+ const parts = name.split(/\.(?=[a-zA-Z])/);
67
+ return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
127
68
  }
128
69
  //#endregion
129
70
  //#region ../../internals/utils/src/reserved.ts
@@ -305,26 +246,24 @@ function resolveContentTypeVariants(entries, baseName) {
305
246
  * shared default naming so every plugin groups output consistently:
306
247
  *
307
248
  * - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
308
- * - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).
249
+ * - other groups use the camelCased group (`pet store``petStore`).
309
250
  *
310
251
  * A user-provided `group.name` always wins over the default namer, so callers stay in
311
252
  * control of their output folders. Returns `null` when grouping is disabled, matching the
312
253
  * per-plugin convention.
313
254
  *
314
255
  * @param group - The user-supplied group option, or `undefined` to disable grouping.
315
- * @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
316
256
  *
317
257
  * @example
318
258
  * ```ts
319
- * createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-client, …
320
- * createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp
259
+ * createGroupConfig(group) // shared across every plugin
321
260
  * ```
322
261
  */
323
- function createGroupConfig(group, options) {
262
+ function createGroupConfig(group) {
324
263
  if (!group) return null;
325
264
  const defaultName = (ctx) => {
326
265
  if (group.type === "path") return `${ctx.group.split("/")[1]}`;
327
- return `${camelCase(ctx.group)}${options.suffix}`;
266
+ return camelCase(ctx.group);
328
267
  };
329
268
  return {
330
269
  ...group,
@@ -487,7 +426,7 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
487
426
  if (hasCodec(node)) return true;
488
427
  if (node.type === "ref") {
489
428
  if (!node.ref) return false;
490
- const refName = ast.extractRefName(node.ref);
429
+ const refName = extractRefName(node.ref);
491
430
  if (refName) {
492
431
  if (seen.has(refName)) return false;
493
432
  seen.add(refName);
@@ -713,14 +652,14 @@ const printerZod = ast.definePrinter((options) => {
713
652
  },
714
653
  ref(node) {
715
654
  if (!node.name) return null;
716
- const refName = node.ref ? ast.extractRefName(node.ref) ?? node.name : node.name;
655
+ const refName = node.ref ? extractRefName(node.ref) ?? node.name : node.name;
717
656
  const useInputVariant = node.ref != null && this.options.direction === "input" && containsCodec(node);
718
657
  const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.resolveInputSchemaName(refName) ?? refName : this.options.resolver?.default(refName, "function") ?? refName : node.name;
719
658
  if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
720
659
  return resolvedName;
721
660
  },
722
661
  object(node) {
723
- const objectBase = `z.object({\n ${node.properties.map((prop) => {
662
+ const objectBase = `z.object(${buildObject(node.properties.map((prop) => {
724
663
  const { name: propName, schema } = prop;
725
664
  const meta = ast.syncSchemaRef(schema);
726
665
  const isNullable = meta.nullable;
@@ -744,9 +683,9 @@ const printerZod = ast.definePrinter((options) => {
744
683
  defaultValue: meta.default,
745
684
  description: descriptionToApply
746
685
  });
747
- if (hasSelfRef) return `get "${propName}"() { return ${value} }`;
748
- return `"${propName}": ${value}`;
749
- }).join(",\n ")}\n })`;
686
+ if (hasSelfRef) return `get ${objectKey(propName)}() { return ${value} }`;
687
+ return `${objectKey(propName)}: ${value}`;
688
+ }))})`;
750
689
  return (() => {
751
690
  if (node.additionalProperties && node.additionalProperties !== true) {
752
691
  const catchallType = this.transform(node.additionalProperties);
@@ -762,7 +701,7 @@ const printerZod = ast.definePrinter((options) => {
762
701
  return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
763
702
  },
764
703
  tuple(node) {
765
- return `z.tuple([${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ")}])`;
704
+ return `z.tuple(${buildList((node.items ?? []).map((item) => this.transform(item)).filter(Boolean))})`;
766
705
  },
767
706
  union(node) {
768
707
  const nodeMembers = node.members ?? [];
@@ -772,8 +711,8 @@ const printerZod = ast.definePrinter((options) => {
772
711
  }).filter(Boolean);
773
712
  if (members.length === 0) return "";
774
713
  if (members.length === 1) return members[0];
775
- if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, [${members.join(", ")}])`;
776
- return `z.union([${members.join(", ")}])`;
714
+ if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
715
+ return `z.union(${buildList(members)})`;
777
716
  },
778
717
  intersection(node) {
779
718
  const members = node.members ?? [];
@@ -892,13 +831,13 @@ const printerZodMini = ast.definePrinter((options) => {
892
831
  },
893
832
  ref(node) {
894
833
  if (!node.name) return null;
895
- const refName = node.ref ? ast.extractRefName(node.ref) ?? node.name : node.name;
834
+ const refName = node.ref ? extractRefName(node.ref) ?? node.name : node.name;
896
835
  const resolvedName = node.ref ? this.options.resolver?.default(refName, "function") ?? refName : node.name;
897
836
  if (node.ref && this.options.cyclicSchemas?.has(refName)) return `z.lazy(() => ${resolvedName})`;
898
837
  return resolvedName;
899
838
  },
900
839
  object(node) {
901
- return `z.object({\n ${node.properties.map((prop) => {
840
+ return `z.object(${buildObject(node.properties.map((prop) => {
902
841
  const { name: propName, schema } = prop;
903
842
  const meta = ast.syncSchemaRef(schema);
904
843
  const isNullable = meta.nullable;
@@ -919,16 +858,16 @@ const printerZodMini = ast.definePrinter((options) => {
919
858
  nullish: isNullish,
920
859
  defaultValue: meta.default
921
860
  });
922
- if (hasSelfRef) return `get "${propName}"() { return ${value} }`;
923
- return `"${propName}": ${value}`;
924
- }).join(",\n ")}\n })`;
861
+ if (hasSelfRef) return `get ${objectKey(propName)}() { return ${value} }`;
862
+ return `${objectKey(propName)}: ${value}`;
863
+ }))})`;
925
864
  },
926
865
  array(node) {
927
866
  const base = `z.array(${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ") || this.transform(ast.createSchema({ type: "unknown" }))})${lengthChecksMini(node)}`;
928
867
  return node.unique ? `${base}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })` : base;
929
868
  },
930
869
  tuple(node) {
931
- return `z.tuple([${(node.items ?? []).map((item) => this.transform(item)).filter(Boolean).join(", ")}])`;
870
+ return `z.tuple(${buildList((node.items ?? []).map((item) => this.transform(item)).filter(Boolean))})`;
932
871
  },
933
872
  union(node) {
934
873
  const nodeMembers = node.members ?? [];
@@ -938,8 +877,8 @@ const printerZodMini = ast.definePrinter((options) => {
938
877
  }).filter(Boolean);
939
878
  if (members.length === 0) return "";
940
879
  if (members.length === 1) return members[0];
941
- if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, [${members.join(", ")}])`;
942
- return `z.union([${members.join(", ")}])`;
880
+ if (node.discriminatorPropertyName && !nodeMembers.some((m) => m.type === "intersection")) return `z.discriminatedUnion(${stringify(node.discriminatorPropertyName)}, ${buildList(members)})`;
881
+ return `z.union(${buildList(members)})`;
943
882
  },
944
883
  intersection(node) {
945
884
  const members = node.members ?? [];
@@ -1037,17 +976,16 @@ function getMiniPrinter(resolver, params) {
1037
976
  */
1038
977
  const zodGenerator = defineGenerator({
1039
978
  name: "zod",
1040
- renderer: jsxRendererSync,
979
+ renderer: jsxRenderer,
1041
980
  schema(node, ctx) {
1042
981
  const { adapter, config, resolver, root } = ctx;
1043
982
  const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, printer } = ctx.options;
1044
983
  const dateType = adapter.options.dateType;
1045
984
  if (!node.name) return;
1046
- const mode = ctx.getMode(output);
1047
985
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1048
986
  const cyclicSchemas = new Set(ctx.meta.circularNames);
1049
987
  const hasCodec = !mini && containsCodec(node);
1050
- const codecRefNames = new Set(hasCodec ? ast.collect(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? ast.extractRefName(n.ref) ?? void 0 : void 0 }) : []);
988
+ const codecRefNames = new Set(hasCodec ? ast.collect(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? extractRefName(n.ref) ?? void 0 : void 0 }) : []);
1051
989
  const importEntries = adapter.getImports(node, (schemaName) => ({
1052
990
  name: resolver.resolveSchemaName(schemaName),
1053
991
  path: resolver.resolveFile({
@@ -1060,7 +998,7 @@ const zodGenerator = defineGenerator({
1060
998
  }).path
1061
999
  }));
1062
1000
  const inputImportEntries = hasCodec ? [...codecRefNames].map((schemaName) => ({
1063
- name: resolver.resolveInputSchemaName(schemaName),
1001
+ name: [resolver.resolveInputSchemaName(schemaName)],
1064
1002
  path: resolver.resolveFile({
1065
1003
  name: schemaName,
1066
1004
  extname: ".ts"
@@ -1129,7 +1067,7 @@ const zodGenerator = defineGenerator({
1129
1067
  path: importPath,
1130
1068
  isNameSpace: isZodImport
1131
1069
  }),
1132
- mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1070
+ imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1133
1071
  root: meta.file.path,
1134
1072
  path: imp.path,
1135
1073
  name: imp.name
@@ -1158,7 +1096,6 @@ const zodGenerator = defineGenerator({
1158
1096
  const { adapter, config, resolver, root } = ctx;
1159
1097
  const { output, coercion, guidType, mini, wrapOutput, inferred, importPath, group, paramsCasing, printer } = ctx.options;
1160
1098
  const dateType = adapter.options.dateType;
1161
- const mode = ctx.getMode(output);
1162
1099
  const isZodImport = ZOD_NAMESPACE_IMPORTS.has(importPath);
1163
1100
  const params = ast.caseParams(node.parameters, paramsCasing);
1164
1101
  const meta = { file: resolver.resolveFile({
@@ -1175,7 +1112,7 @@ const zodGenerator = defineGenerator({
1175
1112
  function renderSchemaEntry({ schema, name, keysToOmit, direction = "output" }) {
1176
1113
  if (!schema) return null;
1177
1114
  const inferTypeName = inferred ? resolver.resolveTypeName(name) : null;
1178
- const codecRefNames = direction === "input" && !mini ? new Set(ast.collect(schema, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? ast.extractRefName(n.ref) ?? void 0 : void 0 })) : null;
1115
+ const codecRefNames = direction === "input" && !mini ? new Set(ast.collect(schema, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? extractRefName(n.ref) ?? void 0 : void 0 })) : null;
1179
1116
  const imports = adapter.getImports(schema, (schemaName) => ({
1180
1117
  name: codecRefNames?.has(schemaName) ? resolver.resolveInputSchemaName(schemaName) : resolver.resolveSchemaName(schemaName),
1181
1118
  path: resolver.resolveFile({
@@ -1217,7 +1154,7 @@ const zodGenerator = defineGenerator({
1217
1154
  cyclicSchemas,
1218
1155
  nodes: printer?.nodes
1219
1156
  })[direction];
1220
- return /* @__PURE__ */ jsxs(Fragment, { children: [mode === "split" && imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1157
+ return /* @__PURE__ */ jsxs(Fragment, { children: [imports.map((imp) => /* @__PURE__ */ jsx(File.Import, {
1221
1158
  root: meta.file.path,
1222
1159
  path: imp.path,
1223
1160
  name: imp.name
@@ -1425,14 +1362,16 @@ const zodGenerator = defineGenerator({
1425
1362
  /**
1426
1363
  * Default resolver used by `@kubb/plugin-zod`. Decides the names and file
1427
1364
  * paths for every generated Zod schema. Schemas use camelCase with a
1428
- * `Schema` suffix (`listPetsSchema`); their inferred types use PascalCase.
1365
+ * `Schema` suffix (`listPetsSchema`); their inferred types use PascalCase
1366
+ * with a `SchemaType` suffix (`PetSchemaType`), so the value and the type
1367
+ * never share an identifier even when the schema name is all-uppercase.
1429
1368
  *
1430
1369
  * @example Resolve schema and type names
1431
1370
  * ```ts
1432
1371
  * import { resolverZod } from '@kubb/plugin-zod'
1433
1372
  *
1434
1373
  * resolverZod.default('list pets', 'function') // 'listPetsSchema'
1435
- * resolverZod.resolveSchemaTypeName('pet') // 'PetSchema'
1374
+ * resolverZod.resolveSchemaTypeName('pet') // 'PetSchemaType'
1436
1375
  * ```
1437
1376
  */
1438
1377
  const resolverZod = defineResolver(() => {
@@ -1440,17 +1379,14 @@ const resolverZod = defineResolver(() => {
1440
1379
  name: "default",
1441
1380
  pluginName: "plugin-zod",
1442
1381
  default(name, type) {
1443
- const resolved = camelCase(name, {
1444
- isFile: type === "file",
1445
- suffix: type ? "schema" : void 0
1446
- });
1447
- return type === "file" ? resolved : ensureValidVarName(resolved);
1382
+ if (type === "file") return toFilePath(name, (part) => camelCase(part, { suffix: "schema" }));
1383
+ return ensureValidVarName(camelCase(name, { suffix: type ? "schema" : void 0 }));
1448
1384
  },
1449
1385
  resolveSchemaName(name) {
1450
1386
  return ensureValidVarName(camelCase(name, { suffix: "schema" }));
1451
1387
  },
1452
1388
  resolveSchemaTypeName(name) {
1453
- return ensureValidVarName(pascalCase(name, { suffix: "schema" }));
1389
+ return ensureValidVarName(pascalCase(name, { suffix: "schema type" }));
1454
1390
  },
1455
1391
  resolveInputSchemaName(name) {
1456
1392
  return this.resolveSchemaName(`${name} input`);
@@ -1459,7 +1395,7 @@ const resolverZod = defineResolver(() => {
1459
1395
  return this.resolveSchemaTypeName(`${name} input`);
1460
1396
  },
1461
1397
  resolveTypeName(name) {
1462
- return ensureValidVarName(pascalCase(name));
1398
+ return ensureValidVarName(pascalCase(name, { suffix: "type" }));
1463
1399
  },
1464
1400
  resolvePathName(name, type) {
1465
1401
  return this.default(name, type);
@@ -1525,9 +1461,9 @@ const pluginZodName = "plugin-zod";
1525
1461
  const pluginZod = definePlugin((options) => {
1526
1462
  const { output = {
1527
1463
  path: "zod",
1528
- barrelType: "named"
1464
+ barrel: { type: "named" }
1529
1465
  }, group, exclude = [], include, override = [], typed = false, operations = false, mini = false, guidType = "uuid", importPath = mini ? "zod/mini" : "zod", coercion = false, inferred = false, wrapOutput = void 0, paramsCasing, printer, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
1530
- const groupConfig = createGroupConfig(group, { suffix: "Controller" });
1466
+ const groupConfig = createGroupConfig(group);
1531
1467
  return {
1532
1468
  name: pluginZodName,
1533
1469
  options,