iterflow 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -223
- package/dist/fn/index.cjs +26 -3
- package/dist/fn/index.cjs.map +1 -1
- package/dist/fn/index.d.cts +1 -3
- package/dist/fn/index.d.ts +1 -3
- package/dist/fn/index.js +26 -3
- package/dist/fn/index.js.map +1 -1
- package/dist/index.cjs +324 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1058 -17
- package/dist/index.d.ts +1058 -17
- package/dist/index.js +324 -10
- package/dist/index.js.map +1 -1
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
Iterator utilities for ES2022+ with statistical operations, windowing, and lazy evaluation.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/iterflow)
|
|
6
|
+
[](https://github.com/mathscapes/iterflow/actions)
|
|
7
|
+
[](https://github.com/mathscapes/iterflow)
|
|
8
|
+
[](https://github.com/mathscapes/iterflow/blob/main/package.json)
|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
6
10
|
[](https://unlicense.org/)
|
|
7
11
|
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
|
|
11
12
|
## Installation
|
|
12
13
|
|
|
13
14
|
```bash
|
|
@@ -38,217 +39,88 @@ iter([1, 2, 3, 4, 5, 6])
|
|
|
38
39
|
// [[4, 8], [12]]
|
|
39
40
|
```
|
|
40
41
|
|
|
41
|
-
##
|
|
42
|
-
|
|
43
|
-
New in v0.8.0: Production-ready safety features to protect against infinite loops, slow operations, and runaway resource usage:
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
// Prevent infinite loops with hard limits
|
|
47
|
-
iter.range(Infinity)
|
|
48
|
-
.limit(10000) // Throws if exceeded
|
|
49
|
-
.toArray(1000); // Collects max 1000 items
|
|
50
|
-
|
|
51
|
-
// Timeout async operations
|
|
52
|
-
await asyncIter(items)
|
|
53
|
-
.map(slowOperation)
|
|
54
|
-
.timeout(5000) // 5s per iteration
|
|
55
|
-
.toArray();
|
|
56
|
-
|
|
57
|
-
// User cancellation with AbortController
|
|
58
|
-
const controller = new AbortController();
|
|
59
|
-
const promise = asyncIter(largeJob)
|
|
60
|
-
.withSignal(controller.signal)
|
|
61
|
-
.toArray();
|
|
62
|
-
|
|
63
|
-
// User clicks cancel
|
|
64
|
-
controller.abort('User cancelled');
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**New APIs:**
|
|
68
|
-
- `limit(maxIterations)` - Throw OperationError if iteration limit exceeded
|
|
69
|
-
- `timeout(ms)` - Throw TimeoutError if async operations are too slow
|
|
70
|
-
- `withSignal(signal)` - Integrate with AbortController for cancellation
|
|
71
|
-
- `toArray(maxSize?)` - Optional size limit for safe collection
|
|
72
|
-
- New error types: `TimeoutError`, `AbortError`
|
|
73
|
-
|
|
74
|
-
For complete details, see the [Resource Limits Guide](docs/guides/resource-limits.md).
|
|
75
|
-
|
|
76
|
-
## API
|
|
77
|
-
|
|
78
|
-
### Wrapper API
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
import { iter } from 'iterflow';
|
|
82
|
-
|
|
83
|
-
iter([1, 2, 3, 4, 5])
|
|
84
|
-
.filter(x => x > 2) // Native iterator method
|
|
85
|
-
.map(x => x * 2) // Native iterator method
|
|
86
|
-
.sum(); // iterflow extension - 24
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Functional API
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
import { sum, filter, map } from 'iterflow/fn';
|
|
93
|
-
|
|
94
|
-
const data = [1, 2, 3, 4, 5];
|
|
95
|
-
sum(map(x => x * 2)(filter(x => x > 2)(data))); // 24
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Operations
|
|
42
|
+
## Core Operations
|
|
99
43
|
|
|
100
44
|
### Statistical
|
|
101
45
|
|
|
102
46
|
```typescript
|
|
103
|
-
iter([1, 2, 3, 4, 5
|
|
104
|
-
iter([1, 2, 3, 4, 5
|
|
105
|
-
iter([1, 2, 3, 4, 5
|
|
106
|
-
iter([1, 2, 3, 4, 5
|
|
107
|
-
iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).percentile(75); // 7.75
|
|
47
|
+
iter([1, 2, 3, 4, 5]).sum(); // 15
|
|
48
|
+
iter([1, 2, 3, 4, 5]).mean(); // 3
|
|
49
|
+
iter([1, 2, 3, 4, 5]).median(); // 3
|
|
50
|
+
iter([1, 2, 3, 4, 5]).variance(); // 2
|
|
108
51
|
```
|
|
109
52
|
|
|
110
53
|
### Windowing
|
|
111
54
|
|
|
112
55
|
```typescript
|
|
113
|
-
//
|
|
114
|
-
iter([1, 2, 3, 4, 5]).
|
|
115
|
-
// [[1,2,3], [2,3,4], [3,4,5]]
|
|
116
|
-
|
|
117
|
-
// Non-overlapping chunks
|
|
118
|
-
iter([1, 2, 3, 4, 5]).chunk(2).toArray();
|
|
119
|
-
// [[1,2], [3,4], [5]]
|
|
120
|
-
|
|
121
|
-
// Consecutive pairs
|
|
122
|
-
iter([1, 2, 3, 4]).pairwise().toArray();
|
|
123
|
-
// [[1,2], [2,3], [3,4]]
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Grouping
|
|
127
|
-
|
|
128
|
-
```typescript
|
|
129
|
-
// Partition by predicate
|
|
130
|
-
const [evens, odds] = iter([1, 2, 3, 4, 5, 6])
|
|
131
|
-
.partition(x => x % 2 === 0);
|
|
132
|
-
|
|
133
|
-
// Group by key function
|
|
134
|
-
const items = [
|
|
135
|
-
{ category: 'fruit', name: 'apple' },
|
|
136
|
-
{ category: 'vegetable', name: 'carrot' },
|
|
137
|
-
{ category: 'fruit', name: 'banana' }
|
|
138
|
-
];
|
|
139
|
-
|
|
140
|
-
const groups = iter(items).groupBy(item => item.category);
|
|
56
|
+
iter([1, 2, 3, 4, 5]).window(3).toArray(); // [[1,2,3], [2,3,4], [3,4,5]]
|
|
57
|
+
iter([1, 2, 3, 4, 5]).chunk(2).toArray(); // [[1,2], [3,4], [5]]
|
|
141
58
|
```
|
|
142
59
|
|
|
143
|
-
###
|
|
60
|
+
### Transformations
|
|
144
61
|
|
|
145
62
|
```typescript
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
//
|
|
151
|
-
iter(people).distinctBy(person => person.id).toArray();
|
|
63
|
+
iter([1, 2, 3, 4, 5])
|
|
64
|
+
.map(x => x * 2)
|
|
65
|
+
.filter(x => x > 5)
|
|
66
|
+
.take(3)
|
|
67
|
+
.toArray(); // [6, 8, 10]
|
|
152
68
|
```
|
|
153
69
|
|
|
154
|
-
###
|
|
70
|
+
### Resource Limits (v0.8.0+)
|
|
155
71
|
|
|
156
72
|
```typescript
|
|
157
|
-
//
|
|
158
|
-
iter.
|
|
159
|
-
//
|
|
73
|
+
// Prevent infinite loops
|
|
74
|
+
iter.range(Infinity)
|
|
75
|
+
.limit(10000) // Throws if exceeded
|
|
76
|
+
.toArray(1000); // Collects max 1000
|
|
160
77
|
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
//
|
|
78
|
+
// Timeout async operations
|
|
79
|
+
await asyncIter(items)
|
|
80
|
+
.timeout(5000) // 5s per iteration
|
|
81
|
+
.toArray();
|
|
164
82
|
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
83
|
+
// User cancellation
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
asyncIter(data).withSignal(controller.signal).toArray();
|
|
86
|
+
controller.abort(); // Cancel anytime
|
|
168
87
|
```
|
|
169
88
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
```typescript
|
|
173
|
-
// Side effects
|
|
174
|
-
iter([1, 2, 3])
|
|
175
|
-
.tap(x => console.log(`Processing: ${x}`))
|
|
176
|
-
.map(x => x * 2)
|
|
177
|
-
.toArray();
|
|
89
|
+
## Documentation
|
|
178
90
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
// [1, 2, 3]
|
|
91
|
+
- **[API Reference](./docs/api/index.md)** - Complete TypeScript API documentation
|
|
92
|
+
- **[Examples](./examples/)** - Real-world usage examples
|
|
182
93
|
|
|
183
|
-
|
|
184
|
-
// [3, 4, 5]
|
|
185
|
-
```
|
|
94
|
+
## When to Use iterflow
|
|
186
95
|
|
|
187
|
-
###
|
|
96
|
+
### Use iterflow when
|
|
188
97
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// Repeat values
|
|
196
|
-
iter.repeat('hello', 3).toArray(); // ['hello', 'hello', 'hello']
|
|
197
|
-
iter.repeat(0).take(5).toArray(); // [0, 0, 0, 0, 0]
|
|
198
|
-
```
|
|
98
|
+
- Large datasets (1000+ items) - lazy evaluation avoids unnecessary work
|
|
99
|
+
- Early termination - finding first match, taking limited results
|
|
100
|
+
- Memory efficiency - windowing, chunking, processing huge files
|
|
101
|
+
- Complex pipelines - chaining 3+ operations
|
|
102
|
+
- Statistical operations - mean, median, variance, percentiles
|
|
199
103
|
|
|
200
|
-
|
|
104
|
+
### Consider alternatives when
|
|
201
105
|
|
|
202
|
-
|
|
106
|
+
- Small arrays (< 100 items) - native Array methods are slightly faster
|
|
107
|
+
- Single simple operation - map or filter alone
|
|
108
|
+
- Need multiple iterations - arrays are easier to loop over multiple times
|
|
203
109
|
|
|
204
|
-
|
|
205
|
-
interface Sale {
|
|
206
|
-
product: string;
|
|
207
|
-
amount: number;
|
|
208
|
-
category: string;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const sales: Sale[] = [
|
|
212
|
-
{ product: 'Laptop', amount: 1200, category: 'Electronics' },
|
|
213
|
-
{ product: 'Mouse', amount: 25, category: 'Electronics' },
|
|
214
|
-
{ product: 'Book', amount: 15, category: 'Books' },
|
|
215
|
-
];
|
|
216
|
-
|
|
217
|
-
// Average electronics sale amount
|
|
218
|
-
const electronicsAvg = iter(sales)
|
|
219
|
-
.filter(sale => sale.category === 'Electronics')
|
|
220
|
-
.map(sale => sale.amount)
|
|
221
|
-
.mean();
|
|
222
|
-
|
|
223
|
-
// Total sales by category
|
|
224
|
-
const salesByCategory = iter(sales)
|
|
225
|
-
.groupBy(sale => sale.category)
|
|
226
|
-
.entries()
|
|
227
|
-
.map(([category, sales]) => ({
|
|
228
|
-
category,
|
|
229
|
-
total: iter(sales).map(sale => sale.amount).sum()
|
|
230
|
-
}));
|
|
231
|
-
```
|
|
110
|
+
## API Styles
|
|
232
111
|
|
|
233
|
-
###
|
|
112
|
+
### Wrapper API (Recommended for most use cases)
|
|
234
113
|
|
|
235
114
|
```typescript
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
yield a;
|
|
240
|
-
[a, b] = [b, a + b];
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// First 10 even fibonacci numbers
|
|
245
|
-
const evenFibs = iter(fibonacci())
|
|
115
|
+
import { iter } from 'iterflow';
|
|
116
|
+
|
|
117
|
+
iter([1, 2, 3, 4, 5])
|
|
246
118
|
.filter(x => x % 2 === 0)
|
|
247
|
-
.
|
|
248
|
-
.
|
|
119
|
+
.map(x => x * 2)
|
|
120
|
+
.sum(); // 12
|
|
249
121
|
```
|
|
250
122
|
|
|
251
|
-
###
|
|
123
|
+
### Functional API (Better tree-shaking)
|
|
252
124
|
|
|
253
125
|
```typescript
|
|
254
126
|
const temperatures = [20, 22, 25, 23, 21, 19, 18, 20, 22, 24];
|
|
@@ -300,11 +172,8 @@ See **[docs/BENCHMARKS.md](docs/BENCHMARKS.md)** for detailed performance data a
|
|
|
300
172
|
|
|
301
173
|
## Documentation
|
|
302
174
|
|
|
303
|
-
- **[API Reference](docs/API.md)** - Complete API documentation for all methods (v0.9.0+)
|
|
304
|
-
- **[Migration Guide](docs/MIGRATION.md)** - Upgrading from v0.x to v1.0 (v0.9.0+)
|
|
305
175
|
- **[FAQ](FAQ.md)** - Frequently asked questions, common patterns, and troubleshooting
|
|
306
176
|
- **[Examples](examples/)** - Real-world usage examples
|
|
307
|
-
- **[Resource Limits Guide](docs/guides/resource-limits.md)** - Production safety features (v0.8.0+)
|
|
308
177
|
- **[Memory Safety Guide](docs/guides/memory-safety.md)** - Avoiding memory leaks and efficient memory usage
|
|
309
178
|
- **[Performance Guide](docs/PERFORMANCE.md)** - Optimization techniques and benchmarking
|
|
310
179
|
- **[Benchmarking Guide](docs/BENCHMARKING.md)** - Running and interpreting benchmarks
|
|
@@ -312,14 +181,7 @@ See **[docs/BENCHMARKS.md](docs/BENCHMARKS.md)** for detailed performance data a
|
|
|
312
181
|
|
|
313
182
|
## Contributing
|
|
314
183
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
- Development workflow and branching strategy
|
|
318
|
-
- Commit message guidelines
|
|
319
|
-
- Testing requirements
|
|
320
|
-
- Release process
|
|
321
|
-
|
|
322
|
-
For quick start:
|
|
184
|
+
Quick start:
|
|
323
185
|
|
|
324
186
|
1. Fork the repository
|
|
325
187
|
2. Create a feature branch from `dev`
|
|
@@ -328,38 +190,6 @@ For quick start:
|
|
|
328
190
|
|
|
329
191
|
See [PLAYBOOK.md](PLAYBOOK.md) for complete details.
|
|
330
192
|
|
|
331
|
-
## Semantic Versioning Commitment
|
|
332
|
-
|
|
333
|
-
Starting with v1.0.0, iterflow follows strict semantic versioning:
|
|
334
|
-
|
|
335
|
-
- **Major versions** (2.0.0, 3.0.0): Breaking changes to public API
|
|
336
|
-
- **Minor versions** (1.1.0, 1.2.0): New features, backwards-compatible
|
|
337
|
-
- **Patch versions** (1.0.1, 1.0.2): Bug fixes, no API changes
|
|
338
|
-
|
|
339
|
-
### API Stability Guarantee
|
|
340
|
-
|
|
341
|
-
The following APIs are stable and will not have breaking changes in 1.x:
|
|
342
|
-
|
|
343
|
-
- All public methods on `iterflow<T>` class (116 methods)
|
|
344
|
-
- All public methods on `Asynciterflow<T>` class (116 methods)
|
|
345
|
-
- All exports from `iterflow/fn` functional API
|
|
346
|
-
- All error classes (`iterflowError`, `TimeoutError`, `AbortError`, `OperationError`)
|
|
347
|
-
- All TypeScript type definitions and interfaces
|
|
348
|
-
|
|
349
|
-
### What We Promise
|
|
350
|
-
|
|
351
|
-
- **No breaking changes** in minor or patch releases
|
|
352
|
-
- **Comprehensive changelog** for all releases
|
|
353
|
-
- **Deprecation warnings** before any breaking changes (minimum 1 major version notice)
|
|
354
|
-
- **Migration guides** for major version upgrades
|
|
355
|
-
- **Long-term support** for 1.x (at least 18 months from v1.0.0 release)
|
|
356
|
-
|
|
357
|
-
### Reporting Issues
|
|
358
|
-
|
|
359
|
-
- **Bugs**: https://github.com/mathscapes/iterflow/issues
|
|
360
|
-
- **Security**: See [SECURITY.md](SECURITY.md) for responsible disclosure
|
|
361
|
-
- **Feature Requests**: https://github.com/mathscapes/iterflow/discussions
|
|
362
|
-
|
|
363
193
|
## License
|
|
364
194
|
|
|
365
195
|
The Unlicense - See [LICENSE](LICENSE) for details.
|
package/dist/fn/index.cjs
CHANGED
|
@@ -15,6 +15,26 @@ var iterflowError = class extends Error {
|
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* Returns a detailed error message with context
|
|
18
|
+
*
|
|
19
|
+
* Formats the error as a multi-line string including operation name, context data,
|
|
20
|
+
* and stack trace for comprehensive debugging information.
|
|
21
|
+
*
|
|
22
|
+
* @returns A formatted string containing all error details
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const error = new iterflowError(
|
|
26
|
+
* "Processing failed",
|
|
27
|
+
* "transform",
|
|
28
|
+
* { index: 42, value: null }
|
|
29
|
+
* );
|
|
30
|
+
* console.log(error.toDetailedString());
|
|
31
|
+
* // iterflowError: Processing failed
|
|
32
|
+
* // Operation: transform
|
|
33
|
+
* // Context:
|
|
34
|
+
* // index: 42
|
|
35
|
+
* // value: null
|
|
36
|
+
* // Stack: ...
|
|
37
|
+
* ```
|
|
18
38
|
*/
|
|
19
39
|
toDetailedString() {
|
|
20
40
|
let msg = `${this.name}: ${this.message}`;
|
|
@@ -87,11 +107,11 @@ function compose(...fns) {
|
|
|
87
107
|
}
|
|
88
108
|
function createOperation(name, generator) {
|
|
89
109
|
if (generator.length === 1) {
|
|
90
|
-
return (iterable) => {
|
|
110
|
+
return ((iterable) => {
|
|
91
111
|
const result = generator(iterable);
|
|
92
112
|
Object.defineProperty(result, "name", { value: name });
|
|
93
113
|
return result;
|
|
94
|
-
};
|
|
114
|
+
});
|
|
95
115
|
}
|
|
96
116
|
return (...configs) => {
|
|
97
117
|
return (iterable) => {
|
|
@@ -133,7 +153,10 @@ function takeTransducer(n) {
|
|
|
133
153
|
}
|
|
134
154
|
function composeTransducers(...transducers) {
|
|
135
155
|
return (reducer) => {
|
|
136
|
-
return transducers.reduceRight(
|
|
156
|
+
return transducers.reduceRight(
|
|
157
|
+
(acc, xf) => xf(acc),
|
|
158
|
+
reducer
|
|
159
|
+
);
|
|
137
160
|
};
|
|
138
161
|
}
|
|
139
162
|
var REDUCED = Symbol("@@transducer/reduced");
|