Skip to content

Commit a38070d

Browse files
committed
Update README of to-json-schema package to match source code
1 parent 04bcbae commit a38070d

File tree

1 file changed

+280
-47
lines changed

1 file changed

+280
-47
lines changed

packages/to-json-schema/README.md

Lines changed: 280 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ import * as v from 'valibot';
99
toJsonSchema(v.string()); // { type: "string" }
1010
```
1111

12-
Some Valibot features can't be mapped to JSON schema. For example, transformation actions have no equivalent in JSON schema. Also, some Valibot schemas or validations are too JS-specific and do not have an equivalent JSON schema attribute.
12+
This package is particularly popular for:
13+
14+
- **API Documentation**: Generate OpenAPI specifications from your Valibot schemas
15+
- **Code Generation**: Create client SDKs and types from your validation schemas
16+
- **LLM Integration**: Generate structured outputs for Large Language Models
17+
- **Schema Sharing**: Share validation logic between backend and frontend
18+
19+
> Some Valibot features can't be mapped to JSON schema. For example, transformation actions have no equivalent in JSON schema. Also, some Valibot schemas or validations are too JS-specific and do not have an equivalent JSON schema attribute.
1320
1421
## Supported features
1522

@@ -23,7 +30,7 @@ Some Valibot features can't be mapped to JSON schema. For example, transformatio
2330
| `enum` || |
2431
| `exactOptional` || |
2532
| `intersect` || |
26-
| `lazy` | ⚠️ | The `.getter`function is always executed with `undefined` as input |
33+
| `lazy` | ⚠️ | The `.getter` function is always executed with `undefined` as input |
2734
| `literal` | ⚠️ | Only JSON compatible values are supported |
2835
| `looseObject` || |
2936
| `looseTuple` || |
@@ -50,14 +57,14 @@ Some Valibot features can't be mapped to JSON schema. For example, transformatio
5057
| -------------- | ------ | ----------------------------------------------------------- |
5158
| `base64` || |
5259
| `bic` || |
53-
| `description` || |
5460
| `cuid2` || |
61+
| `decimal` || |
62+
| `description` || |
63+
| `digits` || |
5564
| `email` || |
5665
| `emoji` || |
5766
| `empty` || |
5867
| `entries` || |
59-
| `decimal` || |
60-
| `digits` || |
6168
| `hexadecimal` || |
6269
| `hexColor` || |
6370
| `integer` || |
@@ -68,10 +75,10 @@ Some Valibot features can't be mapped to JSON schema. For example, transformatio
6875
| `isoTime` || |
6976
| `isoTimestamp` || |
7077
| `length` | ⚠️ | Only in combination with `string` and `array` schema |
71-
| `metadata` | ⚠️ | Only for valid `title`, `description` and `examples` values |
7278
| `maxEntries` || |
7379
| `maxLength` | ⚠️ | Only in combination with `string` and `array` schema |
7480
| `maxValue` | ⚠️ | Only in combination with `number` schema |
81+
| `metadata` | ⚠️ | Only for valid `title`, `description` and `examples` values |
7582
| `minEntries` || |
7683
| `minLength` | ⚠️ | Only in combination with `string` and `array` schemas |
7784
| `minValue` | ⚠️ | Only in combination with `number` schema |
@@ -88,10 +95,54 @@ Some Valibot features can't be mapped to JSON schema. For example, transformatio
8895

8996
## Configurations
9097

91-
| Option | Type | Note |
92-
| ----------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
93-
| errorMode | `'throw' \| 'warn' \| 'ignore'` | The policy for handling incompatible schemas and actions. |
94-
| definitions | `Record<string, GenericSchema>` | The schema definitions for constructing recursive schemas. If not specified, the definitions are generated automatically. |
98+
| Option | Type | Note |
99+
| -------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
100+
| typeMode | `'ignore' \| 'input' \| 'output'` | Whether to convert the input or output type of the Valibot schema to JSON Schema. |
101+
| errorMode | `'throw' \| 'warn' \| 'ignore'` | The policy for handling incompatible schemas and actions. |
102+
| definitions | `Record<string, GenericSchema>` | The schema definitions for constructing recursive schemas. If not specified, the definitions are generated automatically. |
103+
| overrideSchema | `(context: OverrideSchemaContext) => JSONSchema7 \| null \| undefined` | Overrides the JSON Schema conversion for a specific Valibot schema. |
104+
| ignoreActions | `string[]` | The actions that should be ignored during the conversion. |
105+
| overrideAction | `(context: OverrideActionContext) => JSONSchema7 \| null \| undefined` | Overrides the JSON Schema reference for a specific Valibot action. |
106+
| overrideRef | `(context: OverrideRefContext) => string \| null \| undefined` | Overrides the JSON Schema reference for a specific reference ID. |
107+
108+
### Type mode
109+
110+
The `typeMode` configuration controls whether to convert the input or output type of the Valibot schema to JSON Schema.
111+
112+
- When set to `'input'`, conversion stops before the first potential type transformation action or second schema in any pipeline.
113+
- When set to `'output'`, conversion of any pipelines starts from the last schema in the pipeline. Therefore, the output type must be specified explicitly with a schema after the last type transformation action.
114+
- When set to `'ignore'` (default), the entire pipeline is converted.
115+
116+
This is particularly useful when defining API endpoints where external developers need different schema information for requests vs responses:
117+
118+
```js
119+
import { toJsonSchema } from '@valibot/to-json-schema';
120+
import * as v from 'valibot';
121+
122+
const ValibotSchema = v.pipe(
123+
v.string(),
124+
v.decimal(),
125+
v.transform(Number),
126+
v.number(),
127+
v.maxValue(100)
128+
);
129+
130+
toJsonSchema(ValibotSchema, { typeMode: 'input' });
131+
132+
// {
133+
// $schema: "http://json-schema.org/draft-07/schema#",
134+
// type: "string",
135+
// pattern: "^[+-]?(?:\\d*\\.)?\\d+$"
136+
// }
137+
138+
toJsonSchema(ValibotSchema, { typeMode: 'output' });
139+
140+
// {
141+
// $schema: "http://json-schema.org/draft-07/schema#",
142+
// type: "number",
143+
// maximum: 100
144+
// }
145+
```
95146

96147
### Error mode
97148

@@ -108,9 +159,87 @@ toJsonSchema(v.file(), { errorMode: 'ignore' }); // {}
108159
toJsonSchema(v.pipe(v.string(), v.creditCard()), { errorMode: 'ignore' }); // { type: "string" }
109160
```
110161

162+
### Override functions
163+
164+
The package provides powerful override capabilities to customize the JSON Schema conversion process. You can override the conversion of specific schemas, actions, or references.
165+
166+
#### Override schema conversion
167+
168+
Handle unsupported schemas or customize conversion behavior:
169+
170+
```js
171+
import { toJsonSchema } from '@valibot/to-json-schema';
172+
import * as v from 'valibot';
173+
174+
const ValibotSchema = v.object({ createdAt: v.date() });
175+
176+
toJsonSchema(ValibotSchema, {
177+
overrideSchema(context) {
178+
if (context.valibotSchema.type === 'date') {
179+
return { type: 'string', format: 'date-time' };
180+
}
181+
},
182+
});
183+
184+
// {
185+
// $schema: "http://json-schema.org/draft-07/schema#",
186+
// type: "object",
187+
// properties: {
188+
// createdAt: { type: "string" format: "date-time" }
189+
// },
190+
// required: ["createdAt"]
191+
// }
192+
```
193+
194+
#### Override reference IDs
195+
196+
Customize reference IDs for OpenAPI or other specifications:
197+
198+
```js
199+
import { toJsonSchemaDefs } from '@valibot/to-json-schema';
200+
import * as v from 'valibot';
201+
202+
const UserSchema = v.object({ name: v.string() });
203+
204+
toJsonSchemaDefs(
205+
{ UserSchema },
206+
{ overrideRef: (context) => `#/schemas/${context.referenceId}` }
207+
);
208+
```
209+
210+
### Enhanced metadata support
211+
212+
Use the generic `metadata` action to add title, description, and examples to your schemas or the individual `title`and `description` actions:
213+
214+
```js
215+
import { toJsonSchema } from '@valibot/to-json-schema';
216+
import * as v from 'valibot';
217+
218+
const ValibotSchema = v.pipe(
219+
v.string(),
220+
v.email(),
221+
v.metadata({
222+
title: 'Email Schema',
223+
description: 'A schema that validates email addresses.',
224+
examples: ['[email protected]'],
225+
})
226+
);
227+
228+
toJsonSchema(ValibotSchema);
229+
230+
// {
231+
// $schema: "http://json-schema.org/draft-07/schema#",
232+
// type: "string",
233+
// format: "email",
234+
// title: "Email Schema",
235+
// description: "A schema that validates email addresses.",
236+
// examples: ["[email protected]"]
237+
// }
238+
```
239+
111240
### Definitions
112241

113-
Nested schemas can be broken in multiple named definitions.
242+
Nested and recursive schemas can be broken in multiple reusable definitions.
114243

115244
```js
116245
import { toJsonSchema } from '@valibot/to-json-schema';
@@ -121,25 +250,22 @@ toJsonSchema(v.object({ email: EmailSchema }), {
121250
definitions: { EmailSchema },
122251
});
123252

124-
/*
125-
{
126-
$schema: "http://json-schema.org/draft-07/schema#",
127-
type: "object",
128-
properties: {
129-
email: {
130-
$ref: "#/$defs/EmailSchema",
131-
},
132-
},
133-
required: ["email"],
134-
additionalProperties: false,
135-
$defs: {
136-
EmailSchema: {
137-
type: "string",
138-
format: "email",
139-
},
140-
},
141-
}
142-
*/
253+
// {
254+
// $schema: "http://json-schema.org/draft-07/schema#",
255+
// type: "object",
256+
// properties: {
257+
// email: {
258+
// $ref: "#/$defs/EmailSchema"
259+
// }
260+
// },
261+
// required: ["email"],
262+
// $defs: {
263+
// EmailSchema: {
264+
// type: "string",
265+
// format: "email"
266+
// }
267+
// }
268+
// }
143269
```
144270

145271
Definitions are not required for converting `lazy` schemas. Missing definitions will be generated automatically.
@@ -151,22 +277,129 @@ import * as v from 'valibot';
151277
const StringSchema = v.string();
152278
toJsonSchema(v.object({ key: v.lazy(() => StringSchema) }));
153279

154-
/*
155-
{
156-
$schema: "http://json-schema.org/draft-07/schema#",
157-
type: "object",
158-
properties: {
159-
key: {
160-
$ref: "#/$defs/0",
161-
},
162-
},
163-
required: ["key"],
164-
additionalProperties: false,
165-
$defs: {
166-
"0": {
167-
type: "string",
168-
},
169-
},
280+
// {
281+
// $schema: "http://json-schema.org/draft-07/schema#",
282+
// type: "object",
283+
// properties: {
284+
// key: {
285+
// $ref: "#/$defs/0"
286+
// }
287+
// },
288+
// required: ["key"],
289+
// $defs: {
290+
// 0: {
291+
// type: "string"
292+
// }
293+
// }
294+
// }
295+
```
296+
297+
## Additional functions
298+
299+
### `toJsonSchemaDefs`
300+
301+
Converts only the provided Valibot schema definitions to JSON Schema definitions, without wrapping them in a root schema. This is particularly useful for OpenAPI specifications where you need only the schema definitions.
302+
303+
```js
304+
import { toJsonSchemaDefs } from '@valibot/to-json-schema';
305+
import * as v from 'valibot';
306+
307+
const EmailSchema = v.pipe(v.string(), v.email());
308+
const UserSchema = v.object({
309+
name: v.string(),
310+
email: EmailSchema,
311+
});
312+
313+
toJsonSchemaDefs({ EmailSchema, UserSchema });
314+
315+
// {
316+
// EmailSchema: {
317+
// type: "string",
318+
// format: "email"
319+
// },
320+
// UserSchema: {
321+
// type: "object",
322+
// properties: {
323+
// name: {
324+
// type: "string"
325+
// },
326+
// email: {
327+
// $ref: "#/$defs/EmailSchema"
328+
// }
329+
// },
330+
// required: ["name", "email"]
331+
// }
332+
// }
333+
```
334+
335+
#### OpenAPI integration
336+
337+
For OpenAPI specifications, you can customize reference IDs:
338+
339+
```js
340+
import { toJsonSchemaDefs } from '@valibot/to-json-schema';
341+
import * as v from 'valibot';
342+
343+
const ValibotSchema1 = v.string();
344+
const ValibotSchema2 = v.number();
345+
const ValibotSchema3 = v.tuple([ValibotSchema1, ValibotSchema2]);
346+
347+
toJsonSchemaDefs(
348+
{ ValibotSchema1, ValibotSchema2, ValibotSchema3 },
349+
{ overrideRef: (context) => `#/schemas/${context.referenceId}` }
350+
);
351+
352+
// {
353+
// ValibotSchema1: { type: "string" },
354+
// ValibotSchema2: { type: "number" },
355+
// ValibotSchema3: {
356+
// type: "array",
357+
// items: [
358+
// { $ref: "#/schemas/ValibotSchema1" },
359+
// { $ref: "#/schemas/ValibotSchema2" }
360+
// ],
361+
// minItems: 2
362+
// }
363+
// }
364+
```
365+
366+
### Global Definitions
367+
368+
For advanced use cases, you can manage global schema definitions that will be automatically used when converting schemas. This is particularly useful for larger projects with many reusable schemas.
369+
370+
```js
371+
import { addGlobalDefs, toJsonSchema } from '@valibot/to-json-schema';
372+
import * as v from 'valibot';
373+
374+
const ValibotSchema1 = v.string();
375+
const ValibotSchema2 = v.number();
376+
377+
addGlobalDefs({ ValibotSchema1, ValibotSchema2 });
378+
379+
const ValibotSchema3 = v.tuple([ValibotSchema1, ValibotSchema2]);
380+
381+
toJsonSchema(ValibotSchema3);
382+
383+
// {
384+
// $schema: "http://json-schema.org/draft-07/schema#",
385+
// type: "array",
386+
// items: [
387+
// { $ref: "#/$defs/ValibotSchema1" },
388+
// { $ref: "#/$defs/ValibotSchema2" }
389+
// ],
390+
// minItems: 2,
391+
// $defs: {
392+
// ValibotSchema1: { type: "string" },
393+
// ValibotSchema2: { type: "number" }
394+
// }
395+
// }
396+
```
397+
398+
You can also convert global definitions directly using `toJsonSchemaDefs`:
399+
400+
```js
401+
const globalDefs = getGlobalDefs();
402+
if (globalDefs) {
403+
const schemaDefs = toJsonSchemaDefs(globalDefs);
170404
}
171-
*/
172405
```

0 commit comments

Comments
 (0)