@ai-sdk/provider-utils 4.0.4 → 4.0.6
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/CHANGELOG.md +14 -0
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
- package/src/__snapshots__/schema.test.ts.snap +346 -0
- package/src/add-additional-properties-to-json-schema.test.ts +289 -0
- package/src/add-additional-properties-to-json-schema.ts +53 -0
- package/src/combine-headers.ts +11 -0
- package/src/convert-async-iterator-to-readable-stream.test.ts +78 -0
- package/src/convert-async-iterator-to-readable-stream.ts +47 -0
- package/src/convert-image-model-file-to-data-uri.test.ts +85 -0
- package/src/convert-image-model-file-to-data-uri.ts +19 -0
- package/src/convert-to-form-data.test.ts +167 -0
- package/src/convert-to-form-data.ts +61 -0
- package/src/create-tool-name-mapping.test.ts +163 -0
- package/src/create-tool-name-mapping.ts +66 -0
- package/src/delay.test.ts +212 -0
- package/src/delay.ts +47 -0
- package/src/delayed-promise.test.ts +132 -0
- package/src/delayed-promise.ts +61 -0
- package/src/download-blob.test.ts +145 -0
- package/src/download-blob.ts +31 -0
- package/src/download-error.ts +39 -0
- package/src/extract-response-headers.ts +9 -0
- package/src/fetch-function.ts +4 -0
- package/src/generate-id.test.ts +31 -0
- package/src/generate-id.ts +57 -0
- package/src/get-error-message.ts +15 -0
- package/src/get-from-api.test.ts +199 -0
- package/src/get-from-api.ts +97 -0
- package/src/get-runtime-environment-user-agent.test.ts +47 -0
- package/src/get-runtime-environment-user-agent.ts +24 -0
- package/src/handle-fetch-error.ts +39 -0
- package/src/index.ts +67 -0
- package/src/inject-json-instruction.test.ts +404 -0
- package/src/inject-json-instruction.ts +63 -0
- package/src/is-abort-error.ts +8 -0
- package/src/is-async-iterable.ts +3 -0
- package/src/is-non-nullable.ts +12 -0
- package/src/is-url-supported.test.ts +282 -0
- package/src/is-url-supported.ts +40 -0
- package/src/load-api-key.ts +45 -0
- package/src/load-optional-setting.ts +30 -0
- package/src/load-setting.ts +62 -0
- package/src/maybe-promise-like.ts +3 -0
- package/src/media-type-to-extension.test.ts +26 -0
- package/src/media-type-to-extension.ts +22 -0
- package/src/normalize-headers.test.ts +64 -0
- package/src/normalize-headers.ts +38 -0
- package/src/parse-json-event-stream.ts +33 -0
- package/src/parse-json.test.ts +191 -0
- package/src/parse-json.ts +122 -0
- package/src/parse-provider-options.ts +32 -0
- package/src/post-to-api.ts +166 -0
- package/src/provider-tool-factory.ts +125 -0
- package/src/remove-undefined-entries.test.ts +57 -0
- package/src/remove-undefined-entries.ts +12 -0
- package/src/resolve.test.ts +125 -0
- package/src/resolve.ts +17 -0
- package/src/response-handler.test.ts +89 -0
- package/src/response-handler.ts +187 -0
- package/src/schema.test-d.ts +11 -0
- package/src/schema.test.ts +502 -0
- package/src/schema.ts +267 -0
- package/src/secure-json-parse.test.ts +59 -0
- package/src/secure-json-parse.ts +92 -0
- package/src/test/convert-array-to-async-iterable.ts +9 -0
- package/src/test/convert-array-to-readable-stream.ts +15 -0
- package/src/test/convert-async-iterable-to-array.ts +9 -0
- package/src/test/convert-readable-stream-to-array.ts +14 -0
- package/src/test/convert-response-stream-to-array.ts +9 -0
- package/src/test/index.ts +7 -0
- package/src/test/is-node-version.ts +4 -0
- package/src/test/mock-id.ts +8 -0
- package/src/to-json-schema/zod3-to-json-schema/LICENSE +16 -0
- package/src/to-json-schema/zod3-to-json-schema/README.md +24 -0
- package/src/to-json-schema/zod3-to-json-schema/get-relative-path.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/index.ts +1 -0
- package/src/to-json-schema/zod3-to-json-schema/options.ts +98 -0
- package/src/to-json-schema/zod3-to-json-schema/parse-def.test.ts +224 -0
- package/src/to-json-schema/zod3-to-json-schema/parse-def.ts +109 -0
- package/src/to-json-schema/zod3-to-json-schema/parse-types.ts +57 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/any.ts +5 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/array.test.ts +98 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/array.ts +38 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.test.ts +51 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.ts +44 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/boolean.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/branded.test.ts +16 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/branded.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/catch.test.ts +15 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/catch.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/date.test.ts +97 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/date.ts +64 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/default.test.ts +54 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/default.ts +14 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/effects.test.ts +41 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/effects.ts +14 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/enum.ts +13 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.test.ts +92 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.ts +52 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/literal.ts +29 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/map.test.ts +48 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/map.ts +47 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.test.ts +102 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.ts +31 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/never.ts +9 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/null.ts +9 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.test.ts +67 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.ts +42 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/number.test.ts +65 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/number.ts +44 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/object.test.ts +149 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/object.ts +88 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/optional.test.ts +147 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/optional.ts +23 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/pipe.test.ts +35 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/pipeline.ts +29 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/promise.test.ts +15 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/promise.ts +11 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.test.ts +20 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/record.test.ts +108 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/record.ts +71 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/set.test.ts +20 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/set.ts +35 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/string.test.ts +438 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/string.ts +426 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.test.ts +33 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.ts +61 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/undefined.ts +11 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/union.test.ts +226 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/union.ts +144 -0
- package/src/to-json-schema/zod3-to-json-schema/parsers/unknown.ts +7 -0
- package/src/to-json-schema/zod3-to-json-schema/refs.test.ts +919 -0
- package/src/to-json-schema/zod3-to-json-schema/refs.ts +39 -0
- package/src/to-json-schema/zod3-to-json-schema/select-parser.ts +115 -0
- package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.test.ts +862 -0
- package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.ts +93 -0
- package/src/types/assistant-model-message.ts +39 -0
- package/src/types/content-part.ts +379 -0
- package/src/types/data-content.ts +4 -0
- package/src/types/execute-tool.ts +27 -0
- package/src/types/index.ts +40 -0
- package/src/types/model-message.ts +14 -0
- package/src/types/provider-options.ts +9 -0
- package/src/types/system-model-message.ts +20 -0
- package/src/types/tool-approval-request.ts +16 -0
- package/src/types/tool-approval-response.ts +27 -0
- package/src/types/tool-call.ts +31 -0
- package/src/types/tool-model-message.ts +23 -0
- package/src/types/tool-result.ts +35 -0
- package/src/types/tool.test-d.ts +193 -0
- package/src/types/tool.ts +324 -0
- package/src/types/user-model-message.ts +22 -0
- package/src/uint8-utils.ts +26 -0
- package/src/validate-types.test.ts +105 -0
- package/src/validate-types.ts +81 -0
- package/src/version.ts +6 -0
- package/src/with-user-agent-suffix.test.ts +84 -0
- package/src/with-user-agent-suffix.ts +27 -0
- package/src/without-trailing-slash.ts +3 -0
- package/LICENSE +0 -13
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { z } from 'zod/v3';
|
|
3
|
+
import { parseDef } from './parse-def';
|
|
4
|
+
import { getRefs } from './refs';
|
|
5
|
+
import { JSONSchema7 } from '@ai-sdk/provider';
|
|
6
|
+
|
|
7
|
+
describe('parseDef', () => {
|
|
8
|
+
it('should return a proper json schema with some common types without validation', () => {
|
|
9
|
+
const zodSchema = z.object({
|
|
10
|
+
requiredString: z.string(),
|
|
11
|
+
optionalString: z.string().optional(),
|
|
12
|
+
literalString: z.literal('literalStringValue'),
|
|
13
|
+
stringArray: z.array(z.string()),
|
|
14
|
+
stringEnum: z.enum(['stringEnumOptionA', 'stringEnumOptionB']),
|
|
15
|
+
tuple: z.tuple([z.string(), z.number(), z.boolean()]),
|
|
16
|
+
record: z.record(z.boolean()),
|
|
17
|
+
requiredNumber: z.number(),
|
|
18
|
+
optionalNumber: z.number().optional(),
|
|
19
|
+
numberOrNull: z.number().nullable(),
|
|
20
|
+
numberUnion: z.union([z.literal(1), z.literal(2), z.literal(3)]),
|
|
21
|
+
mixedUnion: z.union([
|
|
22
|
+
z.literal('abc'),
|
|
23
|
+
z.literal(123),
|
|
24
|
+
z.object({ nowItGetsAnnoying: z.literal(true) }),
|
|
25
|
+
]),
|
|
26
|
+
objectOrNull: z.object({ myString: z.string() }).nullable(),
|
|
27
|
+
passthrough: z.object({ myString: z.string() }).passthrough(),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const parsedSchema = parseDef(zodSchema._def, getRefs());
|
|
31
|
+
|
|
32
|
+
expect(parsedSchema).toStrictEqual({
|
|
33
|
+
type: 'object',
|
|
34
|
+
properties: {
|
|
35
|
+
requiredString: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
},
|
|
38
|
+
optionalString: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
},
|
|
41
|
+
literalString: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
const: 'literalStringValue',
|
|
44
|
+
},
|
|
45
|
+
stringArray: {
|
|
46
|
+
type: 'array',
|
|
47
|
+
items: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
stringEnum: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
enum: ['stringEnumOptionA', 'stringEnumOptionB'],
|
|
54
|
+
},
|
|
55
|
+
tuple: {
|
|
56
|
+
type: 'array',
|
|
57
|
+
minItems: 3,
|
|
58
|
+
items: [
|
|
59
|
+
{
|
|
60
|
+
type: 'string',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
type: 'number',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
type: 'boolean',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
maxItems: 3,
|
|
70
|
+
},
|
|
71
|
+
record: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
additionalProperties: {
|
|
74
|
+
type: 'boolean',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
requiredNumber: {
|
|
78
|
+
type: 'number',
|
|
79
|
+
},
|
|
80
|
+
optionalNumber: {
|
|
81
|
+
type: 'number',
|
|
82
|
+
},
|
|
83
|
+
numberOrNull: {
|
|
84
|
+
type: ['number', 'null'],
|
|
85
|
+
},
|
|
86
|
+
numberUnion: {
|
|
87
|
+
type: 'number',
|
|
88
|
+
enum: [1, 2, 3],
|
|
89
|
+
},
|
|
90
|
+
mixedUnion: {
|
|
91
|
+
anyOf: [
|
|
92
|
+
{
|
|
93
|
+
type: 'string',
|
|
94
|
+
const: 'abc',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: 'number',
|
|
98
|
+
const: 123,
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
type: 'object',
|
|
102
|
+
properties: {
|
|
103
|
+
nowItGetsAnnoying: {
|
|
104
|
+
type: 'boolean',
|
|
105
|
+
const: true,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
required: ['nowItGetsAnnoying'],
|
|
109
|
+
additionalProperties: false,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
objectOrNull: {
|
|
114
|
+
anyOf: [
|
|
115
|
+
{
|
|
116
|
+
type: 'object',
|
|
117
|
+
properties: {
|
|
118
|
+
myString: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
required: ['myString'],
|
|
123
|
+
additionalProperties: false,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'null',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
passthrough: {
|
|
131
|
+
type: 'object',
|
|
132
|
+
properties: {
|
|
133
|
+
myString: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
required: ['myString'],
|
|
138
|
+
additionalProperties: true,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
required: [
|
|
142
|
+
'requiredString',
|
|
143
|
+
'literalString',
|
|
144
|
+
'stringArray',
|
|
145
|
+
'stringEnum',
|
|
146
|
+
'tuple',
|
|
147
|
+
'record',
|
|
148
|
+
'requiredNumber',
|
|
149
|
+
'numberOrNull',
|
|
150
|
+
'numberUnion',
|
|
151
|
+
'mixedUnion',
|
|
152
|
+
'objectOrNull',
|
|
153
|
+
'passthrough',
|
|
154
|
+
],
|
|
155
|
+
additionalProperties: false,
|
|
156
|
+
} satisfies JSONSchema7);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should handle a nullable string properly', () => {
|
|
160
|
+
const shorthand = z.string().nullable();
|
|
161
|
+
const union = z.union([z.string(), z.null()]);
|
|
162
|
+
|
|
163
|
+
expect(parseDef(shorthand._def, getRefs())).toStrictEqual({
|
|
164
|
+
type: ['string', 'null'],
|
|
165
|
+
} satisfies JSONSchema7);
|
|
166
|
+
expect(parseDef(union._def, getRefs())).toStrictEqual({
|
|
167
|
+
type: ['string', 'null'],
|
|
168
|
+
} satisfies JSONSchema7);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should be possible to use branded string', () => {
|
|
172
|
+
const schema = z.string().brand<'x'>();
|
|
173
|
+
const parsedSchema = parseDef(schema._def, getRefs());
|
|
174
|
+
|
|
175
|
+
expect(parsedSchema).toStrictEqual({
|
|
176
|
+
type: 'string',
|
|
177
|
+
} satisfies JSONSchema7);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should be possible to use readonly', () => {
|
|
181
|
+
const parsedSchema = parseDef(z.object({}).readonly()._def, getRefs());
|
|
182
|
+
|
|
183
|
+
expect(parsedSchema).toStrictEqual({
|
|
184
|
+
type: 'object',
|
|
185
|
+
properties: {},
|
|
186
|
+
additionalProperties: false,
|
|
187
|
+
} satisfies JSONSchema7);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should be possible to use catch', () => {
|
|
191
|
+
const parsedSchema = parseDef(z.number().catch(5)._def, getRefs());
|
|
192
|
+
|
|
193
|
+
expect(parsedSchema).toStrictEqual({
|
|
194
|
+
type: 'number',
|
|
195
|
+
} satisfies JSONSchema7);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should be possible to use pipeline', () => {
|
|
199
|
+
const schema = z.number().pipe(z.number().int());
|
|
200
|
+
|
|
201
|
+
expect(parseDef(schema._def, getRefs())).toStrictEqual({
|
|
202
|
+
allOf: [{ type: 'number' }, { type: 'integer' }],
|
|
203
|
+
} satisfies JSONSchema7);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should get undefined for function', () => {
|
|
207
|
+
const parsedSchema = parseDef(z.function()._def, getRefs());
|
|
208
|
+
expect(parsedSchema).toBeUndefined();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('should get undefined for void', () => {
|
|
212
|
+
const parsedSchema = parseDef(z.void()._def, getRefs());
|
|
213
|
+
expect(parsedSchema).toBeUndefined();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('nested lazy', () => {
|
|
217
|
+
const zodSchema = z.lazy(() => z.lazy(() => z.string()));
|
|
218
|
+
const parsed = parseDef(zodSchema._def, getRefs());
|
|
219
|
+
|
|
220
|
+
expect(parsed).toStrictEqual({
|
|
221
|
+
type: 'string',
|
|
222
|
+
} satisfies JSONSchema7);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { ZodTypeDef } from 'zod/v3';
|
|
2
|
+
import { Refs, Seen } from './refs';
|
|
3
|
+
import { ignoreOverride } from './options';
|
|
4
|
+
import { JsonSchema7Type } from './parse-types';
|
|
5
|
+
import { selectParser } from './select-parser';
|
|
6
|
+
import { getRelativePath } from './get-relative-path';
|
|
7
|
+
import { parseAnyDef } from './parsers/any';
|
|
8
|
+
|
|
9
|
+
export function parseDef(
|
|
10
|
+
def: ZodTypeDef,
|
|
11
|
+
refs: Refs,
|
|
12
|
+
forceResolution = false, // Forces a new schema to be instantiated even though its def has been seen. Used for improving refs in definitions. See https://github.com/StefanTerdell/zod-to-json-schema/pull/61.
|
|
13
|
+
): JsonSchema7Type | undefined {
|
|
14
|
+
const seenItem = refs.seen.get(def);
|
|
15
|
+
|
|
16
|
+
if (refs.override) {
|
|
17
|
+
const overrideResult = refs.override?.(
|
|
18
|
+
def,
|
|
19
|
+
refs,
|
|
20
|
+
seenItem,
|
|
21
|
+
forceResolution,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
if (overrideResult !== ignoreOverride) {
|
|
25
|
+
return overrideResult;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (seenItem && !forceResolution) {
|
|
30
|
+
const seenSchema = get$ref(seenItem, refs);
|
|
31
|
+
|
|
32
|
+
if (seenSchema !== undefined) {
|
|
33
|
+
return seenSchema;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const newItem: Seen = { def, path: refs.currentPath, jsonSchema: undefined };
|
|
38
|
+
|
|
39
|
+
refs.seen.set(def, newItem);
|
|
40
|
+
|
|
41
|
+
const jsonSchemaOrGetter = selectParser(def, (def as any).typeName, refs);
|
|
42
|
+
|
|
43
|
+
// If the return was a function, then the inner definition needs to be extracted before a call to parseDef (recursive)
|
|
44
|
+
const jsonSchema =
|
|
45
|
+
typeof jsonSchemaOrGetter === 'function'
|
|
46
|
+
? parseDef(jsonSchemaOrGetter(), refs)
|
|
47
|
+
: jsonSchemaOrGetter;
|
|
48
|
+
|
|
49
|
+
if (jsonSchema) {
|
|
50
|
+
addMeta(def, refs, jsonSchema);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (refs.postProcess) {
|
|
54
|
+
const postProcessResult = refs.postProcess(jsonSchema, def, refs);
|
|
55
|
+
|
|
56
|
+
newItem.jsonSchema = jsonSchema;
|
|
57
|
+
|
|
58
|
+
return postProcessResult;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
newItem.jsonSchema = jsonSchema;
|
|
62
|
+
|
|
63
|
+
return jsonSchema;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const get$ref = (
|
|
67
|
+
item: Seen,
|
|
68
|
+
refs: Refs,
|
|
69
|
+
):
|
|
70
|
+
| {
|
|
71
|
+
$ref: string;
|
|
72
|
+
}
|
|
73
|
+
| {}
|
|
74
|
+
| undefined => {
|
|
75
|
+
switch (refs.$refStrategy) {
|
|
76
|
+
case 'root':
|
|
77
|
+
return { $ref: item.path.join('/') };
|
|
78
|
+
case 'relative':
|
|
79
|
+
return { $ref: getRelativePath(refs.currentPath, item.path) };
|
|
80
|
+
case 'none':
|
|
81
|
+
case 'seen': {
|
|
82
|
+
if (
|
|
83
|
+
item.path.length < refs.currentPath.length &&
|
|
84
|
+
item.path.every((value, index) => refs.currentPath[index] === value)
|
|
85
|
+
) {
|
|
86
|
+
console.warn(
|
|
87
|
+
`Recursive reference detected at ${refs.currentPath.join(
|
|
88
|
+
'/',
|
|
89
|
+
)}! Defaulting to any`,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
return parseAnyDef();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return refs.$refStrategy === 'seen' ? parseAnyDef() : undefined;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const addMeta = (
|
|
101
|
+
def: ZodTypeDef,
|
|
102
|
+
refs: Refs,
|
|
103
|
+
jsonSchema: JsonSchema7Type,
|
|
104
|
+
): JsonSchema7Type => {
|
|
105
|
+
if (def.description) {
|
|
106
|
+
jsonSchema.description = def.description;
|
|
107
|
+
}
|
|
108
|
+
return jsonSchema;
|
|
109
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { JsonSchema7AnyType } from './parsers/any';
|
|
2
|
+
import { JsonSchema7ArrayType } from './parsers/array';
|
|
3
|
+
import { JsonSchema7BigintType } from './parsers/bigint';
|
|
4
|
+
import { JsonSchema7BooleanType } from './parsers/boolean';
|
|
5
|
+
import { JsonSchema7DateType } from './parsers/date';
|
|
6
|
+
import { JsonSchema7EnumType } from './parsers/enum';
|
|
7
|
+
import { JsonSchema7AllOfType } from './parsers/intersection';
|
|
8
|
+
import { JsonSchema7LiteralType } from './parsers/literal';
|
|
9
|
+
import { JsonSchema7MapType } from './parsers/map';
|
|
10
|
+
import { JsonSchema7NativeEnumType } from './parsers/native-enum';
|
|
11
|
+
import { JsonSchema7NeverType } from './parsers/never';
|
|
12
|
+
import { JsonSchema7NullType } from './parsers/null';
|
|
13
|
+
import { JsonSchema7NullableType } from './parsers/nullable';
|
|
14
|
+
import { JsonSchema7NumberType } from './parsers/number';
|
|
15
|
+
import { JsonSchema7ObjectType } from './parsers/object';
|
|
16
|
+
import { JsonSchema7RecordType } from './parsers/record';
|
|
17
|
+
import { JsonSchema7SetType } from './parsers/set';
|
|
18
|
+
import { JsonSchema7StringType } from './parsers/string';
|
|
19
|
+
import { JsonSchema7TupleType } from './parsers/tuple';
|
|
20
|
+
import { JsonSchema7UndefinedType } from './parsers/undefined';
|
|
21
|
+
import { JsonSchema7UnionType } from './parsers/union';
|
|
22
|
+
import { JsonSchema7UnknownType } from './parsers/unknown';
|
|
23
|
+
|
|
24
|
+
type JsonSchema7RefType = { $ref: string };
|
|
25
|
+
type JsonSchema7Meta = {
|
|
26
|
+
title?: string;
|
|
27
|
+
default?: any;
|
|
28
|
+
description?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type JsonSchema7TypeUnion =
|
|
32
|
+
| JsonSchema7StringType
|
|
33
|
+
| JsonSchema7ArrayType
|
|
34
|
+
| JsonSchema7NumberType
|
|
35
|
+
| JsonSchema7BigintType
|
|
36
|
+
| JsonSchema7BooleanType
|
|
37
|
+
| JsonSchema7DateType
|
|
38
|
+
| JsonSchema7EnumType
|
|
39
|
+
| JsonSchema7LiteralType
|
|
40
|
+
| JsonSchema7NativeEnumType
|
|
41
|
+
| JsonSchema7NullType
|
|
42
|
+
| JsonSchema7NumberType
|
|
43
|
+
| JsonSchema7ObjectType
|
|
44
|
+
| JsonSchema7RecordType
|
|
45
|
+
| JsonSchema7TupleType
|
|
46
|
+
| JsonSchema7UnionType
|
|
47
|
+
| JsonSchema7UndefinedType
|
|
48
|
+
| JsonSchema7RefType
|
|
49
|
+
| JsonSchema7NeverType
|
|
50
|
+
| JsonSchema7MapType
|
|
51
|
+
| JsonSchema7AnyType
|
|
52
|
+
| JsonSchema7NullableType
|
|
53
|
+
| JsonSchema7AllOfType
|
|
54
|
+
| JsonSchema7UnknownType
|
|
55
|
+
| JsonSchema7SetType;
|
|
56
|
+
|
|
57
|
+
export type JsonSchema7Type = JsonSchema7TypeUnion & JsonSchema7Meta;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { JSONSchema7 } from '@ai-sdk/provider';
|
|
3
|
+
import { z } from 'zod/v3';
|
|
4
|
+
import { parseArrayDef } from './array';
|
|
5
|
+
import { getRefs } from '../refs';
|
|
6
|
+
|
|
7
|
+
describe('array', () => {
|
|
8
|
+
it('should be possible to describe a simple array', () => {
|
|
9
|
+
const parsedSchema = parseArrayDef(z.array(z.string())._def, getRefs());
|
|
10
|
+
|
|
11
|
+
expect(parsedSchema).toStrictEqual({
|
|
12
|
+
type: 'array',
|
|
13
|
+
items: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
},
|
|
16
|
+
} satisfies JSONSchema7);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should be possible to describe a simple array with any item', () => {
|
|
20
|
+
const parsedSchema = parseArrayDef(z.array(z.any())._def, getRefs());
|
|
21
|
+
|
|
22
|
+
expect(parsedSchema).toStrictEqual({
|
|
23
|
+
type: 'array',
|
|
24
|
+
} satisfies JSONSchema7);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should be possible to describe a string array with a minimum and maximum length', () => {
|
|
28
|
+
const parsedSchema = parseArrayDef(
|
|
29
|
+
z.array(z.string()).min(2).max(4)._def,
|
|
30
|
+
getRefs(),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(parsedSchema).toStrictEqual({
|
|
34
|
+
type: 'array',
|
|
35
|
+
items: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
},
|
|
38
|
+
minItems: 2,
|
|
39
|
+
maxItems: 4,
|
|
40
|
+
} satisfies JSONSchema7);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should be possible to describe a string array with an exact length', () => {
|
|
44
|
+
const parsedSchema = parseArrayDef(
|
|
45
|
+
z.array(z.string()).length(5)._def,
|
|
46
|
+
getRefs(),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(parsedSchema).toStrictEqual({
|
|
50
|
+
type: 'array',
|
|
51
|
+
items: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
},
|
|
54
|
+
minItems: 5,
|
|
55
|
+
maxItems: 5,
|
|
56
|
+
} satisfies JSONSchema7);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should be possible to describe a string array with a minimum length of 1 by using nonempty', () => {
|
|
60
|
+
const parsedSchema = parseArrayDef(
|
|
61
|
+
z.array(z.any()).nonempty()._def,
|
|
62
|
+
getRefs(),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
expect(parsedSchema).toStrictEqual({
|
|
66
|
+
type: 'array',
|
|
67
|
+
minItems: 1,
|
|
68
|
+
} satisfies JSONSchema7);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should be possible do properly reference array items', () => {
|
|
72
|
+
const willHaveBeenSeen = z.object({ hello: z.string() });
|
|
73
|
+
const unionSchema = z.union([willHaveBeenSeen, willHaveBeenSeen]);
|
|
74
|
+
const arraySchema = z.array(unionSchema);
|
|
75
|
+
const jsonSchema = parseArrayDef(arraySchema._def, getRefs());
|
|
76
|
+
|
|
77
|
+
expect(jsonSchema).toStrictEqual({
|
|
78
|
+
items: {
|
|
79
|
+
anyOf: [
|
|
80
|
+
{
|
|
81
|
+
additionalProperties: false,
|
|
82
|
+
properties: {
|
|
83
|
+
hello: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
required: ['hello'],
|
|
88
|
+
type: 'object',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
$ref: '#/items/anyOf/0',
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
type: 'array',
|
|
96
|
+
} satisfies JSONSchema7);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ZodArrayDef, ZodFirstPartyTypeKind } from 'zod/v3';
|
|
2
|
+
import { parseDef } from '../parse-def';
|
|
3
|
+
import { JsonSchema7Type } from '../parse-types';
|
|
4
|
+
import { Refs } from '../refs';
|
|
5
|
+
|
|
6
|
+
export type JsonSchema7ArrayType = {
|
|
7
|
+
type: 'array';
|
|
8
|
+
items?: JsonSchema7Type;
|
|
9
|
+
minItems?: number;
|
|
10
|
+
maxItems?: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function parseArrayDef(def: ZodArrayDef, refs: Refs) {
|
|
14
|
+
const res: JsonSchema7ArrayType = {
|
|
15
|
+
type: 'array',
|
|
16
|
+
};
|
|
17
|
+
if (
|
|
18
|
+
def.type?._def &&
|
|
19
|
+
def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny
|
|
20
|
+
) {
|
|
21
|
+
res.items = parseDef(def.type._def, {
|
|
22
|
+
...refs,
|
|
23
|
+
currentPath: [...refs.currentPath, 'items'],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (def.minLength) {
|
|
28
|
+
res.minItems = def.minLength.value;
|
|
29
|
+
}
|
|
30
|
+
if (def.maxLength) {
|
|
31
|
+
res.maxItems = def.maxLength.value;
|
|
32
|
+
}
|
|
33
|
+
if (def.exactLength) {
|
|
34
|
+
res.minItems = def.exactLength.value;
|
|
35
|
+
res.maxItems = def.exactLength.value;
|
|
36
|
+
}
|
|
37
|
+
return res;
|
|
38
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { JSONSchema7 } from '@ai-sdk/provider';
|
|
3
|
+
import { z } from 'zod/v3';
|
|
4
|
+
import { parseBigintDef } from './bigint';
|
|
5
|
+
|
|
6
|
+
describe('bigint', () => {
|
|
7
|
+
it('should be possible to use bigint', () => {
|
|
8
|
+
const parsedSchema = parseBigintDef(z.bigint()._def);
|
|
9
|
+
|
|
10
|
+
expect(parsedSchema).toStrictEqual({
|
|
11
|
+
type: 'integer',
|
|
12
|
+
format: 'int64',
|
|
13
|
+
} satisfies JSONSchema7);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should be possible to define gt/lt', () => {
|
|
17
|
+
const parsedSchema = parseBigintDef(
|
|
18
|
+
z.bigint().gte(BigInt(10)).lte(BigInt(20))._def,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
expect(parsedSchema).toStrictEqual({
|
|
22
|
+
type: 'integer',
|
|
23
|
+
format: 'int64',
|
|
24
|
+
minimum: BigInt(10) as any, // json schema type does not support bigint
|
|
25
|
+
maximum: BigInt(20) as any, // json schema type does not support bigint
|
|
26
|
+
} satisfies JSONSchema7);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should be possible to define gt/lt', () => {
|
|
30
|
+
const parsedSchema = parseBigintDef(
|
|
31
|
+
z.bigint().gt(BigInt(10)).lt(BigInt(20))._def,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(parsedSchema).toStrictEqual({
|
|
35
|
+
type: 'integer',
|
|
36
|
+
format: 'int64',
|
|
37
|
+
exclusiveMinimum: BigInt(10) as any, // json schema type does not support bigint
|
|
38
|
+
exclusiveMaximum: BigInt(20) as any, // json schema type does not support bigint
|
|
39
|
+
} satisfies JSONSchema7);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should be possible to define multipleOf', () => {
|
|
43
|
+
const parsedSchema = parseBigintDef(z.bigint().multipleOf(BigInt(5))._def);
|
|
44
|
+
|
|
45
|
+
expect(parsedSchema).toStrictEqual({
|
|
46
|
+
type: 'integer',
|
|
47
|
+
format: 'int64',
|
|
48
|
+
multipleOf: BigInt(5) as any, // json schema type does not support bigint
|
|
49
|
+
} satisfies JSONSchema7);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ZodBigIntDef } from 'zod/v3';
|
|
2
|
+
|
|
3
|
+
export type JsonSchema7BigintType = {
|
|
4
|
+
type: 'integer';
|
|
5
|
+
format: 'int64';
|
|
6
|
+
minimum?: BigInt;
|
|
7
|
+
exclusiveMinimum?: BigInt;
|
|
8
|
+
maximum?: BigInt;
|
|
9
|
+
exclusiveMaximum?: BigInt;
|
|
10
|
+
multipleOf?: BigInt;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function parseBigintDef(def: ZodBigIntDef): JsonSchema7BigintType {
|
|
14
|
+
const res: JsonSchema7BigintType = {
|
|
15
|
+
type: 'integer',
|
|
16
|
+
format: 'int64',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
if (!def.checks) return res;
|
|
20
|
+
|
|
21
|
+
for (const check of def.checks) {
|
|
22
|
+
switch (check.kind) {
|
|
23
|
+
case 'min':
|
|
24
|
+
if (check.inclusive) {
|
|
25
|
+
res.minimum = check.value;
|
|
26
|
+
} else {
|
|
27
|
+
res.exclusiveMinimum = check.value;
|
|
28
|
+
}
|
|
29
|
+
break;
|
|
30
|
+
case 'max':
|
|
31
|
+
if (check.inclusive) {
|
|
32
|
+
res.maximum = check.value;
|
|
33
|
+
} else {
|
|
34
|
+
res.exclusiveMaximum = check.value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
break;
|
|
38
|
+
case 'multipleOf':
|
|
39
|
+
res.multipleOf = check.value;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return res;
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { z } from 'zod/v3';
|
|
3
|
+
import { parseBrandedDef } from './branded';
|
|
4
|
+
import { getRefs } from '../refs';
|
|
5
|
+
import { JSONSchema7 } from '@ai-sdk/provider';
|
|
6
|
+
|
|
7
|
+
describe('branded', () => {
|
|
8
|
+
it('should be possible to use branded string', () => {
|
|
9
|
+
const schema = z.string().brand<'x'>();
|
|
10
|
+
const parsedSchema = parseBrandedDef(schema._def, getRefs());
|
|
11
|
+
|
|
12
|
+
expect(parsedSchema).toStrictEqual({
|
|
13
|
+
type: 'string',
|
|
14
|
+
} satisfies JSONSchema7);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { z } from 'zod/v3';
|
|
3
|
+
import { parseCatchDef } from './catch';
|
|
4
|
+
import { getRefs } from '../refs';
|
|
5
|
+
import { JSONSchema7 } from '@ai-sdk/provider';
|
|
6
|
+
|
|
7
|
+
describe('catch', () => {
|
|
8
|
+
it('should be possible to use catch', () => {
|
|
9
|
+
const parsedSchema = parseCatchDef(z.number().catch(5)._def, getRefs());
|
|
10
|
+
|
|
11
|
+
expect(parsedSchema).toStrictEqual({
|
|
12
|
+
type: 'number',
|
|
13
|
+
} satisfies JSONSchema7);
|
|
14
|
+
});
|
|
15
|
+
});
|