aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/bindings/JSBufferList.cpp2
-rw-r--r--src/bun.js/bindings/JSMockFunction.cpp711
-rw-r--r--src/bun.js/bindings/JSMockFunction.h34
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp2
-rw-r--r--src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h1
-rw-r--r--src/bun.js/bindings/webcore/DOMIsoSubspaces.h1
-rw-r--r--src/bun.js/test/jest.zig23
-rw-r--r--src/js/out/WebCoreJSBuiltins.cpp4
-rw-r--r--src/js/out/modules/node/http.js3
-rw-r--r--src/js/out/modules/node/net.js4
10 files changed, 503 insertions, 282 deletions
diff --git a/src/bun.js/bindings/JSBufferList.cpp b/src/bun.js/bindings/JSBufferList.cpp
index 409d50df6..a8cefa710 100644
--- a/src/bun.js/bindings/JSBufferList.cpp
+++ b/src/bun.js/bindings/JSBufferList.cpp
@@ -445,4 +445,4 @@ void JSBufferListConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject*
const ClassInfo JSBufferListConstructor::s_info = { "BufferList"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSBufferListConstructor) };
-} // namespace Zig \ No newline at end of file
+} // namespace Zig
diff --git a/src/bun.js/bindings/JSMockFunction.cpp b/src/bun.js/bindings/JSMockFunction.cpp
index fcd80102b..b7c2659b4 100644
--- a/src/bun.js/bindings/JSMockFunction.cpp
+++ b/src/bun.js/bindings/JSMockFunction.cpp
@@ -22,9 +22,31 @@
namespace Bun {
+/**
+ * intended to be used in an if statement as an abstraction over this double if statement
+ *
+ * if(jsValue) {
+ * if(auto value = jsDynamicCast(jsValue)) {
+ * ...
+ * }
+ * }
+ *
+ * the reason this is needed is because jsDynamicCast will segfault if given a zero JSValue
+ */
+template<typename To>
+inline To tryJSDynamicCast(JSValue from)
+{
+ if (UNLIKELY(!from))
+ return nullptr;
+ if (UNLIKELY(!from.isCell()))
+ return nullptr;
+ return jsDynamicCast<To>(from.asCell());
+}
+
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionCall);
JSC_DECLARE_CUSTOM_GETTER(jsMockFunctionGetter_protoImpl);
JSC_DECLARE_CUSTOM_GETTER(jsMockFunctionGetter_mock);
+JSC_DECLARE_HOST_FUNCTION(jsMockFunctionGetter_mockGetLastCall);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionGetMockImplementation);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionGetMockName);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionMockClear);
@@ -40,8 +62,10 @@ JSC_DECLARE_HOST_FUNCTION(jsMockFunctionMockResolvedValue);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionMockResolvedValueOnce);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionMockRejectedValue);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionMockRejectedValueOnce);
+JSC_DECLARE_HOST_FUNCTION(jsMockFunctionWithImplementationCleanup);
JSC_DECLARE_HOST_FUNCTION(jsMockFunctionWithImplementation);
-JSC_DECLARE_HOST_FUNCTION(jsMockFunctionMockImplementationOnce);
+
+uint64_t JSMockModule::s_nextInvocationId = 0;
// This is taken from JSWeakSet
// We only want to hold onto the list of active spies which haven't already been collected
@@ -79,9 +103,7 @@ class JSMockImplementation final : public JSNonFinalObject {
public:
enum class Kind : uint8_t {
Call,
- Promise,
ReturnValue,
- ThrowValue,
ReturnThis,
};
@@ -112,7 +134,14 @@ public:
static constexpr unsigned numberOfInternalFields = 2;
- mutable JSC::WriteBarrier<Unknown> internalFields[2];
+ // either a function or a return value, depends on kind
+ mutable JSC::WriteBarrier<Unknown> underlyingValue;
+
+ // a combination of a pointer to the next implementation and a flag indicating if this is a once implementation
+ // - undefined - no next value
+ // - jsNumber(1) - no next value + is a once implementation
+ // - JSMockImplementation - next value + is a once implementation
+ mutable JSC::WriteBarrier<Unknown> nextValueOrSentinel;
DECLARE_EXPORT_INFO;
DECLARE_VISIT_CHILDREN;
@@ -121,11 +150,7 @@ public:
bool isOnce()
{
- auto secondField = internalFields[1].get();
- if (secondField.isNumber() && secondField.asInt32() == 1) {
- return true;
- }
- return jsDynamicCast<JSMockImplementation*>(secondField.asCell());
+ return !nextValueOrSentinel.get().isUndefined();
}
JSMockImplementation(JSC::VM& vm, JSC::Structure* structure, Kind kind)
@@ -137,8 +162,8 @@ public:
void finishCreation(JSC::VM& vm, JSC::JSValue first, JSC::JSValue second)
{
Base::finishCreation(vm);
- this->internalFields[0].set(vm, this, first);
- this->internalFields[1].set(vm, this, second);
+ this->underlyingValue.set(vm, this, first);
+ this->nextValueOrSentinel.set(vm, this, second);
}
};
@@ -149,32 +174,17 @@ void JSMockImplementation::visitChildrenImpl(JSCell* cell, Visitor& visitor)
ASSERT_GC_OBJECT_INHERITS(fn, info());
Base::visitChildren(fn, visitor);
- visitor.append(fn->internalFields[0]);
- visitor.append(fn->internalFields[1]);
+ visitor.append(fn->underlyingValue);
+ visitor.append(fn->nextValueOrSentinel);
}
DEFINE_VISIT_CHILDREN(JSMockImplementation);
enum class CallbackKind : uint8_t {
- Wrapper,
Call,
GetterSetter,
};
-static NativeFunction jsMockFunctionForCallbackKind(CallbackKind kind)
-{
- switch (kind) {
- // return jsMockFunctionGetterSetter;
- case CallbackKind::Wrapper:
- return jsMockFunctionMockImplementation;
- case CallbackKind::GetterSetter:
- case CallbackKind::Call:
- return jsMockFunctionCall;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
-}
-
const ClassInfo JSMockImplementation::s_info = { "MockImpl"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMockImplementation) };
class JSMockFunction : public JSC::InternalFunction {
@@ -197,12 +207,20 @@ public:
DECLARE_VISIT_CHILDREN;
JSC::LazyProperty<JSMockFunction, JSObject> mock;
+ // three pointers to implementation objects
+ // head of the list, this one is run next
mutable JSC::WriteBarrier<JSC::Unknown> implementation;
+ // this contains the non-once implementation. there is only ever one of these
+ mutable JSC::WriteBarrier<JSC::Unknown> fallbackImplmentation;
+ // the last once implementation
+ mutable JSC::WriteBarrier<JSC::Unknown> tail;
+ // original implementation from spy. separate from `implementation` so restoration always works
+ mutable JSC::WriteBarrier<JSC::Unknown> spyOriginal;
mutable JSC::WriteBarrier<JSC::JSArray> calls;
mutable JSC::WriteBarrier<JSC::JSArray> contexts;
+ mutable JSC::WriteBarrier<JSC::JSArray> invocationCallOrder;
mutable JSC::WriteBarrier<JSC::JSArray> instances;
mutable JSC::WriteBarrier<JSC::JSArray> returnValues;
- mutable JSC::WriteBarrier<JSC::Unknown> tail;
JSC::Weak<JSObject> spyTarget;
JSC::Identifier spyIdentifier;
@@ -214,6 +232,28 @@ public:
this->putDirect(vm, vm.propertyNames->name, jsString(vm, name), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly);
}
+ void copyNameAndLength(JSC::VM& vm, JSGlobalObject* global, JSC::JSValue value)
+ {
+ auto catcher = DECLARE_CATCH_SCOPE(vm);
+ WTF::String nameToUse;
+ if (auto* fn = jsDynamicCast<JSFunction*>(value)) {
+ nameToUse = fn->name(vm);
+ JSValue lengthJSValue = fn->get(global, vm.propertyNames->length);
+ if (lengthJSValue.isNumber()) {
+ this->putDirect(vm, vm.propertyNames->length, (lengthJSValue), JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly);
+ }
+ } else if (auto* fn = jsDynamicCast<InternalFunction*>(value)) {
+ nameToUse = fn->name();
+ } else {
+ nameToUse = "mockConstructor"_s;
+ }
+ this->setName(nameToUse);
+
+ if (catcher.exception()) {
+ catcher.clearException();
+ }
+ }
+
void initMock()
{
mock.initLater(
@@ -226,11 +266,12 @@ public:
object->putDirectOffset(init.vm, 1, mock->getContexts());
object->putDirectOffset(init.vm, 2, mock->getInstances());
object->putDirectOffset(init.vm, 3, mock->getReturnValues());
+ object->putDirectOffset(init.vm, 4, mock->getInvocationCallOrder());
init.set(object);
});
}
- void reset()
+ void clear()
{
this->calls.clear();
this->instances.clear();
@@ -242,12 +283,22 @@ public:
}
}
+ void reset()
+ {
+ this->clear();
+ this->implementation.clear();
+ this->fallbackImplmentation.clear();
+ this->tail.clear();
+ }
+
void clearSpy()
{
+ this->reset();
+
if (auto* target = this->spyTarget.get()) {
- JSValue implValue = jsUndefined();
- if (auto* impl = jsDynamicCast<JSMockImplementation*>(this->implementation.get())) {
- implValue = impl->internalFields[0].get();
+ JSValue implValue = this->spyOriginal.get();
+ if (!implValue) {
+ implValue = jsUndefined();
}
// Reset the spy back to the original value.
@@ -295,6 +346,15 @@ public:
}
return val;
}
+ JSArray* getInvocationCallOrder() const
+ {
+ JSArray* val = invocationCallOrder.get();
+ if (!val) {
+ val = JSC::constructEmptyArray(globalObject(), nullptr, 0);
+ this->invocationCallOrder.set(vm(), this, val);
+ }
+ return val;
+ }
template<typename, JSC::SubspaceAccess mode>
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
@@ -310,7 +370,7 @@ public:
}
JSMockFunction(JSC::VM& vm, JSC::Structure* structure, CallbackKind wrapKind)
- : Base(vm, structure, jsMockFunctionForCallbackKind(wrapKind), jsMockFunctionForCallbackKind(wrapKind))
+ : Base(vm, structure, jsMockFunctionCall, jsMockFunctionCall)
{
initMock();
}
@@ -324,41 +384,56 @@ void JSMockFunction::visitChildrenImpl(JSCell* cell, Visitor& visitor)
Base::visitChildren(fn, visitor);
visitor.append(fn->implementation);
+ visitor.append(fn->tail);
+ visitor.append(fn->fallbackImplmentation);
visitor.append(fn->calls);
visitor.append(fn->contexts);
visitor.append(fn->instances);
visitor.append(fn->returnValues);
- visitor.append(fn->tail);
+ visitor.append(fn->invocationCallOrder);
fn->mock.visit(visitor);
}
DEFINE_VISIT_CHILDREN(JSMockFunction);
-static void pushImplInternal(JSMockFunction* fn, JSGlobalObject* jsGlobalObject, JSMockImplementation::Kind kind, JSValue value, bool isOnce)
+static void pushImpl(JSMockFunction* fn, JSGlobalObject* jsGlobalObject, JSMockImplementation::Kind kind, JSValue value)
{
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(jsGlobalObject);
auto& vm = globalObject->vm();
- JSMockImplementation* impl = JSMockImplementation::create(globalObject, globalObject->mockModule.mockImplementationStructure.getInitializedOnMainThread(globalObject), kind, value, isOnce);
- JSValue currentTail = fn->tail.get();
- JSValue currentImpl = fn->implementation.get();
- if (currentTail) {
- if (auto* current = jsDynamicCast<JSMockImplementation*>(currentTail)) {
- current->internalFields[1].set(vm, current, impl);
- }
+
+ if (auto* current = tryJSDynamicCast<JSMockImplementation*>(fn->fallbackImplmentation.get())) {
+ current->underlyingValue.set(vm, current, value);
+ current->kind = kind;
+ return;
}
- fn->tail.set(vm, fn, impl);
- if (!currentImpl || !currentImpl.inherits<JSMockImplementation>()) {
+
+ JSMockImplementation* impl = JSMockImplementation::create(globalObject, globalObject->mockModule.mockImplementationStructure.getInitializedOnMainThread(globalObject), kind, value, false);
+ fn->fallbackImplmentation.set(vm, fn, impl);
+ if (auto* tail = tryJSDynamicCast<JSMockImplementation*>(fn->tail.get())) {
+ tail->nextValueOrSentinel.set(vm, tail, impl);
+ } else {
fn->implementation.set(vm, fn, impl);
}
}
-static void pushImpl(JSMockFunction* fn, JSGlobalObject* globalObject, JSMockImplementation::Kind kind, JSValue value)
+static void pushImplOnce(JSMockFunction* fn, JSGlobalObject* jsGlobalObject, JSMockImplementation::Kind kind, JSValue value)
{
- pushImplInternal(fn, globalObject, kind, value, false);
-}
+ Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(jsGlobalObject);
+ auto& vm = globalObject->vm();
-static void pushImplOnce(JSMockFunction* fn, JSGlobalObject* globalObject, JSMockImplementation::Kind kind, JSValue value)
-{
- pushImplInternal(fn, globalObject, kind, value, true);
+ JSMockImplementation* impl = JSMockImplementation::create(globalObject, globalObject->mockModule.mockImplementationStructure.getInitializedOnMainThread(globalObject), kind, value, true);
+
+ if (!fn->implementation.get()) {
+ fn->implementation.set(vm, fn, impl);
+ }
+ if (auto* tail = tryJSDynamicCast<JSMockImplementation*>(fn->tail.get())) {
+ tail->nextValueOrSentinel.set(vm, tail, impl);
+ } else {
+ fn->implementation.set(vm, fn, impl);
+ }
+ if (auto fallback = fn->fallbackImplmentation.get()) {
+ impl->nextValueOrSentinel.set(vm, impl, fallback);
+ }
+ fn->tail.set(vm, fn, impl);
}
class JSMockFunctionPrototype final : public JSC::JSNonFinalObject {
@@ -409,8 +484,8 @@ static const HashTableValue JSMockFunctionPrototypeTableValues[] = {
{ "mockReturnValueOnce"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMockFunctionMockReturnValueOnce, 1 } },
{ "mockResolvedValue"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMockFunctionMockResolvedValue, 1 } },
{ "mockResolvedValueOnce"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMockFunctionMockResolvedValueOnce, 1 } },
- { "mockRejectedValueOnce"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMockFunctionMockRejectedValue, 1 } },
- { "mockRejectedValue"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMockFunctionMockRejectedValueOnce, 1 } },
+ { "mockRejectedValue"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMockFunctionMockRejectedValue, 1 } },
+ { "mockRejectedValueOnce"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::NativeFunctionType, jsMockFunctionMockRejectedValueOnce, 1 } },
};
const ClassInfo JSMockFunction::s_info = { "Mock"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSMockFunction) };
@@ -446,7 +521,6 @@ extern "C" void JSMock__resetSpies(Zig::GlobalObject* globalObject)
continue;
auto* spyObject = jsCast<JSMockFunction*>(spy);
- spyObject->reset();
spyObject->clearSpy();
}
globalObject->mockModule.activeSpies.clear();
@@ -508,20 +582,7 @@ extern "C" EncodedJSValue JSMock__spyOn(JSC::JSGlobalObject* lexicalGlobalObject
if (hasValue)
attributes = slot.attributes();
- {
- auto catcher = DECLARE_CATCH_SCOPE(vm);
- WTF::String nameToUse;
- if (auto* fn = jsDynamicCast<JSFunction*>(value)) {
- nameToUse = fn->name(vm);
- } else if (auto* fn = jsDynamicCast<InternalFunction*>(value)) {
- nameToUse = fn->name();
- }
- if (nameToUse.length()) {
- mock->setName(nameToUse);
- }
- if (catcher.exception())
- catcher.clearException();
- }
+ mock->copyNameAndLength(vm, globalObject, value);
attributes |= PropertyAttribute::Function;
object->putDirect(vm, propertyKey, mock, attributes);
@@ -534,11 +595,14 @@ extern "C" EncodedJSValue JSMock__spyOn(JSC::JSGlobalObject* lexicalGlobalObject
attributes |= PropertyAttribute::Accessor;
object->putDirect(vm, propertyKey, JSC::GetterSetter::create(vm, globalObject, mock, mock), attributes);
+ // mock->setName(propertyKey.publicName());
RETURN_IF_EXCEPTION(scope, {});
pushImpl(mock, globalObject, JSMockImplementation::Kind::ReturnValue, value);
}
+ mock->spyOriginal.set(vm, mock, value);
+
if (!globalObject->mockModule.activeSpies) {
ActiveSpySet* activeSpies = ActiveSpySet::create(vm, globalObject->mockModule.activeSpySetStructure.getInitializedOnMainThread(globalObject));
globalObject->mockModule.activeSpies.set(vm, activeSpies);
@@ -561,7 +625,6 @@ JSMockModule JSMockModule::create(JSC::JSGlobalObject* globalObject)
mock.mockFunctionStructure.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) {
auto* prototype = JSMockFunctionPrototype::create(init.vm, init.owner, JSMockFunctionPrototype::createStructure(init.vm, init.owner, init.owner->functionPrototype()));
-
init.set(JSMockFunction::createStructure(init.vm, init.owner, prototype));
});
mock.mockResultStructure.initLater(
@@ -602,10 +665,25 @@ JSMockModule JSMockModule::create(JSC::JSGlobalObject* globalObject)
mock.mockObjectStructure.initLater(
[](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::Structure>::Initializer& init) {
Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(init.owner);
- JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype(
+
+ auto* prototype = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
+ // `putDirectCustomAccessor` doesn't pass the `this` value as expected. unfortunatly we
+ // need to use a JSFunction for the getter and assign it via `putDirectAccessor` instead.
+ prototype->putDirectAccessor(
globalObject,
- globalObject->objectPrototype(),
- 4);
+ JSC::Identifier::fromString(init.vm, "lastCall"_s),
+ JSC::GetterSetter::create(
+ init.vm,
+ globalObject,
+ JSC::JSFunction::create(init.vm, init.owner, 0, "lastCall"_s, jsMockFunctionGetter_mockGetLastCall, ImplementationVisibility::Public),
+ jsUndefined()),
+ JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
+
+ JSC::Structure* structure
+ = globalObject->structureCache().emptyObjectStructureForPrototype(
+ globalObject,
+ prototype,
+ 5);
JSC::PropertyOffset offset;
structure = structure->addPropertyTransition(
init.vm,
@@ -631,9 +709,23 @@ JSMockModule JSMockModule::create(JSC::JSGlobalObject* globalObject)
JSC::Identifier::fromString(init.vm, "results"_s),
JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly,
offset);
+ structure = structure->addPropertyTransition(
+ init.vm,
+ structure,
+ JSC::Identifier::fromString(init.vm, "invocationCallOrder"_s),
+ JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly,
+ offset);
init.set(structure);
});
+ mock.withImplementationCleanupFunction.initLater(
+ [](const JSC::LazyProperty<JSC::JSGlobalObject, JSC::JSFunction>::Initializer& init) {
+ init.set(JSC::JSFunction::create(init.vm, init.owner, 2, String(), jsMockFunctionWithImplementationCleanup, ImplementationVisibility::Public));
+ });
+ mock.mockWithImplementationCleanupDataStructure.initLater(
+ [](const JSC::LazyProperty<JSC::JSGlobalObject, Structure>::Initializer& init) {
+ init.set(Bun::MockWithImplementationCleanupData::createStructure(init.vm, init.owner, init.owner->objectPrototype()));
+ });
return mock;
}
@@ -705,8 +797,8 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionCall, (JSGlobalObject * lexicalGlobalObje
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
1);
calls->initializeIndex(object, 0, argumentsArray);
+ fn->calls.set(vm, fn, calls);
}
- fn->calls.set(vm, fn, calls);
JSC::JSArray* contexts = fn->contexts.get();
if (contexts) {
@@ -718,39 +810,51 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionCall, (JSGlobalObject * lexicalGlobalObje
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
1);
contexts->initializeIndex(object, 0, thisValue);
+ fn->contexts.set(vm, fn, contexts);
}
- fn->contexts.set(vm, fn, contexts);
- JSValue implementationValue = fn->implementation.get();
- if (!implementationValue)
- implementationValue = jsUndefined();
+ auto invocationId = JSMockModule::nextInvocationId();
+ JSC::JSArray* invocationCallOrder = fn->invocationCallOrder.get();
+ if (invocationCallOrder) {
+ invocationCallOrder->push(globalObject, jsNumber(invocationId));
+ } else {
+ JSC::ObjectInitializationScope object(vm);
+ invocationCallOrder = JSC::JSArray::tryCreateUninitializedRestricted(
+ object,
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
+ 1);
+ invocationCallOrder->initializeIndex(object, 0, jsNumber(invocationId));
+ fn->invocationCallOrder.set(vm, fn, invocationCallOrder);
+ }
- if (auto* impl = jsDynamicCast<JSMockImplementation*>(implementationValue)) {
- if (JSValue nextValue = impl->internalFields[1].get()) {
- if (nextValue.inherits<JSMockImplementation>() || (nextValue.isInt32() && nextValue.asInt32() == 1)) {
- fn->implementation.set(vm, fn, nextValue);
- }
+ unsigned int returnValueIndex = 0;
+ auto setReturnValue = [&](JSC::JSValue value) -> void {
+ if (auto* returnValuesArray = fn->returnValues.get()) {
+ returnValuesArray->push(globalObject, value);
+ returnValueIndex = returnValuesArray->length() - 1;
+ } else {
+ JSC::ObjectInitializationScope object(vm);
+ returnValuesArray = JSC::JSArray::tryCreateUninitializedRestricted(
+ object,
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
+ 1);
+ returnValuesArray->initializeIndex(object, 0, value);
+ fn->returnValues.set(vm, fn, returnValuesArray);
}
+ };
- unsigned int returnValueIndex = 0;
- auto setReturnValue = [&](JSC::JSValue value) -> void {
- if (auto* returnValuesArray = fn->returnValues.get()) {
- returnValuesArray->push(globalObject, value);
- returnValueIndex = returnValuesArray->length() - 1;
- } else {
- JSC::ObjectInitializationScope object(vm);
- returnValuesArray = JSC::JSArray::tryCreateUninitializedRestricted(
- object,
- globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
- 1);
- returnValuesArray->initializeIndex(object, 0, value);
- fn->returnValues.set(vm, fn, returnValuesArray);
+ if (auto* impl = tryJSDynamicCast<JSMockImplementation*>(fn->implementation.get())) {
+ if (impl->isOnce()) {
+ auto next = impl->nextValueOrSentinel.get();
+ fn->implementation.set(vm, fn, next);
+ if (next.isNumber() || !jsDynamicCast<JSMockImplementation*>(next)->isOnce()) {
+ fn->tail.clear();
}
- };
+ }
switch (impl->kind) {
case JSMockImplementation::Kind::Call: {
- JSValue result = impl->internalFields[0].get();
+ JSValue result = impl->underlyingValue.get();
JSC::CallData callData = JSC::getCallData(result);
if (UNLIKELY(callData.type == JSC::CallData::Type::None)) {
throwTypeError(globalObject, scope, "Expected mock implementation to be callable"_s);
@@ -783,9 +887,8 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionCall, (JSGlobalObject * lexicalGlobalObje
return JSValue::encode(returnValue);
}
- case JSMockImplementation::Kind::ReturnValue:
- case JSMockImplementation::Kind::Promise: {
- JSValue returnValue = impl->internalFields[0].get();
+ case JSMockImplementation::Kind::ReturnValue: {
+ JSValue returnValue = impl->underlyingValue.get();
setReturnValue(createMockResult(vm, globalObject, "return"_s, returnValue));
return JSValue::encode(returnValue);
}
@@ -799,6 +902,7 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionCall, (JSGlobalObject * lexicalGlobalObje
}
}
+ setReturnValue(createMockResult(vm, globalObject, "return"_s, jsUndefined()));
return JSValue::encode(jsUndefined());
}
@@ -820,10 +924,9 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionGetMockImplementation, (JSC::JSGlobalObje
throwTypeError(globalObject, scope, "Expected Mock"_s);
}
- JSValue impl = thisObject->implementation.get();
- if (auto* implementation = jsDynamicCast<JSMockImplementation*>(impl)) {
+ if (auto* implementation = tryJSDynamicCast<JSMockImplementation*>(thisObject->implementation.get())) {
if (implementation->kind == JSMockImplementation::Kind::Call) {
- RELEASE_AND_RETURN(scope, JSValue::encode(implementation->internalFields[0].get()));
+ RELEASE_AND_RETURN(scope, JSValue::encode(implementation->underlyingValue.get()));
}
}
@@ -851,41 +954,59 @@ JSC_DEFINE_CUSTOM_GETTER(jsMockFunctionGetter_protoImpl, (JSC::JSGlobalObject *
return {};
}
- if (auto implValue = thisObject->implementation.get()) {
- if (auto* impl = jsDynamicCast<JSMockImplementation*>(implValue)) {
- if (impl->kind == JSMockImplementation::Kind::Call) {
- return JSValue::encode(impl->internalFields[0].get());
- }
-
- return JSValue::encode(jsUndefined());
+ if (auto* impl = tryJSDynamicCast<JSMockImplementation*>(thisObject->implementation.get())) {
+ if (impl->kind == JSMockImplementation::Kind::Call) {
+ return JSValue::encode(impl->underlyingValue.get());
}
}
return JSValue::encode(jsUndefined());
}
-#define HANDLE_STATIC_CALL \
- if (!thisObject->implementation.get()) { \
- thisObject = JSMockFunction::create( \
- vm, \
- globalObject, \
- reinterpret_cast<Zig::GlobalObject*>(globalObject)->mockModule.mockFunctionStructure.getInitializedOnMainThread(globalObject), \
- CallbackKind::Call); \
+JSC_DEFINE_HOST_FUNCTION(jsMockFunctionConstructor, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callframe))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto thisObject_ = callframe->thisValue().toThis(globalObject, JSC::ECMAMode::strict());
+ JSMockFunction* thisObject = JSMockFunction::create(
+ vm,
+ globalObject,
+ globalObject->mockModule.mockFunctionStructure.getInitializedOnMainThread(globalObject));
+
+ if (UNLIKELY(!thisObject)) {
+ throwOutOfMemoryError(globalObject, scope);
+ return {};
+ }
+
+ if (callframe->argumentCount() > 0) {
+ JSValue value = callframe->argument(0);
+ if (value.isCallable()) {
+ thisObject->copyNameAndLength(vm, lexicalGlobalObject, value);
+ pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Call, value);
+ } else {
+ // jest doesn't support doing `jest.fn(10)`, but we support it.
+ pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, value);
+ thisObject->setName("mockConstructor"_s);
+ }
+ } else {
+ thisObject->setName("mockConstructor"_s);
}
+ return JSValue::encode(thisObject);
+}
+
extern "C" EncodedJSValue JSMockFunction__createObject(Zig::GlobalObject* globalObject)
{
- return JSValue::encode(
- JSMockFunction::create(globalObject->vm(), globalObject, globalObject->mockModule.mockFunctionStructure.getInitializedOnMainThread(globalObject), CallbackKind::Wrapper));
+ auto& vm = globalObject->vm();
+ return JSValue::encode(JSC::JSFunction::create(vm, globalObject, 0, "mock"_s, jsMockFunctionConstructor, ImplementationVisibility::Public));
}
-
extern "C" EncodedJSValue JSMockFunction__getCalls(EncodedJSValue encodedValue)
{
JSValue value = JSValue::decode(encodedValue);
- if (value) {
- if (auto* mock = jsDynamicCast<JSMockFunction*>(value)) {
- return JSValue::encode(mock->getCalls());
- }
+ if (auto* mock = tryJSDynamicCast<JSMockFunction*>(value)) {
+ return JSValue::encode(mock->getCalls());
}
return JSValue::encode({});
@@ -893,10 +1014,8 @@ extern "C" EncodedJSValue JSMockFunction__getCalls(EncodedJSValue encodedValue)
extern "C" EncodedJSValue JSMockFunction__getReturns(EncodedJSValue encodedValue)
{
JSValue value = JSValue::decode(encodedValue);
- if (value) {
- if (auto* mock = jsDynamicCast<JSMockFunction*>(value)) {
- return JSValue::encode(mock->getReturnValues());
- }
+ if (auto* mock = tryJSDynamicCast<JSMockFunction*>(value)) {
+ return JSValue::encode(mock->getReturnValues());
}
return JSValue::encode({});
@@ -911,19 +1030,16 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionGetMockName, (JSC::JSGlobalObject * globa
throwTypeError(globalObject, scope, "Expected Mock"_s);
}
- JSValue implValue = thisObject->implementation.get();
- if (!implValue) {
- implValue = jsUndefined();
- }
-
- if (auto* impl = jsDynamicCast<JSMockImplementation*>(implValue)) {
+ if (auto* impl = tryJSDynamicCast<JSMockImplementation*>(thisObject->implementation.get())) {
if (impl->kind == JSMockImplementation::Kind::Call) {
- JSObject* object = impl->internalFields[0].get().asCell()->getObject();
- if (auto nameValue = object->getIfPropertyExists(globalObject, PropertyName(vm.propertyNames->name))) {
- RELEASE_AND_RETURN(scope, JSValue::encode(nameValue));
- }
+ if (JSValue underlyingValue = impl->underlyingValue.get()) {
+ JSObject* object = underlyingValue.asCell()->getObject();
+ if (auto nameValue = object->getIfPropertyExists(globalObject, PropertyName(vm.propertyNames->name))) {
+ RELEASE_AND_RETURN(scope, JSValue::encode(nameValue));
+ }
- RETURN_IF_EXCEPTION(scope, {});
+ RETURN_IF_EXCEPTION(scope, {});
+ }
}
}
@@ -938,7 +1054,7 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockClear, (JSC::JSGlobalObject * globalO
throwTypeError(globalObject, scope, "Expected Mock"_s);
}
- thisObject->reset();
+ thisObject->clear();
RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
}
@@ -964,6 +1080,8 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockRestore, (JSC::JSGlobalObject * globa
throwTypeError(globalObject, scope, "Expected Mock"_s);
}
+ thisObject->clearSpy();
+
RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
}
JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockImplementation, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callframe))
@@ -971,37 +1089,20 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockImplementation, (JSC::JSGlobalObject
auto& vm = lexicalGlobalObject->vm();
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
- JSMockFunction* thisObject = JSMockFunction::create(
- vm,
- globalObject,
- globalObject->mockModule.mockFunctionStructure.getInitializedOnMainThread(globalObject));
+ JSMockFunction* thisObject = jsDynamicCast<JSMockFunction*>(callframe->thisValue().toThis(globalObject, JSC::ECMAMode::strict()));
if (UNLIKELY(!thisObject)) {
throwOutOfMemoryError(globalObject, scope);
return {};
}
- if (callframe->argumentCount() > 0) {
- JSValue value = callframe->argument(0);
- if (value.isCallable()) {
- {
- auto catcher = DECLARE_CATCH_SCOPE(vm);
- WTF::String nameToUse;
- if (auto* fn = jsDynamicCast<JSFunction*>(value)) {
- nameToUse = fn->name(vm);
- } else if (auto* fn = jsDynamicCast<InternalFunction*>(value)) {
- nameToUse = fn->name();
- }
- if (nameToUse.length()) {
- thisObject->setName(nameToUse);
- }
- if (catcher.exception())
- catcher.clearException();
- }
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Call, value);
- } else {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, value);
- }
+ JSValue value = callframe->argument(0);
+
+ // This check is for a jest edge case, truthy values will throw but not immediatly, and falsy values return undefined.
+ if (value.toBoolean(globalObject)) {
+ pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Call, value);
+ } else {
+ pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, jsUndefined());
}
return JSValue::encode(thisObject);
@@ -1018,59 +1119,16 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockImplementationOnce, (JSC::JSGlobalObj
return {};
}
- HANDLE_STATIC_CALL;
-
- if (callframe->argumentCount() > 0) {
- JSValue value = callframe->argument(0);
- if (value.isCallable()) {
- if (!thisObject->implementation) {
- auto catcher = DECLARE_CATCH_SCOPE(vm);
- WTF::String nameToUse;
- if (auto* fn = jsDynamicCast<JSFunction*>(value)) {
- nameToUse = fn->name(vm);
- } else if (auto* fn = jsDynamicCast<InternalFunction*>(value)) {
- nameToUse = fn->name();
- }
- if (nameToUse.length()) {
- thisObject->setName(nameToUse);
- }
- if (catcher.exception())
- catcher.clearException();
- }
-
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Call, value);
- } else {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, value);
- }
- }
-
- return JSValue::encode(thisObject);
-}
-
-JSC_DEFINE_HOST_FUNCTION(jsMockFunctionWithImplementation, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
-{
- JSMockFunction* thisObject = jsDynamicCast<JSMockFunction*>(callframe->thisValue().toThis(globalObject, JSC::ECMAMode::strict()));
- auto& vm = globalObject->vm();
- auto scope = DECLARE_THROW_SCOPE(vm);
- if (UNLIKELY(!thisObject)) {
- throwTypeError(globalObject, scope, "Expected Mock"_s);
- RELEASE_AND_RETURN(scope, JSValue::encode(jsUndefined()));
- }
-
- HANDLE_STATIC_CALL;
-
- JSValue arg = callframe->argument(0);
+ JSValue value = callframe->argument(0);
- if (callframe->argumentCount() < 1 || arg.isEmpty() || arg.isUndefined()) {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, jsUndefined());
- } else if (arg.isCallable()) {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Call, arg);
+ // This check is for a jest edge case, truthy values will throw but not immediatly, and falsy values return undefined.
+ if (value.toBoolean(globalObject)) {
+ pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::Call, value);
} else {
- throwTypeError(globalObject, scope, "Expected a function or undefined"_s);
- RELEASE_AND_RETURN(scope, JSValue::encode(jsUndefined()));
+ pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, jsUndefined());
}
- RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
+ return JSValue::encode(thisObject);
}
JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockName, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
{
@@ -1082,8 +1140,6 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockName, (JSC::JSGlobalObject * globalOb
return {};
}
- HANDLE_STATIC_CALL;
-
if (callframe->argumentCount() > 0) {
auto* newName = callframe->argument(0).toStringOrNull(globalObject);
if (UNLIKELY(!newName)) {
@@ -1105,7 +1161,6 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockReturnThis, (JSC::JSGlobalObject * gl
throwTypeError(globalObject, scope, "Expected Mock"_s);
}
- HANDLE_STATIC_CALL;
pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnThis, jsUndefined());
RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
@@ -1117,13 +1172,10 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockReturnValue, (JSC::JSGlobalObject * g
auto scope = DECLARE_THROW_SCOPE(vm);
if (UNLIKELY(!thisObject)) {
throwTypeError(globalObject, scope, "Expected Mock"_s);
+ return {};
}
- if (callframe->argumentCount() < 1) {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, jsUndefined());
- } else {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, callframe->argument(0));
- }
+ pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, callframe->argument(0));
RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
}
@@ -1134,35 +1186,24 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockReturnValueOnce, (JSC::JSGlobalObject
auto scope = DECLARE_THROW_SCOPE(vm);
if (UNLIKELY(!thisObject)) {
throwTypeError(globalObject, scope, "Expected Mock"_s);
+ return {};
}
- HANDLE_STATIC_CALL;
- if (callframe->argumentCount() < 1) {
- pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, jsUndefined());
- } else {
- pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, callframe->argument(0));
- }
+ pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, callframe->argument(0));
RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
}
-JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockResolvedValue, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callframe))
+JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockResolvedValue, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
{
- auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
JSMockFunction* thisObject = jsDynamicCast<JSMockFunction*>(callframe->thisValue().toThis(globalObject, JSC::ECMAMode::strict()));
auto& vm = globalObject->vm();
-
auto scope = DECLARE_THROW_SCOPE(vm);
if (UNLIKELY(!thisObject)) {
throwTypeError(globalObject, scope, "Expected Mock"_s);
+ return {};
}
- HANDLE_STATIC_CALL;
-
- if (callframe->argumentCount() < 1) {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Promise, JSC::JSPromise::resolvedPromise(globalObject, jsUndefined()));
- } else {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Promise, JSC::JSPromise::resolvedPromise(globalObject, callframe->argument(0)));
- }
+ pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, JSC::JSPromise::resolvedPromise(globalObject, callframe->argument(0)));
RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
}
@@ -1173,15 +1214,10 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockResolvedValueOnce, (JSC::JSGlobalObje
auto scope = DECLARE_THROW_SCOPE(vm);
if (UNLIKELY(!thisObject)) {
throwTypeError(globalObject, scope, "Expected Mock"_s);
+ return {};
}
- HANDLE_STATIC_CALL;
-
- if (callframe->argumentCount() < 1) {
- pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::Promise, JSC::JSPromise::resolvedPromise(globalObject, jsUndefined()));
- } else {
- pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::Promise, JSC::JSPromise::resolvedPromise(globalObject, callframe->argument(0)));
- }
+ pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, JSC::JSPromise::resolvedPromise(globalObject, callframe->argument(0)));
RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
}
@@ -1192,15 +1228,10 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockRejectedValue, (JSC::JSGlobalObject *
auto scope = DECLARE_THROW_SCOPE(vm);
if (UNLIKELY(!thisObject)) {
throwTypeError(globalObject, scope, "Expected Mock"_s);
+ return {};
}
- HANDLE_STATIC_CALL;
-
- if (callframe->argumentCount() < 1) {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Promise, JSC::JSPromise::rejectedPromise(globalObject, jsUndefined()));
- } else {
- pushImpl(thisObject, globalObject, JSMockImplementation::Kind::Promise, JSC::JSPromise::rejectedPromise(globalObject, callframe->argument(0)));
- }
+ pushImpl(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, JSC::JSPromise::rejectedPromise(globalObject, callframe->argument(0)));
RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
}
@@ -1211,16 +1242,178 @@ JSC_DEFINE_HOST_FUNCTION(jsMockFunctionMockRejectedValueOnce, (JSC::JSGlobalObje
auto scope = DECLARE_THROW_SCOPE(vm);
if (UNLIKELY(!thisObject)) {
throwTypeError(globalObject, scope, "Expected Mock"_s);
+ return {};
}
- HANDLE_STATIC_CALL;
+ pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::ReturnValue, JSC::JSPromise::rejectedPromise(globalObject, callframe->argument(0)));
- if (callframe->argumentCount() < 1) {
- pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::Promise, JSC::JSPromise::rejectedPromise(globalObject, jsUndefined()));
- } else {
- pushImplOnce(thisObject, globalObject, JSMockImplementation::Kind::Promise, JSC::JSPromise::resolvedPromise(globalObject, callframe->argument(0)));
+ RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
+}
+JSC_DEFINE_HOST_FUNCTION(jsMockFunctionGetter_mockGetLastCall, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
+{
+ JSValue thisObject = callframe->thisValue();
+ if (UNLIKELY(!thisObject.isObject())) {
+ return JSValue::encode(jsUndefined());
}
+ JSValue callsValue = thisObject.get(globalObject, Identifier::fromString(globalObject->vm(), "calls"_s));
- RELEASE_AND_RETURN(scope, JSValue::encode(thisObject));
+ if (auto callsArray = jsDynamicCast<JSC::JSArray*>(callsValue)) {
+ auto len = callsArray->length();
+ if (len > 0) {
+ return JSValue::encode(callsArray->getIndex(globalObject, len - 1));
+ }
+ }
+ return JSValue::encode(jsUndefined());
+}
+
+const JSC::ClassInfo MockWithImplementationCleanupData::s_info = { "MockWithImplementationCleanupData"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(MockWithImplementationCleanupData) };
+
+template<typename, JSC::SubspaceAccess mode>
+JSC::GCClient::IsoSubspace* MockWithImplementationCleanupData::subspaceFor(JSC::VM& vm)
+{
+ return WebCore::subspaceForImpl<MockWithImplementationCleanupData, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForMockWithImplementationCleanupData.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForMockWithImplementationCleanupData = std::forward<decltype(space)>(space); },
+ [](auto& spaces) { return spaces.m_subspaceForMockWithImplementationCleanupData.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForMockWithImplementationCleanupData = std::forward<decltype(space)>(space); });
+}
+
+MockWithImplementationCleanupData* MockWithImplementationCleanupData::create(VM& vm, Structure* structure)
+{
+ MockWithImplementationCleanupData* mod = new (NotNull, allocateCell<MockWithImplementationCleanupData>(vm)) MockWithImplementationCleanupData(vm, structure);
+ return mod;
+}
+Structure* MockWithImplementationCleanupData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
+}
+
+MockWithImplementationCleanupData::MockWithImplementationCleanupData(VM& vm, Structure* structure)
+ : Base(vm, structure)
+{
+}
+
+void MockWithImplementationCleanupData::finishCreation(VM& vm, JSMockFunction* fn, JSValue impl, JSValue tail, JSValue fallback)
+{
+ Base::finishCreation(vm);
+ this->internalField(0).set(vm, this, fn);
+ this->internalField(1).set(vm, this, impl);
+ this->internalField(2).set(vm, this, tail);
+ this->internalField(3).set(vm, this, fallback);
+}
+
+template<typename Visitor>
+void MockWithImplementationCleanupData::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ auto* thisObject = jsCast<MockWithImplementationCleanupData*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+}
+
+DEFINE_VISIT_CHILDREN(MockWithImplementationCleanupData);
+
+MockWithImplementationCleanupData* MockWithImplementationCleanupData::create(JSC::JSGlobalObject* globalObject, JSMockFunction* fn, JSValue impl, JSValue tail, JSValue fallback)
+{
+ auto* obj = create(globalObject->vm(), reinterpret_cast<Zig::GlobalObject*>(globalObject)->mockModule.mockWithImplementationCleanupDataStructure.getInitializedOnMainThread(globalObject));
+ obj->finishCreation(globalObject->vm(), fn, impl, tail, fallback);
+ return obj;
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsMockFunctionWithImplementationCleanup, (JSC::JSGlobalObject * jsGlobalObject, JSC::CallFrame* callframe))
+{
+ auto& vm = jsGlobalObject->vm();
+ auto count = callframe->argumentCount();
+ auto ctx = jsDynamicCast<MockWithImplementationCleanupData*>(callframe->argument(1));
+ if (!ctx) {
+ return JSValue::encode(jsUndefined());
+ }
+
+ auto fn = jsDynamicCast<JSMockFunction*>(ctx->internalField(0).get());
+ fn->implementation.set(vm, fn, ctx->internalField(1).get());
+ fn->tail.set(vm, fn, ctx->internalField(2).get());
+ fn->fallbackImplmentation.set(vm, fn, ctx->internalField(3).get());
+
+ return JSValue::encode(jsUndefined());
+}
+JSC_DEFINE_HOST_FUNCTION(jsMockFunctionWithImplementation, (JSC::JSGlobalObject * jsGlobalObject, JSC::CallFrame* callframe))
+{
+ Zig::GlobalObject* globalObject = jsCast<Zig::GlobalObject*>(jsGlobalObject);
+
+ JSMockFunction* thisObject = jsDynamicCast<JSMockFunction*>(callframe->thisValue().toThis(globalObject, JSC::ECMAMode::strict()));
+ auto& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ if (UNLIKELY(!thisObject)) {
+ throwTypeError(globalObject, scope, "Expected Mock"_s);
+ return {};
+ }
+
+ JSValue tempImplValue = callframe->argument(0);
+ JSValue callback = callframe->argument(1);
+ JSC::CallData callData = JSC::getCallData(callback);
+ if (UNLIKELY(callData.type == JSC::CallData::Type::None)) {
+ throwTypeError(globalObject, scope, "Expected mock implementation to be callable"_s);
+ return {};
+ }
+
+ auto lastImpl = thisObject->implementation.get();
+ auto lastTail = thisObject->tail.get();
+ auto lastFallback = thisObject->fallbackImplmentation.get();
+
+ JSMockImplementation* impl = JSMockImplementation::create(
+ globalObject,
+ globalObject->mockModule.mockImplementationStructure.getInitializedOnMainThread(globalObject),
+ JSMockImplementation::Kind::Call,
+ tempImplValue,
+ false);
+
+ thisObject->implementation.set(vm, thisObject, impl);
+ thisObject->fallbackImplmentation.clear();
+ thisObject->tail.clear();
+
+ MarkedArgumentBuffer args;
+ NakedPtr<Exception> exception;
+ JSValue returnValue = call(globalObject, callback, callData, jsUndefined(), args, exception);
+
+ if (auto promise = tryJSDynamicCast<JSC::JSPromise*>(returnValue)) {
+ auto capability = JSC::JSPromise::createNewPromiseCapability(globalObject, globalObject->promiseConstructor());
+ auto ctx = MockWithImplementationCleanupData::create(globalObject, thisObject, lastImpl, lastTail, lastFallback);
+
+ JSFunction* cleanup = globalObject->mockModule.withImplementationCleanupFunction.getInitializedOnMainThread(globalObject);
+ JSFunction* performPromiseThenFunction = globalObject->performPromiseThenFunction();
+ auto callData = JSC::getCallData(performPromiseThenFunction);
+ MarkedArgumentBuffer arguments;
+ arguments.append(promise);
+ arguments.append(cleanup);
+ arguments.append(cleanup);
+ arguments.append(capability);
+ arguments.append(ctx);
+ ASSERT(!arguments.hasOverflowed());
+ call(globalObject, performPromiseThenFunction, callData, jsUndefined(), arguments);
+
+ return JSC::JSValue::encode(promise);
+ }
+
+ thisObject->implementation.set(vm, thisObject, lastImpl);
+ thisObject->tail.set(vm, thisObject, lastImpl);
+ thisObject->fallbackImplmentation.set(vm, thisObject, lastFallback);
+
+ return JSC::JSValue::encode(jsUndefined());
+}
+} // namespace Bun
+
+namespace JSC {
+
+template<unsigned passedNumberOfInternalFields>
+template<typename Visitor>
+void JSInternalFieldObjectImpl<passedNumberOfInternalFields>::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ auto* thisObject = jsCast<JSInternalFieldObjectImpl*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.appendValues(thisObject->m_internalFields, numberOfInternalFields);
}
-} \ No newline at end of file
+
+DEFINE_VISIT_CHILDREN_WITH_MODIFIER(template<unsigned passedNumberOfInternalFields>, JSInternalFieldObjectImpl<passedNumberOfInternalFields>);
+
+} // namespace JSC
diff --git a/src/bun.js/bindings/JSMockFunction.h b/src/bun.js/bindings/JSMockFunction.h
index 288ca2e89..93c8bb015 100644
--- a/src/bun.js/bindings/JSMockFunction.h
+++ b/src/bun.js/bindings/JSMockFunction.h
@@ -16,15 +16,47 @@ class JSMockFunction;
class JSMockModule final {
public:
+ static uint64_t s_nextInvocationId;
+ static uint64_t nextInvocationId() { return ++s_nextInvocationId; }
+
LazyProperty<JSC::JSGlobalObject, Structure> mockFunctionStructure;
LazyProperty<JSC::JSGlobalObject, Structure> mockResultStructure;
LazyProperty<JSC::JSGlobalObject, Structure> mockImplementationStructure;
LazyProperty<JSC::JSGlobalObject, Structure> mockObjectStructure;
LazyProperty<JSC::JSGlobalObject, Structure> activeSpySetStructure;
+ LazyProperty<JSC::JSGlobalObject, JSFunction> withImplementationCleanupFunction;
+ LazyProperty<JSC::JSGlobalObject, JSC::Structure> mockWithImplementationCleanupDataStructure;
static JSMockModule create(JSC::JSGlobalObject*);
JSC::Strong<Unknown> activeSpies;
};
-} \ No newline at end of file
+class MockWithImplementationCleanupData : public JSC::JSInternalFieldObjectImpl<4> {
+public:
+ using Base = JSC::JSInternalFieldObjectImpl<4>;
+
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm);
+
+ JS_EXPORT_PRIVATE static MockWithImplementationCleanupData* create(VM&, Structure*);
+ static MockWithImplementationCleanupData* create(JSC::JSGlobalObject* globalObject, JSMockFunction* fn, JSValue impl, JSValue tail, JSValue fallback);
+ static MockWithImplementationCleanupData* createWithInitialValues(VM&, Structure*);
+ static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+ static std::array<JSValue, numberOfInternalFields> initialValues()
+ {
+ return { {
+ jsUndefined(),
+ jsUndefined(),
+ jsUndefined(),
+ jsUndefined(),
+ } };
+ }
+
+ DECLARE_EXPORT_INFO;
+ DECLARE_VISIT_CHILDREN;
+
+ MockWithImplementationCleanupData(JSC::VM&, JSC::Structure*);
+ void finishCreation(JSC::VM&, JSMockFunction* fn, JSValue impl, JSValue tail, JSValue fallback);
+};
+}
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 5589d2add..e49b94687 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -4042,6 +4042,8 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->mockModule.mockImplementationStructure.visit(visitor);
thisObject->mockModule.mockObjectStructure.visit(visitor);
thisObject->mockModule.activeSpySetStructure.visit(visitor);
+ thisObject->mockModule.mockWithImplementationCleanupDataStructure.visit(visitor);
+ thisObject->mockModule.withImplementationCleanupFunction.visit(visitor);
for (auto& barrier : thisObject->m_thenables) {
visitor.append(barrier);
diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
index d595dc866..3997c1d88 100644
--- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
+++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h
@@ -36,6 +36,7 @@ public:
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForCommonJSModuleRecord;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSMockImplementation;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSMockFunction;
+ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMockWithImplementationCleanupData;
#include "ZigGeneratedClasses+DOMClientIsoSubspaces.h"
/* --- bun --- */
diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
index b4a5e9d55..4feca1754 100644
--- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
+++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h
@@ -36,6 +36,7 @@ public:
std::unique_ptr<IsoSubspace> m_subspaceForCommonJSModuleRecord;
std::unique_ptr<IsoSubspace> m_subspaceForJSMockImplementation;
std::unique_ptr<IsoSubspace> m_subspaceForJSMockFunction;
+ std::unique_ptr<IsoSubspace> m_subspaceForMockWithImplementationCleanupData;
#include "ZigGeneratedClasses+DOMIsoSubspaces.h"
/*-- BUN --*/
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 6c77d7aaa..00cc954ad 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -698,22 +698,22 @@ pub const Jest = struct {
Expect.getConstructor(globalObject),
);
- const mock_object = JSMockFunction__createObject(globalObject);
+ const mock_fn = JSMockFunction__createObject(globalObject);
const spyOn = JSC.NewFunction(globalObject, ZigString.static("spyOn"), 2, JSMock__spyOn, false);
const restoreAllMocks = JSC.NewFunction(globalObject, ZigString.static("restoreAllMocks"), 2, jsFunctionResetSpies, false);
- module.put(
- globalObject,
- ZigString.static("mock"),
- mock_object,
- );
+ module.put(globalObject, ZigString.static("mock"), mock_fn);
const jest = JSValue.createEmptyObject(globalObject, 3);
- jest.put(globalObject, ZigString.static("fn"), mock_object);
+ jest.put(globalObject, ZigString.static("fn"), mock_fn);
jest.put(globalObject, ZigString.static("spyOn"), spyOn);
jest.put(globalObject, ZigString.static("restoreAllMocks"), restoreAllMocks);
module.put(globalObject, ZigString.static("jest"), jest);
module.put(globalObject, ZigString.static("spyOn"), spyOn);
+ const vi = JSValue.createEmptyObject(globalObject, 1);
+ vi.put(globalObject, ZigString.static("fn"), mock_fn);
+ module.put(globalObject, ZigString.static("vi"), vi);
+
return module;
}
@@ -989,15 +989,10 @@ pub const Expect = struct {
}
pub fn call(globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
- const arguments_ = callframe.arguments(1);
- if (arguments_.len < 1) {
- globalObject.throw("expect() requires one argument\n", .{});
- return .zero;
- }
- const arguments = arguments_.ptr[0..arguments_.len];
+ const arguments = callframe.arguments(1);
+ const value = if (arguments.len < 1) JSC.JSValue.jsUndefined() else arguments.ptr[0];
var expect = globalObject.bunVM().allocator.create(Expect) catch unreachable;
- const value = arguments[0];
if (Jest.runner.?.pending_test == null) {
const err = globalObject.createErrorInstance("expect() must be called in a test", .{});
diff --git a/src/js/out/WebCoreJSBuiltins.cpp b/src/js/out/WebCoreJSBuiltins.cpp
index 55238274b..1fecb34e3 100644
--- a/src/js/out/WebCoreJSBuiltins.cpp
+++ b/src/js/out/WebCoreJSBuiltins.cpp
@@ -2916,9 +2916,9 @@ WEBCORE_FOREACH_WRITABLESTREAMDEFAULTCONTROLLER_BUILTIN_CODE(DEFINE_BUILTIN_GENE
const JSC::ConstructAbility s_eventSourceGetEventSourceCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
const JSC::ConstructorKind s_eventSourceGetEventSourceCodeConstructorKind = JSC::ConstructorKind::None;
const JSC::ImplementationVisibility s_eventSourceGetEventSourceCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
-const int s_eventSourceGetEventSourceCodeLength = 5476;
+const int s_eventSourceGetEventSourceCodeLength = 5477;
static const JSC::Intrinsic s_eventSourceGetEventSourceCodeIntrinsic = JSC::NoIntrinsic;
-const char* const s_eventSourceGetEventSourceCode = "(function (){\"use strict\";class j extends EventTarget{#$;#j;#w;#A;#B;#F=!1;#G=null;#J=\"\";#K=\"\";#L=\"\";#M=!0;#O=0;#Q=0;#U=0;#V=null;static#W(w){w.#H()}static#X(w,A){const B=w.data,F=B.#L\?`Last-Event-ID: ${B.#L}\\r\\n`:\"\",G=`GET ${A.pathname}${A.search} HTTP/1.1\\r\\nHost: bun\\r\\nContent-type: text/event-stream\\r\\nContent-length: 0\\r\\n${F}\\r\\n`,J=w.write(G);if(J!==G.length)B.#K=G.substring(J)}static#Y(w,A,B){for(;;){if(B>=A.length)return;let F=-1,G=A.indexOf(\"\\r\\n\",B);const J=G+2;if(G>0)if(w.#O===0){const Q=parseInt(A.substring(B,G),16);if(Q===0){w.#j=2,w.#G\?.end();return}F=J+Q}else F=A.length;else{if(w.#J.length===0){w.#J+=A.substring(B);return}F=A.length}let K=A.substring(J,F);B=F+2;let L=0,M=K.indexOf(\"\\n\\n\");if(M==-1){w.#J+=A.substring(J);return}if(w.#J.length)w.#J+=K,K=w.#J,w.#J=\"\";let O=!0;while(O){const Q=K.substring(L,M);let U,V=\"\",W,X=0,Y=-1;for(;;){let z=Q.indexOf(\"\\n\",X);if(z===-1){if(X>=Q.length)break;z=Q.length}const H=Q.substring(X,z);if(H.startsWith(\"data:\"))if(V.length)V+=`\\n${H.substring(5).trim()}`;else V=H.substring(5).trim();else if(H.startsWith(\"event:\"))U=H.substring(6).trim();else if(H.startsWith(\"id:\"))W=H.substring(3).trim();else if(H.startsWith(\"retry:\")){if(Y=parseInt(H.substring(6).trim(),10),@isNaN(Y))Y=-1}X=z+1}if(w.#L=W||\"\",Y>=0)w.#U=Y;if(V||W||U)w.dispatchEvent(new MessageEvent(U||\"message\",{data:V||\"\",origin:w.#$.origin,source:w,lastEventId:W}));if(K.length===M+2){O=!1;break}const Z=K.indexOf(\"\\n\\n\",M+1);if(Z===-1)break;L=M,M=Z}}}static#Z={open(w){const A=w.data;if(A.#G=w,!A.#F)j.#X(w,A.#$)},handshake(w,A,B){const F=w.data;if(A)j.#X(w,F.#$);else F.#j=2,F.dispatchEvent(new ErrorEvent(\"error\",{error:B})),w.end()},data(w,A){const B=w.data;switch(B.#j){case 0:{let F=A.toString();const G=F.indexOf(\"\\r\\n\\r\\n\");if(G===-1){B.#J+=F;return}if(B.#J.length)B.#J+=F,F=B.#J,B.#J=\"\";const J=F.substring(0,G),K=J.indexOf(\"\\r\\n\");if(K===-1){B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Invalid HTTP request\")})),w.end();return}const L=J.substring(0,K);if(L!==\"HTTP/1.1 200 OK\"){B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(L)})),w.end();return}let M=K+1,O=!1,Q=-1;for(;;){let V=J.indexOf(\"\\r\\n\",M);if(V===-1){if(M>=J.length){if(!O)B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's response has no MIME type and \"text/event-stream\" is required. Aborting the connection.`)})),w.end();return}V=J.length}const W=J.substring(M+1,V),X=W.indexOf(\":\"),Y=W.substring(0,X),Z=Y.localeCompare(\"content-type\",@undefined,{sensitivity:\"accent\"})===0;if(M=V+1,Z)if(W.endsWith(\" text/event-stream\"))O=!0;else{B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's response has a MIME type that is not \"text/event-stream\". Aborting the connection.`)})),w.end();return}else if(Y.localeCompare(\"content-length\",@undefined,{sensitivity:\"accent\"})===0){if(Q=parseInt(W.substring(X+1).trim(),10),@isNaN(Q)||Q<=0){B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's Content-Length is invalid. Aborting the connection.`)})),w.end();return}if(O)break}else if(Y.localeCompare(\"transfer-encoding\",@undefined,{sensitivity:\"accent\"})===0){if(W.substring(X+1).trim()!==\"chunked\"){B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's Transfer-Encoding is invalid. Aborting the connection.`)})),w.end();return}if(Q=0,O)break}}B.#O=Q,B.#j=1,B.dispatchEvent(new Event(\"open\"));const U=F.substring(G+4);if(j.#Y(B,U,0),B.#O>0){if(B.#Q+=U.length,B.#Q>=B.#O)B.#j=2,w.end()}return}case 1:if(j.#Y(B,A.toString(),2),B.#O>0){if(B.#Q+=A.byteLength,B.#Q>=B.#O)B.#j=2,w.end()}return;default:break}},drain(w){const A=w.data;if(A.#j===0){const B=A.#J;if(B.length){const F=w.write(B);if(F!==B.length)w.data.#K=B.substring(F);else w.data.#K=\"\"}}},close:j.#z,end(w){j.#z(w).dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Connection closed by server\")}))},timeout(w){j.#z(w).dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Timeout\")}))},binaryType:\"buffer\"};static#z(w){const A=w.data;if(A.#G=null,A.#Q=0,A.#j=2,A.#M){if(A.#V)clearTimeout(A.#V);A.#V=setTimeout(j.#W,A.#U,A)}return A}constructor(w,A=@undefined){super();const B=new URL(w);this.#F=B.protocol===\"https:\",this.#$=B,this.#j=2,process.nextTick(j.#W,this)}ref(){this.#V\?.ref(),this.#G\?.ref()}unref(){this.#V\?.unref(),this.#G\?.unref()}#H(){if(this.#j!==2)return;const w=this.#$,A=this.#F;this.#j=0,@Bun.connect({data:this,socket:j.#Z,hostname:w.hostname,port:parseInt(w.port||(A\?\"443\":\"80\"),10),tls:A\?{requestCert:!0,rejectUnauthorized:!1}:!1}).catch((B)=>{if(this.dispatchEvent(new ErrorEvent(\"error\",{error:B})),this.#M){if(this.#V)this.#V.unref\?.();this.#V=setTimeout(j.#W,1000,this)}})}get url(){return this.#$.href}get readyState(){return this.#j}close(){this.#M=!1,this.#j=2,this.#G\?.unref(),this.#G\?.end()}get onopen(){return this.#B}get onerror(){return this.#w}get onmessage(){return this.#A}set onopen(w){if(this.#B)super.removeEventListener(\"close\",this.#B);super.addEventListener(\"open\",w),this.#B=w}set onerror(w){if(this.#w)super.removeEventListener(\"error\",this.#w);super.addEventListener(\"error\",w),this.#w=w}set onmessage(w){if(this.#A)super.removeEventListener(\"message\",this.#A);super.addEventListener(\"message\",w),this.#A=w}}return Object.defineProperty(j.prototype,\"CONNECTING\",{enumerable:!0,value:0}),Object.defineProperty(j.prototype,\"OPEN\",{enumerable:!0,value:1}),Object.defineProperty(j.prototype,\"CLOSED\",{enumerable:!0,value:2}),j[Symbol.for(\"CommonJS\")]=0,j})\n";
+const char* const s_eventSourceGetEventSourceCode = "(function (){\"use strict\";class j extends EventTarget{#$;#j;#w;#A;#B;#F=!1;#G=null;#J=\"\";#K=\"\";#L=\"\";#M=!0;#O=0;#Q=0;#U=0;#V=null;static#W(w){w.#H()}static#X(w,A){const B=w.data,F=B.#L\?`Last-Event-ID: ${B.#L}\\r\\n`:\"\",G=`GET ${A.pathname}${A.search} HTTP/1.1\\r\\nHost: bun\\r\\nContent-type: text/event-stream\\r\\nContent-length: 0\\r\\n${F}\\r\\n`,J=w.write(G);if(J!==G.length)B.#K=G.substring(J)}static#Y(w,A,B){for(;;){if(B>=A.length)return;let F=-1,G=A.indexOf(\"\\r\\n\",B);const J=G+2;if(G>0)if(w.#O===0){const Q=parseInt(A.substring(B,G),16);if(Q===0){w.#j=2,w.#G\?.end();return}F=J+Q}else F=A.length;else{if(w.#J.length===0){w.#J+=A.substring(B);return}F=A.length}let K=A.substring(J,F);B=F+2;let L=0,M=K.indexOf(\"\\n\\n\");if(M==-1){w.#J+=A.substring(J);return}if(w.#J.length)w.#J+=K,K=w.#J,w.#J=\"\";let O=!0;while(O){const Q=K.substring(L,M);let U,V=\"\",W,X=0,Y=-1;for(;;){let z=Q.indexOf(\"\\n\",X);if(z===-1){if(X>=Q.length)break;z=Q.length}const H=Q.substring(X,z);if(H.startsWith(\"data:\"))if(V.length)V+=`\\n${H.substring(5).trim()}`;else V=H.substring(5).trim();else if(H.startsWith(\"event:\"))U=H.substring(6).trim();else if(H.startsWith(\"id:\"))W=H.substring(3).trim();else if(H.startsWith(\"retry:\")){if(Y=parseInt(H.substring(6).trim(),10),@isNaN(Y))Y=-1}X=z+1}if(w.#L=W||\"\",Y>=0)w.#U=Y;if(V||W||U)w.dispatchEvent(new MessageEvent(U||\"message\",{data:V||\"\",origin:w.#$.origin,source:w,lastEventId:W}));if(K.length===M+2){O=!1;break}const Z=K.indexOf(\"\\n\\n\",M+1);if(Z===-1)break;L=M,M=Z}}}static#Z={open(w){const A=w.data;if(A.#G=w,!A.#F)j.#X(w,A.#$)},handshake(w,A,B){const F=w.data;if(A)j.#X(w,F.#$);else F.#j=2,F.dispatchEvent(new ErrorEvent(\"error\",{error:B})),w.end()},data(w,A){const B=w.data;switch(B.#j){case 0:{let F=A.toString();const G=F.indexOf(\"\\r\\n\\r\\n\");if(G===-1){B.#J+=F;return}if(B.#J.length)B.#J+=F,F=B.#J,B.#J=\"\";const J=F.substring(0,G),K=J.indexOf(\"\\r\\n\");if(K===-1){B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Invalid HTTP request\")})),w.end();return}const L=J.substring(0,K);if(L!==\"HTTP/1.1 200 OK\"){B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(L)})),w.end();return}let M=K+1,O=!1,Q=-1;for(;;){let V=J.indexOf(\"\\r\\n\",M);if(V===-1){if(M>=J.length){if(!O)B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's response has no MIME type and \"text/event-stream\" is required. Aborting the connection.`)})),w.end();return}V=J.length}const W=J.substring(M+1,V),X=W.indexOf(\":\"),Y=W.substring(0,X),Z=Y.localeCompare(\"content-type\",@undefined,{sensitivity:\"accent\"})===0;if(M=V+1,Z)if(W.endsWith(\" text/event-stream\"))O=!0;else{B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's response has a MIME type that is not \"text/event-stream\". Aborting the connection.`)})),w.end();return}else if(Y.localeCompare(\"content-length\",@undefined,{sensitivity:\"accent\"})===0){if(Q=parseInt(W.substring(X+1).trim(),10),@isNaN(Q)||Q<=0){B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's Content-Length is invalid. Aborting the connection.`)})),w.end();return}if(O)break}else if(Y.localeCompare(\"transfer-encoding\",@undefined,{sensitivity:\"accent\"})===0){if(W.substring(X+1).trim()!==\"chunked\"){B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's Transfer-Encoding is invalid. Aborting the connection.`)})),w.end();return}if(Q=0,O)break}}B.#O=Q,B.#j=1,B.dispatchEvent(new Event(\"open\"));const U=F.substring(G+4);if(j.#Y(B,U,0),B.#O>0){if(B.#Q+=U.length,B.#Q>=B.#O)B.#j=2,w.end()}return}case 1:if(j.#Y(B,A.toString(),2),B.#O>0){if(B.#Q+=A.byteLength,B.#Q>=B.#O)B.#j=2,w.end()}return;default:break}},drain(w){const A=w.data;if(A.#j===0){const B=A.#J;if(B.length){const F=w.write(B);if(F!==B.length)w.data.#K=B.substring(F);else w.data.#K=\"\"}}},close:j.#z,end(w){j.#z(w).dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Connection closed by server\")}))},timeout(w){j.#z(w).dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Timeout\")}))},binaryType:\"buffer\"};static#z(w){const A=w.data;if(A.#G=null,A.#Q=0,A.#j=2,A.#M){if(A.#V)clearTimeout(A.#V);A.#V=setTimeout(j.#W,A.#U,A)}return A}constructor(w,A=@undefined){super();const B=new URL(w);this.#F=B.protocol===\"https:\",this.#$=B,this.#j=2,process.nextTick(j.#W,this)}ref(){this.#V\?.ref(),this.#G\?.ref()}unref(){this.#V\?.unref(),this.#G\?.unref()}#H(){if(this.#j!==2)return;const w=this.#$,A=this.#F;this.#j=0,@Bun.connect({data:this,socket:j.#Z,hostname:w.hostname,port:parseInt(w.port||(A\?\"443\":\"80\"),10),tls:A\?{requestCert:!0,rejectUnauthorized:!1}:!1}).catch((B)=>{if(super.dispatchEvent(new ErrorEvent(\"error\",{error:B})),this.#M){if(this.#V)this.#V.unref\?.();this.#V=setTimeout(j.#W,1000,this)}})}get url(){return this.#$.href}get readyState(){return this.#j}close(){this.#M=!1,this.#j=2,this.#G\?.unref(),this.#G\?.end()}get onopen(){return this.#B}get onerror(){return this.#w}get onmessage(){return this.#A}set onopen(w){if(this.#B)super.removeEventListener(\"close\",this.#B);super.addEventListener(\"open\",w),this.#B=w}set onerror(w){if(this.#w)super.removeEventListener(\"error\",this.#w);super.addEventListener(\"error\",w),this.#w=w}set onmessage(w){if(this.#A)super.removeEventListener(\"message\",this.#A);super.addEventListener(\"message\",w),this.#A=w}}return Object.defineProperty(j.prototype,\"CONNECTING\",{enumerable:!0,value:0}),Object.defineProperty(j.prototype,\"OPEN\",{enumerable:!0,value:1}),Object.defineProperty(j.prototype,\"CLOSED\",{enumerable:!0,value:2}),j[Symbol.for(\"CommonJS\")]=0,j})\n";
#define DEFINE_BUILTIN_GENERATOR(codeName, functionName, overriddenName, argumentCount) \
JSC::FunctionExecutable* codeName##Generator(JSC::VM& vm) \
diff --git a/src/js/out/modules/node/http.js b/src/js/out/modules/node/http.js
index 02e000138..dd007e740 100644
--- a/src/js/out/modules/node/http.js
+++ b/src/js/out/modules/node/http.js
@@ -93,8 +93,7 @@ function get(url, options, cb) {
return req.end(), req;
}
var { EventEmitter } = import.meta.require("node:events"), { isIPv6 } = import.meta.require("node:net"), { Readable, Writable, Duplex } = import.meta.require("node:stream"), { URL } = import.meta.require("node:url"), { newArrayWithSize, String, Object, Array } = import.meta.primordials, { isTypedArray } = import.meta.require("util/types"), globalReportError = globalThis.reportError, setTimeout = globalThis.setTimeout, fetch = Bun.fetch, nop = () => {
-}, __DEBUG__ = process.env.__DEBUG__, debug = __DEBUG__ ? (...args) => console.log("node:http", ...args) : nop, kEmptyObject = Object.freeze(Object.create(null)), kOutHeaders = Symbol.for("kOutHeaders"), kEndCalled = Symbol.for("kEndCalled"), kAbortController = Symbol.for("kAbortController"), kClearTimeout = Symbol("kClearTimeout"), kCorked = Symbol.for("kCorked"), searchParamsSymbol = Symbol.for("query"), StringPrototypeSlice = String.prototype.slice, StringPrototypeStartsWith = String.prototype.startsWith, StringPrototypeToUpperCase = String.prototype.toUpperCase, StringPrototypeIncludes = String.prototype.includes, StringPrototypeCharCodeAt = String.prototype.charCodeAt, StringPrototypeIndexOf = String.prototype.indexOf, ArrayIsArray = Array.isArray, RegExpPrototypeExec = RegExp.prototype.exec, ObjectAssign = Object.assign, ObjectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty, INVALID_PATH_REGEX = /[^\u0021-\u00ff]/;
-var _globalAgent, _defaultHTTPSAgent, kInternalRequest = Symbol("kInternalRequest"), kInternalSocketData = Symbol.for("::bunternal::"), kEmptyBuffer = Buffer.alloc(0), FakeSocket = class Socket extends Duplex {
+}, __DEBUG__ = process.env.__DEBUG__, debug = __DEBUG__ ? (...args) => console.log("node:http", ...args) : nop, kEmptyObject = Object.freeze(Object.create(null)), kOutHeaders = Symbol.for("kOutHeaders"), kEndCalled = Symbol.for("kEndCalled"), kAbortController = Symbol.for("kAbortController"), kClearTimeout = Symbol("kClearTimeout"), kCorked = Symbol.for("kCorked"), searchParamsSymbol = Symbol.for("query"), StringPrototypeSlice = String.prototype.slice, StringPrototypeStartsWith = String.prototype.startsWith, StringPrototypeToUpperCase = String.prototype.toUpperCase, StringPrototypeIncludes = String.prototype.includes, StringPrototypeCharCodeAt = String.prototype.charCodeAt, StringPrototypeIndexOf = String.prototype.indexOf, ArrayIsArray = Array.isArray, RegExpPrototypeExec = RegExp.prototype.exec, ObjectAssign = Object.assign, ObjectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty, INVALID_PATH_REGEX = /[^\u0021-\u00ff]/, NODE_HTTP_WARNING = "WARN: Agent is mostly unused in Bun's implementation of http. If you see strange behavior, this is probably the cause.", _globalAgent, _defaultHTTPSAgent, kInternalRequest = Symbol("kInternalRequest"), kInternalSocketData = Symbol.for("::bunternal::"), kEmptyBuffer = Buffer.alloc(0), FakeSocket = class Socket extends Duplex {
bytesRead = 0;
bytesWritten = 0;
connecting = !1;
diff --git a/src/js/out/modules/node/net.js b/src/js/out/modules/node/net.js
index 162da7754..ddd799cf2 100644
--- a/src/js/out/modules/node/net.js
+++ b/src/js/out/modules/node/net.js
@@ -24,9 +24,7 @@ var isIPv4 = function(s) {
self.emit("listening");
}, createServer = function(options, connectionListener) {
return new Server(options, connectionListener);
-};
-var IPv4Reg = new RegExp("^((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$");
-var IPv6Reg = new RegExp("^((?:(?:[0-9a-fA-F]{1,4}):){7}(?:(?:[0-9a-fA-F]{1,4})|:)|(?:(?:[0-9a-fA-F]{1,4}):){6}(?:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|:(?:[0-9a-fA-F]{1,4})|:)|(?:(?:[0-9a-fA-F]{1,4}):){5}(?::((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,2}|:)|(?:(?:[0-9a-fA-F]{1,4}):){4}(?:(:(?:[0-9a-fA-F]{1,4})){0,1}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,3}|:)|(?:(?:[0-9a-fA-F]{1,4}):){3}(?:(:(?:[0-9a-fA-F]{1,4})){0,2}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,4}|:)|(?:(?:[0-9a-fA-F]{1,4}):){2}(?:(:(?:[0-9a-fA-F]{1,4})){0,3}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,5}|:)|(?:(?:[0-9a-fA-F]{1,4}):){1}(?:(:(?:[0-9a-fA-F]{1,4})){0,4}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,6}|:)|(?::((?::(?:[0-9a-fA-F]{1,4})){0,5}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(?::(?:[0-9a-fA-F]{1,4})){1,7}|:)))(%[0-9a-zA-Z-.:]{1,})?$"), { Bun, createFIFO, Object } = import.meta.primordials, { connect: bunConnect } = Bun, { Duplex } = import.meta.require("node:stream"), { EventEmitter } = import.meta.require("node:events"), { setTimeout } = globalThis, bunTlsSymbol = Symbol.for("::buntls::"), bunSocketServerHandlers = Symbol.for("::bunsocket_serverhandlers::"), bunSocketServerConnections = Symbol.for("::bunnetserverconnections::"), bunSocketServerOptions = Symbol.for("::bunnetserveroptions::"), SocketClass, Socket = function(InternalSocket) {
+}, v4Seg = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])", v4Str = "((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])", IPv4Reg = new RegExp("^((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"), v6Seg = "(?:[0-9a-fA-F]{1,4})", IPv6Reg = new RegExp("^((?:(?:[0-9a-fA-F]{1,4}):){7}(?:(?:[0-9a-fA-F]{1,4})|:)|(?:(?:[0-9a-fA-F]{1,4}):){6}(?:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|:(?:[0-9a-fA-F]{1,4})|:)|(?:(?:[0-9a-fA-F]{1,4}):){5}(?::((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,2}|:)|(?:(?:[0-9a-fA-F]{1,4}):){4}(?:(:(?:[0-9a-fA-F]{1,4})){0,1}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,3}|:)|(?:(?:[0-9a-fA-F]{1,4}):){3}(?:(:(?:[0-9a-fA-F]{1,4})){0,2}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,4}|:)|(?:(?:[0-9a-fA-F]{1,4}):){2}(?:(:(?:[0-9a-fA-F]{1,4})){0,3}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,5}|:)|(?:(?:[0-9a-fA-F]{1,4}):){1}(?:(:(?:[0-9a-fA-F]{1,4})){0,4}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,6}|:)|(?::((?::(?:[0-9a-fA-F]{1,4})){0,5}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(?::(?:[0-9a-fA-F]{1,4})){1,7}|:)))(%[0-9a-zA-Z-.:]{1,})?$"), { Bun, createFIFO, Object } = import.meta.primordials, { connect: bunConnect } = Bun, { Duplex } = import.meta.require("node:stream"), { EventEmitter } = import.meta.require("node:events"), { setTimeout } = globalThis, bunTlsSymbol = Symbol.for("::buntls::"), bunSocketServerHandlers = Symbol.for("::bunsocket_serverhandlers::"), bunSocketServerConnections = Symbol.for("::bunnetserverconnections::"), bunSocketServerOptions = Symbol.for("::bunnetserveroptions::"), SocketClass, Socket = function(InternalSocket) {
return SocketClass = InternalSocket, Object.defineProperty(SocketClass.prototype, Symbol.toStringTag, {
value: "Socket",
enumerable: !1