events-ex 2.1.1 → 2.3.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.cn.md +119 -170
  3. package/README.md +140 -150
  4. package/docs/README.md +143 -149
  5. package/docs/all-off/README.md +17 -0
  6. package/docs/all-off/functions/allOff.md +33 -0
  7. package/docs/consts/README.md +12 -0
  8. package/docs/consts/variables/RegExpEventSymbol.md +11 -0
  9. package/docs/consts/variables/states.md +29 -0
  10. package/docs/default-methods/README.md +17 -0
  11. package/docs/default-methods/functions/getEventableMethods.md +309 -0
  12. package/docs/event/README.md +17 -0
  13. package/docs/event/classes/Event.md +143 -0
  14. package/docs/event-emitter/README-1.md +17 -0
  15. package/docs/event-emitter/README.md +17 -0
  16. package/docs/event-emitter/classes/EventEmitter-1.md +29 -0
  17. package/docs/event-emitter/classes/EventEmitter.md +369 -0
  18. package/docs/eventable/README.md +17 -0
  19. package/docs/eventable/functions/eventable.md +82 -0
  20. package/docs/has-listeners/README.md +17 -0
  21. package/docs/has-listeners/functions/hasListeners.md +38 -0
  22. package/docs/index/README.md +85 -0
  23. package/docs/modules.md +24 -23
  24. package/docs/pipe/README.md +17 -0
  25. package/docs/pipe/functions/pipe.md +41 -0
  26. package/docs/pipe-async/README.md +17 -0
  27. package/docs/pipe-async/functions/pipeAsync.md +41 -0
  28. package/docs/unify/README.md +17 -0
  29. package/docs/unify/functions/unify.md +35 -0
  30. package/docs/util/array-remove/README.md +17 -0
  31. package/docs/util/array-remove/functions/remove.md +21 -0
  32. package/docs/util/object-for-each/README.md +17 -0
  33. package/docs/util/object-for-each/functions/forEach.md +29 -0
  34. package/docs/util/promise-any/README.md +11 -0
  35. package/docs/util/promise-any/variables/default.md +9 -0
  36. package/docs/util/string-pad/README.md +17 -0
  37. package/docs/util/string-pad/functions/pad.md +25 -0
  38. package/docs/util/to-int/README.md +17 -0
  39. package/docs/util/to-int/functions/toInt.md +21 -0
  40. package/docs/util/valid-callable/README.md +17 -0
  41. package/docs/util/valid-callable/functions/validCallable.md +21 -0
  42. package/docs/util/valid-object/README.md +17 -0
  43. package/docs/util/valid-object/functions/validObject.md +21 -0
  44. package/docs/wrap-event-emitter/README.md +21 -0
  45. package/docs/wrap-event-emitter/functions/wrapEventEmitter.md +33 -0
  46. package/docs/wrap-event-emitter/variables/methods.md +11 -0
  47. package/lib/all-off.d.ts +1 -1
  48. package/lib/all-off.js +1 -1
  49. package/lib/default-methods.d.ts +38 -7
  50. package/lib/default-methods.js +155 -32
  51. package/lib/event-emitter.d.ts +12 -2
  52. package/lib/event.d.ts +9 -3
  53. package/lib/event.js +6 -0
  54. package/lib/eventable.js +4 -1
  55. package/lib/pipe-async.d.ts +4 -1
  56. package/lib/pipe-async.js +39 -5
  57. package/lib/pipe.d.ts +1 -1
  58. package/lib/pipe.js +1 -1
  59. package/lib/unify.d.ts +1 -1
  60. package/lib/unify.js +1 -1
  61. package/lib/util/array-remove.js +1 -1
  62. package/lib/util/object-for-each.js +1 -1
  63. package/lib/util/promise-any.d.ts +1 -0
  64. package/lib/util/promise-any.js +44 -0
  65. package/lib/util/string-pad.js +1 -1
  66. package/lib/wrap-event-emitter.d.ts +2 -1
  67. package/lib/wrap-event-emitter.js +24 -3
  68. package/package.json +17 -17
  69. package/src/default-methods.js +159 -26
  70. package/src/event-emitter.d.ts +12 -2
  71. package/src/event.js +6 -0
  72. package/src/eventable.js +3 -0
  73. package/src/pipe-async.js +64 -30
  74. package/src/util/promise-any.js +45 -0
  75. package/src/wrap-event-emitter.js +23 -18
  76. package/docs/.nojekyll +0 -1
  77. package/docs/classes/event.Event.md +0 -141
  78. package/docs/classes/event_emitter-1.EventEmitter.md +0 -29
  79. package/docs/classes/event_emitter.EventEmitter.md +0 -352
  80. package/docs/modules/all_off.md +0 -44
  81. package/docs/modules/consts.md +0 -39
  82. package/docs/modules/default_methods.md +0 -51
  83. package/docs/modules/event.md +0 -19
  84. package/docs/modules/event_emitter-1.md +0 -19
  85. package/docs/modules/event_emitter.md +0 -19
  86. package/docs/modules/eventable.md +0 -92
  87. package/docs/modules/has_listeners.md +0 -49
  88. package/docs/modules/index.md +0 -99
  89. package/docs/modules/pipe.md +0 -49
  90. package/docs/modules/pipe_async.md +0 -49
  91. package/docs/modules/unify.md +0 -46
  92. package/docs/modules/util_array_remove.md +0 -39
  93. package/docs/modules/util_object_for_each.md +0 -41
  94. package/docs/modules/util_string_pad.md +0 -40
  95. package/docs/modules/util_to_int.md +0 -39
  96. package/docs/modules/util_valid_callable.md +0 -39
  97. package/docs/modules/util_valid_object.md +0 -39
  98. package/docs/modules/wrap_event_emitter.md +0 -57
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  exports.getEventableMethods = getEventableMethods;
8
8
  var _utilEx = require("util-ex");
9
+ require("./util/promise-any");
9
10
  var _consts = require("./consts");
10
11
  var _event = require("./event");
11
12
  const create = Object.create;
@@ -17,11 +18,61 @@ function isRegExp(value) {
17
18
  }
18
19
  function getEventableMethods(aClass) {
19
20
  return {
21
+ /**
22
+ * Configures the event emitter with specified options using a Fluent API.
23
+ * @param {Object} options - Configuration options for event emission.
24
+ * @param {string} [options.asyncMode='serial'] - The mode of asynchronous emission ('serial' or 'parallel').
25
+ * @param {string} [options.resultMode='last'] - The strategy for handling multiple return values ('last', 'first', 'collect').
26
+ * @returns {import('./event-emitter').EventEmitter} A proxy object representing the configured EventEmitter.
27
+ */
28
+ configure(options) {
29
+ const proxy = Object.create(this);
30
+ const mergedOptions = Object.assign({}, this._eeRuntimeOptions, options);
31
+ (0, _utilEx.defineProperty)(proxy, '_eeRuntimeOptions', mergedOptions);
32
+ return proxy;
33
+ },
34
+ /**
35
+ * A shortcut for parallel configuration.
36
+ * @param {string} [resultMode='last'] - The strategy for handling multiple return values.
37
+ * @returns {import('./event-emitter').EventEmitter} A proxy object representing the configured EventEmitter.
38
+ */
39
+ parallel(resultMode) {
40
+ return this.configure({
41
+ asyncMode: 'parallel',
42
+ resultMode: resultMode || 'last'
43
+ });
44
+ },
45
+ /**
46
+ * Sets the configuration options for the EventEmitter instance.
47
+ * @param {Object} options - Configuration options for the emitter (e.g., asyncMode, resultMode, maxListeners).
48
+ * @returns {import('./event-emitter').EventEmitter} The EventEmitter instance for chaining.
49
+ */
50
+ setEmitterOptions(options) {
51
+ if (!(0, _utilEx.isObject)(options)) {
52
+ return this;
53
+ }
54
+ let data;
55
+ if (!this.hasOwnProperty('_emitterOptions')) {
56
+ data = create(null);
57
+ (0, _utilEx.defineProperty)(this, '_emitterOptions', data);
58
+ } else {
59
+ data = this._emitterOptions;
60
+ }
61
+ Object.assign(data, options);
62
+ if (!(0, _utilEx.isUndefined)(options.maxListeners) && (0, _utilEx.isFunction)(this.setMaxListeners)) {
63
+ this.setMaxListeners(options.maxListeners);
64
+ }
65
+ return this;
66
+ },
20
67
  /**
21
68
  * Adds a listener function to the specified event type.
22
69
  * @param {string|RegExp} type - The event type to listen for.
23
70
  * @param {Function} listener - The listener function to be called when the event is emitted.
24
- * @param {number} [index] - The index at which to insert the listener. If not specified, the listener will be added at the end of the listeners array.
71
+ * @param {number|'first'|'last'} [index] - The index at which to insert the listener.
72
+ * - 'first' or -Infinity: Adds to the "Head" zone. The first listener added as 'first' is placed at the very front.
73
+ * - 'last' or Infinity: Adds to the "Tail" zone. The first listener added as 'last' will always be the very last one to execute.
74
+ * - number: Inserts at the specified index within the "Body" (normal) zone.
75
+ * If not specified, the listener is added to the end of the "Body" zone.
25
76
  * @returns {import('./event-emitter').EventEmitter} The EventEmitter instance to allow chaining.
26
77
  * @throws {TypeError} If the listener is not a function.
27
78
  */
@@ -44,16 +95,35 @@ function getEventableMethods(aClass) {
44
95
  if (isRegExp(type)) {
45
96
  data = data[_consts.RegExpEventSymbol] || (data[_consts.RegExpEventSymbol] = create(null));
46
97
  }
98
+ const isFirst = index === 'first' || index === -Infinity;
99
+ const isLast = index === 'last' || index === Infinity;
47
100
  if (!data[type]) {
48
- data[type] = listener;
49
- } else if ((0, _utilEx.isObject)(data[type])) {
50
- if (typeof index === 'number') {
51
- data[type].splice(index, 0, listener);
101
+ if (isFirst || isLast || typeof index === 'number') {
102
+ data[type] = [listener];
103
+ if (isFirst) data[type]._headCount = 1;
104
+ if (isLast) data[type]._tailCount = 1;
52
105
  } else {
53
- data[type].push(listener);
106
+ data[type] = listener;
54
107
  }
55
108
  } else {
56
- data[type] = [data[type], listener];
109
+ if ((0, _utilEx.isFunction)(data[type])) {
110
+ data[type] = [data[type]];
111
+ }
112
+ const listeners = data[type];
113
+ const headCount = listeners._headCount || 0;
114
+ const tailCount = listeners._tailCount || 0;
115
+ if (isFirst) {
116
+ listeners.splice(headCount, 0, listener);
117
+ listeners._headCount = headCount + 1;
118
+ } else if (isLast) {
119
+ listeners.splice(listeners.length - tailCount, 0, listener);
120
+ listeners._tailCount = tailCount + 1;
121
+ } else if (typeof index === 'number' && !isNaN(index)) {
122
+ const pos = Math.min(Math.max(headCount + index, headCount), listeners.length - tailCount);
123
+ listeners.splice(pos, 0, listener);
124
+ } else {
125
+ listeners.splice(listeners.length - tailCount, 0, listener);
126
+ }
57
127
  }
58
128
  // Check for listener leak
59
129
  if ((0, _utilEx.isObject)(data[type]) && !data[type].warned) {
@@ -74,7 +144,11 @@ function getEventableMethods(aClass) {
74
144
  * Adds a one-time listener function to the specified event type.
75
145
  * @param {string|RegExp} type - The event type to listen for.
76
146
  * @param {Function} listener - The listener function to be called once when the event is emitted.
77
- * @param {number} [index] - The index at which to insert the listener. If not specified, the listener will be added at the end of the listeners array.
147
+ * @param {number|'first'|'last'} [index] - The index at which to insert the listener.
148
+ * - 'first' or -Infinity: Adds to the "Head" zone. The first listener added as 'first' is placed at the very front.
149
+ * - 'last' or Infinity: Adds to the "Tail" zone. The first listener added as 'last' will always be the very last one to execute.
150
+ * - number: Inserts at the specified index within the "Body" (normal) zone.
151
+ * If not specified, the listener is added to the end of the "Body" zone.
78
152
  * @returns {import('./event-emitter').EventEmitter} The EventEmitter instance to allow chaining.
79
153
  * @throws {TypeError} If the listener is not a function.
80
154
  */
@@ -100,7 +174,7 @@ function getEventableMethods(aClass) {
100
174
  * @param {...*} args - The event type followed by any number of arguments to be passed to the listener functions.
101
175
  * @returns {*} The result of the event.
102
176
  */
103
- emit( /* type, msg , ... */
177
+ emit(/* type, msg , ... */
104
178
  ) {
105
179
  const r = _emit.apply(this, arguments);
106
180
  if (!r) {
@@ -143,7 +217,7 @@ function getEventableMethods(aClass) {
143
217
  * @param {...*} args - The event type followed by any number of arguments to be passed to the listener functions.
144
218
  * @returns {Promise<*>} A promise that resolves with the result of the event.
145
219
  */
146
- async emitAsync( /* type, msg , ... */
220
+ async emitAsync(/* type, msg , ... */
147
221
  ) {
148
222
  const r = _emit.apply(this, arguments);
149
223
  if (!r) {
@@ -152,27 +226,9 @@ function getEventableMethods(aClass) {
152
226
  const args = r.args;
153
227
  const listeners = r.listeners;
154
228
  const evt = (0, _event.Event)(this, r.type);
155
- const errs = [];
229
+ const options = Object.assign({}, this._emitterOptions, this._eeRuntimeOptions);
156
230
  try {
157
- for (const listener of listeners) {
158
- try {
159
- await _notify(listener, evt, args);
160
- if (evt.stopped) {
161
- break;
162
- }
163
- } catch (err) {
164
- errs.push({
165
- err: err,
166
- listener: listener
167
- });
168
- }
169
- }
170
- if (errs.length) {
171
- for (let i = 0; i < errs.length; i++) {
172
- const it = errs[i];
173
- this.emit('error', it.err, 'notify', r.type, it.listener, args);
174
- }
175
- }
231
+ await _executeAsync.call(this, listeners, evt, args, options);
176
232
  } finally {
177
233
  // eslint-disable-next-line no-unsafe-finally
178
234
  return evt.end();
@@ -266,10 +322,14 @@ function getEventableMethods(aClass) {
266
322
  if (i < 0) {
267
323
  return this;
268
324
  }
325
+ if (listeners._headCount && i < listeners._headCount) {
326
+ listeners._headCount--;
327
+ } else if (listeners._tailCount && i >= listeners.length - listeners._tailCount) {
328
+ listeners._tailCount--;
329
+ }
269
330
  if (listeners.length === 1) {
270
- listeners.length = 0;
271
331
  delete data[type];
272
- } else if (listeners.length === 2) {
332
+ } else if (listeners.length === 2 && !listeners._headCount && !listeners._tailCount) {
273
333
  data[type] = listeners[i ? 0 : 1];
274
334
  listeners.length = 1;
275
335
  } else {
@@ -420,4 +480,67 @@ function _notify(listener, evt, args) {
420
480
  }
421
481
  }
422
482
  return result;
483
+ }
484
+ async function _executeAsync(listeners, evt, args, options) {
485
+ const asyncMode = options.asyncMode || 'serial';
486
+ const resultMode = options.resultMode || 'last';
487
+ const errs = [];
488
+ if (resultMode === 'collect') {
489
+ evt.result = [];
490
+ }
491
+ const notifyListener = async listener => {
492
+ try {
493
+ const result = await _notify(listener, evt, args);
494
+ if (result !== undefined) {
495
+ if (resultMode === 'first' && !evt.resolved) {
496
+ evt.result = result;
497
+ evt.resolved = true;
498
+ } else if (resultMode === 'last') {
499
+ evt.result = result;
500
+ }
501
+ }
502
+ return result;
503
+ } catch (err) {
504
+ errs.push({
505
+ err,
506
+ listener
507
+ });
508
+ throw err;
509
+ }
510
+ };
511
+ if (asyncMode === 'parallel') {
512
+ const promises = listeners.map(listener => notifyListener(listener));
513
+ if (resultMode === 'collect') {
514
+ evt.result = await Promise.all(promises.map(p => p.catch(() => undefined)));
515
+ } else if (resultMode === 'first') {
516
+ try {
517
+ await Promise.any(promises.map(p => p.then(res => res === undefined ? Promise.reject() : res)));
518
+ } catch (e) {
519
+ // If all rejected or returned undefined, ignore
520
+ }
521
+ } else {
522
+ await Promise.all(promises.map(p => p.catch(() => undefined)));
523
+ }
524
+ } else {
525
+ // Serial mode (default)
526
+ for (const listener of listeners) {
527
+ try {
528
+ const result = await notifyListener(listener);
529
+ if (resultMode === 'collect') {
530
+ evt.result.push(result);
531
+ }
532
+ if (evt.stopped || resultMode === 'first' && evt.resolved) break;
533
+ } catch (err) {
534
+ if (resultMode === 'collect') {
535
+ evt.result.push(undefined);
536
+ }
537
+ }
538
+ }
539
+ }
540
+ if (errs.length) {
541
+ for (let i = 0; i < errs.length; i++) {
542
+ const it = errs[i];
543
+ this.emit('error', it.err, 'notify', evt.type, it.listener, args);
544
+ }
545
+ }
423
546
  }
@@ -10,18 +10,28 @@ export class EventEmitter {
10
10
  * Adds a listener function to the specified event type.
11
11
  * @param {string|RegExp} type - The event type to listen for.
12
12
  * @param {Function} listener - The listener function to be called when the event is emitted.
13
+ * @param {number|'first'|'last'} [index] - The index at which to insert the listener.
14
+ * - 'first' or -Infinity: adds to the beginning of the listeners (stay at the front).
15
+ * - 'last' or Infinity: adds to the end of the listeners (stay at the back).
16
+ * - number: inserts at the specified index within the normal listeners zone.
17
+ * If not specified, the listener will be added at the end of the normal listeners.
13
18
  * @returns {EventEmitter} The EventEmitter instance to allow chaining.
14
19
  * @throws {TypeError} If the listener is not a function.
15
20
  */
16
- on(eventName: string|RegExp, listener: ListenerCallbackFunc): EventEmitter;
21
+ on(eventName: string|RegExp, listener: ListenerCallbackFunc, index?: number|'first'|'last'): EventEmitter;
17
22
  /**
18
23
  * Adds a one-time listener function to the specified event type.
19
24
  * @param {string|RegExp} type - The event type to listen for.
20
25
  * @param {Function} listener - The listener function to be called once when the event is emitted.
26
+ * @param {number|'first'|'last'} [index] - The index at which to insert the listener.
27
+ * - 'first' or -Infinity: adds to the beginning of the listeners (stay at the front).
28
+ * - 'last' or Infinity: adds to the end of the listeners (stay at the back).
29
+ * - number: inserts at the specified index within the normal listeners zone.
30
+ * If not specified, the listener will be added at the end of the normal listeners.
21
31
  * @returns {EventEmitter} The EventEmitter instance to allow chaining.
22
32
  * @throws {TypeError} If the listener is not a function.
23
33
  */
24
- once(eventName: string|RegExp, listener: ListenerCallbackFunc): EventEmitter;
34
+ once(eventName: string|RegExp, listener: ListenerCallbackFunc, index?: number|'first'|'last'): EventEmitter;
25
35
  /**
26
36
  * Removes a listener function from the specified event type.
27
37
  * @param {string|RegExp} type - The event type to remove the listener from.
package/lib/event.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * @param {import('./event-emitter').EventEmitter} target - Who trigger the event
6
6
  * @returns {Event} - The new Event instance.
7
7
  */
8
- export function Event(target: import('./event-emitter').EventEmitter, type: any): Event;
8
+ export function Event(target: import("./event-emitter").EventEmitter, type: any): Event;
9
9
  export class Event {
10
10
  /**
11
11
  * Creates a new Event object instance that contains information about the event, such as the target element and the return value of the event.
@@ -14,12 +14,12 @@ export class Event {
14
14
  * @param {import('./event-emitter').EventEmitter} target - Who trigger the event
15
15
  * @returns {Event} - The new Event instance.
16
16
  */
17
- constructor(target: import('./event-emitter').EventEmitter, type: any);
17
+ constructor(target: import("./event-emitter").EventEmitter, type: any);
18
18
  /**
19
19
  * Initializes the event with the target object.
20
20
  * @param {import('./event-emitter').EventEmitter} target - The target object for the event.
21
21
  */
22
- init(target: import('./event-emitter').EventEmitter, type: any): void;
22
+ init(target: import("./event-emitter").EventEmitter, type: any): void;
23
23
  /**
24
24
  * Who trigger the event
25
25
  * @type {Object}
@@ -32,6 +32,12 @@ export class Event {
32
32
  * @public
33
33
  */
34
34
  public stopped: boolean;
35
+ /**
36
+ * Whether a result has been resolved (for 'first' result mode)
37
+ * @type {boolean}
38
+ * @public
39
+ */
40
+ public resolved: boolean;
35
41
  /**
36
42
  * Keep your event result here if any.
37
43
  * @type {*}
package/lib/event.js CHANGED
@@ -37,6 +37,12 @@ Event.prototype.init = function (target, type) {
37
37
  * @public
38
38
  */
39
39
  this.stopped = false;
40
+ /**
41
+ * Whether a result has been resolved (for 'first' result mode)
42
+ * @type {boolean}
43
+ * @public
44
+ */
45
+ this.resolved = false;
40
46
  /**
41
47
  * Keep your event result here if any.
42
48
  * @type {*}
package/lib/eventable.js CHANGED
@@ -7,7 +7,7 @@ exports.eventable = exports.default = void 0;
7
7
  var _customAbility = require("custom-ability");
8
8
  var _defineProperty = _interopRequireDefault(require("util-ex/lib/defineProperty"));
9
9
  var _defaultMethods = _interopRequireDefault(require("./default-methods"));
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
11
  /**
12
12
  * Creates an Eventable class with event-emitting capabilities.
13
13
  *
@@ -31,6 +31,9 @@ function getEventableClass(aClass) {
31
31
  Eventable.prototype.listenerCount = methods.listenerCount;
32
32
  Eventable.prototype.emit = methods.emit;
33
33
  Eventable.prototype.emitAsync = methods.emitAsync;
34
+ Eventable.prototype.configure = methods.configure;
35
+ Eventable.prototype.parallel = methods.parallel;
36
+ Eventable.prototype.setEmitterOptions = methods.setEmitterOptions;
34
37
  Eventable.prototype.on = methods.on;
35
38
  Eventable.prototype.addListener = methods.on;
36
39
  Eventable.prototype.off = methods.off;
@@ -4,8 +4,11 @@
4
4
  * @param {import('./event-emitter').EventEmitter} e1 - The first event emitter.
5
5
  * @param {import('./event-emitter').EventEmitter} e2 - The second event emitter.
6
6
  * @param {string} [name='emitAsync'] - The name of the event to pipe (defaults to 'emitAsync').
7
+ * @param {Object} [options] - Configuration for the pipeline.
8
+ * @param {string} [options.asyncMode='serial'] - The mode of propagation ('serial' or 'parallel').
9
+ * @param {string} [options.resultMode] - Strategy for aggregating results from the pipe chain ('collect', 'first').
7
10
  * @returns {Object} - An object with a `close` method that removes the pipeline between the two event emitters.
8
11
  * @throws {TypeError} - If either of the arguments is not an event emitter object.
9
12
  */
10
- export function pipeAsync(e1: import('./event-emitter').EventEmitter, e2: import('./event-emitter').EventEmitter, ...args: any[]): any;
13
+ export function pipeAsync(e1: import("./event-emitter").EventEmitter, e2: import("./event-emitter").EventEmitter, ...args: any[]): any;
11
14
  export default pipeAsync;
package/lib/pipe-async.js CHANGED
@@ -9,7 +9,7 @@ var _defineProperty = _interopRequireDefault(require("util-ex/lib/defineProperty
9
9
  var _wrapEventEmitter = require("./wrap-event-emitter");
10
10
  var _arrayRemove = _interopRequireDefault(require("./util/array-remove"));
11
11
  var _validObject = _interopRequireDefault(require("./util/valid-object"));
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
13
  const hasOwnProperty = Object.prototype.hasOwnProperty;
14
14
  const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
15
15
  const arrFrom = Array.from;
@@ -21,16 +21,27 @@ const emit = _wrapEventEmitter.methods.emitAsync;
21
21
  * @param {import('./event-emitter').EventEmitter} e1 - The first event emitter.
22
22
  * @param {import('./event-emitter').EventEmitter} e2 - The second event emitter.
23
23
  * @param {string} [name='emitAsync'] - The name of the event to pipe (defaults to 'emitAsync').
24
+ * @param {Object} [options] - Configuration for the pipeline.
25
+ * @param {string} [options.asyncMode='serial'] - The mode of propagation ('serial' or 'parallel').
26
+ * @param {string} [options.resultMode] - Strategy for aggregating results from the pipe chain ('collect', 'first').
24
27
  * @returns {Object} - An object with a `close` method that removes the pipeline between the two event emitters.
25
28
  * @throws {TypeError} - If either of the arguments is not an event emitter object.
26
29
  */
27
- function pipeAsync(e1, e2 /* , name */) {
30
+ function pipeAsync(e1, e2 /* , name, options */) {
28
31
  let pipes;
29
32
  (0, _validObject.default)(e1) && (0, _validObject.default)(e2);
30
33
  let name = arguments[2];
34
+ let options = arguments[3];
35
+ if (typeof name === 'object') {
36
+ options = name;
37
+ name = undefined;
38
+ }
31
39
  if (name === undefined) {
32
40
  name = 'emitAsync';
33
41
  }
42
+ if (!options) {
43
+ options = {};
44
+ }
34
45
  const result = {
35
46
  close() {
36
47
  _arrayRemove.default.call(pipes, e2);
@@ -50,9 +61,32 @@ function pipeAsync(e1, e2 /* , name */) {
50
61
  }
51
62
  desc.value = async function () {
52
63
  const data = arrFrom(pipes);
53
- await emit.apply(this, arguments);
54
- let emitter;
55
- for (let i = 0; emitter = data[i]; ++i) await emit.apply(emitter, arguments);
64
+ const asyncMode = options.asyncMode || 'serial';
65
+ const resultMode = options.resultMode;
66
+ const forward = async (target, args) => {
67
+ const fn = target[name] || target.emitAsync || emit;
68
+ return fn.apply(target, args);
69
+ };
70
+ if (asyncMode === 'parallel') {
71
+ const promises = [emit.apply(this, arguments)];
72
+ for (let i = 0; i < data.length; ++i) {
73
+ promises.push(forward(data[i], arguments));
74
+ }
75
+ const results = await Promise.all(promises);
76
+ if (resultMode === 'collect') return results;
77
+ if (resultMode === 'first') return results.find(r => r !== undefined);
78
+ return results[0]; // Default: return main emitter's result
79
+ } else {
80
+ const mainResult = await emit.apply(this, arguments);
81
+ const allResults = [mainResult];
82
+ for (let i = 0; i < data.length; ++i) {
83
+ const res = await forward(data[i], arguments);
84
+ allResults.push(res);
85
+ }
86
+ if (resultMode === 'collect') return allResults;
87
+ if (resultMode === 'first') return allResults.find(r => r !== undefined);
88
+ return mainResult; // Default: return main emitter's result
89
+ }
56
90
  };
57
91
  (0, _defineProperty.default)(e1, name, desc.value, desc);
58
92
  return result;
package/lib/pipe.d.ts CHANGED
@@ -7,5 +7,5 @@
7
7
  * @returns {Object} - An object with a `close` method that removes the pipeline between the two event emitters.
8
8
  * @throws {TypeError} - If either of the arguments is not an event emitter object.
9
9
  */
10
- export function pipe(e1: import('./event-emitter').EventEmitter, e2: import('./event-emitter').EventEmitter, ...args: any[]): any;
10
+ export function pipe(e1: import("./event-emitter").EventEmitter, e2: import("./event-emitter").EventEmitter, ...args: any[]): any;
11
11
  export default pipe;
package/lib/pipe.js CHANGED
@@ -9,7 +9,7 @@ var _defineProperty = _interopRequireDefault(require("util-ex/lib/defineProperty
9
9
  var _wrapEventEmitter = require("./wrap-event-emitter");
10
10
  var _arrayRemove = _interopRequireDefault(require("./util/array-remove"));
11
11
  var _validObject = _interopRequireDefault(require("./util/valid-object"));
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
13
  const hasOwnProperty = Object.prototype.hasOwnProperty;
14
14
  const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
15
15
  const arrFrom = Array.from;
package/lib/unify.d.ts CHANGED
@@ -5,5 +5,5 @@
5
5
  * @param {import('./event-emitter').EventEmitter} e2 - The second event emitter object.
6
6
  * @throws {TypeError} - If either of the arguments is not an event emitter object.
7
7
  */
8
- export function unify(e1: import('./event-emitter').EventEmitter, e2: import('./event-emitter').EventEmitter): void;
8
+ export function unify(e1: import("./event-emitter").EventEmitter, e2: import("./event-emitter").EventEmitter): void;
9
9
  export default unify;
package/lib/unify.js CHANGED
@@ -7,7 +7,7 @@ exports.default = void 0;
7
7
  exports.unify = unify;
8
8
  var _validObject = _interopRequireDefault(require("./util/valid-object"));
9
9
  var _objectForEach = _interopRequireDefault(require("./util/object-for-each"));
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
11
  const push = Array.prototype.apply;
12
12
  const defineProperty = Object.defineProperty;
13
13
  const create = Object.create;
@@ -8,7 +8,7 @@ exports.remove = remove;
8
8
  const indexOf = Array.prototype.indexOf;
9
9
  const forEach = Array.prototype.forEach;
10
10
  const splice = Array.prototype.splice;
11
- function remove( /* ...itemsToRemove */
11
+ function remove(/* ...itemsToRemove */
12
12
  ) {
13
13
  forEach.call(arguments, function (item) {
14
14
  const index = indexOf.call(this, item);
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  exports.forEach = forEach;
8
8
  var _validObject = _interopRequireDefault(require("./valid-object"));
9
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
10
  const bind = Function.prototype.bind;
11
11
  const keys = Object.keys;
12
12
  function forEach(obj, cb /* , thisArg, compareFn */) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ /**
8
+ * Simple polyfill for AggregateError if it doesn't exist.
9
+ */
10
+ const _AggregateError = typeof AggregateError !== 'undefined' ? AggregateError : function AggregateError(errors, message) {
11
+ const error = new Error(message);
12
+ error.name = 'AggregateError';
13
+ error.errors = errors;
14
+ return error;
15
+ };
16
+
17
+ /**
18
+ * Ensures Promise.any exists, or provides a polyfill.
19
+ */
20
+ if (typeof Promise.any !== 'function') {
21
+ Promise.any = function (promises) {
22
+ return new Promise((resolve, reject) => {
23
+ promises = Array.from(promises);
24
+ const len = promises.length;
25
+ let errors = [];
26
+ let rejectedCount = 0;
27
+ if (len === 0) {
28
+ return reject(new _AggregateError(errors, 'All promises were rejected'));
29
+ }
30
+ promises.forEach((promise, index) => {
31
+ Promise.resolve(promise).then(value => {
32
+ resolve(value);
33
+ }).catch(error => {
34
+ errors[index] = error;
35
+ rejectedCount++;
36
+ if (rejectedCount === len) {
37
+ reject(new _AggregateError(errors, 'All promises were rejected'));
38
+ }
39
+ });
40
+ });
41
+ });
42
+ };
43
+ }
44
+ var _default = exports.default = Promise.any;
@@ -7,7 +7,7 @@ exports.default = void 0;
7
7
  exports.pad = pad;
8
8
  var _toInt = _interopRequireDefault(require("./to-int"));
9
9
  var _validObject = _interopRequireDefault(require("./valid-object"));
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
11
  const repeat = String.prototype.repeat;
12
12
  const abs = Math.abs;
13
13
  const max = Math.max;
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Create or inject the eventable instance into the object
3
3
  * @param {Object} [o] the optional instance to eventable
4
+ * @param {Object} [options] optional configuration for the emitter
4
5
  * @returns o or new Event instance
5
6
  */
6
- export function wrapEventEmitter(o?: any): any;
7
+ export function wrapEventEmitter(o?: any, options?: any): any;
7
8
  export const methods: any;
8
9
  export default wrapEventEmitter;
@@ -7,10 +7,14 @@ exports.methods = exports.default = void 0;
7
7
  exports.wrapEventEmitter = wrapEventEmitter;
8
8
  var _utilEx = require("util-ex");
9
9
  var _eventable = _interopRequireDefault(require("./eventable"));
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
11
  const create = Object.create;
12
12
  const defineProperties = Object.defineProperties;
13
13
  const methods = exports.methods = (0, _eventable.default)().methods;
14
+
15
+ /**
16
+ * Minimal set of core methods to be injected into an existing object.
17
+ */
14
18
  const descriptors = {
15
19
  on: {
16
20
  value: methods.on
@@ -26,18 +30,35 @@ const descriptors = {
26
30
  },
27
31
  emitAsync: {
28
32
  value: methods.emitAsync
33
+ },
34
+ setEmitterOptions: {
35
+ value: methods.setEmitterOptions
29
36
  }
30
37
  };
31
- const base = defineProperties({}, descriptors);
38
+
39
+ /**
40
+ * Full set of all available methods from eventable for standalone instances.
41
+ */
42
+ const fullDescriptors = {};
43
+ Object.keys(methods).forEach(key => {
44
+ fullDescriptors[key] = {
45
+ value: methods[key]
46
+ };
47
+ });
48
+ const base = defineProperties({}, fullDescriptors);
32
49
 
33
50
  /**
34
51
  * Create or inject the eventable instance into the object
35
52
  * @param {Object} [o] the optional instance to eventable
53
+ * @param {Object} [options] optional configuration for the emitter
36
54
  * @returns o or new Event instance
37
55
  */
38
- function wrapEventEmitter(o) {
56
+ function wrapEventEmitter(o, options) {
39
57
  const result = o == null ? create(base) : defineProperties(Object(o), descriptors);
40
58
  (0, _utilEx.defineProperty)(result, '_events', {});
59
+ if (options && options.emitterOptions) {
60
+ result.setEmitterOptions(options.emitterOptions);
61
+ }
41
62
  return result;
42
63
  }
43
64
  ;