@origins-digital/zod-openapi-utils 1.0.5 → 1.1.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
|
@@ -11,10 +11,11 @@ npm install @origins-digital/zod-openapi-utils
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
13
|
- Automatic conversion of Zod schemas to OpenAPI/Swagger schemas
|
|
14
|
-
- Support for all Zod types and validations
|
|
14
|
+
- Support for all Zod types and validations including lazy schemas
|
|
15
15
|
- Type-safe API documentation
|
|
16
16
|
- Seamless integration with NestJS Swagger
|
|
17
17
|
- Custom format support (email, URL, UUID, CUID, etc.)
|
|
18
|
+
- Support for recursive and circular references
|
|
18
19
|
|
|
19
20
|
## Usage
|
|
20
21
|
|
|
@@ -51,7 +52,7 @@ export class AppModule {
|
|
|
51
52
|
import { z } from 'zod';
|
|
52
53
|
import { createZodDto } from '@origins-digital/zod-openapi-utils';
|
|
53
54
|
|
|
54
|
-
// Define your Zod schema
|
|
55
|
+
// Define your Zod schema with .openapi() decorator
|
|
55
56
|
const UserSchema = z
|
|
56
57
|
.object({
|
|
57
58
|
id: z.string().uuid(),
|
|
@@ -61,7 +62,10 @@ const UserSchema = z
|
|
|
61
62
|
createdAt: z.date(),
|
|
62
63
|
password: z.string().min(8).password(),
|
|
63
64
|
})
|
|
64
|
-
.
|
|
65
|
+
.openapi({
|
|
66
|
+
title: 'User',
|
|
67
|
+
description: 'User entity schema',
|
|
68
|
+
});
|
|
65
69
|
|
|
66
70
|
// Create DTO from Zod schema
|
|
67
71
|
export class CreateUserDto extends createZodDto(UserSchema) {}
|
|
@@ -86,8 +90,9 @@ export class UsersController {
|
|
|
86
90
|
- **Objects**: nested schemas
|
|
87
91
|
- **Arrays**: min/max length
|
|
88
92
|
- **Unions and Enums**
|
|
93
|
+
- **Lazy Schemas**: recursive and circular references
|
|
89
94
|
- **Custom Formats**: password, time, etc.
|
|
90
|
-
- **Nested types**: This package is also able to detect nested types when using the .
|
|
95
|
+
- **Nested types**: This package is also able to detect nested types when using the .openapi() method, and create the reference in the openapi spec.
|
|
91
96
|
|
|
92
97
|
## Error Handling
|
|
93
98
|
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import { UnknownKeysParam, z, ZodStringCheck } from 'zod';
|
|
2
|
-
import { objectOutputType } from 'zod';
|
|
3
|
-
import { objectUtil } from 'zod';
|
|
4
|
-
import { objectInputType } from 'zod';
|
|
5
|
-
import { ZodTypeAny } from 'zod';
|
|
6
|
-
import { AnyZodObject, ZodRawShape } from 'zod';
|
|
1
|
+
import { ZodObject, AnyZodObject, ZodRawShape, ZodType, ZodTypeAny, objectInputType, objectUtil, objectOutputType, UnknownKeysParam, z, ZodStringCheck } from 'zod';
|
|
7
2
|
export type ZodStringCheckAugmented = ZodStringCheck | {
|
|
8
3
|
kind: 'password';
|
|
9
4
|
message?: string;
|
|
@@ -22,6 +17,9 @@ export type ZodOpenAPIMetadata = {
|
|
|
22
17
|
};
|
|
23
18
|
};
|
|
24
19
|
declare module 'zod' {
|
|
20
|
+
interface ZodSchema<Output = any, Def extends ZodTypeDef = ZodTypeDef, Input = Output> {
|
|
21
|
+
openapi<T extends ZodSchema<Output, Def, Input>>(this: T, metadata: ZodOpenAPIMetadata): T;
|
|
22
|
+
}
|
|
25
23
|
interface ZodTypeDef {
|
|
26
24
|
metadata?: ZodOpenAPIMetadata;
|
|
27
25
|
}
|
|
@@ -29,9 +27,6 @@ declare module 'zod' {
|
|
|
29
27
|
metadata?: ZodOpenAPIMetadata;
|
|
30
28
|
mergedSchemas?: ZodType<any, any, any>[];
|
|
31
29
|
}
|
|
32
|
-
interface ZodType<Output = any, Def extends ZodTypeDef = ZodTypeDef, Input = Output> {
|
|
33
|
-
openapi(metadata: ZodOpenAPIMetadata): this;
|
|
34
|
-
}
|
|
35
30
|
interface ZodObject<T extends ZodRawShape, UnknownKeys extends UnknownKeysParam = UnknownKeysParam, Catchall extends ZodTypeAny = ZodTypeAny, Output = objectOutputType<T, Catchall, UnknownKeys>, Input = objectInputType<T, Catchall, UnknownKeys>> {
|
|
36
31
|
merge<Incoming extends AnyZodObject, Augmentation extends Incoming['shape']>(this: this, other: Incoming): ZodObject<objectUtil.extendShape<T, Augmentation>, Incoming['_def']['unknownKeys'], Incoming['_def']['catchall']>;
|
|
37
32
|
}
|
|
@@ -40,6 +35,8 @@ declare module 'zod' {
|
|
|
40
35
|
_addCheck(check: ZodStringCheckAugmented): this;
|
|
41
36
|
}
|
|
42
37
|
}
|
|
43
|
-
export declare
|
|
38
|
+
export declare function extendApi<T extends ZodType<any, any, any>>(schema: T, schemaObject?: ZodOpenAPIMetadata): T;
|
|
39
|
+
export declare function extendZodWithOpenApi(zod: typeof z, forceOverride?: boolean): void;
|
|
40
|
+
export declare const ZodRecord: <KeyType extends string, ZodValueType extends z.ZodTypeAny>(keys: KeyType[], zodValueType: ZodValueType) => ZodObject<Record<KeyType, ZodValueType>, "strip", ZodTypeAny, objectUtil.addQuestionMarks<z.baseObjectOutputType<Record<KeyType, ZodValueType>>, any> extends infer T ? { [k in keyof T]: objectUtil.addQuestionMarks<z.baseObjectOutputType<Record<KeyType, ZodValueType>>, any>[k]; } : never, z.baseObjectInputType<Record<KeyType, ZodValueType>> extends infer T_1 ? { [k_1 in keyof T_1]: z.baseObjectInputType<Record<KeyType, ZodValueType>>[k_1]; } : never>;
|
|
44
41
|
export declare function extendZodWithOpenAPI<T extends z.ZodTypeAny>(schema: T, metadata: ZodOpenAPIMetadata): T;
|
|
45
42
|
//# sourceMappingURL=zod.extension.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zod.extension.d.ts","sourceRoot":"","sources":["../../src/openapi/zod.extension.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"zod.extension.d.ts","sourceRoot":"","sources":["../../src/openapi/zod.extension.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,26 +1,57 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ZodRecord = void 0;
|
|
4
|
+
exports.extendApi = extendApi;
|
|
5
|
+
exports.extendZodWithOpenApi = extendZodWithOpenApi;
|
|
4
6
|
exports.extendZodWithOpenAPI = extendZodWithOpenAPI;
|
|
5
7
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
6
8
|
const zod_1 = require("zod");
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
function extendApi(schema, schemaObject = {}) {
|
|
10
|
+
const This = schema.constructor;
|
|
11
|
+
const newSchema = new This(schema._def);
|
|
12
|
+
newSchema._def.metadata = Object.assign({}, schema._def.metadata || {}, schemaObject);
|
|
13
|
+
return newSchema;
|
|
14
|
+
}
|
|
15
|
+
function extendZodWithOpenApi(zod, forceOverride = false) {
|
|
16
|
+
if (forceOverride || typeof zod.ZodType.prototype.openapi === 'undefined') {
|
|
17
|
+
zod.ZodType.prototype.openapi = function (metadata) {
|
|
18
|
+
this._def.metadata = metadata;
|
|
19
|
+
return extendApi(this, metadata);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (forceOverride || typeof zod.ZodObject.prototype.merge === 'undefined') {
|
|
23
|
+
const originalMerge = zod.ZodObject.prototype.merge;
|
|
24
|
+
zod.ZodObject.prototype.merge = function (other) {
|
|
25
|
+
const merged = originalMerge.apply(this, [other]);
|
|
26
|
+
merged._def.mergedSchemas = [this, other];
|
|
27
|
+
return merged;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (forceOverride ||
|
|
31
|
+
typeof zod.ZodString.prototype._addCheck === 'undefined') {
|
|
32
|
+
const originalStringCheck = zod_1.ZodString.prototype._addCheck;
|
|
33
|
+
zod_1.ZodString.prototype._addCheck = function (check) {
|
|
34
|
+
return originalStringCheck.call(this, check);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (forceOverride ||
|
|
38
|
+
typeof zod.ZodString.prototype.password === 'undefined') {
|
|
39
|
+
zod_1.ZodString.prototype.password = function () {
|
|
40
|
+
return this._addCheck({ kind: 'password' });
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const originalMerge = zod_1.ZodObject.prototype.merge;
|
|
45
|
+
zod_1.ZodObject.prototype.merge = function (other) {
|
|
15
46
|
const merged = originalMerge.apply(this, [other]);
|
|
16
47
|
merged._def.mergedSchemas = [this, other];
|
|
17
48
|
return merged;
|
|
18
49
|
};
|
|
19
|
-
const originalStringCheck =
|
|
20
|
-
|
|
50
|
+
const originalStringCheck = zod_1.ZodString.prototype._addCheck;
|
|
51
|
+
zod_1.ZodString.prototype._addCheck = function (check) {
|
|
21
52
|
return originalStringCheck.call(this, check);
|
|
22
53
|
};
|
|
23
|
-
|
|
54
|
+
zod_1.ZodString.prototype.password = function () {
|
|
24
55
|
return this._addCheck({ kind: 'password' });
|
|
25
56
|
};
|
|
26
57
|
const ZodRecord = (keys, zodValueType) => zod_1.z.object(keys.reduce((agg, k) => (Object.assign(Object.assign({}, agg), { [k]: zodValueType })), {}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zod.extension.js","sourceRoot":"","sources":["../../src/openapi/zod.extension.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"zod.extension.js","sourceRoot":"","sources":["../../src/openapi/zod.extension.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@origins-digital/zod-openapi-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Origins Zod OpenAPI Utils",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.d.ts",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
-
"sideEffects": [
|
|
9
|
-
"./dist/openapi/zod.extension.js"
|
|
10
|
-
],
|
|
11
8
|
"author": "Origins Digital (https://www.origins-digital.com/)",
|
|
12
9
|
"license": "MIT",
|
|
13
10
|
"exports": {
|