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/LICENSE +24 -0
- package/README.md +228 -0
- package/dist/fn/index.cjs +904 -0
- package/dist/fn/index.cjs.map +1 -0
- package/dist/fn/index.d.cts +1187 -0
- package/dist/fn/index.d.ts +1187 -0
- package/dist/fn/index.js +837 -0
- package/dist/fn/index.js.map +1 -0
- package/dist/index.cjs +4030 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2264 -0
- package/dist/index.d.ts +2264 -0
- package/dist/index.js +3977 -0
- package/dist/index.js.map +1 -0
- package/package.json +111 -0
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
|