zod-openapi 2.13.0 → 2.14.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
@@ -17,12 +17,14 @@ A Typescript library to use <a href="https://github.com/colinhacks/zod">Zod</a>
17
17
 
18
18
  ## Install
19
19
 
20
- Install via `npm` or `yarn`:
20
+ Install via `npm`, `yarn` or `pnpm`:
21
21
 
22
22
  ```bash
23
23
  npm install zod zod-openapi
24
24
  ## or
25
25
  yarn add zod zod-openapi
26
+ ## or
27
+ pnpm install zod zod-openapi
26
28
  ```
27
29
 
28
30
  ## Usage
@@ -48,8 +50,8 @@ Use the `.openapi()` method to add metadata to a specific Zod type. The `.openap
48
50
  | :-------------: | :-------------------------------------------------------------------------------------------------------------------------: |
49
51
  | OpenAPI Options | This will take any option you would put on a [SchemaObject](https://swagger.io/docs/specification/data-models/data-types/). |
50
52
  | `effectType` | Use to override the creation type for a [Zod Effect](#zod-effects) |
51
- | `param` | Use to provide metadata for [request parameters](#parameters) |
52
53
  | `header` | Use to provide metadata for [response headers](#response-headers) |
54
+ | `param` | Use to provide metadata for [request parameters](#parameters) |
53
55
  | `ref` | Use this to [auto register a schema](#creating-components) |
54
56
  | `refType` | Use this to set the creation type for a component which is not referenced in the document. |
55
57
  | `type` | Use this to override the generated type. If this is provided no metadata will be generated. |
@@ -328,13 +330,13 @@ createDocument({
328
330
 
329
331
  ##### Zod Effects
330
332
 
331
- `.transform()` 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:
333
+ `.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:
332
334
 
333
335
  _Input_: Request Bodies, Request Parameters, Headers
334
336
 
335
337
  _Output_: Responses, Response Headers
336
338
 
337
- If a registered schema with a transform or pipeline is used in both a request and response schema you will receive an error because the created schema for each will be different. To override the creation type for a specific ZodEffect, add an `.openapi()` field on it and set the `effectType` field to `input`, `output` or `same`. This will force this library to always generate the input/output type even if we are creating a response (output) or request (input) type. You typically want to set this when you know the type has not changed in the transform. `same` is the recommended choice as it will throw a type error if the input and output types in the transform drift.
339
+ If a registered schema with a transform or pipeline is used in both a request and response schema you will receive an error because the created schema for each will be different. To override the creation type for a specific ZodEffect, add an `.openapi()` field on it and set the `effectType` field to `input`, `output` or `same`. This will force this library to always generate the input/output type even if we are creating a response (output) or request (input) type. You typically want to set this when you know the type has not changed in the transform. `same` is the recommended choice as it will generate a TypeScript compiler error if the input and output types in the transform drift.
338
340
 
339
341
  `.preprocess()` will always return the `output` type even if we are creating an input schema. If a different input type is required you can achieve this with a `.transform()` combined with a `.pipe()` or simply declare a manual `type` in `.openapi()`.
340
342
 
@@ -578,27 +580,27 @@ See the library in use in the [examples](./examples/) folder.
578
580
  ### Prerequisites
579
581
 
580
582
  - Node.js LTS
581
- - Yarn 1.x
583
+ - pnpm
582
584
 
583
585
  ```shell
584
- yarn
585
- yarn build
586
+ pnpm
587
+ pnpm build
586
588
  ```
587
589
 
588
590
  ### Test
589
591
 
590
592
  ```shell
591
- yarn test
593
+ pnpm test
592
594
  ```
593
595
 
594
596
  ### Lint
595
597
 
596
598
  ```shell
597
599
  # Fix issues
598
- yarn format
600
+ pnpm format
599
601
 
600
602
  # Check for issues
601
- yarn lint
603
+ pnpm lint
602
604
  ```
603
605
 
604
606
  ### Release
@@ -178,11 +178,11 @@ var throwTransformError = (effect) => {
178
178
 
179
179
  This may cause the schema to render incorrectly and is most likely a mistake. You can resolve this by:
180
180
 
181
- 1. Setting an \`effectType\` on the transformation to \`same\` or \`${opposite}\` eg. \`.openapi({type: 'same'})\`
181
+ 1. Setting an \`effectType\` on one of the transformations to \`same\` (Not applicable for ZodDefault), \`input\` or \`output\` eg. \`.openapi({type: 'same'})\`
182
182
  2. Wrapping the transformation in a ZodPipeline
183
183
  3. Assigning a manual type to the transformation eg. \`.openapi({type: 'string'})\`
184
184
  4. Removing the transformation
185
- 5. Deregistering the component containing the transformation`
185
+ 5. Deregister the component containing the transformation`
186
186
  );
187
187
  };
188
188
  var resolveSingleEffect = (effect, state) => {
@@ -1442,11 +1442,12 @@ var createParamOrRef = (zodSchema, components, subpath, type, name) => {
1442
1442
  }
1443
1443
  return paramObject;
1444
1444
  };
1445
- var createParameters = (type, zodObject, components, subpath) => {
1446
- if (!zodObject) {
1445
+ var createParameters = (type, zodObjectType, components, subpath) => {
1446
+ if (!zodObjectType) {
1447
1447
  return [];
1448
1448
  }
1449
- return Object.entries(zodObject.shape).map(
1449
+ const zodObject = getZodObject(zodObjectType, "input").shape;
1450
+ return Object.entries(zodObject).map(
1450
1451
  ([key, zodSchema]) => createParamOrRef(zodSchema, components, [...subpath, key], type, key)
1451
1452
  );
1452
1453
  };
@@ -1500,6 +1501,27 @@ var createParametersObject = (parameters, requestParams, components, subpath) =>
1500
1501
  ];
1501
1502
  return combinedParameters.length ? combinedParameters : void 0;
1502
1503
  };
1504
+ var getZodObject = (schema, type) => {
1505
+ if (isZodType(schema, "ZodObject")) {
1506
+ return schema;
1507
+ }
1508
+ if (isZodType(schema, "ZodLazy")) {
1509
+ return getZodObject(schema.schema, type);
1510
+ }
1511
+ if (isZodType(schema, "ZodEffects")) {
1512
+ return getZodObject(schema.innerType(), type);
1513
+ }
1514
+ if (isZodType(schema, "ZodBranded")) {
1515
+ return getZodObject(schema.unwrap(), type);
1516
+ }
1517
+ if (isZodType(schema, "ZodPipeline")) {
1518
+ if (type === "input") {
1519
+ return getZodObject(schema._def.in, type);
1520
+ }
1521
+ return getZodObject(schema._def.out, type);
1522
+ }
1523
+ throw new Error("failed to find ZodObject in schema");
1524
+ };
1503
1525
 
1504
1526
  // src/create/content.ts
1505
1527
  var createMediaTypeSchema = (schemaObject, components, type, subpath) => {
package/lib-esm/index.mjs CHANGED
@@ -154,11 +154,11 @@ var throwTransformError = (effect) => {
154
154
 
155
155
  This may cause the schema to render incorrectly and is most likely a mistake. You can resolve this by:
156
156
 
157
- 1. Setting an \`effectType\` on the transformation to \`same\` or \`${opposite}\` eg. \`.openapi({type: 'same'})\`
157
+ 1. Setting an \`effectType\` on one of the transformations to \`same\` (Not applicable for ZodDefault), \`input\` or \`output\` eg. \`.openapi({type: 'same'})\`
158
158
  2. Wrapping the transformation in a ZodPipeline
159
159
  3. Assigning a manual type to the transformation eg. \`.openapi({type: 'string'})\`
160
160
  4. Removing the transformation
161
- 5. Deregistering the component containing the transformation`
161
+ 5. Deregister the component containing the transformation`
162
162
  );
163
163
  };
164
164
  var resolveSingleEffect = (effect, state) => {
@@ -1418,11 +1418,12 @@ var createParamOrRef = (zodSchema, components, subpath, type, name) => {
1418
1418
  }
1419
1419
  return paramObject;
1420
1420
  };
1421
- var createParameters = (type, zodObject, components, subpath) => {
1422
- if (!zodObject) {
1421
+ var createParameters = (type, zodObjectType, components, subpath) => {
1422
+ if (!zodObjectType) {
1423
1423
  return [];
1424
1424
  }
1425
- return Object.entries(zodObject.shape).map(
1425
+ const zodObject = getZodObject(zodObjectType, "input").shape;
1426
+ return Object.entries(zodObject).map(
1426
1427
  ([key, zodSchema]) => createParamOrRef(zodSchema, components, [...subpath, key], type, key)
1427
1428
  );
1428
1429
  };
@@ -1476,6 +1477,27 @@ var createParametersObject = (parameters, requestParams, components, subpath) =>
1476
1477
  ];
1477
1478
  return combinedParameters.length ? combinedParameters : void 0;
1478
1479
  };
1480
+ var getZodObject = (schema, type) => {
1481
+ if (isZodType(schema, "ZodObject")) {
1482
+ return schema;
1483
+ }
1484
+ if (isZodType(schema, "ZodLazy")) {
1485
+ return getZodObject(schema.schema, type);
1486
+ }
1487
+ if (isZodType(schema, "ZodEffects")) {
1488
+ return getZodObject(schema.innerType(), type);
1489
+ }
1490
+ if (isZodType(schema, "ZodBranded")) {
1491
+ return getZodObject(schema.unwrap(), type);
1492
+ }
1493
+ if (isZodType(schema, "ZodPipeline")) {
1494
+ if (type === "input") {
1495
+ return getZodObject(schema._def.in, type);
1496
+ }
1497
+ return getZodObject(schema._def.out, type);
1498
+ }
1499
+ throw new Error("failed to find ZodObject in schema");
1500
+ };
1479
1501
 
1480
1502
  // src/create/content.ts
1481
1503
  var createMediaTypeSchema = (schemaObject, components, type, subpath) => {
@@ -1,4 +1,4 @@
1
- import type { AnyZodObject, ZodType } from 'zod';
1
+ import type { AnyZodObject, ZodType, ZodTypeDef } from 'zod';
2
2
  import type { OpenApiVersion } from '../openapi';
3
3
  import type { oas30, oas31 } from '../openapi3-ts/dist';
4
4
  export interface ZodOpenApiMediaTypeObject extends Omit<oas31.MediaTypeObject & oas30.MediaTypeObject, 'schema'> {
@@ -24,7 +24,7 @@ export interface ZodOpenApiResponsesObject extends oas31.ISpecificationExtension
24
24
  [statuscode: `${1 | 2 | 3 | 4 | 5}${string}`]: ZodOpenApiResponseObject | oas31.ReferenceObject;
25
25
  }
26
26
  export type ZodOpenApiParameters = {
27
- [type in oas31.ParameterLocation & oas30.ParameterLocation]?: AnyZodObject;
27
+ [type in oas31.ParameterLocation & oas30.ParameterLocation]?: ZodObjectInputType;
28
28
  };
29
29
  export interface ZodOpenApiOperationObject extends Omit<oas31.OperationObject & oas30.OperationObject, 'requestBody' | 'responses' | 'parameters'> {
30
30
  parameters?: Array<ZodType | oas31.ParameterObject | oas30.ParameterObject | oas31.ReferenceObject | oas30.ReferenceObject>;
@@ -59,4 +59,5 @@ export interface ZodOpenApiObject extends Omit<oas31.OpenAPIObject, 'openapi' |
59
59
  webhooks?: ZodOpenApiPathsObject;
60
60
  components?: ZodOpenApiComponentsObject;
61
61
  }
62
+ export type ZodObjectInputType<Output = unknown, Def extends ZodTypeDef = ZodTypeDef, Input = Record<string, unknown>> = ZodType<Output, Def, Input>;
62
63
  export declare const createDocument: (zodOpenApiObject: ZodOpenApiObject) => oas31.OpenAPIObject;
@@ -1,9 +1,10 @@
1
- import type { ZodType } from 'zod';
1
+ import type { AnyZodObject, ZodType } from 'zod';
2
2
  import type { oas30, oas31 } from '../openapi3-ts/dist';
3
3
  import type { ComponentsObject } from './components';
4
- import type { ZodOpenApiParameters } from './document';
4
+ import type { ZodObjectInputType, ZodOpenApiParameters } from './document';
5
5
  export declare const createComponentParamRef: (ref: string) => string;
6
6
  export declare const createBaseParameter: (schema: ZodType, components: ComponentsObject, subpath: string[]) => oas31.BaseParameterObject;
7
7
  export declare const createParamOrRef: (zodSchema: ZodType, components: ComponentsObject, subpath: string[], type?: keyof ZodOpenApiParameters, name?: string) => oas31.ParameterObject | oas31.ReferenceObject;
8
8
  export declare const createManualParameters: (parameters: Array<oas31.ParameterObject | oas31.ReferenceObject | oas30.ParameterObject | oas30.ReferenceObject | ZodType> | undefined, components: ComponentsObject, subpath: string[]) => Array<oas31.ParameterObject | oas31.ReferenceObject>;
9
9
  export declare const createParametersObject: (parameters: Array<oas31.ParameterObject | oas31.ReferenceObject | oas30.ParameterObject | oas30.ReferenceObject | ZodType> | undefined, requestParams: ZodOpenApiParameters | undefined, components: ComponentsObject, subpath: string[]) => Array<oas31.ParameterObject | oas31.ReferenceObject> | undefined;
10
+ export declare const getZodObject: (schema: ZodObjectInputType, type: 'input' | 'output') => AnyZodObject;
@@ -2,51 +2,70 @@ import type { UnknownKeysParam, ZodDate, ZodObject, ZodRawShape, ZodTypeAny, z }
2
2
  import type { CreationType } from './create/components';
3
3
  import type { oas30, oas31 } from './openapi3-ts/dist';
4
4
  type SchemaObject = oas30.SchemaObject & oas31.SchemaObject;
5
+ /**
6
+ * zod-openapi metadata
7
+ */
5
8
  interface ZodOpenApiMetadata<T extends ZodTypeAny, TInferred = z.input<T> | z.output<T>> extends SchemaObject {
6
9
  example?: TInferred;
7
10
  examples?: [TInferred, ...TInferred[]];
8
11
  default?: T extends ZodDate ? string : TInferred;
9
12
  /**
10
- * Use this field to set the output of a ZodUnion to be `oneOf` instead of `allOf`
13
+ * Used to set the output of a ZodUnion to be `oneOf` instead of `allOf`
11
14
  */
12
15
  unionOneOf?: boolean;
13
16
  /**
14
- * Use this field to output this Zod Schema in the components schemas section. Any usage of this Zod Schema will then be transformed into a $ref.
17
+ * Used to output this Zod Schema in the components schemas section. Any usage of this Zod Schema will then be transformed into a $ref.
15
18
  */
16
19
  ref?: string;
17
20
  /**
18
- * Use this field when you are manually adding a Zod Schema to the components section. This controls whether this should be rendered as request (`input`) or response (`output`). Defaults to `output`
21
+ * Used when you are manually adding a Zod Schema to the components section. This controls whether this should be rendered as request (`input`) or response (`output`). Defaults to `output`
19
22
  */
20
23
  refType?: CreationType;
21
24
  /**
22
- * Use this field to set the created type of an effect.
25
+ * Used to set the created type of an effect.
23
26
  */
24
27
  effectType?: CreationType | (z.input<T> extends z.output<T> ? z.output<T> extends z.input<T> ? 'same' : never : never);
28
+ /**
29
+ * Used to set metadata for a parameter, request header or cookie
30
+ */
25
31
  param?: Partial<oas31.ParameterObject> & {
26
32
  example?: TInferred;
27
33
  examples?: Record<string, (oas31.ExampleObject & {
28
34
  value: TInferred;
29
35
  }) | oas31.ReferenceObject>;
30
36
  /**
31
- * Use this field to output this Zod Schema in the components parameters section. Any usage of this Zod Schema will then be transformed into a $ref.
37
+ * Used to output this Zod Schema in the components parameters section. Any usage of this Zod Schema will then be transformed into a $ref.
32
38
  */
33
39
  ref?: string;
34
40
  };
41
+ /**
42
+ * Used to set data for a response header
43
+ */
35
44
  header?: Partial<oas31.HeaderObject & oas30.HeaderObject> & {
36
45
  /**
37
- * Use this field to output this Zod Schema in the components headers section. Any usage of this Zod Schema will then be transformed into a $ref.
46
+ * Used to output this Zod Schema in the components headers section. Any usage of this Zod Schema will then be transformed into a $ref.
38
47
  */
39
48
  ref?: string;
40
49
  };
50
+ /**
51
+ * Used to override the generated type. If this is provided no metadata will be generated.
52
+ */
53
+ type?: SchemaObject['type'];
41
54
  }
42
55
  interface ZodOpenApiExtendMetadata {
43
56
  extends: ZodObject<any, any, any, any, any>;
44
57
  }
45
58
  declare module 'zod' {
46
59
  interface ZodType<Output, Def extends ZodTypeDef, Input = Output> {
60
+ /**
61
+ * Add OpenAPI metadata to a Zod Type
62
+ */
47
63
  openapi<T extends ZodTypeAny>(this: T, metadata: ZodOpenApiMetadata<T>): T;
48
64
  }
49
65
  interface ZodTypeDef {
66
+ /**
67
+ * OpenAPI metadata
68
+ */
50
69
  openapi?: ZodOpenApiMetadata<ZodTypeAny>;
51
70
  }
52
71
  interface ZodObjectDef<T extends ZodRawShape = ZodRawShape, UnknownKeys extends UnknownKeysParam = UnknownKeysParam, Catchall extends ZodTypeAny = ZodTypeAny> extends ZodTypeDef {
@@ -88,7 +88,7 @@ export interface OperationObject extends ISpecificationExtension {
88
88
  operationId?: string;
89
89
  parameters?: (ParameterObject | ReferenceObject)[];
90
90
  requestBody?: RequestBodyObject | ReferenceObject;
91
- responses: ResponsesObject;
91
+ responses?: ResponsesObject;
92
92
  callbacks?: CallbacksObject;
93
93
  deprecated?: boolean;
94
94
  security?: SecurityRequirementObject[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-openapi",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "Convert Zod Schemas to OpenAPI v3.x documentation",
5
5
  "keywords": [
6
6
  "typescript",
@@ -37,24 +37,24 @@
37
37
  "lib*/**/*.json"
38
38
  ],
39
39
  "scripts": {
40
- "build": "yarn copy:types && node esbuild.mjs && node esbuild.esm.mjs && tsc --allowJS false --declaration --emitDeclarationOnly --outDir lib-types --project tsconfig.build.json",
40
+ "build": "pnpm copy:types && node esbuild.mjs && node esbuild.esm.mjs && tsc --allowJS false --declaration --emitDeclarationOnly --outDir lib-types --project tsconfig.build.json",
41
41
  "copy:types": "skuba node scripts/copyTypes.ts",
42
42
  "create:docs": " skuba node examples/simple/createSchema.ts && redocly build-docs examples/simple/openapi.yml --output=examples/simple/redoc-static.html",
43
43
  "format": "skuba format",
44
44
  "lint": "skuba lint",
45
- "prepare": "yarn build",
45
+ "prepare": "pnpm build",
46
46
  "test": "skuba test",
47
47
  "test:ci": "skuba test --coverage",
48
48
  "test:watch": "skuba test --watch"
49
49
  },
50
50
  "dependencies": {},
51
51
  "devDependencies": {
52
- "@redocly/cli": "1.8.2",
52
+ "@redocly/cli": "1.9.1",
53
53
  "@types/node": "^20.3.0",
54
54
  "eslint-plugin-zod-openapi": "^0.1.0",
55
- "openapi3-ts": "4.2.1",
56
- "skuba": "7.3.1",
57
- "yaml": "2.3.4",
55
+ "openapi3-ts": "4.2.2",
56
+ "skuba": "7.5.0",
57
+ "yaml": "2.4.0",
58
58
  "zod": "3.22.4"
59
59
  },
60
60
  "peerDependencies": {
@@ -71,6 +71,6 @@
71
71
  "entryPoint": "src/index.ts",
72
72
  "template": "oss-npm-package",
73
73
  "type": "package",
74
- "version": "6.0.0"
74
+ "version": "7.4.1"
75
75
  }
76
76
  }