@xyo-network/module-events
Advanced tools
Comparing version 2.52.1 to 2.53.0-rc.1
@@ -8,4 +8,2 @@ "use strict"; | ||
const resolvedPromise = Promise.resolve(); | ||
const listenerAdded = 'listenerAdded'; | ||
const listenerRemoved = 'listenerRemoved'; | ||
let canEmitMetaEvents = false; | ||
@@ -23,6 +21,8 @@ let isGlobalDebugEnabled = false; | ||
} | ||
const isMetaEvent = (eventName) => eventName === listenerAdded || eventName === listenerRemoved; | ||
const isMetaEvent = (eventName) => eventName === 'listenerAdded' || eventName === 'listenerRemoved'; | ||
class Events { | ||
constructor(options = {}) { | ||
var _a; | ||
//this is here to be able to query the type, not use | ||
this.eventData = {}; | ||
Events.anyMap.set(this, new Set()); | ||
@@ -89,34 +89,7 @@ Events.eventsMap.set(this, new Map()); | ||
} | ||
emit(eventName, eventData) { | ||
emit(eventName, eventArgs) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
yield this.emitInternal(eventName, eventData); | ||
yield this.emitInternal(eventName, eventArgs); | ||
}); | ||
} | ||
emitInternal(eventName, eventArgs) { | ||
var _a; | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
assertEventName(eventName); | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`'); | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs); | ||
const listeners = (_a = this.getListeners(eventName)) !== null && _a !== void 0 ? _a : new Set(); | ||
const anyListeners = (0, assert_1.assertEx)(Events.anyMap.get(this)); | ||
const staticListeners = [...listeners]; | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]; | ||
yield resolvedPromise; | ||
yield Promise.all([ | ||
...staticListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
if (listeners.has(listener)) { | ||
return yield listener(eventArgs); | ||
} | ||
})), | ||
...staticAnyListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
if (anyListeners.has(listener)) { | ||
return yield listener(eventName, eventArgs); | ||
} | ||
})), | ||
]); | ||
}); | ||
} | ||
emitMetaEvent(eventName, eventArgs) { | ||
@@ -127,3 +100,3 @@ return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
canEmitMetaEvents = true; | ||
yield this.emitInternal(eventName, eventArgs); | ||
yield this.emitMetaEventInternal(eventName, eventArgs); | ||
} | ||
@@ -136,3 +109,3 @@ finally { | ||
} | ||
emitSerial(eventName, eventData) { | ||
emitSerial(eventName, eventArgs) { | ||
var _a; | ||
@@ -144,3 +117,3 @@ return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
} | ||
this.logIfDebugEnabled('emitSerial', eventName, eventData); | ||
this.logIfDebugEnabled('emitSerial', eventName, eventArgs); | ||
const listeners = (_a = this.getListeners(eventName)) !== null && _a !== void 0 ? _a : new Set(); | ||
@@ -153,3 +126,3 @@ const anyListeners = (0, assert_1.assertEx)(Events.anyMap.get(this)); | ||
if (listeners.has(listener)) { | ||
yield listener(eventData); | ||
yield listener(eventArgs); | ||
} | ||
@@ -159,3 +132,3 @@ } | ||
if (anyListeners.has(listener)) { | ||
yield listener(eventName, eventData); | ||
yield listener(eventName, eventArgs); | ||
} | ||
@@ -212,3 +185,3 @@ } | ||
if (!isMetaEvent(eventName)) { | ||
(0, forget_1.forget)(this.emitMetaEvent(listenerRemoved, { eventName, listener })); | ||
(0, forget_1.forget)(this.emitMetaEvent('listenerRemoved', { eventName, listener: listener })); | ||
} | ||
@@ -218,7 +191,7 @@ } | ||
offAny(listener) { | ||
var _a; | ||
assertListener(listener); | ||
this.logIfDebugEnabled('unsubscribeAny', undefined, undefined); | ||
(_a = Events.anyMap.get(this)) === null || _a === void 0 ? void 0 : _a.delete(listener); | ||
(0, forget_1.forget)(this.emitMetaEvent(listenerRemoved, { listener })); | ||
const typedMap = Events.anyMap.get(this); | ||
typedMap === null || typedMap === void 0 ? void 0 : typedMap.delete(listener); | ||
(0, forget_1.forget)(this.emitMetaEvent('listenerRemoved', { listener: listener })); | ||
} | ||
@@ -239,3 +212,3 @@ on(eventNames, listener) { | ||
if (!isMetaEvent(eventName)) { | ||
(0, forget_1.forget)(this.emitMetaEvent(listenerAdded, { eventName, listener })); | ||
(0, forget_1.forget)(this.emitMetaEvent('listenerAdded', { eventName, listener: listener })); | ||
} | ||
@@ -250,13 +223,67 @@ } | ||
(_a = Events.anyMap.get(this)) === null || _a === void 0 ? void 0 : _a.add(listener); | ||
(0, forget_1.forget)(this.emitMetaEvent(listenerAdded, { listener })); | ||
(0, forget_1.forget)(this.emitMetaEvent('listenerAdded', { listener: listener })); | ||
return this.offAny.bind(this, listener); | ||
} | ||
once(eventNames, listener) { | ||
once(eventName, listener) { | ||
const subListener = (args) => tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
this.off(eventNames, subListener); | ||
this.off(eventName, subListener); | ||
yield listener(args); | ||
}); | ||
this.on(eventNames, subListener); | ||
return this.off.bind(this, eventNames, subListener); | ||
this.on(eventName, subListener); | ||
return this.off.bind(this, eventName, subListener); | ||
} | ||
emitInternal(eventName, eventArgs) { | ||
var _a; | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
assertEventName(eventName); | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`'); | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs); | ||
const listeners = (_a = this.getListeners(eventName)) !== null && _a !== void 0 ? _a : new Set(); | ||
const anyListeners = (0, assert_1.assertEx)(Events.anyMap.get(this)); | ||
const staticListeners = [...listeners]; | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]; | ||
yield resolvedPromise; | ||
yield Promise.all([ | ||
...staticListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
if (listeners.has(listener)) { | ||
return yield listener(eventArgs); | ||
} | ||
})), | ||
...staticAnyListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
if (anyListeners.has(listener)) { | ||
return yield listener(eventName, eventArgs); | ||
} | ||
})), | ||
]); | ||
}); | ||
} | ||
emitMetaEventInternal(eventName, eventArgs) { | ||
var _a; | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
assertEventName(eventName); | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`'); | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs); | ||
const listeners = (_a = this.getListeners(eventName)) !== null && _a !== void 0 ? _a : new Set(); | ||
const anyListeners = (0, assert_1.assertEx)(Events.anyMap.get(this)); | ||
const staticListeners = [...listeners]; | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]; | ||
yield resolvedPromise; | ||
yield Promise.all([ | ||
...staticListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
if (listeners.has(listener)) { | ||
return yield listener(eventArgs); | ||
} | ||
})), | ||
...staticAnyListeners.map((listener) => tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
if (anyListeners.has(listener)) { | ||
return yield listener(eventName, eventArgs); | ||
} | ||
})), | ||
]); | ||
}); | ||
} | ||
} | ||
@@ -263,0 +290,0 @@ exports.Events = Events; |
import { assertEx } from '@xylabs/assert'; | ||
import { forget } from '@xylabs/forget'; | ||
const resolvedPromise = Promise.resolve(); | ||
const listenerAdded = 'listenerAdded'; | ||
const listenerRemoved = 'listenerRemoved'; | ||
let canEmitMetaEvents = false; | ||
@@ -18,3 +16,3 @@ let isGlobalDebugEnabled = false; | ||
} | ||
const isMetaEvent = (eventName) => eventName === listenerAdded || eventName === listenerRemoved; | ||
const isMetaEvent = (eventName) => eventName === 'listenerAdded' || eventName === 'listenerRemoved'; | ||
export class Events { | ||
@@ -25,2 +23,4 @@ static anyMap = new WeakMap(); | ||
debug; | ||
//this is here to be able to query the type, not use | ||
eventData = {}; | ||
constructor(options = {}) { | ||
@@ -87,29 +87,5 @@ Events.anyMap.set(this, new Set()); | ||
} | ||
async emit(eventName, eventData) { | ||
await this.emitInternal(eventName, eventData); | ||
async emit(eventName, eventArgs) { | ||
await this.emitInternal(eventName, eventArgs); | ||
} | ||
async emitInternal(eventName, eventArgs) { | ||
assertEventName(eventName); | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`'); | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs); | ||
const listeners = this.getListeners(eventName) ?? new Set(); | ||
const anyListeners = assertEx(Events.anyMap.get(this)); | ||
const staticListeners = [...listeners]; | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]; | ||
await resolvedPromise; | ||
await Promise.all([ | ||
...staticListeners.map(async (listener) => { | ||
if (listeners.has(listener)) { | ||
return await listener(eventArgs); | ||
} | ||
}), | ||
...staticAnyListeners.map(async (listener) => { | ||
if (anyListeners.has(listener)) { | ||
return await listener(eventName, eventArgs); | ||
} | ||
}), | ||
]); | ||
} | ||
async emitMetaEvent(eventName, eventArgs) { | ||
@@ -119,3 +95,3 @@ if (isMetaEvent(eventName)) { | ||
canEmitMetaEvents = true; | ||
await this.emitInternal(eventName, eventArgs); | ||
await this.emitMetaEventInternal(eventName, eventArgs); | ||
} | ||
@@ -127,3 +103,3 @@ finally { | ||
} | ||
async emitSerial(eventName, eventData) { | ||
async emitSerial(eventName, eventArgs) { | ||
assertEventName(eventName); | ||
@@ -133,3 +109,3 @@ if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
} | ||
this.logIfDebugEnabled('emitSerial', eventName, eventData); | ||
this.logIfDebugEnabled('emitSerial', eventName, eventArgs); | ||
const listeners = this.getListeners(eventName) ?? new Set(); | ||
@@ -142,3 +118,3 @@ const anyListeners = assertEx(Events.anyMap.get(this)); | ||
if (listeners.has(listener)) { | ||
await listener(eventData); | ||
await listener(eventArgs); | ||
} | ||
@@ -148,3 +124,3 @@ } | ||
if (anyListeners.has(listener)) { | ||
await listener(eventName, eventData); | ||
await listener(eventName, eventArgs); | ||
} | ||
@@ -198,3 +174,3 @@ } | ||
if (!isMetaEvent(eventName)) { | ||
forget(this.emitMetaEvent(listenerRemoved, { eventName, listener })); | ||
forget(this.emitMetaEvent('listenerRemoved', { eventName, listener: listener })); | ||
} | ||
@@ -206,4 +182,5 @@ } | ||
this.logIfDebugEnabled('unsubscribeAny', undefined, undefined); | ||
Events.anyMap.get(this)?.delete(listener); | ||
forget(this.emitMetaEvent(listenerRemoved, { listener })); | ||
const typedMap = Events.anyMap.get(this); | ||
typedMap?.delete(listener); | ||
forget(this.emitMetaEvent('listenerRemoved', { listener: listener })); | ||
} | ||
@@ -224,3 +201,3 @@ on(eventNames, listener) { | ||
if (!isMetaEvent(eventName)) { | ||
forget(this.emitMetaEvent(listenerAdded, { eventName, listener })); | ||
forget(this.emitMetaEvent('listenerAdded', { eventName, listener: listener })); | ||
} | ||
@@ -234,14 +211,62 @@ } | ||
Events.anyMap.get(this)?.add(listener); | ||
forget(this.emitMetaEvent(listenerAdded, { listener })); | ||
forget(this.emitMetaEvent('listenerAdded', { listener: listener })); | ||
return this.offAny.bind(this, listener); | ||
} | ||
once(eventNames, listener) { | ||
once(eventName, listener) { | ||
const subListener = async (args) => { | ||
this.off(eventNames, subListener); | ||
this.off(eventName, subListener); | ||
await listener(args); | ||
}; | ||
this.on(eventNames, subListener); | ||
return this.off.bind(this, eventNames, subListener); | ||
this.on(eventName, subListener); | ||
return this.off.bind(this, eventName, subListener); | ||
} | ||
async emitInternal(eventName, eventArgs) { | ||
assertEventName(eventName); | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`'); | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs); | ||
const listeners = this.getListeners(eventName) ?? new Set(); | ||
const anyListeners = assertEx(Events.anyMap.get(this)); | ||
const staticListeners = [...listeners]; | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]; | ||
await resolvedPromise; | ||
await Promise.all([ | ||
...staticListeners.map(async (listener) => { | ||
if (listeners.has(listener)) { | ||
return await listener(eventArgs); | ||
} | ||
}), | ||
...staticAnyListeners.map(async (listener) => { | ||
if (anyListeners.has(listener)) { | ||
return await listener(eventName, eventArgs); | ||
} | ||
}), | ||
]); | ||
} | ||
async emitMetaEventInternal(eventName, eventArgs) { | ||
assertEventName(eventName); | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`'); | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs); | ||
const listeners = this.getListeners(eventName) ?? new Set(); | ||
const anyListeners = assertEx(Events.anyMap.get(this)); | ||
const staticListeners = [...listeners]; | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]; | ||
await resolvedPromise; | ||
await Promise.all([ | ||
...staticListeners.map(async (listener) => { | ||
if (listeners.has(listener)) { | ||
return await listener(eventArgs); | ||
} | ||
}), | ||
...staticAnyListeners.map(async (listener) => { | ||
if (anyListeners.has(listener)) { | ||
return await listener(eventName, eventArgs); | ||
} | ||
}), | ||
]); | ||
} | ||
} | ||
//# sourceMappingURL=Events.js.map |
@@ -27,13 +27,14 @@ import { EventAnyListener, EventArgs, EventData, EventFunctions, EventListener, EventName } from '../model'; | ||
eventName?: keyof TEventData; | ||
listener: EventListener<TEventData>; | ||
listener: EventListener<TEventData[keyof TEventData]> | EventAnyListener<TEventData[keyof TEventData]>; | ||
}; | ||
listenerRemoved: { | ||
eventName?: keyof TEventData; | ||
listener: EventListener<TEventData>; | ||
listener: EventListener<TEventData[keyof TEventData]> | EventAnyListener<TEventData[keyof TEventData]>; | ||
}; | ||
}; | ||
export declare class Events<TEventData extends EventData> implements EventFunctions<TEventData> { | ||
static anyMap: WeakMap<object, Set<EventAnyListener<any>>>; | ||
static eventsMap: WeakMap<object, Map<keyof EventData, Set<EventListener<any>>>>; | ||
export declare class Events<TEventData extends EventData = EventData> implements EventFunctions<TEventData> { | ||
static anyMap: WeakMap<object, Set<EventAnyListener<EventArgs>>>; | ||
static eventsMap: WeakMap<object, Map<PropertyKey, Set<EventListener<EventArgs>>>>; | ||
debug?: DebugOptions<any>; | ||
eventData: TEventData; | ||
constructor(options?: Options<TEventData>); | ||
@@ -43,15 +44,16 @@ static get isDebugEnabled(): boolean; | ||
clearListeners(eventNames: keyof TEventData | (keyof TEventData)[]): void; | ||
emit(eventName: keyof TEventData, eventData?: TEventData[keyof TEventData]): Promise<void>; | ||
emitInternal<TEventName extends EventName, TEventArgs extends EventArgs>(eventName: TEventName, eventArgs?: TEventArgs): Promise<void>; | ||
emitMetaEvent<TEventName extends EventName, TEventArgs extends EventArgs>(eventName: TEventName, eventArgs: TEventArgs): Promise<void>; | ||
emitSerial(eventName: keyof TEventData, eventData: TEventData[keyof TEventData]): Promise<void>; | ||
getListeners(eventName: keyof TEventData): Set<EventListener<any>> | undefined; | ||
emit<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void>; | ||
emitMetaEvent<TEventName extends keyof MetaEventData<TEventData>>(eventName: TEventName, eventArgs: MetaEventData<TEventData>[TEventName]): Promise<void>; | ||
emitSerial<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void>; | ||
getListeners(eventName: keyof TEventData): Set<EventListener<EventArgs>> | undefined; | ||
listenerCount(eventNames: keyof TEventData | (keyof TEventData)[]): number; | ||
logIfDebugEnabled<TEventName extends EventName, TEventArgs extends EventArgs>(type: string, eventName?: TEventName, eventArgs?: TEventArgs): void; | ||
off(eventNames: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): void; | ||
offAny(listener: EventAnyListener<TEventData>): void; | ||
on(eventNames: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): () => void; | ||
onAny(listener: EventAnyListener<TEventData>): () => void; | ||
once(eventNames: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): () => void; | ||
off<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>): void; | ||
offAny(listener: EventAnyListener): void; | ||
on<TEventName extends keyof TEventData = keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>): () => void; | ||
onAny(listener: EventAnyListener): () => void; | ||
once<TEventName extends keyof TEventData>(eventName: TEventName, listener: EventListener<TEventData[TEventName]>): () => void; | ||
private emitInternal; | ||
private emitMetaEventInternal; | ||
} | ||
//# sourceMappingURL=Events.d.ts.map |
@@ -1,2 +0,1 @@ | ||
import { BaseParams } from '@xyo-network/core'; | ||
import { Promisable } from '@xyo-network/promise'; | ||
@@ -9,21 +8,16 @@ export type EventName = PropertyKey; | ||
export type EventUnsubscribeFunction = () => void; | ||
export type EventAnyListener<TEventData extends EventData = EventData> = (eventName: keyof TEventData, eventData?: TEventData[keyof TEventData]) => Promisable<void>; | ||
export type EventListener<TEventData extends EventData = EventData> = (eventData?: TEventData[keyof TEventData]) => Promisable<void>; | ||
export type OncePromise<T> = { | ||
off(): void; | ||
} & Promise<T>; | ||
export type EventAnyListener<TEventArgs extends EventArgs = EventArgs> = (eventName: EventName, eventData: TEventArgs) => Promisable<void>; | ||
export type EventListener<TEventArgs extends EventArgs = EventArgs> = (eventData: TEventArgs) => Promisable<void>; | ||
export interface EventFunctions<TEventData extends EventData> { | ||
eventData: TEventData; | ||
clearListeners(eventNames: keyof TEventData | (keyof TEventData)[]): void; | ||
emit(eventName: keyof TEventData, eventData: TEventData[keyof TEventData]): Promise<void>; | ||
emitSerial(eventName: keyof TEventData, eventData: TEventData[keyof TEventData]): Promise<void>; | ||
emit<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void>; | ||
emitSerial<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void>; | ||
listenerCount(eventNames: keyof TEventData | (keyof TEventData)[]): number; | ||
off(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): void; | ||
offAny(listener: EventAnyListener<TEventData> | Promise<void>): void; | ||
on(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): EventUnsubscribeFunction; | ||
onAny(listener: EventAnyListener<TEventData>): EventUnsubscribeFunction; | ||
once(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): EventUnsubscribeFunction; | ||
off<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>): void; | ||
offAny(listener: EventAnyListener | Promise<void>): void; | ||
on<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>): EventUnsubscribeFunction; | ||
onAny(listener: EventAnyListener): EventUnsubscribeFunction; | ||
once<TEventName extends keyof TEventData>(eventName: TEventName, listener: EventListener<TEventData[TEventName]>): EventUnsubscribeFunction; | ||
} | ||
export type EventDataParams<TEventData extends EventData | undefined = undefined, TParams extends BaseParams = BaseParams> = TParams & { | ||
eventData?: TEventData extends EventData ? TEventData | any : any; | ||
}; | ||
//# sourceMappingURL=Event.d.ts.map |
@@ -15,4 +15,3 @@ { | ||
"@xylabs/forget": "^2.7.4", | ||
"@xyo-network/core": "^2.52.1", | ||
"@xyo-network/promise": "^2.52.1" | ||
"@xyo-network/promise": "^2.53.0-rc.1" | ||
}, | ||
@@ -57,3 +56,4 @@ "devDependencies": { | ||
"types": "dist/types/index.d.ts", | ||
"version": "2.52.1" | ||
"version": "2.53.0-rc.1", | ||
"stableVersion": "2.52.1" | ||
} |
@@ -38,8 +38,11 @@ import { assertEx } from '@xylabs/assert' | ||
const listenerAdded = 'listenerAdded' | ||
const listenerRemoved = 'listenerRemoved' | ||
export type MetaEventData<TEventData extends EventData> = { | ||
listenerAdded: { eventName?: keyof TEventData; listener: EventListener<TEventData> } | ||
listenerRemoved: { eventName?: keyof TEventData; listener: EventListener<TEventData> } | ||
listenerAdded: { | ||
eventName?: keyof TEventData | ||
listener: EventListener<TEventData[keyof TEventData]> | EventAnyListener<TEventData[keyof TEventData]> | ||
} | ||
listenerRemoved: { | ||
eventName?: keyof TEventData | ||
listener: EventListener<TEventData[keyof TEventData]> | EventAnyListener<TEventData[keyof TEventData]> | ||
} | ||
} | ||
@@ -62,7 +65,7 @@ | ||
const isMetaEvent = (eventName: EventName) => eventName === listenerAdded || eventName === listenerRemoved | ||
const isMetaEvent = (eventName: EventName) => eventName === 'listenerAdded' || eventName === 'listenerRemoved' | ||
export class Events<TEventData extends EventData> implements EventFunctions<TEventData> { | ||
static anyMap = new WeakMap<object, Set<EventAnyListener<any>>>() | ||
static eventsMap = new WeakMap<object, Map<keyof EventData, Set<EventListener<any>>>>() | ||
export class Events<TEventData extends EventData = EventData> implements EventFunctions<TEventData> { | ||
static anyMap = new WeakMap<object, Set<EventAnyListener>>() | ||
static eventsMap = new WeakMap<object, Map<EventName, Set<EventListener>>>() | ||
@@ -72,5 +75,8 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
//this is here to be able to query the type, not use | ||
eventData = {} as TEventData | ||
constructor(options: Options<TEventData> = {}) { | ||
Events.anyMap.set(this, new Set<EventAnyListener<TEventData>>()) | ||
Events.eventsMap.set(this, new Map<keyof TEventData, Set<EventListener<TEventData>>>()) | ||
Events.anyMap.set(this, new Set<EventAnyListener>()) | ||
Events.eventsMap.set(this, new Map<keyof TEventData, Set<EventListener>>()) | ||
@@ -145,40 +151,11 @@ this.debug = options.debug | ||
async emit(eventName: keyof TEventData, eventData?: TEventData[keyof TEventData]) { | ||
await this.emitInternal(eventName, eventData) | ||
async emit<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]) { | ||
await this.emitInternal(eventName, eventArgs) | ||
} | ||
async emitInternal<TEventName extends EventName, TEventArgs extends EventArgs>(eventName: TEventName, eventArgs?: TEventArgs) { | ||
assertEventName(eventName) | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`') | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs) | ||
const listeners = this.getListeners(eventName) ?? new Set() | ||
const anyListeners = assertEx(Events.anyMap.get(this)) | ||
const staticListeners = [...listeners] | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners] | ||
await resolvedPromise | ||
await Promise.all([ | ||
...staticListeners.map(async (listener) => { | ||
if (listeners.has(listener)) { | ||
return await listener(eventArgs) | ||
} | ||
}), | ||
...staticAnyListeners.map(async (listener) => { | ||
if (anyListeners.has(listener)) { | ||
return await listener(eventName, eventArgs) | ||
} | ||
}), | ||
]) | ||
} | ||
async emitMetaEvent<TEventName extends EventName, TEventArgs extends EventArgs>(eventName: TEventName, eventArgs: TEventArgs) { | ||
async emitMetaEvent<TEventName extends keyof MetaEventData<TEventData>>(eventName: TEventName, eventArgs: MetaEventData<TEventData>[TEventName]) { | ||
if (isMetaEvent(eventName)) { | ||
try { | ||
canEmitMetaEvents = true | ||
await this.emitInternal(eventName, eventArgs) | ||
await this.emitMetaEventInternal(eventName, eventArgs) | ||
} finally { | ||
@@ -190,3 +167,3 @@ canEmitMetaEvents = false | ||
async emitSerial(eventName: keyof TEventData, eventData: TEventData[keyof TEventData]) { | ||
async emitSerial<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]) { | ||
assertEventName(eventName) | ||
@@ -198,3 +175,3 @@ | ||
this.logIfDebugEnabled('emitSerial', eventName, eventData) | ||
this.logIfDebugEnabled('emitSerial', eventName, eventArgs) | ||
@@ -210,3 +187,3 @@ const listeners = this.getListeners(eventName) ?? new Set() | ||
if (listeners.has(listener)) { | ||
await listener(eventData) | ||
await listener(eventArgs) | ||
} | ||
@@ -217,3 +194,3 @@ } | ||
if (anyListeners.has(listener)) { | ||
await listener(eventName, eventData) | ||
await listener(eventName, eventArgs) | ||
} | ||
@@ -263,3 +240,3 @@ } | ||
off(eventNames: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>) { | ||
off<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>) { | ||
assertListener(listener) | ||
@@ -270,3 +247,3 @@ | ||
assertEventName(eventName) | ||
const set = this.getListeners(eventName) | ||
const set = this.getListeners(eventName) as Set<EventListener<TEventData[TEventName]>> | ||
if (set) { | ||
@@ -283,3 +260,3 @@ set.delete(listener) | ||
if (!isMetaEvent(eventName)) { | ||
forget(this.emitMetaEvent(listenerRemoved, { eventName, listener })) | ||
forget(this.emitMetaEvent('listenerRemoved', { eventName, listener: listener as EventListener })) | ||
} | ||
@@ -289,3 +266,3 @@ } | ||
offAny(listener: EventAnyListener<TEventData>) { | ||
offAny(listener: EventAnyListener) { | ||
assertListener(listener) | ||
@@ -295,7 +272,8 @@ | ||
Events.anyMap.get(this)?.delete(listener) | ||
forget(this.emitMetaEvent(listenerRemoved, { listener })) | ||
const typedMap = Events.anyMap.get(this) as Set<EventAnyListener<TEventData[keyof TEventData]>> | ||
typedMap?.delete(listener) | ||
forget(this.emitMetaEvent('listenerRemoved', { listener: listener as EventAnyListener })) | ||
} | ||
on(eventNames: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>) { | ||
on<TEventName extends keyof TEventData = keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>) { | ||
assertListener(listener) | ||
@@ -313,3 +291,3 @@ | ||
set.add(listener) | ||
set.add(listener as EventListener) | ||
@@ -319,10 +297,10 @@ this.logIfDebugEnabled('subscribe', eventName, undefined) | ||
if (!isMetaEvent(eventName)) { | ||
forget(this.emitMetaEvent(listenerAdded, { eventName, listener })) | ||
forget(this.emitMetaEvent('listenerAdded', { eventName, listener: listener as EventListener })) | ||
} | ||
} | ||
return this.off.bind(this, eventNames, listener) | ||
return this.off.bind(this, eventNames, listener as EventListener) | ||
} | ||
onAny(listener: EventAnyListener<TEventData>) { | ||
onAny(listener: EventAnyListener) { | ||
assertListener(listener) | ||
@@ -332,15 +310,79 @@ | ||
Events.anyMap.get(this)?.add(listener) | ||
forget(this.emitMetaEvent(listenerAdded, { listener })) | ||
return this.offAny.bind(this, listener) | ||
Events.anyMap.get(this)?.add(listener as EventAnyListener) | ||
forget(this.emitMetaEvent('listenerAdded', { listener: listener as EventAnyListener })) | ||
return this.offAny.bind(this, listener as EventAnyListener) | ||
} | ||
once(eventNames: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>) { | ||
const subListener = async (args?: TEventData[keyof TEventData]) => { | ||
this.off(eventNames, subListener) | ||
once<TEventName extends keyof TEventData>(eventName: TEventName, listener: EventListener<TEventData[TEventName]>) { | ||
const subListener = async (args: TEventData[TEventName]) => { | ||
this.off(eventName, subListener) | ||
await listener(args) | ||
} | ||
this.on(eventNames, subListener) | ||
return this.off.bind(this, eventNames, subListener) | ||
this.on(eventName, subListener) | ||
return this.off.bind(this, eventName, subListener as EventListener) | ||
} | ||
private async emitInternal<TEventName extends keyof TEventData, TEventArgs extends TEventData[TEventName]>( | ||
eventName: TEventName, | ||
eventArgs: TEventArgs, | ||
) { | ||
assertEventName(eventName) | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`') | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs) | ||
const listeners = this.getListeners(eventName) ?? new Set() | ||
const anyListeners = assertEx(Events.anyMap.get(this)) | ||
const staticListeners = [...listeners] | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners] | ||
await resolvedPromise | ||
await Promise.all([ | ||
...staticListeners.map(async (listener) => { | ||
if (listeners.has(listener)) { | ||
return await listener(eventArgs) | ||
} | ||
}), | ||
...staticAnyListeners.map(async (listener) => { | ||
if (anyListeners.has(listener)) { | ||
return await listener(eventName, eventArgs) | ||
} | ||
}), | ||
]) | ||
} | ||
private async emitMetaEventInternal<TEventName extends keyof MetaEventData<TEventData>>( | ||
eventName: TEventName, | ||
eventArgs: MetaEventData<TEventData>[TEventName], | ||
) { | ||
assertEventName(eventName) | ||
if (isMetaEvent(eventName) && !canEmitMetaEvents) { | ||
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`') | ||
} | ||
this.logIfDebugEnabled('emit', eventName, eventArgs) | ||
const listeners = this.getListeners(eventName) ?? new Set() | ||
const anyListeners = assertEx(Events.anyMap.get(this)) | ||
const staticListeners = [...listeners] | ||
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners] | ||
await resolvedPromise | ||
await Promise.all([ | ||
...staticListeners.map(async (listener) => { | ||
if (listeners.has(listener)) { | ||
return await listener(eventArgs) | ||
} | ||
}), | ||
...staticAnyListeners.map(async (listener) => { | ||
if (anyListeners.has(listener)) { | ||
return await listener(eventName, eventArgs) | ||
} | ||
}), | ||
]) | ||
} | ||
} |
@@ -1,2 +0,1 @@ | ||
import { BaseParams } from '@xyo-network/core' | ||
import { Promisable } from '@xyo-network/promise' | ||
@@ -8,27 +7,19 @@ | ||
export type EventUnsubscribeFunction = () => void | ||
export type EventAnyListener<TEventData extends EventData = EventData> = ( | ||
eventName: keyof TEventData, | ||
eventData?: TEventData[keyof TEventData], | ||
) => Promisable<void> | ||
export type EventListener<TEventData extends EventData = EventData> = (eventData?: TEventData[keyof TEventData]) => Promisable<void> | ||
export type EventAnyListener<TEventArgs extends EventArgs = EventArgs> = (eventName: EventName, eventData: TEventArgs) => Promisable<void> | ||
export type EventListener<TEventArgs extends EventArgs = EventArgs> = (eventData: TEventArgs) => Promisable<void> | ||
export type OncePromise<T> = { | ||
off(): void | ||
} & Promise<T> | ||
export interface EventFunctions<TEventData extends EventData> { | ||
eventData: TEventData | ||
clearListeners(eventNames: keyof TEventData | (keyof TEventData)[]): void | ||
emit(eventName: keyof TEventData, eventData: TEventData[keyof TEventData]): Promise<void> | ||
emitSerial(eventName: keyof TEventData, eventData: TEventData[keyof TEventData]): Promise<void> | ||
emit<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void> | ||
emitSerial<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void> | ||
listenerCount(eventNames: keyof TEventData | (keyof TEventData)[]): number | ||
off(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): void | ||
offAny(listener: EventAnyListener<TEventData> | Promise<void>): void | ||
on(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): EventUnsubscribeFunction | ||
onAny(listener: EventAnyListener<TEventData>): EventUnsubscribeFunction | ||
once(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): EventUnsubscribeFunction | ||
off<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>): void | ||
offAny(listener: EventAnyListener | Promise<void>): void | ||
on<TEventName extends keyof TEventData>( | ||
eventNames: TEventName | TEventName[], | ||
listener: EventListener<TEventData[TEventName]>, | ||
): EventUnsubscribeFunction | ||
onAny(listener: EventAnyListener): EventUnsubscribeFunction | ||
once<TEventName extends keyof TEventData>(eventName: TEventName, listener: EventListener<TEventData[TEventName]>): EventUnsubscribeFunction | ||
} | ||
export type EventDataParams<TEventData extends EventData | undefined = undefined, TParams extends BaseParams = BaseParams> = TParams & { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
eventData?: TEventData extends EventData ? TEventData | any : any | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
169757
3
4749
0
1
371
- Removed@xyo-network/core@^2.52.1
- Removed@adraffy/ens-normalize@1.10.1(transitive)
- Removed@babel/helper-string-parser@7.25.9(transitive)
- Removed@babel/helper-validator-identifier@7.25.9(transitive)
- Removed@babel/types@7.26.0(transitive)
- Removed@noble/curves@1.2.0(transitive)
- Removed@noble/hashes@1.3.2(transitive)
- Removed@scure/base@1.1.9(transitive)
- Removed@types/lodash@4.17.13(transitive)
- Removed@types/lodash-es@4.17.12(transitive)
- Removed@types/node@18.15.13(transitive)
- Removed@xylabs/arraybuffer@3.6.12(transitive)
- Removed@xylabs/assert@3.6.12(transitive)
- Removed@xylabs/error@3.6.12(transitive)
- Removed@xylabs/hex@3.6.12(transitive)
- Removed@xylabs/lodash@3.6.12(transitive)
- Removed@xylabs/logger@3.6.12(transitive)
- Removed@xylabs/object@3.6.12(transitive)
- Removed@xylabs/platform@3.6.12(transitive)
- Removed@xylabs/promise@3.6.12(transitive)
- Removed@xylabs/threads@3.6.12(transitive)
- Removed@xylabs/typeof@3.6.12(transitive)
- Removed@xyo-network/core@2.111.3(transitive)
- Removed@xyo-network/data@2.111.3(transitive)
- Removed@xyo-network/hash@2.111.3(transitive)
- Removed@xyo-network/wasm@2.111.3(transitive)
- Removedaes-js@4.0.0-beta.5(transitive)
- Removedcallsites@3.1.0(transitive)
- Removeddebug@4.3.7(transitive)
- Removedesm@3.2.25(transitive)
- Removedethers@6.13.2(transitive)
- Removedhash-wasm@4.11.0(transitive)
- Removedis-observable@2.1.0(transitive)
- Removedms@2.1.3(transitive)
- Removedobservable-fns@0.6.1(transitive)
- Removedtiny-worker@2.3.0(transitive)
- Removedtslib@2.4.0(transitive)
- Removedwasm-feature-detect@1.8.0(transitive)
- Removedws@8.17.1(transitive)