zod-openapi 3.1.1 → 3.3.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/README.md +4 -1
- package/dist/components.chunk.cjs +93 -100
- package/dist/components.chunk.mjs +93 -100
- package/dist/create/schema/single.d.ts +4 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -276,6 +276,7 @@ const { schema, components } = createSchema(job, {
|
|
|
276
276
|
schemaType: 'input'; // This controls whether this should be rendered as a request (`input`) or response (`output`). Defaults to `output`
|
|
277
277
|
openapi: '3.0.0'; // OpenAPI version to use, defaults to `'3.1.0'`
|
|
278
278
|
components: { jobId: z.string() } // Additional components to use and create while rendering the schema
|
|
279
|
+
componentRefPath: '#/definitions/' // Defaults to #/components/schemas/
|
|
279
280
|
})
|
|
280
281
|
```
|
|
281
282
|
|
|
@@ -468,7 +469,7 @@ createDocument({
|
|
|
468
469
|
|
|
469
470
|
##### Zod Effects
|
|
470
471
|
|
|
471
|
-
`.transform()`, `.default()` and `.pipe()` are complicated because they technically comprise of two types (input & output). This means that we need to understand which type you are creating. In particular with transform it is very difficult to infer the output type. This library will automatically select which _type_ to use by checking how the schema is used based on the following rules:
|
|
472
|
+
`.transform()`, `.catch()`, `.default()` and `.pipe()` are complicated because they technically comprise of two types (input & output). This means that we need to understand which type you are creating. In particular with transform it is very difficult to infer the output type. This library will automatically select which _type_ to use by checking how the schema is used based on the following rules:
|
|
472
473
|
|
|
473
474
|
_Input_: Request Bodies, Request Parameters, Headers
|
|
474
475
|
|
|
@@ -693,6 +694,8 @@ For example in `z.string().nullable()` will be rendered differently
|
|
|
693
694
|
- ZodBoolean
|
|
694
695
|
- ZodBranded
|
|
695
696
|
- ZodCatch
|
|
697
|
+
- Treated as ZodDefault
|
|
698
|
+
- ZodCustom
|
|
696
699
|
- ZodDate
|
|
697
700
|
- `type` is mapped as `string` by default
|
|
698
701
|
- ZodDefault
|
|
@@ -55,7 +55,18 @@ const createBooleanSchema = (_zodBoolean) => ({
|
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
57
|
const createBrandedSchema = (zodBranded, state) => createSchemaObject(zodBranded._def.type, state, ["brand"]);
|
|
58
|
-
const createCatchSchema = (zodCatch, state) =>
|
|
58
|
+
const createCatchSchema = (zodCatch, state) => {
|
|
59
|
+
const schemaObject = createSchemaObject(zodCatch._def.innerType, state, [
|
|
60
|
+
"default"
|
|
61
|
+
]);
|
|
62
|
+
const catchResult = zodCatch.safeParse(void 0);
|
|
63
|
+
const maybeDefaultValue = catchResult.success ? {
|
|
64
|
+
default: catchResult.data
|
|
65
|
+
} : void 0;
|
|
66
|
+
return enhanceWithMetadata(schemaObject, {
|
|
67
|
+
...maybeDefaultValue
|
|
68
|
+
});
|
|
69
|
+
};
|
|
59
70
|
const createDateSchema = (_zodDate, state) => {
|
|
60
71
|
var _a;
|
|
61
72
|
return {
|
|
@@ -565,74 +576,7 @@ const getZodNumberChecks = (zodNumber) => zodNumber._def.checks.reduce((acc, che
|
|
|
565
576
|
}, {});
|
|
566
577
|
const mapNumberType = (zodNumberChecks) => zodNumberChecks.int ? "integer" : "number";
|
|
567
578
|
const createOptionalSchema = (zodOptional, state) => createSchemaObject(zodOptional.unwrap(), state, ["optional"]);
|
|
568
|
-
const
|
|
569
|
-
var _a, _b, _c;
|
|
570
|
-
if (isZodType(zodSchema, "ZodOptional") || isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined") || isZodType(zodSchema, "ZodLiteral") && zodSchema._def.value === void 0) {
|
|
571
|
-
return { optional: true };
|
|
572
|
-
}
|
|
573
|
-
if (isZodType(zodSchema, "ZodDefault")) {
|
|
574
|
-
if (((_a = zodSchema._def.openapi) == null ? void 0 : _a.effectType) === "input") {
|
|
575
|
-
return { optional: true };
|
|
576
|
-
}
|
|
577
|
-
if (((_b = zodSchema._def.openapi) == null ? void 0 : _b.effectType) === "output") {
|
|
578
|
-
return { optional: false };
|
|
579
|
-
}
|
|
580
|
-
return {
|
|
581
|
-
optional: state.type === "input",
|
|
582
|
-
effects: [
|
|
583
|
-
{
|
|
584
|
-
type: "schema",
|
|
585
|
-
creationType: state.type,
|
|
586
|
-
zodType: zodSchema,
|
|
587
|
-
path: [...state.path]
|
|
588
|
-
}
|
|
589
|
-
]
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
if (isZodType(zodSchema, "ZodNullable") || isZodType(zodSchema, "ZodCatch")) {
|
|
593
|
-
return isOptionalSchema(zodSchema._def.innerType, state);
|
|
594
|
-
}
|
|
595
|
-
if (isZodType(zodSchema, "ZodEffects")) {
|
|
596
|
-
return isOptionalSchema(zodSchema._def.schema, state);
|
|
597
|
-
}
|
|
598
|
-
if (isZodType(zodSchema, "ZodUnion") || isZodType(zodSchema, "ZodDiscriminatedUnion")) {
|
|
599
|
-
const results = zodSchema._def.options.map(
|
|
600
|
-
(schema) => isOptionalSchema(schema, state)
|
|
601
|
-
);
|
|
602
|
-
return results.reduce(
|
|
603
|
-
(acc, result) => ({
|
|
604
|
-
optional: acc.optional || result.optional,
|
|
605
|
-
effects: flattenEffects([acc.effects, result.effects])
|
|
606
|
-
}),
|
|
607
|
-
{ optional: false }
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
if (isZodType(zodSchema, "ZodIntersection")) {
|
|
611
|
-
const results = [zodSchema._def.left, zodSchema._def.right].map(
|
|
612
|
-
(schema) => isOptionalSchema(schema, state)
|
|
613
|
-
);
|
|
614
|
-
return results.reduce(
|
|
615
|
-
(acc, result) => ({
|
|
616
|
-
optional: acc.optional || result.optional,
|
|
617
|
-
effects: flattenEffects([acc.effects, result.effects])
|
|
618
|
-
}),
|
|
619
|
-
{ optional: false }
|
|
620
|
-
);
|
|
621
|
-
}
|
|
622
|
-
if (isZodType(zodSchema, "ZodPipeline")) {
|
|
623
|
-
const type = ((_c = zodSchema._def.openapi) == null ? void 0 : _c.effectType) ?? state.type;
|
|
624
|
-
if (type === "input") {
|
|
625
|
-
return isOptionalSchema(zodSchema._def.in, state);
|
|
626
|
-
}
|
|
627
|
-
if (type === "output") {
|
|
628
|
-
return isOptionalSchema(zodSchema._def.out, state);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
if (isZodType(zodSchema, "ZodLazy")) {
|
|
632
|
-
return isOptionalSchema(zodSchema._def.getter(), state);
|
|
633
|
-
}
|
|
634
|
-
return { optional: zodSchema.isOptional() };
|
|
635
|
-
};
|
|
579
|
+
const isOptionalObjectKey = (zodSchema) => isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined") || isZodType(zodSchema, "ZodLiteral") && zodSchema._def.value === void 0;
|
|
636
580
|
const createObjectSchema = (zodObject, state) => {
|
|
637
581
|
var _a;
|
|
638
582
|
const extendedSchema = createExtendedSchema(
|
|
@@ -653,7 +597,7 @@ const createObjectSchema = (zodObject, state) => {
|
|
|
653
597
|
);
|
|
654
598
|
};
|
|
655
599
|
const createExtendedSchema = (zodObject, baseZodObject, state) => {
|
|
656
|
-
var _a;
|
|
600
|
+
var _a, _b;
|
|
657
601
|
if (!baseZodObject) {
|
|
658
602
|
return void 0;
|
|
659
603
|
}
|
|
@@ -693,7 +637,14 @@ const createExtendedSchema = (zodObject, baseZodObject, state) => {
|
|
|
693
637
|
return {
|
|
694
638
|
type: "schema",
|
|
695
639
|
schema: {
|
|
696
|
-
allOf: [
|
|
640
|
+
allOf: [
|
|
641
|
+
{
|
|
642
|
+
$ref: createComponentSchemaRef(
|
|
643
|
+
completeComponent.ref,
|
|
644
|
+
(_b = state.documentOptions) == null ? void 0 : _b.componentRefPath
|
|
645
|
+
)
|
|
646
|
+
}
|
|
647
|
+
],
|
|
697
648
|
...extendedSchema.schema
|
|
698
649
|
},
|
|
699
650
|
effects: flattenEffects([
|
|
@@ -735,7 +686,7 @@ const createShapeDiff = (baseObj, extendedObj) => {
|
|
|
735
686
|
};
|
|
736
687
|
const createObjectSchemaFromShape = (shape, { unknownKeys, catchAll }, state) => {
|
|
737
688
|
const properties = mapProperties(shape, state);
|
|
738
|
-
const required = mapRequired(shape, state);
|
|
689
|
+
const required = mapRequired(properties, shape, state);
|
|
739
690
|
const additionalProperties = !isZodType(catchAll, "ZodNever") ? createSchemaObject(catchAll, state, ["additional properties"]) : void 0;
|
|
740
691
|
return {
|
|
741
692
|
type: "schema",
|
|
@@ -755,17 +706,38 @@ const createObjectSchemaFromShape = (shape, { unknownKeys, catchAll }, state) =>
|
|
|
755
706
|
])
|
|
756
707
|
};
|
|
757
708
|
};
|
|
758
|
-
const mapRequired = (shape, state) => {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
709
|
+
const mapRequired = (properties, shape, state) => {
|
|
710
|
+
if (!properties) {
|
|
711
|
+
return void 0;
|
|
712
|
+
}
|
|
713
|
+
const { required, effects } = Object.entries(properties.schemas).reduce(
|
|
714
|
+
(acc, [key, schemaOrRef]) => {
|
|
715
|
+
const zodSchema = shape[key];
|
|
716
|
+
if (!zodSchema) {
|
|
717
|
+
throw new Error("Property somehow doesn't exist in shape");
|
|
718
|
+
}
|
|
719
|
+
const result = zodSchema.safeParse(void 0);
|
|
720
|
+
if (!result.success) {
|
|
765
721
|
acc.required.push(key);
|
|
722
|
+
return acc;
|
|
766
723
|
}
|
|
767
|
-
if (
|
|
768
|
-
|
|
724
|
+
if (result.data !== void 0) {
|
|
725
|
+
const baseEffect = {
|
|
726
|
+
zodType: zodSchema,
|
|
727
|
+
path: [...state.path, `property: ${key}`]
|
|
728
|
+
};
|
|
729
|
+
const effect = schemaOrRef.type === "ref" ? {
|
|
730
|
+
...baseEffect,
|
|
731
|
+
type: "component"
|
|
732
|
+
} : {
|
|
733
|
+
...baseEffect,
|
|
734
|
+
type: "schema",
|
|
735
|
+
creationType: state.type
|
|
736
|
+
};
|
|
737
|
+
acc.effects.push(effect);
|
|
738
|
+
if (state.type === "output") {
|
|
739
|
+
acc.required.push(key);
|
|
740
|
+
}
|
|
769
741
|
}
|
|
770
742
|
return acc;
|
|
771
743
|
},
|
|
@@ -774,7 +746,7 @@ const mapRequired = (shape, state) => {
|
|
|
774
746
|
effects: []
|
|
775
747
|
}
|
|
776
748
|
);
|
|
777
|
-
return { required, effects
|
|
749
|
+
return { required, effects };
|
|
778
750
|
};
|
|
779
751
|
const mapProperties = (shape, state) => {
|
|
780
752
|
const shapeEntries = Object.entries(shape);
|
|
@@ -783,17 +755,17 @@ const mapProperties = (shape, state) => {
|
|
|
783
755
|
}
|
|
784
756
|
return shapeEntries.reduce(
|
|
785
757
|
(acc, [key, zodSchema]) => {
|
|
786
|
-
if (
|
|
758
|
+
if (isOptionalObjectKey(zodSchema)) {
|
|
787
759
|
return acc;
|
|
788
760
|
}
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
]
|
|
792
|
-
acc.
|
|
793
|
-
acc.effects.push(property.effects);
|
|
761
|
+
const schema = createSchemaObject(zodSchema, state, [`property: ${key}`]);
|
|
762
|
+
acc.schemas[key] = schema;
|
|
763
|
+
acc.properties[key] = schema.schema;
|
|
764
|
+
acc.effects.push(schema.effects);
|
|
794
765
|
return acc;
|
|
795
766
|
},
|
|
796
767
|
{
|
|
768
|
+
schemas: {},
|
|
797
769
|
properties: {},
|
|
798
770
|
effects: []
|
|
799
771
|
}
|
|
@@ -1134,9 +1106,12 @@ const mapPrefixItems = (items, state) => {
|
|
|
1134
1106
|
};
|
|
1135
1107
|
const createUnionSchema = (zodUnion, state) => {
|
|
1136
1108
|
var _a, _b;
|
|
1137
|
-
const schemas = zodUnion.options.
|
|
1138
|
-
(option
|
|
1139
|
-
|
|
1109
|
+
const schemas = zodUnion.options.reduce((acc, option, index) => {
|
|
1110
|
+
if (!isOptionalObjectKey(option)) {
|
|
1111
|
+
acc.push(createSchemaObject(option, state, [`union option ${index}`]));
|
|
1112
|
+
}
|
|
1113
|
+
return acc;
|
|
1114
|
+
}, []);
|
|
1140
1115
|
if (((_a = zodUnion._def.openapi) == null ? void 0 : _a.unionOneOf) ?? ((_b = state.documentOptions) == null ? void 0 : _b.unionOneOf)) {
|
|
1141
1116
|
return {
|
|
1142
1117
|
type: "schema",
|
|
@@ -1281,6 +1256,7 @@ const createNewSchema = (zodSchema, state) => {
|
|
|
1281
1256
|
return schemaWithMetadata;
|
|
1282
1257
|
};
|
|
1283
1258
|
const createNewRef = (ref, zodSchema, state) => {
|
|
1259
|
+
var _a;
|
|
1284
1260
|
state.components.schemas.set(zodSchema, {
|
|
1285
1261
|
type: "in-progress",
|
|
1286
1262
|
ref
|
|
@@ -1297,7 +1273,12 @@ const createNewRef = (ref, zodSchema, state) => {
|
|
|
1297
1273
|
});
|
|
1298
1274
|
return {
|
|
1299
1275
|
type: "ref",
|
|
1300
|
-
schema: {
|
|
1276
|
+
schema: {
|
|
1277
|
+
$ref: createComponentSchemaRef(
|
|
1278
|
+
ref,
|
|
1279
|
+
(_a = state.documentOptions) == null ? void 0 : _a.componentRefPath
|
|
1280
|
+
)
|
|
1281
|
+
},
|
|
1301
1282
|
effects: newSchema.effects ? [
|
|
1302
1283
|
{
|
|
1303
1284
|
type: "component",
|
|
@@ -1309,10 +1290,16 @@ const createNewRef = (ref, zodSchema, state) => {
|
|
|
1309
1290
|
};
|
|
1310
1291
|
};
|
|
1311
1292
|
const createExistingRef = (zodSchema, component, state) => {
|
|
1293
|
+
var _a, _b;
|
|
1312
1294
|
if (component && component.type === "complete") {
|
|
1313
1295
|
return {
|
|
1314
1296
|
type: "ref",
|
|
1315
|
-
schema: {
|
|
1297
|
+
schema: {
|
|
1298
|
+
$ref: createComponentSchemaRef(
|
|
1299
|
+
component.ref,
|
|
1300
|
+
(_a = state.documentOptions) == null ? void 0 : _a.componentRefPath
|
|
1301
|
+
)
|
|
1302
|
+
},
|
|
1316
1303
|
effects: component.effects ? [
|
|
1317
1304
|
{
|
|
1318
1305
|
type: "component",
|
|
@@ -1326,7 +1313,12 @@ const createExistingRef = (zodSchema, component, state) => {
|
|
|
1326
1313
|
if (component && component.type === "in-progress") {
|
|
1327
1314
|
return {
|
|
1328
1315
|
type: "ref",
|
|
1329
|
-
schema: {
|
|
1316
|
+
schema: {
|
|
1317
|
+
$ref: createComponentSchemaRef(
|
|
1318
|
+
component.ref,
|
|
1319
|
+
(_b = state.documentOptions) == null ? void 0 : _b.componentRefPath
|
|
1320
|
+
)
|
|
1321
|
+
},
|
|
1330
1322
|
effects: [
|
|
1331
1323
|
{
|
|
1332
1324
|
type: "component",
|
|
@@ -1417,7 +1409,7 @@ const createContent = (contentObject, components, type, subpath, documentOptions
|
|
|
1417
1409
|
);
|
|
1418
1410
|
const createComponentParamRef = (ref) => `#/components/parameters/${ref}`;
|
|
1419
1411
|
const createBaseParameter = (schema, components, subpath, documentOptions) => {
|
|
1420
|
-
var _a, _b
|
|
1412
|
+
var _a, _b;
|
|
1421
1413
|
const { ref, ...rest } = ((_a = schema._def.openapi) == null ? void 0 : _a.param) ?? {};
|
|
1422
1414
|
const state = {
|
|
1423
1415
|
components,
|
|
@@ -1427,8 +1419,8 @@ const createBaseParameter = (schema, components, subpath, documentOptions) => {
|
|
|
1427
1419
|
documentOptions
|
|
1428
1420
|
};
|
|
1429
1421
|
const schemaObject = createSchema(schema, state, [...subpath, "schema"]);
|
|
1430
|
-
const required = !
|
|
1431
|
-
const description = ((
|
|
1422
|
+
const required = !schema.isOptional();
|
|
1423
|
+
const description = ((_b = schema._def.openapi) == null ? void 0 : _b.description) ?? schema._def.description;
|
|
1432
1424
|
return {
|
|
1433
1425
|
...description && { description },
|
|
1434
1426
|
...rest,
|
|
@@ -1625,7 +1617,7 @@ const createHeaderOrRef = (schema, components, documentOptions) => {
|
|
|
1625
1617
|
return baseHeader;
|
|
1626
1618
|
};
|
|
1627
1619
|
const createBaseHeader = (schema, components, documentOptions) => {
|
|
1628
|
-
var _a
|
|
1620
|
+
var _a;
|
|
1629
1621
|
const { ref, ...rest } = ((_a = schema._def.openapi) == null ? void 0 : _a.header) ?? {};
|
|
1630
1622
|
const state = {
|
|
1631
1623
|
components,
|
|
@@ -1635,7 +1627,8 @@ const createBaseHeader = (schema, components, documentOptions) => {
|
|
|
1635
1627
|
documentOptions
|
|
1636
1628
|
};
|
|
1637
1629
|
const schemaObject = createSchema(schema, state, ["header"]);
|
|
1638
|
-
const
|
|
1630
|
+
const optionalResult = schema.safeParse(void 0);
|
|
1631
|
+
const required = !optionalResult.success || optionalResult !== void 0;
|
|
1639
1632
|
return {
|
|
1640
1633
|
...rest,
|
|
1641
1634
|
...schema && { schema: schemaObject },
|
|
@@ -1998,7 +1991,7 @@ const getCallbacks = (callbacks, components) => {
|
|
|
1998
1991
|
});
|
|
1999
1992
|
});
|
|
2000
1993
|
};
|
|
2001
|
-
const createComponentSchemaRef = (schemaRef) =>
|
|
1994
|
+
const createComponentSchemaRef = (schemaRef, componentPath) => `${componentPath ?? "#/components/schemas/"}${schemaRef}`;
|
|
2002
1995
|
const createComponentResponseRef = (responseRef) => `#/components/responses/${responseRef}`;
|
|
2003
1996
|
const createComponentRequestBodyRef = (requestBodyRef) => `#/components/requestBodies/${requestBodyRef}`;
|
|
2004
1997
|
const createComponentCallbackRef = (callbackRef) => `#/components/callbacks/${callbackRef}`;
|
|
@@ -54,7 +54,18 @@ const createBooleanSchema = (_zodBoolean) => ({
|
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
const createBrandedSchema = (zodBranded, state) => createSchemaObject(zodBranded._def.type, state, ["brand"]);
|
|
57
|
-
const createCatchSchema = (zodCatch, state) =>
|
|
57
|
+
const createCatchSchema = (zodCatch, state) => {
|
|
58
|
+
const schemaObject = createSchemaObject(zodCatch._def.innerType, state, [
|
|
59
|
+
"default"
|
|
60
|
+
]);
|
|
61
|
+
const catchResult = zodCatch.safeParse(void 0);
|
|
62
|
+
const maybeDefaultValue = catchResult.success ? {
|
|
63
|
+
default: catchResult.data
|
|
64
|
+
} : void 0;
|
|
65
|
+
return enhanceWithMetadata(schemaObject, {
|
|
66
|
+
...maybeDefaultValue
|
|
67
|
+
});
|
|
68
|
+
};
|
|
58
69
|
const createDateSchema = (_zodDate, state) => {
|
|
59
70
|
var _a;
|
|
60
71
|
return {
|
|
@@ -564,74 +575,7 @@ const getZodNumberChecks = (zodNumber) => zodNumber._def.checks.reduce((acc, che
|
|
|
564
575
|
}, {});
|
|
565
576
|
const mapNumberType = (zodNumberChecks) => zodNumberChecks.int ? "integer" : "number";
|
|
566
577
|
const createOptionalSchema = (zodOptional, state) => createSchemaObject(zodOptional.unwrap(), state, ["optional"]);
|
|
567
|
-
const
|
|
568
|
-
var _a, _b, _c;
|
|
569
|
-
if (isZodType(zodSchema, "ZodOptional") || isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined") || isZodType(zodSchema, "ZodLiteral") && zodSchema._def.value === void 0) {
|
|
570
|
-
return { optional: true };
|
|
571
|
-
}
|
|
572
|
-
if (isZodType(zodSchema, "ZodDefault")) {
|
|
573
|
-
if (((_a = zodSchema._def.openapi) == null ? void 0 : _a.effectType) === "input") {
|
|
574
|
-
return { optional: true };
|
|
575
|
-
}
|
|
576
|
-
if (((_b = zodSchema._def.openapi) == null ? void 0 : _b.effectType) === "output") {
|
|
577
|
-
return { optional: false };
|
|
578
|
-
}
|
|
579
|
-
return {
|
|
580
|
-
optional: state.type === "input",
|
|
581
|
-
effects: [
|
|
582
|
-
{
|
|
583
|
-
type: "schema",
|
|
584
|
-
creationType: state.type,
|
|
585
|
-
zodType: zodSchema,
|
|
586
|
-
path: [...state.path]
|
|
587
|
-
}
|
|
588
|
-
]
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
if (isZodType(zodSchema, "ZodNullable") || isZodType(zodSchema, "ZodCatch")) {
|
|
592
|
-
return isOptionalSchema(zodSchema._def.innerType, state);
|
|
593
|
-
}
|
|
594
|
-
if (isZodType(zodSchema, "ZodEffects")) {
|
|
595
|
-
return isOptionalSchema(zodSchema._def.schema, state);
|
|
596
|
-
}
|
|
597
|
-
if (isZodType(zodSchema, "ZodUnion") || isZodType(zodSchema, "ZodDiscriminatedUnion")) {
|
|
598
|
-
const results = zodSchema._def.options.map(
|
|
599
|
-
(schema) => isOptionalSchema(schema, state)
|
|
600
|
-
);
|
|
601
|
-
return results.reduce(
|
|
602
|
-
(acc, result) => ({
|
|
603
|
-
optional: acc.optional || result.optional,
|
|
604
|
-
effects: flattenEffects([acc.effects, result.effects])
|
|
605
|
-
}),
|
|
606
|
-
{ optional: false }
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
if (isZodType(zodSchema, "ZodIntersection")) {
|
|
610
|
-
const results = [zodSchema._def.left, zodSchema._def.right].map(
|
|
611
|
-
(schema) => isOptionalSchema(schema, state)
|
|
612
|
-
);
|
|
613
|
-
return results.reduce(
|
|
614
|
-
(acc, result) => ({
|
|
615
|
-
optional: acc.optional || result.optional,
|
|
616
|
-
effects: flattenEffects([acc.effects, result.effects])
|
|
617
|
-
}),
|
|
618
|
-
{ optional: false }
|
|
619
|
-
);
|
|
620
|
-
}
|
|
621
|
-
if (isZodType(zodSchema, "ZodPipeline")) {
|
|
622
|
-
const type = ((_c = zodSchema._def.openapi) == null ? void 0 : _c.effectType) ?? state.type;
|
|
623
|
-
if (type === "input") {
|
|
624
|
-
return isOptionalSchema(zodSchema._def.in, state);
|
|
625
|
-
}
|
|
626
|
-
if (type === "output") {
|
|
627
|
-
return isOptionalSchema(zodSchema._def.out, state);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
if (isZodType(zodSchema, "ZodLazy")) {
|
|
631
|
-
return isOptionalSchema(zodSchema._def.getter(), state);
|
|
632
|
-
}
|
|
633
|
-
return { optional: zodSchema.isOptional() };
|
|
634
|
-
};
|
|
578
|
+
const isOptionalObjectKey = (zodSchema) => isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined") || isZodType(zodSchema, "ZodLiteral") && zodSchema._def.value === void 0;
|
|
635
579
|
const createObjectSchema = (zodObject, state) => {
|
|
636
580
|
var _a;
|
|
637
581
|
const extendedSchema = createExtendedSchema(
|
|
@@ -652,7 +596,7 @@ const createObjectSchema = (zodObject, state) => {
|
|
|
652
596
|
);
|
|
653
597
|
};
|
|
654
598
|
const createExtendedSchema = (zodObject, baseZodObject, state) => {
|
|
655
|
-
var _a;
|
|
599
|
+
var _a, _b;
|
|
656
600
|
if (!baseZodObject) {
|
|
657
601
|
return void 0;
|
|
658
602
|
}
|
|
@@ -692,7 +636,14 @@ const createExtendedSchema = (zodObject, baseZodObject, state) => {
|
|
|
692
636
|
return {
|
|
693
637
|
type: "schema",
|
|
694
638
|
schema: {
|
|
695
|
-
allOf: [
|
|
639
|
+
allOf: [
|
|
640
|
+
{
|
|
641
|
+
$ref: createComponentSchemaRef(
|
|
642
|
+
completeComponent.ref,
|
|
643
|
+
(_b = state.documentOptions) == null ? void 0 : _b.componentRefPath
|
|
644
|
+
)
|
|
645
|
+
}
|
|
646
|
+
],
|
|
696
647
|
...extendedSchema.schema
|
|
697
648
|
},
|
|
698
649
|
effects: flattenEffects([
|
|
@@ -734,7 +685,7 @@ const createShapeDiff = (baseObj, extendedObj) => {
|
|
|
734
685
|
};
|
|
735
686
|
const createObjectSchemaFromShape = (shape, { unknownKeys, catchAll }, state) => {
|
|
736
687
|
const properties = mapProperties(shape, state);
|
|
737
|
-
const required = mapRequired(shape, state);
|
|
688
|
+
const required = mapRequired(properties, shape, state);
|
|
738
689
|
const additionalProperties = !isZodType(catchAll, "ZodNever") ? createSchemaObject(catchAll, state, ["additional properties"]) : void 0;
|
|
739
690
|
return {
|
|
740
691
|
type: "schema",
|
|
@@ -754,17 +705,38 @@ const createObjectSchemaFromShape = (shape, { unknownKeys, catchAll }, state) =>
|
|
|
754
705
|
])
|
|
755
706
|
};
|
|
756
707
|
};
|
|
757
|
-
const mapRequired = (shape, state) => {
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
708
|
+
const mapRequired = (properties, shape, state) => {
|
|
709
|
+
if (!properties) {
|
|
710
|
+
return void 0;
|
|
711
|
+
}
|
|
712
|
+
const { required, effects } = Object.entries(properties.schemas).reduce(
|
|
713
|
+
(acc, [key, schemaOrRef]) => {
|
|
714
|
+
const zodSchema = shape[key];
|
|
715
|
+
if (!zodSchema) {
|
|
716
|
+
throw new Error("Property somehow doesn't exist in shape");
|
|
717
|
+
}
|
|
718
|
+
const result = zodSchema.safeParse(void 0);
|
|
719
|
+
if (!result.success) {
|
|
764
720
|
acc.required.push(key);
|
|
721
|
+
return acc;
|
|
765
722
|
}
|
|
766
|
-
if (
|
|
767
|
-
|
|
723
|
+
if (result.data !== void 0) {
|
|
724
|
+
const baseEffect = {
|
|
725
|
+
zodType: zodSchema,
|
|
726
|
+
path: [...state.path, `property: ${key}`]
|
|
727
|
+
};
|
|
728
|
+
const effect = schemaOrRef.type === "ref" ? {
|
|
729
|
+
...baseEffect,
|
|
730
|
+
type: "component"
|
|
731
|
+
} : {
|
|
732
|
+
...baseEffect,
|
|
733
|
+
type: "schema",
|
|
734
|
+
creationType: state.type
|
|
735
|
+
};
|
|
736
|
+
acc.effects.push(effect);
|
|
737
|
+
if (state.type === "output") {
|
|
738
|
+
acc.required.push(key);
|
|
739
|
+
}
|
|
768
740
|
}
|
|
769
741
|
return acc;
|
|
770
742
|
},
|
|
@@ -773,7 +745,7 @@ const mapRequired = (shape, state) => {
|
|
|
773
745
|
effects: []
|
|
774
746
|
}
|
|
775
747
|
);
|
|
776
|
-
return { required, effects
|
|
748
|
+
return { required, effects };
|
|
777
749
|
};
|
|
778
750
|
const mapProperties = (shape, state) => {
|
|
779
751
|
const shapeEntries = Object.entries(shape);
|
|
@@ -782,17 +754,17 @@ const mapProperties = (shape, state) => {
|
|
|
782
754
|
}
|
|
783
755
|
return shapeEntries.reduce(
|
|
784
756
|
(acc, [key, zodSchema]) => {
|
|
785
|
-
if (
|
|
757
|
+
if (isOptionalObjectKey(zodSchema)) {
|
|
786
758
|
return acc;
|
|
787
759
|
}
|
|
788
|
-
const
|
|
789
|
-
|
|
790
|
-
]
|
|
791
|
-
acc.
|
|
792
|
-
acc.effects.push(property.effects);
|
|
760
|
+
const schema = createSchemaObject(zodSchema, state, [`property: ${key}`]);
|
|
761
|
+
acc.schemas[key] = schema;
|
|
762
|
+
acc.properties[key] = schema.schema;
|
|
763
|
+
acc.effects.push(schema.effects);
|
|
793
764
|
return acc;
|
|
794
765
|
},
|
|
795
766
|
{
|
|
767
|
+
schemas: {},
|
|
796
768
|
properties: {},
|
|
797
769
|
effects: []
|
|
798
770
|
}
|
|
@@ -1133,9 +1105,12 @@ const mapPrefixItems = (items, state) => {
|
|
|
1133
1105
|
};
|
|
1134
1106
|
const createUnionSchema = (zodUnion, state) => {
|
|
1135
1107
|
var _a, _b;
|
|
1136
|
-
const schemas = zodUnion.options.
|
|
1137
|
-
(option
|
|
1138
|
-
|
|
1108
|
+
const schemas = zodUnion.options.reduce((acc, option, index) => {
|
|
1109
|
+
if (!isOptionalObjectKey(option)) {
|
|
1110
|
+
acc.push(createSchemaObject(option, state, [`union option ${index}`]));
|
|
1111
|
+
}
|
|
1112
|
+
return acc;
|
|
1113
|
+
}, []);
|
|
1139
1114
|
if (((_a = zodUnion._def.openapi) == null ? void 0 : _a.unionOneOf) ?? ((_b = state.documentOptions) == null ? void 0 : _b.unionOneOf)) {
|
|
1140
1115
|
return {
|
|
1141
1116
|
type: "schema",
|
|
@@ -1280,6 +1255,7 @@ const createNewSchema = (zodSchema, state) => {
|
|
|
1280
1255
|
return schemaWithMetadata;
|
|
1281
1256
|
};
|
|
1282
1257
|
const createNewRef = (ref, zodSchema, state) => {
|
|
1258
|
+
var _a;
|
|
1283
1259
|
state.components.schemas.set(zodSchema, {
|
|
1284
1260
|
type: "in-progress",
|
|
1285
1261
|
ref
|
|
@@ -1296,7 +1272,12 @@ const createNewRef = (ref, zodSchema, state) => {
|
|
|
1296
1272
|
});
|
|
1297
1273
|
return {
|
|
1298
1274
|
type: "ref",
|
|
1299
|
-
schema: {
|
|
1275
|
+
schema: {
|
|
1276
|
+
$ref: createComponentSchemaRef(
|
|
1277
|
+
ref,
|
|
1278
|
+
(_a = state.documentOptions) == null ? void 0 : _a.componentRefPath
|
|
1279
|
+
)
|
|
1280
|
+
},
|
|
1300
1281
|
effects: newSchema.effects ? [
|
|
1301
1282
|
{
|
|
1302
1283
|
type: "component",
|
|
@@ -1308,10 +1289,16 @@ const createNewRef = (ref, zodSchema, state) => {
|
|
|
1308
1289
|
};
|
|
1309
1290
|
};
|
|
1310
1291
|
const createExistingRef = (zodSchema, component, state) => {
|
|
1292
|
+
var _a, _b;
|
|
1311
1293
|
if (component && component.type === "complete") {
|
|
1312
1294
|
return {
|
|
1313
1295
|
type: "ref",
|
|
1314
|
-
schema: {
|
|
1296
|
+
schema: {
|
|
1297
|
+
$ref: createComponentSchemaRef(
|
|
1298
|
+
component.ref,
|
|
1299
|
+
(_a = state.documentOptions) == null ? void 0 : _a.componentRefPath
|
|
1300
|
+
)
|
|
1301
|
+
},
|
|
1315
1302
|
effects: component.effects ? [
|
|
1316
1303
|
{
|
|
1317
1304
|
type: "component",
|
|
@@ -1325,7 +1312,12 @@ const createExistingRef = (zodSchema, component, state) => {
|
|
|
1325
1312
|
if (component && component.type === "in-progress") {
|
|
1326
1313
|
return {
|
|
1327
1314
|
type: "ref",
|
|
1328
|
-
schema: {
|
|
1315
|
+
schema: {
|
|
1316
|
+
$ref: createComponentSchemaRef(
|
|
1317
|
+
component.ref,
|
|
1318
|
+
(_b = state.documentOptions) == null ? void 0 : _b.componentRefPath
|
|
1319
|
+
)
|
|
1320
|
+
},
|
|
1329
1321
|
effects: [
|
|
1330
1322
|
{
|
|
1331
1323
|
type: "component",
|
|
@@ -1416,7 +1408,7 @@ const createContent = (contentObject, components, type, subpath, documentOptions
|
|
|
1416
1408
|
);
|
|
1417
1409
|
const createComponentParamRef = (ref) => `#/components/parameters/${ref}`;
|
|
1418
1410
|
const createBaseParameter = (schema, components, subpath, documentOptions) => {
|
|
1419
|
-
var _a, _b
|
|
1411
|
+
var _a, _b;
|
|
1420
1412
|
const { ref, ...rest } = ((_a = schema._def.openapi) == null ? void 0 : _a.param) ?? {};
|
|
1421
1413
|
const state = {
|
|
1422
1414
|
components,
|
|
@@ -1426,8 +1418,8 @@ const createBaseParameter = (schema, components, subpath, documentOptions) => {
|
|
|
1426
1418
|
documentOptions
|
|
1427
1419
|
};
|
|
1428
1420
|
const schemaObject = createSchema(schema, state, [...subpath, "schema"]);
|
|
1429
|
-
const required = !
|
|
1430
|
-
const description = ((
|
|
1421
|
+
const required = !schema.isOptional();
|
|
1422
|
+
const description = ((_b = schema._def.openapi) == null ? void 0 : _b.description) ?? schema._def.description;
|
|
1431
1423
|
return {
|
|
1432
1424
|
...description && { description },
|
|
1433
1425
|
...rest,
|
|
@@ -1624,7 +1616,7 @@ const createHeaderOrRef = (schema, components, documentOptions) => {
|
|
|
1624
1616
|
return baseHeader;
|
|
1625
1617
|
};
|
|
1626
1618
|
const createBaseHeader = (schema, components, documentOptions) => {
|
|
1627
|
-
var _a
|
|
1619
|
+
var _a;
|
|
1628
1620
|
const { ref, ...rest } = ((_a = schema._def.openapi) == null ? void 0 : _a.header) ?? {};
|
|
1629
1621
|
const state = {
|
|
1630
1622
|
components,
|
|
@@ -1634,7 +1626,8 @@ const createBaseHeader = (schema, components, documentOptions) => {
|
|
|
1634
1626
|
documentOptions
|
|
1635
1627
|
};
|
|
1636
1628
|
const schemaObject = createSchema(schema, state, ["header"]);
|
|
1637
|
-
const
|
|
1629
|
+
const optionalResult = schema.safeParse(void 0);
|
|
1630
|
+
const required = !optionalResult.success || optionalResult !== void 0;
|
|
1638
1631
|
return {
|
|
1639
1632
|
...rest,
|
|
1640
1633
|
...schema && { schema: schemaObject },
|
|
@@ -1997,7 +1990,7 @@ const getCallbacks = (callbacks, components) => {
|
|
|
1997
1990
|
});
|
|
1998
1991
|
});
|
|
1999
1992
|
};
|
|
2000
|
-
const createComponentSchemaRef = (schemaRef) =>
|
|
1993
|
+
const createComponentSchemaRef = (schemaRef, componentPath) => `${componentPath ?? "#/components/schemas/"}${schemaRef}`;
|
|
2001
1994
|
const createComponentResponseRef = (responseRef) => `#/components/responses/${responseRef}`;
|
|
2002
1995
|
const createComponentRequestBodyRef = (requestBodyRef) => `#/components/requestBodies/${requestBodyRef}`;
|
|
2003
1996
|
const createComponentCallbackRef = (callbackRef) => `#/components/callbacks/${callbackRef}`;
|
|
@@ -22,6 +22,10 @@ interface CreateSchemaOptions extends CreateDocumentOptions {
|
|
|
22
22
|
* Additional components to use and create while rendering the schema
|
|
23
23
|
*/
|
|
24
24
|
components?: Record<string, ZodType>;
|
|
25
|
+
/**
|
|
26
|
+
* The $ref path to use for the component. Defaults to `#/components/schemas/`
|
|
27
|
+
*/
|
|
28
|
+
componentRefPath?: string;
|
|
25
29
|
}
|
|
26
30
|
declare const createSchema: (zodType: ZodType, opts?: CreateSchemaOptions) => SchemaResult;
|
|
27
31
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod-openapi",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Convert Zod Schemas to OpenAPI v3.x documentation",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -74,12 +74,12 @@
|
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@arethetypeswrong/cli": "0.16.4",
|
|
76
76
|
"@crackle/cli": "0.15.5",
|
|
77
|
-
"@redocly/cli": "1.25.
|
|
77
|
+
"@redocly/cli": "1.25.9",
|
|
78
78
|
"@types/node": "^20.3.0",
|
|
79
79
|
"eslint-plugin-zod-openapi": "^1.0.0-beta.0",
|
|
80
80
|
"openapi3-ts": "4.4.0",
|
|
81
|
-
"skuba": "9.0
|
|
82
|
-
"yaml": "2.
|
|
81
|
+
"skuba": "9.1.0",
|
|
82
|
+
"yaml": "2.6.0",
|
|
83
83
|
"zod": "3.23.8"
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|