@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.
@@ -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: { eventName?: keyof TEventData; listener: EventListener<TEventData> }
43
- listenerRemoved: { eventName?: keyof TEventData; listener: EventListener<TEventData> }
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<any>>>()
65
- static eventsMap = new WeakMap<object, Map<keyof EventData, Set<EventListener<any>>>>()
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<TEventData>>())
72
- Events.eventsMap.set(this, new Map<keyof TEventData, Set<EventListener<TEventData>>>())
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: keyof TEventData, eventData?: TEventData[keyof TEventData]) {
143
- await this.emitInternal(eventName, eventData)
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 EventName, TEventArgs extends EventArgs>(eventName: TEventName, eventArgs: TEventArgs) {
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.emitInternal(eventName, eventArgs)
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: keyof TEventData, eventData: TEventData[keyof TEventData]) {
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, eventData)
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(eventData)
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, eventData)
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: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>) {
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<TEventData>) {
255
+ offAny(listener: EventAnyListener) {
279
256
  assertListener(listener)
280
257
 
281
258
  this.logIfDebugEnabled('unsubscribeAny', undefined, undefined)
282
259
 
283
- Events.anyMap.get(this)?.delete(listener)
284
- forget(this.emitMetaEvent(listenerRemoved, { listener }))
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(eventNames: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>) {
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<TEventData>) {
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(eventNames: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>) {
323
- const subListener = async (args?: TEventData[keyof TEventData]) => {
324
- this.off(eventNames, subListener)
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(eventNames, subListener)
328
- return this.off.bind(this, eventNames, subListener)
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
  }
@@ -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<TEventData extends EventData = EventData> = (
9
- eventName: keyof TEventData,
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: keyof TEventData, eventData: TEventData[keyof TEventData]): Promise<void>
21
- emitSerial(eventName: keyof TEventData, eventData: TEventData[keyof TEventData]): Promise<void>
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(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): void
24
- offAny(listener: EventAnyListener<TEventData> | Promise<void>): void
25
- on(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): EventUnsubscribeFunction
26
- onAny(listener: EventAnyListener<TEventData>): EventUnsubscribeFunction
27
- once(eventName: keyof TEventData | (keyof TEventData)[], listener: EventListener<TEventData>): EventUnsubscribeFunction
28
- }
29
-
30
- export type EventDataParams<TEventData extends EventData | undefined = undefined, TParams extends BaseParams = BaseParams> = TParams & {
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
  }