@gjsify/events 0.0.4 → 0.1.1

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.
@@ -0,0 +1,726 @@
1
+ // Native EventEmitter implementation for GJS
2
+ // Reference: Node.js lib/events.js, Deno ext/node/polyfills/_events.mjs
3
+
4
+ import type { EventEmitterOptions, OnOptions, OnceOptions } from 'node:events';
5
+
6
+ type EventListener = (...args: any[]) => void;
7
+
8
+ /** An EventListener that may have been wrapped by `once`, carrying the original listener. */
9
+ interface WrappedEventListener extends EventListener {
10
+ listener?: EventListener;
11
+ }
12
+
13
+ /** Error subtype with optional `code` and `cause` fields (used for abort errors, etc.). */
14
+ interface NodeError extends Error {
15
+ code?: string;
16
+ cause?: unknown;
17
+ context?: unknown;
18
+ }
19
+
20
+ /** Array of listeners augmented with a `warned` flag for max-listener leak detection. */
21
+ interface WarnableListenerArray extends Array<EventListener> {
22
+ warned?: boolean;
23
+ }
24
+
25
+ // Internal symbols
26
+ const kCapture = Symbol('kCapture');
27
+ const kRejection = Symbol.for('nodejs.rejection');
28
+
29
+ /**
30
+ * Wraps a once listener so it removes itself after first invocation.
31
+ */
32
+ function onceWrapper(this: { target: EventEmitter; type: string | symbol; listener: EventListener; wrapperFn?: EventListener }) {
33
+ const { target, type, listener } = this;
34
+ if (this.wrapperFn) target.removeListener(type, this.wrapperFn);
35
+ const result = listener.apply(target, arguments as any);
36
+ return result;
37
+ }
38
+
39
+ function _onceWrap(target: EventEmitter, type: string | symbol, listener: EventListener): EventListener {
40
+ const state = { target, type, listener, wrapperFn: undefined as EventListener | undefined };
41
+ const wrapped = onceWrapper.bind(state) as EventListener & { listener: EventListener };
42
+ state.wrapperFn = wrapped;
43
+ wrapped.listener = listener;
44
+ return wrapped;
45
+ }
46
+
47
+ function arrayClone(arr: EventListener[]): EventListener[] {
48
+ switch (arr.length) {
49
+ case 0: return [];
50
+ case 1: return [arr[0]];
51
+ case 2: return [arr[0], arr[1]];
52
+ case 3: return [arr[0], arr[1], arr[2]];
53
+ default: return arr.slice();
54
+ }
55
+ }
56
+
57
+ function checkListener(listener: unknown): void {
58
+ if (typeof listener !== 'function') {
59
+ throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
60
+ }
61
+ }
62
+
63
+ function validateNumber(value: unknown, name: string): void {
64
+ if (typeof value !== 'number' || value !== value) {
65
+ throw new TypeError(`The "${name}" argument must be of type number. Received type ${typeof value}`);
66
+ }
67
+ }
68
+
69
+ function spliceOne(list: unknown[], index: number): void {
70
+ for (; index + 1 < list.length; index++) {
71
+ list[index] = list[index + 1];
72
+ }
73
+ list.pop();
74
+ }
75
+
76
+ /**
77
+ * Node.js-compatible EventEmitter for GJS.
78
+ */
79
+ export class EventEmitter {
80
+ static defaultMaxListeners = 10;
81
+ static readonly errorMonitor: unique symbol = Symbol('events.errorMonitor') as unknown as typeof EventEmitter.errorMonitor;
82
+ static readonly captureRejectionSymbol: symbol = kRejection;
83
+
84
+ private static _captureRejections = false;
85
+
86
+ static get captureRejections(): boolean {
87
+ return EventEmitter._captureRejections;
88
+ }
89
+
90
+ static set captureRejections(value: boolean) {
91
+ if (typeof value !== 'boolean') {
92
+ throw new TypeError('The "captureRejections" argument must be of type boolean.');
93
+ }
94
+ EventEmitter._captureRejections = value;
95
+ }
96
+
97
+ _events: Record<string | symbol, EventListener | EventListener[]>;
98
+ _eventsCount: number;
99
+ _maxListeners: number | undefined;
100
+ [kCapture]: boolean;
101
+
102
+ constructor(opts?: EventEmitterOptions) {
103
+ this._events = Object.create(null);
104
+ this._eventsCount = 0;
105
+ this._maxListeners = undefined;
106
+ this[kCapture] = opts?.captureRejections ?? EventEmitter._captureRejections;
107
+ }
108
+
109
+ setMaxListeners(n: number): this {
110
+ validateNumber(n, 'n');
111
+ if (n < 0) {
112
+ throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n);
113
+ }
114
+ this._maxListeners = n;
115
+ return this;
116
+ }
117
+
118
+ getMaxListeners(): number {
119
+ return this._maxListeners ?? EventEmitter.defaultMaxListeners;
120
+ }
121
+
122
+ emit(type: string | symbol, ...args: any[]): boolean {
123
+ const events = this._events;
124
+ let doError = (type === 'error');
125
+
126
+ if (events !== undefined) {
127
+ // If error event and errorMonitor listeners exist, emit to them first
128
+ if (doError && events[EventEmitter.errorMonitor] !== undefined) {
129
+ this.emit(EventEmitter.errorMonitor, ...args);
130
+ }
131
+ doError = doError && events.error === undefined;
132
+ } else if (!doError) {
133
+ return false;
134
+ }
135
+
136
+ // If no error listeners and it's an error event, throw
137
+ if (doError) {
138
+ let er: Error;
139
+ if (args.length > 0) {
140
+ er = args[0];
141
+ } else {
142
+ er = new Error('Unhandled error.');
143
+ }
144
+ if (er instanceof Error) {
145
+ throw er;
146
+ }
147
+ const err = new Error('Unhandled error. (' + er + ')') as NodeError;
148
+ err.context = er;
149
+ throw err;
150
+ }
151
+
152
+ const handler = events[type];
153
+
154
+ if (handler === undefined) {
155
+ return false;
156
+ }
157
+
158
+ if (typeof handler === 'function') {
159
+ const result = handler.apply(this, args);
160
+ if (result !== undefined && result !== null && this[kCapture]) {
161
+ this._addCatch(result, type, args);
162
+ }
163
+ } else {
164
+ const listeners = arrayClone(handler);
165
+ const len = listeners.length;
166
+ for (let i = 0; i < len; ++i) {
167
+ const result = listeners[i].apply(this, args);
168
+ if (result !== undefined && result !== null && this[kCapture]) {
169
+ this._addCatch(result, type, args);
170
+ }
171
+ }
172
+ }
173
+
174
+ return true;
175
+ }
176
+
177
+ private _addCatch(result: PromiseLike<unknown> | unknown, type: string | symbol, args: unknown[]): void {
178
+ if (typeof (result as PromiseLike<unknown>)?.then === 'function') {
179
+ (result as PromiseLike<unknown>).then(undefined, (err: Error) => {
180
+ // Check if instance has a custom rejection handler
181
+ const handler = (this as Record<symbol, unknown>)[kRejection];
182
+ if (typeof handler === 'function') {
183
+ handler.call(this, err, type, ...args);
184
+ } else {
185
+ // Temporarily disable capture to avoid infinite loop
186
+ const prev = this[kCapture];
187
+ try {
188
+ this[kCapture] = false;
189
+ this.emit('error', err);
190
+ } finally {
191
+ this[kCapture] = prev;
192
+ }
193
+ }
194
+ });
195
+ }
196
+ }
197
+
198
+ addListener(type: string | symbol, listener: EventListener): this {
199
+ return this._addListener(type, listener, false);
200
+ }
201
+
202
+ on(type: string | symbol, listener: EventListener): this {
203
+ return this._addListener(type, listener, false);
204
+ }
205
+
206
+ prependListener(type: string | symbol, listener: EventListener): this {
207
+ return this._addListener(type, listener, true);
208
+ }
209
+
210
+ private _addListener(type: string | symbol, listener: EventListener, prepend: boolean): this {
211
+ checkListener(listener);
212
+
213
+ let events = this._events;
214
+
215
+ // Lazy initialization for objects that mixin EventEmitter without calling constructor
216
+ if (events === undefined) {
217
+ events = this._events = Object.create(null);
218
+ this._eventsCount = 0;
219
+ } else if (events.newListener !== undefined) {
220
+ // Emit newListener before adding
221
+ this.emit('newListener', type, (listener as WrappedEventListener).listener ?? listener);
222
+ // Re-read in case newListener handler modified _events
223
+ events = this._events;
224
+ }
225
+
226
+ let existing = events[type];
227
+
228
+ if (existing === undefined) {
229
+ events[type] = listener;
230
+ ++this._eventsCount;
231
+ } else if (typeof existing === 'function') {
232
+ events[type] = prepend ? [listener, existing] : [existing, listener];
233
+ } else {
234
+ if (prepend) {
235
+ existing.unshift(listener);
236
+ } else {
237
+ existing.push(listener);
238
+ }
239
+ }
240
+
241
+ // Check for listener leak
242
+ const m = this.getMaxListeners();
243
+ if (m > 0) {
244
+ const count = typeof events[type] === 'function' ? 1 : (events[type] as EventListener[]).length;
245
+ if (count > m && !(events[type] as WarnableListenerArray).warned) {
246
+ if (typeof events[type] !== 'function') {
247
+ (events[type] as WarnableListenerArray).warned = true;
248
+ }
249
+ const w = new Error(
250
+ `Possible EventEmitter memory leak detected. ${count} ${String(type)} listeners ` +
251
+ `added to [${this.constructor.name}]. Use emitter.setMaxListeners() to increase limit`
252
+ );
253
+ w.name = 'MaxListenersExceededWarning';
254
+ console.warn(w.message);
255
+ }
256
+ }
257
+
258
+ return this;
259
+ }
260
+
261
+ once(type: string | symbol, listener: EventListener): this {
262
+ checkListener(listener);
263
+ this.on(type, _onceWrap(this, type, listener));
264
+ return this;
265
+ }
266
+
267
+ prependOnceListener(type: string | symbol, listener: EventListener): this {
268
+ checkListener(listener);
269
+ this.prependListener(type, _onceWrap(this, type, listener));
270
+ return this;
271
+ }
272
+
273
+ removeListener(type: string | symbol, listener: EventListener): this {
274
+ checkListener(listener);
275
+
276
+ const events = this._events;
277
+ if (events === undefined) {
278
+ return this;
279
+ }
280
+ const list = events[type];
281
+ if (list === undefined) {
282
+ return this;
283
+ }
284
+
285
+ if (list === listener || (list as WrappedEventListener).listener === listener) {
286
+ if (--this._eventsCount === 0) {
287
+ this._events = Object.create(null);
288
+ } else {
289
+ delete events[type];
290
+ if (events.removeListener) {
291
+ this.emit('removeListener', type, (list as WrappedEventListener).listener ?? listener);
292
+ }
293
+ }
294
+ } else if (typeof list !== 'function') {
295
+ let position = -1;
296
+ for (let i = list.length - 1; i >= 0; i--) {
297
+ if (list[i] === listener || (list[i] as WrappedEventListener).listener === listener) {
298
+ position = i;
299
+ break;
300
+ }
301
+ }
302
+
303
+ if (position < 0) {
304
+ return this;
305
+ }
306
+
307
+ if (position === 0) {
308
+ list.shift();
309
+ } else {
310
+ spliceOne(list, position);
311
+ }
312
+
313
+ if (list.length === 1) {
314
+ events[type] = list[0];
315
+ }
316
+
317
+ if (events.removeListener !== undefined) {
318
+ this.emit('removeListener', type, (listener as WrappedEventListener).listener ?? listener);
319
+ }
320
+ }
321
+
322
+ return this;
323
+ }
324
+
325
+ off(type: string | symbol, listener: EventListener): this {
326
+ return this.removeListener(type, listener);
327
+ }
328
+
329
+ removeAllListeners(type?: string | symbol): this {
330
+ const events = this._events;
331
+ if (events === undefined) {
332
+ return this;
333
+ }
334
+
335
+ // Not listening for removeListener, no need to emit
336
+ if (events.removeListener === undefined) {
337
+ if (arguments.length === 0) {
338
+ this._events = Object.create(null);
339
+ this._eventsCount = 0;
340
+ } else if (events[type!] !== undefined) {
341
+ if (--this._eventsCount === 0) {
342
+ this._events = Object.create(null);
343
+ } else {
344
+ delete events[type!];
345
+ }
346
+ }
347
+ return this;
348
+ }
349
+
350
+ // Emit removeListener for all listeners
351
+ if (arguments.length === 0) {
352
+ const keys = Object.keys(events);
353
+ for (let i = 0; i < keys.length; ++i) {
354
+ const key = keys[i];
355
+ if (key === 'removeListener') continue;
356
+ this.removeAllListeners(key);
357
+ }
358
+ this.removeAllListeners('removeListener');
359
+ this._events = Object.create(null);
360
+ this._eventsCount = 0;
361
+ return this;
362
+ }
363
+
364
+ const listeners = events[type!];
365
+ if (typeof listeners === 'function') {
366
+ this.removeListener(type!, listeners);
367
+ } else if (listeners !== undefined) {
368
+ // LIFO order
369
+ for (let i = listeners.length - 1; i >= 0; i--) {
370
+ this.removeListener(type!, listeners[i]);
371
+ }
372
+ }
373
+
374
+ return this;
375
+ }
376
+
377
+ listeners(type: string | symbol): EventListener[] {
378
+ const events = this._events;
379
+ if (events === undefined) {
380
+ return [];
381
+ }
382
+ const evlistener = events[type];
383
+
384
+ if (evlistener === undefined) {
385
+ return [];
386
+ }
387
+
388
+ if (typeof evlistener === 'function') {
389
+ return [(evlistener as WrappedEventListener).listener ?? evlistener];
390
+ }
391
+
392
+ return unwrapListeners(evlistener);
393
+ }
394
+
395
+ rawListeners(type: string | symbol): EventListener[] {
396
+ const events = this._events;
397
+ if (events === undefined) {
398
+ return [];
399
+ }
400
+ const evlistener = events[type];
401
+
402
+ if (evlistener === undefined) {
403
+ return [];
404
+ }
405
+
406
+ if (typeof evlistener === 'function') {
407
+ return [evlistener];
408
+ }
409
+
410
+ return arrayClone(evlistener);
411
+ }
412
+
413
+ listenerCount(type: string | symbol): number {
414
+ const events = this._events;
415
+ if (events === undefined) {
416
+ return 0;
417
+ }
418
+ const evlistener = events[type];
419
+
420
+ if (evlistener === undefined) {
421
+ return 0;
422
+ }
423
+
424
+ if (typeof evlistener === 'function') {
425
+ return 1;
426
+ }
427
+
428
+ return evlistener.length;
429
+ }
430
+
431
+ eventNames(): (string | symbol)[] {
432
+ return (this._eventsCount ?? 0) > 0
433
+ ? Reflect.ownKeys(this._events)
434
+ : [];
435
+ }
436
+
437
+ // -- Static methods --
438
+
439
+ /**
440
+ * Returns a promise that resolves when the emitter emits the given event,
441
+ * or rejects if the emitter emits 'error' while waiting.
442
+ */
443
+ static once(emitter: EventEmitter | EventTarget, name: string | symbol, options?: OnceOptions): Promise<unknown[]> {
444
+ return new Promise((resolve, reject) => {
445
+ const signal = options?.signal;
446
+ if (signal?.aborted) {
447
+ reject(createAbortError(signal));
448
+ return;
449
+ }
450
+
451
+ // EventTarget support
452
+ if (typeof (emitter as EventTarget).addEventListener === 'function') {
453
+ const eventTarget = emitter as EventTarget;
454
+ const handler = (...args: any[]) => {
455
+ if (signal) {
456
+ signal.removeEventListener('abort', abortHandler);
457
+ }
458
+ resolve(args);
459
+ };
460
+ const errorHandler = (err: unknown) => {
461
+ if (signal) {
462
+ signal.removeEventListener('abort', abortHandler);
463
+ }
464
+ eventTarget.removeEventListener('error', errorHandler);
465
+ reject(err);
466
+ };
467
+ const abortHandler = () => {
468
+ eventTarget.removeEventListener(name as string, handler);
469
+ eventTarget.removeEventListener('error', errorHandler);
470
+ reject(createAbortError(signal!));
471
+ };
472
+ eventTarget.addEventListener(name as string, handler, { once: true });
473
+ if (name !== 'error') {
474
+ eventTarget.addEventListener('error', errorHandler, { once: true });
475
+ }
476
+ if (signal) {
477
+ signal.addEventListener('abort', abortHandler, { once: true });
478
+ }
479
+ return;
480
+ }
481
+
482
+ // EventEmitter support
483
+ const ee = emitter as EventEmitter;
484
+ const eventHandler = (...args: any[]) => {
485
+ if (signal) {
486
+ signal.removeEventListener('abort', abortHandler);
487
+ }
488
+ if (errorHandler !== undefined) {
489
+ ee.removeListener('error', errorHandler);
490
+ }
491
+ resolve(args);
492
+ };
493
+
494
+ let errorHandler: EventListener | undefined;
495
+ if (name !== 'error') {
496
+ errorHandler = (err: Error) => {
497
+ ee.removeListener(name, eventHandler);
498
+ if (signal) {
499
+ signal.removeEventListener('abort', abortHandler);
500
+ }
501
+ reject(err);
502
+ };
503
+ ee.once('error', errorHandler);
504
+ }
505
+
506
+ ee.once(name, eventHandler);
507
+
508
+ const abortHandler = () => {
509
+ ee.removeListener(name, eventHandler);
510
+ if (errorHandler) {
511
+ ee.removeListener('error', errorHandler);
512
+ }
513
+ reject(createAbortError(signal!));
514
+ };
515
+
516
+ if (signal) {
517
+ signal.addEventListener('abort', abortHandler, { once: true });
518
+ }
519
+ });
520
+ }
521
+
522
+ /**
523
+ * Returns an async iterator that yields event arguments each time the emitter emits.
524
+ */
525
+ static on(emitter: EventEmitter, event: string | symbol, options?: OnOptions): AsyncIterableIterator<unknown[]> {
526
+ const signal = options?.signal;
527
+ if (signal?.aborted) {
528
+ throw createAbortError(signal);
529
+ }
530
+
531
+ const highWaterMark = options?.highWaterMark ?? Number.MAX_SAFE_INTEGER;
532
+ const lowWaterMark = options?.lowWaterMark ?? 1;
533
+
534
+ validateNumber(highWaterMark, 'highWaterMark');
535
+ validateNumber(lowWaterMark, 'lowWaterMark');
536
+
537
+ const unconsumedEvents: unknown[][] = [];
538
+ const unconsumedPromises: { resolve: (value: IteratorResult<unknown[]>) => void; reject: (reason?: unknown) => void }[] = [];
539
+ let error: Error | null = null;
540
+ let finished = false;
541
+ let paused = false;
542
+
543
+ const eventHandler = (...args: any[]) => {
544
+ if (unconsumedPromises.length > 0) {
545
+ const { resolve } = unconsumedPromises.shift()!;
546
+ resolve({ value: args, done: false });
547
+ } else {
548
+ unconsumedEvents.push(args);
549
+ if (unconsumedEvents.length >= highWaterMark && !paused) {
550
+ paused = true;
551
+ if (typeof (emitter as unknown as Record<string, unknown>).pause === 'function') {
552
+ ((emitter as unknown as Record<string, () => void>).pause)();
553
+ }
554
+ }
555
+ }
556
+ };
557
+
558
+ const errorHandler = (err: Error) => {
559
+ error = err;
560
+ if (unconsumedPromises.length > 0) {
561
+ const { reject } = unconsumedPromises.shift()!;
562
+ reject(err);
563
+ }
564
+ iterator.return!();
565
+ };
566
+
567
+ const abortHandler = () => {
568
+ errorHandler(createAbortError(signal!));
569
+ };
570
+
571
+ emitter.on(event, eventHandler);
572
+ if (event !== 'error') {
573
+ emitter.on('error', errorHandler);
574
+ }
575
+ if (signal) {
576
+ signal.addEventListener('abort', abortHandler, { once: true });
577
+ }
578
+
579
+ const cleanup = () => {
580
+ emitter.removeListener(event, eventHandler);
581
+ emitter.removeListener('error', errorHandler);
582
+ if (signal) {
583
+ signal.removeEventListener('abort', abortHandler);
584
+ }
585
+ finished = true;
586
+ // Resolve remaining promises
587
+ for (const { resolve } of unconsumedPromises) {
588
+ resolve({ value: undefined, done: true as const });
589
+ }
590
+ unconsumedPromises.length = 0;
591
+ unconsumedEvents.length = 0;
592
+ };
593
+
594
+ const iterator: AsyncIterableIterator<unknown[]> = {
595
+ next(): Promise<IteratorResult<unknown[]>> {
596
+ if (unconsumedEvents.length > 0) {
597
+ const value = unconsumedEvents.shift()!;
598
+ if (paused && unconsumedEvents.length < lowWaterMark) {
599
+ paused = false;
600
+ if (typeof (emitter as unknown as Record<string, unknown>).resume === 'function') {
601
+ ((emitter as unknown as Record<string, () => void>).resume)();
602
+ }
603
+ }
604
+ return Promise.resolve({ value, done: false });
605
+ }
606
+
607
+ if (error) {
608
+ const p = Promise.reject(error);
609
+ error = null;
610
+ return p;
611
+ }
612
+
613
+ if (finished) {
614
+ return Promise.resolve({ value: undefined, done: true as const });
615
+ }
616
+
617
+ return new Promise((resolve, reject) => {
618
+ unconsumedPromises.push({ resolve, reject });
619
+ });
620
+ },
621
+
622
+ return(): Promise<IteratorResult<unknown[]>> {
623
+ cleanup();
624
+ return Promise.resolve({ value: undefined, done: true as const });
625
+ },
626
+
627
+ throw(err: Error): Promise<IteratorResult<unknown[]>> {
628
+ if (!finished) {
629
+ error = err;
630
+ cleanup();
631
+ }
632
+ return Promise.reject(err);
633
+ },
634
+
635
+ [Symbol.asyncIterator]() {
636
+ return this;
637
+ }
638
+ };
639
+
640
+ return iterator;
641
+ }
642
+
643
+ /**
644
+ * Returns the number of listeners listening to the event name.
645
+ * @deprecated Use emitter.listenerCount() instead.
646
+ */
647
+ static listenerCount(emitter: EventEmitter, type: string | symbol): number {
648
+ return emitter.listenerCount(type);
649
+ }
650
+
651
+ /**
652
+ * Returns a copy of the array of listeners for the event named eventName.
653
+ */
654
+ static getEventListeners(emitter: EventEmitter | EventTarget, name: string | symbol): EventListener[] {
655
+ if (typeof (emitter as EventEmitter).listeners === 'function') {
656
+ return (emitter as EventEmitter).listeners(name);
657
+ }
658
+ return [];
659
+ }
660
+
661
+ /**
662
+ * Set max listeners on one or more emitters.
663
+ */
664
+ static setMaxListeners(n: number, ...emitters: (EventEmitter | EventTarget)[]): void {
665
+ validateNumber(n, 'n');
666
+ if (n < 0) {
667
+ throw new RangeError('The value of "n" is out of range.');
668
+ }
669
+ if (emitters.length === 0) {
670
+ EventEmitter.defaultMaxListeners = n;
671
+ } else {
672
+ for (const emitter of emitters) {
673
+ if (typeof (emitter as EventEmitter).setMaxListeners === 'function') {
674
+ (emitter as EventEmitter).setMaxListeners(n);
675
+ }
676
+ }
677
+ }
678
+ }
679
+
680
+ /**
681
+ * Returns the currently set max listeners on the emitter.
682
+ */
683
+ static getMaxListeners(emitter: EventEmitter | EventTarget): number {
684
+ if (typeof (emitter as EventEmitter).getMaxListeners === 'function') {
685
+ return (emitter as EventEmitter).getMaxListeners();
686
+ }
687
+ return EventEmitter.defaultMaxListeners;
688
+ }
689
+
690
+ /**
691
+ * Listens once to an abort event on the provided signal and returns a disposable.
692
+ */
693
+ static addAbortListener(signal: AbortSignal, listener: EventListener): { [Symbol.dispose](): void } {
694
+ if (signal.aborted) {
695
+ Promise.resolve().then(() => listener());
696
+ }
697
+ const handler = () => listener();
698
+ signal.addEventListener('abort', handler, { once: true });
699
+ return {
700
+ [Symbol.dispose]() {
701
+ signal.removeEventListener('abort', handler);
702
+ }
703
+ };
704
+ }
705
+ }
706
+
707
+ // Make EventEmitter reference itself for backwards compatibility
708
+ (EventEmitter as unknown as Record<string, typeof EventEmitter>).EventEmitter = EventEmitter;
709
+
710
+ function unwrapListeners(arr: EventListener[]): EventListener[] {
711
+ const ret = new Array(arr.length);
712
+ for (let i = 0; i < ret.length; ++i) {
713
+ ret[i] = (arr[i] as WrappedEventListener).listener ?? arr[i];
714
+ }
715
+ return ret;
716
+ }
717
+
718
+ function createAbortError(signal?: AbortSignal): NodeError {
719
+ const err: NodeError = new Error('The operation was aborted');
720
+ err.name = 'AbortError';
721
+ err.code = 'ABORT_ERR';
722
+ if (signal?.reason) {
723
+ err.cause = signal.reason;
724
+ }
725
+ return err;
726
+ }