@xec-sh/core
Version:
Universal shell execution engine
146 lines • 5.41 kB
JavaScript
import { EventEmitter } from 'events';
export class EnhancedEventEmitter extends EventEmitter {
constructor() {
super(...arguments);
this.filteredListeners = new Map();
this.wildcardListeners = new Map();
this.wildcardSetupMap = new Map();
}
onFiltered(event, filterOrListener, listener) {
let filter;
let handler;
if (typeof filterOrListener === 'function') {
handler = filterOrListener;
}
else {
filter = filterOrListener;
handler = listener;
}
const eventStr = String(event);
if (eventStr.includes('*')) {
const pattern = eventStr.replace(/\*/g, '.*');
const regex = new RegExp(`^${pattern}$`);
if (!this.wildcardListeners.has(eventStr)) {
this.wildcardListeners.set(eventStr, []);
}
this.wildcardListeners.get(eventStr).push({ listener: handler, filter });
this.setupWildcardListener(regex, eventStr);
}
else {
if (!this.filteredListeners.has(eventStr)) {
this.filteredListeners.set(eventStr, []);
super.on(eventStr, (data) => {
this.handleFilteredEvent(eventStr, data);
});
}
this.filteredListeners.get(eventStr).push({ listener: handler, filter });
}
return this;
}
handleFilteredEvent(event, data) {
const listeners = this.filteredListeners.get(event) || [];
for (const { listener, filter } of listeners) {
if (this.matchesFilter(data, filter)) {
listener(data);
}
}
}
setupWildcardListener(regex, pattern) {
const eventNames = this.eventNames();
for (const eventName of eventNames) {
if (regex.test(eventName) && !this.hasWildcardListenerSetup(eventName, pattern)) {
this.markWildcardListenerSetup(eventName, pattern);
super.on(eventName, (data) => {
this.handleWildcardEvent(pattern, eventName, data);
});
}
}
const originalEmit = this.emit.bind(this);
this.emit = (event, ...args) => {
const eventStr = String(event);
for (const [pattern, listeners] of this.wildcardListeners.entries()) {
const regex = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`);
if (regex.test(eventStr) && !this.hasWildcardListenerSetup(eventStr, pattern)) {
this.markWildcardListenerSetup(eventStr, pattern);
super.on(eventStr, (data) => {
this.handleWildcardEvent(pattern, eventStr, data);
});
}
}
return originalEmit(event, ...args);
};
}
hasWildcardListenerSetup(event, pattern) {
return this.wildcardSetupMap.get(event)?.has(pattern) || false;
}
markWildcardListenerSetup(event, pattern) {
if (!this.wildcardSetupMap.has(event)) {
this.wildcardSetupMap.set(event, new Set());
}
this.wildcardSetupMap.get(event).add(pattern);
}
handleWildcardEvent(pattern, actualEvent, data) {
const listeners = this.wildcardListeners.get(pattern) || [];
for (const { listener, filter } of listeners) {
if (this.matchesFilter(data, filter)) {
listener(data);
}
}
}
matchesFilter(data, filter) {
if (!filter)
return true;
for (const [key, value] of Object.entries(filter)) {
if (key === 'adapter') {
const adapters = Array.isArray(value) ? value : [value];
if (!adapters.includes(data.adapter)) {
return false;
}
}
else if (data[key] !== value) {
return false;
}
}
return true;
}
offFiltered(event, listener) {
const eventStr = String(event);
if (eventStr.includes('*')) {
const listeners = this.wildcardListeners.get(eventStr);
if (listeners) {
const index = listeners.findIndex(l => l.listener === listener);
if (index !== -1) {
listeners.splice(index, 1);
}
if (listeners.length === 0) {
this.wildcardListeners.delete(eventStr);
}
}
}
else {
const listeners = this.filteredListeners.get(eventStr);
if (listeners) {
const index = listeners.findIndex(l => l.listener === listener);
if (index !== -1) {
listeners.splice(index, 1);
}
if (listeners.length === 0) {
this.filteredListeners.delete(eventStr);
this.removeAllListeners(eventStr);
}
}
}
return this;
}
emitEnhanced(event, data, adapter) {
return this.emit(event, {
...data,
timestamp: new Date(),
adapter
});
}
}
export function createEnhancedEventEmitter() {
return new EnhancedEventEmitter();
}
//# sourceMappingURL=event-emitter.js.map