UNPKG

@sebgroup/frontend-tools

Version:
246 lines (243 loc) 9.84 kB
import { isEmpty } from '../isEmpty/isEmpty.js'; import { isPhoneNumber } from '../isPhoneNumber/isPhoneNumber.js'; import { isEmail } from '../isEmail/isEmail.js'; import { deepCopy } from '../deepCopy/deepCopy.js'; import { isStrongPassword } from '../isStrongPassword/isStrongPassword.js'; import { isValidDate } from '../isValidDate/isValidDate.js'; import { isDateBefore } from '../isDateBefore/isDateBefore.js'; import { isDateAfter } from '../isDateAfter/isDateAfter.js'; class ValidatorModelItem { constructor(name, value) { this.value = null; this.specs = {}; this.validations = []; this.name = name; this.value = value; this.specs = {}; this.validations = []; } } class FormValidator { constructor(formObject) { this.formObject = new Map(); this.formObjectErrors = {}; this.customValidators = []; if (!isEmpty(formObject) && typeof formObject === "object") { const clone = deepCopy(formObject); this.originalFormObject = clone; for (const field in clone) { this.formObject.set(field, new ValidatorModelItem(field, clone[field])); } } } addValidation(fields, type, specs) { if (fields && fields instanceof Array && type && typeof type === "string" && this.isValidType(type)) { if (fields.length) { fields.map((field) => { if (this.formObject.has(field)) { this.formObject.get(field).validations.push(type); if (!isEmpty(specs)) { this.formObject.get(field).specs = Object.assign(Object.assign({}, this.formObject.get(field).specs), specs); } } }); } else { this.formObject.forEach((item) => { item.validations.push(type); if (!isEmpty(specs)) { item.specs = Object.assign(Object.assign({}, item.specs), specs); } }); } } return this; } /** * Add a custom validator that returns an error message if found * @param {Array<string>} errorFields The fields where the error is reported to * @param {function} validator The validator method * @returns {FormValidator} The form validator object * @example addValidator(["balance", "payment"], ["payment"], (balance: number, payment: number) => { return payment > balance ? "The payment exceeds your balance" : null; }); */ addCustomValidation(errorFields, validator) { if (errorFields && errorFields instanceof Array && errorFields.length && validator && validator instanceof Function) { this.customValidators.push({ errorFields, validator }); } return this; } /** * Get the error found in the form object. Has to be called after `validate` method has been called. * @returns {any} The form object object populated by validation errors, if found any. Otherwise, it's an empty object. */ getErrors() { return this.formObjectErrors; } /** * Get a specific error found during validation, if any. Has to be called after `validate` method has been called. * @returns {any} The error of the specific item in the form, if any. */ getError(name) { return this.formObjectErrors[name]; } /** * Validates the form object passed in the constructor * @returns {FormValidator} The form validator object */ validate() { this.formObject.forEach((item) => { if (item.validations.length) { let fieldError; let i = 0; do { fieldError = this.validateField(item.value, item.validations[i], item.specs); if (!isEmpty(fieldError)) { this.formObjectErrors[item.name] = fieldError; } i++; } while (i < item.validations.length && !fieldError); } }); if (this.customValidators.length) { this.customValidators.map((customValidator) => { const customValidatorError = customValidator.validator(this.originalFormObject); customValidator.errorFields.map((field) => { if (this.formObject.has(field) && !this.getError(field) && customValidatorError) { this.formObjectErrors[field] = customValidatorError; } }); }); } return this; } /** * Validate a parameter in the form formObject based on predefined set of criteria * @param {ValidatorModelItem} fieldObject The field object stored in the local formObject * @returns {string} The error found in the parameter */ validateField(value, type, specs) { let fieldError = null; // Don't validate an empty field if it's not required const date = new Date(value); const empty = isEmpty(value); if (empty && type !== "required") { return null; } const valid = isValidDate(date); switch (type) { case "required": return empty ? { errorCode: "empty" } : null; case "isDate": return valid ? null : { errorCode: "invalidDate" }; case "dateRange": if (valid) { if (specs.minDate) { fieldError = isDateBefore(date, specs.minDate) ? { errorCode: "beforeMinDate", specs: { minDate: specs.minDate }, } : null; } if (!fieldError && specs.maxDate) { fieldError = isDateAfter(date, specs.maxDate) ? { errorCode: "afterMaxDate", specs: { maxDate: specs.maxDate }, } : null; } return fieldError; } else { return null; } case "textLength": if (typeof value === "string") { if (specs.minLength) { fieldError = value.length < specs.minLength ? { errorCode: "lessThanMinLength", specs: { minLength: specs.minLength }, } : null; } if (!fieldError && specs.maxLength) { fieldError = value.length > specs.maxLength ? { errorCode: "moreThanMaxLength", specs: { maxLength: specs.maxLength }, } : null; } return fieldError; } else { return null; } case "valueRange": if (typeof value === "number") { if (specs.minValue) { fieldError = value < specs.minValue ? { errorCode: "lessThanMinValue", specs: { minValue: specs.minValue }, } : null; } if (!fieldError && specs.maxValue) { fieldError = value > specs.maxValue ? { errorCode: "moreThanMaxValue", specs: { maxValue: specs.maxValue }, } : null; } return fieldError; } else { return null; } case "validEmail": return isEmail(value) ? null : { errorCode: "invalidEmail" }; case "strongPassword": return isStrongPassword(value) ? null : { errorCode: "weakPassword" }; case "isPhoneNumber": return isPhoneNumber(value) ? null : { errorCode: "invalidPhoneNumber" }; } } // Helpers isValidType(type) { const availableValidationTypes = { required: true, isDate: true, dateRange: true, textLength: true, valueRange: true, validEmail: true, strongPassword: true, isPhoneNumber: true, }; return availableValidationTypes.hasOwnProperty(type); } } export { FormValidator }; //# sourceMappingURL=FormValidator.js.map