@byloth/core 1.5.3 → 2.0.0-rc.10

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 (45) hide show
  1. package/dist/core.js +1468 -826
  2. package/dist/core.js.map +1 -1
  3. package/dist/core.umd.cjs +3 -3
  4. package/dist/core.umd.cjs.map +1 -1
  5. package/package.json +8 -10
  6. package/src/helpers.ts +10 -0
  7. package/src/index.ts +33 -16
  8. package/src/models/aggregators/aggregated-async-iterator.ts +129 -81
  9. package/src/models/aggregators/aggregated-iterator.ts +128 -82
  10. package/src/models/aggregators/index.ts +1 -3
  11. package/src/models/aggregators/reduced-iterator.ts +119 -31
  12. package/src/models/aggregators/types.ts +15 -10
  13. package/src/models/callbacks/callable-object.ts +23 -0
  14. package/src/models/callbacks/index.ts +5 -0
  15. package/src/models/callbacks/publisher.ts +45 -0
  16. package/src/models/callbacks/switchable-callback.ts +108 -0
  17. package/src/models/callbacks/types.ts +1 -0
  18. package/src/models/exceptions/core.ts +6 -7
  19. package/src/models/exceptions/index.ts +50 -10
  20. package/src/models/game-loop.ts +83 -0
  21. package/src/models/index.ts +10 -7
  22. package/src/models/iterators/smart-async-iterator.ts +112 -24
  23. package/src/models/iterators/smart-iterator.ts +108 -13
  24. package/src/models/iterators/types.ts +17 -7
  25. package/src/models/json/index.ts +3 -0
  26. package/src/models/{json-storage.ts → json/json-storage.ts} +40 -28
  27. package/src/models/json/types.ts +5 -0
  28. package/src/models/promises/deferred-promise.ts +1 -1
  29. package/src/models/promises/index.ts +3 -1
  30. package/src/models/promises/long-running-task.ts +294 -0
  31. package/src/models/promises/smart-promise.ts +6 -1
  32. package/src/models/promises/thenable.ts +97 -0
  33. package/src/models/promises/timed-promise.ts +1 -1
  34. package/src/models/promises/types.ts +2 -0
  35. package/src/models/timers/clock.ts +69 -0
  36. package/src/models/timers/countdown.ts +117 -0
  37. package/src/models/timers/index.ts +4 -0
  38. package/src/models/types.ts +20 -9
  39. package/src/utils/async.ts +9 -4
  40. package/src/utils/date.ts +7 -4
  41. package/src/utils/index.ts +2 -2
  42. package/src/utils/random.ts +4 -3
  43. package/src/models/aggregators/aggregator.ts +0 -46
  44. package/src/models/aggregators/async-aggregator.ts +0 -56
  45. package/src/models/subscribers.ts +0 -35
@@ -0,0 +1,108 @@
1
+ import { KeyException, NotImplementedException, RuntimeException } from "../exceptions/index.js";
2
+
3
+ import CallableObject from "./callable-object.js";
4
+ import type { Callback } from "./types.js";
5
+
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ export default class SwitchableCallback<T extends Callback<any[], any> = Callback> extends CallableObject<T>
8
+ {
9
+ protected _callback: T;
10
+ protected _callbacks: Map<string, T>;
11
+
12
+ protected _isEnabled: boolean;
13
+ public get isEnabled(): boolean { return this._isEnabled; }
14
+
15
+ protected _key: string;
16
+ public get key(): string { return this._key; }
17
+
18
+ public readonly invoke: (...args: Parameters<T>) => ReturnType<T>;
19
+
20
+ public constructor()
21
+ {
22
+ const _default = () =>
23
+ {
24
+ throw new NotImplementedException(
25
+ "The `SwitchableCallback` has no callback defined yet. " +
26
+ "Did you forget to call the `register` method?"
27
+ );
28
+ };
29
+
30
+ super();
31
+
32
+ this._callback = ((_default) as unknown) as T;
33
+ this._callbacks = new Map<string, T>();
34
+
35
+ this._isEnabled = true;
36
+ this._key = "";
37
+
38
+ this.invoke = (...args: Parameters<T>): ReturnType<T> => this._callback(...args);
39
+ }
40
+
41
+ public enable(): void
42
+ {
43
+ if (!(this._key))
44
+ {
45
+ throw new KeyException(
46
+ "The `SwitchableCallback` has no callback defined yet. " +
47
+ "Did you forget to call the `register` method?"
48
+ );
49
+ }
50
+ if (this._isEnabled)
51
+ {
52
+ throw new RuntimeException("The `SwitchableCallback` is already enabled.");
53
+ }
54
+
55
+ this._callback = this._callbacks.get(this._key)!;
56
+ this._isEnabled = true;
57
+ }
58
+ public disable(): void
59
+ {
60
+ if (!(this._isEnabled))
61
+ {
62
+ throw new RuntimeException("The `SwitchableCallback` is already disabled.");
63
+ }
64
+
65
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
66
+ this._callback = (() => { }) as T;
67
+ this._isEnabled = false;
68
+ }
69
+
70
+ public register(key: string, callback: T): void
71
+ {
72
+ if (this._callbacks.size === 0)
73
+ {
74
+ this._key = key;
75
+ this._callback = callback;
76
+ }
77
+ else if (this._callbacks.has(key))
78
+ {
79
+ throw new KeyException(`The key '${key}' has already been used for another callback.`);
80
+ }
81
+
82
+ this._callbacks.set(key, callback);
83
+ }
84
+ public unregister(key: string): void
85
+ {
86
+ if (!(this._callbacks.has(key)))
87
+ {
88
+ throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);
89
+ }
90
+
91
+ this._callbacks.delete(key);
92
+ }
93
+
94
+ public switch(key: string): void
95
+ {
96
+ if (!(this._callbacks.has(key)))
97
+ {
98
+ throw new KeyException(`The key '${key}' doesn't yet have any associated callback.`);
99
+ }
100
+
101
+ this._key = key;
102
+
103
+ if (this._isEnabled)
104
+ {
105
+ this._callback = this._callbacks.get(key)!;
106
+ }
107
+ }
108
+ }
@@ -0,0 +1 @@
1
+ export type Callback<A extends unknown[] = [], R = void> = (...args: A) => R;
@@ -39,7 +39,7 @@ export default class Exception extends Error
39
39
  }
40
40
  }
41
41
 
42
- public get [Symbol.toStringTag]() { return "Exception"; }
42
+ public readonly [Symbol.toStringTag]: string = "Exception";
43
43
  }
44
44
 
45
45
  export class FatalErrorException extends Exception
@@ -48,17 +48,16 @@ export class FatalErrorException extends Exception
48
48
  {
49
49
  if (message === undefined)
50
50
  {
51
- message = "The routine has encountered an unrecoverable error and cannot continue as expected. " +
52
- "Please, refresh the page and try again. If the problem persists, contact the support team.";
51
+ message = "The program has encountered an unrecoverable error and cannot continue as expected. " +
52
+ "Please, try again later. If the problem persists, contact the support team.";
53
53
  }
54
54
 
55
55
  super(message, cause, name);
56
56
  }
57
57
 
58
- public get [Symbol.toStringTag]() { return "FatalErrorException"; }
58
+ public readonly [Symbol.toStringTag]: string = "FatalErrorException";
59
59
  }
60
-
61
- export class NotImplementedException extends Exception
60
+ export class NotImplementedException extends FatalErrorException
62
61
  {
63
62
  public constructor(message?: string, cause?: unknown, name = "NotImplementedException")
64
63
  {
@@ -70,5 +69,5 @@ export class NotImplementedException extends Exception
70
69
  super(message, cause, name);
71
70
  }
72
71
 
73
- public get [Symbol.toStringTag]() { return "NotImplementedException"; }
72
+ public readonly [Symbol.toStringTag]: string = "NotImplementedException";
74
73
  }
@@ -1,14 +1,33 @@
1
1
  import Exception from "./core.js";
2
2
 
3
- export class FileNotFoundException extends Exception
3
+ export class FileException extends Exception
4
+ {
5
+ public constructor(message: string, cause?: unknown, name = "FileException")
6
+ {
7
+ super(message, cause, name);
8
+ }
9
+
10
+ public readonly [Symbol.toStringTag]: string = "FileException";
11
+ }
12
+ export class FileExistsException extends FileException
13
+ {
14
+ public constructor(message: string, cause?: unknown, name = "FileExistsException")
15
+ {
16
+ super(message, cause, name);
17
+ }
18
+
19
+ public readonly [Symbol.toStringTag]: string = "FileExistsException";
20
+ }
21
+ export class FileNotFoundException extends FileException
4
22
  {
5
23
  public constructor(message: string, cause?: unknown, name = "FileNotFoundException")
6
24
  {
7
25
  super(message, cause, name);
8
26
  }
9
27
 
10
- public get [Symbol.toStringTag]() { return "FileNotFoundException"; }
28
+ public readonly [Symbol.toStringTag]: string = "FileNotFoundException";
11
29
  }
30
+
12
31
  export class KeyException extends Exception
13
32
  {
14
33
  public constructor(message: string, cause?: unknown, name = "KeyException")
@@ -16,7 +35,7 @@ export class KeyException extends Exception
16
35
  super(message, cause, name);
17
36
  }
18
37
 
19
- public get [Symbol.toStringTag]() { return "KeyException"; }
38
+ public readonly [Symbol.toStringTag]: string = "KeyException";
20
39
  }
21
40
  export class NetworkException extends Exception
22
41
  {
@@ -25,7 +44,7 @@ export class NetworkException extends Exception
25
44
  super(message, cause, name);
26
45
  }
27
46
 
28
- public get [Symbol.toStringTag]() { return "NetworkException"; }
47
+ public readonly [Symbol.toStringTag]: string = "NetworkException";
29
48
  }
30
49
  export class PermissionException extends Exception
31
50
  {
@@ -34,7 +53,7 @@ export class PermissionException extends Exception
34
53
  super(message, cause, name);
35
54
  }
36
55
 
37
- public get [Symbol.toStringTag]() { return "PermissionException"; }
56
+ public readonly [Symbol.toStringTag]: string = "PermissionException";
38
57
  }
39
58
  export class ReferenceException extends Exception
40
59
  {
@@ -43,8 +62,9 @@ export class ReferenceException extends Exception
43
62
  super(message, cause, name);
44
63
  }
45
64
 
46
- public get [Symbol.toStringTag]() { return "ReferenceException"; }
65
+ public readonly [Symbol.toStringTag]: string = "ReferenceException";
47
66
  }
67
+
48
68
  export class RuntimeException extends Exception
49
69
  {
50
70
  public constructor(message: string, cause?: unknown, name = "RuntimeException")
@@ -52,8 +72,18 @@ export class RuntimeException extends Exception
52
72
  super(message, cause, name);
53
73
  }
54
74
 
55
- public get [Symbol.toStringTag]() { return "RuntimeException"; }
75
+ public readonly [Symbol.toStringTag]: string = "RuntimeException";
56
76
  }
77
+ export class EnvironmentException extends RuntimeException
78
+ {
79
+ public constructor(message: string, cause?: unknown, name = "EnvironmentException")
80
+ {
81
+ super(message, cause, name);
82
+ }
83
+
84
+ public readonly [Symbol.toStringTag]: string = "EnvironmentException";
85
+ }
86
+
57
87
  export class TimeoutException extends Exception
58
88
  {
59
89
  public constructor(message: string, cause?: unknown, name = "TimeoutException")
@@ -61,7 +91,7 @@ export class TimeoutException extends Exception
61
91
  super(message, cause, name);
62
92
  }
63
93
 
64
- public get [Symbol.toStringTag]() { return "TimeoutException"; }
94
+ public readonly [Symbol.toStringTag]: string = "TimeoutException";
65
95
  }
66
96
  export class TypeException extends Exception
67
97
  {
@@ -70,8 +100,9 @@ export class TypeException extends Exception
70
100
  super(message, cause, name);
71
101
  }
72
102
 
73
- public get [Symbol.toStringTag]() { return "TypeException"; }
103
+ public readonly [Symbol.toStringTag]: string = "TypeException";
74
104
  }
105
+
75
106
  export class ValueException extends Exception
76
107
  {
77
108
  public constructor(message: string, cause?: unknown, name = "ValueException")
@@ -79,7 +110,16 @@ export class ValueException extends Exception
79
110
  super(message, cause, name);
80
111
  }
81
112
 
82
- public get [Symbol.toStringTag]() { return "ValueException"; }
113
+ public readonly [Symbol.toStringTag]: string = "ValueException";
114
+ }
115
+ export class RangeException extends ValueException
116
+ {
117
+ public constructor(message: string, cause?: unknown, name = "RangeException")
118
+ {
119
+ super(message, cause, name);
120
+ }
121
+
122
+ public readonly [Symbol.toStringTag]: string = "RangeException";
83
123
  }
84
124
 
85
125
  export { Exception };
@@ -0,0 +1,83 @@
1
+ import type { Interval } from "../core/types.js";
2
+ import { isBrowser } from "../helpers.js";
3
+
4
+ import { FatalErrorException, RuntimeException } from "./exceptions/index.js";
5
+
6
+ export default class GameLoop
7
+ {
8
+ protected _handle?: number | Interval;
9
+
10
+ protected _startTime: number;
11
+ public get startTime(): number
12
+ {
13
+ return this._startTime;
14
+ }
15
+
16
+ protected _isRunning: boolean;
17
+ public get isRunning(): boolean
18
+ {
19
+ return this._isRunning;
20
+ }
21
+
22
+ public get elapsedTime(): number
23
+ {
24
+ return performance.now() - this._startTime;
25
+ }
26
+
27
+ protected _start: () => void;
28
+ protected _stop: () => void;
29
+
30
+ public constructor(callback: FrameRequestCallback, msIfNotBrowser = 40)
31
+ {
32
+ this._startTime = 0;
33
+ this._isRunning = false;
34
+
35
+ if (isBrowser)
36
+ {
37
+ this._start = () =>
38
+ {
39
+ callback(this.elapsedTime);
40
+
41
+ this._handle = window.requestAnimationFrame(this._start);
42
+ };
43
+
44
+ this._stop = () => window.cancelAnimationFrame(this._handle as number);
45
+ }
46
+ else
47
+ {
48
+ // eslint-disable-next-line no-console
49
+ console.warn(
50
+ "Not a browser environment detected. " +
51
+ `Using setInterval@${msIfNotBrowser}ms instead of requestAnimationFrame...`
52
+ );
53
+
54
+ this._start = () =>
55
+ {
56
+ this._handle = setInterval(() => callback(this.elapsedTime), msIfNotBrowser);
57
+ };
58
+
59
+ this._stop = () => clearInterval(this._handle as Interval);
60
+ }
61
+ }
62
+
63
+ public start(elapsedTime = 0): void
64
+ {
65
+ if (this._isRunning) { throw new RuntimeException("The game loop has already been started."); }
66
+
67
+ this._startTime = performance.now() - elapsedTime;
68
+ this._start();
69
+ this._isRunning = true;
70
+ }
71
+
72
+ public stop(): void
73
+ {
74
+ if (!(this._isRunning)) { throw new RuntimeException("The game loop hadn't yet started."); }
75
+ if (!(this._handle)) { throw new FatalErrorException(); }
76
+
77
+ this._stop();
78
+ this._handle = undefined;
79
+ this._isRunning = false;
80
+ }
81
+
82
+ public readonly [Symbol.toStringTag]: string = "GameLoop";
83
+ }
@@ -1,20 +1,22 @@
1
1
  export {
2
- Aggregator,
3
- AsyncAggregator,
4
2
  AggregatedIterator,
5
3
  AggregatedAsyncIterator,
6
4
  ReducedIterator
7
5
 
8
6
  } from "./aggregators/index.js";
9
7
 
8
+ export { CallableObject, Publisher, SmartFunction, SwitchableCallback } from "./callbacks/index.js";
10
9
  export {
11
10
  Exception,
12
11
  FatalErrorException,
13
12
  NotImplementedException,
13
+ FileException,
14
+ FileExistsException,
14
15
  FileNotFoundException,
15
16
  KeyException,
16
17
  NetworkException,
17
18
  PermissionException,
19
+ RangeException,
18
20
  ReferenceException,
19
21
  RuntimeException,
20
22
  TimeoutException,
@@ -23,11 +25,12 @@ export {
23
25
 
24
26
  } from "./exceptions/index.js";
25
27
 
26
- export { SmartIterator, SmartAsyncIterator } from "./iterators/index.js";
28
+ import GameLoop from "./game-loop.js";
27
29
 
28
- import JsonStorage from "./json-storage.js";
29
- import Subscribers from "./subscribers.js";
30
+ export { SmartIterator, SmartAsyncIterator } from "./iterators/index.js";
31
+ export { JSONStorage } from "./json/index.js";
32
+ export { DeferredPromise, LongRunningTask, SmartPromise, Thenable, TimedPromise } from "./promises/index.js";
30
33
 
31
- export { DeferredPromise, SmartPromise, TimedPromise } from "./promises/index.js";
34
+ export { Clock, Countdown } from "./timers/index.js";
32
35
 
33
- export { JsonStorage, Subscribers };
36
+ export { GameLoop };
@@ -1,9 +1,14 @@
1
+ import AggregatedAsyncIterator from "../aggregators/aggregated-async-iterator.js";
2
+ import { ValueException } from "../exceptions/index.js";
3
+
1
4
  import type {
2
- AsyncGeneratorFunction,
3
5
  GeneratorFunction,
6
+ AsyncGeneratorFunction,
7
+ MaybeAsyncGeneratorFunction,
4
8
  MaybeAsyncIteratee,
5
9
  MaybeAsyncReducer,
6
- MaybeAsyncIterLike,
10
+ MaybeAsyncIterable,
11
+ MaybeAsyncIteratorLike,
7
12
  MaybeAsyncTypeGuardIteratee
8
13
 
9
14
  } from "./types.js";
@@ -21,8 +26,8 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
21
26
  public constructor(iterator: AsyncIterator<T, R, N>);
22
27
  public constructor(generatorFn: GeneratorFunction<T, R, N>);
23
28
  public constructor(generatorFn: AsyncGeneratorFunction<T, R, N>);
24
- public constructor(argument: MaybeAsyncIterLike<T, R, N>);
25
- public constructor(argument: MaybeAsyncIterLike<T, R, N>)
29
+ public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>);
30
+ public constructor(argument: MaybeAsyncIteratorLike<T, R, N> | MaybeAsyncGeneratorFunction<T, R, N>)
26
31
  {
27
32
  if (argument instanceof Function)
28
33
  {
@@ -92,13 +97,12 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
92
97
  {
93
98
  let index = 0;
94
99
 
95
- // eslint-disable-next-line no-constant-condition
96
100
  while (true)
97
101
  {
98
102
  const result = await this._iterator.next();
99
103
 
100
104
  if (result.done) { return true; }
101
- if (!(predicate(result.value, index))) { return false; }
105
+ if (!(await predicate(result.value, index))) { return false; }
102
106
 
103
107
  index += 1;
104
108
  }
@@ -107,13 +111,12 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
107
111
  {
108
112
  let index = 0;
109
113
 
110
- // eslint-disable-next-line no-constant-condition
111
114
  while (true)
112
115
  {
113
116
  const result = await this._iterator.next();
114
117
 
115
118
  if (result.done) { return false; }
116
- if (predicate(result.value, index)) { return true; }
119
+ if (await predicate(result.value, index)) { return true; }
117
120
 
118
121
  index += 1;
119
122
  }
@@ -134,7 +137,7 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
134
137
  const result = await iterator.next();
135
138
 
136
139
  if (result.done) { return result.value; }
137
- if (predicate(result.value, index)) { yield result.value; }
140
+ if (await predicate(result.value, index)) { yield result.value; }
138
141
 
139
142
  index += 1;
140
143
  }
@@ -153,7 +156,7 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
153
156
  const result = await iterator.next();
154
157
  if (result.done) { return result.value; }
155
158
 
156
- yield iteratee(result.value, index);
159
+ yield await iteratee(result.value, index);
157
160
 
158
161
  index += 1;
159
162
  }
@@ -168,13 +171,12 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
168
171
  if (accumulator === undefined)
169
172
  {
170
173
  const result = await this._iterator.next();
171
- if (result.done) { throw new TypeError("Reduce of empty iterator with no initial value"); }
174
+ if (result.done) { throw new ValueException("Cannot reduce an empty iterator without an initial value."); }
172
175
 
173
176
  accumulator = (result.value as unknown) as A;
174
177
  index += 1;
175
178
  }
176
179
 
177
- // eslint-disable-next-line no-constant-condition
178
180
  while (true)
179
181
  {
180
182
  const result = await this._iterator.next();
@@ -186,6 +188,93 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
186
188
  }
187
189
  }
188
190
 
191
+ public flatMap<V>(iteratee: MaybeAsyncIteratee<T, MaybeAsyncIterable<V>>): SmartAsyncIterator<V, R>
192
+ {
193
+ const iterator = this._iterator;
194
+
195
+ return new SmartAsyncIterator<V, R>(async function* ()
196
+ {
197
+ let index = 0;
198
+
199
+ while (true)
200
+ {
201
+ const result = await iterator.next();
202
+ if (result.done) { return result.value; }
203
+
204
+ const elements = await iteratee(result.value, index);
205
+
206
+ for await (const element of elements)
207
+ {
208
+ yield element;
209
+ }
210
+
211
+ index += 1;
212
+ }
213
+ });
214
+ }
215
+
216
+ public drop(count: number): SmartAsyncIterator<T, R | undefined>
217
+ {
218
+ const iterator = this._iterator;
219
+
220
+ return new SmartAsyncIterator<T, R | undefined>(async function* ()
221
+ {
222
+ let index = 0;
223
+
224
+ while (index < count)
225
+ {
226
+ const result = await iterator.next();
227
+ if (result.done) { return; }
228
+
229
+ index += 1;
230
+ }
231
+
232
+ while (true)
233
+ {
234
+ const result = await iterator.next();
235
+ if (result.done) { return result.value; }
236
+
237
+ yield result.value;
238
+ }
239
+ });
240
+ }
241
+ public take(limit: number): SmartAsyncIterator<T, R | undefined>
242
+ {
243
+ const iterator = this._iterator;
244
+
245
+ return new SmartAsyncIterator<T, R | undefined>(async function* ()
246
+ {
247
+ let index = 0;
248
+
249
+ while (index < limit)
250
+ {
251
+ const result = await iterator.next();
252
+ if (result.done) { return result.value; }
253
+
254
+ yield result.value;
255
+
256
+ index += 1;
257
+ }
258
+
259
+ return;
260
+ });
261
+ }
262
+
263
+ public async find(predicate: MaybeAsyncIteratee<T, boolean>): Promise<T | undefined>
264
+ {
265
+ let index = 0;
266
+
267
+ while (true)
268
+ {
269
+ const result = await this._iterator.next();
270
+
271
+ if (result.done) { return; }
272
+ if (await predicate(result.value, index)) { return result.value; }
273
+
274
+ index += 1;
275
+ }
276
+ }
277
+
189
278
  public enumerate(): SmartAsyncIterator<[number, T], R>
190
279
  {
191
280
  return this.map((value, index) => [index, value]);
@@ -216,7 +305,6 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
216
305
  {
217
306
  let index = 0;
218
307
 
219
- // eslint-disable-next-line no-constant-condition
220
308
  while (true)
221
309
  {
222
310
  const result = await this._iterator.next();
@@ -229,7 +317,6 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
229
317
  {
230
318
  let index = 0;
231
319
 
232
- // eslint-disable-next-line no-constant-condition
233
320
  while (true)
234
321
  {
235
322
  const result = await this._iterator.next();
@@ -246,21 +333,22 @@ export default class SmartAsyncIterator<T, R = void, N = undefined> implements A
246
333
  return this._iterator.next(...values);
247
334
  }
248
335
 
249
- public async toArray(): Promise<T[]>
336
+ public groupBy<K extends PropertyKey>(iteratee: MaybeAsyncIteratee<T, K>): AggregatedAsyncIterator<K, T>
250
337
  {
251
- const elements: T[] = [];
252
-
253
- // eslint-disable-next-line no-constant-condition
254
- while (true)
338
+ return new AggregatedAsyncIterator(this.map(async (element, index) =>
255
339
  {
256
- const result = await this._iterator.next();
257
- if (result.done) { return elements; }
340
+ const key = await iteratee(element, index);
258
341
 
259
- elements.push(result.value);
260
- }
342
+ return [key, element] as [K, T];
343
+ }));
344
+ }
345
+
346
+ public toArray(): Promise<T[]>
347
+ {
348
+ return Array.fromAsync(this as AsyncIterable<T>);
261
349
  }
262
350
 
263
- public get [Symbol.toStringTag]() { return "SmartAsyncIterator"; }
351
+ public readonly [Symbol.toStringTag]: string = "SmartAsyncIterator";
264
352
 
265
353
  public [Symbol.asyncIterator](): SmartAsyncIterator<T, R, N> { return this; }
266
354
  }