diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index af9a78fcfd..33365da5cb 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -512,16 +512,40 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepEquals, (JSGlobalObject * globalObject, if (strict.isBoolean() && strict.asBoolean()) { - bool isEqual = Bun__deepEquals(globalObject, arg1, arg2, gcBuffer, stack, &scope, true); + bool isEqual = Bun__deepEquals(globalObject, arg1, arg2, gcBuffer, stack, &scope, true); RETURN_IF_EXCEPTION(scope, {}); return JSValue::encode(jsBoolean(isEqual)); } else { - bool isEqual = Bun__deepEquals(globalObject, arg1, arg2, gcBuffer, stack, &scope, true); + bool isEqual = Bun__deepEquals(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); + 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, 16> stack; + MarkedArgumentBuffer gcBuffer; + + bool isEqual = Bun__deepEquals(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); @@ -547,7 +571,7 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepMatch, (JSGlobalObject * globalObject, J std::set objVisited; std::set subsetVisited; MarkedArgumentBuffer gcBuffer; - bool match = Bun__deepMatch(object, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, false, false); + bool match = Bun__deepMatch(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 { diff --git a/src/bun.js/bindings/BunObject.h b/src/bun.js/bindings/BunObject.h index e42d23c7f1..77fcdffc6b 100644 --- a/src/bun.js/bindings/BunObject.h +++ b/src/bun.js/bindings/BunObject.h @@ -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); diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 856b21e41d..97c0c54868 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -458,7 +458,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm()); Vector, 16> stack; MarkedArgumentBuffer gcBuffer; - if (Bun__deepEquals(globalObject, expectedValue, otherValue, gcBuffer, stack, &scope, true)) { + if (Bun__deepEquals(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(otherProp, nullptr, patternObject, nullptr, globalObject, &scope, nullptr, false, true)) { + if (Bun__deepMatch(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 +template std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, MarkedArgumentBuffer& gcBuffer, Vector, 16>& stack, ThrowScope* scope, JSCell* _Nonnull c1, JSCell* _Nonnull c2); -template +template bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector, 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 isSpecialEqual = specialObjectsDequal(globalObject, gcBuffer, stack, scope, c1, c2); + std::optional isSpecialEqual = specialObjectsDequal(globalObject, gcBuffer, stack, scope, c1, c2); if (isSpecialEqual.has_value()) return std::move(*isSpecialEqual); - isSpecialEqual = specialObjectsDequal(globalObject, gcBuffer, stack, scope, c2, c1); + isSpecialEqual = specialObjectsDequal(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(globalObject, left, right, gcBuffer, stack, scope, true)) { + if (!Bun__deepEquals(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(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) { + if (!Bun__deepEquals(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(v2); auto v1Value = v1Wrapper->internalValue(); auto v2Value = v2Wrapper->internalValue(); - if (!Bun__deepEquals(globalObject, v1Value, v2Value, gcBuffer, stack, scope, addToStack)) { + if (!Bun__deepEquals(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(globalObject, left, right, gcBuffer, stack, scope, true)) { + if (!Bun__deepEquals(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(globalObject, left, right, gcBuffer, stack, scope, true)) { + if (!Bun__deepEquals(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(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) { + if (!Bun__deepEquals(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 +template bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector, 16>& stack, ThrowScope* scope, bool addToStack); +template bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSValue v1, JSValue v2, MarkedArgumentBuffer& gcBuffer, Vector, 16>& stack, ThrowScope* scope, bool addToStack); + +template std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, MarkedArgumentBuffer& gcBuffer, Vector, 16>& stack, ThrowScope* scope, JSCell* _Nonnull c1, JSCell* _Nonnull c2) { uint8_t c1Type = c1->type(); uint8_t c2Type = c2->type(); + std::optional matchMaybeCheckProperties = true; + if constexpr (mode == BunDeepEqualsMode_Node) { + matchMaybeCheckProperties = std::nullopt; + } switch (c1Type) { case JSSetType: { @@ -1035,7 +1042,7 @@ std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark JSValue key2; bool foundMatchingKey = false; while (iter2->next(globalObject, key2)) { - if (Bun__deepEquals(globalObject, key1, key2, gcBuffer, stack, scope, false)) { + if (Bun__deepEquals(globalObject, key1, key2, gcBuffer, stack, scope, false)) { foundMatchingKey = true; break; } @@ -1047,7 +1054,7 @@ std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark } } - return std::nullopt; + return matchMaybeCheckProperties; } case JSMapType: { if (c2Type != JSMapType) { @@ -1074,7 +1081,7 @@ std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark JSValue key2; bool foundMatchingKey = false; while (iter2->nextKeyValue(globalObject, key2, value2)) { - if (Bun__deepEquals(globalObject, key1, key2, gcBuffer, stack, scope, false)) { + if (Bun__deepEquals(globalObject, key1, key2, gcBuffer, stack, scope, false)) { foundMatchingKey = true; break; } @@ -1088,12 +1095,12 @@ std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark // Compare both values below. } - if (!Bun__deepEquals(globalObject, value1, value2, gcBuffer, stack, scope, false)) { + if (!Bun__deepEquals(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 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 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 specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark RETURN_IF_EXCEPTION(*scope, false); auto rightCause = right->get(globalObject, cause); RETURN_IF_EXCEPTION(*scope, false); - if (!Bun__deepEquals(globalObject, leftCause, rightCause, gcBuffer, stack, scope, true)) { + if (!Bun__deepEquals(globalObject, leftCause, rightCause, gcBuffer, stack, scope, true)) { return false; } RETURN_IF_EXCEPTION(*scope, false); @@ -1249,7 +1256,7 @@ std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark return false; } - if (!Bun__deepEquals(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) { + if (!Bun__deepEquals(globalObject, prop1, prop2, gcBuffer, stack, scope, true)) { return false; } @@ -1304,7 +1311,7 @@ std::optional 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 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 specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark return false; } } - return std::nullopt; + return matchMaybeCheckProperties; } else if (c1Type == Float32ArrayType) { auto* leftFloat = static_cast(vector); auto* rightFloat = static_cast(rightVector); @@ -1343,7 +1350,7 @@ std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark return false; } } - return std::nullopt; + return matchMaybeCheckProperties; } else { // Float64Array auto* leftDouble = static_cast(vector); auto* rightDouble = static_cast(rightVector); @@ -1354,12 +1361,12 @@ std::optional 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 specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark } } else { if ((url1 == nullptr) != (url2 == nullptr)) { - return std::nullopt; + return matchMaybeCheckProperties; } } @@ -1397,7 +1404,7 @@ std::optional specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark return false; } - return std::nullopt; + return matchMaybeCheckProperties; } // TODO: FormData. @@ -1423,7 +1430,7 @@ std::optional 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 specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark } } else { if ((urlSearchParams1 == nullptr) != (urlSearchParams2 == nullptr)) { - return std::nullopt; + return matchMaybeCheckProperties; } } } @@ -1462,7 +1469,7 @@ std::optional 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 specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark } } else { if ((headers1 == nullptr) != (headers2 == nullptr)) { - return std::nullopt; + return matchMaybeCheckProperties; } } } @@ -1505,14 +1512,14 @@ std::optional 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 specialObjectsDequal(JSC::JSGlobalObject* globalObject, Mark * @return true * @return false */ -template +template bool Bun__deepMatch( JSValue objValue, std::set* 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, 16> stack; MarkedArgumentBuffer gcBuffer; - if (!Bun__deepEquals(globalObject, prop, subsetProp, gcBuffer, stack, throwScope, true)) { + if (!Bun__deepEquals(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(prop, seenObjProperties, subsetProp, seenSubsetProperties, globalObject, throwScope, gcBuffer, replacePropsWithAsymmetricMatchers, isMatchingObjectContaining)) { + if (!Bun__deepMatch(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 +template inline bool deepEqualsWrapperImpl(JSC::EncodedJSValue a, JSC::EncodedJSValue b, JSC::JSGlobalObject* global) { auto& vm = global->vm(); auto scope = DECLARE_THROW_SCOPE(vm); Vector, 16> stack; MarkedArgumentBuffer args; - return Bun__deepEquals(global, JSC::JSValue::decode(a), JSC::JSValue::decode(b), args, stack, &scope, true); + return Bun__deepEquals(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(JSValue0, JSValue1, globalObject); + return deepEqualsWrapperImpl(JSValue0, JSValue1, globalObject); } bool JSC__JSValue__jestDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject) { - return deepEqualsWrapperImpl(JSValue0, JSValue1, globalObject); + return deepEqualsWrapperImpl(JSValue0, JSValue1, globalObject); } bool JSC__JSValue__strictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject) { - return deepEqualsWrapperImpl(JSValue0, JSValue1, globalObject); + return deepEqualsWrapperImpl(JSValue0, JSValue1, globalObject); } bool JSC__JSValue__jestStrictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* globalObject) { - return deepEqualsWrapperImpl(JSValue0, JSValue1, globalObject); + return deepEqualsWrapperImpl(JSValue0, JSValue1, globalObject); } #undef IMPL_DEEP_EQUALS_WRAPPER @@ -2593,7 +2600,7 @@ bool JSC__JSValue__deepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue J std::set objVisited; std::set subsetVisited; MarkedArgumentBuffer gcBuffer; - return Bun__deepMatch(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false); + return Bun__deepMatch(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 objVisited; std::set subsetVisited; MarkedArgumentBuffer gcBuffer; - return Bun__deepMatch(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false); + return Bun__deepMatch(obj, &objVisited, subset, &subsetVisited, globalObject, &scope, &gcBuffer, replacePropsWithAsymmetricMatchers, false); } extern "C" bool Bun__JSValue__isAsyncContextFrame(JSC::EncodedJSValue value) diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h index d4b56c87fc..5e01a1e8da 100644 --- a/src/bun.js/bindings/headers-handwritten.h +++ b/src/bun.js/bindings/headers-handwritten.h @@ -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 +template bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JSValue v2, JSC::MarkedArgumentBuffer&, Vector, 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 +template bool Bun__deepMatch( JSC::JSValue object, std::set* seenObjProperties, diff --git a/src/js/node/util.ts b/src/js/node/util.ts index 470f2ca6b6..fa7ec8b9ac 100644 --- a/src/js/node/util.ts +++ b/src/js/node/util.ts @@ -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);