still check properties when passing specialObjectsDequal only for node util isDeepStrictEqual

This commit is contained in:
pfg
2025-05-16 15:07:22 -07:00
parent 43f780618d
commit d533b602e5
5 changed files with 95 additions and 59 deletions

View File

@@ -512,16 +512,40 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepEquals, (JSGlobalObject * globalObject,
if (strict.isBoolean() && strict.asBoolean()) {
bool isEqual = Bun__deepEquals<true, false>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
bool isEqual = Bun__deepEquals<true, BunDeepEqualsMode_Bun>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsBoolean(isEqual));
} else {
bool isEqual = Bun__deepEquals<false, false>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
bool isEqual = Bun__deepEquals<false, BunDeepEqualsMode_Bun>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsBoolean(isEqual));
}
}
JSC_DEFINE_HOST_FUNCTION(jsFunction_nodeIsDeepStrictEqual, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto* global = reinterpret_cast<GlobalObject*>(globalObject);
auto& vm = JSC::getVM(global);
auto scope = DECLARE_THROW_SCOPE(vm);
if (callFrame->argumentCount() < 2) {
auto throwScope = DECLARE_THROW_SCOPE(vm);
throwTypeError(globalObject, throwScope, "Expected 2 values to compare"_s);
return {};
}
JSC::JSValue arg1 = callFrame->uncheckedArgument(0);
JSC::JSValue arg2 = callFrame->uncheckedArgument(1);
Vector<std::pair<JSValue, JSValue>, 16> stack;
MarkedArgumentBuffer gcBuffer;
bool isEqual = Bun__deepEquals<true, BunDeepEqualsMode_Node>(globalObject, arg1, arg2, gcBuffer, stack, &scope, true);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsBoolean(isEqual));
}
JSC_DEFINE_HOST_FUNCTION(functionBunDeepMatch, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
auto* global = reinterpret_cast<GlobalObject*>(globalObject);
@@ -547,7 +571,7 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepMatch, (JSGlobalObject * globalObject, J
std::set<EncodedJSValue> objVisited;
std::set<EncodedJSValue> subsetVisited;
MarkedArgumentBuffer gcBuffer;
bool match = Bun__deepMatch</* enableAsymmetricMatchers */ false>(object, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, false, false);
bool match = Bun__deepMatch<BunDeepEqualsMode_Bun>(object, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, false, false);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsBoolean(match));
@@ -898,7 +922,6 @@ static void exportBunObject(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC:
exportValues.append(value);
}
}
}
namespace Zig {

View File

@@ -11,6 +11,7 @@ JSC_DECLARE_HOST_FUNCTION(functionBunDeepMatch);
JSC_DECLARE_HOST_FUNCTION(functionBunNanoseconds);
JSC_DECLARE_HOST_FUNCTION(functionPathToFileURL);
JSC_DECLARE_HOST_FUNCTION(functionFileURLToPath);
JSC_DECLARE_HOST_FUNCTION(jsFunction_nodeIsDeepStrictEqual);
JSC::JSValue constructBunFetchObject(VM& vm, JSObject* bunObject);
JSC::JSObject* createBunObject(VM& vm, JSObject* globalObject);

View File

@@ -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)

View File

@@ -276,6 +276,12 @@ typedef struct StringPointer {
} StringPointer;
#endif
enum BunDeepEqualsMode {
BunDeepEqualsMode_Node,
BunDeepEqualsMode_Jest,
BunDeepEqualsMode_Bun,
};
typedef void WebSocketHTTPClient;
typedef void WebSocketHTTPSClient;
typedef void WebSocketClient;
@@ -403,7 +409,7 @@ extern "C" void Bun__EventLoop__runCallback2(JSC::JSGlobalObject* global, JSC::E
extern "C" void Bun__EventLoop__runCallback3(JSC::JSGlobalObject* global, JSC::EncodedJSValue callback, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue arg1, JSC::EncodedJSValue arg2, JSC::EncodedJSValue arg3);
/// @note throws a JS exception and returns false if a stack overflow occurs
template<bool isStrict, bool enableAsymmetricMatchers>
template<bool isStrict, BunDeepEqualsMode mode>
bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JSValue v2, JSC::MarkedArgumentBuffer&, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, JSC::ThrowScope* scope, bool addToStack);
/**
@@ -438,7 +444,7 @@ bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JS
* @return true
* @return false
*/
template<bool enableAsymmetricMatchers>
template<BunDeepEqualsMode enableAsymmetricMatchers>
bool Bun__deepMatch(
JSC::JSValue object,
std::set<JSC::EncodedJSValue>* seenObjProperties,

View File

@@ -21,8 +21,7 @@ function isFunction(value) {
return typeof value === "function";
}
const deepEquals = Bun.deepEquals;
const isDeepStrictEqual = (a, b) => deepEquals(a, b, true);
const isDeepStrictEqual = $newCppFunction("BunObject.cpp", "jsFunction_nodeIsDeepStrictEqual", 2);
const parseArgs = $newZigFunction("parse_args.zig", "parseArgs", 1);