@t8/event-patterns
Version:
Lightweight event emitter with flexible event type matching
84 lines (82 loc) • 2.05 kB
JavaScript
// 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
};