@kubb/plugin-zod 5.7.2 → 5.7.4
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 +434 -243
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -12
- package/dist/index.d.ts +4 -12
- package/dist/index.js +429 -238
- package/dist/index.js.map +1 -1
- package/kubb-extension.json +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -2,11 +2,10 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
//#endregion
|
|
6
5
|
let kubb_kit = require("kubb/kit");
|
|
7
6
|
let kubb_jsx = require("kubb/jsx");
|
|
8
7
|
let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
|
|
9
|
-
|
|
8
|
+
// ../../internals/shared/src/operation.ts
|
|
10
9
|
/**
|
|
11
10
|
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
12
11
|
* (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
|
|
@@ -89,7 +88,10 @@ function getOperationParameters(node) {
|
|
|
89
88
|
* shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
|
|
90
89
|
* printer to emit `z.object(…)` rather than a record.
|
|
91
90
|
*/
|
|
92
|
-
function
|
|
91
|
+
function hasRequestContentTypeChoice(node) {
|
|
92
|
+
return (node.requestBody?.content ?? []).filter((entry) => entry.schema).length > 1;
|
|
93
|
+
}
|
|
94
|
+
function buildOptionsSchema(node, resolver, { pairContentTypes = false } = {}) {
|
|
93
95
|
const { path, query, header } = getOperationParameters(node);
|
|
94
96
|
const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
95
97
|
const createNever = () => kubb_kit.ast.factory.createSchema({
|
|
@@ -114,29 +116,57 @@ function buildOptionsSchema(node, resolver) {
|
|
|
114
116
|
resolve: resolver.param.headers
|
|
115
117
|
}
|
|
116
118
|
];
|
|
117
|
-
|
|
119
|
+
const createOptions = (body, extra = []) => kubb_kit.ast.factory.createSchema({
|
|
118
120
|
type: "object",
|
|
119
121
|
primitive: "object",
|
|
120
122
|
deprecated: node.deprecated,
|
|
121
|
-
properties: [
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
|
|
123
|
+
properties: [
|
|
124
|
+
kubb_kit.ast.factory.createProperty({
|
|
125
|
+
name: "body",
|
|
126
|
+
required: hasBody,
|
|
127
|
+
schema: body
|
|
128
|
+
}),
|
|
129
|
+
...groups.map(({ name, params, resolve }) => {
|
|
130
|
+
const required = params.some((param) => param.required);
|
|
131
|
+
return kubb_kit.ast.factory.createProperty({
|
|
132
|
+
name,
|
|
133
|
+
required,
|
|
134
|
+
schema: params.length > 0 ? kubb_kit.ast.factory.createSchema({
|
|
135
|
+
type: "ref",
|
|
136
|
+
name: resolve.call(resolver.param, node, params[0]),
|
|
137
|
+
optional: !required
|
|
138
|
+
}) : createNever()
|
|
139
|
+
});
|
|
140
|
+
}),
|
|
141
|
+
...extra
|
|
142
|
+
]
|
|
143
|
+
});
|
|
144
|
+
const variants = pairContentTypes && hasRequestContentTypeChoice(node) ? resolveContentTypeVariants(node.requestBody?.content ?? [], resolver.response.body(node)) : [];
|
|
145
|
+
if (variants.length < 2) return createOptions(hasBody ? kubb_kit.ast.factory.createSchema({
|
|
146
|
+
type: "ref",
|
|
147
|
+
name: resolver.response.body(node)
|
|
148
|
+
}) : createNever());
|
|
149
|
+
return kubb_kit.ast.factory.createSchema({
|
|
150
|
+
type: "union",
|
|
151
|
+
members: variants.map((variant, index) => createOptions(kubb_kit.ast.factory.createSchema({
|
|
152
|
+
type: "ref",
|
|
153
|
+
name: variant.name
|
|
154
|
+
}), [kubb_kit.ast.factory.createProperty({
|
|
155
|
+
name: "contentType",
|
|
156
|
+
required: index > 0,
|
|
157
|
+
schema: kubb_kit.ast.factory.createSchema({
|
|
158
|
+
type: "object",
|
|
159
|
+
primitive: "object",
|
|
160
|
+
properties: [kubb_kit.ast.factory.createProperty({
|
|
161
|
+
name: "request",
|
|
162
|
+
required: true,
|
|
163
|
+
schema: kubb_kit.ast.factory.createSchema({
|
|
164
|
+
type: "enum",
|
|
165
|
+
enumValues: [variant.contentType]
|
|
166
|
+
})
|
|
167
|
+
})]
|
|
168
|
+
})
|
|
169
|
+
})]))
|
|
140
170
|
});
|
|
141
171
|
}
|
|
142
172
|
/**
|
|
@@ -206,8 +236,7 @@ function isSuccessStatusCode(statusCode) {
|
|
|
206
236
|
function getSuccessResponses(responses) {
|
|
207
237
|
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
208
238
|
}
|
|
209
|
-
|
|
210
|
-
//#region ../../internals/shared/src/adapter.ts
|
|
239
|
+
// ../../internals/shared/src/adapter.ts
|
|
211
240
|
/**
|
|
212
241
|
* Narrows the generic `Adapter` from a generator context to the OpenAPI adapter,
|
|
213
242
|
* so OAS-only options (`dateType`, `enums`) and the parsed `document` are typed.
|
|
@@ -230,58 +259,7 @@ function getOasAdapter(adapter) {
|
|
|
230
259
|
});
|
|
231
260
|
return adapter;
|
|
232
261
|
}
|
|
233
|
-
|
|
234
|
-
//#region ../../internals/utils/src/casing.ts
|
|
235
|
-
/**
|
|
236
|
-
* Shared implementation for camelCase and PascalCase conversion.
|
|
237
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
238
|
-
* and capitalizes each word according to `pascal`.
|
|
239
|
-
*
|
|
240
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
241
|
-
*/
|
|
242
|
-
function convert(text, pascal) {
|
|
243
|
-
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
244
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
245
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
246
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
247
|
-
}
|
|
248
|
-
const cache = /* @__PURE__ */ new Map();
|
|
249
|
-
const cacheLimit = 1e4;
|
|
250
|
-
function toCamelOrPascal(text, pascal) {
|
|
251
|
-
const key = `${pascal ? "P" : "c"}${text}`;
|
|
252
|
-
const cached = cache.get(key);
|
|
253
|
-
if (cached !== void 0) return cached;
|
|
254
|
-
const result = convert(text, pascal);
|
|
255
|
-
if (cache.size >= cacheLimit) cache.clear();
|
|
256
|
-
cache.set(key, result);
|
|
257
|
-
return result;
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Converts `text` to camelCase.
|
|
261
|
-
*
|
|
262
|
-
* @example Word boundaries
|
|
263
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
264
|
-
*
|
|
265
|
-
* @example With a prefix
|
|
266
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
267
|
-
*/
|
|
268
|
-
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
269
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Converts `text` to PascalCase.
|
|
273
|
-
*
|
|
274
|
-
* @example Word boundaries
|
|
275
|
-
* `pascalCase('hello-world') // 'HelloWorld'`
|
|
276
|
-
*
|
|
277
|
-
* @example With a suffix
|
|
278
|
-
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
|
|
279
|
-
*/
|
|
280
|
-
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
281
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
282
|
-
}
|
|
283
|
-
//#endregion
|
|
284
|
-
//#region ../../internals/utils/src/reserved.ts
|
|
262
|
+
// ../../internals/utils/src/reserved.ts
|
|
285
263
|
/**
|
|
286
264
|
* JavaScript and Java reserved words.
|
|
287
265
|
* @link https://github.com/jonschlinkert/reserved/blob/master/index.js
|
|
@@ -289,6 +267,7 @@ function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
|
289
267
|
const reservedWords = /* @__PURE__ */ new Set([
|
|
290
268
|
"abstract",
|
|
291
269
|
"arguments",
|
|
270
|
+
"await",
|
|
292
271
|
"boolean",
|
|
293
272
|
"break",
|
|
294
273
|
"byte",
|
|
@@ -419,8 +398,7 @@ function ensureValidVarName(name) {
|
|
|
419
398
|
function isIdentifier(name) {
|
|
420
399
|
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
421
400
|
}
|
|
422
|
-
|
|
423
|
-
//#region ../../internals/utils/src/strings.ts
|
|
401
|
+
// ../../internals/utils/src/strings.ts
|
|
424
402
|
/**
|
|
425
403
|
* Wraps a value in single quotes for emitting a single-quoted JavaScript string literal, escaping
|
|
426
404
|
* any backslash or single quote in the content.
|
|
@@ -469,6 +447,34 @@ function stringify(value) {
|
|
|
469
447
|
if (value === void 0 || value === null) return "''";
|
|
470
448
|
return `'${JSON.stringify(trimQuotes(value.toString())).slice(1, -1).replace(/\\"/g, "\"").replace(/'/g, "\\'")}'`;
|
|
471
449
|
}
|
|
450
|
+
const NEEDS_UNICODE = /(?<!\\)(?:\\\\)*\\[pPu]\{|[\u{10000}-\u{10FFFF}]/u;
|
|
451
|
+
const KEPT_ESCAPE = /[A-Za-z0-9^$\\.*+?()[\]{}|/]/;
|
|
452
|
+
/**
|
|
453
|
+
* Drops the backslash from escapes that the `u` flag rejects: an escaped punctuation character that is
|
|
454
|
+
* not a syntax character, and `\-` outside a class. Both match the same character without the backslash.
|
|
455
|
+
*/
|
|
456
|
+
function dropIdentityEscapes(pattern) {
|
|
457
|
+
let inClass = false;
|
|
458
|
+
return pattern.replace(/\\(.)|[[\]]/gs, (match, escaped) => {
|
|
459
|
+
if (escaped === void 0) {
|
|
460
|
+
inClass = match === "[";
|
|
461
|
+
return match;
|
|
462
|
+
}
|
|
463
|
+
return KEPT_ESCAPE.test(escaped) || escaped === "-" && inClass ? match : escaped;
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Builds the `RegExp` for a pattern, adding the `u` flag when it uses `\p{...}`, `\P{...}` or `\u{...}`, or
|
|
468
|
+
* holds a character outside the BMP. A pattern that is not valid under `u` keeps the flags it came with.
|
|
469
|
+
*/
|
|
470
|
+
function toRegExp(pattern, flags) {
|
|
471
|
+
if (flags?.includes("u") || !NEEDS_UNICODE.test(pattern)) return new RegExp(pattern, flags);
|
|
472
|
+
try {
|
|
473
|
+
return new RegExp(dropIdentityEscapes(pattern), `${flags ?? ""}u`);
|
|
474
|
+
} catch {
|
|
475
|
+
return new RegExp(pattern, flags);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
472
478
|
/**
|
|
473
479
|
* Converts a pattern string into a `new RegExp(...)` constructor call or a regex literal string.
|
|
474
480
|
* Inline flags expressed as a `^(?im)` prefix are extracted and applied to the resulting expression.
|
|
@@ -485,13 +491,11 @@ function toRegExpString(text, func = "RegExp") {
|
|
|
485
491
|
const match = raw.match(/^\^(\(\?([igmsuy]+)\))/i);
|
|
486
492
|
const replacementTarget = match?.[1] ?? "";
|
|
487
493
|
const matchedFlags = match?.[2];
|
|
488
|
-
const
|
|
489
|
-
const { source, flags } = new RegExp(cleaned, matchedFlags);
|
|
494
|
+
const { source, flags } = toRegExp(raw.replace(/^\\?\//, "").replace(/\\?\/$/, "").replace(replacementTarget, ""), matchedFlags);
|
|
490
495
|
if (func === null) return `/${source}/${flags}`;
|
|
491
496
|
return `new ${func}(${JSON.stringify(source)}${flags ? `, ${JSON.stringify(flags)}` : ""})`;
|
|
492
497
|
}
|
|
493
|
-
|
|
494
|
-
//#region ../../internals/utils/src/codegen.ts
|
|
498
|
+
// ../../internals/utils/src/codegen.ts
|
|
495
499
|
const INDENT = " ";
|
|
496
500
|
/**
|
|
497
501
|
* Indents every non-empty line of `text` by one indent level, leaving blank lines empty.
|
|
@@ -560,8 +564,7 @@ function buildList(items, brackets = ["[", "]"]) {
|
|
|
560
564
|
function lazyGetter({ name, body }) {
|
|
561
565
|
return `get ${objectKey(name)}() { return ${body} }`;
|
|
562
566
|
}
|
|
563
|
-
|
|
564
|
-
//#region ../../internals/utils/src/fs.ts
|
|
567
|
+
// ../../internals/utils/src/fs.ts
|
|
565
568
|
/**
|
|
566
569
|
* Builds a nested file path from a dotted name. Splits on dots that precede a letter
|
|
567
570
|
* (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
|
|
@@ -581,21 +584,28 @@ function lazyGetter({ name, body }) {
|
|
|
581
584
|
* @example Suffix applied to the final segment only
|
|
582
585
|
* `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
|
|
583
586
|
*/
|
|
584
|
-
function toFilePath(name, caseLast = camelCase) {
|
|
587
|
+
function toFilePath(name, caseLast = kubb_kit.camelCase) {
|
|
585
588
|
const parts = name.split(/\.(?=[a-zA-Z])/);
|
|
586
|
-
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
589
|
+
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : (0, kubb_kit.camelCase)(part)).filter(Boolean).join("/");
|
|
587
590
|
}
|
|
588
|
-
|
|
589
|
-
//#region ../../internals/shared/src/resolver.ts
|
|
591
|
+
// ../../internals/shared/src/resolver.ts
|
|
590
592
|
/**
|
|
591
|
-
*
|
|
592
|
-
*
|
|
593
|
+
* Builds the allocation key for a declaration an operation owns. `scope` names which declaration
|
|
594
|
+
* it is, so two of them never share an allocation even when a custom resolver gives both the same
|
|
595
|
+
* name. Leave `scope` empty for the operation's own declaration.
|
|
593
596
|
*
|
|
594
597
|
* @example
|
|
595
|
-
*
|
|
598
|
+
* ```ts
|
|
599
|
+
* resolver.resolveName({ key: operationKey(node, 'response', 'status', 404), name })
|
|
600
|
+
* ```
|
|
596
601
|
*/
|
|
597
|
-
function
|
|
598
|
-
return
|
|
602
|
+
function operationKey(node, ...scope) {
|
|
603
|
+
return [
|
|
604
|
+
"operation",
|
|
605
|
+
node.method,
|
|
606
|
+
node.path,
|
|
607
|
+
...scope.map(String)
|
|
608
|
+
];
|
|
599
609
|
}
|
|
600
610
|
/**
|
|
601
611
|
* Builds the shared `param` namespace. Spread the result into `createResolver`
|
|
@@ -608,15 +618,33 @@ function operationParamName(node, param) {
|
|
|
608
618
|
*/
|
|
609
619
|
function createOperationParamResolver() {
|
|
610
620
|
return {
|
|
611
|
-
name
|
|
621
|
+
name(node, param) {
|
|
622
|
+
const name = this.name(`${node.operationId} ${param.in} ${param.name}`);
|
|
623
|
+
return this.resolveName({
|
|
624
|
+
key: operationKey(node, "param", "name", param.in, param.name),
|
|
625
|
+
name
|
|
626
|
+
});
|
|
627
|
+
},
|
|
612
628
|
path(node) {
|
|
613
|
-
|
|
629
|
+
const name = this.name(`${node.operationId} Path`);
|
|
630
|
+
return this.resolveName({
|
|
631
|
+
key: operationKey(node, "param", "path"),
|
|
632
|
+
name
|
|
633
|
+
});
|
|
614
634
|
},
|
|
615
635
|
query(node) {
|
|
616
|
-
|
|
636
|
+
const name = this.name(`${node.operationId} Query`);
|
|
637
|
+
return this.resolveName({
|
|
638
|
+
key: operationKey(node, "param", "query"),
|
|
639
|
+
name
|
|
640
|
+
});
|
|
617
641
|
},
|
|
618
642
|
headers(node) {
|
|
619
|
-
|
|
643
|
+
const name = this.name(`${node.operationId} Headers`);
|
|
644
|
+
return this.resolveName({
|
|
645
|
+
key: operationKey(node, "param", "headers"),
|
|
646
|
+
name
|
|
647
|
+
});
|
|
620
648
|
}
|
|
621
649
|
};
|
|
622
650
|
}
|
|
@@ -633,16 +661,32 @@ function createOperationParamResolver() {
|
|
|
633
661
|
function createOperationResponseResolver() {
|
|
634
662
|
return {
|
|
635
663
|
status(node, statusCode) {
|
|
636
|
-
|
|
664
|
+
const name = this.name(`${node.operationId} Status ${statusCode}`);
|
|
665
|
+
return this.resolveName({
|
|
666
|
+
key: operationKey(node, "response", "status", statusCode),
|
|
667
|
+
name
|
|
668
|
+
});
|
|
637
669
|
},
|
|
638
670
|
body(node) {
|
|
639
|
-
|
|
671
|
+
const name = this.name(`${node.operationId} Body`);
|
|
672
|
+
return this.resolveName({
|
|
673
|
+
key: operationKey(node, "response", "body"),
|
|
674
|
+
name
|
|
675
|
+
});
|
|
640
676
|
},
|
|
641
677
|
responses(node) {
|
|
642
|
-
|
|
678
|
+
const name = this.name(`${node.operationId} Responses`);
|
|
679
|
+
return this.resolveName({
|
|
680
|
+
key: operationKey(node, "response", "responses"),
|
|
681
|
+
name
|
|
682
|
+
});
|
|
643
683
|
},
|
|
644
684
|
response(node) {
|
|
645
|
-
|
|
685
|
+
const name = this.name(`${node.operationId} Response`);
|
|
686
|
+
return this.resolveName({
|
|
687
|
+
key: operationKey(node, "response", "response"),
|
|
688
|
+
name
|
|
689
|
+
});
|
|
646
690
|
}
|
|
647
691
|
};
|
|
648
692
|
}
|
|
@@ -657,11 +701,10 @@ function createOperationResponseResolver() {
|
|
|
657
701
|
*/
|
|
658
702
|
function createCasedFile(caseLast) {
|
|
659
703
|
return { baseName({ name, extname }) {
|
|
660
|
-
return `${toFilePath(name, caseLast)}${extname}
|
|
704
|
+
return this.memo(`file:${name}\0${extname}`, () => `${toFilePath(name, caseLast)}${extname}`);
|
|
661
705
|
} };
|
|
662
706
|
}
|
|
663
|
-
|
|
664
|
-
//#region ../../internals/shared/src/group.ts
|
|
707
|
+
// ../../internals/shared/src/group.ts
|
|
665
708
|
/**
|
|
666
709
|
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
667
710
|
* shared default naming so every plugin groups output consistently:
|
|
@@ -684,15 +727,14 @@ function createGroupConfig(group) {
|
|
|
684
727
|
if (!group) return null;
|
|
685
728
|
const defaultName = (ctx) => {
|
|
686
729
|
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
687
|
-
return camelCase(ctx.group);
|
|
730
|
+
return (0, kubb_kit.camelCase)(ctx.group);
|
|
688
731
|
};
|
|
689
732
|
return {
|
|
690
733
|
...group,
|
|
691
734
|
name: group.name ? group.name : defaultName
|
|
692
735
|
};
|
|
693
736
|
}
|
|
694
|
-
|
|
695
|
-
//#region ../../internals/shared/src/schemaTraversal.ts
|
|
737
|
+
// ../../internals/shared/src/schemaTraversal.ts
|
|
696
738
|
/**
|
|
697
739
|
* Maps each property of an object schema to its transformed output. Pairs every result with the
|
|
698
740
|
* original property so the printer keeps full control over modifiers, getters, and key syntax.
|
|
@@ -730,8 +772,7 @@ function mapSchemaItems(node, transform) {
|
|
|
730
772
|
output: transform(schema)
|
|
731
773
|
}));
|
|
732
774
|
}
|
|
733
|
-
|
|
734
|
-
//#region src/components/Zod.tsx
|
|
775
|
+
// src/components/Zod.tsx
|
|
735
776
|
function Zod({ name, node, printer, inferTypeName, inferKind = "infer", typeGuards, isName, assertName, mini, cyclic, compile }) {
|
|
736
777
|
const output = printer.print(node);
|
|
737
778
|
const printerImports = printer.drainImports();
|
|
@@ -803,8 +844,7 @@ function Zod({ name, node, printer, inferTypeName, inferKind = "infer", typeGuar
|
|
|
803
844
|
})
|
|
804
845
|
] });
|
|
805
846
|
}
|
|
806
|
-
|
|
807
|
-
//#region src/utils.ts
|
|
847
|
+
// src/utils.ts
|
|
808
848
|
/**
|
|
809
849
|
* Returns `true` when the given coercion option enables coercion for the specified type.
|
|
810
850
|
*/
|
|
@@ -833,11 +873,12 @@ function isClosedKeySchema(node) {
|
|
|
833
873
|
}
|
|
834
874
|
/**
|
|
835
875
|
* Whether the node is a plain inline object whose shape can be lifted into an `.extend({ … })`
|
|
836
|
-
* argument.
|
|
876
|
+
* argument. Property counts, a catchall, `patternProperties`, or a nullable/optional wrapper cannot, so those stay
|
|
837
877
|
* on `.and(…)`.
|
|
838
878
|
*/
|
|
839
879
|
function isPlainInlineObject(node) {
|
|
840
880
|
if (node.type !== "object") return false;
|
|
881
|
+
if (node.minProperties !== void 0 || node.maxProperties !== void 0) return false;
|
|
841
882
|
if (node.nullable || node.optional || node.nullish) return false;
|
|
842
883
|
const hasAdditionalProperties = node.additionalProperties !== void 0;
|
|
843
884
|
const hasPatternProperties = Boolean(node.patternProperties);
|
|
@@ -848,11 +889,12 @@ function isPlainInlineObject(node) {
|
|
|
848
889
|
* `z.discriminatedUnion` option. Covers object nodes, `$ref`s that resolve to (or are still
|
|
849
890
|
* unresolved) objects, single-member unions of an object, and object-composable `allOf`.
|
|
850
891
|
*
|
|
851
|
-
*
|
|
892
|
+
* Property counts render as a pipe. A ref into `cyclicSchemas` renders as `z.lazy(…)`.
|
|
852
893
|
*/
|
|
853
894
|
function isObjectSchemaNode(node, cyclicSchemas) {
|
|
854
895
|
if (node.nullable || node.optional || node.nullish) return false;
|
|
855
896
|
if (node.type === "object") {
|
|
897
|
+
if (node.minProperties !== void 0 || node.maxProperties !== void 0) return false;
|
|
856
898
|
const hasProperties = Boolean(node.properties?.length);
|
|
857
899
|
const hasTypedAdditionalProperties = Boolean(node.additionalProperties && node.additionalProperties !== true);
|
|
858
900
|
const hasPatternProperties = Boolean(node.patternProperties);
|
|
@@ -880,6 +922,49 @@ function isObjectComposableIntersection(node, cyclicSchemas) {
|
|
|
880
922
|
const [first, ...rest] = node.members ?? [];
|
|
881
923
|
return !!first && isObjectSchemaNode(first, cyclicSchemas) && rest.every(isPlainInlineObject);
|
|
882
924
|
}
|
|
925
|
+
function preserveRequiredProperties(members) {
|
|
926
|
+
const hasRequiredProperty = ({ node, propertyName, seen = /* @__PURE__ */ new Set() }) => {
|
|
927
|
+
if (seen.has(node)) return false;
|
|
928
|
+
seen.add(node);
|
|
929
|
+
const resolved = (0, kubb_kit.syncSchemaRef)(node);
|
|
930
|
+
const composition = kubb_kit.ast.narrowSchema(resolved, kubb_kit.ast.schemaTypes.intersection) ?? kubb_kit.ast.narrowSchema(resolved, kubb_kit.ast.schemaTypes.union);
|
|
931
|
+
if (composition) {
|
|
932
|
+
if (composition.type === kubb_kit.ast.schemaTypes.union && composition.members?.length !== 1) return false;
|
|
933
|
+
return composition.members?.some((child) => hasRequiredProperty({
|
|
934
|
+
node: child,
|
|
935
|
+
propertyName,
|
|
936
|
+
seen
|
|
937
|
+
})) ?? false;
|
|
938
|
+
}
|
|
939
|
+
return kubb_kit.ast.resolveSchemaProperties({
|
|
940
|
+
node: resolved,
|
|
941
|
+
propertyName
|
|
942
|
+
}).some((property) => property.required !== false && !property.schema.optional && !property.schema.nullish);
|
|
943
|
+
};
|
|
944
|
+
return members.map((member, index) => {
|
|
945
|
+
const object = kubb_kit.ast.narrowSchema(member, kubb_kit.ast.schemaTypes.object);
|
|
946
|
+
if (!object || index === 0) return member;
|
|
947
|
+
return {
|
|
948
|
+
...object,
|
|
949
|
+
properties: object.properties.map((property) => {
|
|
950
|
+
if (!members.slice(0, index).some((base) => hasRequiredProperty({
|
|
951
|
+
node: base,
|
|
952
|
+
propertyName: property.name
|
|
953
|
+
}))) return property;
|
|
954
|
+
return {
|
|
955
|
+
...property,
|
|
956
|
+
required: true,
|
|
957
|
+
schema: {
|
|
958
|
+
...property.schema,
|
|
959
|
+
optional: false,
|
|
960
|
+
nullish: false,
|
|
961
|
+
nullable: property.schema.nullable || property.schema.nullish
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
})
|
|
965
|
+
};
|
|
966
|
+
});
|
|
967
|
+
}
|
|
883
968
|
/**
|
|
884
969
|
* Format a default value as a code-level literal.
|
|
885
970
|
* Arrays and objects keep their contents as a JSON literal, primitives become their string
|
|
@@ -926,11 +1011,20 @@ function defaultLiteral(node, value) {
|
|
|
926
1011
|
*/
|
|
927
1012
|
function buildEnum(values) {
|
|
928
1013
|
if (values.every((v) => typeof v === "string")) return `z.enum([${values.map((v) => formatDefault(v)).join(", ")}])`;
|
|
929
|
-
const literals = values.map((
|
|
1014
|
+
const literals = values.map((value) => buildLiteral(value));
|
|
930
1015
|
if (literals.length === 1) return literals[0];
|
|
931
1016
|
return `z.union([${literals.join(", ")}])`;
|
|
932
1017
|
}
|
|
933
1018
|
/**
|
|
1019
|
+
* Preserves the structure of JSON const values in both Zod APIs.
|
|
1020
|
+
*/
|
|
1021
|
+
function buildLiteral(value) {
|
|
1022
|
+
if (value === null) return "z.null()";
|
|
1023
|
+
if (Array.isArray(value)) return `z.tuple([${value.map((item) => buildLiteral(item)).join(", ")}])`;
|
|
1024
|
+
if (typeof value === "object") return `z.strictObject({${Object.entries(value).map(([name, item]) => `${JSON.stringify(name)}: ${buildLiteral(item)}`).join(", ")}})`;
|
|
1025
|
+
return `z.literal(${formatDefault(value)})`;
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
934
1028
|
* Digit pattern for a `type: 'string'` schema that carries an integer `format`, the way ProtoJSON
|
|
935
1029
|
* encodes 64-bit integers. Returns `undefined` for every other format, and a `pattern` from the
|
|
936
1030
|
* spec takes precedence over this fallback.
|
|
@@ -1013,6 +1107,17 @@ function lengthChecksMini({ min, max, pattern, regexType }) {
|
|
|
1013
1107
|
return checks.length ? `.check(${checks.join(", ")})` : "";
|
|
1014
1108
|
}
|
|
1015
1109
|
/**
|
|
1110
|
+
* Checks property counts before object parsing strips unknown keys or inserts defaults.
|
|
1111
|
+
*/
|
|
1112
|
+
function objectConstraints({ value, node }) {
|
|
1113
|
+
if (node.type !== "object") return value;
|
|
1114
|
+
const checks = [];
|
|
1115
|
+
const skip = "typeof value !== \"object\" || value === null || Array.isArray(value)";
|
|
1116
|
+
if (node.minProperties !== void 0) checks.push(`z.refine(value => ${skip} || Object.keys(value).length >= ${node.minProperties}, { message: "Object must have at least ${node.minProperties} properties" })`);
|
|
1117
|
+
if (node.maxProperties !== void 0) checks.push(`z.refine(value => ${skip} || Object.keys(value).length <= ${node.maxProperties}, { message: "Object must have at most ${node.maxProperties} properties" })`);
|
|
1118
|
+
return checks.length ? `z.pipe(z.unknown().check(${checks.join(", ")}), ${value})` : value;
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1016
1121
|
* Apply nullable / optional / nullish modifiers, an optional `.describe()` call, and an
|
|
1017
1122
|
* optional `.meta({ examples })` call to a schema value string using the chainable Zod v4 API.
|
|
1018
1123
|
*/
|
|
@@ -1102,7 +1207,7 @@ function getMemberConstraint({ member, regexType, lengths, numbers }) {
|
|
|
1102
1207
|
/**
|
|
1103
1208
|
* Builds the `{ key: value, … }` shape shared by the `z.object(...)` and `.extend(...)` renderings.
|
|
1104
1209
|
*/
|
|
1105
|
-
function buildObjectShape(ctx, node,
|
|
1210
|
+
function buildObjectShape(ctx, node, renderProperty) {
|
|
1106
1211
|
const objectNode = kubb_kit.ast.narrowSchema(node, "object");
|
|
1107
1212
|
if (!objectNode) return "{}";
|
|
1108
1213
|
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && (0, kubb_kit.containsCircularRef)(schema, { circularSchemas: ctx.options.cyclicSchemas });
|
|
@@ -1113,18 +1218,16 @@ function buildObjectShape(ctx, node, modify) {
|
|
|
1113
1218
|
const baseOutput = ctx.transform(schema) ?? ctx.transform(kubb_kit.ast.factory.createSchema({ type: "unknown" }));
|
|
1114
1219
|
if (hasSelfRef) ctx.options.cyclicSchemas = savedCyclicSchemas;
|
|
1115
1220
|
return baseOutput;
|
|
1116
|
-
}).map(({ name
|
|
1221
|
+
}).map(({ name, property, output: value }) => {
|
|
1117
1222
|
const { schema } = property;
|
|
1118
|
-
|
|
1119
|
-
|
|
1223
|
+
return renderProperty({
|
|
1224
|
+
name,
|
|
1225
|
+
value,
|
|
1120
1226
|
schema,
|
|
1121
1227
|
required: property.required,
|
|
1122
|
-
meta: (0, kubb_kit.syncSchemaRef)(schema)
|
|
1228
|
+
meta: (0, kubb_kit.syncSchemaRef)(schema),
|
|
1229
|
+
cyclic: isCyclic(schema)
|
|
1123
1230
|
});
|
|
1124
|
-
return isCyclic(schema) ? lazyGetter({
|
|
1125
|
-
name: propName,
|
|
1126
|
-
body: value
|
|
1127
|
-
}) : `${objectKey(propName)}: ${value}`;
|
|
1128
1231
|
}));
|
|
1129
1232
|
}
|
|
1130
1233
|
/**
|
|
@@ -1139,22 +1242,28 @@ function printWithOmit(ctx, node, modify, mini = false) {
|
|
|
1139
1242
|
if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
|
|
1140
1243
|
const unwrap = omitUnwrapChain(node, mini ? "._zod.def.innerType" : ".unwrap()");
|
|
1141
1244
|
const mask = `{ ${keysToOmit.map((k) => `"${k}": true`).join(", ")} }`;
|
|
1142
|
-
const omit = (target) =>
|
|
1245
|
+
const omit = (target) => {
|
|
1246
|
+
const inner = `${target}${unwrap}`;
|
|
1247
|
+
const hasObjectConstraints = meta.type === "object" && (meta.minProperties !== void 0 || meta.maxProperties !== void 0);
|
|
1248
|
+
const pipe = mini ? `${inner}._zod.def` : inner;
|
|
1249
|
+
const object = hasObjectConstraints ? `${pipe}.out` : inner;
|
|
1250
|
+
const omitted = mini ? `z.omit(${object}, ${mask})` : `${object}.omit(${mask})`;
|
|
1251
|
+
return hasObjectConstraints ? `z.pipe(${pipe}.in, ${omitted})` : omitted;
|
|
1252
|
+
};
|
|
1143
1253
|
const lazyMatch = transformed.match(/^z\.lazy\(\(\)\s*=>\s*(.+)\)$/);
|
|
1144
1254
|
if (lazyMatch) return `z.lazy(() => ${omit(lazyMatch[1])})`;
|
|
1145
1255
|
return omit(transformed);
|
|
1146
1256
|
})(), meta);
|
|
1147
1257
|
}
|
|
1148
|
-
|
|
1149
|
-
//#region src/printers/printerZod.ts
|
|
1258
|
+
// src/printers/printerZod.ts
|
|
1150
1259
|
function strictOneOfMember(member, node, cyclicSchemas) {
|
|
1151
|
-
if (node.type ===
|
|
1260
|
+
if (node.type === kubb_kit.ast.schemaTypes.ref) {
|
|
1152
1261
|
if (member.startsWith("z.lazy(")) return member;
|
|
1153
1262
|
const refName = kubb_kit.ast.resolveRefName(node);
|
|
1154
1263
|
if (refName && cyclicSchemas?.has(refName)) return member;
|
|
1155
1264
|
const schema = (0, kubb_kit.syncSchemaRef)(node);
|
|
1156
1265
|
if (schema.nullable || schema.optional || node.nullable || node.optional) return member;
|
|
1157
|
-
if (schema.type ===
|
|
1266
|
+
if (schema.type === kubb_kit.ast.schemaTypes.object && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
|
|
1158
1267
|
}
|
|
1159
1268
|
return member;
|
|
1160
1269
|
}
|
|
@@ -1162,28 +1271,70 @@ function strictOneOfMember(member, node, cyclicSchemas) {
|
|
|
1162
1271
|
* Builds the `{ key: value, … }` shape for an object node with the chainable modifiers.
|
|
1163
1272
|
*/
|
|
1164
1273
|
function buildZodObjectShape(ctx, node) {
|
|
1165
|
-
return buildObjectShape(ctx, node, ({ value, schema, required, meta }) =>
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1274
|
+
return buildObjectShape(ctx, node, ({ name, value, schema, required, meta, cyclic }) => {
|
|
1275
|
+
const body = applyModifiers({
|
|
1276
|
+
value,
|
|
1277
|
+
schema,
|
|
1278
|
+
nullable: meta.nullable,
|
|
1279
|
+
optional: schema.optional || required === false,
|
|
1280
|
+
nullish: schema.nullish,
|
|
1281
|
+
defaultValue: meta.default,
|
|
1282
|
+
description: schema.type !== kubb_kit.ast.schemaTypes.ref && meta.type === kubb_kit.ast.schemaTypes.ref ? void 0 : meta.description,
|
|
1283
|
+
examples: meta.examples
|
|
1284
|
+
});
|
|
1285
|
+
if (!cyclic) return `${objectKey(name)}: ${body}`;
|
|
1286
|
+
const returnType = recursiveGetterType({
|
|
1287
|
+
ctx,
|
|
1288
|
+
schema,
|
|
1289
|
+
required
|
|
1290
|
+
});
|
|
1291
|
+
return returnType ? `get ${objectKey(name)}(): ${returnType} { return ${body} }` : lazyGetter({
|
|
1292
|
+
name,
|
|
1293
|
+
body
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Breaks getter inference cycles without widening recursive refs and arrays to `z.ZodType`.
|
|
1299
|
+
*/
|
|
1300
|
+
function recursiveGetterType({ ctx, schema, required }) {
|
|
1301
|
+
function baseType(schema) {
|
|
1302
|
+
if (ctx.options.nodes?.[schema.type]) return void 0;
|
|
1303
|
+
if (schema.type === kubb_kit.ast.schemaTypes.ref) {
|
|
1304
|
+
const saved = ctx.options.cyclicSchemas;
|
|
1305
|
+
ctx.options.cyclicSchemas = void 0;
|
|
1306
|
+
const name = ctx.transform(schema);
|
|
1307
|
+
ctx.options.cyclicSchemas = saved;
|
|
1308
|
+
return name ? `typeof ${name}` : void 0;
|
|
1309
|
+
}
|
|
1310
|
+
if (schema.type === kubb_kit.ast.schemaTypes.array && schema.items?.length === 1) {
|
|
1311
|
+
const item = baseType(schema.items[0]);
|
|
1312
|
+
return item ? `z.ZodArray<${item}>` : void 0;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
const base = baseType(schema);
|
|
1316
|
+
if (!base) return void 0;
|
|
1317
|
+
const meta = (0, kubb_kit.syncSchemaRef)(schema);
|
|
1318
|
+
const optional = schema.optional || required === false;
|
|
1319
|
+
const wrapped = (() => {
|
|
1320
|
+
if (schema.nullish || meta.nullable && optional) return `z.ZodOptional<z.ZodNullable<${base}>>`;
|
|
1321
|
+
if (optional) return `z.ZodOptional<${base}>`;
|
|
1322
|
+
if (meta.nullable) return `z.ZodNullable<${base}>`;
|
|
1323
|
+
return base;
|
|
1324
|
+
})();
|
|
1325
|
+
return meta.default !== void 0 && defaultLiteral(schema, meta.default) !== null ? `z.ZodDefault<${wrapped}>` : wrapped;
|
|
1175
1326
|
}
|
|
1176
1327
|
/**
|
|
1177
1328
|
* Types the direction probe skips. They delegate to their children rather than reading
|
|
1178
1329
|
* `direction` themselves, so {@link containsDirectionalNode} walks into the children instead.
|
|
1179
1330
|
*/
|
|
1180
1331
|
const CONTAINER_TYPES = /* @__PURE__ */ new Set([
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1332
|
+
kubb_kit.ast.schemaTypes.object,
|
|
1333
|
+
kubb_kit.ast.schemaTypes.array,
|
|
1334
|
+
kubb_kit.ast.schemaTypes.tuple,
|
|
1335
|
+
kubb_kit.ast.schemaTypes.union,
|
|
1336
|
+
kubb_kit.ast.schemaTypes.intersection,
|
|
1337
|
+
kubb_kit.ast.schemaTypes.ref
|
|
1187
1338
|
]);
|
|
1188
1339
|
/**
|
|
1189
1340
|
* Runs the node's effective handler (a `printer.nodes` override, else the built-in) once per
|
|
@@ -1215,7 +1366,7 @@ function variesByDirection({ node, printerOptions }) {
|
|
|
1215
1366
|
*/
|
|
1216
1367
|
function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */ new Set() }) {
|
|
1217
1368
|
if (!node) return false;
|
|
1218
|
-
if (node.type ===
|
|
1369
|
+
if (node.type === kubb_kit.ast.schemaTypes.ref) {
|
|
1219
1370
|
if (!node.ref) return false;
|
|
1220
1371
|
const refName = (0, kubb_kit.extractRefName)(node.ref);
|
|
1221
1372
|
if (refName) {
|
|
@@ -1223,7 +1374,7 @@ function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */
|
|
|
1223
1374
|
seen.add(refName);
|
|
1224
1375
|
}
|
|
1225
1376
|
const resolved = (0, kubb_kit.syncSchemaRef)(node);
|
|
1226
|
-
if (resolved.type ===
|
|
1377
|
+
if (resolved.type === kubb_kit.ast.schemaTypes.ref) return false;
|
|
1227
1378
|
return containsDirectionalNode({
|
|
1228
1379
|
node: resolved,
|
|
1229
1380
|
printerOptions,
|
|
@@ -1239,7 +1390,7 @@ function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */
|
|
|
1239
1390
|
if ("items" in node && node.items) children.push(...node.items);
|
|
1240
1391
|
if ("members" in node && node.members) children.push(...node.members);
|
|
1241
1392
|
if ("additionalProperties" in node && node.additionalProperties && node.additionalProperties !== true) children.push(node.additionalProperties);
|
|
1242
|
-
const propertyNames = node.type ===
|
|
1393
|
+
const propertyNames = node.type === kubb_kit.ast.schemaTypes.object ? node.propertyNames : void 0;
|
|
1243
1394
|
if (propertyNames) children.push(propertyNames);
|
|
1244
1395
|
return children.some((child) => containsDirectionalNode({
|
|
1245
1396
|
node: child,
|
|
@@ -1251,7 +1402,7 @@ function containsDirectionalNode({ node, printerOptions, seen = /* @__PURE__ */
|
|
|
1251
1402
|
* Names of the `$ref` schemas the generator should route to their input (encode) variant.
|
|
1252
1403
|
*/
|
|
1253
1404
|
function collectDirectionalRefNames({ node, printerOptions }) {
|
|
1254
|
-
return kubb_kit.ast.collectSync(node, { schema: (n) => n.type ===
|
|
1405
|
+
return kubb_kit.ast.collectSync(node, { schema: (n) => n.type === kubb_kit.ast.schemaTypes.ref && n.ref && containsDirectionalNode({
|
|
1255
1406
|
node: n,
|
|
1256
1407
|
printerOptions
|
|
1257
1408
|
}) ? kubb_kit.ast.resolveRefName(n) ?? void 0 : void 0 });
|
|
@@ -1343,7 +1494,7 @@ const scalarNodes = {
|
|
|
1343
1494
|
enum(node) {
|
|
1344
1495
|
const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
|
|
1345
1496
|
if (node.namedEnumValues?.length) {
|
|
1346
|
-
const literals = nonNullValues.map((v) =>
|
|
1497
|
+
const literals = nonNullValues.map((v) => buildLiteral(v));
|
|
1347
1498
|
if (literals.length === 1) return literals[0];
|
|
1348
1499
|
return `z.union([${literals.join(", ")}])`;
|
|
1349
1500
|
}
|
|
@@ -1364,6 +1515,7 @@ const scalarNodes = {
|
|
|
1364
1515
|
*/
|
|
1365
1516
|
const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
1366
1517
|
const cyclicSchemaNames = options.cyclicSchemas;
|
|
1518
|
+
const unionsWithSiblings = /* @__PURE__ */ new WeakSet();
|
|
1367
1519
|
return {
|
|
1368
1520
|
name: "zod",
|
|
1369
1521
|
options,
|
|
@@ -1389,37 +1541,40 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
1389
1541
|
const isStrict = node.additionalProperties === false && patterns.length === 0;
|
|
1390
1542
|
const isLoose = node.additionalProperties === true;
|
|
1391
1543
|
const objectBase = `${isStrict ? "z.strictObject" : isLoose ? "z.looseObject" : "z.object"}(${buildZodObjectShape(this, node)})`;
|
|
1392
|
-
return (
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
const
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1544
|
+
return objectConstraints({
|
|
1545
|
+
value: (() => {
|
|
1546
|
+
const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
|
|
1547
|
+
if (node.additionalProperties && node.additionalProperties !== true) {
|
|
1548
|
+
const catchallType = this.transform(node.additionalProperties);
|
|
1549
|
+
if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
|
|
1550
|
+
return catchallType ? `${objectBase}.catchall(${catchallType})` : objectBase;
|
|
1551
|
+
}
|
|
1552
|
+
if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) {
|
|
1553
|
+
const unknownType = this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }));
|
|
1554
|
+
return `${recordFn}(${propertyNamesKeySchema}, ${unknownType})`;
|
|
1555
|
+
}
|
|
1556
|
+
if (node.additionalProperties === true) return objectBase;
|
|
1557
|
+
if (isStrict) return objectBase;
|
|
1558
|
+
if (patterns.length > 0) {
|
|
1559
|
+
const values = patterns.map(([, valueSchema]) => {
|
|
1560
|
+
const valueType = this.transform(valueSchema) ?? this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }));
|
|
1561
|
+
return valueSchema.nullable ? `${valueType}.nullable()` : valueType;
|
|
1562
|
+
});
|
|
1563
|
+
const distinct = [...new Set(values)];
|
|
1564
|
+
const value = distinct.length === 1 ? distinct[0] : `z.union([${distinct.join(", ")}])`;
|
|
1565
|
+
if (entries.length > 0) return `${objectBase}.catchall(${value})`;
|
|
1566
|
+
return `z.record(${patternKeySchema({
|
|
1567
|
+
patterns: patterns.map(([pattern]) => pattern),
|
|
1568
|
+
regexType: this.options.regexType
|
|
1569
|
+
})}, ${value})`;
|
|
1570
|
+
}
|
|
1571
|
+
return objectBase;
|
|
1572
|
+
})(),
|
|
1573
|
+
node
|
|
1574
|
+
});
|
|
1420
1575
|
},
|
|
1421
1576
|
array(node) {
|
|
1422
|
-
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(kubb_kit.ast.factory.createSchema({ type:
|
|
1577
|
+
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }))})${lengthConstraints({
|
|
1423
1578
|
...node,
|
|
1424
1579
|
regexType: this.options.regexType
|
|
1425
1580
|
})}`;
|
|
@@ -1432,7 +1587,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
1432
1587
|
const nodeMembers = node.members ?? [];
|
|
1433
1588
|
const isDiscriminated = !!node.discriminatorPropertyName && nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
|
|
1434
1589
|
const isXor = node.strategy === "one" && !isDiscriminated && this.options.oneOfType === "xor";
|
|
1435
|
-
const isStrict = node.strategy === "one" && !isXor;
|
|
1590
|
+
const isStrict = node.strategy === "one" && !isXor && !unionsWithSiblings.has(node);
|
|
1436
1591
|
const members = mapSchemaMembers(node, (memberNode) => this.transform(isStrict ? strictOneOfNode(memberNode) : memberNode)).map(({ schema, output }) => output && isStrict ? strictOneOfMember(output, schema, cyclicSchemaNames) : output).filter(Boolean);
|
|
1437
1592
|
if (members.length === 0) return "";
|
|
1438
1593
|
if (members.length === 1) return members[0];
|
|
@@ -1443,11 +1598,21 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
1443
1598
|
intersection(node) {
|
|
1444
1599
|
const members = node.members ?? [];
|
|
1445
1600
|
if (members.length === 0) return "";
|
|
1601
|
+
const hasSiblingProperties = members.some((member) => member.type === kubb_kit.ast.schemaTypes.object && member.properties.length > 0);
|
|
1602
|
+
const transform = (member) => {
|
|
1603
|
+
if (!hasSiblingProperties) return this.transform(member);
|
|
1604
|
+
unionsWithSiblings.add(member);
|
|
1605
|
+
try {
|
|
1606
|
+
return this.transform(member);
|
|
1607
|
+
} finally {
|
|
1608
|
+
unionsWithSiblings.delete(member);
|
|
1609
|
+
}
|
|
1610
|
+
};
|
|
1446
1611
|
const [first, ...rest] = members;
|
|
1447
1612
|
if (!first) return "";
|
|
1448
|
-
const firstBase =
|
|
1613
|
+
const firstBase = transform(first);
|
|
1449
1614
|
if (!firstBase) return "";
|
|
1450
|
-
if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return
|
|
1615
|
+
if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return preserveRequiredProperties(members).slice(1).reduce((acc, member) => `${acc}.extend(${buildZodObjectShape(this, member)})`, firstBase);
|
|
1451
1616
|
return rest.reduce((acc, member) => {
|
|
1452
1617
|
const constraint = getMemberConstraint({
|
|
1453
1618
|
member,
|
|
@@ -1456,7 +1621,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
1456
1621
|
numbers: numberConstraints
|
|
1457
1622
|
});
|
|
1458
1623
|
if (constraint) return acc + constraint;
|
|
1459
|
-
const transformed =
|
|
1624
|
+
const transformed = transform(member);
|
|
1460
1625
|
return transformed ? `${acc}.and(${transformed})` : acc;
|
|
1461
1626
|
}, firstBase);
|
|
1462
1627
|
}
|
|
@@ -1476,20 +1641,25 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
1476
1641
|
}
|
|
1477
1642
|
};
|
|
1478
1643
|
});
|
|
1479
|
-
|
|
1480
|
-
//#region src/printers/printerZodMini.ts
|
|
1644
|
+
// src/printers/printerZodMini.ts
|
|
1481
1645
|
/**
|
|
1482
1646
|
* Builds the `{ key: value, … }` shape for an object node with the functional `zod/mini` modifiers.
|
|
1483
1647
|
*/
|
|
1484
1648
|
function buildZodMiniObjectShape(ctx, node) {
|
|
1485
|
-
return buildObjectShape(ctx, node, ({ value, schema, required, meta }) =>
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1649
|
+
return buildObjectShape(ctx, node, ({ name, value, schema, required, meta, cyclic }) => {
|
|
1650
|
+
const body = applyMiniModifiers({
|
|
1651
|
+
value,
|
|
1652
|
+
schema,
|
|
1653
|
+
nullable: meta.nullable,
|
|
1654
|
+
optional: schema.optional || required === false,
|
|
1655
|
+
nullish: schema.nullish,
|
|
1656
|
+
defaultValue: meta.default
|
|
1657
|
+
});
|
|
1658
|
+
return cyclic ? lazyGetter({
|
|
1659
|
+
name,
|
|
1660
|
+
body
|
|
1661
|
+
}) : `${objectKey(name)}: ${body}`;
|
|
1662
|
+
});
|
|
1493
1663
|
}
|
|
1494
1664
|
/**
|
|
1495
1665
|
* Zod v4 Mini printer built with `definePrinter`.
|
|
@@ -1505,6 +1675,7 @@ function buildZodMiniObjectShape(ctx, node) {
|
|
|
1505
1675
|
*/
|
|
1506
1676
|
const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
1507
1677
|
const cyclicSchemaNames = options.cyclicSchemas;
|
|
1678
|
+
const unionsWithSiblings = /* @__PURE__ */ new WeakSet();
|
|
1508
1679
|
return {
|
|
1509
1680
|
name: "zod-mini",
|
|
1510
1681
|
options,
|
|
@@ -1577,7 +1748,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1577
1748
|
enum(node) {
|
|
1578
1749
|
const nonNullValues = (node.namedEnumValues?.map((v) => v.value) ?? node.enumValues ?? []).filter((v) => v !== null);
|
|
1579
1750
|
if (node.namedEnumValues?.length) {
|
|
1580
|
-
const literals = nonNullValues.map((v) =>
|
|
1751
|
+
const literals = nonNullValues.map((v) => buildLiteral(v));
|
|
1581
1752
|
if (literals.length === 1) return literals[0];
|
|
1582
1753
|
return `z.union([${literals.join(", ")}])`;
|
|
1583
1754
|
}
|
|
@@ -1599,32 +1770,40 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1599
1770
|
const isStrict = node.additionalProperties === false && patterns.length === 0;
|
|
1600
1771
|
const isLoose = node.additionalProperties === true;
|
|
1601
1772
|
const objectBase = `${isStrict ? "z.strictObject" : isLoose ? "z.looseObject" : "z.object"}(${buildZodMiniObjectShape(this, node)})`;
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1773
|
+
return objectConstraints({
|
|
1774
|
+
value: (() => {
|
|
1775
|
+
const recordFn = isClosedKeySchema(propertyNamesNode) ? "z.partialRecord" : "z.record";
|
|
1776
|
+
if (node.additionalProperties && node.additionalProperties !== true) {
|
|
1777
|
+
const catchallType = this.transform(node.additionalProperties);
|
|
1778
|
+
if (entries.length === 0) return catchallType ? `${recordFn}(${propertyNamesKeySchema || "z.string()"}, ${catchallType})` : objectBase;
|
|
1779
|
+
return catchallType ? `z.catchall(${objectBase}, ${catchallType})` : objectBase;
|
|
1780
|
+
}
|
|
1781
|
+
if (entries.length === 0 && patterns.length === 0 && propertyNamesKeySchema && !isStrict) {
|
|
1782
|
+
const unknownType = this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }));
|
|
1783
|
+
return `${recordFn}(${propertyNamesKeySchema}, ${unknownType})`;
|
|
1784
|
+
}
|
|
1785
|
+
if (node.additionalProperties === true) return objectBase;
|
|
1786
|
+
if (isStrict) return objectBase;
|
|
1787
|
+
if (patterns.length > 0) {
|
|
1788
|
+
const values = patterns.map(([, valueSchema]) => {
|
|
1789
|
+
const valueType = this.transform(valueSchema) ?? this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }));
|
|
1790
|
+
return valueSchema.nullable ? `z.nullable(${valueType})` : valueType;
|
|
1791
|
+
});
|
|
1792
|
+
const distinct = [...new Set(values)];
|
|
1793
|
+
const value = distinct.length === 1 ? distinct[0] : `z.union([${distinct.join(", ")}])`;
|
|
1794
|
+
if (entries.length > 0) return `z.catchall(${objectBase}, ${value})`;
|
|
1795
|
+
return `z.record(${patternKeySchemaMini({
|
|
1796
|
+
patterns: patterns.map(([pattern]) => pattern),
|
|
1797
|
+
regexType: this.options.regexType
|
|
1798
|
+
})}, ${value})`;
|
|
1799
|
+
}
|
|
1800
|
+
return objectBase;
|
|
1801
|
+
})(),
|
|
1802
|
+
node
|
|
1803
|
+
});
|
|
1625
1804
|
},
|
|
1626
1805
|
array(node) {
|
|
1627
|
-
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(kubb_kit.ast.factory.createSchema({ type:
|
|
1806
|
+
const base = `z.array(${mapSchemaItems(node, (item) => this.transform(item)).map(({ output }) => output).filter(Boolean).join(", ") || this.transform(kubb_kit.ast.factory.createSchema({ type: kubb_kit.ast.schemaTypes.unknown }))})${lengthChecksMini({
|
|
1628
1807
|
...node,
|
|
1629
1808
|
regexType: this.options.regexType
|
|
1630
1809
|
})}`;
|
|
@@ -1637,7 +1816,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1637
1816
|
const nodeMembers = node.members ?? [];
|
|
1638
1817
|
const isDiscriminated = !!node.discriminatorPropertyName && nodeMembers.every((m) => isObjectSchemaNode(m, cyclicSchemaNames));
|
|
1639
1818
|
const isXor = node.strategy === "one" && !isDiscriminated && this.options.oneOfType === "xor";
|
|
1640
|
-
const isStrict = node.strategy === "one" && !isXor;
|
|
1819
|
+
const isStrict = node.strategy === "one" && !isXor && !unionsWithSiblings.has(node);
|
|
1641
1820
|
const members = mapSchemaMembers(node, (memberNode) => this.transform(isStrict ? strictOneOfNode(memberNode) : memberNode)).map(({ output }) => output).filter(Boolean);
|
|
1642
1821
|
if (members.length === 0) return "";
|
|
1643
1822
|
if (members.length === 1) return members[0];
|
|
@@ -1648,11 +1827,21 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1648
1827
|
intersection(node) {
|
|
1649
1828
|
const members = node.members ?? [];
|
|
1650
1829
|
if (members.length === 0) return "";
|
|
1830
|
+
const hasSiblingProperties = members.some((member) => member.type === kubb_kit.ast.schemaTypes.object && member.properties.length > 0);
|
|
1831
|
+
const transform = (member) => {
|
|
1832
|
+
if (!hasSiblingProperties) return this.transform(member);
|
|
1833
|
+
unionsWithSiblings.add(member);
|
|
1834
|
+
try {
|
|
1835
|
+
return this.transform(member);
|
|
1836
|
+
} finally {
|
|
1837
|
+
unionsWithSiblings.delete(member);
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1651
1840
|
const [first, ...rest] = members;
|
|
1652
1841
|
if (!first) return "";
|
|
1653
|
-
const firstBase =
|
|
1842
|
+
const firstBase = transform(first);
|
|
1654
1843
|
if (!firstBase) return "";
|
|
1655
|
-
if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return
|
|
1844
|
+
if (rest.length > 0 && isObjectComposableIntersection(node, cyclicSchemaNames)) return preserveRequiredProperties(members).slice(1).reduce((acc, member) => `z.extend(${acc}, ${buildZodMiniObjectShape(this, member)})`, firstBase);
|
|
1656
1845
|
return rest.reduce((acc, member) => {
|
|
1657
1846
|
const constraint = getMemberConstraint({
|
|
1658
1847
|
member,
|
|
@@ -1661,7 +1850,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1661
1850
|
numbers: numberChecksMini
|
|
1662
1851
|
});
|
|
1663
1852
|
if (constraint) return acc + constraint;
|
|
1664
|
-
const transformed =
|
|
1853
|
+
const transformed = transform(member);
|
|
1665
1854
|
return transformed ? `z.intersection(${acc}, ${transformed})` : acc;
|
|
1666
1855
|
}, firstBase);
|
|
1667
1856
|
}
|
|
@@ -1679,8 +1868,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1679
1868
|
}
|
|
1680
1869
|
};
|
|
1681
1870
|
});
|
|
1682
|
-
|
|
1683
|
-
//#region src/generators/zodGenerator.tsx
|
|
1871
|
+
// src/generators/zodGenerator.tsx
|
|
1684
1872
|
/**
|
|
1685
1873
|
* The helper an inferred alias is printed with. `'codec'` reads a request (encode) schema from its
|
|
1686
1874
|
* input and a response (decode) schema from its output; `true` keeps `z.infer` for both.
|
|
@@ -2141,17 +2329,14 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
2141
2329
|
});
|
|
2142
2330
|
}
|
|
2143
2331
|
});
|
|
2144
|
-
|
|
2145
|
-
//#region kubb-extension.json
|
|
2332
|
+
// kubb-extension.json
|
|
2146
2333
|
var compatibility = {
|
|
2147
|
-
"kubb": ">=5.
|
|
2334
|
+
"kubb": ">=5.14.6",
|
|
2148
2335
|
"node": ">=22.22"
|
|
2149
2336
|
};
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
//#endregion
|
|
2154
|
-
//#region src/resolvers/resolverZod.ts
|
|
2337
|
+
// package.json
|
|
2338
|
+
var version = "5.7.4";
|
|
2339
|
+
// src/resolvers/resolverZod.ts
|
|
2155
2340
|
/**
|
|
2156
2341
|
* Default resolver used by `@kubb/plugin-zod`. Decides the names and file
|
|
2157
2342
|
* paths for every generated Zod schema. Schemas use camelCase with a
|
|
@@ -2170,15 +2355,15 @@ var version = "5.7.2";
|
|
|
2170
2355
|
const resolverZod = (0, kubb_kit.createResolver)({
|
|
2171
2356
|
pluginName: "plugin-zod",
|
|
2172
2357
|
name(name) {
|
|
2173
|
-
return ensureValidVarName(camelCase(name, { suffix: "schema" }));
|
|
2358
|
+
return this.memo(`name:${name}`, () => ensureValidVarName((0, kubb_kit.camelCase)(name, { suffix: "schema" })));
|
|
2174
2359
|
},
|
|
2175
|
-
file: createCasedFile((part) => camelCase(part, { suffix: "schema" })),
|
|
2360
|
+
file: createCasedFile((part) => (0, kubb_kit.camelCase)(part, { suffix: "schema" })),
|
|
2176
2361
|
schema: {
|
|
2177
2362
|
typeName(name) {
|
|
2178
|
-
return ensureValidVarName(pascalCase(name, { suffix: "schema type" }));
|
|
2363
|
+
return this.memo(`typeName:${name}`, () => ensureValidVarName((0, kubb_kit.pascalCase)(name, { suffix: "schema type" })));
|
|
2179
2364
|
},
|
|
2180
2365
|
type(name) {
|
|
2181
|
-
return ensureValidVarName(pascalCase(name, { suffix: "type" }));
|
|
2366
|
+
return this.memo(`type:${name}`, () => ensureValidVarName((0, kubb_kit.pascalCase)(name, { suffix: "type" })));
|
|
2182
2367
|
},
|
|
2183
2368
|
inputName(name) {
|
|
2184
2369
|
return this.name(`${name} input`);
|
|
@@ -2187,25 +2372,32 @@ const resolverZod = (0, kubb_kit.createResolver)({
|
|
|
2187
2372
|
return this.schema.typeName(`${name} input`);
|
|
2188
2373
|
},
|
|
2189
2374
|
isName(name) {
|
|
2190
|
-
return ensureValidVarName(camelCase(name, { prefix: "is" }));
|
|
2375
|
+
return ensureValidVarName((0, kubb_kit.camelCase)(name, { prefix: "is" }));
|
|
2191
2376
|
},
|
|
2192
2377
|
assertName(name) {
|
|
2193
|
-
return ensureValidVarName(camelCase(name, { prefix: "assert" }));
|
|
2378
|
+
return ensureValidVarName((0, kubb_kit.camelCase)(name, { prefix: "assert" }));
|
|
2194
2379
|
}
|
|
2195
2380
|
},
|
|
2196
2381
|
param: createOperationParamResolver(),
|
|
2197
2382
|
response: {
|
|
2198
2383
|
...createOperationResponseResolver(),
|
|
2199
2384
|
error(node) {
|
|
2200
|
-
|
|
2385
|
+
const name = this.name(`${node.operationId} Error`);
|
|
2386
|
+
return this.resolveName({
|
|
2387
|
+
key: operationKey(node, "response", "error"),
|
|
2388
|
+
name
|
|
2389
|
+
});
|
|
2201
2390
|
},
|
|
2202
2391
|
options(node) {
|
|
2203
|
-
|
|
2392
|
+
const name = this.schema.type(this.name(`${node.operationId} Options`));
|
|
2393
|
+
return this.resolveName({
|
|
2394
|
+
key: operationKey(node, "response", "options"),
|
|
2395
|
+
name
|
|
2396
|
+
});
|
|
2204
2397
|
}
|
|
2205
2398
|
}
|
|
2206
2399
|
});
|
|
2207
|
-
|
|
2208
|
-
//#region src/plugin.ts
|
|
2400
|
+
// src/plugin.ts
|
|
2209
2401
|
/**
|
|
2210
2402
|
* Canonical plugin name for `@kubb/plugin-zod`. Used for driver lookups and
|
|
2211
2403
|
* cross-plugin dependency references.
|
|
@@ -2271,7 +2463,6 @@ const pluginZod = (0, kubb_kit.defineExtension)({
|
|
|
2271
2463
|
};
|
|
2272
2464
|
}
|
|
2273
2465
|
});
|
|
2274
|
-
//#endregion
|
|
2275
2466
|
exports.default = pluginZod;
|
|
2276
2467
|
exports.pluginZod = pluginZod;
|
|
2277
2468
|
exports.pluginZodName = pluginZodName;
|