@xyo-network/module-events 2.52.1 → 2.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Events/Events.js +74 -47
- package/dist/cjs/Events/Events.js.map +1 -1
- package/dist/docs.json +1089 -881
- package/dist/esm/Events/Events.js +68 -43
- package/dist/esm/Events/Events.js.map +1 -1
- package/dist/types/Events/Events.d.ts +17 -15
- package/dist/types/Events/Events.d.ts.map +1 -1
- package/dist/types/model/Event.d.ts +10 -16
- package/dist/types/model/Event.d.ts.map +1 -1
- package/package.json +2 -3
- package/src/Events/Events.ts +109 -67
- package/src/model/Event.ts +13 -22
package/src/Events/Events.ts
CHANGED
|
@@ -35,12 +35,15 @@ export type Options<TEventData extends EventData> = {
|
|
|
35
35
|
|
|
36
36
|
const resolvedPromise = Promise.resolve()
|
|
37
37
|
|
|
38
|
-
const listenerAdded = 'listenerAdded'
|
|
39
|
-
const listenerRemoved = 'listenerRemoved'
|
|
40
|
-
|
|
41
38
|
export type MetaEventData<TEventData extends EventData> = {
|
|
42
|
-
listenerAdded: {
|
|
43
|
-
|
|
39
|
+
listenerAdded: {
|
|
40
|
+
eventName?: keyof TEventData
|
|
41
|
+
listener: EventListener<TEventData[keyof TEventData]> | EventAnyListener<TEventData[keyof TEventData]>
|
|
42
|
+
}
|
|
43
|
+
listenerRemoved: {
|
|
44
|
+
eventName?: keyof TEventData
|
|
45
|
+
listener: EventListener<TEventData[keyof TEventData]> | EventAnyListener<TEventData[keyof TEventData]>
|
|
46
|
+
}
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
let canEmitMetaEvents = false
|
|
@@ -58,18 +61,21 @@ function assertListener(listener: object) {
|
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
|
|
61
|
-
const isMetaEvent = (eventName: EventName) => eventName === listenerAdded || eventName === listenerRemoved
|
|
64
|
+
const isMetaEvent = (eventName: EventName) => eventName === 'listenerAdded' || eventName === 'listenerRemoved'
|
|
62
65
|
|
|
63
|
-
export class Events<TEventData extends EventData> implements EventFunctions<TEventData> {
|
|
64
|
-
static anyMap = new WeakMap<object, Set<EventAnyListener
|
|
65
|
-
static eventsMap = new WeakMap<object, Map<
|
|
66
|
+
export class Events<TEventData extends EventData = EventData> implements EventFunctions<TEventData> {
|
|
67
|
+
static anyMap = new WeakMap<object, Set<EventAnyListener>>()
|
|
68
|
+
static eventsMap = new WeakMap<object, Map<EventName, Set<EventListener>>>()
|
|
66
69
|
|
|
67
70
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
68
71
|
debug?: DebugOptions<any>
|
|
69
72
|
|
|
73
|
+
//this is here to be able to query the type, not use
|
|
74
|
+
eventData = {} as TEventData
|
|
75
|
+
|
|
70
76
|
constructor(options: Options<TEventData> = {}) {
|
|
71
|
-
Events.anyMap.set(this, new Set<EventAnyListener
|
|
72
|
-
Events.eventsMap.set(this, new Map<keyof TEventData, Set<EventListener
|
|
77
|
+
Events.anyMap.set(this, new Set<EventAnyListener>())
|
|
78
|
+
Events.eventsMap.set(this, new Map<keyof TEventData, Set<EventListener>>())
|
|
73
79
|
|
|
74
80
|
this.debug = options.debug
|
|
75
81
|
|
|
@@ -139,58 +145,29 @@ export class Events<TEventData extends EventData> implements EventFunctions<TEve
|
|
|
139
145
|
}
|
|
140
146
|
}
|
|
141
147
|
|
|
142
|
-
async emit(eventName:
|
|
143
|
-
await this.emitInternal(eventName,
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async emitInternal<TEventName extends EventName, TEventArgs extends EventArgs>(eventName: TEventName, eventArgs?: TEventArgs) {
|
|
147
|
-
assertEventName(eventName)
|
|
148
|
-
|
|
149
|
-
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
|
|
150
|
-
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`')
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
this.logIfDebugEnabled('emit', eventName, eventArgs)
|
|
154
|
-
|
|
155
|
-
const listeners = this.getListeners(eventName) ?? new Set()
|
|
156
|
-
const anyListeners = assertEx(Events.anyMap.get(this))
|
|
157
|
-
const staticListeners = [...listeners]
|
|
158
|
-
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]
|
|
159
|
-
|
|
160
|
-
await resolvedPromise
|
|
161
|
-
await Promise.all([
|
|
162
|
-
...staticListeners.map(async (listener) => {
|
|
163
|
-
if (listeners.has(listener)) {
|
|
164
|
-
return await listener(eventArgs)
|
|
165
|
-
}
|
|
166
|
-
}),
|
|
167
|
-
...staticAnyListeners.map(async (listener) => {
|
|
168
|
-
if (anyListeners.has(listener)) {
|
|
169
|
-
return await listener(eventName, eventArgs)
|
|
170
|
-
}
|
|
171
|
-
}),
|
|
172
|
-
])
|
|
148
|
+
async emit<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]) {
|
|
149
|
+
await this.emitInternal(eventName, eventArgs)
|
|
173
150
|
}
|
|
174
151
|
|
|
175
|
-
async emitMetaEvent<TEventName extends
|
|
152
|
+
async emitMetaEvent<TEventName extends keyof MetaEventData<TEventData>>(eventName: TEventName, eventArgs: MetaEventData<TEventData>[TEventName]) {
|
|
176
153
|
if (isMetaEvent(eventName)) {
|
|
177
154
|
try {
|
|
178
155
|
canEmitMetaEvents = true
|
|
179
|
-
await this.
|
|
156
|
+
await this.emitMetaEventInternal(eventName, eventArgs)
|
|
180
157
|
} finally {
|
|
181
158
|
canEmitMetaEvents = false
|
|
182
159
|
}
|
|
183
160
|
}
|
|
184
161
|
}
|
|
185
162
|
|
|
186
|
-
async emitSerial(eventName:
|
|
163
|
+
async emitSerial<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]) {
|
|
187
164
|
assertEventName(eventName)
|
|
188
165
|
|
|
189
166
|
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
|
|
190
167
|
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`')
|
|
191
168
|
}
|
|
192
169
|
|
|
193
|
-
this.logIfDebugEnabled('emitSerial', eventName,
|
|
170
|
+
this.logIfDebugEnabled('emitSerial', eventName, eventArgs)
|
|
194
171
|
|
|
195
172
|
const listeners = this.getListeners(eventName) ?? new Set()
|
|
196
173
|
const anyListeners = assertEx(Events.anyMap.get(this))
|
|
@@ -201,13 +178,13 @@ export class Events<TEventData extends EventData> implements EventFunctions<TEve
|
|
|
201
178
|
|
|
202
179
|
for (const listener of staticListeners) {
|
|
203
180
|
if (listeners.has(listener)) {
|
|
204
|
-
await listener(
|
|
181
|
+
await listener(eventArgs)
|
|
205
182
|
}
|
|
206
183
|
}
|
|
207
184
|
|
|
208
185
|
for (const listener of staticAnyListeners) {
|
|
209
186
|
if (anyListeners.has(listener)) {
|
|
210
|
-
await listener(eventName,
|
|
187
|
+
await listener(eventName, eventArgs)
|
|
211
188
|
}
|
|
212
189
|
}
|
|
213
190
|
}
|
|
@@ -252,13 +229,13 @@ export class Events<TEventData extends EventData> implements EventFunctions<TEve
|
|
|
252
229
|
}
|
|
253
230
|
}
|
|
254
231
|
|
|
255
|
-
off(eventNames:
|
|
232
|
+
off<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>) {
|
|
256
233
|
assertListener(listener)
|
|
257
234
|
|
|
258
235
|
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames]
|
|
259
236
|
for (const eventName of eventNamesArray) {
|
|
260
237
|
assertEventName(eventName)
|
|
261
|
-
const set = this.getListeners(eventName)
|
|
238
|
+
const set = this.getListeners(eventName) as Set<EventListener<TEventData[TEventName]>>
|
|
262
239
|
if (set) {
|
|
263
240
|
set.delete(listener)
|
|
264
241
|
if (set.size === 0) {
|
|
@@ -270,21 +247,22 @@ export class Events<TEventData extends EventData> implements EventFunctions<TEve
|
|
|
270
247
|
this.logIfDebugEnabled('unsubscribe', eventName, undefined)
|
|
271
248
|
|
|
272
249
|
if (!isMetaEvent(eventName)) {
|
|
273
|
-
forget(this.emitMetaEvent(listenerRemoved, { eventName, listener }))
|
|
250
|
+
forget(this.emitMetaEvent('listenerRemoved', { eventName, listener: listener as EventListener }))
|
|
274
251
|
}
|
|
275
252
|
}
|
|
276
253
|
}
|
|
277
254
|
|
|
278
|
-
offAny(listener: EventAnyListener
|
|
255
|
+
offAny(listener: EventAnyListener) {
|
|
279
256
|
assertListener(listener)
|
|
280
257
|
|
|
281
258
|
this.logIfDebugEnabled('unsubscribeAny', undefined, undefined)
|
|
282
259
|
|
|
283
|
-
Events.anyMap.get(this)
|
|
284
|
-
|
|
260
|
+
const typedMap = Events.anyMap.get(this) as Set<EventAnyListener<TEventData[keyof TEventData]>>
|
|
261
|
+
typedMap?.delete(listener)
|
|
262
|
+
forget(this.emitMetaEvent('listenerRemoved', { listener: listener as EventAnyListener }))
|
|
285
263
|
}
|
|
286
264
|
|
|
287
|
-
on
|
|
265
|
+
on<TEventName extends keyof TEventData = keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>) {
|
|
288
266
|
assertListener(listener)
|
|
289
267
|
|
|
290
268
|
const eventNamesArray = Array.isArray(eventNames) ? eventNames : [eventNames]
|
|
@@ -297,34 +275,98 @@ export class Events<TEventData extends EventData> implements EventFunctions<TEve
|
|
|
297
275
|
events?.set(eventName, set)
|
|
298
276
|
}
|
|
299
277
|
|
|
300
|
-
set.add(listener)
|
|
278
|
+
set.add(listener as EventListener)
|
|
301
279
|
|
|
302
280
|
this.logIfDebugEnabled('subscribe', eventName, undefined)
|
|
303
281
|
|
|
304
282
|
if (!isMetaEvent(eventName)) {
|
|
305
|
-
forget(this.emitMetaEvent(listenerAdded, { eventName, listener }))
|
|
283
|
+
forget(this.emitMetaEvent('listenerAdded', { eventName, listener: listener as EventListener }))
|
|
306
284
|
}
|
|
307
285
|
}
|
|
308
286
|
|
|
309
|
-
return this.off.bind(this, eventNames, listener)
|
|
287
|
+
return this.off.bind(this, eventNames, listener as EventListener)
|
|
310
288
|
}
|
|
311
289
|
|
|
312
|
-
onAny(listener: EventAnyListener
|
|
290
|
+
onAny(listener: EventAnyListener) {
|
|
313
291
|
assertListener(listener)
|
|
314
292
|
|
|
315
293
|
this.logIfDebugEnabled('subscribeAny', undefined, undefined)
|
|
316
294
|
|
|
317
|
-
Events.anyMap.get(this)?.add(listener)
|
|
318
|
-
forget(this.emitMetaEvent(listenerAdded, { listener }))
|
|
319
|
-
return this.offAny.bind(this, listener)
|
|
295
|
+
Events.anyMap.get(this)?.add(listener as EventAnyListener)
|
|
296
|
+
forget(this.emitMetaEvent('listenerAdded', { listener: listener as EventAnyListener }))
|
|
297
|
+
return this.offAny.bind(this, listener as EventAnyListener)
|
|
320
298
|
}
|
|
321
299
|
|
|
322
|
-
once
|
|
323
|
-
const subListener = async (args
|
|
324
|
-
this.off(
|
|
300
|
+
once<TEventName extends keyof TEventData>(eventName: TEventName, listener: EventListener<TEventData[TEventName]>) {
|
|
301
|
+
const subListener = async (args: TEventData[TEventName]) => {
|
|
302
|
+
this.off(eventName, subListener)
|
|
325
303
|
await listener(args)
|
|
326
304
|
}
|
|
327
|
-
this.on(
|
|
328
|
-
return this.off.bind(this,
|
|
305
|
+
this.on(eventName, subListener)
|
|
306
|
+
return this.off.bind(this, eventName, subListener as EventListener)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private async emitInternal<TEventName extends keyof TEventData, TEventArgs extends TEventData[TEventName]>(
|
|
310
|
+
eventName: TEventName,
|
|
311
|
+
eventArgs: TEventArgs,
|
|
312
|
+
) {
|
|
313
|
+
assertEventName(eventName)
|
|
314
|
+
|
|
315
|
+
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
|
|
316
|
+
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`')
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
this.logIfDebugEnabled('emit', eventName, eventArgs)
|
|
320
|
+
|
|
321
|
+
const listeners = this.getListeners(eventName) ?? new Set()
|
|
322
|
+
const anyListeners = assertEx(Events.anyMap.get(this))
|
|
323
|
+
const staticListeners = [...listeners]
|
|
324
|
+
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]
|
|
325
|
+
|
|
326
|
+
await resolvedPromise
|
|
327
|
+
await Promise.all([
|
|
328
|
+
...staticListeners.map(async (listener) => {
|
|
329
|
+
if (listeners.has(listener)) {
|
|
330
|
+
return await listener(eventArgs)
|
|
331
|
+
}
|
|
332
|
+
}),
|
|
333
|
+
...staticAnyListeners.map(async (listener) => {
|
|
334
|
+
if (anyListeners.has(listener)) {
|
|
335
|
+
return await listener(eventName, eventArgs)
|
|
336
|
+
}
|
|
337
|
+
}),
|
|
338
|
+
])
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private async emitMetaEventInternal<TEventName extends keyof MetaEventData<TEventData>>(
|
|
342
|
+
eventName: TEventName,
|
|
343
|
+
eventArgs: MetaEventData<TEventData>[TEventName],
|
|
344
|
+
) {
|
|
345
|
+
assertEventName(eventName)
|
|
346
|
+
|
|
347
|
+
if (isMetaEvent(eventName) && !canEmitMetaEvents) {
|
|
348
|
+
throw new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`')
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
this.logIfDebugEnabled('emit', eventName, eventArgs)
|
|
352
|
+
|
|
353
|
+
const listeners = this.getListeners(eventName) ?? new Set()
|
|
354
|
+
const anyListeners = assertEx(Events.anyMap.get(this))
|
|
355
|
+
const staticListeners = [...listeners]
|
|
356
|
+
const staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners]
|
|
357
|
+
|
|
358
|
+
await resolvedPromise
|
|
359
|
+
await Promise.all([
|
|
360
|
+
...staticListeners.map(async (listener) => {
|
|
361
|
+
if (listeners.has(listener)) {
|
|
362
|
+
return await listener(eventArgs)
|
|
363
|
+
}
|
|
364
|
+
}),
|
|
365
|
+
...staticAnyListeners.map(async (listener) => {
|
|
366
|
+
if (anyListeners.has(listener)) {
|
|
367
|
+
return await listener(eventName, eventArgs)
|
|
368
|
+
}
|
|
369
|
+
}),
|
|
370
|
+
])
|
|
329
371
|
}
|
|
330
372
|
}
|
package/src/model/Event.ts
CHANGED
|
@@ -1,33 +1,24 @@
|
|
|
1
|
-
import { BaseParams } from '@xyo-network/core'
|
|
2
1
|
import { Promisable } from '@xyo-network/promise'
|
|
3
2
|
|
|
4
3
|
export type EventName = PropertyKey
|
|
5
4
|
export type EventArgs = string | number | object
|
|
6
5
|
export type EventData = { [key: EventName]: EventArgs }
|
|
7
6
|
export type EventUnsubscribeFunction = () => void
|
|
8
|
-
export type EventAnyListener<
|
|
9
|
-
|
|
10
|
-
eventData?: TEventData[keyof TEventData],
|
|
11
|
-
) => Promisable<void>
|
|
12
|
-
export type EventListener<TEventData extends EventData = EventData> = (eventData?: TEventData[keyof TEventData]) => Promisable<void>
|
|
13
|
-
|
|
14
|
-
export type OncePromise<T> = {
|
|
15
|
-
off(): void
|
|
16
|
-
} & Promise<T>
|
|
7
|
+
export type EventAnyListener<TEventArgs extends EventArgs = EventArgs> = (eventName: EventName, eventData: TEventArgs) => Promisable<void>
|
|
8
|
+
export type EventListener<TEventArgs extends EventArgs = EventArgs> = (eventData: TEventArgs) => Promisable<void>
|
|
17
9
|
|
|
18
10
|
export interface EventFunctions<TEventData extends EventData> {
|
|
11
|
+
eventData: TEventData
|
|
19
12
|
clearListeners(eventNames: keyof TEventData | (keyof TEventData)[]): void
|
|
20
|
-
emit(eventName:
|
|
21
|
-
emitSerial(eventName:
|
|
13
|
+
emit<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void>
|
|
14
|
+
emitSerial<TEventName extends keyof TEventData>(eventName: TEventName, eventArgs: TEventData[TEventName]): Promise<void>
|
|
22
15
|
listenerCount(eventNames: keyof TEventData | (keyof TEventData)[]): number
|
|
23
|
-
off
|
|
24
|
-
offAny(listener: EventAnyListener
|
|
25
|
-
on
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
-
eventData?: TEventData extends EventData ? TEventData | any : any
|
|
16
|
+
off<TEventName extends keyof TEventData>(eventNames: TEventName | TEventName[], listener: EventListener<TEventData[TEventName]>): void
|
|
17
|
+
offAny(listener: EventAnyListener | Promise<void>): void
|
|
18
|
+
on<TEventName extends keyof TEventData>(
|
|
19
|
+
eventNames: TEventName | TEventName[],
|
|
20
|
+
listener: EventListener<TEventData[TEventName]>,
|
|
21
|
+
): EventUnsubscribeFunction
|
|
22
|
+
onAny(listener: EventAnyListener): EventUnsubscribeFunction
|
|
23
|
+
once<TEventName extends keyof TEventData>(eventName: TEventName, listener: EventListener<TEventData[TEventName]>): EventUnsubscribeFunction
|
|
33
24
|
}
|