@orpc/zod 2.0.0-beta.46 → 2.0.0-beta.48
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 +6 -4
- package/dist/converter.d.mts +30 -0
- package/dist/converter.mjs +118 -0
- package/dist/index.d.mts +3 -98
- package/dist/index.mjs +2 -97
- package/dist/registries.d.mts +62 -0
- package/dist/registries.mjs +7 -0
- package/package.json +3 -3
- package/dist/index.d.ts +0 -98
package/README.md
CHANGED
|
@@ -156,10 +156,11 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
156
156
|
<td align="center"><a href="https://github.com/christ12938?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="christ12938"><img src="https://avatars.githubusercontent.com/u/25758598?v=4" width="167" alt="christ12938"/><br />christ12938</a></td>
|
|
157
157
|
<td align="center"><a href="https://github.com/Ryanjso?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ryan Soderberg"><img src="https://avatars.githubusercontent.com/u/39172778?u=5ed913c31d57e7221b75784abcad48c7ebddde27&v=4" width="167" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
|
|
158
158
|
<td align="center"><a href="https://github.com/itigoore01?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="shota"><img src="https://avatars.githubusercontent.com/u/11831107?u=c976a6dc7e055eb026304c46c99100ed22b0c8e0&v=4" width="167" alt="shota"/><br />shota</a></td>
|
|
159
|
+
<td align="center"><a href="https://github.com/Nic13Gamer?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Nicholas"><img src="https://avatars.githubusercontent.com/u/54724556?u=56a7ab430ce7a80d648ab6eba051d454a818ed0b&v=4" width="167" alt="Nicholas"/><br />Nicholas</a></td>
|
|
159
160
|
<td align="center"><a href="https://github.com/ellis-driscoll?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ellis Driscoll"><img src="https://avatars.githubusercontent.com/u/70685966?u=c5f95bc33b5991d9744abe00052542e4a2ed3cb9&v=4" width="167" alt="Ellis Driscoll"/><br />Ellis Driscoll</a></td>
|
|
160
|
-
<td align="center"><a href="https://github.com/hoangbn?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Hoang Nguyen"><img src="https://avatars.githubusercontent.com/u/38968280?u=c90084c6de65c56facabab7ba13a72a49ddbc3e4&v=4" width="167" alt="Hoang Nguyen"/><br />Hoang Nguyen</a></td>
|
|
161
161
|
</tr>
|
|
162
162
|
<tr>
|
|
163
|
+
<td align="center"><a href="https://github.com/hoangbn?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Hoang Nguyen"><img src="https://avatars.githubusercontent.com/u/38968280?u=c90084c6de65c56facabab7ba13a72a49ddbc3e4&v=4" width="167" alt="Hoang Nguyen"/><br />Hoang Nguyen</a></td>
|
|
163
164
|
<td align="center"><a href="https://opencollective.com/guest-ac41de3b?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Orestis Ioannou"><img src="https://images.opencollective.com/guest-ac41de3b/avatar/460.png" width="167" alt="Orestis Ioannou"/><br />Orestis Ioannou</a></td>
|
|
164
165
|
<td align="center"><a href="https://automatio.ai/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Stefan Smiljkovic"><img src="https://avatars.githubusercontent.com/u/1984909?u=b7bf5bc40ed49df3c22f69d2da7b8d78709c49ed&v=4" width="167" alt="Stefan Smiljkovic"/><br />Stefan Smiljkovic</a></td>
|
|
165
166
|
</tr>
|
|
@@ -190,10 +191,9 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
190
191
|
<td align="center"><a href="https://kellychan.im/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&v=4" width="139" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
|
|
191
192
|
<td align="center"><a href="https://guyariely.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guy Ariely"><img src="https://avatars.githubusercontent.com/u/42813496?u=edb6b7f563bf28e160a290832e7da57c0506f8ca&v=4" width="139" alt="Guy Ariely"/><br />Guy Ariely</a></td>
|
|
192
193
|
<td align="center"><a href="https://paulsenon.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="PaulSenon"><img src="https://avatars.githubusercontent.com/u/19531087?u=6385741eb91d200b8c513ec6045482e301767ca6&v=4" width="139" alt="PaulSenon"/><br />PaulSenon</a></td>
|
|
193
|
-
<td align="center"><a href="https://
|
|
194
|
+
<td align="center"><a href="https://piscis.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&v=4" width="139" alt="Alex"/><br />Alex</a></td>
|
|
194
195
|
</tr>
|
|
195
196
|
<tr>
|
|
196
|
-
<td align="center"><a href="https://piscis.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&v=4" width="139" alt="Alex"/><br />Alex</a></td>
|
|
197
197
|
<td align="center"><a href="https://opensource.gubanov.eu/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Andrey Gubanov"><img src="https://avatars.githubusercontent.com/u/1082083?u=c5f2daf7ebece498e85c83367bb37b4e10e2649d&v=4" width="139" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
|
|
198
198
|
</tr>
|
|
199
199
|
</table>
|
|
@@ -206,7 +206,9 @@ With thanks to [40 past sponsors](https://orpc.dev/sponsors#past-sponsors) who h
|
|
|
206
206
|
|
|
207
207
|
<table>
|
|
208
208
|
<tr>
|
|
209
|
-
<td align="center"><a href="https://claude.com/contact-sales/claude-for-oss" target="_blank" rel="noopener" title="Claude for Open Source"><img src="https://cdn.simpleicons.org/claude" width="64" alt="Claude"/><br />Claude
|
|
209
|
+
<td align="center"><a href="https://claude.com/contact-sales/claude-for-oss" target="_blank" rel="noopener" title="Claude for Open Source"><img src="https://cdn.simpleicons.org/claude" width="64" alt="Claude"/><br />Claude</a></td>
|
|
210
|
+
<td align="center"><a href="https://pullfrog.com/for-oss" target="_blank" rel="noopener" title="Pullfrog for OSS"><img src="https://avatars.githubusercontent.com/in/1768019?s=128&v=4" width="64" alt="Pullfrog"/><br />Pullfrog</a></td>
|
|
211
|
+
<td align="center"><a href="https://macroscope.com/open-source" target="_blank" rel="noopener" title="Macroscope for Open Source"><img src="https://avatars.githubusercontent.com/in/900172?s=128&v=4" width="64" alt="Macroscope"/><br />Macroscope</a></td>
|
|
210
212
|
</tr>
|
|
211
213
|
</table>
|
|
212
214
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AnySchema, JsonSchema, JsonSchemaConverter, JsonSchemaConverterDirection } from "@orpc/json-schema";
|
|
2
|
+
import type { ToJSONSchemaParams } from "zod/v4/core";
|
|
3
|
+
export interface ZodToJsonSchemaConverterOptions extends Omit<ToJSONSchemaParams, "target" | "io"> {
|
|
4
|
+
/**
|
|
5
|
+
* Caches conversion results in a WeakMap keyed by the Zod schema instance,
|
|
6
|
+
* so converting the same schema again is free.
|
|
7
|
+
*
|
|
8
|
+
* When enabled, repeated conversions return the same JSON schema object,
|
|
9
|
+
* so treat returned schemas as immutable.
|
|
10
|
+
*
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
cache?: boolean | undefined;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Converts Zod schemas into JSON Schema using Zod's built-in `toJSONSchema`,
|
|
17
|
+
* with additional support for types such as `z.bigint()`, `z.date()`, `z.set()`, and `z.map()`.
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
20
|
+
*/
|
|
21
|
+
export declare class ZodToJsonSchemaConverter implements JsonSchemaConverter {
|
|
22
|
+
private readonly toJSONSchemaParams;
|
|
23
|
+
private readonly cache;
|
|
24
|
+
constructor({ cache, ...toJSONSchemaParams }?: ZodToJsonSchemaConverterOptions);
|
|
25
|
+
condition(schema: AnySchema | undefined, _direction: JsonSchemaConverterDirection): boolean;
|
|
26
|
+
convert(schema: AnySchema | undefined, direction: JsonSchemaConverterDirection): [jsonSchema: JsonSchema, optional: boolean];
|
|
27
|
+
private convertUncached;
|
|
28
|
+
private convertZod;
|
|
29
|
+
private getCustomJsonSchema;
|
|
30
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { isStandardSchemaOptional, JsonSchemaFormat, JsonSchemaXNativeType } from "@orpc/json-schema";
|
|
2
|
+
import { process as processZodSchema, toJSONSchema } from "zod/v4/core";
|
|
3
|
+
import { JSON_SCHEMA_INPUT_REGISTRY, JSON_SCHEMA_OUTPUT_REGISTRY, JSON_SCHEMA_REGISTRY } from "./registries.mjs";
|
|
4
|
+
|
|
5
|
+
export class ZodToJsonSchemaConverter {
|
|
6
|
+
toJSONSchemaParams;
|
|
7
|
+
cache;
|
|
8
|
+
constructor({ cache, ...toJSONSchemaParams } = {}) {
|
|
9
|
+
this.toJSONSchemaParams = toJSONSchemaParams;
|
|
10
|
+
if (cache) {
|
|
11
|
+
this.cache = {
|
|
12
|
+
input: new WeakMap(),
|
|
13
|
+
output: new WeakMap()
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
condition(schema, _direction) {
|
|
18
|
+
return schema?.["~standard"].vendor === "zod";
|
|
19
|
+
}
|
|
20
|
+
convert(schema, direction) {
|
|
21
|
+
const zodSchema = schema;
|
|
22
|
+
if (this.cache) {
|
|
23
|
+
const cached = this.cache[direction].get(zodSchema);
|
|
24
|
+
if (cached) {
|
|
25
|
+
return cached;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const result = this.convertUncached(zodSchema, direction);
|
|
29
|
+
if (this.cache) {
|
|
30
|
+
this.cache[direction].set(zodSchema, result);
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
convertUncached(zodSchema, direction) {
|
|
35
|
+
const jsonSchema = this.convertZod(zodSchema, direction);
|
|
36
|
+
return [jsonSchema, isStandardSchemaOptional(zodSchema, direction)];
|
|
37
|
+
}
|
|
38
|
+
convertZod(schema, direction) {
|
|
39
|
+
const { unrepresentable = "any" } = this.toJSONSchemaParams;
|
|
40
|
+
const jsonSchema = toJSONSchema(schema, {
|
|
41
|
+
...this.toJSONSchemaParams,
|
|
42
|
+
target: "draft-2020-12",
|
|
43
|
+
io: direction,
|
|
44
|
+
unrepresentable(info) {
|
|
45
|
+
return convertNativeType(this, info.zodSchema, info.path) ?? (typeof unrepresentable === "function" ? unrepresentable(info) : unrepresentable);
|
|
46
|
+
},
|
|
47
|
+
override: (ctx) => {
|
|
48
|
+
const customJsonSchema = this.getCustomJsonSchema(ctx.zodSchema, direction);
|
|
49
|
+
if (customJsonSchema) {
|
|
50
|
+
Object.assign(ctx.jsonSchema, customJsonSchema);
|
|
51
|
+
}
|
|
52
|
+
this.toJSONSchemaParams.override?.(ctx);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
const { $schema, ...rest } = jsonSchema;
|
|
58
|
+
return rest;
|
|
59
|
+
}
|
|
60
|
+
getCustomJsonSchema(schema, direction) {
|
|
61
|
+
const general = JSON_SCHEMA_REGISTRY.get(schema);
|
|
62
|
+
const directional = direction === "input" ? JSON_SCHEMA_INPUT_REGISTRY.get(schema) : JSON_SCHEMA_OUTPUT_REGISTRY.get(schema);
|
|
63
|
+
if (general === undefined && directional === undefined) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
...general,
|
|
68
|
+
...directional
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function convertNativeType(ctx, zodSchema, path) {
|
|
73
|
+
const def = zodSchema._zod.def;
|
|
74
|
+
switch (def.type) {
|
|
75
|
+
case "bigint": return {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"pattern": "^-?[0-9]+$",
|
|
78
|
+
"x-native-type": JsonSchemaXNativeType.BigInt
|
|
79
|
+
};
|
|
80
|
+
case "date": return {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"format": JsonSchemaFormat.DateTime,
|
|
83
|
+
"x-native-type": JsonSchemaXNativeType.Date
|
|
84
|
+
};
|
|
85
|
+
case "set":
|
|
86
|
+
case "map": {
|
|
87
|
+
const schemaPath = [];
|
|
88
|
+
for (const [seenSchema, seen] of ctx.seen) {
|
|
89
|
+
if (seen.path && seen.path.length <= path.length && seen.path.every((segment, i) => segment === path[i])) {
|
|
90
|
+
schemaPath.push(seenSchema);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const processItems = (schema, ...segments) => processZodSchema(schema, ctx, {
|
|
94
|
+
path: [
|
|
95
|
+
...path,
|
|
96
|
+
"items",
|
|
97
|
+
...segments
|
|
98
|
+
],
|
|
99
|
+
schemaPath
|
|
100
|
+
});
|
|
101
|
+
return def.type === "set" ? {
|
|
102
|
+
"type": "array",
|
|
103
|
+
"uniqueItems": true,
|
|
104
|
+
"items": processItems(def.valueType),
|
|
105
|
+
"x-native-type": JsonSchemaXNativeType.Set
|
|
106
|
+
} : {
|
|
107
|
+
"type": "array",
|
|
108
|
+
"items": {
|
|
109
|
+
type: "array",
|
|
110
|
+
prefixItems: [processItems(def.keyType, "prefixItems", 0), processItems(def.valueType, "prefixItems", 1)],
|
|
111
|
+
maxItems: 2,
|
|
112
|
+
minItems: 2
|
|
113
|
+
},
|
|
114
|
+
"x-native-type": JsonSchemaXNativeType.Map
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,98 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
import { ToJSONSchemaParams, $input, $output } from 'zod/v4/core';
|
|
5
|
-
import * as _openapi_spec_types_v3_2 from '@openapi-spec/types/v3.2';
|
|
6
|
-
|
|
7
|
-
interface ZodToJsonSchemaConverterOptions extends Omit<ToJSONSchemaParams, 'target' | 'io'> {
|
|
8
|
-
/**
|
|
9
|
-
* Caches conversion results in a WeakMap keyed by the Zod schema instance,
|
|
10
|
-
* so converting the same schema again is free.
|
|
11
|
-
*
|
|
12
|
-
* When enabled, repeated conversions return the same JSON schema object,
|
|
13
|
-
* so treat returned schemas as immutable.
|
|
14
|
-
*
|
|
15
|
-
* @default false
|
|
16
|
-
*/
|
|
17
|
-
cache?: boolean | undefined;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Converts Zod schemas into JSON Schema using Zod's built-in `toJSONSchema`,
|
|
21
|
-
* with additional support for types such as `z.bigint()`, `z.date()`, `z.set()`, and `z.map()`.
|
|
22
|
-
*
|
|
23
|
-
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
24
|
-
*/
|
|
25
|
-
declare class ZodToJsonSchemaConverter implements JsonSchemaConverter {
|
|
26
|
-
private readonly toJSONSchemaParams;
|
|
27
|
-
private readonly cache;
|
|
28
|
-
constructor({ cache, ...toJSONSchemaParams }?: ZodToJsonSchemaConverterOptions);
|
|
29
|
-
condition(schema: AnySchema | undefined, _direction: JsonSchemaConverterDirection): boolean;
|
|
30
|
-
convert(schema: AnySchema | undefined, direction: JsonSchemaConverterDirection): [jsonSchema: JsonSchema, optional: boolean];
|
|
31
|
-
private convertUncached;
|
|
32
|
-
private convertZod;
|
|
33
|
-
private getCustomJsonSchema;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Zod registry for customizing generated JSON schema, can use both for .input and .output
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```ts
|
|
41
|
-
* import { JSON_SCHEMA_REGISTRY } from '@orpc/zod'
|
|
42
|
-
*
|
|
43
|
-
* const user = z.object({
|
|
44
|
-
* name: z.string(),
|
|
45
|
-
* age: z.number(),
|
|
46
|
-
* })
|
|
47
|
-
*
|
|
48
|
-
* JSON_SCHEMA_REGISTRY.add(user, {
|
|
49
|
-
* examples: [{ name: 'John', age: 20 }],
|
|
50
|
-
* })
|
|
51
|
-
* ```
|
|
52
|
-
*
|
|
53
|
-
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
54
|
-
*/
|
|
55
|
-
declare const JSON_SCHEMA_REGISTRY: zod_v4_core.$ZodRegistry<_openapi_spec_types_v3_2.SchemaObjectFields<typeof $input | typeof $output>, zod_v4_core.$ZodType<unknown, unknown, zod_v4_core.$ZodTypeInternals<unknown, unknown>>>;
|
|
56
|
-
/**
|
|
57
|
-
* Zod registry for customizing generated JSON schema, only useful for .input
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```ts
|
|
61
|
-
* import { JSON_SCHEMA_INPUT_REGISTRY } from '@orpc/zod'
|
|
62
|
-
*
|
|
63
|
-
* const user = z.object({
|
|
64
|
-
* name: z.string(),
|
|
65
|
-
* age: z.string().transform(v => Number(v)),
|
|
66
|
-
* })
|
|
67
|
-
*
|
|
68
|
-
* JSON_SCHEMA_INPUT_REGISTRY.add(user, {
|
|
69
|
-
* examples: [{ name: 'John', age: "20" }],
|
|
70
|
-
* })
|
|
71
|
-
* ```
|
|
72
|
-
*
|
|
73
|
-
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
74
|
-
*/
|
|
75
|
-
declare const JSON_SCHEMA_INPUT_REGISTRY: zod_v4_core.$ZodRegistry<_openapi_spec_types_v3_2.SchemaObjectFields<typeof $input>, zod_v4_core.$ZodType<unknown, unknown, zod_v4_core.$ZodTypeInternals<unknown, unknown>>>;
|
|
76
|
-
/**
|
|
77
|
-
* Zod registry for customizing generated JSON schema, only useful for .output
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* import { JSON_SCHEMA_OUTPUT_REGISTRY } from '@orpc/zod'
|
|
82
|
-
*
|
|
83
|
-
* const user = z.object({
|
|
84
|
-
* name: z.string(),
|
|
85
|
-
* age: z.string().transform(v => Number(v)),
|
|
86
|
-
* })
|
|
87
|
-
*
|
|
88
|
-
* JSON_SCHEMA_OUTPUT_REGISTRY.add(user, {
|
|
89
|
-
* examples: [{ name: 'John', age: 20 }],
|
|
90
|
-
* })
|
|
91
|
-
* ```
|
|
92
|
-
*
|
|
93
|
-
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
94
|
-
*/
|
|
95
|
-
declare const JSON_SCHEMA_OUTPUT_REGISTRY: zod_v4_core.$ZodRegistry<_openapi_spec_types_v3_2.SchemaObjectFields<typeof $output>, zod_v4_core.$ZodType<unknown, unknown, zod_v4_core.$ZodTypeInternals<unknown, unknown>>>;
|
|
96
|
-
|
|
97
|
-
export { JSON_SCHEMA_INPUT_REGISTRY, JSON_SCHEMA_OUTPUT_REGISTRY, JSON_SCHEMA_REGISTRY, ZodToJsonSchemaConverter };
|
|
98
|
-
export type { ZodToJsonSchemaConverterOptions };
|
|
1
|
+
export * from "./converter.mjs";
|
|
2
|
+
export * from "./registries.mjs";
|
|
3
|
+
export type { JsonSchema } from "@orpc/json-schema";
|
package/dist/index.mjs
CHANGED
|
@@ -1,97 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const JSON_SCHEMA_REGISTRY = registry();
|
|
5
|
-
const JSON_SCHEMA_INPUT_REGISTRY = registry();
|
|
6
|
-
const JSON_SCHEMA_OUTPUT_REGISTRY = registry();
|
|
7
|
-
|
|
8
|
-
class ZodToJsonSchemaConverter {
|
|
9
|
-
toJSONSchemaParams;
|
|
10
|
-
cache;
|
|
11
|
-
constructor({ cache, ...toJSONSchemaParams } = {}) {
|
|
12
|
-
this.toJSONSchemaParams = toJSONSchemaParams;
|
|
13
|
-
if (cache) {
|
|
14
|
-
this.cache = { input: /* @__PURE__ */ new WeakMap(), output: /* @__PURE__ */ new WeakMap() };
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
condition(schema, _direction) {
|
|
18
|
-
return schema?.["~standard"].vendor === "zod";
|
|
19
|
-
}
|
|
20
|
-
convert(schema, direction) {
|
|
21
|
-
const zodSchema = schema;
|
|
22
|
-
if (this.cache) {
|
|
23
|
-
const cached = this.cache[direction].get(zodSchema);
|
|
24
|
-
if (cached) {
|
|
25
|
-
return cached;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
const result = this.convertUncached(zodSchema, direction);
|
|
29
|
-
if (this.cache) {
|
|
30
|
-
this.cache[direction].set(zodSchema, result);
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
}
|
|
34
|
-
convertUncached(zodSchema, direction) {
|
|
35
|
-
const jsonSchema = this.convertZod(zodSchema, direction);
|
|
36
|
-
return [jsonSchema, isStandardSchemaOptional(zodSchema, direction)];
|
|
37
|
-
}
|
|
38
|
-
convertZod(schema, direction) {
|
|
39
|
-
const { unrepresentable = "any" } = this.toJSONSchemaParams;
|
|
40
|
-
const jsonSchema = toJSONSchema(schema, {
|
|
41
|
-
...this.toJSONSchemaParams,
|
|
42
|
-
target: "draft-2020-12",
|
|
43
|
-
io: direction,
|
|
44
|
-
unrepresentable(info) {
|
|
45
|
-
return convertNativeType(this, info.zodSchema, info.path) ?? (typeof unrepresentable === "function" ? unrepresentable(info) : unrepresentable);
|
|
46
|
-
},
|
|
47
|
-
override: (ctx) => {
|
|
48
|
-
const customJsonSchema = this.getCustomJsonSchema(ctx.zodSchema, direction);
|
|
49
|
-
if (customJsonSchema) {
|
|
50
|
-
Object.assign(ctx.jsonSchema, customJsonSchema);
|
|
51
|
-
}
|
|
52
|
-
this.toJSONSchemaParams.override?.(ctx);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
const { $schema, ...rest } = jsonSchema;
|
|
56
|
-
return rest;
|
|
57
|
-
}
|
|
58
|
-
getCustomJsonSchema(schema, direction) {
|
|
59
|
-
const general = JSON_SCHEMA_REGISTRY.get(schema);
|
|
60
|
-
const directional = direction === "input" ? JSON_SCHEMA_INPUT_REGISTRY.get(schema) : JSON_SCHEMA_OUTPUT_REGISTRY.get(schema);
|
|
61
|
-
if (general === void 0 && directional === void 0) {
|
|
62
|
-
return void 0;
|
|
63
|
-
}
|
|
64
|
-
return { ...general, ...directional };
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function convertNativeType(ctx, zodSchema, path) {
|
|
68
|
-
const def = zodSchema._zod.def;
|
|
69
|
-
switch (def.type) {
|
|
70
|
-
case "bigint":
|
|
71
|
-
return { "type": "string", "pattern": "^-?[0-9]+$", "x-native-type": JsonSchemaXNativeType.BigInt };
|
|
72
|
-
case "date":
|
|
73
|
-
return { "type": "string", "format": JsonSchemaFormat.DateTime, "x-native-type": JsonSchemaXNativeType.Date };
|
|
74
|
-
case "set":
|
|
75
|
-
case "map": {
|
|
76
|
-
const schemaPath = [];
|
|
77
|
-
for (const [seenSchema, seen] of ctx.seen) {
|
|
78
|
-
if (seen.path && seen.path.length <= path.length && seen.path.every((segment, i) => segment === path[i])) {
|
|
79
|
-
schemaPath.push(seenSchema);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
const processItems = (schema, ...segments) => process(schema, ctx, { path: [...path, "items", ...segments], schemaPath });
|
|
83
|
-
return def.type === "set" ? { "type": "array", "uniqueItems": true, "items": processItems(def.valueType), "x-native-type": JsonSchemaXNativeType.Set } : {
|
|
84
|
-
"type": "array",
|
|
85
|
-
"items": {
|
|
86
|
-
type: "array",
|
|
87
|
-
prefixItems: [processItems(def.keyType, "prefixItems", 0), processItems(def.valueType, "prefixItems", 1)],
|
|
88
|
-
maxItems: 2,
|
|
89
|
-
minItems: 2
|
|
90
|
-
},
|
|
91
|
-
"x-native-type": JsonSchemaXNativeType.Map
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export { JSON_SCHEMA_INPUT_REGISTRY, JSON_SCHEMA_OUTPUT_REGISTRY, JSON_SCHEMA_REGISTRY, ZodToJsonSchemaConverter };
|
|
1
|
+
export * from "./converter.mjs";
|
|
2
|
+
export * from "./registries.mjs";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { JsonSchema } from "@orpc/json-schema";
|
|
2
|
+
import type { $input, $output, $ZodRegistry } from "zod/v4/core";
|
|
3
|
+
/**
|
|
4
|
+
* Zod registry for customizing generated JSON schema, can use both for .input and .output
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { JSON_SCHEMA_REGISTRY } from '@orpc/zod'
|
|
9
|
+
*
|
|
10
|
+
* const user = z.object({
|
|
11
|
+
* name: z.string(),
|
|
12
|
+
* age: z.number(),
|
|
13
|
+
* })
|
|
14
|
+
*
|
|
15
|
+
* JSON_SCHEMA_REGISTRY.add(user, {
|
|
16
|
+
* examples: [{ name: 'John', age: 20 }],
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
21
|
+
*/
|
|
22
|
+
export declare const JSON_SCHEMA_REGISTRY: $ZodRegistry<Exclude<JsonSchema<$input | $output>, boolean>>;
|
|
23
|
+
/**
|
|
24
|
+
* Zod registry for customizing generated JSON schema, only useful for .input
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { JSON_SCHEMA_INPUT_REGISTRY } from '@orpc/zod'
|
|
29
|
+
*
|
|
30
|
+
* const user = z.object({
|
|
31
|
+
* name: z.string(),
|
|
32
|
+
* age: z.string().transform(v => Number(v)),
|
|
33
|
+
* })
|
|
34
|
+
*
|
|
35
|
+
* JSON_SCHEMA_INPUT_REGISTRY.add(user, {
|
|
36
|
+
* examples: [{ name: 'John', age: "20" }],
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
41
|
+
*/
|
|
42
|
+
export declare const JSON_SCHEMA_INPUT_REGISTRY: $ZodRegistry<Exclude<JsonSchema<$input>, boolean>>;
|
|
43
|
+
/**
|
|
44
|
+
* Zod registry for customizing generated JSON schema, only useful for .output
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { JSON_SCHEMA_OUTPUT_REGISTRY } from '@orpc/zod'
|
|
49
|
+
*
|
|
50
|
+
* const user = z.object({
|
|
51
|
+
* name: z.string(),
|
|
52
|
+
* age: z.string().transform(v => Number(v)),
|
|
53
|
+
* })
|
|
54
|
+
*
|
|
55
|
+
* JSON_SCHEMA_OUTPUT_REGISTRY.add(user, {
|
|
56
|
+
* examples: [{ name: 'John', age: 20 }],
|
|
57
|
+
* })
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
61
|
+
*/
|
|
62
|
+
export declare const JSON_SCHEMA_OUTPUT_REGISTRY: $ZodRegistry<Exclude<JsonSchema<$output>, boolean>>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orpc/zod",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.48",
|
|
5
5
|
"description": "Zod integration for oRPC: convert Zod schemas into JSON Schema for OpenAPI generation",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": [
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"zod": ">=4.5.0"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@openapi-spec/types": "~0.
|
|
43
|
-
"@orpc/json-schema": "2.0.0-beta.
|
|
42
|
+
"@openapi-spec/types": "~0.6.0",
|
|
43
|
+
"@orpc/json-schema": "2.0.0-beta.48"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"zod": "^4.6.7"
|
package/dist/index.d.ts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { JsonSchemaConverter, AnySchema, JsonSchemaConverterDirection, JsonSchema } from '@orpc/json-schema';
|
|
2
|
-
export { JsonSchema } from '@orpc/json-schema';
|
|
3
|
-
import * as zod_v4_core from 'zod/v4/core';
|
|
4
|
-
import { ToJSONSchemaParams, $input, $output } from 'zod/v4/core';
|
|
5
|
-
import * as _openapi_spec_types_v3_2 from '@openapi-spec/types/v3.2';
|
|
6
|
-
|
|
7
|
-
interface ZodToJsonSchemaConverterOptions extends Omit<ToJSONSchemaParams, 'target' | 'io'> {
|
|
8
|
-
/**
|
|
9
|
-
* Caches conversion results in a WeakMap keyed by the Zod schema instance,
|
|
10
|
-
* so converting the same schema again is free.
|
|
11
|
-
*
|
|
12
|
-
* When enabled, repeated conversions return the same JSON schema object,
|
|
13
|
-
* so treat returned schemas as immutable.
|
|
14
|
-
*
|
|
15
|
-
* @default false
|
|
16
|
-
*/
|
|
17
|
-
cache?: boolean | undefined;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Converts Zod schemas into JSON Schema using Zod's built-in `toJSONSchema`,
|
|
21
|
-
* with additional support for types such as `z.bigint()`, `z.date()`, `z.set()`, and `z.map()`.
|
|
22
|
-
*
|
|
23
|
-
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
24
|
-
*/
|
|
25
|
-
declare class ZodToJsonSchemaConverter implements JsonSchemaConverter {
|
|
26
|
-
private readonly toJSONSchemaParams;
|
|
27
|
-
private readonly cache;
|
|
28
|
-
constructor({ cache, ...toJSONSchemaParams }?: ZodToJsonSchemaConverterOptions);
|
|
29
|
-
condition(schema: AnySchema | undefined, _direction: JsonSchemaConverterDirection): boolean;
|
|
30
|
-
convert(schema: AnySchema | undefined, direction: JsonSchemaConverterDirection): [jsonSchema: JsonSchema, optional: boolean];
|
|
31
|
-
private convertUncached;
|
|
32
|
-
private convertZod;
|
|
33
|
-
private getCustomJsonSchema;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Zod registry for customizing generated JSON schema, can use both for .input and .output
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```ts
|
|
41
|
-
* import { JSON_SCHEMA_REGISTRY } from '@orpc/zod'
|
|
42
|
-
*
|
|
43
|
-
* const user = z.object({
|
|
44
|
-
* name: z.string(),
|
|
45
|
-
* age: z.number(),
|
|
46
|
-
* })
|
|
47
|
-
*
|
|
48
|
-
* JSON_SCHEMA_REGISTRY.add(user, {
|
|
49
|
-
* examples: [{ name: 'John', age: 20 }],
|
|
50
|
-
* })
|
|
51
|
-
* ```
|
|
52
|
-
*
|
|
53
|
-
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
54
|
-
*/
|
|
55
|
-
declare const JSON_SCHEMA_REGISTRY: zod_v4_core.$ZodRegistry<_openapi_spec_types_v3_2.SchemaObjectFields<typeof $input | typeof $output>, zod_v4_core.$ZodType<unknown, unknown, zod_v4_core.$ZodTypeInternals<unknown, unknown>>>;
|
|
56
|
-
/**
|
|
57
|
-
* Zod registry for customizing generated JSON schema, only useful for .input
|
|
58
|
-
*
|
|
59
|
-
* @example
|
|
60
|
-
* ```ts
|
|
61
|
-
* import { JSON_SCHEMA_INPUT_REGISTRY } from '@orpc/zod'
|
|
62
|
-
*
|
|
63
|
-
* const user = z.object({
|
|
64
|
-
* name: z.string(),
|
|
65
|
-
* age: z.string().transform(v => Number(v)),
|
|
66
|
-
* })
|
|
67
|
-
*
|
|
68
|
-
* JSON_SCHEMA_INPUT_REGISTRY.add(user, {
|
|
69
|
-
* examples: [{ name: 'John', age: "20" }],
|
|
70
|
-
* })
|
|
71
|
-
* ```
|
|
72
|
-
*
|
|
73
|
-
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
74
|
-
*/
|
|
75
|
-
declare const JSON_SCHEMA_INPUT_REGISTRY: zod_v4_core.$ZodRegistry<_openapi_spec_types_v3_2.SchemaObjectFields<typeof $input>, zod_v4_core.$ZodType<unknown, unknown, zod_v4_core.$ZodTypeInternals<unknown, unknown>>>;
|
|
76
|
-
/**
|
|
77
|
-
* Zod registry for customizing generated JSON schema, only useful for .output
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* import { JSON_SCHEMA_OUTPUT_REGISTRY } from '@orpc/zod'
|
|
82
|
-
*
|
|
83
|
-
* const user = z.object({
|
|
84
|
-
* name: z.string(),
|
|
85
|
-
* age: z.string().transform(v => Number(v)),
|
|
86
|
-
* })
|
|
87
|
-
*
|
|
88
|
-
* JSON_SCHEMA_OUTPUT_REGISTRY.add(user, {
|
|
89
|
-
* examples: [{ name: 'John', age: 20 }],
|
|
90
|
-
* })
|
|
91
|
-
* ```
|
|
92
|
-
*
|
|
93
|
-
* @see {@link https://orpc.dev/docs/integrations/zod | Zod Integration}
|
|
94
|
-
*/
|
|
95
|
-
declare const JSON_SCHEMA_OUTPUT_REGISTRY: zod_v4_core.$ZodRegistry<_openapi_spec_types_v3_2.SchemaObjectFields<typeof $output>, zod_v4_core.$ZodType<unknown, unknown, zod_v4_core.$ZodTypeInternals<unknown, unknown>>>;
|
|
96
|
-
|
|
97
|
-
export { JSON_SCHEMA_INPUT_REGISTRY, JSON_SCHEMA_OUTPUT_REGISTRY, JSON_SCHEMA_REGISTRY, ZodToJsonSchemaConverter };
|
|
98
|
-
export type { ZodToJsonSchemaConverterOptions };
|