-
Notifications
You must be signed in to change notification settings - Fork 0
/
Validator.ts
57 lines (50 loc) · 2.09 KB
/
Validator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import React from 'react'
import { CancellablePromise } from 'real-cancellable-promise'
/**
* If the value is valid, a validator should return something falsy
* (`undefined`, `null`, or `''`). If the value is invalid, the validator should
* return validation feedback which will be displayed to the user. The
* validation feedback can be a string or a `ReactNode` (e.g. a JSX element).
*
* There are two special values of `ValidatorOutput`:
*
* - [[`ASYNC_VALIDATION_PENDING`]]: The value should be considered invalid
* because async validation is in progress.
* - [[`ASYNC_VALIDATION_DEBOUNCE_PENDING`]]: The value should be considered invalid
* because async validation has not started yet.
* - [[`INVALID_NO_FEEDBACK`]]: The value is invalid but no feedback should be
* displayed **because the reason why the input is invalid is being displayed
* somewhere else.**
*/
export type ValidatorOutput = string | undefined | null | React.ReactNode
export const ASYNC_VALIDATION_PENDING = 'ASYNC_VALIDATION_PENDING'
export const ASYNC_VALIDATION_DEBOUNCE_PENDING = 'ASYNC_VALIDATION_DEBOUNCE_PENDING'
export const INVALID_NO_FEEDBACK = 'INVALID_NO_FEEDBACK'
/** The "contract" that all validators must implement. */
export type Validator<TValue> = (value: TValue) => ValidatorOutput
/** The "contract" that all async validators must implement. */
export type AsyncValidator<TValue> = (
input: TValue
) => CancellablePromise<ValidatorOutput>
/**
* Takes in multiple `ValidatorOutput`'s and returns the first invalid one, or
* `undefined` if all are valid.
*/
export function combineValidatorOutput(outputs: ValidatorOutput[]): ValidatorOutput {
for (const output of outputs) {
if (output) {
return output
}
}
return undefined
}
/**
* Applies multiple validators to a value and returns the combined result. Thin wrapper
* around [[`combineValidatorOutput`]].
*/
export function getCombinedValidatorOutput<TValue>(
value: TValue,
validators: Validator<TValue>[]
): ValidatorOutput {
return combineValidatorOutput(validators.map((v) => v(value)))
}