fix(javascript-semantics): keep emitted data out of dispatch listener fields (#2952)

* fix(javascript-semantics): keep emitted data out of dispatch listener fields

The EventEmitter operation collector read argument position 1 as the
listener for every event method, so a dispatch such as
bus.emit("ready", data) reported the data binding and its range as the
listener. Only registration and removal name a listener there; emit
passes its remaining arguments to listeners that already exist. Read the
listener argument only for register and remove operations.

Fixes #2574

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(javascript-semantics): read listener arguments only for listener-taking methods

removeAllListeners accepts only an optional event name, so gating the
listener argument on operation kind still reported an ignored second
argument as a listener. Gate on the methods whose argument position 1
names a listener instead: the registration methods, off, and
removeListener.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
saurabh sharmaandClaude Fable 5.1 authored and GitHub committed 2026-10-14 02:48:54 +08:00
1 parent 0bc422d7be
commit 090b454350
2 files changed
+81 -1

No files matched your search

@@ -37,6 +37,13 @@ const EVENT_REMOVE_METHODS = [
"removeListener",
"removeAllListeners",
] as const;
/**
* Methods whose argument position 1 names a listener. `removeAllListeners`
* takes only an optional event name, and `emit` passes its remaining
* arguments as data to listeners that already exist.
*/
const EVENT_LISTENER_METHODS: readonly JavaScriptSemanticEventOperation["method"][] =
[...EVENT_REGISTER_METHODS, "off", "removeListener"];
const EVENT_METHODS = [
...EVENT_REGISTER_METHODS,
...EVENT_REMOVE_METHODS,
@@ -137,7 +144,9 @@ const collectEvent = (
if (method === undefined) return;
const kind = eventKind(method);
const eventArgument = node.arguments[0];
const listenerArgument = node.arguments[1];
const listenerArgument = EVENT_LISTENER_METHODS.includes(method)
? node.arguments[1]
: undefined;
const emitter = emitterIdentity(member.object, state);
const eventName = dataEffectLiteralString(eventArgument);
output.push({