UNPKG

@t8/event-patterns

Version:

Lightweight event emitter with flexible event type matching

84 lines (82 loc) 2.05 kB
// src/matchPattern.ts function toObject(x) { return x.reduce((p, v, k) => { p[String(k)] = v; return p; }, {}); } function matchPattern(pattern, value) { if (Array.isArray(pattern)) { for (let p of pattern) { let matches = matchPattern(p, value); if (matches) return matches; } return null; } if (pattern instanceof RegExp) { let matches = String(value).match(pattern); if (matches) return { ...toObject(Array.from(matches).slice(1)), ...matches.groups }; } if (pattern === "*" || pattern === value) return {}; return null; } // src/EventEmitter.ts function getId() { return Math.random().toString(36).slice(2); } var EventEmitter = class { _listeners; constructor() { this._listeners = []; } on(type, handler) { return this._addListener(type, handler); } once(type, handler) { return this._addListener(type, handler, true); } addListener(type, handler) { return this._addListener(type, handler); } _addListener(type, handler, once = false) { if (typeof handler !== "function") throw new Error("handler is not a function"); let id = getId(); this._listeners.push({ id, type, handler, once }); return { remove: () => this._removeListener(id) }; } _removeListener(id) { for (let i = this._listeners.length - 1; i >= 0; i--) { if (this._listeners[i].id === id) this._listeners.splice(i, 1); } } emit(type, data) { let event = { type, data }; for (let listener of this._listeners) { if (this.matches(listener, event)) { if (listener.once) this._removeListener(listener.id); listener.handler(this.toHandlerPayload(listener, event)); } } } matches(listener, event) { return matchPattern(listener.type, event.type) !== null; } toHandlerPayload(listener, event) { let params = matchPattern(listener.type, event.type); return { ...event, params }; } }; export { EventEmitter, matchPattern };