import { EventEmitter } from "events" ; import { IDisposable , IEvent , IEventProvider } from "@fluidframework/common-definitions" ; import { TypedEventEmitter } from "./typedEventEmitter" ; /**
 * Base class used for forwarding events from a source EventEmitter.
 * This can be useful when all arbitrary listeners need to be removed,
 * but the primary source needs to stay intact.
 */ export class EventForwarder < TEvent = IEvent > extends TypedEventEmitter < TEvent > implements IDisposable { protected static isEmitterEvent ( event ) { return event === EventForwarder . newListenerEvent || event === EventForwarder . removeListenerEvent ; } private static readonly newListenerEvent = "newListener" ; private static readonly removeListenerEvent = "removeListener" ; public get disposed ( ) { return this . isDisposed ; } private isDisposed : boolean = false ; private readonly forwardingEvents = new Map < string , Map < EventEmitter | IEventProvider < TEvent & IEvent > , ( ) => void > > ( ) ; constructor ( source ? ) { super ( ) ; if ( source !== undefined ) { const removeListenerHandler = ( event ) => this . unforwardEvent ( source , event ) ; const newListenerHandler = ( event ) => this . forwardEvent ( source , event ) ; this . on ( EventForwarder . removeListenerEvent , removeListenerHandler ) ; this . on ( EventForwarder . newListenerEvent , newListenerHandler ) ; } } public dispose ( ) { this . isDisposed = true ; for ( const listenerRemovers of this . forwardingEvents . values ( ) ) { for ( const listenerRemover of listenerRemovers . values ( ) ) { try { listenerRemover ( ) ; } catch { } } } this . removeAllListeners ( ) ; this . forwardingEvents . clear ( ) ; } protected forwardEvent ( source , ... events ) { for ( const event of events ) { if ( source !== undefined && event !== undefined && ! EventForwarder . isEmitterEvent ( event ) ) { let sources = this . forwardingEvents . get ( event ) ; if ( sources === undefined ) { sources = new Map ( ) ; this . forwardingEvents . set ( event , sources ) ; } if ( ! sources . has ( source ) ) { const listener = ( ... args ) => this . emit ( event , ... args ) ; sources . set ( source , ( ) => source . off ( event , listener ) ) ; source . on ( event , listener ) ; } } } } protected unforwardEvent ( source , ... events ) { for ( const event of events ) { if ( event !== undefined && ! EventForwarder . isEmitterEvent ( event ) ) { const sources = this . forwardingEvents . get ( event ) ; if ( sources ?. has ( source ) ) { if ( this . listenerCount ( event ) === 0 ) { const listenerRemover = sources . get ( source ) ; if ( listenerRemover !== undefined ) { listenerRemover ( ) ; } sources . delete ( source ) ; if ( sources . size === 0 ) { this . forwardingEvents . delete ( event ) ; } } } } } } }