mirror of
https://github.com/Expand-sys/ccashfrontend
synced 2025-12-19 16:12:14 +11:00
105 lines
3.2 KiB
JavaScript
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));
|
|
};
|
|
}
|