iterflow 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,4030 @@
1
+ 'use strict';
2
+
3
+ // src/errors.ts
4
+ var iterflowError = class extends Error {
5
+ operation;
6
+ context;
7
+ constructor(message, operation, context) {
8
+ super(message);
9
+ this.name = "iterflowError";
10
+ this.operation = operation;
11
+ this.context = context;
12
+ if (Error.captureStackTrace) {
13
+ Error.captureStackTrace(this, this.constructor);
14
+ }
15
+ }
16
+ /**
17
+ * Returns a detailed error message with context
18
+ */
19
+ toDetailedString() {
20
+ let msg = `${this.name}: ${this.message}`;
21
+ if (this.operation) {
22
+ msg += `
23
+ Operation: ${this.operation}`;
24
+ }
25
+ if (this.context && Object.keys(this.context).length > 0) {
26
+ msg += "\n Context:";
27
+ for (const [key, value] of Object.entries(this.context)) {
28
+ msg += `
29
+ ${key}: ${JSON.stringify(value)}`;
30
+ }
31
+ }
32
+ if (this.stack) {
33
+ msg += `
34
+ Stack: ${this.stack.split("\n").slice(1).join("\n")}`;
35
+ }
36
+ return msg;
37
+ }
38
+ };
39
+ var ValidationError = class extends iterflowError {
40
+ constructor(message, operation, context) {
41
+ super(message, operation, context);
42
+ this.name = "ValidationError";
43
+ }
44
+ };
45
+ var OperationError = class extends iterflowError {
46
+ cause;
47
+ constructor(message, operation, cause, context) {
48
+ super(message, operation, context);
49
+ this.name = "OperationError";
50
+ this.cause = cause;
51
+ }
52
+ toDetailedString() {
53
+ let msg = super.toDetailedString();
54
+ if (this.cause) {
55
+ msg += `
56
+ Caused by: ${this.cause.message}`;
57
+ if (this.cause.stack) {
58
+ msg += `
59
+ ${this.cause.stack}`;
60
+ }
61
+ }
62
+ return msg;
63
+ }
64
+ };
65
+ var EmptySequenceError = class extends iterflowError {
66
+ constructor(operation, message) {
67
+ super(
68
+ message || `Operation '${operation}' requires a non-empty sequence`,
69
+ operation
70
+ );
71
+ this.name = "EmptySequenceError";
72
+ }
73
+ };
74
+ var IndexOutOfBoundsError = class extends iterflowError {
75
+ index;
76
+ size;
77
+ constructor(index, size, operation) {
78
+ const sizeInfo = size !== void 0 ? ` (size: ${size})` : "";
79
+ super(`Index ${index} is out of bounds${sizeInfo}`, operation, {
80
+ index,
81
+ size
82
+ });
83
+ this.name = "IndexOutOfBoundsError";
84
+ this.index = index;
85
+ this.size = size;
86
+ }
87
+ };
88
+ var TypeConversionError = class extends iterflowError {
89
+ value;
90
+ expectedType;
91
+ constructor(value, expectedType, operation) {
92
+ super(
93
+ `Cannot convert value ${JSON.stringify(value)} to type ${expectedType}`,
94
+ operation,
95
+ { value, expectedType }
96
+ );
97
+ this.name = "TypeConversionError";
98
+ this.value = value;
99
+ this.expectedType = expectedType;
100
+ }
101
+ };
102
+
103
+ // src/validation.ts
104
+ function validatePositiveInteger(value, paramName, operation) {
105
+ if (!Number.isInteger(value)) {
106
+ throw new ValidationError(
107
+ `${paramName} must be an integer, got ${value}`,
108
+ operation,
109
+ { paramName, value }
110
+ );
111
+ }
112
+ if (value < 1) {
113
+ throw new ValidationError(
114
+ `${paramName} must be at least 1, got ${value}`,
115
+ operation,
116
+ { paramName, value }
117
+ );
118
+ }
119
+ }
120
+ function validateNonNegativeInteger(value, paramName, operation) {
121
+ if (!Number.isInteger(value)) {
122
+ throw new ValidationError(
123
+ `${paramName} must be an integer, got ${value}`,
124
+ operation,
125
+ { paramName, value }
126
+ );
127
+ }
128
+ if (value < 0) {
129
+ throw new ValidationError(
130
+ `${paramName} must be non-negative, got ${value}`,
131
+ operation,
132
+ { paramName, value }
133
+ );
134
+ }
135
+ }
136
+ function validateRange(value, min, max, paramName, operation) {
137
+ if (value < min || value > max) {
138
+ throw new ValidationError(
139
+ `${paramName} must be between ${min} and ${max}, got ${value}`,
140
+ operation,
141
+ { paramName, value, min, max }
142
+ );
143
+ }
144
+ }
145
+ function validateFiniteNumber(value, paramName, operation) {
146
+ if (!Number.isFinite(value)) {
147
+ throw new ValidationError(
148
+ `${paramName} must be a finite number, got ${value}`,
149
+ operation,
150
+ { paramName, value }
151
+ );
152
+ }
153
+ }
154
+ function validateNonZero(value, paramName, operation) {
155
+ if (value === 0) {
156
+ throw new ValidationError(`${paramName} cannot be zero`, operation, {
157
+ paramName,
158
+ value
159
+ });
160
+ }
161
+ }
162
+ function validateFunction(value, paramName, operation) {
163
+ if (typeof value !== "function") {
164
+ throw new ValidationError(
165
+ `${paramName} must be a function, got ${typeof value}`,
166
+ operation,
167
+ { paramName, type: typeof value }
168
+ );
169
+ }
170
+ }
171
+ function validateIterable(value, paramName, operation) {
172
+ if (value == null || typeof value[Symbol.iterator] !== "function") {
173
+ throw new ValidationError(`${paramName} must be iterable`, operation, {
174
+ paramName,
175
+ type: typeof value
176
+ });
177
+ }
178
+ }
179
+ function validateComparator(fn, operation) {
180
+ validateFunction(fn, "comparator", operation);
181
+ }
182
+ function validateNonEmpty(arr, operation) {
183
+ if (arr.length === 0) {
184
+ throw new ValidationError("Sequence cannot be empty", operation);
185
+ }
186
+ }
187
+ function toNumber(value, operation) {
188
+ const num = Number(value);
189
+ if (Number.isNaN(num)) {
190
+ throw new TypeConversionError(value, "number", operation);
191
+ }
192
+ return num;
193
+ }
194
+ function toInteger(value, operation) {
195
+ const num = toNumber(value, operation);
196
+ const int = Math.trunc(num);
197
+ if (num !== int) {
198
+ throw new TypeConversionError(value, "integer", operation);
199
+ }
200
+ return int;
201
+ }
202
+ function validateIndex(index, size, operation) {
203
+ validateNonNegativeInteger(index, "index", operation);
204
+ if (index >= size) {
205
+ throw new ValidationError(
206
+ `Index ${index} is out of bounds for size ${size}`,
207
+ operation,
208
+ { index, size }
209
+ );
210
+ }
211
+ }
212
+
213
+ // src/iter-flow.ts
214
+ var iterflow = class _iterflow {
215
+ source;
216
+ /**
217
+ * Creates a new iterflow instance from an iterable or iterator.
218
+ *
219
+ * @param source - The source iterable or iterator to wrap
220
+ * @example
221
+ * ```typescript
222
+ * const flow1 = new iterflow([1, 2, 3]);
223
+ * const flow2 = new iterflow(someIterator);
224
+ * ```
225
+ */
226
+ constructor(source) {
227
+ this.source = Symbol.iterator in source ? source[Symbol.iterator]() : source;
228
+ }
229
+ // Iterator protocol
230
+ /**
231
+ * Returns the iterator for this iterflow instance.
232
+ * This allows iterflow to be used in for...of loops.
233
+ *
234
+ * @returns The underlying iterator
235
+ */
236
+ [Symbol.iterator]() {
237
+ return this.source;
238
+ }
239
+ /**
240
+ * Retrieves the next value from the iterator.
241
+ *
242
+ * @returns An IteratorResult containing the next value or indicating completion
243
+ */
244
+ next() {
245
+ return this.source.next();
246
+ }
247
+ // ES2025 native passthrough methods (would normally delegate to native implementations)
248
+ /**
249
+ * Transforms each element using the provided function.
250
+ *
251
+ * @template U The type of the transformed elements
252
+ * @param fn - Function to transform each element
253
+ * @returns A new iterflow with transformed elements
254
+ * @example
255
+ * ```typescript
256
+ * iter([1, 2, 3]).map(x => x * 2).toArray(); // [2, 4, 6]
257
+ * ```
258
+ */
259
+ map(fn) {
260
+ const self = this;
261
+ return new _iterflow({
262
+ *[Symbol.iterator]() {
263
+ for (const value of self) {
264
+ yield fn(value);
265
+ }
266
+ }
267
+ });
268
+ }
269
+ /**
270
+ * Filters elements based on a predicate function.
271
+ * Only elements for which the predicate returns true are included.
272
+ *
273
+ * @param predicate - Function to test each element
274
+ * @returns A new iterflow with only elements that pass the predicate
275
+ * @example
276
+ * ```typescript
277
+ * iter([1, 2, 3, 4]).filter(x => x % 2 === 0).toArray(); // [2, 4]
278
+ * ```
279
+ */
280
+ filter(predicate) {
281
+ const self = this;
282
+ return new _iterflow({
283
+ *[Symbol.iterator]() {
284
+ for (const value of self) {
285
+ if (predicate(value)) {
286
+ yield value;
287
+ }
288
+ }
289
+ }
290
+ });
291
+ }
292
+ /**
293
+ * Takes only the first `limit` elements from the iterator.
294
+ *
295
+ * @param limit - Maximum number of elements to take
296
+ * @returns A new iterflow with at most `limit` elements
297
+ * @example
298
+ * ```typescript
299
+ * iter([1, 2, 3, 4, 5]).take(3).toArray(); // [1, 2, 3]
300
+ * ```
301
+ */
302
+ take(limit) {
303
+ const self = this;
304
+ return new _iterflow({
305
+ *[Symbol.iterator]() {
306
+ let count = 0;
307
+ for (const value of self) {
308
+ if (count >= limit) break;
309
+ yield value;
310
+ count++;
311
+ }
312
+ }
313
+ });
314
+ }
315
+ /**
316
+ * Skips the first `count` elements from the iterator.
317
+ *
318
+ * @param count - Number of elements to skip
319
+ * @returns A new iterflow without the first `count` elements
320
+ * @example
321
+ * ```typescript
322
+ * iter([1, 2, 3, 4, 5]).drop(2).toArray(); // [3, 4, 5]
323
+ * ```
324
+ */
325
+ drop(count) {
326
+ const self = this;
327
+ return new _iterflow({
328
+ *[Symbol.iterator]() {
329
+ let dropped = 0;
330
+ for (const value of self) {
331
+ if (dropped < count) {
332
+ dropped++;
333
+ continue;
334
+ }
335
+ yield value;
336
+ }
337
+ }
338
+ });
339
+ }
340
+ /**
341
+ * Maps each element to an iterable and flattens the results into a single iterator.
342
+ *
343
+ * @template U The type of elements in the resulting iterator
344
+ * @param fn - Function that maps each element to an iterable
345
+ * @returns A new iterflow with all mapped iterables flattened
346
+ * @example
347
+ * ```typescript
348
+ * iter([1, 2, 3]).flatMap(x => [x, x * 2]).toArray(); // [1, 2, 2, 4, 3, 6]
349
+ * ```
350
+ */
351
+ flatMap(fn) {
352
+ const self = this;
353
+ return new _iterflow({
354
+ *[Symbol.iterator]() {
355
+ for (const value of self) {
356
+ yield* fn(value);
357
+ }
358
+ }
359
+ });
360
+ }
361
+ /**
362
+ * Concatenates multiple iterators sequentially.
363
+ * Yields all elements from this iterator, then from each provided iterator.
364
+ *
365
+ * @param iterables - Additional iterables to concatenate
366
+ * @returns A new iterflow with all elements from all iterables
367
+ * @example
368
+ * ```typescript
369
+ * iter([1, 2]).concat([3, 4], [5, 6]).toArray();
370
+ * // [1, 2, 3, 4, 5, 6]
371
+ * ```
372
+ */
373
+ concat(...iterables) {
374
+ const self = this;
375
+ return new _iterflow({
376
+ *[Symbol.iterator]() {
377
+ yield* self;
378
+ for (const iterable of iterables) {
379
+ yield* iterable;
380
+ }
381
+ }
382
+ });
383
+ }
384
+ /**
385
+ * Inserts a separator element between each item.
386
+ * The separator is not added before the first element or after the last.
387
+ *
388
+ * @param separator - The element to insert between items
389
+ * @returns A new iterflow with separators interspersed
390
+ * @example
391
+ * ```typescript
392
+ * iter([1, 2, 3]).intersperse(0).toArray();
393
+ * // [1, 0, 2, 0, 3]
394
+ * iter(['a', 'b', 'c']).intersperse('-').toArray();
395
+ * // ['a', '-', 'b', '-', 'c']
396
+ * ```
397
+ */
398
+ intersperse(separator) {
399
+ const self = this;
400
+ return new _iterflow({
401
+ *[Symbol.iterator]() {
402
+ let isFirst = true;
403
+ for (const value of self) {
404
+ if (!isFirst) {
405
+ yield separator;
406
+ }
407
+ yield value;
408
+ isFirst = false;
409
+ }
410
+ }
411
+ });
412
+ }
413
+ /**
414
+ * Like reduce, but emits all intermediate accumulator values.
415
+ * Similar to reduce but returns an iterator of partial results.
416
+ *
417
+ * @template U The type of the accumulated value
418
+ * @param fn - Function to combine the accumulator with each element
419
+ * @param initial - The initial value for the accumulator
420
+ * @returns A new iterflow of intermediate accumulator values
421
+ * @example
422
+ * ```typescript
423
+ * iter([1, 2, 3, 4]).scan((acc, x) => acc + x, 0).toArray();
424
+ * // [0, 1, 3, 6, 10]
425
+ * iter([1, 2, 3]).scan((acc, x) => acc * x, 1).toArray();
426
+ * // [1, 1, 2, 6]
427
+ * ```
428
+ */
429
+ scan(fn, initial) {
430
+ const self = this;
431
+ return new _iterflow({
432
+ *[Symbol.iterator]() {
433
+ let accumulator = initial;
434
+ yield accumulator;
435
+ for (const value of self) {
436
+ accumulator = fn(accumulator, value);
437
+ yield accumulator;
438
+ }
439
+ }
440
+ });
441
+ }
442
+ /**
443
+ * Adds index as tuple with each element [index, value].
444
+ * Creates tuples pairing each element with its zero-based index.
445
+ *
446
+ * @returns A new iterflow of tuples containing [index, value]
447
+ * @example
448
+ * ```typescript
449
+ * iter(['a', 'b', 'c']).enumerate().toArray();
450
+ * // [[0, 'a'], [1, 'b'], [2, 'c']]
451
+ * ```
452
+ */
453
+ enumerate() {
454
+ const self = this;
455
+ return new _iterflow({
456
+ *[Symbol.iterator]() {
457
+ let index = 0;
458
+ for (const value of self) {
459
+ yield [index, value];
460
+ index++;
461
+ }
462
+ }
463
+ });
464
+ }
465
+ /**
466
+ * Reverses the iterator order.
467
+ * Warning: This operation buffers all elements in memory and may cause
468
+ * performance issues with large iterables. Consider using only when necessary.
469
+ *
470
+ * @returns A new iterflow with elements in reverse order
471
+ * @example
472
+ * ```typescript
473
+ * iter([1, 2, 3, 4, 5]).reverse().toArray();
474
+ * // [5, 4, 3, 2, 1]
475
+ * ```
476
+ */
477
+ reverse() {
478
+ const self = this;
479
+ return new _iterflow({
480
+ *[Symbol.iterator]() {
481
+ const buffer = Array.from(self);
482
+ for (let i = buffer.length - 1; i >= 0; i--) {
483
+ yield buffer[i];
484
+ }
485
+ }
486
+ });
487
+ }
488
+ /**
489
+ * Sorts elements using default comparison.
490
+ * Numbers are sorted numerically, strings lexicographically.
491
+ * Warning: This operation buffers all elements in memory. Avoid chaining
492
+ * with other buffering operations (reverse, sort, sortBy) for better performance.
493
+ *
494
+ * @param this - iterflow instance constrained to numbers or strings
495
+ * @returns A new iterflow with elements sorted
496
+ * @example
497
+ * ```typescript
498
+ * iter([3, 1, 4, 1, 5]).sort().toArray();
499
+ * // [1, 1, 3, 4, 5]
500
+ * iter(['c', 'a', 'b']).sort().toArray();
501
+ * // ['a', 'b', 'c']
502
+ * ```
503
+ */
504
+ sort() {
505
+ const self = this;
506
+ return new _iterflow({
507
+ *[Symbol.iterator]() {
508
+ const buffer = Array.from(self);
509
+ buffer.sort((a, b) => {
510
+ if (typeof a === "number" && typeof b === "number") {
511
+ return a - b;
512
+ }
513
+ return String(a).localeCompare(String(b));
514
+ });
515
+ yield* buffer;
516
+ }
517
+ });
518
+ }
519
+ /**
520
+ * Sorts elements using a custom comparison function.
521
+ * Warning: This operation buffers all elements in memory. Avoid chaining
522
+ * with other buffering operations (reverse, sort, sortBy) for better performance.
523
+ *
524
+ * @param compareFn - Function that compares two elements (returns negative if a < b, 0 if equal, positive if a > b)
525
+ * @returns A new iterflow with elements sorted
526
+ * @example
527
+ * ```typescript
528
+ * iter([3, 1, 4, 1, 5]).sortBy((a, b) => a - b).toArray();
529
+ * // [1, 1, 3, 4, 5]
530
+ * iter([3, 1, 4, 1, 5]).sortBy((a, b) => b - a).toArray();
531
+ * // [5, 4, 3, 1, 1]
532
+ * iter(['alice', 'bob', 'charlie']).sortBy((a, b) => a.length - b.length).toArray();
533
+ * // ['bob', 'alice', 'charlie']
534
+ * ```
535
+ */
536
+ sortBy(compareFn) {
537
+ const self = this;
538
+ return new _iterflow({
539
+ *[Symbol.iterator]() {
540
+ const buffer = Array.from(self);
541
+ buffer.sort(compareFn);
542
+ yield* buffer;
543
+ }
544
+ });
545
+ }
546
+ // Terminal operations (consume the iterator)
547
+ /**
548
+ * Collects all elements into an array.
549
+ * This is a terminal operation that consumes the iterator.
550
+ *
551
+ * @returns An array containing all elements
552
+ * @example
553
+ * ```typescript
554
+ * iter([1, 2, 3]).map(x => x * 2).toArray(); // [2, 4, 6]
555
+ * ```
556
+ */
557
+ toArray() {
558
+ return Array.from(this);
559
+ }
560
+ /**
561
+ * Counts the total number of elements in the iterator.
562
+ * This is a terminal operation that consumes the iterator.
563
+ *
564
+ * @returns The total count of elements
565
+ * @example
566
+ * ```typescript
567
+ * iter([1, 2, 3, 4, 5]).count(); // 5
568
+ * ```
569
+ */
570
+ count() {
571
+ let count = 0;
572
+ for (const _ of this) {
573
+ count++;
574
+ }
575
+ return count;
576
+ }
577
+ // Statistical operations - type-constrained to numbers
578
+ /**
579
+ * Calculates the sum of all numeric elements.
580
+ * This method is only available when T is number.
581
+ * This is a terminal operation that consumes the iterator.
582
+ *
583
+ * @param this - iterflow instance constrained to numbers
584
+ * @returns The sum of all elements
585
+ * @example
586
+ * ```typescript
587
+ * iter([1, 2, 3, 4, 5]).sum(); // 15
588
+ * ```
589
+ */
590
+ sum() {
591
+ let total = 0;
592
+ for (const value of this) {
593
+ total += value;
594
+ }
595
+ return total;
596
+ }
597
+ /**
598
+ * Calculates the arithmetic mean (average) of all numeric elements.
599
+ * This method is only available when T is number.
600
+ * This is a terminal operation that consumes the iterator.
601
+ *
602
+ * @param this - iterflow instance constrained to numbers
603
+ * @returns The mean value, or undefined if the iterator is empty
604
+ * @example
605
+ * ```typescript
606
+ * iter([1, 2, 3, 4, 5]).mean(); // 3
607
+ * iter([]).mean(); // undefined
608
+ * ```
609
+ */
610
+ mean() {
611
+ let total = 0;
612
+ let count = 0;
613
+ for (const value of this) {
614
+ total += value;
615
+ count++;
616
+ }
617
+ return count === 0 ? void 0 : total / count;
618
+ }
619
+ /**
620
+ * Finds the minimum value among all numeric elements.
621
+ * This method is only available when T is number.
622
+ * This is a terminal operation that consumes the iterator.
623
+ *
624
+ * @param this - iterflow instance constrained to numbers
625
+ * @returns The minimum value, or undefined if the iterator is empty
626
+ * @example
627
+ * ```typescript
628
+ * iter([3, 1, 4, 1, 5]).min(); // 1
629
+ * iter([]).min(); // undefined
630
+ * ```
631
+ */
632
+ min() {
633
+ let minimum = void 0;
634
+ for (const value of this) {
635
+ if (minimum === void 0 || value < minimum) {
636
+ minimum = value;
637
+ }
638
+ }
639
+ return minimum;
640
+ }
641
+ /**
642
+ * Finds the maximum value among all numeric elements.
643
+ * This method is only available when T is number.
644
+ * This is a terminal operation that consumes the iterator.
645
+ *
646
+ * @param this - iterflow instance constrained to numbers
647
+ * @returns The maximum value, or undefined if the iterator is empty
648
+ * @example
649
+ * ```typescript
650
+ * iter([3, 1, 4, 1, 5]).max(); // 5
651
+ * iter([]).max(); // undefined
652
+ * ```
653
+ */
654
+ max() {
655
+ let maximum = void 0;
656
+ for (const value of this) {
657
+ if (maximum === void 0 || value > maximum) {
658
+ maximum = value;
659
+ }
660
+ }
661
+ return maximum;
662
+ }
663
+ /**
664
+ * Calculates the median value of all numeric elements.
665
+ * The median is the middle value when elements are sorted.
666
+ * This method is only available when T is number.
667
+ * This is a terminal operation that consumes the iterator.
668
+ *
669
+ * @param this - iterflow instance constrained to numbers
670
+ * @returns The median value, or undefined if the iterator is empty
671
+ * @example
672
+ * ```typescript
673
+ * iter([1, 2, 3, 4, 5]).median(); // 3
674
+ * iter([1, 2, 3, 4]).median(); // 2.5
675
+ * iter([]).median(); // undefined
676
+ * ```
677
+ */
678
+ median() {
679
+ const values = this.toArray();
680
+ if (values.length === 0) return void 0;
681
+ values.sort((a, b) => a - b);
682
+ const mid = Math.floor(values.length / 2);
683
+ if (values.length % 2 === 0) {
684
+ return (values[mid - 1] + values[mid]) / 2;
685
+ } else {
686
+ return values[mid];
687
+ }
688
+ }
689
+ /**
690
+ * Calculates the variance of all numeric elements.
691
+ * Variance measures how far each number in the set is from the mean.
692
+ * This method is only available when T is number.
693
+ * This is a terminal operation that consumes the iterator.
694
+ *
695
+ * @param this - iterflow instance constrained to numbers
696
+ * @returns The variance, or undefined if the iterator is empty
697
+ * @example
698
+ * ```typescript
699
+ * iter([1, 2, 3, 4, 5]).variance(); // 2
700
+ * iter([]).variance(); // undefined
701
+ * ```
702
+ */
703
+ variance() {
704
+ const values = this.toArray();
705
+ if (values.length === 0) return void 0;
706
+ const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
707
+ let sumSquaredDiffs = 0;
708
+ for (let i = 0; i < values.length; i++) {
709
+ const value = values[i];
710
+ const diff = value - mean;
711
+ sumSquaredDiffs += diff * diff;
712
+ }
713
+ return sumSquaredDiffs / values.length;
714
+ }
715
+ /**
716
+ * Calculates the standard deviation of all numeric elements.
717
+ * Standard deviation is the square root of variance and measures dispersion.
718
+ * This method is only available when T is number.
719
+ * This is a terminal operation that consumes the iterator.
720
+ *
721
+ * @param this - iterflow instance constrained to numbers
722
+ * @returns The standard deviation, or undefined if the iterator is empty
723
+ * @example
724
+ * ```typescript
725
+ * iter([2, 4, 4, 4, 5, 5, 7, 9]).stdDev(); // ~2
726
+ * iter([]).stdDev(); // undefined
727
+ * ```
728
+ */
729
+ stdDev() {
730
+ const variance = this.variance();
731
+ return variance === void 0 ? void 0 : Math.sqrt(variance);
732
+ }
733
+ /**
734
+ * Calculates the specified percentile of all numeric elements.
735
+ * Uses linear interpolation between closest ranks.
736
+ * This method is only available when T is number.
737
+ * This is a terminal operation that consumes the iterator.
738
+ *
739
+ * @param this - iterflow instance constrained to numbers
740
+ * @param p - The percentile to calculate (0-100)
741
+ * @returns The percentile value, or undefined if the iterator is empty
742
+ * @throws {Error} If p is not between 0 and 100
743
+ * @example
744
+ * ```typescript
745
+ * iter([1, 2, 3, 4, 5]).percentile(50); // 3 (median)
746
+ * iter([1, 2, 3, 4, 5]).percentile(75); // 4
747
+ * iter([]).percentile(50); // undefined
748
+ * ```
749
+ */
750
+ percentile(p) {
751
+ validateRange(p, 0, 100, "percentile", "percentile");
752
+ const values = this.toArray();
753
+ if (values.length === 0) return void 0;
754
+ values.sort((a, b) => a - b);
755
+ if (p === 0) return values[0];
756
+ if (p === 100) return values[values.length - 1];
757
+ const index = p / 100 * (values.length - 1);
758
+ const lower = Math.floor(index);
759
+ const upper = Math.ceil(index);
760
+ if (lower === upper) {
761
+ return values[lower];
762
+ }
763
+ const weight = index - lower;
764
+ return values[lower] * (1 - weight) + values[upper] * weight;
765
+ }
766
+ /**
767
+ * Finds the most frequent value(s) in the dataset.
768
+ * Returns an array of all values that appear most frequently.
769
+ * This method is only available when T is number.
770
+ * This is a terminal operation that consumes the iterator.
771
+ *
772
+ * @param this - iterflow instance constrained to numbers
773
+ * @returns An array of the most frequent value(s), or undefined if the iterator is empty
774
+ * @example
775
+ * ```typescript
776
+ * iter([1, 2, 2, 3, 3, 3]).mode(); // [3]
777
+ * iter([1, 1, 2, 2, 3]).mode(); // [1, 2] (bimodal)
778
+ * iter([]).mode(); // undefined
779
+ * ```
780
+ */
781
+ mode() {
782
+ const values = this.toArray();
783
+ if (values.length === 0) return void 0;
784
+ const frequency = /* @__PURE__ */ new Map();
785
+ let maxFreq = 0;
786
+ for (const value of values) {
787
+ const count = (frequency.get(value) || 0) + 1;
788
+ frequency.set(value, count);
789
+ maxFreq = Math.max(maxFreq, count);
790
+ }
791
+ const modes = [];
792
+ for (const [value, freq] of frequency) {
793
+ if (freq === maxFreq) {
794
+ modes.push(value);
795
+ }
796
+ }
797
+ return modes.sort((a, b) => a - b);
798
+ }
799
+ /**
800
+ * Calculates the quartiles (Q1, Q2, Q3) of all numeric elements.
801
+ * Q1 is the 25th percentile, Q2 is the median (50th percentile), Q3 is the 75th percentile.
802
+ * This method is only available when T is number.
803
+ * This is a terminal operation that consumes the iterator.
804
+ *
805
+ * @param this - iterflow instance constrained to numbers
806
+ * @returns An object with Q1, Q2, and Q3 values, or undefined if the iterator is empty
807
+ * @example
808
+ * ```typescript
809
+ * iter([1, 2, 3, 4, 5, 6, 7, 8, 9]).quartiles();
810
+ * // { Q1: 3, Q2: 5, Q3: 7 }
811
+ * iter([]).quartiles(); // undefined
812
+ * ```
813
+ */
814
+ quartiles() {
815
+ const values = this.toArray();
816
+ if (values.length === 0) return void 0;
817
+ values.sort((a, b) => a - b);
818
+ const calculatePercentile = (p) => {
819
+ if (p === 0) return values[0];
820
+ if (p === 100) return values[values.length - 1];
821
+ const index = p / 100 * (values.length - 1);
822
+ const lower = Math.floor(index);
823
+ const upper = Math.ceil(index);
824
+ if (lower === upper) {
825
+ return values[lower];
826
+ }
827
+ const weight = index - lower;
828
+ return values[lower] * (1 - weight) + values[upper] * weight;
829
+ };
830
+ return {
831
+ Q1: calculatePercentile(25),
832
+ Q2: calculatePercentile(50),
833
+ Q3: calculatePercentile(75)
834
+ };
835
+ }
836
+ /**
837
+ * Calculates the span (range from minimum to maximum value) of all numeric elements.
838
+ * This method is only available when T is number.
839
+ * This is a terminal operation that consumes the iterator.
840
+ *
841
+ * @param this - iterflow instance constrained to numbers
842
+ * @returns The span (max - min), or undefined if the iterator is empty
843
+ * @example
844
+ * ```typescript
845
+ * iter([1, 2, 3, 4, 5]).span(); // 4
846
+ * iter([10]).span(); // 0
847
+ * iter([]).span(); // undefined
848
+ * ```
849
+ */
850
+ span() {
851
+ let minimum = void 0;
852
+ let maximum = void 0;
853
+ for (const value of this) {
854
+ if (minimum === void 0 || value < minimum) {
855
+ minimum = value;
856
+ }
857
+ if (maximum === void 0 || value > maximum) {
858
+ maximum = value;
859
+ }
860
+ }
861
+ return minimum === void 0 || maximum === void 0 ? void 0 : maximum - minimum;
862
+ }
863
+ /**
864
+ * Calculates the product of all numeric elements.
865
+ * This method is only available when T is number.
866
+ * This is a terminal operation that consumes the iterator.
867
+ *
868
+ * @param this - iterflow instance constrained to numbers
869
+ * @returns The product of all elements, or 1 if the iterator is empty
870
+ * @example
871
+ * ```typescript
872
+ * iter([1, 2, 3, 4, 5]).product(); // 120
873
+ * iter([2, 3, 4]).product(); // 24
874
+ * iter([]).product(); // 1
875
+ * ```
876
+ */
877
+ product() {
878
+ let result = 1;
879
+ for (const value of this) {
880
+ result *= value;
881
+ }
882
+ return result;
883
+ }
884
+ /**
885
+ * Calculates the covariance between two numeric sequences.
886
+ * Covariance measures the joint variability of two random variables.
887
+ * This method is only available when T is number.
888
+ * This is a terminal operation that consumes the iterator.
889
+ *
890
+ * @param this - iterflow instance constrained to numbers
891
+ * @param other - An iterable of numbers to compare with
892
+ * @returns The covariance, or undefined if either sequence is empty or sequences have different lengths
893
+ * @example
894
+ * ```typescript
895
+ * iter([1, 2, 3, 4, 5]).covariance([2, 4, 6, 8, 10]); // 4
896
+ * iter([]).covariance([1, 2, 3]); // undefined
897
+ * ```
898
+ */
899
+ covariance(other) {
900
+ const values1 = this.toArray();
901
+ const values2 = Array.from(other);
902
+ if (values1.length === 0 || values2.length === 0 || values1.length !== values2.length) {
903
+ return void 0;
904
+ }
905
+ const mean1 = values1.reduce((sum, val) => sum + val, 0) / values1.length;
906
+ const mean2 = values2.reduce((sum, val) => sum + val, 0) / values2.length;
907
+ let covariance = 0;
908
+ for (let i = 0; i < values1.length; i++) {
909
+ covariance += (values1[i] - mean1) * (values2[i] - mean2);
910
+ }
911
+ return covariance / values1.length;
912
+ }
913
+ /**
914
+ * Calculates the Pearson correlation coefficient between two numeric sequences.
915
+ * Correlation measures the strength and direction of the linear relationship between two variables.
916
+ * Values range from -1 (perfect negative correlation) to 1 (perfect positive correlation).
917
+ * This method is only available when T is number.
918
+ * This is a terminal operation that consumes the iterator.
919
+ *
920
+ * @param this - iterflow instance constrained to numbers
921
+ * @param other - An iterable of numbers to compare with
922
+ * @returns The correlation coefficient, or undefined if either sequence is empty or sequences have different lengths
923
+ * @example
924
+ * ```typescript
925
+ * iter([1, 2, 3, 4, 5]).correlation([2, 4, 6, 8, 10]); // 1 (perfect positive correlation)
926
+ * iter([1, 2, 3]).correlation([3, 2, 1]); // -1 (perfect negative correlation)
927
+ * iter([]).correlation([1, 2, 3]); // undefined
928
+ * ```
929
+ */
930
+ correlation(other) {
931
+ const values1 = this.toArray();
932
+ const values2 = Array.from(other);
933
+ if (values1.length === 0 || values2.length === 0 || values1.length !== values2.length) {
934
+ return void 0;
935
+ }
936
+ const mean1 = values1.reduce((sum, val) => sum + val, 0) / values1.length;
937
+ const mean2 = values2.reduce((sum, val) => sum + val, 0) / values2.length;
938
+ let covariance = 0;
939
+ let variance1 = 0;
940
+ let variance2 = 0;
941
+ for (let i = 0; i < values1.length; i++) {
942
+ const diff1 = values1[i] - mean1;
943
+ const diff2 = values2[i] - mean2;
944
+ covariance += diff1 * diff2;
945
+ variance1 += diff1 * diff1;
946
+ variance2 += diff2 * diff2;
947
+ }
948
+ const stdDev1 = Math.sqrt(variance1 / values1.length);
949
+ const stdDev2 = Math.sqrt(variance2 / values2.length);
950
+ if (stdDev1 === 0 || stdDev2 === 0) {
951
+ return void 0;
952
+ }
953
+ return covariance / (values1.length * stdDev1 * stdDev2);
954
+ }
955
+ // Windowing operations
956
+ /**
957
+ * Creates a sliding window of the specified size over the elements.
958
+ * Each window contains `size` consecutive elements.
959
+ *
960
+ * @param size - The size of each window (must be at least 1)
961
+ * @returns A new iterflow of arrays, each containing `size` consecutive elements
962
+ * @throws {Error} If size is less than 1
963
+ * @example
964
+ * ```typescript
965
+ * iter([1, 2, 3, 4, 5]).window(3).toArray();
966
+ * // [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
967
+ * ```
968
+ */
969
+ window(size) {
970
+ validatePositiveInteger(size, "size", "window");
971
+ const self = this;
972
+ return new _iterflow({
973
+ *[Symbol.iterator]() {
974
+ const buffer = new Array(size);
975
+ let count = 0;
976
+ let index = 0;
977
+ for (const value of self) {
978
+ buffer[index] = value;
979
+ count++;
980
+ index = (index + 1) % size;
981
+ if (count >= size) {
982
+ const window = new Array(size);
983
+ for (let i = 0; i < size; i++) {
984
+ window[i] = buffer[(index + i) % size];
985
+ }
986
+ yield window;
987
+ }
988
+ }
989
+ }
990
+ });
991
+ }
992
+ /**
993
+ * Splits elements into chunks of the specified size.
994
+ * Unlike window, chunks don't overlap. The last chunk may be smaller.
995
+ *
996
+ * @param size - The size of each chunk (must be at least 1)
997
+ * @returns A new iterflow of arrays, each containing up to `size` elements
998
+ * @throws {Error} If size is less than 1
999
+ * @example
1000
+ * ```typescript
1001
+ * iter([1, 2, 3, 4, 5]).chunk(2).toArray();
1002
+ * // [[1, 2], [3, 4], [5]]
1003
+ * ```
1004
+ */
1005
+ chunk(size) {
1006
+ validatePositiveInteger(size, "size", "chunk");
1007
+ const self = this;
1008
+ return new _iterflow({
1009
+ *[Symbol.iterator]() {
1010
+ let buffer = new Array(size);
1011
+ let bufferIndex = 0;
1012
+ for (const value of self) {
1013
+ buffer[bufferIndex++] = value;
1014
+ if (bufferIndex === size) {
1015
+ yield buffer;
1016
+ buffer = new Array(size);
1017
+ bufferIndex = 0;
1018
+ }
1019
+ }
1020
+ if (bufferIndex > 0) {
1021
+ yield buffer.slice(0, bufferIndex);
1022
+ }
1023
+ }
1024
+ });
1025
+ }
1026
+ /**
1027
+ * Creates pairs of consecutive elements.
1028
+ * Equivalent to window(2) but returns tuples instead of arrays.
1029
+ *
1030
+ * @returns A new iterflow of tuples, each containing two consecutive elements
1031
+ * @example
1032
+ * ```typescript
1033
+ * iter([1, 2, 3, 4]).pairwise().toArray();
1034
+ * // [[1, 2], [2, 3], [3, 4]]
1035
+ * ```
1036
+ */
1037
+ pairwise() {
1038
+ return this.window(2).map((arr) => [arr[0], arr[1]]);
1039
+ }
1040
+ // Set operations
1041
+ /**
1042
+ * Removes duplicate elements, keeping only the first occurrence of each.
1043
+ * Uses strict equality (===) to compare elements.
1044
+ *
1045
+ * @returns A new iterflow with duplicate elements removed
1046
+ * @example
1047
+ * ```typescript
1048
+ * iter([1, 2, 2, 3, 1, 4]).distinct().toArray();
1049
+ * // [1, 2, 3, 4]
1050
+ * ```
1051
+ */
1052
+ distinct() {
1053
+ const self = this;
1054
+ return new _iterflow({
1055
+ *[Symbol.iterator]() {
1056
+ const seen = /* @__PURE__ */ new Set();
1057
+ for (const value of self) {
1058
+ if (!seen.has(value)) {
1059
+ seen.add(value);
1060
+ yield value;
1061
+ }
1062
+ }
1063
+ }
1064
+ });
1065
+ }
1066
+ /**
1067
+ * Removes duplicate elements based on a key function.
1068
+ * Keeps only the first occurrence of each unique key.
1069
+ *
1070
+ * @template K The type of the key used for comparison
1071
+ * @param keyFn - Function to extract the comparison key from each element
1072
+ * @returns A new iterflow with duplicate elements (by key) removed
1073
+ * @example
1074
+ * ```typescript
1075
+ * const users = [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}, {id: 1, name: 'Charlie'}];
1076
+ * iter(users).distinctBy(u => u.id).toArray();
1077
+ * // [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}]
1078
+ * ```
1079
+ */
1080
+ distinctBy(keyFn) {
1081
+ const self = this;
1082
+ return new _iterflow({
1083
+ *[Symbol.iterator]() {
1084
+ const seenKeys = /* @__PURE__ */ new Set();
1085
+ for (const value of self) {
1086
+ const key = keyFn(value);
1087
+ if (!seenKeys.has(key)) {
1088
+ seenKeys.add(key);
1089
+ yield value;
1090
+ }
1091
+ }
1092
+ }
1093
+ });
1094
+ }
1095
+ // Utility operations
1096
+ /**
1097
+ * Executes a side-effect function on each element without modifying the stream.
1098
+ * Useful for debugging or performing operations like logging.
1099
+ *
1100
+ * @param fn - Function to execute for each element
1101
+ * @returns A new iterflow with the same elements
1102
+ * @example
1103
+ * ```typescript
1104
+ * iter([1, 2, 3])
1105
+ * .tap(x => console.log('Processing:', x))
1106
+ * .map(x => x * 2)
1107
+ * .toArray(); // logs each value, returns [2, 4, 6]
1108
+ * ```
1109
+ */
1110
+ tap(fn) {
1111
+ const self = this;
1112
+ return new _iterflow({
1113
+ *[Symbol.iterator]() {
1114
+ for (const value of self) {
1115
+ fn(value);
1116
+ yield value;
1117
+ }
1118
+ }
1119
+ });
1120
+ }
1121
+ /**
1122
+ * Takes elements while the predicate returns true, then stops.
1123
+ * Stops at the first element that fails the predicate.
1124
+ *
1125
+ * @param predicate - Function to test each element
1126
+ * @returns A new iterflow with elements up to the first failing predicate
1127
+ * @example
1128
+ * ```typescript
1129
+ * iter([1, 2, 3, 4, 1, 2]).takeWhile(x => x < 4).toArray();
1130
+ * // [1, 2, 3]
1131
+ * ```
1132
+ */
1133
+ takeWhile(predicate) {
1134
+ const self = this;
1135
+ return new _iterflow({
1136
+ *[Symbol.iterator]() {
1137
+ for (const value of self) {
1138
+ if (!predicate(value)) break;
1139
+ yield value;
1140
+ }
1141
+ }
1142
+ });
1143
+ }
1144
+ /**
1145
+ * Skips elements while the predicate returns true, then yields all remaining elements.
1146
+ * Starts yielding from the first element that fails the predicate.
1147
+ *
1148
+ * @param predicate - Function to test each element
1149
+ * @returns A new iterflow starting from the first element that fails the predicate
1150
+ * @example
1151
+ * ```typescript
1152
+ * iter([1, 2, 3, 4, 1, 2]).dropWhile(x => x < 3).toArray();
1153
+ * // [3, 4, 1, 2]
1154
+ * ```
1155
+ */
1156
+ dropWhile(predicate) {
1157
+ const self = this;
1158
+ return new _iterflow({
1159
+ *[Symbol.iterator]() {
1160
+ let dropping = true;
1161
+ for (const value of self) {
1162
+ if (dropping && predicate(value)) {
1163
+ continue;
1164
+ }
1165
+ dropping = false;
1166
+ yield value;
1167
+ }
1168
+ }
1169
+ });
1170
+ }
1171
+ // Grouping operations (terminal)
1172
+ /**
1173
+ * Splits elements into two arrays based on a predicate.
1174
+ * This is a terminal operation that consumes the iterator.
1175
+ *
1176
+ * @param predicate - Function to test each element
1177
+ * @returns A tuple of two arrays: [elements passing predicate, elements failing predicate]
1178
+ * @example
1179
+ * ```typescript
1180
+ * iter([1, 2, 3, 4, 5]).partition(x => x % 2 === 0);
1181
+ * // [[2, 4], [1, 3, 5]]
1182
+ * ```
1183
+ */
1184
+ partition(predicate) {
1185
+ const truthy = [];
1186
+ const falsy = [];
1187
+ for (const value of this) {
1188
+ if (predicate(value)) {
1189
+ truthy.push(value);
1190
+ } else {
1191
+ falsy.push(value);
1192
+ }
1193
+ }
1194
+ return [truthy, falsy];
1195
+ }
1196
+ /**
1197
+ * Groups elements by a key function into a Map.
1198
+ * This is a terminal operation that consumes the iterator.
1199
+ *
1200
+ * @template K The type of the grouping key
1201
+ * @param keyFn - Function to extract the grouping key from each element
1202
+ * @returns A Map where keys are the result of keyFn and values are arrays of elements
1203
+ * @example
1204
+ * ```typescript
1205
+ * iter(['alice', 'bob', 'charlie', 'dave'])
1206
+ * .groupBy(name => name.length);
1207
+ * // Map { 3 => ['bob'], 5 => ['alice'], 7 => ['charlie'], 4 => ['dave'] }
1208
+ * ```
1209
+ */
1210
+ groupBy(keyFn) {
1211
+ const groups = /* @__PURE__ */ new Map();
1212
+ for (const value of this) {
1213
+ const key = keyFn(value);
1214
+ if (!groups.has(key)) {
1215
+ groups.set(key, []);
1216
+ }
1217
+ groups.get(key).push(value);
1218
+ }
1219
+ return groups;
1220
+ }
1221
+ // Additional terminal operations
1222
+ /**
1223
+ * Reduces the iterator to a single value using an accumulator function.
1224
+ * This is a terminal operation that consumes the iterator.
1225
+ *
1226
+ * @template U The type of the accumulated value
1227
+ * @param fn - Function to combine the accumulator with each element
1228
+ * @param initial - The initial value for the accumulator
1229
+ * @returns The final accumulated value
1230
+ * @example
1231
+ * ```typescript
1232
+ * iter([1, 2, 3, 4]).reduce((acc, x) => acc + x, 0); // 10
1233
+ * iter(['a', 'b', 'c']).reduce((acc, x) => acc + x, ''); // 'abc'
1234
+ * ```
1235
+ */
1236
+ reduce(fn, initial) {
1237
+ let accumulator = initial;
1238
+ for (const value of this) {
1239
+ accumulator = fn(accumulator, value);
1240
+ }
1241
+ return accumulator;
1242
+ }
1243
+ /**
1244
+ * Finds the first element that matches the predicate.
1245
+ * This is a terminal operation that may consume part of the iterator.
1246
+ *
1247
+ * @param predicate - Function to test each element
1248
+ * @returns The first matching element, or undefined if none found
1249
+ * @example
1250
+ * ```typescript
1251
+ * iter([1, 2, 3, 4, 5]).find(x => x > 3); // 4
1252
+ * iter([1, 2, 3]).find(x => x > 10); // undefined
1253
+ * ```
1254
+ */
1255
+ find(predicate) {
1256
+ for (const value of this) {
1257
+ if (predicate(value)) {
1258
+ return value;
1259
+ }
1260
+ }
1261
+ return void 0;
1262
+ }
1263
+ /**
1264
+ * Finds the index of the first element that matches the predicate.
1265
+ * This is a terminal operation that may consume part of the iterator.
1266
+ *
1267
+ * @param predicate - Function to test each element
1268
+ * @returns The index of the first matching element, or -1 if none found
1269
+ * @example
1270
+ * ```typescript
1271
+ * iter([1, 2, 3, 4, 5]).findIndex(x => x > 3); // 3
1272
+ * iter([1, 2, 3]).findIndex(x => x > 10); // -1
1273
+ * ```
1274
+ */
1275
+ findIndex(predicate) {
1276
+ let index = 0;
1277
+ for (const value of this) {
1278
+ if (predicate(value)) {
1279
+ return index;
1280
+ }
1281
+ index++;
1282
+ }
1283
+ return -1;
1284
+ }
1285
+ /**
1286
+ * Tests whether at least one element matches the predicate.
1287
+ * This is a terminal operation that may consume part of the iterator.
1288
+ *
1289
+ * @param predicate - Function to test each element
1290
+ * @returns true if any element matches, false otherwise
1291
+ * @example
1292
+ * ```typescript
1293
+ * iter([1, 2, 3, 4, 5]).some(x => x > 3); // true
1294
+ * iter([1, 2, 3]).some(x => x > 10); // false
1295
+ * ```
1296
+ */
1297
+ some(predicate) {
1298
+ for (const value of this) {
1299
+ if (predicate(value)) {
1300
+ return true;
1301
+ }
1302
+ }
1303
+ return false;
1304
+ }
1305
+ /**
1306
+ * Tests whether all elements match the predicate.
1307
+ * This is a terminal operation that may consume part or all of the iterator.
1308
+ *
1309
+ * @param predicate - Function to test each element
1310
+ * @returns true if all elements match, false otherwise
1311
+ * @example
1312
+ * ```typescript
1313
+ * iter([2, 4, 6]).every(x => x % 2 === 0); // true
1314
+ * iter([1, 2, 3]).every(x => x % 2 === 0); // false
1315
+ * ```
1316
+ */
1317
+ every(predicate) {
1318
+ for (const value of this) {
1319
+ if (!predicate(value)) {
1320
+ return false;
1321
+ }
1322
+ }
1323
+ return true;
1324
+ }
1325
+ /**
1326
+ * Executes a function for each element in the iterator.
1327
+ * This is a terminal operation that consumes the entire iterator.
1328
+ *
1329
+ * @param fn - Function to execute for each element
1330
+ * @example
1331
+ * ```typescript
1332
+ * iter([1, 2, 3]).forEach(x => console.log(x));
1333
+ * // Logs: 1, 2, 3
1334
+ * ```
1335
+ */
1336
+ forEach(fn) {
1337
+ for (const value of this) {
1338
+ fn(value);
1339
+ }
1340
+ }
1341
+ /**
1342
+ * Gets the first element from the iterator.
1343
+ * This is a terminal operation that consumes the first element.
1344
+ *
1345
+ * @param defaultValue - Optional default value to return if iterator is empty
1346
+ * @returns The first element, the default value, or undefined if empty and no default
1347
+ * @example
1348
+ * ```typescript
1349
+ * iter([1, 2, 3]).first(); // 1
1350
+ * iter([]).first(); // undefined
1351
+ * iter([]).first(0); // 0
1352
+ * ```
1353
+ */
1354
+ first(defaultValue) {
1355
+ const result = this.source.next();
1356
+ return result.done ? defaultValue : result.value;
1357
+ }
1358
+ /**
1359
+ * Gets the last element from the iterator.
1360
+ * This is a terminal operation that consumes the entire iterator.
1361
+ *
1362
+ * @param defaultValue - Optional default value to return if iterator is empty
1363
+ * @returns The last element, the default value, or undefined if empty and no default
1364
+ * @example
1365
+ * ```typescript
1366
+ * iter([1, 2, 3]).last(); // 3
1367
+ * iter([]).last(); // undefined
1368
+ * iter([]).last(0); // 0
1369
+ * ```
1370
+ */
1371
+ last(defaultValue) {
1372
+ let lastValue = defaultValue;
1373
+ let hasValue = false;
1374
+ for (const value of this) {
1375
+ lastValue = value;
1376
+ hasValue = true;
1377
+ }
1378
+ return hasValue ? lastValue : defaultValue;
1379
+ }
1380
+ /**
1381
+ * Gets the element at the specified index.
1382
+ * This is a terminal operation that may consume part of the iterator.
1383
+ *
1384
+ * @param index - Zero-based index of the element to retrieve
1385
+ * @returns The element at the index, or undefined if index is out of bounds
1386
+ * @example
1387
+ * ```typescript
1388
+ * iter([1, 2, 3, 4, 5]).nth(2); // 3
1389
+ * iter([1, 2, 3]).nth(10); // undefined
1390
+ * iter([1, 2, 3]).nth(-1); // undefined
1391
+ * ```
1392
+ */
1393
+ nth(index) {
1394
+ if (index < 0) {
1395
+ return void 0;
1396
+ }
1397
+ let currentIndex = 0;
1398
+ for (const value of this) {
1399
+ if (currentIndex === index) {
1400
+ return value;
1401
+ }
1402
+ currentIndex++;
1403
+ }
1404
+ return void 0;
1405
+ }
1406
+ /**
1407
+ * Checks if the iterator is empty.
1408
+ * This is a terminal operation that may consume the first element.
1409
+ *
1410
+ * @returns true if the iterator has no elements, false otherwise
1411
+ * @example
1412
+ * ```typescript
1413
+ * iter([]).isEmpty(); // true
1414
+ * iter([1, 2, 3]).isEmpty(); // false
1415
+ * ```
1416
+ */
1417
+ isEmpty() {
1418
+ const result = this.source.next();
1419
+ return result.done === true;
1420
+ }
1421
+ /**
1422
+ * Checks if the iterator includes a specific value.
1423
+ * Uses strict equality (===) for comparison.
1424
+ * This is a terminal operation that may consume part or all of the iterator.
1425
+ *
1426
+ * @param searchValue - The value to search for
1427
+ * @returns true if the value is found, false otherwise
1428
+ * @example
1429
+ * ```typescript
1430
+ * iter([1, 2, 3, 4, 5]).includes(3); // true
1431
+ * iter([1, 2, 3]).includes(10); // false
1432
+ * iter(['a', 'b', 'c']).includes('b'); // true
1433
+ * ```
1434
+ */
1435
+ includes(searchValue) {
1436
+ for (const value of this) {
1437
+ if (value === searchValue) {
1438
+ return true;
1439
+ }
1440
+ }
1441
+ return false;
1442
+ }
1443
+ // Alias methods for compatibility
1444
+ /**
1445
+ * Alias for stdDev() method for compatibility.
1446
+ * Calculates the standard deviation of all numeric elements.
1447
+ */
1448
+ stddev() {
1449
+ return this.stdDev();
1450
+ }
1451
+ /**
1452
+ * Alias for drop() method for compatibility.
1453
+ * Skips the first `count` elements from the iterator.
1454
+ */
1455
+ skip(count) {
1456
+ return this.drop(count);
1457
+ }
1458
+ /**
1459
+ * Interleaves elements from this iterator with elements from other iterables.
1460
+ * Takes one element from each iterable in round-robin fashion.
1461
+ *
1462
+ * @param others - Variable number of iterables to interleave with
1463
+ * @returns A new iterflow with elements from all iterables interleaved
1464
+ * @example
1465
+ * ```typescript
1466
+ * iter([1, 2, 3]).interleave([4, 5, 6]).toArray(); // [1, 4, 2, 5, 3, 6]
1467
+ * ```
1468
+ */
1469
+ interleave(...others) {
1470
+ const self = this;
1471
+ return new _iterflow({
1472
+ *[Symbol.iterator]() {
1473
+ const allIterables = [self, ...others];
1474
+ if (allIterables.length === 0) return;
1475
+ const iterators = allIterables.map((it) => it[Symbol.iterator]());
1476
+ const active = new Set(iterators);
1477
+ while (active.size > 0) {
1478
+ for (const iterator of iterators) {
1479
+ if (!active.has(iterator)) continue;
1480
+ const result = iterator.next();
1481
+ if (result.done) {
1482
+ active.delete(iterator);
1483
+ } else {
1484
+ yield result.value;
1485
+ }
1486
+ }
1487
+ }
1488
+ }
1489
+ });
1490
+ }
1491
+ /**
1492
+ * Merges this iterator with other sorted iterables into a single sorted iterator.
1493
+ * Assumes all input iterables are already sorted in ascending order.
1494
+ *
1495
+ * @param others - Variable number of sorted iterables to merge with
1496
+ * @returns A new iterflow with all elements merged in sorted order
1497
+ * @example
1498
+ * ```typescript
1499
+ * iter([1, 3, 5]).merge([2, 4, 6]).toArray(); // [1, 2, 3, 4, 5, 6]
1500
+ * ```
1501
+ */
1502
+ merge(...others) {
1503
+ const self = this;
1504
+ return new _iterflow({
1505
+ *[Symbol.iterator]() {
1506
+ const allIterables = [self, ...others];
1507
+ if (allIterables.length === 0) return;
1508
+ const compareFn = (a, b) => {
1509
+ if (a < b) return -1;
1510
+ if (a > b) return 1;
1511
+ return 0;
1512
+ };
1513
+ const heap = [];
1514
+ for (let i = 0; i < allIterables.length; i++) {
1515
+ const iterator = allIterables[i][Symbol.iterator]();
1516
+ const result = iterator.next();
1517
+ if (!result.done) {
1518
+ heap.push({ value: result.value, iterator, index: i });
1519
+ }
1520
+ }
1521
+ const bubbleDown = (index) => {
1522
+ const length = heap.length;
1523
+ while (true) {
1524
+ let smallest = index;
1525
+ const leftChild = 2 * index + 1;
1526
+ const rightChild = 2 * index + 2;
1527
+ if (leftChild < length && compareFn(heap[leftChild].value, heap[smallest].value) < 0) {
1528
+ smallest = leftChild;
1529
+ }
1530
+ if (rightChild < length && compareFn(heap[rightChild].value, heap[smallest].value) < 0) {
1531
+ smallest = rightChild;
1532
+ }
1533
+ if (smallest === index) break;
1534
+ const temp = heap[index];
1535
+ heap[index] = heap[smallest];
1536
+ heap[smallest] = temp;
1537
+ index = smallest;
1538
+ }
1539
+ };
1540
+ for (let i = Math.floor(heap.length / 2) - 1; i >= 0; i--) {
1541
+ bubbleDown(i);
1542
+ }
1543
+ while (heap.length > 0) {
1544
+ const min = heap[0];
1545
+ yield min.value;
1546
+ const nextResult = min.iterator.next();
1547
+ if (nextResult.done) {
1548
+ heap[0] = heap[heap.length - 1];
1549
+ heap.pop();
1550
+ if (heap.length > 0) {
1551
+ bubbleDown(0);
1552
+ }
1553
+ } else {
1554
+ heap[0].value = nextResult.value;
1555
+ bubbleDown(0);
1556
+ }
1557
+ }
1558
+ }
1559
+ });
1560
+ }
1561
+ };
1562
+
1563
+ // src/async-iter-flow.ts
1564
+ var Asynciterflow = class _Asynciterflow {
1565
+ source;
1566
+ /**
1567
+ * Creates a new async iterflow instance from an async iterable or async iterator.
1568
+ *
1569
+ * @param source - The source async iterable or async iterator to wrap
1570
+ * @example
1571
+ * ```typescript
1572
+ * const flow1 = new Asynciterflow(asyncIterable);
1573
+ * const flow2 = new Asynciterflow(asyncIterator);
1574
+ * ```
1575
+ */
1576
+ constructor(source) {
1577
+ this.source = Symbol.asyncIterator in source ? source[Symbol.asyncIterator]() : source;
1578
+ }
1579
+ // Async Iterator protocol
1580
+ /**
1581
+ * Returns the async iterator for this iterflow instance.
1582
+ * This allows iterflow to be used in for await...of loops.
1583
+ *
1584
+ * @returns The underlying async iterator
1585
+ */
1586
+ [Symbol.asyncIterator]() {
1587
+ return this.source;
1588
+ }
1589
+ /**
1590
+ * Retrieves the next value from the async iterator.
1591
+ *
1592
+ * @returns A promise of an IteratorResult containing the next value or indicating completion
1593
+ */
1594
+ next() {
1595
+ return this.source.next();
1596
+ }
1597
+ // Transformation operations
1598
+ /**
1599
+ * Transforms each element using the provided async or sync function.
1600
+ *
1601
+ * @template U The type of the transformed elements
1602
+ * @param fn - Async or sync function to transform each element
1603
+ * @returns A new async iterflow with transformed elements
1604
+ * @example
1605
+ * ```typescript
1606
+ * await asyncIter([1, 2, 3]).map(async x => x * 2).toArray(); // [2, 4, 6]
1607
+ * ```
1608
+ */
1609
+ map(fn) {
1610
+ const self = this;
1611
+ return new _Asynciterflow({
1612
+ async *[Symbol.asyncIterator]() {
1613
+ for await (const value of self) {
1614
+ yield await fn(value);
1615
+ }
1616
+ }
1617
+ });
1618
+ }
1619
+ /**
1620
+ * Filters elements based on an async or sync predicate function.
1621
+ * Only elements for which the predicate returns true are included.
1622
+ *
1623
+ * @param predicate - Async or sync function to test each element
1624
+ * @returns A new async iterflow with only elements that pass the predicate
1625
+ * @example
1626
+ * ```typescript
1627
+ * await asyncIter([1, 2, 3, 4]).filter(async x => x % 2 === 0).toArray(); // [2, 4]
1628
+ * ```
1629
+ */
1630
+ filter(predicate) {
1631
+ const self = this;
1632
+ return new _Asynciterflow({
1633
+ async *[Symbol.asyncIterator]() {
1634
+ for await (const value of self) {
1635
+ if (await predicate(value)) {
1636
+ yield value;
1637
+ }
1638
+ }
1639
+ }
1640
+ });
1641
+ }
1642
+ /**
1643
+ * Takes only the first `limit` elements from the async iterator.
1644
+ *
1645
+ * @param limit - Maximum number of elements to take
1646
+ * @returns A new async iterflow with at most `limit` elements
1647
+ * @example
1648
+ * ```typescript
1649
+ * await asyncIter([1, 2, 3, 4, 5]).take(3).toArray(); // [1, 2, 3]
1650
+ * ```
1651
+ */
1652
+ take(limit) {
1653
+ const self = this;
1654
+ return new _Asynciterflow({
1655
+ async *[Symbol.asyncIterator]() {
1656
+ let count = 0;
1657
+ for await (const value of self) {
1658
+ if (count >= limit) break;
1659
+ yield value;
1660
+ count++;
1661
+ }
1662
+ }
1663
+ });
1664
+ }
1665
+ /**
1666
+ * Skips the first `count` elements from the async iterator.
1667
+ *
1668
+ * @param count - Number of elements to skip
1669
+ * @returns A new async iterflow without the first `count` elements
1670
+ * @example
1671
+ * ```typescript
1672
+ * await asyncIter([1, 2, 3, 4, 5]).drop(2).toArray(); // [3, 4, 5]
1673
+ * ```
1674
+ */
1675
+ drop(count) {
1676
+ const self = this;
1677
+ return new _Asynciterflow({
1678
+ async *[Symbol.asyncIterator]() {
1679
+ let dropped = 0;
1680
+ for await (const value of self) {
1681
+ if (dropped < count) {
1682
+ dropped++;
1683
+ continue;
1684
+ }
1685
+ yield value;
1686
+ }
1687
+ }
1688
+ });
1689
+ }
1690
+ /**
1691
+ * Maps each element to an async iterable and flattens the results.
1692
+ *
1693
+ * @template U The type of elements in the resulting iterator
1694
+ * @param fn - Async or sync function that maps each element to an async iterable
1695
+ * @returns A new async iterflow with all mapped iterables flattened
1696
+ * @example
1697
+ * ```typescript
1698
+ * await asyncIter([1, 2, 3]).flatMap(async x => [x, x * 2]).toArray(); // [1, 2, 2, 4, 3, 6]
1699
+ * ```
1700
+ */
1701
+ flatMap(fn) {
1702
+ const self = this;
1703
+ return new _Asynciterflow({
1704
+ async *[Symbol.asyncIterator]() {
1705
+ for await (const value of self) {
1706
+ const result = await fn(value);
1707
+ if (Symbol.asyncIterator in result) {
1708
+ yield* result;
1709
+ } else {
1710
+ yield* result;
1711
+ }
1712
+ }
1713
+ }
1714
+ });
1715
+ }
1716
+ /**
1717
+ * Concatenates multiple async iterators sequentially.
1718
+ *
1719
+ * @param iterables - Additional async iterables to concatenate
1720
+ * @returns A new async iterflow with all elements from all iterables
1721
+ * @example
1722
+ * ```typescript
1723
+ * await asyncIter([1, 2]).concat([3, 4], [5, 6]).toArray();
1724
+ * // [1, 2, 3, 4, 5, 6]
1725
+ * ```
1726
+ */
1727
+ concat(...iterables) {
1728
+ const self = this;
1729
+ return new _Asynciterflow({
1730
+ async *[Symbol.asyncIterator]() {
1731
+ yield* self;
1732
+ for (const iterable of iterables) {
1733
+ if (Symbol.asyncIterator in iterable) {
1734
+ yield* iterable;
1735
+ } else {
1736
+ yield* iterable;
1737
+ }
1738
+ }
1739
+ }
1740
+ });
1741
+ }
1742
+ /**
1743
+ * Inserts a separator element between each item.
1744
+ *
1745
+ * @param separator - The element to insert between items
1746
+ * @returns A new async iterflow with separators interspersed
1747
+ * @example
1748
+ * ```typescript
1749
+ * await asyncIter([1, 2, 3]).intersperse(0).toArray();
1750
+ * // [1, 0, 2, 0, 3]
1751
+ * ```
1752
+ */
1753
+ intersperse(separator) {
1754
+ const self = this;
1755
+ return new _Asynciterflow({
1756
+ async *[Symbol.asyncIterator]() {
1757
+ let isFirst = true;
1758
+ for await (const value of self) {
1759
+ if (!isFirst) {
1760
+ yield separator;
1761
+ }
1762
+ yield value;
1763
+ isFirst = false;
1764
+ }
1765
+ }
1766
+ });
1767
+ }
1768
+ /**
1769
+ * Like reduce, but emits all intermediate accumulator values.
1770
+ *
1771
+ * @template U The type of the accumulated value
1772
+ * @param fn - Async or sync function to combine the accumulator with each element
1773
+ * @param initial - The initial value for the accumulator
1774
+ * @returns A new async iterflow of intermediate accumulator values
1775
+ * @example
1776
+ * ```typescript
1777
+ * await asyncIter([1, 2, 3, 4]).scan((acc, x) => acc + x, 0).toArray();
1778
+ * // [0, 1, 3, 6, 10]
1779
+ * ```
1780
+ */
1781
+ scan(fn, initial) {
1782
+ const self = this;
1783
+ return new _Asynciterflow({
1784
+ async *[Symbol.asyncIterator]() {
1785
+ let accumulator = initial;
1786
+ yield accumulator;
1787
+ for await (const value of self) {
1788
+ accumulator = await fn(accumulator, value);
1789
+ yield accumulator;
1790
+ }
1791
+ }
1792
+ });
1793
+ }
1794
+ /**
1795
+ * Adds index as tuple with each element [index, value].
1796
+ *
1797
+ * @returns A new async iterflow of tuples containing [index, value]
1798
+ * @example
1799
+ * ```typescript
1800
+ * await asyncIter(['a', 'b', 'c']).enumerate().toArray();
1801
+ * // [[0, 'a'], [1, 'b'], [2, 'c']]
1802
+ * ```
1803
+ */
1804
+ enumerate() {
1805
+ const self = this;
1806
+ return new _Asynciterflow({
1807
+ async *[Symbol.asyncIterator]() {
1808
+ let index = 0;
1809
+ for await (const value of self) {
1810
+ yield [index, value];
1811
+ index++;
1812
+ }
1813
+ }
1814
+ });
1815
+ }
1816
+ /**
1817
+ * Reverses the async iterator order.
1818
+ * Warning: This operation buffers all elements in memory.
1819
+ *
1820
+ * @returns A new async iterflow with elements in reverse order
1821
+ * @example
1822
+ * ```typescript
1823
+ * await asyncIter([1, 2, 3, 4, 5]).reverse().toArray();
1824
+ * // [5, 4, 3, 2, 1]
1825
+ * ```
1826
+ */
1827
+ reverse() {
1828
+ const self = this;
1829
+ return new _Asynciterflow({
1830
+ async *[Symbol.asyncIterator]() {
1831
+ const buffer = await self.toArray();
1832
+ for (let i = buffer.length - 1; i >= 0; i--) {
1833
+ yield buffer[i];
1834
+ }
1835
+ }
1836
+ });
1837
+ }
1838
+ /**
1839
+ * Sorts elements using default comparison.
1840
+ * Warning: This operation buffers all elements in memory.
1841
+ *
1842
+ * @param this - async iterflow instance constrained to numbers or strings
1843
+ * @returns A new async iterflow with elements sorted
1844
+ * @example
1845
+ * ```typescript
1846
+ * await asyncIter([3, 1, 4, 1, 5]).sort().toArray();
1847
+ * // [1, 1, 3, 4, 5]
1848
+ * ```
1849
+ */
1850
+ sort() {
1851
+ const self = this;
1852
+ return new _Asynciterflow({
1853
+ async *[Symbol.asyncIterator]() {
1854
+ const buffer = await self.toArray();
1855
+ buffer.sort((a, b) => {
1856
+ if (typeof a === "number" && typeof b === "number") {
1857
+ return a - b;
1858
+ }
1859
+ return String(a).localeCompare(String(b));
1860
+ });
1861
+ yield* buffer;
1862
+ }
1863
+ });
1864
+ }
1865
+ /**
1866
+ * Sorts elements using a custom comparison function.
1867
+ * Warning: This operation buffers all elements in memory.
1868
+ *
1869
+ * @param compareFn - Function that compares two elements
1870
+ * @returns A new async iterflow with elements sorted
1871
+ * @example
1872
+ * ```typescript
1873
+ * await asyncIter([3, 1, 4, 1, 5]).sortBy((a, b) => a - b).toArray();
1874
+ * // [1, 1, 3, 4, 5]
1875
+ * ```
1876
+ */
1877
+ sortBy(compareFn) {
1878
+ const self = this;
1879
+ return new _Asynciterflow({
1880
+ async *[Symbol.asyncIterator]() {
1881
+ const buffer = await self.toArray();
1882
+ buffer.sort(compareFn);
1883
+ yield* buffer;
1884
+ }
1885
+ });
1886
+ }
1887
+ // Terminal operations
1888
+ /**
1889
+ * Collects all elements into an array.
1890
+ * This is a terminal operation that consumes the async iterator.
1891
+ *
1892
+ * @returns A promise of an array containing all elements
1893
+ * @example
1894
+ * ```typescript
1895
+ * await asyncIter([1, 2, 3]).map(async x => x * 2).toArray(); // [2, 4, 6]
1896
+ * ```
1897
+ */
1898
+ async toArray() {
1899
+ const result = [];
1900
+ for await (const value of this) {
1901
+ result.push(value);
1902
+ }
1903
+ return result;
1904
+ }
1905
+ /**
1906
+ * Counts the total number of elements in the async iterator.
1907
+ * This is a terminal operation that consumes the async iterator.
1908
+ *
1909
+ * @returns A promise of the total count of elements
1910
+ * @example
1911
+ * ```typescript
1912
+ * await asyncIter([1, 2, 3, 4, 5]).count(); // 5
1913
+ * ```
1914
+ */
1915
+ async count() {
1916
+ let count = 0;
1917
+ for await (const _ of this) {
1918
+ count++;
1919
+ }
1920
+ return count;
1921
+ }
1922
+ /**
1923
+ * Executes a function for each element.
1924
+ * This is a terminal operation that consumes the async iterator.
1925
+ *
1926
+ * @param fn - Async or sync function to execute for each element
1927
+ * @returns A promise that resolves when all elements have been processed
1928
+ * @example
1929
+ * ```typescript
1930
+ * await asyncIter([1, 2, 3]).forEach(async x => console.log(x));
1931
+ * ```
1932
+ */
1933
+ async forEach(fn) {
1934
+ for await (const value of this) {
1935
+ await fn(value);
1936
+ }
1937
+ }
1938
+ // Statistical operations
1939
+ /**
1940
+ * Calculates the sum of all numeric elements.
1941
+ * This is a terminal operation that consumes the async iterator.
1942
+ *
1943
+ * @param this - async iterflow instance constrained to numbers
1944
+ * @returns A promise of the sum of all elements
1945
+ * @example
1946
+ * ```typescript
1947
+ * await asyncIter([1, 2, 3, 4, 5]).sum(); // 15
1948
+ * ```
1949
+ */
1950
+ async sum() {
1951
+ let total = 0;
1952
+ for await (const value of this) {
1953
+ total += value;
1954
+ }
1955
+ return total;
1956
+ }
1957
+ /**
1958
+ * Calculates the arithmetic mean (average) of all numeric elements.
1959
+ * This is a terminal operation that consumes the async iterator.
1960
+ *
1961
+ * @param this - async iterflow instance constrained to numbers
1962
+ * @returns A promise of the mean value, or undefined if empty
1963
+ * @example
1964
+ * ```typescript
1965
+ * await asyncIter([1, 2, 3, 4, 5]).mean(); // 3
1966
+ * ```
1967
+ */
1968
+ async mean() {
1969
+ let total = 0;
1970
+ let count = 0;
1971
+ for await (const value of this) {
1972
+ total += value;
1973
+ count++;
1974
+ }
1975
+ return count === 0 ? void 0 : total / count;
1976
+ }
1977
+ /**
1978
+ * Finds the minimum value among all numeric elements.
1979
+ * This is a terminal operation that consumes the async iterator.
1980
+ *
1981
+ * @param this - async iterflow instance constrained to numbers
1982
+ * @returns A promise of the minimum value, or undefined if empty
1983
+ * @example
1984
+ * ```typescript
1985
+ * await asyncIter([3, 1, 4, 1, 5]).min(); // 1
1986
+ * ```
1987
+ */
1988
+ async min() {
1989
+ let minimum = void 0;
1990
+ for await (const value of this) {
1991
+ if (minimum === void 0 || value < minimum) {
1992
+ minimum = value;
1993
+ }
1994
+ }
1995
+ return minimum;
1996
+ }
1997
+ /**
1998
+ * Finds the maximum value among all numeric elements.
1999
+ * This is a terminal operation that consumes the async iterator.
2000
+ *
2001
+ * @param this - async iterflow instance constrained to numbers
2002
+ * @returns A promise of the maximum value, or undefined if empty
2003
+ * @example
2004
+ * ```typescript
2005
+ * await asyncIter([3, 1, 4, 1, 5]).max(); // 5
2006
+ * ```
2007
+ */
2008
+ async max() {
2009
+ let maximum = void 0;
2010
+ for await (const value of this) {
2011
+ if (maximum === void 0 || value > maximum) {
2012
+ maximum = value;
2013
+ }
2014
+ }
2015
+ return maximum;
2016
+ }
2017
+ /**
2018
+ * Calculates the median value of all numeric elements.
2019
+ * This is a terminal operation that consumes the async iterator.
2020
+ *
2021
+ * @param this - async iterflow instance constrained to numbers
2022
+ * @returns A promise of the median value, or undefined if empty
2023
+ * @example
2024
+ * ```typescript
2025
+ * await asyncIter([1, 2, 3, 4, 5]).median(); // 3
2026
+ * ```
2027
+ */
2028
+ async median() {
2029
+ const values = await this.toArray();
2030
+ if (values.length === 0) return void 0;
2031
+ values.sort((a, b) => a - b);
2032
+ const mid = Math.floor(values.length / 2);
2033
+ if (values.length % 2 === 0) {
2034
+ return (values[mid - 1] + values[mid]) / 2;
2035
+ } else {
2036
+ return values[mid];
2037
+ }
2038
+ }
2039
+ /**
2040
+ * Calculates the variance of all numeric elements.
2041
+ * This is a terminal operation that consumes the async iterator.
2042
+ *
2043
+ * @param this - async iterflow instance constrained to numbers
2044
+ * @returns A promise of the variance, or undefined if empty
2045
+ * @example
2046
+ * ```typescript
2047
+ * await asyncIter([1, 2, 3, 4, 5]).variance(); // 2
2048
+ * ```
2049
+ */
2050
+ async variance() {
2051
+ const values = await this.toArray();
2052
+ if (values.length === 0) return void 0;
2053
+ const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
2054
+ let sumSquaredDiffs = 0;
2055
+ for (let i = 0; i < values.length; i++) {
2056
+ const diff = values[i] - mean;
2057
+ sumSquaredDiffs += diff * diff;
2058
+ }
2059
+ return sumSquaredDiffs / values.length;
2060
+ }
2061
+ /**
2062
+ * Calculates the standard deviation of all numeric elements.
2063
+ * This is a terminal operation that consumes the async iterator.
2064
+ *
2065
+ * @param this - async iterflow instance constrained to numbers
2066
+ * @returns A promise of the standard deviation, or undefined if empty
2067
+ * @example
2068
+ * ```typescript
2069
+ * await asyncIter([2, 4, 4, 4, 5, 5, 7, 9]).stdDev(); // ~2
2070
+ * ```
2071
+ */
2072
+ async stdDev() {
2073
+ const variance = await this.variance();
2074
+ return variance === void 0 ? void 0 : Math.sqrt(variance);
2075
+ }
2076
+ /**
2077
+ * Calculates the specified percentile of all numeric elements.
2078
+ * This is a terminal operation that consumes the async iterator.
2079
+ *
2080
+ * @param this - async iterflow instance constrained to numbers
2081
+ * @param p - The percentile to calculate (0-100)
2082
+ * @returns A promise of the percentile value, or undefined if empty
2083
+ * @throws {Error} If p is not between 0 and 100
2084
+ * @example
2085
+ * ```typescript
2086
+ * await asyncIter([1, 2, 3, 4, 5]).percentile(50); // 3
2087
+ * ```
2088
+ */
2089
+ async percentile(p) {
2090
+ validateRange(p, 0, 100, "percentile", "percentile");
2091
+ const values = await this.toArray();
2092
+ if (values.length === 0) return void 0;
2093
+ values.sort((a, b) => a - b);
2094
+ if (p === 0) return values[0];
2095
+ if (p === 100) return values[values.length - 1];
2096
+ const index = p / 100 * (values.length - 1);
2097
+ const lower = Math.floor(index);
2098
+ const upper = Math.ceil(index);
2099
+ if (lower === upper) {
2100
+ return values[lower];
2101
+ }
2102
+ const weight = index - lower;
2103
+ return values[lower] * (1 - weight) + values[upper] * weight;
2104
+ }
2105
+ /**
2106
+ * Finds the most frequent value(s) in the dataset.
2107
+ * This is a terminal operation that consumes the async iterator.
2108
+ *
2109
+ * @param this - async iterflow instance constrained to numbers
2110
+ * @returns A promise of an array of the most frequent value(s), or undefined if empty
2111
+ * @example
2112
+ * ```typescript
2113
+ * await asyncIter([1, 2, 2, 3, 3, 3]).mode(); // [3]
2114
+ * ```
2115
+ */
2116
+ async mode() {
2117
+ const values = await this.toArray();
2118
+ if (values.length === 0) return void 0;
2119
+ const frequency = /* @__PURE__ */ new Map();
2120
+ let maxFreq = 0;
2121
+ for (const value of values) {
2122
+ const count = (frequency.get(value) || 0) + 1;
2123
+ frequency.set(value, count);
2124
+ maxFreq = Math.max(maxFreq, count);
2125
+ }
2126
+ const modes = [];
2127
+ for (const [value, freq] of frequency) {
2128
+ if (freq === maxFreq) {
2129
+ modes.push(value);
2130
+ }
2131
+ }
2132
+ return modes.sort((a, b) => a - b);
2133
+ }
2134
+ /**
2135
+ * Calculates the quartiles (Q1, Q2, Q3) of all numeric elements.
2136
+ * This is a terminal operation that consumes the async iterator.
2137
+ *
2138
+ * @param this - async iterflow instance constrained to numbers
2139
+ * @returns A promise of an object with Q1, Q2, and Q3 values, or undefined if empty
2140
+ * @example
2141
+ * ```typescript
2142
+ * await asyncIter([1, 2, 3, 4, 5, 6, 7, 8, 9]).quartiles();
2143
+ * // { Q1: 3, Q2: 5, Q3: 7 }
2144
+ * ```
2145
+ */
2146
+ async quartiles() {
2147
+ const values = await this.toArray();
2148
+ if (values.length === 0) return void 0;
2149
+ values.sort((a, b) => a - b);
2150
+ const calculatePercentile = (p) => {
2151
+ if (p === 0) return values[0];
2152
+ if (p === 100) return values[values.length - 1];
2153
+ const index = p / 100 * (values.length - 1);
2154
+ const lower = Math.floor(index);
2155
+ const upper = Math.ceil(index);
2156
+ if (lower === upper) {
2157
+ return values[lower];
2158
+ }
2159
+ const weight = index - lower;
2160
+ return values[lower] * (1 - weight) + values[upper] * weight;
2161
+ };
2162
+ return {
2163
+ Q1: calculatePercentile(25),
2164
+ Q2: calculatePercentile(50),
2165
+ Q3: calculatePercentile(75)
2166
+ };
2167
+ }
2168
+ /**
2169
+ * Calculates the span (range from minimum to maximum value).
2170
+ * This is a terminal operation that consumes the async iterator.
2171
+ *
2172
+ * @param this - async iterflow instance constrained to numbers
2173
+ * @returns A promise of the span (max - min), or undefined if empty
2174
+ * @example
2175
+ * ```typescript
2176
+ * await asyncIter([1, 2, 3, 4, 5]).span(); // 4
2177
+ * ```
2178
+ */
2179
+ async span() {
2180
+ let minimum = void 0;
2181
+ let maximum = void 0;
2182
+ for await (const value of this) {
2183
+ if (minimum === void 0 || value < minimum) {
2184
+ minimum = value;
2185
+ }
2186
+ if (maximum === void 0 || value > maximum) {
2187
+ maximum = value;
2188
+ }
2189
+ }
2190
+ return minimum === void 0 || maximum === void 0 ? void 0 : maximum - minimum;
2191
+ }
2192
+ /**
2193
+ * Calculates the product of all numeric elements.
2194
+ * This is a terminal operation that consumes the async iterator.
2195
+ *
2196
+ * @param this - async iterflow instance constrained to numbers
2197
+ * @returns A promise of the product of all elements
2198
+ * @example
2199
+ * ```typescript
2200
+ * await asyncIter([1, 2, 3, 4, 5]).product(); // 120
2201
+ * ```
2202
+ */
2203
+ async product() {
2204
+ let result = 1;
2205
+ for await (const value of this) {
2206
+ result *= value;
2207
+ }
2208
+ return result;
2209
+ }
2210
+ /**
2211
+ * Calculates the covariance between two numeric sequences.
2212
+ * This is a terminal operation that consumes the async iterator.
2213
+ *
2214
+ * @param this - async iterflow instance constrained to numbers
2215
+ * @param other - An async iterable of numbers to compare with
2216
+ * @returns A promise of the covariance, or undefined if sequences are empty or have different lengths
2217
+ * @example
2218
+ * ```typescript
2219
+ * await asyncIter([1, 2, 3, 4, 5]).covariance([2, 4, 6, 8, 10]); // 4
2220
+ * ```
2221
+ */
2222
+ async covariance(other) {
2223
+ const values1 = await this.toArray();
2224
+ const values2 = [];
2225
+ if (Symbol.asyncIterator in other) {
2226
+ for await (const value of other) {
2227
+ values2.push(value);
2228
+ }
2229
+ } else {
2230
+ for (const value of other) {
2231
+ values2.push(value);
2232
+ }
2233
+ }
2234
+ if (values1.length === 0 || values2.length === 0 || values1.length !== values2.length) {
2235
+ return void 0;
2236
+ }
2237
+ const mean1 = values1.reduce((sum, val) => sum + val, 0) / values1.length;
2238
+ const mean2 = values2.reduce((sum, val) => sum + val, 0) / values2.length;
2239
+ let covariance = 0;
2240
+ for (let i = 0; i < values1.length; i++) {
2241
+ covariance += (values1[i] - mean1) * (values2[i] - mean2);
2242
+ }
2243
+ return covariance / values1.length;
2244
+ }
2245
+ /**
2246
+ * Calculates the Pearson correlation coefficient between two numeric sequences.
2247
+ * This is a terminal operation that consumes the async iterator.
2248
+ *
2249
+ * @param this - async iterflow instance constrained to numbers
2250
+ * @param other - An async iterable of numbers to compare with
2251
+ * @returns A promise of the correlation coefficient, or undefined if sequences are empty or have different lengths
2252
+ * @example
2253
+ * ```typescript
2254
+ * await asyncIter([1, 2, 3, 4, 5]).correlation([2, 4, 6, 8, 10]); // 1
2255
+ * ```
2256
+ */
2257
+ async correlation(other) {
2258
+ const values1 = await this.toArray();
2259
+ const values2 = [];
2260
+ if (Symbol.asyncIterator in other) {
2261
+ for await (const value of other) {
2262
+ values2.push(value);
2263
+ }
2264
+ } else {
2265
+ for (const value of other) {
2266
+ values2.push(value);
2267
+ }
2268
+ }
2269
+ if (values1.length === 0 || values2.length === 0 || values1.length !== values2.length) {
2270
+ return void 0;
2271
+ }
2272
+ const mean1 = values1.reduce((sum, val) => sum + val, 0) / values1.length;
2273
+ const mean2 = values2.reduce((sum, val) => sum + val, 0) / values2.length;
2274
+ let covariance = 0;
2275
+ let variance1 = 0;
2276
+ let variance2 = 0;
2277
+ for (let i = 0; i < values1.length; i++) {
2278
+ const diff1 = values1[i] - mean1;
2279
+ const diff2 = values2[i] - mean2;
2280
+ covariance += diff1 * diff2;
2281
+ variance1 += diff1 * diff1;
2282
+ variance2 += diff2 * diff2;
2283
+ }
2284
+ const stdDev1 = Math.sqrt(variance1 / values1.length);
2285
+ const stdDev2 = Math.sqrt(variance2 / values2.length);
2286
+ if (stdDev1 === 0 || stdDev2 === 0) {
2287
+ return void 0;
2288
+ }
2289
+ return covariance / (values1.length * stdDev1 * stdDev2);
2290
+ }
2291
+ // Windowing operations
2292
+ /**
2293
+ * Creates a sliding window of the specified size over the elements.
2294
+ *
2295
+ * @param size - The size of each window
2296
+ * @returns A new async iterflow of arrays, each containing `size` consecutive elements
2297
+ * @throws {Error} If size is less than 1
2298
+ * @example
2299
+ * ```typescript
2300
+ * await asyncIter([1, 2, 3, 4, 5]).window(3).toArray();
2301
+ * // [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
2302
+ * ```
2303
+ */
2304
+ window(size) {
2305
+ validatePositiveInteger(size, "size", "window");
2306
+ const self = this;
2307
+ return new _Asynciterflow({
2308
+ async *[Symbol.asyncIterator]() {
2309
+ const buffer = new Array(size);
2310
+ let count = 0;
2311
+ let index = 0;
2312
+ for await (const value of self) {
2313
+ buffer[index] = value;
2314
+ count++;
2315
+ index = (index + 1) % size;
2316
+ if (count >= size) {
2317
+ const window = new Array(size);
2318
+ for (let i = 0; i < size; i++) {
2319
+ window[i] = buffer[(index + i) % size];
2320
+ }
2321
+ yield window;
2322
+ }
2323
+ }
2324
+ }
2325
+ });
2326
+ }
2327
+ /**
2328
+ * Splits elements into chunks of the specified size.
2329
+ *
2330
+ * @param size - The size of each chunk
2331
+ * @returns A new async iterflow of arrays, each containing up to `size` elements
2332
+ * @throws {Error} If size is less than 1
2333
+ * @example
2334
+ * ```typescript
2335
+ * await asyncIter([1, 2, 3, 4, 5]).chunk(2).toArray();
2336
+ * // [[1, 2], [3, 4], [5]]
2337
+ * ```
2338
+ */
2339
+ chunk(size) {
2340
+ validatePositiveInteger(size, "size", "chunk");
2341
+ const self = this;
2342
+ return new _Asynciterflow({
2343
+ async *[Symbol.asyncIterator]() {
2344
+ let buffer = new Array(size);
2345
+ let bufferIndex = 0;
2346
+ for await (const value of self) {
2347
+ buffer[bufferIndex++] = value;
2348
+ if (bufferIndex === size) {
2349
+ yield buffer;
2350
+ buffer = new Array(size);
2351
+ bufferIndex = 0;
2352
+ }
2353
+ }
2354
+ if (bufferIndex > 0) {
2355
+ yield buffer.slice(0, bufferIndex);
2356
+ }
2357
+ }
2358
+ });
2359
+ }
2360
+ /**
2361
+ * Creates pairs of consecutive elements.
2362
+ *
2363
+ * @returns A new async iterflow of tuples, each containing two consecutive elements
2364
+ * @example
2365
+ * ```typescript
2366
+ * await asyncIter([1, 2, 3, 4]).pairwise().toArray();
2367
+ * // [[1, 2], [2, 3], [3, 4]]
2368
+ * ```
2369
+ */
2370
+ pairwise() {
2371
+ return this.window(2).map((arr) => [arr[0], arr[1]]);
2372
+ }
2373
+ // Set operations
2374
+ /**
2375
+ * Removes duplicate elements, keeping only the first occurrence.
2376
+ *
2377
+ * @returns A new async iterflow with duplicate elements removed
2378
+ * @example
2379
+ * ```typescript
2380
+ * await asyncIter([1, 2, 2, 3, 1, 4]).distinct().toArray();
2381
+ * // [1, 2, 3, 4]
2382
+ * ```
2383
+ */
2384
+ distinct() {
2385
+ const self = this;
2386
+ return new _Asynciterflow({
2387
+ async *[Symbol.asyncIterator]() {
2388
+ const seen = /* @__PURE__ */ new Set();
2389
+ for await (const value of self) {
2390
+ if (!seen.has(value)) {
2391
+ seen.add(value);
2392
+ yield value;
2393
+ }
2394
+ }
2395
+ }
2396
+ });
2397
+ }
2398
+ /**
2399
+ * Removes duplicate elements based on a key function.
2400
+ *
2401
+ * @template K The type of the key used for comparison
2402
+ * @param keyFn - Async or sync function to extract the comparison key
2403
+ * @returns A new async iterflow with duplicate elements (by key) removed
2404
+ * @example
2405
+ * ```typescript
2406
+ * const users = [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}, {id: 1, name: 'Charlie'}];
2407
+ * await asyncIter(users).distinctBy(async u => u.id).toArray();
2408
+ * // [{id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}]
2409
+ * ```
2410
+ */
2411
+ distinctBy(keyFn) {
2412
+ const self = this;
2413
+ return new _Asynciterflow({
2414
+ async *[Symbol.asyncIterator]() {
2415
+ const seenKeys = /* @__PURE__ */ new Set();
2416
+ for await (const value of self) {
2417
+ const key = await keyFn(value);
2418
+ if (!seenKeys.has(key)) {
2419
+ seenKeys.add(key);
2420
+ yield value;
2421
+ }
2422
+ }
2423
+ }
2424
+ });
2425
+ }
2426
+ // Utility operations
2427
+ /**
2428
+ * Executes a side-effect function on each element without modifying the stream.
2429
+ *
2430
+ * @param fn - Async or sync function to execute for each element
2431
+ * @returns A new async iterflow with the same elements
2432
+ * @example
2433
+ * ```typescript
2434
+ * await asyncIter([1, 2, 3])
2435
+ * .tap(async x => console.log('Processing:', x))
2436
+ * .map(async x => x * 2)
2437
+ * .toArray(); // logs each value, returns [2, 4, 6]
2438
+ * ```
2439
+ */
2440
+ tap(fn) {
2441
+ const self = this;
2442
+ return new _Asynciterflow({
2443
+ async *[Symbol.asyncIterator]() {
2444
+ for await (const value of self) {
2445
+ await fn(value);
2446
+ yield value;
2447
+ }
2448
+ }
2449
+ });
2450
+ }
2451
+ /**
2452
+ * Takes elements while the predicate returns true, then stops.
2453
+ *
2454
+ * @param predicate - Async or sync function to test each element
2455
+ * @returns A new async iterflow with elements up to the first failing predicate
2456
+ * @example
2457
+ * ```typescript
2458
+ * await asyncIter([1, 2, 3, 4, 1, 2]).takeWhile(async x => x < 4).toArray();
2459
+ * // [1, 2, 3]
2460
+ * ```
2461
+ */
2462
+ takeWhile(predicate) {
2463
+ const self = this;
2464
+ return new _Asynciterflow({
2465
+ async *[Symbol.asyncIterator]() {
2466
+ for await (const value of self) {
2467
+ if (!await predicate(value)) break;
2468
+ yield value;
2469
+ }
2470
+ }
2471
+ });
2472
+ }
2473
+ /**
2474
+ * Skips elements while the predicate returns true, then yields all remaining.
2475
+ *
2476
+ * @param predicate - Async or sync function to test each element
2477
+ * @returns A new async iterflow starting from the first element that fails the predicate
2478
+ * @example
2479
+ * ```typescript
2480
+ * await asyncIter([1, 2, 3, 4, 1, 2]).dropWhile(async x => x < 3).toArray();
2481
+ * // [3, 4, 1, 2]
2482
+ * ```
2483
+ */
2484
+ dropWhile(predicate) {
2485
+ const self = this;
2486
+ return new _Asynciterflow({
2487
+ async *[Symbol.asyncIterator]() {
2488
+ let dropping = true;
2489
+ for await (const value of self) {
2490
+ if (dropping && await predicate(value)) {
2491
+ continue;
2492
+ }
2493
+ dropping = false;
2494
+ yield value;
2495
+ }
2496
+ }
2497
+ });
2498
+ }
2499
+ // Grouping operations (terminal)
2500
+ /**
2501
+ * Splits elements into two arrays based on a predicate.
2502
+ * This is a terminal operation that consumes the async iterator.
2503
+ *
2504
+ * @param predicate - Async or sync function to test each element
2505
+ * @returns A promise of a tuple of two arrays
2506
+ * @example
2507
+ * ```typescript
2508
+ * await asyncIter([1, 2, 3, 4, 5]).partition(async x => x % 2 === 0);
2509
+ * // [[2, 4], [1, 3, 5]]
2510
+ * ```
2511
+ */
2512
+ async partition(predicate) {
2513
+ const truthy = [];
2514
+ const falsy = [];
2515
+ for await (const value of this) {
2516
+ if (await predicate(value)) {
2517
+ truthy.push(value);
2518
+ } else {
2519
+ falsy.push(value);
2520
+ }
2521
+ }
2522
+ return [truthy, falsy];
2523
+ }
2524
+ /**
2525
+ * Groups elements by a key function into a Map.
2526
+ * This is a terminal operation that consumes the async iterator.
2527
+ *
2528
+ * @template K The type of the grouping key
2529
+ * @param keyFn - Async or sync function to extract the grouping key
2530
+ * @returns A promise of a Map where keys are the result of keyFn and values are arrays of elements
2531
+ * @example
2532
+ * ```typescript
2533
+ * await asyncIter(['alice', 'bob', 'charlie', 'dave'])
2534
+ * .groupBy(async name => name.length);
2535
+ * // Map { 3 => ['bob'], 5 => ['alice'], 7 => ['charlie'], 4 => ['dave'] }
2536
+ * ```
2537
+ */
2538
+ async groupBy(keyFn) {
2539
+ const groups = /* @__PURE__ */ new Map();
2540
+ for await (const value of this) {
2541
+ const key = await keyFn(value);
2542
+ if (!groups.has(key)) {
2543
+ groups.set(key, []);
2544
+ }
2545
+ groups.get(key).push(value);
2546
+ }
2547
+ return groups;
2548
+ }
2549
+ // Additional terminal operations
2550
+ /**
2551
+ * Reduces the async iterator to a single value using an accumulator function.
2552
+ * This is a terminal operation that consumes the async iterator.
2553
+ *
2554
+ * @template U The type of the accumulated value
2555
+ * @param fn - Async or sync function to combine the accumulator with each element
2556
+ * @param initial - The initial value for the accumulator
2557
+ * @returns A promise of the final accumulated value
2558
+ * @example
2559
+ * ```typescript
2560
+ * await asyncIter([1, 2, 3, 4]).reduce(async (acc, x) => acc + x, 0); // 10
2561
+ * ```
2562
+ */
2563
+ async reduce(fn, initial) {
2564
+ let accumulator = initial;
2565
+ for await (const value of this) {
2566
+ accumulator = await fn(accumulator, value);
2567
+ }
2568
+ return accumulator;
2569
+ }
2570
+ /**
2571
+ * Finds the first element that matches the predicate.
2572
+ * This is a terminal operation that may consume part of the async iterator.
2573
+ *
2574
+ * @param predicate - Async or sync function to test each element
2575
+ * @returns A promise of the first matching element, or undefined if none found
2576
+ * @example
2577
+ * ```typescript
2578
+ * await asyncIter([1, 2, 3, 4, 5]).find(async x => x > 3); // 4
2579
+ * ```
2580
+ */
2581
+ async find(predicate) {
2582
+ for await (const value of this) {
2583
+ if (await predicate(value)) {
2584
+ return value;
2585
+ }
2586
+ }
2587
+ return void 0;
2588
+ }
2589
+ /**
2590
+ * Finds the index of the first element that matches the predicate.
2591
+ * This is a terminal operation that may consume part of the async iterator.
2592
+ *
2593
+ * @param predicate - Async or sync function to test each element
2594
+ * @returns A promise of the index of the first matching element, or -1 if none found
2595
+ * @example
2596
+ * ```typescript
2597
+ * await asyncIter([1, 2, 3, 4, 5]).findIndex(async x => x > 3); // 3
2598
+ * ```
2599
+ */
2600
+ async findIndex(predicate) {
2601
+ let index = 0;
2602
+ for await (const value of this) {
2603
+ if (await predicate(value)) {
2604
+ return index;
2605
+ }
2606
+ index++;
2607
+ }
2608
+ return -1;
2609
+ }
2610
+ /**
2611
+ * Tests whether at least one element matches the predicate.
2612
+ * This is a terminal operation that may consume part of the async iterator.
2613
+ *
2614
+ * @param predicate - Async or sync function to test each element
2615
+ * @returns A promise of true if any element matches, false otherwise
2616
+ * @example
2617
+ * ```typescript
2618
+ * await asyncIter([1, 2, 3, 4, 5]).some(async x => x > 3); // true
2619
+ * ```
2620
+ */
2621
+ async some(predicate) {
2622
+ for await (const value of this) {
2623
+ if (await predicate(value)) {
2624
+ return true;
2625
+ }
2626
+ }
2627
+ return false;
2628
+ }
2629
+ /**
2630
+ * Tests whether all elements match the predicate.
2631
+ * This is a terminal operation that may consume part or all of the async iterator.
2632
+ *
2633
+ * @param predicate - Async or sync function to test each element
2634
+ * @returns A promise of true if all elements match, false otherwise
2635
+ * @example
2636
+ * ```typescript
2637
+ * await asyncIter([2, 4, 6]).every(async x => x % 2 === 0); // true
2638
+ * ```
2639
+ */
2640
+ async every(predicate) {
2641
+ for await (const value of this) {
2642
+ if (!await predicate(value)) {
2643
+ return false;
2644
+ }
2645
+ }
2646
+ return true;
2647
+ }
2648
+ /**
2649
+ * Gets the first element from the async iterator.
2650
+ * This is a terminal operation that consumes the first element.
2651
+ *
2652
+ * @param defaultValue - Optional default value to return if iterator is empty
2653
+ * @returns A promise of the first element, the default value, or undefined if empty and no default
2654
+ * @example
2655
+ * ```typescript
2656
+ * await asyncIter([1, 2, 3]).first(); // 1
2657
+ * ```
2658
+ */
2659
+ async first(defaultValue) {
2660
+ const result = await this.source.next();
2661
+ return result.done ? defaultValue : result.value;
2662
+ }
2663
+ /**
2664
+ * Gets the last element from the async iterator.
2665
+ * This is a terminal operation that consumes the entire async iterator.
2666
+ *
2667
+ * @param defaultValue - Optional default value to return if iterator is empty
2668
+ * @returns A promise of the last element, the default value, or undefined if empty and no default
2669
+ * @example
2670
+ * ```typescript
2671
+ * await asyncIter([1, 2, 3]).last(); // 3
2672
+ * ```
2673
+ */
2674
+ async last(defaultValue) {
2675
+ let lastValue = defaultValue;
2676
+ let hasValue = false;
2677
+ for await (const value of this) {
2678
+ lastValue = value;
2679
+ hasValue = true;
2680
+ }
2681
+ return hasValue ? lastValue : defaultValue;
2682
+ }
2683
+ /**
2684
+ * Gets the element at the specified index.
2685
+ * This is a terminal operation that may consume part of the async iterator.
2686
+ *
2687
+ * @param index - Zero-based index of the element to retrieve
2688
+ * @returns A promise of the element at the index, or undefined if index is out of bounds
2689
+ * @example
2690
+ * ```typescript
2691
+ * await asyncIter([1, 2, 3, 4, 5]).nth(2); // 3
2692
+ * ```
2693
+ */
2694
+ async nth(index) {
2695
+ if (index < 0) {
2696
+ return void 0;
2697
+ }
2698
+ let currentIndex = 0;
2699
+ for await (const value of this) {
2700
+ if (currentIndex === index) {
2701
+ return value;
2702
+ }
2703
+ currentIndex++;
2704
+ }
2705
+ return void 0;
2706
+ }
2707
+ /**
2708
+ * Checks if the async iterator is empty.
2709
+ * This is a terminal operation that may consume the first element.
2710
+ *
2711
+ * @returns A promise of true if the iterator has no elements, false otherwise
2712
+ * @example
2713
+ * ```typescript
2714
+ * await asyncIter([]).isEmpty(); // true
2715
+ * ```
2716
+ */
2717
+ async isEmpty() {
2718
+ const result = await this.source.next();
2719
+ return result.done === true;
2720
+ }
2721
+ /**
2722
+ * Checks if the async iterator includes a specific value.
2723
+ * This is a terminal operation that may consume part or all of the async iterator.
2724
+ *
2725
+ * @param searchValue - The value to search for
2726
+ * @returns A promise of true if the value is found, false otherwise
2727
+ * @example
2728
+ * ```typescript
2729
+ * await asyncIter([1, 2, 3, 4, 5]).includes(3); // true
2730
+ * ```
2731
+ */
2732
+ async includes(searchValue) {
2733
+ for await (const value of this) {
2734
+ if (value === searchValue) {
2735
+ return true;
2736
+ }
2737
+ }
2738
+ return false;
2739
+ }
2740
+ // Concurrent/Parallel processing operations
2741
+ /**
2742
+ * Maps elements in parallel with a concurrency limit.
2743
+ * Processes multiple elements simultaneously while respecting the concurrency limit.
2744
+ *
2745
+ * @template U The type of the transformed elements
2746
+ * @param fn - Async function to transform each element
2747
+ * @param concurrency - Maximum number of concurrent operations (default: 10)
2748
+ * @returns A new async iterflow with transformed elements
2749
+ * @example
2750
+ * ```typescript
2751
+ * await asyncIter([1, 2, 3, 4, 5])
2752
+ * .mapParallel(async x => {
2753
+ * await sleep(100);
2754
+ * return x * 2;
2755
+ * }, 3)
2756
+ * .toArray(); // Processes 3 items at a time
2757
+ * ```
2758
+ */
2759
+ mapParallel(fn, concurrency = 10) {
2760
+ const self = this;
2761
+ return new _Asynciterflow({
2762
+ async *[Symbol.asyncIterator]() {
2763
+ const promises = [];
2764
+ const results = /* @__PURE__ */ new Map();
2765
+ let nextIndex = 0;
2766
+ let completedIndex = 0;
2767
+ for await (const value of self) {
2768
+ const currentIndex = nextIndex++;
2769
+ const promise = fn(value).then((result) => ({
2770
+ index: currentIndex,
2771
+ value: result
2772
+ }));
2773
+ promises.push(promise);
2774
+ if (promises.length >= concurrency) {
2775
+ const completed = await Promise.race(promises);
2776
+ results.set(completed.index, completed.value);
2777
+ promises.splice(
2778
+ promises.findIndex(
2779
+ (p) => p.then((r) => r.index === completed.index)
2780
+ ),
2781
+ 1
2782
+ );
2783
+ while (results.has(completedIndex)) {
2784
+ yield results.get(completedIndex);
2785
+ results.delete(completedIndex);
2786
+ completedIndex++;
2787
+ }
2788
+ }
2789
+ }
2790
+ while (promises.length > 0) {
2791
+ const completed = await Promise.race(promises);
2792
+ results.set(completed.index, completed.value);
2793
+ promises.splice(
2794
+ promises.findIndex(
2795
+ (p) => p.then((r) => r.index === completed.index)
2796
+ ),
2797
+ 1
2798
+ );
2799
+ while (results.has(completedIndex)) {
2800
+ yield results.get(completedIndex);
2801
+ results.delete(completedIndex);
2802
+ completedIndex++;
2803
+ }
2804
+ }
2805
+ }
2806
+ });
2807
+ }
2808
+ /**
2809
+ * Filters elements in parallel with a concurrency limit.
2810
+ *
2811
+ * @param predicate - Async function to test each element
2812
+ * @param concurrency - Maximum number of concurrent operations (default: 10)
2813
+ * @returns A new async iterflow with only elements that pass the predicate
2814
+ * @example
2815
+ * ```typescript
2816
+ * await asyncIter([1, 2, 3, 4, 5])
2817
+ * .filterParallel(async x => {
2818
+ * await sleep(100);
2819
+ * return x % 2 === 0;
2820
+ * }, 3)
2821
+ * .toArray(); // [2, 4]
2822
+ * ```
2823
+ */
2824
+ filterParallel(predicate, concurrency = 10) {
2825
+ const self = this;
2826
+ return new _Asynciterflow({
2827
+ async *[Symbol.asyncIterator]() {
2828
+ const promises = [];
2829
+ const results = /* @__PURE__ */ new Map();
2830
+ let nextIndex = 0;
2831
+ let completedIndex = 0;
2832
+ for await (const value of self) {
2833
+ const currentIndex = nextIndex++;
2834
+ const promise = predicate(value).then((keep) => ({
2835
+ index: currentIndex,
2836
+ value,
2837
+ keep
2838
+ }));
2839
+ promises.push(promise);
2840
+ if (promises.length >= concurrency) {
2841
+ const completed = await Promise.race(promises);
2842
+ results.set(completed.index, {
2843
+ value: completed.value,
2844
+ keep: completed.keep
2845
+ });
2846
+ promises.splice(
2847
+ promises.findIndex(
2848
+ (p) => p.then((r) => r.index === completed.index)
2849
+ ),
2850
+ 1
2851
+ );
2852
+ while (results.has(completedIndex)) {
2853
+ const result = results.get(completedIndex);
2854
+ if (result.keep) {
2855
+ yield result.value;
2856
+ }
2857
+ results.delete(completedIndex);
2858
+ completedIndex++;
2859
+ }
2860
+ }
2861
+ }
2862
+ while (promises.length > 0) {
2863
+ const completed = await Promise.race(promises);
2864
+ results.set(completed.index, {
2865
+ value: completed.value,
2866
+ keep: completed.keep
2867
+ });
2868
+ promises.splice(
2869
+ promises.findIndex(
2870
+ (p) => p.then((r) => r.index === completed.index)
2871
+ ),
2872
+ 1
2873
+ );
2874
+ while (results.has(completedIndex)) {
2875
+ const result = results.get(completedIndex);
2876
+ if (result.keep) {
2877
+ yield result.value;
2878
+ }
2879
+ results.delete(completedIndex);
2880
+ completedIndex++;
2881
+ }
2882
+ }
2883
+ }
2884
+ });
2885
+ }
2886
+ /**
2887
+ * FlatMaps elements in parallel with a concurrency limit.
2888
+ *
2889
+ * @template U The type of elements in the resulting iterator
2890
+ * @param fn - Async function that maps each element to an async iterable
2891
+ * @param concurrency - Maximum number of concurrent operations (default: 10)
2892
+ * @returns A new async iterflow with all mapped iterables flattened
2893
+ * @example
2894
+ * ```typescript
2895
+ * await asyncIter([1, 2, 3])
2896
+ * .flatMapParallel(async x => [x, x * 2], 2)
2897
+ * .toArray(); // [1, 2, 2, 4, 3, 6]
2898
+ * ```
2899
+ */
2900
+ flatMapParallel(fn, concurrency = 10) {
2901
+ const self = this;
2902
+ return new _Asynciterflow({
2903
+ async *[Symbol.asyncIterator]() {
2904
+ const promises = [];
2905
+ const results = /* @__PURE__ */ new Map();
2906
+ let nextIndex = 0;
2907
+ let completedIndex = 0;
2908
+ for await (const value of self) {
2909
+ const currentIndex = nextIndex++;
2910
+ const promise = fn(value).then((values) => ({
2911
+ index: currentIndex,
2912
+ values
2913
+ }));
2914
+ promises.push(promise);
2915
+ if (promises.length >= concurrency) {
2916
+ const completed = await Promise.race(promises);
2917
+ results.set(completed.index, completed.values);
2918
+ promises.splice(
2919
+ promises.findIndex(
2920
+ (p) => p.then((r) => r.index === completed.index)
2921
+ ),
2922
+ 1
2923
+ );
2924
+ while (results.has(completedIndex)) {
2925
+ const result = results.get(completedIndex);
2926
+ if (Symbol.asyncIterator in result) {
2927
+ yield* result;
2928
+ } else {
2929
+ yield* result;
2930
+ }
2931
+ results.delete(completedIndex);
2932
+ completedIndex++;
2933
+ }
2934
+ }
2935
+ }
2936
+ while (promises.length > 0) {
2937
+ const completed = await Promise.race(promises);
2938
+ results.set(completed.index, completed.values);
2939
+ promises.splice(
2940
+ promises.findIndex(
2941
+ (p) => p.then((r) => r.index === completed.index)
2942
+ ),
2943
+ 1
2944
+ );
2945
+ while (results.has(completedIndex)) {
2946
+ const result = results.get(completedIndex);
2947
+ if (Symbol.asyncIterator in result) {
2948
+ yield* result;
2949
+ } else {
2950
+ yield* result;
2951
+ }
2952
+ results.delete(completedIndex);
2953
+ completedIndex++;
2954
+ }
2955
+ }
2956
+ }
2957
+ });
2958
+ }
2959
+ // Backpressure handling
2960
+ /**
2961
+ * Buffers elements up to a specified size.
2962
+ *
2963
+ * @param size - Maximum buffer size
2964
+ * @returns A new async iterflow with buffered elements
2965
+ * @example
2966
+ * ```typescript
2967
+ * await asyncIter([1, 2, 3, 4, 5]).buffer(2).toArray();
2968
+ * // [[1, 2], [3, 4], [5]]
2969
+ * ```
2970
+ */
2971
+ buffer(size) {
2972
+ return this.chunk(size);
2973
+ }
2974
+ /**
2975
+ * Throttles the stream to emit at most one value per time interval.
2976
+ *
2977
+ * @param intervalMs - Minimum time between emissions in milliseconds
2978
+ * @returns A new async iterflow with throttled elements
2979
+ * @example
2980
+ * ```typescript
2981
+ * await asyncIter([1, 2, 3, 4, 5]).throttle(100).toArray();
2982
+ * // Emits one value every 100ms
2983
+ * ```
2984
+ */
2985
+ throttle(intervalMs) {
2986
+ const self = this;
2987
+ return new _Asynciterflow({
2988
+ async *[Symbol.asyncIterator]() {
2989
+ let lastEmitTime = 0;
2990
+ for await (const value of self) {
2991
+ const now = Date.now();
2992
+ if (now - lastEmitTime >= intervalMs) {
2993
+ lastEmitTime = now;
2994
+ yield value;
2995
+ } else {
2996
+ const delay = intervalMs - (now - lastEmitTime);
2997
+ await new Promise((resolve) => setTimeout(resolve, delay));
2998
+ lastEmitTime = Date.now();
2999
+ yield value;
3000
+ }
3001
+ }
3002
+ }
3003
+ });
3004
+ }
3005
+ /**
3006
+ * Debounces the stream, only emitting values after a period of silence.
3007
+ *
3008
+ * @param waitMs - Time to wait for silence in milliseconds
3009
+ * @returns A new async iterflow with debounced elements
3010
+ * @example
3011
+ * ```typescript
3012
+ * await asyncIter([1, 2, 3, 4, 5]).debounce(100).toArray();
3013
+ * // Only emits values after 100ms of no new values
3014
+ * ```
3015
+ */
3016
+ debounce(waitMs) {
3017
+ const self = this;
3018
+ return new _Asynciterflow({
3019
+ async *[Symbol.asyncIterator]() {
3020
+ const buffer = [];
3021
+ let lastValue;
3022
+ let hasValue = false;
3023
+ for await (const value of self) {
3024
+ hasValue = true;
3025
+ lastValue = value;
3026
+ buffer.push(value);
3027
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
3028
+ if (lastValue === value && buffer[buffer.length - 1] === value) {
3029
+ yield value;
3030
+ buffer.length = 0;
3031
+ }
3032
+ }
3033
+ if (hasValue && buffer.length > 0 && lastValue !== void 0) {
3034
+ yield lastValue;
3035
+ }
3036
+ }
3037
+ });
3038
+ }
3039
+ // Error handling
3040
+ /**
3041
+ * Catches errors and continues with a fallback value or stream.
3042
+ *
3043
+ * @param handler - Function to handle errors and return a fallback value or async iterable
3044
+ * @returns A new async iterflow with error handling
3045
+ * @example
3046
+ * ```typescript
3047
+ * await asyncIter([1, 2, 3])
3048
+ * .map(async x => {
3049
+ * if (x === 2) throw new Error('Error!');
3050
+ * return x;
3051
+ * })
3052
+ * .catchError(async (error) => [-1])
3053
+ * .toArray(); // [1, -1, 3]
3054
+ * ```
3055
+ */
3056
+ catchError(handler) {
3057
+ const self = this;
3058
+ return new _Asynciterflow({
3059
+ async *[Symbol.asyncIterator]() {
3060
+ try {
3061
+ for await (const value of self) {
3062
+ yield value;
3063
+ }
3064
+ } catch (error) {
3065
+ const fallback = await handler(error);
3066
+ if (typeof fallback === "object" && fallback !== null && (Symbol.asyncIterator in fallback || Symbol.iterator in fallback)) {
3067
+ if (Symbol.asyncIterator in fallback) {
3068
+ yield* fallback;
3069
+ } else {
3070
+ yield* fallback;
3071
+ }
3072
+ } else {
3073
+ yield fallback;
3074
+ }
3075
+ }
3076
+ }
3077
+ });
3078
+ }
3079
+ /**
3080
+ * Retries failed operations a specified number of times.
3081
+ *
3082
+ * @param maxRetries - Maximum number of retry attempts
3083
+ * @param delayMs - Optional delay between retries in milliseconds
3084
+ * @returns A new async iterflow with retry logic
3085
+ * @example
3086
+ * ```typescript
3087
+ * await asyncIter([1, 2, 3])
3088
+ * .map(async x => {
3089
+ * if (Math.random() > 0.5) throw new Error('Random error');
3090
+ * return x;
3091
+ * })
3092
+ * .retry(3, 100)
3093
+ * .toArray(); // Retries up to 3 times with 100ms delay
3094
+ * ```
3095
+ */
3096
+ retry(maxRetries, delayMs = 0) {
3097
+ const self = this;
3098
+ return new _Asynciterflow({
3099
+ async *[Symbol.asyncIterator]() {
3100
+ const iterator = self[Symbol.asyncIterator]();
3101
+ let retryCount = 0;
3102
+ while (true) {
3103
+ try {
3104
+ const result = await iterator.next();
3105
+ if (result.done) break;
3106
+ yield result.value;
3107
+ retryCount = 0;
3108
+ } catch (error) {
3109
+ if (retryCount < maxRetries) {
3110
+ retryCount++;
3111
+ if (delayMs > 0) {
3112
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
3113
+ }
3114
+ } else {
3115
+ throw error;
3116
+ }
3117
+ }
3118
+ }
3119
+ }
3120
+ });
3121
+ }
3122
+ /**
3123
+ * Handles errors for each element individually.
3124
+ *
3125
+ * @param handler - Async or sync function to handle errors for each element
3126
+ * @returns A new async iterflow with error handling
3127
+ * @example
3128
+ * ```typescript
3129
+ * await asyncIter([1, 2, 3])
3130
+ * .map(async x => {
3131
+ * if (x === 2) throw new Error('Error!');
3132
+ * return x;
3133
+ * })
3134
+ * .onError(async (error, value) => console.error('Error:', error))
3135
+ * .toArray(); // [1, 3] (2 is skipped)
3136
+ * ```
3137
+ */
3138
+ onError(handler) {
3139
+ const self = this;
3140
+ return new _Asynciterflow({
3141
+ async *[Symbol.asyncIterator]() {
3142
+ for await (const value of self) {
3143
+ try {
3144
+ yield value;
3145
+ } catch (error) {
3146
+ await handler(error, value);
3147
+ }
3148
+ }
3149
+ }
3150
+ });
3151
+ }
3152
+ };
3153
+ function asyncIter(source) {
3154
+ if (Symbol.asyncIterator in source) {
3155
+ return new Asynciterflow(source);
3156
+ }
3157
+ return new Asynciterflow({
3158
+ async *[Symbol.asyncIterator]() {
3159
+ yield* source;
3160
+ }
3161
+ });
3162
+ }
3163
+ ((asyncIter2) => {
3164
+ function zip(iter1, iter2) {
3165
+ return new Asynciterflow({
3166
+ async *[Symbol.asyncIterator]() {
3167
+ const it1 = Symbol.asyncIterator in iter1 ? iter1[Symbol.asyncIterator]() : (async function* () {
3168
+ yield* iter1;
3169
+ })();
3170
+ const it2 = Symbol.asyncIterator in iter2 ? iter2[Symbol.asyncIterator]() : (async function* () {
3171
+ yield* iter2;
3172
+ })();
3173
+ while (true) {
3174
+ const result1 = await it1.next();
3175
+ const result2 = await it2.next();
3176
+ if (result1.done || result2.done) {
3177
+ break;
3178
+ }
3179
+ yield [result1.value, result2.value];
3180
+ }
3181
+ }
3182
+ });
3183
+ }
3184
+ asyncIter2.zip = zip;
3185
+ function zipWith(iter1, iter2, fn) {
3186
+ return zip(iter1, iter2).map(async ([a, b]) => await fn(a, b));
3187
+ }
3188
+ asyncIter2.zipWith = zipWith;
3189
+ function range(startOrStop, stop, step = 1) {
3190
+ const actualStart = stop === void 0 ? 0 : startOrStop;
3191
+ const actualStop = stop === void 0 ? startOrStop : stop;
3192
+ return new Asynciterflow({
3193
+ async *[Symbol.asyncIterator]() {
3194
+ if (step === 0) {
3195
+ validateNonZero(step, "step", "range");
3196
+ }
3197
+ if (step > 0) {
3198
+ for (let i = actualStart; i < actualStop; i += step) {
3199
+ yield i;
3200
+ }
3201
+ } else {
3202
+ for (let i = actualStart; i > actualStop; i += step) {
3203
+ yield i;
3204
+ }
3205
+ }
3206
+ }
3207
+ });
3208
+ }
3209
+ asyncIter2.range = range;
3210
+ function repeat(value, times) {
3211
+ return new Asynciterflow({
3212
+ async *[Symbol.asyncIterator]() {
3213
+ if (times === void 0) {
3214
+ while (true) {
3215
+ yield value;
3216
+ }
3217
+ } else {
3218
+ for (let i = 0; i < times; i++) {
3219
+ yield value;
3220
+ }
3221
+ }
3222
+ }
3223
+ });
3224
+ }
3225
+ asyncIter2.repeat = repeat;
3226
+ function interleave(...iterables) {
3227
+ return new Asynciterflow({
3228
+ async *[Symbol.asyncIterator]() {
3229
+ if (iterables.length === 0) return;
3230
+ const iterators = iterables.map(
3231
+ (it) => Symbol.asyncIterator in it ? it[Symbol.asyncIterator]() : (async function* () {
3232
+ yield* it;
3233
+ })()
3234
+ );
3235
+ const active = new Set(iterators);
3236
+ while (active.size > 0) {
3237
+ for (const iterator of iterators) {
3238
+ if (!active.has(iterator)) continue;
3239
+ const result = await iterator.next();
3240
+ if (result.done) {
3241
+ active.delete(iterator);
3242
+ } else {
3243
+ yield result.value;
3244
+ }
3245
+ }
3246
+ }
3247
+ }
3248
+ });
3249
+ }
3250
+ asyncIter2.interleave = interleave;
3251
+ function merge(...args) {
3252
+ let compareFn;
3253
+ let iterables;
3254
+ if (typeof args[0] === "function") {
3255
+ compareFn = args[0];
3256
+ iterables = args.slice(1);
3257
+ } else {
3258
+ compareFn = (a, b) => {
3259
+ if (a < b) return -1;
3260
+ if (a > b) return 1;
3261
+ return 0;
3262
+ };
3263
+ iterables = args;
3264
+ }
3265
+ return new Asynciterflow({
3266
+ async *[Symbol.asyncIterator]() {
3267
+ if (iterables.length === 0) return;
3268
+ const heap = [];
3269
+ for (let i = 0; i < iterables.length; i++) {
3270
+ const iterable = iterables[i];
3271
+ const iterator = Symbol.asyncIterator in iterable ? iterable[Symbol.asyncIterator]() : (async function* () {
3272
+ yield* iterable;
3273
+ })();
3274
+ const result = await iterator.next();
3275
+ if (!result.done) {
3276
+ heap.push({ value: result.value, iterator, index: i });
3277
+ }
3278
+ }
3279
+ const bubbleDown = (index) => {
3280
+ const length = heap.length;
3281
+ while (true) {
3282
+ let smallest = index;
3283
+ const leftChild = 2 * index + 1;
3284
+ const rightChild = 2 * index + 2;
3285
+ if (leftChild < length && compareFn(heap[leftChild].value, heap[smallest].value) < 0) {
3286
+ smallest = leftChild;
3287
+ }
3288
+ if (rightChild < length && compareFn(heap[rightChild].value, heap[smallest].value) < 0) {
3289
+ smallest = rightChild;
3290
+ }
3291
+ if (smallest === index) break;
3292
+ [heap[index], heap[smallest]] = [heap[smallest], heap[index]];
3293
+ index = smallest;
3294
+ }
3295
+ };
3296
+ for (let i = Math.floor(heap.length / 2) - 1; i >= 0; i--) {
3297
+ bubbleDown(i);
3298
+ }
3299
+ while (heap.length > 0) {
3300
+ const { value, iterator } = heap[0];
3301
+ yield value;
3302
+ const result = await iterator.next();
3303
+ if (result.done) {
3304
+ heap[0] = heap[heap.length - 1];
3305
+ heap.pop();
3306
+ if (heap.length > 0) {
3307
+ bubbleDown(0);
3308
+ }
3309
+ } else {
3310
+ heap[0].value = result.value;
3311
+ bubbleDown(0);
3312
+ }
3313
+ }
3314
+ }
3315
+ });
3316
+ }
3317
+ asyncIter2.merge = merge;
3318
+ function chain(...iterables) {
3319
+ return new Asynciterflow({
3320
+ async *[Symbol.asyncIterator]() {
3321
+ for (const iterable of iterables) {
3322
+ if (Symbol.asyncIterator in iterable) {
3323
+ yield* iterable;
3324
+ } else {
3325
+ yield* iterable;
3326
+ }
3327
+ }
3328
+ }
3329
+ });
3330
+ }
3331
+ asyncIter2.chain = chain;
3332
+ function fromGenerator(fn) {
3333
+ return new Asynciterflow(fn());
3334
+ }
3335
+ asyncIter2.fromGenerator = fromGenerator;
3336
+ function fromPromise(promise) {
3337
+ return new Asynciterflow({
3338
+ async *[Symbol.asyncIterator]() {
3339
+ yield await promise;
3340
+ }
3341
+ });
3342
+ }
3343
+ asyncIter2.fromPromise = fromPromise;
3344
+ function fromPromises(promises) {
3345
+ return new Asynciterflow({
3346
+ async *[Symbol.asyncIterator]() {
3347
+ const pending = new Set(promises);
3348
+ const results = /* @__PURE__ */ new Map();
3349
+ const indexed = promises.map((p, i) => p.then((v) => ({ i, v })));
3350
+ while (pending.size > 0) {
3351
+ const result = await Promise.race(indexed);
3352
+ results.set(result.i, result.v);
3353
+ pending.delete(promises[result.i]);
3354
+ let nextIndex = promises.length - pending.size - 1;
3355
+ while (results.has(nextIndex)) {
3356
+ yield results.get(nextIndex);
3357
+ results.delete(nextIndex);
3358
+ nextIndex++;
3359
+ }
3360
+ }
3361
+ }
3362
+ });
3363
+ }
3364
+ asyncIter2.fromPromises = fromPromises;
3365
+ })(asyncIter || (asyncIter = {}));
3366
+
3367
+ // src/debug.ts
3368
+ var DebugState = class {
3369
+ config = {
3370
+ enabled: false,
3371
+ traceOperations: false,
3372
+ traceInput: false,
3373
+ traceOutput: false,
3374
+ logToConsole: false,
3375
+ maxTraceEntries: 1e3
3376
+ };
3377
+ traces = [];
3378
+ /**
3379
+ * Enable debug mode with optional configuration
3380
+ */
3381
+ enable(config2) {
3382
+ this.config = {
3383
+ ...this.config,
3384
+ enabled: true,
3385
+ traceOperations: true,
3386
+ ...config2
3387
+ };
3388
+ if (this.config.logToConsole) {
3389
+ console.log("[iterflow Debug] Debug mode enabled", this.config);
3390
+ }
3391
+ }
3392
+ /**
3393
+ * Disable debug mode
3394
+ */
3395
+ disable() {
3396
+ this.config.enabled = false;
3397
+ this.config.traceOperations = false;
3398
+ if (this.config.logToConsole) {
3399
+ console.log("[iterflow Debug] Debug mode disabled");
3400
+ }
3401
+ }
3402
+ /**
3403
+ * Check if debug mode is enabled
3404
+ */
3405
+ isEnabled() {
3406
+ return this.config.enabled;
3407
+ }
3408
+ /**
3409
+ * Get current configuration
3410
+ */
3411
+ getConfig() {
3412
+ return { ...this.config };
3413
+ }
3414
+ /**
3415
+ * Add a trace entry
3416
+ */
3417
+ trace(entry) {
3418
+ if (!this.config.traceOperations) {
3419
+ return;
3420
+ }
3421
+ if (this.traces.length >= (this.config.maxTraceEntries || 1e3)) {
3422
+ this.traces.shift();
3423
+ }
3424
+ this.traces.push(entry);
3425
+ if (this.config.logToConsole) {
3426
+ this.logTrace(entry);
3427
+ }
3428
+ }
3429
+ /**
3430
+ * Get all trace entries
3431
+ */
3432
+ getTraces() {
3433
+ return [...this.traces];
3434
+ }
3435
+ /**
3436
+ * Clear all traces
3437
+ */
3438
+ clearTraces() {
3439
+ this.traces = [];
3440
+ if (this.config.logToConsole) {
3441
+ console.log("[iterflow Debug] Traces cleared");
3442
+ }
3443
+ }
3444
+ /**
3445
+ * Get traces for a specific operation
3446
+ */
3447
+ getTracesForOperation(operation) {
3448
+ return this.traces.filter((t) => t.operation === operation);
3449
+ }
3450
+ /**
3451
+ * Get summary statistics for traces
3452
+ */
3453
+ getTraceSummary() {
3454
+ const summary = {};
3455
+ for (const trace of this.traces) {
3456
+ if (!summary[trace.operation]) {
3457
+ summary[trace.operation] = { count: 0, totalDuration: 0, errors: 0 };
3458
+ }
3459
+ const operationSummary = summary[trace.operation];
3460
+ operationSummary.count++;
3461
+ if (trace.duration !== void 0) {
3462
+ operationSummary.totalDuration += trace.duration;
3463
+ }
3464
+ if (trace.error) {
3465
+ operationSummary.errors++;
3466
+ }
3467
+ }
3468
+ const result = {};
3469
+ for (const [op, stats] of Object.entries(summary)) {
3470
+ result[op] = {
3471
+ count: stats.count,
3472
+ avgDuration: stats.count > 0 ? stats.totalDuration / stats.count : 0,
3473
+ errors: stats.errors
3474
+ };
3475
+ }
3476
+ return result;
3477
+ }
3478
+ /**
3479
+ * Log a trace entry to console
3480
+ */
3481
+ logTrace(entry) {
3482
+ const timestamp = new Date(entry.timestamp).toISOString();
3483
+ const duration = entry.duration !== void 0 ? `${entry.duration.toFixed(2)}ms` : "N/A";
3484
+ if (entry.error) {
3485
+ console.error(
3486
+ `[iterflow Debug] ${timestamp} | ${entry.operation} | ERROR | ${duration}`,
3487
+ entry.error
3488
+ );
3489
+ } else {
3490
+ console.log(
3491
+ `[iterflow Debug] ${timestamp} | ${entry.operation} | ${duration}`
3492
+ );
3493
+ if (this.config.traceInput && entry.input !== void 0) {
3494
+ console.log(" Input:", entry.input);
3495
+ }
3496
+ if (this.config.traceOutput && entry.output !== void 0) {
3497
+ console.log(" Output:", entry.output);
3498
+ }
3499
+ if (entry.metadata) {
3500
+ console.log(" Metadata:", entry.metadata);
3501
+ }
3502
+ }
3503
+ }
3504
+ };
3505
+ var debugState = new DebugState();
3506
+ function enableDebug(config2) {
3507
+ debugState.enable(config2);
3508
+ }
3509
+ function disableDebug() {
3510
+ debugState.disable();
3511
+ }
3512
+ function isDebugEnabled() {
3513
+ return debugState.isEnabled();
3514
+ }
3515
+ function getDebugConfig() {
3516
+ return debugState.getConfig();
3517
+ }
3518
+ function addTrace(entry) {
3519
+ debugState.trace(entry);
3520
+ }
3521
+ function getTraces() {
3522
+ return debugState.getTraces();
3523
+ }
3524
+ function clearTraces() {
3525
+ debugState.clearTraces();
3526
+ }
3527
+ function getTracesForOperation(operation) {
3528
+ return debugState.getTracesForOperation(operation);
3529
+ }
3530
+ function getTraceSummary() {
3531
+ return debugState.getTraceSummary();
3532
+ }
3533
+ function traceOperation(operation, fn, metadata) {
3534
+ if (!debugState.isEnabled()) {
3535
+ return fn();
3536
+ }
3537
+ const startTime = performance.now();
3538
+ const timestamp = Date.now();
3539
+ try {
3540
+ const result = fn();
3541
+ const duration = performance.now() - startTime;
3542
+ debugState.trace({
3543
+ operation,
3544
+ timestamp,
3545
+ duration,
3546
+ output: debugState.getConfig().traceOutput ? result : void 0,
3547
+ metadata
3548
+ });
3549
+ return result;
3550
+ } catch (error) {
3551
+ const duration = performance.now() - startTime;
3552
+ debugState.trace({
3553
+ operation,
3554
+ timestamp,
3555
+ duration,
3556
+ error,
3557
+ metadata
3558
+ });
3559
+ throw error;
3560
+ }
3561
+ }
3562
+ async function traceOperationAsync(operation, fn, metadata) {
3563
+ if (!debugState.isEnabled()) {
3564
+ return fn();
3565
+ }
3566
+ const startTime = performance.now();
3567
+ const timestamp = Date.now();
3568
+ try {
3569
+ const result = await fn();
3570
+ const duration = performance.now() - startTime;
3571
+ debugState.trace({
3572
+ operation,
3573
+ timestamp,
3574
+ duration,
3575
+ output: debugState.getConfig().traceOutput ? result : void 0,
3576
+ metadata
3577
+ });
3578
+ return result;
3579
+ } catch (error) {
3580
+ const duration = performance.now() - startTime;
3581
+ debugState.trace({
3582
+ operation,
3583
+ timestamp,
3584
+ duration,
3585
+ error,
3586
+ metadata
3587
+ });
3588
+ throw error;
3589
+ }
3590
+ }
3591
+
3592
+ // src/recovery.ts
3593
+ function withErrorRecovery(fn, errorHandler) {
3594
+ return (value, index) => {
3595
+ try {
3596
+ return fn(value, index);
3597
+ } catch (error) {
3598
+ return errorHandler(error, value, index);
3599
+ }
3600
+ };
3601
+ }
3602
+ function withRetry(fn, options = {}) {
3603
+ const { maxAttempts = 3, delay = 0, backoff = false, onRetry } = options;
3604
+ return (...args) => {
3605
+ let lastError;
3606
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3607
+ try {
3608
+ return fn(...args);
3609
+ } catch (error) {
3610
+ lastError = error;
3611
+ if (attempt < maxAttempts) {
3612
+ if (onRetry) {
3613
+ onRetry(attempt, lastError);
3614
+ }
3615
+ }
3616
+ }
3617
+ }
3618
+ throw new OperationError(
3619
+ `Operation failed after ${maxAttempts} attempts`,
3620
+ "retry",
3621
+ lastError
3622
+ );
3623
+ };
3624
+ }
3625
+ function withRetryAsync(fn, options = {}) {
3626
+ const { maxAttempts = 3, delay = 0, backoff = false, onRetry } = options;
3627
+ return async (...args) => {
3628
+ let lastError;
3629
+ let currentDelay = delay;
3630
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
3631
+ try {
3632
+ return await fn(...args);
3633
+ } catch (error) {
3634
+ lastError = error;
3635
+ if (attempt < maxAttempts) {
3636
+ if (onRetry) {
3637
+ onRetry(attempt, lastError);
3638
+ }
3639
+ if (currentDelay > 0) {
3640
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
3641
+ }
3642
+ if (backoff) {
3643
+ currentDelay *= 2;
3644
+ }
3645
+ }
3646
+ }
3647
+ }
3648
+ throw new OperationError(
3649
+ `Operation failed after ${maxAttempts} attempts`,
3650
+ "retry",
3651
+ lastError
3652
+ );
3653
+ };
3654
+ }
3655
+ function withDefault(fn, defaultValue) {
3656
+ return (value) => {
3657
+ try {
3658
+ return fn(value);
3659
+ } catch {
3660
+ return defaultValue;
3661
+ }
3662
+ };
3663
+ }
3664
+ function tryOr(fn, fallback) {
3665
+ return (value) => {
3666
+ try {
3667
+ return fn(value);
3668
+ } catch {
3669
+ return fallback;
3670
+ }
3671
+ };
3672
+ }
3673
+ function tryCatch(fn, value) {
3674
+ try {
3675
+ return [fn(value), void 0];
3676
+ } catch (error) {
3677
+ return [void 0, error];
3678
+ }
3679
+ }
3680
+ async function tryCatchAsync(fn, value) {
3681
+ try {
3682
+ return [await fn(value), void 0];
3683
+ } catch (error) {
3684
+ return [void 0, error];
3685
+ }
3686
+ }
3687
+ function toResult(fn) {
3688
+ return (value) => {
3689
+ try {
3690
+ return { success: true, value: fn(value) };
3691
+ } catch (error) {
3692
+ return { success: false, error };
3693
+ }
3694
+ };
3695
+ }
3696
+ function toResultAsync(fn) {
3697
+ return async (value) => {
3698
+ try {
3699
+ return { success: true, value: await fn(value) };
3700
+ } catch (error) {
3701
+ return { success: false, error };
3702
+ }
3703
+ };
3704
+ }
3705
+ function safePredicate(predicate, defaultValue = false) {
3706
+ return (value, index) => {
3707
+ try {
3708
+ return predicate(value, index);
3709
+ } catch {
3710
+ return defaultValue;
3711
+ }
3712
+ };
3713
+ }
3714
+ function safeComparator(comparator, defaultComparison = 0) {
3715
+ return (a, b) => {
3716
+ try {
3717
+ return comparator(a, b);
3718
+ } catch {
3719
+ return defaultComparison;
3720
+ }
3721
+ };
3722
+ }
3723
+ function errorBoundary(fn, options = {}) {
3724
+ const { onError, rethrow = true, defaultValue } = options;
3725
+ return (...args) => {
3726
+ try {
3727
+ return fn(...args);
3728
+ } catch (error) {
3729
+ if (onError) {
3730
+ onError(error, args);
3731
+ }
3732
+ if (rethrow) {
3733
+ throw error;
3734
+ }
3735
+ return defaultValue;
3736
+ }
3737
+ };
3738
+ }
3739
+
3740
+ // src/deprecation.ts
3741
+ var config = {
3742
+ enabled: typeof process !== "undefined" && process.env.NODE_ENV !== "production",
3743
+ showStackTrace: false
3744
+ };
3745
+ var warnedFeatures = /* @__PURE__ */ new Set();
3746
+ function configureDeprecation(options) {
3747
+ config = { ...config, ...options };
3748
+ }
3749
+ function getDeprecationConfig() {
3750
+ return { ...config };
3751
+ }
3752
+ function clearDeprecationWarnings() {
3753
+ warnedFeatures.clear();
3754
+ }
3755
+ function emitWarning(warning) {
3756
+ if (!config.enabled) return;
3757
+ if (warnedFeatures.has(warning.feature)) return;
3758
+ warnedFeatures.add(warning.feature);
3759
+ if (config.handler) {
3760
+ config.handler(warning);
3761
+ return;
3762
+ }
3763
+ let message = `[iterflow] DEPRECATED: ${warning.feature} has been deprecated since v${warning.since}`;
3764
+ if (warning.removeIn) {
3765
+ message += ` and will be removed in v${warning.removeIn}`;
3766
+ }
3767
+ if (warning.alternative) {
3768
+ message += `
3769
+ Please use ${warning.alternative} instead.`;
3770
+ }
3771
+ if (warning.message) {
3772
+ message += `
3773
+ ${warning.message}`;
3774
+ }
3775
+ if (typeof process !== "undefined" && process.emitWarning) {
3776
+ const options = {
3777
+ type: "DeprecationWarning",
3778
+ code: "ITERFLOW_DEPRECATION",
3779
+ detail: warning.message
3780
+ };
3781
+ process.emitWarning(message, options);
3782
+ } else {
3783
+ console.warn(message);
3784
+ }
3785
+ if (config.showStackTrace && warning.stack) {
3786
+ console.warn("Stack trace:", warning.stack);
3787
+ }
3788
+ }
3789
+ function deprecate(options) {
3790
+ const warning = {
3791
+ ...options,
3792
+ stack: config.showStackTrace ? new Error().stack : void 0
3793
+ };
3794
+ emitWarning(warning);
3795
+ }
3796
+ function deprecated(options) {
3797
+ return function(target, propertyKey, descriptor) {
3798
+ const originalMethod = descriptor.value;
3799
+ if (!originalMethod) return;
3800
+ const className = target.constructor?.name || "Object";
3801
+ const feature = `${className}.${propertyKey}`;
3802
+ descriptor.value = function(...args) {
3803
+ deprecate({ ...options, feature });
3804
+ return originalMethod.apply(this, args);
3805
+ };
3806
+ return descriptor;
3807
+ };
3808
+ }
3809
+ function deprecatedFunction(fn, options) {
3810
+ return function(...args) {
3811
+ deprecate(options);
3812
+ return fn.apply(this, args);
3813
+ };
3814
+ }
3815
+ function hasDeprecationWarning(feature) {
3816
+ return warnedFeatures.has(feature);
3817
+ }
3818
+
3819
+ // src/index.ts
3820
+ function iter(source) {
3821
+ return new iterflow(source);
3822
+ }
3823
+ ((iter2) => {
3824
+ function zip(iter1, iter22) {
3825
+ return new iterflow({
3826
+ *[Symbol.iterator]() {
3827
+ const it1 = iter1[Symbol.iterator]();
3828
+ const it2 = iter22[Symbol.iterator]();
3829
+ while (true) {
3830
+ const result1 = it1.next();
3831
+ const result2 = it2.next();
3832
+ if (result1.done || result2.done) {
3833
+ break;
3834
+ }
3835
+ yield [result1.value, result2.value];
3836
+ }
3837
+ }
3838
+ });
3839
+ }
3840
+ iter2.zip = zip;
3841
+ function zipWith(iter1, iter22, fn) {
3842
+ return zip(iter1, iter22).map(([a, b]) => fn(a, b));
3843
+ }
3844
+ iter2.zipWith = zipWith;
3845
+ function range(startOrStop, stop, step = 1) {
3846
+ const actualStart = stop === void 0 ? 0 : startOrStop;
3847
+ const actualStop = stop === void 0 ? startOrStop : stop;
3848
+ return new iterflow({
3849
+ *[Symbol.iterator]() {
3850
+ validateNonZero(step, "step", "range");
3851
+ if (step > 0) {
3852
+ for (let i = actualStart; i < actualStop; i += step) {
3853
+ yield i;
3854
+ }
3855
+ } else {
3856
+ for (let i = actualStart; i > actualStop; i += step) {
3857
+ yield i;
3858
+ }
3859
+ }
3860
+ }
3861
+ });
3862
+ }
3863
+ iter2.range = range;
3864
+ function repeat(value, times) {
3865
+ return new iterflow({
3866
+ *[Symbol.iterator]() {
3867
+ if (times === void 0) {
3868
+ while (true) {
3869
+ yield value;
3870
+ }
3871
+ } else {
3872
+ for (let i = 0; i < times; i++) {
3873
+ yield value;
3874
+ }
3875
+ }
3876
+ }
3877
+ });
3878
+ }
3879
+ iter2.repeat = repeat;
3880
+ function interleave(...iterables) {
3881
+ return new iterflow({
3882
+ *[Symbol.iterator]() {
3883
+ if (iterables.length === 0) return;
3884
+ const iterators = iterables.map((it) => it[Symbol.iterator]());
3885
+ const active = new Set(iterators);
3886
+ while (active.size > 0) {
3887
+ for (const iterator of iterators) {
3888
+ if (!active.has(iterator)) continue;
3889
+ const result = iterator.next();
3890
+ if (result.done) {
3891
+ active.delete(iterator);
3892
+ } else {
3893
+ yield result.value;
3894
+ }
3895
+ }
3896
+ }
3897
+ }
3898
+ });
3899
+ }
3900
+ iter2.interleave = interleave;
3901
+ function merge(...args) {
3902
+ let compareFn;
3903
+ let iterables;
3904
+ if (typeof args[0] === "function") {
3905
+ compareFn = args[0];
3906
+ iterables = args.slice(1);
3907
+ } else {
3908
+ compareFn = (a, b) => {
3909
+ if (a < b) return -1;
3910
+ if (a > b) return 1;
3911
+ return 0;
3912
+ };
3913
+ iterables = args;
3914
+ }
3915
+ return new iterflow({
3916
+ *[Symbol.iterator]() {
3917
+ if (iterables.length === 0) return;
3918
+ const heap = [];
3919
+ for (let i = 0; i < iterables.length; i++) {
3920
+ const iterator = iterables[i][Symbol.iterator]();
3921
+ const result = iterator.next();
3922
+ if (!result.done) {
3923
+ heap.push({ value: result.value, iterator, index: i });
3924
+ }
3925
+ }
3926
+ const bubbleDown = (index) => {
3927
+ const length = heap.length;
3928
+ while (true) {
3929
+ let smallest = index;
3930
+ const leftChild = 2 * index + 1;
3931
+ const rightChild = 2 * index + 2;
3932
+ if (leftChild < length && compareFn(heap[leftChild].value, heap[smallest].value) < 0) {
3933
+ smallest = leftChild;
3934
+ }
3935
+ if (rightChild < length && compareFn(heap[rightChild].value, heap[smallest].value) < 0) {
3936
+ smallest = rightChild;
3937
+ }
3938
+ if (smallest === index) break;
3939
+ [heap[index], heap[smallest]] = [heap[smallest], heap[index]];
3940
+ index = smallest;
3941
+ }
3942
+ };
3943
+ for (let i = Math.floor(heap.length / 2) - 1; i >= 0; i--) {
3944
+ bubbleDown(i);
3945
+ }
3946
+ while (heap.length > 0) {
3947
+ const { value, iterator } = heap[0];
3948
+ yield value;
3949
+ const result = iterator.next();
3950
+ if (result.done) {
3951
+ heap[0] = heap[heap.length - 1];
3952
+ heap.pop();
3953
+ if (heap.length > 0) {
3954
+ bubbleDown(0);
3955
+ }
3956
+ } else {
3957
+ heap[0].value = result.value;
3958
+ bubbleDown(0);
3959
+ }
3960
+ }
3961
+ }
3962
+ });
3963
+ }
3964
+ iter2.merge = merge;
3965
+ function chain(...iterables) {
3966
+ return new iterflow({
3967
+ *[Symbol.iterator]() {
3968
+ for (const iterable of iterables) {
3969
+ yield* iterable;
3970
+ }
3971
+ }
3972
+ });
3973
+ }
3974
+ iter2.chain = chain;
3975
+ })(iter || (iter = {}));
3976
+
3977
+ exports.Asynciterflow = Asynciterflow;
3978
+ exports.EmptySequenceError = EmptySequenceError;
3979
+ exports.IndexOutOfBoundsError = IndexOutOfBoundsError;
3980
+ exports.OperationError = OperationError;
3981
+ exports.TypeConversionError = TypeConversionError;
3982
+ exports.ValidationError = ValidationError;
3983
+ exports.addTrace = addTrace;
3984
+ exports.asyncIter = asyncIter;
3985
+ exports.clearDeprecationWarnings = clearDeprecationWarnings;
3986
+ exports.clearTraces = clearTraces;
3987
+ exports.configureDeprecation = configureDeprecation;
3988
+ exports.deprecate = deprecate;
3989
+ exports.deprecated = deprecated;
3990
+ exports.deprecatedFunction = deprecatedFunction;
3991
+ exports.disableDebug = disableDebug;
3992
+ exports.enableDebug = enableDebug;
3993
+ exports.errorBoundary = errorBoundary;
3994
+ exports.getDebugConfig = getDebugConfig;
3995
+ exports.getDeprecationConfig = getDeprecationConfig;
3996
+ exports.getTraceSummary = getTraceSummary;
3997
+ exports.getTraces = getTraces;
3998
+ exports.getTracesForOperation = getTracesForOperation;
3999
+ exports.hasDeprecationWarning = hasDeprecationWarning;
4000
+ exports.isDebugEnabled = isDebugEnabled;
4001
+ exports.iter = iter;
4002
+ exports.iterflow = iterflow;
4003
+ exports.iterflowError = iterflowError;
4004
+ exports.safeComparator = safeComparator;
4005
+ exports.safePredicate = safePredicate;
4006
+ exports.toInteger = toInteger;
4007
+ exports.toNumber = toNumber;
4008
+ exports.toResult = toResult;
4009
+ exports.toResultAsync = toResultAsync;
4010
+ exports.traceOperation = traceOperation;
4011
+ exports.traceOperationAsync = traceOperationAsync;
4012
+ exports.tryCatch = tryCatch;
4013
+ exports.tryCatchAsync = tryCatchAsync;
4014
+ exports.tryOr = tryOr;
4015
+ exports.validateComparator = validateComparator;
4016
+ exports.validateFiniteNumber = validateFiniteNumber;
4017
+ exports.validateFunction = validateFunction;
4018
+ exports.validateIndex = validateIndex;
4019
+ exports.validateIterable = validateIterable;
4020
+ exports.validateNonEmpty = validateNonEmpty;
4021
+ exports.validateNonNegativeInteger = validateNonNegativeInteger;
4022
+ exports.validateNonZero = validateNonZero;
4023
+ exports.validatePositiveInteger = validatePositiveInteger;
4024
+ exports.validateRange = validateRange;
4025
+ exports.withDefault = withDefault;
4026
+ exports.withErrorRecovery = withErrorRecovery;
4027
+ exports.withRetry = withRetry;
4028
+ exports.withRetryAsync = withRetryAsync;
4029
+ //# sourceMappingURL=index.cjs.map
4030
+ //# sourceMappingURL=index.cjs.map