evg_observable 2.15.8 → 3.0.1

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/MIGRATION.md ADDED
@@ -0,0 +1,410 @@
1
+ # Migration Guide: v2.x → v3.0.0
2
+
3
+ This is a **breaking change** release. All operator names have been updated for better clarity and RxJS alignment.
4
+
5
+ ---
6
+
7
+ ## Quick Start
8
+
9
+ ### Automated Migration (Recommended)
10
+
11
+ Use this command to automatically update your codebase:
12
+
13
+ ```bash
14
+ find src -name "*.ts" -exec sed -i \
15
+ -e 's/\.stream(/\.of(/g' \
16
+ -e 's/\.refine(/\.and(/g' \
17
+ -e 's/\.then(/\.map(/g' \
18
+ -e 's/\.setOnce(/\.once(/g' \
19
+ -e 's/\.serialize(/\.toJson(/g' \
20
+ -e 's/\.deserialize(/\.fromJson(/g' \
21
+ -e 's/\.switch(/\.choice(/g' \
22
+ -e 's/\.case(/\.or(/g' \
23
+ -e 's/\.pushRefiners(/\.allOf(/g' \
24
+ -e 's/\.pushFilters(/\.allOf(/g' \
25
+ -e 's/\.pushCases(/\.anyOf(/g' \
26
+ -e 's/\.setAscendingSort(/\.ascendingSort(/g' \
27
+ -e 's/\.setDescendingSort(/\.descendingSort(/g' \
28
+ {} \;
29
+ ```
30
+
31
+ **Note:** Test your code after migration to ensure correct behavior.
32
+
33
+ ---
34
+
35
+ ## Manual Migration Table
36
+
37
+ ### Pipe Operators (Outbound Transformations)
38
+
39
+ | v2.x Method | v3.0.0 Method | Description |
40
+ |-------------|---------------|-------------|
41
+ | `.stream(values)` | `.of(values)` | Emit array elements one by one |
42
+ | `.refine(condition)` | `.and(condition)` | Filter values (AND logic) |
43
+ | `.then<K>(fn)` | `.map<K>(fn)` | Transform value type |
44
+ | `.setOnce()` | `.once()` | Receive one value then unsubscribe |
45
+ | `.serialize()` | `.toJson()` | Convert to JSON string |
46
+ | `.deserialize<K>()` | `.fromJson<K>()` | Parse from JSON string |
47
+ | `.switch()` | `.choice()` | Begin OR-logic branching |
48
+ | `.case(condition)` | `.or(condition)` | Add OR condition |
49
+ | `.pushRefiners(arr)` | `.allOf(arr)` | Add multiple AND filters |
50
+ | `.pushCases(arr)` | `.anyOf(arr)` | Add multiple OR conditions |
51
+
52
+ ### FilterCollection Operators (Inbound Filters)
53
+
54
+ | v2.x Method | v3.0.0 Method | Description |
55
+ |-------------|---------------|-------------|
56
+ | `.filter(condition)` | `.and(condition)` | Add inbound filter (AND logic) |
57
+ | `.pushFilters(arr)` | `.allOf(arr)` | Add multiple inbound filters |
58
+ | `.switch()` | `.choice()` | Begin OR-logic branching |
59
+ | `.case(condition)` | `.or(condition)` | Add OR condition |
60
+ | `.pushCases(arr)` | `.anyOf(arr)` | Add multiple OR conditions |
61
+
62
+ ### OrderedObservable Operators
63
+
64
+ | v2.x Method | v3.0.0 Method | Description |
65
+ |-------------|---------------|-------------|
66
+ | `.setAscendingSort()` | `.ascendingSort()` | Sort subscribers ascending by order |
67
+ | `.setDescendingSort()` | `.descendingSort()` | Sort subscribers descending by order |
68
+
69
+ ---
70
+
71
+ ## Migration Examples
72
+
73
+ ### Example 1: Basic Pipe Chain
74
+
75
+ **Before (v2.x):**
76
+ ```typescript
77
+ observable$
78
+ .pipe()
79
+ .refine(x => x > 0)
80
+ .then(x => x * 2)
81
+ .setOnce()
82
+ .subscribe(result => console.log(result));
83
+ ```
84
+
85
+ **After (v3.0.0):**
86
+ ```typescript
87
+ observable$
88
+ .pipe()
89
+ .and(x => x > 0) // refine → and
90
+ .map(x => x * 2) // then → map
91
+ .once() // setOnce → once
92
+ .subscribe(result => console.log(result));
93
+ ```
94
+
95
+ ---
96
+
97
+ ### Example 2: Batch Emission
98
+
99
+ **Before (v2.x):**
100
+ ```typescript
101
+ observable$.stream([1, 2, 3, 4, 5]);
102
+ ```
103
+
104
+ **After (v3.0.0):**
105
+ ```typescript
106
+ observable$.of([1, 2, 3, 4, 5]); // stream → of
107
+ ```
108
+
109
+ ---
110
+
111
+ ### Example 3: JSON Serialization
112
+
113
+ **Before (v2.x):**
114
+ ```typescript
115
+ const jsonPipe = observable$
116
+ .pipe()
117
+ .serialize()
118
+ .subscribe(jsonString => { /* ... */ });
119
+
120
+ const objPipe = jsonObservable$
121
+ .pipe()
122
+ .deserialize<MyType>()
123
+ .subscribe(obj => { /* ... */ });
124
+ ```
125
+
126
+ **After (v3.0.0):**
127
+ ```typescript
128
+ const jsonPipe = observable$
129
+ .pipe()
130
+ .toJson() // serialize → toJson
131
+ .subscribe(jsonString => { /* ... */ });
132
+
133
+ const objPipe = jsonObservable$
134
+ .pipe()
135
+ .fromJson<MyType>() // deserialize → fromJson
136
+ .subscribe(obj => { /* ... */ });
137
+ ```
138
+
139
+ ---
140
+
141
+ ### Example 4: OR Logic (Switch/Case)
142
+
143
+ **Before (v2.x):**
144
+ ```typescript
145
+ observable$
146
+ .pipe()
147
+ .switch()
148
+ .case(x => x === 'red')
149
+ .case(x => x === 'blue')
150
+ .subscribe(color => { /* ... */ });
151
+ ```
152
+
153
+ **After (v3.0.0):**
154
+ ```typescript
155
+ observable$
156
+ .pipe()
157
+ .choice() // switch → choice
158
+ .or(x => x === 'red') // case → or
159
+ .or(x => x === 'blue')
160
+ .subscribe(color => { /* ... */ });
161
+ ```
162
+
163
+ ---
164
+
165
+ ### Example 5: Batch Filters
166
+
167
+ **Before (v2.x):**
168
+ ```typescript
169
+ const filters = [
170
+ (x: Person) => x.age > 18,
171
+ (x: Person) => x.name.length > 0,
172
+ (x: Person) => x.email.includes('@')
173
+ ];
174
+
175
+ observable$
176
+ .pipe()
177
+ .pushRefiners(filters)
178
+ .subscribe(person => { /* ... */ });
179
+ ```
180
+
181
+ **After (v3.0.0):**
182
+ ```typescript
183
+ const filters = [
184
+ (x: Person) => x.age > 18,
185
+ (x: Person) => x.name.length > 0,
186
+ (x: Person) => x.email.includes('@')
187
+ ];
188
+
189
+ observable$
190
+ .pipe()
191
+ .allOf(filters) // pushRefiners → allOf
192
+ .subscribe(person => { /* ... */ });
193
+ ```
194
+
195
+ ---
196
+
197
+ ### Example 6: Inbound Filters
198
+
199
+ **Before (v2.x):**
200
+ ```typescript
201
+ men$.addFilter()
202
+ .filter(person => person.age > 17)
203
+ .filter(person => person.age < 60);
204
+ ```
205
+
206
+ **After (v3.0.0):**
207
+ ```typescript
208
+ men$.addFilter()
209
+ .and(person => person.age > 17) // filter → and
210
+ .and(person => person.age < 60);
211
+ ```
212
+
213
+ ---
214
+
215
+ ## New Features in v3.0.0
216
+
217
+ ### 1. `in<K,V>()` Operator - Object Iteration
218
+
219
+ Iterate over object properties and emit `[key, value]` tuples:
220
+
221
+ ```typescript
222
+ const stats = {
223
+ users: 1500,
224
+ sessions: 4200,
225
+ errors: 12
226
+ };
227
+
228
+ observable$.in(stats);
229
+ // Emits: ['users', 1500], ['sessions', 4200], ['errors', 12]
230
+
231
+ // Usage with pipe:
232
+ observable$
233
+ .pipe()
234
+ .subscribe(([metric, count]) => {
235
+ console.log(`${metric}: ${count}`);
236
+ });
237
+
238
+ observable$.in(stats);
239
+ ```
240
+
241
+ **Use cases:**
242
+ - Iterating over configuration objects
243
+ - Processing key-value data structures
244
+ - Converting objects to streams
245
+
246
+ ---
247
+
248
+ ### 2. `group()` Operator - Multi-Listener Optimization
249
+
250
+ Optimize performance when multiple listeners need the same pipe transformations:
251
+
252
+ ```typescript
253
+ const group = observable$
254
+ .pipe()
255
+ .and(x => x > 0)
256
+ .map(x => x * 2)
257
+ .group(); // Type finalizer - prevents further chaining
258
+
259
+ // All listeners share single pipe execution
260
+ group.add(listener1);
261
+ group.add(listener2);
262
+ group.add(listener3);
263
+
264
+ // Performance: 1x pipe execution instead of 3x
265
+ ```
266
+
267
+ **Key benefits:**
268
+ - **Performance:** Single pipe execution for all listeners (up to 54,000x faster in benchmarks)
269
+ - **Type safety:** TypeScript prevents adding operators after `.group()`
270
+ - **Convenience:** Fluent API for adding multiple listeners
271
+
272
+ **Use cases:**
273
+ - Multiple UI components listening to same data stream
274
+ - Event broadcasting to multiple handlers
275
+ - Optimizing high-frequency emissions with many subscribers
276
+
277
+ ---
278
+
279
+ ## Breaking Changes
280
+
281
+ ### API Changes
282
+
283
+ 1. **All 14 operator names changed** - See migration table above
284
+ 2. **Semantic consistency:** `and()` for AND logic, `or()` for OR logic, `allOf()`/`anyOf()` for batch operations
285
+ 3. **RxJS alignment:** `map()`, `of()` match RxJS naming for easier migration
286
+
287
+ ### Type Signatures
288
+
289
+ **No changes** - All type signatures remain the same. Only method names changed.
290
+
291
+ ### Bundle Size
292
+
293
+ **Increased:** 6.4 kB → 7.2 kB (+12.5%)
294
+ - **Reason:** New operators (`in()`, `group()`) add functionality
295
+ - **Trade-off:** Still **12.2x smaller** than RxJS (88 kB)
296
+
297
+ ### Performance
298
+
299
+ **Improved or maintained:**
300
+ - Emit performance: +7% faster than v2.x
301
+ - Multiple subscribers (10): +10% faster than v2.x
302
+ - Still **2-7x faster** than RxJS across all operations
303
+
304
+ ---
305
+
306
+ ## Compatibility
307
+
308
+ ### Requirements
309
+
310
+ - **Node.js:** 16.x or higher (unchanged from v2.x)
311
+ - **TypeScript:** 4.4+ (required for `Object.hasOwn` support)
312
+ - **ES Target:** ES2022 or higher (updated from ES2020)
313
+
314
+ ### Supported Environments
315
+
316
+ - ✅ Node.js 16+
317
+ - ✅ Modern browsers (Chrome 94+, Firefox 92+, Safari 15.4+)
318
+ - ✅ TypeScript 4.4+
319
+ - ⚠️ Legacy browsers: May need polyfill for `Object.hasOwn`
320
+
321
+ ---
322
+
323
+ ## Common Migration Issues
324
+
325
+ ### Issue 1: TypeScript Compilation Errors
326
+
327
+ **Symptom:**
328
+ ```
329
+ error TS2339: Property 'refine' does not exist on type 'ISetup<T>'
330
+ ```
331
+
332
+ **Solution:**
333
+ Update method name: `.refine()` → `.and()`
334
+
335
+ ---
336
+
337
+ ### Issue 2: Runtime Errors After Migration
338
+
339
+ **Symptom:**
340
+ ```
341
+ TypeError: observable$.stream is not a function
342
+ ```
343
+
344
+ **Solution:**
345
+ Ensure all method names are updated. Run automated migration script again.
346
+
347
+ ---
348
+
349
+ ### Issue 3: Test Failures
350
+
351
+ **Symptom:**
352
+ Tests fail after migration with method not found errors.
353
+
354
+ **Solution:**
355
+ Update test files as well:
356
+ ```bash
357
+ find test -name "*.test.ts" -exec sed -i -e 's/\.refine(/\.and(/g' {} \;
358
+ ```
359
+
360
+ ---
361
+
362
+ ## Rollback Plan
363
+
364
+ If you need to rollback to v2.x:
365
+
366
+ 1. **Revert package version:**
367
+ ```bash
368
+ npm install evg_observable@2.x
369
+ ```
370
+
371
+ 2. **Revert code changes:**
372
+ ```bash
373
+ git revert <migration-commit-hash>
374
+ ```
375
+
376
+ 3. **Or use reverse migration script:**
377
+ ```bash
378
+ find src -name "*.ts" -exec sed -i \
379
+ -e 's/\.of(/\.stream(/g' \
380
+ -e 's/\.and(/\.refine(/g' \
381
+ -e 's/\.map(/\.then(/g' \
382
+ -e 's/\.once(/\.setOnce(/g' \
383
+ {} \;
384
+ ```
385
+
386
+ ---
387
+
388
+ ## Need Help?
389
+
390
+ - **Documentation:** [README.md](./README.md)
391
+ - **Issues:** https://github.com/your-repo/issues
392
+ - **Examples:** See `test/*.test.ts` for v3.0.0 usage patterns
393
+
394
+ ---
395
+
396
+ ## Changelog Summary
397
+
398
+ See [CHANGELOG.md](./CHANGELOG.md) for detailed changes.
399
+
400
+ **Major Changes:**
401
+ - 14 operators renamed for consistency and RxJS alignment
402
+ - New `in<K,V>()` operator for object iteration
403
+ - New `group()` operator for multi-listener optimization
404
+ - Performance improvements (+7% emit, +10% multi-subscriber)
405
+ - Bundle size increased to 7.2 kB (+12.5%) for new features
406
+
407
+ **No Breaking Changes:**
408
+ - All type signatures preserved
409
+ - No behavioral changes to existing operators
410
+ - Full backward compatibility in logic (only names changed)