diff --git a/lib/fs.js b/lib/fs.js index c930cb04946966..c9896e45fcfe64 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -154,6 +154,7 @@ let ReadStream; let WriteStream; let rimraf; let rimrafSync; +let kResistStopPropagation; // These have to be separate because of how graceful-fs happens to do it's // monkeypatching. @@ -2439,7 +2440,8 @@ function watch(filename, options, listener) { process.nextTick(() => watcher.close()); } else { const listener = () => watcher.close(); - options.signal.addEventListener('abort', listener); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + options.signal.addEventListener('abort', listener, { __proto__: null, [kResistStopPropagation]: true }); watcher.once('close', () => { options.signal.removeEventListener('abort', listener); }); diff --git a/lib/internal/fs/recursive_watch.js b/lib/internal/fs/recursive_watch.js index cbe513a166ec20..54298832da5a1b 100644 --- a/lib/internal/fs/recursive_watch.js +++ b/lib/internal/fs/recursive_watch.js @@ -42,6 +42,7 @@ function lazyLoadFsSync() { internalSync ??= require('fs'); return internalSync; } +let kResistStopPropagation; async function traverse(dir, files = new SafeMap(), symbolicLinks = new SafeSet()) { const { opendir } = lazyLoadFsPromises(); @@ -265,7 +266,8 @@ class FSWatcher extends EventEmitter { } : (resolve, reject) => { const onAbort = () => reject(new AbortError(undefined, { cause: signal.reason })); if (signal.aborted) return onAbort(); - signal.addEventListener('abort', onAbort, { __proto__: null, once: true }); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', onAbort, { __proto__: null, once: true, [kResistStopPropagation]: true }); this.once('change', (eventType, filename) => { signal.removeEventListener('abort', onAbort); resolve({ __proto__: null, value: { eventType, filename } }); diff --git a/lib/internal/fs/watchers.js b/lib/internal/fs/watchers.js index ce885c154c81c5..99212fa713bf3f 100644 --- a/lib/internal/fs/watchers.js +++ b/lib/internal/fs/watchers.js @@ -299,6 +299,8 @@ ObjectDefineProperty(FSEvent.prototype, 'owner', { set(v) { return this[owner_symbol] = v; }, }); +let kResistStopPropagation; + async function* watch(filename, options = kEmptyObject) { const path = toNamespacedPath(getValidatedPath(filename)); validateObject(options, 'options'); @@ -330,7 +332,10 @@ async function* watch(filename, options = kEmptyObject) { }; try { - signal?.addEventListener('abort', oncancel, { once: true }); + if (signal) { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', oncancel, { __proto__: null, once: true, [kResistStopPropagation]: true }); + } handle.onchange = (status, eventType, filename) => { if (status < 0) { const error = uvException({ diff --git a/lib/internal/test_runner/mock/mock_timers.js b/lib/internal/test_runner/mock/mock_timers.js index 0af581423fefea..ec79b9e860de3d 100644 --- a/lib/internal/test_runner/mock/mock_timers.js +++ b/lib/internal/test_runner/mock/mock_timers.js @@ -33,6 +33,8 @@ const nodeTimers = require('timers'); const nodeTimersPromises = require('timers/promises'); const EventEmitter = require('events'); +let kResistStopPropagation; + function compareTimersLists(a, b) { return (a.runAt - b.runAt) || (a.id - b.id); } @@ -101,7 +103,7 @@ class MockTimers { if (options?.signal) { validateAbortSignal(options.signal, 'options.signal'); - if (options.signal?.aborted) { + if (options.signal.aborted) { throw abortIt(options.signal); } @@ -109,9 +111,11 @@ class MockTimers { emitter.emit('data', { __proto__: null, aborted: true, reason }); }; - options.signal?.addEventListener('abort', onAbort, { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + options.signal.addEventListener('abort', onAbort, { __proto__: null, once: true, + [kResistStopPropagation]: true, }); } @@ -162,7 +166,7 @@ class MockTimers { return reject(err); } - if (options.signal?.aborted) { + if (options.signal.aborted) { return reject(abortIt(options.signal)); } } @@ -176,10 +180,14 @@ class MockTimers { return resolve(result || id); }, ms); - options?.signal?.addEventListener('abort', onabort, { - __proto__: null, - once: true, - }); + if (options?.signal) { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + options.signal.addEventListener('abort', onabort, { + __proto__: null, + once: true, + [kResistStopPropagation]: true, + }); + } }); } diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 9f6d8ff4bac821..09d0df2e660e71 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -77,6 +77,8 @@ const kDiagnosticsFilterArgs = ['tests', 'suites', 'pass', 'fail', 'cancelled', const kCanceledTests = new SafeSet() .add(kCancelledByParent).add(kAborted).add(kTestTimeoutFailure); +let kResistStopPropagation; + // TODO(cjihrig): Replace this with recursive readdir once it lands. function processPath(path, testFiles, options) { const stats = statSync(path); @@ -442,7 +444,14 @@ function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) { triggerUncaughtException(error, true /* fromPromise */); })); }); - signal?.addEventListener('abort', () => root.postRun(), { __proto__: null, once: true }); + if (signal) { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener( + 'abort', + () => root.postRun(), + { __proto__: null, once: true, [kResistStopPropagation]: true }, + ); + } return filesWatcher; } diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index a85eef48c7df35..f5cc0fb98f6271 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -72,6 +72,7 @@ const kUnwrapErrors = new SafeSet() .add(kTestCodeFailure).add(kHookFailure) .add('uncaughtException').add('unhandledRejection'); const { testNamePatterns, testOnlyFlag } = parseCommandLine(); +let kResistStopPropagation; function stopTest(timeout, signal) { if (timeout === kDefaultTimeout) { @@ -266,7 +267,15 @@ class Test extends AsyncResource { this.signal = this.#abortController.signal; validateAbortSignal(signal, 'options.signal'); - this.#outerSignal?.addEventListener('abort', this.#abortHandler); + if (signal) { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + } + + this.#outerSignal?.addEventListener( + 'abort', + this.#abortHandler, + { __proto__: null, [kResistStopPropagation]: true }, + ); this.fn = fn; this.harness = null; // Configured on the root test by the test harness. diff --git a/lib/timers/promises.js b/lib/timers/promises.js index d224520f10694d..2bf36d6cc51700 100644 --- a/lib/timers/promises.js +++ b/lib/timers/promises.js @@ -40,6 +40,7 @@ const { } = require('internal/util'); const kScheduler = Symbol('kScheduler'); +let kResistStopPropagation; function cancelListenerHandler(clear, reject, signal) { if (!this._destroyed) { @@ -81,7 +82,8 @@ function setTimeout(after, value, options = kEmptyObject) { if (signal) { oncancel = FunctionPrototypeBind(cancelListenerHandler, timeout, clearTimeout, reject, signal); - signal.addEventListener('abort', oncancel); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', oncancel, { __proto__: null, [kResistStopPropagation]: true }); } }); return oncancel !== undefined ? @@ -123,7 +125,8 @@ function setImmediate(value, options = kEmptyObject) { oncancel = FunctionPrototypeBind(cancelListenerHandler, immediate, clearImmediate, reject, signal); - signal.addEventListener('abort', oncancel); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', oncancel, { __proto__: null, [kResistStopPropagation]: true }); } }); return oncancel !== undefined ? @@ -164,7 +167,8 @@ async function* setInterval(after, value, options = kEmptyObject) { callback = undefined; } }; - signal.addEventListener('abort', onCancel, { once: true }); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', onCancel, { __proto__: null, once: true, [kResistStopPropagation]: true }); } while (!signal?.aborted) {