UNPKG

react-form-generator

Version:
171 lines (145 loc) 5.38 kB
var t = require( '../tools' ) , reduce = t.reduce , getOrNull = t.getOrNull; /** * Provides validation for GeneratedForm. * Can be configured by `conf` arguments: * @param {Object} conf - settings of validation. * @param {Object[]} conf.validators - array of custom validators. */ module.exports = function ( conf ) { conf = conf || {}; var VALIDATORS = t.merge( require( './validators' ), conf.validators ); VALIDATORS.or = composite( t.or, false ); VALIDATORS.and = composite( t.and, true ); /** * Build composite validator, which * combines result of all nested validators * by `comb` function. * * @param {Function} comp - `and`, `or`, etc. * @param {Object} zero - intital value of composite * validator result. * @returns {Function) */ function composite ( comb, zero ) { return function ( conf, value, fieldMeta ) { var validators = conf.value; return reduce(function ( acc, v ) { var f = VALIDATORS[ v.rule ]; checkRuleExistence( f, v.rule ); return comb( acc, f( v, value, fieldMeta ) ); }, zero, validators ); }; } /** * Validates field's value against of validation rule. * Returs sublist of validateion rules that was not sutisfied * by value. * @param {Object} ruleInfo - validation rules. * @param {Object} value - value to validate. * @param {Object} fieldMeta - for some validation rules * field meta is required. * @returns {Object} */ function checkByRule ( ruleInfo, value, fieldMeta ) { var rule = ruleInfo.rule , isValid = VALIDATORS[ rule ]; checkRuleExistence( isValid, rule ); return isValid( ruleInfo, value, fieldMeta ) ? null : ruleInfo; } function checkRuleExistence ( validate, rule ) { if ( !validate ) throw new Error( 'Valdiation rule does not exist: ' + rule ); } /** * Validates field's value against list of validation rules. * Returs sublist of validation rules that was not sutisfied * by value. * @param {Object[]} rules - list of validation rules. * @param {Object} value - value to validate. * @returns {Object[]} */ function checkByAll ( rules, value, fieldMeta ) { return (rules || []) .map(function ( rule ) { return checkByRule( rule, value, fieldMeta ); }) .filter(function ( el ) { return null !== el; }); } /** * Calculates field's validity by it's meta and value. * @param {Object} fieldMeta - metadata of one field * in FormGenerator format. * @param {Object} value - { %fieldID%: %fieldValue% } * @return {Object[]} - [ %failed_validators% ] */ function validateField ( fldID, fieldMeta, value ) { var res = {} , errs = checkByAll( fieldMeta.validators, value, fieldMeta ); res[ fldID ] = errs.length ? errs : null; return res; } /** * Calculates validity of the array of fields. * @param {Object[]} fldsMeta - array of metadata. * @param {Object[]} fldsValue - map with fields value. * @returns {Object} - { * %fieldID%: [ %failed_validators% ], * ... * } */ function validateFields ( fldsMeta, fldsValue ) { return reduce(function ( acc, fldMeta, fldID ) { var value = getOrNull( fldsValue, fldID ) , errors = validateField( fldID, fldMeta, value ); return t.merge( acc, errors ); }, {}, fldsMeta ); } /** * Calculates form's validity by it's meta and value. * Wraps `validateFields` and filters array of fields * before validation. * @param {Object} formMeta - metadata in GeneratedForm format. * @param {Object} formValue - data in GeneratedForm format. * @returns {Object} - { * %fieldID%: [ %failed_validators% ], * ... * } */ function validateForm ( formMeta, formValue ) { var fields = getOrNull( formMeta, 'fields' ) , validable = reduce(function ( acc, fld, fldID ) { var noValidate = !t.isDefined( fld.validators ) || fld.isHidden || fld.isReadOnly , fldMeta = {}; if ( noValidate ) return acc; else { fldMeta[ fldID ] = fld; return t.merge( acc, fldMeta ); } }, {}, fields ); return validateFields( validable, formValue ); } /** * Accepts result of `validateForm` and returns true * if `formErrors` contains only null-values. * @param {Object} formErrors - { * %fieldID%: [ %failed_validators% ], * ... * } * @returns {Boolean} */ function isFormValid ( formErrors ) { return t.reduce(function ( acc, v, k ) { return acc && !(v && v.length); }, true, formErrors ); } return { validateField: validateField, validateForm: validateForm, isFormValid: isFormValid }; };