aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/bindings/JSBundlerPlugin.cpp3
-rw-r--r--src/bun.js/bindings/Process.cpp290
-rw-r--r--src/bun.js/bindings/Process.h2
-rw-r--r--src/bun.js/bindings/ScriptExecutionContext.cpp6
-rw-r--r--src/bun.js/bindings/ScriptExecutionContext.h8
-rw-r--r--src/bun.js/bindings/bindings.cpp14
-rw-r--r--src/bun.js/bindings/exports.zig43
-rw-r--r--src/bun.js/bindings/webcore/EventEmitter.cpp7
-rw-r--r--src/bun.js/bindings/webcore/EventEmitter.h6
-rw-r--r--src/bun.js/bindings/webcore/JSEventEmitter.cpp15
-rw-r--r--src/bun.js/bindings/webcore/JSEventEmitter.h3
-rw-r--r--src/bun.js/test/pretty_format.zig42
12 files changed, 305 insertions, 134 deletions
diff --git a/src/bun.js/bindings/JSBundlerPlugin.cpp b/src/bun.js/bindings/JSBundlerPlugin.cpp
index d55c5fc2e..ec3933574 100644
--- a/src/bun.js/bindings/JSBundlerPlugin.cpp
+++ b/src/bun.js/bindings/JSBundlerPlugin.cpp
@@ -157,7 +157,8 @@ public:
JSC::LazyProperty<JSBundlerPlugin, JSC::JSFunction> setupFunction;
private:
- JSBundlerPlugin(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure, void* config, BunPluginTarget target, JSBundlerPluginAddErrorCallback addError, JSBundlerPluginOnLoadAsyncCallback onLoadAsync, JSBundlerPluginOnResolveAsyncCallback onResolveAsync)
+ JSBundlerPlugin(JSC::VM& vm, JSC::JSGlobalObject*, JSC::Structure* structure, void* config, BunPluginTarget target,
+ JSBundlerPluginAddErrorCallback addError, JSBundlerPluginOnLoadAsyncCallback onLoadAsync, JSBundlerPluginOnResolveAsyncCallback onResolveAsync)
: JSC::JSNonFinalObject(vm, structure)
, plugin(BundlerPlugin(config, target, addError, onLoadAsync, onResolveAsync))
{
diff --git a/src/bun.js/bindings/Process.cpp b/src/bun.js/bindings/Process.cpp
index 7d7bdd982..f9fb85b95 100644
--- a/src/bun.js/bindings/Process.cpp
+++ b/src/bun.js/bindings/Process.cpp
@@ -437,91 +437,215 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionChdir,
return JSC::JSValue::encode(result);
}
-// static const NeverDestroyed<String> signalNames[] = {
-// MAKE_STATIC_STRING_IMPL("SIGHUP"),
-// MAKE_STATIC_STRING_IMPL("SIGINT"),
-// MAKE_STATIC_STRING_IMPL("SIGQUIT"),
-// MAKE_STATIC_STRING_IMPL("SIGILL"),
-// MAKE_STATIC_STRING_IMPL("SIGTRAP"),
-// MAKE_STATIC_STRING_IMPL("SIGABRT"),
-// MAKE_STATIC_STRING_IMPL("SIGIOT"),
-// MAKE_STATIC_STRING_IMPL("SIGBUS"),
-// MAKE_STATIC_STRING_IMPL("SIGFPE"),
-// MAKE_STATIC_STRING_IMPL("SIGKILL"),
-// MAKE_STATIC_STRING_IMPL("SIGUSR1"),
-// MAKE_STATIC_STRING_IMPL("SIGSEGV"),
-// MAKE_STATIC_STRING_IMPL("SIGUSR2"),
-// MAKE_STATIC_STRING_IMPL("SIGPIPE"),
-// MAKE_STATIC_STRING_IMPL("SIGALRM"),
-// MAKE_STATIC_STRING_IMPL("SIGTERM"),
-// MAKE_STATIC_STRING_IMPL("SIGCHLD"),
-// MAKE_STATIC_STRING_IMPL("SIGCONT"),
-// MAKE_STATIC_STRING_IMPL("SIGSTOP"),
-// MAKE_STATIC_STRING_IMPL("SIGTSTP"),
-// MAKE_STATIC_STRING_IMPL("SIGTTIN"),
-// MAKE_STATIC_STRING_IMPL("SIGTTOU"),
-// MAKE_STATIC_STRING_IMPL("SIGURG"),
-// MAKE_STATIC_STRING_IMPL("SIGXCPU"),
-// MAKE_STATIC_STRING_IMPL("SIGXFSZ"),
-// MAKE_STATIC_STRING_IMPL("SIGVTALRM"),
-// MAKE_STATIC_STRING_IMPL("SIGPROF"),
-// MAKE_STATIC_STRING_IMPL("SIGWINCH"),
-// MAKE_STATIC_STRING_IMPL("SIGIO"),
-// MAKE_STATIC_STRING_IMPL("SIGINFO"),
-// MAKE_STATIC_STRING_IMPL("SIGSYS"),
-// };
-// static const int signalNumbers[] = {
-// SIGHUP,
-// SIGINT,
-// SIGQUIT,
-// SIGILL,
-// SIGTRAP,
-// SIGABRT,
-// SIGIOT,
-// SIGBUS,
-// SIGFPE,
-// SIGKILL,
-// SIGUSR1,
-// SIGSEGV,
-// SIGUSR2,
-// SIGPIPE,
-// SIGALRM,
-// SIGTERM,
-// SIGCHLD,
-// SIGCONT,
-// SIGSTOP,
-// SIGTSTP,
-// SIGTTIN,
-// SIGTTOU,
-// SIGURG,
-// SIGXCPU,
-// SIGXFSZ,
-// SIGVTALRM,
-// SIGPROF,
-// SIGWINCH,
-// SIGIO,
-// SIGINFO,
-// SIGSYS,
-// };
-
-// JSC_DEFINE_HOST_FUNCTION(jsFunctionProcessOn, (JSGlobalObject * globalObject, CallFrame* callFrame))
-// {
-// VM& vm = globalObject->vm();
-// auto scope = DECLARE_THROW_SCOPE(vm);
-
-// if (callFrame->argumentCount() < 2) {
-// throwVMError(globalObject, scope, "Not enough arguments"_s);
-// return JSValue::encode(jsUndefined());
-// }
-
-// String eventName = callFrame->uncheckedArgument(0).toWTFString(globalObject);
-// RETURN_IF_EXCEPTION(scope, encodedJSValue());
-// }
+static HashMap<String, int>* signalNameToNumberMap = nullptr;
+static HashMap<int, String>* signalNumberToNameMap = nullptr;
+
+// signal number to array of script execution context ids that care about the signal
+static HashMap<int, HashSet<uint32_t>>* signalToContextIdsMap = nullptr;
+static Lock signalToContextIdsMapLock;
+
+static void onDidChangeListeners(EventEmitter& eventEmitter, const Identifier& eventName, bool isAdded)
+{
+
+ static const NeverDestroyed<String> signalNames[] = {
+ MAKE_STATIC_STRING_IMPL("SIGHUP"),
+ MAKE_STATIC_STRING_IMPL("SIGINT"),
+ MAKE_STATIC_STRING_IMPL("SIGQUIT"),
+ MAKE_STATIC_STRING_IMPL("SIGILL"),
+ MAKE_STATIC_STRING_IMPL("SIGTRAP"),
+ MAKE_STATIC_STRING_IMPL("SIGABRT"),
+ MAKE_STATIC_STRING_IMPL("SIGIOT"),
+ MAKE_STATIC_STRING_IMPL("SIGBUS"),
+ MAKE_STATIC_STRING_IMPL("SIGFPE"),
+ MAKE_STATIC_STRING_IMPL("SIGKILL"),
+ MAKE_STATIC_STRING_IMPL("SIGUSR1"),
+ MAKE_STATIC_STRING_IMPL("SIGSEGV"),
+ MAKE_STATIC_STRING_IMPL("SIGUSR2"),
+ MAKE_STATIC_STRING_IMPL("SIGPIPE"),
+ MAKE_STATIC_STRING_IMPL("SIGALRM"),
+ MAKE_STATIC_STRING_IMPL("SIGTERM"),
+ MAKE_STATIC_STRING_IMPL("SIGCHLD"),
+ MAKE_STATIC_STRING_IMPL("SIGCONT"),
+ MAKE_STATIC_STRING_IMPL("SIGSTOP"),
+ MAKE_STATIC_STRING_IMPL("SIGTSTP"),
+ MAKE_STATIC_STRING_IMPL("SIGTTIN"),
+ MAKE_STATIC_STRING_IMPL("SIGTTOU"),
+ MAKE_STATIC_STRING_IMPL("SIGURG"),
+ MAKE_STATIC_STRING_IMPL("SIGXCPU"),
+ MAKE_STATIC_STRING_IMPL("SIGXFSZ"),
+ MAKE_STATIC_STRING_IMPL("SIGVTALRM"),
+ MAKE_STATIC_STRING_IMPL("SIGPROF"),
+ MAKE_STATIC_STRING_IMPL("SIGWINCH"),
+ MAKE_STATIC_STRING_IMPL("SIGIO"),
+ MAKE_STATIC_STRING_IMPL("SIGINFO"),
+ MAKE_STATIC_STRING_IMPL("SIGSYS"),
+ };
+
+ static std::once_flag signalNameToNumberMapOnceFlag;
+ std::call_once(signalNameToNumberMapOnceFlag, [] {
+ signalNameToNumberMap = new HashMap<String, int>();
+ signalNameToNumberMap->reserveInitialCapacity(31);
+ signalNameToNumberMap->add(signalNames[0], SIGHUP);
+ signalNameToNumberMap->add(signalNames[1], SIGINT);
+ signalNameToNumberMap->add(signalNames[2], SIGQUIT);
+ signalNameToNumberMap->add(signalNames[3], SIGILL);
+ signalNameToNumberMap->add(signalNames[4], SIGTRAP);
+ signalNameToNumberMap->add(signalNames[5], SIGABRT);
+ signalNameToNumberMap->add(signalNames[6], SIGIOT);
+ signalNameToNumberMap->add(signalNames[7], SIGBUS);
+ signalNameToNumberMap->add(signalNames[8], SIGFPE);
+ // signalNameToNumberMap->add(signalNames[9], SIGKILL);
+ signalNameToNumberMap->add(signalNames[10], SIGUSR1);
+ signalNameToNumberMap->add(signalNames[11], SIGSEGV);
+ signalNameToNumberMap->add(signalNames[12], SIGUSR2);
+ signalNameToNumberMap->add(signalNames[13], SIGPIPE);
+ signalNameToNumberMap->add(signalNames[14], SIGALRM);
+ signalNameToNumberMap->add(signalNames[15], SIGTERM);
+ signalNameToNumberMap->add(signalNames[16], SIGCHLD);
+ signalNameToNumberMap->add(signalNames[17], SIGCONT);
+ // signalNameToNumberMap->add(signalNames[18], SIGSTOP);
+ signalNameToNumberMap->add(signalNames[19], SIGTSTP);
+ signalNameToNumberMap->add(signalNames[20], SIGTTIN);
+ signalNameToNumberMap->add(signalNames[21], SIGTTOU);
+ signalNameToNumberMap->add(signalNames[22], SIGURG);
+ signalNameToNumberMap->add(signalNames[23], SIGXCPU);
+ signalNameToNumberMap->add(signalNames[24], SIGXFSZ);
+ signalNameToNumberMap->add(signalNames[25], SIGVTALRM);
+ signalNameToNumberMap->add(signalNames[26], SIGPROF);
+ signalNameToNumberMap->add(signalNames[27], SIGWINCH);
+ signalNameToNumberMap->add(signalNames[28], SIGIO);
+#ifdef SIGINFO
+ signalNameToNumberMap->add(signalNames[29], SIGINFO);
+#endif
+
+#ifndef SIGINFO
+ signalNameToNumberMap->add(signalNames[29], 255);
+#endif
+ signalNameToNumberMap->add(signalNames[30], SIGSYS);
+ });
+
+ static std::once_flag signalNumberToNameMapOnceFlag;
+ std::call_once(signalNumberToNameMapOnceFlag, [] {
+ signalNumberToNameMap = new HashMap<int, String>();
+ signalNumberToNameMap->reserveInitialCapacity(31);
+ signalNumberToNameMap->add(SIGHUP, signalNames[0]);
+ signalNumberToNameMap->add(SIGINT, signalNames[1]);
+ signalNumberToNameMap->add(SIGQUIT, signalNames[2]);
+ signalNumberToNameMap->add(SIGILL, signalNames[3]);
+ signalNumberToNameMap->add(SIGTRAP, signalNames[4]);
+ signalNumberToNameMap->add(SIGABRT, signalNames[5]);
+ signalNumberToNameMap->add(SIGIOT, signalNames[6]);
+ signalNumberToNameMap->add(SIGBUS, signalNames[7]);
+ signalNumberToNameMap->add(SIGFPE, signalNames[8]);
+ // signalNumberToNameMap->add(SIGKILL, signalNames[9]);
+ signalNumberToNameMap->add(SIGUSR1, signalNames[10]);
+ signalNumberToNameMap->add(SIGSEGV, signalNames[11]);
+ signalNumberToNameMap->add(SIGUSR2, signalNames[12]);
+ signalNumberToNameMap->add(SIGPIPE, signalNames[13]);
+ signalNumberToNameMap->add(SIGALRM, signalNames[14]);
+ signalNumberToNameMap->add(SIGTERM, signalNames[15]);
+ signalNumberToNameMap->add(SIGCHLD, signalNames[16]);
+ signalNumberToNameMap->add(SIGCONT, signalNames[17]);
+ // signalNumberToNameMap->add(SIGSTOP, signalNames[18]);
+ signalNumberToNameMap->add(SIGTSTP, signalNames[19]);
+ signalNumberToNameMap->add(SIGTTIN, signalNames[20]);
+ signalNumberToNameMap->add(SIGTTOU, signalNames[21]);
+ signalNumberToNameMap->add(SIGURG, signalNames[22]);
+ signalNumberToNameMap->add(SIGXCPU, signalNames[23]);
+ signalNumberToNameMap->add(SIGXFSZ, signalNames[24]);
+ signalNumberToNameMap->add(SIGVTALRM, signalNames[25]);
+ signalNumberToNameMap->add(SIGPROF, signalNames[26]);
+ signalNumberToNameMap->add(SIGWINCH, signalNames[27]);
+ signalNumberToNameMap->add(SIGIO, signalNames[28]);
+#ifdef SIGINFO
+ signalNameToNumberMap->add(signalNames[29], SIGINFO);
+#endif
+ signalNumberToNameMap->add(SIGSYS, signalNames[30]);
+ });
+
+ if (!signalToContextIdsMap) {
+ signalToContextIdsMap = new HashMap<int, HashSet<uint32_t>>();
+ }
+
+ if (isAdded) {
+ if (auto signalNumber = signalNameToNumberMap->get(eventName.string())) {
+ uint32_t contextId = eventEmitter.scriptExecutionContext()->identifier();
+ Locker lock { signalToContextIdsMapLock };
+ if (!signalToContextIdsMap->contains(signalNumber)) {
+ HashSet<uint32_t> contextIds;
+ contextIds.add(contextId);
+ signalToContextIdsMap->set(signalNumber, contextIds);
+
+ lock.unlockEarly();
+
+ struct sigaction action;
+ memset(&action, 0, sizeof(struct sigaction));
+
+ // Set the handler in the action struct
+ action.sa_handler = [](int signalNumber) {
+ if (UNLIKELY(signalNumberToNameMap->find(signalNumber) == signalNumberToNameMap->end()))
+ return;
+
+ Locker lock { signalToContextIdsMapLock };
+ if (UNLIKELY(signalToContextIdsMap->find(signalNumber) == signalToContextIdsMap->end()))
+ return;
+ auto contextIds = signalToContextIdsMap->get(signalNumber);
+
+ for (int contextId : contextIds) {
+ auto* context = ScriptExecutionContext::getScriptExecutionContext(contextId);
+ if (UNLIKELY(!context))
+ continue;
+
+ JSGlobalObject* lexicalGlobalObject = context->jsGlobalObject();
+ Zig::GlobalObject* globalObject = static_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+
+ Process* process = jsCast<Process*>(globalObject->processObject());
+
+ context->postCrossThreadTask(*process, &Process::emitSignalEvent, signalNumber);
+ }
+ };
+
+ // Clear the sa_mask
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, signalNumber);
+ action.sa_flags = SA_RESTART;
+
+ sigaction(signalNumber, &action, nullptr);
+ } else {
+ auto contextIds = signalToContextIdsMap->get(signalNumber);
+ contextIds.add(contextId);
+ signalToContextIdsMap->set(signalNumber, contextIds);
+ }
+ }
+ } else {
+ if (auto signalNumber = signalNameToNumberMap->get(eventName.string())) {
+ uint32_t contextId = eventEmitter.scriptExecutionContext()->identifier();
+ Locker lock { signalToContextIdsMapLock };
+ if (signalToContextIdsMap->find(signalNumber) != signalToContextIdsMap->end()) {
+ HashSet<uint32_t> contextIds = signalToContextIdsMap->get(signalNumber);
+ contextIds.remove(contextId);
+ if (contextIds.isEmpty()) {
+ signal(signalNumber, SIG_DFL);
+ signalToContextIdsMap->remove(signalNumber);
+ } else {
+ signalToContextIdsMap->set(signalNumber, contextIds);
+ }
+ }
+ }
+ }
+}
+
+void Process::emitSignalEvent(int signalNumber)
+{
+ String signalName = signalNumberToNameMap->get(signalNumber);
+ Identifier signalNameIdentifier = Identifier::fromString(vm(), signalName);
+ MarkedArgumentBuffer args;
+ args.append(jsNumber(signalNumber));
+ wrapped().emitForBindings(signalNameIdentifier, args);
+}
Process::~Process()
{
- for (auto& listener : this->wrapped().eventListenerMap().entries()) {
- }
}
JSC_DEFINE_HOST_FUNCTION(Process_functionAbort, (JSGlobalObject * globalObject, CallFrame*))
@@ -1550,6 +1674,8 @@ void Process::finishCreation(JSC::VM& vm)
{
Base::finishCreation(vm);
+ this->wrapped().onDidChangeListener = &onDidChangeListeners;
+
this->cpuUsageStructure.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::Structure>::Initializer& init) {
init.set(constructCPUUsageStructure(init.vm, init.owner->globalObject()));
});
diff --git a/src/bun.js/bindings/Process.h b/src/bun.js/bindings/Process.h
index fbad9b1ff..0ee6f4243 100644
--- a/src/bun.js/bindings/Process.h
+++ b/src/bun.js/bindings/Process.h
@@ -19,6 +19,8 @@ public:
{
}
+ void emitSignalEvent(int signalNumber);
+
DECLARE_EXPORT_INFO;
static void destroy(JSC::JSCell* cell)
diff --git a/src/bun.js/bindings/ScriptExecutionContext.cpp b/src/bun.js/bindings/ScriptExecutionContext.cpp
index e8cae5e33..3262bdb5d 100644
--- a/src/bun.js/bindings/ScriptExecutionContext.cpp
+++ b/src/bun.js/bindings/ScriptExecutionContext.cpp
@@ -20,6 +20,12 @@ static HashMap<ScriptExecutionContextIdentifier, ScriptExecutionContext*>& allSc
return contexts;
}
+ScriptExecutionContext* ScriptExecutionContext::getScriptExecutionContext(ScriptExecutionContextIdentifier identifier)
+{
+ Locker locker { allScriptExecutionContextsMapLock };
+ return allScriptExecutionContextsMap().get(identifier);
+}
+
template<bool SSL, bool isServer>
static void registerHTTPContextForWebSocket(ScriptExecutionContext* script, us_socket_context_t* ctx, us_loop_t* loop)
{
diff --git a/src/bun.js/bindings/ScriptExecutionContext.h b/src/bun.js/bindings/ScriptExecutionContext.h
index 5f6c56a90..aed7977a5 100644
--- a/src/bun.js/bindings/ScriptExecutionContext.h
+++ b/src/bun.js/bindings/ScriptExecutionContext.h
@@ -96,7 +96,12 @@ public:
}
}
- const WTF::URL& url() const { return m_url; }
+ static ScriptExecutionContext* getScriptExecutionContext(ScriptExecutionContextIdentifier identifier);
+
+ const WTF::URL& url() const
+ {
+ return m_url;
+ }
bool activeDOMObjectsAreSuspended() { return false; }
bool activeDOMObjectsAreStopped() { return false; }
bool isContextThread() { return true; }
@@ -141,6 +146,7 @@ public:
auto* task = new EventLoopTask(WTFMove(lambda));
postTaskOnTimeout(task, timeout);
}
+
template<typename... Arguments>
void postCrossThreadTask(Arguments&&... arguments)
{
diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp
index 9f9b20c1e..d311072e4 100644
--- a/src/bun.js/bindings/bindings.cpp
+++ b/src/bun.js/bindings/bindings.cpp
@@ -2775,8 +2775,18 @@ void JSC__JSValue__put(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, const Z
bool JSC__JSValue__isClass(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1)
{
- JSC::JSValue value = JSC::JSValue::decode(JSValue0);
- return value.isConstructor();
+ JSValue value = JSValue::decode(JSValue0);
+ auto callData = getCallData(value);
+
+ switch (callData.type) {
+ case CallData::Type::JS:
+ return callData.js.functionExecutable->isClassConstructorFunction();
+ case CallData::Type::Native:
+ if (callData.native.isBoundFunction)
+ return false;
+ return value.isConstructor();
+ }
+ return false;
}
bool JSC__JSValue__isCell(JSC__JSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isCell(); }
bool JSC__JSValue__isCustomGetterSetter(JSC__JSValue JSValue0)
diff --git a/src/bun.js/bindings/exports.zig b/src/bun.js/bindings/exports.zig
index 73a26e4be..e9e9d3a8d 100644
--- a/src/bun.js/bindings/exports.zig
+++ b/src/bun.js/bindings/exports.zig
@@ -460,7 +460,7 @@ pub const ZigStackTrace = extern struct {
var source_line_len = source_lines_iter.getLength();
if (source_line_len > 0) {
- var source_lines = try allocator.alloc(Api.SourceLine, @intCast(usize, @max(source_lines_iter.i, 0)));
+ var source_lines = try allocator.alloc(Api.SourceLine, @intCast(usize, @max(source_lines_iter.i + 1, 0)));
var source_line_buf = try allocator.alloc(u8, source_line_len);
source_lines_iter = this.sourceLineIterator();
var remain_buf = source_line_buf[0..];
@@ -468,7 +468,7 @@ pub const ZigStackTrace = extern struct {
while (source_lines_iter.next()) |source| {
const text = source.text.slice();
defer source.text.deinit();
- defer bun.copy(
+ bun.copy(
u8,
remain_buf,
text,
@@ -515,7 +515,7 @@ pub const ZigStackTrace = extern struct {
pub fn getLength(this: *SourceLineIterator) usize {
var count: usize = 0;
- for (this.trace.source_lines_ptr[0..@intCast(usize, this.i)]) |*line| {
+ for (this.trace.source_lines_ptr[0..@intCast(usize, this.i + 1)]) |*line| {
count += line.length();
}
@@ -1417,23 +1417,20 @@ pub const ZigConsoleClient = struct {
// If we check an Object has a method table and it does not
// it will crash
- const callable = js_type != .Object and value.isCallable(globalThis.vm());
-
- if (value.isClass(globalThis) and !callable) {
- return .{
- .tag = .Object,
- .cell = js_type,
- };
- }
+ if (js_type != .Object and value.isCallable(globalThis.vm())) {
+ if (value.isClass(globalThis)) {
+ return .{
+ .tag = .Class,
+ .cell = js_type,
+ };
+ }
- if (callable and js_type == .JSFunction) {
- return .{
- .tag = .Function,
- .cell = js_type,
- };
- } else if (callable and js_type == .InternalFunction) {
return .{
- .tag = .Object,
+ // TODO: we print InternalFunction as Object because we have a lot of
+ // callable namespaces and printing the contents of it is better than [Function: namespace]
+ // ideally, we would print [Function: namespace] { ... } on all functions, internal and js.
+ // what we'll do later is rid of .Function and .Class and handle the prefix in the .Object formatter
+ .tag = if (js_type == .InternalFunction) .Object else .Function,
.cell = js_type,
};
}
@@ -1756,7 +1753,7 @@ pub const ZigConsoleClient = struct {
parent: JSValue,
const enable_ansi_colors = enable_ansi_colors_;
pub fn handleFirstProperty(this: *@This(), globalThis: *JSC.JSGlobalObject, value: JSValue) void {
- if (!value.jsType().isFunction() and !value.isClass(globalThis)) {
+ if (!value.jsType().isFunction()) {
var writer = WrappedWriter(Writer){
.ctx = this.writer,
.failed = false,
@@ -2094,9 +2091,9 @@ pub const ZigConsoleClient = struct {
this.addForNewLine(printable.len);
if (printable.len == 0) {
- writer.print(comptime Output.prettyFmt("[class]", enable_ansi_colors), .{});
+ writer.print(comptime Output.prettyFmt("<cyan>[class]<r>", enable_ansi_colors), .{});
} else {
- writer.print(comptime Output.prettyFmt("[class <cyan>{}<r>]", enable_ansi_colors), .{printable});
+ writer.print(comptime Output.prettyFmt("<cyan>[class {}]<r>", enable_ansi_colors), .{printable});
}
},
.Function => {
@@ -2106,7 +2103,7 @@ pub const ZigConsoleClient = struct {
if (printable.len == 0) {
writer.print(comptime Output.prettyFmt("<cyan>[Function]<r>", enable_ansi_colors), .{});
} else {
- writer.print(comptime Output.prettyFmt("<cyan>[Function<d>:<r> <cyan>{}]<r>", enable_ansi_colors), .{printable});
+ writer.print(comptime Output.prettyFmt("<cyan>[Function: {}]<r>", enable_ansi_colors), .{printable});
}
},
.Getter => {
@@ -2802,7 +2799,7 @@ pub const ZigConsoleClient = struct {
}
if (iter.i == 0) {
- if (value.isClass(this.globalThis) and !value.isCallable(this.globalThis.vm()))
+ if (value.isClass(this.globalThis))
this.printAs(.Class, Writer, writer_, value, jsType, enable_ansi_colors)
else if (value.isCallable(this.globalThis.vm()))
this.printAs(.Function, Writer, writer_, value, jsType, enable_ansi_colors)
diff --git a/src/bun.js/bindings/webcore/EventEmitter.cpp b/src/bun.js/bindings/webcore/EventEmitter.cpp
index 0650d624c..0e273042b 100644
--- a/src/bun.js/bindings/webcore/EventEmitter.cpp
+++ b/src/bun.js/bindings/webcore/EventEmitter.cpp
@@ -35,6 +35,8 @@ bool EventEmitter::addListener(const Identifier& eventType, Ref<EventListener>&&
}
eventListenersDidChange();
+ if (this->onDidChangeListener)
+ this->onDidChangeListener(*this, eventType, true);
return true;
}
@@ -62,6 +64,9 @@ bool EventEmitter::removeListener(const Identifier& eventType, EventListener& li
if (data->eventListenerMap.remove(eventType, listener)) {
eventListenersDidChange();
+
+ if (this->onDidChangeListener)
+ this->onDidChangeListener(*this, eventType, false);
return true;
}
return false;
@@ -93,6 +98,8 @@ bool EventEmitter::removeAllListeners(const Identifier& eventType)
if (data->eventListenerMap.removeAll(eventType)) {
eventListenersDidChange();
+ if (this->onDidChangeListener)
+ this->onDidChangeListener(*this, eventType, false);
return true;
}
return false;
diff --git a/src/bun.js/bindings/webcore/EventEmitter.h b/src/bun.js/bindings/webcore/EventEmitter.h
index b46bcff5d..8db59c188 100644
--- a/src/bun.js/bindings/webcore/EventEmitter.h
+++ b/src/bun.js/bindings/webcore/EventEmitter.h
@@ -67,6 +67,8 @@ public:
bool hasActiveEventListeners(const Identifier& eventType) const;
bool hasEventListeners(JSC::VM& vm, ASCIILiteral eventType) const;
+ WTF::Function<void(EventEmitter&, const Identifier& eventName, bool isAdded)> onDidChangeListener = WTF::Function<void(EventEmitter&, const Identifier& eventName, bool isAdded)>(nullptr);
+
unsigned getMaxListeners() const { return m_maxListeners; };
void setMaxListeners(unsigned count);
@@ -101,7 +103,9 @@ private:
EventEmitterData* eventTargetData() { return &m_eventTargetData; }
EventEmitterData* eventTargetDataConcurrently() { return &m_eventTargetData; }
EventEmitterData& ensureEventEmitterData() { return m_eventTargetData; }
- void eventListenersDidChange() {}
+ void eventListenersDidChange()
+ {
+ }
void innerInvokeEventListeners(const Identifier&, SimpleEventListenerVector, const MarkedArgumentBuffer& arguments);
void invalidateEventListenerRegions();
diff --git a/src/bun.js/bindings/webcore/JSEventEmitter.cpp b/src/bun.js/bindings/webcore/JSEventEmitter.cpp
index 231ae0db4..959cbd8d7 100644
--- a/src/bun.js/bindings/webcore/JSEventEmitter.cpp
+++ b/src/bun.js/bindings/webcore/JSEventEmitter.cpp
@@ -219,7 +219,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsEventEmitterConstructor, (JSGlobalObject * lexicalGlo
return JSValue::encode(JSEventEmitter::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject()));
}
-static inline JSC::EncodedJSValue addListener(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSEventEmitter>::ClassParameter castedThis, bool once, bool prepend)
+inline JSC::EncodedJSValue JSEventEmitter::addListener(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, JSEventEmitter* castedThis, bool once, bool prepend)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
@@ -251,7 +251,7 @@ static inline JSC::EncodedJSValue addListener(JSC::JSGlobalObject* lexicalGlobal
static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_addListenerBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSEventEmitter>::ClassParameter castedThis)
{
- return addListener(lexicalGlobalObject, callFrame, castedThis, false, false);
+ return JSEventEmitter::addListener(lexicalGlobalObject, callFrame, castedThis, false, false);
}
static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_setMaxListenersBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSEventEmitter>::ClassParameter castedThis)
@@ -280,17 +280,17 @@ static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_getMaxListener
static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_addOnceListenerBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSEventEmitter>::ClassParameter castedThis)
{
- return addListener(lexicalGlobalObject, callFrame, castedThis, true, false);
+ return JSEventEmitter::addListener(lexicalGlobalObject, callFrame, castedThis, true, false);
}
static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_prependListenerBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSEventEmitter>::ClassParameter castedThis)
{
- return addListener(lexicalGlobalObject, callFrame, castedThis, false, true);
+ return JSEventEmitter::addListener(lexicalGlobalObject, callFrame, castedThis, false, true);
}
static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_prependOnceListenerBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSEventEmitter>::ClassParameter castedThis)
{
- return addListener(lexicalGlobalObject, callFrame, castedThis, true, true);
+ return JSEventEmitter::addListener(lexicalGlobalObject, callFrame, castedThis, true, true);
}
JSC_DEFINE_HOST_FUNCTION(jsEventEmitterPrototypeFunction_addListener, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
@@ -325,6 +325,11 @@ JSC_DEFINE_HOST_FUNCTION(jsEventEmitterPrototypeFunction_prependOnceListener, (J
static inline JSC::EncodedJSValue jsEventEmitterPrototypeFunction_removeListenerBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSEventEmitter>::ClassParameter castedThis)
{
+ return JSEventEmitter::removeListener(lexicalGlobalObject, callFrame, castedThis);
+}
+
+inline JSC::EncodedJSValue JSEventEmitter::removeListener(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, JSEventEmitter* castedThis)
+{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
JSC::JSValue actualThis = callFrame->thisValue();
diff --git a/src/bun.js/bindings/webcore/JSEventEmitter.h b/src/bun.js/bindings/webcore/JSEventEmitter.h
index 855241011..30d62d792 100644
--- a/src/bun.js/bindings/webcore/JSEventEmitter.h
+++ b/src/bun.js/bindings/webcore/JSEventEmitter.h
@@ -27,6 +27,9 @@ public:
static EventEmitter* toWrapped(JSC::VM&, JSC::JSValue);
static void destroy(JSC::JSCell*);
+ static inline JSC::EncodedJSValue addListener(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, JSEventEmitter* castedThis, bool once, bool prepend);
+ static inline JSC::EncodedJSValue removeListener(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, JSEventEmitter* castedThis);
+
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
diff --git a/src/bun.js/test/pretty_format.zig b/src/bun.js/test/pretty_format.zig
index 4a245c3bb..a6c6aa631 100644
--- a/src/bun.js/test/pretty_format.zig
+++ b/src/bun.js/test/pretty_format.zig
@@ -423,23 +423,20 @@ pub const JestPrettyFormat = struct {
// If we check an Object has a method table and it does not
// it will crash
- const callable = js_type != .Object and value.isCallable(globalThis.vm());
+ if (js_type != .Object and value.isCallable(globalThis.vm())) {
+ if (value.isClass(globalThis)) {
+ return .{
+ .tag = .Class,
+ .cell = js_type,
+ };
+ }
- if (value.isClass(globalThis) and !callable) {
return .{
- .tag = .Object,
- .cell = js_type,
- };
- }
-
- if (callable and js_type == .JSFunction) {
- return .{
- .tag = .Function,
- .cell = js_type,
- };
- } else if (callable and js_type == .InternalFunction) {
- return .{
- .tag = .Object,
+ // TODO: we print InternalFunction as Object because we have a lot of
+ // callable namespaces and printing the contents of it is better than [Function: namespace]
+ // ideally, we would print [Function: namespace] { ... } on all functions, internal and js.
+ // what we'll do later is rid of .Function and .Class and handle the prefix in the .Object formatter
+ .tag = if (js_type == .InternalFunction) .Object else .Function,
.cell = js_type,
};
}
@@ -750,7 +747,7 @@ pub const JestPrettyFormat = struct {
parent: JSValue,
const enable_ansi_colors = enable_ansi_colors_;
pub fn handleFirstProperty(this: *@This(), globalThis: *JSC.JSGlobalObject, value: JSValue) void {
- if (!value.jsType().isFunction() and !value.isClass(globalThis)) {
+ if (!value.jsType().isFunction()) {
var writer = WrappedWriter(Writer){
.ctx = this.writer,
.failed = false,
@@ -1126,13 +1123,20 @@ pub const JestPrettyFormat = struct {
this.addForNewLine(printable.len);
if (printable.len == 0) {
- writer.print(comptime Output.prettyFmt("[class]", enable_ansi_colors), .{});
+ writer.print(comptime Output.prettyFmt("<cyan>[class]<r>", enable_ansi_colors), .{});
} else {
- writer.print(comptime Output.prettyFmt("[class <cyan>{}<r>]", enable_ansi_colors), .{printable});
+ writer.print(comptime Output.prettyFmt("<cyan>[class {}]<r>", enable_ansi_colors), .{printable});
}
},
.Function => {
- writer.writeAll("[Function]");
+ var printable = ZigString.init(&name_buf);
+ value.getNameProperty(this.globalThis, &printable);
+
+ if (printable.len == 0) {
+ writer.print(comptime Output.prettyFmt("<cyan>[Function]<r>", enable_ansi_colors), .{});
+ } else {
+ writer.print(comptime Output.prettyFmt("<cyan>[Function: {}]<r>", enable_ansi_colors), .{printable});
+ }
},
.Array => {
const len = @truncate(u32, value.getLength(this.globalThis));