zod-openapi 2.15.2 → 2.17.0-beta.1

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
@@ -29,12 +29,25 @@ pnpm install zod zod-openapi
29
29
 
30
30
  ## Usage
31
31
 
32
- ### `extendZodWithOpenApi`
32
+ ### Extend Zod
33
33
 
34
34
  This mutates Zod to add an extra `.openapi()` method. Call this at the top of your entry point(s).
35
35
 
36
- ```typescript
36
+ #### Automatic
37
+
38
+ ```ts
39
+ import 'zod-openapi/extend';
37
40
  import { z } from 'zod';
41
+
42
+ z.string().openapi({ description: 'hello world!', example: 'hello world' });
43
+ ```
44
+
45
+ #### Manual
46
+
47
+ This is useful if you have a different instance of Zod that you would like to extend.
48
+
49
+ ```typescript
50
+ import { z } from 'another-lib';
38
51
  import { extendZodWithOpenApi } from 'zod-openapi';
39
52
 
40
53
  extendZodWithOpenApi(z);
@@ -65,11 +78,10 @@ Creates an OpenAPI documentation object
65
78
  import { z } from 'zod';
66
79
  import { createDocument, extendZodWithOpenApi } from 'zod-openapi';
67
80
 
68
- extendZodWithOpenApi(z);
69
-
70
81
  const jobId = z.string().openapi({
71
- description: 'Job ID',
82
+ description: 'A unique identifier for a job',
72
83
  example: '12345',
84
+ ref: 'jobId',
73
85
  });
74
86
 
75
87
  const title = z.string().openapi({
@@ -122,10 +134,9 @@ Generates the following object:
122
134
  {
123
135
  "in": "path",
124
136
  "name": "jobId",
137
+ "description": "A unique identifier for a job",
125
138
  "schema": {
126
- "type": "string",
127
- "description": "Job ID",
128
- "example": "12345"
139
+ "$ref": "#/components/schemas/jobId"
129
140
  }
130
141
  }
131
142
  ],
@@ -155,9 +166,7 @@ Generates the following object:
155
166
  "type": "object",
156
167
  "properties": {
157
168
  "jobId": {
158
- "type": "string",
159
- "description": "Job ID",
160
- "example": "12345"
169
+ "$ref": "#/components/schemas/jobId"
161
170
  },
162
171
  "title": {
163
172
  "type": "string",
@@ -173,6 +182,15 @@ Generates the following object:
173
182
  }
174
183
  }
175
184
  }
185
+ },
186
+ "components": {
187
+ "schemas": {
188
+ "jobId": {
189
+ "type": "string",
190
+ "description": "A unique identifier for a job",
191
+ "example": "12345"
192
+ }
193
+ }
176
194
  }
177
195
  }
178
196
  ```
@@ -512,7 +530,7 @@ For example in `z.string().nullable()` will be rendered differently
512
530
  - `string` `type` mapping by default
513
531
  - ZodDefault
514
532
  - ZodDiscriminatedUnion
515
- - `discriminator` mapping when all schemas in the union contain a `ref`.
533
+ - `discriminator` mapping when all schemas in the union are [registered](#creating-components). The discriminator must be a `ZodLiteral`, `ZodEnum` or `ZodNativeEnum` with string values. Only values wrapped in `ZodBranded`, `ZodReadOnly` and `ZodCatch` are supported.
516
534
  - ZodEffects
517
535
  - `transform` support for request schemas. See [Zod Effects](#zod-effects) for how to enable response schema support
518
536
  - `pre-process` support. We assume that the input type is the same as the output type. Otherwise pipe and transform can be used instead.
@@ -541,9 +559,10 @@ For example in `z.string().nullable()` will be rendered differently
541
559
  - ZodSet
542
560
  - Treated as an array with `uniqueItems` (you may need to add a pre-process)
543
561
  - ZodString
544
- - `format` mapping for `.url()`, `.uuid()`, `.email()`, `.datetime()`
562
+ - `format` mapping for `.url()`, `.uuid()`, `.email()`, `.datetime()`, `.date()`, `.time()`, `.duration()`
545
563
  - `minLength`/`maxLength` mapping for `.length()`, `.min()`, `.max()`
546
564
  - `pattern` mapping for `.regex()`, `.startsWith()`, `.endsWith()`, `.includes()`
565
+ - `contentEncoding` mapping for `.base64()` for OpenAPI 3.1.0+
547
566
  - ZodTuple
548
567
  - `items` mapping for `.rest()`
549
568
  - `prefixItems` mapping for OpenAPI 3.1.0+
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/extend.ts
17
+ var extend_exports = {};
18
+ module.exports = __toCommonJS(extend_exports);
19
+ var import_zod = require("zod");
20
+
21
+ // src/extendZod.ts
22
+ function extendZodWithOpenApi(zod) {
23
+ if (typeof zod.ZodType.prototype.openapi !== "undefined") {
24
+ return;
25
+ }
26
+ zod.ZodType.prototype.openapi = function(openapi) {
27
+ const result = new this.constructor({
28
+ ...this._def,
29
+ openapi
30
+ });
31
+ return result;
32
+ };
33
+ const zodObjectExtend = zod.ZodObject.prototype.extend;
34
+ zod.ZodObject.prototype.extend = function(...args) {
35
+ const extendResult = zodObjectExtend.apply(this, args);
36
+ extendResult._def.extendMetadata = {
37
+ extends: this
38
+ };
39
+ delete extendResult._def.openapi;
40
+ return extendResult;
41
+ };
42
+ const zodObjectOmit = zod.ZodObject.prototype.omit;
43
+ zod.ZodObject.prototype.omit = function(...args) {
44
+ const omitResult = zodObjectOmit.apply(this, args);
45
+ delete omitResult._def.extendMetadata;
46
+ delete omitResult._def.openapi;
47
+ return omitResult;
48
+ };
49
+ const zodObjectPick = zod.ZodObject.prototype.pick;
50
+ zod.ZodObject.prototype.pick = function(...args) {
51
+ const pickResult = zodObjectPick.apply(this, args);
52
+ delete pickResult._def.extendMetadata;
53
+ delete pickResult._def.openapi;
54
+ return pickResult;
55
+ };
56
+ }
57
+
58
+ // src/extend.ts
59
+ extendZodWithOpenApi(import_zod.z);
@@ -108,6 +108,67 @@ var createDefaultSchema = (zodDefault, state) => {
108
108
  });
109
109
  };
110
110
 
111
+ // src/openapi.ts
112
+ var openApiVersions = [
113
+ "3.0.0",
114
+ "3.0.1",
115
+ "3.0.2",
116
+ "3.0.3",
117
+ "3.1.0"
118
+ ];
119
+ var satisfiesVersion = (test, against) => openApiVersions.indexOf(test) >= openApiVersions.indexOf(against);
120
+
121
+ // src/create/schema/parsers/nativeEnum.ts
122
+ var createNativeEnumSchema = (zodEnum, state) => {
123
+ const enumValues = getValidEnumValues(zodEnum._def.values);
124
+ const { numbers, strings } = sortStringsAndNumbers(enumValues);
125
+ if (strings.length && numbers.length) {
126
+ if (satisfiesVersion(state.components.openapi, "3.1.0"))
127
+ return {
128
+ type: "schema",
129
+ schema: {
130
+ type: ["string", "number"],
131
+ enum: [...strings, ...numbers]
132
+ }
133
+ };
134
+ return {
135
+ type: "schema",
136
+ schema: {
137
+ oneOf: [
138
+ { type: "string", enum: strings },
139
+ { type: "number", enum: numbers }
140
+ ]
141
+ }
142
+ };
143
+ }
144
+ if (strings.length) {
145
+ return {
146
+ type: "schema",
147
+ schema: {
148
+ type: "string",
149
+ enum: strings
150
+ }
151
+ };
152
+ }
153
+ return {
154
+ type: "schema",
155
+ schema: {
156
+ type: "number",
157
+ enum: numbers
158
+ }
159
+ };
160
+ };
161
+ var getValidEnumValues = (enumValues) => {
162
+ const keys = Object.keys(enumValues).filter(
163
+ (key) => typeof enumValues[enumValues[key]] !== "number"
164
+ );
165
+ return keys.map((key) => enumValues[key]);
166
+ };
167
+ var sortStringsAndNumbers = (values) => ({
168
+ strings: values.filter((value) => typeof value === "string"),
169
+ numbers: values.filter((value) => typeof value === "number")
170
+ });
171
+
111
172
  // src/create/schema/parsers/transform.ts
112
173
  var createTransformSchema = (zodTransform, state) => {
113
174
  if (zodTransform._def.openapi?.effectType === "output") {
@@ -290,6 +351,33 @@ var createDiscriminatedUnionSchema = (zodDiscriminatedUnion, state) => {
290
351
  effects: flattenEffects(schemas.map((schema) => schema.effects))
291
352
  };
292
353
  };
354
+ var unwrapLiterals = (zodType, state) => {
355
+ if (isZodType(zodType, "ZodLiteral")) {
356
+ if (typeof zodType._def.value !== "string") {
357
+ return void 0;
358
+ }
359
+ return [zodType._def.value];
360
+ }
361
+ if (isZodType(zodType, "ZodNativeEnum")) {
362
+ const schema = createNativeEnumSchema(zodType, state);
363
+ if (schema.type === "schema" && schema.schema.type === "string") {
364
+ return schema.schema.enum;
365
+ }
366
+ }
367
+ if (isZodType(zodType, "ZodEnum")) {
368
+ return zodType._def.values;
369
+ }
370
+ if (isZodType(zodType, "ZodBranded")) {
371
+ return unwrapLiterals(zodType._def.type, state);
372
+ }
373
+ if (isZodType(zodType, "ZodReadonly")) {
374
+ return unwrapLiterals(zodType._def.innerType, state);
375
+ }
376
+ if (isZodType(zodType, "ZodCatch")) {
377
+ return unwrapLiterals(zodType._def.innerType, state);
378
+ }
379
+ return void 0;
380
+ };
293
381
  var mapDiscriminator = (schemas, zodObjects, discriminator, state) => {
294
382
  if (typeof discriminator !== "string") {
295
383
  return void 0;
@@ -302,21 +390,13 @@ var mapDiscriminator = (schemas, zodObjects, discriminator, state) => {
302
390
  return void 0;
303
391
  }
304
392
  const value = zodObject.shape[discriminator];
305
- if (isZodType(value, "ZodEnum")) {
306
- for (const enumValue of value._def.values) {
307
- mapping[enumValue] = componentSchemaRef;
308
- }
309
- continue;
393
+ const literals = unwrapLiterals(value, state);
394
+ if (!literals) {
395
+ return void 0;
310
396
  }
311
- const literalValue = (value?._def).value;
312
- if (typeof literalValue !== "string") {
313
- throw new Error(
314
- `Discriminator ${discriminator} could not be found in on index ${index} of a discriminated union at ${state.path.join(
315
- " > "
316
- )}`
317
- );
397
+ for (const enumValue of literals) {
398
+ mapping[enumValue] = componentSchemaRef;
318
399
  }
319
- mapping[literalValue] = componentSchemaRef;
320
400
  }
321
401
  return {
322
402
  propertyName: discriminator,
@@ -356,16 +436,6 @@ var createLazySchema = (zodLazy, state) => {
356
436
  return createSchemaObject(innerSchema, state, ["lazy schema"]);
357
437
  };
358
438
 
359
- // src/openapi.ts
360
- var openApiVersions = [
361
- "3.0.0",
362
- "3.0.1",
363
- "3.0.2",
364
- "3.0.3",
365
- "3.1.0"
366
- ];
367
- var satisfiesVersion = (test, against) => openApiVersions.indexOf(test) >= openApiVersions.indexOf(against);
368
-
369
439
  // src/create/schema/parsers/null.ts
370
440
  var createNullSchema = () => ({
371
441
  type: "schema",
@@ -415,57 +485,6 @@ var createManualTypeSchema = (zodSchema, state) => {
415
485
  };
416
486
  };
417
487
 
418
- // src/create/schema/parsers/nativeEnum.ts
419
- var createNativeEnumSchema = (zodEnum, state) => {
420
- const enumValues = getValidEnumValues(zodEnum._def.values);
421
- const { numbers, strings } = sortStringsAndNumbers(enumValues);
422
- if (strings.length && numbers.length) {
423
- if (satisfiesVersion(state.components.openapi, "3.1.0"))
424
- return {
425
- type: "schema",
426
- schema: {
427
- type: ["string", "number"],
428
- enum: [...strings, ...numbers]
429
- }
430
- };
431
- return {
432
- type: "schema",
433
- schema: {
434
- oneOf: [
435
- { type: "string", enum: strings },
436
- { type: "number", enum: numbers }
437
- ]
438
- }
439
- };
440
- }
441
- if (strings.length) {
442
- return {
443
- type: "schema",
444
- schema: {
445
- type: "string",
446
- enum: strings
447
- }
448
- };
449
- }
450
- return {
451
- type: "schema",
452
- schema: {
453
- type: "number",
454
- enum: numbers
455
- }
456
- };
457
- };
458
- var getValidEnumValues = (enumValues) => {
459
- const keys = Object.keys(enumValues).filter(
460
- (key) => typeof enumValues[enumValues[key]] !== "number"
461
- );
462
- return keys.map((key) => enumValues[key]);
463
- };
464
- var sortStringsAndNumbers = (values) => ({
465
- strings: values.filter((value) => typeof value === "string"),
466
- numbers: values.filter((value) => typeof value === "number")
467
- });
468
-
469
488
  // src/create/schema/parsers/nullable.ts
470
489
  var createNullableSchema = (zodNullable, state) => {
471
490
  const schemaObject = createSchemaObject(zodNullable.unwrap(), state, [
@@ -971,12 +990,13 @@ var createSetSchema = (zodSet, state) => {
971
990
  };
972
991
 
973
992
  // src/create/schema/parsers/string.ts
974
- var createStringSchema = (zodString) => {
993
+ var createStringSchema = (zodString, state) => {
975
994
  const zodStringChecks = getZodStringChecks(zodString);
976
995
  const format = mapStringFormat(zodStringChecks);
977
996
  const patterns = mapPatterns(zodStringChecks);
978
997
  const minLength = zodStringChecks.length?.[0]?.value ?? zodStringChecks.min?.[0]?.value;
979
998
  const maxLength = zodStringChecks.length?.[0]?.value ?? zodStringChecks.max?.[0]?.value;
999
+ const contentEncoding = satisfiesVersion(state.components.openapi, "3.1.0") ? mapContentEncoding(zodStringChecks) : void 0;
980
1000
  if (patterns.length <= 1) {
981
1001
  return {
982
1002
  type: "schema",
@@ -985,7 +1005,8 @@ var createStringSchema = (zodString) => {
985
1005
  ...format && { format },
986
1006
  ...patterns[0] && { pattern: patterns[0] },
987
1007
  ...minLength !== void 0 && { minLength },
988
- ...maxLength !== void 0 && { maxLength }
1008
+ ...maxLength !== void 0 && { maxLength },
1009
+ ...contentEncoding && { contentEncoding }
989
1010
  }
990
1011
  };
991
1012
  }
@@ -998,7 +1019,8 @@ var createStringSchema = (zodString) => {
998
1019
  ...format && { format },
999
1020
  ...patterns[0] && { pattern: patterns[0] },
1000
1021
  ...minLength !== void 0 && { minLength },
1001
- ...maxLength !== void 0 && { maxLength }
1022
+ ...maxLength !== void 0 && { maxLength },
1023
+ ...contentEncoding && { contentEncoding }
1002
1024
  },
1003
1025
  ...patterns.slice(1).map(
1004
1026
  (pattern) => ({
@@ -1064,6 +1086,15 @@ var mapStringFormat = (zodStringChecks) => {
1064
1086
  if (zodStringChecks.datetime) {
1065
1087
  return "date-time";
1066
1088
  }
1089
+ if (zodStringChecks.date) {
1090
+ return "date";
1091
+ }
1092
+ if (zodStringChecks.time) {
1093
+ return "time";
1094
+ }
1095
+ if (zodStringChecks.duration) {
1096
+ return "duration";
1097
+ }
1067
1098
  if (zodStringChecks.email) {
1068
1099
  return "email";
1069
1100
  }
@@ -1072,6 +1103,12 @@ var mapStringFormat = (zodStringChecks) => {
1072
1103
  }
1073
1104
  return void 0;
1074
1105
  };
1106
+ var mapContentEncoding = (zodStringChecks) => {
1107
+ if (zodStringChecks.base64) {
1108
+ return "base64";
1109
+ }
1110
+ return void 0;
1111
+ };
1075
1112
 
1076
1113
  // src/create/schema/parsers/tuple.ts
1077
1114
  var createTupleSchema = (zodTuple, state) => {
@@ -1191,7 +1228,7 @@ var createSchemaSwitch = (zodSchema, state) => {
1191
1228
  return createManualTypeSchema(zodSchema, state);
1192
1229
  }
1193
1230
  if (isZodType(zodSchema, "ZodString")) {
1194
- return createStringSchema(zodSchema);
1231
+ return createStringSchema(zodSchema, state);
1195
1232
  }
1196
1233
  if (isZodType(zodSchema, "ZodNumber")) {
1197
1234
  return createNumberSchema(zodSchema, state);
@@ -0,0 +1,42 @@
1
+ // src/extend.ts
2
+ import { z } from "zod";
3
+
4
+ // src/extendZod.ts
5
+ function extendZodWithOpenApi(zod) {
6
+ if (typeof zod.ZodType.prototype.openapi !== "undefined") {
7
+ return;
8
+ }
9
+ zod.ZodType.prototype.openapi = function(openapi) {
10
+ const result = new this.constructor({
11
+ ...this._def,
12
+ openapi
13
+ });
14
+ return result;
15
+ };
16
+ const zodObjectExtend = zod.ZodObject.prototype.extend;
17
+ zod.ZodObject.prototype.extend = function(...args) {
18
+ const extendResult = zodObjectExtend.apply(this, args);
19
+ extendResult._def.extendMetadata = {
20
+ extends: this
21
+ };
22
+ delete extendResult._def.openapi;
23
+ return extendResult;
24
+ };
25
+ const zodObjectOmit = zod.ZodObject.prototype.omit;
26
+ zod.ZodObject.prototype.omit = function(...args) {
27
+ const omitResult = zodObjectOmit.apply(this, args);
28
+ delete omitResult._def.extendMetadata;
29
+ delete omitResult._def.openapi;
30
+ return omitResult;
31
+ };
32
+ const zodObjectPick = zod.ZodObject.prototype.pick;
33
+ zod.ZodObject.prototype.pick = function(...args) {
34
+ const pickResult = zodObjectPick.apply(this, args);
35
+ delete pickResult._def.extendMetadata;
36
+ delete pickResult._def.openapi;
37
+ return pickResult;
38
+ };
39
+ }
40
+
41
+ // src/extend.ts
42
+ extendZodWithOpenApi(z);
package/lib-esm/index.mjs CHANGED
@@ -84,6 +84,67 @@ var createDefaultSchema = (zodDefault, state) => {
84
84
  });
85
85
  };
86
86
 
87
+ // src/openapi.ts
88
+ var openApiVersions = [
89
+ "3.0.0",
90
+ "3.0.1",
91
+ "3.0.2",
92
+ "3.0.3",
93
+ "3.1.0"
94
+ ];
95
+ var satisfiesVersion = (test, against) => openApiVersions.indexOf(test) >= openApiVersions.indexOf(against);
96
+
97
+ // src/create/schema/parsers/nativeEnum.ts
98
+ var createNativeEnumSchema = (zodEnum, state) => {
99
+ const enumValues = getValidEnumValues(zodEnum._def.values);
100
+ const { numbers, strings } = sortStringsAndNumbers(enumValues);
101
+ if (strings.length && numbers.length) {
102
+ if (satisfiesVersion(state.components.openapi, "3.1.0"))
103
+ return {
104
+ type: "schema",
105
+ schema: {
106
+ type: ["string", "number"],
107
+ enum: [...strings, ...numbers]
108
+ }
109
+ };
110
+ return {
111
+ type: "schema",
112
+ schema: {
113
+ oneOf: [
114
+ { type: "string", enum: strings },
115
+ { type: "number", enum: numbers }
116
+ ]
117
+ }
118
+ };
119
+ }
120
+ if (strings.length) {
121
+ return {
122
+ type: "schema",
123
+ schema: {
124
+ type: "string",
125
+ enum: strings
126
+ }
127
+ };
128
+ }
129
+ return {
130
+ type: "schema",
131
+ schema: {
132
+ type: "number",
133
+ enum: numbers
134
+ }
135
+ };
136
+ };
137
+ var getValidEnumValues = (enumValues) => {
138
+ const keys = Object.keys(enumValues).filter(
139
+ (key) => typeof enumValues[enumValues[key]] !== "number"
140
+ );
141
+ return keys.map((key) => enumValues[key]);
142
+ };
143
+ var sortStringsAndNumbers = (values) => ({
144
+ strings: values.filter((value) => typeof value === "string"),
145
+ numbers: values.filter((value) => typeof value === "number")
146
+ });
147
+
87
148
  // src/create/schema/parsers/transform.ts
88
149
  var createTransformSchema = (zodTransform, state) => {
89
150
  if (zodTransform._def.openapi?.effectType === "output") {
@@ -266,6 +327,33 @@ var createDiscriminatedUnionSchema = (zodDiscriminatedUnion, state) => {
266
327
  effects: flattenEffects(schemas.map((schema) => schema.effects))
267
328
  };
268
329
  };
330
+ var unwrapLiterals = (zodType, state) => {
331
+ if (isZodType(zodType, "ZodLiteral")) {
332
+ if (typeof zodType._def.value !== "string") {
333
+ return void 0;
334
+ }
335
+ return [zodType._def.value];
336
+ }
337
+ if (isZodType(zodType, "ZodNativeEnum")) {
338
+ const schema = createNativeEnumSchema(zodType, state);
339
+ if (schema.type === "schema" && schema.schema.type === "string") {
340
+ return schema.schema.enum;
341
+ }
342
+ }
343
+ if (isZodType(zodType, "ZodEnum")) {
344
+ return zodType._def.values;
345
+ }
346
+ if (isZodType(zodType, "ZodBranded")) {
347
+ return unwrapLiterals(zodType._def.type, state);
348
+ }
349
+ if (isZodType(zodType, "ZodReadonly")) {
350
+ return unwrapLiterals(zodType._def.innerType, state);
351
+ }
352
+ if (isZodType(zodType, "ZodCatch")) {
353
+ return unwrapLiterals(zodType._def.innerType, state);
354
+ }
355
+ return void 0;
356
+ };
269
357
  var mapDiscriminator = (schemas, zodObjects, discriminator, state) => {
270
358
  if (typeof discriminator !== "string") {
271
359
  return void 0;
@@ -278,21 +366,13 @@ var mapDiscriminator = (schemas, zodObjects, discriminator, state) => {
278
366
  return void 0;
279
367
  }
280
368
  const value = zodObject.shape[discriminator];
281
- if (isZodType(value, "ZodEnum")) {
282
- for (const enumValue of value._def.values) {
283
- mapping[enumValue] = componentSchemaRef;
284
- }
285
- continue;
369
+ const literals = unwrapLiterals(value, state);
370
+ if (!literals) {
371
+ return void 0;
286
372
  }
287
- const literalValue = (value?._def).value;
288
- if (typeof literalValue !== "string") {
289
- throw new Error(
290
- `Discriminator ${discriminator} could not be found in on index ${index} of a discriminated union at ${state.path.join(
291
- " > "
292
- )}`
293
- );
373
+ for (const enumValue of literals) {
374
+ mapping[enumValue] = componentSchemaRef;
294
375
  }
295
- mapping[literalValue] = componentSchemaRef;
296
376
  }
297
377
  return {
298
378
  propertyName: discriminator,
@@ -332,16 +412,6 @@ var createLazySchema = (zodLazy, state) => {
332
412
  return createSchemaObject(innerSchema, state, ["lazy schema"]);
333
413
  };
334
414
 
335
- // src/openapi.ts
336
- var openApiVersions = [
337
- "3.0.0",
338
- "3.0.1",
339
- "3.0.2",
340
- "3.0.3",
341
- "3.1.0"
342
- ];
343
- var satisfiesVersion = (test, against) => openApiVersions.indexOf(test) >= openApiVersions.indexOf(against);
344
-
345
415
  // src/create/schema/parsers/null.ts
346
416
  var createNullSchema = () => ({
347
417
  type: "schema",
@@ -391,57 +461,6 @@ var createManualTypeSchema = (zodSchema, state) => {
391
461
  };
392
462
  };
393
463
 
394
- // src/create/schema/parsers/nativeEnum.ts
395
- var createNativeEnumSchema = (zodEnum, state) => {
396
- const enumValues = getValidEnumValues(zodEnum._def.values);
397
- const { numbers, strings } = sortStringsAndNumbers(enumValues);
398
- if (strings.length && numbers.length) {
399
- if (satisfiesVersion(state.components.openapi, "3.1.0"))
400
- return {
401
- type: "schema",
402
- schema: {
403
- type: ["string", "number"],
404
- enum: [...strings, ...numbers]
405
- }
406
- };
407
- return {
408
- type: "schema",
409
- schema: {
410
- oneOf: [
411
- { type: "string", enum: strings },
412
- { type: "number", enum: numbers }
413
- ]
414
- }
415
- };
416
- }
417
- if (strings.length) {
418
- return {
419
- type: "schema",
420
- schema: {
421
- type: "string",
422
- enum: strings
423
- }
424
- };
425
- }
426
- return {
427
- type: "schema",
428
- schema: {
429
- type: "number",
430
- enum: numbers
431
- }
432
- };
433
- };
434
- var getValidEnumValues = (enumValues) => {
435
- const keys = Object.keys(enumValues).filter(
436
- (key) => typeof enumValues[enumValues[key]] !== "number"
437
- );
438
- return keys.map((key) => enumValues[key]);
439
- };
440
- var sortStringsAndNumbers = (values) => ({
441
- strings: values.filter((value) => typeof value === "string"),
442
- numbers: values.filter((value) => typeof value === "number")
443
- });
444
-
445
464
  // src/create/schema/parsers/nullable.ts
446
465
  var createNullableSchema = (zodNullable, state) => {
447
466
  const schemaObject = createSchemaObject(zodNullable.unwrap(), state, [
@@ -947,12 +966,13 @@ var createSetSchema = (zodSet, state) => {
947
966
  };
948
967
 
949
968
  // src/create/schema/parsers/string.ts
950
- var createStringSchema = (zodString) => {
969
+ var createStringSchema = (zodString, state) => {
951
970
  const zodStringChecks = getZodStringChecks(zodString);
952
971
  const format = mapStringFormat(zodStringChecks);
953
972
  const patterns = mapPatterns(zodStringChecks);
954
973
  const minLength = zodStringChecks.length?.[0]?.value ?? zodStringChecks.min?.[0]?.value;
955
974
  const maxLength = zodStringChecks.length?.[0]?.value ?? zodStringChecks.max?.[0]?.value;
975
+ const contentEncoding = satisfiesVersion(state.components.openapi, "3.1.0") ? mapContentEncoding(zodStringChecks) : void 0;
956
976
  if (patterns.length <= 1) {
957
977
  return {
958
978
  type: "schema",
@@ -961,7 +981,8 @@ var createStringSchema = (zodString) => {
961
981
  ...format && { format },
962
982
  ...patterns[0] && { pattern: patterns[0] },
963
983
  ...minLength !== void 0 && { minLength },
964
- ...maxLength !== void 0 && { maxLength }
984
+ ...maxLength !== void 0 && { maxLength },
985
+ ...contentEncoding && { contentEncoding }
965
986
  }
966
987
  };
967
988
  }
@@ -974,7 +995,8 @@ var createStringSchema = (zodString) => {
974
995
  ...format && { format },
975
996
  ...patterns[0] && { pattern: patterns[0] },
976
997
  ...minLength !== void 0 && { minLength },
977
- ...maxLength !== void 0 && { maxLength }
998
+ ...maxLength !== void 0 && { maxLength },
999
+ ...contentEncoding && { contentEncoding }
978
1000
  },
979
1001
  ...patterns.slice(1).map(
980
1002
  (pattern) => ({
@@ -1040,6 +1062,15 @@ var mapStringFormat = (zodStringChecks) => {
1040
1062
  if (zodStringChecks.datetime) {
1041
1063
  return "date-time";
1042
1064
  }
1065
+ if (zodStringChecks.date) {
1066
+ return "date";
1067
+ }
1068
+ if (zodStringChecks.time) {
1069
+ return "time";
1070
+ }
1071
+ if (zodStringChecks.duration) {
1072
+ return "duration";
1073
+ }
1043
1074
  if (zodStringChecks.email) {
1044
1075
  return "email";
1045
1076
  }
@@ -1048,6 +1079,12 @@ var mapStringFormat = (zodStringChecks) => {
1048
1079
  }
1049
1080
  return void 0;
1050
1081
  };
1082
+ var mapContentEncoding = (zodStringChecks) => {
1083
+ if (zodStringChecks.base64) {
1084
+ return "base64";
1085
+ }
1086
+ return void 0;
1087
+ };
1051
1088
 
1052
1089
  // src/create/schema/parsers/tuple.ts
1053
1090
  var createTupleSchema = (zodTuple, state) => {
@@ -1167,7 +1204,7 @@ var createSchemaSwitch = (zodSchema, state) => {
1167
1204
  return createManualTypeSchema(zodSchema, state);
1168
1205
  }
1169
1206
  if (isZodType(zodSchema, "ZodString")) {
1170
- return createStringSchema(zodSchema);
1207
+ return createStringSchema(zodSchema, state);
1171
1208
  }
1172
1209
  if (isZodType(zodSchema, "ZodNumber")) {
1173
1210
  return createNumberSchema(zodSchema, state);
@@ -1,3 +1,3 @@
1
1
  import type { ZodString } from 'zod';
2
- import type { Schema } from '..';
3
- export declare const createStringSchema: (zodString: ZodString) => Schema;
2
+ import type { Schema, SchemaState } from '..';
3
+ export declare const createStringSchema: (zodString: ZodString, state: SchemaState) => Schema;
@@ -0,0 +1 @@
1
+ export type * from './extendZod';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-openapi",
3
- "version": "2.15.2",
3
+ "version": "2.17.0-beta.1",
4
4
  "description": "Convert Zod Schemas to OpenAPI v3.x documentation",
5
5
  "keywords": [
6
6
  "typescript",
@@ -20,12 +20,21 @@
20
20
  "url": "git+ssh://git@github.com/samchungy/zod-openapi.git"
21
21
  },
22
22
  "license": "MIT",
23
- "sideEffects": false,
23
+ "sideEffects": [
24
+ "./src/extend.ts",
25
+ "./lib-esm/extend.mjs",
26
+ "./lib-commonjs/extend.js"
27
+ ],
24
28
  "exports": {
25
29
  ".": {
26
30
  "import": "./lib-esm/index.mjs",
27
31
  "require": "./lib-commonjs/index.js",
28
32
  "types": "./lib-types/index.d.ts"
33
+ },
34
+ "./extend": {
35
+ "import": "./lib-esm/extend.mjs",
36
+ "require": "./lib-commonjs/extend.js",
37
+ "types": "./lib-types/extend.d.ts"
29
38
  }
30
39
  },
31
40
  "main": "./lib-commonjs/index.js",
@@ -52,9 +61,9 @@
52
61
  "@types/node": "^20.3.0",
53
62
  "eslint-plugin-zod-openapi": "^0.1.0",
54
63
  "openapi3-ts": "4.3.1",
55
- "skuba": "8.0.0",
64
+ "skuba": "8.0.1",
56
65
  "yaml": "2.4.1",
57
- "zod": "3.22.4"
66
+ "zod": "3.23.3"
58
67
  },
59
68
  "peerDependencies": {
60
69
  "zod": "^3.21.4"