import { BaseListener, BaseObserver, BaseObserverInterface } from './BaseObserver.js'; /** * Represents the counts of listeners for each event type in a BaseListener. */ export type ListenerCounts = Partial> & { total: number; }; /** * Meta listener which reports the counts of listeners for each event type. */ export interface MetaListener extends BaseListener { listenersChanged?: (counts: ListenerCounts) => void; } export interface ListenerMetaManager extends BaseObserverInterface> { counts: ListenerCounts; } export interface MetaBaseObserverInterface extends BaseObserverInterface { listenerMeta: ListenerMetaManager; } /** * A BaseObserver that tracks the counts of listeners for each event type. */ export class MetaBaseObserver extends BaseObserver implements MetaBaseObserverInterface { protected get listenerCounts(): ListenerCounts { const counts = {} as Partial>; let total = 0; for (const listener of this.listeners) { for (const key in listener) { if (listener[key]) { counts[key] = (counts[key] ?? 0) + 1; total++; } } } return { ...counts, total }; } get listenerMeta(): ListenerMetaManager { return { counts: this.listenerCounts, // Allows registering a meta listener that will be notified of changes in listener counts registerListener: (listener: Partial>) => { return this.metaListener.registerListener(listener); } }; } protected metaListener: BaseObserver>; constructor() { super(); this.metaListener = new BaseObserver>(); } registerListener(listener: Partial): () => void { const dispose = super.registerListener(listener); const updatedCount = this.listenerCounts; this.metaListener.iterateListeners((l) => { l.listenersChanged?.(updatedCount); }); return () => { dispose(); const updatedCount = this.listenerCounts; this.metaListener.iterateListeners((l) => { l.listenersChanged?.(updatedCount); }); }; } }