UNPKG

@amaui/ui-react

Version:
204 lines (184 loc) 8.25 kB
import is from '@amaui/utils/is'; import isValid from '@amaui/utils/isValid'; import { capitalize, cleanValue, equalDeep, merge, stringify } from '@amaui/utils'; import { ValidationError } from '@amaui/errors'; export const onValidateError = (options, model, message) => { const error = new ValidationError(message); // Entire model message if (options.message !== undefined) error.message = options.message; // model item message else if (model.message !== undefined) error.message = model.message; // error throw error; }; const validate = async (model, property, form, options_) => { const options = merge(options_ && is('object', options_) ? options_ : {}, { uriDecode: true, parse: true }); const name = is('function', model.propertyNameUpdate) ? model.propertyNameUpdate(model.name) : model.capitalize !== false ? capitalize(model.name) : model.name; const value = model.value; // value validate // with options above // required if (model.required) { const response = value; if (response === undefined) onValidateError(options, model, model.messages?.required || `${name} is required`); } // only validate // if value is not undefined // as it is optional if (value === undefined) return; // is if (model.is !== undefined) { const is_ = (is('array', model.is) ? model.is : [model.is]).filter(Boolean); for (const item of is_) { const itemType = item?.type || item; const itemOptions = item?.options || undefined; const response = is(itemType, value, itemOptions); if (!response) onValidateError(options, model, model.messages?.is || `${name} has to be a valid ${cleanValue(itemType)}`); } } // is valid if (model.isValid !== undefined) { const isValid_ = (is('array', model.isValid) ? model.isValid : [model.isValid]).filter(Boolean); for (const item of isValid_) { const itemType = item?.type || item; const itemOptions = item?.options || undefined; const response = isValid(itemType, value, itemOptions); if (!response) onValidateError(options, model, model.messages?.isValid || `${name} has to be a valid ${cleanValue(itemType)}`); } } // of if (model.of !== undefined) { const of_ = (is('array', model.of) ? model.of : [model.of]).filter(Boolean); if (is('array', value)) { const response = value.every(valueItem => { return of_.some(item => { const itemType = item?.type || item; const itemOptions = item?.options || undefined; return is(itemType, valueItem, itemOptions); }); }); if (!response) onValidateError(options, model, model.messages?.of || `${name} items have to be one of ${of_.map(item => item?.type || item).join(', ')}`); } } // ofValid if (model.ofValid !== undefined) { const ofValid = (is('array', model.ofValid) ? model.ofValid : [model.ofValid]).filter(Boolean); if (is('array', value)) { const response = value.every(valueItem => { return ofValid.some(item => { const itemType = item?.type || item; const itemOptions = item?.options || undefined; return isValid(itemType, valueItem, itemOptions); }); }); if (!response) onValidateError(options, model, model.messages?.ofValid || `${name} items have to be one of valid ${ofValid.map(item => item?.type || item).join(', ')}`); } } // equal if (model.equal !== undefined) { const response = value === model.equal; if (!response) onValidateError(options, model, model.messages?.equal || `${name} has to be equal to ${stringify(model.equal)}`); } // not equal if (model.notEqual !== undefined) { const response = value !== model.equal; if (!response) onValidateError(options, model, model.messages?.notEqual || `${name} has to not be equal to ${stringify(model.equal)}`); } // equal deep if (model.equalDeep !== undefined) { const response = equalDeep(value, model.equalDeep); if (!response) onValidateError(options, model, model.messages?.equalDeep || `${name} has to be equal to ${stringify(model.equalDeep)}`); } // not equal deep if (model.notEqualDeep !== undefined) { const response = !equalDeep(value, model.notEqualDeep); if (!response) onValidateError(options, model, model.messages?.notEqualDeep || `${name} has to not be equal to ${stringify(model.notEqualDeep)}`); } // some if (is('array', model.some)) { let response; if (is('string', value)) { response = !!model.some.find(item => equalDeep(value, item)); if (!response) onValidateError(options, model, model.messages?.some || `${name} has to be one of ${model.some.map(item => stringify(item)).join(', ')}`); } else if (is('array', value)) { response = value.some(item => !!model.some.find(item_ => equalDeep(item, item_))); if (!response) onValidateError(options, model, model.messages?.some || `${name} has to include some of ${model.some.map(item => stringify(item)).join(', ')}`); } } // in // every const every = model.in || model.every; if (is('array', every)) { let response; if (is('string', value)) { response = !!every.find(item => equalDeep(value, item)); if (!response) onValidateError(options, model, model.messages?.in || model.messages?.every || `${name} has to be one of ${every.map(item => stringify(item)).join(', ')}`); } else if (is('array', value)) { response = value.every(item => !!every.find(item_ => equalDeep(item, item_))); if (!response) onValidateError(options, model, model.messages?.in || model.messages?.every || `${name} has to include one of ${every.map(item => stringify(item)).join(', ')}`); } } // properties if (is('array', model.properties)) { const allowed = model.properties; const keys = Object.keys(value); const response = keys.every(item => allowed.includes(item)); if (!response) onValidateError(options, model, model.messages?.properties || `${name} allowed properties are ${allowed.join(', ')}`); } // not properties if (is('array', model.notProperties)) { const notAllowed = model.notProperties; const keys = Object.keys(value); const response = keys.every(item => !notAllowed.includes(item)); if (!response) onValidateError(options, model, model.messages?.notProperties || `${name} includes not allowed property. Not allowed properties are ${notAllowed.join(', ')}`); } // min // max // length if (![undefined, null].includes(value) && (is('number', model.min) || is('number', model.max) || is('number', model.length))) { let length = value; // object if (is('object', value)) length = Object.keys(value).length; // number else if (is('number', value)) length = value; // string, array, map, etc. else { length = value?.length !== undefined ? value?.length : value?.size; } if (is('number', model.min)) { const response = length >= model.min; if (!response) onValidateError(options, model, model.messages?.min || `${name} has to be minimum ${model.min}`); } if (is('number', model.max)) { const response = length <= model.max; if (!response) onValidateError(options, model, model.messages?.max || `${name} can be maximum ${model.max}`); } if (is('number', model.length)) { const response = length === model.length; if (!response) onValidateError(options, model, model.messages?.length || `${name} has to be exactly ${model.length} in length/size`); } } // method const methods = (is('array', model.method) ? model.method : [model.method]).filter(Boolean); for (const method_ of methods) { try { // either throw error or Promise.reject or return false const response = await method_(value, { form, object: model, property, options }); if (response !== undefined) { if (!response) throw new ValidationError(`${name} is invalid`); } } catch (error) { const messageValue = error?.message !== undefined ? error.message : error; onValidateError(options, model, model.messages?.method || messageValue); } } }; export default validate;