From e04ddfc92a8fffa79d91ddeb5eaf338a3f73054d Mon Sep 17 00:00:00 2001 From: sangwook Date: Tue, 7 Oct 2025 12:38:02 +0900 Subject: [PATCH 1/2] test: ensure removeListener event fires for once() listeners Adds test coverage for the removeListener event being emitted when a once() listener is automatically removed after execution. This verifies that streams and other EventEmitters correctly emit removeListener events when once() wrappers clean up. --- .../test-event-emitter-remove-listeners.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/parallel/test-event-emitter-remove-listeners.js b/test/parallel/test-event-emitter-remove-listeners.js index f37d26eb258c23..7b94d31f45d221 100644 --- a/test/parallel/test-event-emitter-remove-listeners.js +++ b/test/parallel/test-event-emitter-remove-listeners.js @@ -168,3 +168,19 @@ function listener2() {} ee.removeListener('foo', listener1); assert.strictEqual(ee._events.foo, listener2); } + +{ + const { Writable } = require('stream'); + const stream = new Writable({ + write(chunk, encoding, callback) { + callback(); + } + }); + + stream.on('removeListener', common.mustCall((eventName, listener) => { + assert.strictEqual(eventName, 'finish'); + })); + + stream.once('finish', common.mustCall()); + stream.end(); +} From d322e4de739c3930ccfe05fde0c17849db7ad65c Mon Sep 17 00:00:00 2001 From: sangwook Date: Tue, 7 Oct 2025 13:08:22 +0900 Subject: [PATCH 2/2] fix: emit removeListener event when last listener is removed When the last listener is removed and _eventsCount becomes 0, the removeListener event was not being emitted because the check was inside the else block. This moves the removeListener emission outside the conditional to ensure it always fires when a listener is removed. --- lib/events.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/events.js b/lib/events.js index 1c732802ef28aa..bfd22ce4e6cae1 100644 --- a/lib/events.js +++ b/lib/events.js @@ -687,9 +687,10 @@ EventEmitter.prototype.removeListener = this._events = { __proto__: null }; } else { delete events[type]; - if (events.removeListener) - this.emit('removeListener', type, list.listener || listener); } + + if (events.removeListener !== undefined) + this.emit('removeListener', type, list.listener || listener); } else if (typeof list !== 'function') { let position = -1;