@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.
Files changed (47) hide show
  1. package/dist/core.js +3371 -608
  2. package/dist/core.js.map +1 -1
  3. package/dist/core.umd.cjs +2 -2
  4. package/dist/core.umd.cjs.map +1 -1
  5. package/package.json +13 -10
  6. package/src/core/types.ts +41 -0
  7. package/src/helpers.ts +11 -2
  8. package/src/index.ts +12 -9
  9. package/src/models/aggregators/aggregated-async-iterator.ts +765 -21
  10. package/src/models/aggregators/aggregated-iterator.ts +698 -22
  11. package/src/models/aggregators/reduced-iterator.ts +699 -10
  12. package/src/models/aggregators/types.ts +153 -10
  13. package/src/models/callbacks/callable-object.ts +42 -6
  14. package/src/models/callbacks/index.ts +2 -2
  15. package/src/models/callbacks/publisher.ts +139 -4
  16. package/src/models/callbacks/switchable-callback.ts +138 -4
  17. package/src/models/callbacks/types.ts +16 -0
  18. package/src/models/exceptions/core.ts +112 -3
  19. package/src/models/exceptions/index.ts +340 -13
  20. package/src/models/index.ts +4 -8
  21. package/src/models/iterators/smart-async-iterator.ts +687 -22
  22. package/src/models/iterators/smart-iterator.ts +631 -21
  23. package/src/models/iterators/types.ts +268 -9
  24. package/src/models/json/json-storage.ts +388 -110
  25. package/src/models/json/types.ts +10 -1
  26. package/src/models/promises/deferred-promise.ts +75 -5
  27. package/src/models/promises/index.ts +1 -3
  28. package/src/models/promises/smart-promise.ts +232 -4
  29. package/src/models/promises/timed-promise.ts +38 -1
  30. package/src/models/promises/types.ts +84 -2
  31. package/src/models/timers/clock.ts +91 -19
  32. package/src/models/timers/countdown.ts +152 -22
  33. package/src/models/timers/game-loop.ts +243 -0
  34. package/src/models/timers/index.ts +2 -1
  35. package/src/models/types.ts +6 -5
  36. package/src/utils/async.ts +43 -0
  37. package/src/utils/curve.ts +75 -0
  38. package/src/utils/date.ts +204 -10
  39. package/src/utils/dom.ts +16 -2
  40. package/src/utils/index.ts +3 -2
  41. package/src/utils/iterator.ts +200 -17
  42. package/src/utils/math.ts +55 -3
  43. package/src/utils/random.ts +109 -2
  44. package/src/utils/string.ts +11 -0
  45. package/src/models/game-loop.ts +0 -83
  46. package/src/models/promises/long-running-task.ts +0 -294
  47. package/src/models/promises/thenable.ts +0 -97
package/dist/core.js CHANGED
@@ -1,148 +1,366 @@
1
- var Ne = Object.defineProperty;
2
- var Ye = (i, t, e) => t in i ? Ne(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
3
- var a = (i, t, e) => Ye(i, typeof t != "symbol" ? t + "" : t, e);
1
+ var ze = Object.defineProperty;
2
+ var De = (i, t, e) => t in i ? ze(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
3
+ var a = (i, t, e) => De(i, typeof t != "symbol" ? t + "" : t, e);
4
4
  const Oe = typeof window < "u" && typeof window.document < "u";
5
- var O;
6
- const Qe = typeof process < "u" && ((O = process.versions) == null ? void 0 : O.node);
5
+ var I;
6
+ const Ze = typeof process < "u" && !!((I = process.versions) != null && I.node);
7
7
  var A;
8
- const Xe = typeof self == "object" && ((A = self.constructor) == null ? void 0 : A.name) === "DedicatedWorkerGlobalScope";
9
- var $, q;
10
- class f extends (q = Error, $ = Symbol.toStringTag, q) {
8
+ const We = typeof self == "object" && ((A = self.constructor) == null ? void 0 : A.name) === "DedicatedWorkerGlobalScope";
9
+ var N, O;
10
+ class c extends (O = Error, N = Symbol.toStringTag, O) {
11
+ /**
12
+ * Initializes a new instance of the {@link Exception} class.
13
+ *
14
+ * ```ts
15
+ * throw new Exception("An error occurred while processing the request.");
16
+ * ```
17
+ *
18
+ * @param message The message that describes the error.
19
+ * @param cause The previous caught error that caused this one, if any.
20
+ * @param name The name of the exception. Default is `"Exception"`.
21
+ */
11
22
  constructor(e, n, s = "Exception") {
12
23
  super(e);
13
- a(this, $, "Exception");
24
+ a(this, N, "Exception");
14
25
  this.cause = n, this.name = s, n && (n instanceof Error ? this.stack += `
15
26
 
16
27
  Caused by ${n.stack}` : this.stack += `
17
28
 
18
29
  Caused by ${n}`);
19
30
  }
31
+ /**
32
+ * A static method to convert a generic caught error, ensuring it's an instance of the {@link Exception} class.
33
+ *
34
+ * ```ts
35
+ * try { [...] }
36
+ * catch (error)
37
+ * {
38
+ * const exc = Exception.FromUnknown(error);
39
+ *
40
+ * [...]
41
+ * }
42
+ * ```
43
+ *
44
+ * @param error The caught error to convert.
45
+ *
46
+ * @returns An instance of the {@link Exception} class.
47
+ */
20
48
  static FromUnknown(e) {
21
- if (e instanceof f)
49
+ if (e instanceof c)
22
50
  return e;
23
51
  if (e instanceof Error) {
24
- const n = new f(e.message);
52
+ const n = new c(e.message);
25
53
  return n.stack = e.stack, n.name = e.name, n;
26
54
  }
27
- return new f(`${e}`);
55
+ return new c(`${e}`);
28
56
  }
29
57
  }
30
- var N, Y;
31
- class k extends (Y = f, N = Symbol.toStringTag, Y) {
58
+ var $, q;
59
+ class x extends (q = c, $ = Symbol.toStringTag, q) {
60
+ /**
61
+ * Initializes a new instance of the {@link FatalErrorException} class.
62
+ *
63
+ * ```ts
64
+ * throw new FatalErrorException("This error should never happen. Please, contact the support team.");
65
+ * ```
66
+ *
67
+ * @param message The message that describes the error.
68
+ * @param cause The previous caught error that caused this one, if any.
69
+ * @param name The name of the exception. Default is `"FatalErrorException"`.
70
+ */
32
71
  constructor(e, n, s = "FatalErrorException") {
33
72
  e === void 0 && (e = "The program has encountered an unrecoverable error and cannot continue as expected. Please, try again later. If the problem persists, contact the support team.");
34
73
  super(e, n, s);
35
- a(this, N, "FatalErrorException");
74
+ a(this, $, "FatalErrorException");
36
75
  }
37
76
  }
38
- var z, J;
39
- class ze extends (J = k, z = Symbol.toStringTag, J) {
77
+ var z, D;
78
+ class Be extends (D = x, z = Symbol.toStringTag, D) {
79
+ /**
80
+ * Initializes a new instance of the {@link NotImplementedException} class.
81
+ *
82
+ * ```ts
83
+ * throw new NotImplementedException("This method hasn't been implemented yet. Check back later.");
84
+ * ```
85
+ *
86
+ * @param message The message that describes the error.
87
+ * @param cause The previous caught error that caused this one, if any.
88
+ * @param name The name of the exception. Default is `"NotImplementedException"`.
89
+ */
40
90
  constructor(e, n, s = "NotImplementedException") {
41
- e === void 0 && (e = "This feature is not implemented yet. Please, try again later.");
91
+ e === void 0 && (e = "This feature isn't implemented yet. Please, try again later.");
42
92
  super(e, n, s);
43
93
  a(this, z, "NotImplementedException");
44
94
  }
45
95
  }
46
- var V, W;
47
- class Ae extends (W = f, V = Symbol.toStringTag, W) {
96
+ var B, J;
97
+ class $e extends (J = c, B = Symbol.toStringTag, J) {
98
+ /**
99
+ * Initializes a new instance of the {@link FileException} class.
100
+ *
101
+ * ```ts
102
+ * throw new FileException("An error occurred while trying to read the file.");
103
+ * ```
104
+ *
105
+ * @param message The message that describes the error.
106
+ * @param cause The previous caught error that caused this one, if any.
107
+ * @param name The name of the exception. Default is `"FileException"`.
108
+ */
48
109
  constructor(e, n, s = "FileException") {
49
110
  super(e, n, s);
50
- a(this, V, "FileException");
111
+ a(this, B, "FileException");
51
112
  }
52
113
  }
53
- var B, G;
54
- class Ze extends (G = Ae, B = Symbol.toStringTag, G) {
114
+ var Y, L;
115
+ class Ue extends (L = $e, Y = Symbol.toStringTag, L) {
116
+ /**
117
+ * Initializes a new instance of the {@link FileExistsException} class.
118
+ *
119
+ * ```ts
120
+ * throw new FileExistsException("The file named 'data.json' already exists on the server.");
121
+ * ```
122
+ *
123
+ * @param message The message that describes the error.
124
+ * @param cause The previous caught error that caused this one, if any.
125
+ * @param name The name of the exception. Default is `"FileExistsException"`.
126
+ */
55
127
  constructor(e, n, s = "FileExistsException") {
56
128
  super(e, n, s);
57
- a(this, B, "FileExistsException");
129
+ a(this, Y, "FileExistsException");
58
130
  }
59
131
  }
60
- var K, L;
61
- class Ue extends (L = Ae, K = Symbol.toStringTag, L) {
132
+ var G, K;
133
+ class et extends (K = $e, G = Symbol.toStringTag, K) {
134
+ /**
135
+ * Initializes a new instance of the {@link FileNotFoundException} class.
136
+ *
137
+ * ```ts
138
+ * throw new FileNotFoundException("The file named 'data.json' wasn't found on the server.");
139
+ * ```
140
+ *
141
+ * @param message The message that describes the error.
142
+ * @param cause The previous caught error that caused this one, if any.
143
+ * @param name The name of the exception. Default is `"FileNotFoundException"`.
144
+ */
62
145
  constructor(e, n, s = "FileNotFoundException") {
63
146
  super(e, n, s);
64
- a(this, K, "FileNotFoundException");
147
+ a(this, G, "FileNotFoundException");
65
148
  }
66
149
  }
67
150
  var H, Q;
68
- class x extends (Q = f, H = Symbol.toStringTag, Q) {
151
+ class b extends (Q = c, H = Symbol.toStringTag, Q) {
152
+ /**
153
+ * Initializes a new instance of the {@link KeyException} class.
154
+ *
155
+ * ```ts
156
+ * throw new KeyException("The 'id' key wasn't found in the dictionary.");
157
+ * ```
158
+ *
159
+ * @param message The message that describes the error.
160
+ * @param cause The previous caught error that caused this one, if any.
161
+ * @param name The name of the exception. Default is `"KeyException"`.
162
+ */
69
163
  constructor(e, n, s = "KeyException") {
70
164
  super(e, n, s);
71
165
  a(this, H, "KeyException");
72
166
  }
73
167
  }
74
- var X, Z;
75
- class et extends (Z = f, X = Symbol.toStringTag, Z) {
168
+ var V, X;
169
+ class tt extends (X = c, V = Symbol.toStringTag, X) {
170
+ /**
171
+ * Initializes a new instance of the {@link NetworkException} class.
172
+ *
173
+ * ```ts
174
+ * throw new NetworkException("Couldn't connect to the server. Please, try again later.");
175
+ * ```
176
+ *
177
+ * @param message The message that describes the error.
178
+ * @param cause The previous caught error that caused this one, if any.
179
+ * @param name The name of the exception. Default is `"NetworkException"`.
180
+ */
76
181
  constructor(e, n, s = "NetworkException") {
77
182
  super(e, n, s);
78
- a(this, X, "NetworkException");
183
+ a(this, V, "NetworkException");
79
184
  }
80
185
  }
81
- var U, ee;
82
- class tt extends (ee = f, U = Symbol.toStringTag, ee) {
186
+ var Z, W;
187
+ class nt extends (W = c, Z = Symbol.toStringTag, W) {
188
+ /**
189
+ * Initializes a new instance of the {@link PermissionException} class.
190
+ *
191
+ * ```ts
192
+ * throw new PermissionException("You don't have permission to access this resource.");
193
+ * ```
194
+ *
195
+ * @param message The message that describes the error.
196
+ * @param cause The previous caught error that caused this one, if any.
197
+ * @param name The name of the exception. Default is `"PermissionException"`.
198
+ */
83
199
  constructor(e, n, s = "PermissionException") {
84
200
  super(e, n, s);
85
- a(this, U, "PermissionException");
201
+ a(this, Z, "PermissionException");
86
202
  }
87
203
  }
88
- var te, ne;
89
- class Je extends (ne = f, te = Symbol.toStringTag, ne) {
204
+ var U, ee;
205
+ class C extends (ee = c, U = Symbol.toStringTag, ee) {
206
+ /**
207
+ * Initializes a new instance of the {@link ReferenceException} class.
208
+ *
209
+ * ```ts
210
+ * throw new ReferenceException("The 'canvas' element wasn't found in the document.");
211
+ * ```
212
+ *
213
+ * @param message The message that describes the error.
214
+ * @param cause The previous caught error that caused this one, if any.
215
+ * @param name The name of the exception. Default is `"ReferenceException"`.
216
+ */
90
217
  constructor(e, n, s = "ReferenceException") {
91
218
  super(e, n, s);
92
- a(this, te, "ReferenceException");
219
+ a(this, U, "ReferenceException");
93
220
  }
94
221
  }
95
- var se, re;
96
- class m extends (re = f, se = Symbol.toStringTag, re) {
222
+ var te, ne;
223
+ class y extends (ne = c, te = Symbol.toStringTag, ne) {
224
+ /**
225
+ * Initializes a new instance of the {@link RuntimeException} class.
226
+ *
227
+ * ```ts
228
+ * throw new RuntimeException("The received input seems to be malformed or corrupted.");
229
+ * ```
230
+ *
231
+ * @param message The message that describes the error.
232
+ * @param cause The previous caught error that caused this one, if any.
233
+ * @param name The name of the exception. Default is `"RuntimeException"`.
234
+ */
97
235
  constructor(e, n, s = "RuntimeException") {
98
236
  super(e, n, s);
99
- a(this, se, "RuntimeException");
237
+ a(this, te, "RuntimeException");
100
238
  }
101
239
  }
102
- var ie, oe;
103
- class Ve extends (oe = m, ie = Symbol.toStringTag, oe) {
240
+ var se, re;
241
+ class Je extends (re = y, se = Symbol.toStringTag, re) {
242
+ /**
243
+ * Initializes a new instance of the {@link EnvironmentException} class.
244
+ *
245
+ * ```ts
246
+ * throw new EnvironmentException("The required environment variable 'API_KEY' isn't set.");
247
+ * ```
248
+ *
249
+ * @param message The message that describes the error.
250
+ * @param cause The previous caught error that caused this one, if any.
251
+ * @param name The name of the exception. Default is `"EnvironmentException"`.
252
+ */
104
253
  constructor(e, n, s = "EnvironmentException") {
105
254
  super(e, n, s);
106
- a(this, ie, "EnvironmentException");
255
+ a(this, se, "EnvironmentException");
107
256
  }
108
257
  }
109
- var ae, le;
110
- class We extends (le = f, ae = Symbol.toStringTag, le) {
258
+ var ie, oe;
259
+ class Ye extends (oe = c, ie = Symbol.toStringTag, oe) {
260
+ /**
261
+ * Initializes a new instance of the {@link TimeoutException} class.
262
+ *
263
+ * ```ts
264
+ * throw new TimeoutException("The task took too long to complete.");
265
+ * ```
266
+ *
267
+ * @param message The message that describes the error.
268
+ * @param cause The previous caught error that caused this one, if any.
269
+ * @param name The name of the exception. Default is `"TimeoutException"`.
270
+ */
111
271
  constructor(e, n, s = "TimeoutException") {
112
272
  super(e, n, s);
113
- a(this, ae, "TimeoutException");
273
+ a(this, ie, "TimeoutException");
114
274
  }
115
275
  }
116
- var ue, ce;
117
- class nt extends (ce = f, ue = Symbol.toStringTag, ce) {
276
+ var ae, le;
277
+ class st extends (le = c, ae = Symbol.toStringTag, le) {
278
+ /**
279
+ * Initializes a new instance of the {@link TypeException} class.
280
+ *
281
+ * ```ts
282
+ * throw new TypeException("The 'username' argument must be a valid string.");
283
+ * ```
284
+ *
285
+ * @param message The message that describes the error.
286
+ * @param cause The previous caught error that caused this one, if any.
287
+ * @param name The name of the exception. Default is `"TypeException"`.
288
+ */
118
289
  constructor(e, n, s = "TypeException") {
119
290
  super(e, n, s);
120
- a(this, ue, "TypeException");
291
+ a(this, ae, "TypeException");
121
292
  }
122
293
  }
123
- var he, fe;
124
- class p extends (fe = f, he = Symbol.toStringTag, fe) {
294
+ var ue, ce;
295
+ class d extends (ce = c, ue = Symbol.toStringTag, ce) {
296
+ /**
297
+ * Initializes a new instance of the {@link ValueException} class.
298
+ *
299
+ * ```ts
300
+ * throw new ValueException("The 'grade' argument cannot be negative.");
301
+ * ```
302
+ *
303
+ * @param message The message that describes the error.
304
+ * @param cause The previous caught error that caused this one, if any.
305
+ * @param name The name of the exception. Default is `"ValueException"`.
306
+ */
125
307
  constructor(e, n, s = "ValueException") {
126
308
  super(e, n, s);
127
- a(this, he, "ValueException");
309
+ a(this, ue, "ValueException");
128
310
  }
129
311
  }
130
- var de, me;
131
- class $e extends (me = p, de = Symbol.toStringTag, me) {
312
+ var he, fe;
313
+ class p extends (fe = d, he = Symbol.toStringTag, fe) {
314
+ /**
315
+ * Initializes a new instance of the {@link RangeException} class.
316
+ *
317
+ * ```ts
318
+ * throw new RangeException("The 'percentage' argument must be between 0 and 100.");
319
+ * ```
320
+ *
321
+ * @param message The message that describes the error.
322
+ * @param cause The previous caught error that caused this one, if any.
323
+ * @param name The name of the exception. Default is `"RangeException"`.
324
+ */
132
325
  constructor(e, n, s = "RangeException") {
133
326
  super(e, n, s);
134
- a(this, de, "RangeException");
327
+ a(this, he, "RangeException");
135
328
  }
136
329
  }
137
- var _e;
138
- class c {
330
+ var de;
331
+ class u {
139
332
  constructor(t) {
333
+ /**
334
+ * The native {@link Iterator} object that is being wrapped by this instance.
335
+ */
140
336
  a(this, "_iterator");
141
- a(this, "return");
142
- a(this, "throw");
143
- a(this, _e, "SmartIterator");
144
- t instanceof Function ? this._iterator = t() : Symbol.iterator in t ? this._iterator = t[Symbol.iterator]() : this._iterator = t, this._iterator.return && (this.return = (e) => this._iterator.return(e)), this._iterator.throw && (this.throw = (e) => this._iterator.throw(e));
337
+ a(this, de, "SmartIterator");
338
+ t instanceof Function ? this._iterator = t() : Symbol.iterator in t ? this._iterator = t[Symbol.iterator]() : this._iterator = t;
145
339
  }
340
+ /**
341
+ * Determines whether all elements of the iterator satisfy a given condition.
342
+ * See also {@link SmartIterator.some}.
343
+ *
344
+ * This method will iterate over all elements of the iterator checking if they satisfy the condition.
345
+ * Once a single element doesn't satisfy the condition, the method will return `false` immediately.
346
+ *
347
+ * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
348
+ * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
349
+ * Consider using {@link SmartIterator.find} instead.
350
+ *
351
+ * If the iterator is infinite and every element satisfies the condition, the method will never return.
352
+ *
353
+ * ```ts
354
+ * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
355
+ * const result = iterator.every((value) => value < 0);
356
+ *
357
+ * console.log(result); // false
358
+ * ```
359
+ *
360
+ * @param predicate The condition to check for each element of the iterator.
361
+ *
362
+ * @returns `true` if all elements satisfy the condition, `false` otherwise.
363
+ */
146
364
  every(t) {
147
365
  let e = 0;
148
366
  for (; ; ) {
@@ -154,6 +372,30 @@ class c {
154
372
  e += 1;
155
373
  }
156
374
  }
375
+ /**
376
+ * Determines whether any element of the iterator satisfies a given condition.
377
+ * See also {@link SmartIterator.every}.
378
+ *
379
+ * This method will iterate over all elements of the iterator checking if they satisfy the condition.
380
+ * Once a single element satisfies the condition, the method will return `true` immediately.
381
+ *
382
+ * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
383
+ * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
384
+ * Consider using {@link SmartIterator.find} instead.
385
+ *
386
+ * If the iterator is infinite and no element satisfies the condition, the method will never return.
387
+ *
388
+ * ```ts
389
+ * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
390
+ * const result = iterator.some((value) => value < 0);
391
+ *
392
+ * console.log(result); // true
393
+ * ```
394
+ *
395
+ * @param predicate The condition to check for each element of the iterator.
396
+ *
397
+ * @returns `true` if any element satisfies the condition, `false` otherwise.
398
+ */
157
399
  some(t) {
158
400
  let e = 0;
159
401
  for (; ; ) {
@@ -167,7 +409,7 @@ class c {
167
409
  }
168
410
  filter(t) {
169
411
  const e = this._iterator;
170
- return new c(function* () {
412
+ return new u(function* () {
171
413
  let n = 0;
172
414
  for (; ; ) {
173
415
  const s = e.next();
@@ -177,9 +419,35 @@ class c {
177
419
  }
178
420
  });
179
421
  }
422
+ /**
423
+ * Maps the elements of the iterator using a given transformation function.
424
+ *
425
+ * This method will iterate over all elements of the iterator applying the transformation function.
426
+ * The result of each transformation will be included in the new iterator.
427
+ *
428
+ * Since the iterator is lazy, the mapping process will
429
+ * be executed once the resulting iterator is materialized.
430
+ *
431
+ * A new iterator will be created, holding the reference to the original one.
432
+ * This means that the original iterator won't be consumed until the
433
+ * new one is and that consuming one of them will consume the other as well.
434
+ *
435
+ * ```ts
436
+ * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
437
+ * const result = iterator.map((value) => Math.abs(value));
438
+ *
439
+ * console.log(result.toArray()); // [2, 1, 0, 1, 2]
440
+ * ```
441
+ *
442
+ * @template V The type of the elements after the transformation.
443
+ *
444
+ * @param iteratee The transformation function to apply to each element of the iterator.
445
+ *
446
+ * @returns A new {@link SmartIterator} containing the transformed elements.
447
+ */
180
448
  map(t) {
181
449
  const e = this._iterator;
182
- return new c(function* () {
450
+ return new u(function* () {
183
451
  let n = 0;
184
452
  for (; ; ) {
185
453
  const s = e.next();
@@ -194,7 +462,7 @@ class c {
194
462
  if (s === void 0) {
195
463
  const r = this._iterator.next();
196
464
  if (r.done)
197
- throw new p("Cannot reduce an empty iterator without an initial value.");
465
+ throw new d("Cannot reduce an empty iterator without an initial value.");
198
466
  s = r.value, n += 1;
199
467
  }
200
468
  for (; ; ) {
@@ -204,24 +472,79 @@ class c {
204
472
  s = t(s, r.value, n), n += 1;
205
473
  }
206
474
  }
475
+ /**
476
+ * Flattens the elements of the iterator using a given transformation function.
477
+ *
478
+ * This method will iterate over all elements of the iterator applying the transformation function.
479
+ * The result of each transformation will be flattened into the new iterator.
480
+ *
481
+ * Since the iterator is lazy, the flattening process will
482
+ * be executed once the resulting iterator is materialized.
483
+ *
484
+ * A new iterator will be created, holding the reference to the original one.
485
+ * This means that the original iterator won't be consumed until the
486
+ * new one is and that consuming one of them will consume the other as well.
487
+ *
488
+ * ```ts
489
+ * const iterator = new SmartIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);
490
+ * const result = iterator.flatMap((value) => value);
491
+ *
492
+ * console.log(result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]
493
+ * ```
494
+ *
495
+ * @template V The type of the elements after the transformation.
496
+ *
497
+ * @param iteratee The transformation function to apply to each element of the iterator.
498
+ *
499
+ * @returns A new {@link SmartIterator} containing the flattened elements.
500
+ */
207
501
  flatMap(t) {
208
502
  const e = this._iterator;
209
- return new c(function* () {
503
+ return new u(function* () {
210
504
  let n = 0;
211
505
  for (; ; ) {
212
506
  const s = e.next();
213
507
  if (s.done)
214
508
  return s.value;
215
509
  const r = t(s.value, n);
216
- for (const o of r)
217
- yield o;
510
+ if (r instanceof Array)
511
+ for (const o of r)
512
+ yield o;
513
+ else
514
+ yield r;
218
515
  n += 1;
219
516
  }
220
517
  });
221
518
  }
519
+ /**
520
+ * Drops a given number of elements at the beginning of the iterator.
521
+ * The remaining elements will be included in a new iterator.
522
+ * See also {@link SmartIterator.take}.
523
+ *
524
+ * Since the iterator is lazy, the dropping process will
525
+ * be executed once the resulting iterator is materialized.
526
+ *
527
+ * A new iterator will be created, holding the reference to the original one.
528
+ * This means that the original iterator won't be consumed until the
529
+ * new one is and that consuming one of them will consume the other as well.
530
+ *
531
+ * Only the dropped elements will be consumed in the process.
532
+ * The rest of the iterator will be consumed only once the new one is.
533
+ *
534
+ * ```ts
535
+ * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
536
+ * const result = iterator.drop(3);
537
+ *
538
+ * console.log(result.toArray()); // [1, 2]
539
+ * ```
540
+ *
541
+ * @param count The number of elements to drop.
542
+ *
543
+ * @returns A new {@link SmartIterator} containing the remaining elements.
544
+ */
222
545
  drop(t) {
223
546
  const e = this._iterator;
224
- return new c(function* () {
547
+ return new u(function* () {
225
548
  let n = 0;
226
549
  for (; n < t; ) {
227
550
  if (e.next().done)
@@ -236,9 +559,36 @@ class c {
236
559
  }
237
560
  });
238
561
  }
562
+ /**
563
+ * Takes a given number of elements at the beginning of the iterator.
564
+ * These elements will be included in a new iterator.
565
+ * See also {@link SmartIterator.drop}.
566
+ *
567
+ * Since the iterator is lazy, the taking process will
568
+ * be executed once the resulting iterator is materialized.
569
+ *
570
+ * A new iterator will be created, holding the reference to the original one.
571
+ * This means that the original iterator won't be consumed until the
572
+ * new one is and that consuming one of them will consume the other as well.
573
+ *
574
+ * Only the taken elements will be consumed from the original iterator.
575
+ * The rest of the original iterator will be available for further consumption.
576
+ *
577
+ * ```ts
578
+ * const iterator = new SmartIterator<number>([-2, -1, 0, 1, 2]);
579
+ * const result = iterator.take(3);
580
+ *
581
+ * console.log(result.toArray()); // [-2, -1, 0]
582
+ * console.log(iterator.toArray()); // [1, 2]
583
+ * ```
584
+ *
585
+ * @param limit The number of elements to take.
586
+ *
587
+ * @returns A new {@link SmartIterator} containing the taken elements.
588
+ */
239
589
  take(t) {
240
590
  const e = this._iterator;
241
- return new c(function* () {
591
+ return new u(function* () {
242
592
  let n = 0;
243
593
  for (; n < t; ) {
244
594
  const s = e.next();
@@ -259,12 +609,52 @@ class c {
259
609
  e += 1;
260
610
  }
261
611
  }
612
+ /**
613
+ * Enumerates the elements of the iterator.
614
+ * Each element is be paired with its index in a new iterator.
615
+ *
616
+ * Since the iterator is lazy, the enumeration process will
617
+ * be executed once the resulting iterator is materialized.
618
+ *
619
+ * A new iterator will be created, holding the reference to the original one.
620
+ * This means that the original iterator won't be consumed until the
621
+ * new one is and that consuming one of them will consume the other as well.
622
+ *
623
+ * ```ts
624
+ * const iterator = new SmartIterator<string>(["A", "M", "N", "Z"]);
625
+ * const result = iterator.enumerate();
626
+ *
627
+ * console.log(result.toArray()); // [[0, "A"], [1, "M"], [2, "N"], [3, "Z"]]
628
+ * ```
629
+ *
630
+ * @returns A new {@link SmartIterator} containing the enumerated elements.
631
+ */
262
632
  enumerate() {
263
633
  return this.map((t, e) => [e, t]);
264
634
  }
635
+ /**
636
+ * Removes all duplicate elements from the iterator.
637
+ * The first occurrence of each element will be kept.
638
+ *
639
+ * Since the iterator is lazy, the deduplication process will
640
+ * be executed once the resulting iterator is materialized.
641
+ *
642
+ * A new iterator will be created, holding the reference to the original one.
643
+ * This means that the original iterator won't be consumed until the
644
+ * new one is and that consuming one of them will consume the other as well.
645
+ *
646
+ * ```ts
647
+ * const iterator = new SmartIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);
648
+ * const result = iterator.unique();
649
+ *
650
+ * console.log(result.toArray()); // [1, 2, 3, 4, 5]
651
+ * ```
652
+ *
653
+ * @returns A new {@link SmartIterator} containing only the unique elements.
654
+ */
265
655
  unique() {
266
656
  const t = this._iterator;
267
- return new c(function* () {
657
+ return new u(function* () {
268
658
  const e = /* @__PURE__ */ new Set();
269
659
  for (; ; ) {
270
660
  const n = t.next();
@@ -274,6 +664,21 @@ class c {
274
664
  }
275
665
  });
276
666
  }
667
+ /**
668
+ * Counts the number of elements in the iterator.
669
+ * This method will consume the entire iterator in the process.
670
+ *
671
+ * If the iterator is infinite, the method will never return.
672
+ *
673
+ * ```ts
674
+ * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);
675
+ * const result = iterator.count();
676
+ *
677
+ * console.log(result); // 5
678
+ * ```
679
+ *
680
+ * @returns The number of elements in the iterator.
681
+ */
277
682
  count() {
278
683
  let t = 0;
279
684
  for (; ; ) {
@@ -282,6 +687,23 @@ class c {
282
687
  t += 1;
283
688
  }
284
689
  }
690
+ /**
691
+ * Iterates over all elements of the iterator.
692
+ * The elements are passed to the function along with their index.
693
+ *
694
+ * This method will consume the entire iterator in the process.
695
+ * If the iterator is infinite, the method will never return.
696
+ *
697
+ * ```ts
698
+ * const iterator = new SmartIterator<number>(["A", "M", "N", "Z"]);
699
+ * iterator.forEach((value, index) =>
700
+ * {
701
+ * console.log(`${index}: ${value}`); // "0: A", "1: M", "2: N", "3: Z"
702
+ * }
703
+ * ```
704
+ *
705
+ * @param iteratee The function to apply to each element of the iterator.
706
+ */
285
707
  forEach(t) {
286
708
  let e = 0;
287
709
  for (; ; ) {
@@ -291,33 +713,226 @@ class c {
291
713
  t(n.value, e), e += 1;
292
714
  }
293
715
  }
716
+ /**
717
+ * Advances the iterator to the next element and returns the result.
718
+ * If the iterator requires it, a value must be provided to be passed to the next element.
719
+ *
720
+ * Once the iterator is done, the method will return an object with the `done` property set to `true`.
721
+ *
722
+ * ```ts
723
+ * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5]);
724
+ *
725
+ * let result = iterator.next();
726
+ * while (!result.done)
727
+ * {
728
+ * console.log(result.value); // 1, 2, 3, 4, 5
729
+ *
730
+ * result = iterator.next();
731
+ * }
732
+ *
733
+ * console.log(result); // { done: true, value: undefined }
734
+ * ```
735
+ *
736
+ * @param values The value to pass to the next element, if required.
737
+ *
738
+ * @returns The result of the iteration, containing the value of the operation.
739
+ */
294
740
  next(...t) {
295
741
  return this._iterator.next(...t);
296
742
  }
743
+ /**
744
+ * An utility method that may be used to close the iterator gracefully,
745
+ * free the resources and perform any cleanup operation.
746
+ * It may also be used to signal the end or to compute a specific final result of the iteration process.
747
+ *
748
+ * ```ts
749
+ * const iterator = new SmartIterator<number>({
750
+ * _index: 0,
751
+ * next: function()
752
+ * {
753
+ * return { done: false, value: this._index += 1 };
754
+ * },
755
+ * return: function() { console.log("Closing the iterator..."); }
756
+ * });
757
+ *
758
+ * for (const value of iterator)
759
+ * {
760
+ * if (value > 5) { break; } // Closing the iterator...
761
+ *
762
+ * console.log(value); // 1, 2, 3, 4, 5
763
+ * }
764
+ * ```
765
+ *
766
+ * @param value The final value of the iterator.
767
+ *
768
+ * @returns The result of the iterator.
769
+ */
770
+ return(t) {
771
+ return this._iterator.return ? this._iterator.return(t) : { done: !0, value: t };
772
+ }
773
+ /**
774
+ * An utility method that may be used to close the iterator due to an error,
775
+ * free the resources and perform any cleanup operation.
776
+ * It may also be used to signal that an error occurred during the iteration process or to handle it.
777
+ *
778
+ * ```ts
779
+ * const iterator = new SmartIterator<number>({
780
+ * _index: 0,
781
+ * next: function()
782
+ * {
783
+ * return { done: this._index > 10, value: this._index += 1 };
784
+ * },
785
+ * throw: function(error)
786
+ * {
787
+ * console.warn(error.message);
788
+ *
789
+ * this._index = 0;
790
+ * }
791
+ * });
792
+ *
793
+ * for (const value of iterator) // 1, 2, 3, 4, 5, "The index is too high.", 1, 2, 3, 4, 5, ...
794
+ * {
795
+ * try
796
+ * {
797
+ * if (value > 5) { throw new Error("The index is too high."); }
798
+ *
799
+ * console.log(value); // 1, 2, 3, 4, 5
800
+ * }
801
+ * catch (error) { iterator.throw(error); }
802
+ * }
803
+ * ```
804
+ *
805
+ * @param error The error to throw into the iterator.
806
+ *
807
+ * @returns The final result of the iterator.
808
+ */
809
+ throw(t) {
810
+ if (this._iterator.throw)
811
+ return this._iterator.throw(t);
812
+ throw t;
813
+ }
814
+ /**
815
+ * An utility method that aggregates the elements of the iterator using a given key function.
816
+ * The elements will be grouped by the resulting keys in a new specialized iterator.
817
+ * See {@link AggregatedIterator}.
818
+ *
819
+ * Since the iterator is lazy, the grouping process will
820
+ * be executed once the resulting iterator is materialized.
821
+ *
822
+ * A new iterator will be created, holding the reference to the original one.
823
+ * This means that the original iterator won't be consumed until the
824
+ * the new one is and that consuming one of them will consume the other as well.
825
+ *
826
+ * ```ts
827
+ * const iterator = new SmartIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
828
+ * const result = iterator.groupBy<string>((value) => value % 2 === 0 ? "even" : "odd");
829
+ *
830
+ * console.log(result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }
831
+ * ```
832
+ *
833
+ * @template K The type of the keys used to group the elements.
834
+ *
835
+ * @param iteratee The key function to apply to each element of the iterator.
836
+ *
837
+ * @returns A new instance of the {@link AggregatedIterator} class containing the grouped elements.
838
+ */
297
839
  groupBy(t) {
298
- return new S(this.map((e, n) => [t(e, n), e]));
840
+ return new g(this.map((e, n) => [t(e, n), e]));
299
841
  }
842
+ /**
843
+ * Materializes the iterator into an array.
844
+ * This method will consume the entire iterator in the process.
845
+ *
846
+ * If the iterator is infinite, the method will never return.
847
+ *
848
+ * ```ts
849
+ * const iterator = new SmartIterator(function* ()
850
+ * {
851
+ * for (let i = 0; i < 5; i += 1) { yield i; }
852
+ * });
853
+ * const result = iterator.toArray();
854
+ *
855
+ * console.log(result); // [0, 1, 2, 3, 4]
856
+ * ```
857
+ *
858
+ * @returns The {@link Array} containing all elements of the iterator.
859
+ */
300
860
  toArray() {
301
861
  return Array.from(this);
302
862
  }
303
- [(_e = Symbol.toStringTag, Symbol.iterator)]() {
863
+ [(de = Symbol.toStringTag, Symbol.iterator)]() {
304
864
  return this;
305
865
  }
306
866
  }
307
- var we;
308
- we = Symbol.toStringTag;
309
- const b = class b {
867
+ var me;
868
+ me = Symbol.toStringTag;
869
+ const _ = class _ {
310
870
  constructor(t) {
871
+ /**
872
+ * The internal {@link SmartIterator} object that holds the reduced elements.
873
+ */
311
874
  a(this, "_elements");
312
- a(this, we, "ReducedIterator");
313
- this._elements = new c(t);
875
+ a(this, me, "ReducedIterator");
876
+ this._elements = new u(t);
314
877
  }
878
+ /**
879
+ * Determines whether all elements of the reduced iterator satisfy the given condition.
880
+ * See also {@link ReducedIterator.some}.
881
+ *
882
+ * This method will iterate over all the elements of the iterator checking if they satisfy the condition.
883
+ * Once a single element doesn't satisfy the condition, the method will return `false` immediately.
884
+ *
885
+ * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
886
+ * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
887
+ * Consider using {@link ReducedIterator.find} instead.
888
+ *
889
+ * If the iterator is infinite and every element satisfies the condition, the method will never return.
890
+ *
891
+ * ```ts
892
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
893
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
894
+ * .reduce((key, accumulator, value) => accumulator + value)
895
+ * .every((key, value) => value > 0);
896
+ *
897
+ * console.log(results); // true
898
+ * ```
899
+ *
900
+ * @param predicate The condition to check for each element of the iterator.
901
+ *
902
+ * @returns `true` if all elements satisfy the condition, `false` otherwise.
903
+ */
315
904
  every(t) {
316
905
  for (const [e, [n, s]] of this._elements.enumerate())
317
906
  if (!t(n, s, e))
318
907
  return !1;
319
908
  return !0;
320
909
  }
910
+ /**
911
+ * Determines whether any element of the reduced iterator satisfies the given condition.
912
+ * See also {@link ReducedIterator.every}.
913
+ *
914
+ * This method will iterate over all the elements of the iterator checking if they satisfy the condition.
915
+ * Once a single element satisfies the condition, the method will return `true` immediately.
916
+ *
917
+ * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
918
+ * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
919
+ * Consider using {@link ReducedIterator.find} instead.
920
+ *
921
+ * If the iterator is infinite and no element satisfies the condition, the method will never return.
922
+ *
923
+ * ```ts
924
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
925
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
926
+ * .reduce((key, accumulator, value) => accumulator + value)
927
+ * .some((key, value) => value > 0);
928
+ *
929
+ * console.log(results); // true
930
+ * ```
931
+ *
932
+ * @param predicate The condition to check for each element of the iterator.
933
+ *
934
+ * @returns `true` if any element satisfies the condition, `false` otherwise.
935
+ */
321
936
  some(t) {
322
937
  for (const [e, [n, s]] of this._elements.enumerate())
323
938
  if (t(n, s, e))
@@ -326,14 +941,42 @@ const b = class b {
326
941
  }
327
942
  filter(t) {
328
943
  const e = this._elements.enumerate();
329
- return new b(function* () {
944
+ return new _(function* () {
330
945
  for (const [n, [s, r]] of e)
331
946
  t(s, r, n) && (yield [s, r]);
332
947
  });
333
948
  }
949
+ /**
950
+ * Maps the elements of the reduced iterator using a given transformation function.
951
+ *
952
+ * This method will iterate over all the elements of the iterator applying the transformation function.
953
+ * The result of the transformation will be included in the new iterator.
954
+ *
955
+ * Since the iterator is lazy, the mapping process will
956
+ * be executed once the resulting iterator is materialized.
957
+ *
958
+ * A new iterator will be created, holding the reference to the original one.
959
+ * This means that the original iterator won't be consumed until the
960
+ * new one is and that consuming one of them will consume the other as well.
961
+ *
962
+ * ```ts
963
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
964
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
965
+ * .reduce((key, accumulator, value) => accumulator + value)
966
+ * .map((key, value) => value * 2);
967
+ *
968
+ * console.log(results.toObject()); // { odd: 8, even: 32 }
969
+ * ```
970
+ *
971
+ * @template V The type of the elements after the transformation.
972
+ *
973
+ * @param iteratee The transformation function to apply to each element of the iterator.
974
+ *
975
+ * @returns A new {@link ReducedIterator} containing the transformed elements.
976
+ */
334
977
  map(t) {
335
978
  const e = this._elements.enumerate();
336
- return new b(function* () {
979
+ return new _(function* () {
337
980
  for (const [n, [s, r]] of e)
338
981
  yield [s, t(s, r, n)];
339
982
  });
@@ -343,31 +986,122 @@ const b = class b {
343
986
  if (s === void 0) {
344
987
  const r = this._elements.next();
345
988
  if (r.done)
346
- throw new p("Cannot reduce an empty iterator without an initial value.");
989
+ throw new d("Cannot reduce an empty iterator without an initial value.");
347
990
  s = r.value[1], n += 1;
348
991
  }
349
992
  for (const [r, o] of this._elements)
350
993
  s = t(r, s, o, n), n += 1;
351
994
  return s;
352
995
  }
996
+ /**
997
+ * Flattens the elements of the reduced iterator using a given transformation function.
998
+ *
999
+ * This method will iterate over all the elements of the iterator applying the transformation function.
1000
+ * The result of each transformation will be flattened into the new iterator.
1001
+ *
1002
+ * Since the iterator is lazy, the flattening process will
1003
+ * be executed once the resulting iterator is materialized.
1004
+ *
1005
+ * A new iterator will be created, holding the reference to the original one.
1006
+ * This means that the original iterator won't be consumed until the
1007
+ * new one is and that consuming one of them will consume the other as well.
1008
+ *
1009
+ * ```ts
1010
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1011
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1012
+ * .reduce((key, accumulator, value) => accumulator.concat([value]), () => [])
1013
+ * .flatMap((key, value) => value);
1014
+ *
1015
+ * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
1016
+ * ```
1017
+ *
1018
+ * @template V The type of the elements after the transformation.
1019
+ *
1020
+ * @param iteratee The transformation function to apply to each element of the iterator.
1021
+ *
1022
+ * @returns A new {@link AggregatedIterator} containing the flattened elements.
1023
+ */
353
1024
  flatMap(t) {
354
1025
  const e = this._elements.enumerate();
355
- return new S(function* () {
356
- for (const [n, [s, r]] of e)
357
- for (const o of t(s, r, n))
1026
+ return new g(function* () {
1027
+ for (const [n, [s, r]] of e) {
1028
+ const o = t(s, r, n);
1029
+ if (o instanceof Array)
1030
+ for (const l of o)
1031
+ yield [s, l];
1032
+ else
358
1033
  yield [s, o];
1034
+ }
359
1035
  });
360
1036
  }
361
- drop(t) {
362
- const e = this._elements.enumerate();
363
- return new b(function* () {
364
- for (const [n, [s, r]] of e)
1037
+ /**
1038
+ * Drops a given number of elements at the beginning of the reduced iterator.
1039
+ * The remaining elements will be included in the new iterator.
1040
+ * See also {@link ReducedIterator.take}.
1041
+ *
1042
+ * Since the iterator is lazy, the dropping process will
1043
+ * be executed once the resulting iterator is materialized.
1044
+ *
1045
+ * A new iterator will be created, holding the reference to the original one.
1046
+ * This means that the original iterator won't be consumed until the
1047
+ * new one is and that consuming one of them will consume the other as well.
1048
+ *
1049
+ * Only the dropped elements will be consumed in the process.
1050
+ * The rest of the iterator will be consumed once the new iterator is.
1051
+ *
1052
+ * ```ts
1053
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1054
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1055
+ * .reduce((key, accumulator, value) => accumulator.concat(value), () => [])
1056
+ * .drop(1);
1057
+ *
1058
+ * console.log(results.toObject()); // { even: [0, 2, 6, 8] }
1059
+ * ```
1060
+ *
1061
+ * @param count The number of elements to drop.
1062
+ *
1063
+ * @returns A new {@link ReducedIterator} containing the remaining elements.
1064
+ */
1065
+ drop(t) {
1066
+ const e = this._elements.enumerate();
1067
+ return new _(function* () {
1068
+ for (const [n, [s, r]] of e)
365
1069
  n >= t && (yield [s, r]);
366
1070
  });
367
1071
  }
1072
+ /**
1073
+ * Takes a given number of elements at the beginning of the reduced iterator.
1074
+ * The elements will be included in the new iterator.
1075
+ * See also {@link ReducedIterator.drop}.
1076
+ *
1077
+ * Since the iterator is lazy, the taking process will
1078
+ * be executed once the resulting iterator is materialized.
1079
+ *
1080
+ * A new iterator will be created, holding the reference to the original one.
1081
+ * This means that the original iterator won't be consumed until the
1082
+ * new one is and that consuming one of them will consume the other as well.
1083
+ *
1084
+ * Only the taken elements will be consumed from the original reduced iterator.
1085
+ * The rest of the original reduced iterator will be available for further consumption.
1086
+ *
1087
+ * ```ts
1088
+ * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1089
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1090
+ * .reduce((key, accumulator, value) => accumulator.concat(value), () => []);
1091
+ *
1092
+ * const results = iterator.take(1);
1093
+ *
1094
+ * console.log(results.toObject()); // { odd: [-3, -1, 3, 5] }
1095
+ * console.log(reduced.toObject()); // { even: [0, 2, 6, 8] }
1096
+ * ```
1097
+ *
1098
+ * @param count The number of elements to take.
1099
+ *
1100
+ * @returns A new {@link ReducedIterator} containing the taken elements.
1101
+ */
368
1102
  take(t) {
369
1103
  const e = this._elements.enumerate();
370
- return new b(function* () {
1104
+ return new _(function* () {
371
1105
  for (const [n, [s, r]] of e) {
372
1106
  if (n >= t)
373
1107
  break;
@@ -375,88 +1109,377 @@ const b = class b {
375
1109
  }
376
1110
  });
377
1111
  }
1112
+ find(t) {
1113
+ for (const [e, [n, s]] of this._elements.enumerate())
1114
+ if (t(n, s, e))
1115
+ return s;
1116
+ }
1117
+ /**
1118
+ * Enumerates the elements of the reduced iterator.
1119
+ * Each element is paired with its index in a new iterator.
1120
+ *
1121
+ * Since the iterator is lazy, the enumeration process will
1122
+ * be executed once the resulting iterator is materialized.
1123
+ *
1124
+ * A new iterator will be created, holding the reference to the original one.
1125
+ * This means that the original iterator won't be consumed until the
1126
+ * new one is and that consuming one of them will consume the other as well.
1127
+ *
1128
+ * ```ts
1129
+ * const results = new ReducedIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1130
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1131
+ * .reduce((key, accumulator, value) => accumulator + value)
1132
+ * .enumerate();
1133
+ *
1134
+ * console.log(results.toObject()); // [[0, 4], [1, 16]]
1135
+ * ```
1136
+ *
1137
+ * @returns A new {@link ReducedIterator} object containing the enumerated elements.
1138
+ */
378
1139
  enumerate() {
379
1140
  return this.map((t, e, n) => [n, e]);
380
1141
  }
1142
+ /**
1143
+ * Removes all duplicate elements from the reduced iterator.
1144
+ * The first occurrence of each element will be kept.
1145
+ *
1146
+ * Since the iterator is lazy, the deduplication process will
1147
+ * be executed once the resulting iterator is materialized.
1148
+ *
1149
+ * A new iterator will be created, holding the reference to the original one.
1150
+ * This means that the original iterator won't be consumed until the
1151
+ * new one is and that consuming one of them will consume the other as well.
1152
+ *
1153
+ * ```ts
1154
+ * const results = new ReducedIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 1, 5, 6, 8, 7, 2])
1155
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1156
+ * .map((key, value) => Math.abs(value))
1157
+ * .reduce((key, accumulator, value) => accumulator + value)
1158
+ * .unique();
1159
+ *
1160
+ * console.log(results.toObject()); // { odd: 24 }
1161
+ *
1162
+ * @returns A new {@link ReducedIterator} containing only the unique elements.
1163
+ */
381
1164
  unique() {
382
1165
  const t = this._elements;
383
- return new b(function* () {
1166
+ return new _(function* () {
384
1167
  const e = /* @__PURE__ */ new Set();
385
1168
  for (const [n, s] of t)
386
1169
  e.has(s) || (e.add(s), yield [n, s]);
387
1170
  });
388
1171
  }
1172
+ /**
1173
+ * Counts the number of elements in the reduced iterator.
1174
+ * This method will consume the entire iterator in the process.
1175
+ *
1176
+ * If the iterator is infinite, the method will never return.
1177
+ *
1178
+ * ```ts
1179
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1180
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1181
+ * .reduce((key, accumulator, value) => accumulator + value)
1182
+ * .count();
1183
+ *
1184
+ * console.log(results); // 2
1185
+ * ```
1186
+ *
1187
+ * @returns The number of elements in the iterator.
1188
+ */
389
1189
  count() {
390
1190
  let t = 0;
391
1191
  for (const e of this._elements)
392
1192
  t += 1;
393
1193
  return t;
394
1194
  }
1195
+ /**
1196
+ * Iterates over all elements of the reduced iterator.
1197
+ * The elements are passed to the function along with their key and index.
1198
+ *
1199
+ * This method will consume the entire iterator in the process.
1200
+ * If the iterator is infinite, the method will never return.
1201
+ *
1202
+ * ```ts
1203
+ * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1204
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1205
+ * .reduce((key, accumulator, value) => accumulator + value);
1206
+ *
1207
+ * reduced.forEach((key, value, index) =>
1208
+ * {
1209
+ * console.log(`#${index} - ${key}: ${value}`); // "#0 - odd: 4", "#1 - even: 16"
1210
+ * });
1211
+ * ```
1212
+ *
1213
+ * @param iteratee The function to apply to each element of the reduced iterator.
1214
+ */
395
1215
  forEach(t) {
396
1216
  for (const [e, [n, s]] of this._elements.enumerate())
397
1217
  t(n, s, e);
398
1218
  }
1219
+ /**
1220
+ * Reaggregates the elements of the reduced iterator.
1221
+ * The elements are grouped by a new key computed by the given iteratee function.
1222
+ *
1223
+ * Since the iterator is lazy, the reorganizing process will
1224
+ * be executed once the resulting iterator is materialized.
1225
+ *
1226
+ * A new iterator will be created, holding the reference to the original one.
1227
+ * This means that the original iterator won't be consumed until the
1228
+ * new one is and that consuming one of them will consume the other as well.
1229
+ *
1230
+ * ```ts
1231
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, -6, -8])
1232
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1233
+ * .reduce((key, accumulator, value) => accumulator + value)
1234
+ * .reorganizeBy((key, value) => value > 0 ? "positive" : "negative");
1235
+ *
1236
+ * console.log(results.toObject()); // { positive: 4, negative: -12 }
1237
+ * ```
1238
+ *
1239
+ * @template J The type of the new keys used to group the elements.
1240
+ *
1241
+ * @param iteratee The function to determine the new key of each element of the iterator.
1242
+ *
1243
+ * @returns A new {@link AggregatedIterator} containing the elements reorganized by the new keys.
1244
+ */
1245
+ reorganizeBy(t) {
1246
+ const e = this._elements.enumerate();
1247
+ return new g(function* () {
1248
+ for (const [n, [s, r]] of e)
1249
+ yield [t(s, r, n), r];
1250
+ });
1251
+ }
1252
+ /**
1253
+ * An utility method that returns a new {@link SmartIterator}
1254
+ * object containing all the keys of the iterator.
1255
+ *
1256
+ * Since the iterator is lazy, the keys will be extracted
1257
+ * be executed once the resulting iterator is materialized.
1258
+ *
1259
+ * A new iterator will be created, holding the reference to the original one.
1260
+ * This means that the original iterator won't be consumed until the
1261
+ * new one is and that consuming one of them will consume the other as well.
1262
+ *
1263
+ * ```ts
1264
+ * const keys = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1265
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1266
+ * .reduce((key, accumulator, value) => accumulator + value)
1267
+ * .keys();
1268
+ *
1269
+ * console.log(keys.toArray()); // ["odd", "even"]
1270
+ * ```
1271
+ *
1272
+ * @returns A new {@link SmartIterator} containing all the keys of the iterator.
1273
+ */
399
1274
  keys() {
400
1275
  const t = this._elements;
401
- return new c(function* () {
1276
+ return new u(function* () {
402
1277
  for (const [e] of t)
403
1278
  yield e;
404
1279
  });
405
1280
  }
406
- items() {
1281
+ /**
1282
+ * An utility method that returns a new {@link SmartIterator}
1283
+ * object containing all the entries of the iterator.
1284
+ * Each entry is a tuple containing the key and the element.
1285
+ *
1286
+ * Since the iterator is lazy, the entries will be extracted
1287
+ * be executed once the resulting iterator is materialized.
1288
+ *
1289
+ * A new iterator will be created, holding the reference to the original one.
1290
+ * This means that the original iterator won't be consumed until the
1291
+ * new one is and that consuming one of them will consume the other as well.
1292
+ *
1293
+ * ```ts
1294
+ * const entries = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1295
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1296
+ * .reduce((key, accumulator, value) => accumulator + value)
1297
+ * .entries();
1298
+ *
1299
+ * console.log(entries.toArray()); // [["odd", 4], ["even", 16]]
1300
+ * ```
1301
+ *
1302
+ * @returns A new {@link SmartIterator} containing all the entries of the iterator.
1303
+ */
1304
+ entries() {
407
1305
  return this._elements;
408
1306
  }
1307
+ /**
1308
+ * An utility method that returns a new {@link SmartIterator}
1309
+ * object containing all the values of the iterator.
1310
+ *
1311
+ * Since the iterator is lazy, the values will be extracted
1312
+ * be executed once the resulting iterator is materialized.
1313
+ *
1314
+ * A new iterator will be created, holding the reference to the original one.
1315
+ * This means that the original iterator won't be consumed until the
1316
+ * new one is and that consuming one of them will consume the other as well.
1317
+ *
1318
+ * ```ts
1319
+ * const values = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1320
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1321
+ * .reduce((key, accumulator, value) => accumulator + value)
1322
+ * .values();
1323
+ *
1324
+ * console.log(values.toArray()); // [4, 16]
1325
+ * ```
1326
+ *
1327
+ * @returns A new {@link SmartIterator} containing all the values of the iterator.
1328
+ */
409
1329
  values() {
410
1330
  const t = this._elements;
411
- return new c(function* () {
1331
+ return new u(function* () {
412
1332
  for (const [e, n] of t)
413
1333
  yield n;
414
1334
  });
415
1335
  }
1336
+ /**
1337
+ * Materializes the iterator into an array.
1338
+ * This method will consume the entire iterator in the process.
1339
+ *
1340
+ * If the iterator is infinite, the method will never return.
1341
+ *
1342
+ * ```ts
1343
+ * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1344
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1345
+ * .reduce((key, accumulator, value) => accumulator + value);
1346
+ *
1347
+ * console.log(reduced.toArray()); // [4, 16]
1348
+ * ```
1349
+ *
1350
+ * @returns The {@link Array} containing all elements of the iterator.
1351
+ */
416
1352
  toArray() {
417
1353
  return Array.from(this.values());
418
1354
  }
1355
+ /**
1356
+ * Materializes the iterator into a map.
1357
+ * This method will consume the entire iterator in the process.
1358
+ *
1359
+ * If the iterator is infinite, the method will never return.
1360
+ *
1361
+ * ```ts
1362
+ * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1363
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1364
+ * .reduce((key, accumulator, value) => accumulator + value);
1365
+ *
1366
+ * console.log(reduced.toMap()); // Map(2) { "odd" => 4, "even" => 16 }
1367
+ * ```
1368
+ *
1369
+ * @returns The {@link Map} containing all elements of the iterator.
1370
+ */
419
1371
  toMap() {
420
- return new Map(this.items());
1372
+ return new Map(this.entries());
421
1373
  }
1374
+ /**
1375
+ * Materializes the iterator into an object.
1376
+ * This method will consume the entire iterator in the process.
1377
+ *
1378
+ * If the iterator is infinite, the method will never return.
1379
+ *
1380
+ * ```ts
1381
+ * const reduced = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1382
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
1383
+ * .reduce((key, accumulator, value) => accumulator + value);
1384
+ *
1385
+ * console.log(reduced.toObject()); // { odd: 4, even: 16 }
1386
+ * ```
1387
+ *
1388
+ * @returns The {@link Object} containing all elements of the iterator.
1389
+ */
422
1390
  toObject() {
423
- return Object.fromEntries(this.items());
1391
+ return Object.fromEntries(this.entries());
424
1392
  }
425
1393
  };
426
- let d = b;
427
- var pe;
428
- pe = Symbol.toStringTag;
429
- const y = class y {
1394
+ let h = _;
1395
+ var we;
1396
+ we = Symbol.toStringTag;
1397
+ const m = class m {
430
1398
  constructor(t) {
1399
+ /**
1400
+ * The internal {@link SmartAsyncIterator} object that holds the elements to aggregate.
1401
+ */
431
1402
  a(this, "_elements");
432
- a(this, pe, "AggregatedAsyncIterator");
433
- this._elements = new w(t);
1403
+ a(this, we, "AggregatedAsyncIterator");
1404
+ this._elements = new f(t);
434
1405
  }
1406
+ /**
1407
+ * Determines whether all elements of each group of the iterator satisfy a given condition.
1408
+ * See also {@link AggregatedAsyncIterator.some}.
1409
+ * This method will consume the entire iterator in the process.
1410
+ *
1411
+ * It will iterate over all elements of the iterator checjing if they satisfy the condition.
1412
+ * Once a single element of one group doesn't satisfy the condition,
1413
+ * the result for the respective group will be `false`.
1414
+ *
1415
+ * Eventually, it will return a new {@link ReducedIterator}
1416
+ * object that will contain all the boolean results for each group.
1417
+ * If the iterator is infinite, the method will never return.
1418
+ *
1419
+ * ```ts
1420
+ * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1421
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1422
+ * .every(async (key, value) => value >= 0);
1423
+ *
1424
+ * console.log(await results.toObject()); // { odd: false, even: true }
1425
+ * ```
1426
+ *
1427
+ * @param predicate The condition to check for each element of the iterator.
1428
+ *
1429
+ * @returns
1430
+ * A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.
1431
+ */
435
1432
  async every(t) {
436
1433
  const e = /* @__PURE__ */ new Map();
437
1434
  for await (const [n, s] of this._elements) {
438
1435
  const [r, o] = e.get(n) ?? [0, !0];
439
1436
  o && e.set(n, [r + 1, await t(n, s, r)]);
440
1437
  }
441
- return new d(function* () {
1438
+ return new h(function* () {
442
1439
  for (const [n, [s, r]] of e)
443
1440
  yield [n, r];
444
1441
  });
445
1442
  }
1443
+ /**
1444
+ * Determines whether any element of each group of the iterator satisfies a given condition.
1445
+ * See also {@link AggregatedAsyncIterator.every}.
1446
+ * This method will consume the entire iterator in the process.
1447
+ *
1448
+ * It will iterate over all elements of the iterator checjing if they satisfy the condition.
1449
+ * Once a single element of one group satisfies the condition,
1450
+ * the result for the respective group will be `true`.
1451
+ *
1452
+ * Eventually, it will return a new {@link ReducedIterator}
1453
+ * object that will contain all the boolean results for each group.
1454
+ * If the iterator is infinite, the method will never return.
1455
+ *
1456
+ * ```ts
1457
+ * const results = new SmartAsyncIterator<number>([-5, -4, -3, -2, -1, 0])
1458
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1459
+ * .some(async (key, value) => value >= 0);
1460
+ *
1461
+ * console.log(await results.toObject()); // { odd: false, even: true }
1462
+ * ```
1463
+ *
1464
+ * @param predicate The condition to check for each element of the iterator.
1465
+ *
1466
+ * @returns
1467
+ * A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.
1468
+ */
446
1469
  async some(t) {
447
1470
  const e = /* @__PURE__ */ new Map();
448
1471
  for await (const [n, s] of this._elements) {
449
1472
  const [r, o] = e.get(n) ?? [0, !1];
450
1473
  o || e.set(n, [r + 1, await t(n, s, r)]);
451
1474
  }
452
- return new d(function* () {
1475
+ return new h(function* () {
453
1476
  for (const [n, [s, r]] of e)
454
1477
  yield [n, r];
455
1478
  });
456
1479
  }
457
1480
  filter(t) {
458
1481
  const e = this._elements;
459
- return new y(async function* () {
1482
+ return new m(async function* () {
460
1483
  const n = /* @__PURE__ */ new Map();
461
1484
  for await (const [s, r] of e) {
462
1485
  const o = n.get(s) ?? 0;
@@ -464,9 +1487,36 @@ const y = class y {
464
1487
  }
465
1488
  });
466
1489
  }
1490
+ /**
1491
+ * Maps the elements of the iterator using a given transformation function.
1492
+ *
1493
+ * This method will iterate over all elements of the iterator applying the condition.
1494
+ * The result of each transformation will be included in the new iterator.
1495
+ *
1496
+ * Since the iterator is lazy, the mapping process will
1497
+ * be executed once the resulting iterator is materialized.
1498
+ *
1499
+ * A new iterator will be created, holding the reference to the original one.
1500
+ * This means that the original iterator won't be consumed until the
1501
+ * new one is and that consuming one of them will consume the other as well.
1502
+ *
1503
+ * ```ts
1504
+ * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1505
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1506
+ * .map(async (key, value) => Math.abs(value));
1507
+ *
1508
+ * console.log(await results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }
1509
+ * ```
1510
+ *
1511
+ * @template V The type of the elements after the transformation.
1512
+ *
1513
+ * @param iteratee The transformation function to apply to each element of the iterator.
1514
+ *
1515
+ * @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.
1516
+ */
467
1517
  map(t) {
468
1518
  const e = this._elements;
469
- return new y(async function* () {
1519
+ return new m(async function* () {
470
1520
  const n = /* @__PURE__ */ new Map();
471
1521
  for await (const [s, r] of e) {
472
1522
  const o = n.get(s) ?? 0;
@@ -481,33 +1531,91 @@ const y = class y {
481
1531
  if (n.has(s))
482
1532
  [o, l] = n.get(s);
483
1533
  else if (e !== void 0)
484
- o = 0, l = await e(s);
1534
+ o = 0, e instanceof Function ? l = await e(s) : l = await e;
485
1535
  else {
486
1536
  n.set(s, [0, r]);
487
1537
  continue;
488
1538
  }
489
1539
  n.set(s, [o + 1, await t(s, l, r, o)]);
490
1540
  }
491
- return new d(function* () {
1541
+ return new h(function* () {
492
1542
  for (const [s, [r, o]] of n)
493
1543
  yield [s, o];
494
1544
  });
495
1545
  }
1546
+ /**
1547
+ * Flattens the elements of the iterator using a given transformation function.
1548
+ *
1549
+ * This method will iterate over all elements of the iterator applying the transformation function.
1550
+ * The result of each transformation will be included in the new iterator.
1551
+ *
1552
+ * Since the iterator is lazy, the mapping process will
1553
+ * be executed once the resulting iterator is materialized.
1554
+ *
1555
+ * A new iterator will be created, holding the reference to the original one.
1556
+ * This means that the original iterator won't be consumed until the
1557
+ * new one is and that consuming one of them will consume the other as well.
1558
+ *
1559
+ * ```ts
1560
+ * const results = new SmartAsyncIterator<number>([[-3, -1], 0, 2, 3, 5, [6, 8]])
1561
+ * .groupBy(async (values) =>
1562
+ * {
1563
+ * const value = values instanceof Array ? values[0] : values;
1564
+ * return value % 2 === 0 ? "even" : "odd";
1565
+ * })
1566
+ * .flatMap(async (key, values) => values);
1567
+ *
1568
+ * console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
1569
+ * ```
1570
+ *
1571
+ * @template V The type of the elements after the transformation.
1572
+ *
1573
+ * @param iteratee The transformation function to apply to each element of the iterator.
1574
+ *
1575
+ * @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.
1576
+ */
496
1577
  flatMap(t) {
497
1578
  const e = this._elements;
498
- return new y(async function* () {
1579
+ return new m(async function* () {
499
1580
  const n = /* @__PURE__ */ new Map();
500
1581
  for await (const [s, r] of e) {
501
1582
  const o = n.get(s) ?? 0, l = await t(s, r, o);
502
- for await (const u of l)
503
- yield [s, u];
1583
+ if (l instanceof Array)
1584
+ for (const v of l)
1585
+ yield [s, v];
1586
+ else
1587
+ yield [s, l];
504
1588
  n.set(s, o + 1);
505
1589
  }
506
1590
  });
507
1591
  }
1592
+ /**
1593
+ * Drops a given number of elements from the beginning of each group of the iterator.
1594
+ * The remaining elements will be included in the new iterator.
1595
+ * See also {@link AggregatedAsyncIterator.take}.
1596
+ *
1597
+ * Since the iterator is lazy, the dropping process will
1598
+ * be executed once the resulting iterator is materialized.
1599
+ *
1600
+ * A new iterator will be created, holding the reference to the original one.
1601
+ * This means that the original iterator won't be consumed until the
1602
+ * new one is and that consuming one of them will consume the other as well.
1603
+ *
1604
+ * ```ts
1605
+ * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1606
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1607
+ * .drop(2);
1608
+ *
1609
+ * console.log(await results.toObject()); // { odd: [3, 5], even: [6, 8] }
1610
+ * ```
1611
+ *
1612
+ * @param count The number of elements to drop from the beginning of each group.
1613
+ *
1614
+ * @returns A new {@link AggregatedAsyncIterator} containing the remaining elements.
1615
+ */
508
1616
  drop(t) {
509
1617
  const e = this._elements;
510
- return new y(async function* () {
1618
+ return new m(async function* () {
511
1619
  const n = /* @__PURE__ */ new Map();
512
1620
  for await (const [s, r] of e) {
513
1621
  const o = n.get(s) ?? 0;
@@ -519,9 +1627,33 @@ const y = class y {
519
1627
  }
520
1628
  });
521
1629
  }
1630
+ /**
1631
+ * Takes a given number of elements from the beginning of each group of the iterator.
1632
+ * The elements will be included in the new iterator.
1633
+ * See also {@link AggregatedAsyncIterator.drop}.
1634
+ *
1635
+ * Since the iterator is lazy, the taking process will
1636
+ * be executed once the resulting iterator is materialized.
1637
+ *
1638
+ * A new iterator will be created, holding the reference to the original one.
1639
+ * This means that the original iterator won't be consumed until the
1640
+ * new one is and that consuming one of them will consume the other as well.
1641
+ *
1642
+ * ```ts
1643
+ * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1644
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1645
+ * .take(2);
1646
+ *
1647
+ * console.log(await results.toObject()); // { odd: [-3, -1], even: [0, 2] }
1648
+ * ```
1649
+ *
1650
+ * @param count The number of elements to take from the beginning of each group.
1651
+ *
1652
+ * @returns A new {@link AggregatedAsyncIterator} containing the taken elements.
1653
+ */
522
1654
  take(t) {
523
1655
  const e = this._elements;
524
- return new y(async function* () {
1656
+ return new m(async function* () {
525
1657
  const n = /* @__PURE__ */ new Map();
526
1658
  for await (const [s, r] of e) {
527
1659
  const o = n.get(s) ?? 0;
@@ -535,14 +1667,59 @@ const y = class y {
535
1667
  let [r, o] = e.get(n) ?? [0, void 0];
536
1668
  o === void 0 && (await t(n, s, r) && (o = s), e.set(n, [r + 1, o]));
537
1669
  }
538
- return new d(function* () {
1670
+ return new h(function* () {
539
1671
  for (const [n, [s, r]] of e)
540
1672
  yield [n, r];
541
1673
  });
542
1674
  }
1675
+ /**
1676
+ * Enumerates the elements of the iterator.
1677
+ * Each element is paired with its index within the group in the new iterator.
1678
+ *
1679
+ * Since the iterator is lazy, the enumeration process will
1680
+ * be executed once the resulting iterator is materialized.
1681
+ *
1682
+ * A new iterator will be created, holding the reference to the original one.
1683
+ * This means that the original iterator won't be consumed until the
1684
+ * new one is and that consuming one of them will consume the other as well.
1685
+ *
1686
+ * ```ts
1687
+ * const results = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])
1688
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1689
+ * .enumerate();
1690
+ *
1691
+ * console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }
1692
+ * ```
1693
+ *
1694
+ * @returns A new {@link AggregatedAsyncIterator} containing the enumerated elements.
1695
+ */
1696
+ enumerate() {
1697
+ return this.map((t, e, n) => [n, e]);
1698
+ }
1699
+ /**
1700
+ * Removes all duplicate elements from within each group of the iterator.
1701
+ * The first occurrence of each element will be included in the new iterator.
1702
+ *
1703
+ * Since the iterator is lazy, the deduplication process will
1704
+ * be executed once the resulting iterator is materialized.
1705
+ *
1706
+ * A new iterator will be created, holding the reference to the original one.
1707
+ * This means that the original iterator won't be consumed until the
1708
+ * new one is and that consuming one of them will consume the other as well.
1709
+ *
1710
+ * ```ts
1711
+ * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])
1712
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1713
+ * .unique();
1714
+ *
1715
+ * console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
1716
+ * ```
1717
+ *
1718
+ * @returns A new {@link AggregatedAsyncIterator} containing only the unique elements.
1719
+ */
543
1720
  unique() {
544
1721
  const t = this._elements;
545
- return new y(async function* () {
1722
+ return new m(async function* () {
546
1723
  const e = /* @__PURE__ */ new Map();
547
1724
  for await (const [n, s] of t) {
548
1725
  const r = e.get(n) ?? /* @__PURE__ */ new Set();
@@ -550,46 +1727,214 @@ const y = class y {
550
1727
  }
551
1728
  });
552
1729
  }
1730
+ /**
1731
+ * Counts the number of elements within each group of the iterator.
1732
+ * This method will consume the entire iterator in the process.
1733
+ *
1734
+ * If the iterator is infinite, the method will never return.
1735
+ *
1736
+ * ```ts
1737
+ * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1738
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1739
+ * .count();
1740
+ *
1741
+ * console.log(await results.toObject()); // { odd: 4, even: 4 }
1742
+ * ```
1743
+ *
1744
+ * @returns
1745
+ * A {@link Promise} resolving to a new {@link ReducedIterator} containing the number of elements for each group.
1746
+ */
553
1747
  async count() {
554
1748
  const t = /* @__PURE__ */ new Map();
555
1749
  for await (const [e] of this._elements) {
556
1750
  const n = t.get(e) ?? 0;
557
1751
  t.set(e, n + 1);
558
1752
  }
559
- return new d(function* () {
1753
+ return new h(function* () {
560
1754
  for (const [e, n] of t)
561
1755
  yield [e, n];
562
1756
  });
563
1757
  }
1758
+ /**
1759
+ * Iterates over the elements of the iterator.
1760
+ * The elements are passed to the given iteratee function along with their key and index within the group.
1761
+ *
1762
+ * This method will consume the entire iterator in the process.
1763
+ * If the iterator is infinite, the method will never return.
1764
+ *
1765
+ * ```ts
1766
+ * const aggregator = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])
1767
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd");
1768
+ *
1769
+ * await aggregator.forEach(async (key, value, index) =>
1770
+ * {
1771
+ * console.log(`${index}: ${value}`); // "0: -3", "0: 0", "1: 2", "1: -1", "2: 3"
1772
+ * };
1773
+ * ```
1774
+ *
1775
+ * @param iteratee The function to execute for each element of the iterator.
1776
+ *
1777
+ * @returns A {@link Promise} that will resolve once the iteration is complete.
1778
+ */
564
1779
  async forEach(t) {
565
1780
  const e = /* @__PURE__ */ new Map();
566
1781
  for await (const [n, s] of this._elements) {
567
1782
  const r = e.get(n) ?? 0;
568
- t(n, s, r), e.set(n, r + 1);
1783
+ await t(n, s, r), e.set(n, r + 1);
569
1784
  }
570
1785
  }
1786
+ /**
1787
+ * Changes the key of each element on which the iterator is aggregated.
1788
+ * The new key is determined by the given iteratee function.
1789
+ *
1790
+ * Since the iterator is lazy, the reorganization process will
1791
+ * be executed once the resulting iterator is materialized.
1792
+ *
1793
+ * A new iterator will be created, holding the reference to the original one.
1794
+ * This means that the original iterator won't be consumed until the
1795
+ * new one is and that consuming one of them will consume the other as well.
1796
+ *
1797
+ * ```ts
1798
+ * const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1799
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1800
+ * .map(async (key, value, index) => index % 2 === 0 ? value : -value)
1801
+ * .reorganizeBy(async (key, value) => value >= 0 ? "+" : "-");
1802
+ *
1803
+ * console.log(await results.toObject()); // { "+": [1, 0, 3, 6], "-": [-3, -2, -5, -8] }
1804
+ * ```
1805
+ *
1806
+ * @template J The type of the new key.
1807
+ *
1808
+ * @param iteratee The function to determine the new key for each element of the iterator.
1809
+ *
1810
+ * @returns A new {@link AggregatedAsyncIterator} containing the elements reorganized by the new keys.
1811
+ */
1812
+ reorganizeBy(t) {
1813
+ const e = this._elements;
1814
+ return new m(async function* () {
1815
+ const n = /* @__PURE__ */ new Map();
1816
+ for await (const [s, r] of e) {
1817
+ const o = n.get(s) ?? 0;
1818
+ yield [await t(s, r, o), r], n.set(s, o + 1);
1819
+ }
1820
+ });
1821
+ }
1822
+ /**
1823
+ * An utility method that returns a new {@link SmartAsyncIterator}
1824
+ * object containing all the keys of the iterator.
1825
+ *
1826
+ * Since the iterator is lazy, the keys will be extracted
1827
+ * be executed once the resulting iterator is materialized.
1828
+ *
1829
+ * A new iterator will be created, holding the reference to the original one.
1830
+ * This means that the original iterator won't be consumed until the
1831
+ * new one is and that consuming one of them will consume the other as well.
1832
+ *
1833
+ * ```ts
1834
+ * const keys = new SmartAsyncIterator([-3, Symbol(), "A", { }, null, [1 , 2, 3], false])
1835
+ * .groupBy(async (value) => typeof value)
1836
+ * .keys();
1837
+ *
1838
+ * console.log(await keys.toArray()); // ["number", "symbol", "string", "object", "boolean"]
1839
+ * ```
1840
+ *
1841
+ * @returns A new {@link SmartAsyncIterator} containing all the keys of the iterator.
1842
+ */
571
1843
  keys() {
572
1844
  const t = this._elements;
573
- return new w(async function* () {
1845
+ return new f(async function* () {
574
1846
  const e = /* @__PURE__ */ new Set();
575
1847
  for await (const [n] of t)
576
1848
  e.has(n) || (e.add(n), yield n);
577
1849
  });
578
1850
  }
579
- items() {
1851
+ /**
1852
+ * An utility method that returns a new {@link SmartAsyncIterator}
1853
+ * object containing all the entries of the iterator.
1854
+ * Each entry is a tuple containing the key and the element.
1855
+ *
1856
+ * Since the iterator is lazy, the entries will be extracted
1857
+ * be executed once the resulting iterator is materialized.
1858
+ *
1859
+ * A new iterator will be created, holding the reference to the original one.
1860
+ * This means that the original iterator won't be consumed until the
1861
+ * new one is and that consuming one of them will consume the other as well.
1862
+ *
1863
+ * ```ts
1864
+ * const entries = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])
1865
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1866
+ * .entries();
1867
+ *
1868
+ * console.log(await entries.toArray()); // [["odd", -3], ["even", 0], ["even", 2], ["odd", -1], ["odd", 3]]
1869
+ * ```
1870
+ *
1871
+ * @returns A new {@link SmartAsyncIterator} containing all the entries of the iterator.
1872
+ */
1873
+ entries() {
580
1874
  return this._elements;
581
1875
  }
1876
+ /**
1877
+ * An utility method that returns a new {@link SmartAsyncIterator}
1878
+ * object containing all the values of the iterator.
1879
+ *
1880
+ * Since the iterator is lazy, the values will be extracted
1881
+ * be executed once the resulting iterator is materialized.
1882
+ *
1883
+ * A new iterator will be created, holding the reference to the original one.
1884
+ * This means that the original iterator won't be consumed until the
1885
+ * new one is and that consuming one of them will consume the other as well.
1886
+ *
1887
+ * ```ts
1888
+ * const values = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1889
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
1890
+ * .values();
1891
+ *
1892
+ * console.log(await values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]
1893
+ * ```
1894
+ *
1895
+ * @returns A new {@link SmartAsyncIterator} containing all the values of the iterator.
1896
+ */
582
1897
  values() {
583
1898
  const t = this._elements;
584
- return new w(async function* () {
1899
+ return new f(async function* () {
585
1900
  for await (const [e, n] of t)
586
1901
  yield n;
587
1902
  });
588
1903
  }
1904
+ /**
1905
+ * Materializes the iterator into an array of arrays.
1906
+ * This method will consume the entire iterator in the process.
1907
+ *
1908
+ * If the iterator is infinite, the method will never return.
1909
+ *
1910
+ * ```ts
1911
+ * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1912
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd");
1913
+ *
1914
+ * console.log(await aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]
1915
+ * ```
1916
+ *
1917
+ * @returns A {@link Promise} resolving to an {@link Array} containing all the values of the iterator.
1918
+ */
589
1919
  async toArray() {
590
1920
  const t = await this.toMap();
591
1921
  return Array.from(t.values());
592
1922
  }
1923
+ /**
1924
+ * Materializes the iterator into a map.
1925
+ * This method will consume the entire iterator in the process.
1926
+ *
1927
+ * If the iterator is infinite, the method will never return.
1928
+ *
1929
+ * ```ts
1930
+ * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1931
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd");
1932
+ *
1933
+ * console.log(await aggregator.toMap()); // Map(2) { "odd" => [-3, -1, 3, 5], "even" => [0, 2, 6, 8] }
1934
+ * ```
1935
+ *
1936
+ * @returns A {@link Promise} resolving to a {@link Map} containing all the entries of the iterator.
1937
+ */
593
1938
  async toMap() {
594
1939
  const t = /* @__PURE__ */ new Map();
595
1940
  for await (const [e, n] of this._elements) {
@@ -598,6 +1943,21 @@ const y = class y {
598
1943
  }
599
1944
  return t;
600
1945
  }
1946
+ /**
1947
+ * Materializes the iterator into an object.
1948
+ * This method will consume the entire iterator in the process.
1949
+ *
1950
+ * If the iterator is infinite, the method will never return.
1951
+ *
1952
+ * ```ts
1953
+ * const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
1954
+ * .groupBy(async (value) => value % 2 === 0 ? "even" : "odd");
1955
+ *
1956
+ * console.log(await aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
1957
+ * ```
1958
+ *
1959
+ * @returns A {@link Promise} resolving to an object containing all the entries of the iterator.
1960
+ */
601
1961
  async toObject() {
602
1962
  const t = {};
603
1963
  for await (const [e, n] of this._elements) {
@@ -607,13 +1967,14 @@ const y = class y {
607
1967
  return t;
608
1968
  }
609
1969
  };
610
- let E = y;
1970
+ let T = m;
611
1971
  var ye;
612
- class w {
1972
+ class f {
613
1973
  constructor(t) {
1974
+ /**
1975
+ * The native {@link AsyncIterator} object that is being wrapped by this instance.
1976
+ */
614
1977
  a(this, "_iterator");
615
- a(this, "return");
616
- a(this, "throw");
617
1978
  a(this, ye, "SmartAsyncIterator");
618
1979
  if (t instanceof Function) {
619
1980
  const e = t();
@@ -648,8 +2009,32 @@ class w {
648
2009
  e = [yield n.value];
649
2010
  }
650
2011
  }();
651
- this._iterator.return && (this.return = (e) => this._iterator.return(e)), this._iterator.throw && (this.throw = (e) => this._iterator.throw(e));
652
2012
  }
2013
+ /**
2014
+ * Determines whether all elements of the iterator satisfy a given condition.
2015
+ * See also {@link SmartAsyncIterator.some}.
2016
+ *
2017
+ * This method will iterate over all elements of the iterator checking if they satisfy the condition.
2018
+ * Once a single element doesn't satisfy the condition, the method will return `false` immediately.
2019
+ *
2020
+ * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
2021
+ * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
2022
+ * Consider using {@link SmartAsyncIterator.find} instead.
2023
+ *
2024
+ * If the iterator is infinite and every element satisfies the condition, the method will never return.
2025
+ *
2026
+ * ```ts
2027
+ * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
2028
+ * const result = await iterator.every(async (value) => value < 0);
2029
+ *
2030
+ * console.log(result); // false
2031
+ * ```
2032
+ *
2033
+ * @param predicate The condition to check for each element of the iterator.
2034
+ *
2035
+ * @returns
2036
+ * A {@link Promise} that will resolve to `true` if all elements satisfy the condition, `false` otherwise.
2037
+ */
653
2038
  async every(t) {
654
2039
  let e = 0;
655
2040
  for (; ; ) {
@@ -661,9 +2046,34 @@ class w {
661
2046
  e += 1;
662
2047
  }
663
2048
  }
664
- async some(t) {
665
- let e = 0;
666
- for (; ; ) {
2049
+ /**
2050
+ * Determines whether any element of the iterator satisfies a given condition.
2051
+ * See also {@link SmartAsyncIterator.every}.
2052
+ *
2053
+ * This method will iterate over all elements of the iterator checking if they satisfy the condition.
2054
+ * Once a single element satisfies the condition, the method will return `true` immediately.
2055
+ *
2056
+ * This may lead to an unknown final state of the iterator, which may be entirely or partially consumed.
2057
+ * For this reason, it's recommended to consider it as consumed in any case and to not use it anymore.
2058
+ * Consider using {@link SmartAsyncIterator.find} instead.
2059
+ *
2060
+ * If the iterator is infinite and no element satisfies the condition, the method will never return.
2061
+ *
2062
+ * ```ts
2063
+ * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
2064
+ * const result = await iterator.some(async (value) => value > 0);
2065
+ *
2066
+ * console.log(result); // true
2067
+ * ```
2068
+ *
2069
+ * @param predicate The condition to check for each element of the iterator.
2070
+ *
2071
+ * @returns
2072
+ * A {@link Promise} that will resolve to `true` if any element satisfies the condition, `false` otherwise.
2073
+ */
2074
+ async some(t) {
2075
+ let e = 0;
2076
+ for (; ; ) {
667
2077
  const n = await this._iterator.next();
668
2078
  if (n.done)
669
2079
  return !1;
@@ -674,7 +2084,7 @@ class w {
674
2084
  }
675
2085
  filter(t) {
676
2086
  const e = this._iterator;
677
- return new w(async function* () {
2087
+ return new f(async function* () {
678
2088
  let n = 0;
679
2089
  for (; ; ) {
680
2090
  const s = await e.next();
@@ -684,9 +2094,35 @@ class w {
684
2094
  }
685
2095
  });
686
2096
  }
2097
+ /**
2098
+ * Maps the elements of the iterator using a given transformation function.
2099
+ *
2100
+ * This method will iterate over all elements of the iterator applying the transformation function.
2101
+ * The result of each transformation will be included in the new iterator.
2102
+ *
2103
+ * Since the iterator is lazy, the mapping process will
2104
+ * be executed once the resulting iterator is materialized.
2105
+ *
2106
+ * A new iterator will be created, holding the reference to the original one.
2107
+ * This means that the original iterator won't be consumed until the
2108
+ * new one is and that consuming one of them will consume the other as well.
2109
+ *
2110
+ * ```ts
2111
+ * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
2112
+ * const result = iterator.map(async (value) => Math.abs(value));
2113
+ *
2114
+ * console.log(await result.toArray()); // [2, 1, 0, 1, 2]
2115
+ * ```
2116
+ *
2117
+ * @template V The type of the elements after the transformation.
2118
+ *
2119
+ * @param iteratee The transformation function to apply to each element of the iterator.
2120
+ *
2121
+ * @returns A new {@link SmartAsyncIterator} containing the transformed elements.
2122
+ */
687
2123
  map(t) {
688
2124
  const e = this._iterator;
689
- return new w(async function* () {
2125
+ return new f(async function* () {
690
2126
  let n = 0;
691
2127
  for (; ; ) {
692
2128
  const s = await e.next();
@@ -701,7 +2137,7 @@ class w {
701
2137
  if (s === void 0) {
702
2138
  const r = await this._iterator.next();
703
2139
  if (r.done)
704
- throw new p("Cannot reduce an empty iterator without an initial value.");
2140
+ throw new d("Cannot reduce an empty iterator without an initial value.");
705
2141
  s = r.value, n += 1;
706
2142
  }
707
2143
  for (; ; ) {
@@ -711,24 +2147,79 @@ class w {
711
2147
  s = await t(s, r.value, n), n += 1;
712
2148
  }
713
2149
  }
2150
+ /**
2151
+ * Flattens the elements of the iterator using a given transformation function.
2152
+ *
2153
+ * This method will iterate over all elements of the iterator applying the transformation function.
2154
+ * The result of each transformation will be flattened and included in the new iterator.
2155
+ *
2156
+ * Since the iterator is lazy, the flattening process will
2157
+ * be executed once the resulting iterator is materialized.
2158
+ *
2159
+ * A new iterator will be created, holding the reference to the original one.
2160
+ * This means that the original iterator won't be consumed until the
2161
+ * new one is and that consuming one of them will consume the other as well.
2162
+ *
2163
+ * ```ts
2164
+ * const iterator = new SmartAsyncIterator<number[]>([[-2, -1], 0, 1, 2, [3, 4, 5]]);
2165
+ * const result = iterator.flatMap(async (value) => value);
2166
+ *
2167
+ * console.log(await result.toArray()); // [-2, -1, 0, 1, 2, 3, 4, 5]
2168
+ * ```
2169
+ *
2170
+ * @template V The type of the elements after the transformation.
2171
+ *
2172
+ * @param iteratee The transformation function to apply to each element of the iterator.
2173
+ *
2174
+ * @returns A new {@link SmartAsyncIterator} containing the flattened elements.
2175
+ */
714
2176
  flatMap(t) {
715
2177
  const e = this._iterator;
716
- return new w(async function* () {
2178
+ return new f(async function* () {
717
2179
  let n = 0;
718
2180
  for (; ; ) {
719
2181
  const s = await e.next();
720
2182
  if (s.done)
721
2183
  return s.value;
722
2184
  const r = await t(s.value, n);
723
- for await (const o of r)
724
- yield o;
2185
+ if (r instanceof Array)
2186
+ for (const o of r)
2187
+ yield o;
2188
+ else
2189
+ yield r;
725
2190
  n += 1;
726
2191
  }
727
2192
  });
728
2193
  }
2194
+ /**
2195
+ * Drops a given number of elements at the beginning of the iterator.
2196
+ * The remaining elements will be included in a new iterator.
2197
+ * See also {@link SmartAsyncIterator.take}.
2198
+ *
2199
+ * Since the iterator is lazy, the dropping process will
2200
+ * be executed once the resulting iterator is materialized.
2201
+ *
2202
+ * A new iterator will be created, holding the reference to the original one.
2203
+ * This means that the original iterator won't be consumed until the
2204
+ * new one is and that consuming one of them will consume the other as well.
2205
+ *
2206
+ * Only the dropped elements will be consumed in the process.
2207
+ * The rest of the iterator will be consumed only once the new one is.
2208
+ *
2209
+ * ```ts
2210
+ * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
2211
+ * const result = iterator.drop(3);
2212
+ *
2213
+ * console.log(await result.toArray()); // [1, 2]
2214
+ * ```
2215
+ *
2216
+ * @param count The number of elements to drop.
2217
+ *
2218
+ * @returns A new {@link SmartAsyncIterator} containing the remaining elements.
2219
+ */
729
2220
  drop(t) {
730
2221
  const e = this._iterator;
731
- return new w(async function* () {
2222
+ return new f(async function* () {
732
2223
  let n = 0;
733
2224
  for (; n < t; ) {
734
2225
  if ((await e.next()).done)
@@ -743,9 +2234,36 @@ class w {
743
2234
  }
744
2235
  });
745
2236
  }
2237
+ /**
2238
+ * Takes a given number of elements at the beginning of the iterator.
2239
+ * These elements will be included in a new iterator.
2240
+ * See also {@link SmartAsyncIterator.drop}.
2241
+ *
2242
+ * Since the iterator is lazy, the taking process will
2243
+ * be executed once the resulting iterator is materialized.
2244
+ *
2245
+ * A new iterator will be created, holding the reference to the original one.
2246
+ * This means that the original iterator won't be consumed until the
2247
+ * new one is and that consuming one of them will consume the other as well.
2248
+ *
2249
+ * Only the taken elements will be consumed from the original iterator.
2250
+ * The rest of the original iterator will be available for further consumption.
2251
+ *
2252
+ * ```ts
2253
+ * const iterator = new SmartAsyncIterator<number>([-2, -1, 0, 1, 2]);
2254
+ * const result = iterator.take(3);
2255
+ *
2256
+ * console.log(await result.toArray()); // [-2, -1, 0]
2257
+ * console.log(await iterator.toArray()); // [1, 2]
2258
+ * ```
2259
+ *
2260
+ * @param limit The number of elements to take.
2261
+ *
2262
+ * @returns A new {@link SmartAsyncIterator} containing the taken elements.
2263
+ */
746
2264
  take(t) {
747
2265
  const e = this._iterator;
748
- return new w(async function* () {
2266
+ return new f(async function* () {
749
2267
  let n = 0;
750
2268
  for (; n < t; ) {
751
2269
  const s = await e.next();
@@ -766,12 +2284,55 @@ class w {
766
2284
  e += 1;
767
2285
  }
768
2286
  }
2287
+ /**
2288
+ * Enumerates the elements of the iterator.
2289
+ * Each element is be paired with its index in a new iterator.
2290
+ *
2291
+ * Since the iterator is lazy, the enumeration process will
2292
+ * be executed once the resulting iterator is materialized.
2293
+ *
2294
+ * A new iterator will be created, holding the reference to the original one.
2295
+ * This means that the original iterator won't be consumed until the
2296
+ * new one is and that consuming one of them will consume the other as well.
2297
+ *
2298
+ * ```ts
2299
+ * const iterator = new SmartAsyncIterator<string>(["A", "M", "N", "Z"]);
2300
+ * const result = iterator.enumerate();
2301
+ *
2302
+ * for await (const [index, value] of result)
2303
+ * {
2304
+ * console.log(`${index}: ${value}`); // "0: A", "1: M", "2: N", "3: Z"
2305
+ * }
2306
+ * ```
2307
+ *
2308
+ * @returns A new {@link SmartAsyncIterator} containing the enumerated elements.
2309
+ */
769
2310
  enumerate() {
770
2311
  return this.map((t, e) => [e, t]);
771
2312
  }
2313
+ /**
2314
+ * Removes all duplicate elements from the iterator.
2315
+ * The first occurrence of each element will be kept.
2316
+ *
2317
+ * Since the iterator is lazy, the deduplication process will
2318
+ * be executed once the resulting iterator is materialized.
2319
+ *
2320
+ * A new iterator will be created, holding the reference to the original one.
2321
+ * This means that the original iterator won't be consumed until the
2322
+ * new one is and that consuming one of them will consume the other as well.
2323
+ *
2324
+ * ```ts
2325
+ * const iterator = new SmartAsyncIterator<number>([1, 1, 2, 3, 2, 3, 4, 5, 5, 4]);
2326
+ * const result = iterator.unique();
2327
+ *
2328
+ * console.log(await result.toArray()); // [1, 2, 3, 4, 5]
2329
+ * ```
2330
+ *
2331
+ * @returns A new {@link SmartAsyncIterator} containing only the unique elements.
2332
+ */
772
2333
  unique() {
773
2334
  const t = this._iterator;
774
- return new w(async function* () {
2335
+ return new f(async function* () {
775
2336
  const e = /* @__PURE__ */ new Set();
776
2337
  for (; ; ) {
777
2338
  const n = await t.next();
@@ -781,6 +2342,21 @@ class w {
781
2342
  }
782
2343
  });
783
2344
  }
2345
+ /**
2346
+ * Counts the number of elements in the iterator.
2347
+ * This method will consume the entire iterator in the process.
2348
+ *
2349
+ * If the iterator is infinite, the method will never return.
2350
+ *
2351
+ * ```ts
2352
+ * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);
2353
+ * const result = await iterator.count();
2354
+ *
2355
+ * console.log(result); // 5
2356
+ * ```
2357
+ *
2358
+ * @returns A {@link Promise} that will resolve to the number of elements in the iterator.
2359
+ */
784
2360
  async count() {
785
2361
  let t = 0;
786
2362
  for (; ; ) {
@@ -789,6 +2365,25 @@ class w {
789
2365
  t += 1;
790
2366
  }
791
2367
  }
2368
+ /**
2369
+ * Iterates over all elements of the iterator.
2370
+ * The elements are passed to the function along with their index.
2371
+ *
2372
+ * This method will consume the entire iterator in the process.
2373
+ * If the iterator is infinite, the method will never return.
2374
+ *
2375
+ * ```ts
2376
+ * const iterator = new SmartAsyncIterator<number>(["A", "M", "N", "Z"]);
2377
+ * await iterator.forEach(async (value, index) =>
2378
+ * {
2379
+ * console.log(`${index}: ${value}`); // "0: A", "1: M", "2: N", "3: Z"
2380
+ * }
2381
+ * ```
2382
+ *
2383
+ * @param iteratee The function to apply to each element of the iterator.
2384
+ *
2385
+ * @returns A {@link Promise} that will resolve once the iteration is complete.
2386
+ */
792
2387
  async forEach(t) {
793
2388
  let e = 0;
794
2389
  for (; ; ) {
@@ -798,12 +2393,152 @@ class w {
798
2393
  await t(n.value, e), e += 1;
799
2394
  }
800
2395
  }
2396
+ /**
2397
+ * Advances the iterator to the next element and returns the result.
2398
+ * If the iterator requires it, a value must be provided to be passed to the next element.
2399
+ *
2400
+ * Once the iterator is done, the method will return an object with the `done` property set to `true`.
2401
+ *
2402
+ * ```ts
2403
+ * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5]);
2404
+ *
2405
+ * let result = await iterator.next();
2406
+ * while (!result.done)
2407
+ * {
2408
+ * console.log(result.value); // 1, 2, 3, 4, 5
2409
+ *
2410
+ * result = await iterator.next();
2411
+ * }
2412
+ *
2413
+ * console.log(result); // { done: true, value: undefined }
2414
+ * ```
2415
+ *
2416
+ * @param values The value to pass to the next element, if required.
2417
+ *
2418
+ * @returns
2419
+ * A {@link Promise} that will resolve to the result of the iteration, containing the value of the operation.
2420
+ */
801
2421
  next(...t) {
802
2422
  return this._iterator.next(...t);
803
2423
  }
2424
+ /**
2425
+ * An utility method that may be used to close the iterator gracefully,
2426
+ * free the resources and perform any cleanup operation.
2427
+ * It may also be used to signal the end or to compute a specific final result of the iteration process.
2428
+ *
2429
+ * ```ts
2430
+ * const iterator = new SmartAsyncIterator<number>({
2431
+ * _index: 0,
2432
+ * next: async function()
2433
+ * {
2434
+ * return { done: false, value: this._index += 1 };
2435
+ * },
2436
+ * return: async function() { console.log("Closing the iterator..."); }
2437
+ * });
2438
+ *
2439
+ * for await (const value of iterator)
2440
+ * {
2441
+ * if (value > 5) { break; } // Closing the iterator...
2442
+ *
2443
+ * console.log(value); // 1, 2, 3, 4, 5
2444
+ * }
2445
+ * ```
2446
+ *
2447
+ * @param value The final value of the iterator.
2448
+ *
2449
+ * @returns A {@link Promise} that will resolve to the final result of the iterator.
2450
+ */
2451
+ async return(t) {
2452
+ const e = await t;
2453
+ return this._iterator.return ? await this._iterator.return(e) : { done: !0, value: e };
2454
+ }
2455
+ /**
2456
+ * An utility method that may be used to close the iterator due to an error,
2457
+ * free the resources and perform any cleanup operation.
2458
+ * It may also be used to signal that an error occurred during the iteration process or to handle it.
2459
+ *
2460
+ * ```ts
2461
+ * const iterator = new SmartAsyncIterator<number>({
2462
+ * _index: 0,
2463
+ * next: async function()
2464
+ * {
2465
+ * return { done: this._index > 10, value: this._index += 1 };
2466
+ * },
2467
+ * throw: async function(error)
2468
+ * {
2469
+ * console.warn(error.message);
2470
+ *
2471
+ * this._index = 0;
2472
+ * }
2473
+ * });
2474
+ *
2475
+ * for await (const value of iterator) // 1, 2, 3, 4, 5, "The index is too high.", 1, 2, 3, 4, 5, ...
2476
+ * {
2477
+ * try
2478
+ * {
2479
+ * if (value > 5) { throw new Error("The index is too high."); }
2480
+ *
2481
+ * console.log(value); // 1, 2, 3, 4, 5
2482
+ * }
2483
+ * catch (error) { await iterator.throw(error); }
2484
+ * }
2485
+ * ```
2486
+ *
2487
+ * @param error The error to throw into the iterator.
2488
+ *
2489
+ * @returns A {@link Promise} that will resolve to the final result of the iterator.
2490
+ */
2491
+ throw(t) {
2492
+ if (this._iterator.throw)
2493
+ return this._iterator.throw(t);
2494
+ throw t;
2495
+ }
2496
+ /**
2497
+ * An utility method that aggregates the elements of the iterator using a given key function.
2498
+ * The elements will be grouped by the resulting keys in a new specialized iterator.
2499
+ * See {@link AggregatedAsyncIterator}.
2500
+ *
2501
+ * Since the iterator is lazy, the grouping process will
2502
+ * be executed once the resulting iterator is materialized.
2503
+ *
2504
+ * A new iterator will be created, holding the reference to the original one.
2505
+ * This means that the original iterator won't be consumed until the
2506
+ * the new one is and that consuming one of them will consume the other as well.
2507
+ *
2508
+ * ```ts
2509
+ * const iterator = new SmartAsyncIterator<number>([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
2510
+ * const result = iterator.groupBy<string>(async (value) => value % 2 === 0 ? "even" : "odd");
2511
+ *
2512
+ * console.log(await result.toObject()); // { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }
2513
+ * ```
2514
+ *
2515
+ * @template K The type of the keys used to group the elements.
2516
+ *
2517
+ * @param iteratee The key function to apply to each element of the iterator.
2518
+ *
2519
+ * @returns A new instance of the {@link AggregatedAsyncIterator} class containing the grouped elements.
2520
+ */
804
2521
  groupBy(t) {
805
- return new E(this.map(async (e, n) => [await t(e, n), e]));
2522
+ return new T(this.map(async (e, n) => [await t(e, n), e]));
806
2523
  }
2524
+ /**
2525
+ * Materializes the iterator into an array.
2526
+ * This method will consume the entire iterator in the process.
2527
+ *
2528
+ * If the iterator is infinite, the method will never return.
2529
+ *
2530
+ * ```ts
2531
+ * const iterator = new SmartAsyncIterator(async function* ()
2532
+ * {
2533
+ * for (let i = 0; i < 5; i += 1) { yield i; }
2534
+ * });
2535
+ * const result = await iterator.toArray();
2536
+ *
2537
+ * console.log(result); // [0, 1, 2, 3, 4]
2538
+ * ```
2539
+ *
2540
+ * @returns A {@link Promise} that will resolve to an array containing all elements of the iterator.
2541
+ */
807
2542
  toArray() {
808
2543
  return Array.fromAsync(this);
809
2544
  }
@@ -811,39 +2546,92 @@ class w {
811
2546
  return this;
812
2547
  }
813
2548
  }
814
- var ge;
815
- ge = Symbol.toStringTag;
816
- const g = class g {
2549
+ var _e;
2550
+ _e = Symbol.toStringTag;
2551
+ const w = class w {
817
2552
  constructor(t) {
2553
+ /**
2554
+ * The internal {@link SmartIterator} object that holds the elements to aggregate.
2555
+ */
818
2556
  a(this, "_elements");
819
- a(this, ge, "AggregatedIterator");
820
- this._elements = new c(t);
2557
+ a(this, _e, "AggregatedIterator");
2558
+ this._elements = new u(t);
821
2559
  }
2560
+ /**
2561
+ * Determines whether all elements of each group of the iterator satisfy a given condition.
2562
+ * See also {@link AggregatedIterator.some}.
2563
+ * This method will consume the entire iterator in the process.
2564
+ *
2565
+ * It will iterate over all elements of the iterator checking if they satisfy the condition.
2566
+ * Once a single element of one group doesn't satisfy the condition,
2567
+ * the result for the respective group will be `false`.
2568
+ *
2569
+ * Eventually, it will return a new {@link ReducedIterator}
2570
+ * object that will contain all the boolean results for each group.
2571
+ * If the iterator is infinite, the method will never return.
2572
+ *
2573
+ * ```ts
2574
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
2575
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2576
+ * .every((key, value) => value >= 0);
2577
+ *
2578
+ * console.log(results.toObject()); // { odd: false, even: true }
2579
+ * ```
2580
+ *
2581
+ * @param predicate The condition to check for each element of the iterator.
2582
+ *
2583
+ * @returns A new {@link ReducedIterator} containing the boolean results for each group.
2584
+ */
822
2585
  every(t) {
823
2586
  const e = /* @__PURE__ */ new Map();
824
2587
  for (const [n, s] of this._elements) {
825
2588
  const [r, o] = e.get(n) ?? [0, !0];
826
2589
  o && e.set(n, [r + 1, t(n, s, r)]);
827
2590
  }
828
- return new d(function* () {
2591
+ return new h(function* () {
829
2592
  for (const [n, [s, r]] of e)
830
2593
  yield [n, r];
831
2594
  });
832
2595
  }
2596
+ /**
2597
+ * Determines whether any elements of each group of the iterator satisfy a given condition.
2598
+ * See also {@link AggregatedIterator.every}.
2599
+ * This method will consume the entire iterator in the process.
2600
+ *
2601
+ * It will iterate over all elements of the iterator checking if they satisfy the condition.
2602
+ * Once a single element of one group satisfies the condition,
2603
+ * the result for the respective group will be `true`.
2604
+ *
2605
+ * Eventually, it will return a new {@link ReducedIterator}
2606
+ * object that will contain all the boolean results for each group.
2607
+ * If the iterator is infinite, the method will never return.
2608
+ *
2609
+ * ```ts
2610
+ * const results = new SmartIterator<number>([-5, -4, -3, -2, -1, 0])
2611
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2612
+ * .some((key, value) => value >= 0);
2613
+ *
2614
+ * console.log(results.toObject()); // { odd: false, even: true }
2615
+ * ```
2616
+ *
2617
+ * @param predicate The condition to check for each element of the iterator.
2618
+ *
2619
+ * @returns A {@link ReducedIterator} containing the boolean results for each group.
2620
+ */
833
2621
  some(t) {
834
2622
  const e = /* @__PURE__ */ new Map();
835
2623
  for (const [n, s] of this._elements) {
836
2624
  const [r, o] = e.get(n) ?? [0, !1];
837
2625
  o || e.set(n, [r + 1, t(n, s, r)]);
838
2626
  }
839
- return new d(function* () {
2627
+ return new h(function* () {
840
2628
  for (const [n, [s, r]] of e)
841
2629
  yield [n, r];
842
2630
  });
843
2631
  }
844
2632
  filter(t) {
845
2633
  const e = this._elements;
846
- return new g(function* () {
2634
+ return new w(function* () {
847
2635
  const n = /* @__PURE__ */ new Map();
848
2636
  for (const [s, r] of e) {
849
2637
  const o = n.get(s) ?? 0;
@@ -851,9 +2639,36 @@ const g = class g {
851
2639
  }
852
2640
  });
853
2641
  }
2642
+ /**
2643
+ * Maps the elements of the iterator using a given transformation function.
2644
+ *
2645
+ * This method will iterate over all elements of the iterator applying the transformation function.
2646
+ * The result of each transformation will be included in the new iterator.
2647
+ *
2648
+ * Since the iterator is lazy, the mapping process will
2649
+ * be executed once the resulting iterator is materialized.
2650
+ *
2651
+ * A new iterator will be created, holding the reference to the original one.
2652
+ * This means that the original iterator won't be consumed until the
2653
+ * new one is and that consuming one of them will consume the other as well.
2654
+ *
2655
+ * ```ts
2656
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
2657
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2658
+ * .map((key, value) => Math.abs(value));
2659
+ *
2660
+ * console.log(results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }
2661
+ * ```
2662
+ *
2663
+ * @template V The type of the elements after the transformation.
2664
+ *
2665
+ * @param iteratee The transformation function to apply to each element of the iterator.
2666
+ *
2667
+ * @returns A new {@link AggregatedIterator} containing the transformed elements.
2668
+ */
854
2669
  map(t) {
855
2670
  const e = this._elements;
856
- return new g(function* () {
2671
+ return new w(function* () {
857
2672
  const n = /* @__PURE__ */ new Map();
858
2673
  for (const [s, r] of e) {
859
2674
  const o = n.get(s) ?? 0;
@@ -868,33 +2683,91 @@ const g = class g {
868
2683
  if (n.has(s))
869
2684
  [o, l] = n.get(s);
870
2685
  else if (e !== void 0)
871
- o = 0, l = e(s);
2686
+ o = 0, e instanceof Function ? l = e(s) : l = e;
872
2687
  else {
873
2688
  n.set(s, [0, r]);
874
2689
  continue;
875
2690
  }
876
2691
  n.set(s, [o + 1, t(s, l, r, o)]);
877
2692
  }
878
- return new d(function* () {
2693
+ return new h(function* () {
879
2694
  for (const [s, [r, o]] of n)
880
2695
  yield [s, o];
881
2696
  });
882
2697
  }
2698
+ /**
2699
+ * Flattens the elements of the iterator using a given transformation function.
2700
+ *
2701
+ * This method will iterate over all elements of the iterator applying the transformation function.
2702
+ * The result of each transformation will be included in the new iterator.
2703
+ *
2704
+ * Since the iterator is lazy, the flattening process will
2705
+ * be executed once the resulting iterator is materialized.
2706
+ *
2707
+ * A new iterator will be created, holding the reference to the original one.
2708
+ * This means that the original iterator won't be consumed until the
2709
+ * new one is and that consuming one of them will consume the other as well.
2710
+ *
2711
+ * ```ts
2712
+ * const results = new SmartIterator<number[]>([[-3, -1], 0, 2, 3, 5, [6, 8]])
2713
+ * .groupBy((values) =>
2714
+ * {
2715
+ * const value = values instanceof Array ? values[0] : values;
2716
+ * return value % 2 === 0 ? "even" : "odd";
2717
+ * })
2718
+ * .flatMap((key, values) => values);
2719
+ *
2720
+ * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
2721
+ * ```
2722
+ *
2723
+ * @template V The type of the elements after the transformation.
2724
+ *
2725
+ * @param iteratee The transformation function to apply to each element of the iterator.
2726
+ *
2727
+ * @returns A new {@link AggregatedIterator} containing the transformed elements.
2728
+ */
883
2729
  flatMap(t) {
884
2730
  const e = this._elements;
885
- return new g(function* () {
2731
+ return new w(function* () {
886
2732
  const n = /* @__PURE__ */ new Map();
887
2733
  for (const [s, r] of e) {
888
2734
  const o = n.get(s) ?? 0, l = t(s, r, o);
889
- for (const u of l)
890
- yield [s, u];
2735
+ if (l instanceof Array)
2736
+ for (const v of l)
2737
+ yield [s, v];
2738
+ else
2739
+ yield [s, l];
891
2740
  n.set(s, o + 1);
892
2741
  }
893
2742
  });
894
2743
  }
2744
+ /**
2745
+ * Drops a given number of elements from the beginning of each group of the iterator.
2746
+ * The remaining elements will be included in the new iterator.
2747
+ * See also {@link AggregatedIterator.take}.
2748
+ *
2749
+ * Since the iterator is lazy, the dropping process will
2750
+ * be executed once the resulting iterator is materialized.
2751
+ *
2752
+ * A new iterator will be created, holding the reference to the original one.
2753
+ * This means that the original iterator won't be consumed until the
2754
+ * new one is and that consuming one of them will consume the other as well.
2755
+ *
2756
+ * ```ts
2757
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
2758
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2759
+ * .drop(2);
2760
+ *
2761
+ * console.log(results.toObject()); // { odd: [3, 5], even: [6, 8] }
2762
+ * ```
2763
+ *
2764
+ * @param count The number of elements to drop from the beginning of each group.
2765
+ *
2766
+ * @returns A new {@link AggregatedIterator} containing the remaining elements.
2767
+ */
895
2768
  drop(t) {
896
2769
  const e = this._elements;
897
- return new g(function* () {
2770
+ return new w(function* () {
898
2771
  const n = /* @__PURE__ */ new Map();
899
2772
  for (const [s, r] of e) {
900
2773
  const o = n.get(s) ?? 0;
@@ -906,9 +2779,33 @@ const g = class g {
906
2779
  }
907
2780
  });
908
2781
  }
2782
+ /**
2783
+ * Takes a given number of elements from the beginning of each group of the iterator.
2784
+ * The elements will be included in the new iterator.
2785
+ * See also {@link AggregatedIterator.drop}.
2786
+ *
2787
+ * Since the iterator is lazy, the taking process will
2788
+ * be executed once the resulting iterator is materialized.
2789
+ *
2790
+ * A new iterator will be created, holding the reference to the original one.
2791
+ * This means that the original iterator won't be consumed until the
2792
+ * new one is and that consuming one of them will consume the other as well.
2793
+ *
2794
+ * ```ts
2795
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
2796
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2797
+ * .take(2);
2798
+ *
2799
+ * console.log(results.toObject()); // { odd: [-3, -1], even: [0, 2] }
2800
+ * ```
2801
+ *
2802
+ * @param count The number of elements to take from the beginning of each group.
2803
+ *
2804
+ * @returns A new {@link AggregatedIterator} containing the taken elements.
2805
+ */
909
2806
  take(t) {
910
2807
  const e = this._elements;
911
- return new g(function* () {
2808
+ return new w(function* () {
912
2809
  const n = /* @__PURE__ */ new Map();
913
2810
  for (const [s, r] of e) {
914
2811
  const o = n.get(s) ?? 0;
@@ -922,17 +2819,59 @@ const g = class g {
922
2819
  let [r, o] = e.get(n) ?? [0, void 0];
923
2820
  o === void 0 && (t(n, s, r) && (o = s), e.set(n, [r + 1, o]));
924
2821
  }
925
- return new d(function* () {
2822
+ return new h(function* () {
926
2823
  for (const [n, [s, r]] of e)
927
2824
  yield [n, r];
928
2825
  });
929
2826
  }
2827
+ /**
2828
+ * Enumerates the elements of the iterator.
2829
+ * Each element is paired with its index within the group in a new iterator.
2830
+ *
2831
+ * Since the iterator is lazy, the enumeration process will
2832
+ * be executed once the resulting iterator is materialized.
2833
+ *
2834
+ * A new iterator will be created, holding the reference to the original one.
2835
+ * This means that the original iterator won't be consumed until the
2836
+ * new one is and that consuming one of them will consume the other as well.
2837
+ *
2838
+ * ```ts
2839
+ * const results = new SmartIterator<number>([-3, 0, 2, -1, 3])
2840
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2841
+ * .enumerate();
2842
+ *
2843
+ * console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }
2844
+ * ```
2845
+ *
2846
+ * @returns A new {@link AggregatedIterator} containing the enumerated elements.
2847
+ */
930
2848
  enumerate() {
931
2849
  return this.map((t, e, n) => [n, e]);
932
2850
  }
2851
+ /**
2852
+ * Removes all duplicate elements from within each group of the iterator.
2853
+ * The first occurrence of each element will be included in the new iterator.
2854
+ *
2855
+ * Since the iterator is lazy, the deduplication process will
2856
+ * be executed once the resulting iterator is materialized.
2857
+ *
2858
+ * A new iterator will be created, holding the reference to the original one.
2859
+ * This means that the original iterator won't be consumed until the
2860
+ * new one is and that consuming one of them will consume the other as well.
2861
+ *
2862
+ * ```ts
2863
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])
2864
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2865
+ * .unique();
2866
+ *
2867
+ * console.log(results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
2868
+ * ```
2869
+ *
2870
+ * @returns A new {@link AggregatedIterator} containing only the unique elements.
2871
+ */
933
2872
  unique() {
934
2873
  const t = this._elements;
935
- return new g(function* () {
2874
+ return new w(function* () {
936
2875
  const e = /* @__PURE__ */ new Map();
937
2876
  for (const [n, s] of t) {
938
2877
  const r = e.get(n) ?? /* @__PURE__ */ new Set();
@@ -940,17 +2879,52 @@ const g = class g {
940
2879
  }
941
2880
  });
942
2881
  }
2882
+ /**
2883
+ * Counts the number of elements within each group of the iterator.
2884
+ * This method will consume the entire iterator in the process.
2885
+ *
2886
+ * If the iterator is infinite, the method will never return.
2887
+ *
2888
+ * ```ts
2889
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
2890
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2891
+ * .count();
2892
+ *
2893
+ * console.log(results.toObject()); // { odd: 4, even: 4 }
2894
+ * ```
2895
+ *
2896
+ * @returns A new {@link ReducedIterator} containing the number of elements for each group.
2897
+ */
943
2898
  count() {
944
2899
  const t = /* @__PURE__ */ new Map();
945
2900
  for (const [e] of this._elements) {
946
2901
  const n = t.get(e) ?? 0;
947
2902
  t.set(e, n + 1);
948
2903
  }
949
- return new d(function* () {
2904
+ return new h(function* () {
950
2905
  for (const [e, n] of t)
951
2906
  yield [e, n];
952
2907
  });
953
2908
  }
2909
+ /**
2910
+ * Iterates over the elements of the iterator.
2911
+ * The elements are passed to the given iteratee function along with their key and index within the group.
2912
+ *
2913
+ * This method will consume the entire iterator in the process.
2914
+ * If the iterator is infinite, the method will never return.
2915
+ *
2916
+ * ```ts
2917
+ * const aggregator = new SmartIterator<number>([-3, 0, 2, -1, 3])
2918
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd");
2919
+ *
2920
+ * aggregator.forEach((key, value, index) =>
2921
+ * {
2922
+ * console.log(`${index}: ${value}`); // "0: -3", "0: 0", "1: 2", "1: -1", "2: 3"
2923
+ * };
2924
+ * ```
2925
+ *
2926
+ * @param iteratee The function to execute for each element of the iterator.
2927
+ */
954
2928
  forEach(t) {
955
2929
  const e = /* @__PURE__ */ new Map();
956
2930
  for (const [n, s] of this._elements) {
@@ -958,28 +2932,158 @@ const g = class g {
958
2932
  t(n, s, r), e.set(n, r + 1);
959
2933
  }
960
2934
  }
2935
+ /**
2936
+ * Changes the key of each element on which the iterator is aggregated.
2937
+ * The new key is determined by the given iteratee function.
2938
+ *
2939
+ * Since the iterator is lazy, the reorganization process will
2940
+ * be executed once the resulting iterator is materialized.
2941
+ *
2942
+ * A new iterator will be created, holding the reference to the original one.
2943
+ * This means that the original iterator won't be consumed until the
2944
+ * new one is and that consuming one of them will consume the other as well.
2945
+ *
2946
+ * ```ts
2947
+ * const results = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
2948
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
2949
+ * .map((key, value, index) => index % 2 === 0 ? value : -value)
2950
+ * .reorganizeBy((key, value) => value >= 0 ? "+" : "-");
2951
+ *
2952
+ * console.log(results.toObject()); // { "+": [1, 0, 3, 6], "-": [-3, -2, -5, -8] }
2953
+ * ```
2954
+ *
2955
+ * @template J The type of the new key.
2956
+ *
2957
+ * @param iteratee The function to determine the new key for each element of the iterator.
2958
+ *
2959
+ * @returns A new {@link AggregatedIterator} containing the elements reorganized by the new keys.
2960
+ */
2961
+ reorganizeBy(t) {
2962
+ const e = this._elements;
2963
+ return new w(function* () {
2964
+ const n = /* @__PURE__ */ new Map();
2965
+ for (const [s, r] of e) {
2966
+ const o = n.get(s) ?? 0;
2967
+ yield [t(s, r, o), r], n.set(s, o + 1);
2968
+ }
2969
+ });
2970
+ }
2971
+ /**
2972
+ * An utility method that returns a new {@link SmartIterator}
2973
+ * object containing all the keys of the iterator.
2974
+ *
2975
+ * Since the iterator is lazy, the keys will be extracted
2976
+ * be executed once the resulting iterator is materialized.
2977
+ *
2978
+ * A new iterator will be created, holding the reference to the original one.
2979
+ * This means that the original iterator won't be consumed until the
2980
+ * new one is and that consuming one of them will consume the other as well.
2981
+ *
2982
+ * ```ts
2983
+ * const keys = new SmartIterator([-3, Symbol(), "A", { }, null, [1 , 2, 3], false])
2984
+ * .groupBy((value) => typeof value)
2985
+ * .keys();
2986
+ *
2987
+ * console.log(keys.toArray()); // ["number", "symbol", "string", "object", "boolean"]
2988
+ * ```
2989
+ *
2990
+ * @returns A new {@link SmartIterator} containing all the keys of the iterator.
2991
+ */
961
2992
  keys() {
962
2993
  const t = this._elements;
963
- return new c(function* () {
2994
+ return new u(function* () {
964
2995
  const e = /* @__PURE__ */ new Set();
965
2996
  for (const [n] of t)
966
2997
  e.has(n) || (e.add(n), yield n);
967
2998
  });
968
2999
  }
969
- items() {
3000
+ /**
3001
+ * An utility method that returns a new {@link SmartIterator}
3002
+ * object containing all the entries of the iterator.
3003
+ * Each entry is a tuple containing the key and the element.
3004
+ *
3005
+ * Since the iterator is lazy, the entries will be extracted
3006
+ * be executed once the resulting iterator is materialized.
3007
+ *
3008
+ * A new iterator will be created, holding the reference to the original one.
3009
+ * This means that the original iterator won't be consumed until the
3010
+ * new one is and that consuming one of them will consume the other as well.
3011
+ *
3012
+ * ```ts
3013
+ * const entries = new SmartIterator<number>([-3, 0, 2, -1, 3])
3014
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
3015
+ * .entries();
3016
+ *
3017
+ * console.log(entries.toArray()); // [["odd", -3], ["even", 0], ["even", 2], ["odd", -1], ["odd", 3]]
3018
+ * ```
3019
+ *
3020
+ * @returns A new {@link SmartIterator} containing all the entries of the iterator.
3021
+ */
3022
+ entries() {
970
3023
  return this._elements;
971
3024
  }
3025
+ /**
3026
+ * An utility method that returns a new {@link SmartIterator}
3027
+ * object containing all the values of the iterator.
3028
+ *
3029
+ * Since the iterator is lazy, the values will be extracted
3030
+ * be executed once the resulting iterator is materialized.
3031
+ *
3032
+ * A new iterator will be created, holding the reference to the original one.
3033
+ * This means that the original iterator won't be consumed until the
3034
+ * new one is and that consuming one of them will consume the other as well.
3035
+ *
3036
+ * ```ts
3037
+ * const values = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
3038
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd")
3039
+ * .values();
3040
+ *
3041
+ * console.log(values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]
3042
+ * ```
3043
+ *
3044
+ * @returns A new {@link SmartIterator} containing all the values of the iterator.
3045
+ */
972
3046
  values() {
973
3047
  const t = this._elements;
974
- return new c(function* () {
3048
+ return new u(function* () {
975
3049
  for (const [e, n] of t)
976
3050
  yield n;
977
3051
  });
978
3052
  }
3053
+ /**
3054
+ * Materializes the iterator into an array of arrays.
3055
+ * This method will consume the entire iterator in the process.
3056
+ *
3057
+ * If the iterator is infinite, the method will never return.
3058
+ *
3059
+ * ```ts
3060
+ * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
3061
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd");
3062
+ *
3063
+ * console.log(aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]
3064
+ * ```
3065
+ *
3066
+ * @returns An {@link Array} of arrays containing the elements of the iterator.
3067
+ */
979
3068
  toArray() {
980
3069
  const t = this.toMap();
981
3070
  return Array.from(t.values());
982
3071
  }
3072
+ /**
3073
+ * Materializes the iterator into a map.
3074
+ * This method will consume the entire iterator in the process.
3075
+ *
3076
+ * If the iterator is infinite, the method will never return.
3077
+ *
3078
+ * ```ts
3079
+ * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
3080
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd");
3081
+ *
3082
+ * console.log(aggregator.toMap()); // Map(2) { "odd" => [-3, -1, 3, 5], "even" => [0, 2, 6, 8] }
3083
+ * ```
3084
+ *
3085
+ * @returns A {@link Map} containing the elements of the iterator.
3086
+ */
983
3087
  toMap() {
984
3088
  const t = /* @__PURE__ */ new Map();
985
3089
  for (const [e, n] of this._elements) {
@@ -988,154 +3092,360 @@ const g = class g {
988
3092
  }
989
3093
  return t;
990
3094
  }
991
- toObject() {
992
- const t = {};
993
- for (const [e, n] of this._elements) {
994
- const s = t[e] ?? [];
995
- s.push(n), t[e] = s;
3095
+ /**
3096
+ * Materializes the iterator into an object.
3097
+ * This method will consume the entire iterator in the process.
3098
+ *
3099
+ * If the iterator is infinite, the method will never return.
3100
+ *
3101
+ * ```ts
3102
+ * const aggregator = new SmartIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
3103
+ * .groupBy((value) => value % 2 === 0 ? "even" : "odd");
3104
+ *
3105
+ * console.log(aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
3106
+ * ```
3107
+ *
3108
+ * @returns An {@link Object} containing the elements of the iterator.
3109
+ */
3110
+ toObject() {
3111
+ const t = {};
3112
+ for (const [e, n] of this._elements) {
3113
+ const s = t[e] ?? [];
3114
+ s.push(n), t[e] = s;
996
3115
  }
997
3116
  return t;
998
3117
  }
999
3118
  };
1000
- let S = g;
1001
- const Be = Function;
1002
- class Ge extends Be {
3119
+ let g = w;
3120
+ const Le = Function;
3121
+ var pe, be;
3122
+ class Ge extends (be = Le, pe = Symbol.toStringTag, be) {
3123
+ /**
3124
+ * Initializes a new instance of the {@link CallableObject} class.
3125
+ */
1003
3126
  constructor() {
1004
- super("return this.invoke(...arguments);");
1005
- const t = this.bind(this);
1006
- return Object.setPrototypeOf(this, t), t;
3127
+ super("return this._invoke(...arguments);");
3128
+ a(this, pe, "CallableObject");
3129
+ const e = this.bind(this);
3130
+ return Object.setPrototypeOf(this, e), e;
1007
3131
  }
1008
3132
  }
1009
- var be;
1010
- be = Symbol.toStringTag;
1011
- class M {
3133
+ var xe;
3134
+ xe = Symbol.toStringTag;
3135
+ class E {
3136
+ /**
3137
+ * Initializes a new instance of the {@link Publisher} class.
3138
+ *
3139
+ * ```ts
3140
+ * const publisher = new Publisher();
3141
+ * ```
3142
+ */
1012
3143
  constructor() {
3144
+ /**
3145
+ * A map containing all the subscribers for each event.
3146
+ *
3147
+ * The keys are the names of the events they are subscribed to.
3148
+ * The values are the arrays of the subscribers themselves.
3149
+ */
1013
3150
  a(this, "_subscribers");
1014
- a(this, be, "Publisher");
3151
+ a(this, xe, "Publisher");
1015
3152
  this._subscribers = /* @__PURE__ */ new Map();
1016
3153
  }
3154
+ /**
3155
+ * Unsubscribes all the subscribers from all the events.
3156
+ *
3157
+ * ```ts
3158
+ * publisher.subscribe("player:spawn", (evt) => { [...] });
3159
+ * publisher.subscribe("player:move", (coords) => { [...] });
3160
+ * publisher.subscribe("player:move", () => { [...] });
3161
+ * publisher.subscribe("player:move", ({ x, y }) => { [...] });
3162
+ * publisher.subscribe("player:death", () => { [...] });
3163
+ *
3164
+ * // All these subscribers are working fine...
3165
+ *
3166
+ * publisher.clear();
3167
+ *
3168
+ * // ... but now they're all gone!
3169
+ * ```
3170
+ */
3171
+ clear() {
3172
+ this._subscribers.clear();
3173
+ }
3174
+ /**
3175
+ * Publishes an event to all the subscribers.
3176
+ *
3177
+ * ```ts
3178
+ * publisher.subscribe("player:move", (coords) => { [...] });
3179
+ * publisher.subscribe("player:move", ({ x, y }) => { [...] });
3180
+ * publisher.subscribe("player:move", (evt) => { [...] });
3181
+ *
3182
+ * publisher.publish("player:move", { x: 10, y: 20 });
3183
+ * ```
3184
+ *
3185
+ * @template K The key of the map containing the callback signature to publish.
3186
+ *
3187
+ * @param event The name of the event to publish.
3188
+ * @param args The arguments to pass to the subscribers.
3189
+ *
3190
+ * @returns An array containing the return values of all the subscribers.
3191
+ */
3192
+ publish(t, ...e) {
3193
+ const n = this._subscribers.get(t);
3194
+ return n ? n.slice().map((s) => s(...e)) : [];
3195
+ }
3196
+ /**
3197
+ * Subscribes a new subscriber to an event.
3198
+ *
3199
+ * ```ts
3200
+ * let unsubscribe: () => void;
3201
+ * publisher.subscribe("player:death", unsubscribe);
3202
+ * publisher.subscribe("player:spawn", (evt) =>
3203
+ * {
3204
+ * unsubscribe = publisher.subscribe("player:move", ({ x, y }) => { [...] });
3205
+ * });
3206
+ * ```
3207
+ *
3208
+ * @template K The key of the map containing the callback signature to subscribe.
3209
+ *
3210
+ * @param event The name of the event to subscribe to.
3211
+ * @param subscriber The subscriber to add to the event.
3212
+ *
3213
+ * @returns A function that can be used to unsubscribe the subscriber.
3214
+ */
1017
3215
  subscribe(t, e) {
1018
3216
  this._subscribers.has(t) || this._subscribers.set(t, []);
1019
3217
  const n = this._subscribers.get(t);
1020
3218
  return n.push(e), () => {
1021
3219
  const s = n.indexOf(e);
1022
3220
  if (s < 0)
1023
- throw new Je("Unable to unsubscribe the required subscriber. The subscription was already unsubscribed.");
3221
+ throw new C("Unable to unsubscribe the required subscriber. The subscription was already unsubscribed.");
1024
3222
  n.splice(s, 1);
1025
3223
  };
1026
3224
  }
1027
- publish(t, ...e) {
3225
+ /**
3226
+ * Unsubscribes a subscriber from an event.
3227
+ *
3228
+ * ```ts
3229
+ * const onPlayerMove = ({ x, y }: Point) => { [...] };
3230
+ *
3231
+ * publisher.subscribe("player:spawn", (evt) => publisher.subscribe("player:move", onPlayerMove));
3232
+ * publisher.subscribe("player:death", () => publisher.unsubscribe("player:move", onPlayerMove));
3233
+ * ```
3234
+ *
3235
+ * @template K The key of the map containing the callback signature to unsubscribe.
3236
+ *
3237
+ * @param event The name of the event to unsubscribe from.
3238
+ * @param subscriber The subscriber to remove from the event.
3239
+ */
3240
+ unsubscribe(t, e) {
1028
3241
  const n = this._subscribers.get(t);
1029
- return n ? n.slice().map((s) => s(...e)) : [];
3242
+ if (!n)
3243
+ return;
3244
+ const s = n.indexOf(e);
3245
+ if (s < 0)
3246
+ throw new C("Unable to unsubscribe the required subscriber. The subscription was already unsubscribed or was never subscribed.");
3247
+ n.splice(s, 1);
1030
3248
  }
1031
3249
  }
1032
- class st extends Ge {
3250
+ var ge, ve;
3251
+ class rt extends (ve = Ge, ge = Symbol.toStringTag, ve) {
3252
+ /**
3253
+ * Initializes a new instance of the {@link SwitchableCallback} class.
3254
+ *
3255
+ * ```ts
3256
+ * const onPointerMove = new SwitchableCallback<(evt: PointerEvent) => void>();
3257
+ * ```
3258
+ */
1033
3259
  constructor() {
1034
3260
  const e = () => {
1035
- throw new ze(
3261
+ throw new Be(
1036
3262
  "The `SwitchableCallback` has no callback defined yet. Did you forget to call the `register` method?"
1037
3263
  );
1038
3264
  };
1039
3265
  super();
3266
+ /**
3267
+ * The currently selected implementation of the callback.
3268
+ */
1040
3269
  a(this, "_callback");
3270
+ /**
3271
+ * All the implementations that have been registered for the callback.
3272
+ *
3273
+ * The keys are the names of the implementations they were registered with.
3274
+ * The values are the implementations themselves.
3275
+ */
1041
3276
  a(this, "_callbacks");
3277
+ /**
3278
+ * A flag indicating whether the callback is enabled or not.
3279
+ *
3280
+ * This protected property is the only one that can be modified directly by the derived classes.
3281
+ * If you're looking for the public and readonly property, use
3282
+ * the {@link SwitchableCallback.isEnabled} getter instead.
3283
+ */
1042
3284
  a(this, "_isEnabled");
3285
+ /**
3286
+ * The key that is associated with the currently selected implementation.
3287
+ *
3288
+ * This protected property is the only one that can be modified directly by the derived classes.
3289
+ * If you're looking for the public and readonly property, use the {@link SwitchableCallback.key} getter instead.
3290
+ */
1043
3291
  a(this, "_key");
1044
- a(this, "invoke");
1045
- this._callback = e, this._callbacks = /* @__PURE__ */ new Map(), this._isEnabled = !1, this._key = "", this.invoke = (...n) => this._callback(...n);
3292
+ /**
3293
+ * The function that will be called by the extended class when the object is invoked as a function.
3294
+ */
3295
+ a(this, "_invoke");
3296
+ a(this, ge, "SwitchableCallback");
3297
+ this._callback = e, this._callbacks = /* @__PURE__ */ new Map(), this._isEnabled = !0, this._key = "", this._invoke = (...n) => this._callback(...n);
1046
3298
  }
3299
+ /**
3300
+ * A flag indicating whether the callback is enabled or not.
3301
+ *
3302
+ * It indicates whether the callback is currently able to execute the currently selected implementation.
3303
+ * If it's disabled, the callback will be invoked without executing anything.
3304
+ */
1047
3305
  get isEnabled() {
1048
3306
  return this._isEnabled;
1049
3307
  }
3308
+ /**
3309
+ * The key that is associated with the currently selected implementation.
3310
+ */
1050
3311
  get key() {
1051
3312
  return this._key;
1052
3313
  }
3314
+ /**
3315
+ * Enables the callback, allowing it to execute the currently selected implementation.
3316
+ *
3317
+ * Also note that:
3318
+ * - If any implementation has been registered yet, a {@link KeyException} will be thrown.
3319
+ * - If the callback is already enabled, a {@link RuntimeException} will be thrown.
3320
+ *
3321
+ * ```ts
3322
+ * window.addEventListener("pointerdown", () => { onPointerMove.enable(); });
3323
+ * window.addEventListener("pointermove", onPointerMove);
3324
+ * ```
3325
+ */
1053
3326
  enable() {
1054
3327
  if (!this._key)
1055
- throw new x(
3328
+ throw new b(
1056
3329
  "The `SwitchableCallback` has no callback defined yet. Did you forget to call the `register` method?"
1057
3330
  );
1058
3331
  if (this._isEnabled)
1059
- throw new m("The `SwitchableCallback` is already enabled.");
3332
+ throw new y("The `SwitchableCallback` is already enabled.");
1060
3333
  this._callback = this._callbacks.get(this._key), this._isEnabled = !0;
1061
3334
  }
3335
+ /**
3336
+ * Disables the callback, allowing it to be invoked without executing any implementation.
3337
+ *
3338
+ * If the callback is already disabled, a {@link RuntimeException} will be thrown.
3339
+ *
3340
+ * ```ts
3341
+ * window.addEventListener("pointermove", onPointerMove);
3342
+ * window.addEventListener("pointerup", () => { onPointerMove.disable(); });
3343
+ * ```
3344
+ */
1062
3345
  disable() {
1063
3346
  if (!this._isEnabled)
1064
- throw new m("The `SwitchableCallback` is already disabled.");
3347
+ throw new y("The `SwitchableCallback` is already disabled.");
1065
3348
  this._callback = () => {
1066
3349
  }, this._isEnabled = !1;
1067
3350
  }
3351
+ /**
3352
+ * Registers a new implementation for the callback.
3353
+ *
3354
+ * Also note that:
3355
+ * - If the callback has no other implementation registered yet, this one will be selected as default.
3356
+ * - If the key has already been used for another implementation, a {@link KeyException} will be thrown.
3357
+ *
3358
+ * ```ts
3359
+ * onPointerMove.register("pressed", () => { [...] });
3360
+ * onPointerMove.register("released", () => { [...] });
3361
+ * ```
3362
+ *
3363
+ * @param key The key that will be associated with the implementation.
3364
+ * @param callback The implementation to register.
3365
+ */
1068
3366
  register(e, n) {
1069
3367
  if (this._callbacks.size === 0)
1070
3368
  this._key = e, this._callback = n;
1071
3369
  else if (this._callbacks.has(e))
1072
- throw new x(`The key '${e}' has already been used for another callback.`);
3370
+ throw new b(`The key '${e}' has already been used for another callback.`);
1073
3371
  this._callbacks.set(e, n);
1074
3372
  }
3373
+ /**
3374
+ * Unregisters an implementation for the callback.
3375
+ *
3376
+ * Also note that:
3377
+ * - If the key is the currently selected implementation, a {@link KeyException} will be thrown.
3378
+ * - If the key has no associated implementation yet, a {@link KeyException} will be thrown.
3379
+ *
3380
+ * ```ts
3381
+ * onPointerMove.unregister("released");
3382
+ * ```
3383
+ *
3384
+ * @param key The key that is associated with the implementation to unregister.
3385
+ */
1075
3386
  unregister(e) {
3387
+ if (this._key === e)
3388
+ throw new b("Unable to unregister the currently selected callback.");
1076
3389
  if (!this._callbacks.has(e))
1077
- throw new x(`The key '${e}' doesn't yet have any associated callback.`);
3390
+ throw new b(`The key '${e}' doesn't yet have any associated callback.`);
1078
3391
  this._callbacks.delete(e);
1079
3392
  }
3393
+ /**
3394
+ * Switches the callback to the implementation associated with the given key.
3395
+ *
3396
+ * If the key has no associated implementation yet, a {@link KeyException} will be thrown.
3397
+ *
3398
+ * ```ts
3399
+ * window.addEventListener("pointerdown", () => { onPointerMove.switch("pressed"); });
3400
+ * window.addEventListener("pointermove", onPointerMove);
3401
+ * window.addEventListener("pointerup", () => { onPointerMove.switch("released"); });
3402
+ * ```
3403
+ *
3404
+ * @param key The key that is associated with the implementation to switch to.
3405
+ */
1080
3406
  switch(e) {
1081
3407
  if (!this._callbacks.has(e))
1082
- throw new x(`The key '${e}' doesn't yet have any associated callback.`);
3408
+ throw new b(`The key '${e}' doesn't yet have any associated callback.`);
1083
3409
  this._key = e, this._isEnabled && (this._callback = this._callbacks.get(e));
1084
3410
  }
1085
3411
  }
1086
- var xe;
1087
- xe = Symbol.toStringTag;
1088
- class qe {
1089
- constructor(t, e = 40) {
1090
- a(this, "_handle");
1091
- a(this, "_startTime");
1092
- a(this, "_isRunning");
1093
- a(this, "_start");
1094
- a(this, "_stop");
1095
- a(this, xe, "GameLoop");
1096
- this._startTime = 0, this._isRunning = !1, Oe ? (this._start = () => {
1097
- t(this.elapsedTime), this._handle = window.requestAnimationFrame(this._start);
1098
- }, this._stop = () => window.cancelAnimationFrame(this._handle)) : (console.warn(
1099
- `Not a browser environment detected. Using setInterval@${e}ms instead of requestAnimationFrame...`
1100
- ), this._start = () => {
1101
- this._handle = setInterval(() => t(this.elapsedTime), e);
1102
- }, this._stop = () => clearInterval(this._handle));
1103
- }
1104
- get startTime() {
1105
- return this._startTime;
1106
- }
1107
- get isRunning() {
1108
- return this._isRunning;
1109
- }
1110
- get elapsedTime() {
1111
- return performance.now() - this._startTime;
1112
- }
1113
- start(t = 0) {
1114
- if (this._isRunning)
1115
- throw new m("The game loop has already been started.");
1116
- this._startTime = performance.now() - t, this._start(), this._isRunning = !0;
1117
- }
1118
- stop() {
1119
- if (!this._isRunning)
1120
- throw new m("The game loop hadn't yet started.");
1121
- if (!this._handle)
1122
- throw new k();
1123
- this._stop(), this._handle = void 0, this._isRunning = !1;
1124
- }
1125
- }
1126
- var ve;
1127
- ve = Symbol.toStringTag;
1128
- class rt {
3412
+ var ke;
3413
+ ke = Symbol.toStringTag;
3414
+ class it {
3415
+ /**
3416
+ * Initializes a new instance of the {@link JSONStorage} class.
3417
+ * It cannot be instantiated outside of a browser environment or an {@link EnvironmentException} is thrown.
3418
+ *
3419
+ * ```ts
3420
+ * const jsonStorage = new JSONStorage();
3421
+ * ```
3422
+ *
3423
+ * @param preferPersistence
3424
+ * Whether to prefer the {@link localStorage} over the {@link sessionStorage} when calling an ambivalent method.
3425
+ * If omitted, it defaults to `true` to prefer the persistent storage.
3426
+ */
1129
3427
  constructor(t = !0) {
3428
+ /**
3429
+ * Whether to prefer the {@link localStorage} over the {@link sessionStorage} when calling an ambivalent method.
3430
+ *
3431
+ * If `true`, the persistent storage is preferred. If `false`, the volatile storage is preferred.
3432
+ * Default is `true`.
3433
+ */
1130
3434
  a(this, "_preferPersistence");
3435
+ /**
3436
+ * A reference to the volatile {@link sessionStorage} storage.
3437
+ */
1131
3438
  a(this, "_volatile");
3439
+ /**
3440
+ * A reference to the persistent {@link localStorage} storage.
3441
+ */
1132
3442
  a(this, "_persistent");
1133
- a(this, ve, "JSONStorage");
1134
- if (this._preferPersistence = t, !Oe)
1135
- throw new Ve(
3443
+ a(this, ke, "JSONStorage");
3444
+ if (!Oe)
3445
+ throw new Je(
1136
3446
  "The `JSONStorage` class can only be instantiated within a browser environment."
1137
3447
  );
1138
- this._volatile = window.sessionStorage, this._persistent = window.localStorage;
3448
+ this._preferPersistence = t, this._volatile = window.sessionStorage, this._persistent = window.localStorage;
1139
3449
  }
1140
3450
  _get(t, e, n) {
1141
3451
  const s = t.getItem(e);
@@ -1167,128 +3477,274 @@ class rt {
1167
3477
  return this._get(this._persistent, t, e);
1168
3478
  }
1169
3479
  /**
1170
- * Checks whether the property with the specified name exists in the corresponding storage.
3480
+ * Checks whether the value with the specified key exists within the default storage.
3481
+ *
3482
+ * ```ts
3483
+ * if (jsonStorage.has("key"))
3484
+ * {
3485
+ * // The key exists. Do something...
3486
+ * }
3487
+ * ```
1171
3488
  *
1172
- * @param propertyName The name of the property to check.
1173
- * @param persistent Whether to use the persistent `localStorage` or the volatile `sessionStorage`.
3489
+ * @param key The key of the value to check.
3490
+ * @param persistent
3491
+ * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}.
3492
+ * If omitted, it defaults to the `preferPersistence` value set in the constructor.
1174
3493
  *
1175
- * @returns `true` if the property exists, `false` otherwise.
3494
+ * @returns `true` if the key exists, `false` otherwise.
1176
3495
  */
1177
3496
  has(t, e) {
1178
3497
  return (e ? this._persistent : this._volatile).getItem(t) !== null;
1179
3498
  }
1180
3499
  /**
1181
- * Checks whether the property with the specified name exists in the volatile `sessionStorage`.
3500
+ * Checks whether the value with the specified key exists within the volatile {@link sessionStorage}.
1182
3501
  *
1183
- * @param propertyName The name of the property to check.
3502
+ * ```ts
3503
+ * if (jsonStorage.knows("key"))
3504
+ * {
3505
+ * // The key exists. Do something...
3506
+ * }
3507
+ * ```
1184
3508
  *
1185
- * @returns `true` if the property exists, `false` otherwise.
3509
+ * @param key The key of the value to check.
3510
+ *
3511
+ * @returns `true` if the key exists, `false` otherwise.
1186
3512
  */
1187
3513
  knows(t) {
1188
3514
  return this._volatile.getItem(t) !== null;
1189
3515
  }
1190
3516
  /**
1191
- * Checks whether the property with the specified name exists looking first in the
1192
- * volatile `sessionStorage` and then in the persistent `localStorage`.
3517
+ * Checks whether the value with the specified key exists looking first in the
3518
+ * volatile {@link sessionStorage} and then, if not found, in the persistent {@link localStorage}.
3519
+ *
3520
+ * ```ts
3521
+ * if (jsonStorage.find("key"))
3522
+ * {
3523
+ * // The key exists. Do something...
3524
+ * }
3525
+ * ```
1193
3526
  *
1194
- * @param propertyName The name of the property to check.
3527
+ * @param key The key of the value to check.
1195
3528
  *
1196
- * @returns `true` if the property exists, `false` otherwise.
3529
+ * @returns `true` if the key exists, `false` otherwise.
1197
3530
  */
1198
3531
  find(t) {
1199
3532
  return this.knows(t) ?? this.exists(t);
1200
3533
  }
1201
3534
  /**
1202
- * Checks whether the property with the specified name exists in the persistent `localStorage`.
3535
+ * Checks whether the value with the specified key exists within the persistent {@link localStorage}.
1203
3536
  *
1204
- * @param propertyName The name of the property to check.
3537
+ * ```ts
3538
+ * if (jsonStorage.exists("key"))
3539
+ * {
3540
+ * // The key exists. Do something...
3541
+ * }
3542
+ * ```
1205
3543
  *
1206
- * @returns `true` if the property exists, `false` otherwise.
3544
+ * @param key The key of the value to check.
3545
+ *
3546
+ * @returns `true` if the key exists, `false` otherwise.
1207
3547
  */
1208
3548
  exists(t) {
1209
3549
  return this._persistent.getItem(t) !== null;
1210
3550
  }
1211
3551
  /**
1212
- * Sets the value with the specified name in the corresponding storage.
1213
- * If the value is `undefined`, the property is removed from the storage.
3552
+ * Sets the value with the specified key in the default storage.
3553
+ * If the value is `undefined` or omitted, the key is removed from the storage.
3554
+ *
3555
+ * ```ts
3556
+ * jsonStorage.set("key");
3557
+ * jsonStorage.set("key", value);
3558
+ * jsonStorage.set("key", obj?.value);
3559
+ * ```
3560
+ *
3561
+ * @template T The type of the value to set.
1214
3562
  *
1215
- * @param propertyName The name of the property to set.
1216
- * @param newValue The new value to set.
1217
- * @param persistent Whether to use the persistent `localStorage` or the volatile `sessionStorage`.
3563
+ * @param key The key of the value to set.
3564
+ * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.
3565
+ * @param persistent
3566
+ * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}.
3567
+ * If omitted, it defaults to the `preferPersistence` value set in the constructor.
1218
3568
  */
1219
3569
  set(t, e, n = this._preferPersistence) {
1220
3570
  const s = n ? this._persistent : this._volatile;
1221
3571
  this._set(s, t, e);
1222
3572
  }
1223
3573
  /**
1224
- * Sets the value with the specified name in the volatile `sessionStorage`.
1225
- * If the value is `undefined`, the property is removed from the storage.
3574
+ * Sets the value with the specified key in the volatile {@link sessionStorage}.
3575
+ * If the value is `undefined` or omitted, the key is removed from the storage.
1226
3576
  *
1227
- * @param propertyName The name of the property to set.
1228
- * @param newValue The new value to set.
3577
+ * ```ts
3578
+ * jsonStorage.remember("key");
3579
+ * jsonStorage.remember("key", value);
3580
+ * jsonStorage.remember("key", obj?.value);
3581
+ * ```
3582
+ *
3583
+ * @template T The type of the value to set.
3584
+ *
3585
+ * @param key The key of the value to set.
3586
+ * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.
1229
3587
  */
1230
3588
  remember(t, e) {
1231
3589
  this._set(this._volatile, t, e);
1232
3590
  }
1233
3591
  /**
1234
- * Sets the value with the specified name in the persistent `localStorage`.
1235
- * If the value is `undefined`, the property is removed from the storage.
3592
+ * Sets the value with the specified key in the persistent {@link localStorage}.
3593
+ * If the value is `undefined` or omitted, the key is removed from the storage.
3594
+ *
3595
+ * ```ts
3596
+ * jsonStorage.write("key");
3597
+ * jsonStorage.write("key", value);
3598
+ * jsonStorage.write("key", obj?.value);
3599
+ * ```
1236
3600
  *
1237
- * @param propertyName The name of the property to set.
1238
- * @param newValue The new value to set.
3601
+ * @template T The type of the value to set.
3602
+ *
3603
+ * @param key The key of the value to set.
3604
+ * @param newValue The new value to set. If it's `undefined` or omitted, the key is removed instead.
1239
3605
  */
1240
3606
  write(t, e) {
1241
3607
  this._set(this._persistent, t, e);
1242
3608
  }
1243
3609
  /**
1244
- * Removes the value with the specified name from the volatile `sessionStorage`.
3610
+ * Removes the value with the specified key from the default storage.
3611
+ *
3612
+ * ```ts
3613
+ * jsonStorage.delete("key");
3614
+ * ```
1245
3615
  *
1246
- * @param propertyName The name of the property to remove.
3616
+ * @param key The key of the value to remove.
3617
+ * @param persistent
3618
+ * Whether to prefer the persistent {@link localStorage} over the volatile {@link sessionStorage}.
3619
+ * If omitted, it defaults to the `preferPersistence` value set in the constructor.
3620
+ */
3621
+ delete(t, e) {
3622
+ (e ? this._persistent : this._volatile).removeItem(t);
3623
+ }
3624
+ /**
3625
+ * Removes the value with the specified key from the volatile {@link sessionStorage}.
3626
+ *
3627
+ * ```ts
3628
+ * jsonStorage.forget("key");
3629
+ * ```
3630
+ *
3631
+ * @param key The key of the value to remove.
1247
3632
  */
1248
3633
  forget(t) {
1249
3634
  this._volatile.removeItem(t);
1250
3635
  }
1251
3636
  /**
1252
- * Removes the value with the specified name from the persistent `localStorage`.
3637
+ * Removes the value with the specified key from the persistent {@link localStorage}.
1253
3638
  *
1254
- * @param propertyName The name of the property to remove.
3639
+ * ```ts
3640
+ * jsonStorage.erase("key");
3641
+ * ```
3642
+ *
3643
+ * @param key The key of the value to remove.
1255
3644
  */
1256
3645
  erase(t) {
1257
3646
  this._persistent.removeItem(t);
1258
3647
  }
1259
3648
  /**
1260
- * Removes the value with the specified name from all the storages.
3649
+ * Removes the value with the specified key from both the
3650
+ * volatile {@link sessionStorage} and the persistent {@link localStorage}.
3651
+ *
3652
+ * ```ts
3653
+ * jsonStorage.clear("key");
3654
+ * ```
1261
3655
  *
1262
- * @param propertyName The name of the property to remove.
3656
+ * @param key The key of the value to remove.
1263
3657
  */
1264
3658
  clear(t) {
1265
3659
  this._volatile.removeItem(t), this._persistent.removeItem(t);
1266
3660
  }
1267
3661
  }
1268
- var ke;
1269
- ke = Symbol.toStringTag;
3662
+ var Se;
3663
+ Se = Symbol.toStringTag;
1270
3664
  const R = class R {
3665
+ /**
3666
+ * Initializes a new instance of the {@link SmartPromise} class.
3667
+ *
3668
+ * ```ts
3669
+ * const promise = new SmartPromise<string>((resolve, reject) =>
3670
+ * {
3671
+ * setTimeout(() => resolve("Hello, World!"), 1_000);
3672
+ * });
3673
+ * ```
3674
+ *
3675
+ * @param executor
3676
+ * The function responsible for eventually resolving or rejecting the promise.
3677
+ * Similarly to the native {@link Promise} object, it's immediately executed after the promise is created.
3678
+ */
1271
3679
  constructor(t) {
3680
+ /**
3681
+ * A flag indicating whether the promise is still pending or not.
3682
+ *
3683
+ * The protected property is the only one that can be modified directly by the derived classes.
3684
+ * If you're looking for the public and readonly property, use the {@link SmartPromise.isPending} getter instead.
3685
+ */
1272
3686
  a(this, "_isPending");
3687
+ /**
3688
+ * A flag indicating whether the promise has been fulfilled or not.
3689
+ *
3690
+ * The protected property is the only one that can be modified directly by the derived classes.
3691
+ * If you're looking for the public and readonly property, use the {@link SmartPromise.isFulfilled} getter instead.
3692
+ */
1273
3693
  a(this, "_isFulfilled");
3694
+ /**
3695
+ * A flag indicating whether the promise has been rejected or not.
3696
+ *
3697
+ * The protected property is the only one that can be modified directly by the derived classes.
3698
+ * If you're looking for the public and readonly property, use the {@link SmartPromise.isRejected} getter instead.
3699
+ */
1274
3700
  a(this, "_isRejected");
3701
+ /**
3702
+ * The native {@link Promise} object wrapped by this instance.
3703
+ */
1275
3704
  a(this, "_promise");
1276
- a(this, ke, "SmartPromise");
3705
+ a(this, Se, "SmartPromise");
1277
3706
  this._isPending = !0, this._isFulfilled = !1, this._isRejected = !1;
1278
3707
  const e = (s) => (this._isPending = !1, this._isFulfilled = !0, s), n = (s) => {
1279
3708
  throw this._isPending = !1, this._isRejected = !0, s;
1280
3709
  };
1281
3710
  this._promise = new Promise(t).then(e, n);
1282
3711
  }
3712
+ /**
3713
+ * Wraps a new {@link SmartPromise} object around an existing native {@link Promise} object.
3714
+ *
3715
+ * ```ts
3716
+ * const request = fetch("https://api.example.com/data");
3717
+ * const smartRequest = SmartPromise.FromPromise(request);
3718
+ *
3719
+ * console.log(request.isPending); // Throws an error: `isPending` is not a property of `Promise`.
3720
+ * console.log(smartRequest.isPending); // true
3721
+ *
3722
+ * const response = await request;
3723
+ * console.log(smartRequest.isFulfilled); // true
3724
+ * ```
3725
+ *
3726
+ * @param promise The promise to wrap.
3727
+ *
3728
+ * @returns A new {@link SmartPromise} object that wraps the provided promise.
3729
+ */
1283
3730
  static FromPromise(t) {
1284
3731
  return new R((e, n) => t.then(e, n));
1285
3732
  }
3733
+ /**
3734
+ * A flag indicating whether the promise is still pending or not.
3735
+ */
1286
3736
  get isPending() {
1287
3737
  return this._isPending;
1288
3738
  }
3739
+ /**
3740
+ * A flag indicating whether the promise has been fulfilled or not.
3741
+ */
1289
3742
  get isFulfilled() {
1290
3743
  return this._isFulfilled;
1291
3744
  }
3745
+ /**
3746
+ * A flag indicating whether the promise has been rejected or not.
3747
+ */
1292
3748
  get isRejected() {
1293
3749
  return this._isRejected;
1294
3750
  }
@@ -1298,296 +3754,384 @@ const R = class R {
1298
3754
  catch(t) {
1299
3755
  return this._promise.catch(t);
1300
3756
  }
3757
+ /**
3758
+ * Attaches a callback that executes right after the promise is settled, regardless of the outcome.
3759
+ *
3760
+ * ```ts
3761
+ * const promise = new SmartPromise((resolve, reject) =>
3762
+ * {
3763
+ * setTimeout(resolve, Math.random() * 1_000);
3764
+ * setTimeout(reject, Math.random() * 1_000);
3765
+ * });
3766
+ *
3767
+ *
3768
+ * promise
3769
+ * .then(() => console.log("OK!")) // Logs "OK!" if the promise is fulfilled.
3770
+ * .catch(() => console.log("KO!")) // Logs "KO!" if the promise is rejected.
3771
+ * .finally(() => console.log("Done!")); // Always logs "Done!".
3772
+ * ```
3773
+ *
3774
+ * @param onFinally The callback to execute when once promise is settled.
3775
+ *
3776
+ * @returns A new {@link Promise} that executes the callback once the promise is settled.
3777
+ */
1301
3778
  finally(t) {
1302
3779
  return this._promise.finally(t);
1303
3780
  }
1304
3781
  };
1305
- let T = R;
1306
- var Se, Te;
1307
- class Ke extends (Te = T, Se = Symbol.toStringTag, Te) {
3782
+ let k = R;
3783
+ var Te, Ee;
3784
+ class Ke extends (Ee = k, Te = Symbol.toStringTag, Ee) {
3785
+ /**
3786
+ * Initializes a new instance of the {@link DeferredPromise} class.
3787
+ *
3788
+ * ```ts
3789
+ * const promise = new DeferredPromise<string, string[]>((value: string) => value.split(" "));
3790
+ * ```
3791
+ *
3792
+ * @param onFulfilled The callback to execute once the promise is fulfilled.
3793
+ * @param onRejected The callback to execute once the promise is rejected.
3794
+ */
1308
3795
  constructor(e, n) {
1309
3796
  let s, r;
1310
3797
  super((o, l) => {
1311
3798
  s = o, r = l;
1312
3799
  });
3800
+ /**
3801
+ * The exposed function that allows to resolve the promise.
3802
+ *
3803
+ * This protected property is the only one that can be modified directly by the derived classes.
3804
+ * If you're looking for the public and readonly property, use the {@link DeferredPromise.resolve} getter instead.
3805
+ */
1313
3806
  a(this, "_resolve");
3807
+ /**
3808
+ * The exposed function that allows to reject the promise.
3809
+ *
3810
+ * This protected property is the only one that can be modified directly by the derived classes.
3811
+ * If you're looking for the public and readonly property, use the {@link DeferredPromise.reject} getter instead.
3812
+ */
1314
3813
  a(this, "_reject");
1315
- a(this, Se, "DeferredPromise");
1316
- this._promise.then(e, n), this._resolve = s, this._reject = r;
3814
+ a(this, Te, "DeferredPromise");
3815
+ this._promise = this._promise.then(e, n), this._resolve = s, this._reject = r;
1317
3816
  }
3817
+ /**
3818
+ * The exposed function that allows to reject the promise.
3819
+ */
1318
3820
  get resolve() {
1319
3821
  return this._resolve;
1320
3822
  }
3823
+ /**
3824
+ * The exposed function that allows to reject the promise.
3825
+ */
1321
3826
  get reject() {
1322
3827
  return this._reject;
1323
3828
  }
3829
+ /**
3830
+ * Watches another promise and resolves or rejects this promise when the other one is settled.
3831
+ *
3832
+ * ```ts
3833
+ * const promise = new Promise<string>((resolve) => setTimeout(() => resolve("Hello, World!"), 1_000));
3834
+ * const deferred = new DeferredPromise<string, string[]>((value: string) => value.split(" "));
3835
+ *
3836
+ * deferred.then((result) => console.log(result)); // ["Hello,", "World!"]
3837
+ * deferred.watch(promise);
3838
+ * ```
3839
+ *
3840
+ * @param otherPromise The promise to watch.
3841
+ *
3842
+ * @returns The current instance of the {@link DeferredPromise} class.
3843
+ */
1324
3844
  watch(e) {
1325
3845
  return e.then(this.resolve, this.reject), this;
1326
3846
  }
1327
3847
  }
1328
- function it(i) {
1329
- return new Promise((t) => setTimeout(t, i));
3848
+ var Me, Re;
3849
+ class ot extends (Re = k, Me = Symbol.toStringTag, Re) {
3850
+ /**
3851
+ * Initializes a new instance of the {@link TimedPromise} class.
3852
+ *
3853
+ * ```ts
3854
+ * const promise = new TimedPromise<string>((resolve, reject) =>
3855
+ * {
3856
+ * setTimeout(() => resolve("Hello, World!"), Math.random() * 10_000);
3857
+ *
3858
+ * }, 5_000);
3859
+ * ```
3860
+ *
3861
+ * @param executor
3862
+ * The function responsible for eventually resolving or rejecting the promise.
3863
+ * Similarly to the native {@link Promise} object, it's immediately executed after the promise is created.
3864
+ *
3865
+ * @param timeout The maximum time in milliseconds that the operation can take before timing out.
3866
+ */
3867
+ constructor(e, n) {
3868
+ super((s, r) => {
3869
+ const o = (S) => {
3870
+ clearTimeout(P), s(S);
3871
+ }, l = (S) => {
3872
+ clearTimeout(P), r(S);
3873
+ }, P = setTimeout(() => l(new Ye("The operation has timed out.")), n);
3874
+ e(o, l);
3875
+ });
3876
+ a(this, Me, "TimedPromise");
3877
+ }
1330
3878
  }
1331
- function ot() {
1332
- return new Promise((i) => requestAnimationFrame(() => i()));
3879
+ var M = /* @__PURE__ */ ((i) => (i[i.Millisecond = 1] = "Millisecond", i[i.Second = 1e3] = "Second", i[i.Minute = 6e4] = "Minute", i[i.Hour = 36e5] = "Hour", i[i.Day = 864e5] = "Day", i[i.Week = 6048e5] = "Week", i[i.Month = 2592e6] = "Month", i[i.Year = 31536e6] = "Year", i))(M || {}), He = /* @__PURE__ */ ((i) => (i[i.Sunday = 0] = "Sunday", i[i.Monday = 1] = "Monday", i[i.Tuesday = 2] = "Tuesday", i[i.Wednesday = 3] = "Wednesday", i[i.Thursday = 4] = "Thursday", i[i.Friday = 5] = "Friday", i[i.Saturday = 6] = "Saturday", i))(He || {});
3880
+ function at(i, t, e = 864e5) {
3881
+ let n;
3882
+ return i = new Date(i), t = new Date(t), i < t ? n = Math.floor : n = Math.ceil, n((t.getTime() - i.getTime()) / e);
1333
3883
  }
1334
- function v() {
1335
- return new Promise((i) => setTimeout(i));
3884
+ function lt(i, t, e = 864e5) {
3885
+ if (i >= t)
3886
+ throw new p("The end date must be greater than the start date.");
3887
+ return new u(function* () {
3888
+ const n = new Date(t).getTime();
3889
+ let s = new Date(i).getTime();
3890
+ for (; s < n; )
3891
+ yield new Date(s), s += e;
3892
+ });
3893
+ }
3894
+ function Qe(i, t = 864e5) {
3895
+ if (t <= 1)
3896
+ throw new p(
3897
+ "Rounding a timestamp by milliseconds or less makes no sense.Use the timestamp value directly instead."
3898
+ );
3899
+ if (t > 864e5)
3900
+ throw new p(
3901
+ "Rounding by more than a day leads to unexpected results. Consider using other methods to round dates by weeks, months or years."
3902
+ );
3903
+ return i = new Date(i), new Date(Math.floor(i.getTime() / t) * t);
1336
3904
  }
1337
- var Ee;
1338
- Ee = Symbol.toStringTag;
1339
- const P = class P {
1340
- constructor(t, e) {
3905
+ function ut(i, t = 0) {
3906
+ i = new Date(i);
3907
+ const e = 7 - t, n = (i.getUTCDay() + e) % 7, s = i.getTime() - 864e5 * n;
3908
+ return Qe(new Date(s));
3909
+ }
3910
+ var Fe;
3911
+ Fe = Symbol.toStringTag;
3912
+ class qe {
3913
+ /**
3914
+ * Initializes a new instance of the {@link GameLoop} class.
3915
+ *
3916
+ * ```ts
3917
+ * const loop = new GameLoop((elapsedTime: number) => { [...] });
3918
+ * ```
3919
+ *
3920
+ * @param callback The function that will be executed at each iteration of the game loop.
3921
+ * @param msIfNotBrowser
3922
+ * The interval in milliseconds that will be used if the current environment isn't a browser. Default is `40`.
3923
+ */
3924
+ constructor(t, e = 40) {
3925
+ /**
3926
+ * The handle of the interval or the animation frame, depending on the environment.
3927
+ * It's used to stop the game loop when the {@link GameLoop._stop} method is called.
3928
+ */
3929
+ a(this, "_handle");
3930
+ /**
3931
+ * The time when the game loop has started.
3932
+ * In addition to indicating the {@link https://en.wikipedia.org/wiki/Unix_time|Unix timestamp}
3933
+ * of the start of the game loop, it's also used to calculate the elapsed time.
3934
+ *
3935
+ * This protected property is the only one that can be modified directly by the derived classes.
3936
+ * If you're looking for the public and readonly property, use the {@link GameLoop.startTime} getter instead.
3937
+ */
1341
3938
  a(this, "_startTime");
1342
- a(this, "_estimatedTime");
1343
- a(this, "_endTime");
1344
- a(this, "_currentStep");
1345
- a(this, "_percentage");
3939
+ /**
3940
+ * A flag indicating whether the game loop is currently running or not.
3941
+ *
3942
+ * This protected property is the only one that can be modified directly by the derived classes.
3943
+ * If you're looking for the public and readonly property, use the {@link GameLoop.isRunning} getter instead.
3944
+ */
1346
3945
  a(this, "_isRunning");
1347
- a(this, "_hasCompleted");
1348
- a(this, "_hasFailed");
1349
- a(this, "_promise");
3946
+ /**
3947
+ * The {@link Publisher} object that will be used to publish the events of the game loop.
3948
+ */
1350
3949
  a(this, "_publisher");
1351
- a(this, Ee, "LongRunningTask");
1352
- this._startTime = 0, this._estimatedTime = 0, this._currentStep = 0, this._percentage = 0, this._isRunning = !0, this._hasCompleted = !1, this._hasFailed = !1;
1353
- const n = (o) => (this._estimatedTime = 0, this._endTime = Date.now(), this._percentage = 100, this._isRunning = !1, this._hasCompleted = !0, o), s = (o) => {
1354
- throw this._endTime = Date.now(), this._isRunning = !1, this._hasFailed = !0, o;
1355
- };
1356
- let r;
1357
- if (e = { ...P._DefaultOptions, ...e }, e.trackProgress) {
1358
- let o;
1359
- this._publisher = new M(), e.totalSteps ? e.stepIncrement ? o = (l) => {
1360
- l ? this._currentStep += l : this._currentStep += e.stepIncrement, this._percentage = this._currentStep / e.totalSteps * 100;
1361
- const u = Date.now() - this._startTime, h = e.totalSteps - this._currentStep;
1362
- this._estimatedTime = u / this._currentStep * h;
1363
- } : o = (l) => {
1364
- if (l) {
1365
- this._currentStep += l, this._percentage = this._currentStep / e.totalSteps * 100;
1366
- const u = Date.now() - this._startTime, h = e.totalSteps - this._currentStep;
1367
- this._estimatedTime = u / this._currentStep * h;
1368
- }
1369
- } : e.stepIncrement ? o = (l) => {
1370
- l ? this._currentStep += l : this._currentStep += e.stepIncrement;
1371
- } : o = (l) => {
1372
- l && (this._currentStep += l);
1373
- }, e.ignoreErrors ? r = async (l) => {
1374
- const u = t();
1375
- for (this._startTime = Date.now(); ; ) {
1376
- try {
1377
- const { done: h, value: _ } = await u.next();
1378
- if (h)
1379
- return l(_);
1380
- o(_);
1381
- } catch (h) {
1382
- console.error(h);
1383
- }
1384
- this._publisher.publish("progress"), await v();
1385
- }
1386
- } : r = async (l, u) => {
1387
- try {
1388
- const h = t();
1389
- for (this._startTime = Date.now(); ; ) {
1390
- const { done: _, value: I } = await h.next();
1391
- if (_)
1392
- return l(I);
1393
- o(I), this._publisher.publish("progress"), await v();
1394
- }
1395
- } catch (h) {
1396
- u(h);
1397
- }
1398
- };
1399
- } else e.ignoreErrors ? r = async (o) => {
1400
- const l = t();
1401
- for (this._startTime = Date.now(); ; ) {
1402
- try {
1403
- const { done: u, value: h } = await l.next();
1404
- if (u)
1405
- return o(h);
1406
- } catch (u) {
1407
- console.error(u);
1408
- }
1409
- await v();
1410
- }
1411
- } : r = async (o, l) => {
1412
- try {
1413
- const u = t();
1414
- for (this._startTime = Date.now(); ; ) {
1415
- const { done: h, value: _ } = await u.next();
1416
- if (h)
1417
- return o(_);
1418
- await v();
1419
- }
1420
- } catch (u) {
1421
- l(u);
1422
- }
1423
- };
1424
- this._promise = new Promise(r).then(n, s);
1425
- }
1426
- static get _DefaultOptions() {
1427
- return {
1428
- ignoreErrors: !1,
1429
- stepIncrement: 1,
1430
- totalSteps: null,
1431
- trackProgress: !1
1432
- };
3950
+ /**
3951
+ * The internal method actually responsible for starting the game loop.
3952
+ *
3953
+ * Depending on the current environment, it could use the
3954
+ * {@link requestAnimationFrame} or the {@link setInterval} function.
3955
+ */
3956
+ a(this, "_start");
3957
+ /**
3958
+ * The internal method actually responsible for stopping the game loop.
3959
+ *
3960
+ * Depending on the current environment, it could use the
3961
+ * {@link cancelAnimationFrame} or the {@link clearInterval} function.
3962
+ */
3963
+ a(this, "_stop");
3964
+ a(this, Fe, "GameLoop");
3965
+ this._startTime = 0, this._isRunning = !1, Oe ? (this._start = () => {
3966
+ t(this.elapsedTime), this._handle = window.requestAnimationFrame(this._start);
3967
+ }, this._stop = () => window.cancelAnimationFrame(this._handle)) : (console.warn(
3968
+ `Not a browser environment detected. Using setInterval@${e}ms instead of requestAnimationFrame...`
3969
+ ), this._start = () => {
3970
+ this._handle = setInterval(() => t(this.elapsedTime), e);
3971
+ }, this._stop = () => clearInterval(this._handle)), this._publisher = new E();
1433
3972
  }
3973
+ /**
3974
+ * The time when the game loop has started.
3975
+ * In addition to indicating the {@link https://en.wikipedia.org/wiki/Unix_time|Unix timestamp}
3976
+ * of the start of the game loop, it's also used to calculate the elapsed time.
3977
+ */
1434
3978
  get startTime() {
1435
3979
  return this._startTime;
1436
3980
  }
1437
- get elapsedTime() {
1438
- return this._isRunning ? Date.now() - this._startTime : this._endTime - this._startTime;
1439
- }
1440
- get estimatedTime() {
1441
- return this._estimatedTime;
1442
- }
1443
- get endTime() {
1444
- if (this._isRunning)
1445
- throw new m("The task is still running and has no end time yet.");
1446
- return this._endTime;
1447
- }
1448
- get currentStep() {
1449
- return this._currentStep;
1450
- }
1451
- get percentage() {
1452
- return this._percentage;
1453
- }
3981
+ /**
3982
+ * A flag indicating whether the game loop is currently running or not.
3983
+ */
1454
3984
  get isRunning() {
1455
3985
  return this._isRunning;
1456
3986
  }
1457
- get hasCompleted() {
1458
- return this._hasCompleted;
1459
- }
1460
- get hasFailed() {
1461
- return this._hasFailed;
1462
- }
1463
- then(t, e) {
1464
- return this._promise.then(t, e);
1465
- }
1466
- catch(t) {
1467
- return this._promise.catch(t);
1468
- }
1469
- finally(t) {
1470
- return this._promise.finally(t);
1471
- }
1472
- onProgress(t) {
1473
- if (!this._publisher)
1474
- throw new m(
1475
- "You cannot subscribe to progress events without enabling progress tracking. Did you forget to set the `trackProgress` option to `true` when creating the task?"
1476
- );
1477
- return this._publisher.subscribe("progress", t);
1478
- }
1479
- };
1480
- let C = P;
1481
- var Me;
1482
- Me = Symbol.toStringTag;
1483
- class at {
1484
- constructor() {
1485
- a(this, "_onFulfilled");
1486
- a(this, Me, "Thenable");
1487
- this._onFulfilled = (t) => t;
1488
- }
1489
- _resolve(t) {
1490
- return this._onFulfilled(t);
3987
+ /**
3988
+ * The elapsed time since the start of the game loop.
3989
+ * It's calculated as the difference between the current time and the {@link GameLoop.startTime}.
3990
+ */
3991
+ get elapsedTime() {
3992
+ return performance.now() - this._startTime;
1491
3993
  }
1492
- then(t, e) {
1493
- if (e) {
1494
- const n = this._onFulfilled;
1495
- this._onFulfilled = (s) => {
1496
- try {
1497
- return s = n(s), t(s);
1498
- } catch (r) {
1499
- return e(r);
1500
- }
1501
- };
1502
- } else if (t) {
1503
- const n = this._onFulfilled;
1504
- this._onFulfilled = (s) => (s = n(s), t(s));
1505
- }
1506
- return this;
3994
+ /**
3995
+ * Starts the execution of the game loop.
3996
+ *
3997
+ * If the game loop is already running, a {@link RuntimeException} will be thrown.
3998
+ *
3999
+ * ```ts
4000
+ * loop.onStart(() => { [...] }); // This callback will be executed.
4001
+ * loop.start();
4002
+ * ```
4003
+ *
4004
+ * @param elapsedTime The elapsed time to set as default when the game loop starts. Default is `0`.
4005
+ */
4006
+ start(t = 0) {
4007
+ if (this._isRunning)
4008
+ throw new y("The game loop has already been started.");
4009
+ this._startTime = performance.now() - t, this._start(), this._isRunning = !0, this._publisher.publish("start");
1507
4010
  }
1508
- catch(t) {
1509
- if (t) {
1510
- const e = this._onFulfilled;
1511
- this._onFulfilled = (n) => {
1512
- try {
1513
- return e(n);
1514
- } catch (s) {
1515
- return t(s);
1516
- }
1517
- };
1518
- }
1519
- return this;
4011
+ /**
4012
+ * Stops the execution of the game loop.
4013
+ *
4014
+ * If the game loop hasn't yet started, a {@link RuntimeException} will be thrown.
4015
+ *
4016
+ * ```ts
4017
+ * loop.onStop(() => { [...] }); // This callback will be executed.
4018
+ * loop.stop();
4019
+ * ```
4020
+ */
4021
+ stop() {
4022
+ if (!this._isRunning)
4023
+ throw new y("The game loop had already stopped or hadn't yet started.");
4024
+ if (!this._handle)
4025
+ throw new x();
4026
+ this._stop(), this._handle = void 0, this._isRunning = !1, this._publisher.publish("stop");
1520
4027
  }
1521
- finally(t) {
1522
- if (t) {
1523
- const e = this._onFulfilled;
1524
- this._onFulfilled = (n) => {
1525
- try {
1526
- return e(n);
1527
- } finally {
1528
- t();
1529
- }
1530
- };
1531
- }
1532
- return this;
4028
+ /**
4029
+ * Subscribes to the `start` event of the game loop.
4030
+ *
4031
+ * ```ts
4032
+ * loop.onStart(() => { console.log("The game loop has started."); });
4033
+ * ```
4034
+ *
4035
+ * @param callback The function that will be executed when the game loop starts.
4036
+ *
4037
+ * @returns A function that can be used to unsubscribe from the event.
4038
+ */
4039
+ onStart(t) {
4040
+ return this._publisher.subscribe("start", t);
1533
4041
  }
1534
- }
1535
- var Fe, Re;
1536
- class lt extends (Re = T, Fe = Symbol.toStringTag, Re) {
1537
- constructor(e, n) {
1538
- super((s, r) => {
1539
- const o = (_) => {
1540
- clearTimeout(h), s(_);
1541
- }, l = (_) => {
1542
- clearTimeout(h), r(_);
1543
- }, h = setTimeout(() => l(new We("The operation has timed out.")), n);
1544
- e(o, l);
1545
- });
1546
- a(this, Fe, "TimedPromise");
4042
+ /**
4043
+ * Subscribes to the `stop` event of the game loop.
4044
+ *
4045
+ * ```ts
4046
+ * loop.onStop(() => { console.log("The game loop has stopped."); });
4047
+ * ```
4048
+ *
4049
+ * @param callback The function that will be executed when the game loop stops.
4050
+ *
4051
+ * @returns A function that can be used to unsubscribe from the event.
4052
+ */
4053
+ onStop(t) {
4054
+ return this._publisher.subscribe("stop", t);
1547
4055
  }
1548
4056
  }
1549
- var F = /* @__PURE__ */ ((i) => (i[i.Millisecond = 1] = "Millisecond", i[i.Second = 1e3] = "Second", i[i.Minute = 6e4] = "Minute", i[i.Hour = 36e5] = "Hour", i[i.Day = 864e5] = "Day", i[i.Week = 6048e5] = "Week", i[i.Month = 2592e6] = "Month", i[i.Year = 31536e6] = "Year", i))(F || {});
1550
- function ut(i, t, e = 864e5) {
1551
- return i = new Date(i), t = new Date(t), Math.floor((t.getTime() - i.getTime()) / e);
1552
- }
1553
- function ct(i, t, e = 864e5) {
1554
- return i = new Date(i), t = new Date(t), new c(function* () {
1555
- const n = t.getTime();
1556
- let s = i.getTime();
1557
- for (; s < n; )
1558
- yield new Date(s), s += e;
1559
- });
1560
- }
1561
- function ht(i, t = 864e5) {
1562
- return i = new Date(i), new Date(Math.floor(i.getTime() / t) * t);
1563
- }
1564
- var Pe, De;
1565
- class ft extends (De = qe, Pe = Symbol.toStringTag, De) {
1566
- constructor(e = F.Second) {
4057
+ var Pe, Ce;
4058
+ class ct extends (Ce = qe, Pe = Symbol.toStringTag, Ce) {
4059
+ /**
4060
+ * Initializes a new instance of the {@link Clock} class.
4061
+ *
4062
+ * ```ts
4063
+ * const clock = new Clock();
4064
+ * ```
4065
+ *
4066
+ * @param msIfNotBrowser
4067
+ * The interval in milliseconds at which the clock will tick if the environment is not a browser.
4068
+ * `TimeUnit.Second` by default.
4069
+ */
4070
+ constructor(e = M.Second) {
1567
4071
  super((n) => this._publisher.publish("tick", n), e);
4072
+ /**
4073
+ * The {@link Publisher} object that will be used to publish the events of the clock.
4074
+ */
1568
4075
  a(this, "_publisher");
1569
4076
  a(this, Pe, "Clock");
1570
- this._publisher = new M();
4077
+ this._publisher = new E();
1571
4078
  }
4079
+ /**
4080
+ * Starts the execution of the clock.
4081
+ *
4082
+ * If the clock is already running, a {@link RuntimeException} will be thrown.
4083
+ *
4084
+ * ```ts
4085
+ * clock.onStart(() => { [...] }); // This callback will be executed.
4086
+ * clock.start();
4087
+ * ```
4088
+ *
4089
+ * @param elapsedTime The elapsed time to set as default when the clock starts. Default is `0`.
4090
+ */
1572
4091
  start(e = 0) {
1573
4092
  if (this._isRunning)
1574
- throw new m("The clock has already been started.");
1575
- super.start(e), this._publisher.publish("start");
4093
+ throw new y("The clock has already been started.");
4094
+ this._startTime = performance.now() - e, this._start(), this._isRunning = !0, this._publisher.publish("start");
1576
4095
  }
4096
+ /**
4097
+ * Stops the execution of the clock.
4098
+ *
4099
+ * If the clock hasn't yet started, a {@link RuntimeException} will be thrown.
4100
+ *
4101
+ * ```ts
4102
+ * clock.onStop(() => { [...] }); // This callback will be executed.
4103
+ * clock.stop();
4104
+ * ```
4105
+ */
1577
4106
  stop() {
1578
4107
  if (!this._isRunning)
1579
- throw new m("The clock hadn't yet started.");
1580
- super.stop(), this._publisher.publish("stop");
1581
- }
1582
- onStart(e) {
1583
- return this._publisher.subscribe("start", e);
1584
- }
1585
- onStop(e) {
1586
- return this._publisher.subscribe("stop", e);
4108
+ throw new y("The clock had already stopped or hadn't yet started.");
4109
+ if (!this._handle)
4110
+ throw new x();
4111
+ this._stop(), this._handle = void 0, this._isRunning = !1, this._publisher.publish("stop");
1587
4112
  }
4113
+ /**
4114
+ * Subscribes to the `tick` event of the clock.
4115
+ *
4116
+ * ```ts
4117
+ * clock.onTick((elapsedTime) => { [...] }); // This callback will be executed.
4118
+ * clock.start();
4119
+ * ```
4120
+ *
4121
+ * @param callback The callback that will be executed when the clock ticks.
4122
+ * @param tickStep
4123
+ * The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.
4124
+ *
4125
+ * - If it's a positive number, the callback will be executed only if the
4126
+ * time passed from the previous execution is greater than this number.
4127
+ * - If it's `0`, the callback will be executed every tick without even checking for the time.
4128
+ * - If it's a negative number, a {@link RangeException} will be thrown.
4129
+ *
4130
+ * @returns A function that can be used to unsubscribe from the event.
4131
+ */
1588
4132
  onTick(e, n = 0) {
1589
4133
  if (n < 0)
1590
- throw new $e("The tick step must be a non-negative number.");
4134
+ throw new p("The tick step must be a non-negative number.");
1591
4135
  if (n === 0)
1592
4136
  return this._publisher.subscribe("tick", e);
1593
4137
  let s = 0;
@@ -1596,68 +4140,246 @@ class ft extends (De = qe, Pe = Symbol.toStringTag, De) {
1596
4140
  });
1597
4141
  }
1598
4142
  }
1599
- var Ie, Ce;
1600
- class dt extends (Ce = qe, Ie = Symbol.toStringTag, Ce) {
1601
- constructor(e, n = F.Second) {
4143
+ var je, Ie;
4144
+ class ht extends (Ie = qe, je = Symbol.toStringTag, Ie) {
4145
+ /**
4146
+ * Initializes a new instance of the {@link Countdown} class.
4147
+ *
4148
+ * ```ts
4149
+ * const countdown = new Countdown(10_000);
4150
+ * ```
4151
+ *
4152
+ * @param duration
4153
+ * The total duration of the countdown in milliseconds.
4154
+ *
4155
+ * @param msIfNotBrowser
4156
+ * The interval in milliseconds at which the countdown will tick if the environment is not a browser.
4157
+ * `TimeUnit.Second` by default.
4158
+ */
4159
+ constructor(e, n = M.Second) {
1602
4160
  super(() => {
1603
4161
  const r = this.remainingTime;
1604
- this._publisher.publish("tick", r), r <= 0 && (this._deferrerStop(), this._publisher.publish("expire"));
4162
+ r <= 0 ? (this._deferrerStop(), this._publisher.publish("tick", 0), this._publisher.publish("expire")) : this._publisher.publish("tick", r);
1605
4163
  }, n);
1606
- a(this, "_deferrer");
4164
+ /**
4165
+ * The {@link Publisher} object that will be used to publish the events of the countdown.
4166
+ */
1607
4167
  a(this, "_publisher");
4168
+ /**
4169
+ * The total duration of the countdown in milliseconds.
4170
+ *
4171
+ * This protected property is the only one that can be modified directly by the derived classes.
4172
+ * If you're looking for the public and readonly property, use the {@link Countdown.duration} getter instead.
4173
+ */
1608
4174
  a(this, "_duration");
1609
- a(this, Ie, "Countdown");
1610
- this._publisher = new M(), this._duration = e;
4175
+ /**
4176
+ * The {@link DeferredPromise} that will be resolved or rejected when the countdown expires or stops.
4177
+ */
4178
+ a(this, "_deferrer");
4179
+ a(this, je, "Countdown");
4180
+ this._publisher = new E(), this._duration = e;
1611
4181
  }
4182
+ /**
4183
+ * The total duration of the countdown in milliseconds.
4184
+ */
1612
4185
  get duration() {
1613
4186
  return this._duration;
1614
4187
  }
4188
+ /**
4189
+ * The remaining time of the countdown in milliseconds.
4190
+ * It's calculated as the difference between the total duration and the elapsed time.
4191
+ */
1615
4192
  get remainingTime() {
1616
4193
  return this._duration - this.elapsedTime;
1617
4194
  }
4195
+ /**
4196
+ * The internal method actually responsible for stopping the
4197
+ * countdown and resolving or rejecting the {@link Countdown._deferrer} promise.
4198
+ *
4199
+ * @param reason
4200
+ * The reason why the countdown has stopped.
4201
+ *
4202
+ * - If it's `undefined`, the promise will be resolved.
4203
+ * - If it's a value, the promise will be rejected with that value.
4204
+ */
1618
4205
  _deferrerStop(e) {
1619
4206
  if (!this._isRunning)
1620
- throw new m("The countdown hadn't yet started.");
4207
+ throw new y("The countdown hadn't yet started.");
1621
4208
  if (!this._deferrer)
1622
- throw new k();
1623
- super.stop(), e !== void 0 ? this._deferrer.reject(e) : this._deferrer.resolve(), this._deferrer = void 0;
4209
+ throw new x();
4210
+ this._stop(), this._handle = void 0, this._isRunning = !1, e !== void 0 ? this._deferrer.reject(e) : this._deferrer.resolve(), this._deferrer = void 0;
1624
4211
  }
4212
+ /**
4213
+ * Starts the execution of the countdown.
4214
+ *
4215
+ * If the countdown is already running, a {@link RuntimeException} will be thrown.
4216
+ *
4217
+ * ```ts
4218
+ * countdown.onStart(() => { [...] }); // This callback will be executed.
4219
+ * countdown.start();
4220
+ * ```
4221
+ *
4222
+ * @param remainingTime
4223
+ * The remaining time to set as default when the countdown starts.
4224
+ * Default is the {@link Countdown.duration} itself.
4225
+ *
4226
+ * @returns A {@link SmartPromise} that will be resolved or rejected when the countdown expires or stops.
4227
+ */
1625
4228
  start(e = this.duration) {
1626
4229
  if (this._isRunning)
1627
- throw new m("The countdown has already been started.");
4230
+ throw new y("The countdown had already stopped or hadn't yet started.");
1628
4231
  if (this._deferrer)
1629
- throw new k();
4232
+ throw new x();
1630
4233
  return this._deferrer = new Ke(), super.start(this.duration - e), this._publisher.publish("start"), this._deferrer;
1631
4234
  }
4235
+ /**
4236
+ * Stops the execution of the countdown.
4237
+ *
4238
+ * If the countdown hasn't yet started, a {@link RuntimeException} will be thrown.
4239
+ *
4240
+ * ```ts
4241
+ * countdown.onStop(() => { [...] }); // This callback will be executed.
4242
+ * countdown.stop();
4243
+ * ```
4244
+ *
4245
+ * @param reason
4246
+ * The reason why the countdown has stopped.
4247
+ *
4248
+ * - If it's `undefined`, the promise will be resolved.
4249
+ * - If it's a value, the promise will be rejected with that value.
4250
+ */
1632
4251
  stop(e) {
1633
4252
  this._deferrerStop(e), this._publisher.publish("stop", e);
1634
4253
  }
4254
+ /**
4255
+ * Subscribes to the `expire` event of the countdown.
4256
+ *
4257
+ * ```ts
4258
+ * countdown.onExpire(() => { [...] }); // This callback will be executed once the countdown has expired.
4259
+ * countdown.start();
4260
+ * ```
4261
+ *
4262
+ * @param callback The callback that will be executed when the countdown expires.
4263
+ *
4264
+ * @returns A function that can be used to unsubscribe from the event.
4265
+ */
1635
4266
  onExpire(e) {
1636
4267
  return this._publisher.subscribe("expire", e);
1637
4268
  }
1638
- onStart(e) {
1639
- return this._publisher.subscribe("start", e);
1640
- }
1641
- onStop(e) {
1642
- return this._publisher.subscribe("stop", e);
1643
- }
4269
+ /**
4270
+ * Subscribes to the `tick` event of the countdown.
4271
+ *
4272
+ * ```ts
4273
+ * countdown.onTick((remainingTime) => { [...] }); // This callback will be executed.
4274
+ * countdown.start();
4275
+ * ```
4276
+ *
4277
+ * @param callback The callback that will be executed when the countdown ticks.
4278
+ * @param tickStep
4279
+ * The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.
4280
+ *
4281
+ * - If it's a positive number, the callback will be executed only if the
4282
+ * time passed from the previous execution is greater than this number.
4283
+ * - If it's `0`, the callback will be executed every tick without even checking for the time.
4284
+ * - If it's a negative number, a {@link RangeException} will be thrown.
4285
+ *
4286
+ * @returns A function that can be used to unsubscribe from the event.
4287
+ */
1644
4288
  onTick(e, n = 0) {
1645
4289
  if (n < 0)
1646
- throw new $e("The tick step must be a non-negative number.");
4290
+ throw new p("The tick step must be a non-negative number.");
1647
4291
  if (n === 0)
1648
4292
  return this._publisher.subscribe("tick", e);
1649
- let s = 0;
4293
+ let s = this.remainingTime;
1650
4294
  return this._publisher.subscribe("tick", (r) => {
1651
4295
  s - r < n || (e(r), s = r);
1652
4296
  });
1653
4297
  }
1654
4298
  }
1655
- var je;
1656
- je = Symbol.toStringTag;
1657
- const D = class D {
4299
+ var Ae;
4300
+ Ae = Symbol.toStringTag;
4301
+ class ft {
1658
4302
  constructor() {
1659
- a(this, je, "Random");
4303
+ a(this, Ae, "Curve");
1660
4304
  }
4305
+ /**
4306
+ * Generates a given number of values following a linear curve.
4307
+ * The values are equally spaced and normalized between 0 and 1.
4308
+ *
4309
+ * ```ts
4310
+ * for (const value of Curve.Linear(5))
4311
+ * {
4312
+ * console.log(value); // 0, 0.25, 0.5, 0.75, 1
4313
+ * }
4314
+ * ```
4315
+ *
4316
+ * @param values The number of values to generate.
4317
+ *
4318
+ * @returns A {@link SmartIterator} object that generates the values following a linear curve.
4319
+ */
4320
+ static Linear(t) {
4321
+ const e = t - 1;
4322
+ return new u(function* () {
4323
+ for (let n = 0; n < t; n += 1)
4324
+ yield n / e;
4325
+ });
4326
+ }
4327
+ /**
4328
+ * Generates a given number of values following an exponential curve.
4329
+ * The values are equally spaced and normalized between 0 and 1.
4330
+ *
4331
+ * ```ts
4332
+ * for (const value of Curve.Exponential(6))
4333
+ * {
4334
+ * console.log(value); // 0, 0.04, 0.16, 0.36, 0.64, 1
4335
+ * }
4336
+ * ```
4337
+ *
4338
+ * @param values The number of values to generate.
4339
+ * @param base
4340
+ * The base of the exponential curve. Default is `2`.
4341
+ *
4342
+ * Also note that:
4343
+ * - If it's equal to `1`, the curve will be linear.
4344
+ * - If it's included between `0` and `1`, the curve will be logarithmic.
4345
+ *
4346
+ * The base cannot be negative. If so, a {@link ValueException} will be thrown.
4347
+ *
4348
+ * @returns A {@link SmartIterator} object that generates the values following an exponential curve.
4349
+ */
4350
+ static Exponential(t, e = 2) {
4351
+ if (e < 0)
4352
+ throw new d("The base of the exponential curve cannot be negative.");
4353
+ const n = t - 1;
4354
+ return new u(function* () {
4355
+ for (let s = 0; s < t; s += 1)
4356
+ yield Math.pow(s / n, e);
4357
+ });
4358
+ }
4359
+ }
4360
+ var Ne;
4361
+ Ne = Symbol.toStringTag;
4362
+ const F = class F {
4363
+ constructor() {
4364
+ a(this, Ne, "Random");
4365
+ }
4366
+ /**
4367
+ * Generates a random boolean value.
4368
+ *
4369
+ * ```ts
4370
+ * if (Random.Boolean())
4371
+ * {
4372
+ * // Do something...
4373
+ * }
4374
+ * ```
4375
+ *
4376
+ * @param ratio
4377
+ * The probability of generating `true`.
4378
+ *
4379
+ * It must be included between `0` and `1`. Default is `0.5`.
4380
+ *
4381
+ * @returns A random boolean value.
4382
+ */
1661
4383
  static Boolean(t = 0.5) {
1662
4384
  return Math.random() < t;
1663
4385
  }
@@ -1667,47 +4389,86 @@ const D = class D {
1667
4389
  static Decimal(t, e) {
1668
4390
  return t === void 0 ? Math.random() : e === void 0 ? Math.random() * t : Math.random() * (e - t) + t;
1669
4391
  }
4392
+ /**
4393
+ * Picks a random valid index from a given array of elements.
4394
+ *
4395
+ * @template T The type of the elements in the array.
4396
+ *
4397
+ * @param elements
4398
+ * The array of elements to pick from.
4399
+ *
4400
+ * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.
4401
+ *
4402
+ * @returns A valid random index from the given array.
4403
+ */
1670
4404
  static Index(t) {
1671
4405
  if (t.length === 0)
1672
- throw new p("You must provide at least one element.");
4406
+ throw new d("You must provide at least one element.");
1673
4407
  return this.Integer(t.length);
1674
4408
  }
4409
+ /**
4410
+ * Picks a random element from a given array of elements.
4411
+ *
4412
+ * @template T The type of the elements in the array.
4413
+ *
4414
+ * @param elements
4415
+ * The array of elements to pick from.
4416
+ *
4417
+ * It must contain at least one element. Otherwise, a {@link ValueException} will be thrown.
4418
+ *
4419
+ * @returns A random element from the given array.
4420
+ */
1675
4421
  static Choice(t) {
1676
- return t[D.Index(t)];
4422
+ return t[F.Index(t)];
1677
4423
  }
1678
4424
  };
1679
- let j = D;
1680
- function mt(i, t = "text/javascript") {
4425
+ let j = F;
4426
+ function dt(i) {
4427
+ return new Promise((t) => setTimeout(t, i));
4428
+ }
4429
+ function mt() {
4430
+ return new Promise((i) => requestAnimationFrame(() => i()));
4431
+ }
4432
+ function wt() {
4433
+ return new Promise((i) => setTimeout(i));
4434
+ }
4435
+ function yt(i, t = "text/javascript") {
1681
4436
  return new Promise((e, n) => {
1682
4437
  const s = document.createElement("script");
1683
- s.async = !0, s.defer = !0, s.src = i, s.type = t, s.onload = () => e(), s.onerror = () => n(), document.body.appendChild(s);
4438
+ s.async = !0, s.defer = !0, s.src = i, s.type = t, s.onload = (r) => e(), s.onerror = (r) => n(r), document.body.appendChild(s);
1684
4439
  });
1685
4440
  }
1686
4441
  function _t(...i) {
1687
- return new c(function* () {
4442
+ return new u(function* () {
1688
4443
  for (const t of i)
1689
4444
  for (const e of t)
1690
4445
  yield e;
1691
4446
  });
1692
4447
  }
1693
- function wt(i) {
1694
- if (Array.isArray(i))
4448
+ function pt(i) {
4449
+ if (i instanceof Array)
1695
4450
  return i.length;
1696
4451
  let t = 0;
1697
4452
  for (const e of i)
1698
4453
  t += 1;
1699
4454
  return t;
1700
4455
  }
1701
- function pt(i) {
1702
- return new c(function* () {
4456
+ function bt(i) {
4457
+ return new u(function* () {
1703
4458
  let t = 0;
1704
4459
  for (const e of i)
1705
4460
  yield [t, e], t += 1;
1706
4461
  });
1707
4462
  }
1708
- function yt(i, t, e = 1) {
1709
- return new c(function* () {
1710
- t === void 0 && (t = i, i = 0), i > t && (e = e ?? -1);
4463
+ function xt(i, t, e = 1) {
4464
+ if (e <= 0)
4465
+ throw new p(
4466
+ "Step must be always a positive number, even when generating numbers in reverse order."
4467
+ );
4468
+ return t === void 0 && (t = i, i = 0), i > t ? new u(function* () {
4469
+ for (let n = i; n > t; n -= e)
4470
+ yield n;
4471
+ }) : new u(function* () {
1711
4472
  for (let n = i; n < t; n += e)
1712
4473
  yield n;
1713
4474
  });
@@ -1720,16 +4481,16 @@ function gt(i) {
1720
4481
  }
1721
4482
  return t;
1722
4483
  }
1723
- function bt(i) {
1724
- return new c(function* () {
4484
+ function vt(i) {
4485
+ return new u(function* () {
1725
4486
  const t = /* @__PURE__ */ new Set();
1726
4487
  for (const e of i)
1727
4488
  t.has(e) || (t.add(e), yield e);
1728
4489
  });
1729
4490
  }
1730
- function Le(i, t) {
1731
- return new c(function* () {
1732
- const e = i[Symbol.iterator](), n = t[Symbol.iterator]();
4491
+ function Ve(i, t) {
4492
+ const e = i[Symbol.iterator](), n = t[Symbol.iterator]();
4493
+ return new u(function* () {
1733
4494
  for (; ; ) {
1734
4495
  const s = e.next(), r = n.next();
1735
4496
  if (s.done || r.done)
@@ -1738,28 +4499,28 @@ function Le(i, t) {
1738
4499
  }
1739
4500
  });
1740
4501
  }
1741
- function xt(i, t) {
4502
+ function kt(i, t) {
1742
4503
  if (t === void 0) {
1743
4504
  let r = 0, o = 0;
1744
4505
  for (const l of i)
1745
4506
  r += l, o += 1;
1746
4507
  if (o === 0)
1747
- throw new p("You must provide at least one value.");
4508
+ throw new d("You must provide at least one value.");
1748
4509
  return r / o;
1749
4510
  }
1750
4511
  let e = 0, n = 0, s = 0;
1751
- for (const [r, o] of Le(i, t)) {
4512
+ for (const [r, o] of Ve(i, t)) {
1752
4513
  if (o <= 0)
1753
- throw new p(`The weight for the value #${s} must be greater than zero.`);
4514
+ throw new d(`The weight for the value #${s} must be greater than zero.`);
1754
4515
  e += r * o, n += o, s += 1;
1755
4516
  }
1756
4517
  if (s === 0)
1757
- throw new p("You must provide at least one value and weight.");
1758
- if (n > 0)
1759
- throw new p("The sum of weights must be greater than zero.");
4518
+ throw new d("You must provide at least one value and weight.");
4519
+ if (n <= 0)
4520
+ throw new d("The sum of weights must be greater than zero.");
1760
4521
  return e / n;
1761
4522
  }
1762
- function vt(i) {
4523
+ function St(i) {
1763
4524
  let t = 0;
1764
4525
  for (let e = 0; e < i.length; e += 1) {
1765
4526
  const n = i.charCodeAt(e);
@@ -1767,72 +4528,74 @@ function vt(i) {
1767
4528
  }
1768
4529
  return t;
1769
4530
  }
1770
- function kt(i) {
4531
+ function Tt(i) {
1771
4532
  let t = 0;
1772
4533
  for (const e of i)
1773
4534
  t += e;
1774
4535
  return t;
1775
4536
  }
1776
- function St(i) {
4537
+ function Et(i) {
1777
4538
  return `${i.charAt(0).toUpperCase()}${i.slice(1)}`;
1778
4539
  }
1779
- const Tt = "2.0.0-rc.9";
4540
+ const Mt = "2.0.0";
1780
4541
  export {
1781
- E as AggregatedAsyncIterator,
1782
- S as AggregatedIterator,
4542
+ T as AggregatedAsyncIterator,
4543
+ g as AggregatedIterator,
1783
4544
  Ge as CallableObject,
1784
- ft as Clock,
1785
- dt as Countdown,
4545
+ ct as Clock,
4546
+ ht as Countdown,
4547
+ ft as Curve,
1786
4548
  Ke as DeferredPromise,
1787
- f as Exception,
1788
- k as FatalErrorException,
1789
- Ae as FileException,
1790
- Ze as FileExistsException,
1791
- Ue as FileNotFoundException,
4549
+ Je as EnvironmentException,
4550
+ c as Exception,
4551
+ x as FatalErrorException,
4552
+ $e as FileException,
4553
+ Ue as FileExistsException,
4554
+ et as FileNotFoundException,
1792
4555
  qe as GameLoop,
1793
- rt as JSONStorage,
1794
- x as KeyException,
1795
- C as LongRunningTask,
1796
- et as NetworkException,
1797
- ze as NotImplementedException,
1798
- tt as PermissionException,
1799
- M as Publisher,
4556
+ it as JSONStorage,
4557
+ b as KeyException,
4558
+ tt as NetworkException,
4559
+ Be as NotImplementedException,
4560
+ nt as PermissionException,
4561
+ E as Publisher,
1800
4562
  j as Random,
1801
- $e as RangeException,
1802
- d as ReducedIterator,
1803
- Je as ReferenceException,
1804
- m as RuntimeException,
1805
- w as SmartAsyncIterator,
1806
- c as SmartIterator,
1807
- T as SmartPromise,
1808
- st as SwitchableCallback,
1809
- at as Thenable,
1810
- F as TimeUnit,
1811
- lt as TimedPromise,
1812
- We as TimeoutException,
1813
- nt as TypeException,
1814
- Tt as VERSION,
1815
- p as ValueException,
1816
- xt as average,
1817
- St as capitalize,
4563
+ p as RangeException,
4564
+ h as ReducedIterator,
4565
+ C as ReferenceException,
4566
+ y as RuntimeException,
4567
+ f as SmartAsyncIterator,
4568
+ u as SmartIterator,
4569
+ k as SmartPromise,
4570
+ rt as SwitchableCallback,
4571
+ M as TimeUnit,
4572
+ ot as TimedPromise,
4573
+ Ye as TimeoutException,
4574
+ st as TypeException,
4575
+ Mt as VERSION,
4576
+ d as ValueException,
4577
+ He as WeekDay,
4578
+ kt as average,
4579
+ Et as capitalize,
1818
4580
  _t as chain,
1819
- wt as count,
1820
- ut as dateDifference,
1821
- ct as dateRange,
1822
- ht as dateRound,
1823
- it as delay,
1824
- pt as enumerate,
1825
- vt as hash,
4581
+ pt as count,
4582
+ at as dateDifference,
4583
+ lt as dateRange,
4584
+ Qe as dateRound,
4585
+ dt as delay,
4586
+ bt as enumerate,
4587
+ ut as getWeek,
4588
+ St as hash,
1826
4589
  Oe as isBrowser,
1827
- Qe as isNode,
1828
- Xe as isWebWorker,
1829
- mt as loadScript,
1830
- ot as nextAnimationFrame,
1831
- yt as range,
4590
+ Ze as isNode,
4591
+ We as isWorker,
4592
+ yt as loadScript,
4593
+ mt as nextAnimationFrame,
4594
+ xt as range,
1832
4595
  gt as shuffle,
1833
- kt as sum,
1834
- bt as unique,
1835
- v as yieldToEventLoop,
1836
- Le as zip
4596
+ Tt as sum,
4597
+ vt as unique,
4598
+ wt as yieldToEventLoop,
4599
+ Ve as zip
1837
4600
  };
1838
4601
  //# sourceMappingURL=core.js.map