UNPKG

@edirect/form-engine

Version:

Achieve form logic reusage with forms expressed in json format.

555 lines (554 loc) 14.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.run = exports.hasError = exports.generateCustomError = void 0; var utils = _interopRequireWildcard(require("../utils/index.js")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } // ERROR HELPERS const searchFailedError = errors => { const defaultResponse = { fail: false }; if (!errors) return defaultResponse; return Object.keys(errors).reduce((acc, key) => { return errors[key].fail ? errors[key] : acc; }, defaultResponse); }; // VALIDATIONS const length = ({ value, validationValue }) => { let targetValue = value; // We want length even if it is a numeric if (typeof targetValue !== 'string') { targetValue = value === null || value === void 0 ? void 0 : value.toString(); } return { fail: !value || (targetValue === null || targetValue === void 0 ? void 0 : targetValue.length) === validationValue }; }; const greaterThan = ({ value, validationValue }) => { return { fail: !value || parseInt(value) <= parseInt(validationValue) }; }; const lessThan = ({ value, validationValue }) => { return { fail: !value || parseInt(value) >= parseInt(validationValue) }; }; const maxLength = ({ value = '', validationValue }) => { let targetValue = value; // We want length even if it is a numeric if (Number.isInteger(targetValue)) { targetValue = value.toString(); } return { fail: targetValue.length > validationValue }; }; const minLength = ({ value = '', validationValue }) => { let targetValue = value; // We want length even if it is a numeric if (Number.isInteger(targetValue)) { targetValue = value.toString(); } return { fail: targetValue.length < validationValue }; }; const required = ({ value, validationValue }) => { return { fail: validationValue && !value }; }; const value = ({ value, validationValue }) => { return { fail: value !== validationValue }; }; const regex = ({ value, validationValue }) => { const regex = new RegExp(validationValue); const fail = !regex.test(value); return { fail }; }; const email = ({ value }) => { const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const fail = !regex.test(value); return { fail }; }; const isCreditCard = ({ value, validationValue }) => { var _a, _b; if (!value) return { fail: true }; const [type] = utils.creditCard.getTypeCard(value, validationValue); return { fail: !type, metadata: { typeCard: type === null || type === void 0 ? void 0 : type.type, creditCardCC: (_a = type === null || type === void 0 ? void 0 : type.code) === null || _a === void 0 ? void 0 : _a.name, creditCardCCSize: (_b = type === null || type === void 0 ? void 0 : type.code) === null || _b === void 0 ? void 0 : _b.size } }; }; const isCreditCodeMatch = ({ value, validationValue }) => { var _a; if (!value) return { fail: true }; const [type] = utils.creditCard.getTypeCard(validationValue.numberCard, validationValue.availableOptions); return { fail: ((_a = type === null || type === void 0 ? void 0 : type.code) === null || _a === void 0 ? void 0 : _a.size) !== value.length }; }; const isCreditCardAndLength = ({ value, validationValue }) => { if (!value) return { fail: true }; const [type, rawValue] = utils.creditCard.getTypeCard(value, validationValue); const fail = type && !type.lengths.includes(rawValue.length); return { fail }; }; const url = ({ value }) => { const regex = /[(http(s)?)://(www.)?a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/gi; const fail = !regex.test(value); return { fail }; }; const onlyLetters = ({ value }) => { const fail = !/^[a-zA-Z\s]*$/.test(value); return { fail }; }; const customValidation = ({ value, validationValue }) => generic({ value, validationValue }); /* - Allow to use specific validations for specific position caracters * * customValidation: [ * { * from: 0, * to: 2, * validations: { * greaterThan: date.getMonth(), * lessThan: '13', * } * }, * { * from: 3, * to: 5, * validations: { * greaterThan: date.getFullYear().toString().substr(-2) - 1, * } * }, * ], */ const generic = ({ value = '', validationValue }) => { const fail = validationValue.some(item => { const { to, from, validations } = item; const substring = value.substring(to, from); return hasError(run(substring, validations)); }); return { fail }; }; const notAllowSpaces = ({ value }) => { const fail = /\s/.test(value); return { fail }; }; const callback = ({ value, validationValue }) => { const result = validationValue(value); return { message: result.errorMessage, fail: result.fail }; }; const isNumber = ({ value }) => { const fail = !!value && !/^[0-9\s]*$/.test(value); return { fail }; }; const notEmpty = ({ value }) => { return { fail: !value.trim().length }; }; /** * Check if has tralling/landing spaces. */ const hasNoExtraSpaces = ({ value }) => { const regexToCheckTrailingSpaces = '^[A-Za-z0-9.-]+(?: +[A-Za-z0-9.-]+)*$'; const { fail } = regex({ value, validationValue: regexToCheckTrailingSpaces, errorMessage: '' }); return { fail }; }; const numericRange = ({ value, validationValue }) => { const replacedValue = String(value).replace(/[^0-9]/g, ''); const fail = !replacedValue || !Number.isInteger(parseInt(replacedValue.toString())) || +replacedValue > validationValue.end || +replacedValue < validationValue.start; return { fail }; }; const isInTheList = ({ value, validationValue }) => { if (!value || !Array.isArray(validationValue)) return { fail: true }; return { fail: !validationValue.some(code => code === value || JSON.stringify(code) === value) }; }; const sequentialNumber = ({ value }) => { const numbers = '0123456789'; const numbersRev = '9876543210'; const replacedValue = String(value).replace(/[^0-9]/g, ''); const fail = !(numbers.indexOf(replacedValue) === -1 && numbersRev.indexOf(replacedValue) === -1); return { fail }; }; const repeatedNumbers = ({ value }) => { const replacedValue = String(value).replace(/[^0-9]/g, ''); const regex = /\b(\d)\1+\b/gm; const fail = regex.test(replacedValue); return { fail }; }; const path = ({ value, validationValue }) => { const searchErrorInPath = path => { const valueForPath = utils.object.getValueByPath(value, path); if (validationValue.preventUnMountValidation && !(path in value)) { return { fail: false }; } const validationsResult = run(valueForPath, validationValue); return searchFailedError(validationsResult); }; if (Array.isArray(validationValue.paths)) { return validationValue.paths.reduce((acc, path) => { const res = searchErrorInPath(path); if (res.fail) { return res; } return acc; }, {}); } return searchErrorInPath(validationValue.path); }; const fields = ({ values, validationValue }) => ({ fail: validationValue === null || validationValue === void 0 ? void 0 : validationValue.set[validationValue.rule](validation => { var _a; return hasError(run((_a = values[validation.fieldName]) === null || _a === void 0 ? void 0 : _a.value, validation.validations)); }) }); const customNameRule = ({ value, validationValue }) => { if (typeof validationValue !== 'object') return { fail: false }; return { fail: hasError(run(value, validationValue)) }; }; const date = ({ value = '', validationValue }) => { var _a, _b, _c, _d; if (!((_a = validationValue === null || validationValue === void 0 ? void 0 : validationValue.target) === null || _a === void 0 ? void 0 : _a.value) && !((_b = validationValue === null || validationValue === void 0 ? void 0 : validationValue.origin) === null || _b === void 0 ? void 0 : _b.intervals)) { return { fail: false }; } const dateRearangeMapper = { DDMMYYYY: value => { const dateParts = value.split(value.includes('/') ? '/' : '-'); return `${dateParts[1]}/${dateParts[0]}/${dateParts[2]}`; }, YYYYMMDD: value => { const dateParts = value.split(value.includes('/') ? '/' : '-'); return `${dateParts[1]}/${dateParts[2]}/${dateParts[0]}`; }, YYYYDDMM: value => { const dateParts = value.split(value.includes('/') ? '/' : '-'); return `${dateParts[2]}/${dateParts[1]}/${dateParts[0]}`; }, MMDDYYYY: value => value, timestamp: value => new Date(value).toString() }; const getIntervalsDate = (date, intervals) => { const intervalsMapper = { years: (date, value) => new Date(date.setUTCFullYear(date.getUTCFullYear() + value)), months: (date, value) => new Date(date.setUTCMonth(date.getUTCMonth() + value)), days: (date, value) => new Date(date.setDate(date.getUTCDate() + value)) }; return Object.keys(intervals).reduce((acc, interval) => intervalsMapper[interval](acc, intervals[interval]), new Date(date)); }; const originValue = validationValue.origin.value || value; let originDate = new Date(dateRearangeMapper[validationValue === null || validationValue === void 0 ? void 0 : validationValue.origin.format](originValue).toString()); let targetDate = ((_c = validationValue === null || validationValue === void 0 ? void 0 : validationValue.target) === null || _c === void 0 ? void 0 : _c.format) ? new Date(dateRearangeMapper[(_d = validationValue === null || validationValue === void 0 ? void 0 : validationValue.target) === null || _d === void 0 ? void 0 : _d.format](validationValue.target.value).toString()) : new Date(); if (validationValue.origin.intervals) { targetDate = getIntervalsDate(originDate, validationValue.origin.intervals); const date = new Date(); originDate = new Date(`${date.getUTCMonth() + 1}/${date.getUTCDate()}/${date.getUTCFullYear()}`); } if (validationValue.onlyValidDate && (!(targetDate instanceof Date && isFinite(targetDate)) || !(targetDate instanceof Date && isFinite(originDate)) || originValue.length < 8)) { return { fail: true }; } const originTimestamp = originDate.getTime(); const targetTimestamp = targetDate.getTime(); const operationsMapper = { '>': originTimestamp > targetTimestamp, '>=': originTimestamp >= targetTimestamp, '<': originTimestamp < targetTimestamp, '<=': originTimestamp <= targetTimestamp, '===': originTimestamp === targetTimestamp, '!==': originTimestamp !== targetTimestamp }; return { fail: operationsMapper[validationValue === null || validationValue === void 0 ? void 0 : validationValue.operator] }; }; const conditions = ({ value = '', validationValue }) => { if (!validationValue) return { fail: false }; const conditionResult = rule => { if (rule.forceDefinedOrigin && rule.origin === undefined || rule.forceDefinedTarget && rule.target === undefined) return { fail: false }; const origin = rule.origin === undefined ? value : rule.origin; const target = rule.target === undefined ? value : rule.target; const conditionMapper = { '!==': (origin || value) !== (target || value), '===': (origin || value) === (target || value), '<': (origin || value) < (target || value), '>': (origin || value) > (target || value), '<=': (origin || value) <= (target || value), '>=': (origin || value) >= (target || value) }; return conditionMapper[rule.condition]; }; const rulesMapper = { and: () => !!validationValue.set.every(conditionResult), or: () => !!validationValue.set.some(conditionResult) }; return { fail: rulesMapper[validationValue.rule]() }; }; const validations = { conditions, date, length, greaterThan, maxLength, minLength, required, value, regex, hasNoExtraSpaces, isCreditCard, isCreditCardAndLength, isCreditCodeMatch, onlyLetters, notAllowSpaces, callback, isNumber, customValidation, notEmpty, numericRange, email, lessThan, sequentialNumber, repeatedNumbers, url, path, isInTheList, fields, customNameRule }; const run = (value, rules, errorMessages = {}, formData = {}) => { let result = {}; Object.keys(rules).forEach(key => { const validationValue = rules[key]; let validationFN = validations[key]; if (!validationFN) { validationFN = validations.customNameRule; } const errorMessage = errorMessages[key] || errorMessages.default; const ruleResult = validationFN({ value, validationValue, errorMessage: errorMessage, values: formData }); result = Object.assign(Object.assign({}, result), { [key]: Object.assign(Object.assign({}, ruleResult), { validationValue, message: errorMessage }) }); }); return result; }; exports.run = run; const generateCustomError = (name, message) => { return { [name]: { fail: true, message, value: undefined } }; }; exports.generateCustomError = generateCustomError; const hasError = errors => { if (!errors) { return false; } return !!Object.keys(errors).find(key => errors && errors[key].fail, []); }; exports.hasError = hasError;