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 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) => createSchemaObject(zodCatch._def.innerType, state, ["catch"]);
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 isOptionalSchema = (zodSchema, state) => {
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: [{ $ref: createComponentSchemaRef(completeComponent.ref) }],
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
- const { required, effects: allEffects } = Object.entries(shape).reduce(
760
- (acc, [key, zodSchema]) => {
761
- state.path.push(`property: ${key}`);
762
- const { optional, effects } = isOptionalSchema(zodSchema, state);
763
- state.path.pop();
764
- if (!optional) {
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 (effects) {
768
- acc.effects.push(effects);
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: flattenEffects(allEffects) };
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 (isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined")) {
758
+ if (isOptionalObjectKey(zodSchema)) {
787
759
  return acc;
788
760
  }
789
- const property = createSchemaObject(zodSchema, state, [
790
- `property: ${key}`
791
- ]);
792
- acc.properties[key] = property.schema;
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.map(
1138
- (option, index) => createSchemaObject(option, state, [`union option ${index}`])
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: { $ref: createComponentSchemaRef(ref) },
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: { $ref: createComponentSchemaRef(component.ref) },
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: { $ref: createComponentSchemaRef(component.ref) },
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, _c;
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 = !((_b = isOptionalSchema(schema, state)) == null ? void 0 : _b.optional);
1431
- const description = ((_c = schema._def.openapi) == null ? void 0 : _c.description) ?? schema._def.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, _b;
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 required = !((_b = isOptionalSchema(schema, state)) == null ? void 0 : _b.optional);
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) => `#/components/schemas/${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) => createSchemaObject(zodCatch._def.innerType, state, ["catch"]);
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 isOptionalSchema = (zodSchema, state) => {
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: [{ $ref: createComponentSchemaRef(completeComponent.ref) }],
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
- const { required, effects: allEffects } = Object.entries(shape).reduce(
759
- (acc, [key, zodSchema]) => {
760
- state.path.push(`property: ${key}`);
761
- const { optional, effects } = isOptionalSchema(zodSchema, state);
762
- state.path.pop();
763
- if (!optional) {
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 (effects) {
767
- acc.effects.push(effects);
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: flattenEffects(allEffects) };
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 (isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined")) {
757
+ if (isOptionalObjectKey(zodSchema)) {
786
758
  return acc;
787
759
  }
788
- const property = createSchemaObject(zodSchema, state, [
789
- `property: ${key}`
790
- ]);
791
- acc.properties[key] = property.schema;
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.map(
1137
- (option, index) => createSchemaObject(option, state, [`union option ${index}`])
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: { $ref: createComponentSchemaRef(ref) },
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: { $ref: createComponentSchemaRef(component.ref) },
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: { $ref: createComponentSchemaRef(component.ref) },
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, _c;
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 = !((_b = isOptionalSchema(schema, state)) == null ? void 0 : _b.optional);
1430
- const description = ((_c = schema._def.openapi) == null ? void 0 : _c.description) ?? schema._def.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, _b;
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 required = !((_b = isOptionalSchema(schema, state)) == null ? void 0 : _b.optional);
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) => `#/components/schemas/${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.1.1",
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.5",
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.1",
82
- "yaml": "2.5.1",
81
+ "skuba": "9.1.0",
82
+ "yaml": "2.6.0",
83
83
  "zod": "3.23.8"
84
84
  },
85
85
  "peerDependencies": {