@@ -2,9 +2,11 @@ import { Schema, SchemaMetaData } from 'type-level-schema/schema';
2
2
import { objectKeys , Nominal , AnyFunc , AllRequired , Optional , Unknown } from 'simplytyped' ;
3
3
import * as Ajv from 'ajv' ;
4
4
5
- type ObjectValidator < O extends Record < string , Validator < any > > , OptionalKeys extends keyof O > = Optional < {
5
+ type ObjectValidator < O extends Record < string , Validator < any > > > = {
6
6
[ S in keyof O ] : ValidType < O [ S ] > ;
7
- } , OptionalKeys > ;
7
+ } ;
8
+
9
+ type OptionalObjectValidator < O extends Record < string , Validator < any > > , OptionalKeys extends keyof O > = Optional < ObjectValidator < O > , OptionalKeys > ;
8
10
9
11
export type ObjectOptions < OptionalKeys > = Partial < {
10
12
optional : OptionalKeys [ ] ;
@@ -50,10 +52,16 @@ export default class Validator<T> {
50
52
return new Validator ( { type : 'boolean' } ) ;
51
53
}
52
54
55
+ static any ( ) : Validator < any > {
56
+ return new Validator ( { } ) ;
57
+ }
58
+
53
59
static nominal < T , S extends string > ( v : Validator < T > , s : S ) : Validator < Nominal < T , S > > {
54
60
return new Validator ( v . getSchema ( ) ) ;
55
61
}
56
62
63
+ static object < O extends Record < string , Validator < any > > > ( o : O ) : Validator < ObjectValidator < O > > ;
64
+ static object < O extends Record < string , Validator < any > > , OptionalKeys extends keyof O = never > ( o : O , opts ?: ObjectOptions < OptionalKeys > ) : Validator < OptionalObjectValidator < O , OptionalKeys > > ;
57
65
static object < O extends Record < string , Validator < any > > , OptionalKeys extends keyof O = never > ( o : O , opts ?: ObjectOptions < OptionalKeys > ) {
58
66
const options : AllRequired < ObjectOptions < OptionalKeys > > = {
59
67
optional : [ ] as OptionalKeys [ ] ,
@@ -68,7 +76,7 @@ export default class Validator<T> {
68
76
69
77
const required = Object . keys ( o ) . filter ( key => ! options . optional . includes ( key as OptionalKeys ) ) ;
70
78
71
- return new Validator < ObjectValidator < O , OptionalKeys > > ( {
79
+ return new Validator ( {
72
80
type : 'object' ,
73
81
properties,
74
82
required,
@@ -82,6 +90,16 @@ export default class Validator<T> {
82
90
} ) ;
83
91
}
84
92
93
+ static partial < T extends Record < string , any > > ( v : Validator < T > ) : Validator < Partial < T > > {
94
+ const schema = v . getSchema ( ) ;
95
+ if ( ! ( 'type' in schema ) ) throw new Error ( 'Must apply partial only to a type definition' ) ;
96
+ if ( schema . type !== 'object' ) throw new Error ( 'Must only apply partial to an object schema' ) ;
97
+ return new Validator ( {
98
+ ...schema ,
99
+ required : [ ] ,
100
+ } ) ;
101
+ }
102
+
85
103
static array < V extends Validator < any > > ( v : V [ ] ) {
86
104
return new Validator < Array < ValidType < V > > > ( {
87
105
type : 'array' ,
@@ -96,6 +114,10 @@ export default class Validator<T> {
96
114
} ) ;
97
115
}
98
116
117
+ static intersect < T1 , T2 > ( v1 : Validator < T1 > , v2 : Validator < T2 > ) {
118
+ return new Validator < T1 & T2 > ( { allOf : [ v1 . getSchema ( ) , v2 . getSchema ( ) ] } ) ;
119
+ }
120
+
99
121
private constructor ( private schema : Schema ) { }
100
122
101
123
private getAjv = once ( ( ) => new Ajv ( ) ) ;
@@ -131,6 +153,14 @@ export default class Validator<T> {
131
153
} ;
132
154
return this ;
133
155
}
156
+
157
+ or < V extends Validator < any > > ( v : V ) : Validator < T | ValidType < V > > {
158
+ return Validator . union ( [ this , v ] ) ;
159
+ }
160
+
161
+ and < V extends Validator < any > > ( v : V ) : Validator < T & ValidType < V > > {
162
+ return Validator . intersect ( this , v ) ;
163
+ }
134
164
}
135
165
136
166
export type ValidType < V extends Validator < any > > = V extends Validator < infer T > ? T : never ;
0 commit comments