justus 0.4.2 → 0.5.1

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 (103) hide show
  1. package/README.md +78 -0
  2. package/dist/dts-generator.cjs +36 -22
  3. package/dist/dts-generator.cjs.map +1 -1
  4. package/dist/dts-generator.d.ts +1 -1
  5. package/dist/dts-generator.mjs +15 -22
  6. package/dist/dts-generator.mjs.map +1 -1
  7. package/dist/extra/arn.cjs +101 -0
  8. package/dist/extra/arn.cjs.map +6 -0
  9. package/dist/extra/arn.d.ts +73 -0
  10. package/dist/extra/arn.mjs +71 -0
  11. package/dist/extra/arn.mjs.map +6 -0
  12. package/dist/extra/ean13.cjs +52 -0
  13. package/dist/extra/ean13.cjs.map +6 -0
  14. package/dist/extra/ean13.d.ts +9 -0
  15. package/dist/extra/ean13.mjs +26 -0
  16. package/dist/extra/ean13.mjs.map +6 -0
  17. package/dist/{validators → extra}/url.cjs +4 -6
  18. package/dist/{validators → extra}/url.cjs.map +3 -3
  19. package/dist/{validators → extra}/url.d.ts +2 -2
  20. package/dist/{validators → extra}/url.mjs +4 -6
  21. package/dist/{validators → extra}/url.mjs.map +3 -3
  22. package/dist/extra/uuid.cjs +45 -0
  23. package/dist/extra/uuid.cjs.map +6 -0
  24. package/dist/extra/uuid.d.ts +10 -0
  25. package/dist/extra/uuid.mjs +18 -0
  26. package/dist/extra/uuid.mjs.map +6 -0
  27. package/dist/index.cjs +0 -5
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.ts +0 -2
  30. package/dist/index.mjs +0 -3
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/registry.cjs +44 -0
  33. package/dist/registry.cjs.map +6 -0
  34. package/dist/registry.d.ts +16 -0
  35. package/dist/registry.mjs +19 -0
  36. package/dist/registry.mjs.map +6 -0
  37. package/dist/schema.cjs +3 -5
  38. package/dist/schema.cjs.map +1 -1
  39. package/dist/schema.d.ts +6 -5
  40. package/dist/schema.mjs +3 -4
  41. package/dist/schema.mjs.map +1 -1
  42. package/dist/types.cjs.map +1 -1
  43. package/dist/types.d.ts +38 -12
  44. package/dist/types.mjs.map +1 -1
  45. package/dist/utilities.cjs +5 -7
  46. package/dist/utilities.cjs.map +1 -1
  47. package/dist/utilities.mjs +5 -7
  48. package/dist/utilities.mjs.map +1 -1
  49. package/dist/validators/array.cjs.map +1 -1
  50. package/dist/validators/array.d.ts +1 -1
  51. package/dist/validators/array.mjs.map +1 -1
  52. package/dist/validators/constant.cjs +4 -5
  53. package/dist/validators/constant.cjs.map +1 -1
  54. package/dist/validators/constant.d.ts +0 -2
  55. package/dist/validators/constant.mjs +3 -3
  56. package/dist/validators/constant.mjs.map +1 -1
  57. package/dist/validators/date.cjs +2 -6
  58. package/dist/validators/date.cjs.map +1 -1
  59. package/dist/validators/date.d.ts +1 -1
  60. package/dist/validators/date.mjs +2 -6
  61. package/dist/validators/date.mjs.map +1 -1
  62. package/dist/validators/number.cjs.map +1 -1
  63. package/dist/validators/number.d.ts +1 -1
  64. package/dist/validators/number.mjs.map +1 -1
  65. package/dist/validators/object.cjs +3 -2
  66. package/dist/validators/object.cjs.map +1 -1
  67. package/dist/validators/object.d.ts +4 -4
  68. package/dist/validators/object.mjs +4 -7
  69. package/dist/validators/object.mjs.map +1 -1
  70. package/dist/validators/optional.cjs.map +1 -1
  71. package/dist/validators/optional.d.ts +5 -4
  72. package/dist/validators/optional.mjs.map +1 -1
  73. package/dist/validators/string.cjs.map +1 -1
  74. package/dist/validators/string.d.ts +1 -1
  75. package/dist/validators/string.mjs.map +1 -1
  76. package/dist/validators/tuple.cjs +3 -2
  77. package/dist/validators/tuple.cjs.map +1 -1
  78. package/dist/validators/tuple.d.ts +3 -3
  79. package/dist/validators/tuple.mjs +3 -2
  80. package/dist/validators/tuple.mjs.map +1 -1
  81. package/dist/validators/union.cjs.map +1 -1
  82. package/dist/validators/union.d.ts +9 -7
  83. package/dist/validators/union.mjs.map +1 -1
  84. package/package.json +43 -3
  85. package/src/dts-generator.ts +17 -27
  86. package/src/extra/arn.ts +172 -0
  87. package/src/extra/ean13.ts +31 -0
  88. package/src/{validators → extra}/url.ts +4 -6
  89. package/src/extra/uuid.ts +18 -0
  90. package/src/index.ts +0 -2
  91. package/src/registry.ts +28 -0
  92. package/src/schema.ts +10 -11
  93. package/src/types.ts +80 -11
  94. package/src/utilities.ts +5 -9
  95. package/src/validators/array.ts +1 -1
  96. package/src/validators/constant.ts +3 -2
  97. package/src/validators/date.ts +7 -7
  98. package/src/validators/number.ts +1 -1
  99. package/src/validators/object.ts +13 -12
  100. package/src/validators/optional.ts +9 -7
  101. package/src/validators/string.ts +1 -1
  102. package/src/validators/tuple.ts +20 -6
  103. package/src/validators/union.ts +35 -10
package/src/types.ts CHANGED
@@ -49,7 +49,7 @@ export const defaultValidationOptions: Readonly<Required<ValidationOptions>> = {
49
49
  * A `Validator` is an object capable of validating a given _value_ and
50
50
  * (possibly) converting it the required type `T`.
51
51
  */
52
- export interface Validator<T = any> extends Iterable<TupleRestParameter<T>> {
52
+ export interface Validator<T = any, I = T> extends Iterable<TupleRestParameter<T, I>> {
53
53
  [Symbol.justusValidator]: this
54
54
 
55
55
  optional?: boolean
@@ -58,7 +58,7 @@ export interface Validator<T = any> extends Iterable<TupleRestParameter<T>> {
58
58
  validate(value: unknown, options?: ValidationOptions | undefined): T
59
59
 
60
60
  /** Allow any `Validator` to be used as a rest parameter in `Tuple`s */
61
- [Symbol.iterator](): Generator<TupleRestParameter<T>>;
61
+ [Symbol.iterator](): Generator<TupleRestParameter<T, I>>;
62
62
  }
63
63
 
64
64
  /**
@@ -83,8 +83,8 @@ export function makeValidatorFactory<
83
83
  * A `Validator` is an object capable of validating a given _value_ and
84
84
  * (possibly) converting it the required type `T`.
85
85
  */
86
- export abstract class AbstractValidator<T = any>
87
- implements Validator<T>, Iterable<TupleRestParameter<T>> {
86
+ export abstract class AbstractValidator<T, I = T>
87
+ implements Validator<T, I>, Iterable<TupleRestParameter<T, I>> {
88
88
  [Symbol.justusValidator] = this
89
89
 
90
90
  optional?: boolean = undefined
@@ -93,7 +93,7 @@ implements Validator<T>, Iterable<TupleRestParameter<T>> {
93
93
  abstract validate(value: unknown, options?: ValidationOptions | undefined): T
94
94
 
95
95
  /** Allow any `Validator` to be used as a rest parameter in `Tuple`s */
96
- * [Symbol.iterator](): Generator<TupleRestParameter<T>> {
96
+ * [Symbol.iterator](): Generator<TupleRestParameter<T, I>> {
97
97
  yield { [Symbol.justusRestValidator]: this }
98
98
  }
99
99
  }
@@ -118,7 +118,7 @@ export type Validation =
118
118
  */
119
119
  export type InferValidation<V> =
120
120
  // Validators return their validation type
121
- V extends Validator<infer T> ? T :
121
+ V extends Validator<infer T, any> ? T :
122
122
 
123
123
  // Primitives are returned as constants
124
124
  V extends undefined ? V :
@@ -133,6 +133,25 @@ export type InferValidation<V> =
133
133
  // Anyhing else can only be a schema
134
134
  InferSchema<V>
135
135
 
136
+ /**
137
+ * Infer the type compatible with a `Validation`'s input.
138
+ */
139
+ export type InferInput<V> =
140
+ // Validators return their validation type
141
+ V extends Validator<any, infer T> ? T :
142
+
143
+ // Primitives are returned as constants
144
+ V extends undefined ? V :
145
+ V extends boolean ? V :
146
+ V extends number ? V :
147
+ V extends string ? V :
148
+ V extends null ? V :
149
+
150
+ // // Tuples are inferred using their own types
151
+ V extends Tuple ? InferInputTuple<V> :
152
+
153
+ // // Anyhing else can only be a schema
154
+ InferInputSchema<V>
136
155
 
137
156
  /* ========================================================================== *
138
157
  * TUPLES *
@@ -140,16 +159,22 @@ export type InferValidation<V> =
140
159
 
141
160
  /** Infer the type validated by a `Validation` or `TupleRestParameter` */
142
161
  export type InferValidationOrTupleRest<T> =
143
- T extends TupleRestParameter<infer X> ? X :
162
+ T extends TupleRestParameter<infer X, any> ? X :
144
163
  T extends Validation ? InferValidation<T> :
145
164
  never
146
165
 
166
+ /** Infer the input type for a `Validation` or `TupleRestParameter` */
167
+ export type InferInputValidationOrTupleRest<T> =
168
+ T extends TupleRestParameter<any, infer X> ? X :
169
+ T extends Validation ? InferInput<T> :
170
+ never
171
+
147
172
  /* -------------------------------------------------------------------------- */
148
173
 
149
174
  /**
150
175
  * A `Tuple` is defined to be an array of `Validation` or `TupleRest`
151
176
  */
152
- export type Tuple = readonly (Validation | TupleRestParameter)[]
177
+ export type Tuple = readonly (Validation | TupleRestParameter<any, any>)[]
153
178
 
154
179
  /**
155
180
  * The `TupleRestParameter` defines a tuple member that can occur several
@@ -164,8 +189,8 @@ export type Tuple = readonly (Validation | TupleRestParameter)[]
164
189
  * const myTuple = tuple([ number, ...nonEmptyString ])
165
190
  * ```
166
191
  */
167
- export type TupleRestParameter<T = any> = {
168
- [Symbol.justusRestValidator] : Validator<T>
192
+ export type TupleRestParameter<T, I> = {
193
+ [Symbol.justusRestValidator] : Validator<T, I>
169
194
  }
170
195
 
171
196
  /**
@@ -187,6 +212,24 @@ export type InferTuple<T> =
187
212
  never :
188
213
  never
189
214
 
215
+ /**
216
+ * Infer a time compatible with a `TupleValidator`'s input.
217
+ */
218
+ export type InferInputTuple<T> =
219
+ T extends Tuple ?
220
+ T extends readonly [] ? [] :
221
+ T extends readonly [ Validation, ...any[] ] ?
222
+ T extends readonly [ infer V, ...infer Rest ] ?
223
+ [ InferInput<V>, ...InferInputTuple<Rest> ] :
224
+ never :
225
+ T extends readonly [ ...any[], Validation ] ?
226
+ T extends readonly [ ...infer Rest, infer V ] ?
227
+ [ ...InferInputTuple<Rest>, InferInput<V> ] :
228
+ never :
229
+ T extends readonly (infer V)[] ?
230
+ [ ...InferInputValidationOrTupleRest<V>[] ] :
231
+ never :
232
+ never
190
233
 
191
234
  /* ========================================================================== *
192
235
  * OBJECT SCHEMAS *
@@ -237,11 +280,37 @@ export type InferSchema2<S> = {
237
280
  InferValidation<S[key]>
238
281
  }
239
282
 
283
+ /** Infer the input type compatible with a `Schema` */
284
+ export type InferInputSchema<S> =
285
+ S extends AdditionalProperties<Validator<any, infer X>> ?
286
+ { [ key in string ] : X } & InferInputSchema2<S> :
287
+ InferInputSchema2<S>
288
+
289
+ /** Infer the input type of the properties described by a `Schema` */
290
+ export type InferInputSchema2<S> = {
291
+ // this first part of the type infers all keys from the schema into their
292
+ // type, but makes *each* key optional... we'll restrict in the next part...
293
+ [ key in keyof S as key extends string ? key : never ] ? : InferInput<S[key]>
294
+ } & {
295
+ // this second part infers *only* keys that _do not_ contain a "undefined"
296
+ // in their unions, and associates them with the inferred value, basically
297
+ // making the key *non optional*
298
+ [ key in keyof S as
299
+ key extends string ?
300
+ InferInput<S[key]> extends never ?
301
+ never :
302
+ undefined extends InferInput<S[key]> ?
303
+ never :
304
+ key :
305
+ never ] -? :
306
+ InferInput<S[key]>
307
+ }
308
+
240
309
  /* ========================================================================== *
241
310
  * TYPE BRANDING *
242
311
  * ========================================================================== */
243
312
 
244
313
  /** Utility type to infer primitive branding according to a string */
245
314
  export type Branding<S extends string> = {
246
- [ key in keyof { __brand: never } as `__brand_${S}` ] : never
315
+ [ brand in `__brand_${S}` ] : never
247
316
  }
package/src/utilities.ts CHANGED
@@ -1,8 +1,4 @@
1
- import { ConstantValidator, nullValidator } from './validators/constant'
2
- // eslint-disable-next-line import/no-cycle
3
- import { ObjectValidator } from './validators/object'
4
- // eslint-disable-next-line import/no-cycle
5
- import { TupleValidator } from './validators/tuple'
1
+ import { registry } from './registry'
6
2
 
7
3
  import type { Schema, Validation, Validator } from './types'
8
4
 
@@ -17,7 +13,7 @@ import type { Schema, Validation, Validator } from './types'
17
13
  */
18
14
  export function getValidator(validation: Validation): Validator {
19
15
  // Null is a constant
20
- if (validation === null) return nullValidator
16
+ if (validation === null) return new (registry.get('constant'))(null)
21
17
 
22
18
  // Anything with a validor associated with
23
19
  if ((<any> validation)[Symbol.justusValidator]) {
@@ -30,14 +26,14 @@ export function getValidator(validation: Validation): Validator {
30
26
  case 'boolean':
31
27
  case 'string':
32
28
  case 'number':
33
- return new ConstantValidator(validation)
29
+ return new (registry.get('constant'))(validation)
34
30
 
35
31
  // other objects...
36
32
  case 'object':
37
33
  // arrays are tuples
38
- if (Array.isArray(validation)) return new TupleValidator(validation)
34
+ if (Array.isArray(validation)) return new (registry.get('tuple'))(validation)
39
35
  // any other object is a schema
40
- return new ObjectValidator(validation as Schema)
36
+ return new (registry.get('object'))(validation as Schema)
41
37
 
42
38
  // definitely not one of our types
43
39
  default:
@@ -22,7 +22,7 @@ export interface ArrayConstraints<V extends Validation> {
22
22
  }
23
23
 
24
24
  /** Basic validator for `Array` instances. */
25
- export class AnyArrayValidator<T = any> extends AbstractValidator<T[]> {
25
+ export class AnyArrayValidator<T = any> extends AbstractValidator<T[], T[]> {
26
26
  validate(value: unknown): T[] {
27
27
  assertValidation(Array.isArray(value), 'Value is not an "array"')
28
28
  return [ ...value ]
@@ -1,4 +1,5 @@
1
1
  import { assertValidation } from '../errors'
2
+ import { registry } from '../registry'
2
3
  import { AbstractValidator } from '../types'
3
4
 
4
5
  import type { Validator } from '../types'
@@ -23,5 +24,5 @@ export function constant<T extends string | number | boolean | null>(constant: T
23
24
  return new ConstantValidator(constant)
24
25
  }
25
26
 
26
- /** The `Validator` for the `null` constant. */
27
- export const nullValidator = new ConstantValidator(null)
27
+ // Register our "constant" validator
28
+ registry.set('constant', ConstantValidator)
@@ -15,7 +15,7 @@ export interface DateConstraints {
15
15
  }
16
16
 
17
17
  /** A `Validator` validating dates and converting them to `Date` instances. */
18
- export class DateValidator extends AbstractValidator<Date> {
18
+ export class DateValidator extends AbstractValidator<Date, Date | string | number> {
19
19
  readonly format?: 'iso' | 'timestamp'
20
20
  readonly from?: Date
21
21
  readonly until?: Date
@@ -36,12 +36,12 @@ export class DateValidator extends AbstractValidator<Date> {
36
36
  }
37
37
 
38
38
  validate(value: unknown): Date {
39
- let date: Date
40
- try {
41
- date = new Date(value as any)
42
- } catch (error) {
43
- throw new ValidationError('Value could not be converted to a "Date"')
44
- }
39
+ const date =
40
+ value instanceof Date ? new Date(value.getTime()) :
41
+ typeof value === 'string' ? new Date(value) :
42
+ typeof value === 'number' ? new Date(value) :
43
+ undefined
44
+ assertValidation(!! date, 'Value could not be converted to a "Date"')
45
45
 
46
46
  if (isNaN(date.getTime())) throw new ValidationError('Invalid date')
47
47
 
@@ -53,7 +53,7 @@ export class AnyNumberValidator extends AbstractValidator<number> {
53
53
  }
54
54
 
55
55
  /** A `Validator` validating `number`s with constaints. */
56
- export class NumberValidator<N extends number = number> extends AbstractValidator<N> {
56
+ export class NumberValidator<N extends number = number> extends AbstractValidator<N, number> {
57
57
  #isMultipleOf?: ((value: number) => boolean)
58
58
 
59
59
  readonly allowNaN: boolean
@@ -1,15 +1,12 @@
1
1
  import { assertValidation, ValidationErrorBuilder } from '../errors'
2
- // eslint-disable-next-line import/no-cycle
3
- import { allowAdditionalProperties } from '../schema'
4
- import {
5
- AbstractValidator,
6
- defaultValidationOptions,
7
- makeValidatorFactory,
8
- } from '../types'
2
+ import { registry } from '../registry'
3
+ import { AbstractValidator, defaultValidationOptions, makeValidatorFactory } from '../types'
9
4
  import { getValidator } from '../utilities'
10
5
 
11
6
  import type {
12
- InferSchema, InferValidation, Schema, TupleRestParameter, Validation, ValidationOptions,
7
+ InferInputSchema,
8
+ InferSchema, InferValidation, Schema, TupleRestParameter, Validation,
9
+ ValidationOptions,
13
10
  Validator,
14
11
  } from '../types'
15
12
 
@@ -27,7 +24,7 @@ export class AnyObjectValidator extends AbstractValidator<Record<string, any>> {
27
24
  }
28
25
 
29
26
  /** A `Validator` validating `object`s according to a `Schema`. */
30
- export class ObjectValidator<S extends Schema> extends AbstractValidator<InferSchema<S>> {
27
+ export class ObjectValidator<S extends Schema> extends AbstractValidator<InferSchema<S>, InferInputSchema<S>> {
31
28
  readonly schema: Readonly<S>
32
29
 
33
30
  validators = new Map<string, Validator>()
@@ -118,10 +115,11 @@ export class ObjectValidator<S extends Schema> extends AbstractValidator<InferSc
118
115
  }
119
116
 
120
117
  export function objectFactory<S extends Schema>(schema: S): S & {
121
- [Symbol.iterator](): Generator<TupleRestParameter<InferSchema<S>>>
118
+ [Symbol.iterator](): Generator<TupleRestParameter<InferSchema<S>, InferInputSchema<S>>>
122
119
  } {
123
120
  const validator = new ObjectValidator(schema)
124
- function* iterator(): Generator<TupleRestParameter> {
121
+
122
+ function* iterator(): Generator<TupleRestParameter<any, any>> {
125
123
  yield { [Symbol.justusRestValidator]: validator }
126
124
  }
127
125
 
@@ -136,5 +134,8 @@ export const object = makeValidatorFactory(new AnyObjectValidator(), objectFacto
136
134
 
137
135
  /** Validate `Object`s containing only the specified elements. */
138
136
  export function objectOf<V extends Validation>(validation: V): Validator<Record<string, InferValidation<V>>> {
139
- return new ObjectValidator({ ...allowAdditionalProperties(validation) })
137
+ return new ObjectValidator({ [Symbol.justusAdditionalValidator]: getValidator(validation) })
140
138
  }
139
+
140
+ // Register our "object" validator
141
+ registry.set('object', ObjectValidator)
@@ -1,15 +1,16 @@
1
1
  import { AbstractValidator, defaultValidationOptions } from '../types'
2
2
  import { getValidator } from '../utilities'
3
3
 
4
- import type { InferValidation, Validation, ValidationOptions, Validator } from '../types'
4
+ import type { InferInput, InferValidation, Validation, ValidationOptions, Validator } from '../types'
5
5
 
6
6
  /**
7
7
  * A `Validator` for _optional_ properties (that is `type | undefined`).
8
8
  */
9
9
  export class OptionalValidator<
10
10
  T = any, // the type of the "validation", that is the optional type to validate
11
+ I = T, // the _input_ type of the "validation", that is anything acceptable
11
12
  D = undefined, // the default value (or undefined)
12
- > extends AbstractValidator<D extends undefined ? T | undefined : T> {
13
+ > extends AbstractValidator<D extends undefined ? T | undefined : T, I | undefined> {
13
14
  validator: Validator<T>
14
15
  defaultValue: T | undefined
15
16
 
@@ -32,8 +33,9 @@ export class OptionalValidator<
32
33
  }
33
34
  }
34
35
 
35
- validate(value: unknown, options?: ValidationOptions): D extends undefined ? T | undefined : T {
36
- if (value === undefined) return this.defaultValue as any // do not validate defaults!
36
+ validate(value: unknown, options?: ValidationOptions): D extends undefined ? T | undefined : T
37
+ validate(value: unknown, options?: ValidationOptions): T | undefined {
38
+ if (value === undefined) return this.defaultValue // do not validate defaults!
37
39
  return this.validator.validate(value, options)
38
40
  }
39
41
  }
@@ -45,15 +47,15 @@ export class OptionalValidator<
45
47
  */
46
48
  export function optional<
47
49
  V extends Validation
48
- >(validation: V): OptionalValidator<InferValidation<V>, undefined>
50
+ >(validation: V): OptionalValidator<InferValidation<V>, InferInput<V>, undefined>
49
51
 
50
52
  export function optional<
51
53
  V extends Validation, D,
52
- >(validation: V, defaultValue: D): OptionalValidator<InferValidation<V>, D>
54
+ >(validation: V, defaultValue: D): OptionalValidator<InferValidation<V>, InferInput<V>, D>
53
55
 
54
56
  export function optional<
55
57
  V extends Validation, D,
56
- >(validation: V, defaultValue?: D): OptionalValidator<InferValidation<V>> {
58
+ >(validation: V, defaultValue?: D): OptionalValidator<InferValidation<V>, InferInput<V>, D> {
57
59
  const validator = getValidator(validation)
58
60
  return new OptionalValidator(validator, defaultValue)
59
61
  }
@@ -28,7 +28,7 @@ export class AnyStringValidator extends AbstractValidator<string> {
28
28
  }
29
29
 
30
30
  /** A `Validator` validating `string`s with constraints. */
31
- export class StringValidator<S extends string = string> extends AbstractValidator<S> {
31
+ export class StringValidator<S extends string = string, I = string> extends AbstractValidator<S, I> {
32
32
  readonly maxLength: number
33
33
  readonly minLength: number
34
34
  readonly pattern?: RegExp
@@ -1,15 +1,22 @@
1
1
  import { assertValidation, ValidationError } from '../errors'
2
+ import { registry } from '../registry'
2
3
  import { AbstractValidator } from '../types'
3
- // eslint-disable-next-line import/no-cycle
4
4
  import { getValidator } from '../utilities'
5
- import { nullValidator } from './constant'
6
5
 
7
- import type { InferTuple, Tuple, ValidationOptions, Validator } from '../types'
6
+ import type {
7
+ InferInputTuple,
8
+ InferTuple,
9
+ Tuple,
10
+ TupleRestParameter,
11
+ Validation,
12
+ ValidationOptions,
13
+ Validator,
14
+ } from '../types'
8
15
 
9
16
  export interface TupleMember { single: boolean, validator: Validator }
10
17
 
11
18
  /** A `Validator` for _tuples_. */
12
- export class TupleValidator<T extends Tuple> extends AbstractValidator<InferTuple<T>> {
19
+ export class TupleValidator<T extends Tuple> extends AbstractValidator<InferTuple<T>, InferInputTuple<T>> {
13
20
  readonly members: readonly TupleMember[]
14
21
  readonly tuple: T
15
22
 
@@ -19,7 +26,7 @@ export class TupleValidator<T extends Tuple> extends AbstractValidator<InferTupl
19
26
  const members: TupleMember[] = []
20
27
  for (const item of tuple) {
21
28
  if (item === null) { // god knows why typeof null === "object"
22
- members.push({ single: true, validator: nullValidator })
29
+ members.push({ single: true, validator: getValidator(null) })
23
30
  } else if ((typeof item === 'object') && (Symbol.justusRestValidator in item)) {
24
31
  members.push({ single: false, validator: (<any>item)[Symbol.justusRestValidator] })
25
32
  } else {
@@ -77,6 +84,13 @@ export class TupleValidator<T extends Tuple> extends AbstractValidator<InferTupl
77
84
  }
78
85
 
79
86
  /** Validate _tuples_. */
80
- export function tuple<T extends Tuple>(tuple: T): Validator<InferTuple<T>> {
87
+ export function tuple<T extends
88
+ | readonly [ Validation | TupleRestParameter<any, any>, ...Tuple ]
89
+ | readonly [ ...Tuple, Validation | TupleRestParameter<any, any> ]
90
+ | readonly [ ...Tuple ] // ... this is bascially an array...
91
+ >(tuple: T): Validator<InferTuple<T>, InferInputTuple<T>> {
81
92
  return new TupleValidator(tuple)
82
93
  }
94
+
95
+ // Register our "tuple" validator
96
+ registry.set('tuple', TupleValidator)
@@ -3,6 +3,7 @@ import { AbstractValidator } from '../types'
3
3
  import { getValidator } from '../utilities'
4
4
 
5
5
  import type {
6
+ InferInput,
6
7
  InferValidation,
7
8
  Validation,
8
9
  ValidationOptions,
@@ -13,11 +14,11 @@ import type {
13
14
 
14
15
  export type OneOfArguments = readonly Validation[]
15
16
 
16
- export type InferOneOfValidationType<A extends OneOfArguments> =
17
+ export type InferOneOfValidation<A extends OneOfArguments> =
17
18
  A extends readonly [ infer First, ...infer Rest ] ?
18
19
  First extends Validation ?
19
20
  Rest extends OneOfArguments ?
20
- InferValidation<First> | InferOneOfValidationType<Rest> :
21
+ InferValidation<First> | InferOneOfValidation<Rest> :
21
22
  InferValidation<First> :
22
23
  never :
23
24
  A extends readonly (infer Type)[] ?
@@ -26,8 +27,22 @@ export type InferOneOfValidationType<A extends OneOfArguments> =
26
27
  never :
27
28
  never
28
29
 
30
+ export type InferOneOfInput<A extends OneOfArguments> =
31
+ A extends readonly [ infer First, ...infer Rest ] ?
32
+ First extends Validation ?
33
+ Rest extends OneOfArguments ?
34
+ InferInput<First> | InferOneOfValidation<Rest> :
35
+ InferInput<First> :
36
+ never :
37
+ A extends readonly (infer Type)[] ?
38
+ Type extends Validation ?
39
+ InferInput<Type> :
40
+ never :
41
+ never
42
+
29
43
  /** A `Validator` validating a value as _one of_ the specified arguments. */
30
- export class OneOfValidator<A extends OneOfArguments> extends AbstractValidator<InferOneOfValidationType<A>> {
44
+ export class OneOfValidator<A extends OneOfArguments>
45
+ extends AbstractValidator<InferOneOfValidation<A>, InferOneOfInput<A>> {
31
46
  readonly validators: readonly Validator[]
32
47
 
33
48
  constructor(args: A) {
@@ -36,7 +51,7 @@ export class OneOfValidator<A extends OneOfArguments> extends AbstractValidator<
36
51
  assertSchema(this.validators.length > 0, 'At least one validation required in "oneOf"')
37
52
  }
38
53
 
39
- validate(value: unknown, options?: ValidationOptions): InferOneOfValidationType<A> {
54
+ validate(value: unknown, options?: ValidationOptions): InferOneOfValidation<A> {
40
55
  const builder = new ValidationErrorBuilder()
41
56
  for (const validator of this.validators) {
42
57
  try {
@@ -45,7 +60,7 @@ export class OneOfValidator<A extends OneOfArguments> extends AbstractValidator<
45
60
  builder.record(error)
46
61
  }
47
62
  }
48
- return builder.assert(value as InferOneOfValidationType<A>)
63
+ return builder.assert(value as InferOneOfValidation<A>)
49
64
  }
50
65
  }
51
66
 
@@ -58,17 +73,27 @@ export function oneOf<A extends OneOfArguments>(...args: A): OneOfValidator<A> {
58
73
 
59
74
  export type AllOfArguments = readonly [ Validation, ...Validation[] ]
60
75
 
61
- export type InferAllOfValidationType<A extends AllOfArguments> =
76
+ export type InferAllOfValidation<A extends AllOfArguments> =
62
77
  A extends readonly [ infer First, ...infer Rest ] ?
63
78
  First extends Validation ?
64
79
  Rest extends AllOfArguments ?
65
- InferValidation<First> & InferAllOfValidationType<Rest> :
80
+ InferValidation<First> & InferAllOfValidation<Rest> :
66
81
  InferValidation<First> :
67
82
  never :
68
83
  never
69
84
 
85
+ export type InferAllOfInput<A extends AllOfArguments> =
86
+ A extends readonly [ infer First, ...infer Rest ] ?
87
+ First extends Validation ?
88
+ Rest extends AllOfArguments ?
89
+ InferInput<First> & InferAllOfValidation<Rest> :
90
+ InferInput<First> :
91
+ never :
92
+ never
93
+
70
94
  /** A `Validator` validating a value as _all of_ the specified arguments. */
71
- export class AllOfValidator<A extends AllOfArguments> extends AbstractValidator<InferAllOfValidationType<A>> {
95
+ export class AllOfValidator<A extends AllOfArguments>
96
+ extends AbstractValidator<InferAllOfValidation<A>, InferAllOfInput<A>> {
72
97
  readonly validators: readonly Validator[]
73
98
 
74
99
  constructor(args: A) {
@@ -77,11 +102,11 @@ export class AllOfValidator<A extends AllOfArguments> extends AbstractValidator<
77
102
  assertSchema(this.validators.length > 0, 'At least one validation required in "allOf"')
78
103
  }
79
104
 
80
- validate(value: unknown, options?: ValidationOptions): InferAllOfValidationType<A> {
105
+ validate(value: unknown, options?: ValidationOptions): InferAllOfValidation<A> {
81
106
  for (const validator of this.validators) {
82
107
  value = validator.validate(value, options)
83
108
  }
84
- return value as InferAllOfValidationType<A>
109
+ return value as InferAllOfValidation<A>
85
110
  }
86
111
  }
87
112