import { IBaklavaEvent , IHook } from "../types" ; export type TokenType = object | symbol ; export type Listener < T > = ( ev : T ) => any ; export type HookTap < I , O > = ( i : I ) => O ; /** Main event class for Baklava */ export class BaklavaEvent < T > implements IBaklavaEvent < T > { protected listeners : Map < TokenType , Listener < T > > = new Map ( ) ; param token param listener public addListener ( token , listener ) { this . listeners . set ( token , listener ) ; } param token public removeListener ( token ) { if ( this . listeners . has ( token ) ) { this . listeners . delete ( token ) ; } } param data emit ( data ) { this . listeners . forEach ( ( l ) => l ( data ) ) ; } } /** Extension for the [[BaklavaEvent]] class. A listener can return `false` to prevent
 * this event from happening.
 */ export class PreventableBaklavaEvent < T > extends BaklavaEvent < T > implements IBaklavaEvent < T > { param data returns emit ( data ) { for ( const l of Array . from ( this . listeners . values ( ) ) ) { if ( l ( data ) === false ) { return true ; } } return false ; } } /** Base class for hooks in Baklava */ export abstract class Hook < I , O = I > implements IHook < I , O > { private tapMap : Map < TokenType , HookTap < I , O > > = new Map ( ) ; protected taps : Array < HookTap < I , O > > = [ ] ; public tap ( token , tapFn ) { if ( this . tapMap . has ( token ) ) { this . untap ( token ) ; } this . tapMap . set ( token , tapFn ) ; this . taps . push ( tapFn ) ; } public untap ( token ) { if ( this . tapMap . has ( token ) ) { const tapFn = this . tapMap . get ( token ) ! ; this . tapMap . delete ( token ) ; const i = this . taps . indexOf ( tapFn ) ; if ( i >= 0 ) { this . taps . splice ( i , 1 ) ; } } } public abstract execute ( data ) ; } /** This class will run the taps one after each other and pass the data from every tap to another. */ export class SequentialHook < T > extends Hook < T > { public execute ( data ) { let currentValue = data ; for ( const tapFn of this . taps ) { currentValue = tapFn ( currentValue ) ; } return currentValue ; } }