aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp10
-rw-r--r--src/bun.js/bindings/bindings.cpp347
-rw-r--r--src/bun.js/bindings/bindings.zig28
-rw-r--r--src/bun.js/bindings/headers-handwritten.h3
-rw-r--r--src/bun.js/bindings/headers.h3
-rw-r--r--src/bun.js/bindings/headers.zig3
-rw-r--r--src/bun.js/test/jest.zig14
7 files changed, 261 insertions, 147 deletions
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 9b3bfd2a2..5589d2add 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -2077,11 +2077,11 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepEquals, (JSGlobalObject * globalObject,
Vector<std::pair<JSValue, JSValue>, 16> stack;
if (arg3.isBoolean() && arg3.asBoolean()) {
- bool isEqual = Bun__deepEquals<true>(globalObject, arg1, arg2, stack, &scope, true);
+ bool isEqual = Bun__deepEquals<true, false>(globalObject, arg1, arg2, stack, &scope, true);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsBoolean(isEqual));
} else {
- bool isEqual = Bun__deepEquals<false>(globalObject, arg1, arg2, stack, &scope, true);
+ bool isEqual = Bun__deepEquals<false, false>(globalObject, arg1, arg2, stack, &scope, true);
RETURN_IF_EXCEPTION(scope, {});
return JSValue::encode(jsBoolean(isEqual));
}
@@ -2107,13 +2107,13 @@ JSC_DEFINE_HOST_FUNCTION(functionBunDeepMatch, (JSGlobalObject * globalObject, J
if (!subset.isObject() || !object.isObject()) {
auto throwScope = DECLARE_THROW_SCOPE(vm);
- throwTypeError(globalObject, throwScope, "Expected 2 object to match"_s);
+ throwTypeError(globalObject, throwScope, "Expected 2 objects to match"_s);
return JSValue::encode(jsUndefined());
}
- bool isEqual = Bun__deepMatch(object, subset, globalObject, &scope, false);
+ bool match = Bun__deepMatch<false>(object, subset, globalObject, &scope, false);
RETURN_IF_EXCEPTION(scope, {});
- return JSValue::encode(jsBoolean(isEqual));
+ return JSValue::encode(jsBoolean(match));
}
JSC_DECLARE_HOST_FUNCTION(functionBunNanoseconds);
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp
index 2ec1bd902..4eee81f4d 100644
--- a/src/bun.js/bindings/bindings.cpp
+++ b/src/bun.js/bindings/bindings.cpp
@@ -123,6 +123,115 @@ static void copyToUWS(WebCore::FetchHeaders* headers, UWSResponse* res)
using namespace JSC;
+using namespace WebCore;
+
+enum class AsymmetricMatcherResult : uint8_t {
+ PASS,
+ FAIL,
+ NOT_MATCHER,
+};
+
+AsymmetricMatcherResult matchAsymmetricMatcher(JSGlobalObject* globalObject, JSCell* matcherPropCell, JSValue otherProp, ThrowScope* throwScope)
+{
+ VM& vm = globalObject->vm();
+
+ if (auto* expectAnything = jsDynamicCast<JSExpectAnything*>(matcherPropCell)) {
+ if (otherProp.isUndefinedOrNull()) {
+ return AsymmetricMatcherResult::FAIL;
+ }
+
+ return AsymmetricMatcherResult::PASS;
+ } else if (auto* expectAny = jsDynamicCast<JSExpectAny*>(matcherPropCell)) {
+ JSValue constructorValue = expectAny->m_constructorValue.get();
+ JSObject* constructorObject = constructorValue.getObject();
+
+ if (otherProp.isPrimitive()) {
+ if (otherProp.isNumber() && globalObject->numberObjectConstructor() == constructorObject) {
+ return AsymmetricMatcherResult::PASS;
+ } else if (otherProp.isBoolean() && globalObject->booleanObjectConstructor() == constructorObject) {
+ return AsymmetricMatcherResult::PASS;
+ } else if (otherProp.isSymbol() && globalObject->symbolObjectConstructor() == constructorObject) {
+ return AsymmetricMatcherResult::PASS;
+ } else if (otherProp.isString()) {
+ if (auto* constructorFunction = jsDynamicCast<JSFunction*>(constructorObject)) {
+ String name = constructorFunction->name(vm);
+ if (name == "String"_s) {
+ return AsymmetricMatcherResult::PASS;
+ }
+ } else if (auto* internalConstructorFunction = jsDynamicCast<InternalFunction*>(constructorObject)) {
+ String name = internalConstructorFunction->name();
+ if (name == "String"_s) {
+ return AsymmetricMatcherResult::PASS;
+ }
+ }
+ } else if (otherProp.isBigInt()) {
+ if (auto* constructorFunction = jsDynamicCast<JSFunction*>(constructorObject)) {
+ String name = constructorFunction->name(vm);
+ if (name == "BigInt"_s) {
+ return AsymmetricMatcherResult::PASS;
+ }
+ } else if (auto* internalConstructorFunction = jsDynamicCast<InternalFunction*>(constructorObject)) {
+ String name = internalConstructorFunction->name();
+ if (name == "BigInt"_s) {
+ return AsymmetricMatcherResult::PASS;
+ }
+ }
+ }
+
+ return AsymmetricMatcherResult::FAIL;
+ }
+
+ if (constructorObject->hasInstance(globalObject, otherProp)) {
+ return AsymmetricMatcherResult::PASS;
+ }
+
+ return AsymmetricMatcherResult::FAIL;
+ } else if (auto* expectStringContaining = jsDynamicCast<JSExpectStringContaining*>(matcherPropCell)) {
+ JSValue expectedSubstring = expectStringContaining->m_stringValue.get();
+
+ if (otherProp.isString()) {
+ String otherString = otherProp.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(*throwScope, AsymmetricMatcherResult::FAIL);
+
+ String substring = expectedSubstring.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(*throwScope, AsymmetricMatcherResult::FAIL);
+
+ if (otherString.find(substring) != WTF::notFound) {
+ return AsymmetricMatcherResult::PASS;
+ }
+ }
+
+ return AsymmetricMatcherResult::FAIL;
+ } else if (auto* expectStringMatching = jsDynamicCast<JSExpectStringMatching*>(matcherPropCell)) {
+ JSValue expectedTestValue = expectStringMatching->m_testValue.get();
+
+ if (otherProp.isString()) {
+ if (expectedTestValue.isString()) {
+ String otherString = otherProp.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(*throwScope, AsymmetricMatcherResult::FAIL);
+
+ String substring = expectedTestValue.toWTFString(globalObject);
+ RETURN_IF_EXCEPTION(*throwScope, AsymmetricMatcherResult::FAIL);
+
+ if (otherString.find(substring) != WTF::notFound) {
+ return AsymmetricMatcherResult::PASS;
+ }
+ } else if (expectedTestValue.isCell() and expectedTestValue.asCell()->type() == RegExpObjectType) {
+ if (auto* regex = jsDynamicCast<RegExpObject*>(expectedTestValue)) {
+ JSString* otherString = otherProp.toString(globalObject);
+ if (regex->match(globalObject, otherString)) {
+ return AsymmetricMatcherResult::PASS;
+ }
+ }
+ }
+ }
+
+ return AsymmetricMatcherResult::FAIL;
+ }
+
+ return AsymmetricMatcherResult::NOT_MATCHER;
+}
+
template<typename PromiseType, bool isInternal>
static void handlePromise(PromiseType* promise, JSC__JSGlobalObject* globalObject, JSC::EncodedJSValue ctx, JSC__JSValue (*resolverFunction)(JSC__JSGlobalObject* arg0, JSC__CallFrame* callFrame), JSC__JSValue (*rejecterFunction)(JSC__JSGlobalObject* arg0, JSC__CallFrame* callFrame))
{
@@ -183,10 +292,39 @@ JSValue getIndexWithoutAccessors(JSGlobalObject* globalObject, JSObject* obj, ui
return JSValue();
}
-template<bool isStrict>
+template<bool isStrict, bool enableAsymmetricMatchers>
bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, ThrowScope* scope, bool addToStack)
{
VM& vm = globalObject->vm();
+
+ // need to check this before primitives, asymmetric matchers
+ // can match against any type of value.
+ if constexpr (enableAsymmetricMatchers) {
+ JSCell* c1 = v1.asCell();
+ JSCell* c2 = v2.asCell();
+ if (v2.isCell() && !v2.isEmpty() && c2->type() == JSC::JSType(JSDOMWrapperType)) {
+ switch (matchAsymmetricMatcher(globalObject, c2, v1, scope)) {
+ case AsymmetricMatcherResult::FAIL:
+ return false;
+ case AsymmetricMatcherResult::PASS:
+ return true;
+ case AsymmetricMatcherResult::NOT_MATCHER:
+ // continue comparison
+ break;
+ }
+ } else if (v1.isCell() && !v1.isEmpty() && c1->type() == JSC::JSType(JSDOMWrapperType)) {
+ switch (matchAsymmetricMatcher(globalObject, c1, v2, scope)) {
+ case AsymmetricMatcherResult::FAIL:
+ return false;
+ case AsymmetricMatcherResult::PASS:
+ return true;
+ case AsymmetricMatcherResult::NOT_MATCHER:
+ // continue comparison
+ break;
+ }
+ }
+ }
+
if (!v1.isEmpty() && !v2.isEmpty() && JSC::sameValue(globalObject, v1, v2)) {
return true;
}
@@ -257,7 +395,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
RETURN_IF_EXCEPTION(*scope, false);
// set has unique values, no need to count
- if (Bun__deepEquals<isStrict>(globalObject, nextValue1, nextValue2, stack, scope, false)) {
+ if (Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, nextValue1, nextValue2, stack, scope, false)) {
found = true;
if (!nextValue1.isPrimitive()) {
stack.append({ nextValue1, nextValue2 });
@@ -276,7 +414,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return false;
}
- break;
+ return true;
}
case JSMapType: {
if (c2Type != JSMapType) {
@@ -337,8 +475,8 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
JSValue value2 = nextValueObject2->getIndex(globalObject, static_cast<unsigned>(1));
RETURN_IF_EXCEPTION(*scope, false);
- if (Bun__deepEquals<isStrict>(globalObject, key1, key2, stack, scope, false)) {
- if (Bun__deepEquals<isStrict>(globalObject, nextValue1, nextValue2, stack, scope, false)) {
+ if (Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, key1, key2, stack, scope, false)) {
+ if (Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, nextValue1, nextValue2, stack, scope, false)) {
found = true;
if (!nextValue1.isPrimitive()) {
stack.append({ nextValue1, nextValue2 });
@@ -358,7 +496,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return false;
}
- break;
+ return true;
}
case ArrayBufferType: {
if (c2Type != ArrayBufferType) {
@@ -399,10 +537,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
JSC::DateInstance* left = jsCast<DateInstance*>(v1);
JSC::DateInstance* right = jsCast<DateInstance*>(v2);
- if (left->structureID() == right->structureID()) {
- return left->internalNumber() == right->internalNumber();
- }
- break;
+ return left->internalNumber() == right->internalNumber();
}
case RegExpObjectType: {
if (c2Type != RegExpObjectType) {
@@ -463,10 +598,18 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return (memcmp(vector, rightVector, byteLength) == 0);
}
case StringObjectType: {
+ if (c2Type != StringObjectType) {
+ return false;
+ }
+
if (!equal(JSObject::calculatedClassName(o1), JSObject::calculatedClassName(o2))) {
return false;
}
- break;
+
+ JSString* s1 = c1->toStringInline(globalObject);
+ JSString* s2 = c2->toStringInline(globalObject);
+
+ return s1->equal(globalObject, s2);
}
case JSFunctionType: {
return false;
@@ -518,7 +661,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
}
}
- if (!Bun__deepEquals<isStrict>(globalObject, left, right, stack, scope, true)) {
+ if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, left, right, stack, scope, true)) {
return false;
}
@@ -573,7 +716,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return false;
}
- if (!Bun__deepEquals<isStrict>(globalObject, prop1, prop2, stack, scope, true)) {
+ if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, prop1, prop2, stack, scope, true)) {
return false;
}
@@ -633,7 +776,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return true;
}
- if (!Bun__deepEquals<isStrict>(globalObject, left, right, stack, scope, true)) {
+ if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, left, right, stack, scope, true)) {
result = false;
return false;
}
@@ -707,7 +850,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return false;
}
- if (!Bun__deepEquals<isStrict>(globalObject, prop1, prop2, stack, scope, true)) {
+ if (!Bun__deepEquals<isStrict, enableAsymmetricMatchers>(globalObject, prop1, prop2, stack, scope, true)) {
return false;
}
@@ -721,93 +864,7 @@ bool Bun__deepEquals(JSC__JSGlobalObject* globalObject, JSValue v1, JSValue v2,
return true;
}
-using namespace WebCore;
-
-enum class AsymmetricMatcherResult : uint8_t {
- PASS,
- FAIL,
- NOT_MATCHER,
-};
-
-AsymmetricMatcherResult matchAsymmetricMatcher(JSGlobalObject* globalObject, JSCell* matcherPropCell, JSValue otherProp, ThrowScope* throwScope)
-{
- if (auto* expectAnything = jsDynamicCast<JSExpectAnything*>(matcherPropCell)) {
- if (otherProp.isUndefinedOrNull()) {
- return AsymmetricMatcherResult::FAIL;
- }
-
- return AsymmetricMatcherResult::PASS;
- } else if (auto* expectAny = jsDynamicCast<JSExpectAny*>(matcherPropCell)) {
- JSValue constructorValue = expectAny->m_constructorValue.get();
- JSObject* constructorObject = constructorValue.getObject();
-
- if (constructorObject->hasInstance(globalObject, otherProp)) {
- return AsymmetricMatcherResult::PASS;
- }
-
- // check for basic types
- VM& vm = globalObject->vm();
- ZigString name = {};
- JSC__JSValue__getNameProperty(JSValue::encode(constructorValue), globalObject, &name);
- StringView nameView(name.ptr, name.len);
-
- if (otherProp.isNumber() && nameView == "Number"_s) {
- return AsymmetricMatcherResult::PASS;
- } else if (otherProp.isBoolean() && nameView == "Boolean"_s) {
- return AsymmetricMatcherResult::PASS;
- } else if (otherProp.isString() && nameView == "String"_s) {
- return AsymmetricMatcherResult::PASS;
- } else if (otherProp.isBigInt() && nameView == "BigInt"_s) {
- return AsymmetricMatcherResult::PASS;
- }
-
- return AsymmetricMatcherResult::FAIL;
- } else if (auto* expectStringContaining = jsDynamicCast<JSExpectStringContaining*>(matcherPropCell)) {
- JSValue expectedSubstring = expectStringContaining->m_stringValue.get();
-
- if (otherProp.isString()) {
- String otherString = otherProp.toWTFString(globalObject);
- RETURN_IF_EXCEPTION(*throwScope, AsymmetricMatcherResult::FAIL);
-
- String substring = expectedSubstring.toWTFString(globalObject);
- RETURN_IF_EXCEPTION(*throwScope, AsymmetricMatcherResult::FAIL);
-
- if (otherString.find(substring) != WTF::notFound) {
- return AsymmetricMatcherResult::PASS;
- }
- }
-
- return AsymmetricMatcherResult::FAIL;
- } else if (auto* expectStringMatching = jsDynamicCast<JSExpectStringMatching*>(matcherPropCell)) {
- JSValue expectedTestValue = expectStringMatching->m_testValue.get();
-
- if (otherProp.isString()) {
- if (expectedTestValue.isString()) {
- String otherString = otherProp.toWTFString(globalObject);
- RETURN_IF_EXCEPTION(*throwScope, AsymmetricMatcherResult::FAIL);
-
- String substring = expectedTestValue.toWTFString(globalObject);
- RETURN_IF_EXCEPTION(*throwScope, AsymmetricMatcherResult::FAIL);
-
- if (otherString.find(substring) != WTF::notFound) {
- return AsymmetricMatcherResult::PASS;
- }
- } else if (expectedTestValue.isCell() and expectedTestValue.asCell()->type() == RegExpObjectType) {
- if (auto* regex = jsDynamicCast<RegExpObject*>(expectedTestValue)) {
- JSString* otherString = otherProp.toString(globalObject);
- if (regex->match(globalObject, otherString)) {
- return AsymmetricMatcherResult::PASS;
- }
- }
- }
- }
-
- return AsymmetricMatcherResult::FAIL;
- }
-
- return AsymmetricMatcherResult::NOT_MATCHER;
-}
-
+template<bool enableAsymmetricMatchers>
bool Bun__deepMatch(JSValue objValue, JSValue subsetValue, JSGlobalObject* globalObject, ThrowScope* throwScope, bool replacePropsWithAsymmetricMatchers)
{
VM& vm = globalObject->vm();
@@ -848,36 +905,38 @@ bool Bun__deepMatch(JSValue objValue, JSValue subsetValue, JSGlobalObject* globa
JSCell* subsetPropCell = subsetProp.asCell();
JSCell* propCell = prop.asCell();
- if (subsetProp.isCell() and subsetPropCell->type() == JSC::JSType(JSDOMWrapperType)) {
- switch (matchAsymmetricMatcher(globalObject, subsetPropCell, prop, throwScope)) {
- case AsymmetricMatcherResult::FAIL:
- return false;
- case AsymmetricMatcherResult::PASS:
- if (replacePropsWithAsymmetricMatchers) {
- obj->putDirect(vm, subsetProps[i], subsetProp);
+ if constexpr (enableAsymmetricMatchers) {
+ if (subsetProp.isCell() && !subsetProp.isEmpty() && subsetPropCell->type() == JSC::JSType(JSDOMWrapperType)) {
+ switch (matchAsymmetricMatcher(globalObject, subsetPropCell, prop, throwScope)) {
+ case AsymmetricMatcherResult::FAIL:
+ return false;
+ case AsymmetricMatcherResult::PASS:
+ if (replacePropsWithAsymmetricMatchers) {
+ obj->putDirect(vm, subsetProps[i], subsetProp);
+ }
+ // continue to next subset prop
+ continue;
+ case AsymmetricMatcherResult::NOT_MATCHER:
+ break;
}
- // continue to next subset prop
- continue;
- case AsymmetricMatcherResult::NOT_MATCHER:
- break;
- }
- } else if (prop.isCell() and propCell->type() == JSC::JSType(JSDOMWrapperType)) {
- switch (matchAsymmetricMatcher(globalObject, propCell, subsetProp, throwScope)) {
- case AsymmetricMatcherResult::FAIL:
- return false;
- case AsymmetricMatcherResult::PASS:
- if (replacePropsWithAsymmetricMatchers) {
- subsetObj->putDirect(vm, subsetProps[i], prop);
+ } else if (prop.isCell() && !prop.isEmpty() && propCell->type() == JSC::JSType(JSDOMWrapperType)) {
+ switch (matchAsymmetricMatcher(globalObject, propCell, subsetProp, throwScope)) {
+ case AsymmetricMatcherResult::FAIL:
+ return false;
+ case AsymmetricMatcherResult::PASS:
+ if (replacePropsWithAsymmetricMatchers) {
+ subsetObj->putDirect(vm, subsetProps[i], prop);
+ }
+ // continue to next subset prop
+ continue;
+ case AsymmetricMatcherResult::NOT_MATCHER:
+ break;
}
- // continue to next subset prop
- continue;
- case AsymmetricMatcherResult::NOT_MATCHER:
- break;
}
}
if (subsetProp.isObject() and prop.isObject()) {
- if (!Bun__deepMatch(prop, subsetProp, globalObject, throwScope, replacePropsWithAsymmetricMatchers)) {
+ if (!Bun__deepMatch<enableAsymmetricMatchers>(prop, subsetProp, globalObject, throwScope, replacePropsWithAsymmetricMatchers)) {
return false;
}
} else {
@@ -1622,7 +1681,17 @@ bool JSC__JSValue__deepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC_
ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
Vector<std::pair<JSValue, JSValue>, 16> stack;
- return Bun__deepEquals<false>(globalObject, v1, v2, stack, &scope, true);
+ return Bun__deepEquals<false, false>(globalObject, v1, v2, stack, &scope, true);
+}
+
+bool JSC__JSValue__jestDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject)
+{
+ JSValue v1 = JSValue::decode(JSValue0);
+ JSValue v2 = JSValue::decode(JSValue1);
+
+ ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
+ Vector<std::pair<JSValue, JSValue>, 16> stack;
+ return Bun__deepEquals<false, true>(globalObject, v1, v2, stack, &scope, true);
}
bool JSC__JSValue__strictDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject)
@@ -1632,7 +1701,17 @@ bool JSC__JSValue__strictDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1
ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
Vector<std::pair<JSValue, JSValue>, 16> stack;
- return Bun__deepEquals<true>(globalObject, v1, v2, stack, &scope, true);
+ return Bun__deepEquals<true, false>(globalObject, v1, v2, stack, &scope, true);
+}
+
+bool JSC__JSValue__jestStrictDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject)
+{
+ JSValue v1 = JSValue::decode(JSValue0);
+ JSValue v2 = JSValue::decode(JSValue1);
+
+ ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
+ Vector<std::pair<JSValue, JSValue>, 16> stack;
+ return Bun__deepEquals<true, true>(globalObject, v1, v2, stack, &scope, true);
}
bool JSC__JSValue__deepMatch(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject, bool replacePropsWithAsymmetricMatchers)
@@ -1642,7 +1721,17 @@ bool JSC__JSValue__deepMatch(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__
ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
- return Bun__deepMatch(obj, subset, globalObject, &scope, replacePropsWithAsymmetricMatchers);
+ return Bun__deepMatch<false>(obj, subset, globalObject, &scope, replacePropsWithAsymmetricMatchers);
+}
+
+bool JSC__JSValue__jestDeepMatch(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject, bool replacePropsWithAsymmetricMatchers)
+{
+ JSValue obj = JSValue::decode(JSValue0);
+ JSValue subset = JSValue::decode(JSValue1);
+
+ ThrowScope scope = DECLARE_THROW_SCOPE(globalObject->vm());
+
+ return Bun__deepMatch<true>(obj, subset, globalObject, &scope, replacePropsWithAsymmetricMatchers);
}
// This is the same as the C API version, except it returns a JSValue which may be a *Exception
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 18aaf3db9..35c9d26fa 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -4414,14 +4414,29 @@ pub const JSValue = enum(JSValueReprInt) {
return cppFn("deepEquals", .{ this, other, global });
}
+ /// same as `JSValue.deepEquals`, but with jest asymmetric matchers enabled
+ pub fn jestDeepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) bool {
+ return cppFn("jestDeepEquals", .{ this, other, global });
+ }
+
pub fn strictDeepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) bool {
return cppFn("strictDeepEquals", .{ this, other, global });
}
+ /// same as `JSValue.strictDeepEquals`, but with jest asymmetric matchers enabled
+ pub fn jestStrictDeepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) bool {
+ return cppFn("jestStrictDeepEquals", .{ this, other, global });
+ }
+
pub fn deepMatch(this: JSValue, subset: JSValue, global: *JSGlobalObject, replace_props_with_asymmetric_matchers: bool) bool {
return cppFn("deepMatch", .{ this, subset, global, replace_props_with_asymmetric_matchers });
}
+ /// same as `JSValue.deepMatch`, but with jest asymmetric matchers enabled
+ pub fn jestDeepMatch(this: JSValue, subset: JSValue, global: *JSGlobalObject, replace_props_with_asymmetric_matchers: bool) bool {
+ return cppFn("jestDeepMatch", .{ this, subset, global, replace_props_with_asymmetric_matchers });
+ }
+
pub const DiffMethod = enum(u8) {
none,
character,
@@ -4705,7 +4720,6 @@ pub const JSValue = enum(JSValueReprInt) {
"createTypeError",
"createUninitializedUint8Array",
"deepEquals",
- "deepMatch",
"eqlCell",
"eqlValue",
"fastGetDirect_",
@@ -4739,13 +4753,11 @@ pub const JSValue = enum(JSValueReprInt) {
"isBoolean",
"isCallable",
"isClass",
- "isConstructor",
"isCustomGetterSetter",
"isError",
"isException",
"isGetterSetter",
"isHeapBigInt",
- "isInstanceOf",
"isInt32",
"isInt32AsAnyInt",
"isIterable",
@@ -4775,7 +4787,6 @@ pub const JSValue = enum(JSValueReprInt) {
"putIndex",
"putRecord",
"strictDeepEquals",
- "stringIncludes",
"symbolFor",
"symbolKeyFor",
"toBoolean",
@@ -4783,7 +4794,6 @@ pub const JSValue = enum(JSValueReprInt) {
"toError_",
"toInt32",
"toInt64",
- "toMatch",
"toObject",
"toPropertyKeyValue",
"toString",
@@ -4792,6 +4802,14 @@ pub const JSValue = enum(JSValueReprInt) {
"toWTFString",
"toZigException",
"toZigString",
+ "toMatch",
+ "isConstructor",
+ "isInstanceOf",
+ "stringIncludes",
+ "deepMatch",
+ "jestDeepEquals",
+ "jestStrictDeepEquals",
+ "jestDeepMatch",
};
};
diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h
index a4287cf2e..57940550f 100644
--- a/src/bun.js/bindings/headers-handwritten.h
+++ b/src/bun.js/bindings/headers-handwritten.h
@@ -338,9 +338,10 @@ extern "C" size_t Bun__encoding__byteLengthUTF16(const UChar* ptr, size_t len, E
extern "C" int64_t Bun__encoding__constructFromLatin1(void*, const unsigned char* ptr, size_t len, Encoding encoding);
extern "C" int64_t Bun__encoding__constructFromUTF16(void*, const UChar* ptr, size_t len, Encoding encoding);
-template<bool isStrict>
+template<bool isStrict, bool enableAsymmetricMatchers>
bool Bun__deepEquals(JSC::JSGlobalObject* globalObject, JSC::JSValue v1, JSC::JSValue v2, Vector<std::pair<JSC::JSValue, JSC::JSValue>, 16>& stack, JSC::ThrowScope* scope, bool addToStack);
+template<bool enableAsymmetricMatchers>
bool Bun__deepMatch(JSC::JSValue object, JSC::JSValue subset, JSC::JSGlobalObject* globalObject, JSC::ThrowScope* throwScope, bool replacePropsWithAsymmetricMatchers);
extern "C" void Bun__remapStackFramePositions(JSC::JSGlobalObject*, ZigStackFrame*, size_t);
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index 4b3875d83..cdf7e05f4 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -365,6 +365,9 @@ CPP_DECL bool JSC__JSValue__isSameValue(JSC__JSValue JSValue0, JSC__JSValue JSVa
CPP_DECL bool JSC__JSValue__isSymbol(JSC__JSValue JSValue0);
CPP_DECL bool JSC__JSValue__isTerminationException(JSC__JSValue JSValue0, JSC__VM* arg1);
CPP_DECL bool JSC__JSValue__isUInt32AsAnyInt(JSC__JSValue JSValue0);
+CPP_DECL bool JSC__JSValue__jestDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* arg2);
+CPP_DECL bool JSC__JSValue__jestDeepMatch(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* arg2, bool arg3);
+CPP_DECL bool JSC__JSValue__jestStrictDeepEquals(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* arg2);
CPP_DECL JSC__JSValue JSC__JSValue__jsBoolean(bool arg0);
CPP_DECL JSC__JSValue JSC__JSValue__jsDoubleNumber(double arg0);
CPP_DECL JSC__JSValue JSC__JSValue__jsNull();
diff --git a/src/bun.js/bindings/headers.zig b/src/bun.js/bindings/headers.zig
index 403be20f6..4dda5f30b 100644
--- a/src/bun.js/bindings/headers.zig
+++ b/src/bun.js/bindings/headers.zig
@@ -265,6 +265,9 @@ pub extern fn JSC__JSValue__isSameValue(JSValue0: JSC__JSValue, JSValue1: JSC__J
pub extern fn JSC__JSValue__isSymbol(JSValue0: JSC__JSValue) bool;
pub extern fn JSC__JSValue__isTerminationException(JSValue0: JSC__JSValue, arg1: *bindings.VM) bool;
pub extern fn JSC__JSValue__isUInt32AsAnyInt(JSValue0: JSC__JSValue) bool;
+pub extern fn JSC__JSValue__jestDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool;
+pub extern fn JSC__JSValue__jestDeepMatch(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject, arg3: bool) bool;
+pub extern fn JSC__JSValue__jestStrictDeepEquals(JSValue0: JSC__JSValue, JSValue1: JSC__JSValue, arg2: *bindings.JSGlobalObject) bool;
pub extern fn JSC__JSValue__jsBoolean(arg0: bool) JSC__JSValue;
pub extern fn JSC__JSValue__jsDoubleNumber(arg0: f64) JSC__JSValue;
pub extern fn JSC__JSValue__jsNull(...) JSC__JSValue;
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index ad60a9c5e..6c77d7aaa 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -1620,7 +1620,7 @@ pub const Expect = struct {
value.ensureStillAlive();
const not = this.op.contains(.not);
- var pass = value.deepEquals(expected, globalObject);
+ var pass = value.jestDeepEquals(expected, globalObject);
if (not) pass = !pass;
if (pass) return thisValue;
@@ -1673,7 +1673,7 @@ pub const Expect = struct {
value.ensureStillAlive();
const not = this.op.contains(.not);
- var pass = value.strictDeepEquals(expected, globalObject);
+ var pass = value.jestStrictDeepEquals(expected, globalObject);
if (not) pass = !pass;
if (pass) return thisValue;
@@ -1750,7 +1750,7 @@ pub const Expect = struct {
}
if (pass and expected_property != null) {
- pass = received_property.deepEquals(expected_property.?, globalObject);
+ pass = received_property.jestDeepEquals(expected_property.?, globalObject);
}
if (not) pass = !pass;
@@ -2828,7 +2828,7 @@ pub const Expect = struct {
if (property_matchers) |_prop_matchers| {
var prop_matchers = _prop_matchers;
- if (!value.deepMatch(prop_matchers, globalObject, true)) {
+ if (!value.jestDeepMatch(prop_matchers, globalObject, true)) {
// TODO: print diff with properties from propertyMatchers
const signature = comptime getSignature("toMatchSnapshot", "<green>propertyMatchers<r>", false);
const fmt = signature ++ "\n\nExpected <green>propertyMatchers<r> to match properties from received object" ++
@@ -4179,18 +4179,18 @@ pub const Expect = struct {
if (args.len < 1 or !args[0].isObject()) {
const matcher_error = "\n\n<b>Matcher error<r>: <green>expected<r> value must be a non-null object\n";
if (not) {
- const fmt = comptime getSignature("toMatchObject", "", true) ++ matcher_error;
+ const fmt = comptime getSignature("toMatchObject", "<green>expected<r>", true) ++ matcher_error;
globalObject.throwPretty(fmt, .{});
return .zero;
}
- const fmt = comptime getSignature("toMatchObject", "", false) ++ matcher_error;
+ const fmt = comptime getSignature("toMatchObject", "<green>expected<r>", false) ++ matcher_error;
globalObject.throwPretty(fmt, .{});
return .zero;
}
const property_matchers = args[0];
- var pass = received_object.deepMatch(property_matchers, globalObject, true);
+ var pass = received_object.jestDeepMatch(property_matchers, globalObject, true);
if (not) pass = !pass;
if (pass) return thisValue;