@kubb/plugin-zod 5.9.0-canary.20261111T122006 → 5.9.1
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 +849 -816
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -4
- package/dist/index.d.ts +13 -4
- package/dist/index.js +850 -817
- package/dist/index.js.map +1 -1
- package/docs/guides/customization.md +36 -27
- package/docs/options.md +15 -8
- package/kubb-extension.json +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -5,143 +5,407 @@ Object.defineProperties(exports, {
|
|
|
5
5
|
let _kubb_kit = require("@kubb/kit");
|
|
6
6
|
let _kubb_renderer_jsx = require("@kubb/renderer-jsx");
|
|
7
7
|
let _kubb_renderer_jsx_jsx_runtime = require("@kubb/renderer-jsx/jsx-runtime");
|
|
8
|
-
// ../../internals/
|
|
8
|
+
// ../../internals/utils/src/reserved.ts
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
* JavaScript and Java reserved words.
|
|
11
|
+
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
12
|
+
*/
|
|
13
|
+
const reservedWords = /* @__PURE__ */ new Set([
|
|
14
|
+
"abstract",
|
|
15
|
+
"arguments",
|
|
16
|
+
"await",
|
|
17
|
+
"boolean",
|
|
18
|
+
"break",
|
|
19
|
+
"byte",
|
|
20
|
+
"case",
|
|
21
|
+
"catch",
|
|
22
|
+
"char",
|
|
23
|
+
"class",
|
|
24
|
+
"const",
|
|
25
|
+
"continue",
|
|
26
|
+
"debugger",
|
|
27
|
+
"default",
|
|
28
|
+
"delete",
|
|
29
|
+
"do",
|
|
30
|
+
"double",
|
|
31
|
+
"else",
|
|
32
|
+
"enum",
|
|
33
|
+
"eval",
|
|
34
|
+
"export",
|
|
35
|
+
"extends",
|
|
36
|
+
"false",
|
|
37
|
+
"final",
|
|
38
|
+
"finally",
|
|
39
|
+
"float",
|
|
40
|
+
"for",
|
|
41
|
+
"function",
|
|
42
|
+
"goto",
|
|
43
|
+
"if",
|
|
44
|
+
"implements",
|
|
45
|
+
"import",
|
|
46
|
+
"in",
|
|
47
|
+
"instanceof",
|
|
48
|
+
"int",
|
|
49
|
+
"interface",
|
|
50
|
+
"let",
|
|
51
|
+
"long",
|
|
52
|
+
"native",
|
|
53
|
+
"new",
|
|
54
|
+
"null",
|
|
55
|
+
"package",
|
|
56
|
+
"private",
|
|
57
|
+
"protected",
|
|
58
|
+
"public",
|
|
59
|
+
"return",
|
|
60
|
+
"short",
|
|
61
|
+
"static",
|
|
62
|
+
"super",
|
|
63
|
+
"switch",
|
|
64
|
+
"synchronized",
|
|
65
|
+
"this",
|
|
66
|
+
"throw",
|
|
67
|
+
"throws",
|
|
68
|
+
"transient",
|
|
69
|
+
"true",
|
|
70
|
+
"try",
|
|
71
|
+
"typeof",
|
|
72
|
+
"var",
|
|
73
|
+
"void",
|
|
74
|
+
"volatile",
|
|
75
|
+
"while",
|
|
76
|
+
"with",
|
|
77
|
+
"yield",
|
|
78
|
+
"Array",
|
|
79
|
+
"Date",
|
|
80
|
+
"hasOwnProperty",
|
|
81
|
+
"Infinity",
|
|
82
|
+
"isFinite",
|
|
83
|
+
"isNaN",
|
|
84
|
+
"isPrototypeOf",
|
|
85
|
+
"length",
|
|
86
|
+
"Math",
|
|
87
|
+
"name",
|
|
88
|
+
"NaN",
|
|
89
|
+
"Number",
|
|
90
|
+
"Object",
|
|
91
|
+
"prototype",
|
|
92
|
+
"String",
|
|
93
|
+
"toString",
|
|
94
|
+
"undefined",
|
|
95
|
+
"valueOf"
|
|
96
|
+
]);
|
|
97
|
+
/**
|
|
98
|
+
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
14
99
|
*
|
|
15
100
|
* @example
|
|
16
101
|
* ```ts
|
|
17
|
-
*
|
|
102
|
+
* isValidVarName('status') // true
|
|
103
|
+
* isValidVarName('class') // false (reserved word)
|
|
104
|
+
* isValidVarName('42foo') // false (starts with digit)
|
|
18
105
|
* ```
|
|
19
106
|
*/
|
|
20
|
-
function
|
|
21
|
-
return
|
|
22
|
-
|
|
23
|
-
extname,
|
|
24
|
-
tag: node.tags[0] ?? "default",
|
|
25
|
-
path: node.path
|
|
26
|
-
};
|
|
107
|
+
function isValidVarName(name) {
|
|
108
|
+
if (!name || reservedWords.has(name)) return false;
|
|
109
|
+
return isIdentifier(name);
|
|
27
110
|
}
|
|
28
111
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* operation. The plugin itself and every plugin that imports from it call this, so they all get
|
|
32
|
-
* the same path.
|
|
112
|
+
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
113
|
+
* otherwise prefixes it with `_` so the result is a valid identifier.
|
|
33
114
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* Only the file name changes. The declarations keep their names.
|
|
115
|
+
* Useful for sanitizing OpenAPI schema names or operation IDs that start with
|
|
116
|
+
* a digit (e.g. `409`, `504AccountCancel`) before using them as exported
|
|
117
|
+
* variable, type, or function names.
|
|
38
118
|
*
|
|
39
|
-
* @example
|
|
119
|
+
* @example
|
|
40
120
|
* ```ts
|
|
41
|
-
*
|
|
121
|
+
* ensureValidVarName('409') // '_409'
|
|
122
|
+
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
123
|
+
* ensureValidVarName('Pet') // 'Pet'
|
|
124
|
+
* ensureValidVarName('class') // '_class'
|
|
42
125
|
* ```
|
|
43
126
|
*/
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const location = {
|
|
48
|
-
root,
|
|
49
|
-
output,
|
|
50
|
-
group: options.group ?? void 0
|
|
51
|
-
};
|
|
52
|
-
return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () => {
|
|
53
|
-
const schemaPaths = memo(`${resolver.pluginName}:schemaFilePaths`, () => new Set((ctx.driver.inputNode?.schemas ?? []).flatMap((schema) => schema.name ? [resolver.file({
|
|
54
|
-
name: schema.name,
|
|
55
|
-
extname: ".ts",
|
|
56
|
-
...location
|
|
57
|
-
}).path.toLowerCase()] : [])));
|
|
58
|
-
let file = resolver.file({
|
|
59
|
-
...operationFileEntry(node, node.operationId),
|
|
60
|
-
...location
|
|
61
|
-
});
|
|
62
|
-
for (let name = `${node.operationId}Operation`; schemaPaths.has(file.path.toLowerCase()); name += "Operation") {
|
|
63
|
-
const next = resolver.file({
|
|
64
|
-
...operationFileEntry(node, name),
|
|
65
|
-
...location
|
|
66
|
-
});
|
|
67
|
-
if (next.path === file.path) break;
|
|
68
|
-
file = next;
|
|
69
|
-
}
|
|
70
|
-
return file;
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
function baseContentType(contentType) {
|
|
74
|
-
return contentType.split(";")[0].trim().toLowerCase();
|
|
127
|
+
function ensureValidVarName(name) {
|
|
128
|
+
if (!name || isValidVarName(name)) return name;
|
|
129
|
+
return `_${name}`;
|
|
75
130
|
}
|
|
76
131
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
132
|
+
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
133
|
+
*
|
|
134
|
+
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
135
|
+
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
136
|
+
* deciding whether an object key needs quoting.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* isIdentifier('name') // true
|
|
141
|
+
* isIdentifier('x-total')// false
|
|
142
|
+
* ```
|
|
79
143
|
*/
|
|
80
|
-
function
|
|
81
|
-
|
|
82
|
-
return Boolean(entry.stream) && baseType !== "text/event-stream" && !baseType.startsWith("multipart/");
|
|
83
|
-
}
|
|
84
|
-
function isJsonContentType(baseType) {
|
|
85
|
-
return baseType === "application/json" || baseType.endsWith("+json") || baseType === "text/json";
|
|
144
|
+
function isIdentifier(name) {
|
|
145
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
86
146
|
}
|
|
147
|
+
// ../../internals/utils/src/codegen.ts
|
|
87
148
|
/**
|
|
88
|
-
*
|
|
149
|
+
* Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
|
|
150
|
+
* level and closing the brace at column zero. Entries that are themselves multi-line objects indent
|
|
151
|
+
* cumulatively. Each entry ends with a trailing comma to match the formatter's multi-line style.
|
|
89
152
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* buildObject(['id: z.number()', 'name: z.string()'])
|
|
156
|
+
* // '{\n id: z.number(),\n name: z.string(),\n}'
|
|
157
|
+
* ```
|
|
94
158
|
*/
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (baseType === "text/event-stream" || isJsonLines(entry)) return "stream";
|
|
99
|
-
if (isJsonContentType(baseType)) return void 0;
|
|
100
|
-
if (entry.schema?.type === "blob") return "blob";
|
|
101
|
-
if (baseType.startsWith("text/")) return "text";
|
|
102
|
-
if (isBinaryContentType(baseType)) return "blob";
|
|
103
|
-
}
|
|
104
|
-
function isBinaryContentType(baseType) {
|
|
105
|
-
return baseType === "application/octet-stream" || baseType === "application/pdf" || /^(image|audio|video)\//.test(baseType);
|
|
159
|
+
function buildObject(entries) {
|
|
160
|
+
if (entries.length === 0) return "{}";
|
|
161
|
+
return `{\n${entries.map((entry) => `${_kubb_kit.text.indent({ text: entry })},`).join("\n")}\n}`;
|
|
106
162
|
}
|
|
107
163
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
164
|
+
* Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on
|
|
165
|
+
* one line when no item spans multiple lines, and otherwise puts each item on its own line, indented
|
|
166
|
+
* one level with a trailing comma and the closing bracket at column zero. Used for member lists such
|
|
167
|
+
* as `z.union([…])` and `z.array([…])`.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* buildList(['z.string()', 'z.number()'])
|
|
172
|
+
* // '[z.string(), z.number()]'
|
|
173
|
+
* ```
|
|
110
174
|
*/
|
|
111
|
-
function
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
117
|
-
if (parts.length === 0) return "Unknown";
|
|
118
|
-
return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
175
|
+
function buildList(items, brackets = ["[", "]"]) {
|
|
176
|
+
const [open, close] = brackets;
|
|
177
|
+
if (items.length === 0) return `${open}${close}`;
|
|
178
|
+
if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`;
|
|
179
|
+
return `${open}\n${items.map((item) => `${_kubb_kit.text.indent({ text: item })},`).join("\n")}\n${close}`;
|
|
119
180
|
}
|
|
120
181
|
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
182
|
+
* Emits a lazy getter for a circular-ref property position, `get name() { return body }`. The key
|
|
183
|
+
* is quoted only when it is not a valid identifier. Used by the string printers to defer evaluation
|
|
184
|
+
* of a recursive schema until first access.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* lazyGetter({ name: 'parent', body: 'z.lazy(() => Pet)' })
|
|
189
|
+
* // "get parent() { return z.lazy(() => Pet) }"
|
|
190
|
+
* ```
|
|
123
191
|
*/
|
|
124
|
-
function
|
|
125
|
-
|
|
126
|
-
return baseName + suffix;
|
|
192
|
+
function lazyGetter({ name, body }) {
|
|
193
|
+
return `get ${objectKey(name)}() { return ${body} }`;
|
|
127
194
|
}
|
|
128
195
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
196
|
+
* An object key, quoted only when it is not identifier-shaped. Reserved words such as `class` stay bare.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* objectKey('x-total') // "'x-total'"
|
|
201
|
+
* ```
|
|
133
202
|
*/
|
|
134
|
-
function
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
203
|
+
function objectKey(name) {
|
|
204
|
+
return isIdentifier(name) ? name : _kubb_kit.text.quote(name);
|
|
205
|
+
}
|
|
206
|
+
// ../../internals/utils/src/fs.ts
|
|
207
|
+
/**
|
|
208
|
+
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
209
|
+
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
210
|
+
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
211
|
+
*
|
|
212
|
+
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
213
|
+
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
214
|
+
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
215
|
+
* absolute path, letting generated files escape the configured output directory.
|
|
216
|
+
*
|
|
217
|
+
* @example Nested path from a dotted name
|
|
218
|
+
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
219
|
+
*
|
|
220
|
+
* @example PascalCase the final segment
|
|
221
|
+
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
222
|
+
*
|
|
223
|
+
* @example Suffix applied to the final segment only
|
|
224
|
+
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
225
|
+
*/
|
|
226
|
+
function toFilePath(name, caseLast = _kubb_kit.casing.camel) {
|
|
227
|
+
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
228
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : _kubb_kit.casing.camel(part)).filter(Boolean).join("/");
|
|
229
|
+
}
|
|
230
|
+
// ../../internals/utils/src/strings.ts
|
|
231
|
+
const NEEDS_UNICODE = /(?<!\\)(?:\\\\)*\\[pPu]\{|[\u{10000}-\u{10FFFF}]/u;
|
|
232
|
+
const KEPT_ESCAPE = /[A-Za-z0-9^$\\.*+?()[\]{}|/]/;
|
|
233
|
+
/**
|
|
234
|
+
* Drops the backslash from escapes that the `u` flag rejects: an escaped punctuation character that is
|
|
235
|
+
* not a syntax character, and `\-` outside a class. Both match the same character without the backslash.
|
|
236
|
+
*/
|
|
237
|
+
function dropIdentityEscapes(pattern) {
|
|
238
|
+
let inClass = false;
|
|
239
|
+
return pattern.replace(/\\(.)|[[\]]/gs, (match, escaped) => {
|
|
240
|
+
if (escaped === void 0) {
|
|
241
|
+
inClass = match === "[";
|
|
242
|
+
return match;
|
|
243
|
+
}
|
|
244
|
+
return KEPT_ESCAPE.test(escaped) || escaped === "-" && inClass ? match : escaped;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Builds the `RegExp` for a pattern, adding the `u` flag when it uses `\p{...}`, `\P{...}` or `\u{...}`, or
|
|
249
|
+
* holds a character outside the BMP. A pattern that is not valid under `u` keeps the flags it came with.
|
|
250
|
+
*/
|
|
251
|
+
function toRegExp(pattern, flags) {
|
|
252
|
+
if (flags?.includes("u") || !NEEDS_UNICODE.test(pattern)) return new RegExp(pattern, flags);
|
|
253
|
+
try {
|
|
254
|
+
return new RegExp(dropIdentityEscapes(pattern), `${flags ?? ""}u`);
|
|
255
|
+
} catch {
|
|
256
|
+
return new RegExp(pattern, flags);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
|
|
261
|
+
* Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
|
|
262
|
+
* Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* ```ts
|
|
266
|
+
* toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")'
|
|
267
|
+
* toRegExpString('^(?im)foo', null) // '/^foo/im'
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
function toRegExpString(pattern, func = "RegExp") {
|
|
271
|
+
const raw = _kubb_kit.text.unquote(pattern);
|
|
272
|
+
const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
|
|
273
|
+
const replacementTarget = match?.[1] ?? "";
|
|
274
|
+
const matchedFlags = match?.[2];
|
|
275
|
+
const { source, flags } = toRegExp(raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""), matchedFlags);
|
|
276
|
+
if (func === null) return `/${source}/${flags}`;
|
|
277
|
+
return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
|
|
278
|
+
}
|
|
279
|
+
// ../../internals/shared/src/operation.ts
|
|
280
|
+
/**
|
|
281
|
+
* Builds the `ResolverFileParams` every operation generator passes to
|
|
282
|
+
* `resolver.file`: a file named `name`, tagged by the operation's first
|
|
283
|
+
* tag (or `'default'`), at the operation's path. Centralizes the entry object
|
|
284
|
+
* that was repeated at dozens of call sites across the client and query plugins.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```ts
|
|
288
|
+
* resolver.file(operationFileEntry(node, node.operationId), { root, output, group })
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
function operationFileEntry(node, name, extname = ".ts") {
|
|
292
|
+
return {
|
|
293
|
+
name,
|
|
294
|
+
extname,
|
|
295
|
+
tag: node.tags[0] ?? "default",
|
|
296
|
+
path: node.path
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Resolves the file a schema-emitting plugin (`plugin-ts`, `plugin-zod`, `plugin-faker`) writes
|
|
301
|
+
* `node` to, cached in `ctx.memo` under the resolver's plugin name and the
|
|
302
|
+
* operation. The plugin itself and every plugin that imports from it call this, so they all get
|
|
303
|
+
* the same path.
|
|
304
|
+
*
|
|
305
|
+
* When that path matches the file of a component schema in `ctx.driver.inputNode`, ignoring case, the file name
|
|
306
|
+
* gets an `Operation` suffix: operation `point` goes to `PointOperation.ts` next to schema `Point.ts`.
|
|
307
|
+
* Otherwise the two merge into one file, or overwrite each other on a case-insensitive file system.
|
|
308
|
+
* Only the file name changes. The declarations keep their names.
|
|
309
|
+
*
|
|
310
|
+
* @example Resolve `plugin-ts`'s file for the current operation
|
|
311
|
+
* ```ts
|
|
312
|
+
* const fileTs = resolveOperationFile({ ctx, node, resolver: tsResolver, root, output })
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
function resolveOperationFile(options) {
|
|
316
|
+
const { ctx, node, resolver, root, output } = options;
|
|
317
|
+
const { memo } = ctx;
|
|
318
|
+
const location = {
|
|
319
|
+
root,
|
|
320
|
+
output,
|
|
321
|
+
group: options.group ?? void 0
|
|
322
|
+
};
|
|
323
|
+
return memo(`${resolver.pluginName}:operationFile:${node.operationId}`, () => {
|
|
324
|
+
const schemaPaths = memo(`${resolver.pluginName}:schemaFilePaths`, () => new Set((ctx.driver.inputNode?.schemas ?? []).flatMap((schema) => schema.name ? [resolver.file({
|
|
325
|
+
name: schema.name,
|
|
326
|
+
extname: ".ts",
|
|
327
|
+
...location
|
|
328
|
+
}).path.toLowerCase()] : [])));
|
|
329
|
+
let file = resolver.file({
|
|
330
|
+
...operationFileEntry(node, node.operationId),
|
|
331
|
+
...location
|
|
332
|
+
});
|
|
333
|
+
for (let name = `${node.operationId}Operation`; schemaPaths.has(file.path.toLowerCase()); name += "Operation") {
|
|
334
|
+
const next = resolver.file({
|
|
335
|
+
...operationFileEntry(node, name),
|
|
336
|
+
...location
|
|
337
|
+
});
|
|
338
|
+
if (next.path === file.path) break;
|
|
339
|
+
file = next;
|
|
340
|
+
}
|
|
341
|
+
return file;
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* How a content entry is framed as a stream: `'events'` for Server-Sent Events, `'lines'` for JSON Lines.
|
|
346
|
+
*/
|
|
347
|
+
function getStreamFraming(entry) {
|
|
348
|
+
if (_kubb_kit.ast.mediaType.getBase(entry) === "text/event-stream") return "events";
|
|
349
|
+
return entry.stream && _kubb_kit.ast.mediaType.isStream(entry) ? "lines" : void 0;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Parser for one response content entry.
|
|
353
|
+
*
|
|
354
|
+
* JSON stays unset so the runtime detects it. `text/event-stream` and JSON Lines are streams. A binary schema
|
|
355
|
+
* (`format: binary` / `contentMediaType`) is a blob even when the media type is not a well-known
|
|
356
|
+
* binary type. Other `text/*` is text, and `application/octet-stream`, `application/pdf`,
|
|
357
|
+
* `image/*`, `audio/*`, and `video/*` are blobs.
|
|
358
|
+
*/
|
|
359
|
+
function responseTypeForContent(entry) {
|
|
360
|
+
const baseType = _kubb_kit.ast.mediaType.getBase(entry);
|
|
361
|
+
if (!baseType) return void 0;
|
|
362
|
+
if (getStreamFraming(entry)) return "stream";
|
|
363
|
+
if (_kubb_kit.ast.mediaType.isJson(baseType)) return void 0;
|
|
364
|
+
if (entry.schema?.type === "blob") return "blob";
|
|
365
|
+
if (baseType.startsWith("text/")) return "text";
|
|
366
|
+
if (isBinaryContentType(baseType)) return "blob";
|
|
367
|
+
}
|
|
368
|
+
function isBinaryContentType(baseType) {
|
|
369
|
+
return baseType === "application/octet-stream" || baseType === "application/pdf" || /^(image|audio|video)\//.test(baseType);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
373
|
+
* (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
|
|
374
|
+
*/
|
|
375
|
+
function getContentTypeSuffix(contentType) {
|
|
376
|
+
const baseType = contentType.split(";")[0].trim();
|
|
377
|
+
if (baseType === "application/json") return "Json";
|
|
378
|
+
if (baseType === "multipart/form-data") return "FormData";
|
|
379
|
+
if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
|
|
380
|
+
const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
381
|
+
if (parts.length === 0) return "Unknown";
|
|
382
|
+
return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
|
|
386
|
+
* (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
|
|
387
|
+
*/
|
|
388
|
+
function getPerContentTypeName(baseName, suffix) {
|
|
389
|
+
if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
|
|
390
|
+
return baseName + suffix;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Returns the entry with the schema of the value the client returns: `string` for a body read as text, such as `Pet` on
|
|
394
|
+
* `application/xml`, and `blob` for `image/*`, `audio/*`, `video/*`, PDF, and octet-stream. A binary schema elsewhere is a `Blob`
|
|
395
|
+
* only through `parseAs: 'blob'`, which needs every entry in `entries` binary. JSON, vendor (`application/vnd.*`), stream,
|
|
396
|
+
* schemaless, and wildcard entries keep their schema. `entries` is the response's full list of content types.
|
|
397
|
+
*/
|
|
398
|
+
function toResponseContent(entry, entries = [entry]) {
|
|
399
|
+
const { contentType, schema } = entry;
|
|
400
|
+
if (!schema || entry.stream) return entry;
|
|
401
|
+
const baseType = _kubb_kit.ast.mediaType.getBase(contentType);
|
|
402
|
+
const resolved = _kubb_kit.ast.ref.getSchema(schema);
|
|
403
|
+
if (isBinaryContentType(baseType)) return resolved.type === "blob" ? entry : {
|
|
404
|
+
...entry,
|
|
405
|
+
schema: _kubb_kit.ast.factory.createSchema({ type: "blob" }),
|
|
406
|
+
keysToOmit: null
|
|
407
|
+
};
|
|
408
|
+
const isPlainMediaType = Boolean(baseType) && !_kubb_kit.ast.mediaType.isJson(baseType) && !baseType.includes("*");
|
|
145
409
|
if (resolved.type === "blob") return isPlainMediaType && !entries.every((item) => item.schema?.type === "blob") ? {
|
|
146
410
|
...entry,
|
|
147
411
|
schema: _kubb_kit.ast.factory.createSchema({ type: "string" }),
|
|
@@ -184,50 +448,6 @@ function resolveContentTypeVariants(entries, baseName) {
|
|
|
184
448
|
};
|
|
185
449
|
});
|
|
186
450
|
}
|
|
187
|
-
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
188
|
-
/**
|
|
189
|
-
* An OpenAPI 3.2 `querystring` parameter is the whole query string, so a form-encoded object becomes one query parameter
|
|
190
|
-
* per property, typed and serialized like any other.
|
|
191
|
-
* Another content type, such as JSON, stays one parameter named after it, and the runtime sends its value as the whole query string.
|
|
192
|
-
*/
|
|
193
|
-
function spreadQuerystring(param) {
|
|
194
|
-
const schema = param.schema.type === "ref" ? param.schema.schema : param.schema;
|
|
195
|
-
const formEncoded = !param.contentType || param.contentType.split(";")[0].trim().toLowerCase() === "application/x-www-form-urlencoded";
|
|
196
|
-
if (schema?.type !== "object" || !formEncoded) return [param];
|
|
197
|
-
return schema.properties.map((property) => _kubb_kit.ast.factory.createParameter({
|
|
198
|
-
name: property.name,
|
|
199
|
-
in: "query",
|
|
200
|
-
schema: property.schema,
|
|
201
|
-
required: param.required && property.required
|
|
202
|
-
}));
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
206
|
-
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
207
|
-
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
208
|
-
* same parameters once per plugin.
|
|
209
|
-
*/
|
|
210
|
-
function getOperationParameters(node) {
|
|
211
|
-
const cached = operationParameterGroupsByNode.get(node);
|
|
212
|
-
if (cached) return cached;
|
|
213
|
-
const dedupe = (params) => {
|
|
214
|
-
const seen = /* @__PURE__ */ new Set();
|
|
215
|
-
return params.filter((param) => {
|
|
216
|
-
if (seen.has(param.name)) return false;
|
|
217
|
-
seen.add(param.name);
|
|
218
|
-
return true;
|
|
219
|
-
});
|
|
220
|
-
};
|
|
221
|
-
const group = (location) => dedupe(node.parameters.filter((param) => param.in === location));
|
|
222
|
-
const groups = {
|
|
223
|
-
path: group("path"),
|
|
224
|
-
query: dedupe([...group("query"), ...group("querystring").flatMap(spreadQuerystring)]),
|
|
225
|
-
header: group("header"),
|
|
226
|
-
cookie: group("cookie")
|
|
227
|
-
};
|
|
228
|
-
operationParameterGroupsByNode.set(node, groups);
|
|
229
|
-
return groups;
|
|
230
|
-
}
|
|
231
451
|
/**
|
|
232
452
|
* Whether the operation declares more than one request media type with a schema, so a caller must pick one on `contentType`.
|
|
233
453
|
*/
|
|
@@ -243,8 +463,8 @@ function hasRequestContentTypeChoice(node) {
|
|
|
243
463
|
* than a record.
|
|
244
464
|
*/
|
|
245
465
|
function buildOptionsSchema(node, resolver, { pairContentTypes = false } = {}) {
|
|
246
|
-
const { path, query, header, cookie } =
|
|
247
|
-
const hasBody = Boolean(
|
|
466
|
+
const { path, query, header, cookie } = _kubb_kit.ast.http.groupParameters(node);
|
|
467
|
+
const hasBody = Boolean(_kubb_kit.ast.http.requestBody.getSchema(node));
|
|
248
468
|
const createNever = () => _kubb_kit.ast.factory.createSchema({
|
|
249
469
|
type: "never",
|
|
250
470
|
primitive: void 0,
|
|
@@ -335,9 +555,10 @@ function buildOptionsSchema(node, resolver, { pairContentTypes = false } = {}) {
|
|
|
335
555
|
* The schema a status occupies in the `<Name>Responses` record. A status that documents several
|
|
336
556
|
* content types becomes a `{ contentType; data }` union so the runtime can surface the negotiated type
|
|
337
557
|
* on `result.parsed`, while the standalone `<Name>StatusNNN` alias stays the plain body union that the
|
|
338
|
-
* query hooks and `result.data` use.
|
|
558
|
+
* query hooks and `result.data` use. With `streamData`, the stream variant of a 2xx status holds that schema, since the
|
|
559
|
+
* client returns its body unread.
|
|
339
560
|
*/
|
|
340
|
-
function buildResponseRecordEntry(node, res, resolver) {
|
|
561
|
+
function buildResponseRecordEntry(node, res, resolver, streamData) {
|
|
341
562
|
const statusName = resolver.response.status(node, res.statusCode);
|
|
342
563
|
const variants = (res.content ?? []).filter((entry) => entry.schema);
|
|
343
564
|
if (variants.length <= 1) return _kubb_kit.ast.factory.createSchema({
|
|
@@ -354,12 +575,12 @@ function buildResponseRecordEntry(node, res, resolver) {
|
|
|
354
575
|
required: true,
|
|
355
576
|
schema: _kubb_kit.ast.factory.createSchema({
|
|
356
577
|
type: "enum",
|
|
357
|
-
enumValues: [
|
|
578
|
+
enumValues: [_kubb_kit.ast.mediaType.getBase(variant)]
|
|
358
579
|
})
|
|
359
580
|
}), _kubb_kit.ast.factory.createProperty({
|
|
360
581
|
name: "data",
|
|
361
582
|
required: true,
|
|
362
|
-
schema: _kubb_kit.ast.factory.createSchema({
|
|
583
|
+
schema: streamData && _kubb_kit.ast.http.status.isSuccess(res) && _kubb_kit.ast.mediaType.isStream(variant) ? streamData : _kubb_kit.ast.factory.createSchema({
|
|
363
584
|
type: "ref",
|
|
364
585
|
name: variant.name
|
|
365
586
|
})
|
|
@@ -375,29 +596,20 @@ function buildResponseRecordEntry(node, res, resolver) {
|
|
|
375
596
|
* Always emits the keyed record, even when an operation declares no responses. An operation with no
|
|
376
597
|
* responses renders as an empty object, which keeps every consumer's import (for example the axios
|
|
377
598
|
* SDK's `RequestResult<XResponses>`) resolvable instead of pointing at a missing export.
|
|
599
|
+
*
|
|
600
|
+
* `streamData` is the type of a stream variant's `data`, such as a `ReadableStream<Uint8Array>` reference.
|
|
378
601
|
*/
|
|
379
|
-
function buildResponses(node, resolver) {
|
|
602
|
+
function buildResponses(node, resolver, { streamData } = {}) {
|
|
380
603
|
return _kubb_kit.ast.factory.createSchema({
|
|
381
604
|
type: "object",
|
|
382
605
|
primitive: "object",
|
|
383
606
|
properties: node.responses.map((res) => _kubb_kit.ast.factory.createProperty({
|
|
384
607
|
name: String(res.statusCode),
|
|
385
608
|
required: true,
|
|
386
|
-
schema: buildResponseRecordEntry(node, res, resolver)
|
|
609
|
+
schema: buildResponseRecordEntry(node, res, resolver, streamData)
|
|
387
610
|
}))
|
|
388
611
|
});
|
|
389
612
|
}
|
|
390
|
-
function getStatusCodeNumber(statusCode) {
|
|
391
|
-
const code = Number(statusCode);
|
|
392
|
-
return Number.isNaN(code) ? null : code;
|
|
393
|
-
}
|
|
394
|
-
function isSuccessStatusCode(statusCode) {
|
|
395
|
-
const code = getStatusCodeNumber(statusCode);
|
|
396
|
-
return code !== null && code >= 200 && code < 300;
|
|
397
|
-
}
|
|
398
|
-
function getSuccessResponses(responses) {
|
|
399
|
-
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
400
|
-
}
|
|
401
613
|
// ../../internals/shared/src/adapter.ts
|
|
402
614
|
/**
|
|
403
615
|
* Narrows the generic `Adapter` from a generator context to the OpenAPI adapter,
|
|
@@ -411,344 +623,15 @@ function getSuccessResponses(responses) {
|
|
|
411
623
|
* const { dateType } = getOasAdapter(ctx.adapter).options
|
|
412
624
|
* ```
|
|
413
625
|
*/
|
|
414
|
-
function getOasAdapter(adapter) {
|
|
415
|
-
if (adapter.name !== "oas") throw new _kubb_kit.Diagnostics.Error({
|
|
416
|
-
code: _kubb_kit.Diagnostics.code.adapterRequired,
|
|
417
|
-
severity: "error",
|
|
418
|
-
message: `Expected the OpenAPI adapter (adapterOas), but received "${adapter.name}".`,
|
|
419
|
-
help: "Set `adapter: adapterOas()` in kubb.config.ts.",
|
|
420
|
-
location: { kind: "config" }
|
|
421
|
-
});
|
|
422
|
-
return adapter;
|
|
423
|
-
}
|
|
424
|
-
// ../../internals/utils/src/reserved.ts
|
|
425
|
-
/**
|
|
426
|
-
* JavaScript and Java reserved words.
|
|
427
|
-
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
428
|
-
*/
|
|
429
|
-
const reservedWords = /* @__PURE__ */ new Set([
|
|
430
|
-
"abstract",
|
|
431
|
-
"arguments",
|
|
432
|
-
"await",
|
|
433
|
-
"boolean",
|
|
434
|
-
"break",
|
|
435
|
-
"byte",
|
|
436
|
-
"case",
|
|
437
|
-
"catch",
|
|
438
|
-
"char",
|
|
439
|
-
"class",
|
|
440
|
-
"const",
|
|
441
|
-
"continue",
|
|
442
|
-
"debugger",
|
|
443
|
-
"default",
|
|
444
|
-
"delete",
|
|
445
|
-
"do",
|
|
446
|
-
"double",
|
|
447
|
-
"else",
|
|
448
|
-
"enum",
|
|
449
|
-
"eval",
|
|
450
|
-
"export",
|
|
451
|
-
"extends",
|
|
452
|
-
"false",
|
|
453
|
-
"final",
|
|
454
|
-
"finally",
|
|
455
|
-
"float",
|
|
456
|
-
"for",
|
|
457
|
-
"function",
|
|
458
|
-
"goto",
|
|
459
|
-
"if",
|
|
460
|
-
"implements",
|
|
461
|
-
"import",
|
|
462
|
-
"in",
|
|
463
|
-
"instanceof",
|
|
464
|
-
"int",
|
|
465
|
-
"interface",
|
|
466
|
-
"let",
|
|
467
|
-
"long",
|
|
468
|
-
"native",
|
|
469
|
-
"new",
|
|
470
|
-
"null",
|
|
471
|
-
"package",
|
|
472
|
-
"private",
|
|
473
|
-
"protected",
|
|
474
|
-
"public",
|
|
475
|
-
"return",
|
|
476
|
-
"short",
|
|
477
|
-
"static",
|
|
478
|
-
"super",
|
|
479
|
-
"switch",
|
|
480
|
-
"synchronized",
|
|
481
|
-
"this",
|
|
482
|
-
"throw",
|
|
483
|
-
"throws",
|
|
484
|
-
"transient",
|
|
485
|
-
"true",
|
|
486
|
-
"try",
|
|
487
|
-
"typeof",
|
|
488
|
-
"var",
|
|
489
|
-
"void",
|
|
490
|
-
"volatile",
|
|
491
|
-
"while",
|
|
492
|
-
"with",
|
|
493
|
-
"yield",
|
|
494
|
-
"Array",
|
|
495
|
-
"Date",
|
|
496
|
-
"hasOwnProperty",
|
|
497
|
-
"Infinity",
|
|
498
|
-
"isFinite",
|
|
499
|
-
"isNaN",
|
|
500
|
-
"isPrototypeOf",
|
|
501
|
-
"length",
|
|
502
|
-
"Math",
|
|
503
|
-
"name",
|
|
504
|
-
"NaN",
|
|
505
|
-
"Number",
|
|
506
|
-
"Object",
|
|
507
|
-
"prototype",
|
|
508
|
-
"String",
|
|
509
|
-
"toString",
|
|
510
|
-
"undefined",
|
|
511
|
-
"valueOf"
|
|
512
|
-
]);
|
|
513
|
-
/**
|
|
514
|
-
* Returns `true` when `name` is a syntactically valid JavaScript variable name.
|
|
515
|
-
*
|
|
516
|
-
* @example
|
|
517
|
-
* ```ts
|
|
518
|
-
* isValidVarName('status') // true
|
|
519
|
-
* isValidVarName('class') // false (reserved word)
|
|
520
|
-
* isValidVarName('42foo') // false (starts with digit)
|
|
521
|
-
* ```
|
|
522
|
-
*/
|
|
523
|
-
function isValidVarName(name) {
|
|
524
|
-
if (!name || reservedWords.has(name)) return false;
|
|
525
|
-
return isIdentifier(name);
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
* Returns `name` when it's a syntactically valid JavaScript variable name,
|
|
529
|
-
* otherwise prefixes it with `_` so the result is a valid identifier.
|
|
530
|
-
*
|
|
531
|
-
* Useful for sanitizing OpenAPI schema names or operation IDs that start with
|
|
532
|
-
* a digit (e.g. `409`, `504AccountCancel`) before using them as exported
|
|
533
|
-
* variable, type, or function names.
|
|
534
|
-
*
|
|
535
|
-
* @example
|
|
536
|
-
* ```ts
|
|
537
|
-
* ensureValidVarName('409') // '_409'
|
|
538
|
-
* ensureValidVarName('504AccountCancel') // '_504AccountCancel'
|
|
539
|
-
* ensureValidVarName('Pet') // 'Pet'
|
|
540
|
-
* ensureValidVarName('class') // '_class'
|
|
541
|
-
* ```
|
|
542
|
-
*/
|
|
543
|
-
function ensureValidVarName(name) {
|
|
544
|
-
if (!name || isValidVarName(name)) return name;
|
|
545
|
-
return `_${name}`;
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
|
|
549
|
-
*
|
|
550
|
-
* Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
|
|
551
|
-
* even though they are not valid variable names, so use this (not {@link isValidVarName}) when
|
|
552
|
-
* deciding whether an object key needs quoting.
|
|
553
|
-
*
|
|
554
|
-
* @example
|
|
555
|
-
* ```ts
|
|
556
|
-
* isIdentifier('name') // true
|
|
557
|
-
* isIdentifier('x-total')// false
|
|
558
|
-
* ```
|
|
559
|
-
*/
|
|
560
|
-
function isIdentifier(name) {
|
|
561
|
-
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
562
|
-
}
|
|
563
|
-
// ../../internals/utils/src/strings.ts
|
|
564
|
-
/**
|
|
565
|
-
* Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
|
|
566
|
-
* any backslash or single quote in the content.
|
|
567
|
-
*
|
|
568
|
-
* @example
|
|
569
|
-
* ```ts
|
|
570
|
-
* singleQuote('foo') // "'foo'"
|
|
571
|
-
* singleQuote("o'clock") // "'o\\'clock'"
|
|
572
|
-
* ```
|
|
573
|
-
*/
|
|
574
|
-
function singleQuote(value) {
|
|
575
|
-
if (value === void 0 || value === null) return "''";
|
|
576
|
-
return `'${String(value).replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Strips a single matching pair of `"..."`, `'...'`, or `` `...` `` from both ends of `text`.
|
|
580
|
-
* Returns the string unchanged when no balanced quote pair is found.
|
|
581
|
-
*
|
|
582
|
-
* @example
|
|
583
|
-
* ```ts
|
|
584
|
-
* trimQuotes('"hello"') // 'hello'
|
|
585
|
-
* trimQuotes('hello') // 'hello'
|
|
586
|
-
* ```
|
|
587
|
-
*/
|
|
588
|
-
function trimQuotes(text) {
|
|
589
|
-
if (text.length >= 2) {
|
|
590
|
-
const first = text[0];
|
|
591
|
-
const last = text[text.length - 1];
|
|
592
|
-
if (first === "\"" && last === "\"" || first === "'" && last === "'" || first === "`" && last === "`") return text.slice(1, -1);
|
|
593
|
-
}
|
|
594
|
-
return text;
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* Serializes a primitive to a single-quoted string literal, stripping any surrounding quotes first.
|
|
598
|
-
*
|
|
599
|
-
* Escaping runs through `JSON.stringify`, then the result switches to single quotes so the generated
|
|
600
|
-
* code matches the repo style without a formatter.
|
|
601
|
-
*
|
|
602
|
-
* @example
|
|
603
|
-
* ```ts
|
|
604
|
-
* stringify('hello') // "'hello'"
|
|
605
|
-
* stringify('"hello"') // "'hello'"
|
|
606
|
-
* ```
|
|
607
|
-
*/
|
|
608
|
-
function stringify(value) {
|
|
609
|
-
if (value === void 0 || value === null) return "''";
|
|
610
|
-
return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
|
|
611
|
-
}
|
|
612
|
-
const NEEDS_UNICODE = /(?<!\\)(?:\\\\)*\\[pPu]\{|[\u{10000}-\u{10FFFF}]/u;
|
|
613
|
-
const KEPT_ESCAPE = /[A-Za-z0-9^$\\.*+?()[\]{}|/]/;
|
|
614
|
-
/**
|
|
615
|
-
* Drops the backslash from escapes that the `u` flag rejects: an escaped punctuation character that is
|
|
616
|
-
* not a syntax character, and `\-` outside a class. Both match the same character without the backslash.
|
|
617
|
-
*/
|
|
618
|
-
function dropIdentityEscapes(pattern) {
|
|
619
|
-
let inClass = false;
|
|
620
|
-
return pattern.replace(/\\(.)|[[\]]/gs, (match, escaped) => {
|
|
621
|
-
if (escaped === void 0) {
|
|
622
|
-
inClass = match === "[";
|
|
623
|
-
return match;
|
|
624
|
-
}
|
|
625
|
-
return KEPT_ESCAPE.test(escaped) || escaped === "-" && inClass ? match : escaped;
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Builds the `RegExp` for a pattern, adding the `u` flag when it uses `\p{...}`, `\P{...}` or `\u{...}`, or
|
|
630
|
-
* holds a character outside the BMP. A pattern that is not valid under `u` keeps the flags it came with.
|
|
631
|
-
*/
|
|
632
|
-
function toRegExp(pattern, flags) {
|
|
633
|
-
if (flags?.includes("u") || !NEEDS_UNICODE.test(pattern)) return new RegExp(pattern, flags);
|
|
634
|
-
try {
|
|
635
|
-
return new RegExp(dropIdentityEscapes(pattern), `${flags ?? ""}u`);
|
|
636
|
-
} catch {
|
|
637
|
-
return new RegExp(pattern, flags);
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
|
|
642
|
-
* Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
|
|
643
|
-
* Pass `null` as the second argument to emit a `/pattern/flags` literal instead.
|
|
644
|
-
*
|
|
645
|
-
* @example
|
|
646
|
-
* ```ts
|
|
647
|
-
* toRegExpString('^(?im)foo') // 'new RegExp("^foo", "im")'
|
|
648
|
-
* toRegExpString('^(?im)foo', null) // '/^foo/im'
|
|
649
|
-
* ```
|
|
650
|
-
*/
|
|
651
|
-
function toRegExpString(text, func = "RegExp") {
|
|
652
|
-
const raw = trimQuotes(text);
|
|
653
|
-
const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
|
|
654
|
-
const replacementTarget = match?.[1] ?? "";
|
|
655
|
-
const matchedFlags = match?.[2];
|
|
656
|
-
const { source, flags } = toRegExp(raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""), matchedFlags);
|
|
657
|
-
if (func === null) return `/${source}/${flags}`;
|
|
658
|
-
return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
|
|
659
|
-
}
|
|
660
|
-
// ../../internals/utils/src/codegen.ts
|
|
661
|
-
const INDENT = " ";
|
|
662
|
-
/**
|
|
663
|
-
* Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
|
|
664
|
-
*/
|
|
665
|
-
function indentLines(text) {
|
|
666
|
-
if (!text) return "";
|
|
667
|
-
return text.split("\n").map((line) => line.trim() ? `${INDENT}${line}` : "").join("\n");
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Renders an object key, quoting it with single quotes only when it is not a valid identifier.
|
|
671
|
-
* Reserved words and globals (`name`, `class`, …) are valid bare keys and stay unquoted.
|
|
672
|
-
*
|
|
673
|
-
* @example
|
|
674
|
-
* ```ts
|
|
675
|
-
* objectKey('name') // 'name'
|
|
676
|
-
* objectKey('x-total') // "'x-total'"
|
|
677
|
-
* ```
|
|
678
|
-
*/
|
|
679
|
-
function objectKey(name) {
|
|
680
|
-
return isIdentifier(name) ? name : singleQuote(name);
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Assembles a multi-line object literal from already-rendered `entries`, indenting each entry one
|
|
684
|
-
* level and closing the brace at column zero. Entries that are themselves multi-line objects indent
|
|
685
|
-
* cumulatively. Each entry ends with a trailing comma to match the formatter's multi-line style.
|
|
686
|
-
*
|
|
687
|
-
* @example
|
|
688
|
-
* ```ts
|
|
689
|
-
* buildObject(['id: z.number()', 'name: z.string()'])
|
|
690
|
-
* // '{\n id: z.number(),\n name: z.string(),\n}'
|
|
691
|
-
* ```
|
|
692
|
-
*/
|
|
693
|
-
function buildObject(entries) {
|
|
694
|
-
if (entries.length === 0) return "{}";
|
|
695
|
-
return `{\n${entries.map((entry) => `${indentLines(entry)},`).join("\n")}\n}`;
|
|
696
|
-
}
|
|
697
|
-
/**
|
|
698
|
-
* Assembles a bracketed list (array by default) from already-rendered `items`. Keeps everything on
|
|
699
|
-
* one line when no item spans multiple lines, and otherwise puts each item on its own line, indented
|
|
700
|
-
* one level with a trailing comma and the closing bracket at column zero. Used for member lists such
|
|
701
|
-
* as `z.union([…])` and `z.array([…])`.
|
|
702
|
-
*
|
|
703
|
-
* @example
|
|
704
|
-
* ```ts
|
|
705
|
-
* buildList(['z.string()', 'z.number()'])
|
|
706
|
-
* // '[z.string(), z.number()]'
|
|
707
|
-
* ```
|
|
708
|
-
*/
|
|
709
|
-
function buildList(items, brackets = ["[", "]"]) {
|
|
710
|
-
const [open, close] = brackets;
|
|
711
|
-
if (items.length === 0) return `${open}${close}`;
|
|
712
|
-
if (!items.some((item) => item.includes("\n"))) return `${open}${items.join(", ")}${close}`;
|
|
713
|
-
return `${open}\n${items.map((item) => `${indentLines(item)},`).join("\n")}\n${close}`;
|
|
714
|
-
}
|
|
715
|
-
/**
|
|
716
|
-
* Emits a lazy getter for a circular-ref property position, `get name() { return body }`. The key
|
|
717
|
-
* is quoted only when it is not a valid identifier. Used by the string printers to defer evaluation
|
|
718
|
-
* of a recursive schema until first access.
|
|
719
|
-
*
|
|
720
|
-
* @example
|
|
721
|
-
* ```ts
|
|
722
|
-
* lazyGetter({ name: 'parent', body: 'z.lazy(() => Pet)' })
|
|
723
|
-
* // "get parent() { return z.lazy(() => Pet) }"
|
|
724
|
-
* ```
|
|
725
|
-
*/
|
|
726
|
-
function lazyGetter({ name, body }) {
|
|
727
|
-
return `get ${objectKey(name)}() { return ${body} }`;
|
|
728
|
-
}
|
|
729
|
-
// ../../internals/utils/src/fs.ts
|
|
730
|
-
/**
|
|
731
|
-
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
732
|
-
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
733
|
-
* every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
|
|
734
|
-
*
|
|
735
|
-
* Empty segments are dropped before joining. They arise when the name starts with a dot
|
|
736
|
-
* followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
|
|
737
|
-
* an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
|
|
738
|
-
* absolute path, letting generated files escape the configured output directory.
|
|
739
|
-
*
|
|
740
|
-
* @example Nested path from a dotted name
|
|
741
|
-
* `toFilePath('pet.petId') // 'pet/petId'`
|
|
742
|
-
*
|
|
743
|
-
* @example PascalCase the final segment
|
|
744
|
-
* `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
|
|
745
|
-
*
|
|
746
|
-
* @example Suffix applied to the final segment only
|
|
747
|
-
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
748
|
-
*/
|
|
749
|
-
function toFilePath(name, caseLast = _kubb_kit.camelCase) {
|
|
750
|
-
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
751
|
-
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : (0, _kubb_kit.camelCase)(part)).filter(Boolean).join("/");
|
|
626
|
+
function getOasAdapter(adapter) {
|
|
627
|
+
if (adapter.name !== "oas") throw new _kubb_kit.Diagnostics.Error({
|
|
628
|
+
code: _kubb_kit.Diagnostics.code.adapterRequired,
|
|
629
|
+
severity: "error",
|
|
630
|
+
message: `Expected the OpenAPI adapter (adapterOas), but received "${adapter.name}".`,
|
|
631
|
+
help: "Set `adapter: adapterOas()` in kubb.config.ts.",
|
|
632
|
+
location: { kind: "config" }
|
|
633
|
+
});
|
|
634
|
+
return adapter;
|
|
752
635
|
}
|
|
753
636
|
// ../../internals/shared/src/resolver.ts
|
|
754
637
|
/**
|
|
@@ -838,6 +721,13 @@ function createOperationResponseResolver() {
|
|
|
838
721
|
name
|
|
839
722
|
});
|
|
840
723
|
},
|
|
724
|
+
headers(node, statusCode) {
|
|
725
|
+
const name = this.name(`${node.operationId} Status ${statusCode} Headers`);
|
|
726
|
+
return this.resolveName({
|
|
727
|
+
key: operationKey(node, "response", "headers", statusCode),
|
|
728
|
+
name
|
|
729
|
+
});
|
|
730
|
+
},
|
|
841
731
|
body(node) {
|
|
842
732
|
const name = this.name(`${node.operationId} Body`);
|
|
843
733
|
return this.resolveName({
|
|
@@ -879,147 +769,7 @@ function createCasedFile(caseLast) {
|
|
|
879
769
|
* Names of the schemas in a circular reference chain, computed once per build.
|
|
880
770
|
*/
|
|
881
771
|
function getCircularNames(ctx) {
|
|
882
|
-
return ctx.memo("circularNames:set", () => _kubb_kit.ast.
|
|
883
|
-
}
|
|
884
|
-
// ../../internals/shared/src/group.ts
|
|
885
|
-
/**
|
|
886
|
-
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
887
|
-
* shared default naming so every plugin groups output consistently:
|
|
888
|
-
*
|
|
889
|
-
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
890
|
-
* - other groups use the camelCased group (`pet store` → `petStore`).
|
|
891
|
-
*
|
|
892
|
-
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
893
|
-
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
894
|
-
* per-plugin convention.
|
|
895
|
-
*
|
|
896
|
-
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
897
|
-
*
|
|
898
|
-
* @example
|
|
899
|
-
* ```ts
|
|
900
|
-
* createGroupConfig(group) // shared across every plugin
|
|
901
|
-
* ```
|
|
902
|
-
*/
|
|
903
|
-
function createGroupConfig(group) {
|
|
904
|
-
if (!group) return null;
|
|
905
|
-
const defaultName = (ctx) => {
|
|
906
|
-
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
907
|
-
return (0, _kubb_kit.camelCase)(ctx.group);
|
|
908
|
-
};
|
|
909
|
-
return {
|
|
910
|
-
...group,
|
|
911
|
-
name: group.name ? group.name : defaultName
|
|
912
|
-
};
|
|
913
|
-
}
|
|
914
|
-
// ../../internals/shared/src/schemaTraversal.ts
|
|
915
|
-
/**
|
|
916
|
-
* Maps each property of an object schema to its transformed output. Pairs every result with the
|
|
917
|
-
* original property so the printer keeps full control over modifiers, getters, and key syntax.
|
|
918
|
-
*
|
|
919
|
-
* @example
|
|
920
|
-
* ```ts
|
|
921
|
-
* const entries = mapSchemaProperties(node, (schema) => this.transform(schema))
|
|
922
|
-
* // entries: [{ name: 'id', property, output: 'z.number()' }, ...]
|
|
923
|
-
* ```
|
|
924
|
-
*/
|
|
925
|
-
function mapSchemaProperties(node, transform) {
|
|
926
|
-
return node.properties.map((property) => ({
|
|
927
|
-
name: property.name,
|
|
928
|
-
property,
|
|
929
|
-
output: transform(property.schema)
|
|
930
|
-
}));
|
|
931
|
-
}
|
|
932
|
-
/**
|
|
933
|
-
* Maps each member of a union or intersection schema to its transformed output, pairing every
|
|
934
|
-
* result with the original member.
|
|
935
|
-
*/
|
|
936
|
-
function mapSchemaMembers(node, transform) {
|
|
937
|
-
return (node.members ?? []).map((schema) => ({
|
|
938
|
-
schema,
|
|
939
|
-
output: transform(schema)
|
|
940
|
-
}));
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Maps each item of an array or tuple schema to its transformed output, pairing every result with
|
|
944
|
-
* the original item.
|
|
945
|
-
*/
|
|
946
|
-
function mapSchemaItems(node, transform) {
|
|
947
|
-
return (node.items ?? []).map((schema) => ({
|
|
948
|
-
schema,
|
|
949
|
-
output: transform(schema)
|
|
950
|
-
}));
|
|
951
|
-
}
|
|
952
|
-
// src/components/Zod.tsx
|
|
953
|
-
function Zod({ name, node, printer, inferTypeName, inferKind = "infer", typeGuards, isName, assertName, mini, cyclic, compile }) {
|
|
954
|
-
const output = printer.print(node);
|
|
955
|
-
const printerImports = printer.drainImports();
|
|
956
|
-
if (!output) return;
|
|
957
|
-
const needsAnnotation = cyclic && node.type !== "object";
|
|
958
|
-
const isBare = _kubb_kit.ast.isBareRef(node, printer.options.keysToOmit);
|
|
959
|
-
const isCyclic = Boolean(cyclic || printer.options.cyclicSchemas && (0, _kubb_kit.containsCircularRef)(node, { circularSchemas: printer.options.cyclicSchemas }));
|
|
960
|
-
const value = Boolean(compile) && !isBare && !isCyclic ? typeof compile === "object" && compile.strict ? `z.compile(${output}, { strict: true })` : `z.compile(${output})` : output;
|
|
961
|
-
const targetType = inferTypeName ?? `z.infer<typeof ${name}>`;
|
|
962
|
-
const shouldGenerateIs = isName && (typeof typeGuards === "object" ? typeGuards.is ?? true : Boolean(typeGuards));
|
|
963
|
-
const shouldGenerateAssert = assertName && (typeof typeGuards === "object" ? typeGuards.assert ?? true : Boolean(typeGuards));
|
|
964
|
-
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
965
|
-
printerImports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
966
|
-
name: imp.name,
|
|
967
|
-
path: imp.path,
|
|
968
|
-
root: imp.root,
|
|
969
|
-
isTypeOnly: imp.isTypeOnly,
|
|
970
|
-
isNameSpace: imp.isNameSpace
|
|
971
|
-
}, [
|
|
972
|
-
name,
|
|
973
|
-
imp.path,
|
|
974
|
-
imp.name
|
|
975
|
-
].join("-"))),
|
|
976
|
-
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
977
|
-
name,
|
|
978
|
-
isExportable: true,
|
|
979
|
-
isIndexable: true,
|
|
980
|
-
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
|
|
981
|
-
export: true,
|
|
982
|
-
name,
|
|
983
|
-
type: needsAnnotation ? "z.ZodType" : void 0,
|
|
984
|
-
children: value
|
|
985
|
-
})
|
|
986
|
-
}),
|
|
987
|
-
inferTypeName && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
988
|
-
name: inferTypeName,
|
|
989
|
-
isExportable: true,
|
|
990
|
-
isIndexable: true,
|
|
991
|
-
isTypeOnly: true,
|
|
992
|
-
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Type, {
|
|
993
|
-
export: true,
|
|
994
|
-
name: inferTypeName,
|
|
995
|
-
children: `z.${inferKind}<typeof ${name}>`
|
|
996
|
-
})
|
|
997
|
-
}),
|
|
998
|
-
shouldGenerateIs && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
999
|
-
name: isName,
|
|
1000
|
-
isExportable: true,
|
|
1001
|
-
isIndexable: true,
|
|
1002
|
-
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
|
|
1003
|
-
export: true,
|
|
1004
|
-
name: isName,
|
|
1005
|
-
JSDoc: { comments: [`Type guard for {@link ${name}}`] },
|
|
1006
|
-
children: mini ? `(data: unknown): data is ${targetType} => z.validate(${name}, data)` : `(data: unknown): data is ${targetType} => ${name}.validate(data)`
|
|
1007
|
-
})
|
|
1008
|
-
}),
|
|
1009
|
-
shouldGenerateAssert && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1010
|
-
name: assertName,
|
|
1011
|
-
isExportable: true,
|
|
1012
|
-
isIndexable: true,
|
|
1013
|
-
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Function, {
|
|
1014
|
-
export: true,
|
|
1015
|
-
name: assertName,
|
|
1016
|
-
params: "data: unknown",
|
|
1017
|
-
returnType: `asserts data is ${targetType}`,
|
|
1018
|
-
JSDoc: { comments: [`Asserter for {@link ${name}}`, "@throws {z.ZodError} If data is invalid"] },
|
|
1019
|
-
children: mini ? `if (!z.validate(${name}, data)) {\n z.parse(${name}, data)\n}` : `if (!${name}.validate(data)) {\n ${name}.parse(data)\n}`
|
|
1020
|
-
})
|
|
1021
|
-
})
|
|
1022
|
-
] });
|
|
772
|
+
return ctx.memo("circularNames:set", () => _kubb_kit.ast.graph.getCircularNames(ctx.driver.inputNode?.schemas ?? []));
|
|
1023
773
|
}
|
|
1024
774
|
// src/utils.ts
|
|
1025
775
|
/**
|
|
@@ -1040,7 +790,7 @@ function shouldCoerce(coercion, type) {
|
|
|
1040
790
|
*/
|
|
1041
791
|
function isClosedKeySchema(node) {
|
|
1042
792
|
if (!node) return false;
|
|
1043
|
-
const resolved =
|
|
793
|
+
const resolved = _kubb_kit.ast.ref.mergeSchema(node);
|
|
1044
794
|
if (resolved.type === "enum") return true;
|
|
1045
795
|
if (resolved.type === "union") {
|
|
1046
796
|
const members = resolved.members ?? [];
|
|
@@ -1050,12 +800,12 @@ function isClosedKeySchema(node) {
|
|
|
1050
800
|
}
|
|
1051
801
|
/**
|
|
1052
802
|
* Whether the node is a plain inline object whose shape can be lifted into an `.extend({ … })`
|
|
1053
|
-
* argument.
|
|
803
|
+
* argument. Input checks, a catchall, `patternProperties`, or a nullable/optional wrapper cannot, so those stay
|
|
1054
804
|
* on `.and(…)`.
|
|
1055
805
|
*/
|
|
1056
806
|
function isPlainInlineObject(node) {
|
|
1057
807
|
if (node.type !== "object") return false;
|
|
1058
|
-
if (node
|
|
808
|
+
if (hasInputChecks(node)) return false;
|
|
1059
809
|
if (node.nullable || node.optional || node.nullish) return false;
|
|
1060
810
|
const hasAdditionalProperties = node.additionalProperties !== void 0;
|
|
1061
811
|
const hasPatternProperties = Boolean(node.patternProperties);
|
|
@@ -1066,21 +816,21 @@ function isPlainInlineObject(node) {
|
|
|
1066
816
|
* `z.discriminatedUnion` option. Covers object nodes, `$ref`s that resolve to (or are still
|
|
1067
817
|
* unresolved) objects, single-member unions of an object, and object-composable `allOf`.
|
|
1068
818
|
*
|
|
1069
|
-
*
|
|
819
|
+
* Input checks, such as property counts and `conditionals`, render as a pipe. A ref into `cyclicSchemas` renders as `z.lazy(…)`.
|
|
1070
820
|
*/
|
|
1071
821
|
function isObjectSchemaNode(node, cyclicSchemas) {
|
|
1072
822
|
if (node.nullable || node.optional || node.nullish) return false;
|
|
823
|
+
if (hasInputChecks(node)) return false;
|
|
1073
824
|
if (node.type === "object") {
|
|
1074
|
-
if (node.minProperties !== void 0 || node.maxProperties !== void 0) return false;
|
|
1075
825
|
const hasProperties = Boolean(node.properties?.length);
|
|
1076
826
|
const hasTypedAdditionalProperties = Boolean(node.additionalProperties && node.additionalProperties !== true);
|
|
1077
827
|
const hasPatternProperties = Boolean(node.patternProperties);
|
|
1078
828
|
return !(!hasProperties && (hasTypedAdditionalProperties || hasPatternProperties || node.propertyNames));
|
|
1079
829
|
}
|
|
1080
830
|
if (node.type === "ref") {
|
|
1081
|
-
const refName = _kubb_kit.ast.
|
|
831
|
+
const refName = _kubb_kit.ast.ref.getName(node);
|
|
1082
832
|
if (refName && cyclicSchemas?.has(refName)) return false;
|
|
1083
|
-
const resolved =
|
|
833
|
+
const resolved = _kubb_kit.ast.ref.mergeSchema(node);
|
|
1084
834
|
return resolved.type === "ref" || isObjectSchemaNode(resolved, cyclicSchemas);
|
|
1085
835
|
}
|
|
1086
836
|
if (node.type === "union") {
|
|
@@ -1103,23 +853,23 @@ function preserveRequiredProperties(members) {
|
|
|
1103
853
|
const hasRequiredProperty = ({ node, propertyName, seen = /* @__PURE__ */ new Set() }) => {
|
|
1104
854
|
if (seen.has(node)) return false;
|
|
1105
855
|
seen.add(node);
|
|
1106
|
-
const resolved =
|
|
1107
|
-
const composition = _kubb_kit.ast.
|
|
856
|
+
const resolved = _kubb_kit.ast.ref.mergeSchema(node);
|
|
857
|
+
const composition = _kubb_kit.ast.schema.narrow(resolved, _kubb_kit.ast.schema.types.intersection) ?? _kubb_kit.ast.schema.narrow(resolved, _kubb_kit.ast.schema.types.union);
|
|
1108
858
|
if (composition) {
|
|
1109
|
-
if (composition.type === _kubb_kit.ast.
|
|
859
|
+
if (composition.type === _kubb_kit.ast.schema.types.union && composition.members?.length !== 1) return false;
|
|
1110
860
|
return composition.members?.some((child) => hasRequiredProperty({
|
|
1111
861
|
node: child,
|
|
1112
862
|
propertyName,
|
|
1113
863
|
seen
|
|
1114
864
|
})) ?? false;
|
|
1115
865
|
}
|
|
1116
|
-
return _kubb_kit.ast.
|
|
866
|
+
return _kubb_kit.ast.schema.findProperties({
|
|
1117
867
|
node: resolved,
|
|
1118
868
|
propertyName
|
|
1119
869
|
}).some((property) => property.required !== false && !property.schema.optional && !property.schema.nullish);
|
|
1120
870
|
};
|
|
1121
871
|
return members.map((member, index) => {
|
|
1122
|
-
const object = _kubb_kit.ast.
|
|
872
|
+
const object = _kubb_kit.ast.schema.narrow(member, _kubb_kit.ast.schema.types.object);
|
|
1123
873
|
if (!object || index === 0) return member;
|
|
1124
874
|
return {
|
|
1125
875
|
...object,
|
|
@@ -1148,7 +898,7 @@ function preserveRequiredProperties(members) {
|
|
|
1148
898
|
* representation, strings are quoted.
|
|
1149
899
|
*/
|
|
1150
900
|
function formatDefault(value) {
|
|
1151
|
-
if (typeof value === "string") return
|
|
901
|
+
if (typeof value === "string") return _kubb_kit.text.quote(value);
|
|
1152
902
|
if (typeof value === "object" && value !== null) return JSON.stringify(value);
|
|
1153
903
|
return String(value ?? "");
|
|
1154
904
|
}
|
|
@@ -1163,16 +913,17 @@ function formatDefault(value) {
|
|
|
1163
913
|
*/
|
|
1164
914
|
function defaultLiteral(node, value) {
|
|
1165
915
|
if (value === null) return null;
|
|
1166
|
-
const resolved = node ?
|
|
1167
|
-
if (resolved
|
|
916
|
+
const resolved = node ? _kubb_kit.ast.ref.mergeSchema(node) : void 0;
|
|
917
|
+
if (resolved?.type === "blob") return null;
|
|
918
|
+
if (resolved && _kubb_kit.ast.schema.narrow(resolved, "bigint")) {
|
|
1168
919
|
if (typeof value === "bigint") return `BigInt(${value})`;
|
|
1169
920
|
if (typeof value === "number" && Number.isInteger(value)) return `BigInt(${value})`;
|
|
1170
921
|
return null;
|
|
1171
922
|
}
|
|
1172
|
-
if (resolved && _kubb_kit.ast.
|
|
1173
|
-
const enumNode = resolved ? _kubb_kit.ast.
|
|
923
|
+
if (resolved && _kubb_kit.ast.schema.narrow(resolved, "array")) return Array.isArray(value) ? JSON.stringify(value) : null;
|
|
924
|
+
const enumNode = resolved ? _kubb_kit.ast.schema.narrow(resolved, "enum") : void 0;
|
|
1174
925
|
if (enumNode) {
|
|
1175
|
-
const values =
|
|
926
|
+
const values = _kubb_kit.ast.schema.getLiterals(enumNode);
|
|
1176
927
|
if (values.length) {
|
|
1177
928
|
const match = values.find((member) => member === value || String(member) === String(value));
|
|
1178
929
|
return match != null ? formatDefault(match) : null;
|
|
@@ -1241,13 +992,13 @@ function patternKeySchemaMini({ patterns, regexType }) {
|
|
|
1241
992
|
* Build `.min()` / `.max()` / `.gt()` / `.lt()` constraint chains for numbers
|
|
1242
993
|
* using the standard chainable Zod v4 API.
|
|
1243
994
|
*/
|
|
1244
|
-
function numberConstraints({ min, max,
|
|
995
|
+
function numberConstraints({ min, max, exclusive, multipleOf }, suffix = "") {
|
|
1245
996
|
return [
|
|
1246
|
-
min !== void 0 ? `.min(${min})` : "",
|
|
1247
|
-
max !== void 0 ? `.max(${max})` : "",
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
multipleOf !== void 0 ? `.multipleOf(${multipleOf})` : ""
|
|
997
|
+
min !== void 0 ? `.min(${min}${suffix})` : "",
|
|
998
|
+
max !== void 0 ? `.max(${max}${suffix})` : "",
|
|
999
|
+
exclusive?.min !== void 0 ? `.gt(${exclusive.min}${suffix})` : "",
|
|
1000
|
+
exclusive?.max !== void 0 ? `.lt(${exclusive.max}${suffix})` : "",
|
|
1001
|
+
multipleOf !== void 0 ? `.multipleOf(${multipleOf}${suffix})` : ""
|
|
1251
1002
|
].join("");
|
|
1252
1003
|
}
|
|
1253
1004
|
/**
|
|
@@ -1262,36 +1013,71 @@ function lengthConstraints({ min, max, pattern, regexType }) {
|
|
|
1262
1013
|
].join("");
|
|
1263
1014
|
}
|
|
1264
1015
|
/**
|
|
1016
|
+
* Numeric bounds for a bigint: the inclusive, whole, safe bounds faker mocks against, and a whole, safe `multipleOf`.
|
|
1017
|
+
*/
|
|
1018
|
+
function bigintConstraints({ min, max, exclusive, multipleOf }) {
|
|
1019
|
+
return {
|
|
1020
|
+
..._kubb_kit.ast.schema.getNumberBounds({
|
|
1021
|
+
min,
|
|
1022
|
+
max,
|
|
1023
|
+
exclusive,
|
|
1024
|
+
integer: true
|
|
1025
|
+
}),
|
|
1026
|
+
multipleOf: Number.isSafeInteger(multipleOf) ? multipleOf : void 0
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1265
1030
|
* Build `.check(z.minimum(), z.maximum())` for `zod/mini` numeric constraints.
|
|
1266
1031
|
*/
|
|
1267
|
-
function numberChecksMini({ min, max,
|
|
1268
|
-
const checks = [
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1032
|
+
function numberChecksMini({ min, max, exclusive, multipleOf }, suffix = "") {
|
|
1033
|
+
const checks = [
|
|
1034
|
+
min !== void 0 && `z.minimum(${min}${suffix})`,
|
|
1035
|
+
max !== void 0 && `z.maximum(${max}${suffix})`,
|
|
1036
|
+
exclusive?.min !== void 0 && `z.gt(${exclusive.min}${suffix})`,
|
|
1037
|
+
exclusive?.max !== void 0 && `z.lt(${exclusive.max}${suffix})`,
|
|
1038
|
+
multipleOf !== void 0 && `z.multipleOf(${multipleOf}${suffix})`
|
|
1039
|
+
].filter(Boolean);
|
|
1274
1040
|
return checks.length ? `.check(${checks.join(", ")})` : "";
|
|
1275
1041
|
}
|
|
1276
1042
|
/**
|
|
1277
1043
|
* Build `.check(z.minLength(), z.maxLength(), z.regex())` for `zod/mini` length constraints.
|
|
1278
1044
|
*/
|
|
1279
1045
|
function lengthChecksMini({ min, max, pattern, regexType }) {
|
|
1280
|
-
const checks = [
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1046
|
+
const checks = [
|
|
1047
|
+
min !== void 0 && `z.minLength(${min})`,
|
|
1048
|
+
max !== void 0 && `z.maxLength(${max})`,
|
|
1049
|
+
pattern !== void 0 && `z.regex(${regexSource(pattern, regexType)})`
|
|
1050
|
+
].filter(Boolean);
|
|
1284
1051
|
return checks.length ? `.check(${checks.join(", ")})` : "";
|
|
1285
1052
|
}
|
|
1286
1053
|
/**
|
|
1287
|
-
*
|
|
1054
|
+
* Whether `propertyNames` needs its own check: `z.record` checks the keys of a map, but `z.object` and a record keyed by
|
|
1055
|
+
* `patternProperties` do not.
|
|
1056
|
+
*/
|
|
1057
|
+
function hasKeyCheck(node) {
|
|
1058
|
+
if (node.type !== "object" || !node.propertyNames) return false;
|
|
1059
|
+
const hasTypedAdditionalProperties = Boolean(node.additionalProperties && node.additionalProperties !== true);
|
|
1060
|
+
return node.properties.length > 0 || Boolean(node.patternProperties) && !hasTypedAdditionalProperties;
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Whether the node prints inside `z.pipe(z.unknown().check(…), …)`, see {@link inputChecks}.
|
|
1064
|
+
*/
|
|
1065
|
+
function hasInputChecks(node) {
|
|
1066
|
+
return Boolean(node.conditionals?.length) || node.type === "object" && (node.min !== void 0 || node.max !== void 0) || hasKeyCheck(node);
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Checks the raw input, before parsing strips unknown keys or inserts defaults: property counts, key names, then the
|
|
1070
|
+
* printed `conditionals`.
|
|
1288
1071
|
*/
|
|
1289
|
-
function
|
|
1290
|
-
if (node.type !== "object") return value;
|
|
1291
|
-
const checks = [];
|
|
1072
|
+
function inputChecks({ value, node, keySchema, conditionals }) {
|
|
1292
1073
|
const skip = "typeof value !== \"object\" || value === null || Array.isArray(value)";
|
|
1293
|
-
|
|
1294
|
-
|
|
1074
|
+
const { min, max } = node.type === "object" ? node : {};
|
|
1075
|
+
const checks = [
|
|
1076
|
+
min !== void 0 && `z.refine(value => ${skip} || Object.keys(value).length >= ${min}, { message: "Object must have at least ${min} properties" })`,
|
|
1077
|
+
max !== void 0 && `z.refine(value => ${skip} || Object.keys(value).length <= ${max}, { message: "Object must have at most ${max} properties" })`,
|
|
1078
|
+
keySchema && `z.refine(value => ${skip} || Object.keys(value).every((key) => ${keySchema}.safeParse(key).success), { message: "Object keys must match the property names schema" })`,
|
|
1079
|
+
...conditionals
|
|
1080
|
+
].filter(Boolean);
|
|
1295
1081
|
return checks.length ? `z.pipe(z.unknown().check(${checks.join(", ")}), ${value})` : value;
|
|
1296
1082
|
}
|
|
1297
1083
|
/**
|
|
@@ -1307,8 +1093,8 @@ function applyModifiers({ value, schema, nullable, optional, nullish, defaultVal
|
|
|
1307
1093
|
})();
|
|
1308
1094
|
const literal = defaultValue !== void 0 ? defaultLiteral(schema, defaultValue) : null;
|
|
1309
1095
|
const withDefault = literal !== null ? `${withModifier}.default(${literal})` : withModifier;
|
|
1310
|
-
const withDescription = description ? `${withDefault}.describe(${
|
|
1311
|
-
return examples?.length ? `${withDescription}.meta({ examples: [${examples.map(formatDefault).join(", ")}] })` : withDescription;
|
|
1096
|
+
const withDescription = description ? `${withDefault}.describe(${_kubb_kit.text.quote(description)})` : withDefault;
|
|
1097
|
+
return examples?.length ? `${withDescription}.meta({ examples: [${examples.map((example) => example === null ? "null" : formatDefault(example)).join(", ")}] })` : withDescription;
|
|
1312
1098
|
}
|
|
1313
1099
|
function modifierDepth(schema) {
|
|
1314
1100
|
if (schema.nullish || schema.nullable && schema.optional) return 2;
|
|
@@ -1326,7 +1112,7 @@ function modifierDepth(schema) {
|
|
|
1326
1112
|
* `.unwrap()`, so its printer passes `._zod.def.innerType` as the `step`.
|
|
1327
1113
|
*/
|
|
1328
1114
|
function omitUnwrapChain(node, step = ".unwrap()") {
|
|
1329
|
-
const ref = _kubb_kit.ast.
|
|
1115
|
+
const ref = _kubb_kit.ast.schema.narrow(node, "ref");
|
|
1330
1116
|
if (!ref) return "";
|
|
1331
1117
|
const target = ref.schema ?? ref;
|
|
1332
1118
|
const depth = modifierDepth(target) + (target.default !== void 0 ? 1 : 0);
|
|
@@ -1348,7 +1134,7 @@ function applyMiniModifiers({ value, schema, nullable, optional, nullish, defaul
|
|
|
1348
1134
|
/**
|
|
1349
1135
|
* Calls for string `format`s with a dedicated Zod constructor; a `Map` so `constructor` cannot hit `Object.prototype`.
|
|
1350
1136
|
*/
|
|
1351
|
-
const
|
|
1137
|
+
const stringFormatCalls = /* @__PURE__ */ new Map([
|
|
1352
1138
|
["byte", "z.base64()"],
|
|
1353
1139
|
["base64", "z.base64()"],
|
|
1354
1140
|
["base64url", "z.base64url()"],
|
|
@@ -1359,6 +1145,16 @@ const STRING_FORMAT_CALLS = /* @__PURE__ */ new Map([
|
|
|
1359
1145
|
["hostname", "z.hostname()"]
|
|
1360
1146
|
]);
|
|
1361
1147
|
/**
|
|
1148
|
+
* Calls for a string's `contentEncoding` with a dedicated Zod constructor.
|
|
1149
|
+
*/
|
|
1150
|
+
const contentEncodingCalls = /* @__PURE__ */ new Map([["base64", "z.base64()"], ["base64url", "z.base64url()"]]);
|
|
1151
|
+
/**
|
|
1152
|
+
* The check for a string that holds a JSON document: it must parse, and the parsed value must pass `schema`.
|
|
1153
|
+
*/
|
|
1154
|
+
function jsonContentCheck(schema) {
|
|
1155
|
+
return `(value) => { try { return ${schema}.safeParse(JSON.parse(value)).success } catch { return false } }, { message: "String must hold JSON that matches its content schema" }`;
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1362
1158
|
* Marks an inline `oneOf` object strict, so `object()` builds `z.strictObject(...)` and no eager `.shape` read hits a deferred getter.
|
|
1363
1159
|
*/
|
|
1364
1160
|
function strictOneOfNode(node) {
|
|
@@ -1371,13 +1167,14 @@ function strictOneOfNode(node) {
|
|
|
1371
1167
|
* The constraint chain an `allOf` member adds to a bare string, number or array; each printer passes its own renderers.
|
|
1372
1168
|
*/
|
|
1373
1169
|
function getMemberConstraint({ member, regexType, lengths, numbers }) {
|
|
1170
|
+
if (hasInputChecks(member) || _kubb_kit.ast.schema.narrow(member, "array")?.contains) return void 0;
|
|
1374
1171
|
if (member.primitive === "string") return lengths({
|
|
1375
|
-
..._kubb_kit.ast.
|
|
1172
|
+
..._kubb_kit.ast.schema.narrow(member, "string") ?? {},
|
|
1376
1173
|
regexType
|
|
1377
1174
|
}) || void 0;
|
|
1378
|
-
if (member.primitive === "number" || member.primitive === "integer") return numbers(_kubb_kit.ast.
|
|
1175
|
+
if (member.primitive === "number" || member.primitive === "integer") return numbers(_kubb_kit.ast.schema.narrow(member, "number") ?? _kubb_kit.ast.schema.narrow(member, "integer") ?? {}) || void 0;
|
|
1379
1176
|
if (member.primitive === "array") return lengths({
|
|
1380
|
-
..._kubb_kit.ast.
|
|
1177
|
+
..._kubb_kit.ast.schema.narrow(member, "array") ?? {},
|
|
1381
1178
|
regexType
|
|
1382
1179
|
}) || void 0;
|
|
1383
1180
|
}
|
|
@@ -1385,24 +1182,26 @@ function getMemberConstraint({ member, regexType, lengths, numbers }) {
|
|
|
1385
1182
|
* Builds the `{ key: value, … }` shape shared by the `z.object(...)` and `.extend(...)` renderings.
|
|
1386
1183
|
*/
|
|
1387
1184
|
function buildObjectShape(ctx, node, renderProperty) {
|
|
1388
|
-
const objectNode = _kubb_kit.ast.
|
|
1185
|
+
const objectNode = _kubb_kit.ast.schema.narrow(node, "object");
|
|
1389
1186
|
if (!objectNode) return "{}";
|
|
1390
|
-
const isCyclic = (schema) => ctx.options.cyclicSchemas != null &&
|
|
1391
|
-
|
|
1187
|
+
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && _kubb_kit.ast.graph.containsCircular(schema, { circularSchemas: ctx.options.cyclicSchemas });
|
|
1188
|
+
const transformed = objectNode.properties.map(({ schema }) => {
|
|
1392
1189
|
const hasSelfRef = isCyclic(schema);
|
|
1393
1190
|
const savedCyclicSchemas = ctx.options.cyclicSchemas;
|
|
1394
1191
|
if (hasSelfRef) ctx.options.cyclicSchemas = void 0;
|
|
1395
1192
|
const baseOutput = ctx.transform(schema) ?? ctx.transform(_kubb_kit.ast.factory.createSchema({ type: "unknown" }));
|
|
1396
1193
|
if (hasSelfRef) ctx.options.cyclicSchemas = savedCyclicSchemas;
|
|
1397
1194
|
return baseOutput;
|
|
1398
|
-
})
|
|
1399
|
-
|
|
1195
|
+
});
|
|
1196
|
+
return buildObject(objectNode.properties.map((property, index) => {
|
|
1197
|
+
const { name, schema } = property;
|
|
1198
|
+
const value = transformed[index];
|
|
1400
1199
|
return renderProperty({
|
|
1401
1200
|
name,
|
|
1402
1201
|
value,
|
|
1403
1202
|
schema,
|
|
1404
1203
|
required: property.required,
|
|
1405
|
-
meta:
|
|
1204
|
+
meta: _kubb_kit.ast.ref.mergeSchema(schema),
|
|
1406
1205
|
cyclic: isCyclic(schema)
|
|
1407
1206
|
});
|
|
1408
1207
|
}));
|
|
@@ -1414,14 +1213,14 @@ function printWithOmit(ctx, node, modify, mini = false) {
|
|
|
1414
1213
|
const { keysToOmit } = ctx.options;
|
|
1415
1214
|
const transformed = ctx.transform(node);
|
|
1416
1215
|
if (!transformed) return null;
|
|
1417
|
-
const meta =
|
|
1216
|
+
const meta = _kubb_kit.ast.ref.mergeSchema(node);
|
|
1418
1217
|
return modify((() => {
|
|
1419
1218
|
if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
|
|
1420
1219
|
const unwrap = omitUnwrapChain(node, mini ? "._zod.def.innerType" : ".unwrap()");
|
|
1421
1220
|
const mask = `{ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }`;
|
|
1422
1221
|
const omit = (target) => {
|
|
1423
1222
|
const inner = `${target}${unwrap}`;
|
|
1424
|
-
const hasObjectConstraints =
|
|
1223
|
+
const hasObjectConstraints = hasInputChecks(meta);
|
|
1425
1224
|
const pipe = mini ? `${inner}._zod.def` : inner;
|
|
1426
1225
|
const object = hasObjectConstraints ? `${pipe}.out` : inner;
|
|
1427
1226
|
const omitted = mini ? `z.omit(${object}, ${mask})` : `${object}.omit(${mask})`;
|
|
@@ -1440,7 +1239,7 @@ function printWithOmit(ctx, node, modify, mini = false) {
|
|
|
1440
1239
|
function getLiteralUnion({ node, options }) {
|
|
1441
1240
|
if (node.strategy === "one" && options.oneOfType === "xor" || options.nodes?.enum) return void 0;
|
|
1442
1241
|
const values = (node.members ?? []).map((member) => {
|
|
1443
|
-
const enumNode = _kubb_kit.ast.
|
|
1242
|
+
const enumNode = _kubb_kit.ast.schema.narrow(member, _kubb_kit.ast.schema.types.enum);
|
|
1444
1243
|
return enumNode && !enumNode.name && !enumNode.nullable && !enumNode.namedEnumValues && enumNode.enumValues?.length === 1 ? enumNode.enumValues[0] : void 0;
|
|
1445
1244
|
});
|
|
1446
1245
|
if (!values.length || !values.every((value) => value !== void 0 && value !== null)) return void 0;
|
|
@@ -1453,11 +1252,11 @@ function getLiteralUnion({ node, options }) {
|
|
|
1453
1252
|
* Whether a discriminated union member's discriminator property prints as a coerced literal union.
|
|
1454
1253
|
*/
|
|
1455
1254
|
function hasCoercedDiscriminator({ member, propertyName, options }) {
|
|
1456
|
-
return _kubb_kit.ast.
|
|
1255
|
+
return _kubb_kit.ast.schema.findProperties({
|
|
1457
1256
|
node: member,
|
|
1458
1257
|
propertyName
|
|
1459
1258
|
}).some(({ schema }) => {
|
|
1460
|
-
const resolved =
|
|
1259
|
+
const resolved = _kubb_kit.ast.ref.mergeSchema(schema);
|
|
1461
1260
|
return resolved.type === "union" && !!getLiteralUnion({
|
|
1462
1261
|
node: resolved,
|
|
1463
1262
|
options
|
|
@@ -1465,7 +1264,48 @@ function hasCoercedDiscriminator({ member, propertyName, options }) {
|
|
|
1465
1264
|
});
|
|
1466
1265
|
}
|
|
1467
1266
|
/**
|
|
1468
|
-
*
|
|
1267
|
+
* Whether `z.compile(schema, { strict: true })` throws for the node. Zod runs an unsupported schema below an object
|
|
1268
|
+
* property or an array, tuple or record item on its runtime parser, so only a coerced scalar or a `z.xor` that compiles
|
|
1269
|
+
* inline with the root throws: the node itself, or one reached through refs and union or intersection members.
|
|
1270
|
+
* `siblings` resolves a generated ref, which names another schema of the same file and carries no target.
|
|
1271
|
+
*
|
|
1272
|
+
* Mirrors the built-in handlers, so a type with a `printer.nodes` override is judged as if it printed the built-in output.
|
|
1273
|
+
*/
|
|
1274
|
+
function throwsOnStrictCompile({ node, options, siblings, seen = /* @__PURE__ */ new Set() }) {
|
|
1275
|
+
if (!node || seen.has(node)) return false;
|
|
1276
|
+
seen.add(node);
|
|
1277
|
+
const throws = (child) => throwsOnStrictCompile({
|
|
1278
|
+
node: child,
|
|
1279
|
+
options,
|
|
1280
|
+
siblings,
|
|
1281
|
+
seen
|
|
1282
|
+
});
|
|
1283
|
+
switch (node.type) {
|
|
1284
|
+
case _kubb_kit.ast.schema.types.ref: return throws(node.schema ?? (node.ref || !node.name ? void 0 : siblings?.get(node.name)));
|
|
1285
|
+
case _kubb_kit.ast.schema.types.union:
|
|
1286
|
+
if (node.strategy === "one" && options.oneOfType === "xor") return true;
|
|
1287
|
+
return !!getLiteralUnion({
|
|
1288
|
+
node,
|
|
1289
|
+
options
|
|
1290
|
+
})?.coerce || (node.members ?? []).some(throws);
|
|
1291
|
+
case _kubb_kit.ast.schema.types.intersection: return (node.members ?? []).some(throws);
|
|
1292
|
+
case _kubb_kit.ast.schema.types.bigint: return true;
|
|
1293
|
+
case _kubb_kit.ast.schema.types.string: return shouldCoerce(options.coercion, "strings");
|
|
1294
|
+
case _kubb_kit.ast.schema.types.number:
|
|
1295
|
+
case _kubb_kit.ast.schema.types.integer: return shouldCoerce(options.coercion, "numbers");
|
|
1296
|
+
case _kubb_kit.ast.schema.types.date: return node.representation === "date" && options.direction !== "encode" && shouldCoerce(options.coercion, "dates");
|
|
1297
|
+
default: return false;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
function hasPlainDiscriminator({ member, propertyName }) {
|
|
1301
|
+
const schemas = _kubb_kit.ast.schema.findProperties({
|
|
1302
|
+
node: member,
|
|
1303
|
+
propertyName
|
|
1304
|
+
});
|
|
1305
|
+
return schemas.length > 0 && !schemas.some(({ schema }) => _kubb_kit.ast.schema.getLiterals(_kubb_kit.ast.ref.mergeSchema(schema)).length > 0);
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Builds the scalar handlers both dialects share. Only a string with a `contentSchema` recurses into a child. The temporal
|
|
1469
1309
|
* scalars and `bigint` differ per dialect, so each printer adds its own.
|
|
1470
1310
|
*/
|
|
1471
1311
|
function buildScalarNodes(dialect) {
|
|
@@ -1478,18 +1318,20 @@ function buildScalarNodes(dialect) {
|
|
|
1478
1318
|
null: () => "z.null()",
|
|
1479
1319
|
string(node) {
|
|
1480
1320
|
const coerce = shouldCoerce(this.options.coercion, "strings");
|
|
1481
|
-
const
|
|
1482
|
-
if (call) return `${call}${dialect.lengths({
|
|
1483
|
-
...node,
|
|
1484
|
-
regexType: this.options.regexType
|
|
1485
|
-
})}`;
|
|
1486
|
-
const base = coerce ? "z.coerce.string()" : "z.string()";
|
|
1321
|
+
const base = (coerce ? void 0 : stringFormatCalls.get(node.format) ?? contentEncodingCalls.get(node.content?.encoding?.toLowerCase())) ?? (coerce ? "z.coerce.string()" : "z.string()");
|
|
1487
1322
|
const pattern = node.pattern ?? integerFormatPattern(node.format);
|
|
1488
|
-
|
|
1323
|
+
const value = `${base}${dialect.lengths({
|
|
1489
1324
|
...node,
|
|
1490
1325
|
pattern,
|
|
1491
1326
|
regexType: this.options.regexType
|
|
1492
1327
|
})}`;
|
|
1328
|
+
const contentNode = _kubb_kit.ast.schema.getEmbeddedJson(node);
|
|
1329
|
+
if (!contentNode) return value;
|
|
1330
|
+
const direction = this.options.direction;
|
|
1331
|
+
this.options.direction = "decode";
|
|
1332
|
+
const contentSchema = this.transform(contentNode);
|
|
1333
|
+
this.options.direction = direction;
|
|
1334
|
+
return contentSchema ? dialect.refine(value, jsonContentCheck(contentSchema)) : value;
|
|
1493
1335
|
},
|
|
1494
1336
|
number(node) {
|
|
1495
1337
|
return `${shouldCoerce(this.options.coercion, "numbers") ? "z.coerce.number()" : "z.number()"}${dialect.numbers(node)}`;
|
|
@@ -1522,7 +1364,7 @@ function buildScalarNodes(dialect) {
|
|
|
1522
1364
|
ipv6: () => "z.ipv6()",
|
|
1523
1365
|
blob: () => "z.instanceof(Blob)",
|
|
1524
1366
|
enum(node) {
|
|
1525
|
-
const nonNullValues =
|
|
1367
|
+
const nonNullValues = _kubb_kit.ast.schema.getLiterals(node).filter((v) => v !== null);
|
|
1526
1368
|
if (node.namedEnumValues?.length) {
|
|
1527
1369
|
const literals = nonNullValues.map((v) => buildLiteral(v));
|
|
1528
1370
|
if (literals.length === 1) return literals[0];
|
|
@@ -1541,11 +1383,12 @@ function buildScalarNodes(dialect) {
|
|
|
1541
1383
|
*/
|
|
1542
1384
|
function buildZodNodes(dialect, cyclicSchemas) {
|
|
1543
1385
|
const unionsWithSiblings = /* @__PURE__ */ new WeakSet();
|
|
1386
|
+
const printNullable = (schema, output) => output && schema.nullable ? dialect.nullable(output) : output;
|
|
1544
1387
|
return {
|
|
1545
1388
|
...buildScalarNodes(dialect),
|
|
1546
1389
|
ref(node) {
|
|
1547
1390
|
if (!node.name) return null;
|
|
1548
|
-
const refName = _kubb_kit.ast.
|
|
1391
|
+
const refName = _kubb_kit.ast.ref.getName(node);
|
|
1549
1392
|
if (!refName) return null;
|
|
1550
1393
|
const useInputVariant = node.ref != null && (dialect.useInputVariant?.(node, this.options) ?? false);
|
|
1551
1394
|
const resolvedName = node.ref ? useInputVariant ? this.options.resolver?.schema.inputName(refName) ?? refName : this.options.resolver?.name(refName) ?? refName : node.name;
|
|
@@ -1560,47 +1403,50 @@ function buildZodNodes(dialect, cyclicSchemas) {
|
|
|
1560
1403
|
const isStrict = node.additionalProperties === false && patterns.length === 0;
|
|
1561
1404
|
const isLoose = node.additionalProperties === true;
|
|
1562
1405
|
const objectBase = `${isStrict ? "z.strictObject" : isLoose ? "z.looseObject" : "z.object"}(${dialect.objectShape(this, node)})`;
|
|
1563
|
-
return
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
})(),
|
|
1592
|
-
node
|
|
1593
|
-
});
|
|
1406
|
+
return (() => {
|
|
1407
|
+
const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
|
|
1408
|
+
if (node.additionalProperties && node.additionalProperties !== true) {
|
|
1409
|
+
const catchallType = this.transform(node.additionalProperties);
|
|
1410
|
+
if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
|
|
1411
|
+
return catchallType ? dialect.catchall(objectBase, catchallType) : objectBase;
|
|
1412
|
+
}
|
|
1413
|
+
if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) {
|
|
1414
|
+
const unknownType = this.transform(_kubb_kit.ast.factory.createSchema({ type: _kubb_kit.ast.schema.types.unknown }));
|
|
1415
|
+
return `${recordFn}(${propertyNamesKeySchema}, ${unknownType})`;
|
|
1416
|
+
}
|
|
1417
|
+
if (node.additionalProperties === true) return objectBase;
|
|
1418
|
+
if (isStrict) return objectBase;
|
|
1419
|
+
if (patterns.length > 0) {
|
|
1420
|
+
const values = patterns.map(([, valueSchema]) => {
|
|
1421
|
+
const valueType = this.transform(valueSchema) ?? this.transform(_kubb_kit.ast.factory.createSchema({ type: _kubb_kit.ast.schema.types.unknown }));
|
|
1422
|
+
return valueSchema.nullable ? dialect.nullable(valueType) : valueType;
|
|
1423
|
+
});
|
|
1424
|
+
const distinct = [...new Set(values)];
|
|
1425
|
+
const value = distinct.length === 1 ? distinct[0] : `z.union([${distinct.join(", ")}])`;
|
|
1426
|
+
if (entries.length > 0) return dialect.catchall(objectBase, value);
|
|
1427
|
+
return `z.record(${dialect.patternKey({
|
|
1428
|
+
patterns: patterns.map(([pattern]) => pattern),
|
|
1429
|
+
regexType: this.options.regexType
|
|
1430
|
+
})}, ${value})`;
|
|
1431
|
+
}
|
|
1432
|
+
return objectBase;
|
|
1433
|
+
})();
|
|
1594
1434
|
},
|
|
1595
1435
|
array(node) {
|
|
1596
|
-
const base = `z.array(${
|
|
1436
|
+
const base = `z.array(${(node.items ?? []).map((item) => printNullable(item, this.transform(item))).filter(Boolean).join(", ") || this.transform(_kubb_kit.ast.factory.createSchema({ type: _kubb_kit.ast.schema.types.unknown }))})${dialect.lengths({
|
|
1597
1437
|
...node,
|
|
1598
1438
|
regexType: this.options.regexType
|
|
1599
1439
|
})}`;
|
|
1600
|
-
|
|
1440
|
+
const unique = node.unique ? dialect.unique(base) : base;
|
|
1441
|
+
const contains = node.contains && containsCheck(this, node.contains);
|
|
1442
|
+
return contains ? dialect.refine(unique, contains) : unique;
|
|
1601
1443
|
},
|
|
1602
1444
|
tuple(node) {
|
|
1603
|
-
|
|
1445
|
+
const items = (node.items ?? []).map((item) => printNullable(item, this.transform(item))).filter(Boolean);
|
|
1446
|
+
const rest = node.rest ? this.transform(node.rest) : void 0;
|
|
1447
|
+
const tuple = `z.tuple(${buildList(items)}${rest ? `, ${rest}` : ""})`;
|
|
1448
|
+
const contains = node.contains && containsCheck(this, node.contains);
|
|
1449
|
+
return contains ? dialect.refine(tuple, contains) : tuple;
|
|
1604
1450
|
},
|
|
1605
1451
|
union(node) {
|
|
1606
1452
|
const literalUnion = getLiteralUnion({
|
|
@@ -1613,24 +1459,30 @@ function buildZodNodes(dialect, cyclicSchemas) {
|
|
|
1613
1459
|
}
|
|
1614
1460
|
const nodeMembers = node.members ?? [];
|
|
1615
1461
|
const { discriminatorPropertyName } = node;
|
|
1616
|
-
const isDiscriminated = !!discriminatorPropertyName && nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemas)
|
|
1462
|
+
const isDiscriminated = !!discriminatorPropertyName && nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemas) && !hasPlainDiscriminator({
|
|
1463
|
+
member: m,
|
|
1464
|
+
propertyName: discriminatorPropertyName
|
|
1465
|
+
})) && !nodeMembers.some((m) => hasCoercedDiscriminator({
|
|
1617
1466
|
member: m,
|
|
1618
1467
|
propertyName: discriminatorPropertyName,
|
|
1619
1468
|
options: this.options
|
|
1620
1469
|
}));
|
|
1621
1470
|
const isXor = node.strategy === "one" && !isDiscriminated && this.options.oneOfType === "xor";
|
|
1622
|
-
const isStrict = node.strategy === "one" && !isXor && !unionsWithSiblings.has(node);
|
|
1623
|
-
const members =
|
|
1471
|
+
const isStrict = node.strategy === "one" && !isXor && !isDiscriminated && !unionsWithSiblings.has(node);
|
|
1472
|
+
const members = (node.members ?? []).map((memberNode) => {
|
|
1473
|
+
const output = this.transform(isStrict ? strictOneOfNode(memberNode) : memberNode);
|
|
1474
|
+
return output && isStrict && dialect.strictMember ? dialect.strictMember(output, memberNode, cyclicSchemas) : output;
|
|
1475
|
+
}).map((output, index) => printNullable(nodeMembers[index], output)).filter(Boolean);
|
|
1624
1476
|
if (members.length === 0) return "";
|
|
1625
1477
|
if (members.length === 1) return members[0];
|
|
1626
|
-
if (isDiscriminated) return `z.discriminatedUnion(${
|
|
1478
|
+
if (isDiscriminated) return `z.discriminatedUnion(${_kubb_kit.text.quote(node.discriminatorPropertyName)}, ${buildList(members)})`;
|
|
1627
1479
|
if (isXor) return `z.xor(${buildList(members)})`;
|
|
1628
1480
|
return `z.union(${buildList(members)})`;
|
|
1629
1481
|
},
|
|
1630
1482
|
intersection(node) {
|
|
1631
1483
|
const members = node.members ?? [];
|
|
1632
1484
|
if (members.length === 0) return "";
|
|
1633
|
-
const hasSiblingProperties = members.some((member) => member.type === _kubb_kit.ast.
|
|
1485
|
+
const hasSiblingProperties = members.some((member) => member.type === _kubb_kit.ast.schema.types.object && member.properties.length > 0);
|
|
1634
1486
|
const transform = (member) => {
|
|
1635
1487
|
if (!hasSiblingProperties) return this.transform(member);
|
|
1636
1488
|
unionsWithSiblings.add(member);
|
|
@@ -1644,7 +1496,18 @@ function buildZodNodes(dialect, cyclicSchemas) {
|
|
|
1644
1496
|
if (!first) return "";
|
|
1645
1497
|
const firstBase = transform(first);
|
|
1646
1498
|
if (!firstBase) return "";
|
|
1647
|
-
if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemas))
|
|
1499
|
+
if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemas)) {
|
|
1500
|
+
const discriminator = _kubb_kit.ast.schema.narrow(first, _kubb_kit.ast.schema.types.union)?.discriminatorPropertyName;
|
|
1501
|
+
return preserveRequiredProperties(members).slice(1).reduce((acc, member) => {
|
|
1502
|
+
const object = _kubb_kit.ast.schema.narrow(member, _kubb_kit.ast.schema.types.object);
|
|
1503
|
+
if (!discriminator || !object?.properties.some((property) => property.name === discriminator)) return dialect.extend(acc, dialect.objectShape(this, member));
|
|
1504
|
+
const properties = object.properties.filter((property) => property.name !== discriminator);
|
|
1505
|
+
return properties.length ? dialect.extend(acc, dialect.objectShape(this, {
|
|
1506
|
+
...object,
|
|
1507
|
+
properties
|
|
1508
|
+
})) : acc;
|
|
1509
|
+
}, firstBase);
|
|
1510
|
+
}
|
|
1648
1511
|
return rest.reduce((acc, member) => {
|
|
1649
1512
|
const constraint = getMemberConstraint({
|
|
1650
1513
|
member,
|
|
@@ -1659,15 +1522,162 @@ function buildZodNodes(dialect, cyclicSchemas) {
|
|
|
1659
1522
|
}
|
|
1660
1523
|
};
|
|
1661
1524
|
}
|
|
1525
|
+
function containsCheck(ctx, { schema, min = 1, max }) {
|
|
1526
|
+
if (min === 0 && max === void 0) return null;
|
|
1527
|
+
const countBounds = [`count >= ${min}`, max !== void 0 && `count <= ${max}`].filter(Boolean).join(" && ");
|
|
1528
|
+
const message = max !== void 0 ? `Array must contain ${min} to ${max} matching items` : `Array must contain at least ${min} matching items`;
|
|
1529
|
+
return `(items) => { const count = items.filter((item) => ${ctx.transform(schema) ?? "z.unknown()"}.safeParse(item).success).length; return ${countBounds} }, { message: ${_kubb_kit.text.quote(message)} }`;
|
|
1530
|
+
}
|
|
1531
|
+
function conditionExpression(ctx, schema) {
|
|
1532
|
+
if (!schema) return "true";
|
|
1533
|
+
const object = _kubb_kit.ast.schema.narrow(schema, _kubb_kit.ast.schema.types.object);
|
|
1534
|
+
const keyOnlyNames = object?.properties.filter((property) => property.required && property.schema.type === _kubb_kit.ast.schema.types.unknown).map((property) => property.name) ?? [];
|
|
1535
|
+
const restSchema = object ? {
|
|
1536
|
+
...object,
|
|
1537
|
+
properties: object.properties.filter((property) => !keyOnlyNames.includes(property.name))
|
|
1538
|
+
} : schema;
|
|
1539
|
+
const isOnlyKeys = keyOnlyNames.length > 0 && restSchema.type === "object" && restSchema.properties.length === 0 && restSchema.additionalProperties === void 0 && !restSchema.patternProperties && !restSchema.propertyNames && !hasInputChecks(restSchema);
|
|
1540
|
+
return [keyOnlyNames.length > 0 && `typeof value === "object" && value !== null && ${JSON.stringify(keyOnlyNames)}.every((key) => key in value)`, !isOnlyKeys && `${ctx.transform(restSchema) ?? "z.unknown()"}.safeParse(value).success`].filter(Boolean).join(" && ");
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Wraps each handler so its output first checks the raw input, see {@link inputChecks}.
|
|
1544
|
+
*/
|
|
1545
|
+
function withInputChecks(nodes) {
|
|
1546
|
+
const wrapHandler = (type) => {
|
|
1547
|
+
const handler = nodes[type];
|
|
1548
|
+
if (!handler) return [];
|
|
1549
|
+
const checkedHandler = function(node) {
|
|
1550
|
+
const output = handler.call(this, node);
|
|
1551
|
+
if (!output || !hasInputChecks(node)) return output;
|
|
1552
|
+
return inputChecks({
|
|
1553
|
+
value: output,
|
|
1554
|
+
node,
|
|
1555
|
+
keySchema: hasKeyCheck(node) ? this.transform(node.propertyNames) : void 0,
|
|
1556
|
+
conditionals: (node.conditionals ?? []).map((entry) => `z.refine((value) => (${conditionExpression(this, entry.if)} ? ${conditionExpression(this, entry.then)} : ${conditionExpression(this, entry.else)}), { message: "Value does not meet a conditional schema" })`)
|
|
1557
|
+
});
|
|
1558
|
+
};
|
|
1559
|
+
return [[type, checkedHandler]];
|
|
1560
|
+
};
|
|
1561
|
+
return Object.fromEntries(Object.values(_kubb_kit.ast.schema.types).flatMap(wrapHandler));
|
|
1562
|
+
}
|
|
1563
|
+
// src/components/Zod.tsx
|
|
1564
|
+
/**
|
|
1565
|
+
* Whether the schema reaches a circular schema through its refs. `containsCircular` reads the refs the node holds,
|
|
1566
|
+
* while Zod refuses to compile a cycle anywhere below the root. A generated ref carries no target, so `siblings` resolves it.
|
|
1567
|
+
*/
|
|
1568
|
+
function reachesCycle({ node, siblings, cyclicSchemas, seen = /* @__PURE__ */ new Set() }) {
|
|
1569
|
+
if (!cyclicSchemas?.size || seen.has(node)) return false;
|
|
1570
|
+
seen.add(node);
|
|
1571
|
+
return _kubb_kit.ast.schema.find(node, {
|
|
1572
|
+
followRefs: true,
|
|
1573
|
+
predicate(schema) {
|
|
1574
|
+
if (schema.type !== _kubb_kit.ast.schema.types.ref) return false;
|
|
1575
|
+
const name = _kubb_kit.ast.ref.getName(schema);
|
|
1576
|
+
if (name && cyclicSchemas.has(name)) return true;
|
|
1577
|
+
const sibling = schema.ref || !schema.name ? void 0 : siblings?.get(schema.name);
|
|
1578
|
+
return !!sibling && reachesCycle({
|
|
1579
|
+
node: sibling,
|
|
1580
|
+
siblings,
|
|
1581
|
+
cyclicSchemas,
|
|
1582
|
+
seen
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
}) !== void 0;
|
|
1586
|
+
}
|
|
1587
|
+
function Zod({ name, node, printer, inferTypeName, inferKind = "infer", typeGuards, isName, assertName, mini, cyclic, compile, siblings }) {
|
|
1588
|
+
const output = printer.print(node);
|
|
1589
|
+
const printerImports = printer.drainImports();
|
|
1590
|
+
if (!output) return;
|
|
1591
|
+
const needsAnnotation = cyclic && node.type !== "object";
|
|
1592
|
+
const isAlias = _kubb_kit.ast.ref.isAlias(node, printer.options.keysToOmit);
|
|
1593
|
+
const isCyclic = Boolean(cyclic || printer.options.cyclicSchemas && _kubb_kit.ast.graph.containsCircular(node, { circularSchemas: printer.options.cyclicSchemas }));
|
|
1594
|
+
const isStrict = typeof compile === "object" && Boolean(compile.strict);
|
|
1595
|
+
const throwsOnCompile = isStrict && (throwsOnStrictCompile({
|
|
1596
|
+
node,
|
|
1597
|
+
options: printer.options,
|
|
1598
|
+
siblings
|
|
1599
|
+
}) || reachesCycle({
|
|
1600
|
+
node,
|
|
1601
|
+
siblings,
|
|
1602
|
+
cyclicSchemas: printer.options.cyclicSchemas
|
|
1603
|
+
}));
|
|
1604
|
+
const value = Boolean(compile) && !isAlias && !isCyclic && !throwsOnCompile ? isStrict ? `z.compile(${output}, { strict: true })` : `z.compile(${output})` : output;
|
|
1605
|
+
const targetType = inferTypeName ?? `z.infer<typeof ${name}>`;
|
|
1606
|
+
const shouldGenerateIs = isName && (typeof typeGuards === "object" ? typeGuards.is ?? true : Boolean(typeGuards));
|
|
1607
|
+
const shouldGenerateAssert = assertName && (typeof typeGuards === "object" ? typeGuards.assert ?? true : Boolean(typeGuards));
|
|
1608
|
+
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [
|
|
1609
|
+
printerImports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
1610
|
+
name: imp.name,
|
|
1611
|
+
path: imp.path,
|
|
1612
|
+
root: imp.root,
|
|
1613
|
+
isTypeOnly: imp.isTypeOnly,
|
|
1614
|
+
isNameSpace: imp.isNameSpace
|
|
1615
|
+
}, [
|
|
1616
|
+
name,
|
|
1617
|
+
imp.path,
|
|
1618
|
+
imp.name
|
|
1619
|
+
].join("-"))),
|
|
1620
|
+
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1621
|
+
name,
|
|
1622
|
+
isExportable: true,
|
|
1623
|
+
isIndexable: true,
|
|
1624
|
+
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
|
|
1625
|
+
export: true,
|
|
1626
|
+
name,
|
|
1627
|
+
type: needsAnnotation ? mini ? "z.ZodMiniType" : "z.ZodType" : void 0,
|
|
1628
|
+
children: value
|
|
1629
|
+
})
|
|
1630
|
+
}),
|
|
1631
|
+
inferTypeName && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1632
|
+
name: inferTypeName,
|
|
1633
|
+
isExportable: true,
|
|
1634
|
+
isIndexable: true,
|
|
1635
|
+
isTypeOnly: true,
|
|
1636
|
+
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Type, {
|
|
1637
|
+
export: true,
|
|
1638
|
+
name: inferTypeName,
|
|
1639
|
+
children: `z.${inferKind}<typeof ${name}>`
|
|
1640
|
+
})
|
|
1641
|
+
}),
|
|
1642
|
+
shouldGenerateIs && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1643
|
+
name: isName,
|
|
1644
|
+
isExportable: true,
|
|
1645
|
+
isIndexable: true,
|
|
1646
|
+
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
|
|
1647
|
+
export: true,
|
|
1648
|
+
name: isName,
|
|
1649
|
+
JSDoc: { comments: [`Type guard for {@link ${name}}`] },
|
|
1650
|
+
children: mini ? `(data: unknown): data is ${targetType} => z.validate(${name}, data)` : `(data: unknown): data is ${targetType} => ${name}.validate(data)`
|
|
1651
|
+
})
|
|
1652
|
+
}),
|
|
1653
|
+
shouldGenerateAssert && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
|
|
1654
|
+
name: assertName,
|
|
1655
|
+
isExportable: true,
|
|
1656
|
+
isIndexable: true,
|
|
1657
|
+
children: /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Function, {
|
|
1658
|
+
export: true,
|
|
1659
|
+
name: assertName,
|
|
1660
|
+
params: "data: unknown",
|
|
1661
|
+
returnType: `asserts data is ${targetType}`,
|
|
1662
|
+
JSDoc: { comments: [`Asserter for {@link ${name}}`, "@throws {z.ZodError} If data is invalid"] },
|
|
1663
|
+
children: mini ? `if (!z.validate(${name}, data)) {\n z.parse(${name}, data)\n}` : `if (!${name}.validate(data)) {\n ${name}.parse(data)\n}`
|
|
1664
|
+
})
|
|
1665
|
+
})
|
|
1666
|
+
] });
|
|
1667
|
+
}
|
|
1662
1668
|
// src/printers/printerZod.ts
|
|
1663
1669
|
function strictOneOfMember(member, node, cyclicSchemas) {
|
|
1664
|
-
if (node.type === _kubb_kit.ast.
|
|
1670
|
+
if (node.type === _kubb_kit.ast.schema.types.ref) {
|
|
1665
1671
|
if (member.startsWith("z.lazy(")) return member;
|
|
1666
|
-
const refName = _kubb_kit.ast.
|
|
1672
|
+
const refName = _kubb_kit.ast.ref.getName(node);
|
|
1667
1673
|
if (refName && cyclicSchemas?.has(refName)) return member;
|
|
1668
|
-
const schema =
|
|
1674
|
+
const schema = _kubb_kit.ast.ref.mergeSchema(node);
|
|
1669
1675
|
if (schema.nullable || schema.optional || node.nullable || node.optional) return member;
|
|
1670
|
-
if (schema.type === _kubb_kit.ast.
|
|
1676
|
+
if (schema.type === _kubb_kit.ast.schema.types.object && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) {
|
|
1677
|
+
const checks = [node, node.schema].filter((entry) => entry && hasInputChecks(entry)).length;
|
|
1678
|
+
if (checks === 2) return member;
|
|
1679
|
+
return checks ? `z.pipe(${member}.in, ${member}.out.strict())` : `${member}.strict()`;
|
|
1680
|
+
}
|
|
1671
1681
|
}
|
|
1672
1682
|
return member;
|
|
1673
1683
|
}
|
|
@@ -1683,7 +1693,7 @@ function buildZodObjectShape(ctx, node) {
|
|
|
1683
1693
|
optional: schema.optional || required === false,
|
|
1684
1694
|
nullish: schema.nullish,
|
|
1685
1695
|
defaultValue: meta.default,
|
|
1686
|
-
description: schema.type !== _kubb_kit.ast.
|
|
1696
|
+
description: schema.type !== _kubb_kit.ast.schema.types.ref && meta.type === _kubb_kit.ast.schema.types.ref ? void 0 : meta.description,
|
|
1687
1697
|
examples: meta.examples
|
|
1688
1698
|
});
|
|
1689
1699
|
if (!cyclic) return `${objectKey(name)}: ${body}`;
|
|
@@ -1704,21 +1714,22 @@ function buildZodObjectShape(ctx, node) {
|
|
|
1704
1714
|
function recursiveGetterType({ ctx, schema, required }) {
|
|
1705
1715
|
function baseType(schema) {
|
|
1706
1716
|
if (ctx.options.nodes?.[schema.type]) return void 0;
|
|
1707
|
-
if (schema.type === _kubb_kit.ast.
|
|
1717
|
+
if (schema.type === _kubb_kit.ast.schema.types.ref) {
|
|
1708
1718
|
const saved = ctx.options.cyclicSchemas;
|
|
1709
1719
|
ctx.options.cyclicSchemas = void 0;
|
|
1710
1720
|
const name = ctx.transform(schema);
|
|
1711
1721
|
ctx.options.cyclicSchemas = saved;
|
|
1712
1722
|
return name ? `typeof ${name}` : void 0;
|
|
1713
1723
|
}
|
|
1714
|
-
if (schema.type === _kubb_kit.ast.
|
|
1724
|
+
if (schema.type === _kubb_kit.ast.schema.types.array && schema.items?.length === 1) {
|
|
1715
1725
|
const item = baseType(schema.items[0]);
|
|
1716
|
-
|
|
1726
|
+
if (!item) return void 0;
|
|
1727
|
+
return `z.ZodArray<${schema.items[0].nullable ? `z.ZodNullable<${item}>` : item}>`;
|
|
1717
1728
|
}
|
|
1718
1729
|
}
|
|
1719
1730
|
const base = baseType(schema);
|
|
1720
1731
|
if (!base) return void 0;
|
|
1721
|
-
const meta =
|
|
1732
|
+
const meta = _kubb_kit.ast.ref.mergeSchema(schema);
|
|
1722
1733
|
const optional = schema.optional || required === false;
|
|
1723
1734
|
const wrapped = (() => {
|
|
1724
1735
|
if (schema.nullish || meta.nullable && optional) return `z.ZodOptional<z.ZodNullable<${base}>>`;
|
|
@@ -1733,12 +1744,12 @@ function recursiveGetterType({ ctx, schema, required }) {
|
|
|
1733
1744
|
* `direction` themselves, so {@link containsDirectionalNode} probes their children instead.
|
|
1734
1745
|
*/
|
|
1735
1746
|
const CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
1736
|
-
_kubb_kit.ast.
|
|
1737
|
-
_kubb_kit.ast.
|
|
1738
|
-
_kubb_kit.ast.
|
|
1739
|
-
_kubb_kit.ast.
|
|
1740
|
-
_kubb_kit.ast.
|
|
1741
|
-
_kubb_kit.ast.
|
|
1747
|
+
_kubb_kit.ast.schema.types.object,
|
|
1748
|
+
_kubb_kit.ast.schema.types.array,
|
|
1749
|
+
_kubb_kit.ast.schema.types.tuple,
|
|
1750
|
+
_kubb_kit.ast.schema.types.union,
|
|
1751
|
+
_kubb_kit.ast.schema.types.intersection,
|
|
1752
|
+
_kubb_kit.ast.schema.types.ref
|
|
1742
1753
|
]);
|
|
1743
1754
|
/**
|
|
1744
1755
|
* Runs the node's effective handler (a `printer.nodes` override, else the built-in) once per
|
|
@@ -1769,22 +1780,31 @@ function variesByDirection({ node, printerOptions }) {
|
|
|
1769
1780
|
*/
|
|
1770
1781
|
function containsDirectionalNode({ node, printerOptions }) {
|
|
1771
1782
|
if (!node) return false;
|
|
1772
|
-
return _kubb_kit.ast.
|
|
1783
|
+
return _kubb_kit.ast.schema.find(node, {
|
|
1773
1784
|
predicate: (schema) => variesByDirection({
|
|
1774
1785
|
node: schema,
|
|
1775
1786
|
printerOptions
|
|
1776
1787
|
}),
|
|
1777
|
-
followRefs: true
|
|
1788
|
+
followRefs: true,
|
|
1789
|
+
cache: getDirectionalCache(printerOptions)
|
|
1778
1790
|
}) !== void 0;
|
|
1779
1791
|
}
|
|
1780
1792
|
/**
|
|
1793
|
+
* The `find` cache for {@link containsDirectionalNode}, one per plugin per build and per option set
|
|
1794
|
+
* the probe reads. A `printer.nodes` override has no string key, so it searches without a cache.
|
|
1795
|
+
*/
|
|
1796
|
+
function getDirectionalCache({ resolver, nodes, coercion, dateType }) {
|
|
1797
|
+
if (!resolver || nodes) return void 0;
|
|
1798
|
+
return resolver.memo(`zodDirectionalNodes:${shouldCoerce(coercion, "dates")}:${dateType}`, () => /* @__PURE__ */ new WeakMap());
|
|
1799
|
+
}
|
|
1800
|
+
/**
|
|
1781
1801
|
* Names of the `$ref` schemas the generator should route to their input (encode) variant.
|
|
1782
1802
|
*/
|
|
1783
1803
|
function collectDirectionalRefNames({ node, printerOptions }) {
|
|
1784
|
-
return _kubb_kit.ast.
|
|
1804
|
+
return _kubb_kit.ast.node.collect(node, { schema: (n) => n.type === _kubb_kit.ast.schema.types.ref && n.ref && containsDirectionalNode({
|
|
1785
1805
|
node: n,
|
|
1786
1806
|
printerOptions
|
|
1787
|
-
}) ? _kubb_kit.ast.
|
|
1807
|
+
}) ? _kubb_kit.ast.ref.getName(n) ?? void 0 : void 0 });
|
|
1788
1808
|
}
|
|
1789
1809
|
/**
|
|
1790
1810
|
* Handlers that never recurse into children, so {@link variesByDirection} can call one directly
|
|
@@ -1806,6 +1826,7 @@ const standardDialect = {
|
|
|
1806
1826
|
coercedNumber: (schema) => `z.coerce.number().pipe(${schema})`,
|
|
1807
1827
|
catchall: (object, value) => `${object}.catchall(${value})`,
|
|
1808
1828
|
nullable: (value) => `${value}.nullable()`,
|
|
1829
|
+
refine: (value, check) => `${value}.refine(${check})`,
|
|
1809
1830
|
unique: (array) => `${array}.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" })`,
|
|
1810
1831
|
extend: (base, shape) => `${base}.extend(${shape})`,
|
|
1811
1832
|
intersection: (left, right) => `${left}.and(${right})`,
|
|
@@ -1817,8 +1838,8 @@ const standardDialect = {
|
|
|
1817
1838
|
};
|
|
1818
1839
|
const scalarNodes = {
|
|
1819
1840
|
...buildScalarNodes(standardDialect),
|
|
1820
|
-
bigint() {
|
|
1821
|
-
return
|
|
1841
|
+
bigint(node) {
|
|
1842
|
+
return `z.coerce.bigint()${numberConstraints(bigintConstraints(node), "n")}`;
|
|
1822
1843
|
},
|
|
1823
1844
|
date(node) {
|
|
1824
1845
|
if (node.representation !== "date") return "z.iso.date()";
|
|
@@ -1851,14 +1872,14 @@ const scalarNodes = {
|
|
|
1851
1872
|
* const code = printer.print(stringNode) // "z.string()"
|
|
1852
1873
|
* ```
|
|
1853
1874
|
*/
|
|
1854
|
-
const printerZod = _kubb_kit.
|
|
1875
|
+
const printerZod = (0, _kubb_kit.createPrinter)((options) => {
|
|
1855
1876
|
return {
|
|
1856
1877
|
name: "zod",
|
|
1857
1878
|
options,
|
|
1858
|
-
nodes: {
|
|
1879
|
+
nodes: withInputChecks({
|
|
1859
1880
|
...buildZodNodes(standardDialect, options.cyclicSchemas),
|
|
1860
1881
|
...scalarNodes
|
|
1861
|
-
},
|
|
1882
|
+
}),
|
|
1862
1883
|
overrides: options.nodes,
|
|
1863
1884
|
print(node) {
|
|
1864
1885
|
return printWithOmit(this, node, (value, meta) => applyModifiers({
|
|
@@ -1915,18 +1936,19 @@ const miniDialect = {
|
|
|
1915
1936
|
coercedNumber: (schema) => `z.pipe(z.coerce.number(), ${schema})`,
|
|
1916
1937
|
catchall: (object, value) => `z.catchall(${object}, ${value})`,
|
|
1917
1938
|
nullable: (value) => `z.nullable(${value})`,
|
|
1939
|
+
refine: (value, check) => `${value}.check(z.refine(${check}))`,
|
|
1918
1940
|
unique: (array) => `${array}.check(z.refine(items => new Set(items).size === items.length, { message: "Array entries must be unique" }))`,
|
|
1919
1941
|
extend: (base, shape) => `z.extend(${base}, ${shape})`,
|
|
1920
1942
|
intersection: (left, right) => `z.intersection(${left}, ${right})`
|
|
1921
1943
|
};
|
|
1922
|
-
const printerZodMini = _kubb_kit.
|
|
1944
|
+
const printerZodMini = (0, _kubb_kit.createPrinter)((options) => {
|
|
1923
1945
|
return {
|
|
1924
1946
|
name: "zod-mini",
|
|
1925
1947
|
options,
|
|
1926
|
-
nodes: {
|
|
1948
|
+
nodes: withInputChecks({
|
|
1927
1949
|
...buildZodNodes(miniDialect, options.cyclicSchemas),
|
|
1928
1950
|
bigint(node) {
|
|
1929
|
-
return `z.coerce.bigint()${numberChecksMini(node)}`;
|
|
1951
|
+
return `z.coerce.bigint()${numberChecksMini(bigintConstraints(node), "n")}`;
|
|
1930
1952
|
},
|
|
1931
1953
|
date(node) {
|
|
1932
1954
|
if (node.representation === "string") return "z.iso.date()";
|
|
@@ -1939,7 +1961,7 @@ const printerZodMini = _kubb_kit.ast.createPrinter((options) => {
|
|
|
1939
1961
|
if (node.representation === "string") return "z.iso.time()";
|
|
1940
1962
|
return "z.date()";
|
|
1941
1963
|
}
|
|
1942
|
-
},
|
|
1964
|
+
}),
|
|
1943
1965
|
overrides: options.nodes,
|
|
1944
1966
|
print(node) {
|
|
1945
1967
|
return printWithOmit(this, node, (value, meta) => applyMiniModifiers({
|
|
@@ -2026,7 +2048,8 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2026
2048
|
node,
|
|
2027
2049
|
root,
|
|
2028
2050
|
output,
|
|
2029
|
-
group: group ?? void 0
|
|
2051
|
+
group: group ?? void 0,
|
|
2052
|
+
checks: true
|
|
2030
2053
|
});
|
|
2031
2054
|
const inputImportEntries = hasDirectionalNode ? [...directionalRefNames].map((schemaName) => ({
|
|
2032
2055
|
name: [resolver.schema.inputName(schemaName)],
|
|
@@ -2117,7 +2140,7 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2117
2140
|
});
|
|
2118
2141
|
},
|
|
2119
2142
|
operation(node, ctx) {
|
|
2120
|
-
if (!_kubb_kit.ast.
|
|
2143
|
+
if (!_kubb_kit.ast.http.isOperation(node)) return null;
|
|
2121
2144
|
const { adapter, config, resolver, root } = ctx;
|
|
2122
2145
|
const { output, coercion, guidType, regexType, oneOfType, compile, mini, inferred, importPath, group, printer } = ctx.options;
|
|
2123
2146
|
const dateType = getOasAdapter(adapter).options.dateType;
|
|
@@ -2140,23 +2163,26 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2140
2163
|
cyclicSchemas: getCircularNames(ctx),
|
|
2141
2164
|
nodes: printer?.nodes
|
|
2142
2165
|
};
|
|
2166
|
+
const siblings = /* @__PURE__ */ new Map();
|
|
2143
2167
|
function renderSchemaEntry({ schema, name, keysToOmit, direction = "decode" }) {
|
|
2144
2168
|
if (!schema) return null;
|
|
2169
|
+
siblings.set(name, schema);
|
|
2145
2170
|
const directionalRefNames = direction === "encode" && !mini ? new Set(collectDirectionalRefNames({
|
|
2146
2171
|
node: schema,
|
|
2147
2172
|
printerOptions
|
|
2148
2173
|
})) : null;
|
|
2174
|
+
const schemaPrinter = getPrinter(resolver, {
|
|
2175
|
+
...printerOptions,
|
|
2176
|
+
keysToOmit
|
|
2177
|
+
}, mini, direction);
|
|
2149
2178
|
const imports = resolver.imports({
|
|
2150
2179
|
node: schema,
|
|
2151
2180
|
root,
|
|
2152
2181
|
output,
|
|
2153
2182
|
group: group ?? void 0,
|
|
2183
|
+
checks: true,
|
|
2154
2184
|
name: (schemaName) => directionalRefNames?.has(schemaName) ? resolver.schema.inputName(schemaName) : resolver.name(schemaName)
|
|
2155
2185
|
});
|
|
2156
|
-
const schemaPrinter = getPrinter(resolver, {
|
|
2157
|
-
...printerOptions,
|
|
2158
|
-
keysToOmit
|
|
2159
|
-
}, mini, direction);
|
|
2160
2186
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx_jsx_runtime.Fragment, { children: [imports.map((imp) => /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
2161
2187
|
root: meta.file.path,
|
|
2162
2188
|
path: imp.path,
|
|
@@ -2172,7 +2198,8 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2172
2198
|
inferTypeName: inferred ? resolver.schema.type(name) : null,
|
|
2173
2199
|
inferKind: aliasKind(inferred, direction),
|
|
2174
2200
|
cyclic: false,
|
|
2175
|
-
compile
|
|
2201
|
+
compile,
|
|
2202
|
+
siblings
|
|
2176
2203
|
})] });
|
|
2177
2204
|
}
|
|
2178
2205
|
function buildContentTypeVariants(entries, baseName, decorate, direction) {
|
|
@@ -2196,7 +2223,7 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2196
2223
|
})] });
|
|
2197
2224
|
}
|
|
2198
2225
|
function buildResponseUnion({ responses, name, fallbackUnknown }) {
|
|
2199
|
-
if (new Set(
|
|
2226
|
+
if (new Set(_kubb_kit.ast.http.responses.getImportedNames(responses).map((refName) => resolver.name(refName))).has(name)) return null;
|
|
2200
2227
|
const members = responses.map((res) => _kubb_kit.ast.factory.createSchema({
|
|
2201
2228
|
type: "ref",
|
|
2202
2229
|
name: resolver.response.status(node, res.statusCode)
|
|
@@ -2229,14 +2256,27 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2229
2256
|
keysToOmit: primary?.keysToOmit
|
|
2230
2257
|
});
|
|
2231
2258
|
});
|
|
2259
|
+
const toParamsSchema = (params) => _kubb_kit.ast.factory.createSchema({
|
|
2260
|
+
type: "object",
|
|
2261
|
+
primitive: "object",
|
|
2262
|
+
properties: params.map((param) => _kubb_kit.ast.factory.createProperty({
|
|
2263
|
+
name: param.name,
|
|
2264
|
+
required: param.required,
|
|
2265
|
+
schema: param.schema
|
|
2266
|
+
}))
|
|
2267
|
+
});
|
|
2268
|
+
const responseHeaderSchemas = node.responses.map((res) => res.headers?.length ? renderSchemaEntry({
|
|
2269
|
+
schema: toParamsSchema(res.headers),
|
|
2270
|
+
name: resolver.response.headers(node, res.statusCode)
|
|
2271
|
+
}) : null);
|
|
2232
2272
|
const responsesWithSchema = node.responses.filter((res) => res.content?.some((entry) => entry.schema));
|
|
2233
|
-
const successResponsesWithSchema =
|
|
2273
|
+
const successResponsesWithSchema = responsesWithSchema.filter((res) => _kubb_kit.ast.http.status.isSuccess(res));
|
|
2234
2274
|
const responseUnionSchema = responsesWithSchema.length > 0 ? buildResponseUnion({
|
|
2235
2275
|
responses: successResponsesWithSchema,
|
|
2236
2276
|
name: resolver.response.response(node),
|
|
2237
2277
|
fallbackUnknown: true
|
|
2238
2278
|
}) : null;
|
|
2239
|
-
const errorResponsesWithSchema = responsesWithSchema.filter((res) => !
|
|
2279
|
+
const errorResponsesWithSchema = responsesWithSchema.filter((res) => !_kubb_kit.ast.http.status.isSuccess(res));
|
|
2240
2280
|
const errorUnionSchema = errorResponsesWithSchema.length > 0 ? buildResponseUnion({
|
|
2241
2281
|
responses: errorResponsesWithSchema,
|
|
2242
2282
|
name: resolver.response.error(node),
|
|
@@ -2263,7 +2303,7 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2263
2303
|
description: node.requestBody.description ?? schema.description
|
|
2264
2304
|
}), "encode");
|
|
2265
2305
|
})();
|
|
2266
|
-
const { path, query, header, cookie } =
|
|
2306
|
+
const { path, query, header, cookie } = _kubb_kit.ast.http.groupParameters(node);
|
|
2267
2307
|
const paramGroupSchemas = [
|
|
2268
2308
|
{
|
|
2269
2309
|
kind: "path",
|
|
@@ -2282,15 +2322,7 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2282
2322
|
params: cookie
|
|
2283
2323
|
}
|
|
2284
2324
|
].filter(({ params }) => params.length > 0).map(({ kind, params }) => renderSchemaEntry({
|
|
2285
|
-
schema:
|
|
2286
|
-
type: "object",
|
|
2287
|
-
primitive: "object",
|
|
2288
|
-
properties: params.map((param) => _kubb_kit.ast.factory.createProperty({
|
|
2289
|
-
name: param.name,
|
|
2290
|
-
required: param.required,
|
|
2291
|
-
schema: param.schema
|
|
2292
|
-
}))
|
|
2293
|
-
}),
|
|
2325
|
+
schema: toParamsSchema(params),
|
|
2294
2326
|
name: resolver.param[kind](node, params[0]),
|
|
2295
2327
|
direction: "encode"
|
|
2296
2328
|
}));
|
|
@@ -2331,6 +2363,7 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2331
2363
|
}),
|
|
2332
2364
|
paramSchemas,
|
|
2333
2365
|
responseSchemas,
|
|
2366
|
+
responseHeaderSchemas,
|
|
2334
2367
|
responseUnionSchema,
|
|
2335
2368
|
errorUnionSchema,
|
|
2336
2369
|
requestSchema,
|
|
@@ -2343,11 +2376,11 @@ const zodGenerator = (0, _kubb_kit.defineGenerator)({
|
|
|
2343
2376
|
});
|
|
2344
2377
|
// kubb-extension.json
|
|
2345
2378
|
var compatibility = {
|
|
2346
|
-
"kubb": ">=5.
|
|
2379
|
+
"kubb": ">=5.18.4",
|
|
2347
2380
|
"node": ">=22.22"
|
|
2348
2381
|
};
|
|
2349
2382
|
// package.json
|
|
2350
|
-
var version = "5.9.
|
|
2383
|
+
var version = "5.9.1";
|
|
2351
2384
|
// src/resolvers/resolverZod.ts
|
|
2352
2385
|
/**
|
|
2353
2386
|
* Default resolver used by `@kubb/plugin-zod`. Decides the names and file
|
|
@@ -2367,15 +2400,15 @@ var version = "5.9.0-canary.20261111T122006";
|
|
|
2367
2400
|
const resolverZod = (0, _kubb_kit.createResolver)({
|
|
2368
2401
|
pluginName: "plugin-zod",
|
|
2369
2402
|
name(name) {
|
|
2370
|
-
return this.memo(`name:${name}`, () => ensureValidVarName(
|
|
2403
|
+
return this.memo(`name:${name}`, () => ensureValidVarName(_kubb_kit.casing.camel(name, { suffix: "schema" })));
|
|
2371
2404
|
},
|
|
2372
|
-
file: createCasedFile((part) =>
|
|
2405
|
+
file: createCasedFile((part) => _kubb_kit.casing.camel(part, { suffix: "schema" })),
|
|
2373
2406
|
schema: {
|
|
2374
2407
|
typeName(name) {
|
|
2375
|
-
return this.memo(`typeName:${name}`, () => ensureValidVarName(
|
|
2408
|
+
return this.memo(`typeName:${name}`, () => ensureValidVarName(_kubb_kit.casing.pascal(name, { suffix: "schema type" })));
|
|
2376
2409
|
},
|
|
2377
2410
|
type(name) {
|
|
2378
|
-
return this.memo(`type:${name}`, () => ensureValidVarName(
|
|
2411
|
+
return this.memo(`type:${name}`, () => ensureValidVarName(_kubb_kit.casing.pascal(name, { suffix: "type" })));
|
|
2379
2412
|
},
|
|
2380
2413
|
inputName(name) {
|
|
2381
2414
|
return this.name(`${name} input`);
|
|
@@ -2384,10 +2417,10 @@ const resolverZod = (0, _kubb_kit.createResolver)({
|
|
|
2384
2417
|
return this.schema.typeName(`${name} input`);
|
|
2385
2418
|
},
|
|
2386
2419
|
isName(name) {
|
|
2387
|
-
return ensureValidVarName(
|
|
2420
|
+
return ensureValidVarName(_kubb_kit.casing.camel(name, { prefix: "is" }));
|
|
2388
2421
|
},
|
|
2389
2422
|
assertName(name) {
|
|
2390
|
-
return ensureValidVarName(
|
|
2423
|
+
return ensureValidVarName(_kubb_kit.casing.camel(name, { prefix: "assert" }));
|
|
2391
2424
|
}
|
|
2392
2425
|
},
|
|
2393
2426
|
param: createOperationParamResolver(),
|
|
@@ -2461,7 +2494,7 @@ const pluginZod = (0, _kubb_kit.defineExtension)({
|
|
|
2461
2494
|
exclude,
|
|
2462
2495
|
include,
|
|
2463
2496
|
override,
|
|
2464
|
-
group:
|
|
2497
|
+
group: group ?? null,
|
|
2465
2498
|
importPath,
|
|
2466
2499
|
coercion,
|
|
2467
2500
|
inferred: inferred === "direction" ? "codec" : inferred,
|