@soffinal/stream 0.2.1 → 0.2.3
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 +118 -93
- package/dist/index.js +2 -2
- package/dist/index.js.map +8 -8
- package/dist/reactive/state.d.ts +3 -3
- package/dist/reactive/state.d.ts.map +1 -1
- package/dist/stream.d.ts +6 -14
- package/dist/stream.d.ts.map +1 -1
- package/dist/transformers/filter.d.ts +74 -13
- package/dist/transformers/filter.d.ts.map +1 -1
- package/dist/transformers/flat.d.ts.map +1 -1
- package/dist/transformers/map.d.ts +83 -13
- package/dist/transformers/map.d.ts.map +1 -1
- package/dist/transformers/merge.d.ts +1 -3
- package/dist/transformers/merge.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/transformers/filter.md +244 -120
- package/src/transformers/map.md +336 -122
- package/CHANGELOG.md +0 -22
package/src/transformers/map.md
CHANGED
|
@@ -1,216 +1,430 @@
|
|
|
1
1
|
# Map Transformer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The `map` transformer transforms values flowing through a stream. It supports synchronous and asynchronous transformations, stateful operations, type conversions, and multiple concurrency strategies for optimal performance.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```typescript
|
|
8
|
+
import { Stream, map } from "@soffinal/stream";
|
|
9
|
+
|
|
10
|
+
const numbers = new Stream<number>();
|
|
11
|
+
|
|
12
|
+
// Simple transformation
|
|
13
|
+
const doubled = numbers.pipe(map((n) => n * 2));
|
|
14
|
+
|
|
15
|
+
doubled.listen(console.log);
|
|
16
|
+
numbers.push(1, 2, 3); // Outputs: 2, 4, 6
|
|
17
|
+
```
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
## Basic Usage
|
|
20
|
+
|
|
21
|
+
### Synchronous Transformations
|
|
10
22
|
|
|
11
23
|
```typescript
|
|
12
|
-
|
|
24
|
+
// Number to string
|
|
25
|
+
stream.pipe(map((n) => n.toString()));
|
|
26
|
+
|
|
27
|
+
// Object property extraction
|
|
28
|
+
stream.pipe(map((user) => user.name));
|
|
29
|
+
|
|
30
|
+
// Complex transformations
|
|
31
|
+
stream.pipe(
|
|
32
|
+
map((data) => ({
|
|
33
|
+
id: data.id,
|
|
34
|
+
name: data.name.toUpperCase(),
|
|
35
|
+
timestamp: Date.now(),
|
|
36
|
+
}))
|
|
37
|
+
);
|
|
13
38
|
```
|
|
14
39
|
|
|
15
|
-
|
|
40
|
+
### Type Transformations
|
|
16
41
|
|
|
17
|
-
|
|
42
|
+
Map excels at converting between types with full TypeScript inference:
|
|
18
43
|
|
|
19
44
|
```typescript
|
|
20
|
-
|
|
45
|
+
const numbers = new Stream<number>();
|
|
46
|
+
|
|
47
|
+
// number → string
|
|
48
|
+
const strings = numbers.pipe(map((n) => n.toString()));
|
|
49
|
+
|
|
50
|
+
// number → object
|
|
51
|
+
const objects = numbers.pipe(
|
|
52
|
+
map((n) => ({
|
|
53
|
+
value: n,
|
|
54
|
+
squared: n * n,
|
|
55
|
+
isEven: n % 2 === 0,
|
|
56
|
+
}))
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Chained transformations
|
|
60
|
+
const result = numbers
|
|
61
|
+
.pipe(map((n) => n * 2)) // number → number
|
|
62
|
+
.pipe(map((n) => n.toString())) // number → string
|
|
63
|
+
.pipe(map((s) => s.length)); // string → number
|
|
21
64
|
```
|
|
22
65
|
|
|
23
|
-
|
|
66
|
+
## Asynchronous Transformations
|
|
24
67
|
|
|
25
|
-
###
|
|
68
|
+
### Sequential Processing (Default)
|
|
26
69
|
|
|
27
70
|
```typescript
|
|
28
|
-
|
|
71
|
+
const urls = new Stream<string>();
|
|
72
|
+
|
|
73
|
+
const responses = urls.pipe(
|
|
74
|
+
map(async (url) => {
|
|
75
|
+
const response = await fetch(url);
|
|
76
|
+
return await response.json();
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Requests processed one at a time, maintaining order
|
|
29
81
|
```
|
|
30
82
|
|
|
31
|
-
|
|
83
|
+
### Concurrent Strategies
|
|
84
|
+
|
|
85
|
+
For expensive async operations, choose a concurrency strategy:
|
|
32
86
|
|
|
33
|
-
|
|
87
|
+
#### Concurrent Unordered
|
|
34
88
|
|
|
35
|
-
|
|
89
|
+
Transformations run in parallel, results emit as they complete:
|
|
36
90
|
|
|
37
91
|
```typescript
|
|
38
|
-
|
|
39
|
-
|
|
92
|
+
const ids = new Stream<string>();
|
|
93
|
+
|
|
94
|
+
const users = ids.pipe(
|
|
95
|
+
map(
|
|
96
|
+
async (id) => {
|
|
97
|
+
const user = await fetchUser(id);
|
|
98
|
+
return user;
|
|
99
|
+
},
|
|
100
|
+
{ strategy: "concurrent-unordered" }
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Users emit as API calls complete, potentially out of order
|
|
40
105
|
```
|
|
41
106
|
|
|
42
|
-
|
|
107
|
+
#### Concurrent Ordered
|
|
43
108
|
|
|
44
|
-
|
|
109
|
+
Parallel processing but maintains original order:
|
|
45
110
|
|
|
46
111
|
```typescript
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
112
|
+
const images = new Stream<string>();
|
|
113
|
+
|
|
114
|
+
const processed = images.pipe(
|
|
115
|
+
map(
|
|
116
|
+
async (imageUrl) => {
|
|
117
|
+
const processed = await processImage(imageUrl);
|
|
118
|
+
return processed;
|
|
119
|
+
},
|
|
120
|
+
{ strategy: "concurrent-ordered" }
|
|
121
|
+
)
|
|
122
|
+
);
|
|
53
123
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
124
|
+
// Images always emit in original order despite varying processing times
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Stateful Transformations
|
|
128
|
+
|
|
129
|
+
Maintain state across transformations for complex operations:
|
|
130
|
+
|
|
131
|
+
### Basic Stateful Mapping
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const numbers = new Stream<number>();
|
|
135
|
+
|
|
136
|
+
// Running sum
|
|
137
|
+
const runningSums = numbers.pipe(
|
|
138
|
+
map({ sum: 0 }, (state, value) => {
|
|
139
|
+
const newSum = state.sum + value;
|
|
140
|
+
return [newSum, { sum: newSum }];
|
|
58
141
|
})
|
|
59
142
|
);
|
|
143
|
+
|
|
144
|
+
numbers.push(1, 2, 3, 4);
|
|
145
|
+
// Outputs: 1, 3, 6, 10
|
|
60
146
|
```
|
|
61
147
|
|
|
62
|
-
###
|
|
148
|
+
### Indexing and Counting
|
|
63
149
|
|
|
64
150
|
```typescript
|
|
65
|
-
|
|
66
|
-
stream.pipe(
|
|
67
|
-
map({ multiplier: 1, trend: "stable" }, (state, value) => {
|
|
68
|
-
// Adapt the transformation based on observed patterns
|
|
69
|
-
const newMultiplier = value > 100 ? state.multiplier * 1.1 : state.multiplier * 0.9;
|
|
70
|
-
const trend = newMultiplier > state.multiplier ? "growing" : "shrinking";
|
|
151
|
+
const items = new Stream<string>();
|
|
71
152
|
|
|
72
|
-
|
|
153
|
+
// Add indices
|
|
154
|
+
const indexed = items.pipe(
|
|
155
|
+
map({ index: 0 }, (state, value) => {
|
|
156
|
+
const result = { item: value, index: state.index };
|
|
157
|
+
return [result, { index: state.index + 1 }];
|
|
73
158
|
})
|
|
74
159
|
);
|
|
75
|
-
```
|
|
76
160
|
|
|
77
|
-
|
|
161
|
+
items.push("a", "b", "c");
|
|
162
|
+
// Outputs: {item: "a", index: 0}, {item: "b", index: 1}, {item: "c", index: 2}
|
|
163
|
+
```
|
|
78
164
|
|
|
79
|
-
###
|
|
165
|
+
### Complex State Management
|
|
80
166
|
|
|
81
167
|
```typescript
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
168
|
+
const events = new Stream<{ type: string; data: any }>();
|
|
169
|
+
|
|
170
|
+
// Event aggregation with history
|
|
171
|
+
const aggregated = events.pipe(
|
|
172
|
+
map(
|
|
173
|
+
{
|
|
174
|
+
counts: new Map<string, number>(),
|
|
175
|
+
history: [] as string[],
|
|
176
|
+
total: 0,
|
|
177
|
+
},
|
|
178
|
+
(state, event) => {
|
|
179
|
+
const newCounts = new Map(state.counts);
|
|
180
|
+
const currentCount = newCounts.get(event.type) || 0;
|
|
181
|
+
newCounts.set(event.type, currentCount + 1);
|
|
182
|
+
|
|
183
|
+
const newHistory = [...state.history, event.type].slice(-10); // Keep last 10
|
|
184
|
+
const newTotal = state.total + 1;
|
|
185
|
+
|
|
186
|
+
const result = {
|
|
187
|
+
event: event.type,
|
|
188
|
+
count: currentCount + 1,
|
|
189
|
+
totalEvents: newTotal,
|
|
190
|
+
recentHistory: newHistory,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return [
|
|
194
|
+
result,
|
|
195
|
+
{
|
|
196
|
+
counts: newCounts,
|
|
197
|
+
history: newHistory,
|
|
198
|
+
total: newTotal,
|
|
199
|
+
},
|
|
200
|
+
];
|
|
87
201
|
}
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
```
|
|
88
205
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
206
|
+
### Async Stateful Transformations
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const requests = new Stream<string>();
|
|
210
|
+
|
|
211
|
+
// Caching with async operations
|
|
212
|
+
const cached = requests.pipe(
|
|
213
|
+
map(
|
|
214
|
+
{
|
|
215
|
+
cache: new Map<string, any>(),
|
|
216
|
+
},
|
|
217
|
+
async (state, url) => {
|
|
218
|
+
// Check cache first
|
|
219
|
+
if (state.cache.has(url)) {
|
|
220
|
+
return [state.cache.get(url), state];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Fetch and cache
|
|
224
|
+
const data = await fetch(url).then((r) => r.json());
|
|
225
|
+
const newCache = new Map(state.cache);
|
|
226
|
+
newCache.set(url, data);
|
|
227
|
+
|
|
228
|
+
return [data, { cache: newCache }];
|
|
229
|
+
}
|
|
230
|
+
)
|
|
93
231
|
);
|
|
94
232
|
```
|
|
95
233
|
|
|
96
|
-
|
|
234
|
+
## Performance Considerations
|
|
235
|
+
|
|
236
|
+
### When to Use Concurrency
|
|
97
237
|
|
|
98
|
-
|
|
238
|
+
- **Sequential**: Default choice, maintains order, lowest overhead
|
|
239
|
+
- **Concurrent-unordered**: Use when order doesn't matter and transformations are expensive
|
|
240
|
+
- **Concurrent-ordered**: Use when order matters but transformations are expensive
|
|
99
241
|
|
|
100
|
-
###
|
|
242
|
+
### Benchmarking Example
|
|
101
243
|
|
|
102
244
|
```typescript
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
});
|
|
245
|
+
const urls = Array.from({ length: 100 }, (_, i) => `https://api.example.com/item/${i}`);
|
|
246
|
+
const stream = new Stream<string>();
|
|
247
|
+
|
|
248
|
+
// Sequential: ~10 seconds (100ms per request)
|
|
249
|
+
const sequential = stream.pipe(map(async (url) => await fetch(url)));
|
|
109
250
|
|
|
110
|
-
//
|
|
111
|
-
stream.pipe(
|
|
112
|
-
|
|
251
|
+
// Concurrent-unordered: ~1 second (parallel requests)
|
|
252
|
+
const concurrent = stream.pipe(
|
|
253
|
+
map(async (url) => await fetch(url), {
|
|
254
|
+
strategy: "concurrent-unordered",
|
|
255
|
+
})
|
|
256
|
+
);
|
|
113
257
|
```
|
|
114
258
|
|
|
115
|
-
|
|
259
|
+
### Memory Management
|
|
116
260
|
|
|
117
|
-
|
|
261
|
+
For stateful transformations, manage memory carefully:
|
|
118
262
|
|
|
119
263
|
```typescript
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
264
|
+
// Good: Bounded state
|
|
265
|
+
map(
|
|
266
|
+
{
|
|
267
|
+
recentItems: [] as T[],
|
|
268
|
+
maxSize: 100,
|
|
269
|
+
},
|
|
270
|
+
(state, value) => {
|
|
271
|
+
const newItems = [...state.recentItems, value].slice(-state.maxSize);
|
|
272
|
+
return [
|
|
273
|
+
processItems(newItems),
|
|
274
|
+
{
|
|
275
|
+
recentItems: newItems,
|
|
276
|
+
maxSize: state.maxSize,
|
|
277
|
+
},
|
|
278
|
+
];
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
// Avoid: Unbounded growth
|
|
283
|
+
map({ history: [] }, (state, value) => {
|
|
284
|
+
// This grows indefinitely!
|
|
285
|
+
return [value, { history: [...state.history, value] }];
|
|
286
|
+
});
|
|
125
287
|
```
|
|
126
288
|
|
|
127
|
-
|
|
289
|
+
## Error Handling
|
|
128
290
|
|
|
129
|
-
|
|
291
|
+
Handle transformation errors gracefully:
|
|
130
292
|
|
|
131
293
|
```typescript
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
294
|
+
const stream = new Stream<string>();
|
|
295
|
+
|
|
296
|
+
const safe = stream.pipe(
|
|
297
|
+
map(async (data) => {
|
|
298
|
+
try {
|
|
299
|
+
return await riskyTransformation(data);
|
|
300
|
+
} catch (error) {
|
|
301
|
+
console.error("Transformation failed:", error);
|
|
302
|
+
return { error: error.message, original: data };
|
|
303
|
+
}
|
|
304
|
+
})
|
|
305
|
+
);
|
|
137
306
|
```
|
|
138
307
|
|
|
139
|
-
|
|
308
|
+
## Common Patterns
|
|
140
309
|
|
|
141
|
-
###
|
|
310
|
+
### Enrichment
|
|
142
311
|
|
|
143
312
|
```typescript
|
|
144
|
-
const
|
|
145
|
-
|
|
313
|
+
const enrich = <T>(enrichFn: (item: T) => Promise<any>) =>
|
|
314
|
+
map(async (item: T) => {
|
|
315
|
+
const enrichment = await enrichFn(item);
|
|
316
|
+
return { ...item, ...enrichment };
|
|
317
|
+
});
|
|
146
318
|
|
|
147
|
-
|
|
319
|
+
users.pipe(
|
|
320
|
+
enrich(async (user) => ({
|
|
321
|
+
avatar: await getAvatar(user.id),
|
|
322
|
+
permissions: await getPermissions(user.role),
|
|
323
|
+
}))
|
|
324
|
+
);
|
|
325
|
+
```
|
|
148
326
|
|
|
149
|
-
###
|
|
327
|
+
### Batching
|
|
150
328
|
|
|
151
329
|
```typescript
|
|
152
|
-
const
|
|
153
|
-
map<T, {}, T>({},
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
330
|
+
const batch = <T>(size: number) =>
|
|
331
|
+
map<T, { buffer: T[] }, T[]>({ buffer: [] }, (state, value) => {
|
|
332
|
+
const newBuffer = [...state.buffer, value];
|
|
333
|
+
|
|
334
|
+
if (newBuffer.length >= size) {
|
|
335
|
+
return [newBuffer, { buffer: [] }];
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return [null, { buffer: newBuffer }];
|
|
339
|
+
}).pipe(filter((batch) => batch !== null));
|
|
157
340
|
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
341
|
+
stream.pipe(batch(5)); // Emit arrays of 5 items
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Debouncing with State
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
const debounce = <T>(ms: number) =>
|
|
348
|
+
map<T, { lastValue: T | null; timer: any }, T | null>(
|
|
349
|
+
{
|
|
350
|
+
lastValue: null,
|
|
351
|
+
timer: null,
|
|
352
|
+
},
|
|
353
|
+
(state, value) => {
|
|
354
|
+
if (state.timer) clearTimeout(state.timer);
|
|
355
|
+
|
|
356
|
+
const timer = setTimeout(() => {
|
|
357
|
+
// This would need additional mechanism to emit
|
|
358
|
+
}, ms);
|
|
359
|
+
|
|
360
|
+
return [null, { lastValue: value, timer }];
|
|
361
|
+
}
|
|
362
|
+
);
|
|
161
363
|
```
|
|
162
364
|
|
|
163
|
-
###
|
|
365
|
+
### Windowing
|
|
164
366
|
|
|
165
367
|
```typescript
|
|
166
|
-
const
|
|
167
|
-
map<T, {
|
|
168
|
-
const
|
|
169
|
-
return [
|
|
368
|
+
const slidingWindow = <T>(size: number) =>
|
|
369
|
+
map<T, { window: T[] }, T[]>({ window: [] }, (state, value) => {
|
|
370
|
+
const newWindow = [...state.window, value].slice(-size);
|
|
371
|
+
return [newWindow, { window: newWindow }];
|
|
170
372
|
});
|
|
171
373
|
|
|
172
|
-
//
|
|
173
|
-
stream.pipe(scan((sum, value) => sum + value, 0)); // Running sum
|
|
174
|
-
stream.pipe(scan((max, value) => Math.max(max, value), -Infinity)); // Running max
|
|
374
|
+
stream.pipe(slidingWindow(3)); // Always emit last 3 items
|
|
175
375
|
```
|
|
176
376
|
|
|
177
|
-
|
|
377
|
+
## Advanced Patterns
|
|
178
378
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
Async transformations maintain order because **sequence matters**. Even if transformation B completes before transformation A, the stream waits. This isn't just about correctness - it's about **respecting the narrative** of the data.
|
|
379
|
+
### Conditional Transformation
|
|
182
380
|
|
|
183
381
|
```typescript
|
|
184
|
-
|
|
382
|
+
const conditionalMap = <T, U>(condition: (value: T) => boolean, transform: (value: T) => U) =>
|
|
383
|
+
map((value: T) => (condition(value) ? transform(value) : value));
|
|
384
|
+
|
|
185
385
|
stream.pipe(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
})
|
|
386
|
+
conditionalMap(
|
|
387
|
+
(n) => n > 10,
|
|
388
|
+
(n) => n * 2
|
|
389
|
+
)
|
|
191
390
|
);
|
|
192
391
|
```
|
|
193
392
|
|
|
194
|
-
|
|
393
|
+
### Multi-step Processing
|
|
195
394
|
|
|
196
|
-
|
|
395
|
+
```typescript
|
|
396
|
+
const pipeline = <T>(steps: Array<(value: any) => any>) =>
|
|
397
|
+
map((value: T) => steps.reduce((acc, step) => step(acc), value));
|
|
197
398
|
|
|
198
|
-
|
|
399
|
+
stream.pipe(
|
|
400
|
+
pipeline([(x) => x.toString(), (x) => x.toUpperCase(), (x) => x.split(""), (x) => x.reverse(), (x) => x.join("")])
|
|
401
|
+
);
|
|
402
|
+
```
|
|
199
403
|
|
|
200
|
-
|
|
201
|
-
2. **Simple State** `{ count: 0 }` - It learns to count
|
|
202
|
-
3. **Rich State** `{ sum: 0, count: 0, average: 0 }` - It develops complex understanding
|
|
203
|
-
4. **Intelligent State** `{ cache: Map, patterns: [], predictions: {} }` - It becomes wise
|
|
404
|
+
## Type Signatures
|
|
204
405
|
|
|
205
|
-
|
|
406
|
+
```typescript
|
|
407
|
+
// Simple mapper with optional concurrency
|
|
408
|
+
map<VALUE, MAPPED>(
|
|
409
|
+
mapper: (value: VALUE) => MAPPED | Promise<MAPPED>,
|
|
410
|
+
options?: { strategy: "sequential" | "concurrent-unordered" | "concurrent-ordered" }
|
|
411
|
+
): (stream: Stream<VALUE>) => Stream<MAPPED>
|
|
412
|
+
|
|
413
|
+
// Stateful mapper (always sequential)
|
|
414
|
+
map<VALUE, STATE, MAPPED>(
|
|
415
|
+
initialState: STATE,
|
|
416
|
+
mapper: (state: STATE, value: VALUE) => [MAPPED, STATE] | Promise<[MAPPED, STATE]>
|
|
417
|
+
): (stream: Stream<VALUE>) => Stream<MAPPED>
|
|
418
|
+
```
|
|
206
419
|
|
|
207
|
-
##
|
|
420
|
+
## Best Practices
|
|
208
421
|
|
|
209
|
-
|
|
422
|
+
1. **Choose the right strategy**: Use sequential for simple transformations, concurrent for expensive async operations
|
|
423
|
+
2. **Manage state size**: Keep stateful transformation state bounded to prevent memory leaks
|
|
424
|
+
3. **Handle errors gracefully**: Wrap risky transformations in try-catch blocks
|
|
425
|
+
4. **Leverage TypeScript**: Use proper typing for better development experience and runtime safety
|
|
426
|
+
5. **Consider performance**: Profile your transformations to choose optimal concurrency strategies
|
|
427
|
+
6. **Compose transformations**: Chain multiple simple maps rather than one complex transformation
|
|
428
|
+
7. **Use immutable updates**: Always return new state objects in stateful transformations
|
|
210
429
|
|
|
211
|
-
|
|
212
|
-
- **Learns** from patterns (adaptation)
|
|
213
|
-
- **Evolves** its approach over time (constraints)
|
|
214
|
-
- **Preserves** the narrative order (respect)
|
|
215
|
-
- **Integrates** with reactive state (toState)
|
|
216
|
-
- **Accumulates** knowledge over time (scan)
|
|
430
|
+
The map transformer is the workhorse of stream processing, enabling powerful data transformations that scale from simple synchronous operations to complex stateful async processing with optimal performance characteristics.
|
package/CHANGELOG.md
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [Unreleased]
|
|
9
|
-
|
|
10
|
-
## [0.2.0] - 2024-12-19
|
|
11
|
-
|
|
12
|
-
### Changed
|
|
13
|
-
|
|
14
|
-
- **BREAKING**: Removed instance methods for transformers from Stream class - use `.pipe()` exclusively
|
|
15
|
-
- **BREAKING**: filte and map transformers signatures now require state-based accumulators instead of simple sync/async predicates
|
|
16
|
-
- Improved internal transformer implementation
|
|
17
|
-
|
|
18
|
-
## [0.1.4] - 2024-12-18
|
|
19
|
-
|
|
20
|
-
[Unreleased]: https://github.com/soffinal/stream/compare/v0.1.4...HEAD
|
|
21
|
-
[0.2.0]: https://github.com/soffinal/stream/compare/v0.1.4...v0.2.0
|
|
22
|
-
[0.1.4]: https://github.com/soffinal/stream/releases/tag/v0.1.4
|