summaryrefslogtreecommitdiffstats
path: root/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts
diff options
context:
space:
mode:
Diffstat (limited to 'remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts')
-rw-r--r--remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts66
1 files changed, 66 insertions, 0 deletions
diff --git a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts
index af21c5fe29..c4dc3b6c0d 100644
--- a/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts
+++ b/remote/test/puppeteer/packages/puppeteer-core/src/util/decorators.ts
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
+import type {EventType} from '../common/EventEmitter.js';
+import type {EventEmitter} from '../common/EventEmitter.js';
import type {Disposed, Moveable} from '../common/types.js';
import {asyncDisposeSymbol, disposeSymbol} from './disposable.js';
@@ -138,3 +140,67 @@ export function guarded<T extends object>(
};
};
}
+
+const bubbleHandlers = new WeakMap<object, Map<any, any>>();
+
+/**
+ * Event emitter fields marked with `bubble` will have their events bubble up
+ * the field owner.
+ */
+// The type is too complicated to type.
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export function bubble<T extends EventType[]>(events?: T) {
+ return <This extends EventEmitter<any>, Value extends EventEmitter<any>>(
+ {set, get}: ClassAccessorDecoratorTarget<This, Value>,
+ context: ClassAccessorDecoratorContext<This, Value>
+ ): ClassAccessorDecoratorResult<This, Value> => {
+ context.addInitializer(function () {
+ const handlers = bubbleHandlers.get(this) ?? new Map();
+ if (handlers.has(events)) {
+ return;
+ }
+
+ const handler =
+ events !== undefined
+ ? (type: EventType, event: unknown) => {
+ if (events.includes(type)) {
+ this.emit(type, event);
+ }
+ }
+ : (type: EventType, event: unknown) => {
+ this.emit(type, event);
+ };
+
+ handlers.set(events, handler);
+ bubbleHandlers.set(this, handlers);
+ });
+ return {
+ set(emitter) {
+ const handler = bubbleHandlers.get(this)!.get(events)!;
+
+ // In case we are re-setting.
+ const oldEmitter = get.call(this);
+ if (oldEmitter !== undefined) {
+ oldEmitter.off('*', handler);
+ }
+
+ if (emitter === undefined) {
+ return;
+ }
+ emitter.on('*', handler);
+ set.call(this, emitter);
+ },
+ // @ts-expect-error -- TypeScript incorrectly types init to require a
+ // return.
+ init(emitter) {
+ if (emitter === undefined) {
+ return;
+ }
+ const handler = bubbleHandlers.get(this)!.get(events)!;
+
+ emitter.on('*', handler);
+ return emitter;
+ },
+ };
+ };
+}