@orval/zod 8.18.0 → 8.20.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.d.mts +33 -4
- package/dist/index.mjs +302 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,30 @@
|
|
|
1
|
-
import { ClientBuilder, ClientGeneratorsBuilder, ContextSpec,
|
|
1
|
+
import { ClientBuilder, ClientDependenciesBuilder, ClientGeneratorsBuilder, ContextSpec, GeneratorMutator, OpenApiParameterObject, OpenApiReferenceObject, OpenApiSchemaObject, PackageJson, ZodCoerceType, ZodVariantOption, ZodVersionOption } from "@orval/core";
|
|
2
2
|
|
|
3
3
|
//#region src/compatible-v4.d.ts
|
|
4
4
|
declare const isZodVersionV4: (packageJson: PackageJson) => boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Resolves whether to emit Zod 4-style output.
|
|
7
|
+
*
|
|
8
|
+
* An explicit `override.zod.version` of `3` or `4` always wins; `'auto'` (the
|
|
9
|
+
* default) falls back to inferring from the output project's resolved `zod`
|
|
10
|
+
* version via {@link isZodVersionV4}. When no package metadata is available,
|
|
11
|
+
* `'auto'` now defaults to Zod 4 so fresh or partially-installed workspaces
|
|
12
|
+
* still get the modern baseline. This keeps generation deterministic when a
|
|
13
|
+
* target is pinned while preserving package-detection for `'auto'`.
|
|
14
|
+
*/
|
|
15
|
+
declare const resolveIsZodV4: (version: ZodVersionOption | undefined, packageJson: PackageJson | undefined) => boolean;
|
|
16
|
+
declare const assertZodTarget: ({
|
|
17
|
+
variant,
|
|
18
|
+
isZodV4
|
|
19
|
+
}: {
|
|
20
|
+
variant: ZodVariantOption | undefined;
|
|
21
|
+
isZodV4: boolean;
|
|
22
|
+
}) => void;
|
|
23
|
+
declare const getZodImportSource: (variant: ZodVariantOption | undefined) => "zod/mini" | "zod";
|
|
24
|
+
declare const getZodTypeName: (variant: ZodVariantOption | undefined) => "ZodMiniType" | "ZodType";
|
|
5
25
|
//#endregion
|
|
6
26
|
//#region src/index.d.ts
|
|
7
|
-
declare const getZodDependencies:
|
|
27
|
+
declare const getZodDependencies: ClientDependenciesBuilder;
|
|
8
28
|
declare const predefinedZodFormats: Set<string>;
|
|
9
29
|
interface ZodValidationSchemaDefinition {
|
|
10
30
|
functions: [string, unknown][];
|
|
@@ -47,6 +67,15 @@ declare const generateZodValidationSchemaDefinition: (schema: OpenApiSchemaObjec
|
|
|
47
67
|
* placeholder instead of being inlined.
|
|
48
68
|
*/
|
|
49
69
|
useReusableSchemas?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* When true, suppress File/Blob coercion for binary string fields anywhere
|
|
72
|
+
* in the tree (`format: binary` / `contentMediaType: application/octet-stream`),
|
|
73
|
+
* keeping them as `string`. Set for `application/x-www-form-urlencoded` bodies,
|
|
74
|
+
* which serialize via URLSearchParams (string-only) — mirrors core's
|
|
75
|
+
* `formDataContext.urlEncoded` handling in getScalar (#1624). Threaded into
|
|
76
|
+
* every recursive call so nested/array/composed fields are covered too.
|
|
77
|
+
*/
|
|
78
|
+
urlEncoded?: boolean;
|
|
50
79
|
/**
|
|
51
80
|
* When true (and `isZodV4`), the top-level (named component) schema emits a
|
|
52
81
|
* `.meta({ id, description?, deprecated? })` instead of `.describe(...)`.
|
|
@@ -75,7 +104,7 @@ interface ZodParamsContext {
|
|
|
75
104
|
interface ZodParamsInjection extends Pick<ZodParamsContext, 'operationId' | 'location' | 'schemaName'> {
|
|
76
105
|
mutator: GeneratorMutator;
|
|
77
106
|
}
|
|
78
|
-
declare const parseZodValidationSchemaDefinition: (input: ZodValidationSchemaDefinition, context: ContextSpec, coerceTypes: boolean | ZodCoerceType[] | undefined, strict: boolean, isZodV4: boolean, preprocess?: GeneratorMutator, paramsInjection?: ZodParamsInjection) => {
|
|
107
|
+
declare const parseZodValidationSchemaDefinition: (input: ZodValidationSchemaDefinition, context: ContextSpec, coerceTypes: boolean | ZodCoerceType[] | undefined, strict: boolean, isZodV4: boolean, preprocess?: GeneratorMutator, paramsInjection?: ZodParamsInjection, variant?: ZodVariantOption) => {
|
|
79
108
|
zod: string;
|
|
80
109
|
consts: string;
|
|
81
110
|
usedRefs: Set<string>;
|
|
@@ -139,5 +168,5 @@ declare const parseParameters: ({
|
|
|
139
168
|
declare const generateZod: ClientBuilder;
|
|
140
169
|
declare const builder: () => () => ClientGeneratorsBuilder;
|
|
141
170
|
//#endregion
|
|
142
|
-
export { ZodParamsContext, ZodParamsInjection, ZodValidationSchemaDefinition, builder, builder as default, dereference, generateFormDataZodSchema, generateZod, generateZodValidationSchemaDefinition, getZodDependencies, isZodVersionV4, parseParameters, parseZodValidationSchemaDefinition, predefinedZodFormats };
|
|
171
|
+
export { ZodParamsContext, ZodParamsInjection, ZodValidationSchemaDefinition, assertZodTarget, builder, builder as default, dereference, generateFormDataZodSchema, generateZod, generateZodValidationSchemaDefinition, getZodDependencies, getZodImportSource, getZodTypeName, isZodVersionV4, parseParameters, parseZodValidationSchemaDefinition, predefinedZodFormats, resolveIsZodV4 };
|
|
143
172
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildDynamicScope, camel, compareVersions, generateMutator, getDynamicAnchorName, getFormDataFieldFileType, getNumberWord, getRefInfo, isBoolean, isDynamicReference, isNumber, isObject, isString, jsStringEscape, jsStringLiteralEscape, logVerbose, pascal, resolveDynamicRef, resolveRef, stringify } from "@orval/core";
|
|
1
|
+
import { buildDynamicScope, buildInlineDynamicScope, camel, compareVersions, generateMutator, getDynamicAnchorName, getFormDataFieldFileType, getNumberWord, getRefInfo, isBoolean, isDynamicReference, isNumber, isObject, isString, jsStringEscape, jsStringLiteralEscape, logVerbose, pascal, resolveDynamicRef, resolveRef, stringify } from "@orval/core";
|
|
2
2
|
import { unique } from "remeda";
|
|
3
3
|
//#region src/compatible-v4.ts
|
|
4
4
|
const getZodPackageVersion = (packageJson) => {
|
|
@@ -10,6 +10,27 @@ const isZodVersionV4 = (packageJson) => {
|
|
|
10
10
|
const withoutRc = version.split("-")[0];
|
|
11
11
|
return compareVersions(withoutRc, "4.0.0");
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Resolves whether to emit Zod 4-style output.
|
|
15
|
+
*
|
|
16
|
+
* An explicit `override.zod.version` of `3` or `4` always wins; `'auto'` (the
|
|
17
|
+
* default) falls back to inferring from the output project's resolved `zod`
|
|
18
|
+
* version via {@link isZodVersionV4}. When no package metadata is available,
|
|
19
|
+
* `'auto'` now defaults to Zod 4 so fresh or partially-installed workspaces
|
|
20
|
+
* still get the modern baseline. This keeps generation deterministic when a
|
|
21
|
+
* target is pinned while preserving package-detection for `'auto'`.
|
|
22
|
+
*/
|
|
23
|
+
const resolveIsZodV4 = (version, packageJson) => {
|
|
24
|
+
if (version === 4) return true;
|
|
25
|
+
if (version === 3) return false;
|
|
26
|
+
if (!packageJson || !getZodPackageVersion(packageJson)) return true;
|
|
27
|
+
return isZodVersionV4(packageJson);
|
|
28
|
+
};
|
|
29
|
+
const assertZodTarget = ({ variant, isZodV4 }) => {
|
|
30
|
+
if (variant === "mini" && !isZodV4) throw new Error("Zod Mini requires Zod 4 output. Use override.zod.version: 4 or install zod@^4 when override.zod.version is 'auto'.");
|
|
31
|
+
};
|
|
32
|
+
const getZodImportSource = (variant) => variant === "mini" ? "zod/mini" : "zod";
|
|
33
|
+
const getZodTypeName = (variant) => variant === "mini" ? "ZodMiniType" : "ZodType";
|
|
13
34
|
const getZodDateFormat = (isZodV4) => {
|
|
14
35
|
return isZodV4 ? "iso.date" : "date";
|
|
15
36
|
};
|
|
@@ -38,7 +59,7 @@ const getLooseObjectFunctionName = (isZodV4) => {
|
|
|
38
59
|
};
|
|
39
60
|
//#endregion
|
|
40
61
|
//#region src/index.ts
|
|
41
|
-
const
|
|
62
|
+
const getZodDependencies = (_hasGlobalMutator, _hasParamsSerializerOptions, _packageJson, _httpClient, _hasTagsMutator, override) => [{
|
|
42
63
|
exports: [{
|
|
43
64
|
default: false,
|
|
44
65
|
name: "zod",
|
|
@@ -46,9 +67,8 @@ const ZOD_DEPENDENCIES = [{
|
|
|
46
67
|
namespaceImport: true,
|
|
47
68
|
values: true
|
|
48
69
|
}],
|
|
49
|
-
dependency:
|
|
70
|
+
dependency: getZodImportSource(override?.zod.variant)
|
|
50
71
|
}];
|
|
51
|
-
const getZodDependencies = () => ZOD_DEPENDENCIES;
|
|
52
72
|
/**
|
|
53
73
|
* values that may appear in "type". Equals SchemaObjectType
|
|
54
74
|
*/
|
|
@@ -94,6 +114,9 @@ const COERCIBLE_TYPES = new Set([
|
|
|
94
114
|
"bigint",
|
|
95
115
|
"date"
|
|
96
116
|
]);
|
|
117
|
+
const PURE_COMMENT = "/*#__PURE__*/ ";
|
|
118
|
+
const zodMiniCall = (fn, args = "") => `${PURE_COMMENT}zod.${fn}(${args})`;
|
|
119
|
+
const zodMiniCoerceCall = (fn, args = "") => `${PURE_COMMENT}zod.coerce.${fn}(${args})`;
|
|
97
120
|
const minAndMaxTypes = new Set([
|
|
98
121
|
"number",
|
|
99
122
|
"string",
|
|
@@ -190,6 +213,7 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
190
213
|
schema = dereference(schema, context);
|
|
191
214
|
}
|
|
192
215
|
const useReusableSchemas = rules?.useReusableSchemas ?? false;
|
|
216
|
+
const urlEncoded = rules?.urlEncoded ?? false;
|
|
193
217
|
const consts = [];
|
|
194
218
|
const constNameRegistry = rules?.constNameRegistry ?? {};
|
|
195
219
|
const constsCounter = isNumber(constNameRegistry[name]) ? constNameRegistry[name] + 1 : 0;
|
|
@@ -231,7 +255,8 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
231
255
|
required: true,
|
|
232
256
|
additionalRequired: allOfRequired,
|
|
233
257
|
constNameRegistry,
|
|
234
|
-
useReusableSchemas
|
|
258
|
+
useReusableSchemas,
|
|
259
|
+
urlEncoded
|
|
235
260
|
}));
|
|
236
261
|
if ((schema.allOf || schema.oneOf || schema.anyOf) && schema.properties) {
|
|
237
262
|
const additionalPropertiesSchema = {
|
|
@@ -245,7 +270,8 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
245
270
|
required: true,
|
|
246
271
|
additionalRequired: allOfRequired,
|
|
247
272
|
constNameRegistry,
|
|
248
|
-
useReusableSchemas
|
|
273
|
+
useReusableSchemas,
|
|
274
|
+
urlEncoded
|
|
249
275
|
});
|
|
250
276
|
if (schema.oneOf || schema.anyOf) functions.push(["allOf", [{
|
|
251
277
|
functions: [[separator, baseSchemas]],
|
|
@@ -288,7 +314,8 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
288
314
|
}, context, name, strict, isZodV4, {
|
|
289
315
|
required: true,
|
|
290
316
|
constNameRegistry,
|
|
291
|
-
useReusableSchemas
|
|
317
|
+
useReusableSchemas,
|
|
318
|
+
urlEncoded
|
|
292
319
|
}))]);
|
|
293
320
|
if (!required && nullable) functions.push(["nullish", void 0]);
|
|
294
321
|
else if (nullable) functions.push(["nullable", void 0]);
|
|
@@ -323,12 +350,14 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
323
350
|
functions.push(["tuple", prefixItems.map((item, idx) => generateZodValidationSchemaDefinition(dereference(item, context), context, camel(`${name}-${idx}-item`), isZodV4, strict, {
|
|
324
351
|
required: true,
|
|
325
352
|
constNameRegistry,
|
|
326
|
-
useReusableSchemas
|
|
353
|
+
useReusableSchemas,
|
|
354
|
+
urlEncoded
|
|
327
355
|
}))]);
|
|
328
356
|
if (schema.items && (max ?? Number.POSITIVE_INFINITY) > prefixItems.length) functions.push(["rest", generateZodValidationSchemaDefinition(schema.items, context, camel(`${name}-item`), strict, isZodV4, {
|
|
329
357
|
required: true,
|
|
330
358
|
constNameRegistry,
|
|
331
|
-
useReusableSchemas
|
|
359
|
+
useReusableSchemas,
|
|
360
|
+
urlEncoded
|
|
332
361
|
})]);
|
|
333
362
|
}
|
|
334
363
|
}
|
|
@@ -337,7 +366,8 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
337
366
|
functions.push(["array", generateZodValidationSchemaDefinition(schema.items, context, camel(`${name}-item`), strict, isZodV4, {
|
|
338
367
|
required: true,
|
|
339
368
|
constNameRegistry,
|
|
340
|
-
useReusableSchemas
|
|
369
|
+
useReusableSchemas,
|
|
370
|
+
urlEncoded
|
|
341
371
|
})]);
|
|
342
372
|
break;
|
|
343
373
|
case "string":
|
|
@@ -346,11 +376,11 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
346
376
|
functions.push(["date", void 0]);
|
|
347
377
|
break;
|
|
348
378
|
}
|
|
349
|
-
if (schema.format === "binary") {
|
|
379
|
+
if (!urlEncoded && schema.format === "binary") {
|
|
350
380
|
functions.push(["instanceof", "File"]);
|
|
351
381
|
break;
|
|
352
382
|
}
|
|
353
|
-
if (schema.contentMediaType === "application/octet-stream" && !schema.contentEncoding) {
|
|
383
|
+
if (!urlEncoded && schema.contentMediaType === "application/octet-stream" && !schema.contentEncoding) {
|
|
354
384
|
functions.push(["instanceof", "File"]);
|
|
355
385
|
break;
|
|
356
386
|
}
|
|
@@ -415,7 +445,8 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
415
445
|
functions.push([objectType, Object.keys(properties).map((key) => ({ [key]: rules?.propertyOverrides?.[key] ?? generateZodValidationSchemaDefinition(properties[key], context, camel(`${name}-${key}`), strict, isZodV4, {
|
|
416
446
|
required: requiredKeys.has(key),
|
|
417
447
|
constNameRegistry,
|
|
418
|
-
useReusableSchemas
|
|
448
|
+
useReusableSchemas,
|
|
449
|
+
urlEncoded
|
|
419
450
|
}) })).reduce((acc, curr) => ({
|
|
420
451
|
...acc,
|
|
421
452
|
...curr
|
|
@@ -433,7 +464,8 @@ const generateZodValidationSchemaDefinition = (schema, context, name, strict, is
|
|
|
433
464
|
functions.push(["additionalProperties", generateZodValidationSchemaDefinition(isBoolean(schema.additionalProperties) ? {} : schema.additionalProperties, context, name, strict, isZodV4, {
|
|
434
465
|
required: true,
|
|
435
466
|
constNameRegistry,
|
|
436
|
-
useReusableSchemas
|
|
467
|
+
useReusableSchemas,
|
|
468
|
+
urlEncoded
|
|
437
469
|
})]);
|
|
438
470
|
break;
|
|
439
471
|
}
|
|
@@ -512,7 +544,7 @@ const PARAMS_MERGE_INTO_OPTIONS_VALIDATORS = new Set([
|
|
|
512
544
|
"iso.datetime",
|
|
513
545
|
"iso.time"
|
|
514
546
|
]);
|
|
515
|
-
const parseZodValidationSchemaDefinition = (input, context, coerceTypes = false, strict, isZodV4, preprocess, paramsInjection) => {
|
|
547
|
+
const parseZodValidationSchemaDefinition = (input, context, coerceTypes = false, strict, isZodV4, preprocess, paramsInjection, variant = "classic") => {
|
|
516
548
|
if (input.functions.length === 0) return {
|
|
517
549
|
zod: "",
|
|
518
550
|
consts: "",
|
|
@@ -546,6 +578,196 @@ const parseZodValidationSchemaDefinition = (input, context, coerceTypes = false,
|
|
|
546
578
|
};
|
|
547
579
|
return `${paramsInjection.mutator.name}(${JSON.stringify(ctx)})`;
|
|
548
580
|
};
|
|
581
|
+
const shouldCoerce = (fn) => coerceTypes && (Array.isArray(coerceTypes) ? coerceTypes.includes(fn) : COERCIBLE_TYPES.has(fn));
|
|
582
|
+
const buildCombinedArgs = (fn, args, fieldPath) => {
|
|
583
|
+
const formattedArgs = formatFunctionArgs(args);
|
|
584
|
+
const paramsArg = buildParamsArg(fn, fieldPath);
|
|
585
|
+
if (paramsArg && formattedArgs && PARAMS_MERGE_INTO_OPTIONS_VALIDATORS.has(fn)) return `{ ...${formattedArgs}, ...${paramsArg} }`;
|
|
586
|
+
if (paramsArg) return formattedArgs ? `${formattedArgs}, ${paramsArg}` : paramsArg;
|
|
587
|
+
return formattedArgs;
|
|
588
|
+
};
|
|
589
|
+
const renderMiniDefinition = (definition, fieldPath = []) => {
|
|
590
|
+
let current;
|
|
591
|
+
const requireCurrent = (fn) => {
|
|
592
|
+
if (!current) throw new Error(`Cannot render zod mini ${fn} without a base schema`);
|
|
593
|
+
return current;
|
|
594
|
+
};
|
|
595
|
+
const renderObject = (objectArgs, objectType) => ({
|
|
596
|
+
kind: "object",
|
|
597
|
+
expr: `${zodMiniCall(objectType, `{
|
|
598
|
+
${Object.entries(objectArgs).map(([key, schema]) => {
|
|
599
|
+
const rendered = renderMiniDefinition(schema, [...fieldPath, key]);
|
|
600
|
+
appendConstsChunk(schema.consts.join("\n"));
|
|
601
|
+
if (Array.isArray(coerceTypes) && coerceTypes.includes("array") && schema.functions.some(([fn]) => fn === "array")) return ` "${key}": ${zodMiniCall("pipe", `${zodMiniCall("transform", "(value) => value === undefined || Array.isArray(value) ? value : [value]")}, ${rendered.expr}`)}`;
|
|
602
|
+
return ` "${key}": ${rendered.expr}`;
|
|
603
|
+
}).join(",\n")}
|
|
604
|
+
}`)}`
|
|
605
|
+
});
|
|
606
|
+
for (let index = 0; index < definition.functions.length; index++) {
|
|
607
|
+
const [fn, args = ""] = definition.functions[index];
|
|
608
|
+
if (fn === "namedRef") {
|
|
609
|
+
const refArgs = args;
|
|
610
|
+
usedRefs.add(refArgs.name);
|
|
611
|
+
current = {
|
|
612
|
+
expr: `__REF_${refArgs.name}__`,
|
|
613
|
+
kind: "ref"
|
|
614
|
+
};
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
if (fn === "fileOrString") {
|
|
618
|
+
current = {
|
|
619
|
+
expr: zodMiniCall("union", `[${zodMiniCall("instanceof", "File")}, ${zodMiniCall("string")}]`),
|
|
620
|
+
kind: "union"
|
|
621
|
+
};
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
if (fn === "allOf") {
|
|
625
|
+
const allOfArgs = args;
|
|
626
|
+
if (strict && allOfArgs.length > 0 && allOfArgs.every((partSchema) => {
|
|
627
|
+
if (partSchema.functions.length === 0) return false;
|
|
628
|
+
const firstFn = partSchema.functions[0][0];
|
|
629
|
+
return firstFn === "object" || firstFn === "strictObject";
|
|
630
|
+
})) {
|
|
631
|
+
const mergedProperties = {};
|
|
632
|
+
const allConsts = [];
|
|
633
|
+
for (const partSchema of allOfArgs) {
|
|
634
|
+
if (partSchema.consts.length > 0) allConsts.push(partSchema.consts.join("\n"));
|
|
635
|
+
const objectFunctionIndex = partSchema.functions.findIndex(([fnName]) => fnName === "object" || fnName === "strictObject");
|
|
636
|
+
if (objectFunctionIndex !== -1) {
|
|
637
|
+
const objectArgs = partSchema.functions[objectFunctionIndex][1];
|
|
638
|
+
if (isObject(objectArgs)) Object.assign(mergedProperties, objectArgs);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
appendConstsChunk(allConsts.join("\n"));
|
|
642
|
+
current = renderObject(mergedProperties, getObjectFunctionName(true, strict));
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
const rendered = allOfArgs.map((partSchema) => {
|
|
646
|
+
appendConstsChunk(partSchema.consts.join("\n"));
|
|
647
|
+
return renderMiniDefinition(partSchema, fieldPath).expr;
|
|
648
|
+
});
|
|
649
|
+
if (rendered.length === 0) {
|
|
650
|
+
current = { expr: "" };
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
current = {
|
|
654
|
+
expr: rendered.reduce((acc, value) => acc ? zodMiniCall("intersection", `${acc}, ${value}`) : value),
|
|
655
|
+
kind: "intersection"
|
|
656
|
+
};
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
if (fn === "oneOf" || fn === "anyOf") {
|
|
660
|
+
const unionArgs = args;
|
|
661
|
+
if (unionArgs.length === 1) {
|
|
662
|
+
appendConstsChunk(unionArgs[0].consts.join("\n"));
|
|
663
|
+
current = renderMiniDefinition(unionArgs[0], fieldPath);
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
current = {
|
|
667
|
+
expr: zodMiniCall("union", `[${unionArgs.map((arg) => {
|
|
668
|
+
appendConstsChunk(arg.consts.join("\n"));
|
|
669
|
+
return renderMiniDefinition(arg, fieldPath).expr;
|
|
670
|
+
}).join(",")}]`),
|
|
671
|
+
kind: "union"
|
|
672
|
+
};
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
if (fn === "additionalProperties") {
|
|
676
|
+
const additionalPropertiesArgs = args;
|
|
677
|
+
const rendered = renderMiniDefinition(additionalPropertiesArgs, fieldPath);
|
|
678
|
+
if (Array.isArray(additionalPropertiesArgs.consts)) appendConstsChunk(additionalPropertiesArgs.consts.join("\n"));
|
|
679
|
+
current = {
|
|
680
|
+
expr: zodMiniCall("record", `${zodMiniCall("string")}, ${rendered.expr}`),
|
|
681
|
+
kind: "object"
|
|
682
|
+
};
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
if (fn === "object" || fn === "strictObject" || fn === "looseObject") {
|
|
686
|
+
current = renderObject(args, fn === "looseObject" ? "looseObject" : getObjectFunctionName(true, strict));
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
if (fn === "passthrough" || fn === "strict") continue;
|
|
690
|
+
if (fn === "array") {
|
|
691
|
+
const arrayArgs = args;
|
|
692
|
+
const rendered = renderMiniDefinition(arrayArgs, fieldPath);
|
|
693
|
+
if (isString(arrayArgs.consts)) appendConstsChunk(arrayArgs.consts);
|
|
694
|
+
else if (Array.isArray(arrayArgs.consts)) appendConstsChunk(arrayArgs.consts.join("\n"));
|
|
695
|
+
current = {
|
|
696
|
+
expr: zodMiniCall("array", rendered.expr),
|
|
697
|
+
kind: "array"
|
|
698
|
+
};
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
if (fn === "tuple") {
|
|
702
|
+
const tupleItems = args.map((x) => {
|
|
703
|
+
const rendered = renderMiniDefinition(x, fieldPath);
|
|
704
|
+
appendConstsChunk(x.consts.join("\n"));
|
|
705
|
+
return rendered.expr;
|
|
706
|
+
}).join(",\n");
|
|
707
|
+
const next = definition.functions[index + 1];
|
|
708
|
+
if (next?.[0] === "rest") {
|
|
709
|
+
const restDefinition = next[1];
|
|
710
|
+
const rest = renderMiniDefinition(restDefinition, fieldPath).expr;
|
|
711
|
+
appendConstsChunk(restDefinition.consts.join("\n"));
|
|
712
|
+
current = {
|
|
713
|
+
expr: zodMiniCall("tuple", `[${tupleItems}], ${rest}`),
|
|
714
|
+
kind: "tuple"
|
|
715
|
+
};
|
|
716
|
+
index++;
|
|
717
|
+
} else current = {
|
|
718
|
+
expr: zodMiniCall("tuple", `[${tupleItems}]`),
|
|
719
|
+
kind: "tuple"
|
|
720
|
+
};
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
const combinedArgs = buildCombinedArgs(fn, args, fieldPath);
|
|
724
|
+
if (fn === "optional" || fn === "nullable" || fn === "nullish") {
|
|
725
|
+
const value = requireCurrent(fn);
|
|
726
|
+
current = {
|
|
727
|
+
expr: zodMiniCall(fn, value.expr),
|
|
728
|
+
kind: value.kind
|
|
729
|
+
};
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
if (fn === "default") {
|
|
733
|
+
const value = requireCurrent(fn);
|
|
734
|
+
current = {
|
|
735
|
+
expr: zodMiniCall("_default", `${value.expr}, ${combinedArgs}`),
|
|
736
|
+
kind: value.kind
|
|
737
|
+
};
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
if (fn === "describe" || fn === "meta") {
|
|
741
|
+
const value = requireCurrent(fn);
|
|
742
|
+
current = {
|
|
743
|
+
expr: `${value.expr}.check(${zodMiniCall(fn, combinedArgs)})`,
|
|
744
|
+
kind: value.kind
|
|
745
|
+
};
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
if (fn === "min" || fn === "max" || fn === "gt" || fn === "lt" || fn === "multipleOf" || fn === "regex" || fn === "length") {
|
|
749
|
+
const value = requireCurrent(fn);
|
|
750
|
+
const checkName = fn === "min" ? value.kind === "number" ? "gte" : "minLength" : fn === "max" ? value.kind === "number" ? "lte" : "maxLength" : fn;
|
|
751
|
+
current = {
|
|
752
|
+
expr: `${value.expr}.check(${zodMiniCall(checkName, combinedArgs)})`,
|
|
753
|
+
kind: value.kind
|
|
754
|
+
};
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
if (fn !== "date" && shouldCoerce(fn) || fn === "date" && shouldCoerce(fn) && context.output.override.useDates) {
|
|
758
|
+
current = {
|
|
759
|
+
expr: zodMiniCoerceCall(fn, combinedArgs),
|
|
760
|
+
kind: fn
|
|
761
|
+
};
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
current = {
|
|
765
|
+
expr: zodMiniCall(fn, combinedArgs),
|
|
766
|
+
kind: fn === "enum" || fn === "literal" || fn === "stringFormat" ? "string" : fn.split(".")[0]
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
return current ?? { expr: "" };
|
|
770
|
+
};
|
|
549
771
|
const parseProperty = (property, fieldPath = []) => {
|
|
550
772
|
const [fn, args = ""] = property;
|
|
551
773
|
if (fn === "namedRef") {
|
|
@@ -658,6 +880,16 @@ ${Object.entries(objectArgs).map(([key, schema]) => {
|
|
|
658
880
|
return `.${fn}(${combinedArgs})`;
|
|
659
881
|
};
|
|
660
882
|
appendConstsChunk(input.consts.join("\n"));
|
|
883
|
+
if (variant === "mini") {
|
|
884
|
+
const rendered = renderMiniDefinition(input);
|
|
885
|
+
const value = preprocess ? zodMiniCall("pipe", `${zodMiniCall("transform", preprocess.name)}, ${rendered.expr}`) : rendered.expr;
|
|
886
|
+
if (consts.includes(",export")) consts = consts.replaceAll(",export", "\nexport");
|
|
887
|
+
return {
|
|
888
|
+
zod: value,
|
|
889
|
+
consts,
|
|
890
|
+
usedRefs
|
|
891
|
+
};
|
|
892
|
+
}
|
|
661
893
|
const schema = input.functions.map((prop) => parseProperty(prop)).join("");
|
|
662
894
|
const value = preprocess ? `.preprocess(${preprocess.name}, ${schema.startsWith(".") ? "zod" : ""}${schema})` : schema;
|
|
663
895
|
const zod = `${value.startsWith(".") ? "zod" : ""}${value}`;
|
|
@@ -740,17 +972,27 @@ function dereferenceProperties(schema, context) {
|
|
|
740
972
|
}, {});
|
|
741
973
|
}
|
|
742
974
|
function buildScopedContext(childContext, refName, resolvedSchema) {
|
|
743
|
-
if (
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
975
|
+
if (refName) {
|
|
976
|
+
const schemaName = extractSchemaNameFromRef(refName);
|
|
977
|
+
if (!schemaName) return childContext;
|
|
978
|
+
const schemaRecord = resolvedSchema;
|
|
979
|
+
const hasDynamicAnchor = typeof schemaRecord.$dynamicAnchor === "string";
|
|
980
|
+
const defs = schemaRecord.$defs;
|
|
981
|
+
const hasDefsAnchors = defs && typeof defs === "object" && Object.values(defs).some((d) => d && typeof d === "object" && "$dynamicAnchor" in d);
|
|
982
|
+
if (!hasDynamicAnchor && !hasDefsAnchors) return childContext;
|
|
983
|
+
return {
|
|
984
|
+
...childContext,
|
|
985
|
+
dynamicScope: buildDynamicScope(schemaName, resolvedSchema, childContext)
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
const inlineScope = buildInlineDynamicScope(resolvedSchema);
|
|
989
|
+
if (Object.keys(inlineScope).length === 0) return childContext;
|
|
751
990
|
return {
|
|
752
991
|
...childContext,
|
|
753
|
-
dynamicScope:
|
|
992
|
+
dynamicScope: {
|
|
993
|
+
...childContext.dynamicScope,
|
|
994
|
+
...inlineScope
|
|
995
|
+
}
|
|
754
996
|
};
|
|
755
997
|
}
|
|
756
998
|
function dereferenceDynamicRef(schema, context) {
|
|
@@ -801,6 +1043,15 @@ const generateFormDataZodSchema = (schema, context, name, strict, isZodV4, encod
|
|
|
801
1043
|
useReusableSchemas
|
|
802
1044
|
});
|
|
803
1045
|
};
|
|
1046
|
+
/**
|
|
1047
|
+
* Parse a request body or response into a zod validation schema definition.
|
|
1048
|
+
*
|
|
1049
|
+
* Selects the relevant content type — JSON (and `+json` vendor types),
|
|
1050
|
+
* `multipart/form-data`, or `application/x-www-form-urlencoded`, plus
|
|
1051
|
+
* `text/plain` for responses — and generates the matching schema, handling
|
|
1052
|
+
* array roots. The url-encoded string-contract rationale lives where the flag
|
|
1053
|
+
* is derived (see `isFormUrlEncoded` below).
|
|
1054
|
+
*/
|
|
804
1055
|
const parseBodyAndResponse = ({ data, context, name, strict, generate, isZodV4, parseType, useReusableSchemas }) => {
|
|
805
1056
|
if (!data || !generate) return {
|
|
806
1057
|
input: {
|
|
@@ -813,7 +1064,9 @@ const parseBodyAndResponse = ({ data, context, name, strict, generate, isZodV4,
|
|
|
813
1064
|
const contentEntries = Object.entries(resolvedRef.content ?? {});
|
|
814
1065
|
const jsonContent = contentEntries.find(isMediaType(String.raw`^application\/([^/;]+\+)?json$`));
|
|
815
1066
|
const formDataContent = contentEntries.find(isMediaType(String.raw`^multipart\/form-data$`));
|
|
816
|
-
const
|
|
1067
|
+
const formUrlEncodedContent = contentEntries.find(isMediaType(String.raw`^application\/x-www-form-urlencoded$`));
|
|
1068
|
+
const [contentType, mediaType] = jsonContent ? ["application/json", jsonContent[1]] : formDataContent ? ["multipart/form-data", formDataContent[1]] : formUrlEncodedContent ? ["application/x-www-form-urlencoded", formUrlEncodedContent[1]] : [void 0, void 0];
|
|
1069
|
+
const isFormUrlEncoded = contentType === "application/x-www-form-urlencoded";
|
|
817
1070
|
const schema = mediaType?.schema;
|
|
818
1071
|
if (!schema) {
|
|
819
1072
|
if (parseType === "response") {
|
|
@@ -844,7 +1097,8 @@ const parseBodyAndResponse = ({ data, context, name, strict, generate, isZodV4,
|
|
|
844
1097
|
return {
|
|
845
1098
|
input: generateZodValidationSchemaDefinition(parseType === "body" ? removeReadOnlyProperties(rawItems) : rawItems, context, name, strict, isZodV4, {
|
|
846
1099
|
required: true,
|
|
847
|
-
useReusableSchemas
|
|
1100
|
+
useReusableSchemas,
|
|
1101
|
+
urlEncoded: isFormUrlEncoded
|
|
848
1102
|
}),
|
|
849
1103
|
isArray: true,
|
|
850
1104
|
rules: {
|
|
@@ -857,7 +1111,8 @@ const parseBodyAndResponse = ({ data, context, name, strict, generate, isZodV4,
|
|
|
857
1111
|
return {
|
|
858
1112
|
input: contentType === "multipart/form-data" ? generateFormDataZodSchema(effectiveSchema, context, name, strict, isZodV4, encoding, useReusableSchemas) : generateZodValidationSchemaDefinition(effectiveSchema, context, name, strict, isZodV4, {
|
|
859
1113
|
required: true,
|
|
860
|
-
useReusableSchemas
|
|
1114
|
+
useReusableSchemas,
|
|
1115
|
+
urlEncoded: isFormUrlEncoded
|
|
861
1116
|
}),
|
|
862
1117
|
isArray: false
|
|
863
1118
|
};
|
|
@@ -965,7 +1220,12 @@ const parseParameters = ({ data, context, operationName, isZodV4, strict, genera
|
|
|
965
1220
|
};
|
|
966
1221
|
};
|
|
967
1222
|
const generateZodRoute = async ({ operationId, operationName, verb, override }, { pathRoute, context, output }) => {
|
|
968
|
-
const
|
|
1223
|
+
const zodVariant = context.output.override.zod.variant;
|
|
1224
|
+
const isZodV4 = resolveIsZodV4(context.output.override.zod.version, context.output.packageJson);
|
|
1225
|
+
assertZodTarget({
|
|
1226
|
+
variant: zodVariant,
|
|
1227
|
+
isZodV4
|
|
1228
|
+
});
|
|
969
1229
|
const useReusableSchemas = context.output.override.zod.generateReusableSchemas;
|
|
970
1230
|
const spec = context.spec.paths?.[pathRoute];
|
|
971
1231
|
if (spec == void 0) throw new Error(`No such path ${pathRoute} in ${context.projectName}`);
|
|
@@ -1021,7 +1281,7 @@ const generateZodRoute = async ({ operationId, operationName, verb, override },
|
|
|
1021
1281
|
location,
|
|
1022
1282
|
schemaName: `${pascalOperationName}${schemaSuffix}`
|
|
1023
1283
|
} : void 0;
|
|
1024
|
-
let inputParams = parseZodValidationSchemaDefinition(parsedParameters.params, context, override.zod.coerce.param, override.zod.strict.param, isZodV4, preprocessParams, makeParamsInjection("param", "Params"));
|
|
1284
|
+
let inputParams = parseZodValidationSchemaDefinition(parsedParameters.params, context, override.zod.coerce.param, override.zod.strict.param, isZodV4, preprocessParams, makeParamsInjection("param", "Params"), zodVariant);
|
|
1025
1285
|
const preprocessQueryParams = override.zod.preprocess?.query ? await generateMutator({
|
|
1026
1286
|
output,
|
|
1027
1287
|
mutator: override.zod.preprocess.query,
|
|
@@ -1029,7 +1289,7 @@ const generateZodRoute = async ({ operationId, operationName, verb, override },
|
|
|
1029
1289
|
workspace: context.workspace,
|
|
1030
1290
|
tsconfig: context.output.tsconfig
|
|
1031
1291
|
}) : void 0;
|
|
1032
|
-
let inputQueryParams = parseZodValidationSchemaDefinition(parsedParameters.queryParams, context, override.zod.coerce.query, override.zod.strict.query, isZodV4, preprocessQueryParams, makeParamsInjection("query", "QueryParams"));
|
|
1292
|
+
let inputQueryParams = parseZodValidationSchemaDefinition(parsedParameters.queryParams, context, override.zod.coerce.query, override.zod.strict.query, isZodV4, preprocessQueryParams, makeParamsInjection("query", "QueryParams"), zodVariant);
|
|
1033
1293
|
const preprocessHeader = override.zod.preprocess?.header ? await generateMutator({
|
|
1034
1294
|
output,
|
|
1035
1295
|
mutator: override.zod.preprocess.header,
|
|
@@ -1037,7 +1297,7 @@ const generateZodRoute = async ({ operationId, operationName, verb, override },
|
|
|
1037
1297
|
workspace: context.workspace,
|
|
1038
1298
|
tsconfig: context.output.tsconfig
|
|
1039
1299
|
}) : void 0;
|
|
1040
|
-
let inputHeaders = parseZodValidationSchemaDefinition(parsedParameters.headers, context, override.zod.coerce.header, override.zod.strict.header, isZodV4, preprocessHeader, makeParamsInjection("header", "Header"));
|
|
1300
|
+
let inputHeaders = parseZodValidationSchemaDefinition(parsedParameters.headers, context, override.zod.coerce.header, override.zod.strict.header, isZodV4, preprocessHeader, makeParamsInjection("header", "Header"), zodVariant);
|
|
1041
1301
|
const preprocessBody = override.zod.preprocess?.body ? await generateMutator({
|
|
1042
1302
|
output,
|
|
1043
1303
|
mutator: override.zod.preprocess.body,
|
|
@@ -1045,7 +1305,7 @@ const generateZodRoute = async ({ operationId, operationName, verb, override },
|
|
|
1045
1305
|
workspace: context.workspace,
|
|
1046
1306
|
tsconfig: context.output.tsconfig
|
|
1047
1307
|
}) : void 0;
|
|
1048
|
-
let inputBody = parseZodValidationSchemaDefinition(parsedBody.input, context, override.zod.coerce.body, override.zod.strict.body, isZodV4, preprocessBody, makeParamsInjection("body", "Body"));
|
|
1308
|
+
let inputBody = parseZodValidationSchemaDefinition(parsedBody.input, context, override.zod.coerce.body, override.zod.strict.body, isZodV4, preprocessBody, makeParamsInjection("body", "Body"), zodVariant);
|
|
1049
1309
|
const preprocessResponse = override.zod.preprocess?.response ? await generateMutator({
|
|
1050
1310
|
output,
|
|
1051
1311
|
mutator: override.zod.preprocess.response,
|
|
@@ -1053,7 +1313,7 @@ const generateZodRoute = async ({ operationId, operationName, verb, override },
|
|
|
1053
1313
|
workspace: context.workspace,
|
|
1054
1314
|
tsconfig: context.output.tsconfig
|
|
1055
1315
|
}) : void 0;
|
|
1056
|
-
const inputResponses = parsedResponses.map((parsedResponse, index) => parseZodValidationSchemaDefinition(parsedResponse.input, context, override.zod.coerce.response, override.zod.strict.response, isZodV4, preprocessResponse, makeParamsInjection("response", responses[index][0] ? `${responses[index][0]}Response` : "Response")));
|
|
1316
|
+
const inputResponses = parsedResponses.map((parsedResponse, index) => parseZodValidationSchemaDefinition(parsedResponse.input, context, override.zod.coerce.response, override.zod.strict.response, isZodV4, preprocessResponse, makeParamsInjection("response", responses[index][0] ? `${responses[index][0]}Response` : "Response"), zodVariant));
|
|
1057
1317
|
const SENTINEL_PATTERN = /__REF_([A-Za-z_$][A-Za-z0-9_$]*)__/g;
|
|
1058
1318
|
const rewriteSentinels = (s) => s.replaceAll(SENTINEL_PATTERN, (_m, name) => name);
|
|
1059
1319
|
const allUsedRefs = new Set([
|
|
@@ -1092,6 +1352,11 @@ const generateZodRoute = async ({ operationId, operationName, verb, override },
|
|
|
1092
1352
|
};
|
|
1093
1353
|
const useBrandedTypes = override.zod.useBrandedTypes;
|
|
1094
1354
|
const brand = (name) => useBrandedTypes ? isZodV4 ? `.brand("${name}")` : `.brand<"${name}">()` : "";
|
|
1355
|
+
const zodArrayWithBounds = (itemName, rules) => {
|
|
1356
|
+
const checks = [...rules?.min ? [zodMiniCall("minLength", `${rules.min}`)] : [], ...rules?.max ? [zodMiniCall("maxLength", `${rules.max}`)] : []];
|
|
1357
|
+
if (zodVariant === "mini") return `${zodMiniCall("array", itemName)}${checks.map((check) => `.check(${check})`).join("")}`;
|
|
1358
|
+
return `zod.array(${itemName})${rules?.min ? `.min(${rules.min})` : ""}${rules?.max ? `.max(${rules.max})` : ""}`;
|
|
1359
|
+
};
|
|
1095
1360
|
const localTaken = new Set(allUsedRefs);
|
|
1096
1361
|
const allocateExportName = (baseName, hasItem) => {
|
|
1097
1362
|
const collides = (name) => localTaken.has(name) || hasItem && localTaken.has(`${name}Item`);
|
|
@@ -1126,7 +1391,7 @@ const generateZodRoute = async ({ operationId, operationName, verb, override },
|
|
|
1126
1391
|
...inputHeaders.zod ? [`export const ${headerName} = ${inputHeaders.zod}${brand(headerName)}`] : [],
|
|
1127
1392
|
...inputBody.consts ? [inputBody.consts] : [],
|
|
1128
1393
|
...inputBody.zod ? [parsedBody.isArray ? `export const ${bodyName}Item = ${inputBody.zod}
|
|
1129
|
-
export const ${bodyName} =
|
|
1394
|
+
export const ${bodyName} = ${zodArrayWithBounds(bodyName + "Item", parsedBody.rules)}${brand(bodyName)}` : `export const ${bodyName} = ${inputBody.zod}${brand(bodyName)}`] : [],
|
|
1130
1395
|
...inputResponses.flatMap((inputResponse, index) => {
|
|
1131
1396
|
const operationResponse = allocateExportName(pascal(`${operationName}-${responses[index][0]}-response`), parsedResponses[index].isArray);
|
|
1132
1397
|
if (!inputResponse.zod) {
|
|
@@ -1140,10 +1405,10 @@ export const ${bodyName} = zod.array(${bodyName}Item)${parsedBody.rules?.min ? `
|
|
|
1140
1405
|
const specResponseKeys = new Set(Object.keys(spec[verb]?.responses ?? {}));
|
|
1141
1406
|
isNoContent = !(specResponseKeys.has("200") || specResponseKeys.has("2XX") || specResponseKeys.has("2xx"));
|
|
1142
1407
|
}
|
|
1143
|
-
return [`export const ${operationResponse} = ${isNoContent ? "zod.void()" : "zod.unknown()"}${brand(operationResponse)}`];
|
|
1408
|
+
return [`export const ${operationResponse} = ${isNoContent ? zodVariant === "mini" ? zodMiniCall("void") : "zod.void()" : zodVariant === "mini" ? zodMiniCall("unknown") : "zod.unknown()"}${brand(operationResponse)}`];
|
|
1144
1409
|
}
|
|
1145
1410
|
return [...inputResponse.consts ? [inputResponse.consts] : [], parsedResponses[index].isArray ? `export const ${operationResponse}Item = ${inputResponse.zod}
|
|
1146
|
-
export const ${operationResponse} =
|
|
1411
|
+
export const ${operationResponse} = ${zodArrayWithBounds(`${operationResponse}Item`, parsedResponses[index].rules)}${brand(operationResponse)}` : `export const ${operationResponse} = ${inputResponse.zod}${brand(operationResponse)}`];
|
|
1147
1412
|
})
|
|
1148
1413
|
].join("\n\n"),
|
|
1149
1414
|
mutators: [
|
|
@@ -1175,6 +1440,6 @@ const zodClientBuilder = {
|
|
|
1175
1440
|
};
|
|
1176
1441
|
const builder = () => () => zodClientBuilder;
|
|
1177
1442
|
//#endregion
|
|
1178
|
-
export { builder, builder as default, dereference, generateFormDataZodSchema, generateZod, generateZodValidationSchemaDefinition, getZodDependencies, isZodVersionV4, parseParameters, parseZodValidationSchemaDefinition, predefinedZodFormats };
|
|
1443
|
+
export { assertZodTarget, builder, builder as default, dereference, generateFormDataZodSchema, generateZod, generateZodValidationSchemaDefinition, getZodDependencies, getZodImportSource, getZodTypeName, isZodVersionV4, parseParameters, parseZodValidationSchemaDefinition, predefinedZodFormats, resolveIsZodV4 };
|
|
1179
1444
|
|
|
1180
1445
|
//# sourceMappingURL=index.mjs.map
|