refactor event listener registration

unified listener creation logic under `createEventListener`, adding support for a flexible `RegisterListenerConfig`. Updated associated tests and improved error handling for unregistered events.
This commit is contained in:
dswbx
2025-01-15 17:46:41 +01:00
parent 6625c9bc48
commit 438e36f185
2 changed files with 35 additions and 28 deletions

View File

@@ -61,6 +61,9 @@ describe("EventManager", async () => {
"sync" "sync"
); );
// don't allow unknown
expect(() => emgr.on("unknown", () => void 0)).toThrow();
emgr.onEvent(InformationalEvent, async (event, name) => { emgr.onEvent(InformationalEvent, async (event, name) => {
call(); call();
expect(name).toBe("informational-event"); expect(name).toBe("informational-event");
@@ -135,14 +138,14 @@ describe("EventManager", async () => {
const call = mock(() => null); const call = mock(() => null);
const emgr = new EventManager({ InformationalEvent }); const emgr = new EventManager({ InformationalEvent });
emgr.onEventOnce( emgr.onEvent(
InformationalEvent, InformationalEvent,
async (event, slug) => { async (event, slug) => {
expect(event).toBeInstanceOf(InformationalEvent); expect(event).toBeInstanceOf(InformationalEvent);
expect(slug).toBe("informational-event"); expect(slug).toBe("informational-event");
call(); call();
}, },
"sync" { mode: "sync", once: true }
); );
expect(emgr.getListeners().length).toBe(1); expect(emgr.getListeners().length).toBe(1);

View File

@@ -1,6 +1,13 @@
import { type Event, InvalidEventReturn } from "./Event"; import { type Event, InvalidEventReturn } from "./Event";
import { EventListener, type ListenerHandler, type ListenerMode } from "./EventListener"; import { EventListener, type ListenerHandler, type ListenerMode } from "./EventListener";
export type RegisterListenerConfig =
| ListenerMode
| {
mode?: ListenerMode;
once?: boolean;
};
export interface EmitsEvents { export interface EmitsEvents {
emgr: EventManager; emgr: EventManager;
} }
@@ -86,9 +93,11 @@ export class EventManager<
return !!this.events.find((e) => slug === e.slug); return !!this.events.find((e) => slug === e.slug);
} }
protected throwIfEventNotRegistered(event: EventClass) { protected throwIfEventNotRegistered(event: EventClass | Event | string) {
if (!this.eventExists(event)) { if (!this.eventExists(event as any)) {
throw new Error(`Event "${event.slug}" not registered`); // @ts-expect-error
const name = event.constructor?.slug ?? event.slug ?? event;
throw new Error(`Event "${name}" not registered`);
} }
} }
@@ -121,44 +130,39 @@ export class EventManager<
return this; return this;
} }
onEvent<ActualEvent extends EventClass, Instance extends InstanceType<ActualEvent>>( protected createEventListener(
event: ActualEvent, _event: EventClass | string,
handler: ListenerHandler<Instance>, handler: ListenerHandler<any>,
mode: ListenerMode = "async" _config: RegisterListenerConfig = "async"
) { ) {
this.throwIfEventNotRegistered(event); const event =
typeof _event === "string" ? this.events.find((e) => e.slug === _event)! : _event;
const listener = new EventListener(event, handler, mode); const config = typeof _config === "string" ? { mode: _config } : _config;
const listener = new EventListener(event, handler, config.mode);
if (config.once) {
listener.once = true;
}
this.addListener(listener as any); this.addListener(listener as any);
} }
onEventOnce<ActualEvent extends EventClass, Instance extends InstanceType<ActualEvent>>( onEvent<ActualEvent extends EventClass, Instance extends InstanceType<ActualEvent>>(
event: ActualEvent, event: ActualEvent,
handler: ListenerHandler<Instance>, handler: ListenerHandler<Instance>,
mode: ListenerMode = "async" config?: RegisterListenerConfig
) { ) {
this.throwIfEventNotRegistered(event); this.createEventListener(event, handler, config);
const listener = new EventListener(event, handler, mode);
listener.once = true;
this.addListener(listener as any);
} }
on<Params = any>( on<Params = any>(
slug: string, slug: string,
handler: ListenerHandler<Event<Params>>, handler: ListenerHandler<Event<Params>>,
mode: ListenerMode = "async" config?: RegisterListenerConfig
) { ) {
const event = this.events.find((e) => e.slug === slug); this.createEventListener(slug, handler, config);
if (!event) {
throw new Error(`Event "${slug}" not registered`);
}
this.onEvent(event, handler, mode);
} }
onAny(handler: ListenerHandler<Event<unknown>>, mode: ListenerMode = "async") { onAny(handler: ListenerHandler<Event<unknown>>, config?: RegisterListenerConfig) {
this.events.forEach((event) => this.onEvent(event, handler, mode)); this.events.forEach((event) => this.onEvent(event, handler, config));
} }
protected executeAsyncs(promises: (() => Promise<void>)[]) { protected executeAsyncs(promises: (() => Promise<void>)[]) {