@byloth/core 2.0.0-rc.9 → 2.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.
- package/dist/core.js +3371 -608
- 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 +13 -10
- 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 +765 -21
- package/src/models/aggregators/aggregated-iterator.ts +698 -22
- package/src/models/aggregators/reduced-iterator.ts +699 -10
- 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 +139 -4
- package/src/models/callbacks/switchable-callback.ts +138 -4
- package/src/models/callbacks/types.ts +16 -0
- package/src/models/exceptions/core.ts +112 -3
- package/src/models/exceptions/index.ts +340 -13
- package/src/models/index.ts +4 -8
- package/src/models/iterators/smart-async-iterator.ts +687 -22
- package/src/models/iterators/smart-iterator.ts +631 -21
- package/src/models/iterators/types.ts +268 -9
- package/src/models/json/json-storage.ts +388 -110
- package/src/models/json/types.ts +10 -1
- package/src/models/promises/deferred-promise.ts +75 -5
- package/src/models/promises/index.ts +1 -3
- package/src/models/promises/smart-promise.ts +232 -4
- package/src/models/promises/timed-promise.ts +38 -1
- package/src/models/promises/types.ts +84 -2
- package/src/models/timers/clock.ts +91 -19
- package/src/models/timers/countdown.ts +152 -22
- package/src/models/timers/game-loop.ts +243 -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 +75 -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 +109 -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,18 +1,99 @@
|
|
|
1
1
|
import AggregatedIterator from "../aggregators/aggregated-iterator.js";
|
|
2
2
|
import { ValueException } from "../exceptions/index.js";
|
|
3
3
|
|
|
4
|
-
import type { GeneratorFunction, Iteratee,
|
|
5
|
-
|
|
4
|
+
import type { GeneratorFunction, Iteratee, TypeGuardPredicate, Reducer, IteratorLike } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A wrapper class representing an enhanced and instantiable version
|
|
8
|
+
* of the native {@link Iterable} & {@link Iterator} interfaces.
|
|
9
|
+
*
|
|
10
|
+
* It provides a set of utility methods to better manipulate and
|
|
11
|
+
* transform iterators in a functional and highly performant way.
|
|
12
|
+
* It takes inspiration from the native {@link Array} methods like
|
|
13
|
+
* {@link Array.map}, {@link Array.filter}, {@link Array.reduce}, etc...
|
|
14
|
+
*
|
|
15
|
+
* The class is lazy, meaning that the transformations are applied
|
|
16
|
+
* only when the resulting iterator is materialized, not before.
|
|
17
|
+
* This allows to chain multiple transformations without
|
|
18
|
+
* the need to iterate over the elements multiple times.
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* const result = new SmartIterator<number>(["-5", "-4", "-3", "-2", "-1", "0", "1", "2", "3", "4", "5"])
|
|
22
|
+
* .map(Number)
|
|
23
|
+
* .map((value) => value + Math.ceil(Math.abs(value / 2)))
|
|
24
|
+
* .filter((value) => value >= 0)
|
|
25
|
+
* .map((value) => value + 1)
|
|
26
|
+
* .reduce((acc, value) => acc + value);
|
|
27
|
+
*
|
|
28
|
+
* console.log(result); // 31
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @template T The type of elements in the iterator.
|
|
32
|
+
* @template R The type of the final result of the iterator. Default is `void`.
|
|
33
|
+
* @template N The type of the argument required by the `next` method. Default is `undefined`.
|
|
34
|
+
*/
|
|
6
35
|
export default class SmartIterator<T, R = void, N = undefined> implements Iterator<T, R, N>
|
|
7
36
|
{
|
|
37
|
+
/**
|
|
38
|
+
* The native {@link Iterator} object that is being wrapped by this instance.
|
|
39
|
+
*/
|
|
8
40
|
protected _iterator: Iterator<T, R, N>;
|
|
9
41
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Initializes a new instance of the {@link SmartIterator} class.
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const iterator = new SmartIterator<string>(["A", "B", "C"]);
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @param iterable The iterable object to wrap.
|
|
50
|
+
*/
|
|
13
51
|
public constructor(iterable: Iterable<T, R, N>);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Initializes a new instance of the {@link SmartIterator} class.
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* const iterator = new SmartIterator<number, void, number>({
|
|
58
|
+
* _sum: 0, _count: 0,
|
|
59
|
+
*
|
|
60
|
+
* next: function(value: number)
|
|
61
|
+
* {
|
|
62
|
+
* this._sum += value;
|
|
63
|
+
* this._count += 1;
|
|
64
|
+
*
|
|
65
|
+
* return { done: false, value: this._sum / this._count };
|
|
66
|
+
* }
|
|
67
|
+
* })
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @param iterator The iterator object to wrap.
|
|
71
|
+
*/
|
|
14
72
|
public constructor(iterator: Iterator<T, R, N>);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Initializes a new instance of the {@link SmartIterator} class.
|
|
76
|
+
*
|
|
77
|
+
* ```ts
|
|
78
|
+
* const iterator = new SmartIterator<number>(function* ()
|
|
79
|
+
* {
|
|
80
|
+
* for (let i = 2; i < 65_536; i *= 2) { yield (i - 1); }
|
|
81
|
+
* });
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @param generatorFn The generator function to wrap.
|
|
85
|
+
*/
|
|
15
86
|
public constructor(generatorFn: GeneratorFunction<T, R, N>);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Initializes a new instance of the {@link SmartIterator} class.
|
|
90
|
+
*
|
|
91
|
+
* ```ts
|
|
92
|
+
* const iterator = new SmartIterator(values);
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @param argument The iterable, iterator or generator function to wrap.
|
|
96
|
+
*/
|
|
16
97
|
public constructor(argument: IteratorLike<T, R, N> | GeneratorFunction<T, R, N>);
|
|
17
98
|
public constructor(argument: IteratorLike<T, R, N> | GeneratorFunction<T, R, N>)
|
|
18
99
|
{
|
|
@@ -28,11 +109,32 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
28
109
|
{
|
|
29
110
|
this._iterator = argument;
|
|
30
111
|
}
|
|
31
|
-
|
|
32
|
-
if (this._iterator.return) { this.return = (value) => this._iterator.return!(value); }
|
|
33
|
-
if (this._iterator.throw) { this.throw = (error) => this._iterator.throw!(error); }
|
|
34
112
|
}
|
|
35
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Determines whether all elements of the iterator satisfy a given condition.
|
|
116
|
+
* See also {@link SmartIterator.some}.
|
|
117
|
+
*
|
|
118
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
119
|
+
* Once a single element doesn't satisfy the condition, the method will return `false` immediately.
|
|
120
|
+
*
|
|
121
|
+
* This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
|
|
122
|
+
* For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
|
|
123
|
+
* Consider using {@link SmartIterator.find} instead.
|
|
124
|
+
*
|
|
125
|
+
* If the iterator is infinite and every element satisfies the condition, the method will never return.
|
|
126
|
+
*
|
|
127
|
+
* ```ts
|
|
128
|
+
* const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
|
|
129
|
+
* const result = iterator.every((value) => value < 0);
|
|
130
|
+
*
|
|
131
|
+
* console.log(result); // false
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
135
|
+
*
|
|
136
|
+
* @returns `true` if all elements satisfy the condition, `false` otherwise.
|
|
137
|
+
*/
|
|
36
138
|
public every(predicate: Iteratee<T, boolean>): boolean
|
|
37
139
|
{
|
|
38
140
|
let index = 0;
|
|
@@ -47,6 +149,31 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
47
149
|
index += 1;
|
|
48
150
|
}
|
|
49
151
|
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Determines whether any element of the iterator satisfies a given condition.
|
|
155
|
+
* See also {@link SmartIterator.every}.
|
|
156
|
+
*
|
|
157
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
158
|
+
* Once a single element satisfies the condition, the method will return `true` immediately.
|
|
159
|
+
*
|
|
160
|
+
* This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
|
|
161
|
+
* For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
|
|
162
|
+
* Consider using {@link SmartIterator.find} instead.
|
|
163
|
+
*
|
|
164
|
+
* If the iterator is infinite and no element satisfies the condition, the method will never return.
|
|
165
|
+
*
|
|
166
|
+
* ```ts
|
|
167
|
+
* const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
|
|
168
|
+
* const result = iterator.some((value) => value < 0);
|
|
169
|
+
*
|
|
170
|
+
* console.log(result); // true
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
174
|
+
*
|
|
175
|
+
* @returns `true` if any element satisfies the condition, `false` otherwise.
|
|
176
|
+
*/
|
|
50
177
|
public some(predicate: Iteratee<T, boolean>): boolean
|
|
51
178
|
{
|
|
52
179
|
let index = 0;
|
|
@@ -62,8 +189,63 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
62
189
|
}
|
|
63
190
|
}
|
|
64
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Filters the elements of the iterator using a given condition.
|
|
194
|
+
*
|
|
195
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
196
|
+
* If the condition is met, the element will be included in the new iterator.
|
|
197
|
+
*
|
|
198
|
+
* Since the iterator is lazy, the filtering process will
|
|
199
|
+
* be executed once the resulting iterator is materialized.
|
|
200
|
+
*
|
|
201
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
202
|
+
* This means that the original iterator won't be consumed until the
|
|
203
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
204
|
+
*
|
|
205
|
+
* ```ts
|
|
206
|
+
* const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
|
|
207
|
+
* const result = iterator.filter((value) => value < 0);
|
|
208
|
+
*
|
|
209
|
+
* console.log(result.toArray()); // [-2, -1]
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
213
|
+
*
|
|
214
|
+
* @returns A new {@link SmartIterator} containing only the elements that satisfy the condition.
|
|
215
|
+
*/
|
|
65
216
|
public filter(predicate: Iteratee<T, boolean>): SmartIterator<T, R>;
|
|
66
|
-
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Filters the elements of the iterator using a given condition.
|
|
220
|
+
*
|
|
221
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
222
|
+
* If the condition is met, the element will be included in the new iterator.
|
|
223
|
+
*
|
|
224
|
+
* Since the iterator is lazy, the filtering process will
|
|
225
|
+
* be executed once the resulting iterator is materialized.
|
|
226
|
+
*
|
|
227
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
228
|
+
* This means that the original iterator won't be consumed until the
|
|
229
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
230
|
+
*
|
|
231
|
+
* ```ts
|
|
232
|
+
* const iterator = new SmartIterator<number | string>([-2, "-1", "0", 1, "2"]);
|
|
233
|
+
* const result = iterator.filter<number>((value) => typeof value === "number");
|
|
234
|
+
*
|
|
235
|
+
* console.log(result.toArray()); // [-2, 1]
|
|
236
|
+
* ```
|
|
237
|
+
*
|
|
238
|
+
* @template S
|
|
239
|
+
* The type of the elements that satisfy the condition.
|
|
240
|
+
* This allows the type-system to infer the correct type of the new iterator.
|
|
241
|
+
*
|
|
242
|
+
* It must be a subtype of the original type of the elements.
|
|
243
|
+
*
|
|
244
|
+
* @param predicate The type guard condition to check for each element of the iterator.
|
|
245
|
+
*
|
|
246
|
+
* @returns A new {@link SmartIterator} containing only the elements that satisfy the condition.
|
|
247
|
+
*/
|
|
248
|
+
public filter<S extends T>(predicate: TypeGuardPredicate<T, S>): SmartIterator<S, R>;
|
|
67
249
|
public filter(predicate: Iteratee<T, boolean>): SmartIterator<T, R>
|
|
68
250
|
{
|
|
69
251
|
const iterator = this._iterator;
|
|
@@ -71,11 +253,9 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
71
253
|
return new SmartIterator<T, R>(function* ()
|
|
72
254
|
{
|
|
73
255
|
let index = 0;
|
|
74
|
-
|
|
75
256
|
while (true)
|
|
76
257
|
{
|
|
77
258
|
const result = iterator.next();
|
|
78
|
-
|
|
79
259
|
if (result.done) { return result.value; }
|
|
80
260
|
if (predicate(result.value, index)) { yield result.value; }
|
|
81
261
|
|
|
@@ -83,6 +263,33 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
83
263
|
}
|
|
84
264
|
});
|
|
85
265
|
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Maps the elements of the iterator using a given transformation function.
|
|
269
|
+
*
|
|
270
|
+
* This method will iterate over all elements of the iterator applying the transformation function.
|
|
271
|
+
* The result of each transformation will be included in the new iterator.
|
|
272
|
+
*
|
|
273
|
+
* Since the iterator is lazy, the mapping process will
|
|
274
|
+
* be executed once the resulting iterator is materialized.
|
|
275
|
+
*
|
|
276
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
277
|
+
* This means that the original iterator won't be consumed until the
|
|
278
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
279
|
+
*
|
|
280
|
+
* ```ts
|
|
281
|
+
* const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
|
|
282
|
+
* const result = iterator.map((value) => Math.abs(value));
|
|
283
|
+
*
|
|
284
|
+
* console.log(result.toArray()); // [2, 1, 0, 1, 2]
|
|
285
|
+
* ```
|
|
286
|
+
*
|
|
287
|
+
* @template V The type of the elements after the transformation.
|
|
288
|
+
*
|
|
289
|
+
* @param iteratee The transformation function to apply to each element of the iterator.
|
|
290
|
+
*
|
|
291
|
+
* @returns A new {@link SmartIterator} containing the transformed elements.
|
|
292
|
+
*/
|
|
86
293
|
public map<V>(iteratee: Iteratee<T, V>): SmartIterator<V, R>
|
|
87
294
|
{
|
|
88
295
|
const iterator = this._iterator;
|
|
@@ -90,7 +297,6 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
90
297
|
return new SmartIterator<V, R>(function* ()
|
|
91
298
|
{
|
|
92
299
|
let index = 0;
|
|
93
|
-
|
|
94
300
|
while (true)
|
|
95
301
|
{
|
|
96
302
|
const result = iterator.next();
|
|
@@ -102,7 +308,60 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
102
308
|
}
|
|
103
309
|
});
|
|
104
310
|
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Reduces the elements of the iterator using a given reducer function.
|
|
314
|
+
* This method will consume the entire iterator in the process.
|
|
315
|
+
*
|
|
316
|
+
* It will iterate over all elements of the iterator applying the reducer function.
|
|
317
|
+
* The result of each iteration will be passed as the accumulator to the next one.
|
|
318
|
+
*
|
|
319
|
+
* The first accumulator value will be the first element of the iterator.
|
|
320
|
+
* The last accumulator value will be the final result of the reduction.
|
|
321
|
+
*
|
|
322
|
+
* Also note that:
|
|
323
|
+
* - If an empty iterator is provided, a {@link ValueException} will be thrown.
|
|
324
|
+
* - If the iterator is infinite, the method will never return.
|
|
325
|
+
*
|
|
326
|
+
* ```ts
|
|
327
|
+
* const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);
|
|
328
|
+
* const result = iterator.reduce((acc, value) => acc + value);
|
|
329
|
+
*
|
|
330
|
+
* console.log(result); // 15
|
|
331
|
+
* ```
|
|
332
|
+
*
|
|
333
|
+
* @param reducer The reducer function to apply to each element of the iterator.
|
|
334
|
+
*
|
|
335
|
+
* @returns The final result of the reduction.
|
|
336
|
+
*/
|
|
105
337
|
public reduce(reducer: Reducer<T, T>): T;
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Reduces the elements of the iterator using a given reducer function.
|
|
341
|
+
* This method will consume the entire iterator in the process.
|
|
342
|
+
*
|
|
343
|
+
* It will iterate over all elements of the iterator applying the reducer function.
|
|
344
|
+
* The result of each iteration will be passed as the accumulator to the next one.
|
|
345
|
+
*
|
|
346
|
+
* The first accumulator value will be the provided initial value.
|
|
347
|
+
* The last accumulator value will be the final result of the reduction.
|
|
348
|
+
*
|
|
349
|
+
* If the iterator is infinite, the method will never return.
|
|
350
|
+
*
|
|
351
|
+
* ```ts
|
|
352
|
+
* const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);
|
|
353
|
+
* const result = iterator.reduce((acc, value) => acc + value, 10);
|
|
354
|
+
*
|
|
355
|
+
* console.log(result); // 25
|
|
356
|
+
* ```
|
|
357
|
+
*
|
|
358
|
+
* @template A The type of the accumulator value which will also be the type of the final result of the reduction.
|
|
359
|
+
*
|
|
360
|
+
* @param reducer The reducer function to apply to each element of the iterator.
|
|
361
|
+
* @param initialValue The initial value of the accumulator.
|
|
362
|
+
*
|
|
363
|
+
* @returns The final result of the reduction.
|
|
364
|
+
*/
|
|
106
365
|
public reduce<A>(reducer: Reducer<T, A>, initialValue: A): A;
|
|
107
366
|
public reduce<A>(reducer: Reducer<T, A>, initialValue?: A): A
|
|
108
367
|
{
|
|
@@ -128,30 +387,82 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
128
387
|
}
|
|
129
388
|
}
|
|
130
389
|
|
|
131
|
-
|
|
390
|
+
/**
|
|
391
|
+
* Flattens the elements of the iterator using a given transformation function.
|
|
392
|
+
*
|
|
393
|
+
* This method will iterate over all elements of the iterator applying the transformation function.
|
|
394
|
+
* The result of each transformation will be flattened into the new iterator.
|
|
395
|
+
*
|
|
396
|
+
* Since the iterator is lazy, the flattening process will
|
|
397
|
+
* be executed once the resulting iterator is materialized.
|
|
398
|
+
*
|
|
399
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
400
|
+
* This means that the original iterator won't be consumed until the
|
|
401
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
402
|
+
*
|
|
403
|
+
* ```ts
|
|
404
|
+
* const iterator = new SmartIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);
|
|
405
|
+
* const result = iterator.flatMap((value) => value);
|
|
406
|
+
*
|
|
407
|
+
* console.log(result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]
|
|
408
|
+
* ```
|
|
409
|
+
*
|
|
410
|
+
* @template V The type of the elements after the transformation.
|
|
411
|
+
*
|
|
412
|
+
* @param iteratee The transformation function to apply to each element of the iterator.
|
|
413
|
+
*
|
|
414
|
+
* @returns A new {@link SmartIterator} containing the flattened elements.
|
|
415
|
+
*/
|
|
416
|
+
public flatMap<V>(iteratee: Iteratee<T, V | readonly V[]>): SmartIterator<V, R>
|
|
132
417
|
{
|
|
133
418
|
const iterator = this._iterator;
|
|
134
419
|
|
|
135
420
|
return new SmartIterator<V, R>(function* ()
|
|
136
421
|
{
|
|
137
422
|
let index = 0;
|
|
138
|
-
|
|
139
423
|
while (true)
|
|
140
424
|
{
|
|
141
425
|
const result = iterator.next();
|
|
142
426
|
if (result.done) { return result.value; }
|
|
143
427
|
|
|
144
|
-
const
|
|
145
|
-
|
|
428
|
+
const elements = iteratee(result.value, index);
|
|
429
|
+
if (elements instanceof Array)
|
|
146
430
|
{
|
|
147
|
-
yield value;
|
|
431
|
+
for (const value of elements) { yield value; }
|
|
148
432
|
}
|
|
433
|
+
else { yield elements; }
|
|
149
434
|
|
|
150
435
|
index += 1;
|
|
151
436
|
}
|
|
152
437
|
});
|
|
153
438
|
}
|
|
154
439
|
|
|
440
|
+
/**
|
|
441
|
+
* Drops a given number of elements at the beginning of the iterator.
|
|
442
|
+
* The remaining elements will be included in a new iterator.
|
|
443
|
+
* See also {@link SmartIterator.take}.
|
|
444
|
+
*
|
|
445
|
+
* Since the iterator is lazy, the dropping process will
|
|
446
|
+
* be executed once the resulting iterator is materialized.
|
|
447
|
+
*
|
|
448
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
449
|
+
* This means that the original iterator won't be consumed until the
|
|
450
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
451
|
+
*
|
|
452
|
+
* Only the dropped elements will be consumed in the process.
|
|
453
|
+
* The rest of the iterator will be consumed only once the new one is.
|
|
454
|
+
*
|
|
455
|
+
* ```ts
|
|
456
|
+
* const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
|
|
457
|
+
* const result = iterator.drop(3);
|
|
458
|
+
*
|
|
459
|
+
* console.log(result.toArray()); // [1, 2]
|
|
460
|
+
* ```
|
|
461
|
+
*
|
|
462
|
+
* @param count The number of elements to drop.
|
|
463
|
+
*
|
|
464
|
+
* @returns A new {@link SmartIterator} containing the remaining elements.
|
|
465
|
+
*/
|
|
155
466
|
public drop(count: number): SmartIterator<T, R | undefined>
|
|
156
467
|
{
|
|
157
468
|
const iterator = this._iterator;
|
|
@@ -176,6 +487,34 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
176
487
|
}
|
|
177
488
|
});
|
|
178
489
|
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Takes a given number of elements at the beginning of the iterator.
|
|
493
|
+
* These elements will be included in a new iterator.
|
|
494
|
+
* See also {@link SmartIterator.drop}.
|
|
495
|
+
*
|
|
496
|
+
* Since the iterator is lazy, the taking process will
|
|
497
|
+
* be executed once the resulting iterator is materialized.
|
|
498
|
+
*
|
|
499
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
500
|
+
* This means that the original iterator won't be consumed until the
|
|
501
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
502
|
+
*
|
|
503
|
+
* Only the taken elements will be consumed from the original iterator.
|
|
504
|
+
* The rest of the original iterator will be available for further consumption.
|
|
505
|
+
*
|
|
506
|
+
* ```ts
|
|
507
|
+
* const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
|
|
508
|
+
* const result = iterator.take(3);
|
|
509
|
+
*
|
|
510
|
+
* console.log(result.toArray()); // [-2, -1, 0]
|
|
511
|
+
* console.log(iterator.toArray()); // [1, 2]
|
|
512
|
+
* ```
|
|
513
|
+
*
|
|
514
|
+
* @param limit The number of elements to take.
|
|
515
|
+
*
|
|
516
|
+
* @returns A new {@link SmartIterator} containing the taken elements.
|
|
517
|
+
*/
|
|
179
518
|
public take(limit: number): SmartIterator<T, R | undefined>
|
|
180
519
|
{
|
|
181
520
|
const iterator = this._iterator;
|
|
@@ -197,8 +536,65 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
197
536
|
});
|
|
198
537
|
}
|
|
199
538
|
|
|
539
|
+
/**
|
|
540
|
+
* Finds the first element of the iterator that satisfies a given condition.
|
|
541
|
+
*
|
|
542
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
543
|
+
* The first element that satisfies the condition will be returned immediately.
|
|
544
|
+
*
|
|
545
|
+
* Only the elements that are necessary to find the first
|
|
546
|
+
* satisfying one will be consumed from the original iterator.
|
|
547
|
+
* The rest of the original iterator will be available for further consumption.
|
|
548
|
+
*
|
|
549
|
+
* Also note that:
|
|
550
|
+
* - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.
|
|
551
|
+
* - If the iterator is infinite and no element satisfies the condition, the method will never return.
|
|
552
|
+
*
|
|
553
|
+
* ```ts
|
|
554
|
+
* const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
|
|
555
|
+
* const result = iterator.find((value) => value > 0);
|
|
556
|
+
*
|
|
557
|
+
* console.log(result); // 1
|
|
558
|
+
* ```
|
|
559
|
+
*
|
|
560
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
561
|
+
*
|
|
562
|
+
* @returns The first element that satisfies the condition, `undefined` otherwise.
|
|
563
|
+
*/
|
|
200
564
|
public find(predicate: Iteratee<T, boolean>): T | undefined;
|
|
201
|
-
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Finds the first element of the iterator that satisfies a given condition.
|
|
568
|
+
*
|
|
569
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
570
|
+
* The first element that satisfies the condition will be returned immediately.
|
|
571
|
+
*
|
|
572
|
+
* Only the elements that are necessary to find the first
|
|
573
|
+
* satisfying one will be consumed from the original iterator.
|
|
574
|
+
* The rest of the original iterator will be available for further consumption.
|
|
575
|
+
*
|
|
576
|
+
* Also note that:
|
|
577
|
+
* - If no element satisfies the condition, `undefined` will be returned once the entire iterator is consumed.
|
|
578
|
+
* - If the iterator is infinite and no element satisfies the condition, the method will never return.
|
|
579
|
+
*
|
|
580
|
+
* ```ts
|
|
581
|
+
* const iterator = new SmartIterator<number | string>([-2, "-1", "0", 1, "2"]);
|
|
582
|
+
* const result = iterator.find<number>((value) => typeof value === "number");
|
|
583
|
+
*
|
|
584
|
+
* console.log(result); // -2
|
|
585
|
+
* ```
|
|
586
|
+
*
|
|
587
|
+
* @template S
|
|
588
|
+
* The type of the element that satisfies the condition.
|
|
589
|
+
* This allows the type-system to infer the correct type of the result.
|
|
590
|
+
*
|
|
591
|
+
* It must be a subtype of the original type of the elements.
|
|
592
|
+
*
|
|
593
|
+
* @param predicate The type guard condition to check for each element of the iterator.
|
|
594
|
+
*
|
|
595
|
+
* @returns The first element that satisfies the condition, `undefined` otherwise.
|
|
596
|
+
*/
|
|
597
|
+
public find<S extends T>(predicate: TypeGuardPredicate<T, S>): S | undefined;
|
|
202
598
|
public find(predicate: Iteratee<T, boolean>): T | undefined
|
|
203
599
|
{
|
|
204
600
|
let index = 0;
|
|
@@ -214,10 +610,51 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
214
610
|
}
|
|
215
611
|
}
|
|
216
612
|
|
|
613
|
+
/**
|
|
614
|
+
* Enumerates the elements of the iterator.
|
|
615
|
+
* Each element is be paired with its index in a new iterator.
|
|
616
|
+
*
|
|
617
|
+
* Since the iterator is lazy, the enumeration process will
|
|
618
|
+
* be executed once the resulting iterator is materialized.
|
|
619
|
+
*
|
|
620
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
621
|
+
* This means that the original iterator won't be consumed until the
|
|
622
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
623
|
+
*
|
|
624
|
+
* ```ts
|
|
625
|
+
* const iterator = new SmartIterator<string>(["A", "M", "N", "Z"]);
|
|
626
|
+
* const result = iterator.enumerate();
|
|
627
|
+
*
|
|
628
|
+
* console.log(result.toArray()); // [[0, "A"], [1, "M"], [2, "N"], [3, "Z"]]
|
|
629
|
+
* ```
|
|
630
|
+
*
|
|
631
|
+
* @returns A new {@link SmartIterator} containing the enumerated elements.
|
|
632
|
+
*/
|
|
217
633
|
public enumerate(): SmartIterator<[number, T], R>
|
|
218
634
|
{
|
|
219
635
|
return this.map((value, index) => [index, value]);
|
|
220
636
|
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Removes all duplicate elements from the iterator.
|
|
640
|
+
* The first occurrence of each element will be kept.
|
|
641
|
+
*
|
|
642
|
+
* Since the iterator is lazy, the deduplication process will
|
|
643
|
+
* be executed once the resulting iterator is materialized.
|
|
644
|
+
*
|
|
645
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
646
|
+
* This means that the original iterator won't be consumed until the
|
|
647
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
648
|
+
*
|
|
649
|
+
* ```ts
|
|
650
|
+
* const iterator = new SmartIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);
|
|
651
|
+
* const result = iterator.unique();
|
|
652
|
+
*
|
|
653
|
+
* console.log(result.toArray()); // [1, 2, 3, 4, 5]
|
|
654
|
+
* ```
|
|
655
|
+
*
|
|
656
|
+
* @returns A new {@link SmartIterator} containing only the unique elements.
|
|
657
|
+
*/
|
|
221
658
|
public unique(): SmartIterator<T, R>
|
|
222
659
|
{
|
|
223
660
|
const iterator = this._iterator;
|
|
@@ -225,14 +662,11 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
225
662
|
return new SmartIterator<T, R>(function* ()
|
|
226
663
|
{
|
|
227
664
|
const values = new Set<T>();
|
|
228
|
-
|
|
229
665
|
while (true)
|
|
230
666
|
{
|
|
231
667
|
const result = iterator.next();
|
|
232
|
-
|
|
233
668
|
if (result.done) { return result.value; }
|
|
234
669
|
if (values.has(result.value)) { continue; }
|
|
235
|
-
|
|
236
670
|
values.add(result.value);
|
|
237
671
|
|
|
238
672
|
yield result.value;
|
|
@@ -240,6 +674,21 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
240
674
|
});
|
|
241
675
|
}
|
|
242
676
|
|
|
677
|
+
/**
|
|
678
|
+
* Counts the number of elements in the iterator.
|
|
679
|
+
* This method will consume the entire iterator in the process.
|
|
680
|
+
*
|
|
681
|
+
* If the iterator is infinite, the method will never return.
|
|
682
|
+
*
|
|
683
|
+
* ```ts
|
|
684
|
+
* const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);
|
|
685
|
+
* const result = iterator.count();
|
|
686
|
+
*
|
|
687
|
+
* console.log(result); // 5
|
|
688
|
+
* ```
|
|
689
|
+
*
|
|
690
|
+
* @returns The number of elements in the iterator.
|
|
691
|
+
*/
|
|
243
692
|
public count(): number
|
|
244
693
|
{
|
|
245
694
|
let index = 0;
|
|
@@ -253,6 +702,23 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
253
702
|
}
|
|
254
703
|
}
|
|
255
704
|
|
|
705
|
+
/**
|
|
706
|
+
* Iterates over all elements of the iterator.
|
|
707
|
+
* The elements are passed to the function along with their index.
|
|
708
|
+
*
|
|
709
|
+
* This method will consume the entire iterator in the process.
|
|
710
|
+
* If the iterator is infinite, the method will never return.
|
|
711
|
+
*
|
|
712
|
+
* ```ts
|
|
713
|
+
* const iterator = new SmartIterator<number>(["A", "M", "N", "Z"]);
|
|
714
|
+
* iterator.forEach((value, index) =>
|
|
715
|
+
* {
|
|
716
|
+
* console.log(`${index}: ${value}`); // "0: A", "1: M", "2: N", "3: Z"
|
|
717
|
+
* }
|
|
718
|
+
* ```
|
|
719
|
+
*
|
|
720
|
+
* @param iteratee The function to apply to each element of the iterator.
|
|
721
|
+
*/
|
|
256
722
|
public forEach(iteratee: Iteratee<T>): void
|
|
257
723
|
{
|
|
258
724
|
let index = 0;
|
|
@@ -268,11 +734,137 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
268
734
|
}
|
|
269
735
|
}
|
|
270
736
|
|
|
737
|
+
/**
|
|
738
|
+
* Advances the iterator to the next element and returns the result.
|
|
739
|
+
* If the iterator requires it, a value must be provided to be passed to the next element.
|
|
740
|
+
*
|
|
741
|
+
* Once the iterator is done, the method will return an object with the `done` property set to `true`.
|
|
742
|
+
*
|
|
743
|
+
* ```ts
|
|
744
|
+
* const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);
|
|
745
|
+
*
|
|
746
|
+
* let result = iterator.next();
|
|
747
|
+
* while (!result.done)
|
|
748
|
+
* {
|
|
749
|
+
* console.log(result.value); // 1, 2, 3, 4, 5
|
|
750
|
+
*
|
|
751
|
+
* result = iterator.next();
|
|
752
|
+
* }
|
|
753
|
+
*
|
|
754
|
+
* console.log(result); // { done: true, value: undefined }
|
|
755
|
+
* ```
|
|
756
|
+
*
|
|
757
|
+
* @param values The value to pass to the next element, if required.
|
|
758
|
+
*
|
|
759
|
+
* @returns The result of the iteration, containing the value of the operation.
|
|
760
|
+
*/
|
|
271
761
|
public next(...values: N extends undefined ? [] : [N]): IteratorResult<T, R>
|
|
272
762
|
{
|
|
273
763
|
return this._iterator.next(...values);
|
|
274
764
|
}
|
|
275
765
|
|
|
766
|
+
/**
|
|
767
|
+
* An utility method that may be used to close the iterator gracefully,
|
|
768
|
+
* free the resources and perform any cleanup operation.
|
|
769
|
+
* It may also be used to signal the end or to compute a specific final result of the iteration process.
|
|
770
|
+
*
|
|
771
|
+
* ```ts
|
|
772
|
+
* const iterator = new SmartIterator<number>({
|
|
773
|
+
* _index: 0,
|
|
774
|
+
* next: function()
|
|
775
|
+
* {
|
|
776
|
+
* return { done: false, value: this._index += 1 };
|
|
777
|
+
* },
|
|
778
|
+
* return: function() { console.log("Closing the iterator..."); }
|
|
779
|
+
* });
|
|
780
|
+
*
|
|
781
|
+
* for (const value of iterator)
|
|
782
|
+
* {
|
|
783
|
+
* if (value > 5) { break; } // Closing the iterator...
|
|
784
|
+
*
|
|
785
|
+
* console.log(value); // 1, 2, 3, 4, 5
|
|
786
|
+
* }
|
|
787
|
+
* ```
|
|
788
|
+
*
|
|
789
|
+
* @param value The final value of the iterator.
|
|
790
|
+
*
|
|
791
|
+
* @returns The result of the iterator.
|
|
792
|
+
*/
|
|
793
|
+
public return(value?: R): IteratorResult<T, R>
|
|
794
|
+
{
|
|
795
|
+
if (this._iterator.return) { return this._iterator.return(value); }
|
|
796
|
+
|
|
797
|
+
return { done: true, value: value as R };
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* An utility method that may be used to close the iterator due to an error,
|
|
802
|
+
* free the resources and perform any cleanup operation.
|
|
803
|
+
* It may also be used to signal that an error occurred during the iteration process or to handle it.
|
|
804
|
+
*
|
|
805
|
+
* ```ts
|
|
806
|
+
* const iterator = new SmartIterator<number>({
|
|
807
|
+
* _index: 0,
|
|
808
|
+
* next: function()
|
|
809
|
+
* {
|
|
810
|
+
* return { done: this._index > 10, value: this._index += 1 };
|
|
811
|
+
* },
|
|
812
|
+
* throw: function(error)
|
|
813
|
+
* {
|
|
814
|
+
* console.warn(error.message);
|
|
815
|
+
*
|
|
816
|
+
* this._index = 0;
|
|
817
|
+
* }
|
|
818
|
+
* });
|
|
819
|
+
*
|
|
820
|
+
* for (const value of iterator) // 1, 2, 3, 4, 5, "The index is too high.", 1, 2, 3, 4, 5, ...
|
|
821
|
+
* {
|
|
822
|
+
* try
|
|
823
|
+
* {
|
|
824
|
+
* if (value > 5) { throw new Error("The index is too high."); }
|
|
825
|
+
*
|
|
826
|
+
* console.log(value); // 1, 2, 3, 4, 5
|
|
827
|
+
* }
|
|
828
|
+
* catch (error) { iterator.throw(error); }
|
|
829
|
+
* }
|
|
830
|
+
* ```
|
|
831
|
+
*
|
|
832
|
+
* @param error The error to throw into the iterator.
|
|
833
|
+
*
|
|
834
|
+
* @returns The final result of the iterator.
|
|
835
|
+
*/
|
|
836
|
+
public throw(error: unknown): IteratorResult<T, R>
|
|
837
|
+
{
|
|
838
|
+
if (this._iterator.throw) { return this._iterator.throw(error); }
|
|
839
|
+
|
|
840
|
+
throw error;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* An utility method that aggregates the elements of the iterator using a given key function.
|
|
845
|
+
* The elements will be grouped by the resulting keys in a new specialized iterator.
|
|
846
|
+
* See {@link AggregatedIterator}.
|
|
847
|
+
*
|
|
848
|
+
* Since the iterator is lazy, the grouping process will
|
|
849
|
+
* be executed once the resulting iterator is materialized.
|
|
850
|
+
*
|
|
851
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
852
|
+
* This means that the original iterator won't be consumed until the
|
|
853
|
+
* the new one is and that consuming one of them will consume the other as well.
|
|
854
|
+
*
|
|
855
|
+
* ```ts
|
|
856
|
+
* const iterator = new SmartIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
|
857
|
+
* const result = iterator.groupBy<string>((value) => value % 2 === 0 ? "even" : "odd");
|
|
858
|
+
*
|
|
859
|
+
* console.log(result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }
|
|
860
|
+
* ```
|
|
861
|
+
*
|
|
862
|
+
* @template K The type of the keys used to group the elements.
|
|
863
|
+
*
|
|
864
|
+
* @param iteratee The key function to apply to each element of the iterator.
|
|
865
|
+
*
|
|
866
|
+
* @returns A new instance of the {@link AggregatedIterator} class containing the grouped elements.
|
|
867
|
+
*/
|
|
276
868
|
public groupBy<K extends PropertyKey>(iteratee: Iteratee<T, K>): AggregatedIterator<K, T>
|
|
277
869
|
{
|
|
278
870
|
return new AggregatedIterator(this.map((element, index) =>
|
|
@@ -283,6 +875,24 @@ export default class SmartIterator<T, R = void, N = undefined> implements Iterat
|
|
|
283
875
|
}));
|
|
284
876
|
}
|
|
285
877
|
|
|
878
|
+
/**
|
|
879
|
+
* Materializes the iterator into an array.
|
|
880
|
+
* This method will consume the entire iterator in the process.
|
|
881
|
+
*
|
|
882
|
+
* If the iterator is infinite, the method will never return.
|
|
883
|
+
*
|
|
884
|
+
* ```ts
|
|
885
|
+
* const iterator = new SmartIterator(function* ()
|
|
886
|
+
* {
|
|
887
|
+
* for (let i = 0; i < 5; i += 1) { yield i; }
|
|
888
|
+
* });
|
|
889
|
+
* const result = iterator.toArray();
|
|
890
|
+
*
|
|
891
|
+
* console.log(result); // [0, 1, 2, 3, 4]
|
|
892
|
+
* ```
|
|
893
|
+
*
|
|
894
|
+
* @returns The {@link Array} containing all elements of the iterator.
|
|
895
|
+
*/
|
|
286
896
|
public toArray(): T[]
|
|
287
897
|
{
|
|
288
898
|
return Array.from(this as Iterable<T>);
|