rule-filter-validator
Version:
A object and scope validator based on structured rules
137 lines • 5.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validatePayload = validatePayload;
exports.isValidPayload = isValidPayload;
const lodash_es_1 = require("lodash-es");
const calculate_payload_functions_js_1 = require("./calculate-payload-functions.js");
const is_valid_js_1 = require("./is-valid.js");
const parse_filter_js_1 = require("./parse-filter.js");
const FieldFilterText = {
_eq: 'equal to',
_neq: 'not equal to',
_contains: 'contains',
_ncontains: 'does not contain',
_starts_with: 'starts with',
_nstarts_with: 'does not start with',
_ends_with: 'ends with',
_nends_with: 'does not end with',
_in: 'in',
_nin: 'not in',
_between: 'between',
_nbetween: 'not between',
_gt: 'greater than',
_gte: 'greater than or equal to',
_lt: 'less than',
_lte: 'less than or equal to',
_null: 'null =',
_nnull: 'not null =',
_empty: 'empty =',
_nempty: 'not empty =',
_submitted: 'submitted =',
_regex: 'matching regex',
};
/**
* Validate the payload against the given filter rules
*
* @param {Filter} filter - The filter rules to check against
* @param {Record<string, any>} payload - The payload to validate
* @param {boolean} strict(false) - Type and Case-sensitive validation
* @returns Array<string> errors if any
*/
function validatePayload(filter, payload, strict = false) {
const errors = [];
filter = (0, parse_filter_js_1.parseFilter)(filter);
payload = (0, calculate_payload_functions_js_1.calculatePayloadFunctions)(payload, filter);
validate(filter, payload, errors, '', strict);
errors.reverse();
return errors;
}
/**
* A shorthand function to check if the payload is valid
*/
function isValidPayload(filter, payload, strict = false) {
return validatePayload(filter, payload, strict).length === 0;
}
/**
* Validate the payload against the given filter rules
*
* @param {Filter} filter - The filter rules to check against
* @param {Record<string, any>} payload - The payload to validate
* @param errors
* @param {string} path - Optional options to pass to Joi
* @param {boolean} strict(false) - Type and Case-sensitive validation
* @returns { errors: Array<string> }
*/
function validate(filter, payload, errors = [], path = '', strict = false) {
if (typeof filter !== 'object' && !filter) {
throw new Error('Filter rule is not valid');
}
return Object.keys(filter).every(key => {
const compareValue = (0, lodash_es_1.get)(filter, key);
if (String(key).startsWith('_')) {
switch (key) {
case '_and':
return compareValue.every(subFilter => validate(subFilter, payload, errors, path, strict));
case '_or': {
const swallowErrors = [];
const result = compareValue.some(subFilter => validate(subFilter, payload, swallowErrors, path, strict));
if (!result) {
// If errors then will be false if all checks fail thus &&
errors.push(swallowErrors.join(' and '));
}
return result;
}
case '_$': {
const testValue = (0, lodash_es_1.get)(payload, path, undefined);
if (!Array.isArray(testValue)) {
return errors.push('Failed: ' + path + ' is not an array');
}
const swallowErrors = [];
const result = testValue.some(subItem => validate(compareValue, subItem, swallowErrors, '', strict));
if (!result) {
// If errors then will be false if all checks fail thus &&
errors.push(swallowErrors.join(' and '));
}
return result;
}
case '_some': {
const testValue = (0, lodash_es_1.get)(payload, path, undefined);
if (!Array.isArray(testValue)) {
return errors.push('Failed: ' + path + ' is not an array');
}
const swallowErrors = [];
const result = testValue.some(subItem => validate(compareValue, subItem, swallowErrors, '', strict));
if (!result) {
errors.push(swallowErrors.join(' and '));
}
return result;
}
case '_none': {
const testValue = (0, lodash_es_1.get)(payload, path, undefined);
if (!Array.isArray(testValue)) {
return errors.push('Failed: ' + path + ' is not an array');
}
const swallowErrors = [];
const hasMatch = testValue.some(subItem => validate(compareValue, subItem, swallowErrors, '', strict));
if (hasMatch) {
errors.push('Failed: ' + path + ' has at least one matching related item');
}
return !hasMatch;
}
}
const testValue = (0, lodash_es_1.get)(payload, path, undefined);
const result = (0, is_valid_js_1.isValid)(compareValue, key, testValue, strict);
if (result !== null) {
if (!result) {
errors.push(`Failed: ${path
.split('.')
.reverse()
.join(' of ')} is ${JSON.stringify(testValue)} and is not ${FieldFilterText[key]} ${JSON.stringify(compareValue)}`);
}
return result;
}
}
return validate(compareValue, payload, errors, [path, key].filter(s => s).join('.'), strict);
});
}
//# sourceMappingURL=validate-payload.js.map