mirror of
https://github.com/tiennm99/gsd-framework.git
synced 2026-06-06 20:13:21 +00:00
fix(01-02): replace Node EventEmitter with browser-compatible implementation
Node's 'events' module doesn't work in browsers. Replaced with custom Map-based implementation that provides the same API but works in both Node.js and browser environments. All 98 tests still pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+24
-12
@@ -1,13 +1,11 @@
|
||||
// src/game/EventEmitter.ts - Typed event emitter wrapper
|
||||
// src/game/EventEmitter.ts - Typed event emitter (browser-compatible)
|
||||
/**
|
||||
* TypedEventEmitter provides a type-safe wrapper around Node's EventEmitter.
|
||||
* It ensures event names and payloads are correctly typed.
|
||||
* TypedEventEmitter provides a type-safe event system that works in browsers.
|
||||
* Custom implementation - no Node.js dependencies.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
export class TypedEventEmitter<T extends object> {
|
||||
private emitter = new EventEmitter();
|
||||
private listeners = new Map<keyof T, Set<(data: T[keyof T]) => void>>();
|
||||
|
||||
/**
|
||||
* Register a listener for an event
|
||||
@@ -16,7 +14,10 @@ export class TypedEventEmitter<T extends object> {
|
||||
* @returns this for chaining
|
||||
*/
|
||||
on<K extends keyof T>(event: K, listener: (data: T[K]) => void): this {
|
||||
this.emitter.on(event as string, listener);
|
||||
if (!this.listeners.has(event)) {
|
||||
this.listeners.set(event, new Set());
|
||||
}
|
||||
this.listeners.get(event)!.add(listener as (data: T[keyof T]) => void);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -27,8 +28,11 @@ export class TypedEventEmitter<T extends object> {
|
||||
* @returns this for chaining
|
||||
*/
|
||||
once<K extends keyof T>(event: K, listener: (data: T[K]) => void): this {
|
||||
this.emitter.once(event as string, listener);
|
||||
return this;
|
||||
const onceWrapper = (data: T[K]) => {
|
||||
this.off(event, onceWrapper);
|
||||
listener(data);
|
||||
};
|
||||
return this.on(event, onceWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,7 +42,12 @@ export class TypedEventEmitter<T extends object> {
|
||||
* @returns true if listeners were called, false otherwise
|
||||
*/
|
||||
emit<K extends keyof T>(event: K, data: T[K]): boolean {
|
||||
return this.emitter.emit(event as string, data);
|
||||
const eventListeners = this.listeners.get(event);
|
||||
if (!eventListeners || eventListeners.size === 0) {
|
||||
return false;
|
||||
}
|
||||
eventListeners.forEach(listener => listener(data as T[keyof T]));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +57,10 @@ export class TypedEventEmitter<T extends object> {
|
||||
* @returns this for chaining
|
||||
*/
|
||||
off<K extends keyof T>(event: K, listener: (data: T[K]) => void): this {
|
||||
this.emitter.off(event as string, listener);
|
||||
const eventListeners = this.listeners.get(event);
|
||||
if (eventListeners) {
|
||||
eventListeners.delete(listener as (data: T[keyof T]) => void);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -58,7 +70,7 @@ export class TypedEventEmitter<T extends object> {
|
||||
* @returns this for chaining
|
||||
*/
|
||||
removeAllListeners<K extends keyof T>(event: K): this {
|
||||
this.emitter.removeAllListeners(event as string);
|
||||
this.listeners.delete(event);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user