zod-openapi 2.10.0 → 2.12.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
@@ -182,7 +182,7 @@ Query, Path, Header & Cookie parameters can be created using the `requestParams`
182
182
  ```typescript
183
183
  createDocument({
184
184
  paths: {
185
- '/jobs/:a': {
185
+ '/jobs/{a}': {
186
186
  put: {
187
187
  requestParams: {
188
188
  path: z.object({ a: z.string() }),
@@ -201,7 +201,7 @@ If you would like to declare parameters in a more traditional way you may also d
201
201
  ```ts
202
202
  createDocument({
203
203
  paths: {
204
- '/jobs/:a': {
204
+ '/jobs/{a}': {
205
205
  put: {
206
206
  parameters: [
207
207
  z.string().openapi({
@@ -521,6 +521,7 @@ For example in `z.string().nullable()` will be rendered differently
521
521
  - ZodLiteral
522
522
  - ZodNativeEnum
523
523
  - supporting `string`, `number` and combined enums.
524
+ - ZodNever
524
525
  - ZodNull
525
526
  - ZodNullable
526
527
  - ZodNumber
@@ -543,6 +544,7 @@ For example in `z.string().nullable()` will be rendered differently
543
544
  - ZodTuple
544
545
  - `items` mapping for `.rest()`
545
546
  - `prefixItems` mapping for OpenAPI 3.1.0+
547
+ - ZodUndefined
546
548
  - ZodUnion
547
549
  - By default it outputs an `allOf` schema. Use `unionOneOf` to change this to output `oneOf` instead.
548
550
  - ZodUnknown
@@ -34,9 +34,20 @@ var isAnyZodType = (zodType) => Boolean(
34
34
  zodType?._def?.typeName
35
35
  );
36
36
 
37
+ // src/openapi.ts
38
+ var openApiVersions = [
39
+ "3.0.0",
40
+ "3.0.1",
41
+ "3.0.2",
42
+ "3.0.3",
43
+ "3.1.0"
44
+ ];
45
+ var satisfiesVersion = (test, against) => openApiVersions.indexOf(test) >= openApiVersions.indexOf(against);
46
+ var isReferenceObject = (schemaOrRef) => Boolean("$ref" in schemaOrRef && schemaOrRef.$ref);
47
+
37
48
  // src/create/schema/metadata.ts
38
49
  var enhanceWithMetadata = (schemaObject, metadata) => {
39
- if ("$ref" in schemaObject) {
50
+ if (isReferenceObject(schemaObject)) {
40
51
  if (Object.values(metadata).every((val) => val === void 0)) {
41
52
  return schemaObject;
42
53
  }
@@ -171,17 +182,11 @@ var createLiteralSchema = (zodLiteral) => ({
171
182
  // src/create/schema/parsers/manual.ts
172
183
  var createManualTypeSchema = (zodSchema, state) => {
173
184
  if (!zodSchema._def.openapi?.type) {
174
- const zodType = zodSchema.constructor.name;
175
- if (isZodType(zodSchema, "ZodEffects")) {
176
- const schemaName = `${zodType} - ${zodSchema._def.effect.type}`;
177
- throw new Error(
178
- `Unknown schema ${schemaName} at ${state.path.join(
179
- " > "
180
- )}. Please assign it a manual 'type', wrap it in a ZodPipeline or change the 'effectType'.`
181
- );
182
- }
185
+ const schemaName = zodSchema.constructor.name;
183
186
  throw new Error(
184
- `Unknown schema ${zodType}. Please assign it a manual 'type'.`
187
+ `Unknown schema ${schemaName} at ${state.path.join(
188
+ " > "
189
+ )}. Please assign it a manual 'type'.`
185
190
  );
186
191
  }
187
192
  return {
@@ -189,16 +194,6 @@ var createManualTypeSchema = (zodSchema, state) => {
189
194
  };
190
195
  };
191
196
 
192
- // src/openapi.ts
193
- var openApiVersions = [
194
- "3.0.0",
195
- "3.0.1",
196
- "3.0.2",
197
- "3.0.3",
198
- "3.1.0"
199
- ];
200
- var satisfiesVersion = (test, against) => openApiVersions.indexOf(test) >= openApiVersions.indexOf(against);
201
-
202
197
  // src/create/schema/parsers/nativeEnum.ts
203
198
  var createNativeEnumSchema = (zodEnum, state) => {
204
199
  const enumValues = getValidEnumValues(zodEnum._def.values);
@@ -248,34 +243,41 @@ var createNullableSchema = (zodNullable, state) => {
248
243
  const schemaObject = createSchemaObject(zodNullable.unwrap(), state, [
249
244
  "nullable"
250
245
  ]);
251
- if ("$ref" in schemaObject || schemaObject.allOf) {
252
- return {
253
- oneOf: mapNullOf([schemaObject], state.components.openapi)
254
- };
255
- }
256
- if (schemaObject.oneOf) {
257
- const { oneOf, ...schema2 } = schemaObject;
246
+ if (satisfiesVersion(state.components.openapi, "3.1.0")) {
247
+ if (isReferenceObject(schemaObject) || schemaObject.allOf) {
248
+ return {
249
+ oneOf: mapNullOf([schemaObject], state.components.openapi)
250
+ };
251
+ }
252
+ if (schemaObject.oneOf) {
253
+ const { oneOf, ...schema3 } = schemaObject;
254
+ return {
255
+ oneOf: mapNullOf(oneOf, state.components.openapi),
256
+ ...schema3
257
+ };
258
+ }
259
+ if (schemaObject.anyOf) {
260
+ const { anyOf, ...schema3 } = schemaObject;
261
+ return {
262
+ anyOf: mapNullOf(anyOf, state.components.openapi),
263
+ ...schema3
264
+ };
265
+ }
266
+ const { type: type2, ...schema2 } = schemaObject;
258
267
  return {
259
- oneOf: mapNullOf(oneOf, state.components.openapi),
268
+ type: mapNullType(type2),
260
269
  ...schema2
261
270
  };
262
271
  }
263
- if (schemaObject.anyOf) {
264
- const { anyOf, ...schema2 } = schemaObject;
272
+ if (isReferenceObject(schemaObject)) {
265
273
  return {
266
- anyOf: mapNullOf(anyOf, state.components.openapi),
267
- ...schema2
274
+ allOf: [schemaObject],
275
+ nullable: true
268
276
  };
269
277
  }
270
278
  const { type, ...schema } = schemaObject;
271
- if (satisfiesVersion(state.components.openapi, "3.1.0")) {
272
- return {
273
- type: mapNullType(type),
274
- ...schema
275
- };
276
- }
277
279
  return {
278
- type,
280
+ ...type && { type },
279
281
  nullable: true,
280
282
  ...schema,
281
283
  // https://github.com/OAI/OpenAPI-Specification/blob/main/proposals/2019-10-31-Clarify-Nullable.md#if-a-schema-specifies-nullable-true-and-enum-1-2-3-does-that-schema-allow-null-values-see-1900
@@ -349,7 +351,7 @@ var createOptionalSchema = (zodOptional, state) => (
349
351
  createSchemaObject(zodOptional.unwrap(), state, ["optional"])
350
352
  );
351
353
  var isOptionalSchema = (zodSchema, state) => {
352
- if (isZodType(zodSchema, "ZodOptional")) {
354
+ if (isZodType(zodSchema, "ZodOptional") || isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined")) {
353
355
  return true;
354
356
  }
355
357
  if (isZodType(zodSchema, "ZodDefault")) {
@@ -489,6 +491,9 @@ var mapRequired = (shape, state) => {
489
491
  };
490
492
  var mapProperties = (shape, state) => Object.entries(shape).reduce(
491
493
  (acc, [key, zodSchema]) => {
494
+ if (isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined")) {
495
+ return acc;
496
+ }
492
497
  acc[key] = createSchemaObject(zodSchema, state, [`property: ${key}`]);
493
498
  return acc;
494
499
  },
@@ -546,7 +551,6 @@ var createRecordSchema = (zodRecord, state) => {
546
551
  if (satisfiesVersion(state.components.openapi, "3.1.0") && "type" in renderedKeySchema && renderedKeySchema.type === "string" && Object.keys(renderedKeySchema).length > 1) {
547
552
  return {
548
553
  type: "object",
549
- // @ts-expect-error FIXME: https://github.com/metadevpro/openapi3-ts/pull/120
550
554
  propertyNames: keySchema,
551
555
  additionalProperties
552
556
  };
@@ -674,7 +678,7 @@ var mapStringFormat = (zodStringChecks) => {
674
678
  // src/create/schema/parsers/transform.ts
675
679
  var createTransformSchema = (zodTransform, state) => {
676
680
  if (zodTransform._def.openapi?.effectType === "output") {
677
- return createManualTypeSchema(zodTransform, state);
681
+ return createManualOutputTransformSchema(zodTransform, state);
678
682
  }
679
683
  if (zodTransform._def.openapi?.effectType === "input") {
680
684
  return createSchemaObject(zodTransform._def.schema, state, [
@@ -682,13 +686,27 @@ var createTransformSchema = (zodTransform, state) => {
682
686
  ]);
683
687
  }
684
688
  if (state.type === "output") {
685
- return createManualTypeSchema(zodTransform, state);
689
+ return createManualOutputTransformSchema(zodTransform, state);
686
690
  }
687
691
  state.effectType = "input";
688
692
  return createSchemaObject(zodTransform._def.schema, state, [
689
693
  "transform input"
690
694
  ]);
691
695
  };
696
+ var createManualOutputTransformSchema = (zodTransform, state) => {
697
+ if (!zodTransform._def.openapi?.type) {
698
+ const zodType = zodTransform.constructor.name;
699
+ const schemaName = `${zodType} - ${zodTransform._def.effect.type}`;
700
+ throw new Error(
701
+ `Failed to determine a type for ${schemaName} at ${state.path.join(
702
+ " > "
703
+ )}. Please change the 'effectType' to 'input', wrap it in a ZodPipeline or assign it a manual 'type'.`
704
+ );
705
+ }
706
+ return {
707
+ type: zodTransform._def.openapi.type
708
+ };
709
+ };
692
710
  var throwTransformError = (zodType, state) => {
693
711
  throw new Error(
694
712
  `${JSON.stringify(zodType)} at ${state.path.join(
@@ -980,7 +998,9 @@ var createBaseParameter = (schema, components, subpath) => {
980
998
  "schema"
981
999
  ]);
982
1000
  const required = !isOptionalSchema(schema, state);
1001
+ const description = schema._def.openapi?.description ?? schema._def.description;
983
1002
  return {
1003
+ ...description && { description },
984
1004
  ...rest,
985
1005
  ...schema && { schema: schemaObject },
986
1006
  ...required && { required }
package/lib-esm/index.js CHANGED
@@ -10,9 +10,20 @@ var isAnyZodType = (zodType) => Boolean(
10
10
  zodType?._def?.typeName
11
11
  );
12
12
 
13
+ // src/openapi.ts
14
+ var openApiVersions = [
15
+ "3.0.0",
16
+ "3.0.1",
17
+ "3.0.2",
18
+ "3.0.3",
19
+ "3.1.0"
20
+ ];
21
+ var satisfiesVersion = (test, against) => openApiVersions.indexOf(test) >= openApiVersions.indexOf(against);
22
+ var isReferenceObject = (schemaOrRef) => Boolean("$ref" in schemaOrRef && schemaOrRef.$ref);
23
+
13
24
  // src/create/schema/metadata.ts
14
25
  var enhanceWithMetadata = (schemaObject, metadata) => {
15
- if ("$ref" in schemaObject) {
26
+ if (isReferenceObject(schemaObject)) {
16
27
  if (Object.values(metadata).every((val) => val === void 0)) {
17
28
  return schemaObject;
18
29
  }
@@ -147,17 +158,11 @@ var createLiteralSchema = (zodLiteral) => ({
147
158
  // src/create/schema/parsers/manual.ts
148
159
  var createManualTypeSchema = (zodSchema, state) => {
149
160
  if (!zodSchema._def.openapi?.type) {
150
- const zodType = zodSchema.constructor.name;
151
- if (isZodType(zodSchema, "ZodEffects")) {
152
- const schemaName = `${zodType} - ${zodSchema._def.effect.type}`;
153
- throw new Error(
154
- `Unknown schema ${schemaName} at ${state.path.join(
155
- " > "
156
- )}. Please assign it a manual 'type', wrap it in a ZodPipeline or change the 'effectType'.`
157
- );
158
- }
161
+ const schemaName = zodSchema.constructor.name;
159
162
  throw new Error(
160
- `Unknown schema ${zodType}. Please assign it a manual 'type'.`
163
+ `Unknown schema ${schemaName} at ${state.path.join(
164
+ " > "
165
+ )}. Please assign it a manual 'type'.`
161
166
  );
162
167
  }
163
168
  return {
@@ -165,16 +170,6 @@ var createManualTypeSchema = (zodSchema, state) => {
165
170
  };
166
171
  };
167
172
 
168
- // src/openapi.ts
169
- var openApiVersions = [
170
- "3.0.0",
171
- "3.0.1",
172
- "3.0.2",
173
- "3.0.3",
174
- "3.1.0"
175
- ];
176
- var satisfiesVersion = (test, against) => openApiVersions.indexOf(test) >= openApiVersions.indexOf(against);
177
-
178
173
  // src/create/schema/parsers/nativeEnum.ts
179
174
  var createNativeEnumSchema = (zodEnum, state) => {
180
175
  const enumValues = getValidEnumValues(zodEnum._def.values);
@@ -224,34 +219,41 @@ var createNullableSchema = (zodNullable, state) => {
224
219
  const schemaObject = createSchemaObject(zodNullable.unwrap(), state, [
225
220
  "nullable"
226
221
  ]);
227
- if ("$ref" in schemaObject || schemaObject.allOf) {
228
- return {
229
- oneOf: mapNullOf([schemaObject], state.components.openapi)
230
- };
231
- }
232
- if (schemaObject.oneOf) {
233
- const { oneOf, ...schema2 } = schemaObject;
222
+ if (satisfiesVersion(state.components.openapi, "3.1.0")) {
223
+ if (isReferenceObject(schemaObject) || schemaObject.allOf) {
224
+ return {
225
+ oneOf: mapNullOf([schemaObject], state.components.openapi)
226
+ };
227
+ }
228
+ if (schemaObject.oneOf) {
229
+ const { oneOf, ...schema3 } = schemaObject;
230
+ return {
231
+ oneOf: mapNullOf(oneOf, state.components.openapi),
232
+ ...schema3
233
+ };
234
+ }
235
+ if (schemaObject.anyOf) {
236
+ const { anyOf, ...schema3 } = schemaObject;
237
+ return {
238
+ anyOf: mapNullOf(anyOf, state.components.openapi),
239
+ ...schema3
240
+ };
241
+ }
242
+ const { type: type2, ...schema2 } = schemaObject;
234
243
  return {
235
- oneOf: mapNullOf(oneOf, state.components.openapi),
244
+ type: mapNullType(type2),
236
245
  ...schema2
237
246
  };
238
247
  }
239
- if (schemaObject.anyOf) {
240
- const { anyOf, ...schema2 } = schemaObject;
248
+ if (isReferenceObject(schemaObject)) {
241
249
  return {
242
- anyOf: mapNullOf(anyOf, state.components.openapi),
243
- ...schema2
250
+ allOf: [schemaObject],
251
+ nullable: true
244
252
  };
245
253
  }
246
254
  const { type, ...schema } = schemaObject;
247
- if (satisfiesVersion(state.components.openapi, "3.1.0")) {
248
- return {
249
- type: mapNullType(type),
250
- ...schema
251
- };
252
- }
253
255
  return {
254
- type,
256
+ ...type && { type },
255
257
  nullable: true,
256
258
  ...schema,
257
259
  // https://github.com/OAI/OpenAPI-Specification/blob/main/proposals/2019-10-31-Clarify-Nullable.md#if-a-schema-specifies-nullable-true-and-enum-1-2-3-does-that-schema-allow-null-values-see-1900
@@ -325,7 +327,7 @@ var createOptionalSchema = (zodOptional, state) => (
325
327
  createSchemaObject(zodOptional.unwrap(), state, ["optional"])
326
328
  );
327
329
  var isOptionalSchema = (zodSchema, state) => {
328
- if (isZodType(zodSchema, "ZodOptional")) {
330
+ if (isZodType(zodSchema, "ZodOptional") || isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined")) {
329
331
  return true;
330
332
  }
331
333
  if (isZodType(zodSchema, "ZodDefault")) {
@@ -465,6 +467,9 @@ var mapRequired = (shape, state) => {
465
467
  };
466
468
  var mapProperties = (shape, state) => Object.entries(shape).reduce(
467
469
  (acc, [key, zodSchema]) => {
470
+ if (isZodType(zodSchema, "ZodNever") || isZodType(zodSchema, "ZodUndefined")) {
471
+ return acc;
472
+ }
468
473
  acc[key] = createSchemaObject(zodSchema, state, [`property: ${key}`]);
469
474
  return acc;
470
475
  },
@@ -522,7 +527,6 @@ var createRecordSchema = (zodRecord, state) => {
522
527
  if (satisfiesVersion(state.components.openapi, "3.1.0") && "type" in renderedKeySchema && renderedKeySchema.type === "string" && Object.keys(renderedKeySchema).length > 1) {
523
528
  return {
524
529
  type: "object",
525
- // @ts-expect-error FIXME: https://github.com/metadevpro/openapi3-ts/pull/120
526
530
  propertyNames: keySchema,
527
531
  additionalProperties
528
532
  };
@@ -650,7 +654,7 @@ var mapStringFormat = (zodStringChecks) => {
650
654
  // src/create/schema/parsers/transform.ts
651
655
  var createTransformSchema = (zodTransform, state) => {
652
656
  if (zodTransform._def.openapi?.effectType === "output") {
653
- return createManualTypeSchema(zodTransform, state);
657
+ return createManualOutputTransformSchema(zodTransform, state);
654
658
  }
655
659
  if (zodTransform._def.openapi?.effectType === "input") {
656
660
  return createSchemaObject(zodTransform._def.schema, state, [
@@ -658,13 +662,27 @@ var createTransformSchema = (zodTransform, state) => {
658
662
  ]);
659
663
  }
660
664
  if (state.type === "output") {
661
- return createManualTypeSchema(zodTransform, state);
665
+ return createManualOutputTransformSchema(zodTransform, state);
662
666
  }
663
667
  state.effectType = "input";
664
668
  return createSchemaObject(zodTransform._def.schema, state, [
665
669
  "transform input"
666
670
  ]);
667
671
  };
672
+ var createManualOutputTransformSchema = (zodTransform, state) => {
673
+ if (!zodTransform._def.openapi?.type) {
674
+ const zodType = zodTransform.constructor.name;
675
+ const schemaName = `${zodType} - ${zodTransform._def.effect.type}`;
676
+ throw new Error(
677
+ `Failed to determine a type for ${schemaName} at ${state.path.join(
678
+ " > "
679
+ )}. Please change the 'effectType' to 'input', wrap it in a ZodPipeline or assign it a manual 'type'.`
680
+ );
681
+ }
682
+ return {
683
+ type: zodTransform._def.openapi.type
684
+ };
685
+ };
668
686
  var throwTransformError = (zodType, state) => {
669
687
  throw new Error(
670
688
  `${JSON.stringify(zodType)} at ${state.path.join(
@@ -956,7 +974,9 @@ var createBaseParameter = (schema, components, subpath) => {
956
974
  "schema"
957
975
  ]);
958
976
  const required = !isOptionalSchema(schema, state);
977
+ const description = schema._def.openapi?.description ?? schema._def.description;
959
978
  return {
979
+ ...description && { description },
960
980
  ...rest,
961
981
  ...schema && { schema: schemaObject },
962
982
  ...required && { required }
@@ -1,4 +1,4 @@
1
1
  import type { ZodNullable, ZodTypeAny } from 'zod';
2
2
  import type { oas31 } from '../../../openapi3-ts/dist';
3
3
  import { type SchemaState } from '../../schema';
4
- export declare const createNullableSchema: <T extends ZodTypeAny>(zodNullable: ZodNullable<T>, state: SchemaState) => oas31.SchemaObject;
4
+ export declare const createNullableSchema: <T extends ZodTypeAny>(zodNullable: ZodNullable<T>, state: SchemaState) => oas31.SchemaObject | oas31.ReferenceObject;
@@ -2,4 +2,5 @@ import type { ZodEffects, ZodType, ZodTypeAny, input, output } from 'zod';
2
2
  import type { oas31 } from '../../../openapi3-ts/dist';
3
3
  import { type SchemaState } from '../../schema';
4
4
  export declare const createTransformSchema: <T extends ZodTypeAny, Output = output<T>, Input = input<T>>(zodTransform: ZodEffects<T, Output, Input>, state: SchemaState) => oas31.SchemaObject | oas31.ReferenceObject;
5
+ export declare const createManualOutputTransformSchema: <T extends ZodTypeAny, Output = output<T>, Input = input<T>>(zodTransform: ZodEffects<T, Output, Input>, state: SchemaState) => oas31.SchemaObject;
5
6
  export declare const throwTransformError: (zodType: ZodType, state: SchemaState) => never;
@@ -1,3 +1,5 @@
1
+ import type { oas31 } from './openapi3-ts/dist';
1
2
  export declare const openApiVersions: readonly ["3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.1.0"];
2
3
  export type OpenApiVersion = (typeof openApiVersions)[number];
3
4
  export declare const satisfiesVersion: (test: OpenApiVersion, against: OpenApiVersion) => boolean;
5
+ export declare const isReferenceObject: (schemaOrRef: oas31.SchemaObject | oas31.ReferenceObject) => schemaOrRef is oas31.ReferenceObject;
@@ -28,6 +28,7 @@ export interface ContactObject extends ISpecificationExtension {
28
28
  }
29
29
  export interface LicenseObject extends ISpecificationExtension {
30
30
  name: string;
31
+ identifier?: string;
31
32
  url?: string;
32
33
  }
33
34
  export interface ComponentsObject extends ISpecificationExtension {
@@ -225,6 +226,7 @@ export interface SchemaObject extends ISpecificationExtension {
225
226
  [propertyName: string]: SchemaObject | ReferenceObject;
226
227
  };
227
228
  additionalProperties?: SchemaObject | ReferenceObject | boolean;
229
+ propertyNames?: SchemaObject | ReferenceObject;
228
230
  description?: string;
229
231
  default?: any;
230
232
  title?: string;
@@ -244,6 +246,8 @@ export interface SchemaObject extends ISpecificationExtension {
244
246
  required?: string[];
245
247
  enum?: any[];
246
248
  prefixItems?: (SchemaObject | ReferenceObject)[];
249
+ contentMediaType?: string;
250
+ contentEncoding?: string;
247
251
  }
248
252
  export declare function isSchemaObject(schema: SchemaObject | ReferenceObject): schema is SchemaObject;
249
253
  export interface SchemasObject {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-openapi",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "Convert Zod Schemas to OpenAPI v3.x documentation",
5
5
  "keywords": [
6
6
  "typescript",
@@ -43,12 +43,12 @@
43
43
  },
44
44
  "dependencies": {},
45
45
  "devDependencies": {
46
- "@redocly/cli": "1.4.0",
46
+ "@redocly/cli": "1.6.0",
47
47
  "@types/node": "^20.3.0",
48
48
  "eslint-plugin-zod-openapi": "^0.1.0",
49
- "openapi3-ts": "4.1.2",
50
- "skuba": "7.2.0",
51
- "yaml": "2.3.3",
49
+ "openapi3-ts": "4.2.1",
50
+ "skuba": "7.3.1",
51
+ "yaml": "2.3.4",
52
52
  "zod": "3.22.4"
53
53
  },
54
54
  "peerDependencies": {