first commit

This commit is contained in:
douboer@gmail.com
2026-03-03 13:23:14 +08:00
commit 3b7c1d558a
161 changed files with 28120 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
import Disposable from "../base/disposable";
import type {
XEventEmitter as IEventEmitter,
IEventListener,
IEventName
} from "../types";
import type { IEmitterState } from "./interface";
/**
* EventEmitter class
*
* https://nodejs.dev/api/events.html
*
* https://nodejs.dev/en/learn/the-nodejs-event-emitter/
*/
export default class XEventEmitter extends Disposable implements IEventEmitter {
// private store for states
#state: IEmitterState;
constructor() {
super();
this.#state = {
stack: [],
store: new Map()
};
this.register({ dispose: () => this.#state.store.clear() });
}
public on(eventName: IEventName, listener: IEventListener): void {
const store = this.#state.store;
if (store.has(eventName)) {
store.get(eventName)?.add(listener);
} else {
store.set(eventName, new Set([listener]));
}
}
public once(eventName: IEventName, listener: IEventListener): void {
const evlistener = (...args: unknown[]) => {
listener.call(undefined, ...args);
this.off(eventName, evlistener);
};
const store = this.#state.store;
if (store.has(eventName)) {
store.get(eventName)?.add(evlistener);
} else {
store.set(eventName, new Set([evlistener]));
}
}
public off(eventName: IEventName, listener: IEventListener): void {
const all = this.#state.store.get(eventName);
if (all) {
for (const fn of all) {
if (fn === listener) {
all.delete(listener);
break;
}
}
}
}
public emit(eventName: IEventName, ...args: unknown[]): void {
if (this.isDisposed) return;
const stack = this.#state.stack;
if (stack.includes(eventName)) return;
const listeners = this.#state.store.get(eventName);
if (listeners) {
stack.push(eventName);
for (const fn of listeners) {
fn.call(undefined, ...args);
}
stack.pop();
}
return;
}
}

View File

@@ -0,0 +1,9 @@
import type { IEventName, IEventListener } from "../types";
/**
* State of the Event Emitter
*/
export type IEmitterState = {
store: Map<IEventName, Set<IEventListener>>;
stack: IEventName[];
};