@johnhenry/iteration 0.0.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 (88) hide show
  1. package/MIT-LICENSE.txt +20 -0
  2. package/dist/abort.d.ts +26 -0
  3. package/dist/abort.d.ts.map +1 -0
  4. package/dist/abort.js +69 -0
  5. package/dist/abort.js.map +1 -0
  6. package/dist/assertions/eventualequal.d.ts +9 -0
  7. package/dist/assertions/eventualequal.d.ts.map +1 -0
  8. package/dist/assertions/eventualequal.js +30 -0
  9. package/dist/assertions/eventualequal.js.map +1 -0
  10. package/dist/async-channel.d.ts +101 -0
  11. package/dist/async-channel.d.ts.map +1 -0
  12. package/dist/async-channel.js +208 -0
  13. package/dist/async-channel.js.map +1 -0
  14. package/dist/channel-decorators.d.ts +23 -0
  15. package/dist/channel-decorators.d.ts.map +1 -0
  16. package/dist/channel-decorators.js +31 -0
  17. package/dist/channel-decorators.js.map +1 -0
  18. package/dist/concurrency.d.ts +43 -0
  19. package/dist/concurrency.d.ts.map +1 -0
  20. package/dist/concurrency.js +145 -0
  21. package/dist/concurrency.js.map +1 -0
  22. package/dist/consumers.d.ts +199 -0
  23. package/dist/consumers.d.ts.map +1 -0
  24. package/dist/consumers.js +349 -0
  25. package/dist/consumers.js.map +1 -0
  26. package/dist/count.d.ts +37 -0
  27. package/dist/count.d.ts.map +1 -0
  28. package/dist/count.js +70 -0
  29. package/dist/count.js.map +1 -0
  30. package/dist/empty-iterator.d.ts +15 -0
  31. package/dist/empty-iterator.d.ts.map +1 -0
  32. package/dist/empty-iterator.js +16 -0
  33. package/dist/empty-iterator.js.map +1 -0
  34. package/dist/eventualequal.d.ts +2 -0
  35. package/dist/eventualequal.d.ts.map +1 -0
  36. package/dist/eventualequal.js +54 -0
  37. package/dist/eventualequal.js.map +1 -0
  38. package/dist/exhaust.d.ts +7 -0
  39. package/dist/exhaust.d.ts.map +1 -0
  40. package/dist/exhaust.js +22 -0
  41. package/dist/exhaust.js.map +1 -0
  42. package/dist/index.d.ts +16 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +16 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/is-iterator.d.ts +5 -0
  47. package/dist/is-iterator.d.ts.map +1 -0
  48. package/dist/is-iterator.js +5 -0
  49. package/dist/is-iterator.js.map +1 -0
  50. package/dist/iterator-tools.d.ts +164 -0
  51. package/dist/iterator-tools.d.ts.map +1 -0
  52. package/dist/iterator-tools.js +231 -0
  53. package/dist/iterator-tools.js.map +1 -0
  54. package/dist/itertools.d.ts +237 -0
  55. package/dist/itertools.d.ts.map +1 -0
  56. package/dist/itertools.js +471 -0
  57. package/dist/itertools.js.map +1 -0
  58. package/dist/tee.d.ts +18 -0
  59. package/dist/tee.d.ts.map +1 -0
  60. package/dist/tee.js +118 -0
  61. package/dist/tee.js.map +1 -0
  62. package/dist/transduce.d.ts +79 -0
  63. package/dist/transduce.d.ts.map +1 -0
  64. package/dist/transduce.js +37 -0
  65. package/dist/transduce.js.map +1 -0
  66. package/dist/transducers.d.ts +123 -0
  67. package/dist/transducers.d.ts.map +1 -0
  68. package/dist/transducers.js +212 -0
  69. package/dist/transducers.js.map +1 -0
  70. package/package.json +122 -0
  71. package/readme.md +761 -0
  72. package/src/abort.ts +80 -0
  73. package/src/assertions/eventualequal.ts +36 -0
  74. package/src/async-channel.ts +228 -0
  75. package/src/channel-decorators.ts +49 -0
  76. package/src/concurrency.ts +168 -0
  77. package/src/consumers.ts +425 -0
  78. package/src/count.ts +72 -0
  79. package/src/empty-iterator.ts +17 -0
  80. package/src/eventualequal.ts +54 -0
  81. package/src/exhaust.ts +26 -0
  82. package/src/index.ts +17 -0
  83. package/src/is-iterator.ts +9 -0
  84. package/src/iterator-tools.ts +290 -0
  85. package/src/itertools.ts +518 -0
  86. package/src/tee.ts +136 -0
  87. package/src/transduce.ts +161 -0
  88. package/src/transducers.ts +256 -0
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2018-2022 John Henry
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * AbortSignal plumbing shared by the async consumers (consumers.ts),
3
+ * transduceAsync (transduce.ts), and the concurrency helpers
4
+ * (concurrency.ts).
5
+ */
6
+ /** Options bag accepted by cancellable async operations. */
7
+ export interface SignalOptions {
8
+ signal?: AbortSignal;
9
+ }
10
+ /** Throw the signal's abort reason if it has already aborted. */
11
+ export declare const throwIfAborted: (signal?: AbortSignal) => void;
12
+ /**
13
+ * Wrap an (a)sync iterable so that iteration rejects promptly with an
14
+ * AbortError when `signal` aborts -- even while awaiting a slow source --
15
+ * and `iterator.return()` is propagated to the source on abort, error, or
16
+ * early consumer exit. With no signal, delegates straight through.
17
+ *
18
+ * Note: on abort the source's `return()` is invoked but deliberately not
19
+ * awaited -- an async generator queues `return()` behind its in-flight
20
+ * `next()`, so awaiting it could postpone the rejection indefinitely on a
21
+ * hung source (the very case aborting is for).
22
+ * @kind function
23
+ * @name abortable
24
+ */
25
+ export declare const abortable: <T>(iterable: AsyncIterable<T> | Iterable<T>, signal?: AbortSignal) => AsyncGenerator<T>;
26
+ //# sourceMappingURL=abort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort.d.ts","sourceRoot":"","sources":["../src/abort.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAWD,iEAAiE;AACjE,eAAO,MAAM,cAAc,GAAI,SAAS,WAAW,KAAG,IAIrD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,GAAoB,CAAC,EACzC,UAAU,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,EACxC,SAAS,WAAW,KACnB,cAAc,CAAC,CAAC,CAoClB,CAAC"}
package/dist/abort.js ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * AbortSignal plumbing shared by the async consumers (consumers.ts),
3
+ * transduceAsync (transduce.ts), and the concurrency helpers
4
+ * (concurrency.ts).
5
+ */
6
+ /**
7
+ * The error an aborted operation rejects with: the signal's own `reason`
8
+ * when set (AbortController.abort() defaults it to an "AbortError"
9
+ * DOMException), otherwise a fresh "AbortError" DOMException.
10
+ * @ignore
11
+ */
12
+ const abortError = (signal) => signal.reason ?? new DOMException("This operation was aborted", "AbortError");
13
+ /** Throw the signal's abort reason if it has already aborted. */
14
+ export const throwIfAborted = (signal) => {
15
+ if (signal?.aborted) {
16
+ throw abortError(signal);
17
+ }
18
+ };
19
+ /**
20
+ * Wrap an (a)sync iterable so that iteration rejects promptly with an
21
+ * AbortError when `signal` aborts -- even while awaiting a slow source --
22
+ * and `iterator.return()` is propagated to the source on abort, error, or
23
+ * early consumer exit. With no signal, delegates straight through.
24
+ *
25
+ * Note: on abort the source's `return()` is invoked but deliberately not
26
+ * awaited -- an async generator queues `return()` behind its in-flight
27
+ * `next()`, so awaiting it could postpone the rejection indefinitely on a
28
+ * hung source (the very case aborting is for).
29
+ * @kind function
30
+ * @name abortable
31
+ */
32
+ export const abortable = async function* (iterable, signal) {
33
+ if (!signal) {
34
+ yield* iterable;
35
+ return;
36
+ }
37
+ throwIfAborted(signal);
38
+ const it = Symbol.asyncIterator in Object(iterable)
39
+ ? iterable[Symbol.asyncIterator]()
40
+ : iterable[Symbol.iterator]();
41
+ let onAbort = () => { };
42
+ const aborted = new Promise((_, reject) => {
43
+ onAbort = () => reject(abortError(signal));
44
+ signal.addEventListener("abort", onAbort, { once: true });
45
+ });
46
+ // Pre-handle so an abort that never races (e.g. after completion, before
47
+ // listener removal) can't surface as an unhandled rejection.
48
+ aborted.catch(() => { });
49
+ let done = false;
50
+ try {
51
+ while (true) {
52
+ const result = await Promise.race([Promise.resolve(it.next()), aborted]);
53
+ if (result.done) {
54
+ done = true;
55
+ return;
56
+ }
57
+ yield result.value;
58
+ }
59
+ }
60
+ finally {
61
+ signal.removeEventListener("abort", onAbort);
62
+ if (!done && it.return) {
63
+ // Close the source on abort, error, or early consumer exit --
64
+ // fire-and-forget; see note above.
65
+ Promise.resolve(it.return()).catch(() => { });
66
+ }
67
+ }
68
+ };
69
+ //# sourceMappingURL=abort.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abort.js","sourceRoot":"","sources":["../src/abort.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CAAC,MAAmB,EAAW,EAAE,CAClD,MAAM,CAAC,MAAM,IAAI,IAAI,YAAY,CAAC,4BAA4B,EAAE,YAAY,CAAC,CAAC;AAEhF,iEAAiE;AACjE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAoB,EAAQ,EAAE;IAC3D,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,SAAS,CAAC,EACtC,QAAwC,EACxC,MAAoB;IAEpB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,KAAK,CAAC,CAAC,QAAQ,CAAC;QAChB,OAAO;IACT,CAAC;IACD,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,EAAE,GACN,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,QAAQ,CAAC;QACtC,CAAC,CAAE,QAA6B,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE;QACxD,CAAC,CAAE,QAAwB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;IACnD,IAAI,OAAO,GAAe,GAAG,EAAE,GAAE,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QAC/C,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IACH,yEAAyE;IACzE,6DAA6D;IAC7D,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACxB,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YACzE,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBAChB,IAAI,GAAG,IAAI,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,MAAM,MAAM,CAAC,KAAK,CAAC;QACrB,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;YACvB,8DAA8D;YAC9D,mCAAmC;YACnC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare class TestError extends Error {
2
+ val: Record<string, unknown>;
3
+ constructor(message: string, val?: Record<string, unknown>);
4
+ [Symbol.iterator](): IterableIterator<[string, unknown]>;
5
+ }
6
+ export declare const DefaultMessage = "should eventually be deep equal";
7
+ declare const _default: (actual: unknown, expected: unknown, message?: string, operator?: string) => Promise<string | TestError>;
8
+ export default _default;
9
+ //# sourceMappingURL=eventualequal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventualequal.d.ts","sourceRoot":"","sources":["../../src/assertions/eventualequal.ts"],"names":[],"mappings":"AASA,qBAAa,SAAU,SAAQ,KAAK;IAClC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBACjB,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;IAI9D,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAGzD;AAED,eAAO,MAAM,cAAc,oCAAoC,CAAC;yBAE9D,QAAQ,OAAO,EACf,UAAU,OAAO,EACjB,UAAS,MAAuB,EAChC,iBAA0B,KACzB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;AAL9B,wBAcE"}
@@ -0,0 +1,30 @@
1
+ // Historically this module was a pop-quiz assertion and imported
2
+ // pop-quiz/testerror. pop-quiz is no longer a dependency (the test suite
3
+ // moved to node:test), so a structurally-compatible TestError is inlined
4
+ // here to keep the "@johnhenry/iteration/pop-quiz/asserteventualequal" subpath
5
+ // export working for existing consumers: it extends Error, exposes the
6
+ // details on `.val`, and is iterable over the [key, value] entries --
7
+ // exactly the shape pop-quiz@1's TestError had.
8
+ import { eventualequal } from "../eventualequal.js";
9
+ export class TestError extends Error {
10
+ val;
11
+ constructor(message, val = {}) {
12
+ super(message);
13
+ this.val = val;
14
+ }
15
+ [Symbol.iterator]() {
16
+ return Object.entries(this.val).values();
17
+ }
18
+ }
19
+ export const DefaultMessage = "should eventually be deep equal";
20
+ export default async (actual, expected, message = DefaultMessage, operator = "eventualequal") => {
21
+ if (await eventualequal(actual, expected)) {
22
+ return message;
23
+ }
24
+ return new TestError(message, {
25
+ actual: actual,
26
+ expected: expected,
27
+ operator,
28
+ });
29
+ };
30
+ //# sourceMappingURL=eventualequal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventualequal.js","sourceRoot":"","sources":["../../src/assertions/eventualequal.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,yEAAyE;AACzE,yEAAyE;AACzE,+EAA+E;AAC/E,uEAAuE;AACvE,sEAAsE;AACtE,gDAAgD;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,GAAG,CAA0B;IAC7B,YAAY,OAAe,EAAE,MAA+B,EAAE;QAC5D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IACD,CAAC,MAAM,CAAC,QAAQ,CAAC;QACf,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,iCAAiC,CAAC;AAChE,eAAe,KAAK,EAClB,MAAe,EACf,QAAiB,EACjB,UAAkB,cAAc,EAChC,QAAQ,GAAG,eAAe,EACG,EAAE;IAC/B,IAAI,MAAM,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC1C,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,IAAI,SAAS,CAAC,OAAO,EAAE;QAC5B,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,QAAQ;QAClB,QAAQ;KACT,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Asynchronous Channel
3
+ * @kind namespace
4
+ * @name AsyncChannel
5
+ */
6
+ /**
7
+ * Constant signaling channel's end
8
+ * @kind constant
9
+ * @name CHANNEL_END
10
+ */
11
+ export declare const CHANNEL_END: unique symbol;
12
+ export interface AsyncChannelOptions<T> {
13
+ cache?: Array<T | typeof CHANNEL_END | Error>;
14
+ limit?: number;
15
+ transform?: (item: T) => T | Promise<T>;
16
+ debug?: (...args: unknown[]) => unknown;
17
+ }
18
+ /**
19
+ * Asynchronous Channel class
20
+ * @kind class
21
+ * @name AsyncChannel
22
+ */
23
+ export declare class AsyncChannel<T = unknown> {
24
+ limit: number;
25
+ cache: Array<T | typeof CHANNEL_END | Error>;
26
+ transform: (item: T) => T | Promise<T>;
27
+ debug?: (...args: unknown[]) => unknown;
28
+ private promise?;
29
+ private resolve?;
30
+ private reject?;
31
+ /** Producers awaiting capacity, FIFO (backpressure -- see put()). */
32
+ private putters;
33
+ /**
34
+ * Serializes delivery of concurrent put() calls into call order. Each
35
+ * put() grabs the current tail synchronously (before any `await`, so
36
+ * position is fixed by call order rather than by how long e.g.
37
+ * `transform()` happens to take) and only commits its value once its
38
+ * predecessor has committed.
39
+ */
40
+ private putOrder;
41
+ /**
42
+ * Asynchronous Channel constructor
43
+ * @kind function
44
+ * @name constructor
45
+ */
46
+ constructor({ cache, limit, transform, debug }?: AsyncChannelOptions<T>);
47
+ /**
48
+ * Move waiting producers' items into the cache while there is capacity,
49
+ * releasing their pending put() promises (FIFO).
50
+ * @ignore
51
+ */
52
+ private drainPutters;
53
+ /**
54
+ * Put item onto Asynchronous Channel. Returns a Promise<void> that
55
+ * resolves once the channel has accepted the item: immediately when a
56
+ * taker is waiting or the cache has capacity, otherwise when a later
57
+ * take() frees a slot (backpressure -- bounded by `limit`). Replaces the
58
+ * pre-2.1 behavior of throwing "cache full" at capacity.
59
+ * @kind function
60
+ * @name put
61
+ */
62
+ put(item: T, ...debug: unknown[]): Promise<void>;
63
+ /**
64
+ * Take item off of Asynchronous Channel
65
+ * @kind function
66
+ * @name take
67
+ */
68
+ take(...debug: unknown[]): Promise<T | typeof CHANNEL_END>;
69
+ /**
70
+ * Pause Asynchronous Channel
71
+ * @kind function
72
+ * @name break
73
+ */
74
+ break(...debug: unknown[]): Promise<void>;
75
+ /**
76
+ * Stop Asynchronous Channel
77
+ * @kind function
78
+ * @name throw
79
+ */
80
+ throw(message?: string, ...debug: unknown[]): Promise<void>;
81
+ /**
82
+ * Return pending status of Asynchronous Channel
83
+ * @kind function
84
+ * @name pending
85
+ * Note: should this be a getter?
86
+ */
87
+ pending(): boolean;
88
+ /**
89
+ * Return string representation of Asynchronous Channel
90
+ * @kind function
91
+ * @name toString
92
+ */
93
+ toString(): string;
94
+ /**
95
+ * Return Asynchronous Channel's iterator
96
+ * @kind function
97
+ * @name [Symbol.asyncIterator]
98
+ */
99
+ [Symbol.asyncIterator](...debug: unknown[]): AsyncGenerator<T>;
100
+ }
101
+ //# sourceMappingURL=async-channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-channel.d.ts","sourceRoot":"","sources":["../src/async-channel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,OAAO,MAA8B,CAAC;AAuBhE,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,OAAO,WAAW,GAAG,KAAK,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACxC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;CACzC;AAED;;;;GAIG;AACH,qBAAa,YAAY,CAAC,CAAC,GAAG,OAAO;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,OAAO,WAAW,GAAG,KAAK,CAAC,CAAC;IAC7C,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IACxC,OAAO,CAAC,OAAO,CAAC,CAAkC;IAClD,OAAO,CAAC,OAAO,CAAC,CAA0C;IAC1D,OAAO,CAAC,MAAM,CAAC,CAA6B;IAC5C,qEAAqE;IACrE,OAAO,CAAC,OAAO,CAGP;IACR;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAoC;IAEpD;;;;OAIG;gBACS,EAAE,KAAU,EAAE,KAAgB,EAAE,SAAuB,EAAE,KAAK,EAAE,GAAE,mBAAmB,CAAC,CAAC,CAAM;IAMzG;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAUpB;;;;;;;;OAQG;IACG,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BtD;;;;OAIG;IACG,IAAI,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,OAAO,WAAW,CAAC;IA2BhE;;;;OAIG;IACG,KAAK,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/C;;;;OAIG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjE;;;;;OAKG;IACH,OAAO,IAAI,OAAO;IAGlB;;;;OAIG;IACH,QAAQ,IAAI,MAAM;IAGlB;;;;OAIG;IACI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,KAAK,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC;CAStE"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Asynchronous Channel
3
+ * @kind namespace
4
+ * @name AsyncChannel
5
+ */
6
+ /**
7
+ * Constant signaling channel's end
8
+ * @kind constant
9
+ * @name CHANNEL_END
10
+ */
11
+ export const CHANNEL_END = Symbol("CHANNEL_END");
12
+ /**
13
+ * Creates a promise that can be resolved/rejected outside of initial closure
14
+ * @kind function
15
+ * @name InvertedPromise
16
+ * @ignore
17
+ */
18
+ const InvertedPromise = () => {
19
+ const out = {};
20
+ out.promise = new Promise((resolve, reject) => {
21
+ out.resolve = resolve;
22
+ out.reject = reject;
23
+ });
24
+ return out;
25
+ };
26
+ /**
27
+ * Asynchronous Channel class
28
+ * @kind class
29
+ * @name AsyncChannel
30
+ */
31
+ export class AsyncChannel {
32
+ limit;
33
+ cache;
34
+ transform;
35
+ debug;
36
+ promise;
37
+ resolve;
38
+ reject;
39
+ /** Producers awaiting capacity, FIFO (backpressure -- see put()). */
40
+ putters = [];
41
+ /**
42
+ * Serializes delivery of concurrent put() calls into call order. Each
43
+ * put() grabs the current tail synchronously (before any `await`, so
44
+ * position is fixed by call order rather than by how long e.g.
45
+ * `transform()` happens to take) and only commits its value once its
46
+ * predecessor has committed.
47
+ */
48
+ putOrder = Promise.resolve();
49
+ /**
50
+ * Asynchronous Channel constructor
51
+ * @kind function
52
+ * @name constructor
53
+ */
54
+ constructor({ cache = [], limit = Infinity, transform = ($) => $, debug } = {}) {
55
+ this.limit = limit;
56
+ this.cache = cache.slice(0, limit);
57
+ this.transform = transform;
58
+ this.debug = debug;
59
+ }
60
+ /**
61
+ * Move waiting producers' items into the cache while there is capacity,
62
+ * releasing their pending put() promises (FIFO).
63
+ * @ignore
64
+ */
65
+ drainPutters() {
66
+ while (this.putters.length > 0 && this.cache.length < this.limit) {
67
+ const { value, release } = this.putters.shift();
68
+ this.cache.push(value);
69
+ release();
70
+ }
71
+ }
72
+ /**
73
+ * Put item onto Asynchronous Channel. Returns a Promise<void> that
74
+ * resolves once the channel has accepted the item: immediately when a
75
+ * taker is waiting or the cache has capacity, otherwise when a later
76
+ * take() frees a slot (backpressure -- bounded by `limit`). Replaces the
77
+ * pre-2.1 behavior of throwing "cache full" at capacity.
78
+ * @kind function
79
+ * @name put
80
+ */
81
+ async put(item, ...debug) {
82
+ this.debug?.("put", item, ...debug);
83
+ // Reserve this call's delivery slot synchronously, in call order,
84
+ // before doing any async work (transform() may resolve at a different
85
+ // speed for different items -- see class doc on putOrder).
86
+ const myTurn = this.putOrder;
87
+ let advance;
88
+ this.putOrder = new Promise((resolve) => {
89
+ advance = resolve;
90
+ });
91
+ try {
92
+ const value = await this.transform(item);
93
+ await myTurn;
94
+ if (this.promise) {
95
+ this.resolve?.(value);
96
+ return;
97
+ }
98
+ if (this.cache.length < this.limit) {
99
+ this.cache.push(value);
100
+ return;
101
+ }
102
+ await new Promise((release) => {
103
+ this.putters.push({ value, release });
104
+ });
105
+ }
106
+ finally {
107
+ advance();
108
+ }
109
+ }
110
+ /**
111
+ * Take item off of Asynchronous Channel
112
+ * @kind function
113
+ * @name take
114
+ */
115
+ async take(...debug) {
116
+ this.debug?.("take", ...debug);
117
+ if (this.cache.length) {
118
+ const value = this.cache.shift();
119
+ this.drainPutters();
120
+ return value;
121
+ }
122
+ if (this.putters.length) {
123
+ // limit of 0 (rendezvous) or drained cache with waiting producers:
124
+ // hand off directly.
125
+ const { value, release } = this.putters.shift();
126
+ release();
127
+ return value;
128
+ }
129
+ const { promise, resolve, reject } = InvertedPromise();
130
+ this.promise = promise;
131
+ this.resolve = resolve;
132
+ this.reject = reject;
133
+ const value = await this.promise;
134
+ delete this.promise;
135
+ delete this.resolve;
136
+ delete this.reject;
137
+ return value;
138
+ }
139
+ /**
140
+ * Pause Asynchronous Channel
141
+ * @kind function
142
+ * @name break
143
+ */
144
+ async break(...debug) {
145
+ this.debug?.("break", ...debug);
146
+ if (this.promise) {
147
+ await this.resolve?.(CHANNEL_END);
148
+ }
149
+ else if (this.putters.length > 0) {
150
+ // Keep FIFO order: the end marker must not overtake producers
151
+ // already waiting for capacity.
152
+ this.putters.push({ value: CHANNEL_END, release: () => { } });
153
+ }
154
+ else {
155
+ this.cache.push(CHANNEL_END);
156
+ }
157
+ }
158
+ /**
159
+ * Stop Asynchronous Channel
160
+ * @kind function
161
+ * @name throw
162
+ */
163
+ async throw(message, ...debug) {
164
+ this.debug?.("throw", ...debug);
165
+ if (this.promise) {
166
+ await this.reject?.(new Error(message));
167
+ }
168
+ else if (this.putters.length > 0) {
169
+ // Keep FIFO order behind producers already waiting for capacity.
170
+ this.putters.push({ value: new Error(message), release: () => { } });
171
+ }
172
+ else {
173
+ this.cache.push(new Error(message));
174
+ }
175
+ }
176
+ /**
177
+ * Return pending status of Asynchronous Channel
178
+ * @kind function
179
+ * @name pending
180
+ * Note: should this be a getter?
181
+ */
182
+ pending() {
183
+ return !!this.promise;
184
+ }
185
+ /**
186
+ * Return string representation of Asynchronous Channel
187
+ * @kind function
188
+ * @name toString
189
+ */
190
+ toString() {
191
+ return `AsyncChannel {${this.pending() ? "pending" : ""}} [${this.cache.length}/${this.limit}]`;
192
+ }
193
+ /**
194
+ * Return Asynchronous Channel's iterator
195
+ * @kind function
196
+ * @name [Symbol.asyncIterator]
197
+ */
198
+ async *[Symbol.asyncIterator](...debug) {
199
+ while (true) {
200
+ const answer = await this.take(...debug);
201
+ if (answer === CHANNEL_END) {
202
+ return;
203
+ }
204
+ yield answer;
205
+ }
206
+ }
207
+ }
208
+ //# sourceMappingURL=async-channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-channel.js","sourceRoot":"","sources":["../src/async-channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { AsyncChannel } from "./async-channel.ts";
2
+ interface EmitterLike {
3
+ addListener(event: string, listener: (...args: never[]) => unknown): unknown;
4
+ }
5
+ interface WebSocketLike {
6
+ onmessage: ((event: unknown) => unknown) | null;
7
+ onclose: ((event?: unknown) => unknown) | null;
8
+ onerror: ((event?: unknown) => unknown) | null;
9
+ }
10
+ /**
11
+ * Decorate Asynchronous Channel with generic emitter
12
+ * @kind function
13
+ * @name withEmitter
14
+ */
15
+ export declare const withEmitter: <T, C extends AsyncChannel<T>>(channel: C, emitter: EmitterLike, data?: string, end?: string, error?: string) => C;
16
+ /**
17
+ * Decorate Asynchronous Channel with websocket
18
+ * @kind function
19
+ * @name withWebSocket
20
+ */
21
+ export declare const withWebSocket: <T, C extends AsyncChannel<T>>(channel: C, websocket: WebSocketLike) => C;
22
+ export {};
23
+ //# sourceMappingURL=channel-decorators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-decorators.d.ts","sourceRoot":"","sources":["../src/channel-decorators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,UAAU,WAAW;IACnB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,GAAG,OAAO,CAAC;CAC9E;AAED,UAAU,aAAa;IACrB,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,IAAI,CAAC;IAChD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,IAAI,CAAC;IAC/C,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,IAAI,CAAC;CAChD;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,EACtD,SAAS,CAAC,EACV,SAAS,WAAW,EACpB,aAAa,EACb,YAAW,EACX,cAAe,KACd,CASF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,WAAW,aAAa,KAAG,CASlG,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Decorate Asynchronous Channel with generic emitter
3
+ * @kind function
4
+ * @name withEmitter
5
+ */
6
+ export const withEmitter = (channel, emitter, data = "data", end = "end", error = "error") => {
7
+ emitter.addListener(data, (...args) => {
8
+ void channel.put(...args).catch((reason) => {
9
+ void channel.throw(reason instanceof Error ? reason.message : String(reason));
10
+ });
11
+ });
12
+ emitter.addListener(end, channel.break.bind(channel));
13
+ emitter.addListener(error, channel.throw.bind(channel));
14
+ return channel;
15
+ };
16
+ /**
17
+ * Decorate Asynchronous Channel with websocket
18
+ * @kind function
19
+ * @name withWebSocket
20
+ */
21
+ export const withWebSocket = (channel, websocket) => {
22
+ websocket.onmessage = (event) => {
23
+ void channel.put(event).catch((reason) => {
24
+ void channel.throw(reason instanceof Error ? reason.message : String(reason));
25
+ });
26
+ };
27
+ websocket.onclose = channel.break.bind(channel);
28
+ websocket.onerror = channel.throw.bind(channel);
29
+ return channel;
30
+ };
31
+ //# sourceMappingURL=channel-decorators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel-decorators.js","sourceRoot":"","sources":["../src/channel-decorators.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,OAAU,EACV,OAAoB,EACpB,IAAI,GAAG,MAAM,EACb,GAAG,GAAG,KAAK,EACX,KAAK,GAAG,OAAO,EACZ,EAAE;IACL,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,GAAG,IAAa,EAAE,EAAE;QAC7C,KAAK,OAAO,CAAC,GAAG,CAAC,GAAI,IAAkD,CAAC,CAAC,KAAK,CAAC,CAAC,MAAe,EAAE,EAAE;YACjG,KAAK,OAAO,CAAC,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAA+B,OAAU,EAAE,SAAwB,EAAK,EAAE;IACrG,SAAS,CAAC,SAAS,GAAG,CAAC,KAAc,EAAE,EAAE;QACvC,KAAK,OAAO,CAAC,GAAG,CAAC,KAAU,CAAC,CAAC,KAAK,CAAC,CAAC,MAAe,EAAE,EAAE;YACrD,KAAK,OAAO,CAAC,KAAK,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAChD,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAiC,CAAC;IAChF,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Bounded-concurrency helpers: mapConcurrentAsync (parallel map over an
3
+ * (a)sync iterable with a concurrency limit) and prefetchAsync (eager
4
+ * read-ahead into a bounded buffer). Both propagate cancellation/early
5
+ * consumer exit upstream via iterator.return().
6
+ */
7
+ import { type SignalOptions } from "./abort.ts";
8
+ export interface MapConcurrentOptions extends SignalOptions {
9
+ /** Maximum number of `fn` invocations in flight at once (required, >= 1). */
10
+ concurrency: number;
11
+ /**
12
+ * true (default): yield results in input order.
13
+ * false: yield results in completion order.
14
+ */
15
+ ordered?: boolean;
16
+ }
17
+ /**
18
+ * Map `fn` over `iterable` with up to `concurrency` invocations in flight
19
+ * at once. With `ordered: true` (the default) results are yielded in input
20
+ * order; with `ordered: false` they are yielded in completion order.
21
+ *
22
+ * - Backpressure: at most `concurrency` results are held; the source is
23
+ * only pulled while there is spare in-flight capacity.
24
+ * - Cancellation: an optional `signal` aborts promptly (rejecting with the
25
+ * signal's reason, an "AbortError" DOMException by default) even while
26
+ * awaiting a slow `fn` or source; the source iterator is closed via
27
+ * `return()`.
28
+ * - Early exit / error: breaking out of the loop, or an `fn` rejection,
29
+ * also closes the source via `return()`.
30
+ * @kind function
31
+ * @name mapConcurrentAsync
32
+ */
33
+ export declare const mapConcurrentAsync: <In, Out>(fn: (item: In) => Out | Promise<Out>, iterable: AsyncIterable<In> | Iterable<In>, { concurrency, ordered, signal }: MapConcurrentOptions) => AsyncGenerator<Out>;
34
+ /**
35
+ * Eagerly pull up to `n` items ahead of the consumer into a bounded
36
+ * buffer, so a slow consumer overlaps with a slow producer. `n <= 0`
37
+ * degenerates to plain iteration. Early consumer exit (or an error)
38
+ * closes the source via `return()`.
39
+ * @kind function
40
+ * @name prefetchAsync
41
+ */
42
+ export declare const prefetchAsync: <T>(n: number, iterable: AsyncIterable<T> | Iterable<T>) => AsyncGenerator<T>;
43
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,YAAY,CAAC;AAEhE,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAUD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,kBAAkB,GAAoB,EAAE,EAAE,GAAG,EACxD,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,EACpC,UAAU,aAAa,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,EAC1C,kCAAyC,oBAAoB,KAC5D,cAAc,CAAC,GAAG,CA4EpB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAoB,CAAC,EAC7C,GAAG,MAAM,EACT,UAAU,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,KACvC,cAAc,CAAC,CAAC,CA+BlB,CAAC"}