@ai-sdk/provider-utils 4.0.5 → 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.
Files changed (163) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.mjs +1 -1
  4. package/package.json +4 -2
  5. package/src/__snapshots__/schema.test.ts.snap +346 -0
  6. package/src/add-additional-properties-to-json-schema.test.ts +289 -0
  7. package/src/add-additional-properties-to-json-schema.ts +53 -0
  8. package/src/combine-headers.ts +11 -0
  9. package/src/convert-async-iterator-to-readable-stream.test.ts +78 -0
  10. package/src/convert-async-iterator-to-readable-stream.ts +47 -0
  11. package/src/convert-image-model-file-to-data-uri.test.ts +85 -0
  12. package/src/convert-image-model-file-to-data-uri.ts +19 -0
  13. package/src/convert-to-form-data.test.ts +167 -0
  14. package/src/convert-to-form-data.ts +61 -0
  15. package/src/create-tool-name-mapping.test.ts +163 -0
  16. package/src/create-tool-name-mapping.ts +66 -0
  17. package/src/delay.test.ts +212 -0
  18. package/src/delay.ts +47 -0
  19. package/src/delayed-promise.test.ts +132 -0
  20. package/src/delayed-promise.ts +61 -0
  21. package/src/download-blob.test.ts +145 -0
  22. package/src/download-blob.ts +31 -0
  23. package/src/download-error.ts +39 -0
  24. package/src/extract-response-headers.ts +9 -0
  25. package/src/fetch-function.ts +4 -0
  26. package/src/generate-id.test.ts +31 -0
  27. package/src/generate-id.ts +57 -0
  28. package/src/get-error-message.ts +15 -0
  29. package/src/get-from-api.test.ts +199 -0
  30. package/src/get-from-api.ts +97 -0
  31. package/src/get-runtime-environment-user-agent.test.ts +47 -0
  32. package/src/get-runtime-environment-user-agent.ts +24 -0
  33. package/src/handle-fetch-error.ts +39 -0
  34. package/src/index.ts +67 -0
  35. package/src/inject-json-instruction.test.ts +404 -0
  36. package/src/inject-json-instruction.ts +63 -0
  37. package/src/is-abort-error.ts +8 -0
  38. package/src/is-async-iterable.ts +3 -0
  39. package/src/is-non-nullable.ts +12 -0
  40. package/src/is-url-supported.test.ts +282 -0
  41. package/src/is-url-supported.ts +40 -0
  42. package/src/load-api-key.ts +45 -0
  43. package/src/load-optional-setting.ts +30 -0
  44. package/src/load-setting.ts +62 -0
  45. package/src/maybe-promise-like.ts +3 -0
  46. package/src/media-type-to-extension.test.ts +26 -0
  47. package/src/media-type-to-extension.ts +22 -0
  48. package/src/normalize-headers.test.ts +64 -0
  49. package/src/normalize-headers.ts +38 -0
  50. package/src/parse-json-event-stream.ts +33 -0
  51. package/src/parse-json.test.ts +191 -0
  52. package/src/parse-json.ts +122 -0
  53. package/src/parse-provider-options.ts +32 -0
  54. package/src/post-to-api.ts +166 -0
  55. package/src/provider-tool-factory.ts +125 -0
  56. package/src/remove-undefined-entries.test.ts +57 -0
  57. package/src/remove-undefined-entries.ts +12 -0
  58. package/src/resolve.test.ts +125 -0
  59. package/src/resolve.ts +17 -0
  60. package/src/response-handler.test.ts +89 -0
  61. package/src/response-handler.ts +187 -0
  62. package/src/schema.test-d.ts +11 -0
  63. package/src/schema.test.ts +502 -0
  64. package/src/schema.ts +267 -0
  65. package/src/secure-json-parse.test.ts +59 -0
  66. package/src/secure-json-parse.ts +92 -0
  67. package/src/test/convert-array-to-async-iterable.ts +9 -0
  68. package/src/test/convert-array-to-readable-stream.ts +15 -0
  69. package/src/test/convert-async-iterable-to-array.ts +9 -0
  70. package/src/test/convert-readable-stream-to-array.ts +14 -0
  71. package/src/test/convert-response-stream-to-array.ts +9 -0
  72. package/src/test/index.ts +7 -0
  73. package/src/test/is-node-version.ts +4 -0
  74. package/src/test/mock-id.ts +8 -0
  75. package/src/to-json-schema/zod3-to-json-schema/LICENSE +16 -0
  76. package/src/to-json-schema/zod3-to-json-schema/README.md +24 -0
  77. package/src/to-json-schema/zod3-to-json-schema/get-relative-path.ts +7 -0
  78. package/src/to-json-schema/zod3-to-json-schema/index.ts +1 -0
  79. package/src/to-json-schema/zod3-to-json-schema/options.ts +98 -0
  80. package/src/to-json-schema/zod3-to-json-schema/parse-def.test.ts +224 -0
  81. package/src/to-json-schema/zod3-to-json-schema/parse-def.ts +109 -0
  82. package/src/to-json-schema/zod3-to-json-schema/parse-types.ts +57 -0
  83. package/src/to-json-schema/zod3-to-json-schema/parsers/any.ts +5 -0
  84. package/src/to-json-schema/zod3-to-json-schema/parsers/array.test.ts +98 -0
  85. package/src/to-json-schema/zod3-to-json-schema/parsers/array.ts +38 -0
  86. package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.test.ts +51 -0
  87. package/src/to-json-schema/zod3-to-json-schema/parsers/bigint.ts +44 -0
  88. package/src/to-json-schema/zod3-to-json-schema/parsers/boolean.ts +7 -0
  89. package/src/to-json-schema/zod3-to-json-schema/parsers/branded.test.ts +16 -0
  90. package/src/to-json-schema/zod3-to-json-schema/parsers/branded.ts +7 -0
  91. package/src/to-json-schema/zod3-to-json-schema/parsers/catch.test.ts +15 -0
  92. package/src/to-json-schema/zod3-to-json-schema/parsers/catch.ts +7 -0
  93. package/src/to-json-schema/zod3-to-json-schema/parsers/date.test.ts +97 -0
  94. package/src/to-json-schema/zod3-to-json-schema/parsers/date.ts +64 -0
  95. package/src/to-json-schema/zod3-to-json-schema/parsers/default.test.ts +54 -0
  96. package/src/to-json-schema/zod3-to-json-schema/parsers/default.ts +14 -0
  97. package/src/to-json-schema/zod3-to-json-schema/parsers/effects.test.ts +41 -0
  98. package/src/to-json-schema/zod3-to-json-schema/parsers/effects.ts +14 -0
  99. package/src/to-json-schema/zod3-to-json-schema/parsers/enum.ts +13 -0
  100. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.test.ts +92 -0
  101. package/src/to-json-schema/zod3-to-json-schema/parsers/intersection.ts +52 -0
  102. package/src/to-json-schema/zod3-to-json-schema/parsers/literal.ts +29 -0
  103. package/src/to-json-schema/zod3-to-json-schema/parsers/map.test.ts +48 -0
  104. package/src/to-json-schema/zod3-to-json-schema/parsers/map.ts +47 -0
  105. package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.test.ts +102 -0
  106. package/src/to-json-schema/zod3-to-json-schema/parsers/native-enum.ts +31 -0
  107. package/src/to-json-schema/zod3-to-json-schema/parsers/never.ts +9 -0
  108. package/src/to-json-schema/zod3-to-json-schema/parsers/null.ts +9 -0
  109. package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.test.ts +67 -0
  110. package/src/to-json-schema/zod3-to-json-schema/parsers/nullable.ts +42 -0
  111. package/src/to-json-schema/zod3-to-json-schema/parsers/number.test.ts +65 -0
  112. package/src/to-json-schema/zod3-to-json-schema/parsers/number.ts +44 -0
  113. package/src/to-json-schema/zod3-to-json-schema/parsers/object.test.ts +149 -0
  114. package/src/to-json-schema/zod3-to-json-schema/parsers/object.ts +88 -0
  115. package/src/to-json-schema/zod3-to-json-schema/parsers/optional.test.ts +147 -0
  116. package/src/to-json-schema/zod3-to-json-schema/parsers/optional.ts +23 -0
  117. package/src/to-json-schema/zod3-to-json-schema/parsers/pipe.test.ts +35 -0
  118. package/src/to-json-schema/zod3-to-json-schema/parsers/pipeline.ts +29 -0
  119. package/src/to-json-schema/zod3-to-json-schema/parsers/promise.test.ts +15 -0
  120. package/src/to-json-schema/zod3-to-json-schema/parsers/promise.ts +11 -0
  121. package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.test.ts +20 -0
  122. package/src/to-json-schema/zod3-to-json-schema/parsers/readonly.ts +7 -0
  123. package/src/to-json-schema/zod3-to-json-schema/parsers/record.test.ts +108 -0
  124. package/src/to-json-schema/zod3-to-json-schema/parsers/record.ts +71 -0
  125. package/src/to-json-schema/zod3-to-json-schema/parsers/set.test.ts +20 -0
  126. package/src/to-json-schema/zod3-to-json-schema/parsers/set.ts +35 -0
  127. package/src/to-json-schema/zod3-to-json-schema/parsers/string.test.ts +438 -0
  128. package/src/to-json-schema/zod3-to-json-schema/parsers/string.ts +426 -0
  129. package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.test.ts +33 -0
  130. package/src/to-json-schema/zod3-to-json-schema/parsers/tuple.ts +61 -0
  131. package/src/to-json-schema/zod3-to-json-schema/parsers/undefined.ts +11 -0
  132. package/src/to-json-schema/zod3-to-json-schema/parsers/union.test.ts +226 -0
  133. package/src/to-json-schema/zod3-to-json-schema/parsers/union.ts +144 -0
  134. package/src/to-json-schema/zod3-to-json-schema/parsers/unknown.ts +7 -0
  135. package/src/to-json-schema/zod3-to-json-schema/refs.test.ts +919 -0
  136. package/src/to-json-schema/zod3-to-json-schema/refs.ts +39 -0
  137. package/src/to-json-schema/zod3-to-json-schema/select-parser.ts +115 -0
  138. package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.test.ts +862 -0
  139. package/src/to-json-schema/zod3-to-json-schema/zod3-to-json-schema.ts +93 -0
  140. package/src/types/assistant-model-message.ts +39 -0
  141. package/src/types/content-part.ts +379 -0
  142. package/src/types/data-content.ts +4 -0
  143. package/src/types/execute-tool.ts +27 -0
  144. package/src/types/index.ts +40 -0
  145. package/src/types/model-message.ts +14 -0
  146. package/src/types/provider-options.ts +9 -0
  147. package/src/types/system-model-message.ts +20 -0
  148. package/src/types/tool-approval-request.ts +16 -0
  149. package/src/types/tool-approval-response.ts +27 -0
  150. package/src/types/tool-call.ts +31 -0
  151. package/src/types/tool-model-message.ts +23 -0
  152. package/src/types/tool-result.ts +35 -0
  153. package/src/types/tool.test-d.ts +193 -0
  154. package/src/types/tool.ts +324 -0
  155. package/src/types/user-model-message.ts +22 -0
  156. package/src/uint8-utils.ts +26 -0
  157. package/src/validate-types.test.ts +105 -0
  158. package/src/validate-types.ts +81 -0
  159. package/src/version.ts +6 -0
  160. package/src/with-user-agent-suffix.test.ts +84 -0
  161. package/src/with-user-agent-suffix.ts +27 -0
  162. package/src/without-trailing-slash.ts +3 -0
  163. 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,5 @@
1
+ export type JsonSchema7AnyType = { $ref?: string };
2
+
3
+ export function parseAnyDef(): JsonSchema7AnyType {
4
+ return {};
5
+ }
@@ -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,7 @@
1
+ export type JsonSchema7BooleanType = {
2
+ type: 'boolean';
3
+ };
4
+
5
+ export function parseBooleanDef(): JsonSchema7BooleanType {
6
+ return { type: 'boolean' };
7
+ }
@@ -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,7 @@
1
+ import { ZodBrandedDef } from 'zod/v3';
2
+ import { parseDef } from '../parse-def';
3
+ import { Refs } from '../refs';
4
+
5
+ export function parseBrandedDef(_def: ZodBrandedDef<any>, refs: Refs) {
6
+ return parseDef(_def.type._def, refs);
7
+ }
@@ -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
+ });
@@ -0,0 +1,7 @@
1
+ import { ZodCatchDef } from 'zod/v3';
2
+ import { parseDef } from '../parse-def';
3
+ import { Refs } from '../refs';
4
+
5
+ export const parseCatchDef = (def: ZodCatchDef<any>, refs: Refs) => {
6
+ return parseDef(def.innerType._def, refs);
7
+ };