on e006bf2 help sign in
bridge/src/form/validators.js
118 lines 3.7 kB history raw
1import { some } from 'lodash';
3import {
4 validateNotEmpty,
5 validatePatq,
6 validateMnemonic,
7 validatePoint,
8 validateMaximumPatpByteLength,
9 validateOneOf,
10 validateHexString,
11 validateHexLength,
12 validateEthereumAddress,
13 validateGreaterThan,
14 validateEmail,
15 validateNotNullAddress,
16} from 'lib/validators';
18// iterate over validators, exiting early if there's an error
19const buildValidator = (validators = []) => async value => {
20 for (const validator of validators) {
21 try {
22 const error = await validator(value);
23 if (error) {
24 return error;
25 }
26 } catch (error) {
27 return error.message;
28 }
29 }
30};
32// maps a validator across an array of values
33export const buildArrayValidator = validator => async values =>
34 await Promise.all(values.map(validator));
36// error object has errors if some of its fields are
37// 1) an array with any defined values
38// 2) any defined values
39export const hasErrors = iter =>
40 some(iter, v => (Array.isArray(v) ? hasErrors(v) : v !== undefined));
42export const buildPatqValidator = (validators = []) =>
43 buildValidator([validateNotEmpty, validatePatq, ...validators]);
44export const buildMnemonicValidator = () =>
45 buildValidator([validateNotEmpty, validateMnemonic]);
46export const buildCheckboxValidator = mustBe =>
47 buildValidator([
48 validateOneOf(mustBe !== undefined ? [mustBe] : [true, false]),
49 ]);
50export const buildPassphraseValidator = () => buildValidator([]);
51// TODO: validate hdpath format
52export const buildHdPathValidator = () => buildValidator([validateNotEmpty]);
53export const buildPointValidator = (size = 4, validators = []) =>
54 buildValidator([
55 validateNotEmpty,
56 validateMaximumPatpByteLength(size),
57 validatePoint,
58 ...validators,
59 ]);
60export const buildSelectValidator = options =>
61 buildValidator([validateOneOf(options.map(option => option.value))]);
62export const buildHexValidator = length =>
63 buildValidator([
64 validateNotEmpty,
65 validateHexString,
66 validateHexLength(length),
67 ]);
68export const buildUploadValidator = () => buildValidator([validateNotEmpty]);
69export const buildAddressValidator = () =>
70 buildValidator([
71 validateNotEmpty,
72 validateHexString,
73 validateHexLength(40),
74 validateNotNullAddress,
75 validateEthereumAddress,
76 ]);
77export const buildNumberValidator = (min = 0) =>
78 buildValidator([validateGreaterThan(min)]);
79export const buildEmailValidator = (validators = []) =>
80 buildValidator([validateNotEmpty, validateEmail, ...validators]);
82// the form validator is the composition of all of the field validators
83// plus an additional form validator function
84export const composeValidator = (
85 fieldValidators = {},
86 // the default form validator just returns field-level validations
87 formValidator = (values, errors) => errors
88) => {
89 const names = Object.keys(fieldValidators);
91 const fieldLevelValidators = names.map(name => value =>
92 fieldValidators[name](value)
93 );
95 // async reduce errors per-field into an errors object
96 const fieldLevelValidator = async values => {
97 const errors = await Promise.all(
98 names.map((name, i) => fieldLevelValidators[i](values[name]))
99 );
101 return names.reduce(
102 (memo, name, i) => ({
103 ...memo,
104 [name]: errors[i],
105 }),
106 {}
107 );
108 };
110 // the final-form `validate` function
111 return async values => {
112 // ask for field-level errors
113 const errors = await fieldLevelValidator(values);
114 // pass the current values and their validity to the form-level validator
115 // that can implement conditional logic and more complex validations
116 return await formValidator(values, errors);
117 };
118};