UNPKG

@byted/koa-validation

Version:

The Koa Validation is a single point validation library that enables you to validate params, body, queries, files and headers

339 lines (283 loc) 10.2 kB
'use strict'; var RequiredRules = require('./requiredRules'); var Rules = require('./rules'); var Filters = require('./filters'); class FieldValidator{ constructor(context, fields, rules, messages, filters){ this.ctx = context; this.fields = fields; this.filters = new Filters(this); this.rules = new Rules(this); this.requiredRules = new RequiredRules(this); this.rule = {}; this.validations = {}; this.parseRulesAndFilters(rules, messages, filters); } parseKey(key, data){ var value; var self = this; let keySplit = key.split('.').filter(function(e){ return e !== ''; }); keySplit.map(function(item){ if(typeof value === 'undefined'){ value = data && data[item]; }else{ value = value[item]; } }); return value; } addError(key, type, rule, message){ if (!this.ctx.validationErrors) { this.ctx.validationErrors = []; } var e = {}; e[key] = { type: type, message: message }; if(type === 'filter') e[key].filter = rule; else e[key].rule = rule; this.ctx.validationErrors.push(e); } changeFieldValue(key, value){ key = key.split('.') if(typeof key[1] === 'undefined'){ if(typeof this.fields[key[0]] !== 'undefined') this.fields[key[0]] = value; }else{ var lastField = this.fields; for (var i = 0; i < key.length; ++i){ if(typeof lastField[key[i]] !== 'undefined'){ if(i === key.length - 1){ lastField[key[i]] = value; }else{ lastField = lastField[key[i]] } }else{ break; } } } return; } parseRulesAndFilters(rules, messages, filters) { let rsplit , argsplit , args , fieldfilters , fieldValue , fbSplit , faSplit , fbargsSplit , faargsSplit; if(typeof filters.before === 'undefined') { filters.before = {} }; if(typeof filters.after === 'undefined') { filters.after = {} }; if(Object.keys(rules).length){ for (var r in rules){ if(!this.validations[r]){ this.validations[r] = { field: r, value: this.parseKey(r, this.fields), required: false, rules: [], filters: { before: [], after: [] } }; } if(typeof rules[r] === 'object'){ for(var er in rules[r]){ this.rule = { rule: er }; if(Array.isArray(rules[r][er]) && rules[r][er].length){ this.rule.args = (rules[r][er].length > 1) ? rules[r][er]: rules[r][er][0]; } this.populateRule(r, rules[r], messages); } }else{ rsplit = rules[r].split('|'); for (var rs in rsplit){ argsplit = rsplit[rs].split(':'); if(typeof argsplit[1] !== 'undefined'){ args = argsplit[1].split(','); this.rule = { rule: argsplit[0], args: (args.length > 1) ? args: args[0] }; }else{ this.rule = { rule: argsplit[0] }; } this.populateRule(r, argsplit[0], messages); } } } } if(Object.keys(filters.before).length){ for(var bf in filters.before){ this.populateFilters('before', bf, filters.before[bf]); } } if(Object.keys(filters.after).length){ for(var ba in filters.after){ this.populateFilters('after', ba, filters.after[ba]); } } } populateRule(field, rule, messages){ if(typeof messages[field+'.'+rule] !== 'undefined'){ this.rule.message = messages[field+'.'+rule]; }else if(typeof messages[rule] !== 'undefined'){ this.rule.message = messages[rule]; } if(this.rule.message){ if(this.rule.message.indexOf(':attribute') !== -1){ this.rule.message = eachRule.message.replace(':attribute', r); } if(this.rule.message.indexOf(':value') !== -1){ if(typeof this.validations[field].value === 'object'){ this.rule.message = eachRule.message.replace(':value', JSON.stringify(this.validations[field].value)); }else if(typeof this.validations[field].value === 'undefined'){ this.rule.message = eachRule.message.replace(':value', 'undefined'); }else{ this.rule.message = eachRule.message.replace(':value', this.validations[field].value.toString()); } } } if(typeof this.requiredRules[this.rule.rule] === 'function'){ this.validations[field].rules.unshift(this.rule); }else{ this.validations[field].rules.push(this.rule); } this.rule = {}; } populateFilters(type, field, filters){ let fSplit, fargsSplit, typeFilters, args; if(!this.validations[field]){ this.validations[field] = { field: field, value: this.parseKey(field, this.fields), required: false, rules: [], filters: { before: [], after: [] } }; } if(type === 'before'){ typeFilters = this.validations[field].filters.before; }else if(type === 'after'){ typeFilters = this.validations[field].filters.after; } if(typeof filters === 'object'){ for(var ef in filters){ if(Array.isArray(filters[ef]) && filters[ef].length){ typeFilters.push({ filter: ef, args: filters[ef] }); } } }else{ fSplit = filters.split('|'); for (var f = 0; f < fSplit.length; ++f){ fargsSplit = fSplit[f].split(':'); if(typeof fargsSplit[1] !== 'undefined'){ args = fargsSplit[1].split(','); typeFilters.push({ filter: fargsSplit[0], args: args }); }else{ typeFilters.push({ filter: fargsSplit[0] }); } } } } get valid(){ return this.applyRulesAndFilters(); } async applyRulesAndFilters(){ let fieldValidations = []; for(var i in this.validations){ fieldValidations.push(this.evaluateField(this.validations[i])); } if (fieldValidations.length) await fieldValidations; return (this.ctx.validationErrors && this.ctx.validationErrors.length) ? false : true; } async evaluateField(field){ let proceed = true; if(field.filters.before.length){ for (var fb = 0; fb < field.filters.before.length; ++fb){ if(typeof this.filters[field.filters.before[fb].filter] !== 'undefined'){ if(typeof field.value !== 'undefined' && field.value.toString().trim()){ field.value = await this.filters[field.filters.before[fb].filter].apply(this.filters, [field.field, field.value].concat( field.filters.before[fb].args || [] )); if(typeof field.value === 'undefined'){ break; }else{ this.changeFieldValue(field.field, field.value); } } }else{ this.addError(field.field, 'filter', field.rules[r].rule,'Invalid filter: '+ field.filters.before[fb].filter +' does not exist'); proceed = false; break; } } } if(!proceed) { return; } if(field.rules.length){ for(var r = 0; r < field.rules.length; ++r){ if(typeof this.requiredRules[field.rules[r].rule] === 'function'){ var ruleArgs = [field.field, field.value]; if(field.rules[r].args) ruleArgs.push(field.rules[r].args); if(field.rules[r].message) ruleArgs.push(field.rules[r].message); if(await this.requiredRules[field.rules[r].rule].apply(this.requiredRules, ruleArgs)){ field.required = true; }else{ proceed = false; break; } }else if(typeof this.rules[field.rules[r].rule] === 'function'){ if((!field.required && typeof field.value !== 'undefined') || field.required){ var ruleArgs = [field.field, field.value]; if(field.rules[r].args) ruleArgs.push(field.rules[r].args); if(field.rules[r].message) ruleArgs.push(field.rules[r].message); if(!(await this.rules[field.rules[r].rule].apply(this.rules, ruleArgs))){ proceed = false; break; } }else{ proceed = false; break; } }else{ this.addError(field.field, 'rule', field.rules[r].rule, 'Invalid Validation Rule: '+ field.rules[r].rule +' does not exist'); proceed = false; break; } } } if(!proceed) { return; } if(field.filters.after.length){ for (var fa = 0; fa < field.filters.after.length; ++fa){ if(typeof this.filters[field.filters.after[fa].filter] !== 'undefined'){ if(typeof field.value !== 'undefined' && field.value.toString().trim()){ field.value = await this.filters[field.filters.after[fa].filter].apply(this.filters, [field.field, field.value].concat( field.filters.after[fa].args || [] )); if(typeof field.value !== 'undefined'){ proceed = false; break; }else{ this.changeFieldValue(field.field, field.value); } } }else{ this.addError(field.field, 'filter', field.filters.after[fa].filter, 'Invalid filter: '+ field.filters.after[fa].filter +' does not exist'); proceed = false; break; } } } return; } } module.exports = FieldValidator;