evnty 5.0.0 → 5.1.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 (69) hide show
  1. package/README.md +28 -28
  2. package/build/async.cjs +101 -0
  3. package/build/async.cjs.map +1 -0
  4. package/build/async.d.ts +37 -0
  5. package/build/async.js +83 -0
  6. package/build/async.js.map +1 -0
  7. package/build/broadcast.cjs +205 -0
  8. package/build/broadcast.cjs.map +1 -0
  9. package/build/broadcast.d.ts +164 -0
  10. package/build/broadcast.js +184 -0
  11. package/build/broadcast.js.map +1 -0
  12. package/build/dispatch-result.cjs +154 -0
  13. package/build/dispatch-result.cjs.map +1 -0
  14. package/build/dispatch-result.d.ts +49 -0
  15. package/build/dispatch-result.js +127 -0
  16. package/build/dispatch-result.js.map +1 -0
  17. package/build/event.cjs +92 -127
  18. package/build/event.cjs.map +1 -1
  19. package/build/event.d.ts +92 -167
  20. package/build/event.js +90 -122
  21. package/build/event.js.map +1 -1
  22. package/build/index.cjs +3 -1
  23. package/build/index.cjs.map +1 -1
  24. package/build/index.d.ts +3 -1
  25. package/build/index.js +3 -1
  26. package/build/index.js.map +1 -1
  27. package/build/iterator.cjs +578 -91
  28. package/build/iterator.cjs.map +1 -1
  29. package/build/iterator.d.ts +178 -7
  30. package/build/iterator.js +579 -92
  31. package/build/iterator.js.map +1 -1
  32. package/build/listener-registry.cjs +114 -0
  33. package/build/listener-registry.cjs.map +1 -0
  34. package/build/listener-registry.d.ts +54 -0
  35. package/build/listener-registry.js +104 -0
  36. package/build/listener-registry.js.map +1 -0
  37. package/build/ring-buffer.cjs +171 -0
  38. package/build/ring-buffer.cjs.map +1 -0
  39. package/build/ring-buffer.d.ts +80 -0
  40. package/build/ring-buffer.js +161 -0
  41. package/build/ring-buffer.js.map +1 -0
  42. package/build/sequence.cjs +34 -35
  43. package/build/sequence.cjs.map +1 -1
  44. package/build/sequence.d.ts +38 -24
  45. package/build/sequence.js +34 -35
  46. package/build/sequence.js.map +1 -1
  47. package/build/signal.cjs +26 -35
  48. package/build/signal.cjs.map +1 -1
  49. package/build/signal.d.ts +36 -39
  50. package/build/signal.js +26 -35
  51. package/build/signal.js.map +1 -1
  52. package/build/types.cjs +0 -11
  53. package/build/types.cjs.map +1 -1
  54. package/build/types.d.ts +86 -9
  55. package/build/types.js +1 -5
  56. package/build/types.js.map +1 -1
  57. package/build/utils.cjs +202 -22
  58. package/build/utils.cjs.map +1 -1
  59. package/build/utils.d.ts +85 -26
  60. package/build/utils.js +181 -22
  61. package/build/utils.js.map +1 -1
  62. package/package.json +27 -25
  63. package/src/__tests__/example.js +19 -24
  64. package/src/index.ts +3 -1
  65. package/build/callable.cjs +0 -72
  66. package/build/callable.cjs.map +0 -1
  67. package/build/callable.d.ts +0 -34
  68. package/build/callable.js +0 -51
  69. package/build/callable.js.map +0 -1
package/build/utils.js CHANGED
@@ -1,22 +1,107 @@
1
- export const iterate = (...args)=>{
2
- let start, count, step;
3
- if (args.length === 0) {
4
- start = 0;
5
- count = Infinity;
6
- step = 1;
7
- } else if (args.length === 1) {
8
- start = 0;
9
- count = args[0];
10
- step = 1;
11
- } else if (args.length === 2) {
12
- start = args[0];
13
- count = args[1];
14
- step = 1;
1
+ import { Sequence } from "./sequence.js";
2
+ export function isThenable(value) {
3
+ return value !== null && typeof value === 'object' && typeof value.then === 'function';
4
+ }
5
+ export const noop = ()=>{};
6
+ export function min(values, fallback) {
7
+ let result = Infinity;
8
+ for (const value of values){
9
+ if (value < result) result = value;
10
+ }
11
+ return result === Infinity ? fallback : result;
12
+ }
13
+ export var MapIteratorType = /*#__PURE__*/ function(MapIteratorType) {
14
+ MapIteratorType[MapIteratorType["NEXT"] = 0] = "NEXT";
15
+ MapIteratorType[MapIteratorType["RETURN"] = 1] = "RETURN";
16
+ MapIteratorType[MapIteratorType["THROW"] = 2] = "THROW";
17
+ return MapIteratorType;
18
+ }({});
19
+ export const mapIterator = (iterator, map)=>{
20
+ const subIterator = {
21
+ next: async (...args)=>{
22
+ const result = await iterator.next(...args);
23
+ return map(result, 0);
24
+ }
25
+ };
26
+ if (iterator.return) {
27
+ subIterator.return = async (...args)=>{
28
+ const result = await iterator.return(...args);
29
+ return map(result, 1);
30
+ };
15
31
  } else {
16
- start = args[0];
17
- count = args[1];
18
- step = args[2];
32
+ subIterator.return = async (value)=>{
33
+ return map({
34
+ done: true,
35
+ value
36
+ }, 1);
37
+ };
38
+ }
39
+ if (iterator.throw) {
40
+ subIterator.throw = async (...args)=>{
41
+ const result = await iterator.throw(...args);
42
+ return map(result, 2);
43
+ };
19
44
  }
45
+ return subIterator;
46
+ };
47
+ export function abortableIterable(iterable, signal) {
48
+ return {
49
+ [Symbol.asyncIterator] () {
50
+ const iterator = iterable[Symbol.asyncIterator]();
51
+ const { promise, resolve } = Promise.withResolvers();
52
+ const onAbort = ()=>resolve();
53
+ let closed = false;
54
+ const finish = (value)=>{
55
+ if (closed) {
56
+ return Promise.resolve({
57
+ done: true,
58
+ value: value
59
+ });
60
+ }
61
+ closed = true;
62
+ signal.removeEventListener('abort', onAbort);
63
+ return iterator.return?.(value) ?? Promise.resolve({
64
+ done: true,
65
+ value: value
66
+ });
67
+ };
68
+ if (signal.aborted) {
69
+ onAbort();
70
+ } else {
71
+ signal.addEventListener('abort', onAbort);
72
+ }
73
+ const race = [
74
+ promise,
75
+ undefined
76
+ ];
77
+ return {
78
+ async next (...args) {
79
+ race[1] = iterator.next(...args);
80
+ const result = await Promise.race(race);
81
+ if (result === undefined) {
82
+ void finish();
83
+ return {
84
+ done: true,
85
+ value: undefined
86
+ };
87
+ }
88
+ if (result.done) {
89
+ closed = true;
90
+ signal.removeEventListener('abort', onAbort);
91
+ }
92
+ return result;
93
+ },
94
+ async return (value) {
95
+ return finish(value);
96
+ }
97
+ };
98
+ }
99
+ };
100
+ }
101
+ export const iterate = (startOrCount, countWhenTwoArgs, step = 1)=>{
102
+ const hasStartArg = countWhenTwoArgs !== undefined;
103
+ const start = hasStartArg ? startOrCount : 0;
104
+ const count = startOrCount === undefined ? Infinity : hasStartArg ? countWhenTwoArgs : startOrCount;
20
105
  return {
21
106
  [Symbol.iterator] () {
22
107
  let idx = 0;
@@ -90,16 +175,90 @@ export const toAsyncIterable = (iterable)=>{
90
175
  }
91
176
  };
92
177
  };
178
+ const isAsyncIterable = (value)=>{
179
+ return typeof value[Symbol.asyncIterator] === 'function';
180
+ };
93
181
  export async function* pipe(iterable, generatorFactory, signal) {
182
+ const source = signal ? abortableIterable(iterable, signal) : iterable;
94
183
  const generator = generatorFactory();
95
- for await (const value of iterable){
96
- if (signal?.aborted) return;
97
- for await (const subValue of generator(value)){
184
+ for await (const value of source){
185
+ const produced = generator(value);
186
+ const subIterable = isAsyncIterable(produced) ? produced : toAsyncIterable(produced);
187
+ const abortableSub = signal ? abortableIterable(subIterable, signal) : subIterable;
188
+ for await (const subValue of abortableSub){
98
189
  yield subValue;
99
- if (signal?.aborted) return;
100
190
  }
101
- if (signal?.aborted) return;
102
191
  }
103
192
  }
193
+ export const mergeIterables = (...iterables)=>{
194
+ return {
195
+ [Symbol.asyncIterator] () {
196
+ if (iterables.length === 0) {
197
+ return {
198
+ next: async ()=>({
199
+ value: undefined,
200
+ done: true
201
+ })
202
+ };
203
+ }
204
+ const exit = Symbol('mergeIterables.exit');
205
+ const ctrl = new AbortController();
206
+ const sequence = new Sequence(ctrl.signal);
207
+ let remaining = iterables.length;
208
+ const pump = async (iterable)=>{
209
+ try {
210
+ for await (const value of abortableIterable(iterable, ctrl.signal)){
211
+ if (!sequence.emit(value)) {
212
+ break;
213
+ }
214
+ }
215
+ } catch (error) {
216
+ ctrl.abort(error);
217
+ } finally{
218
+ remaining -= 1;
219
+ if (remaining === 0 && !ctrl.signal.aborted) {
220
+ ctrl.abort(exit);
221
+ }
222
+ }
223
+ };
224
+ for (const iterable of iterables){
225
+ void pump(iterable);
226
+ }
227
+ return {
228
+ next: async ()=>{
229
+ try {
230
+ const value = await sequence.receive();
231
+ return {
232
+ value,
233
+ done: false
234
+ };
235
+ } catch {
236
+ if (ctrl.signal.aborted && ctrl.signal.reason === exit) {
237
+ return {
238
+ value: undefined,
239
+ done: true
240
+ };
241
+ }
242
+ throw ctrl.signal.reason;
243
+ }
244
+ },
245
+ return: async ()=>{
246
+ ctrl.abort(exit);
247
+ return {
248
+ value: undefined,
249
+ done: true
250
+ };
251
+ },
252
+ throw: async (error)=>{
253
+ ctrl.abort(error);
254
+ return {
255
+ value: undefined,
256
+ done: true
257
+ };
258
+ }
259
+ };
260
+ }
261
+ };
262
+ };
104
263
 
105
264
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["/**\n * Interface for creating iterable number sequences with various parameter combinations.\n * Supports infinite sequences, counted sequences, and sequences with custom start and step values.\n */\nexport interface Iterate {\n (): Iterable<number, void, unknown>;\n (count: number): Iterable<number, void, unknown>;\n (start: number, count: number): Iterable<number, void, unknown>;\n (start: number, count: number, step: number): Iterable<number, void, unknown>;\n}\n\n/**\n * Creates an iterable sequence of numbers with flexible parameters.\n * Can generate infinite sequences, finite sequences, or sequences with custom start and step values.\n *\n * @param args Variable arguments to configure the sequence:\n * - No args: Infinite sequence starting at 0 with step 1\n * - 1 arg (count): Sequence from 0 to count-1\n * - 2 args (start, count): Sequence starting at 'start' for 'count' iterations\n * - 3 args (start, count, step): Custom start, count, and step value\n * @returns An iterable that generates numbers according to the parameters\n *\n * @example\n * ```typescript\n * // Infinite sequence: 0, 1, 2, 3, ...\n * for (const n of iterate()) { }\n *\n * // Count only: 0, 1, 2, 3, 4\n * for (const n of iterate(5)) { }\n *\n * // Start and count: 10, 11, 12, 13, 14\n * for (const n of iterate(10, 5)) { }\n *\n * // Start, count, and step: 0, 2, 4, 6, 8\n * for (const n of iterate(0, 5, 2)) { }\n * ```\n */\nexport const iterate: Iterate = (...args: number[]): Iterable<number, void, unknown> => {\n let start: number, count: number, step: number;\n\n if (args.length === 0) {\n start = 0;\n count = Infinity;\n step = 1;\n } else if (args.length === 1) {\n start = 0;\n count = args[0]!;\n step = 1;\n } else if (args.length === 2) {\n start = args[0]!;\n count = args[1]!;\n step = 1;\n } else {\n start = args[0]!;\n count = args[1]!;\n step = args[2]!;\n }\n\n return {\n [Symbol.iterator]() {\n let idx = 0;\n let current = start;\n return {\n next() {\n if (idx < count) {\n const value = current;\n current += step;\n idx++;\n return { value, done: false };\n }\n return { value: undefined, done: true };\n },\n return(value) {\n idx = count;\n return { value, done: true };\n },\n throw(error?: unknown) {\n idx = count;\n throw error;\n },\n } satisfies Iterator<number, void, unknown>;\n },\n };\n};\n\n/**\n * @internal\n * Creates a promise that resolves after a specified timeout. If an `AbortSignal` is provided and triggered,\n * the timeout is cleared, and the promise resolves to `false`.\n *\n * @param {number} timeout - The time in milliseconds to wait before resolving the promise.\n * @param {AbortSignal} [signal] - An optional `AbortSignal` that can abort the timeout.\n * @returns {Promise<boolean>} A promise that resolves to `true` if the timeout completed, or `false` if it was aborted.\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n * setTimeout(() => controller.abort(), 500);\n * const result = await setTimeoutAsync(1000, controller.signal);\n * console.log(result); // false\n * ```\n */\nexport const setTimeoutAsync = async (timeout: number, signal?: AbortSignal): Promise<boolean> => {\n if (signal?.aborted) {\n return false;\n }\n const { promise, resolve } = Promise.withResolvers<boolean>();\n const timerId = setTimeout(resolve, timeout, true);\n const onAbort = () => {\n clearTimeout(timerId);\n resolve(false);\n };\n signal?.addEventListener('abort', onAbort);\n\n return promise.finally(() => signal?.removeEventListener('abort', onAbort));\n};\n\n/**\n * Converts a synchronous iterable to an asynchronous iterable.\n * Wraps the sync iterator methods to return promises, enabling uniform async handling.\n *\n * @template T The type of values yielded by the iterator\n * @template TReturn The return type of the iterator\n * @template TNext The type of value that can be passed to next()\n * @param iterable A synchronous iterable to convert\n * @returns An async iterable that yields the same values as the input\n *\n * @example\n * ```typescript\n * const syncArray = [1, 2, 3, 4, 5];\n * const asyncIterable = toAsyncIterable(syncArray);\n *\n * for await (const value of asyncIterable) {\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n */\nexport const toAsyncIterable = <T, TReturn, TNext>(iterable: Iterable<T, TReturn, TNext>): AsyncIterable<T, TReturn, TNext> => {\n return {\n [Symbol.asyncIterator]() {\n const iterator = iterable[Symbol.iterator]();\n return {\n async next(...args: [TNext] | []) {\n return iterator.next(...args);\n },\n async return(maybeValue) {\n const value = await maybeValue;\n return iterator.return?.(value) ?? ({ value, done: true } as IteratorResult<T, TReturn>);\n },\n async throw(error) {\n if (iterator.throw) {\n return iterator.throw(error);\n }\n throw error;\n },\n } satisfies AsyncIterator<T, TReturn, TNext>;\n },\n };\n};\n\n/**\n * Pipes values from an async iterable through a generator transformation.\n * Applies a generator function to each value, yielding all resulting values.\n * Supports cancellation via AbortSignal for early termination.\n *\n * @template T The input value type\n * @template U The output value type\n * @param iterable The source async iterable\n * @param generatorFactory A factory that returns a generator function for transforming values\n * @param signal Optional AbortSignal to cancel the operation\n * @returns An async generator yielding transformed values\n *\n * @example\n * ```typescript\n * async function* source() {\n * yield 1; yield 2; yield 3;\n * }\n *\n * const doubled = pipe(source(), () => async function*(n) {\n * yield n * 2;\n * });\n *\n * for await (const value of doubled) {\n * console.log(value); // 2, 4, 6\n * }\n * ```\n */\nexport async function* pipe<T, U>(\n iterable: AsyncIterable<T>,\n generatorFactory: () => (value: T) => AsyncIterable<U>,\n signal?: AbortSignal,\n): AsyncGenerator<Awaited<U>, void, unknown> {\n const generator = generatorFactory();\n for await (const value of iterable) {\n if (signal?.aborted) return;\n for await (const subValue of generator(value)) {\n yield subValue;\n if (signal?.aborted) return;\n }\n if (signal?.aborted) return;\n }\n}\n"],"names":["iterate","args","start","count","step","length","Infinity","Symbol","iterator","idx","current","next","value","done","undefined","return","throw","error","setTimeoutAsync","timeout","signal","aborted","promise","resolve","Promise","withResolvers","timerId","setTimeout","onAbort","clearTimeout","addEventListener","finally","removeEventListener","toAsyncIterable","iterable","asyncIterator","maybeValue","pipe","generatorFactory","generator","subValue"],"mappings":"AAqCA,OAAO,MAAMA,UAAmB,CAAC,GAAGC;IAClC,IAAIC,OAAeC,OAAeC;IAElC,IAAIH,KAAKI,MAAM,KAAK,GAAG;QACrBH,QAAQ;QACRC,QAAQG;QACRF,OAAO;IACT,OAAO,IAAIH,KAAKI,MAAM,KAAK,GAAG;QAC5BH,QAAQ;QACRC,QAAQF,IAAI,CAAC,EAAE;QACfG,OAAO;IACT,OAAO,IAAIH,KAAKI,MAAM,KAAK,GAAG;QAC5BH,QAAQD,IAAI,CAAC,EAAE;QACfE,QAAQF,IAAI,CAAC,EAAE;QACfG,OAAO;IACT,OAAO;QACLF,QAAQD,IAAI,CAAC,EAAE;QACfE,QAAQF,IAAI,CAAC,EAAE;QACfG,OAAOH,IAAI,CAAC,EAAE;IAChB;IAEA,OAAO;QACL,CAACM,OAAOC,QAAQ,CAAC;YACf,IAAIC,MAAM;YACV,IAAIC,UAAUR;YACd,OAAO;gBACLS;oBACE,IAAIF,MAAMN,OAAO;wBACf,MAAMS,QAAQF;wBACdA,WAAWN;wBACXK;wBACA,OAAO;4BAAEG;4BAAOC,MAAM;wBAAM;oBAC9B;oBACA,OAAO;wBAAED,OAAOE;wBAAWD,MAAM;oBAAK;gBACxC;gBACAE,QAAOH,KAAK;oBACVH,MAAMN;oBACN,OAAO;wBAAES;wBAAOC,MAAM;oBAAK;gBAC7B;gBACAG,OAAMC,KAAe;oBACnBR,MAAMN;oBACN,MAAMc;gBACR;YACF;QACF;IACF;AACF,EAAE;AAmBF,OAAO,MAAMC,kBAAkB,OAAOC,SAAiBC;IACrD,IAAIA,QAAQC,SAAS;QACnB,OAAO;IACT;IACA,MAAM,EAAEC,OAAO,EAAEC,OAAO,EAAE,GAAGC,QAAQC,aAAa;IAClD,MAAMC,UAAUC,WAAWJ,SAASJ,SAAS;IAC7C,MAAMS,UAAU;QACdC,aAAaH;QACbH,QAAQ;IACV;IACAH,QAAQU,iBAAiB,SAASF;IAElC,OAAON,QAAQS,OAAO,CAAC,IAAMX,QAAQY,oBAAoB,SAASJ;AACpE,EAAE;AAsBF,OAAO,MAAMK,kBAAkB,CAAoBC;IACjD,OAAO;QACL,CAAC3B,OAAO4B,aAAa,CAAC;YACpB,MAAM3B,WAAW0B,QAAQ,CAAC3B,OAAOC,QAAQ,CAAC;YAC1C,OAAO;gBACL,MAAMG,MAAK,GAAGV,IAAkB;oBAC9B,OAAOO,SAASG,IAAI,IAAIV;gBAC1B;gBACA,MAAMc,QAAOqB,UAAU;oBACrB,MAAMxB,QAAQ,MAAMwB;oBACpB,OAAO5B,SAASO,MAAM,GAAGH,UAAW;wBAAEA;wBAAOC,MAAM;oBAAK;gBAC1D;gBACA,MAAMG,OAAMC,KAAK;oBACf,IAAIT,SAASQ,KAAK,EAAE;wBAClB,OAAOR,SAASQ,KAAK,CAACC;oBACxB;oBACA,MAAMA;gBACR;YACF;QACF;IACF;AACF,EAAE;AA6BF,OAAO,gBAAgBoB,KACrBH,QAA0B,EAC1BI,gBAAsD,EACtDlB,MAAoB;IAEpB,MAAMmB,YAAYD;IAClB,WAAW,MAAM1B,SAASsB,SAAU;QAClC,IAAId,QAAQC,SAAS;QACrB,WAAW,MAAMmB,YAAYD,UAAU3B,OAAQ;YAC7C,MAAM4B;YACN,IAAIpB,QAAQC,SAAS;QACvB;QACA,IAAID,QAAQC,SAAS;IACvB;AACF"}
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import { Sequence } from './sequence.js';\nimport { AnyIterator, AnyIterable, MaybePromise } from './types.js';\n\n/**\n * @internal\n */\nexport function isThenable(value: unknown): value is PromiseLike<unknown> {\n return value !== null && typeof value === 'object' && typeof (value as PromiseLike<unknown>).then === 'function';\n}\n\n/**\n * @internal\n * A no-operation function. Useful as a default callback or placeholder.\n */\nexport const noop = () => {};\n\n/**\n * @internal\n * Returns the minimum value from an iterable, or a fallback if empty.\n */\nexport function min(values: Iterable<number>, fallback: number): number {\n let result = Infinity;\n for (const value of values) {\n if (value < result) result = value;\n }\n return result === Infinity ? fallback : result;\n}\n\n/**\n * @internal\n * Indicates which iterator method triggered a mapping operation.\n */\nexport enum MapIteratorType {\n /** The next() method was called */\n NEXT,\n /** The return() method was called */\n RETURN,\n /** The throw() method was called */\n THROW,\n}\n\n/**\n * @internal\n * A mapping function for transforming iterator results.\n * @template T - The input value type\n * @template U - The output value type\n * @template TReturn - The iterator return type\n */\nexport interface MapNext<T, U, TReturn> {\n (result: MaybePromise<IteratorResult<T, TReturn>>, type: MapIteratorType): MaybePromise<IteratorResult<U, TReturn>>;\n}\n\n/**\n * @internal\n * Wraps an iterator with a mapping function applied to each result.\n * @template U - The output value type\n * @template T - The input value type\n * @template TReturn - The iterator return type\n * @template TNext - The type passed to next()\n * @param iterator - The source iterator to wrap\n * @param map - The mapping function to apply to each result\n * @returns An async iterator with mapped results\n */\nexport const mapIterator = <U, T, TReturn, TNext>(iterator: AnyIterator<T, TReturn, TNext>, map: MapNext<T, U, TReturn>): AsyncIterator<U, TReturn, TNext> => {\n const subIterator: AsyncIterator<U, TReturn, TNext> = {\n next: async (...args: [] | [TNext]) => {\n const result = await iterator.next(...args);\n return map(result, MapIteratorType.NEXT);\n },\n };\n if (iterator.return) {\n subIterator.return = async (...args: [] | [TReturn]) => {\n const result = await iterator.return!(...args);\n return map(result, MapIteratorType.RETURN);\n };\n } else {\n subIterator.return = async (value: TReturn) => {\n return map({ done: true, value }, MapIteratorType.RETURN);\n };\n }\n if (iterator.throw) {\n subIterator.throw = async (...args: [] | [unknown]) => {\n const result = await iterator.throw!(...args);\n return map(result, MapIteratorType.THROW);\n };\n }\n\n return subIterator;\n};\n\n/**\n * Wraps an async iterable with abort signal support.\n * Each iteration creates a fresh iterator with scoped abort handling.\n * Listener is added at iteration start and removed on completion/abort/return.\n *\n * @template T - The yielded value type\n * @template TReturn - The return value type\n * @template TNext - The type passed to next()\n * @param iterable - The source async iterable to wrap\n * @param signal - AbortSignal to cancel iteration\n * @returns An async iterable with abort support\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n * const source = async function*() { yield 1; yield 2; yield 3; };\n *\n * for await (const value of abortableIterable(source(), controller.signal)) {\n * console.log(value);\n * if (value === 2) controller.abort();\n * }\n * ```\n */\nexport function abortableIterable<T, TReturn, TNext>(iterable: AsyncIterable<T, TReturn, TNext>, signal: AbortSignal): AsyncIterable<T, TReturn, TNext> {\n return {\n [Symbol.asyncIterator](): AsyncIterator<T, TReturn, TNext> {\n const iterator = iterable[Symbol.asyncIterator]();\n const { promise, resolve } = Promise.withResolvers<void>();\n const onAbort = () => resolve();\n let closed = false;\n\n const finish = (value?: TReturn): Promise<IteratorResult<T, TReturn>> => {\n if (closed) {\n return Promise.resolve({ done: true, value: value as TReturn });\n }\n closed = true;\n signal.removeEventListener('abort', onAbort);\n return iterator.return?.(value) ?? Promise.resolve({ done: true, value: value as TReturn });\n };\n\n if (signal.aborted) {\n onAbort();\n } else {\n signal.addEventListener('abort', onAbort);\n }\n\n const race = [promise, undefined] as unknown as [Promise<void>, Promise<IteratorResult<T, TReturn>>];\n\n return {\n async next(...args: [] | [TNext]): Promise<IteratorResult<T, TReturn>> {\n race[1] = iterator.next(...args);\n const result = await Promise.race(race);\n if (result === undefined) {\n void finish();\n return { done: true, value: undefined as TReturn };\n }\n if (result.done) {\n closed = true;\n signal.removeEventListener('abort', onAbort);\n }\n return result;\n },\n async return(value?: TReturn): Promise<IteratorResult<T, TReturn>> {\n return finish(value);\n },\n };\n },\n };\n}\n\n/**\n * Interface for creating iterable number sequences with various parameter combinations.\n * Supports infinite sequences, counted sequences, and sequences with custom start and step values.\n */\nexport interface Iterate {\n (): Iterable<number, void, unknown>;\n (count: number): Iterable<number, void, unknown>;\n (start: number, count: number): Iterable<number, void, unknown>;\n (start: number, count: number, step: number): Iterable<number, void, unknown>;\n}\n\n/**\n * Creates an iterable sequence of numbers with flexible parameters.\n * Can generate infinite sequences, finite sequences, or sequences with custom start and step values.\n *\n * @param args Variable arguments to configure the sequence:\n * - No args: Infinite sequence starting at 0 with step 1\n * - 1 arg (count): Sequence from 0 to count-1\n * - 2 args (start, count): Sequence starting at 'start' for 'count' iterations\n * - 3 args (start, count, step): Custom start, count, and step value\n * @returns An iterable that generates numbers according to the parameters\n *\n * @example\n * ```typescript\n * // Infinite sequence: 0, 1, 2, 3, ...\n * for (const n of iterate()) { }\n *\n * // Count only: 0, 1, 2, 3, 4\n * for (const n of iterate(5)) { }\n *\n * // Start and count: 10, 11, 12, 13, 14\n * for (const n of iterate(10, 5)) { }\n *\n * // Start, count, and step: 0, 2, 4, 6, 8\n * for (const n of iterate(0, 5, 2)) { }\n * ```\n */\nexport const iterate: Iterate = (startOrCount?: number, countWhenTwoArgs?: number, step: number = 1): Iterable<number, void, unknown> => {\n const hasStartArg = countWhenTwoArgs !== undefined;\n const start = hasStartArg ? startOrCount! : 0;\n const count = startOrCount === undefined ? Infinity : hasStartArg ? countWhenTwoArgs : startOrCount;\n\n return {\n [Symbol.iterator]() {\n let idx = 0;\n let current = start;\n return {\n next() {\n if (idx < count) {\n const value = current;\n current += step;\n idx++;\n return { value, done: false };\n }\n return { value: undefined, done: true };\n },\n return(value) {\n idx = count;\n return { value, done: true };\n },\n throw(error?: unknown) {\n idx = count;\n throw error;\n },\n } satisfies Iterator<number, void, unknown>;\n },\n };\n};\n\n/**\n * @internal\n * Creates a promise that resolves after a specified timeout. If an `AbortSignal` is provided and triggered,\n * the timeout is cleared, and the promise resolves to `false`.\n *\n * @param {number} timeout - The time in milliseconds to wait before resolving the promise.\n * @param {AbortSignal} [signal] - An optional `AbortSignal` that can abort the timeout.\n * @returns {Promise<boolean>} A promise that resolves to `true` if the timeout completed, or `false` if it was aborted.\n *\n * @example\n * ```typescript\n * const controller = new AbortController();\n * setTimeout(() => controller.abort(), 500);\n * const result = await setTimeoutAsync(1000, controller.signal);\n * console.log(result); // false\n * ```\n */\nexport const setTimeoutAsync = async (timeout: number, signal?: AbortSignal): Promise<boolean> => {\n if (signal?.aborted) {\n return false;\n }\n const { promise, resolve } = Promise.withResolvers<boolean>();\n const timerId = setTimeout(resolve, timeout, true);\n const onAbort = () => {\n clearTimeout(timerId);\n resolve(false);\n };\n signal?.addEventListener('abort', onAbort);\n\n return promise.finally(() => signal?.removeEventListener('abort', onAbort));\n};\n\n/**\n * Converts a synchronous iterable to an asynchronous iterable.\n * Wraps the sync iterator methods to return promises, enabling uniform async handling.\n *\n * @template T The type of values yielded by the iterator\n * @template TReturn The return type of the iterator\n * @template TNext The type of value that can be passed to next()\n * @param iterable A synchronous iterable to convert\n * @returns An async iterable that yields the same values as the input\n *\n * @example\n * ```typescript\n * const syncArray = [1, 2, 3, 4, 5];\n * const asyncIterable = toAsyncIterable(syncArray);\n *\n * for await (const value of asyncIterable) {\n * console.log(value); // 1, 2, 3, 4, 5\n * }\n * ```\n */\nexport const toAsyncIterable = <T, TReturn, TNext>(iterable: Iterable<T, TReturn, TNext>): AsyncIterable<T, TReturn, TNext> => {\n return {\n [Symbol.asyncIterator]() {\n const iterator = iterable[Symbol.iterator]();\n return {\n async next(...args: [TNext] | []) {\n return iterator.next(...args);\n },\n async return(maybeValue) {\n const value = await maybeValue;\n return iterator.return?.(value) ?? ({ value, done: true } as IteratorResult<T, TReturn>);\n },\n async throw(error) {\n if (iterator.throw) {\n return iterator.throw(error);\n }\n throw error;\n },\n } satisfies AsyncIterator<T, TReturn, TNext>;\n },\n };\n};\n\n/**\n * @internal\n * Pipes values from an async iterable through a generator transformation.\n * Applies a generator function to each value, yielding all resulting values.\n * Supports cancellation via AbortSignal for early termination.\n *\n * @template T The input value type\n * @template U The output value type\n * @param iterable The source async iterable\n * @param generatorFactory A factory that returns a generator function for transforming values\n * @param signal Optional AbortSignal to cancel the operation\n * @returns An async generator yielding transformed values\n *\n * @example\n * ```typescript\n * async function* source() {\n * yield 1; yield 2; yield 3;\n * }\n *\n * const doubled = pipe(source(), () => async function*(n) {\n * yield n * 2;\n * });\n *\n * for await (const value of doubled) {\n * console.log(value); // 2, 4, 6\n * }\n * ```\n */\nconst isAsyncIterable = <T, TReturn, TNext>(value: AnyIterable<T, TReturn, TNext>): value is AsyncIterable<T, TReturn, TNext> => {\n return typeof (value as AsyncIterable<T, TReturn, TNext>)[Symbol.asyncIterator] === 'function';\n};\n\n/**\n * @internal\n */\nexport async function* pipe<T, U>(\n iterable: AsyncIterable<T>,\n generatorFactory: () => (value: T) => AnyIterable<U, void, unknown>,\n signal?: AbortSignal,\n): AsyncGenerator<Awaited<U>, void, unknown> {\n const source = signal ? abortableIterable(iterable, signal) : iterable;\n const generator = generatorFactory();\n\n for await (const value of source) {\n const produced = generator(value);\n const subIterable = isAsyncIterable(produced) ? produced : toAsyncIterable(produced);\n const abortableSub = signal ? abortableIterable(subIterable, signal) : subIterable;\n\n for await (const subValue of abortableSub) {\n yield subValue;\n }\n }\n}\n\n/**\n * @internal\n * Merges multiple async iterables into a single stream.\n * Values are yielded as they become available from any source.\n * Completes when all sources complete; aborts all on error.\n * @template T - The value type yielded by all iterables\n * @param iterables - The async iterables to merge\n * @returns A merged async iterable\n */\nexport const mergeIterables = <T>(...iterables: AsyncIterable<T, void, unknown>[]): AsyncIterable<T, void, unknown> => {\n return {\n [Symbol.asyncIterator]() {\n if (iterables.length === 0) {\n return {\n next: async () => ({ value: undefined, done: true }),\n };\n }\n\n const exit = Symbol('mergeIterables.exit');\n const ctrl = new AbortController();\n const sequence = new Sequence<T>(ctrl.signal);\n let remaining = iterables.length;\n\n const pump = async (iterable: AsyncIterable<T, void, unknown>) => {\n try {\n for await (const value of abortableIterable(iterable, ctrl.signal)) {\n if (!sequence.emit(value)) {\n break;\n }\n }\n } catch (error) {\n ctrl.abort(error);\n } finally {\n remaining -= 1;\n if (remaining === 0 && !ctrl.signal.aborted) {\n ctrl.abort(exit);\n }\n }\n };\n\n for (const iterable of iterables) {\n void pump(iterable);\n }\n\n return {\n next: async () => {\n try {\n const value = await sequence.receive();\n return { value, done: false };\n } catch {\n if (ctrl.signal.aborted && ctrl.signal.reason === exit) {\n return { value: undefined, done: true };\n }\n throw ctrl.signal.reason;\n }\n },\n return: async () => {\n ctrl.abort(exit);\n return { value: undefined, done: true };\n },\n throw: async (error?: unknown) => {\n ctrl.abort(error);\n return { value: undefined, done: true };\n },\n };\n },\n };\n};\n"],"names":["Sequence","isThenable","value","then","noop","min","values","fallback","result","Infinity","MapIteratorType","mapIterator","iterator","map","subIterator","next","args","return","done","throw","abortableIterable","iterable","signal","Symbol","asyncIterator","promise","resolve","Promise","withResolvers","onAbort","closed","finish","removeEventListener","aborted","addEventListener","race","undefined","iterate","startOrCount","countWhenTwoArgs","step","hasStartArg","start","count","idx","current","error","setTimeoutAsync","timeout","timerId","setTimeout","clearTimeout","finally","toAsyncIterable","maybeValue","isAsyncIterable","pipe","generatorFactory","source","generator","produced","subIterable","abortableSub","subValue","mergeIterables","iterables","length","exit","ctrl","AbortController","sequence","remaining","pump","emit","abort","receive","reason"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "evnty",
3
3
  "description": "Async-first, reactive event handling library for complex event flows in browser and Node.js",
4
- "version": "5.0.0",
4
+ "version": "5.1.0",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
7
7
  "main": "build/index.cjs",
@@ -48,43 +48,45 @@
48
48
  "url": "https://github.com/3axap4eHko/evnty/issues"
49
49
  },
50
50
  "homepage": "https://github.com/3axap4eHko/evnty#readme",
51
- "dependencies": {
52
- "fastds": "0.0.5"
53
- },
54
51
  "devDependencies": {
55
- "@eslint/js": "^9.34.0",
56
- "@types/node": "^24.3.0",
57
- "@typescript-eslint/eslint-plugin": "^8.40.0",
58
- "@typescript-eslint/parser": "^8.40.0",
59
- "@typescript-eslint/typescript-estree": "^8.40.0",
60
- "@vitest/coverage-v8": "^3.2.4",
52
+ "@eslint/js": "^10.0.1",
53
+ "@fast-check/vitest": "^0.2.4",
54
+ "@stryker-mutator/core": "^9.5.1",
55
+ "@stryker-mutator/typescript-checker": "^9.5.1",
56
+ "@stryker-mutator/vitest-runner": "^9.5.1",
57
+ "@types/node": "^25.3.0",
58
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
59
+ "@typescript-eslint/parser": "^8.56.1",
60
+ "@typescript-eslint/typescript-estree": "^8.56.1",
61
+ "@vitest/coverage-v8": "^4.0.18",
61
62
  "@vuepress/bundler-vite": "2.0.0-rc.23",
62
63
  "@vuepress/theme-default": "2.0.0-rc.105",
63
- "eslint": "^9.34.0",
64
+ "eslint": "^10.0.2",
64
65
  "eslint-config-prettier": "^10.1.8",
65
- "eslint-plugin-prettier": "^5.5.4",
66
+ "eslint-plugin-prettier": "^5.5.5",
67
+ "evnty": "^5.0.0",
66
68
  "husky": "^9.1.7",
67
- "inop": "^0.7.8",
68
- "overtake": "1.0.2",
69
- "prettier": "^3.6.2",
69
+ "inop": "^0.9.0",
70
+ "overtake": "1.3.2",
71
+ "prettier": "^3.8.1",
70
72
  "recast": "^0.23.11",
71
- "sass-embedded": "^1.90.0",
72
- "ts-node": "^10.9.2",
73
- "typescript": "^5.9.2",
74
- "typescript-eslint": "^8.40.0",
75
- "vitest": "^3.2.4",
76
- "vue": "^3.5.19",
73
+ "sass-embedded": "^1.97.3",
74
+ "typescript": "^5.9.3",
75
+ "typescript-eslint": "^8.56.1",
76
+ "vitest": "^4.0.18",
77
+ "vue": "^3.5.29",
77
78
  "vuepress": "2.0.0-rc.23"
78
79
  },
79
80
  "scripts": {
80
- "build": "rm -rf build && inop src build -i __tests__ -i *.tmp.ts && tsc --declaration --emitDeclarationOnly",
81
+ "build": "rm -rf build && inop src build -i __tests__ -i __bench__ -i *.tmp.ts && tsc -p tsconfig.build.json --declaration --emitDeclarationOnly",
81
82
  "test": "vitest run",
82
- "test:build": "node src/__tests__/index.cjs && node src/__tests__/index.mjs",
83
83
  "lint": "eslint src",
84
+ "check": "stryker run",
84
85
  "docs:build": "vuepress build docs",
85
86
  "docs:clean-dev": "vuepress dev docs --clean-cache",
86
87
  "docs:dev": "vuepress dev docs",
87
- "docs:gen": "rm -f docs/*.tmp.md && for file in src/*.ts; do node --loader ts-node/esm ./scripts/docgen.ts $file; done",
88
- "docs:update-package": "pnpm dlx vp-update"
88
+ "docs:gen": "node ./scripts/docgen.ts src/*.ts",
89
+ "docs:update-package": "pnpm dlx vp-update",
90
+ "bench": "overtake src/__bench__/event.ts"
89
91
  }
90
92
  }
@@ -1,4 +1,4 @@
1
- const { createEvent, merge, once } = require('evnty');
1
+ import { createEvent, merge } from 'evnty';
2
2
 
3
3
  // Creates a click event
4
4
  const clickEvent = createEvent();
@@ -11,35 +11,30 @@ const handleKeyPress = ({ key }) => console.log('Key pressed', key);
11
11
  const unsubscribeKeyPress = keyPressEvent.on(handleKeyPress);
12
12
 
13
13
  // Merges click and key press events into input event
14
- const handleInput = (input) => console.log('Input', input);;
14
+ const handleInput = (input) => console.log('Input', input);
15
15
  const inputEvent = merge(clickEvent, keyPressEvent);
16
16
  inputEvent.on(handleInput);
17
17
 
18
- // Filters a click event to only include left-click events.
19
- const handleLeftClick = () => console.log('Left button is clicked');
20
- const leftClickEvent = clickEvent.filter(({ button }) => button === 'left');
21
- leftClickEvent.on(handleLeftClick);
18
+ // One-time listener for left clicks only
19
+ clickEvent.once(({ button }) => {
20
+ if (button === 'left') {
21
+ console.log('First left click detected!');
22
+ }
23
+ });
22
24
 
23
- // Will press Enter after one second
24
- setTimeout(keyPressEvent, 1000, { key: 'Enter' });
25
- // Waits once the first Enter key press event occurs
26
- await once(keyPressEvent.first(({ key }) => key === 'Enter'));
25
+ // Emit some events
26
+ keyPressEvent.emit({ key: 'W' });
27
+ keyPressEvent.emit({ key: 'A' });
28
+ keyPressEvent.emit({ key: 'S' });
29
+ keyPressEvent.emit({ key: 'D' });
27
30
 
28
- keyPressEvent({ key: 'W' });
29
- keyPressEvent({ key: 'A' });
30
- keyPressEvent({ key: 'S' });
31
- keyPressEvent({ key: 'D' });
32
-
33
- clickEvent({ button: 'right' });
34
- clickEvent({ button: 'left' });
35
- clickEvent({ button: 'middle' });
31
+ clickEvent.emit({ button: 'right' });
32
+ clickEvent.emit({ button: 'left' });
33
+ clickEvent.emit({ button: 'middle' });
36
34
 
37
35
  // Unsubscribe click listener
38
36
  unsubscribeClick();
39
- // It does not log anything because of click listener is unsubscribed
40
- leftClickEvent.off(handleLeftClick);
41
37
 
42
- // Unsubscribe key press listener once first Esc key press occur
43
- unsubscribeKeyPress.after(() => once(keyPressEvent.first(({ key }) => key === 'Esc')));
44
- // Press Esc to unsubscribe key press listener
45
- keyPressEvent({ key: 'Esc' });
38
+ // Unsubscribe with a follow-up action
39
+ unsubscribeKeyPress();
40
+ console.log('Key press listener has been removed');
package/src/index.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export * from './types.js';
2
- export * from './callable.js';
3
2
  export * from './utils.js';
4
3
  export * from './iterator.js';
5
4
  export * from './signal.js';
6
5
  export * from './sequence.js';
6
+ export * from './broadcast.js';
7
7
  export * from './event.js';
8
+ export * from './listener-registry.js';
9
+ export * from './dispatch-result.js';
@@ -1,72 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get AsyncCallable () {
13
- return AsyncCallable;
14
- },
15
- get Callable () {
16
- return Callable;
17
- },
18
- get CallableAsyncIterator () {
19
- return CallableAsyncIterator;
20
- }
21
- });
22
- class Callable {
23
- static{
24
- Object.setPrototypeOf(Callable.prototype, Function.prototype);
25
- }
26
- constructor(func){
27
- return Object.setPrototypeOf(func, new.target.prototype);
28
- }
29
- }
30
- class AsyncCallable extends Callable {
31
- constructor(func){
32
- super(func);
33
- }
34
- catch(onrejected) {
35
- return this.next().catch(onrejected);
36
- }
37
- finally(onfinally) {
38
- return this.next().finally(onfinally);
39
- }
40
- then(onfulfilled, onrejected) {
41
- return this.next().then(onfulfilled, onrejected);
42
- }
43
- }
44
- class CallableAsyncIterator extends AsyncCallable {
45
- [Symbol.asyncIterator]() {
46
- return {
47
- next: async ()=>{
48
- try {
49
- const value = await this.next();
50
- return {
51
- value,
52
- done: false
53
- };
54
- } catch {
55
- return {
56
- value: undefined,
57
- done: true
58
- };
59
- }
60
- },
61
- return: ()=>{
62
- this[Symbol.dispose]();
63
- return Promise.resolve({
64
- value: undefined,
65
- done: true
66
- });
67
- }
68
- };
69
- }
70
- }
71
-
72
- //# sourceMappingURL=callable.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/callable.ts"],"sourcesContent":["import { Fn, Promiseable } from './types.js';\n/**\n * @internal\n */\nexport interface Callable<T extends unknown[], R> {\n (...args: T): R;\n}\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of Callable is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\n\nexport abstract class Callable<T, R> {\n static {\n Object.setPrototypeOf(Callable.prototype, Function.prototype);\n }\n\n constructor(func: Fn<T, R>) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\n/**\n * @internal\n */\nexport abstract class AsyncCallable<T, R> extends Callable<[T], R> implements Promiseable<T>, Promise<T> {\n constructor(func: Fn<[T], R>) {\n super(func);\n }\n\n abstract [Symbol.toStringTag]: string;\n abstract next(): Promise<T>;\n\n catch<OK = never>(onrejected?: ((reason: any) => OK | PromiseLike<OK>) | null): Promise<T | OK> {\n return this.next().catch(onrejected);\n }\n\n finally(onfinally?: (() => void) | null): Promise<T> {\n return this.next().finally(onfinally);\n }\n\n then<OK = T, ERR = never>(\n onfulfilled?: ((value: T) => OK | PromiseLike<OK>) | null,\n onrejected?: ((reason: unknown) => ERR | PromiseLike<ERR>) | null,\n ): Promise<OK | ERR> {\n return this.next().then(onfulfilled, onrejected);\n }\n}\n\n/**\n * @internal\n */\nexport abstract class CallableAsyncIterator<T, R> extends AsyncCallable<T, R> implements Promiseable<T>, Promise<T>, AsyncIterable<T>, Disposable {\n [Symbol.asyncIterator](): AsyncIterator<T, void, void> {\n return {\n next: async () => {\n try {\n const value = await this.next();\n return { value, done: false };\n } catch {\n return { value: undefined, done: true };\n }\n },\n return: () => {\n this[Symbol.dispose]();\n return Promise.resolve({ value: undefined, done: true });\n },\n };\n }\n abstract [Symbol.dispose](): void;\n}\n"],"names":["AsyncCallable","Callable","CallableAsyncIterator","Object","setPrototypeOf","prototype","Function","func","catch","onrejected","next","finally","onfinally","then","onfulfilled","Symbol","asyncIterator","value","done","undefined","return","dispose","Promise","resolve"],"mappings":";;;;;;;;;;;QA6BsBA;eAAAA;;QAdAC;eAAAA;;QAyCAC;eAAAA;;;AAzCf,MAAeD;IACpB,MAAO;QACLE,OAAOC,cAAc,CAACH,SAASI,SAAS,EAAEC,SAASD,SAAS;IAC9D,CAAC;IAED,YAAYE,IAAc,CAAE;QAE1B,OAAOJ,OAAOC,cAAc,CAACG,MAAM,WAAWF,SAAS;IACzD;AACF;AAKO,MAAeL,sBAA4BC;IAChD,YAAYM,IAAgB,CAAE;QAC5B,KAAK,CAACA;IACR;IAKAC,MAAkBC,UAA2D,EAAmB;QAC9F,OAAO,IAAI,CAACC,IAAI,GAAGF,KAAK,CAACC;IAC3B;IAEAE,QAAQC,SAA+B,EAAc;QACnD,OAAO,IAAI,CAACF,IAAI,GAAGC,OAAO,CAACC;IAC7B;IAEAC,KACEC,WAAyD,EACzDL,UAAiE,EAC9C;QACnB,OAAO,IAAI,CAACC,IAAI,GAAGG,IAAI,CAACC,aAAaL;IACvC;AACF;AAKO,MAAeP,8BAAoCF;IACxD,CAACe,OAAOC,aAAa,CAAC,GAAiC;QACrD,OAAO;YACLN,MAAM;gBACJ,IAAI;oBACF,MAAMO,QAAQ,MAAM,IAAI,CAACP,IAAI;oBAC7B,OAAO;wBAAEO;wBAAOC,MAAM;oBAAM;gBAC9B,EAAE,OAAM;oBACN,OAAO;wBAAED,OAAOE;wBAAWD,MAAM;oBAAK;gBACxC;YACF;YACAE,QAAQ;gBACN,IAAI,CAACL,OAAOM,OAAO,CAAC;gBACpB,OAAOC,QAAQC,OAAO,CAAC;oBAAEN,OAAOE;oBAAWD,MAAM;gBAAK;YACxD;QACF;IACF;AAEF"}
@@ -1,34 +0,0 @@
1
- import { Fn, Promiseable } from './types.js';
2
- /**
3
- * @internal
4
- */
5
- export interface Callable<T extends unknown[], R> {
6
- (...args: T): R;
7
- }
8
- /**
9
- * An abstract class that extends the built-in Function class. It allows instances of the class
10
- * to be called as functions. When an instance of Callable is called as a function, it will
11
- * call the function passed to its constructor with the same arguments.
12
- * @internal
13
- */
14
- export declare abstract class Callable<T, R> {
15
- constructor(func: Fn<T, R>);
16
- }
17
- /**
18
- * @internal
19
- */
20
- export declare abstract class AsyncCallable<T, R> extends Callable<[T], R> implements Promiseable<T>, Promise<T> {
21
- constructor(func: Fn<[T], R>);
22
- abstract [Symbol.toStringTag]: string;
23
- abstract next(): Promise<T>;
24
- catch<OK = never>(onrejected?: ((reason: any) => OK | PromiseLike<OK>) | null): Promise<T | OK>;
25
- finally(onfinally?: (() => void) | null): Promise<T>;
26
- then<OK = T, ERR = never>(onfulfilled?: ((value: T) => OK | PromiseLike<OK>) | null, onrejected?: ((reason: unknown) => ERR | PromiseLike<ERR>) | null): Promise<OK | ERR>;
27
- }
28
- /**
29
- * @internal
30
- */
31
- export declare abstract class CallableAsyncIterator<T, R> extends AsyncCallable<T, R> implements Promiseable<T>, Promise<T>, AsyncIterable<T>, Disposable {
32
- [Symbol.asyncIterator](): AsyncIterator<T, void, void>;
33
- abstract [Symbol.dispose](): void;
34
- }
package/build/callable.js DELETED
@@ -1,51 +0,0 @@
1
- export class Callable {
2
- static{
3
- Object.setPrototypeOf(Callable.prototype, Function.prototype);
4
- }
5
- constructor(func){
6
- return Object.setPrototypeOf(func, new.target.prototype);
7
- }
8
- }
9
- export class AsyncCallable extends Callable {
10
- constructor(func){
11
- super(func);
12
- }
13
- catch(onrejected) {
14
- return this.next().catch(onrejected);
15
- }
16
- finally(onfinally) {
17
- return this.next().finally(onfinally);
18
- }
19
- then(onfulfilled, onrejected) {
20
- return this.next().then(onfulfilled, onrejected);
21
- }
22
- }
23
- export class CallableAsyncIterator extends AsyncCallable {
24
- [Symbol.asyncIterator]() {
25
- return {
26
- next: async ()=>{
27
- try {
28
- const value = await this.next();
29
- return {
30
- value,
31
- done: false
32
- };
33
- } catch {
34
- return {
35
- value: undefined,
36
- done: true
37
- };
38
- }
39
- },
40
- return: ()=>{
41
- this[Symbol.dispose]();
42
- return Promise.resolve({
43
- value: undefined,
44
- done: true
45
- });
46
- }
47
- };
48
- }
49
- }
50
-
51
- //# sourceMappingURL=callable.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/callable.ts"],"sourcesContent":["import { Fn, Promiseable } from './types.js';\n/**\n * @internal\n */\nexport interface Callable<T extends unknown[], R> {\n (...args: T): R;\n}\n\n/**\n * An abstract class that extends the built-in Function class. It allows instances of the class\n * to be called as functions. When an instance of Callable is called as a function, it will\n * call the function passed to its constructor with the same arguments.\n * @internal\n */\n\nexport abstract class Callable<T, R> {\n static {\n Object.setPrototypeOf(Callable.prototype, Function.prototype);\n }\n\n constructor(func: Fn<T, R>) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return Object.setPrototypeOf(func, new.target.prototype);\n }\n}\n\n/**\n * @internal\n */\nexport abstract class AsyncCallable<T, R> extends Callable<[T], R> implements Promiseable<T>, Promise<T> {\n constructor(func: Fn<[T], R>) {\n super(func);\n }\n\n abstract [Symbol.toStringTag]: string;\n abstract next(): Promise<T>;\n\n catch<OK = never>(onrejected?: ((reason: any) => OK | PromiseLike<OK>) | null): Promise<T | OK> {\n return this.next().catch(onrejected);\n }\n\n finally(onfinally?: (() => void) | null): Promise<T> {\n return this.next().finally(onfinally);\n }\n\n then<OK = T, ERR = never>(\n onfulfilled?: ((value: T) => OK | PromiseLike<OK>) | null,\n onrejected?: ((reason: unknown) => ERR | PromiseLike<ERR>) | null,\n ): Promise<OK | ERR> {\n return this.next().then(onfulfilled, onrejected);\n }\n}\n\n/**\n * @internal\n */\nexport abstract class CallableAsyncIterator<T, R> extends AsyncCallable<T, R> implements Promiseable<T>, Promise<T>, AsyncIterable<T>, Disposable {\n [Symbol.asyncIterator](): AsyncIterator<T, void, void> {\n return {\n next: async () => {\n try {\n const value = await this.next();\n return { value, done: false };\n } catch {\n return { value: undefined, done: true };\n }\n },\n return: () => {\n this[Symbol.dispose]();\n return Promise.resolve({ value: undefined, done: true });\n },\n };\n }\n abstract [Symbol.dispose](): void;\n}\n"],"names":["Callable","Object","setPrototypeOf","prototype","Function","func","AsyncCallable","catch","onrejected","next","finally","onfinally","then","onfulfilled","CallableAsyncIterator","Symbol","asyncIterator","value","done","undefined","return","dispose","Promise","resolve"],"mappings":"AAeA,OAAO,MAAeA;IACpB,MAAO;QACLC,OAAOC,cAAc,CAACF,SAASG,SAAS,EAAEC,SAASD,SAAS;IAC9D,CAAC;IAED,YAAYE,IAAc,CAAE;QAE1B,OAAOJ,OAAOC,cAAc,CAACG,MAAM,WAAWF,SAAS;IACzD;AACF;AAKA,OAAO,MAAeG,sBAA4BN;IAChD,YAAYK,IAAgB,CAAE;QAC5B,KAAK,CAACA;IACR;IAKAE,MAAkBC,UAA2D,EAAmB;QAC9F,OAAO,IAAI,CAACC,IAAI,GAAGF,KAAK,CAACC;IAC3B;IAEAE,QAAQC,SAA+B,EAAc;QACnD,OAAO,IAAI,CAACF,IAAI,GAAGC,OAAO,CAACC;IAC7B;IAEAC,KACEC,WAAyD,EACzDL,UAAiE,EAC9C;QACnB,OAAO,IAAI,CAACC,IAAI,GAAGG,IAAI,CAACC,aAAaL;IACvC;AACF;AAKA,OAAO,MAAeM,8BAAoCR;IACxD,CAACS,OAAOC,aAAa,CAAC,GAAiC;QACrD,OAAO;YACLP,MAAM;gBACJ,IAAI;oBACF,MAAMQ,QAAQ,MAAM,IAAI,CAACR,IAAI;oBAC7B,OAAO;wBAAEQ;wBAAOC,MAAM;oBAAM;gBAC9B,EAAE,OAAM;oBACN,OAAO;wBAAED,OAAOE;wBAAWD,MAAM;oBAAK;gBACxC;YACF;YACAE,QAAQ;gBACN,IAAI,CAACL,OAAOM,OAAO,CAAC;gBACpB,OAAOC,QAAQC,OAAO,CAAC;oBAAEN,OAAOE;oBAAWD,MAAM;gBAAK;YACxD;QACF;IACF;AAEF"}