From 5eb2f5eeb4e846649957630127be2137845cdfe8 Mon Sep 17 00:00:00 2001 From: FlorianWoelki Date: Sat, 6 Jul 2024 10:03:56 +0200 Subject: [PATCH] refactor: restructure events library --- src/lib/event/event.test.ts | 31 +++++++++++---------- src/lib/event/event.ts | 55 ++++++++++++++++++++----------------- src/lib/event/events.ts | 11 ++++++-- src/main.ts | 2 +- 4 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/lib/event/event.test.ts b/src/lib/event/event.test.ts index b49620e2..45ef2442 100644 --- a/src/lib/event/event.test.ts +++ b/src/lib/event/event.test.ts @@ -1,6 +1,5 @@ import { describe, it, vi, expect, beforeEach } from 'vitest'; import { EventEmitter } from './event'; -import { AllIconsLoadedEvent } from './events'; describe('EventEmitter', () => { let emitter: EventEmitter; @@ -11,32 +10,34 @@ describe('EventEmitter', () => { it('should register and emit event listeners', () => { const listener = vi.fn(); - emitter.on('allIconsLoaded', listener); + emitter.on('allIconsLoaded', listener); - emitter.emit({ type: 'allIconsLoaded' }); + emitter.emit('allIconsLoaded'); - expect(listener).toHaveBeenCalledWith({ type: 'allIconsLoaded' }); + expect(listener).toHaveBeenCalledWith({ payload: undefined }); expect(listener).toHaveBeenCalledTimes(1); }); it('should unregister event listeners', () => { const listener = vi.fn(); - emitter.on('allIconsLoaded', listener); - emitter.off('allIconsLoaded', listener); + emitter.on('allIconsLoaded', listener); + emitter.off('allIconsLoaded', listener); - emitter.emit({ type: 'allIconsLoaded' }); + emitter.emit('allIconsLoaded'); expect(listener).not.toHaveBeenCalled(); }); it('should support once-only event listeners', () => { const listener = vi.fn(); - emitter.once('allIconsLoaded', listener); + emitter.once('allIconsLoaded', listener); - emitter.emit({ type: 'allIconsLoaded' }); - emitter.emit({ type: 'allIconsLoaded' }); + emitter.emit('allIconsLoaded'); + emitter.emit('allIconsLoaded'); - expect(listener).toHaveBeenCalledWith({ type: 'allIconsLoaded' }); + expect(listener).toHaveBeenCalledWith({ + payload: undefined, + }); expect(listener).toHaveBeenCalledTimes(1); }); @@ -45,11 +46,11 @@ describe('EventEmitter', () => { const listener2 = vi.fn(); const listener3 = vi.fn(); - emitter.on('allIconsLoaded', listener1, 1); - emitter.on('allIconsLoaded', listener2, 2); - emitter.on('allIconsLoaded', listener3, 3); + emitter.on('allIconsLoaded', listener1, 1); + emitter.on('allIconsLoaded', listener2, 2); + emitter.on('allIconsLoaded', listener3, 3); - emitter.emit({ type: 'allIconsLoaded' }); + emitter.emit('allIconsLoaded'); expect(listener3).toHaveBeenCalled(); expect(listener2).toHaveBeenCalled(); diff --git a/src/lib/event/event.ts b/src/lib/event/event.ts index 9967d6fa..b7df2752 100644 --- a/src/lib/event/event.ts +++ b/src/lib/event/event.ts @@ -1,66 +1,71 @@ -type Events = 'allIconsLoaded'; +import type { EventType, EventMap, AnyEvent } from './events'; -export interface Event { - type: Events; +export interface Event

{ + payload?: P; } -type EventListener = (event: T) => void; +type EventListener = (event: E) => void; -interface ListenerEntry { - listener: EventListener; +interface ListenerEntry { + listener: EventListener; once: boolean; priority: number; } export class EventEmitter { - private listeners: { [key: string]: ListenerEntry[] } = {}; + private listeners: { [K in EventType]?: ListenerEntry[] } = {}; - on( - type: T['type'], - listener: EventListener, - priority: number = 0, + on( + type: K, + listener: EventListener, + priority = 0, ): void { this.listeners[type] ??= []; - this.listeners[type].push({ listener, once: false, priority }); + this.listeners[type]?.push({ listener, once: false, priority }); this.sortListeners(type); } - once( - type: T['type'], - listener: EventListener, - priority: number = 0, + once( + type: K, + listener: EventListener, + priority = 0, ): void { this.listeners[type] ??= []; - this.listeners[type].push({ listener, once: true, priority }); + this.listeners[type]?.push({ listener, once: true, priority }); this.sortListeners(type); } - off(type: T['type'], listener: EventListener): void { + off( + type: K, + listener: EventListener, + ): void { if (!this.listeners[type]) { return; } - this.listeners[type] = this.listeners[type].filter( + this.listeners[type] = this.listeners[type]?.filter( (entry) => entry.listener !== listener, ); } - emit(event: T): void { - if (!this.listeners[event.type]) { + emit(type: K, payload?: EventMap[K]['payload']): void { + const listeners = this.listeners[type]; + if (!listeners) { return; } - this.listeners[event.type].forEach((entry) => { + const event = { payload } as EventMap[K]; + listeners.slice().forEach((entry) => { entry.listener(event); if (entry.once) { - this.off(event.type, entry.listener); + this.off(type, entry.listener); } }); } - private sortListeners(type: string): void { + private sortListeners(type: EventType): void { if (this.listeners[type]) { - this.listeners[type].sort((a, b) => b.priority - a.priority); + this.listeners[type]?.sort((a, b) => b.priority - a.priority); } } } diff --git a/src/lib/event/events.ts b/src/lib/event/events.ts index 0c82a062..178b8741 100644 --- a/src/lib/event/events.ts +++ b/src/lib/event/events.ts @@ -1,5 +1,10 @@ import { Event } from './event'; -export interface AllIconsLoadedEvent extends Event { - type: 'allIconsLoaded'; -} +export type AllIconsLoadedEvent = Event; + +export type EventMap = { + allIconsLoaded: AllIconsLoadedEvent; +}; + +export type EventType = keyof EventMap; +export type AnyEvent = EventMap[EventType]; diff --git a/src/main.ts b/src/main.ts index 9b64674f..7ca1b0d3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -394,7 +394,7 @@ export default class IconFolderPlugin extends Plugin { resetPreloadedIcons(); } - this.eventEmitter.emit({ type: 'allIconsLoaded' }); + this.eventEmitter.emit('allIconsLoaded'); }); if (this.getSettings().iconInFrontmatterEnabled) {