|
|
|
|
@@ -458,7 +458,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global
|
|
|
|
|
ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
|
|
|
|
|
Vector<std::pair<JSValue, JSValue>, 16> stack;
|
|
|
|
|
MarkedArgumentBuffer gcBuffer;
|
|
|
|
|
if (Bun__deepEquals<false, true>(globalObject, expectedValue, otherValue, gcBuffer, stack, &scope, true)) {
|
|
|
|
|
if (Bun__deepEquals<false, BunDeepEqualsMode_Jest>(globalObject, expectedValue, otherValue, gcBuffer, stack, &scope, true)) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -483,9 +483,9 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global
|
|
|
|
|
if (otherProp.isObject()) {
|
|
|
|
|
ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
|
|
|
|
|
// SAFETY: visited property sets are not required when
|
|
|
|
|
// `enableAsymmetricMatchers` and `isMatchingObjectContaining`
|
|
|
|
|
// `mode == BunDeepEqualsMode_Jest` and `isMatchingObjectContaining`
|
|
|
|
|
// are both true
|
|
|
|
|
if (Bun__deepMatch<true>(otherProp, nullptr, patternObject, nullptr, globalObject, &scope, nullptr, false, true)) {
|
|
|
|
|
if (Bun__deepMatch<BunDeepEqualsMode_Jest>(otherProp, nullptr, patternObject, nullptr, globalObject, &scope, nullptr, false, true)) {
|
|
|
|
|
return AsymmetricMatcherResult::PASS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -609,10 +609,10 @@ JSValue getIndexWithoutAccessors(JSGlobalObject* globalObject, JSObject* obj, ui
|
|
|
|
|
return JSValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<bool isStrict, bool enableAsymmetricMatchers>
|
|
|
|
|
template<bool isStrict, BunDeepEqualsMode mode>
|
|
|
|
|
std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, JSCell* _Nonnull c1, JSCell* _Nonnull c2);
|
|
|
|
|
|
|
|
|
|
template<bool isStrict, bool enableAsymmetricMatchers>
|
|
|
|
|
template<bool isStrict, BunDeepEqualsMode mode>
|
|
|
|
|
bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, bool addToStack)
|
|
|
|
|
{
|
|
|
|
|
VM& vm = globalObject->vm();
|
|
|
|
|
@@ -623,7 +623,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
|
|
|
|
|
// need to check this before primitives, asymmetric matchers
|
|
|
|
|
// can match against any type of value.
|
|
|
|
|
if constexpr (enableAsymmetricMatchers) {
|
|
|
|
|
if constexpr (mode == BunDeepEqualsMode_Jest) {
|
|
|
|
|
if (v2.isCell() && !v2.isEmpty() && v2.asCell()->type() == JSC::JSType(JSDOMWrapperType)) {
|
|
|
|
|
switch (matchAsymmetricMatcher(globalObject, v2, v1, scope)) {
|
|
|
|
|
case AsymmetricMatcherResult::FAIL:
|
|
|
|
|
@@ -687,9 +687,9 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
JSCell* c2 = v2.asCell();
|
|
|
|
|
ASSERT(c1);
|
|
|
|
|
ASSERT(c2);
|
|
|
|
|
std::optional<bool> isSpecialEqual = specialObjectsDequal<isStrict, enableAsymmetricMatchers>(globalObject, gcBuffer, stack, scope, c1, c2);
|
|
|
|
|
std::optional<bool> isSpecialEqual = specialObjectsDequal<isStrict, mode>(globalObject, gcBuffer, stack, scope, c1, c2);
|
|
|
|
|
if (isSpecialEqual.has_value()) return std::move(*isSpecialEqual);
|
|
|
|
|
isSpecialEqual = specialObjectsDequal<isStrict, enableAsymmetricMatchers>(globalObject, gcBuffer, stack, scope, c2, c1);
|
|
|
|
|
isSpecialEqual = specialObjectsDequal<isStrict, mode>(globalObject, gcBuffer, stack, scope, c2, c1);
|
|
|
|
|
if (isSpecialEqual.has_value()) return std::move(*isSpecialEqual);
|
|
|
|
|
JSObject* o1 = v1.getObject();
|
|
|
|
|
JSObject* o2 = v2.getObject();
|
|
|
|
|
@@ -736,7 +736,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -791,7 +791,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -814,7 +814,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
auto v2Wrapper = jsCast<JSC::JSWrapperObject*>(v2);
|
|
|
|
|
auto v1Value = v1Wrapper->internalValue();
|
|
|
|
|
auto v2Value = v2Wrapper->internalValue();
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, v1Value, v2Value, gcBuffer, stack, scope, addToStack)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, v1Value, v2Value, gcBuffer, stack, scope, addToStack)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -856,7 +856,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
|
|
|
|
result = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@@ -894,7 +894,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, left, right, gcBuffer, stack, scope, true)) {
|
|
|
|
|
result = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@@ -980,7 +980,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1003,11 +1003,18 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2,
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<bool isStrict, bool enableAsymmetricMatchers>
|
|
|
|
|
template bool Bun__deepEquals<false, BunDeepEqualsMode_Node>(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, bool addToStack);
|
|
|
|
|
template bool Bun__deepEquals<true, BunDeepEqualsMode_Node>(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, bool addToStack);
|
|
|
|
|
|
|
|
|
|
template<bool isStrict, BunDeepEqualsMode mode>
|
|
|
|
|
std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, MarkedArgumentBuffer& gcBuffer, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, JSCell* _Nonnull c1, JSCell* _Nonnull c2)
|
|
|
|
|
{
|
|
|
|
|
uint8_t c1Type = c1->type();
|
|
|
|
|
uint8_t c2Type = c2->type();
|
|
|
|
|
std::optional<bool> matchMaybeCheckProperties = true;
|
|
|
|
|
if constexpr (mode == BunDeepEqualsMode_Node) {
|
|
|
|
|
matchMaybeCheckProperties = std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (c1Type) {
|
|
|
|
|
case JSSetType: {
|
|
|
|
|
@@ -1035,7 +1042,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
JSValue key2;
|
|
|
|
|
bool foundMatchingKey = false;
|
|
|
|
|
while (iter2->next(globalObject, key2)) {
|
|
|
|
|
if (Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, key1, key2, gcBuffer, stack, scope, false)) {
|
|
|
|
|
if (Bun__deepEquals<isStrict, mode>(globalObject, key1, key2, gcBuffer, stack, scope, false)) {
|
|
|
|
|
foundMatchingKey = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -1047,7 +1054,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
}
|
|
|
|
|
case JSMapType: {
|
|
|
|
|
if (c2Type != JSMapType) {
|
|
|
|
|
@@ -1074,7 +1081,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
JSValue key2;
|
|
|
|
|
bool foundMatchingKey = false;
|
|
|
|
|
while (iter2->nextKeyValue(globalObject, key2, value2)) {
|
|
|
|
|
if (Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, key1, key2, gcBuffer, stack, scope, false)) {
|
|
|
|
|
if (Bun__deepEquals<isStrict, mode>(globalObject, key1, key2, gcBuffer, stack, scope, false)) {
|
|
|
|
|
foundMatchingKey = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -1088,12 +1095,12 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
// Compare both values below.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, value1, value2, gcBuffer, stack, scope, false)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, value1, value2, gcBuffer, stack, scope, false)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
}
|
|
|
|
|
case ArrayBufferType: {
|
|
|
|
|
if (c2Type != ArrayBufferType) {
|
|
|
|
|
@@ -1113,7 +1120,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (byteLength == 0)
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
|
|
|
|
|
if (UNLIKELY(right->isDetached() || left->isDetached())) {
|
|
|
|
|
return false;
|
|
|
|
|
@@ -1126,7 +1133,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (UNLIKELY(vector == rightVector))
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
|
|
|
|
|
return (memcmp(vector, rightVector, byteLength) == 0);
|
|
|
|
|
}
|
|
|
|
|
@@ -1199,7 +1206,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
RETURN_IF_EXCEPTION(*scope, false);
|
|
|
|
|
auto rightCause = right->get(globalObject, cause);
|
|
|
|
|
RETURN_IF_EXCEPTION(*scope, false);
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, leftCause, rightCause, gcBuffer, stack, scope, true)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, leftCause, rightCause, gcBuffer, stack, scope, true)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
RETURN_IF_EXCEPTION(*scope, false);
|
|
|
|
|
@@ -1249,7 +1256,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
|
|
|
|
if (!Bun__deepEquals<isStrict, mode>(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1304,7 +1311,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (byteLength == 0)
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
|
|
|
|
|
if (UNLIKELY(right->isDetached() || left->isDetached())) {
|
|
|
|
|
return false;
|
|
|
|
|
@@ -1317,7 +1324,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (UNLIKELY(vector == rightVector))
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
|
|
|
|
|
// For Float32Array and Float64Array, when not in strict mode, we need to
|
|
|
|
|
// handle +0 and -0 as equal, and NaN as not equal to itself.
|
|
|
|
|
@@ -1332,7 +1339,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
} else if (c1Type == Float32ArrayType) {
|
|
|
|
|
auto* leftFloat = static_cast<const float*>(vector);
|
|
|
|
|
auto* rightFloat = static_cast<const float*>(rightVector);
|
|
|
|
|
@@ -1343,7 +1350,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
} else { // Float64Array
|
|
|
|
|
auto* leftDouble = static_cast<const double*>(vector);
|
|
|
|
|
auto* rightDouble = static_cast<const double*>(rightVector);
|
|
|
|
|
@@ -1354,12 +1361,12 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (memcmp(vector, rightVector, byteLength) == 0) {
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
@@ -1384,7 +1391,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ((url1 == nullptr) != (url2 == nullptr)) {
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1397,7 +1404,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: FormData.
|
|
|
|
|
@@ -1423,7 +1430,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
} else {
|
|
|
|
|
if constexpr (isStrict) {
|
|
|
|
|
// if one is a URLSearchParams and the other is not a URLSearchParams, toStrictEqual should return false.
|
|
|
|
|
@@ -1432,7 +1439,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ((urlSearchParams1 == nullptr) != (urlSearchParams2 == nullptr)) {
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1462,7 +1469,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
} else {
|
|
|
|
|
if constexpr (isStrict) {
|
|
|
|
|
// if one is a FetchHeaders and the other is not a FetchHeaders, toStrictEqual should return false.
|
|
|
|
|
@@ -1471,7 +1478,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ((headers1 == nullptr) != (headers2 == nullptr)) {
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
return matchMaybeCheckProperties;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1505,14 +1512,14 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
* @note
|
|
|
|
|
* The sets recording already visited properties (`seenObjProperties`,
|
|
|
|
|
* `seenSubsetProperties`, and `gcBuffer`) aren not needed when both
|
|
|
|
|
* `enableAsymmetricMatchers` and `isMatchingObjectContaining` are true. In
|
|
|
|
|
* `mode == BunDeepEqualsMode_Jest` and `isMatchingObjectContaining` are true. In
|
|
|
|
|
* this case, it is safe to pass a `nullptr`.
|
|
|
|
|
*
|
|
|
|
|
* `gcBuffer` ensures JSC's stack scan does not come up empty-handed and free
|
|
|
|
|
* properties currently within those stacks. Likely unnecessary, but better to
|
|
|
|
|
* be safe tnan sorry
|
|
|
|
|
*
|
|
|
|
|
* @tparam enableAsymmetricMatchers
|
|
|
|
|
* @tparam mode
|
|
|
|
|
* @param objValue
|
|
|
|
|
* @param seenObjProperties already visited properties of `objValue`.
|
|
|
|
|
* @param subsetValue
|
|
|
|
|
@@ -1526,7 +1533,7 @@ std::optional<bool> specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark
|
|
|
|
|
* @return true
|
|
|
|
|
* @return false
|
|
|
|
|
*/
|
|
|
|
|
template<bool enableAsymmetricMatchers>
|
|
|
|
|
template<BunDeepEqualsMode mode>
|
|
|
|
|
bool Bun__deepMatch(
|
|
|
|
|
JSValue objValue,
|
|
|
|
|
std::set<EncodedJSValue>* seenObjProperties,
|
|
|
|
|
@@ -1582,7 +1589,7 @@ bool Bun__deepMatch(
|
|
|
|
|
JSCell* subsetPropCell = !subsetProp.isEmpty() && subsetProp.isCell() ? subsetProp.asCell() : nullptr;
|
|
|
|
|
JSCell* propCell = prop.isCell() ? prop.asCell() : nullptr;
|
|
|
|
|
|
|
|
|
|
if constexpr (enableAsymmetricMatchers) {
|
|
|
|
|
if constexpr (mode == BunDeepEqualsMode_Jest) {
|
|
|
|
|
if (subsetPropCell && subsetPropCell->type() == JSC::JSType(JSDOMWrapperType)) {
|
|
|
|
|
switch (matchAsymmetricMatcher(globalObject, subsetProp, prop, throwScope)) {
|
|
|
|
|
case AsymmetricMatcherResult::FAIL:
|
|
|
|
|
@@ -1616,10 +1623,10 @@ bool Bun__deepMatch(
|
|
|
|
|
// if this is called from inside an objectContaining asymmetric matcher, it should behave slightly differently:
|
|
|
|
|
// in such case, it expects exhaustive matching of any nested object properties, not just a subset,
|
|
|
|
|
// and the user would need to opt-in to subset matching by using another nested objectContaining matcher
|
|
|
|
|
if (enableAsymmetricMatchers && isMatchingObjectContaining) {
|
|
|
|
|
if (mode == BunDeepEqualsMode_Jest && isMatchingObjectContaining) {
|
|
|
|
|
Vector<std::pair<JSValue, JSValue>, 16> stack;
|
|
|
|
|
MarkedArgumentBuffer gcBuffer;
|
|
|
|
|
if (!Bun__deepEquals<false, true>(globalObject, prop, subsetProp, gcBuffer, stack, throwScope, true)) {
|
|
|
|
|
if (!Bun__deepEquals<false, BunDeepEqualsMode_Jest>(globalObject, prop, subsetProp, gcBuffer, stack, throwScope, true)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
@@ -1632,7 +1639,7 @@ bool Bun__deepMatch(
|
|
|
|
|
gcBuffer->append(subsetProp);
|
|
|
|
|
// property cycle detected
|
|
|
|
|
if (!didInsertProp.second || !didInsertSubset.second) continue;
|
|
|
|
|
if (!Bun__deepMatch<enableAsymmetricMatchers>(prop, seenObjProperties, subsetProp, seenSubsetProperties, globalObject, throwScope, gcBuffer, replacePropsWithAsymmetricMatchers, isMatchingObjectContaining)) {
|
|
|
|
|
if (!Bun__deepMatch<mode>(prop, seenObjProperties, subsetProp, seenSubsetProperties, globalObject, throwScope, gcBuffer, replacePropsWithAsymmetricMatchers, isMatchingObjectContaining)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1648,14 +1655,14 @@ bool Bun__deepMatch(
|
|
|
|
|
|
|
|
|
|
// anonymous namespace to avoid name collision
|
|
|
|
|
namespace {
|
|
|
|
|
template<bool isStrict, bool enableAsymmetricMatchers>
|
|
|
|
|
template<bool isStrict, BunDeepEqualsMode mode>
|
|
|
|
|
inline bool deepEqualsWrapperImpl(JSC::EncodedJSValue a, JSC::EncodedJSValue b, JSC::JSGlobalObject* global)
|
|
|
|
|
{
|
|
|
|
|
auto& vm = global->vm();
|
|
|
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
|
Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16> stack;
|
|
|
|
|
MarkedArgumentBuffer args;
|
|
|
|
|
return Bun__deepEquals<isStrict, enableAsymmetricMatchers>(global, JSC::JSValue::decode(a), JSC::JSValue::decode(b), args, stack, &scope, true);
|
|
|
|
|
return Bun__deepEquals<isStrict, mode>(global, JSC::JSValue::decode(a), JSC::JSValue::decode(b), args, stack, &scope, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2563,22 +2570,22 @@ bool JSC__JSValue__isSameValue(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue
|
|
|
|
|
|
|
|
|
|
bool JSC__JSValue__deepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
|
|
|
|
{
|
|
|
|
|
return deepEqualsWrapperImpl<false, false>(JSValue0, JSValue1, globalObject);
|
|
|
|
|
return deepEqualsWrapperImpl<false, BunDeepEqualsMode_Bun>(JSValue0, JSValue1, globalObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JSC__JSValue__jestDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
|
|
|
|
{
|
|
|
|
|
return deepEqualsWrapperImpl<false, true>(JSValue0, JSValue1, globalObject);
|
|
|
|
|
return deepEqualsWrapperImpl<false, BunDeepEqualsMode_Jest>(JSValue0, JSValue1, globalObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JSC__JSValue__strictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
|
|
|
|
{
|
|
|
|
|
return deepEqualsWrapperImpl<true, false>(JSValue0, JSValue1, globalObject);
|
|
|
|
|
return deepEqualsWrapperImpl<true, BunDeepEqualsMode_Bun>(JSValue0, JSValue1, globalObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JSC__JSValue__jestStrictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject)
|
|
|
|
|
{
|
|
|
|
|
return deepEqualsWrapperImpl<true, true>(JSValue0, JSValue1, globalObject);
|
|
|
|
|
return deepEqualsWrapperImpl<true, BunDeepEqualsMode_Jest>(JSValue0, JSValue1, globalObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef IMPL_DEEP_EQUALS_WRAPPER
|
|
|
|
|
@@ -2593,7 +2600,7 @@ bool JSC__JSValue__deepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue J
|
|
|
|
|
std::set<EncodedJSValue> objVisited;
|
|
|
|
|
std::set<EncodedJSValue> subsetVisited;
|
|
|
|
|
MarkedArgumentBuffer gcBuffer;
|
|
|
|
|
return Bun__deepMatch<false>(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false);
|
|
|
|
|
return Bun__deepMatch<BunDeepEqualsMode_Bun>(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject, bool replacePropsWithAsymmetricMatchers)
|
|
|
|
|
@@ -2606,7 +2613,7 @@ bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSVal
|
|
|
|
|
std::set<EncodedJSValue> objVisited;
|
|
|
|
|
std::set<EncodedJSValue> subsetVisited;
|
|
|
|
|
MarkedArgumentBuffer gcBuffer;
|
|
|
|
|
return Bun__deepMatch<true>(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false);
|
|
|
|
|
return Bun__deepMatch<BunDeepEqualsMode_Jest>(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C" bool Bun__JSValue__isAsyncContextFrame(JSC::EncodedJSValue value)
|
|
|
|
|
|