mirror of
https://github.com/xfarrow/blink
synced 2025-06-27 09:03:02 +02:00
Change endpoint from persons to people
This commit is contained in:
221
backend/apis/nodejs/node_modules/express-validator/lib/field-selection.js
generated
vendored
Normal file
221
backend/apis/nodejs/node_modules/express-validator/lib/field-selection.js
generated
vendored
Normal file
@ -0,0 +1,221 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.selectUnknownFields = exports.selectFields = void 0;
|
||||
exports.reconstructFieldPath = reconstructFieldPath;
|
||||
const _ = require("lodash");
|
||||
const selectFields = (req, fields, locations) => _(fields)
|
||||
.flatMap(field => _.flatMap(locations, location => {
|
||||
return expandField(req, field, location);
|
||||
}))
|
||||
// Avoid duplicates if multiple field selections would return the same field twice.
|
||||
// E.g. with fields = ['*.foo', 'bar.foo'] and req.body = { bar: { foo: 1 }, baz: { foo: 2 } },
|
||||
// the instance bla.foo would appear twice, and baz.foo once.
|
||||
.uniqWith(isSameFieldInstance)
|
||||
.value();
|
||||
exports.selectFields = selectFields;
|
||||
function isSameFieldInstance(a, b) {
|
||||
return a.path === b.path && a.location === b.location;
|
||||
}
|
||||
function expandField(req, field, location) {
|
||||
const originalPath = field;
|
||||
const pathToExpand = location === 'headers' ? field.toLowerCase() : field;
|
||||
const paths = expandPath(req[location], pathToExpand, []);
|
||||
return paths.map(({ path, values }) => {
|
||||
const value = path === '' ? req[location] : _.get(req[location], path);
|
||||
return {
|
||||
location,
|
||||
path,
|
||||
originalPath,
|
||||
pathValues: values,
|
||||
value,
|
||||
};
|
||||
});
|
||||
}
|
||||
function expandPath(object, path, currPath, currValues = []) {
|
||||
const segments = _.toPath(path);
|
||||
if (!segments.length) {
|
||||
// no more paths to traverse
|
||||
return [
|
||||
{
|
||||
path: reconstructFieldPath(currPath),
|
||||
values: currValues,
|
||||
},
|
||||
];
|
||||
}
|
||||
const key = segments[0];
|
||||
const rest = segments.slice(1);
|
||||
if (object != null && !_.isObjectLike(object)) {
|
||||
if (key === '**') {
|
||||
if (!rest.length) {
|
||||
// globstar leaves are always selected
|
||||
return [
|
||||
{
|
||||
path: reconstructFieldPath(currPath),
|
||||
values: currValues,
|
||||
},
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
if (key === '*') {
|
||||
// wildcard position does not exist
|
||||
return [];
|
||||
}
|
||||
// value is a primitive, paths being traversed from here might be in their prototype, return the entire path
|
||||
return [
|
||||
{
|
||||
path: reconstructFieldPath([...currPath, ...segments]),
|
||||
values: currValues,
|
||||
},
|
||||
];
|
||||
}
|
||||
// Use a non-null value so that inexistent fields are still selected
|
||||
object = object || {};
|
||||
if (key === '*') {
|
||||
return Object.keys(object).flatMap(key => expandPath(object[key], rest, currPath.concat(key), currValues.concat(key)));
|
||||
}
|
||||
if (key === '**') {
|
||||
return Object.keys(object).flatMap(key => {
|
||||
const nextPath = currPath.concat(key);
|
||||
const value = object[key];
|
||||
// recursively find matching subpaths
|
||||
const selectedPaths = expandPath(value, segments, nextPath, [key]).concat(
|
||||
// skip the first remaining segment, if it matches the current key
|
||||
rest[0] === key ? expandPath(value, rest.slice(1), nextPath, []) : []);
|
||||
return _.uniqBy(selectedPaths, ({ path }) => path).map(({ path, values }) => ({
|
||||
path,
|
||||
values: values.length ? [...currValues, values.flat()] : currValues,
|
||||
}));
|
||||
});
|
||||
}
|
||||
return expandPath(object[key], rest, currPath.concat(key), currValues);
|
||||
}
|
||||
const selectUnknownFields = (req, knownFields, locations) => {
|
||||
const tree = {};
|
||||
knownFields.map(field => {
|
||||
const segments = field === '' ? [''] : _.toPath(field);
|
||||
pathToTree(segments, tree);
|
||||
});
|
||||
const instances = [];
|
||||
for (const location of locations) {
|
||||
if (req[location] != null) {
|
||||
instances.push(...findUnknownFields(location, req[location], tree));
|
||||
}
|
||||
}
|
||||
return instances;
|
||||
};
|
||||
exports.selectUnknownFields = selectUnknownFields;
|
||||
function pathToTree(segments, tree) {
|
||||
// Will either create or merge into existing branch for the current path segment
|
||||
const branch = tree[segments[0]] || (tree[segments[0]] = {});
|
||||
if (segments.length > 1) {
|
||||
pathToTree(segments.slice(1), branch);
|
||||
}
|
||||
else {
|
||||
// Leaf value.
|
||||
branch[''] = {};
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Performs a depth-first search for unknown fields in `value`.
|
||||
* The path to the unknown fields will be pushed to the `unknownFields` argument.
|
||||
*
|
||||
* Known fields must be passed via `tree`. A field won't be considered unknown if:
|
||||
* - its branch is validated as a whole; that is, it contains an empty string key (e.g `{ ['']: {} }`); OR
|
||||
* - its path is individually validated; OR
|
||||
* - it's covered by a wildcard (`*`).
|
||||
*
|
||||
* @returns the list of unknown fields
|
||||
*/
|
||||
function findUnknownFields(location, value, tree, treePath = [], unknownFields = []) {
|
||||
const globstarBranch = tree['**'];
|
||||
if (tree[''] || globstarBranch?.['']) {
|
||||
// The rest of the tree from here is covered by some validation chain
|
||||
// For example, when the current treePath is `['foo', 'bar']` but `foo` is known
|
||||
return unknownFields;
|
||||
}
|
||||
if (typeof value !== 'object') {
|
||||
if (!treePath.length || globstarBranch) {
|
||||
// This is either
|
||||
// a. a req.body that isn't an object (e.g. `req.body = 'bla'`), and wasn't validated either
|
||||
// b. a leaf value which wasn't the target of a globstar path, e.g. `foo.**.bar`
|
||||
unknownFields.push({
|
||||
path: reconstructFieldPath(treePath),
|
||||
value,
|
||||
location,
|
||||
});
|
||||
}
|
||||
return unknownFields;
|
||||
}
|
||||
const wildcardBranch = tree['*'];
|
||||
for (const key of Object.keys(value)) {
|
||||
const keyBranch = tree[key];
|
||||
const path = treePath.concat([key]);
|
||||
if (!keyBranch && !wildcardBranch && !globstarBranch) {
|
||||
// No trees cover this path, so it's an unknown one.
|
||||
unknownFields.push({
|
||||
path: reconstructFieldPath(path),
|
||||
value: value[key],
|
||||
location,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const keyUnknowns = keyBranch ? findUnknownFields(location, value[key], keyBranch, path) : [];
|
||||
const wildcardUnknowns = wildcardBranch
|
||||
? findUnknownFields(location, value[key], wildcardBranch, path)
|
||||
: [];
|
||||
const globstarUnknowns = globstarBranch
|
||||
? findUnknownFields(location, value[key], { ['**']: globstarBranch, ...globstarBranch }, path)
|
||||
: [];
|
||||
// If any of the tested branches contain only known fields, then don't mark the fields not covered
|
||||
// by the other branches to the list of unknown ones.
|
||||
// For example, `foo` is more comprehensive than `foo.*.bar`.
|
||||
if ((!keyBranch || keyUnknowns.length) &&
|
||||
(!wildcardBranch || wildcardUnknowns.length) &&
|
||||
(!globstarBranch || globstarUnknowns.length)) {
|
||||
unknownFields.push(...keyUnknowns, ...wildcardUnknowns, ...globstarUnknowns);
|
||||
}
|
||||
}
|
||||
return unknownFields;
|
||||
}
|
||||
/**
|
||||
* Reconstructs a field path from a list of path segments.
|
||||
*
|
||||
* Most segments will be concatenated by a dot, for example `['foo', 'bar']` becomes `foo.bar`.
|
||||
* However, a numeric segment will be wrapped in brackets to match regular JS array syntax:
|
||||
*
|
||||
* ```
|
||||
* reconstructFieldPath(['foo', 0, 'bar']) // foo[0].bar
|
||||
* ```
|
||||
*
|
||||
* Segments which have a special character such as `.` will be wrapped in brackets and quotes,
|
||||
* which also matches JS syntax for objects with such keys.
|
||||
*
|
||||
* ```
|
||||
* reconstructFieldPath(['foo', 'bar.baz', 'qux']) // foo["bar.baz"].qux
|
||||
* ```
|
||||
*/
|
||||
function reconstructFieldPath(segments) {
|
||||
return segments.reduce((prev, segment) => {
|
||||
let part = '';
|
||||
segment = segment === '\\*' ? '*' : segment;
|
||||
// TODO: Handle brackets?
|
||||
if (segment.includes('.')) {
|
||||
// Special char key access
|
||||
part = `["${segment}"]`;
|
||||
}
|
||||
else if (/^\d+$/.test(segment)) {
|
||||
// Index access
|
||||
part = `[${segment}]`;
|
||||
}
|
||||
else if (prev) {
|
||||
// Object key access
|
||||
part = `.${segment}`;
|
||||
}
|
||||
else {
|
||||
// Top level key
|
||||
part = segment;
|
||||
}
|
||||
return prev + part;
|
||||
}, '');
|
||||
}
|
Reference in New Issue
Block a user