LendAndRegret/node_modules/es-toolkit/dist/compat/predicate/isMatchWith.mjs
2026-05-02 17:27:43 +08:00

150 lines
4.4 KiB
JavaScript

import { isObject } from './isObject.mjs';
import { isPrimitive } from '../../predicate/isPrimitive.mjs';
import { isEqualsSameValueZero } from '../../_internal/isEqualsSameValueZero.mjs';
function isMatchWith(target, source, compare) {
if (typeof compare !== 'function') {
return isMatchWith(target, source, () => undefined);
}
return isMatchWithInternal(target, source, function doesMatch(objValue, srcValue, key, object, source, stack) {
const isEqual = compare(objValue, srcValue, key, object, source, stack);
if (isEqual !== undefined) {
return Boolean(isEqual);
}
return isMatchWithInternal(objValue, srcValue, doesMatch, stack);
}, new Map());
}
function isMatchWithInternal(target, source, compare, stack) {
if (source === target) {
return true;
}
switch (typeof source) {
case 'object': {
return isObjectMatch(target, source, compare, stack);
}
case 'function': {
const sourceKeys = Object.keys(source);
if (sourceKeys.length > 0) {
return isMatchWithInternal(target, { ...source }, compare, stack);
}
return isEqualsSameValueZero(target, source);
}
default: {
if (!isObject(target)) {
return isEqualsSameValueZero(target, source);
}
if (typeof source === 'string') {
return source === '';
}
return true;
}
}
}
function isObjectMatch(target, source, compare, stack) {
if (source == null) {
return true;
}
if (Array.isArray(source)) {
return isArrayMatch(target, source, compare, stack);
}
if (source instanceof Map) {
return isMapMatch(target, source, compare, stack);
}
if (source instanceof Set) {
return isSetMatch(target, source, compare, stack);
}
const keys = Object.keys(source);
if (target == null || isPrimitive(target)) {
return keys.length === 0;
}
if (keys.length === 0) {
return true;
}
if (stack?.has(source)) {
return stack.get(source) === target;
}
stack?.set(source, target);
try {
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (!isPrimitive(target) && !(key in target)) {
return false;
}
if (source[key] === undefined && target[key] !== undefined) {
return false;
}
if (source[key] === null && target[key] !== null) {
return false;
}
const isEqual = compare(target[key], source[key], key, target, source, stack);
if (!isEqual) {
return false;
}
}
return true;
}
finally {
stack?.delete(source);
}
}
function isMapMatch(target, source, compare, stack) {
if (source.size === 0) {
return true;
}
if (!(target instanceof Map)) {
return false;
}
for (const [key, sourceValue] of source.entries()) {
const targetValue = target.get(key);
const isEqual = compare(targetValue, sourceValue, key, target, source, stack);
if (isEqual === false) {
return false;
}
}
return true;
}
function isArrayMatch(target, source, compare, stack) {
if (source.length === 0) {
return true;
}
if (!Array.isArray(target)) {
return false;
}
const countedIndex = new Set();
for (let i = 0; i < source.length; i++) {
const sourceItem = source[i];
let found = false;
for (let j = 0; j < target.length; j++) {
if (countedIndex.has(j)) {
continue;
}
const targetItem = target[j];
let matches = false;
const isEqual = compare(targetItem, sourceItem, i, target, source, stack);
if (isEqual) {
matches = true;
}
if (matches) {
countedIndex.add(j);
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
function isSetMatch(target, source, compare, stack) {
if (source.size === 0) {
return true;
}
if (!(target instanceof Set)) {
return false;
}
return isArrayMatch([...target], [...source], compare, stack);
}
export { isMatchWith, isSetMatch };