@soffinal/stream 0.2.0 → 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.
@@ -121,8 +121,6 @@ const take = <T>(n: number) =>
121
121
  });
122
122
  ```
123
123
 
124
- **Psychology**: `take` demonstrates **self-limiting behavior** - the filter knows its purpose and fulfills it completely, then gracefully terminates.
125
-
126
124
  ### distinct - The Memory Gatekeeper
127
125
 
128
126
  ```typescript
@@ -134,7 +132,19 @@ const distinct = <T>() =>
134
132
  });
135
133
  ```
136
134
 
137
- **Philosophy**: `distinct` embodies **perfect memory** - it never forgets what it has seen, ensuring uniqueness through accumulated values.
135
+ ### tap - The Observer Gatekeeper
136
+
137
+ ```typescript
138
+ const tap = <T>(fn: (value: T) => void | Promise<void>) =>
139
+ filter<T, {}>({}, async (_, value) => {
140
+ await fn(value);
141
+ return [true, {}]; // Always pass through
142
+ });
143
+
144
+ // Usage: Side effects without changing the stream
145
+ stream.pipe(tap((value) => console.log("Saw:", value)));
146
+ stream.pipe(tap(async (value) => await logToDatabase(value)));
147
+ ```
138
148
 
139
149
  ## The Termination
140
150
 
@@ -151,6 +161,37 @@ const untilCondition = <T>(condition: (value: T) => boolean) =>
151
161
 
152
162
  This represents a fundamental shift from infinite streams to **purpose-driven streams** that know when their work is done.
153
163
 
164
+ ## Enhanced Pipe Integration
165
+
166
+ The new pipe architecture enables seamless integration:
167
+
168
+ ```typescript
169
+ // Filter integrates with any transformer
170
+ const result = stream
171
+ .pipe(filter({}, (_, v) => [v > 0, {}])) // Returns Stream<T>
172
+ .pipe(map({}, (_, v) => [v.toString(), {}])) // Returns Stream<string>
173
+ .pipe(toState("0")); // Returns State<string>
174
+
175
+ // Complex filtering chains
176
+ const processed = source
177
+ .pipe(
178
+ filter({ seen: 0 }, (state, v) => {
179
+ if (state.seen >= 100) return; // Terminate after 100
180
+ return [v > 0, { seen: state.seen + 1 }];
181
+ })
182
+ )
183
+ .pipe(tap((v) => console.log("Positive:", v)))
184
+ .pipe(
185
+ filter({ count: 0 }, (state, v) => {
186
+ return [state.count % 2 === 0, { count: state.count + 1 }]; // Every other
187
+ })
188
+ );
189
+ ```
190
+
191
+ **Note**: Filters compose naturally because they all speak the same language - **adaptive constraints** that can terminate, remember, and evolve.
192
+
193
+ **Design insight**: Filtering State creates **conditional reactivity** - the derived state only reacts to values that pass the adaptive constraints.
194
+
154
195
  ## Conclusion
155
196
 
156
197
  The `filter` transformer isn't just about removing unwanted values - it's about **intelligent gatekeeping** that:
@@ -146,6 +146,36 @@ const pluck = <T, K extends keyof T>(key: K) => map<T, {}, T[K]>({}, (_, value)
146
146
 
147
147
  `pluck` demonstrates **selective transformation** - the alchemist knows exactly what it wants and ignores everything else.
148
148
 
149
+ ### tap - The Observer Gatekeeper
150
+
151
+ ```typescript
152
+ const tap = <T>(fn: (value: T) => void | Promise<void>) =>
153
+ map<T, {}, T>({}, async (_, value) => {
154
+ await fn(value);
155
+ return [value, {}]; // Always pass through
156
+ });
157
+
158
+ // Usage: Side effects without changing the stream
159
+ stream.pipe(tap((value) => console.log("Saw:", value)));
160
+ stream.pipe(tap(async (value) => await logToDatabase(value)));
161
+ ```
162
+
163
+ ### scan - The Accumulating Alchemist
164
+
165
+ ```typescript
166
+ const scan = <T, U>(fn: (acc: U, value: T) => U, initial: U) =>
167
+ map<T, { acc: U }, U>({ acc: initial }, (state, value) => {
168
+ const newAcc = fn(state.acc, value);
169
+ return [newAcc, { acc: newAcc }];
170
+ });
171
+
172
+ // Usage: Accumulate values over time
173
+ stream.pipe(scan((sum, value) => sum + value, 0)); // Running sum
174
+ stream.pipe(scan((max, value) => Math.max(max, value), -Infinity)); // Running max
175
+ ```
176
+
177
+ `scan` demonstrates **accumulative transformation** - each value builds upon all previous values, creating a growing understanding.
178
+
149
179
  ## The Order Preservation
150
180
 
151
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.
@@ -182,3 +212,5 @@ The `map` transformer isn't just about changing values - it's about **intelligen
182
212
  - **Learns** from patterns (adaptation)
183
213
  - **Evolves** its approach over time (constraints)
184
214
  - **Preserves** the narrative order (respect)
215
+ - **Integrates** with reactive state (toState)
216
+ - **Accumulates** knowledge over time (scan)
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