@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,290 @@
1
+ import { isAsyncIterator } from "./is-iterator.ts";
2
+
3
+ /**
4
+ * Sentinel returned by a reducer step to stop consumption of the source
5
+ * iterator (early termination -- see the `take` transducer).
6
+ */
7
+ export const HALT: unique symbol = Symbol("HALT");
8
+ export type Halt = typeof HALT;
9
+
10
+ /**
11
+ * @deprecated Misspelled legacy alias of {@link HALT} (pre-2.1 name).
12
+ * Kept for backwards compatibility; prefer HALT.
13
+ */
14
+ export { HALT as HAULT };
15
+
16
+ /**
17
+ * The transducer step protocol (v2.1, "pending-emission buffer").
18
+ *
19
+ * The accumulator is a plain array used as a pending-emission buffer: the
20
+ * innermost step ("emit" -- see transduce.ts) pushes emitted items onto it
21
+ * and returns it. A step may instead return {@link HALT} to terminate
22
+ * consumption of the source early. A stateful step (e.g. `group`,
23
+ * `partitionBy`) may carry a `complete` method, invoked once after the
24
+ * source is exhausted (or halted) to flush buffered state; `complete`
25
+ * implementations must cascade to their inner step's own `complete` (see
26
+ * transducers.ts).
27
+ */
28
+ export interface ReducerStep<in In> {
29
+ (buffer: unknown[], item: In, iterator?: Iterable<In> | AsyncIterable<In>): unknown[] | Halt;
30
+ complete?: (buffer: unknown[]) => unknown[];
31
+ }
32
+
33
+ /**
34
+ * A transducer: transforms a step that consumes `Out` items into a step
35
+ * that consumes `In` items. Produced by the factories in transducers.ts
36
+ * (map, filter, take, group, ...), consumed by transduceSync/transduceAsync
37
+ * (left-to-right composition as written).
38
+ */
39
+ export type Transducer<In, Out> = (next: ReducerStep<Out>) => ReducerStep<In>;
40
+
41
+ /**
42
+ * Create a promise that fulfills after a given number of milliseconds
43
+ * The primary purpose of this is to allow pausing of asynchronous functions
44
+ * @kind function
45
+ * @name pause
46
+ * @param milliseconds time in milliseconds before value is resolved
47
+ * @param value value given
48
+ * @returns Promise fulfilled with given value
49
+ * @example <caption>Pause a function for 5000 milliseconds</caption>
50
+ * ```javascript
51
+ * import { pause } from '...';
52
+ * (async ()=>{
53
+ * console.log('hello');
54
+ * await pause(5000);
55
+ * console.log('there.');
56
+ * })();
57
+ * ```
58
+ */
59
+ export const pause = <T = undefined>(milliseconds: number, value?: T): Promise<T> =>
60
+ new Promise((resolve) => setTimeout(resolve as (value?: T) => void, milliseconds, value));
61
+
62
+ /**
63
+ * Streaming reduce for iterators -- the engine under transduceSync.
64
+ *
65
+ * Protocol (v2.1): the accumulator (`init`) is a plain array used as a
66
+ * *pending-emission buffer*, not a threaded iterable. The innermost step
67
+ * ("emit" -- see transduce.ts) pushes emitted items onto the buffer and
68
+ * returns it; after each step call the buffer is drained (yielded out and
69
+ * cleared in place). This replaces the v2.0 protocol, in which the
70
+ * accumulator was an iterable that each step wrapped in a fresh generator
71
+ * (`conjoin(init, item)`) -- that formed an ever-growing generator chain
72
+ * retaining ~176 bytes per item processed, i.e. unbounded heap growth on
73
+ * long streams.
74
+ *
75
+ * Preserved semantics:
76
+ * - Left-to-right composition order as written in transduceSync(...fns).
77
+ * - If `step` carries a `.complete(init)` method (the transducer completion
78
+ * protocol -- see transducers.ts's `group`/`partitionBy`), it is invoked
79
+ * once after the source iterator is exhausted (or halted), letting
80
+ * stateful transducers flush buffered state (e.g. a trailing,
81
+ * under-sized `group`).
82
+ * - HALT early termination: a step returning HALT stops consumption of
83
+ * the source; emissions buffered during the halting step itself are
84
+ * discarded (as in v2.0, where the halting step's accumulator chain was
85
+ * dropped), then `.complete` still flushes.
86
+ * @kind function
87
+ * @name reduceSync
88
+ * @param iterator source iterable
89
+ * @param step reducer/transducer step function
90
+ * @param init pending-emission buffer (defaults to a fresh array)
91
+ * @param ignore_halt ignore when HALT is passed
92
+ * @returns generator yielding each emitted item
93
+ */
94
+ export const reduceSync = function* <In, Out = unknown>(
95
+ iterator: Iterable<In>,
96
+ step: ReducerStep<In>,
97
+ init: unknown[] = [],
98
+ ignore_halt = false,
99
+ ): Generator<Out> {
100
+ for (const item of iterator) {
101
+ const next = step(init, item, iterator);
102
+ if (!ignore_halt && next === HALT) {
103
+ init.length = 0;
104
+ break;
105
+ }
106
+ init = next as unknown[];
107
+ while (init.length > 0) {
108
+ yield init.shift() as Out;
109
+ }
110
+ }
111
+ if (step.complete) {
112
+ init = step.complete(init);
113
+ while (init.length > 0) {
114
+ yield init.shift() as Out;
115
+ }
116
+ }
117
+ };
118
+
119
+ /**
120
+ * Streaming reduce for asynchronous iterators -- the engine under
121
+ * transduceAsync. See reduceSync for the pending-emission-buffer protocol
122
+ * (v2.1), the `.complete` flush protocol, and HALT semantics -- all
123
+ * identical here, just async.
124
+ * @kind function
125
+ * @name reduceAsync
126
+ * @param iterator source (async) iterable
127
+ * @param step reducer/transducer step function
128
+ * @param init pending-emission buffer (defaults to a fresh array)
129
+ * @param ignore_halt ignore when HALT is passed
130
+ * @returns async generator yielding each emitted item
131
+ */
132
+ export const reduceAsync = async function* <In, Out = unknown>(
133
+ iterator: AsyncIterable<In> | Iterable<In>,
134
+ step: ReducerStep<In>,
135
+ init: unknown[] = [],
136
+ ignore_halt = false,
137
+ ): AsyncGenerator<Out> {
138
+ for await (const item of iterator) {
139
+ const next = step(init, item, iterator);
140
+ if (!ignore_halt && next === HALT) {
141
+ init.length = 0;
142
+ break;
143
+ }
144
+ init = next as unknown[];
145
+ while (init.length > 0) {
146
+ yield init.shift() as Out;
147
+ }
148
+ }
149
+ if (step.complete) {
150
+ init = step.complete(init);
151
+ while (init.length > 0) {
152
+ yield init.shift() as Out;
153
+ }
154
+ }
155
+ };
156
+
157
+ /**
158
+ * Concatinates sequence of synchronous iterables
159
+ * @kind function
160
+ * @name concatSync
161
+ * @param iterators iterators
162
+ * @returns iterator generating sequence of combined from given iterables; empty iterator if nothing is passed
163
+ */
164
+ export const concatSync = function* <T>(...iterators: Array<Iterable<T>>): Generator<T> {
165
+ for (const iterator of iterators) {
166
+ yield* iterator;
167
+ }
168
+ };
169
+
170
+ /**
171
+ * Appends items to synchronous iterator
172
+ * @kind function
173
+ * @name conjoinSync
174
+ * @param iterator iterator
175
+ * @param itemList items to be appended
176
+ * @returns copy of initial iterator with items appended
177
+ */
178
+ export const conjoinSync = function* <T>(iterator?: Iterable<T>, ...itemList: T[]): Generator<T> {
179
+ if (iterator) {
180
+ yield* iterator;
181
+ }
182
+ yield* itemList;
183
+ };
184
+
185
+ /**
186
+ * Concatinates sequence of asynchronous iterables
187
+ * @kind function
188
+ * @name concatAsync
189
+ * @param iterators iterators
190
+ * @returns iterator generating sequence of combined from given iterables; empty iterator if nothing is passed
191
+ */
192
+ export const concatAsync = async function* <T>(...iterators: Array<AsyncIterable<T> | Iterable<T>>): AsyncGenerator<T> {
193
+ for (const iterator of iterators) {
194
+ yield* iterator;
195
+ }
196
+ };
197
+
198
+ /**
199
+ * Appends items to asynchronous iterator
200
+ * @kind function
201
+ * @name conjoinAsync
202
+ * @param iterator iterator
203
+ * @param itemList items to be appended
204
+ * @returns copy of initial iterator with items appended
205
+ */
206
+ export const conjoinAsync = async function* <T>(
207
+ iterator?: AsyncIterable<T> | Iterable<T>,
208
+ ...itemList: T[]
209
+ ): AsyncGenerator<T> {
210
+ if (iterator) {
211
+ yield* iterator;
212
+ }
213
+ yield* itemList;
214
+ };
215
+
216
+ /**
217
+ * Zips synchronous iterators
218
+ * @kind function
219
+ * @name zipSync
220
+ * @param iteratorList iterators
221
+ * @returns an iterator who's members are the members of the given iterators zipped sequencially
222
+ */
223
+ export const zipSync = function* <T>(...iteratorList: Array<Iterable<T>>): Generator<T[]> {
224
+ const generators = iteratorList.map((iterator) => iterator[Symbol.iterator]());
225
+ outer: while (true) {
226
+ const result: T[] = [];
227
+ for (const generator of generators) {
228
+ const { value, done } = generator.next();
229
+ if (done) {
230
+ break outer;
231
+ }
232
+ result.push(value);
233
+ }
234
+ yield result;
235
+ }
236
+ };
237
+
238
+ /**
239
+ * Zips asynchronous iterators (dual of zipSync).
240
+ * Pulls the next value from every input in parallel each round (rather than
241
+ * sequentially awaiting one at a time), stopping as soon as any input is
242
+ * exhausted -- matching zipSync's stop-at-shortest semantics.
243
+ * @kind function
244
+ * @name zipAsync
245
+ * @param iteratorList (async or sync) iterators
246
+ * @returns an async iterator who's members are the members of the given iterators zipped sequencially
247
+ */
248
+ export const zipAsync = async function* <T>(
249
+ ...iteratorList: Array<AsyncIterable<T> | Iterable<T>>
250
+ ): AsyncGenerator<T[]> {
251
+ const generators = iteratorList.map((iterator) =>
252
+ isAsyncIterator(iterator)
253
+ ? (iterator as AsyncIterable<T>)[Symbol.asyncIterator]()
254
+ : (iterator as Iterable<T>)[Symbol.iterator](),
255
+ );
256
+ while (true) {
257
+ const results = await Promise.all(generators.map((g) => g.next()));
258
+ if (results.some(({ done }) => done)) {
259
+ break;
260
+ }
261
+ yield results.map(({ value }) => value as T);
262
+ }
263
+ };
264
+
265
+ /**
266
+ * "run" iterator as a program
267
+ * @kind function
268
+ * @name run
269
+ * @param program iterator
270
+ * @param render function to render output from iterator
271
+ */
272
+ export const run = async <T>(
273
+ program: AsyncIterable<T> | Iterable<T>,
274
+ render: (output: T) => unknown = console.log,
275
+ ): Promise<void> => {
276
+ for await (const output of program) {
277
+ await render(output);
278
+ }
279
+ };
280
+
281
+ export const syncFrom = function* <T>(...stuff: T[]): Generator<T> {
282
+ for (const thing of stuff) {
283
+ yield thing;
284
+ }
285
+ };
286
+ export const asyncFrom = async function* <T>(...stuff: T[]): AsyncGenerator<T> {
287
+ for (const thing of stuff) {
288
+ yield thing;
289
+ }
290
+ };