11# Tiny Schema Validator
22
3- JSON schema validator with great type inference.
3+ JSON schema validator with excellent type inference for JavaScript and TypeScript .
44
55[ ![ GitHub license] ( https://img.shields.io/github/license/5alidz/tiny-schema-validator )] ( https://github.com/5alidz/tiny-schema-validator/blob/master/LICENSE ) ![ Minzipped size] ( https://img.shields.io/bundlephobia/minzip/tiny-schema-validator.svg )
66
@@ -19,47 +19,72 @@ yarn add tiny-schema-validator
1919``` js
2020import { createSchema , _ } from ' tiny-schema-validator' ;
2121
22- export const Person = createSchema ({
23- name : _ .string ({
24- maxLength : [ 100 , ' too-long ' ] ,
25- minLength : [ 2 , ' too-short ' ] ,
22+ export const User = createSchema ({
23+ metadata : _ .record ({
24+ date_created : _ . number () ,
25+ id : _ . string () ,
2626 }),
27- age: _ .number ({
28- max: [150 , ' too-old' ],
29- min: [13 , ' too-young' ],
27+ profile: _ .record ({
28+ name: _ .string ({
29+ maxLength: [100 , ' too-long' ],
30+ minLength: [2 , ' too-short' ],
31+ }),
32+ age: _ .number ({
33+ max: [150 , ' too-old' ],
34+ min: [13 , ' too-young' ],
35+ }),
36+ email: _ .string ({
37+ pattern: [/ ^ [^ @] + @[^ @] + \. [^ @] + $ / , ' invalid-email' ],
38+ }),
3039 }),
31- email: _ .string ({
32- pattern: [/ ^ [^ @] + @[^ @] + \. [^ @] + $ / , ' invalid-email' ],
33- });
40+ payment_status: _ .union (
41+ _ .constant (' pending' ),
42+ _ .constant (' failed' ),
43+ _ .constant (' success' ),
44+ _ .constant (' canceled' )
45+ ),
3446});
3547```
3648
3749and in TypeScript, everything is the same, but to get the data type inferred from the schema, you can do this:
3850
3951``` ts
4052/*
41- PersonType {
42- name: string;
43- age: number;
44- email: string;
53+ UserType {
54+ metadata: {
55+ date_created: number;
56+ id: string;
57+ };
58+ profile: {
59+ name: string;
60+ age: number;
61+ email: string;
62+ };
63+ payment_status: 'pending' | 'failed' | 'success' | 'canceled';
4564 }
4665*/
47- export type PersonType = ReturnType <typeof Person .produce >;
66+ export type UserType = ReturnType <typeof User .produce >;
4867```
4968
50- ## Schema
69+ ### Using the schema
5170
5271When you create a schema, you will get a nice API to handle multiple use-cases in the client and the server.
5372
5473- ` is(data: any): boolean ` check if the data is valid (eager evaluation)
5574- ` validate(data: any): Errors ` errors returned has the same shape as the schema you defined (does not throw)
5675- ` produce(data: any): data ` throws an error when the data is invalid. otherwise, it returns data
5776- ` embed(config?: { optional: boolean }) ` embeds the schema in other schemas
58- - ` traverse(visitor, data?, eager?) ` (advanced) see usage below.
77+ - ` source ` the schema itself in a parsable format
5978
60- Continuing from the previous example:
79+ example usage :
6180
6281``` js
82+ const Person = createSchema ({
83+ name: _ .string (),
84+ age: _ .number (),
85+ email: _ .string (),
86+ });
87+
6388const john = { name
: ' john' , age
: 42 , email
: ' [email protected] ' };
6489Person .is ({}); // false
6590Person .is (john); // true
@@ -84,18 +109,37 @@ const GroupOfPeople = createSchema({
84109
85110## Validators
86111
112+ All validators are required by default.
87113All validators are accessible with the ` _ ` (underscore) namespace; The reason for using ` _ ` instead of a good name like ` validators ` is developer experience, and you can alias it to whatever you want.
88114
89115``` js
90116import { _ as validators } from ' tiny-schema-validator' ;
91117
92- validators .string (); // creates a string validator
118+ // NOTE: when you call a validator you just create an object with { type: '<type of validator>', ...options }
119+ // this is just a shorthand for that.
120+
121+ // example of all validators and corresponding Typescript types
122+ validators .string (); // string
123+ validators .number (); // number
124+ validators .boolean (); // boolean
125+ validators .constant (42 ); // 42
126+ validators .union (validators .constant (1 ), validators .constant (2 ), validators .constant (3 )); // 1 | 2 | 3
127+ validators .list ([validators .number (), validators .number ()]); // [number, number]
128+ validators .listof (validators .string ()); // string[]
129+ validators .recordof (validators .string ()); // Record<string, string>
130+ validators .record ({
131+ timestamp: validators .number (),
132+ id: validators .string (),
133+ }); // { timestamp: number; id: string; }
93134```
94135
95136Check out the full validators API below:
96137
97138| validator | signature | props |
98139| :-------- | ------------------------------- | :------------------------------------------------------------- |
140+ | | | |
141+ | constant | ` constant(value) ` | value: ` string \| number \| boolean ` |
142+ | | | |
99143| string | ` string(options?) ` | options (optional): Object |
100144| | | - ` optional : boolean ` defaults to false |
101145| | | - ` maxLength: [length: number, error: string] ` |
@@ -111,6 +155,8 @@ Check out the full validators API below:
111155| boolean | ` boolean(options?) ` | options(optional): Object |
112156| | | - ` optional: boolean ` default to false |
113157| | | |
158+ | union | ` union(...validators) ` | validators: Array of validators as paramaters |
159+ | | | |
114160| list | ` list(validators[], options?) ` | validators: Array of validators |
115161| | | options(optional): Object |
116162| | | - ` optional: boolean ` default to false |
@@ -154,91 +200,6 @@ const Person = createSchema({
154200});
155201```
156202
157- ## Advanced usage
158-
159- In addition to validating data, you can also reuse your schema in other areas, like creating forms UI.
160- ` traverse ` function come-in handy to help you achieve that.
161-
162- ### Example
163-
164- In this example, we will transform a schema to create meta-data to create form UI elements.
165-
166- ``` js
167- const User = createSchema ({
168- id: _ .string (),
169- created: _ .number (),
170- updated: _ .number (),
171- profile: _ .record ({ username: _ .string (), email: _ .string (), age: _ .number () }),
172- });
173-
174- const form_ui = User .traverse ({
175- number ({ path, key }) {
176- if (path .includes (' profile' )) return { type: ' number' , label: key };
177- return null ; // otherwise ignore
178- },
179- string ({ path, key }) {
180- if (path .includes (' profile' )) return { type: ' text' , label: key };
181- return null ; // otherwise ignore
182- },
183- // this is required to get the type of "profile" correct
184- record : () => null ,
185- });
186-
187- console .log (form_ui); /*
188- {
189- profile: {
190- username: { type: 'text', label: 'username' },
191- email: { type: 'text', label: 'email' },
192- age: { type: 'number', label: 'age' }
193- }
194- }
195- */
196- ```
197-
198- ### How to traverse
199-
200- there are a few considerations when defining ` visitor ` object:
201-
202- - In ` string | number | boolean ` visitors, returning ` null ` signals to ignore this node.
203- - In ` record | recordof | list | listof ` visitors, returning ` null ` signals to visit its children.
204- - To skip over ` record | recordof | list | listof ` nodes, return ` {} ` (empty object).
205-
206- Continuing from the previous ` User ` Example
207-
208- ``` js
209- /*
210- Say We need this structure:
211- {
212- profile: {
213- type: 'container',
214- children: [
215- { type: 'text', label: 'username' },
216- { type: 'text', label: 'email' },
217- { type: 'number', label: 'age' }
218- ]
219- }
220- }
221- */
222- const customTraverse = (key , validator ) => {
223- const type = validator .type ;
224-
225- if (type == ' string' ) return { type: key == ' email' ? key : ' text' , label: key };
226- if (type == ' number' ) return { type: ' number' , label: key };
227- if (type == ' record' )
228- return {
229- type: ' container' ,
230- children: Object .entries (validator .shape ).map (entry => customTraverse (... entry)),
231- };
232- return null ;
233- };
234-
235- const form_ui = User .traverse ({
236- record ({ path, key, validator }) {
237- return customTraverse (key, validator);
238- },
239- });
240- ```
241-
242203## Caveats
243204
244205- When using the ` recordof | listof | list ` validators, the optional property of the validator is ignored, example:
0 commit comments