ccashfrontend/views/node_modules/express-validator/utils/select-fields.js
2021-06-18 09:20:09 +10:00

105 lines
3.2 KiB
JavaScript

const _ = require('lodash');
const formatParamOutput = require('./format-param-output');
const persistValues = require('./persist-values');
module.exports = (req, context, options = {}) => {
let allFields = [];
const optionalityFilter = options.filterOptionals == null || options.filterOptionals
? createOptionalityFilter(context)
: Boolean;
const sanitizerMapper = createSanitizerMapper(req, context, options);
context.fields.map(field => field == null ? '' : field).forEach(field => {
let instances = _(context.locations)
.flatMap(createFieldExpander(req, field))
.map(sanitizerMapper)
.filter(optionalityFilter)
.value();
// #331 - When multiple locations are involved, all of them must pass the validation.
// If none of the locations contain the field, we at least include one for error reporting.
// #458, #531 - Wildcards are an exception though: they may yield 0..* instances with different
// paths, so we may want to skip this filtering.
if (instances.length > 1 && context.locations.length > 1 && !field.includes('*')) {
const withValue = instances.filter(field => field.value !== undefined);
instances = withValue.length ? withValue : [instances[0]];
}
allFields = allFields.concat(instances);
});
persistValues(req, allFields);
return _.uniqWith(allFields, _.isEqual);
};
function createFieldExpander(req, field) {
return location => {
const fieldPath = location === 'headers' ? field.toLowerCase() : field;
return expand(req[location], fieldPath, []).map(path => ({
location,
path: path,
value: path === '' ? req[location] : _.get(req[location], path)
})).map(field => Object.assign(field, {
originalValue: field.value
}));
};
}
function expand(object, path, paths) {
const segments = _.toPath(path);
const wildcard = segments.indexOf('*');
if (wildcard > -1) {
const subObject = wildcard ? _.get(object, segments.slice(0, wildcard)) : object;
if (!subObject) {
return paths;
}
Object.keys(subObject)
.map(key => segments
.slice(0, wildcard)
.concat(key)
.concat(segments.slice(wildcard + 1)))
.forEach(path => expand(object, path, paths));
} else {
paths.push(formatParamOutput(segments));
}
return paths;
}
function createSanitizerMapper(req, { sanitizers = [] }, { sanitize = true }) {
return !sanitize ? field => field : field => sanitizers.reduce((prev, sanitizer) => {
const value = typeof prev.value === 'string' ?
callSanitizer(sanitizer, prev) :
prev.value;
return Object.assign({}, prev, { value });
}, field);
function callSanitizer(config, field) {
return !config.custom ?
config.sanitizer(field.value, ...config.options) :
config.sanitizer(field.value, {
req,
location: field.location,
path: field.path
});
}
}
function createOptionalityFilter({ optional }) {
const checks = [
value => value !== undefined,
value => optional.nullable ? value != null : true,
value => optional.checkFalsy ? value : true
];
return field => {
if (!optional) {
return true;
}
return checks.every(check => check(field.value));
};
}