UNPKG

simple-body-validator

Version:

This package is inspired by Laravel validation, and aims to make body validation easier for Javascript developers

128 lines (127 loc) 4.89 kB
'use strict'; import validationData from './validationData'; import ClosureValidationRule from '../rules/closureValidationRule'; import RuleContract from '../rules/ruleContract'; const validationRuleParser = { /** * Convert rules to array */ explodeRules: function (rules, data = {}) { let implicitAttributes = {}; for (let key in rules) { if (key.indexOf('*') !== -1) { rules = this.explodeWildCardRules(rules, key, data, implicitAttributes); delete rules[key]; } else if (rules.hasOwnProperty(key)) { rules[key] = this.explodeExplicitRules(rules[key]); } } return { rules, implicitAttributes }; }, /** * Define a set of rules that apply to each element in an array attribute. */ explodeWildCardRules: function (results, attribute, masterData, implicitAttributes) { const pattern = new RegExp('^' + attribute.replace(/\*/g, '[^.]*') + '$'); const data = validationData.initializeAndGatherData(attribute, masterData); const rule = results[attribute]; for (let key in data) { if (key.slice(0, attribute.length) === attribute || key.match(pattern) !== null) { if (Array.isArray(implicitAttributes[attribute])) { implicitAttributes[attribute].push(key); } else { implicitAttributes[attribute] = [key]; } results = this.mergeRulesForAttribute(results, key, rule); } } return results; }, /** * Merge additional rules into a given attribute. */ mergeRulesForAttribute(results, attribute, rules) { const merge = this.explodeRules([rules]).rules[0]; results[attribute] = [...results[attribute] ? this.explodeExplicitRules(results[attribute]) : [], ...merge]; return results; }, /** * In case the rules specified by the user are a string seperated with '|' - convert them to an array */ explodeExplicitRules: function (rules) { if (typeof rules === 'string') { return rules.split('|'); } if (!Array.isArray(rules)) { return [this.prepareRule(rules)]; } return rules.map((rule) => this.prepareRule(rule)); }, /** * Prepare the given rule for the Validator. */ prepareRule(rule) { if (typeof rule === 'function') { return new ClosureValidationRule(rule); } if (rule instanceof RuleContract) { return rule; } return rule.toString(); }, /** * Extract the rule name and parameters from a rule. */ parse(rule) { if (rule instanceof RuleContract) { return [rule, []]; } return this.parseStringRule(rule); }, /** * Parse the parameters associated with a rule */ parseStringRule: function (rule) { let parameters = []; let parameter; if (rule.indexOf(':') !== -1) { [rule, parameter] = rule.split(/:(.+)/); parameters = parameter.split(','); } return [rule, parameters]; }, /** * Get a rule and its parameters for a given attribute. */ getRule: function (attribute, searchRules, availableRules) { // The available rules are all the rules specified by the uer for example - // { name: ['requied', 'string'], age: ['required', 'gt:10']} // A valid attribute in that case would be age if (!availableRules[attribute]) { return []; } // The search rule can be either a string or an array - lets say we want check if the 'gt' rule exists for // the age attrtibute - in that case the serachRules will be equal to 'gt' - In case an array is used // the method will return the data for the first matched rule searchRules = Array.isArray(searchRules) ? searchRules : [searchRules]; for (let i = 0; i < availableRules[attribute].length; i++) { let [rule, parameters] = this.parse(availableRules[attribute][i]); if (searchRules.indexOf(rule) !== -1) { // return the rule and parameters for the first match return [rule, parameters]; } } return []; }, /** * Determine if the given attribute has a rule in the given set of available rules. */ hasRule: function (attribute, searchRules, availableRules) { return this.getRule(attribute, searchRules, availableRules).length > 0; }, }; export default validationRuleParser;