import type { Disposable } from "../types/Common"; import type { IEventEmitter, ITypedEventEmitter, } from "../interfaces/IEventEmitter"; /** * Simple event emitter implementation that file systems can use * Implementations are free to use their own event system */ export class EventEmitter implements IEventEmitter { private events = new Map>(); on(event: string | symbol, handler: (...args: any[]) => void): Disposable { if (!this.events.has(event)) { this.events.set(event, new Set()); } this.events.get(event)!.add(handler); return { dispose: () => this.off(event, handler), }; } once(event: string | symbol, handler: (...args: any[]) => void): Disposable { const wrappedHandler = (...args: any[]) => { handler(...args); this.off(event, wrappedHandler); }; return this.on(event, wrappedHandler); } emit(event: string | symbol, ...args: any[]): boolean { const handlers = this.events.get(event); if (!handlers || handlers.size === 0) { return false; } handlers.forEach((handler) => { try { handler(...args); } catch (error) { console.error(`Error in event handler for ${String(event)}:`, error); } }); return true; } off(event: string | symbol, handler?: (...args: any[]) => void): void { if (!handler) { this.events.delete(event); return; } const handlers = this.events.get(event); if (handlers) { handlers.delete(handler); if (handlers.size === 0) { this.events.delete(event); } } } removeAllListeners(event?: string | symbol): void { if (event) { this.events.delete(event); } else { this.events.clear(); } } } /** * Typed event emitter implementation */ export class TypedEventEmitter> implements ITypedEventEmitter { private emitter = new EventEmitter(); on( event: K, handler: (payload: T[K]) => void, ): Disposable { return this.emitter.on(event as string, handler); } once( event: K, handler: (payload: T[K]) => void, ): Disposable { return this.emitter.once(event as string, handler); } emit(event: K, payload: T[K]): boolean { return this.emitter.emit(event as string, payload); } off(event: K, handler?: (payload: T[K]) => void): void { this.emitter.off(event as string, handler); } removeAllListeners(event?: K): void { this.emitter.removeAllListeners(event as string); } }