aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/bindings/headers-cpp.h2
-rw-r--r--src/bun.js/bindings/headers.h2
-rw-r--r--src/bun.js/bindings/webcore/JSEventEmitter.cpp53
-rw-r--r--src/bun.js/bindings/webcore/JSEventEmitter.h2
-rw-r--r--src/bun.js/builtins/cpp/NodeEventsBuiltins.cpp111
-rw-r--r--src/bun.js/builtins/cpp/NodeEventsBuiltins.h9
-rw-r--r--src/bun.js/builtins/js/NodeEvents.js100
-rw-r--r--src/bun.js/modules/EventsModule.h11
8 files changed, 206 insertions, 84 deletions
diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h
index 5eac6785d..fcf694b8e 100644
--- a/src/bun.js/bindings/headers-cpp.h
+++ b/src/bun.js/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1680635796
+//-- AUTOGENERATED FILE -- 1680843050
// clang-format off
#pragma once
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index 5b0e9527c..b842848da 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1680635796
+//-- AUTOGENERATED FILE -- 1680843050
#pragma once
#include <stddef.h>
diff --git a/src/bun.js/bindings/webcore/JSEventEmitter.cpp b/src/bun.js/bindings/webcore/JSEventEmitter.cpp
index aa9fb4832..2a573b3b5 100644
--- a/src/bun.js/bindings/webcore/JSEventEmitter.cpp
+++ b/src/bun.js/bindings/webcore/JSEventEmitter.cpp
@@ -573,57 +573,4 @@ JSC_DEFINE_HOST_FUNCTION(Events_functionListenerCount,
RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(impl.listenerCount(eventType))));
}
-JSC_DEFINE_HOST_FUNCTION(Events_functionOnce,
- (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
-{
- auto& vm = JSC::getVM(lexicalGlobalObject);
- auto throwScope = DECLARE_THROW_SCOPE(vm);
- UNUSED_PARAM(throwScope);
- UNUSED_PARAM(callFrame);
-
- if (UNLIKELY(callFrame->argumentCount() < 3))
- return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
- auto argument0 = jsEventEmitterCastFast(vm, lexicalGlobalObject, callFrame->uncheckedArgument(0));
- if (UNLIKELY(!argument0)) {
- throwException(lexicalGlobalObject, throwScope, createError(lexicalGlobalObject, "Expected EventEmitter"_s));
- return JSValue::encode(JSC::jsUndefined());
- }
- auto& impl = argument0->wrapped();
- auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject);
- RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- EnsureStillAliveScope argument2 = callFrame->uncheckedArgument(2);
- auto listener = convert<IDLNullable<IDLEventListener<JSEventListener>>>(*lexicalGlobalObject, argument2.value(), *argument0, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 2, "listener", "EventEmitter", "removeListener"); });
- RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- vm.writeBarrier(argument0, argument2.value());
- RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(argument0));
-}
-
-// JSC_DEFINE_HOST_FUNCTION(Events_functionOn,
-// (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
-// {
-// auto& vm = JSC::getVM(lexicalGlobalObject);
-// auto throwScope = DECLARE_THROW_SCOPE(vm);
-// UNUSED_PARAM(throwScope);
-// UNUSED_PARAM(callFrame);
-
-// if (UNLIKELY(callFrame->argumentCount() < 3))
-// return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
-// auto argument0 = jsEventEmitterCastFast(vm, lexicalGlobalObject, callFrame->uncheckedArgument(0));
-// if (UNLIKELY(!argument0)) {
-// throwException(lexicalGlobalObject, throwScope, createError(lexicalGlobalObject, "Expected EventEmitter"_s));
-// return JSValue::encode(JSC::jsUndefined());
-// }
-// auto& impl = argument0->wrapped();
-// auto eventType = callFrame->uncheckedArgument(1).toPropertyKey(lexicalGlobalObject);
-// RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-// EnsureStillAliveScope argument2 = callFrame->uncheckedArgument(2);
-// auto listener = convert<IDLNullable<IDLEventListener<JSEventListener>>>(*lexicalGlobalObject, argument2.value(), *argument0, [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeObjectError(lexicalGlobalObject, scope, 2, "listener", "EventEmitter", "removeListener"); });
-// RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-// auto result = JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.addListenerForBindings(WTFMove(eventType), WTFMove(listener), false, false); }));
-// RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-// vm.writeBarrier(argument0, argument2.value());
-// return result;
-// }
-
}
diff --git a/src/bun.js/bindings/webcore/JSEventEmitter.h b/src/bun.js/bindings/webcore/JSEventEmitter.h
index 855241011..d09854afd 100644
--- a/src/bun.js/bindings/webcore/JSEventEmitter.h
+++ b/src/bun.js/bindings/webcore/JSEventEmitter.h
@@ -9,8 +9,6 @@ namespace WebCore {
JSC_DECLARE_HOST_FUNCTION(Events_functionGetEventListeners);
JSC_DECLARE_HOST_FUNCTION(Events_functionListenerCount);
-JSC_DECLARE_HOST_FUNCTION(Events_functionOnce);
-JSC_DECLARE_HOST_FUNCTION(Events_functionOn);
class JSEventEmitter : public JSDOMWrapper<EventEmitter> {
public:
diff --git a/src/bun.js/builtins/cpp/NodeEventsBuiltins.cpp b/src/bun.js/builtins/cpp/NodeEventsBuiltins.cpp
index dca0ee431..852dfd6ee 100644
--- a/src/bun.js/builtins/cpp/NodeEventsBuiltins.cpp
+++ b/src/bun.js/builtins/cpp/NodeEventsBuiltins.cpp
@@ -51,7 +51,7 @@ namespace WebCore {
const JSC::ConstructAbility s_nodeEventsOnAsyncIteratorCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
const JSC::ConstructorKind s_nodeEventsOnAsyncIteratorCodeConstructorKind = JSC::ConstructorKind::None;
const JSC::ImplementationVisibility s_nodeEventsOnAsyncIteratorCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
-const int s_nodeEventsOnAsyncIteratorCodeLength = 4455;
+const int s_nodeEventsOnAsyncIteratorCodeLength = 4565;
static const JSC::Intrinsic s_nodeEventsOnAsyncIteratorCodeIntrinsic = JSC::NoIntrinsic;
const char* const s_nodeEventsOnAsyncIteratorCode =
"(function (emitter, event, options) {\n" \
@@ -59,18 +59,21 @@ const char* const s_nodeEventsOnAsyncIteratorCode =
"\n" \
" var { AbortSignal, Symbol, Number, Error } = globalThis;\n" \
"\n" \
- " var AbortError = class AbortError extends Error {\n" \
- " constructor(message = \"The operation was aborted\", options = void 0) {\n" \
- " if (options !== void 0 && typeof options !== \"object\") {\n" \
- " throw new Error(`Invalid AbortError options:\\n" \
+ " function makeAbortError(msg, opts = void 0) {\n" \
+ " var AbortError = class AbortError extends Error {\n" \
+ " constructor(message = \"The operation was aborted\", options = void 0) {\n" \
+ " if (options !== void 0 && typeof options !== \"object\") {\n" \
+ " throw new Error(`Invalid AbortError options:\\n" \
"\\n" \
"${JSON.stringify(options, null, 2)}`);\n" \
+ " }\n" \
+ " super(message, options);\n" \
+ " this.code = \"ABORT_ERR\";\n" \
+ " this.name = \"AbortError\";\n" \
" }\n" \
- " super(message, options);\n" \
- " this.code = \"ABORT_ERR\";\n" \
- " this.name = \"AbortError\";\n" \
- " }\n" \
- " };\n" \
+ " };\n" \
+ " return new AbortError(msg, opts);\n" \
+ " }\n" \
"\n" \
" if (@isUndefinedOrNull(emitter)) @throwTypeError(\"emitter is required\");\n" \
" //\n" \
@@ -86,7 +89,7 @@ const char* const s_nodeEventsOnAsyncIteratorCode =
"\n" \
" if (signal?.aborted) {\n" \
" //\n" \
- " throw new AbortError(@undefined, { cause: signal?.reason });\n" \
+ " throw makeAbortError(@undefined, { cause: signal?.reason });\n" \
" }\n" \
"\n" \
" var highWatermark = options.highWatermark ?? Number.MAX_SAFE_INTEGER;\n" \
@@ -107,7 +110,7 @@ const char* const s_nodeEventsOnAsyncIteratorCode =
" var listeners = [];\n" \
"\n" \
" function abortListener() {\n" \
- " errorHandler(new AbortError(@undefined, { cause: signal?.reason }));\n" \
+ " errorHandler(makeAbortError(@undefined, { cause: signal?.reason }));\n" \
" }\n" \
"\n" \
" function eventHandler(value) {\n" \
@@ -222,6 +225,90 @@ const char* const s_nodeEventsOnAsyncIteratorCode =
"})\n" \
;
+const JSC::ConstructAbility s_nodeEventsOncePromiseCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
+const JSC::ConstructorKind s_nodeEventsOncePromiseCodeConstructorKind = JSC::ConstructorKind::None;
+const JSC::ImplementationVisibility s_nodeEventsOncePromiseCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
+const int s_nodeEventsOncePromiseCodeLength = 2418;
+static const JSC::Intrinsic s_nodeEventsOncePromiseCodeIntrinsic = JSC::NoIntrinsic;
+const char* const s_nodeEventsOncePromiseCode =
+ "(function (emitter, name, options) {\n" \
+ " \"use strict\";\n" \
+ "\n" \
+ " var { AbortSignal, Error } = globalThis;\n" \
+ "\n" \
+ " function makeAbortError(msg, opts = void 0) {\n" \
+ " var AbortError = class AbortError extends Error {\n" \
+ " constructor(message = \"The operation was aborted\", options = void 0) {\n" \
+ " if (options !== void 0 && typeof options !== \"object\") {\n" \
+ " throw new Error(`Invalid AbortError options:\\n" \
+ "\\n" \
+ "${JSON.stringify(options, null, 2)}`);\n" \
+ " }\n" \
+ " super(message, options);\n" \
+ " this.code = \"ABORT_ERR\";\n" \
+ " this.name = \"AbortError\";\n" \
+ " }\n" \
+ " };\n" \
+ " return new AbortError(msg, opts);\n" \
+ " }\n" \
+ "\n" \
+ " if (@isUndefinedOrNull(emitter)) return @Promise.@reject(@makeTypeError(\"emitter is required\"));\n" \
+ " //\n" \
+ " if (!(@isObject(emitter) && @isCallable(emitter.emit) && @isCallable(emitter.on)))\n" \
+ " return @Promise.@reject(@makeTypeError(\"emitter must be an EventEmitter\"));\n" \
+ "\n" \
+ " if (@isUndefinedOrNull(options)) options = {};\n" \
+ "\n" \
+ " //\n" \
+ " var signal = options.signal;\n" \
+ " if (signal !== @undefined && (!@isObject(signal) || !(signal instanceof AbortSignal)))\n" \
+ " return @Promise.@reject(@makeTypeError(\"options.signal must be an AbortSignal\"));\n" \
+ "\n" \
+ " if (signal?.aborted) {\n" \
+ " //\n" \
+ " return @Promise.@reject(makeAbortError(@undefined, { cause: signal?.reason }));\n" \
+ " }\n" \
+ "\n" \
+ " var eventPromiseCapability = @newPromiseCapability(@Promise);\n" \
+ "\n" \
+ " var errorListener = (err) => {\n" \
+ " emitter.removeListener(name, resolver);\n" \
+ " if (!@isUndefinedOrNull(signal)) {\n" \
+ " signal.removeEventListener(\"abort\", abortListener);\n" \
+ " }\n" \
+ " eventPromiseCapability.@reject.@call(@undefined, err);\n" \
+ " };\n" \
+ "\n" \
+ " var resolver = (...args) => {\n" \
+ " if (@isCallable(emitter.removeListener)) {\n" \
+ " emitter.removeListener(\"error\", errorListener);\n" \
+ " }\n" \
+ " if (!@isUndefinedOrNull(signal)) {\n" \
+ " signal.removeEventListener(\"abort\", abortListener);\n" \
+ " }\n" \
+ " eventPromiseCapability.@resolve.@call(@undefined, args);\n" \
+ " };\n" \
+ " \n" \
+ " emitter.once(name, resolver);\n" \
+ " if (name !== \"error\" && @isCallable(emitter.once)) {\n" \
+ " //\n" \
+ " //\n" \
+ " emitter.once(\"error\", errorListener);\n" \
+ " }\n" \
+ "\n" \
+ " function abortListener() {\n" \
+ " emitter.removeListener(name, resolver);\n" \
+ " emitter.removeListener(\"error\", errorListener);\n" \
+ " eventPromiseCapability.@reject.@call(@undefined, makeAbortError(@undefined, { cause: signal?.reason }));\n" \
+ " }\n" \
+ "\n" \
+ " if (!@isUndefinedOrNull(signal))\n" \
+ " signal.addEventListener(\"abort\", abortListener, { once: true });\n" \
+ "\n" \
+ " return eventPromiseCapability.@promise;\n" \
+ "})\n" \
+;
+
#define DEFINE_BUILTIN_GENERATOR(codeName, functionName, overriddenName, argumentCount) \
JSC::FunctionExecutable* codeName##Generator(JSC::VM& vm) \
diff --git a/src/bun.js/builtins/cpp/NodeEventsBuiltins.h b/src/bun.js/builtins/cpp/NodeEventsBuiltins.h
index 11b70ea92..6a3f15403 100644
--- a/src/bun.js/builtins/cpp/NodeEventsBuiltins.h
+++ b/src/bun.js/builtins/cpp/NodeEventsBuiltins.h
@@ -52,17 +52,26 @@ extern const int s_nodeEventsOnAsyncIteratorCodeLength;
extern const JSC::ConstructAbility s_nodeEventsOnAsyncIteratorCodeConstructAbility;
extern const JSC::ConstructorKind s_nodeEventsOnAsyncIteratorCodeConstructorKind;
extern const JSC::ImplementationVisibility s_nodeEventsOnAsyncIteratorCodeImplementationVisibility;
+extern const char* const s_nodeEventsOncePromiseCode;
+extern const int s_nodeEventsOncePromiseCodeLength;
+extern const JSC::ConstructAbility s_nodeEventsOncePromiseCodeConstructAbility;
+extern const JSC::ConstructorKind s_nodeEventsOncePromiseCodeConstructorKind;
+extern const JSC::ImplementationVisibility s_nodeEventsOncePromiseCodeImplementationVisibility;
#define WEBCORE_FOREACH_NODEEVENTS_BUILTIN_DATA(macro) \
macro(onAsyncIterator, nodeEventsOnAsyncIterator, 3) \
+ macro(oncePromise, nodeEventsOncePromise, 3) \
#define WEBCORE_BUILTIN_NODEEVENTS_ONASYNCITERATOR 1
+#define WEBCORE_BUILTIN_NODEEVENTS_ONCEPROMISE 1
#define WEBCORE_FOREACH_NODEEVENTS_BUILTIN_CODE(macro) \
macro(nodeEventsOnAsyncIteratorCode, onAsyncIterator, ASCIILiteral(), s_nodeEventsOnAsyncIteratorCodeLength) \
+ macro(nodeEventsOncePromiseCode, oncePromise, ASCIILiteral(), s_nodeEventsOncePromiseCodeLength) \
#define WEBCORE_FOREACH_NODEEVENTS_BUILTIN_FUNCTION_NAME(macro) \
macro(onAsyncIterator) \
+ macro(oncePromise) \
#define DECLARE_BUILTIN_GENERATOR(codeName, functionName, overriddenName, argumentCount) \
JSC::FunctionExecutable* codeName##Generator(JSC::VM&);
diff --git a/src/bun.js/builtins/js/NodeEvents.js b/src/bun.js/builtins/js/NodeEvents.js
index ded8d1af7..14af767bf 100644
--- a/src/bun.js/builtins/js/NodeEvents.js
+++ b/src/bun.js/builtins/js/NodeEvents.js
@@ -28,16 +28,19 @@ function onAsyncIterator(emitter, event, options) {
var { AbortSignal, Symbol, Number, Error } = globalThis;
- var AbortError = class AbortError extends Error {
- constructor(message = "The operation was aborted", options = void 0) {
- if (options !== void 0 && typeof options !== "object") {
- throw new Error(`Invalid AbortError options:\n\n${JSON.stringify(options, null, 2)}`);
+ function makeAbortError(msg, opts = void 0) {
+ var AbortError = class AbortError extends Error {
+ constructor(message = "The operation was aborted", options = void 0) {
+ if (options !== void 0 && typeof options !== "object") {
+ throw new Error(`Invalid AbortError options:\n\n${JSON.stringify(options, null, 2)}`);
+ }
+ super(message, options);
+ this.code = "ABORT_ERR";
+ this.name = "AbortError";
}
- super(message, options);
- this.code = "ABORT_ERR";
- this.name = "AbortError";
- }
- };
+ };
+ return new AbortError(msg, opts);
+ }
if (@isUndefinedOrNull(emitter)) @throwTypeError("emitter is required");
// TODO: Do a more accurate check
@@ -53,7 +56,7 @@ function onAsyncIterator(emitter, event, options) {
if (signal?.aborted) {
// TODO: Make this a builtin
- throw new AbortError(@undefined, { cause: signal?.reason });
+ throw makeAbortError(@undefined, { cause: signal?.reason });
}
var highWatermark = options.highWatermark ?? Number.MAX_SAFE_INTEGER;
@@ -74,7 +77,7 @@ function onAsyncIterator(emitter, event, options) {
var listeners = [];
function abortListener() {
- errorHandler(new AbortError(@undefined, { cause: signal?.reason }));
+ errorHandler(makeAbortError(@undefined, { cause: signal?.reason }));
}
function eventHandler(value) {
@@ -187,3 +190,78 @@ function onAsyncIterator(emitter, event, options) {
});
return iterator;
}
+
+function oncePromise(emitter, name, options) {
+ "use strict";
+
+ var { AbortSignal, Error } = globalThis;
+
+ function makeAbortError(msg, opts = void 0) {
+ var AbortError = class AbortError extends Error {
+ constructor(message = "The operation was aborted", options = void 0) {
+ if (options !== void 0 && typeof options !== "object") {
+ throw new Error(`Invalid AbortError options:\n\n${JSON.stringify(options, null, 2)}`);
+ }
+ super(message, options);
+ this.code = "ABORT_ERR";
+ this.name = "AbortError";
+ }
+ };
+ return new AbortError(msg, opts);
+ }
+
+ if (@isUndefinedOrNull(emitter)) return @Promise.@reject(@makeTypeError("emitter is required"));
+ // TODO: Do a more accurate check
+ if (!(@isObject(emitter) && @isCallable(emitter.emit) && @isCallable(emitter.on)))
+ return @Promise.@reject(@makeTypeError("emitter must be an EventEmitter"));
+
+ if (@isUndefinedOrNull(options)) options = {};
+
+ // Parameters validation
+ var signal = options.signal;
+ if (signal !== @undefined && (!@isObject(signal) || !(signal instanceof AbortSignal)))
+ return @Promise.@reject(@makeTypeError("options.signal must be an AbortSignal"));
+
+ if (signal?.aborted) {
+ // TODO: Make this a builtin
+ return @Promise.@reject(makeAbortError(@undefined, { cause: signal?.reason }));
+ }
+
+ var eventPromiseCapability = @newPromiseCapability(@Promise);
+
+ var errorListener = (err) => {
+ emitter.removeListener(name, resolver);
+ if (!@isUndefinedOrNull(signal)) {
+ signal.removeEventListener("abort", abortListener);
+ }
+ eventPromiseCapability.@reject.@call(@undefined, err);
+ };
+
+ var resolver = (...args) => {
+ if (@isCallable(emitter.removeListener)) {
+ emitter.removeListener("error", errorListener);
+ }
+ if (!@isUndefinedOrNull(signal)) {
+ signal.removeEventListener("abort", abortListener);
+ }
+ eventPromiseCapability.@resolve.@call(@undefined, args);
+ };
+
+ emitter.once(name, resolver);
+ if (name !== "error" && @isCallable(emitter.once)) {
+ // EventTarget does not have `error` event semantics like Node
+ // EventEmitters, we listen to `error` events only on EventEmitters.
+ emitter.once("error", errorListener);
+ }
+
+ function abortListener() {
+ emitter.removeListener(name, resolver);
+ emitter.removeListener("error", errorListener);
+ eventPromiseCapability.@reject.@call(@undefined, makeAbortError(@undefined, { cause: signal?.reason }));
+ }
+
+ if (!@isUndefinedOrNull(signal))
+ signal.addEventListener("abort", abortListener, { once: true });
+
+ return eventPromiseCapability.@promise;
+}
diff --git a/src/bun.js/modules/EventsModule.h b/src/bun.js/modules/EventsModule.h
index e60624ac9..15981fcca 100644
--- a/src/bun.js/modules/EventsModule.h
+++ b/src/bun.js/modules/EventsModule.h
@@ -24,10 +24,6 @@ inline void generateEventsSourceCode(JSC::JSGlobalObject *lexicalGlobalObject,
exportValues.append(JSC::JSFunction::create(
vm, lexicalGlobalObject, 0, MAKE_STATIC_STRING_IMPL("listenerCount"),
Events_functionListenerCount, ImplementationVisibility::Public));
- exportNames.append(JSC::Identifier::fromString(vm, "once"_s));
- exportValues.append(JSC::JSFunction::create(
- vm, lexicalGlobalObject, 0, MAKE_STATIC_STRING_IMPL("once"),
- Events_functionOnce, ImplementationVisibility::Public));
exportNames.append(
JSC::Identifier::fromString(vm, "captureRejectionSymbol"_s));
exportValues.append(Symbol::create(
@@ -48,6 +44,13 @@ inline void generateEventsSourceCode(JSC::JSGlobalObject *lexicalGlobalObject,
PropertyAttribute::Builtin | PropertyAttribute::DontDelete);
exportValues.append(onAsyncIterFnPtr);
+ exportNames.append(JSC::Identifier::fromString(vm, "once"_s));
+ auto *oncePromiseFnPtr = eventEmitterModuleCJS->putDirectBuiltinFunction(
+ vm, globalObject, JSC::Identifier::fromString(vm, "once"_s),
+ nodeEventsOncePromiseCodeGenerator(vm),
+ PropertyAttribute::Builtin | PropertyAttribute::DontDelete);
+ exportValues.append(oncePromiseFnPtr);
+
eventEmitterModuleCJS->putDirect(
vm,
PropertyName(