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 CHANGED
@@ -3,14 +3,12 @@
3
3
  Iterator utilities for ES2022+ with statistical operations, windowing, and lazy evaluation.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/iterflow.svg)](https://www.npmjs.com/package/iterflow)
6
+ [![CI](https://img.shields.io/github/actions/workflow/status/mathscapes/iterflow/ci.yml?branch=main)](https://github.com/mathscapes/iterflow/actions)
7
+ [![Coverage](https://img.shields.io/badge/coverage-81%25-brightgreen)](https://github.com/mathscapes/iterflow)
8
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](https://github.com/mathscapes/iterflow/blob/main/package.json)
9
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.6%2B-blue)](https://www.typescriptlang.org/)
6
10
  [![License: Unlicense](https://img.shields.io/badge/License-Unlicense-blue.svg)](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
- ## Resource Limits & Safety (v0.8.0)
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, 6, 7, 8, 9, 10]).sum(); // 55
107
- iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).mean(); // 5.5
108
- iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).median(); // 5.5
109
- iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).variance(); // 8.25
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
- // Sliding window
117
- iter([1, 2, 3, 4, 5]).window(3).toArray();
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
- ### Set Operations
60
+ ### Transformations
147
61
 
148
62
  ```typescript
149
- // Remove duplicates
150
- iter([1, 2, 2, 3, 3, 3, 4]).distinct().toArray();
151
- // [1, 2, 3, 4]
152
-
153
- // Remove duplicates by key
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
- ### Combining
70
+ ### Resource Limits (v0.8.0+)
158
71
 
159
72
  ```typescript
160
- // Zip iterators
161
- iter.zip([1, 2, 3], ['a', 'b', 'c']).toArray();
162
- // [[1,'a'], [2,'b'], [3,'c']]
73
+ // Prevent infinite loops
74
+ iter.range(Infinity)
75
+ .limit(10000) // Throws if exceeded
76
+ .toArray(1000); // Collects max 1000
163
77
 
164
- // Interleave round-robin
165
- iter.interleave([1, 2, 3], [4, 5, 6]).toArray();
166
- // [1, 4, 2, 5, 3, 6]
78
+ // Timeout async operations
79
+ await asyncIter(items)
80
+ .timeout(5000) // 5s per iteration
81
+ .toArray();
167
82
 
168
- // Merge sorted iterators
169
- iter.merge([1, 3, 5], [2, 4, 6]).toArray();
170
- // [1, 2, 3, 4, 5, 6]
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
- ### Utilities
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
- // Conditional take/drop
183
- iter([1, 2, 3, 4, 3, 2, 1]).takeWhile(x => x < 4).toArray();
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
- iter([1, 2, 3, 4, 5]).dropWhile(x => x < 3).toArray();
187
- // [3, 4, 5]
188
- ```
94
+ ## When to Use iterflow
189
95
 
190
- ### Generators
96
+ ### Use iterflow when
191
97
 
192
- ```typescript
193
- // Numeric ranges
194
- iter.range(5).toArray(); // [0, 1, 2, 3, 4]
195
- iter.range(2, 8).toArray(); // [2, 3, 4, 5, 6, 7]
196
- iter.range(0, 10, 2).toArray(); // [0, 2, 4, 6, 8]
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
- ## Examples
104
+ ### Consider alternatives when
204
105
 
205
- ### Processing Pipeline
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
- ```typescript
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
- ### Infinite Sequences
112
+ ### Wrapper API (Recommended for most use cases)
237
113
 
238
114
  ```typescript
239
- function* fibonacci() {
240
- let a = 0, b = 1;
241
- while (true) {
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
- .take(10)
251
- .toArray();
119
+ .map(x => x * 2)
120
+ .sum(); // 12
252
121
  ```
253
122
 
254
- ### Moving Averages
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
- We welcome contributions! Please see our [PLAYBOOK.md](PLAYBOOK.md) for:
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((acc, xf) => xf(acc), reducer);
156
+ return transducers.reduceRight(
157
+ (acc, xf) => xf(acc),
158
+ reducer
159
+ );
137
160
  };
138
161
  }
139
162
  var REDUCED = Symbol("@@transducer/reduced");