on e82c628 help sign in
bridge/src/form/validators.js
116 lines 3.5 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// error object has errors if some of its fields are
33// 1) an array with any defined values
34// 2) any defined values
35export const hasErrors = iter =>
36 some(iter, v => (Array.isArray(v) ? hasErrors(v) : v !== undefined));
38export const buildPatqValidator = (validators = []) =>
39 buildValidator([validateNotEmpty, validatePatq, ...validators]);
40export const buildMnemonicValidator = () =>
41 buildValidator([validateNotEmpty, validateMnemonic]);
42export const buildCheckboxValidator = mustBe =>
43 buildValidator([
44 validateOneOf(mustBe !== undefined ? [mustBe] : [true, false]),
45 ]);
46export const buildPassphraseValidator = () => buildValidator([]);
47// TODO: validate hdpath format
48export const buildHdPathValidator = () => buildValidator([validateNotEmpty]);
49export const buildPointValidator = (size = 4, validators = []) =>
50 buildValidator([
51 validateNotEmpty,
52 validateMaximumPatpByteLength(size),
53 validatePoint,
54 ...validators,
55 ]);
56export const buildSelectValidator = options =>
57 buildValidator([validateOneOf(options.map(option => option.value))]);
58export const buildHexValidator = length =>
59 buildValidator([
60 validateNotEmpty,
61 validateHexString,
62 validateHexLength(length),
63 ]);
64export const buildUploadValidator = () => buildValidator([validateNotEmpty]);
65export const buildAddressValidator = () =>
66 buildValidator([
67 validateNotEmpty,
68 validateHexString,
69 validateHexLength(40),
70 validateNotNullAddress,
71 validateEthereumAddress,
72 ]);
73export const buildNumberValidator = (min = 0) =>
74 buildValidator([validateGreaterThan(min)]);
75export const buildEmailValidator = () =>
76 buildValidator([validateNotEmpty, validateEmail]);
78// the default form validator just returns field-level validations
79const kDefaultFormValidator = (values, errors) => errors;
81// the form validator is the composition of all of the field validators
82// plus an additional form validator function
83export const composeValidator = (
84 fieldValidators = {},
85 formValidator = kDefaultFormValidator
86) => {
87 const names = Object.keys(fieldValidators);
89 const fieldLevelValidators = names.map(name => value =>
90 fieldValidators[name](value)
91 );
93 // async reduce errors per-field into an errors object
94 const fieldLevelValidator = async values => {
95 const errors = await Promise.all(
96 names.map((name, i) => fieldLevelValidators[i](values[name]))
97 );
99 return names.reduce(
100 (memo, name, i) => ({
101 ...memo,
102 [name]: errors[i],
103 }),
104 {}
105 );
106 };
108 // final-form `validate` function
109 return async values => {
110 // ask for field-level errors
111 const errors = await fieldLevelValidator(values);
112 // pass the current values and their validity to the form-level validator
113 // that can implement conditional logic and more complex validations
114 return await formValidator(values, errors);
115 };
116};