@byloth/core 2.0.0-rc.9 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.js +4087 -621
- package/dist/core.js.map +1 -1
- package/dist/core.umd.cjs +2 -2
- package/dist/core.umd.cjs.map +1 -1
- package/package.json +17 -13
- package/src/core/types.ts +41 -0
- package/src/helpers.ts +11 -2
- package/src/index.ts +12 -9
- package/src/models/aggregators/aggregated-async-iterator.ts +920 -21
- package/src/models/aggregators/aggregated-iterator.ts +838 -22
- package/src/models/aggregators/reduced-iterator.ts +827 -11
- package/src/models/aggregators/types.ts +153 -10
- package/src/models/callbacks/callable-object.ts +42 -6
- package/src/models/callbacks/index.ts +2 -2
- package/src/models/callbacks/publisher.ts +160 -4
- package/src/models/callbacks/switchable-callback.ts +230 -23
- package/src/models/callbacks/types.ts +16 -0
- package/src/models/exceptions/core.ts +132 -3
- package/src/models/exceptions/index.ts +405 -13
- package/src/models/index.ts +4 -8
- package/src/models/iterators/smart-async-iterator.ts +827 -22
- package/src/models/iterators/smart-iterator.ts +755 -20
- package/src/models/iterators/types.ts +268 -9
- package/src/models/json/json-storage.ts +508 -110
- package/src/models/json/types.ts +10 -1
- package/src/models/promises/deferred-promise.ts +85 -5
- package/src/models/promises/index.ts +1 -3
- package/src/models/promises/smart-promise.ts +272 -4
- package/src/models/promises/timed-promise.ts +43 -1
- package/src/models/promises/types.ts +84 -2
- package/src/models/timers/clock.ts +109 -19
- package/src/models/timers/countdown.ts +176 -21
- package/src/models/timers/game-loop.ts +266 -0
- package/src/models/timers/index.ts +2 -1
- package/src/models/types.ts +6 -5
- package/src/utils/async.ts +43 -0
- package/src/utils/curve.ts +85 -0
- package/src/utils/date.ts +204 -10
- package/src/utils/dom.ts +16 -2
- package/src/utils/index.ts +3 -2
- package/src/utils/iterator.ts +200 -17
- package/src/utils/math.ts +55 -3
- package/src/utils/random.ts +139 -2
- package/src/utils/string.ts +11 -0
- package/src/models/game-loop.ts +0 -83
- package/src/models/promises/long-running-task.ts +0 -294
- package/src/models/promises/thenable.ts +0 -97
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import AggregatedAsyncIterator from "../aggregators/aggregated-async-iterator.js";
|
|
2
2
|
import { ValueException } from "../exceptions/index.js";
|
|
3
|
+
import type { MaybePromise } from "../types.js";
|
|
3
4
|
|
|
4
5
|
import type {
|
|
5
6
|
GeneratorFunction,
|
|
@@ -7,25 +8,182 @@ import type {
|
|
|
7
8
|
MaybeAsyncGeneratorFunction,
|
|
8
9
|
MaybeAsyncIteratee,
|
|
9
10
|
MaybeAsyncReducer,
|
|
10
|
-
|
|
11
|
-
MaybeAsyncIteratorLike,
|
|
12
|
-
MaybeAsyncTypeGuardIteratee
|
|
11
|
+
MaybeAsyncIteratorLike
|
|
13
12
|
|
|
14
13
|
} from "./types.js";
|
|
15
14
|
|
|
15
|
+
/**
|
|
16
|
+
* A wrapper class representing an enhanced and instantiable version
|
|
17
|
+
* of the native {@link AsyncIterable} & {@link AsyncIterator} interfaces.
|
|
18
|
+
*
|
|
19
|
+
* It provides a set of utility methods to better manipulate and transform
|
|
20
|
+
* asynchronous iterators in a functional and highly performant way.
|
|
21
|
+
* It takes inspiration from the native {@link Array} methods like
|
|
22
|
+
* {@link Array.map}, {@link Array.filter}, {@link Array.reduce}, etc...
|
|
23
|
+
*
|
|
24
|
+
* The class is lazy, meaning that the transformations are applied
|
|
25
|
+
* only when the resulting iterator is materialized, not before.
|
|
26
|
+
* This allows to chain multiple transformations without
|
|
27
|
+
* the need to iterate over the elements multiple times.
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* const result = new SmartAsyncIterator<number>(["-5", "-4", "-3", "-2", "-1", "0", "1", "2", "3", "4", "5"])
|
|
31
|
+
* .map((value) => Number(value))
|
|
32
|
+
* .map((value) => value + Math.ceil(Math.abs(value / 2)))
|
|
33
|
+
* .filter((value) => value >= 0)
|
|
34
|
+
* .map((value) => value + 1)
|
|
35
|
+
* .reduce((acc, value) => acc + value);
|
|
36
|
+
*
|
|
37
|
+
* console.log(await result); // 31
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @template T The type of elements in the iterator.
|
|
41
|
+
* @template R The type of the final result of the iterator. Default is `void`.
|
|
42
|
+
* @template N The type of the argument passed to the `next` method. Default is `undefined`.
|
|
43
|
+
*/
|
|
16
44
|
export default class SmartAsyncIterator<T, R = void, N = undefined> implements AsyncIterator<T, R, N>
|
|
17
45
|
{
|
|
46
|
+
/**
|
|
47
|
+
* The native {@link AsyncIterator} object that is being wrapped by this instance.
|
|
48
|
+
*/
|
|
18
49
|
protected _iterator: AsyncIterator<T, R, N>;
|
|
19
50
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Initializes a new instance of the {@link SmartAsyncIterator} class.
|
|
53
|
+
*
|
|
54
|
+
* ---
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const iterator = new SmartAsyncIterator<string>(["A", "B", "C"]);
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* ---
|
|
62
|
+
*
|
|
63
|
+
* @param iterable The iterable object to wrap.
|
|
64
|
+
*/
|
|
23
65
|
public constructor(iterable: Iterable<T>);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Initializes a new instance of the {@link SmartAsyncIterator} class.
|
|
69
|
+
*
|
|
70
|
+
* ---
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* ---
|
|
78
|
+
*
|
|
79
|
+
* @param iterable The asynchronous iterable object to wrap.
|
|
80
|
+
*/
|
|
24
81
|
public constructor(iterable: AsyncIterable<T>);
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Initializes a new instance of the {@link SmartAsyncIterator} class.
|
|
85
|
+
*
|
|
86
|
+
* ---
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* const iterator = new SmartAsyncIterator<number, void, number>({
|
|
91
|
+
* _sum: 0, _count: 0,
|
|
92
|
+
*
|
|
93
|
+
* next: function(value: number)
|
|
94
|
+
* {
|
|
95
|
+
* this._sum += value;
|
|
96
|
+
* this._count += 1;
|
|
97
|
+
*
|
|
98
|
+
* return { done: false, value: this._sum / this._count };
|
|
99
|
+
* }
|
|
100
|
+
* })
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* ---
|
|
104
|
+
*
|
|
105
|
+
* @param iterator The iterator object to wrap.
|
|
106
|
+
*/
|
|
25
107
|
public constructor(iterator: Iterator<T, R, N>);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Initializes a new instance of the {@link SmartAsyncIterator} class.
|
|
111
|
+
*
|
|
112
|
+
* ---
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* const iterator = new SmartAsyncIterator<number, void, number>({
|
|
117
|
+
* _sum: 0, _count: 0,
|
|
118
|
+
*
|
|
119
|
+
* next: async function(value: number)
|
|
120
|
+
* {
|
|
121
|
+
* this._sum += value;
|
|
122
|
+
* this._count += 1;
|
|
123
|
+
*
|
|
124
|
+
* return { done: false, value: this._sum / this._count };
|
|
125
|
+
* }
|
|
126
|
+
* })
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* ---
|
|
130
|
+
*
|
|
131
|
+
* @param iterator The asynchronous iterator object to wrap.
|
|
132
|
+
*/
|
|
26
133
|
public constructor(iterator: AsyncIterator<T, R, N>);
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Initializes a new instance of the {@link SmartAsyncIterator} class.
|
|
137
|
+
*
|
|
138
|
+
* ---
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const iterator = new SmartAsyncIterator<number>(function* ()
|
|
143
|
+
* {
|
|
144
|
+
* for (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }
|
|
145
|
+
* });
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* ---
|
|
149
|
+
*
|
|
150
|
+
* @param generatorFn The generator function to wrap.
|
|
151
|
+
*/
|
|
27
152
|
public constructor(generatorFn: GeneratorFunction<T, R, N>);
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Initializes a new instance of the {@link SmartAsyncIterator} class.
|
|
156
|
+
*
|
|
157
|
+
* ---
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* const iterator = new SmartAsyncIterator<number>(async function* ()
|
|
162
|
+
* {
|
|
163
|
+
* for await (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* ---
|
|
168
|
+
*
|
|
169
|
+
* @param generatorFn The asynchronous generator function to wrap.
|
|
170
|
+
*/
|
|
28
171
|
public constructor(generatorFn: AsyncGeneratorFunction<T, R, N>);
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Initializes a new instance of the {@link SmartAsyncIterator} class.
|
|
175
|
+
*
|
|
176
|
+
* ---
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* const iterator = new SmartAsyncIterator(values);
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* ---
|
|
184
|
+
*
|
|
185
|
+
* @param argument The synchronous or asynchronous iterable, iterator or generator function to wrap.
|
|
186
|
+
*/
|
|
29
187
|
public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>);
|
|
30
188
|
public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>)
|
|
31
189
|
{
|
|
@@ -88,11 +246,38 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
88
246
|
|
|
89
247
|
})();
|
|
90
248
|
}
|
|
91
|
-
|
|
92
|
-
if (this._iterator.return) { this.return = (value?: R) => this._iterator.return!(value); }
|
|
93
|
-
if (this._iterator.throw) { this.throw = (error?: unknown) => this._iterator.throw!(error); }
|
|
94
249
|
}
|
|
95
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Determines whether all elements of the iterator satisfy a given condition.
|
|
253
|
+
* See also {@link SmartAsyncIterator.some}.
|
|
254
|
+
*
|
|
255
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
256
|
+
* Once a single element doesn't satisfy the condition, the method will return `false` immediately.
|
|
257
|
+
*
|
|
258
|
+
* This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
|
|
259
|
+
* For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
|
|
260
|
+
* Consider using {@link SmartAsyncIterator.find} instead.
|
|
261
|
+
*
|
|
262
|
+
* If the iterator is infinite and every element satisfies the condition, the method will never return.
|
|
263
|
+
*
|
|
264
|
+
* ---
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
|
|
269
|
+
* const result = await iterator.every(async (value) => value < 0);
|
|
270
|
+
*
|
|
271
|
+
* console.log(result); // false
|
|
272
|
+
* ```
|
|
273
|
+
*
|
|
274
|
+
* ---
|
|
275
|
+
*
|
|
276
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
277
|
+
*
|
|
278
|
+
* @returns
|
|
279
|
+
* A {@link Promise} that will resolve to `true` if all elements satisfy the condition, `false` otherwise.
|
|
280
|
+
*/
|
|
96
281
|
public async every(predicate: MaybeAsyncIteratee<T, boolean>): Promise<boolean>
|
|
97
282
|
{
|
|
98
283
|
let index = 0;
|
|
@@ -107,6 +292,37 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
107
292
|
index += 1;
|
|
108
293
|
}
|
|
109
294
|
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Determines whether any element of the iterator satisfies a given condition.
|
|
298
|
+
* See also {@link SmartAsyncIterator.every}.
|
|
299
|
+
*
|
|
300
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
301
|
+
* Once a single element satisfies the condition, the method will return `true` immediately.
|
|
302
|
+
*
|
|
303
|
+
* This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
|
|
304
|
+
* For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
|
|
305
|
+
* Consider using {@link SmartAsyncIterator.find} instead.
|
|
306
|
+
*
|
|
307
|
+
* If the iterator is infinite and no element satisfies the condition, the method will never return.
|
|
308
|
+
*
|
|
309
|
+
* ---
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```ts
|
|
313
|
+
* const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
|
|
314
|
+
* const result = await iterator.some(async (value) => value > 0);
|
|
315
|
+
*
|
|
316
|
+
* console.log(result); // true
|
|
317
|
+
* ```
|
|
318
|
+
*
|
|
319
|
+
* ---
|
|
320
|
+
*
|
|
321
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
322
|
+
*
|
|
323
|
+
* @returns
|
|
324
|
+
* A {@link Promise} that will resolve to `true` if any element satisfies the condition, `false` otherwise.
|
|
325
|
+
*/
|
|
110
326
|
public async some(predicate: MaybeAsyncIteratee<T, boolean>): Promise<boolean>
|
|
111
327
|
{
|
|
112
328
|
let index = 0;
|
|
@@ -122,8 +338,73 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
122
338
|
}
|
|
123
339
|
}
|
|
124
340
|
|
|
341
|
+
/**
|
|
342
|
+
* Filters the elements of the iterator using a given condition.
|
|
343
|
+
*
|
|
344
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
345
|
+
* If the condition is met, the element will be included in the new iterator.
|
|
346
|
+
*
|
|
347
|
+
* Since the iterator is lazy, the filtering process will
|
|
348
|
+
* be executed once the resulting iterator is materialized.
|
|
349
|
+
*
|
|
350
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
351
|
+
* This means that the original iterator won't be consumed until the
|
|
352
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
353
|
+
*
|
|
354
|
+
* ---
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* ```ts
|
|
358
|
+
* const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
|
|
359
|
+
* const result = iterator.filter(async (value) => value < 0);
|
|
360
|
+
*
|
|
361
|
+
* console.log(await result.toArray()); // [-2, -1]
|
|
362
|
+
* ```
|
|
363
|
+
*
|
|
364
|
+
* ---
|
|
365
|
+
*
|
|
366
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
367
|
+
*
|
|
368
|
+
* @returns A new {@link SmartAsyncIterator} containing only the elements that satisfy the condition.
|
|
369
|
+
*/
|
|
125
370
|
public filter(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<T, R>;
|
|
126
|
-
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Filters the elements of the iterator using a given condition.
|
|
374
|
+
*
|
|
375
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
376
|
+
* If the condition is met, the element will be included in the new iterator.
|
|
377
|
+
*
|
|
378
|
+
* Since the iterator is lazy, the filtering process will
|
|
379
|
+
* be executed once the resulting iterator is materialized.
|
|
380
|
+
*
|
|
381
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
382
|
+
* This means that the original iterator won't be consumed until the
|
|
383
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
384
|
+
*
|
|
385
|
+
* ---
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```ts
|
|
389
|
+
* const iterator = new SmartAsyncIterator<number | string>([-2, "-1", "0", 1, "2"]);
|
|
390
|
+
* const result = iterator.filter<number>(async (value) => typeof value === "number");
|
|
391
|
+
*
|
|
392
|
+
* console.log(await result.toArray()); // [-2, 1]
|
|
393
|
+
* ```
|
|
394
|
+
*
|
|
395
|
+
* ---
|
|
396
|
+
*
|
|
397
|
+
* @template S
|
|
398
|
+
* The type of the elements that satisfy the condition.
|
|
399
|
+
* This allows the type-system to infer the correct type of the new iterator.
|
|
400
|
+
*
|
|
401
|
+
* It must be a subtype of the original type of the elements.
|
|
402
|
+
*
|
|
403
|
+
* @param predicate The type guard condition to check for each element of the iterator.
|
|
404
|
+
*
|
|
405
|
+
* @returns A new {@link SmartAsyncIterator} containing only the elements that satisfy the condition.
|
|
406
|
+
*/
|
|
407
|
+
public filter<S extends T>(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<S, R>;
|
|
127
408
|
public filter(predicate: MaybeAsyncIteratee<T, boolean>): SmartAsyncIterator<T, R>
|
|
128
409
|
{
|
|
129
410
|
const iterator = this._iterator;
|
|
@@ -131,11 +412,9 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
131
412
|
return new SmartAsyncIterator<T, R>(async function* ()
|
|
132
413
|
{
|
|
133
414
|
let index = 0;
|
|
134
|
-
|
|
135
415
|
while (true)
|
|
136
416
|
{
|
|
137
417
|
const result = await iterator.next();
|
|
138
|
-
|
|
139
418
|
if (result.done) { return result.value; }
|
|
140
419
|
if (await predicate(result.value, index)) { yield result.value; }
|
|
141
420
|
|
|
@@ -143,6 +422,38 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
143
422
|
}
|
|
144
423
|
});
|
|
145
424
|
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Maps the elements of the iterator using a given transformation function.
|
|
428
|
+
*
|
|
429
|
+
* This method will iterate over all elements of the iterator applying the transformation function.
|
|
430
|
+
* The result of each transformation will be included in the new iterator.
|
|
431
|
+
*
|
|
432
|
+
* Since the iterator is lazy, the mapping process will
|
|
433
|
+
* be executed once the resulting iterator is materialized.
|
|
434
|
+
*
|
|
435
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
436
|
+
* This means that the original iterator won't be consumed until the
|
|
437
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
438
|
+
*
|
|
439
|
+
* ---
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```ts
|
|
443
|
+
* const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
|
|
444
|
+
* const result = iterator.map(async (value) => Math.abs(value));
|
|
445
|
+
*
|
|
446
|
+
* console.log(await result.toArray()); // [2, 1, 0, 1, 2]
|
|
447
|
+
* ```
|
|
448
|
+
*
|
|
449
|
+
* ---
|
|
450
|
+
*
|
|
451
|
+
* @template V The type of the elements after the transformation.
|
|
452
|
+
*
|
|
453
|
+
* @param iteratee The transformation function to apply to each element of the iterator.
|
|
454
|
+
*
|
|
455
|
+
* @returns A new {@link SmartAsyncIterator} containing the transformed elements.
|
|
456
|
+
*/
|
|
146
457
|
public map<V>(iteratee: MaybeAsyncIteratee<T, V>): SmartAsyncIterator<V, R>
|
|
147
458
|
{
|
|
148
459
|
const iterator = this._iterator;
|
|
@@ -150,7 +461,6 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
150
461
|
return new SmartAsyncIterator<V, R>(async function* ()
|
|
151
462
|
{
|
|
152
463
|
let index = 0;
|
|
153
|
-
|
|
154
464
|
while (true)
|
|
155
465
|
{
|
|
156
466
|
const result = await iterator.next();
|
|
@@ -162,7 +472,70 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
162
472
|
}
|
|
163
473
|
});
|
|
164
474
|
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Reduces the elements of the iterator using a given reducer function.
|
|
478
|
+
* This method will consume the entire iterator in the process.
|
|
479
|
+
*
|
|
480
|
+
* It will iterate over all elements of the iterator applying the reducer function.
|
|
481
|
+
* The result of each iteration will be passed as the accumulator to the next one.
|
|
482
|
+
*
|
|
483
|
+
* The first accumulator value will be the first element of the iterator.
|
|
484
|
+
* The last accumulator value will be the final result of the reduction.
|
|
485
|
+
*
|
|
486
|
+
* Also note that:
|
|
487
|
+
* - If an empty iterator is provided, a {@link ValueException} will be thrown.
|
|
488
|
+
* - If the iterator is infinite, the method will never return.
|
|
489
|
+
*
|
|
490
|
+
* ---
|
|
491
|
+
*
|
|
492
|
+
* @example
|
|
493
|
+
* ```ts
|
|
494
|
+
* const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);
|
|
495
|
+
* const result = await iterator.reduce(async (acc, value) => acc + value);
|
|
496
|
+
*
|
|
497
|
+
* console.log(result); // 15
|
|
498
|
+
* ```
|
|
499
|
+
*
|
|
500
|
+
* ---
|
|
501
|
+
*
|
|
502
|
+
* @param reducer The reducer function to apply to each element of the iterator.
|
|
503
|
+
*
|
|
504
|
+
* @returns A {@link Promise} that will resolve to the final result of the reduction.
|
|
505
|
+
*/
|
|
165
506
|
public async reduce(reducer: MaybeAsyncReducer<T, T>): Promise<T>;
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Reduces the elements of the iterator using a given reducer function.
|
|
510
|
+
* This method will consume the entire iterator in the process.
|
|
511
|
+
*
|
|
512
|
+
* It will iterate over all elements of the iterator applying the reducer function.
|
|
513
|
+
* The result of each iteration will be passed as the accumulator to the next one.
|
|
514
|
+
*
|
|
515
|
+
* The first accumulator value will be the provided initial value.
|
|
516
|
+
* The last accumulator value will be the final result of the reduction.
|
|
517
|
+
*
|
|
518
|
+
* If the iterator is infinite, the method will never return.
|
|
519
|
+
*
|
|
520
|
+
* ---
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* ```ts
|
|
524
|
+
* const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);
|
|
525
|
+
* const result = await iterator.reduce(async (acc, value) => acc + value, 10);
|
|
526
|
+
*
|
|
527
|
+
* console.log(result); // 25
|
|
528
|
+
* ```
|
|
529
|
+
*
|
|
530
|
+
* ---
|
|
531
|
+
*
|
|
532
|
+
* @template A The type of the accumulator value which will also be the type of the final result of the reduction.
|
|
533
|
+
*
|
|
534
|
+
* @param reducer The reducer function to apply to each element of the iterator.
|
|
535
|
+
* @param initialValue The initial value of the accumulator.
|
|
536
|
+
*
|
|
537
|
+
* @returns A {@link Promise} that will resolve to the final result of the reduction.
|
|
538
|
+
*/
|
|
166
539
|
public async reduce<A>(reducer: MaybeAsyncReducer<T, A>, initialValue: A): Promise<A>;
|
|
167
540
|
public async reduce<A>(reducer: MaybeAsyncReducer<T, A>, initialValue?: A): Promise<A>
|
|
168
541
|
{
|
|
@@ -188,31 +561,92 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
188
561
|
}
|
|
189
562
|
}
|
|
190
563
|
|
|
191
|
-
|
|
564
|
+
/**
|
|
565
|
+
* Flattens the elements of the iterator using a given transformation function.
|
|
566
|
+
*
|
|
567
|
+
* This method will iterate over all elements of the iterator applying the transformation function.
|
|
568
|
+
* The result of each transformation will be flattened and included in the new iterator.
|
|
569
|
+
*
|
|
570
|
+
* Since the iterator is lazy, the flattening process will
|
|
571
|
+
* be executed once the resulting iterator is materialized.
|
|
572
|
+
*
|
|
573
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
574
|
+
* This means that the original iterator won't be consumed until the
|
|
575
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
576
|
+
*
|
|
577
|
+
* ---
|
|
578
|
+
*
|
|
579
|
+
* @example
|
|
580
|
+
* ```ts
|
|
581
|
+
* const iterator = new SmartAsyncIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);
|
|
582
|
+
* const result = iterator.flatMap(async (value) => value);
|
|
583
|
+
*
|
|
584
|
+
* console.log(await result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]
|
|
585
|
+
* ```
|
|
586
|
+
*
|
|
587
|
+
* ---
|
|
588
|
+
*
|
|
589
|
+
* @template V The type of the elements after the transformation.
|
|
590
|
+
*
|
|
591
|
+
* @param iteratee The transformation function to apply to each element of the iterator.
|
|
592
|
+
*
|
|
593
|
+
* @returns A new {@link SmartAsyncIterator} containing the flattened elements.
|
|
594
|
+
*/
|
|
595
|
+
public flatMap<V>(iteratee: MaybeAsyncIteratee<T, V | readonly V[]>): SmartAsyncIterator<V, R>
|
|
192
596
|
{
|
|
193
597
|
const iterator = this._iterator;
|
|
194
598
|
|
|
195
599
|
return new SmartAsyncIterator<V, R>(async function* ()
|
|
196
600
|
{
|
|
197
601
|
let index = 0;
|
|
198
|
-
|
|
199
602
|
while (true)
|
|
200
603
|
{
|
|
201
604
|
const result = await iterator.next();
|
|
202
605
|
if (result.done) { return result.value; }
|
|
203
606
|
|
|
204
607
|
const elements = await iteratee(result.value, index);
|
|
205
|
-
|
|
206
|
-
for await (const element of elements)
|
|
608
|
+
if (elements instanceof Array)
|
|
207
609
|
{
|
|
208
|
-
yield
|
|
610
|
+
for (const value of elements) { yield value; }
|
|
209
611
|
}
|
|
612
|
+
else { yield elements; }
|
|
210
613
|
|
|
211
614
|
index += 1;
|
|
212
615
|
}
|
|
213
616
|
});
|
|
214
617
|
}
|
|
215
618
|
|
|
619
|
+
/**
|
|
620
|
+
* Drops a given number of elements at the beginning of the iterator.
|
|
621
|
+
* The remaining elements will be included in a new iterator.
|
|
622
|
+
* See also {@link SmartAsyncIterator.take}.
|
|
623
|
+
*
|
|
624
|
+
* Since the iterator is lazy, the dropping process will
|
|
625
|
+
* be executed once the resulting iterator is materialized.
|
|
626
|
+
*
|
|
627
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
628
|
+
* This means that the original iterator won't be consumed until the
|
|
629
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
630
|
+
*
|
|
631
|
+
* Only the dropped elements will be consumed in the process.
|
|
632
|
+
* The rest of the iterator will be consumed only once the new one is.
|
|
633
|
+
*
|
|
634
|
+
* ---
|
|
635
|
+
*
|
|
636
|
+
* @example
|
|
637
|
+
* ```ts
|
|
638
|
+
* const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
|
|
639
|
+
* const result = iterator.drop(3);
|
|
640
|
+
*
|
|
641
|
+
* console.log(await result.toArray()); // [1, 2]
|
|
642
|
+
* ```
|
|
643
|
+
*
|
|
644
|
+
* ---
|
|
645
|
+
*
|
|
646
|
+
* @param count The number of elements to drop.
|
|
647
|
+
*
|
|
648
|
+
* @returns A new {@link SmartAsyncIterator} containing the remaining elements.
|
|
649
|
+
*/
|
|
216
650
|
public drop(count: number): SmartAsyncIterator<T, R | undefined>
|
|
217
651
|
{
|
|
218
652
|
const iterator = this._iterator;
|
|
@@ -220,7 +654,6 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
220
654
|
return new SmartAsyncIterator<T, R | undefined>(async function* ()
|
|
221
655
|
{
|
|
222
656
|
let index = 0;
|
|
223
|
-
|
|
224
657
|
while (index < count)
|
|
225
658
|
{
|
|
226
659
|
const result = await iterator.next();
|
|
@@ -238,6 +671,39 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
238
671
|
}
|
|
239
672
|
});
|
|
240
673
|
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Takes a given number of elements at the beginning of the iterator.
|
|
677
|
+
* These elements will be included in a new iterator.
|
|
678
|
+
* See also {@link SmartAsyncIterator.drop}.
|
|
679
|
+
*
|
|
680
|
+
* Since the iterator is lazy, the taking process will
|
|
681
|
+
* be executed once the resulting iterator is materialized.
|
|
682
|
+
*
|
|
683
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
684
|
+
* This means that the original iterator won't be consumed until the
|
|
685
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
686
|
+
*
|
|
687
|
+
* Only the taken elements will be consumed from the original iterator.
|
|
688
|
+
* The rest of the original iterator will be available for further consumption.
|
|
689
|
+
*
|
|
690
|
+
* ---
|
|
691
|
+
*
|
|
692
|
+
* @example
|
|
693
|
+
* ```ts
|
|
694
|
+
* const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
|
|
695
|
+
* const result = iterator.take(3);
|
|
696
|
+
*
|
|
697
|
+
* console.log(await result.toArray()); // [-2, -1, 0]
|
|
698
|
+
* console.log(await iterator.toArray()); // [1, 2]
|
|
699
|
+
* ```
|
|
700
|
+
*
|
|
701
|
+
* ---
|
|
702
|
+
*
|
|
703
|
+
* @param limit The number of elements to take.
|
|
704
|
+
*
|
|
705
|
+
* @returns A new {@link SmartAsyncIterator} containing the taken elements.
|
|
706
|
+
*/
|
|
241
707
|
public take(limit: number): SmartAsyncIterator<T, R | undefined>
|
|
242
708
|
{
|
|
243
709
|
const iterator = this._iterator;
|
|
@@ -245,7 +711,6 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
245
711
|
return new SmartAsyncIterator<T, R | undefined>(async function* ()
|
|
246
712
|
{
|
|
247
713
|
let index = 0;
|
|
248
|
-
|
|
249
714
|
while (index < limit)
|
|
250
715
|
{
|
|
251
716
|
const result = await iterator.next();
|
|
@@ -260,6 +725,77 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
260
725
|
});
|
|
261
726
|
}
|
|
262
727
|
|
|
728
|
+
/**
|
|
729
|
+
* Finds the first element of the iterator that satisfies a given condition.
|
|
730
|
+
*
|
|
731
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
732
|
+
* The first element that satisfies the condition will be returned immediately.
|
|
733
|
+
*
|
|
734
|
+
* Only the elements that are necessary to find the first
|
|
735
|
+
* satisfying one will be consumed from the original iterator.
|
|
736
|
+
* The rest of the original iterator will be available for further consumption.
|
|
737
|
+
*
|
|
738
|
+
* Also note that:
|
|
739
|
+
* - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.
|
|
740
|
+
* - If the iterator is infinite and no element satisfies the condition, the method will never return.
|
|
741
|
+
*
|
|
742
|
+
* ---
|
|
743
|
+
*
|
|
744
|
+
* @example
|
|
745
|
+
* ```ts
|
|
746
|
+
* const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
|
|
747
|
+
* const result = await iterator.find(async (value) => value > 0);
|
|
748
|
+
*
|
|
749
|
+
* console.log(result); // 1
|
|
750
|
+
* ```
|
|
751
|
+
*
|
|
752
|
+
* ---
|
|
753
|
+
*
|
|
754
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
755
|
+
*
|
|
756
|
+
* @returns
|
|
757
|
+
* A {@link Promise} that will resolve to the first element that satisfies the condition, `undefined` otherwise.
|
|
758
|
+
*/
|
|
759
|
+
public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>;
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Finds the first element of the iterator that satisfies a given condition.
|
|
763
|
+
*
|
|
764
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
765
|
+
* The first element that satisfies the condition will be returned immediately.
|
|
766
|
+
*
|
|
767
|
+
* Only the elements that are necessary to find the first
|
|
768
|
+
* satisfying one will be consumed from the original iterator.
|
|
769
|
+
* The rest of the original iterator will be available for further consumption.
|
|
770
|
+
*
|
|
771
|
+
* Also note that:
|
|
772
|
+
* - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.
|
|
773
|
+
* - If the iterator is infinite and no element satisfies the condition, the method will never return.
|
|
774
|
+
*
|
|
775
|
+
* ---
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* ```ts
|
|
779
|
+
* const iterator = new SmartAsyncIterator<number | string>([-2, "-1", "0", 1, "2"]);
|
|
780
|
+
* const result = await iterator.find<number>(async (value) => typeof value === "number");
|
|
781
|
+
*
|
|
782
|
+
* console.log(result); // -2
|
|
783
|
+
* ```
|
|
784
|
+
*
|
|
785
|
+
* ---
|
|
786
|
+
*
|
|
787
|
+
* @template S
|
|
788
|
+
* The type of the element that satisfies the condition.
|
|
789
|
+
* This allows the type-system to infer the correct type of the result.
|
|
790
|
+
*
|
|
791
|
+
* It must be a subtype of the original type of the elements.
|
|
792
|
+
*
|
|
793
|
+
* @param predicate The type guard condition to check for each element of the iterator.
|
|
794
|
+
*
|
|
795
|
+
* @returns
|
|
796
|
+
* A {@link Promise} that will resolve to the first element that satisfies the condition, `undefined` otherwise.
|
|
797
|
+
*/
|
|
798
|
+
public async find<S extends T>(predicate: MaybeAsyncIteratee<T, boolean>): Promise<S | undefined>;
|
|
263
799
|
public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>
|
|
264
800
|
{
|
|
265
801
|
let index = 0;
|
|
@@ -275,10 +811,64 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
275
811
|
}
|
|
276
812
|
}
|
|
277
813
|
|
|
814
|
+
/**
|
|
815
|
+
* Enumerates the elements of the iterator.
|
|
816
|
+
* Each element is be paired with its index in a new iterator.
|
|
817
|
+
*
|
|
818
|
+
* Since the iterator is lazy, the enumeration process will
|
|
819
|
+
* be executed once the resulting iterator is materialized.
|
|
820
|
+
*
|
|
821
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
822
|
+
* This means that the original iterator won't be consumed until the
|
|
823
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
824
|
+
*
|
|
825
|
+
* ---
|
|
826
|
+
*
|
|
827
|
+
* @example
|
|
828
|
+
* ```ts
|
|
829
|
+
* const iterator = new SmartAsyncIterator<string>(["A", "M", "N", "Z"]);
|
|
830
|
+
* const result = iterator.enumerate();
|
|
831
|
+
*
|
|
832
|
+
* for await (const [index, value] of result)
|
|
833
|
+
* {
|
|
834
|
+
* console.log(`${index}: ${value}`); // "0: A", "1: M", "2: N", "3: Z"
|
|
835
|
+
* }
|
|
836
|
+
* ```
|
|
837
|
+
*
|
|
838
|
+
* ---
|
|
839
|
+
*
|
|
840
|
+
* @returns A new {@link SmartAsyncIterator} containing the enumerated elements.
|
|
841
|
+
*/
|
|
278
842
|
public enumerate(): SmartAsyncIterator<[number, T], R>
|
|
279
843
|
{
|
|
280
844
|
return this.map((value, index) => [index, value]);
|
|
281
845
|
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Removes all duplicate elements from the iterator.
|
|
849
|
+
* The first occurrence of each element will be kept.
|
|
850
|
+
*
|
|
851
|
+
* Since the iterator is lazy, the deduplication process will
|
|
852
|
+
* be executed once the resulting iterator is materialized.
|
|
853
|
+
*
|
|
854
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
855
|
+
* This means that the original iterator won't be consumed until the
|
|
856
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
857
|
+
*
|
|
858
|
+
* ---
|
|
859
|
+
*
|
|
860
|
+
* @example
|
|
861
|
+
* ```ts
|
|
862
|
+
* const iterator = new SmartAsyncIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);
|
|
863
|
+
* const result = iterator.unique();
|
|
864
|
+
*
|
|
865
|
+
* console.log(await result.toArray()); // [1, 2, 3, 4, 5]
|
|
866
|
+
* ```
|
|
867
|
+
*
|
|
868
|
+
* ---
|
|
869
|
+
*
|
|
870
|
+
* @returns A new {@link SmartAsyncIterator} containing only the unique elements.
|
|
871
|
+
*/
|
|
282
872
|
public unique(): SmartAsyncIterator<T, R>
|
|
283
873
|
{
|
|
284
874
|
const iterator = this._iterator;
|
|
@@ -286,11 +876,9 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
286
876
|
return new SmartAsyncIterator<T, R>(async function* ()
|
|
287
877
|
{
|
|
288
878
|
const values = new Set<T>();
|
|
289
|
-
|
|
290
879
|
while (true)
|
|
291
880
|
{
|
|
292
881
|
const result = await iterator.next();
|
|
293
|
-
|
|
294
882
|
if (result.done) { return result.value; }
|
|
295
883
|
if (values.has(result.value)) { continue; }
|
|
296
884
|
|
|
@@ -301,6 +889,26 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
301
889
|
});
|
|
302
890
|
}
|
|
303
891
|
|
|
892
|
+
/**
|
|
893
|
+
* Counts the number of elements in the iterator.
|
|
894
|
+
* This method will consume the entire iterator in the process.
|
|
895
|
+
*
|
|
896
|
+
* If the iterator is infinite, the method will never return.
|
|
897
|
+
*
|
|
898
|
+
* ---
|
|
899
|
+
*
|
|
900
|
+
* @example
|
|
901
|
+
* ```ts
|
|
902
|
+
* const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);
|
|
903
|
+
* const result = await iterator.count();
|
|
904
|
+
*
|
|
905
|
+
* console.log(result); // 5
|
|
906
|
+
* ```
|
|
907
|
+
*
|
|
908
|
+
* ---
|
|
909
|
+
*
|
|
910
|
+
* @returns A {@link Promise} that will resolve to the number of elements in the iterator.
|
|
911
|
+
*/
|
|
304
912
|
public async count(): Promise<number>
|
|
305
913
|
{
|
|
306
914
|
let index = 0;
|
|
@@ -313,6 +921,31 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
313
921
|
index += 1;
|
|
314
922
|
}
|
|
315
923
|
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Iterates over all elements of the iterator.
|
|
927
|
+
* The elements are passed to the function along with their index.
|
|
928
|
+
*
|
|
929
|
+
* This method will consume the entire iterator in the process.
|
|
930
|
+
* If the iterator is infinite, the method will never return.
|
|
931
|
+
*
|
|
932
|
+
* ---
|
|
933
|
+
*
|
|
934
|
+
* @example
|
|
935
|
+
* ```ts
|
|
936
|
+
* const iterator = new SmartAsyncIterator<number>(["A", "M", "N", "Z"]);
|
|
937
|
+
* await iterator.forEach(async (value, index) =>
|
|
938
|
+
* {
|
|
939
|
+
* console.log(`${index}: ${value}`); // "0: A", "1: M", "2: N", "3: Z"
|
|
940
|
+
* }
|
|
941
|
+
* ```
|
|
942
|
+
*
|
|
943
|
+
* ---
|
|
944
|
+
*
|
|
945
|
+
* @param iteratee The function to apply to each element of the iterator.
|
|
946
|
+
*
|
|
947
|
+
* @returns A {@link Promise} that will resolve once the iteration is complete.
|
|
948
|
+
*/
|
|
316
949
|
public async forEach(iteratee: MaybeAsyncIteratee<T>): Promise<void>
|
|
317
950
|
{
|
|
318
951
|
let index = 0;
|
|
@@ -328,11 +961,160 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
328
961
|
}
|
|
329
962
|
}
|
|
330
963
|
|
|
964
|
+
/**
|
|
965
|
+
* Advances the iterator to the next element and returns the result.
|
|
966
|
+
* If the iterator requires it, a value must be provided to be passed to the next element.
|
|
967
|
+
*
|
|
968
|
+
* Once the iterator is done, the method will return an object with the `done` property set to `true`.
|
|
969
|
+
*
|
|
970
|
+
* ---
|
|
971
|
+
*
|
|
972
|
+
* @example
|
|
973
|
+
* ```ts
|
|
974
|
+
* const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);
|
|
975
|
+
*
|
|
976
|
+
* let result = await iterator.next();
|
|
977
|
+
* while (!result.done)
|
|
978
|
+
* {
|
|
979
|
+
* console.log(result.value); // 1, 2, 3, 4, 5
|
|
980
|
+
*
|
|
981
|
+
* result = await iterator.next();
|
|
982
|
+
* }
|
|
983
|
+
*
|
|
984
|
+
* console.log(result); // { done: true, value: undefined }
|
|
985
|
+
* ```
|
|
986
|
+
*
|
|
987
|
+
* ---
|
|
988
|
+
*
|
|
989
|
+
* @param values The value to pass to the next element, if required.
|
|
990
|
+
*
|
|
991
|
+
* @returns
|
|
992
|
+
* A {@link Promise} that will resolve to the result of the iteration, containing the value of the operation.
|
|
993
|
+
*/
|
|
331
994
|
public next(...values: N extends undefined ? [] : [N]): Promise<IteratorResult<T, R>>
|
|
332
995
|
{
|
|
333
996
|
return this._iterator.next(...values);
|
|
334
997
|
}
|
|
335
998
|
|
|
999
|
+
/**
|
|
1000
|
+
* An utility method that may be used to close the iterator gracefully,
|
|
1001
|
+
* free the resources and perform any cleanup operation.
|
|
1002
|
+
* It may also be used to signal the end or to compute a specific final result of the iteration process.
|
|
1003
|
+
*
|
|
1004
|
+
* ---
|
|
1005
|
+
*
|
|
1006
|
+
* @example
|
|
1007
|
+
* ```ts
|
|
1008
|
+
* const iterator = new SmartAsyncIterator<number>({
|
|
1009
|
+
* _index: 0,
|
|
1010
|
+
* next: async function()
|
|
1011
|
+
* {
|
|
1012
|
+
* return { done: false, value: this._index += 1 };
|
|
1013
|
+
* },
|
|
1014
|
+
* return: async function() { console.log("Closing the iterator..."); }
|
|
1015
|
+
* });
|
|
1016
|
+
*
|
|
1017
|
+
* for await (const value of iterator)
|
|
1018
|
+
* {
|
|
1019
|
+
* if (value > 5) { break; } // Closing the iterator...
|
|
1020
|
+
*
|
|
1021
|
+
* console.log(value); // 1, 2, 3, 4, 5
|
|
1022
|
+
* }
|
|
1023
|
+
* ```
|
|
1024
|
+
*
|
|
1025
|
+
* ---
|
|
1026
|
+
*
|
|
1027
|
+
* @param value The final value of the iterator.
|
|
1028
|
+
*
|
|
1029
|
+
* @returns A {@link Promise} that will resolve to the final result of the iterator.
|
|
1030
|
+
*/
|
|
1031
|
+
public async return(value?: MaybePromise<R>): Promise<IteratorResult<T, R>>
|
|
1032
|
+
{
|
|
1033
|
+
const _value = (await value) as R;
|
|
1034
|
+
|
|
1035
|
+
if (this._iterator.return) { return await this._iterator.return(_value); }
|
|
1036
|
+
|
|
1037
|
+
return { done: true, value: _value };
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* An utility method that may be used to close the iterator due to an error,
|
|
1042
|
+
* free the resources and perform any cleanup operation.
|
|
1043
|
+
* It may also be used to signal that an error occurred during the iteration process or to handle it.
|
|
1044
|
+
*
|
|
1045
|
+
* ---
|
|
1046
|
+
*
|
|
1047
|
+
* @example
|
|
1048
|
+
* ```ts
|
|
1049
|
+
* const iterator = new SmartAsyncIterator<number>({
|
|
1050
|
+
* _index: 0,
|
|
1051
|
+
* next: async function()
|
|
1052
|
+
* {
|
|
1053
|
+
* return { done: this._index > 10, value: this._index += 1 };
|
|
1054
|
+
* },
|
|
1055
|
+
* throw: async function(error)
|
|
1056
|
+
* {
|
|
1057
|
+
* console.warn(error.message);
|
|
1058
|
+
*
|
|
1059
|
+
* this._index = 0;
|
|
1060
|
+
* }
|
|
1061
|
+
* });
|
|
1062
|
+
*
|
|
1063
|
+
* for await (const value of iterator) // 1, 2, 3, 4, 5, "The index is too high.", 1, 2, 3, 4, 5, ...
|
|
1064
|
+
* {
|
|
1065
|
+
* try
|
|
1066
|
+
* {
|
|
1067
|
+
* if (value > 5) { throw new Error("The index is too high."); }
|
|
1068
|
+
*
|
|
1069
|
+
* console.log(value); // 1, 2, 3, 4, 5
|
|
1070
|
+
* }
|
|
1071
|
+
* catch (error) { await iterator.throw(error); }
|
|
1072
|
+
* }
|
|
1073
|
+
* ```
|
|
1074
|
+
*
|
|
1075
|
+
* ---
|
|
1076
|
+
*
|
|
1077
|
+
* @param error The error to throw into the iterator.
|
|
1078
|
+
*
|
|
1079
|
+
* @returns A {@link Promise} that will resolve to the final result of the iterator.
|
|
1080
|
+
*/
|
|
1081
|
+
public throw(error: unknown): Promise<IteratorResult<T, R>>
|
|
1082
|
+
{
|
|
1083
|
+
if (this._iterator.throw) { return this._iterator.throw(error); }
|
|
1084
|
+
|
|
1085
|
+
throw error;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* An utility method that aggregates the elements of the iterator using a given key function.
|
|
1090
|
+
* The elements will be grouped by the resulting keys in a new specialized iterator.
|
|
1091
|
+
* See {@link AggregatedAsyncIterator}.
|
|
1092
|
+
*
|
|
1093
|
+
* Since the iterator is lazy, the grouping process will
|
|
1094
|
+
* be executed once the resulting iterator is materialized.
|
|
1095
|
+
*
|
|
1096
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
1097
|
+
* This means that the original iterator won't be consumed until the
|
|
1098
|
+
* the new one is and that consuming one of them will consume the other as well.
|
|
1099
|
+
*
|
|
1100
|
+
* ---
|
|
1101
|
+
*
|
|
1102
|
+
* @example
|
|
1103
|
+
* ```ts
|
|
1104
|
+
* const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
|
1105
|
+
* const result = iterator.groupBy<string>(async (value) => value % 2 === 0 ? "even" : "odd");
|
|
1106
|
+
*
|
|
1107
|
+
* console.log(await result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }
|
|
1108
|
+
* ```
|
|
1109
|
+
*
|
|
1110
|
+
* ---
|
|
1111
|
+
*
|
|
1112
|
+
* @template K The type of the keys used to group the elements.
|
|
1113
|
+
*
|
|
1114
|
+
* @param iteratee The key function to apply to each element of the iterator.
|
|
1115
|
+
*
|
|
1116
|
+
* @returns A new instance of the {@link AggregatedAsyncIterator} class containing the grouped elements.
|
|
1117
|
+
*/
|
|
336
1118
|
public groupBy<K extends PropertyKey>(iteratee: MaybeAsyncIteratee<T, K>): AggregatedAsyncIterator<K, T>
|
|
337
1119
|
{
|
|
338
1120
|
return new AggregatedAsyncIterator(this.map(async (element, index) =>
|
|
@@ -343,6 +1125,29 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
|
|
|
343
1125
|
}));
|
|
344
1126
|
}
|
|
345
1127
|
|
|
1128
|
+
/**
|
|
1129
|
+
* Materializes the iterator into an array.
|
|
1130
|
+
* This method will consume the entire iterator in the process.
|
|
1131
|
+
*
|
|
1132
|
+
* If the iterator is infinite, the method will never return.
|
|
1133
|
+
*
|
|
1134
|
+
* ---
|
|
1135
|
+
*
|
|
1136
|
+
* @example
|
|
1137
|
+
* ```ts
|
|
1138
|
+
* const iterator = new SmartAsyncIterator(async function* ()
|
|
1139
|
+
* {
|
|
1140
|
+
* for (let i = 0; i < 5; i += 1) { yield i; }
|
|
1141
|
+
* });
|
|
1142
|
+
* const result = await iterator.toArray();
|
|
1143
|
+
*
|
|
1144
|
+
* console.log(result); // [0, 1, 2, 3, 4]
|
|
1145
|
+
* ```
|
|
1146
|
+
*
|
|
1147
|
+
* ---
|
|
1148
|
+
*
|
|
1149
|
+
* @returns A {@link Promise} that will resolve to an array containing all elements of the iterator.
|
|
1150
|
+
*/
|
|
346
1151
|
public toArray(): Promise<T[]>
|
|
347
1152
|
{
|
|
348
1153
|
return Array.fromAsync(this as AsyncIterable<T>);
|