@kubb/plugin-zod 5.0.0-beta.99 → 5.0.0
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 +275 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +276 -106
- package/dist/index.js.map +1 -1
- package/package.json +3 -6
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,179 @@ var __name = (target, value) => __defProp(target, "name", {
|
|
|
12
12
|
let kubb_kit = require("kubb/kit");
|
|
13
13
|
let kubb_jsx = require("kubb/jsx");
|
|
14
14
|
let kubb_jsx_jsx_runtime = require("kubb/jsx/jsx-runtime");
|
|
15
|
+
//#region ../../internals/shared/src/params.ts
|
|
16
|
+
/**
|
|
17
|
+
* Drops parameters that share the same name, keeping the first.
|
|
18
|
+
*
|
|
19
|
+
* A malformed spec can declare the same parameter name twice within one `in` location. Both would
|
|
20
|
+
* resolve to the same output property, so emitting both would yield an object type with a duplicate
|
|
21
|
+
* member, which TypeScript rejects. This is a defensive guard against that case, not a casing guard:
|
|
22
|
+
* parameter names flow through unchanged, so no two distinct names ever collide here anymore.
|
|
23
|
+
*/
|
|
24
|
+
function dedupeParams(params) {
|
|
25
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26
|
+
return params.filter((param) => {
|
|
27
|
+
if (seen.has(param.name)) return false;
|
|
28
|
+
seen.add(param.name);
|
|
29
|
+
return true;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region ../../internals/shared/src/operation.ts
|
|
34
|
+
/**
|
|
35
|
+
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
36
|
+
* (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
|
|
37
|
+
*/
|
|
38
|
+
function getContentTypeSuffix(contentType) {
|
|
39
|
+
const baseType = contentType.split(";")[0].trim();
|
|
40
|
+
if (baseType === "application/json") return "Json";
|
|
41
|
+
if (baseType === "multipart/form-data") return "FormData";
|
|
42
|
+
if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
|
|
43
|
+
const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
44
|
+
if (parts.length === 0) return "Unknown";
|
|
45
|
+
return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
|
|
49
|
+
* (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
|
|
50
|
+
*/
|
|
51
|
+
function getPerContentTypeName(baseName, suffix) {
|
|
52
|
+
if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
|
|
53
|
+
return baseName + suffix;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolves per-content-type variant names for a set of content entries, deduplicating suffix
|
|
57
|
+
* collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is
|
|
58
|
+
* the final (possibly counter-augmented) value, so callers can derive parallel names in another
|
|
59
|
+
* namespace (e.g. plugin-faker deriving the matching plugin-ts type name).
|
|
60
|
+
*/
|
|
61
|
+
function resolveContentTypeVariants(entries, baseName) {
|
|
62
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
63
|
+
return entries.filter((entry) => entry.schema).map((entry) => {
|
|
64
|
+
const baseSuffix = getContentTypeSuffix(entry.contentType);
|
|
65
|
+
let suffix = baseSuffix;
|
|
66
|
+
let name = getPerContentTypeName(baseName, suffix);
|
|
67
|
+
let counter = 2;
|
|
68
|
+
while (usedNames.has(name)) {
|
|
69
|
+
suffix = `${baseSuffix}${counter++}`;
|
|
70
|
+
name = getPerContentTypeName(baseName, suffix);
|
|
71
|
+
}
|
|
72
|
+
usedNames.add(name);
|
|
73
|
+
return {
|
|
74
|
+
name,
|
|
75
|
+
suffix,
|
|
76
|
+
schema: entry.schema,
|
|
77
|
+
keysToOmit: entry.keysToOmit,
|
|
78
|
+
contentType: entry.contentType
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const operationParameterGroupsByNode = /* @__PURE__ */ new WeakMap();
|
|
83
|
+
/**
|
|
84
|
+
* Groups an operation's parameters by location (`path`/`query`/`header`/`cookie`), deduping each
|
|
85
|
+
* group by name. Every plugin generator visiting the same `OperationNode` shares one AST instance
|
|
86
|
+
* (see `KubbDriver`), so the result is cached per node to avoid re-filtering and re-deduping the
|
|
87
|
+
* same parameters once per plugin.
|
|
88
|
+
*/
|
|
89
|
+
function getOperationParameters(node) {
|
|
90
|
+
const cached = operationParameterGroupsByNode.get(node);
|
|
91
|
+
if (cached) return cached;
|
|
92
|
+
const groups = {
|
|
93
|
+
path: dedupeParams(node.parameters.filter((param) => param.in === "path")),
|
|
94
|
+
query: dedupeParams(node.parameters.filter((param) => param.in === "query")),
|
|
95
|
+
header: dedupeParams(node.parameters.filter((param) => param.in === "header")),
|
|
96
|
+
cookie: dedupeParams(node.parameters.filter((param) => param.in === "cookie"))
|
|
97
|
+
};
|
|
98
|
+
operationParameterGroupsByNode.set(node, groups);
|
|
99
|
+
return groups;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Builds the combined `{ body, path, query, headers }` options object schema for an operation,
|
|
103
|
+
* referencing the already-resolved body and grouped param names. Shared by `@kubb/plugin-ts`'s
|
|
104
|
+
* `Options` type and `@kubb/plugin-zod`'s inferred options schema, so both printers emit the same
|
|
105
|
+
* shape from the same inputs. `primitive: 'object'` is a no-op for the TS printer and tells the Zod
|
|
106
|
+
* printer to emit `z.object(…)` rather than a record.
|
|
107
|
+
*/
|
|
108
|
+
function buildOptionsSchema(node, resolver) {
|
|
109
|
+
const { path, query, header } = getOperationParameters(node);
|
|
110
|
+
const hasBody = Boolean(node.requestBody?.content?.[0]?.schema);
|
|
111
|
+
const createNever = () => kubb_kit.ast.factory.createSchema({
|
|
112
|
+
type: "never",
|
|
113
|
+
primitive: void 0,
|
|
114
|
+
optional: true
|
|
115
|
+
});
|
|
116
|
+
const groups = [
|
|
117
|
+
{
|
|
118
|
+
name: "path",
|
|
119
|
+
params: path,
|
|
120
|
+
resolve: resolver.param.path
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "query",
|
|
124
|
+
params: query,
|
|
125
|
+
resolve: resolver.param.query
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: "headers",
|
|
129
|
+
params: header,
|
|
130
|
+
resolve: resolver.param.headers
|
|
131
|
+
}
|
|
132
|
+
];
|
|
133
|
+
return kubb_kit.ast.factory.createSchema({
|
|
134
|
+
type: "object",
|
|
135
|
+
primitive: "object",
|
|
136
|
+
deprecated: node.deprecated,
|
|
137
|
+
properties: [kubb_kit.ast.factory.createProperty({
|
|
138
|
+
name: "body",
|
|
139
|
+
required: hasBody,
|
|
140
|
+
schema: hasBody ? kubb_kit.ast.factory.createSchema({
|
|
141
|
+
type: "ref",
|
|
142
|
+
name: resolver.response.body(node)
|
|
143
|
+
}) : createNever()
|
|
144
|
+
}), ...groups.map(({ name, params, resolve }) => {
|
|
145
|
+
const required = params.some((param) => param.required);
|
|
146
|
+
return kubb_kit.ast.factory.createProperty({
|
|
147
|
+
name,
|
|
148
|
+
required,
|
|
149
|
+
schema: params.length > 0 ? kubb_kit.ast.factory.createSchema({
|
|
150
|
+
type: "ref",
|
|
151
|
+
name: resolve.call(resolver.param, node, params[0]),
|
|
152
|
+
optional: !required
|
|
153
|
+
}) : createNever()
|
|
154
|
+
});
|
|
155
|
+
})]
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function getStatusCodeNumber(statusCode) {
|
|
159
|
+
const code = Number(statusCode);
|
|
160
|
+
return Number.isNaN(code) ? null : code;
|
|
161
|
+
}
|
|
162
|
+
function isSuccessStatusCode(statusCode) {
|
|
163
|
+
const code = getStatusCodeNumber(statusCode);
|
|
164
|
+
return code !== null && code >= 200 && code < 300;
|
|
165
|
+
}
|
|
166
|
+
function getSuccessResponses(responses) {
|
|
167
|
+
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region ../../internals/shared/src/adapter.ts
|
|
171
|
+
/**
|
|
172
|
+
* Narrows the generic `Adapter` from a generator context to the OpenAPI adapter,
|
|
173
|
+
* so OAS-only options (`dateType`, `enums`) and the parsed `document` are typed.
|
|
174
|
+
*
|
|
175
|
+
* Throws when a non-OAS adapter is configured, turning a silently wrong cast into a
|
|
176
|
+
* clear, actionable error at the point of use.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* const { dateType } = getOasAdapter(ctx.adapter).options
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
function getOasAdapter(adapter) {
|
|
184
|
+
if (adapter.name !== "oas") throw new Error(`Expected the OpenAPI adapter (adapterOas), but received "${adapter.name}". Configure \`adapter: adapterOas()\` in your Kubb config.`);
|
|
185
|
+
return adapter;
|
|
186
|
+
}
|
|
187
|
+
//#endregion
|
|
15
188
|
//#region ../../internals/utils/src/casing.ts
|
|
16
189
|
/**
|
|
17
190
|
* Shared implementation for camelCase and PascalCase conversion.
|
|
@@ -356,85 +529,6 @@ function toFilePath(name, caseLast = camelCase) {
|
|
|
356
529
|
return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
|
|
357
530
|
}
|
|
358
531
|
//#endregion
|
|
359
|
-
//#region ../../internals/shared/src/operation.ts
|
|
360
|
-
/**
|
|
361
|
-
* Maps a content type to the PascalCase suffix used to name per-content-type variants
|
|
362
|
-
* (e.g. `application/json` → `Json`, `application/xml` → `Xml`, `multipart/form-data` → `FormData`).
|
|
363
|
-
*/
|
|
364
|
-
function getContentTypeSuffix(contentType) {
|
|
365
|
-
const baseType = contentType.split(";")[0].trim();
|
|
366
|
-
if (baseType === "application/json") return "Json";
|
|
367
|
-
if (baseType === "multipart/form-data") return "FormData";
|
|
368
|
-
if (baseType === "application/x-www-form-urlencoded") return "FormUrlEncoded";
|
|
369
|
-
const parts = (baseType.split("/").pop() ?? baseType).split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
370
|
-
if (parts.length === 0) return "Unknown";
|
|
371
|
-
return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* Appends a content-type suffix to a base name, keeping a trailing `Data` segment last
|
|
375
|
-
* (e.g. `AddPetData` + `Json` → `AddPetJsonData`, `AddPetStatus200` + `Xml` → `AddPetStatus200Xml`).
|
|
376
|
-
*/
|
|
377
|
-
function getPerContentTypeName(baseName, suffix) {
|
|
378
|
-
if (baseName.endsWith("Data")) return suffix.endsWith("Data") ? baseName.slice(0, -4) + suffix : `${baseName.slice(0, -4)}${suffix}Data`;
|
|
379
|
-
return baseName + suffix;
|
|
380
|
-
}
|
|
381
|
-
/**
|
|
382
|
-
* Resolves per-content-type variant names for a set of content entries, deduplicating suffix
|
|
383
|
-
* collisions with a numeric counter. Entries without a schema are skipped. The returned `suffix` is
|
|
384
|
-
* the final (possibly counter-augmented) value, so callers can derive parallel names in another
|
|
385
|
-
* namespace (e.g. plugin-faker deriving the matching plugin-ts type name).
|
|
386
|
-
*/
|
|
387
|
-
function resolveContentTypeVariants(entries, baseName) {
|
|
388
|
-
const usedNames = /* @__PURE__ */ new Set();
|
|
389
|
-
return entries.filter((entry) => entry.schema).map((entry) => {
|
|
390
|
-
const baseSuffix = getContentTypeSuffix(entry.contentType);
|
|
391
|
-
let suffix = baseSuffix;
|
|
392
|
-
let name = getPerContentTypeName(baseName, suffix);
|
|
393
|
-
let counter = 2;
|
|
394
|
-
while (usedNames.has(name)) {
|
|
395
|
-
suffix = `${baseSuffix}${counter++}`;
|
|
396
|
-
name = getPerContentTypeName(baseName, suffix);
|
|
397
|
-
}
|
|
398
|
-
usedNames.add(name);
|
|
399
|
-
return {
|
|
400
|
-
name,
|
|
401
|
-
suffix,
|
|
402
|
-
schema: entry.schema,
|
|
403
|
-
keysToOmit: entry.keysToOmit,
|
|
404
|
-
contentType: entry.contentType
|
|
405
|
-
};
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
function getStatusCodeNumber(statusCode) {
|
|
409
|
-
const code = Number(statusCode);
|
|
410
|
-
return Number.isNaN(code) ? null : code;
|
|
411
|
-
}
|
|
412
|
-
function isSuccessStatusCode(statusCode) {
|
|
413
|
-
const code = getStatusCodeNumber(statusCode);
|
|
414
|
-
return code !== null && code >= 200 && code < 300;
|
|
415
|
-
}
|
|
416
|
-
function getSuccessResponses(responses) {
|
|
417
|
-
return responses.filter((response) => isSuccessStatusCode(response.statusCode));
|
|
418
|
-
}
|
|
419
|
-
//#endregion
|
|
420
|
-
//#region ../../internals/shared/src/adapter.ts
|
|
421
|
-
/**
|
|
422
|
-
* Narrows the generic `Adapter` from a generator context to the OpenAPI adapter,
|
|
423
|
-
* so OAS-only options (`dateType`, `enums`) and the parsed `document` are typed.
|
|
424
|
-
*
|
|
425
|
-
* Throws when a non-OAS adapter is configured, turning a silently wrong cast into a
|
|
426
|
-
* clear, actionable error at the point of use.
|
|
427
|
-
*
|
|
428
|
-
* @example
|
|
429
|
-
* ```ts
|
|
430
|
-
* const { dateType } = getOasAdapter(ctx.adapter).options
|
|
431
|
-
* ```
|
|
432
|
-
*/
|
|
433
|
-
function getOasAdapter(adapter) {
|
|
434
|
-
if (adapter.name !== "oas") throw new Error(`Expected the OpenAPI adapter (adapterOas), but received "${adapter.name}". Configure \`adapter: adapterOas()\` in your Kubb config.`);
|
|
435
|
-
return adapter;
|
|
436
|
-
}
|
|
437
|
-
//#endregion
|
|
438
532
|
//#region ../../internals/shared/src/resolver.ts
|
|
439
533
|
/**
|
|
440
534
|
* Resolves a single operation parameter name with the
|
|
@@ -447,6 +541,29 @@ function operationParamName(node, param) {
|
|
|
447
541
|
return this.name(`${node.operationId} ${param.in} ${param.name}`);
|
|
448
542
|
}
|
|
449
543
|
/**
|
|
544
|
+
* Builds the shared `param` namespace. Spread the result into `createResolver`
|
|
545
|
+
* and override individual methods next to it when a plugin deviates.
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```ts
|
|
549
|
+
* createResolver<PluginTs>({ param: createOperationParamResolver(), ... })
|
|
550
|
+
* ```
|
|
551
|
+
*/
|
|
552
|
+
function createOperationParamResolver() {
|
|
553
|
+
return {
|
|
554
|
+
name: operationParamName,
|
|
555
|
+
path(node) {
|
|
556
|
+
return this.name(`${node.operationId} Path`);
|
|
557
|
+
},
|
|
558
|
+
query(node) {
|
|
559
|
+
return this.name(`${node.operationId} Query`);
|
|
560
|
+
},
|
|
561
|
+
headers(node) {
|
|
562
|
+
return this.name(`${node.operationId} Headers`);
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
450
567
|
* Builds the shared `response` namespace. Spread the result into
|
|
451
568
|
* `createResolver` and add plugin-specific methods (`options`, `error`) next
|
|
452
569
|
* to it.
|
|
@@ -494,7 +611,7 @@ function createCasedFile(caseLast) {
|
|
|
494
611
|
* `resolver.imports` would resolve file paths that are then discarded.
|
|
495
612
|
*/
|
|
496
613
|
function collectRefNames(schema) {
|
|
497
|
-
return kubb_kit.ast.
|
|
614
|
+
return kubb_kit.ast.collectSync(schema, { schema: (node) => {
|
|
498
615
|
const refNode = kubb_kit.ast.narrowSchema(node, "ref");
|
|
499
616
|
if (!refNode?.ref) return null;
|
|
500
617
|
return kubb_kit.ast.resolveRefName(refNode);
|
|
@@ -654,12 +771,12 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
|
|
|
654
771
|
if (hasCodec(node)) return true;
|
|
655
772
|
if (node.type === "ref") {
|
|
656
773
|
if (!node.ref) return false;
|
|
657
|
-
const refName = kubb_kit.
|
|
774
|
+
const refName = (0, kubb_kit.extractRefName)(node.ref);
|
|
658
775
|
if (refName) {
|
|
659
776
|
if (seen.has(refName)) return false;
|
|
660
777
|
seen.add(refName);
|
|
661
778
|
}
|
|
662
|
-
const resolved = kubb_kit.
|
|
779
|
+
const resolved = (0, kubb_kit.syncSchemaRef)(node);
|
|
663
780
|
if (resolved.type === "ref") return false;
|
|
664
781
|
return containsCodec(resolved, seen);
|
|
665
782
|
}
|
|
@@ -675,7 +792,7 @@ function containsCodec(node, seen = /* @__PURE__ */ new Set()) {
|
|
|
675
792
|
* them to their input (encode) variant.
|
|
676
793
|
*/
|
|
677
794
|
function collectCodecRefNames(node) {
|
|
678
|
-
return kubb_kit.ast.
|
|
795
|
+
return kubb_kit.ast.collectSync(node, { schema: (n) => n.type === "ref" && n.ref && containsCodec(n) ? kubb_kit.ast.resolveRefName(n) ?? void 0 : void 0 });
|
|
679
796
|
}
|
|
680
797
|
/**
|
|
681
798
|
* Whether the node is a plain inline object whose shape can be lifted into an `.extend({ … })`
|
|
@@ -698,7 +815,7 @@ function isObjectSchemaNode(node, cyclicSchemas) {
|
|
|
698
815
|
if (node.type === "ref") {
|
|
699
816
|
const refName = kubb_kit.ast.resolveRefName(node);
|
|
700
817
|
if (refName && cyclicSchemas?.has(refName)) return false;
|
|
701
|
-
const resolved = kubb_kit.
|
|
818
|
+
const resolved = (0, kubb_kit.syncSchemaRef)(node);
|
|
702
819
|
return resolved.type === "ref" || isObjectSchemaNode(resolved, cyclicSchemas);
|
|
703
820
|
}
|
|
704
821
|
if (node.type === "union") {
|
|
@@ -774,6 +891,20 @@ function buildEnum(values) {
|
|
|
774
891
|
return `z.union([${literals.join(", ")}])`;
|
|
775
892
|
}
|
|
776
893
|
/**
|
|
894
|
+
* Digit pattern for a `type: 'string'` schema that carries an integer `format`, the way ProtoJSON
|
|
895
|
+
* encodes 64-bit integers. Returns `undefined` for every other format, and a `pattern` from the
|
|
896
|
+
* spec takes precedence over this fallback.
|
|
897
|
+
*
|
|
898
|
+
* @example
|
|
899
|
+
* ```ts
|
|
900
|
+
* integerFormatPattern('uint64') // '^\\d+$'
|
|
901
|
+
* ```
|
|
902
|
+
*/
|
|
903
|
+
function integerFormatPattern(format) {
|
|
904
|
+
if (format === "int32" || format === "int64") return "^-?\\d+$";
|
|
905
|
+
if (format === "uint64") return "^\\d+$";
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
777
908
|
* Map a `regexType` to the `func` argument of `toRegExpString`: `'constructor'` emits
|
|
778
909
|
* `new RegExp(...)`, while `'literal'` (the default) emits a regex literal.
|
|
779
910
|
*/
|
|
@@ -898,6 +1029,22 @@ function applyMiniModifiers({ value, schema, nullable, optional, nullish, defaul
|
|
|
898
1029
|
const literal = defaultValue !== void 0 ? defaultLiteral(schema, defaultValue) : null;
|
|
899
1030
|
return literal !== null ? `z._default(${withModifier}, ${literal})` : withModifier;
|
|
900
1031
|
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Builds an `object` schema node grouping the given parameter nodes.
|
|
1034
|
+
* The `primitive: 'object'` marker ensures the Zod printer emits `z.object(…)` rather than a record.
|
|
1035
|
+
*/
|
|
1036
|
+
function buildGroupedParamsSchema({ params, optional }) {
|
|
1037
|
+
return kubb_kit.ast.factory.createSchema({
|
|
1038
|
+
type: "object",
|
|
1039
|
+
optional,
|
|
1040
|
+
primitive: "object",
|
|
1041
|
+
properties: params.map((param) => kubb_kit.ast.factory.createProperty({
|
|
1042
|
+
name: param.name,
|
|
1043
|
+
required: param.required,
|
|
1044
|
+
schema: param.schema
|
|
1045
|
+
}))
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
901
1048
|
//#endregion
|
|
902
1049
|
//#region src/printers/printerZod.ts
|
|
903
1050
|
function strictOneOfMember$1(member, node, cyclicSchemas) {
|
|
@@ -906,7 +1053,7 @@ function strictOneOfMember$1(member, node, cyclicSchemas) {
|
|
|
906
1053
|
if (member.startsWith("z.lazy(")) return member;
|
|
907
1054
|
const refName = kubb_kit.ast.resolveRefName(node);
|
|
908
1055
|
if (refName && cyclicSchemas?.has(refName)) return member;
|
|
909
|
-
const schema = kubb_kit.
|
|
1056
|
+
const schema = (0, kubb_kit.syncSchemaRef)(node);
|
|
910
1057
|
if (schema.nullable || schema.optional || node.nullable || node.optional) return member;
|
|
911
1058
|
if (schema.type === "object" && (schema.additionalProperties === void 0 || schema.additionalProperties === false)) return `${member}.strict()`;
|
|
912
1059
|
}
|
|
@@ -931,7 +1078,7 @@ function getMemberConstraint({ member, regexType }) {
|
|
|
931
1078
|
function buildZodObjectShape(ctx, node) {
|
|
932
1079
|
const objectNode = kubb_kit.ast.narrowSchema(node, "object");
|
|
933
1080
|
if (!objectNode) return "{}";
|
|
934
|
-
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && kubb_kit.
|
|
1081
|
+
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && (0, kubb_kit.containsCircularRef)(schema, { circularSchemas: ctx.options.cyclicSchemas });
|
|
935
1082
|
return buildObject(mapSchemaProperties(objectNode, (schema) => {
|
|
936
1083
|
const hasSelfRef = isCyclic(schema);
|
|
937
1084
|
const savedCyclicSchemas = ctx.options.cyclicSchemas;
|
|
@@ -941,7 +1088,7 @@ function buildZodObjectShape(ctx, node) {
|
|
|
941
1088
|
return baseOutput;
|
|
942
1089
|
}).map(({ name: propName, property, output: baseOutput }) => {
|
|
943
1090
|
const { schema } = property;
|
|
944
|
-
const meta = kubb_kit.
|
|
1091
|
+
const meta = (0, kubb_kit.syncSchemaRef)(schema);
|
|
945
1092
|
const descriptionToApply = schema.type !== "ref" && meta.type === "ref" ? void 0 : meta.description;
|
|
946
1093
|
const value = applyModifiers({
|
|
947
1094
|
value: baseOutput,
|
|
@@ -984,8 +1131,11 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
984
1131
|
boolean: () => "z.boolean()",
|
|
985
1132
|
null: () => "z.null()",
|
|
986
1133
|
string(node) {
|
|
987
|
-
|
|
1134
|
+
const base = shouldCoerce(this.options.coercion, "strings") ? "z.coerce.string()" : "z.string()";
|
|
1135
|
+
const pattern = node.pattern ?? integerFormatPattern(node.format);
|
|
1136
|
+
return `${base}${lengthConstraints({
|
|
988
1137
|
...node,
|
|
1138
|
+
pattern,
|
|
989
1139
|
regexType: this.options.regexType
|
|
990
1140
|
})}`;
|
|
991
1141
|
},
|
|
@@ -1126,7 +1276,7 @@ const printerZod = kubb_kit.ast.createPrinter((options) => {
|
|
|
1126
1276
|
const { keysToOmit } = this.options;
|
|
1127
1277
|
const transformed = this.transform(node);
|
|
1128
1278
|
if (!transformed) return null;
|
|
1129
|
-
const meta = kubb_kit.
|
|
1279
|
+
const meta = (0, kubb_kit.syncSchemaRef)(node);
|
|
1130
1280
|
return applyModifiers({
|
|
1131
1281
|
value: (() => {
|
|
1132
1282
|
if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
|
|
@@ -1171,7 +1321,7 @@ function getMemberConstraintMini({ member, regexType }) {
|
|
|
1171
1321
|
function buildZodMiniObjectShape(ctx, node) {
|
|
1172
1322
|
const objectNode = kubb_kit.ast.narrowSchema(node, "object");
|
|
1173
1323
|
if (!objectNode) return "{}";
|
|
1174
|
-
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && kubb_kit.
|
|
1324
|
+
const isCyclic = (schema) => ctx.options.cyclicSchemas != null && (0, kubb_kit.containsCircularRef)(schema, { circularSchemas: ctx.options.cyclicSchemas });
|
|
1175
1325
|
return buildObject(mapSchemaProperties(objectNode, (schema) => {
|
|
1176
1326
|
const hasSelfRef = isCyclic(schema);
|
|
1177
1327
|
const savedCyclicSchemas = ctx.options.cyclicSchemas;
|
|
@@ -1181,7 +1331,7 @@ function buildZodMiniObjectShape(ctx, node) {
|
|
|
1181
1331
|
return baseOutput;
|
|
1182
1332
|
}).map(({ name: propName, property, output: baseOutput }) => {
|
|
1183
1333
|
const { schema } = property;
|
|
1184
|
-
const meta = kubb_kit.
|
|
1334
|
+
const meta = (0, kubb_kit.syncSchemaRef)(schema);
|
|
1185
1335
|
const value = applyMiniModifiers({
|
|
1186
1336
|
value: baseOutput,
|
|
1187
1337
|
schema,
|
|
@@ -1221,8 +1371,10 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1221
1371
|
boolean: () => "z.boolean()",
|
|
1222
1372
|
null: () => "z.null()",
|
|
1223
1373
|
string(node) {
|
|
1374
|
+
const pattern = node.pattern ?? integerFormatPattern(node.format);
|
|
1224
1375
|
return `z.string()${lengthChecksMini({
|
|
1225
1376
|
...node,
|
|
1377
|
+
pattern,
|
|
1226
1378
|
regexType: this.options.regexType
|
|
1227
1379
|
})}`;
|
|
1228
1380
|
},
|
|
@@ -1352,7 +1504,7 @@ const printerZodMini = kubb_kit.ast.createPrinter((options) => {
|
|
|
1352
1504
|
const { keysToOmit } = this.options;
|
|
1353
1505
|
const transformed = this.transform(node);
|
|
1354
1506
|
if (!transformed) return null;
|
|
1355
|
-
const meta = kubb_kit.
|
|
1507
|
+
const meta = (0, kubb_kit.syncSchemaRef)(node);
|
|
1356
1508
|
return applyMiniModifiers({
|
|
1357
1509
|
value: (() => {
|
|
1358
1510
|
if (!keysToOmit?.length || meta.primitive !== "object" || meta.type === "union" && meta.discriminatorPropertyName) return transformed;
|
|
@@ -1703,6 +1855,30 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1703
1855
|
description: node.requestBody.description ?? schema.description
|
|
1704
1856
|
}), "input");
|
|
1705
1857
|
})();
|
|
1858
|
+
const { path, query, header } = getOperationParameters(node);
|
|
1859
|
+
const paramGroupSchemas = inferred ? [
|
|
1860
|
+
{
|
|
1861
|
+
kind: "path",
|
|
1862
|
+
params: path
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
kind: "query",
|
|
1866
|
+
params: query
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
kind: "headers",
|
|
1870
|
+
params: header
|
|
1871
|
+
}
|
|
1872
|
+
].filter(({ params }) => params.length > 0).map(({ kind, params }) => renderSchemaEntry({
|
|
1873
|
+
schema: buildGroupedParamsSchema({ params }),
|
|
1874
|
+
name: resolver.param[kind](node, params[0]),
|
|
1875
|
+
direction: "input"
|
|
1876
|
+
})) : [];
|
|
1877
|
+
const optionsSchema = inferred ? renderSchemaEntry({
|
|
1878
|
+
schema: buildOptionsSchema(node, resolver),
|
|
1879
|
+
name: resolver.name(`${node.operationId} Options`),
|
|
1880
|
+
direction: "input"
|
|
1881
|
+
}) : null;
|
|
1706
1882
|
return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
|
|
1707
1883
|
baseName: meta.file.baseName,
|
|
1708
1884
|
path: meta.file.path,
|
|
@@ -1733,7 +1909,9 @@ const zodGenerator = (0, kubb_kit.defineGenerator)({
|
|
|
1733
1909
|
responseSchemas,
|
|
1734
1910
|
responseUnionSchema,
|
|
1735
1911
|
errorUnionSchema,
|
|
1736
|
-
requestSchema
|
|
1912
|
+
requestSchema,
|
|
1913
|
+
paramGroupSchemas,
|
|
1914
|
+
optionsSchema
|
|
1737
1915
|
]
|
|
1738
1916
|
});
|
|
1739
1917
|
}
|
|
@@ -1775,22 +1953,14 @@ const resolverZod = (0, kubb_kit.createResolver)({
|
|
|
1775
1953
|
return this.schema.typeName(`${name} input`);
|
|
1776
1954
|
}
|
|
1777
1955
|
},
|
|
1778
|
-
param:
|
|
1779
|
-
name: operationParamName,
|
|
1780
|
-
path(node, param) {
|
|
1781
|
-
return this.param.name(node, param);
|
|
1782
|
-
},
|
|
1783
|
-
query(node, param) {
|
|
1784
|
-
return this.param.name(node, param);
|
|
1785
|
-
},
|
|
1786
|
-
headers(node, param) {
|
|
1787
|
-
return this.param.name(node, param);
|
|
1788
|
-
}
|
|
1789
|
-
},
|
|
1956
|
+
param: createOperationParamResolver(),
|
|
1790
1957
|
response: {
|
|
1791
1958
|
...createOperationResponseResolver(),
|
|
1792
1959
|
error(node) {
|
|
1793
1960
|
return this.name(`${node.operationId} Error`);
|
|
1961
|
+
},
|
|
1962
|
+
options(node) {
|
|
1963
|
+
return this.schema.type(this.name(`${node.operationId} Options`));
|
|
1794
1964
|
}
|
|
1795
1965
|
}
|
|
1796
1966
|
});
|