iterflow 0.9.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 -194
- 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 +13 -5
package/README.md
CHANGED
|
@@ -3,14 +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
|
-
**v0.9.0 Release Candidate**. See [MIGRATION.md](docs/MIGRATION.md) for upgrade guidance.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
12
|
## Installation
|
|
15
13
|
|
|
16
14
|
```bash
|
|
@@ -41,217 +39,88 @@ iter([1, 2, 3, 4, 5, 6])
|
|
|
41
39
|
// [[4, 8], [12]]
|
|
42
40
|
```
|
|
43
41
|
|
|
44
|
-
##
|
|
45
|
-
|
|
46
|
-
New in v0.8.0: Production-ready safety features to protect against infinite loops, slow operations, and runaway resource usage:
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
// Prevent infinite loops with hard limits
|
|
50
|
-
iter.range(Infinity)
|
|
51
|
-
.limit(10000) // Throws if exceeded
|
|
52
|
-
.toArray(1000); // Collects max 1000 items
|
|
53
|
-
|
|
54
|
-
// Timeout async operations
|
|
55
|
-
await asyncIter(items)
|
|
56
|
-
.map(slowOperation)
|
|
57
|
-
.timeout(5000) // 5s per iteration
|
|
58
|
-
.toArray();
|
|
59
|
-
|
|
60
|
-
// User cancellation with AbortController
|
|
61
|
-
const controller = new AbortController();
|
|
62
|
-
const promise = asyncIter(largeJob)
|
|
63
|
-
.withSignal(controller.signal)
|
|
64
|
-
.toArray();
|
|
65
|
-
|
|
66
|
-
// User clicks cancel
|
|
67
|
-
controller.abort('User cancelled');
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**New APIs:**
|
|
71
|
-
- `limit(maxIterations)` - Throw OperationError if iteration limit exceeded
|
|
72
|
-
- `timeout(ms)` - Throw TimeoutError if async operations are too slow
|
|
73
|
-
- `withSignal(signal)` - Integrate with AbortController for cancellation
|
|
74
|
-
- `toArray(maxSize?)` - Optional size limit for safe collection
|
|
75
|
-
- New error types: `TimeoutError`, `AbortError`
|
|
76
|
-
|
|
77
|
-
For complete details, see the [Resource Limits Guide](docs/guides/resource-limits.md).
|
|
78
|
-
|
|
79
|
-
## API
|
|
80
|
-
|
|
81
|
-
### Wrapper API
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
import { iter } from 'iterflow';
|
|
85
|
-
|
|
86
|
-
iter([1, 2, 3, 4, 5])
|
|
87
|
-
.filter(x => x > 2) // Native iterator method
|
|
88
|
-
.map(x => x * 2) // Native iterator method
|
|
89
|
-
.sum(); // iterflow extension - 24
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Functional API
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
import { sum, filter, map } from 'iterflow/fn';
|
|
96
|
-
|
|
97
|
-
const data = [1, 2, 3, 4, 5];
|
|
98
|
-
sum(map(x => x * 2)(filter(x => x > 2)(data))); // 24
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Operations
|
|
42
|
+
## Core Operations
|
|
102
43
|
|
|
103
44
|
### Statistical
|
|
104
45
|
|
|
105
46
|
```typescript
|
|
106
|
-
iter([1, 2, 3, 4, 5
|
|
107
|
-
iter([1, 2, 3, 4, 5
|
|
108
|
-
iter([1, 2, 3, 4, 5
|
|
109
|
-
iter([1, 2, 3, 4, 5
|
|
110
|
-
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
|
|
111
51
|
```
|
|
112
52
|
|
|
113
53
|
### Windowing
|
|
114
54
|
|
|
115
55
|
```typescript
|
|
116
|
-
//
|
|
117
|
-
iter([1, 2, 3, 4, 5]).
|
|
118
|
-
// [[1,2,3], [2,3,4], [3,4,5]]
|
|
119
|
-
|
|
120
|
-
// Non-overlapping chunks
|
|
121
|
-
iter([1, 2, 3, 4, 5]).chunk(2).toArray();
|
|
122
|
-
// [[1,2], [3,4], [5]]
|
|
123
|
-
|
|
124
|
-
// Consecutive pairs
|
|
125
|
-
iter([1, 2, 3, 4]).pairwise().toArray();
|
|
126
|
-
// [[1,2], [2,3], [3,4]]
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Grouping
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
// Partition by predicate
|
|
133
|
-
const [evens, odds] = iter([1, 2, 3, 4, 5, 6])
|
|
134
|
-
.partition(x => x % 2 === 0);
|
|
135
|
-
|
|
136
|
-
// Group by key function
|
|
137
|
-
const items = [
|
|
138
|
-
{ category: 'fruit', name: 'apple' },
|
|
139
|
-
{ category: 'vegetable', name: 'carrot' },
|
|
140
|
-
{ category: 'fruit', name: 'banana' }
|
|
141
|
-
];
|
|
142
|
-
|
|
143
|
-
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]]
|
|
144
58
|
```
|
|
145
59
|
|
|
146
|
-
###
|
|
60
|
+
### Transformations
|
|
147
61
|
|
|
148
62
|
```typescript
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
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]
|
|
155
68
|
```
|
|
156
69
|
|
|
157
|
-
###
|
|
70
|
+
### Resource Limits (v0.8.0+)
|
|
158
71
|
|
|
159
72
|
```typescript
|
|
160
|
-
//
|
|
161
|
-
iter.
|
|
162
|
-
//
|
|
73
|
+
// Prevent infinite loops
|
|
74
|
+
iter.range(Infinity)
|
|
75
|
+
.limit(10000) // Throws if exceeded
|
|
76
|
+
.toArray(1000); // Collects max 1000
|
|
163
77
|
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
//
|
|
78
|
+
// Timeout async operations
|
|
79
|
+
await asyncIter(items)
|
|
80
|
+
.timeout(5000) // 5s per iteration
|
|
81
|
+
.toArray();
|
|
167
82
|
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
83
|
+
// User cancellation
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
asyncIter(data).withSignal(controller.signal).toArray();
|
|
86
|
+
controller.abort(); // Cancel anytime
|
|
171
87
|
```
|
|
172
88
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
// Side effects
|
|
177
|
-
iter([1, 2, 3])
|
|
178
|
-
.tap(x => console.log(`Processing: ${x}`))
|
|
179
|
-
.map(x => x * 2)
|
|
180
|
-
.toArray();
|
|
89
|
+
## Documentation
|
|
181
90
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
// [1, 2, 3]
|
|
91
|
+
- **[API Reference](./docs/api/index.md)** - Complete TypeScript API documentation
|
|
92
|
+
- **[Examples](./examples/)** - Real-world usage examples
|
|
185
93
|
|
|
186
|
-
|
|
187
|
-
// [3, 4, 5]
|
|
188
|
-
```
|
|
94
|
+
## When to Use iterflow
|
|
189
95
|
|
|
190
|
-
###
|
|
96
|
+
### Use iterflow when
|
|
191
97
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// Repeat values
|
|
199
|
-
iter.repeat('hello', 3).toArray(); // ['hello', 'hello', 'hello']
|
|
200
|
-
iter.repeat(0).take(5).toArray(); // [0, 0, 0, 0, 0]
|
|
201
|
-
```
|
|
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
|
|
202
103
|
|
|
203
|
-
|
|
104
|
+
### Consider alternatives when
|
|
204
105
|
|
|
205
|
-
|
|
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
|
|
206
109
|
|
|
207
|
-
|
|
208
|
-
interface Sale {
|
|
209
|
-
product: string;
|
|
210
|
-
amount: number;
|
|
211
|
-
category: string;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const sales: Sale[] = [
|
|
215
|
-
{ product: 'Laptop', amount: 1200, category: 'Electronics' },
|
|
216
|
-
{ product: 'Mouse', amount: 25, category: 'Electronics' },
|
|
217
|
-
{ product: 'Book', amount: 15, category: 'Books' },
|
|
218
|
-
];
|
|
219
|
-
|
|
220
|
-
// Average electronics sale amount
|
|
221
|
-
const electronicsAvg = iter(sales)
|
|
222
|
-
.filter(sale => sale.category === 'Electronics')
|
|
223
|
-
.map(sale => sale.amount)
|
|
224
|
-
.mean();
|
|
225
|
-
|
|
226
|
-
// Total sales by category
|
|
227
|
-
const salesByCategory = iter(sales)
|
|
228
|
-
.groupBy(sale => sale.category)
|
|
229
|
-
.entries()
|
|
230
|
-
.map(([category, sales]) => ({
|
|
231
|
-
category,
|
|
232
|
-
total: iter(sales).map(sale => sale.amount).sum()
|
|
233
|
-
}));
|
|
234
|
-
```
|
|
110
|
+
## API Styles
|
|
235
111
|
|
|
236
|
-
###
|
|
112
|
+
### Wrapper API (Recommended for most use cases)
|
|
237
113
|
|
|
238
114
|
```typescript
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
yield a;
|
|
243
|
-
[a, b] = [b, a + b];
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// First 10 even fibonacci numbers
|
|
248
|
-
const evenFibs = iter(fibonacci())
|
|
115
|
+
import { iter } from 'iterflow';
|
|
116
|
+
|
|
117
|
+
iter([1, 2, 3, 4, 5])
|
|
249
118
|
.filter(x => x % 2 === 0)
|
|
250
|
-
.
|
|
251
|
-
.
|
|
119
|
+
.map(x => x * 2)
|
|
120
|
+
.sum(); // 12
|
|
252
121
|
```
|
|
253
122
|
|
|
254
|
-
###
|
|
123
|
+
### Functional API (Better tree-shaking)
|
|
255
124
|
|
|
256
125
|
```typescript
|
|
257
126
|
const temperatures = [20, 22, 25, 23, 21, 19, 18, 20, 22, 24];
|
|
@@ -303,11 +172,8 @@ See **[docs/BENCHMARKS.md](docs/BENCHMARKS.md)** for detailed performance data a
|
|
|
303
172
|
|
|
304
173
|
## Documentation
|
|
305
174
|
|
|
306
|
-
- **[API Reference](docs/API.md)** - Complete API documentation for all methods (v0.9.0+)
|
|
307
|
-
- **[Migration Guide](docs/MIGRATION.md)** - Upgrading from v0.x to v1.0 (v0.9.0+)
|
|
308
175
|
- **[FAQ](FAQ.md)** - Frequently asked questions, common patterns, and troubleshooting
|
|
309
176
|
- **[Examples](examples/)** - Real-world usage examples
|
|
310
|
-
- **[Resource Limits Guide](docs/guides/resource-limits.md)** - Production safety features (v0.8.0+)
|
|
311
177
|
- **[Memory Safety Guide](docs/guides/memory-safety.md)** - Avoiding memory leaks and efficient memory usage
|
|
312
178
|
- **[Performance Guide](docs/PERFORMANCE.md)** - Optimization techniques and benchmarking
|
|
313
179
|
- **[Benchmarking Guide](docs/BENCHMARKING.md)** - Running and interpreting benchmarks
|
|
@@ -315,14 +181,7 @@ See **[docs/BENCHMARKS.md](docs/BENCHMARKS.md)** for detailed performance data a
|
|
|
315
181
|
|
|
316
182
|
## Contributing
|
|
317
183
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
- Development workflow and branching strategy
|
|
321
|
-
- Commit message guidelines
|
|
322
|
-
- Testing requirements
|
|
323
|
-
- Release process
|
|
324
|
-
|
|
325
|
-
For quick start:
|
|
184
|
+
Quick start:
|
|
326
185
|
|
|
327
186
|
1. Fork the repository
|
|
328
187
|
2. Create a feature branch from `dev`
|
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");
|