UNPKG

@dbs-portal/core-module-registry

Version:

Core module registry system for automatic module discovery and registration

214 lines 6.72 kB
/** * Browser Event Emitter * * Browser-compatible event emitter that provides the same API as Node.js EventEmitter * but works in both browser and Node.js environments without external dependencies. */ export class BrowserEventEmitter { events = new Map(); onceEvents = new Map(); maxListeners = 10; /** * Add a listener for the specified event */ on(event, listener) { if (!this.events.has(event)) { this.events.set(event, new Set()); } const listeners = this.events.get(event); listeners.add(listener); // Warn if too many listeners if (listeners.size > this.maxListeners) { console.warn(`MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ${listeners.size} ${event} listeners added.`); } return this; } /** * Add a one-time listener for the specified event */ once(event, listener) { if (!this.onceEvents.has(event)) { this.onceEvents.set(event, new Set()); } this.onceEvents.get(event).add(listener); return this; } /** * Remove a listener for the specified event */ off(event, listener) { const listeners = this.events.get(event); if (listeners) { listeners.delete(listener); if (listeners.size === 0) { this.events.delete(event); } } const onceListeners = this.onceEvents.get(event); if (onceListeners) { onceListeners.delete(listener); if (onceListeners.size === 0) { this.onceEvents.delete(event); } } return this; } /** * Emit an event to all listeners */ emit(event, ...args) { let hasListeners = false; // Emit to regular listeners const listeners = this.events.get(event); if (listeners && listeners.size > 0) { hasListeners = true; // Create array to avoid issues with listeners being removed during iteration const listenersArray = Array.from(listeners); for (const listener of listenersArray) { try { listener.apply(this, args); } catch (error) { // Emit error event if listener throws this.emitError(error); } } } // Emit to once listeners and remove them const onceListeners = this.onceEvents.get(event); if (onceListeners && onceListeners.size > 0) { hasListeners = true; const onceListenersArray = Array.from(onceListeners); this.onceEvents.delete(event); // Remove all once listeners for (const listener of onceListenersArray) { try { listener.apply(this, args); } catch (error) { this.emitError(error); } } } return hasListeners; } /** * Remove all listeners for a specific event or all events */ removeAllListeners(event) { if (event) { this.events.delete(event); this.onceEvents.delete(event); } else { this.events.clear(); this.onceEvents.clear(); } return this; } /** * Get the number of listeners for an event */ listenerCount(event) { const regularCount = this.events.get(event)?.size || 0; const onceCount = this.onceEvents.get(event)?.size || 0; return regularCount + onceCount; } /** * Get all listeners for an event */ listeners(event) { const regularListeners = Array.from(this.events.get(event) || []); const onceListeners = Array.from(this.onceEvents.get(event) || []); return [...regularListeners, ...onceListeners]; } /** * Set the maximum number of listeners before warning */ setMaxListeners(n) { this.maxListeners = n; return this; } /** * Get the maximum number of listeners */ getMaxListeners() { return this.maxListeners; } /** * Get all event names that have listeners */ eventNames() { const regularEvents = Array.from(this.events.keys()); const onceEvents = Array.from(this.onceEvents.keys()); return [...new Set([...regularEvents, ...onceEvents])]; } /** * Add listener (alias for on) */ addListener(event, listener) { return this.on(event, listener); } /** * Remove listener (alias for off) */ removeListener(event, listener) { return this.off(event, listener); } /** * Prepend listener to the beginning of the listeners array */ prependListener(event, listener) { // Since we use Set, we can't really prepend, but we can simulate it // by removing and re-adding all listeners in the right order const listeners = this.events.get(event); if (listeners) { const existingListeners = Array.from(listeners); listeners.clear(); listeners.add(listener); existingListeners.forEach(l => listeners.add(l)); } else { this.on(event, listener); } return this; } /** * Prepend one-time listener */ prependOnceListener(event, listener) { const onceListeners = this.onceEvents.get(event); if (onceListeners) { const existingListeners = Array.from(onceListeners); onceListeners.clear(); onceListeners.add(listener); existingListeners.forEach(l => onceListeners.add(l)); } else { this.once(event, listener); } return this; } /** * Emit error event safely */ emitError(error) { // Avoid infinite recursion if error listener throws if (this.listenerCount('error') > 0) { try { this.emit('error', error); } catch (e) { console.error('EventEmitter error in error handler:', e); } } else { // If no error listeners, log to console console.error('Unhandled EventEmitter error:', error); } } } // Create a default instance for compatibility export const defaultEventEmitter = new BrowserEventEmitter(); // Export as default for easier importing export default BrowserEventEmitter; //# sourceMappingURL=BrowserEventEmitter.js.map