import {toString, isArray} from 'lodash'; import {mapObject} from './utilities'; interface Matcher { (input: Input): boolean; } interface Matcher { (input: Input, fields: Fields): boolean; } interface StringMapper { (input: string): any; } type ErrorContent = string | StringMapper; export function lengthMoreThan(length: number) { return (input: {length: number}) => input.length > length; } export function lengthLessThan(length: number) { return (input: {length: number}) => input.length < length; } export function isNumericString(input: string) { return input !== '' && (input.match(/[^0-9.,]/g) || []).length === 0; } export function isEmpty(input: any) { // eslint-disable-next-line no-undefined return input === null || input === undefined || input.length === 0; } export function isEmptyString(input: string) { return input.trim().length < 1; } export function not(matcher: Matcher): Matcher; export function not(matcher: Matcher) { return (input: Input, fields: Fields) => !matcher(input, fields); } export function validateNested( validatorDictionary: any, ) { // eslint-disable-next-line consistent-return return (input: Input, fields: Fields) => { const errors = mapObject(input, (value, field) => { const validate = validatorDictionary[field]; if (validate == null) { return null; } if (typeof validate === 'function') { return validate(value, fields); } if (!isArray(validate)) { // eslint-disable-next-line consistent-return return; } const errors = validate .map(validator => validator(value, fields)) .filter(input => input != null); if (errors.length === 0) { // eslint-disable-next-line consistent-return return; } return errors; }); const anyErrors = Object.keys(errors) .map(key => errors[key]) .some(value => value != null); if (anyErrors) { return errors; } }; } export function validateList( validatorDictionary: any, ) { const validateItem = validateNested(validatorDictionary); // eslint-disable-next-line consistent-return return (input: Input[], fields: Fields) => { const errors = input.map(item => validateItem(item, fields)); if (errors.some(error => error != null)) { return errors; } }; } export function validate( matcher: Matcher, errorContent: ErrorContent, ): (input: Input) => ErrorContent | void; export function validate( matcher: Matcher, errorContent: ErrorContent, ) { return (input: Input, fields: Fields) => { const matches = matcher(input, fields); if (matches) { return; } if (typeof errorContent === 'function') { // eslint-disable-next-line consistent-return return errorContent(toString(input)); } // eslint-disable-next-line consistent-return return errorContent; }; } const validators = { lengthMoreThan(length: number, errorContent: ErrorContent) { return validate(lengthMoreThan(length), errorContent); }, lengthLessThan(length: number, errorContent: ErrorContent) { return validate(lengthLessThan(length), errorContent); }, numericString(errorContent: ErrorContent) { return validate(isNumericString, errorContent); }, requiredString(errorContent: ErrorContent) { return validate(not(isEmptyString), errorContent); }, nonNumericString(errorContent: ErrorContent) { return validate(not(isNumericString), errorContent); }, required(errorContent: ErrorContent) { return validate(not(isEmpty), errorContent); }, }; export default validators;