UNPKG

simple-body-validator

Version:

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

133 lines (132 loc) 4.89 kB
'use strict'; import { isSizeRule } from './general'; import Lang from '../lang'; import { dotify } from './object'; /** * Get the message type based on the value. The message type is used essentially for size rules */ function getMesageType(value, hasNumericRule = false) { if (typeof value === 'number' || typeof value === 'undefined' || (isNaN(value) === false && hasNumericRule === true)) { return 'number'; } if (Array.isArray(value)) { return 'array'; } return typeof value; } ; /** * Get the custom message for a rule if exists */ function getCustomMessage(attributes, rule, customMessages, messageType, lang) { // The primary attribute is only used for wildcard rules, for example if the attribute is 'user.1.email' // the primary attribute value will be 'user.*.email' let [attribute, primaryAttribute] = attributes; // get the translated messages form the custom attribute in the language file const translatedMessages = dotify(Lang.get(lang)['custom'] || {}); // The key combination will look something like this [user.*.email.required, *.email.required, email.required, required] // This way we will be able to search all the possible combinations const keys = getKeyCombinations(`${attribute}.${rule}`); let allKeys = keys; // If the primary attribute exists we should merge all the combinations together if (primaryAttribute) { allKeys = []; const primaryAttributeKeys = getKeyCombinations(`${primaryAttribute}.${rule}`); for (let i = 0; i < keys.length; i++) { allKeys.push(keys[i]); if (keys[i] !== primaryAttributeKeys[i]) { allKeys.push(primaryAttributeKeys[i]); } } } if (isSizeRule(rule)) { allKeys.pop(); allKeys.push(`${rule}.${messageType}`); allKeys.push(rule); } let key = ''; let message = ''; for (let i = 0; i < allKeys.length; i++) { key = allKeys[i]; // The developer may dynamically specify the object of custom messages on the validator instance // If the key exists in the object it is used over the other ways of pulling the // message for this given key if (customMessages.hasOwnProperty(key)) { return customMessages[key]; } // try to get the custom error message from the translation file message = translatedMessages[key]; if (typeof message === 'string') { return message; } } return null; } ; /** * Get the validation message for an attribute and rule. */ export function getMessage(attributes, rule, value, customMessages, hasNumericRule, lang) { // check if error exists inside the custom message object provided by the user const inlineMessage = getCustomMessage(attributes, rule, customMessages, getMesageType(value, hasNumericRule), lang); if (inlineMessage) { return inlineMessage; } const validationMessages = Lang.get(lang); // check if rule has sizes such as min, max, between ... // and get message from local object if (isSizeRule(rule) === true) { return validationMessages[rule][getMesageType(value, hasNumericRule)]; } // get message from local object return validationMessages[rule] || ''; } ; /** * Convert a string to snake case. */ export function toSnakeCase(string) { return string .split(/ |\B(?=[A-Z])/) .map(word => word.toLowerCase()) .join('_'); } ; /** * Get the formatted name of the attribute */ export function getFormattedAttribute(attribute) { return toSnakeCase(getPrimaryKeyFromPath(attribute)).replace(/_/g, ' ').trim(); } ; /** * Get the combinations of keys from a main key. For example if the main key is 'user.info.name', * the combination will be [user.info.name, info.name, name] */ export function getKeyCombinations(key) { const combinations = [key]; const splittedKey = key.split('.'); while (splittedKey.length > 1) { splittedKey.shift(); combinations.push(splittedKey.join('.')); } return combinations; } /** * The purpose of this method if to get the primary key associated with a path * For example the primary key for path 'user.info.email' will be 'email' */ function getPrimaryKeyFromPath(path) { const splittedPath = path.split('.'); // if the '.' does not exist in the path, then return the path itself if (splittedPath.length <= 1) { return path; } let key = splittedPath.pop(); // if the new key is a number, check the next attribute if (isNaN(parseInt(key)) === false) { return getPrimaryKeyFromPath(splittedPath.join('.')); } return key; } ;