1
0
Fork 0
management/front/dkha-web-sz-main/node_modules/@hapi/hoek/lib/contain.js

157 lines
4.1 KiB
JavaScript
Raw Normal View History

2023-12-18 13:12:25 +08:00
'use strict';
const Assert = require('./assert');
const DeepEqual = require('./deepEqual');
const EscapeRegex = require('./escapeRegex');
const Utils = require('./utils');
const internals = {};
module.exports = function (ref, values, options = {}) { // options: { deep, once, only, part, symbols }
/*
string -> string(s)
array -> item(s)
object -> key(s)
object -> object (key:value)
*/
let valuePairs = null;
if (typeof ref === 'object' &&
typeof values === 'object' &&
!Array.isArray(ref) &&
!Array.isArray(values)) {
valuePairs = values;
const symbols = Object.getOwnPropertySymbols(values).filter(Object.prototype.propertyIsEnumerable.bind(values));
values = [...Object.keys(values), ...symbols];
}
else {
values = [].concat(values);
}
Assert(typeof ref === 'string' || typeof ref === 'object', 'Reference must be string or an object');
Assert(values.length, 'Values array cannot be empty');
let compare;
let compareFlags;
if (options.deep) {
compare = DeepEqual;
const hasOnly = options.only !== undefined;
const hasPart = options.part !== undefined;
compareFlags = {
prototype: hasOnly ? options.only : hasPart ? !options.part : false,
part: hasOnly ? !options.only : hasPart ? options.part : false
};
}
else {
compare = (a, b) => a === b;
}
let misses = false;
const matches = new Array(values.length);
for (let i = 0; i < matches.length; ++i) {
matches[i] = 0;
}
if (typeof ref === 'string') {
if (ref === '') {
if (values.length === 1 && values[0] === '' || // '' contains ''
!options.once && !values.some((v) => v !== '')) { // '' contains multiple '' if !once
return true;
}
return false;
}
let pattern = '(';
for (let i = 0; i < values.length; ++i) {
const value = values[i];
Assert(typeof value === 'string', 'Cannot compare string reference to non-string value');
pattern += (i ? '|' : '') + EscapeRegex(value);
}
const regex = new RegExp(pattern + ')', 'g');
const leftovers = ref.replace(regex, ($0, $1) => {
const index = values.indexOf($1);
++matches[index];
return ''; // Remove from string
});
misses = !!leftovers;
}
else if (Array.isArray(ref)) {
if (!ref.length) {
return false;
}
const onlyOnce = !!(options.only && options.once);
if (onlyOnce && ref.length !== values.length) {
return false;
}
for (let i = 0; i < ref.length; ++i) {
let matched = false;
for (let j = 0; j < values.length && matched === false; ++j) {
if (!onlyOnce || matches[j] === 0) {
matched = compare(values[j], ref[i], compareFlags) && j;
}
}
if (matched !== false) {
++matches[matched];
}
else {
misses = true;
}
}
}
else {
const keys = Utils.keys(ref, options);
if (!keys.length) {
return false;
}
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
const pos = values.indexOf(key);
if (pos !== -1) {
if (valuePairs &&
!compare(valuePairs[key], ref[key], compareFlags)) {
return false;
}
++matches[pos];
}
else {
misses = true;
}
}
}
if (options.only) {
if (misses || !options.once) {
return !misses;
}
}
let result = false;
for (let i = 0; i < matches.length; ++i) {
result = result || !!matches[i];
if ((options.once && matches[i] > 1) ||
(!options.part && !matches[i])) {
return false;
}
}
return result;
};