aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
authorGravatar dave caruso <me@paperdave.net> 2023-09-07 07:45:00 -0700
committerGravatar GitHub <noreply@github.com> 2023-09-07 07:45:00 -0700
commit36e5a072a94805d5644081052391860e2b51f710 (patch)
tree861b4ddc665e28ba321dd5ded17c29371b3358c5 /src/bun.js
parent57a06745a48093c25d0f4729ccea41a918d6427d (diff)
downloadbun-36e5a072a94805d5644081052391860e2b51f710.tar.gz
bun-36e5a072a94805d5644081052391860e2b51f710.tar.zst
bun-36e5a072a94805d5644081052391860e2b51f710.zip
revert (#4539)
* Revert "remove native events from streams" This reverts commit e063a47a53744a2bf5b1c2dd433698c9e37b75d6. * finish revert * remove accidental submodule * dfghj
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/bindings/JSReadableHelper.cpp263
-rw-r--r--src/bun.js/bindings/JSReadableHelper.h13
-rw-r--r--src/bun.js/bindings/JSReadableState.cpp426
-rw-r--r--src/bun.js/bindings/JSReadableState.h154
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp62
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.h9
6 files changed, 916 insertions, 11 deletions
diff --git a/src/bun.js/bindings/JSReadableHelper.cpp b/src/bun.js/bindings/JSReadableHelper.cpp
new file mode 100644
index 000000000..0c459f329
--- /dev/null
+++ b/src/bun.js/bindings/JSReadableHelper.cpp
@@ -0,0 +1,263 @@
+#include "JSReadableHelper.h"
+#include "JSReadableState.h"
+#include "JSBufferList.h"
+#include "JSBuffer.h"
+#include "JSEventEmitter.h"
+#include "JSStringDecoder.h"
+#include "JavaScriptCore/Lookup.h"
+#include "JavaScriptCore/ObjectConstructor.h"
+#include "ZigGlobalObject.h"
+#include "JSDOMOperation.h"
+#include "JSDOMAttribute.h"
+#include "headers.h"
+#include "JSDOMConvertEnumeration.h"
+#include "JavaScriptCore/StrongInlines.h"
+#include "BunClientData.h"
+
+namespace WebCore {
+using namespace JSC;
+
+#define JSReadableHelper_EXTRACT_STREAM_STATE \
+ VM& vm = lexicalGlobalObject->vm(); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ \
+ if (callFrame->argumentCount() < 2) { \
+ throwTypeError(lexicalGlobalObject, throwScope, "Not enough arguments"_s); \
+ return JSValue::encode(jsUndefined()); \
+ } \
+ \
+ JSObject* stream = callFrame->uncheckedArgument(0).toObject(lexicalGlobalObject); \
+ RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); \
+ JSReadableState* state = jsCast<JSReadableState*>(callFrame->uncheckedArgument(1)); \
+ if (!state) { \
+ throwTypeError(lexicalGlobalObject, throwScope, "Second argument not ReadableState"_s); \
+ return JSValue::encode(jsUndefined()); \
+ }
+
+static bool callRead(JSValue stream, JSFunction* read, JSC::MarkedArgumentBuffer&& args, JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, EventEmitter& emitter)
+{
+ WTF::NakedPtr<JSC::Exception> exceptionPtr;
+ JSC::CallData callData = JSC::getCallData(read);
+ JSValue ret = call(lexicalGlobalObject, read, callData, JSValue(stream), WTFMove(args), exceptionPtr);
+ if (auto* exception = exceptionPtr.get()) {
+ JSC::Identifier errorEventName = JSC::Identifier::fromString(vm, "error"_s);
+ if (emitter.hasEventListeners(errorEventName)) {
+ args.clear();
+ JSValue val = exception->value();
+ if (!val) {
+ val = jsUndefined();
+ }
+ args.append(val);
+ emitter.emitForBindings(errorEventName, args);
+ } else {
+ reportException(lexicalGlobalObject, exception);
+ }
+ return true;
+ }
+
+ return !ret.isUndefinedOrNull();
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsReadable_maybeReadMore, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ JSReadableHelper_EXTRACT_STREAM_STATE
+
+ auto clientData
+ = WebCore::clientData(vm);
+ auto readIdentifier = clientData->builtinNames().readPublicName();
+ auto read = stream->get(lexicalGlobalObject, readIdentifier);
+
+ auto callData = JSC::getCallData(read);
+ if (callData.type == CallData::Type::None) {
+ throwException(lexicalGlobalObject, throwScope, createNotAFunctionError(lexicalGlobalObject, read));
+ return JSValue::encode({});
+ }
+
+ auto* jsEmitter = jsEventEmitterCastFast(vm, lexicalGlobalObject, stream);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ if (UNLIKELY(!jsEmitter)) {
+ throwTypeError(lexicalGlobalObject, throwScope, "Stream must be an EventEmitter"_s);
+ return JSValue::encode(JSValue {});
+ }
+ auto& emitter = jsEmitter->wrapped();
+
+ while (
+ !state->getBool(JSReadableState::reading) && !state->getBool(JSReadableState::ended) && (state->m_length < state->m_highWaterMark || (state->m_flowing > 0 && state->m_length == 0))) {
+ int64_t len = state->m_length;
+ MarkedArgumentBuffer args;
+ args.append(jsNumber(0));
+
+ callRead(stream, jsCast<JSFunction*>(read), WTFMove(args), vm, lexicalGlobalObject, emitter);
+
+ if (len == state->m_length)
+ break;
+ }
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined()));
+}
+
+void flow(JSGlobalObject* lexicalGlobalObject, JSObject* streamObj, JSReadableState* state)
+{
+ VM& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ auto clientData = WebCore::clientData(vm);
+ auto readIdentifier = clientData->builtinNames().readPublicName();
+ auto read = streamObj->get(lexicalGlobalObject, readIdentifier);
+
+ auto callData = JSC::getCallData(read);
+ if (callData.type == CallData::Type::None) {
+ throwException(lexicalGlobalObject, throwScope, createNotAFunctionError(lexicalGlobalObject, read));
+ return;
+ }
+
+ if (state->m_flowing > 0) {
+ WebCore::EventEmitter& emitter = jsEventEmitterCastFast(vm, lexicalGlobalObject, streamObj)->wrapped();
+
+ while (state->m_flowing > 0) {
+
+ if (!callRead(streamObj, jsCast<JSFunction*>(read), MarkedArgumentBuffer(), vm, lexicalGlobalObject, emitter)) {
+ break;
+ }
+ }
+ }
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsReadable_resume, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ JSReadableHelper_EXTRACT_STREAM_STATE
+
+ auto* jsEmitterWrap
+ = jsEventEmitterCastFast(vm, lexicalGlobalObject, stream);
+
+ if (UNLIKELY(!jsEmitterWrap)) {
+ throwTypeError(lexicalGlobalObject, throwScope, "Stream must be an EventEmitter"_s);
+ return JSValue::encode(JSValue {});
+ }
+
+ auto& emitter = jsEmitterWrap->wrapped();
+ auto clientData = WebCore::clientData(vm);
+ auto readIdentifier = clientData->builtinNames().readPublicName();
+
+ if (!state->getBool(JSReadableState::reading)) {
+ // stream.read(0)
+ MarkedArgumentBuffer args;
+ args.append(jsNumber(0));
+
+ callRead(stream, jsCast<JSFunction*>(stream->get(lexicalGlobalObject, readIdentifier)), WTFMove(args), vm, lexicalGlobalObject, emitter);
+ }
+
+ state->setBool(JSReadableState::resumeScheduled, true);
+ // stream.emit('resume')
+ auto eventType = clientData->builtinNames().resumePublicName();
+ MarkedArgumentBuffer args;
+
+ emitter.emitForBindings(eventType, args);
+
+ flow(lexicalGlobalObject, stream, state);
+
+ if (state->m_flowing > 0 && !state->getBool(JSReadableState::reading)) {
+ // stream.read(0)
+ auto read = stream->get(lexicalGlobalObject, readIdentifier);
+ auto callData = JSC::getCallData(read);
+ if (callData.type == CallData::Type::None) {
+ throwException(lexicalGlobalObject, throwScope, createNotAFunctionError(lexicalGlobalObject, read));
+ return JSValue::encode(jsUndefined());
+ }
+ MarkedArgumentBuffer args;
+ args.append(jsNumber(0));
+ callRead(stream, jsCast<JSFunction*>(read), WTFMove(args), vm, lexicalGlobalObject, emitter);
+ }
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined()));
+}
+
+EncodedJSValue emitReadable_(JSGlobalObject* lexicalGlobalObject, JSObject* stream, JSReadableState* state)
+{
+ VM& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSValue errored = state->m_errored.get();
+ if (!state->getBool(JSReadableState::destroyed) && !errored.toBoolean(lexicalGlobalObject) && (state->m_length || state->getBool(JSReadableState::ended))) {
+ // stream.emit('readable')
+ auto clientData = WebCore::clientData(vm);
+
+ auto eventType = clientData->builtinNames().readablePublicName();
+ MarkedArgumentBuffer args;
+ auto* emitter
+ = jsEventEmitterCastFast(vm, lexicalGlobalObject, stream);
+ if (UNLIKELY(!emitter)) {
+ throwTypeError(lexicalGlobalObject, throwScope, "Stream must be an EventEmitter"_s);
+ return JSValue::encode(JSValue {});
+ }
+ emitter->wrapped().emitForBindings(eventType, args);
+
+ state->setBool(JSReadableState::emittedReadable, false);
+ }
+
+ state->setBool(JSReadableState::needReadable, state->m_flowing <= 0 && !state->getBool(JSReadableState::ended) && state->m_length <= state->m_highWaterMark);
+ flow(lexicalGlobalObject, stream, state);
+ return JSValue::encode(jsUndefined());
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsReadable_emitReadable_, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ JSReadableHelper_EXTRACT_STREAM_STATE
+
+ emitReadable_(lexicalGlobalObject, stream, state);
+
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined()));
+}
+
+EncodedJSValue emitReadable(JSGlobalObject* lexicalGlobalObject, JSObject* stream, JSReadableState* state)
+{
+ VM& vm = lexicalGlobalObject->vm();
+
+ state->setBool(JSReadableState::needReadable, false);
+ if (!state->getBool(JSReadableState::emittedReadable)) {
+ state->setBool(JSReadableState::emittedReadable, true);
+ Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ globalObject->queueMicrotask(JSValue(globalObject->emitReadableNextTickFunction()), JSValue(stream), JSValue(state), JSValue {}, JSValue {});
+ }
+ return JSValue::encode(jsUndefined());
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsReadable_emitReadable, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ JSReadableHelper_EXTRACT_STREAM_STATE
+
+ RELEASE_AND_RETURN(throwScope, emitReadable(lexicalGlobalObject, stream, state));
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsReadable_onEofChunk, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ JSReadableHelper_EXTRACT_STREAM_STATE
+
+ if (state->getBool(JSReadableState::ended))
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined()));
+
+ auto decoder = jsDynamicCast<JSStringDecoder*>(state->m_decoder.get());
+ if (decoder) {
+ JSString* chunk = jsDynamicCast<JSString*>(decoder->end(vm, lexicalGlobalObject, nullptr, 0));
+ if (chunk && chunk->length()) {
+ auto buffer = jsDynamicCast<JSBufferList*>(state->m_buffer.get());
+ if (!buffer) {
+ throwTypeError(lexicalGlobalObject, throwScope, "Not buffer on stream"_s);
+ return JSValue::encode(jsUndefined());
+ }
+ buffer->push(vm, JSValue(chunk));
+ state->m_length += state->getBool(JSReadableState::objectMode) ? 1 : chunk->length();
+ }
+ }
+
+ state->setBool(JSReadableState::ended, true);
+
+ if (state->getBool(JSReadableState::sync)) {
+ RELEASE_AND_RETURN(throwScope, emitReadable(lexicalGlobalObject, stream, state));
+ } else {
+ state->setBool(JSReadableState::needReadable, false);
+ state->setBool(JSReadableState::emittedReadable, true);
+ RELEASE_AND_RETURN(throwScope, emitReadable_(lexicalGlobalObject, stream, state));
+ }
+}
+
+#undef JSReadableHelper_EXTRACT_STREAM_STATE
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/JSReadableHelper.h b/src/bun.js/bindings/JSReadableHelper.h
new file mode 100644
index 000000000..3e2554c2b
--- /dev/null
+++ b/src/bun.js/bindings/JSReadableHelper.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "root.h"
+
+namespace WebCore {
+
+JSC_DECLARE_HOST_FUNCTION(jsReadable_maybeReadMore);
+JSC_DECLARE_HOST_FUNCTION(jsReadable_resume);
+JSC_DECLARE_HOST_FUNCTION(jsReadable_emitReadable);
+JSC_DECLARE_HOST_FUNCTION(jsReadable_onEofChunk);
+JSC_DECLARE_HOST_FUNCTION(jsReadable_emitReadable_);
+
+} // namespace WebCore
diff --git a/src/bun.js/bindings/JSReadableState.cpp b/src/bun.js/bindings/JSReadableState.cpp
new file mode 100644
index 000000000..1f3a36def
--- /dev/null
+++ b/src/bun.js/bindings/JSReadableState.cpp
@@ -0,0 +1,426 @@
+#include "JSReadableState.h"
+#include "JSBufferList.h"
+#include "JSBuffer.h"
+#include "JavaScriptCore/Lookup.h"
+#include "JavaScriptCore/ObjectConstructor.h"
+#include "ZigGlobalObject.h"
+#include "JSDOMOperation.h"
+#include "JSDOMAttribute.h"
+#include "headers.h"
+#include "JSDOMConvertEnumeration.h"
+#include "BunClientData.h"
+
+namespace WebCore {
+
+using namespace JSC;
+
+static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_pipesCount);
+
+int64_t getHighWaterMark(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options)
+{
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ // We must use getIfPropertyExists because:
+ // - it might be a getter
+ // - it might be from a super class
+ auto* clientData = WebCore::clientData(vm);
+ if (JSValue highWaterMarkVal = options->getIfPropertyExists(globalObject, clientData->builtinNames().highWaterMarkPublicName())) {
+ if (isDuplex && (highWaterMarkVal.isUndefined() || highWaterMarkVal.isNull())) {
+ highWaterMarkVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "readableObjectMode"_s));
+ }
+
+ if (highWaterMarkVal && highWaterMarkVal.isNumber()) {
+ return highWaterMarkVal.toInt32(globalObject);
+ }
+ }
+
+ return -1;
+}
+
+void JSReadableState::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options)
+{
+ Base::finishCreation(vm);
+
+ if (options != nullptr) {
+ JSC::JSValue objectModeVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "objectMode"_s));
+ if (isDuplex && !objectModeVal) {
+ objectModeVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "readableObjectMode"_s));
+ }
+ if (objectModeVal && objectModeVal.toBoolean(globalObject))
+ setBool(JSReadableState::Mask::objectMode, true);
+ }
+
+ m_highWaterMark = getBool(
+ JSReadableState::Mask::objectMode)
+ ? 16
+ : 16 * 1024; // default value
+
+ if (options != nullptr) {
+ int64_t customHightWaterMark = getHighWaterMark(vm, globalObject, isDuplex, options);
+ if (customHightWaterMark >= 0)
+ m_highWaterMark = customHightWaterMark;
+ }
+
+ m_buffer.set(vm, this, JSBufferList::create(vm, globalObject, reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferListStructure()));
+ m_pipes.set(vm, this, JSC::constructEmptyArray(globalObject, nullptr, 0));
+
+ if (options != nullptr) {
+ JSC::JSValue emitCloseVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "emitClose"_s));
+ if (!emitCloseVal || emitCloseVal.toBoolean(globalObject))
+ setBool(JSReadableState::Mask::emitClose, true);
+ // Has it been destroyed.
+ JSC::JSValue autoDestroyVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "autoDestroy"_s));
+ if (!autoDestroyVal || autoDestroyVal.toBoolean(globalObject))
+ setBool(JSReadableState::Mask::autoDestroy, true);
+ } else {
+ setBool(JSReadableState::Mask::emitClose, true);
+ setBool(JSReadableState::Mask::autoDestroy, true);
+ }
+
+ // Indicates whether the stream has finished destroying.
+ m_errored.set(vm, this, JSC::jsNull());
+
+ // Ref the piped dest which we need a drain event on it
+ // type: null | Writable | Set<Writable>.
+ if (options == nullptr) {
+ m_defaultEncoding.set(vm, this, JSC::jsString(vm, WTF::String("utf8"_s)));
+ } else {
+ if (JSC::JSValue defaultEncodingVal = getIfPropertyExists(globalObject, PropertyName(JSC::Identifier::fromString(vm, "defaultEncoding"_s)))) {
+ m_defaultEncoding.set(vm, this, defaultEncodingVal);
+ } else {
+ m_defaultEncoding.set(vm, this, JSC::jsString(vm, WTF::String("utf8"_s)));
+ }
+ }
+
+ m_awaitDrainWriters.set(vm, this, JSC::jsNull());
+ JSValue decodeValue = JSC::jsNull();
+ JSValue encodingValue = JSC::jsNull();
+
+ if (options != nullptr) {
+ JSC::JSValue encodingVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "encoding"_s));
+ if (encodingVal && encodingVal.isString()) {
+ auto constructor = reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSStringDecoder();
+ auto constructData = JSC::getConstructData(constructor);
+ MarkedArgumentBuffer args;
+ args.append(encodingVal);
+ JSObject* decoder = JSC::construct(globalObject, constructor, constructData, args);
+ decodeValue = decoder;
+ encodingValue = encodingVal;
+ }
+ }
+
+ m_decoder.set(vm, this, decodeValue);
+ m_encoding.set(vm, this, encodingValue);
+
+ // ReadableState.constructed is set to false during construction when a _construct method is implemented
+ // this is here so that the ReadableState behavior tracks the behavior in node, and that calling Readable.read
+ // will work when we return early from construct because there is no Readable._construct implemented
+ // See: https://github.com/nodejs/node/blob/main/lib/internal/streams/readable.js
+ setBool(JSReadableState::Mask::constructed, true);
+}
+
+const JSC::ClassInfo JSReadableState::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableState) };
+
+JSC::GCClient::IsoSubspace* JSReadableState::subspaceForImpl(JSC::VM& vm)
+{
+ return WebCore::subspaceForImpl<JSReadableState, UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForReadableState.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableState = std::forward<decltype(space)>(space); },
+ [](auto& spaces) { return spaces.m_subspaceForReadableState.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableState = std::forward<decltype(space)>(space); });
+}
+
+template<typename Visitor>
+void JSReadableState::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ JSReadableState* state = jsCast<JSReadableState*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(state, info());
+ Base::visitChildren(state, visitor);
+ visitor.append(state->m_buffer);
+ visitor.append(state->m_pipes);
+ visitor.append(state->m_errored);
+ visitor.append(state->m_defaultEncoding);
+ visitor.append(state->m_awaitDrainWriters);
+ visitor.append(state->m_decoder);
+ visitor.append(state->m_encoding);
+}
+DEFINE_VISIT_CHILDREN(JSReadableState);
+
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStatePrototype, JSReadableStatePrototype::Base);
+
+JSC_DEFINE_CUSTOM_GETTER(jsReadableState_pipesCount, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue));
+ if (!state) {
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
+ }
+ JSArray* pipes = JSC::jsDynamicCast<JSArray*>(state->m_pipes.get());
+ if (!pipes) {
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
+ }
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(pipes->length())));
+}
+
+#define JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(NAME) \
+ static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \
+ JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \
+ { \
+ auto& vm = JSC::getVM(lexicalGlobalObject); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
+ if (!state) { \
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \
+ } \
+ if (state->m_##NAME == 0) \
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNull())); \
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsBoolean(state->m_##NAME > 0))); \
+ } \
+ static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \
+ JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \
+ { \
+ auto& vm = JSC::getVM(lexicalGlobalObject); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
+ if (!state) { \
+ RETURN_IF_EXCEPTION(throwScope, false); \
+ } \
+ auto value = JSC::JSValue::decode(encodedValue); \
+ state->m_##NAME = value.isNull() ? 0 : value.toBoolean(lexicalGlobalObject) ? 1 \
+ : -1; \
+ RELEASE_AND_RETURN(throwScope, true); \
+ }
+
+JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(paused)
+ JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(flowing)
+
+#undef JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER
+
+#define JSReadableState_NUMBER_GETTER_SETTER(NAME) \
+ static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \
+ JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \
+ { \
+ auto& vm = JSC::getVM(lexicalGlobalObject); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
+ if (!state) { \
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \
+ } \
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(state->m_##NAME))); \
+ } \
+ \
+ static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \
+ JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \
+ { \
+ auto& vm = JSC::getVM(lexicalGlobalObject); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
+ if (!state) { \
+ RETURN_IF_EXCEPTION(throwScope, false); \
+ } \
+ state->m_##NAME = JSC::JSValue::decode(encodedValue).toNumber(lexicalGlobalObject); \
+ RETURN_IF_EXCEPTION(throwScope, false); \
+ RELEASE_AND_RETURN(throwScope, true); \
+ }
+
+ JSReadableState_NUMBER_GETTER_SETTER(length)
+ JSReadableState_NUMBER_GETTER_SETTER(highWaterMark)
+
+#undef JSReadableState_NUMBER_GETTER_SETTER
+
+#define JSReadableState_BOOLEAN_GETTER_SETTER(NAME) \
+ static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \
+ JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \
+ { \
+ auto& vm = JSC::getVM(lexicalGlobalObject); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
+ if (!state) { \
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \
+ } \
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsBoolean(state->getBool(JSReadableState::Mask::NAME)))); \
+ } \
+ \
+ static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \
+ JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \
+ { \
+ auto& vm = JSC::getVM(lexicalGlobalObject); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
+ if (!state) { \
+ RETURN_IF_EXCEPTION(throwScope, false); \
+ } \
+ state->setBool(JSReadableState::Mask::NAME, JSC::JSValue::decode(encodedValue).toBoolean(lexicalGlobalObject)); \
+ RELEASE_AND_RETURN(throwScope, true); \
+ }
+
+ JSReadableState_BOOLEAN_GETTER_SETTER(objectMode)
+ JSReadableState_BOOLEAN_GETTER_SETTER(ended)
+ JSReadableState_BOOLEAN_GETTER_SETTER(endEmitted)
+ JSReadableState_BOOLEAN_GETTER_SETTER(reading)
+ JSReadableState_BOOLEAN_GETTER_SETTER(constructed)
+ JSReadableState_BOOLEAN_GETTER_SETTER(sync)
+ JSReadableState_BOOLEAN_GETTER_SETTER(needReadable)
+ JSReadableState_BOOLEAN_GETTER_SETTER(emittedReadable)
+ JSReadableState_BOOLEAN_GETTER_SETTER(readableListening)
+ JSReadableState_BOOLEAN_GETTER_SETTER(resumeScheduled)
+ JSReadableState_BOOLEAN_GETTER_SETTER(errorEmitted)
+ JSReadableState_BOOLEAN_GETTER_SETTER(emitClose)
+ JSReadableState_BOOLEAN_GETTER_SETTER(autoDestroy)
+ JSReadableState_BOOLEAN_GETTER_SETTER(destroyed)
+ JSReadableState_BOOLEAN_GETTER_SETTER(closed)
+ JSReadableState_BOOLEAN_GETTER_SETTER(closeEmitted)
+ JSReadableState_BOOLEAN_GETTER_SETTER(multiAwaitDrain)
+ JSReadableState_BOOLEAN_GETTER_SETTER(readingMore)
+ JSReadableState_BOOLEAN_GETTER_SETTER(dataEmitted)
+
+#undef JSReadableState_BOOLEAN_GETTER_SETTER
+
+#define JSReadableState_JSVALUE_GETTER_SETTER(NAME) \
+ static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \
+ JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \
+ { \
+ auto& vm = JSC::getVM(lexicalGlobalObject); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
+ if (!state) { \
+ RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \
+ } \
+ RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(state->m_##NAME.get())); \
+ } \
+ static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \
+ JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \
+ { \
+ auto& vm = JSC::getVM(lexicalGlobalObject); \
+ auto throwScope = DECLARE_THROW_SCOPE(vm); \
+ JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
+ if (!state) { \
+ RETURN_IF_EXCEPTION(throwScope, false); \
+ } \
+ auto value = JSC::JSValue::decode(encodedValue); \
+ state->m_##NAME.set(vm, state, value); \
+ RELEASE_AND_RETURN(throwScope, true); \
+ }
+
+ JSReadableState_JSVALUE_GETTER_SETTER(buffer)
+ JSReadableState_JSVALUE_GETTER_SETTER(pipes)
+ JSReadableState_JSVALUE_GETTER_SETTER(errored)
+ JSReadableState_JSVALUE_GETTER_SETTER(defaultEncoding)
+ JSReadableState_JSVALUE_GETTER_SETTER(awaitDrainWriters)
+ JSReadableState_JSVALUE_GETTER_SETTER(decoder)
+ JSReadableState_JSVALUE_GETTER_SETTER(encoding)
+
+#undef JSReadableState_JSVALUE_GETTER_SETTER
+
+#define JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(NAME) \
+ { \
+#NAME ""_s, static_cast < unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, \
+ { \
+ HashTableValue::GetterSetterType, jsReadableState_##NAME, setJSReadableState_##NAME \
+ } \
+ }
+
+ /* Hash table for prototype */
+ static const HashTableValue JSReadableStatePrototypeTableValues[]
+ = {
+ { "pipesCount"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableState_pipesCount, 0 } },
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(paused),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(flowing),
+
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(objectMode),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(ended),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(endEmitted),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(reading),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(constructed),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(sync),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(needReadable),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(emittedReadable),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(readableListening),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(resumeScheduled),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(errorEmitted),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(emitClose),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(autoDestroy),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(destroyed),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(closed),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(closeEmitted),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(multiAwaitDrain),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(readingMore),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(dataEmitted),
+
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(length),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(highWaterMark),
+
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(buffer),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(pipes),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(errored),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(defaultEncoding),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(awaitDrainWriters),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(decoder),
+ JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(encoding),
+ };
+
+#undef JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE
+
+void JSReadableStatePrototype::finishCreation(VM& vm, JSC::JSGlobalObject* globalThis)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSReadableState::info(), JSReadableStatePrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+const ClassInfo JSReadableStatePrototype::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStatePrototype) };
+
+void JSReadableStateConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype)
+{
+ Base::finishCreation(vm, 0, "ReadableState"_s, PropertyAdditionMode::WithoutStructureTransition);
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ ASSERT(inherits(info()));
+}
+
+JSReadableStateConstructor* JSReadableStateConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSReadableStatePrototype* prototype)
+{
+ JSReadableStateConstructor* ptr = new (NotNull, JSC::allocateCell<JSReadableStateConstructor>(vm)) JSReadableStateConstructor(vm, structure, construct);
+ ptr->finishCreation(vm, globalObject, prototype);
+ return ptr;
+}
+
+JSC::EncodedJSValue JSReadableStateConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
+{
+ JSC::VM& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ if (callFrame->argumentCount() < 3) {
+ throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
+ return JSValue::encode(jsUndefined());
+ }
+ JSValue optionsVal = callFrame->uncheckedArgument(0);
+ JSValue streamVal = callFrame->uncheckedArgument(1);
+ JSValue isDuplexVal = callFrame->uncheckedArgument(2);
+
+ bool isDuplex;
+ if (!isDuplexVal.isBoolean()) {
+ // change this to `stream instanceof Duplex` after native Duplex is implemented.
+ JSC::throwTypeError(lexicalGlobalObject, throwScope, "isDuplex should be boolean"_s);
+ return JSValue::encode(jsUndefined());
+ }
+ isDuplex = isDuplexVal.toBoolean(lexicalGlobalObject);
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ JSObject* options = nullptr;
+ if (optionsVal && optionsVal.isObject()) {
+ options = optionsVal.toObject(lexicalGlobalObject);
+ }
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+
+ JSReadableState* stringDecoder = JSReadableState::create(
+ vm, lexicalGlobalObject, reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->JSReadableStateStructure(), isDuplex, options);
+ return JSC::JSValue::encode(stringDecoder);
+}
+
+void JSReadableStateConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype)
+{
+}
+
+const ClassInfo JSReadableStateConstructor::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStateConstructor) };
+
+} // namespace Zig
diff --git a/src/bun.js/bindings/JSReadableState.h b/src/bun.js/bindings/JSReadableState.h
new file mode 100644
index 000000000..c67baebad
--- /dev/null
+++ b/src/bun.js/bindings/JSReadableState.h
@@ -0,0 +1,154 @@
+#pragma once
+
+#include "root.h"
+#include "BufferEncodingType.h"
+
+namespace WebCore {
+using namespace JSC;
+
+class JSReadableState : public JSC::JSDestructibleObject {
+ using Base = JSC::JSDestructibleObject;
+
+public:
+ JSReadableState(JSC::VM& vm, JSC::Structure* structure)
+ : Base(vm, structure)
+ , m_paused(0)
+ {
+ }
+
+ DECLARE_VISIT_CHILDREN;
+ DECLARE_INFO;
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return subspaceForImpl(vm);
+ }
+
+ static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject,
+ JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype,
+ JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ static JSReadableState* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, bool isDuplex, JSObject* options)
+ {
+ JSReadableState* accessor = new (NotNull, JSC::allocateCell<JSReadableState>(vm)) JSReadableState(vm, structure);
+ accessor->finishCreation(vm, globalObject, isDuplex, options);
+ return accessor;
+ }
+
+ void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options);
+ static void destroy(JSCell*) {}
+
+ enum Mask : uint32_t {
+ objectMode = 1 << 0,
+ emitClose = 1 << 1,
+ autoDestroy = 1 << 2,
+ ended = 1 << 3,
+ endEmitted = 1 << 4,
+ reading = 1 << 5,
+ constructed = 1 << 6,
+ sync = 1 << 7,
+ needReadable = 1 << 8,
+ emittedReadable = 1 << 9,
+ readableListening = 1 << 10,
+ resumeScheduled = 1 << 11,
+ errorEmitted = 1 << 12,
+ destroyed = 1 << 13,
+ closed = 1 << 14,
+ closeEmitted = 1 << 15,
+ multiAwaitDrain = 1 << 16,
+ readingMore = 1 << 17,
+ dataEmitted = 1 << 18,
+ };
+
+ constexpr bool getBool(Mask mask) { return m_bools.contains(mask); }
+ constexpr void setBool(Mask mask, bool val)
+ {
+ m_bools.set(mask, val);
+ }
+
+ // 0 for null, 1 for true, -1 for false
+ int8_t m_paused = 0;
+ int8_t m_flowing = 0;
+
+ WTF::OptionSet<Mask> m_bools;
+
+ int64_t m_length = 0;
+ int64_t m_highWaterMark;
+
+ mutable WriteBarrier<Unknown> m_buffer;
+ mutable WriteBarrier<Unknown> m_pipes;
+ mutable WriteBarrier<Unknown> m_errored;
+ mutable WriteBarrier<Unknown> m_defaultEncoding;
+ mutable WriteBarrier<Unknown> m_awaitDrainWriters;
+ mutable WriteBarrier<Unknown> m_decoder;
+ mutable WriteBarrier<Unknown> m_encoding;
+};
+
+class JSReadableStatePrototype : public JSC::JSNonFinalObject {
+public:
+ using Base = JSC::JSNonFinalObject;
+ static JSReadableStatePrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSReadableStatePrototype* ptr = new (NotNull, JSC::allocateCell<JSReadableStatePrototype>(vm)) JSReadableStatePrototype(vm, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+private:
+ JSReadableStatePrototype(JSC::VM& vm, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+};
+
+class JSReadableStateConstructor final : public JSC::InternalFunction {
+public:
+ using Base = JSC::InternalFunction;
+ static JSReadableStateConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSReadableStatePrototype* prototype);
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+ static constexpr bool needsDestruction = false;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
+ }
+
+ void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype);
+
+ // Must be defined for each specialization class.
+ static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+ DECLARE_EXPORT_INFO;
+
+private:
+ JSReadableStateConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
+ : Base(vm, structure, nativeFunction, nativeFunction)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype);
+};
+
+}
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 091cc0b29..6398fb7a0 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -90,6 +90,8 @@
#include "JSCloseEvent.h"
#include "JSFetchHeaders.h"
#include "JSStringDecoder.h"
+#include "JSReadableState.h"
+#include "JSReadableHelper.h"
#include "Process.h"
#include "AsyncContextFrame.h"
@@ -1626,7 +1628,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
switch (callFrame->argumentCount()) {
case 0: {
- JSC::throwTypeError(globalObject, scope, "$lazy needs 1 argument (a string)"_s);
+ JSC::throwTypeError(globalObject, scope, "lazyLoad needs 1 argument (a string)"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
@@ -1635,7 +1637,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
if (moduleName.isNumber()) {
switch (moduleName.toInt32(globalObject)) {
case 0: {
- JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s);
+ JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
@@ -1652,7 +1654,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
default: {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
- JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s);
+ JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
@@ -1661,7 +1663,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
auto string = moduleName.toWTFString(globalObject);
if (string.isNull()) {
- JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s);
+ JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
@@ -1671,6 +1673,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
}
if (string == "worker_threads"_s) {
+
JSValue workerData = jsUndefined();
JSValue threadId = jsNumber(0);
@@ -1705,6 +1708,27 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
JSFunction::create(vm, globalObject, 1, fileURLToPathString, functionFileURLToPath, ImplementationVisibility::Public, NoIntrinsic));
}
+ if (string == "bun:stream"_s) {
+ auto* obj = constructEmptyObject(globalObject);
+ obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "BufferList"_s)), reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferList(), 0);
+ obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "ReadableState"_s)), reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSReadableState(), 0);
+ obj->putDirect(
+ vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "maybeReadMore"_s)),
+ JSC::JSFunction::create(vm, globalObject, 0, "maybeReadMore"_s, jsReadable_maybeReadMore, ImplementationVisibility::Public), 0);
+ obj->putDirect(
+ vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "resume"_s)),
+ JSC::JSFunction::create(vm, globalObject, 0, "resume"_s, jsReadable_resume, ImplementationVisibility::Public), 0);
+ obj->putDirect(
+ vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "emitReadable"_s)),
+ JSC::JSFunction::create(vm, globalObject, 0, "emitReadable"_s, jsReadable_emitReadable, ImplementationVisibility::Public), 0);
+ obj->putDirect(
+ vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "onEofChunk"_s)),
+ JSC::JSFunction::create(vm, globalObject, 0, "onEofChunk"_s, jsReadable_onEofChunk, ImplementationVisibility::Public), 0);
+ return JSValue::encode(obj);
+ }
+ if (string == "events"_s) {
+ return JSValue::encode(WebCore::JSEventEmitter::getConstructor(vm, globalObject));
+ }
if (string == "internal/tls"_s) {
auto* obj = constructEmptyObject(globalObject);
@@ -1735,9 +1759,9 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
return JSValue::encode(obj);
}
- // if (string == "masqueradesAsUndefined"_s) {
- // return JSValue::encode(InternalFunction::createFunctionThatMasqueradesAsUndefined(vm, globalObject, 0, String(), functionCallNotImplemented));
- // }
+ if (string == "masqueradesAsUndefined"_s) {
+ return JSValue::encode(InternalFunction::createFunctionThatMasqueradesAsUndefined(vm, globalObject, 0, String(), functionCallNotImplemented));
+ }
if (string == "vm"_s) {
auto* obj = constructEmptyObject(globalObject);
@@ -1794,9 +1818,9 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
return JSC::JSValue::encode(obj);
}
- JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s);
- scope.release();
- return JSC::JSValue::encode(JSC::JSValue {});
+ return JSC::JSValue::encode(JSC::jsUndefined());
+
+ break;
}
}
}
@@ -2981,6 +3005,10 @@ void GlobalObject::finishCreation(VM& vm)
[](const Initializer<JSFunction>& init) {
init.set(JSFunction::create(init.vm, init.owner, 4, "performMicrotask"_s, jsFunctionPerformMicrotask, ImplementationVisibility::Public));
});
+ m_emitReadableNextTickFunction.initLater(
+ [](const Initializer<JSFunction>& init) {
+ init.set(JSFunction::create(init.vm, init.owner, 4, "emitReadable"_s, WebCore::jsReadable_emitReadable_, ImplementationVisibility::Public));
+ });
m_bunSleepThenCallback.initLater(
[](const Initializer<JSFunction>& init) {
@@ -3295,6 +3323,18 @@ void GlobalObject::finishCreation(VM& vm)
init.setConstructor(constructor);
});
+ m_JSReadableStateClassStructure.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ auto* prototype = JSReadableStatePrototype::create(
+ init.vm, init.global, JSReadableStatePrototype::createStructure(init.vm, init.global, init.global->objectPrototype()));
+ auto* structure = JSReadableState::createStructure(init.vm, init.global, prototype);
+ auto* constructor = JSReadableStateConstructor::create(
+ init.vm, init.global, JSReadableStateConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), prototype);
+ init.setPrototype(prototype);
+ init.setStructure(structure);
+ init.setConstructor(constructor);
+ });
+
m_JSFFIFunctionStructure.initLater(
[](LazyClassStructure::Initializer& init) {
init.setStructure(Zig::JSFFIFunction::createStructure(init.vm, init.global, init.global->functionPrototype()));
@@ -4084,6 +4124,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_JSFileSinkClassStructure.visit(visitor);
thisObject->m_JSHTTPResponseSinkClassStructure.visit(visitor);
thisObject->m_JSHTTPSResponseSinkClassStructure.visit(visitor);
+ thisObject->m_JSReadableStateClassStructure.visit(visitor);
thisObject->m_JSStringDecoderClassStructure.visit(visitor);
thisObject->m_NapiClassStructure.visit(visitor);
thisObject->m_JSBufferClassStructure.visit(visitor);
@@ -4109,6 +4150,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_subtleCryptoObject.visit(visitor);
thisObject->m_JSHTTPResponseController.visit(visitor);
thisObject->m_callSiteStructure.visit(visitor);
+ thisObject->m_emitReadableNextTickFunction.visit(visitor);
thisObject->m_JSBufferSubclassStructure.visit(visitor);
thisObject->m_cryptoObject.visit(visitor);
thisObject->m_JSDOMFileConstructor.visit(visitor);
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index 7377e6693..29c1cd09c 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -238,6 +238,10 @@ public:
JSC::JSObject* JSStringDecoder() { return m_JSStringDecoderClassStructure.constructorInitializedOnMainThread(this); }
JSC::JSValue JSStringDecoderPrototype() { return m_JSStringDecoderClassStructure.prototypeInitializedOnMainThread(this); }
+ JSC::Structure* JSReadableStateStructure() { return m_JSReadableStateClassStructure.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSReadableState() { return m_JSReadableStateClassStructure.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSReadableStatePrototype() { return m_JSReadableStateClassStructure.prototypeInitializedOnMainThread(this); }
+
JSC::Structure* NodeVMScriptStructure() { return m_NodeVMScriptClassStructure.getInitializedOnMainThread(this); }
JSC::JSObject* NodeVMScript() { return m_NodeVMScriptClassStructure.constructorInitializedOnMainThread(this); }
JSC::JSValue NodeVMScriptPrototype() { return m_NodeVMScriptClassStructure.prototypeInitializedOnMainThread(this); }
@@ -257,6 +261,8 @@ public:
JSC::JSFunction* utilInspectStylizeColorFunction() { return m_utilInspectStylizeColorFunction.getInitializedOnMainThread(this); }
JSC::JSFunction* utilInspectStylizeNoColorFunction() { return m_utilInspectStylizeNoColorFunction.getInitializedOnMainThread(this); }
+ JSC::JSFunction* emitReadableNextTickFunction() { return m_emitReadableNextTickFunction.getInitializedOnMainThread(this); }
+
JSObject* requireFunctionUnbound() { return m_requireFunctionUnbound.getInitializedOnMainThread(this); }
JSObject* requireResolveFunctionUnbound() { return m_requireResolveFunctionUnbound.getInitializedOnMainThread(this); }
Bun::InternalModuleRegistry* internalModuleRegistry() { return m_internalModuleRegistry.getInitializedOnMainThread(this); }
@@ -500,6 +506,7 @@ private:
LazyClassStructure m_JSFileSinkClassStructure;
LazyClassStructure m_JSHTTPResponseSinkClassStructure;
LazyClassStructure m_JSHTTPSResponseSinkClassStructure;
+ LazyClassStructure m_JSReadableStateClassStructure;
LazyClassStructure m_JSStringDecoderClassStructure;
LazyClassStructure m_NapiClassStructure;
LazyClassStructure m_callSiteStructure;
@@ -523,7 +530,7 @@ private:
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectStylizeColorFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectStylizeNoColorFunction;
-
+ LazyProperty<JSGlobalObject, JSFunction> m_emitReadableNextTickFunction;
LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap;
LazyProperty<JSGlobalObject, JSMap> m_requireMap;
LazyProperty<JSGlobalObject, Structure> m_encodeIntoObjectStructure;