@edirect/form-engine
Version:
Achieve form logic reusage with forms expressed in json format.
555 lines (554 loc) • 14.8 kB
JavaScript
;
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;