justus 0.0.6 → 0.1.0

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.
@@ -1,22 +1,32 @@
1
1
  import ts from 'typescript'
2
2
  import {
3
3
  AllOfValidator,
4
+ any,
4
5
  AnyArrayValidator,
5
6
  AnyNumberValidator,
6
7
  AnyObjectValidator,
7
8
  AnyStringValidator,
8
9
  AnyValidator,
10
+ array,
9
11
  ArrayValidator,
10
12
  assertSchema,
13
+ boolean,
11
14
  BooleanValidator,
12
15
  ConstantValidator,
16
+ date,
13
17
  DateValidator,
14
18
  getValidator,
19
+ NeverValidator,
20
+ number,
15
21
  NumberValidator,
22
+ object,
16
23
  ObjectValidator,
17
24
  OneOfValidator,
25
+ OptionalValidator,
26
+ string,
18
27
  StringValidator,
19
28
  TupleValidator,
29
+ url,
20
30
  URLValidator,
21
31
  Validation,
22
32
  Validator,
@@ -42,14 +52,13 @@ type ValidatorConstructor<V extends Validator = Validator> = { // <T = any> = {
42
52
  * ========================================================================== */
43
53
 
44
54
  /** Registry of all `Validator` constructors and related `TypeGenerator`s. */
45
- const generators = new Map<Function, TypeGenerator<any>>()
55
+ const generators = new Map<Function | Validator, TypeGenerator<any>>()
46
56
 
47
57
  /** Register a `TypeGenerator` function for a `Validator`. */
48
58
  export function registerTypeGenerator<V extends Validator>(
49
- validator: ValidatorConstructor<V>,
59
+ validator: V | ValidatorConstructor<V>,
50
60
  generator: TypeGenerator<V>,
51
61
  ): void {
52
- assertSchema(validator.prototype instanceof Validator, 'Not a `Validator` class')
53
62
  generators.set(validator, generator)
54
63
  }
55
64
 
@@ -84,7 +93,7 @@ export function generateTypes(validations: Record<string, Validation>): string {
84
93
 
85
94
  // Create a type alias declaration with the name of the export
86
95
  const modifiers = [ ts.factory.createModifier(ts.SyntaxKind.ExportKeyword) ]
87
- const decl = ts.factory.createTypeAliasDeclaration(undefined, modifiers, name, [], type)
96
+ const decl = ts.factory.createTypeAliasDeclaration(modifiers, name, [], type)
88
97
  types.push(decl)
89
98
  }
90
99
 
@@ -107,7 +116,7 @@ function generateTypeNode(
107
116
  const reference = references.get(validator)
108
117
  if (reference) return ts.factory.createTypeReferenceNode(reference)
109
118
 
110
- const generator = generators.get(validator.constructor)
119
+ const generator = generators.get(validator) || generators.get(validator.constructor)
111
120
  assertSchema(!! generator, `Type generator for "${validator.constructor.name}" not found`)
112
121
  return generator(validator, references)
113
122
  }
@@ -122,17 +131,16 @@ const booleanType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeywor
122
131
  const numberType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
123
132
  const neverType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)
124
133
  const stringType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
134
+ const undefinedType = ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
125
135
  const recordType = ts.factory.createMappedTypeNode(
126
136
  undefined, // readonly
127
- ts.factory.createTypeParameterDeclaration('key', stringType),
137
+ ts.factory.createTypeParameterDeclaration([], 'key', stringType),
128
138
  undefined, // name type
129
139
  undefined, // question token
130
140
  anyType, // type of the mapped key
131
141
  undefined) // members
132
142
 
133
- // Modifiers and tokens
134
-
135
- const readonlyKeyword = [ ts.factory.createModifier(ts.SyntaxKind.ReadonlyKeyword) ]
143
+ // "Optional" modifier (the "?" token )
136
144
  const optionalKeyword = ts.factory.createToken(ts.SyntaxKind.QuestionToken)
137
145
 
138
146
 
@@ -146,9 +154,19 @@ registerTypeGenerator(AnyNumberValidator, () => numberType)
146
154
  registerTypeGenerator(AnyObjectValidator, () => recordType)
147
155
  registerTypeGenerator(AnyStringValidator, () => stringType)
148
156
  registerTypeGenerator(BooleanValidator, () => booleanType)
157
+ registerTypeGenerator(NeverValidator, () => neverType)
149
158
  registerTypeGenerator(DateValidator, () => ts.factory.createTypeReferenceNode('Date'))
150
159
  registerTypeGenerator(URLValidator, () => ts.factory.createTypeReferenceNode('URL'))
151
160
 
161
+ registerTypeGenerator(any, () => anyType)
162
+ registerTypeGenerator(array, () => anyArrayType)
163
+ registerTypeGenerator(number, () => numberType)
164
+ registerTypeGenerator(object, () => recordType)
165
+ registerTypeGenerator(string, () => stringType)
166
+ registerTypeGenerator(boolean, () => booleanType)
167
+ registerTypeGenerator(date, () => ts.factory.createTypeReferenceNode('Date'))
168
+ registerTypeGenerator(url, () => ts.factory.createTypeReferenceNode('URL'))
169
+
152
170
  /* ========================================================================== */
153
171
 
154
172
  // Complex generator functions...
@@ -179,6 +197,11 @@ registerTypeGenerator(NumberValidator, (validator: NumberValidator) => {
179
197
  return ts.factory.createIntersectionTypeNode([ numberType, literal ])
180
198
  })
181
199
 
200
+ registerTypeGenerator(OptionalValidator, (validator: OptionalValidator, references) => {
201
+ const type = generateTypeNode(validator.validator, references)
202
+ return ts.factory.createUnionTypeNode([ type, undefinedType ])
203
+ })
204
+
182
205
  registerTypeGenerator(StringValidator, (validator: StringValidator) => {
183
206
  if (! validator.brand) return stringType
184
207
 
@@ -244,26 +267,29 @@ registerTypeGenerator(OneOfValidator, (validator, references) => {
244
267
  registerTypeGenerator(ObjectValidator, (validator, references) => {
245
268
  const properties: ts.PropertySignature[] = []
246
269
 
247
- for (const [ key, property ] of validator.properties.entries()) {
248
- const { validator, readonly, optional } = property || { optional: true }
249
- const type = validator ? generateTypeNode(validator, references) : neverType
270
+ for (const [ key, valueValidator ] of validator.validators.entries()) {
271
+ const type = generateTypeNode(valueValidator, references)
272
+ const optional = valueValidator.optional
250
273
 
251
274
  const signature = ts.factory.createPropertySignature(
252
- readonly ? readonlyKeyword : undefined,
253
- key,
254
- optional ? optionalKeyword : undefined,
255
- type)
275
+ undefined,
276
+ key,
277
+ optional ? optionalKeyword : undefined,
278
+ type)
256
279
 
257
280
  properties.push(signature)
258
281
  }
259
282
 
260
283
  if (validator.additionalProperties) {
284
+ const propertyType = generateTypeNode(validator.additionalProperties, references)
285
+ const optionalPropertyType = ts.factory.createUnionTypeNode([ propertyType, undefinedType ])
286
+
261
287
  const extra = ts.factory.createMappedTypeNode(
262
288
  undefined, // readonly
263
- ts.factory.createTypeParameterDeclaration('key', stringType),
289
+ ts.factory.createTypeParameterDeclaration([], 'key', stringType),
264
290
  undefined, // name type
265
291
  undefined, // question token
266
- generateTypeNode(validator.additionalProperties, references),
292
+ optionalPropertyType, // (type | undefined)
267
293
  undefined) // members
268
294
 
269
295
  if (properties.length == 0) return extra
package/src/index.ts CHANGED
@@ -15,8 +15,10 @@ export { _array, array, arrayOf, AnyArrayValidator, ArrayConstraints, ArrayValid
15
15
  export { boolean, BooleanValidator } from './validators/boolean'
16
16
  export { constant, ConstantValidator } from './validators/constant'
17
17
  export { _date, date, DateConstraints, DateValidator } from './validators/date'
18
+ export { never, NeverValidator } from './validators/never'
18
19
  export { _number, number, AnyNumberValidator, BrandedNumberConstraints, NumberConstraints, NumberValidator } from './validators/number'
19
- export { _object, object, AnyObjectValidator, ObjectProperty, ObjectValidator } from './validators/object'
20
+ export { _object, object, AnyObjectValidator, ObjectValidator } from './validators/object'
21
+ export { optional, OptionalValidator } from './validators/optional'
20
22
  export { _string, string, AnyStringValidator, BrandedStringConstraints, StringConstraints, StringValidator } from './validators/string'
21
23
  export { tuple, TupleMember, TupleValidator } from './validators/tuple'
22
24
  export { _url, url, URLConstraints, URLValidator } from './validators/url'
package/src/schema.ts CHANGED
@@ -3,15 +3,10 @@ import { getValidator } from './utilities'
3
3
 
4
4
  import {
5
5
  AdditionalProperties,
6
- CombinedModifier,
7
6
  InferValidation,
8
- Modifier,
9
- OptionalModifier,
10
- ReadonlyModifier,
11
7
  Validation,
12
8
  Validator,
13
9
  additionalValidator,
14
- modifierValidator,
15
10
  } from './types'
16
11
 
17
12
  /* ========================================================================== *
@@ -28,7 +23,7 @@ export function _allowAdditionalProperties(options?: Validation | boolean): Addi
28
23
  if (options === false) return { [additionalValidator]: false }
29
24
  if (options === true) return { [additionalValidator]: any }
30
25
 
31
- return { [additionalValidator]: getValidator(options) }
26
+ return { [additionalValidator]: options ? getValidator(options) : any }
32
27
  }
33
28
 
34
29
  /**
@@ -44,69 +39,3 @@ export const allowAdditionalProperties = _allowAdditionalProperties as
44
39
  typeof _allowAdditionalProperties & AdditionalProperties<Validator<any>>
45
40
 
46
41
  allowAdditionalProperties[additionalValidator] = any
47
-
48
- /* ========================================================================== *
49
- * SCHEMA KEYS MODIFIERS *
50
- * ========================================================================== */
51
-
52
- export type CombineModifiers<M1 extends Modifier, M2 extends Modifier> =
53
- M1 extends ReadonlyModifier ?
54
- M2 extends ReadonlyModifier<infer V> ? ReadonlyModifier<V> :
55
- M2 extends OptionalModifier<infer V> ? CombinedModifier<V> :
56
- never :
57
- M1 extends OptionalModifier ?
58
- M2 extends ReadonlyModifier<infer V> ? CombinedModifier<V> :
59
- M2 extends OptionalModifier<infer V> ? OptionalModifier<V> :
60
- never :
61
- never
62
-
63
- /* -------------------------------------------------------------------------- */
64
-
65
- /** Type guard for `Modifier` instances */
66
- export function isModifier(what: any): what is Modifier<any> {
67
- return (what && (typeof what === 'object') && (modifierValidator in what))
68
- }
69
-
70
- /* -------------------------------------------------------------------------- */
71
-
72
- /**
73
- * Ensure that the property is marked as _read only_ in the `Schema`.
74
- *
75
- * @param validation - A `Validation` to be marked as _read only_.
76
- */
77
- export function readonly(): ReadonlyModifier<any>
78
- export function readonly<V extends Validation>(validation: V): ReadonlyModifier<Validator<InferValidation<V>>>
79
- export function readonly<M extends Modifier>(modifier: M): CombineModifiers<ReadonlyModifier, M>
80
-
81
- export function readonly(options?: Modifier | Validation): Modifier {
82
- const { [modifierValidator]: validation = any, optional = false } =
83
- isModifier(options) ? options : { [modifierValidator]: options }
84
-
85
- const validator = getValidator(validation)
86
-
87
- return optional ?
88
- { [modifierValidator]: validator, optional, readonly: true } :
89
- { [modifierValidator]: validator, readonly: true }
90
- }
91
-
92
- /* -------------------------------------------------------------------------- */
93
-
94
- /**
95
- * Ensure that the property is marked as _optional_ in the `Schema`.
96
- *
97
- * @param validation - A `Validation` to be marked as _optional_.
98
- */
99
- export function optional(): OptionalModifier<any>
100
- export function optional<V extends Validation>(validation: V): OptionalModifier<Validator<InferValidation<V>>>
101
- export function optional<M extends Modifier>(modifier: M): CombineModifiers<OptionalModifier, M>
102
-
103
- export function optional(options?: Modifier<any> | Validation): Modifier<any> {
104
- const { [modifierValidator]: validation = any, readonly = false } =
105
- isModifier(options) ? options : { [modifierValidator]: options }
106
-
107
- const validator = getValidator(validation)
108
-
109
- return readonly ?
110
- { [modifierValidator]: validator, readonly, optional: true } :
111
- { [modifierValidator]: validator, optional: true }
112
- }
package/src/types.ts CHANGED
@@ -2,21 +2,18 @@
2
2
  * SYMBOLS IDENTIFYING SPECIAL FUNCTIONALITIES *
3
3
  * ========================================================================== */
4
4
 
5
+ /** A symbol indicating that an instance is (in fact) a `Validator`. */
6
+ export const isValidator = Symbol.for('justus.isValidator')
7
+
5
8
  /** A symbol indicating the `Validator` for a `Tuple`'s rest parameter. */
6
9
  export const restValidator = Symbol.for('justus.restValidator')
7
10
 
8
11
  /** A symbol indicating the `Validator` for a `Schema`. */
9
12
  export const schemaValidator = Symbol.for('justus.schemaValidator')
10
13
 
11
- /** A symbol indicating the `Validator` for a `Modifier`. */
12
- export const modifierValidator = Symbol.for('justus.modifierValidator')
13
-
14
14
  /** A symbol indicating the `Validator` for a `Schema`'s additional properties. */
15
15
  export const additionalValidator = Symbol.for('justus.additionalValidator')
16
16
 
17
- /** A symbol indicating that a `Schema` property is _forbidden_. */
18
- export const never = Symbol.for('justus.never')
19
-
20
17
  /* ========================================================================== *
21
18
  * BASIC VALIDATION TYPES *
22
19
  * ========================================================================== */
@@ -37,7 +34,45 @@ export interface ValidationOptions {
37
34
  * A `Validator` is an object capable of validating a given _value_ and
38
35
  * (possibly) converting it the required type `T`.
39
36
  */
40
- export abstract class Validator<T = any> implements Iterable<TupleRestParameter<T>> {
37
+ export interface Validator<T = any> extends Iterable<TupleRestParameter<T>> {
38
+ [isValidator]: true
39
+
40
+ optional?: boolean
41
+
42
+ /** Validate a _value_ and optionally convert it to the required `Type` */
43
+ validate(value: unknown, options: ValidationOptions): T
44
+
45
+ /** Allow any `Validator` to be used as a rest parameter in `Tuple`s */
46
+ [Symbol.iterator](): Generator<TupleRestParameter<T>>;
47
+ }
48
+
49
+ /**
50
+ * Create a validator "factory", that is a function that when invoked will
51
+ * create a new `Validator` according to the parameters specified. This function
52
+ * will also implement the `Validator` interface itself, using the `Validator`
53
+ * supplied as the first parameter.
54
+ */
55
+ export function makeValidatorFactory<
56
+ V extends Validator,
57
+ F extends (...args: any[]) => Validator,
58
+ >(validator: V, factory: F): F & V {
59
+ return Object.assign(factory, {
60
+ optional: validator.optional,
61
+ validate: validator.validate.bind(validator),
62
+ [Symbol.iterator]: validator[Symbol.iterator].bind(validator),
63
+ [isValidator]: true,
64
+ }) as F & V
65
+ }
66
+
67
+ /**
68
+ * A `Validator` is an object capable of validating a given _value_ and
69
+ * (possibly) converting it the required type `T`.
70
+ */
71
+ export abstract class AbstractValidator<T = any> implements Iterable<TupleRestParameter<T>> {
72
+ [isValidator]: true = true
73
+
74
+ optional?: boolean = undefined
75
+
41
76
  /** Validate a _value_ and optionally convert it to the required `Type` */
42
77
  abstract validate(value: unknown, options: ValidationOptions): T
43
78
 
@@ -58,7 +93,7 @@ export abstract class Validator<T = any> implements Iterable<TupleRestParameter<
58
93
  * * Either `null`, a `boolean`, a `number` or a `string` for constants
59
94
  */
60
95
  export type Validation =
61
- (() => Validator) | Validator | // Validator instances or their creators
96
+ Validator | // Validator instances
62
97
  Tuple | Schema | // Tuples or schemas (arrays, objects)
63
98
  null | boolean | number | string // Primitives, mapped as constants
64
99
 
@@ -69,33 +104,6 @@ export type InferValidation<V> =
69
104
  // Let `InferValidationType<T>` be liberal in the type it accepts and check
70
105
  // here whether it extends `Validation`
71
106
  V extends Validation ?
72
-
73
- // `Validation` can be a function returning a `Validator`, here we need to
74
- // extract the return value of its _zero-arguments_ overload
75
- V extends {
76
- (...args: infer A0): Validator<infer R0>;
77
- (...args: infer A1): Validator<infer R1>;
78
- (...args: infer A2): Validator<infer R2>;
79
- (...args: infer A3): Validator<infer R3>;
80
- (...args: infer A4): Validator<infer R4>;
81
- (...args: infer A5): Validator<infer R5>;
82
- (...args: infer A6): Validator<infer R6>;
83
- (...args: infer A7): Validator<infer R7>;
84
- (...args: infer A8): Validator<infer R8>;
85
- (...args: infer A9): Validator<infer R9>;
86
- } ?
87
- A0 extends [] ? R0 :
88
- A1 extends [] ? R1 :
89
- A2 extends [] ? R2 :
90
- A3 extends [] ? R3 :
91
- A4 extends [] ? R4 :
92
- A5 extends [] ? R5 :
93
- A6 extends [] ? R6 :
94
- A7 extends [] ? R7 :
95
- A8 extends [] ? R8 :
96
- A9 extends [] ? R9 :
97
- never :
98
-
99
107
  // Validators return their validation type
100
108
  V extends Validator<infer T> ? T :
101
109
 
@@ -175,7 +183,7 @@ export type InferTuple<T> =
175
183
  * how they should be validated.
176
184
  */
177
185
  export interface Schema {
178
- [ key: string ] : Validation | Modifier | typeof never
186
+ [ key: string ] : Validation
179
187
  [ additionalValidator ]?: Validator | false
180
188
  }
181
189
 
@@ -187,118 +195,23 @@ export interface AdditionalProperties<V extends Validator | false> {
187
195
  [ additionalValidator ]: V
188
196
  }
189
197
 
190
- /* -------------------------------------------------------------------------- */
191
-
192
- /**
193
- * A `Modifier` marks a `Schema` property either _read only_ and/or _optional_.
194
- */
195
- export interface Modifier<V extends Validator = Validator> {
196
- [ modifierValidator ]: V
197
- readonly?: true,
198
- optional?: true,
199
- }
200
-
201
- /**
202
- * Mark a `Schema` property as _read only_.
203
- */
204
- export interface ReadonlyModifier<V extends Validator = Validator> extends Modifier<V> {
205
- readonly: true,
206
- }
207
-
208
- /**
209
- * Mark a `Schema` property as _optional_.
210
- */
211
- export interface OptionalModifier<V extends Validator = Validator> extends Modifier<V> {
212
- optional: true,
213
- }
214
-
215
- /**
216
- * Mark a `Schema` property as both _optional_ and _read only_.
217
- */
218
- export interface CombinedModifier<V extends Validator = Validator>
219
- extends ReadonlyModifier<V>, OptionalModifier<V>, Modifier<V> {
220
- optional: true,
221
- readonly: true,
222
- }
223
-
224
198
  /* ========================================================================== *
225
199
  * INFER OBJECT TYPE FROM SCHEMA *
226
200
  * ========================================================================== */
227
201
 
228
202
  /** Infer the type validated by a `Schema` */
229
203
  export type InferSchema<S extends Schema> =
230
- InferReadonlyModifiers<S> &
231
- InferOptionalModifiers<S> &
232
- InferCombinedModifiers<S> &
233
- ( S extends AdditionalProperties<Validator<infer V>> ?
234
- Record<string, V> &
235
- InferNever<S> &
236
- InferRequired<S> :
237
- InferRequired<S> )
238
-
239
- /* -------------------------------------------------------------------------- */
240
-
241
- /** Infer the type of keys associated with `Validation`s */
242
- export type InferRequired<S extends Schema> = {
243
- [ key in keyof S as
244
- key extends string ?
245
- S[key] extends Validation ? key :
246
- never :
247
- never
248
- ] :
249
- S[key] extends Validation ? InferValidation<S[key]> :
250
- never
251
- }
252
-
253
- /* -------------------------------------------------------------------------- */
254
-
255
- /** Infer the type of _read only_ `Schema` properties */
256
- export type InferReadonlyModifiers<S extends Schema> = {
257
- readonly [ key in keyof S as
258
- key extends string ?
259
- S[key] extends OptionalModifier<Validator> ? never :
260
- S[key] extends ReadonlyModifier<Validator> ? key :
261
- never :
262
- never
263
- ] :
264
- S[key] extends ReadonlyModifier<infer V> ? InferValidation<V> : never
265
- }
266
-
267
- /** Infer the type of _optional_ `Schema` properties */
268
- export type InferOptionalModifiers<S extends Schema> = {
269
- [ key in keyof S as
270
- key extends string ?
271
- S[key] extends ReadonlyModifier<Validator> ? never :
272
- S[key] extends OptionalModifier<Validator> ? key :
273
- never :
274
- never
275
- ] ? :
276
- S[key] extends OptionalModifier<infer V> ? InferValidation<V> : never
277
- }
278
-
279
- /** Infer the type of _read only_ **and** _optional_ `Schema` properties */
280
- export type InferCombinedModifiers<S extends Schema> = {
281
- readonly [ key in keyof S as
282
- key extends string ?
283
- S[key] extends CombinedModifier ? key :
284
- never :
285
- never
286
- ] ? :
287
- S[key] extends CombinedModifier<infer V> ? InferValidation<V> : never
288
- }
289
-
290
- /* -------------------------------------------------------------------------- */
291
-
292
- /** Ensure that we properly type `never` properties */
293
- export type InferNever<S extends Schema> =
294
- { [ key in keyof S as
295
- key extends string ?
296
- S[key] extends typeof never ? key :
297
- never :
298
- never
299
- ] : never
204
+ S extends AdditionalProperties<Validator<infer V>> ?
205
+ { [ key in string ] : V | undefined } & InferSchema2<S> :
206
+ InferSchema2<S>
207
+
208
+ /** Infer the property types described by a `Schema` */
209
+ export type InferSchema2<S extends Schema> =
210
+ { [ key in keyof S as key extends string ? key : never ]:
211
+ InferValidation<S[key]>
300
212
  }
301
213
 
214
+
302
215
  /* ========================================================================== *
303
216
  * TYPE BRANDING *
304
217
  * ========================================================================== */
package/src/utilities.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { any } from './validators/any'
2
1
  import { ConstantValidator, nullValidator } from './validators/constant'
3
- import { Schema, schemaValidator, Validation, Validator } from './types'
2
+ import { isValidator, Schema, schemaValidator, Validation, Validator } from './types'
4
3
  import { TupleValidator } from './validators/tuple'
5
4
  import { ObjectValidator } from './validators/object'
6
5
 
@@ -13,13 +12,12 @@ import { ObjectValidator } from './validators/object'
13
12
  *
14
13
  * When `validation` is `undefined` it will return a `Validator<any>`,
15
14
  */
16
- export function getValidator(validation?: Validation): Validator {
17
- // Undefined maps to `any`, null is a constant
18
- if (validation === undefined) return any
15
+ export function getValidator(validation: Validation): Validator {
16
+ // Null is a constant
19
17
  if (validation === null) return nullValidator
20
18
 
21
- // Validator instances are simply returned
22
- if (validation instanceof Validator) return validation
19
+ // Validator instance (either object or function)
20
+ if ((<any> validation)[isValidator] === true) return validation as Validator
23
21
 
24
22
  // Other types
25
23
  switch (typeof validation) {
@@ -29,10 +27,6 @@ export function getValidator(validation?: Validation): Validator {
29
27
  case 'number':
30
28
  return new ConstantValidator(validation)
31
29
 
32
- // validator generator
33
- case 'function':
34
- return validation()
35
-
36
30
  // other objects...
37
31
  case 'object':
38
32
  // pre-compiled schema with validator
@@ -1,7 +1,7 @@
1
- import { Validator } from '../types'
1
+ import { AbstractValidator } from '../types'
2
2
 
3
3
  /** A `Validator` validating _anything_. */
4
- export class AnyValidator extends Validator<any> {
4
+ export class AnyValidator extends AbstractValidator<any> {
5
5
  validate(value: unknown): any {
6
6
  return value
7
7
  }
@@ -1,8 +1,7 @@
1
1
  import { assertSchema, assertValidation, ValidationErrorBuilder } from '../errors'
2
- import { InferValidation, Validation, ValidationOptions, Validator } from '../types'
2
+ import { InferValidation, Validation, ValidationOptions, AbstractValidator, Validator, makeValidatorFactory } from '../types'
3
3
  import { getValidator } from '../utilities'
4
4
  import { any } from './any'
5
- import { makeTupleRestIterable } from './tuple'
6
5
 
7
6
  /* ========================================================================== *
8
7
  * ARRAYS VALIDATION *
@@ -21,7 +20,7 @@ export interface ArrayConstraints<V extends Validation> {
21
20
  }
22
21
 
23
22
  /** Basic validator for `Array` instances. */
24
- export class AnyArrayValidator<T = any> extends Validator<T[]> {
23
+ export class AnyArrayValidator<T = any> extends AbstractValidator<T[]> {
25
24
  validate(value: unknown, options: ValidationOptions): T[] {
26
25
  void options
27
26
  assertValidation(Array.isArray(value), 'Value is not an "array"')
@@ -30,7 +29,7 @@ export class AnyArrayValidator<T = any> extends Validator<T[]> {
30
29
  }
31
30
 
32
31
  /** A validator for `Array` instances with constraints. */
33
- export class ArrayValidator<T> extends Validator<T[]> {
32
+ export class ArrayValidator<T> extends AbstractValidator<T[]> {
34
33
  readonly maxItems: number
35
34
  readonly minItems: number
36
35
  readonly uniqueItems: boolean
@@ -87,22 +86,15 @@ export class ArrayValidator<T> extends Validator<T[]> {
87
86
  }
88
87
  }
89
88
 
90
- const anyArrayValidator = new AnyArrayValidator()
91
-
92
89
  /* -------------------------------------------------------------------------- */
93
90
 
94
- export function _array(): Validator<any[]>
95
- export function _array<V extends Validation>(constraints: ArrayConstraints<V>): ArrayValidator<InferValidation<V>>
96
-
97
- export function _array(options?: ArrayConstraints<Validation>): Validator<any[]> {
98
- if (! options) return anyArrayValidator
99
-
100
- const items = getValidator(options.items)
101
- return new ArrayValidator({ ...options, items })
91
+ export function _array<V extends Validation>(constraints: ArrayConstraints<V>): ArrayValidator<InferValidation<V>> {
92
+ const items = constraints.items ? getValidator(constraints.items) : any
93
+ return new ArrayValidator({ ...constraints, items })
102
94
  }
103
95
 
104
96
  /** Validate `Array`s. */
105
- export const array = makeTupleRestIterable(_array)
97
+ export const array = makeValidatorFactory(new AnyArrayValidator(), _array)
106
98
 
107
99
  /** Validate `Array`s containing only the specified elements. */
108
100
  export function arrayOf<V extends Validation>(validation: V): ArrayValidator<InferValidation<V>> {
@@ -1,8 +1,8 @@
1
- import { Validator } from '../types'
1
+ import { AbstractValidator } from '../types'
2
2
  import { assertValidation } from '../errors'
3
3
 
4
4
  /** A `Validator` validating `boolean`s. */
5
- export class BooleanValidator extends Validator<boolean> {
5
+ export class BooleanValidator extends AbstractValidator<boolean> {
6
6
  validate(value: unknown): boolean {
7
7
  assertValidation(typeof value === 'boolean', 'Value is not a "boolean"')
8
8
  return value
@@ -1,8 +1,8 @@
1
- import { Validator } from '../types'
1
+ import { AbstractValidator, Validator } from '../types'
2
2
  import { assertValidation } from '../errors'
3
3
 
4
4
  /** A `Validator` for _constants_. */
5
- export class ConstantValidator<T extends string | number | boolean | null> extends Validator<T> {
5
+ export class ConstantValidator<T extends string | number | boolean | null> extends AbstractValidator<T> {
6
6
  readonly constant: T
7
7
 
8
8
  constructor(constant: T) {
@@ -1,6 +1,5 @@
1
1
  import { assertSchema, assertValidation, ValidationError } from '../errors'
2
- import { Validator } from '../types'
3
- import { makeTupleRestIterable } from './tuple'
2
+ import { AbstractValidator, makeValidatorFactory } from '../types'
4
3
 
5
4
  /** Lifted from AngularJS: matches a valid RFC 3339 string. */
6
5
  const ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))?)?$/
@@ -16,7 +15,7 @@ export interface DateConstraints {
16
15
  }
17
16
 
18
17
  /** A `Validator` validating dates and converting them to `Date` instances. */
19
- export class DateValidator extends Validator<Date> {
18
+ export class DateValidator extends AbstractValidator<Date> {
20
19
  readonly format?: 'iso' | 'timestamp'
21
20
  readonly from?: Date
22
21
  readonly until?: Date
@@ -65,14 +64,9 @@ export class DateValidator extends Validator<Date> {
65
64
  }
66
65
  }
67
66
 
68
- const anyDateValidator = new DateValidator()
69
-
70
- export function _date(): DateValidator
71
- export function _date(constraints: DateConstraints): DateValidator
72
-
73
- export function _date(constraints?: DateConstraints): DateValidator {
74
- return constraints ? new DateValidator(constraints) : anyDateValidator
67
+ export function _date(constraints: DateConstraints): DateValidator {
68
+ return new DateValidator(constraints)
75
69
  }
76
70
 
77
71
  /** Validate dates and convert them to `Date` instances. */
78
- export const date = makeTupleRestIterable(_date)
72
+ export const date = makeValidatorFactory(new DateValidator(), _date)