From dea878a1aa16c951cd0215a1bc2d8673fbe4d5e1 Mon Sep 17 00:00:00 2001 From: Karan Mangtani Date: Fri, 27 Mar 2026 16:33:26 +0530 Subject: [PATCH] stream: deprecate piping to emitters without prependListener The prependListener method has been available on EventEmitter since Node.js v6.0.0 (April 2016). The internal fallback code that manually manipulates the _events object was intended for pre-v6 compatibility. This adds a runtime deprecation warning (DEP0205) when piping to an EventEmitter that lacks the prependListener method. The fallback behavior is preserved for now but will be removed in a future version. PR-URL: https://github.com/nodejs/node/pull/XXXXX Refs: https://github.com/nodejs/node/issues/XXXXX --- doc/api/deprecations.md | 16 ++++++++++++++++ lib/internal/streams/legacy.js | 11 +++++++++++ test/parallel/test-event-emitter-prepend.js | 8 ++++++++ test/parallel/test-stream-events-prepend.js | 8 ++++++++ 4 files changed, 43 insertions(+) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index baeabb78505c1b..2690405e9fee88 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -4517,6 +4517,22 @@ Type: Documentation-only Passing a non-extractable [`CryptoKey`][] to [`KeyObject.from()`][] is deprecated and will throw an error in a future version. +### DEP0205: Piping to emitters without `prependListener` + + + +Type: Runtime + +Piping to an EventEmitter that does not have a `prependListener` method is +deprecated. The `prependListener` method has been available on EventEmitter +since Node.js v6.0.0. The internal fallback code that manually manipulates +the `_events` object will be removed in a future version. + [DEP0142]: #dep0142-repl_builtinlibs [NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf [RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3 diff --git a/lib/internal/streams/legacy.js b/lib/internal/streams/legacy.js index 8e75dfe6182207..14d1925f89f119 100644 --- a/lib/internal/streams/legacy.js +++ b/lib/internal/streams/legacy.js @@ -105,6 +105,8 @@ Stream.prototype.eventNames = function eventNames() { return names; }; +let emittedPrependListenerDeprecation = false; + function prependListener(emitter, event, fn) { // Sadly this is not cacheable as some libraries bundle their own // event emitter implementation with them. @@ -115,6 +117,15 @@ function prependListener(emitter, event, fn) { // userland ones. NEVER DO THIS. This is here only because this code needs // to continue to work with older versions of Node.js that do not include // the prependListener() method. The goal is to eventually remove this hack. + if (!emittedPrependListenerDeprecation) { + process.emitWarning( + 'Piping to an EventEmitter without a prependListener method is deprecated. ' + + 'The emitter should have a prependListener method.', + 'DeprecationWarning', + 'DEP0205', + ); + emittedPrependListenerDeprecation = true; + } if (!emitter._events || !emitter._events[event]) emitter.on(event, fn); else if (ArrayIsArray(emitter._events[event])) diff --git a/test/parallel/test-event-emitter-prepend.js b/test/parallel/test-event-emitter-prepend.js index ffe8544911365c..e2229330de78de 100644 --- a/test/parallel/test-event-emitter-prepend.js +++ b/test/parallel/test-event-emitter-prepend.js @@ -37,6 +37,14 @@ function Readable() { Object.setPrototypeOf(Readable.prototype, stream.Stream.prototype); Object.setPrototypeOf(Readable, stream.Stream); +// Expect deprecation warning when using fallback path +common.expectWarning( + 'DeprecationWarning', + 'Piping to an EventEmitter without a prependListener method is deprecated. ' + + 'The emitter should have a prependListener method.', + 'DEP0205', +); + const w = new Writable(); const r = new Readable(); r.pipe(w); diff --git a/test/parallel/test-stream-events-prepend.js b/test/parallel/test-stream-events-prepend.js index 80fedf8faee570..5d09f450e82c80 100644 --- a/test/parallel/test-stream-events-prepend.js +++ b/test/parallel/test-stream-events-prepend.js @@ -19,6 +19,14 @@ class Readable extends stream.Readable { } } +// Expect deprecation warning when using fallback path +common.expectWarning( + 'DeprecationWarning', + 'Piping to an EventEmitter without a prependListener method is deprecated. ' + + 'The emitter should have a prependListener method.', + 'DEP0205', +); + const w = new Writable(); w.on('pipe', common.mustCall());