#include "BunStream.h" #include "JavaScriptCore/JSMicrotask.h" #include "JavaScriptCore/ObjectConstructor.h" namespace WebCore { using JSGlobalObject = JSC::JSGlobalObject; using Exception = JSC::Exception; using JSValue = JSC::JSValue; using JSString = JSC::JSString; using JSModuleLoader = JSC::JSModuleLoader; using JSModuleRecord = JSC::JSModuleRecord; using Identifier = JSC::Identifier; using SourceOrigin = JSC::SourceOrigin; using JSObject = JSC::JSObject; using JSNonFinalObject = JSC::JSNonFinalObject; namespace JSCastingHelpers = JSC::JSCastingHelpers; static ReadableEvent getReadableEvent(const WTF::String& eventName); static ReadableEvent getReadableEvent(const WTF::String& eventName) { if (eventName == "close") return ReadableEvent__Close; else if (eventName == "data") return ReadableEvent__Data; else if (eventName == "end") return ReadableEvent__End; else if (eventName == "error") return ReadableEvent__Error; else if (eventName == "pause") return ReadableEvent__Pause; else if (eventName == "readable") return ReadableEvent__Readable; else if (eventName == "resume") return ReadableEvent__Resume; else if (eventName == "open") return ReadableEvent__Open; else return ReadableEventUser; } static WritableEvent getWritableEvent(const WTF::String& eventName); static WritableEvent getWritableEvent(const WTF::String& eventName) { if (eventName == "close") return WritableEvent__Close; else if (eventName == "drain") return WritableEvent__Drain; else if (eventName == "error") return WritableEvent__Error; else if (eventName == "finish") return WritableEvent__Finish; else if (eventName == "pipe") return WritableEvent__Pipe; else if (eventName == "unpipe") return WritableEvent__Unpipe; else if (eventName == "open") return WritableEvent__Open; else return WritableEventUser; } // clang-format off #define DEFINE_CALLBACK_FUNCTION_BODY(TypeName, ZigFunction) JSC::VM& vm = globalObject->vm(); \ auto* thisObject = JSC::jsDynamicCast(vm, callFrame->thisValue()); \ auto scope = DECLARE_THROW_SCOPE(vm); \ if (!thisObject) \ return throwVMTypeError(globalObject, scope); \ auto argCount = static_cast(callFrame->argumentCount()); \ WTF::Vector arguments; \ arguments.reserveInitialCapacity(argCount); \ if (argCount) { \ for (uint16_t i = 0; i < argCount; ++i) { \ arguments.uncheckedAppend(JSC::JSValue::encode(callFrame->uncheckedArgument(i))); \ } \ } \ JSC::JSValue result = JSC::JSValue::decode( \ ZigFunction(thisObject->state, globalObject, reinterpret_cast(arguments.data()), argCount) \ ); \ JSC::JSObject *obj = result.getObject(); \ if (UNLIKELY(obj != nullptr && obj->isErrorInstance())) { \ scope.throwException(globalObject, obj); \ return JSC::JSValue::encode(JSC::jsUndefined()); \ } \ if (UNLIKELY(scope.exception())) \ return JSC::JSValue::encode(JSC::jsUndefined()); \ return JSC::JSValue::encode(result); // clang-format on // static JSC_DECLARE_HOST_FUNCTION(Writable__addEventListener); // static JSC_DECLARE_HOST_FUNCTION(Readable__addEventListener); // static JSC_DECLARE_HOST_FUNCTION(Writable__prependListener); // static JSC_DECLARE_HOST_FUNCTION(Readable__prependListener); // static JSC_DECLARE_HOST_FUNCTION(Writable__prependOnceListener); // static JSC_DECLARE_HOST_FUNCTION(Readable__prependOnceListener); // static JSC_DECLARE_HOST_FUNCTION(Writable__setMaxListeners); // static JSC_DECLARE_HOST_FUNCTION(Readable__setMaxListeners); // static JSC_DECLARE_HOST_FUNCTION(Writable__getMaxListeners); // static JSC_DECLARE_HOST_FUNCTION(Readable__getMaxListeners); // static JSC_DECLARE_HOST_FUNCTION(Readable__setDefaultEncoding); static JSC_DECLARE_HOST_FUNCTION(Readable__on); // static JSC_DECLARE_HOST_FUNCTION(Readable__off); static JSC_DECLARE_HOST_FUNCTION(Readable__once); static JSC_DECLARE_HOST_FUNCTION(Readable__pause); static JSC_DECLARE_HOST_FUNCTION(Readable__pipe); static JSC_DECLARE_HOST_FUNCTION(Readable__read); static JSC_DECLARE_HOST_FUNCTION(Readable__resume); static JSC_DECLARE_HOST_FUNCTION(Readable__unpipe); static JSC_DECLARE_HOST_FUNCTION(Readable__unshift); static JSC_DECLARE_HOST_FUNCTION(Writable__close); // static JSC_DECLARE_HOST_FUNCTION(Writable__off); static JSC_DECLARE_HOST_FUNCTION(Writable__cork); static JSC_DECLARE_HOST_FUNCTION(Writable__destroy); static JSC_DECLARE_HOST_FUNCTION(Writable__end); static JSC_DECLARE_HOST_FUNCTION(Writable__on); static JSC_DECLARE_HOST_FUNCTION(Writable__once); static JSC_DECLARE_HOST_FUNCTION(Writable__uncork); static JSC_DECLARE_HOST_FUNCTION(Writable__write); static JSC_DEFINE_HOST_FUNCTION(Readable__on, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { if (callFrame->argumentCount() < 2) { return JSC::JSValue::encode(JSC::jsUndefined()); } JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto thisObject = JSC::jsDynamicCast(vm, callFrame->thisValue()); if (UNLIKELY(!thisObject)) { scope.release(); JSC::throwVMTypeError(globalObject, scope); return JSC::JSValue::encode(JSC::jsUndefined()); } auto eventName = callFrame->argument(0).toStringOrNull(globalObject); if (UNLIKELY(!eventName)) { scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } ReadableEvent event = getReadableEvent(eventName->value(globalObject)); if (event == ReadableEventUser) { // TODO: scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } auto listener = callFrame->argument(1); JSC::JSObject* object = listener.getObject(); if (UNLIKELY(!object) || !listener.isCallable(vm)) { scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } Bun__Readable__addEventListener(thisObject->state, globalObject, event, JSC::JSValue::encode(listener), true); scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } extern "C" Bun__Readable* JSC__JSValue__getReadableStreamState(JSC__JSValue value, JSC__VM* vm) { auto* thisObject = JSC::jsDynamicCast(*vm, JSC::JSValue::decode(value)); if (UNLIKELY(!thisObject)) { return nullptr; } return thisObject->state; } extern "C" Bun__Writable* JSC__JSValue__getWritableStreamState(JSC__JSValue value, JSC__VM* vm) { auto* thisObject = JSC::jsDynamicCast(*vm, JSC::JSValue::decode(value)); if (UNLIKELY(!thisObject)) { return nullptr; } return thisObject->state; } const JSC::ClassInfo Readable::s_info = { "Readable"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(Readable) }; const JSC::ClassInfo Writable::s_info = { "Writable"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(Writable) }; static JSC_DEFINE_HOST_FUNCTION(Readable__once, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { if (callFrame->argumentCount() < 2) { return JSC::JSValue::encode(JSC::jsUndefined()); } JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto thisObject = JSC::jsDynamicCast(vm, callFrame->thisValue()); if (UNLIKELY(!thisObject)) { scope.release(); JSC::throwVMTypeError(globalObject, scope); return JSC::JSValue::encode(JSC::jsUndefined()); } auto eventName = callFrame->argument(0).toStringOrNull(globalObject); if (UNLIKELY(!eventName)) { scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } ReadableEvent event = getReadableEvent(eventName->value(globalObject)); if (event == ReadableEventUser) { // TODO: scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } auto listener = callFrame->argument(1); JSC::JSObject* object = listener.getObject(); if (UNLIKELY(!object) || !listener.isCallable(vm)) { scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } Bun__Readable__addEventListener(thisObject->state, globalObject, event, JSC::JSValue::encode(listener), true); scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } static JSC_DEFINE_HOST_FUNCTION(Writable__on, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { if (callFrame->argumentCount() < 2) { return JSC::JSValue::encode(JSC::jsUndefined()); } JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto thisObject = JSC::jsDynamicCast(vm, callFrame->thisValue()); if (UNLIKELY(!thisObject)) { scope.release(); JSC::throwVMTypeError(globalObject, scope); return JSC::JSValue::encode(JSC::jsUndefined()); } auto eventName = callFrame->argument(0).toStringOrNull(globalObject); if (UNLIKELY(!eventName)) { scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } WritableEvent event = getWritableEvent(eventName->value(globalObject)); if (event == WritableEventUser) { // TODO: scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } auto listener = callFrame->argument(1); JSC::JSObject* object = listener.getObject(); if (UNLIKELY(!object) || !listener.isCallable(vm)) { scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } Bun__Writable__addEventListener(thisObject->state, globalObject, event, JSC::JSValue::encode(listener), false); scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } static JSC_DEFINE_HOST_FUNCTION(Writable__once, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { if (callFrame->argumentCount() < 2) { return JSC::JSValue::encode(JSC::jsUndefined()); } JSC::VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto thisObject = JSC::jsDynamicCast(vm, callFrame->thisValue()); if (UNLIKELY(!thisObject)) { scope.release(); JSC::throwVMTypeError(globalObject, scope); return JSC::JSValue::encode(JSC::jsUndefined()); } auto eventName = callFrame->argument(0).toStringOrNull(globalObject); if (UNLIKELY(!eventName)) { scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } WritableEvent event = getWritableEvent(eventName->value(globalObject)); if (event == WritableEventUser) { // TODO: scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } auto listener = callFrame->argument(1); JSC::JSObject* object = listener.getObject(); if (UNLIKELY(!object) || !listener.isCallable(vm)) { scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } Bun__Writable__addEventListener(thisObject->state, globalObject, event, JSC::JSValue::encode(listener), true); scope.release(); return JSC::JSValue::encode(JSC::jsUndefined()); } static JSC_DEFINE_HOST_FUNCTION(Readable__read, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Readable, Bun__Readable__read); } static JSC_DEFINE_HOST_FUNCTION(Readable__pipe, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Readable, Bun__Readable__pipe); } static JSC_DEFINE_HOST_FUNCTION(Readable__resume, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Readable, Bun__Readable__resume); } static JSC_DEFINE_HOST_FUNCTION(Readable__unpipe, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Readable, Bun__Readable__unpipe); } static JSC_DEFINE_HOST_FUNCTION(Readable__pause, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Readable, Bun__Readable__pause); } static JSC_DEFINE_HOST_FUNCTION(Readable__unshift, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Readable, Bun__Readable__unshift); } // static JSC_DECLARE_HOST_FUNCTION(Readable__isPaused); // static JSC_DECLARE_HOST_FUNCTION(Writable__setDefaultEncoding); // static DEFINE_CALLBACK_FUNCTION(Writable__setDefaultEncoding, WebCore::Writable, // Bun__Writable__setDefaultEncoding); static JSC_DEFINE_HOST_FUNCTION(Writable__write, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Writable, Bun__Writable__write); } static JSC_DEFINE_HOST_FUNCTION(Writable__end, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Writable, Bun__Writable__end); } static JSC_DEFINE_HOST_FUNCTION(Writable__close, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Writable, Bun__Writable__close); } static JSC_DEFINE_HOST_FUNCTION(Writable__destroy, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Writable, Bun__Writable__destroy); } static JSC_DEFINE_HOST_FUNCTION(Writable__cork, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Writable, Bun__Writable__cork); } static JSC_DEFINE_HOST_FUNCTION(Writable__uncork, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { DEFINE_CALLBACK_FUNCTION_BODY(WebCore::Writable, Bun__Writable__uncork); } extern "C" JSC__JSValue Bun__Readable__create(Bun__Readable* state, JSC__JSGlobalObject* globalObject) { JSC::JSValue result = JSC::JSValue(Readable::create( globalObject->vm(), state, Readable::createStructure(globalObject->vm(), globalObject, globalObject->objectPrototype()))); return JSC::JSValue::encode(result); } extern "C" JSC__JSValue Bun__Writable__create(Bun__Writable* state, JSC__JSGlobalObject* globalObject) { JSC::JSValue result = JSC::JSValue(Writable::create( globalObject->vm(), state, Writable::createStructure(globalObject->vm(), globalObject, globalObject->objectPrototype()))); return JSC::JSValue::encode(result); } Readable::~Readable() { if (this->state) { Bun__Readable__deinit(this->state); } } Writable::~Writable() { if (this->state) { Bun__Writable__deinit(this->state); } } void Readable::finishCreation(JSC::VM& vm) { Base::finishCreation(vm); auto clientData = WebCore::clientData(vm); auto* globalObject = this->globalObject(); putDirect(vm, clientData->builtinNames().onPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().onPublicName().string(), Readable__on), 0); putDirect(vm, clientData->builtinNames().oncePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().oncePublicName().string(), Readable__once), 0); putDirect(vm, clientData->builtinNames().pausePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().pausePublicName().string(), Readable__pause), 0); putDirect(vm, clientData->builtinNames().pipePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().pipePublicName().string(), Readable__pipe), 0); putDirect(vm, clientData->builtinNames().readPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().readPublicName().string(), Readable__read), 0); putDirect(vm, clientData->builtinNames().resumePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().resumePublicName().string(), Readable__resume), 0); putDirect(vm, clientData->builtinNames().unpipePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().unpipePublicName().string(), Readable__unpipe), 0); putDirect(vm, clientData->builtinNames().unshiftPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().unshiftPublicName().string(), Readable__unshift), 0); } void Writable::finishCreation(JSC::VM& vm) { Base::finishCreation(vm); auto clientData = WebCore::clientData(vm); auto* globalObject = this->globalObject(); putDirect(vm, clientData->builtinNames().onPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().onPublicName().string(), Writable__on), 0); putDirect(vm, clientData->builtinNames().oncePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().oncePublicName().string(), Writable__once), 0); putDirect(vm, clientData->builtinNames().closePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().closePublicName().string(), Writable__close), 0); putDirect(vm, clientData->builtinNames().corkPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().corkPublicName().string(), Writable__cork), 0); putDirect(vm, clientData->builtinNames().destroyPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().destroyPublicName().string(), Writable__destroy), 0); putDirect(vm, clientData->builtinNames().endPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().endPublicName().string(), Writable__end), 0); putDirect(vm, clientData->builtinNames().onPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().onPublicName().string(), Writable__on), 0); putDirect(vm, clientData->builtinNames().oncePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().oncePublicName().string(), Writable__once), 0); putDirect(vm, clientData->builtinNames().uncorkPublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().uncorkPublicName().string(), Writable__uncork), 0); putDirect(vm, clientData->builtinNames().writePublicName(), JSFunction::create(vm, globalObject, 2, clientData->builtinNames().writePublicName().string(), Writable__write), 0); } } // namespace WebCore