semantic-typescript 2.0.0 → 2.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/CHANGELOG.md +587 -574
- package/dist/asynchronous/collectable.js +10 -4
- package/dist/optional.js +0 -1
- package/dist/readonly-map.d.ts +1 -0
- package/dist/readonly-map.js +26 -0
- package/dist/synchronous/collectable.js +2 -1
- package/package.json +1 -1
- package/readme.cn.md +1271 -1271
- package/readme.de.md +1397 -1397
- package/readme.es.md +1381 -1381
- package/readme.fr.md +1390 -1390
- package/readme.jp.md +1300 -1300
- package/readme.kr.md +1297 -1297
- package/readme.md +1442 -1442
- package/readme.ru.md +1378 -1378
- package/readme.tw.md +1271 -1271
package/CHANGELOG.md
CHANGED
|
@@ -1,574 +1,587 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
Notable changes to `semantic-typescript`. The format follows
|
|
4
|
-
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the version numbers
|
|
5
|
-
follow [Semantic Versioning](https://semver.org/).
|
|
6
|
-
|
|
7
|
-
A Simplified Chinese edition is kept in [`CHANGELOG.cn.md`](./CHANGELOG.cn.md).
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## [2.0.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
`
|
|
43
|
-
|
|
44
|
-
`
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
`
|
|
48
|
-
|
|
49
|
-
`
|
|
50
|
-
- **`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
`
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
`
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
`
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
`
|
|
112
|
-
`
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
- **`
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
-
|
|
182
|
-
`
|
|
183
|
-
`
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
- `
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
`
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
-
|
|
210
|
-
`
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
-
|
|
223
|
-
`
|
|
224
|
-
`
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
`
|
|
238
|
-
`
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
- **
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
`
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
`
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
###
|
|
398
|
-
|
|
399
|
-
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
`
|
|
446
|
-
- `
|
|
447
|
-
|
|
448
|
-
- `
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
`
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
- `
|
|
494
|
-
|
|
495
|
-
- `
|
|
496
|
-
|
|
497
|
-
- `
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
- `
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
- `
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
- `
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
`
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
[1.0.0]
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to `semantic-typescript`. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the version numbers
|
|
5
|
+
follow [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
A Simplified Chinese edition is kept in [`CHANGELOG.cn.md`](./CHANGELOG.cn.md).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## [2.0.1] - 2026-11-07
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`Optional` no longer freezes `Function.prototype`.** Importing the module ran
|
|
16
|
+
`Object.freeze(Object.getPrototypeOf(Optional))`; for a base class that value is
|
|
17
|
+
the shared `Function.prototype`, so the whole process lost the ability to augment
|
|
18
|
+
functions (`Object.defineProperty(Function.prototype, …)` threw a `TypeError`).
|
|
19
|
+
Instance immutability is unchanged: the constructor still freezes every instance
|
|
20
|
+
and defines its fields as non-writable, and the class plus its own prototype stay
|
|
21
|
+
frozen. Only the mutation of the global intrinsic was removed.
|
|
22
|
+
- **Unordered collectable buffers now use a read-only `Map` facade.** `Object.freeze(map)` does not disable `Map.prototype.set`, `delete` or `clear`, so the old buffer freeze did not actually protect buffered data. Attempts to mutate either synchronous or completed asynchronous unordered buffers now throw `TypeError`.
|
|
23
|
+
|
|
24
|
+
## [2.0.0] - 2026-11-05
|
|
25
|
+
|
|
26
|
+
This release covers the work merged after 1.2.0. It is a large change: the
|
|
27
|
+
collection families were split, the phase-ring API was reworked, the statistics,
|
|
28
|
+
window, signal and distribution modules became public entry points, and several
|
|
29
|
+
asynchronous lifecycle defects were fixed. Read the "Breaking", "Changed" and
|
|
30
|
+
"Removed" sections before upgrading.
|
|
31
|
+
|
|
32
|
+
### Breaking
|
|
33
|
+
|
|
34
|
+
**Statistics now default to the definitions used by R, NumPy, pandas and Excel**
|
|
35
|
+
|
|
36
|
+
These are deliberate, owner-approved breaks: the old values were defined
|
|
37
|
+
differently from the mainstream tools, so keeping them would have preserved
|
|
38
|
+
compatibility at the cost of correctness. Each old behaviour remains reachable
|
|
39
|
+
through an explicit option.
|
|
40
|
+
|
|
41
|
+
- **`quantile(probability)` now defaults to Hyndman–Fan type 7**, the
|
|
42
|
+
parameterisation `h = (n - 1)p + 1` with linear interpolation, instead of
|
|
43
|
+
type 1 (`ceil(np)` nearest rank). Type 7 is the default of R `quantile`,
|
|
44
|
+
NumPy `quantile` (`method="linear"`), Excel `PERCENTILE.INC` and pandas
|
|
45
|
+
`quantile`. On `[1..8]` at `p = 0.75` it returns `6.25` where it returned
|
|
46
|
+
`6`; on `[2,4,4,4,5,5,7,9]` at `p = 0.9` it returns `7.6` where it returned
|
|
47
|
+
`9`. All nine types are available as
|
|
48
|
+
`quantile(p, { method: "type-1" })` … `{ method: "type-9" }`, and
|
|
49
|
+
`"type-1"` restores the old nearest-rank answer exactly.
|
|
50
|
+
- **`interquartileRange()` follows the same method** (default type 7), so
|
|
51
|
+
Tukey fences now line up with R and NumPy: `[1..8]` gives `3.5`, not `4`,
|
|
52
|
+
and `[1,2,3,4]` gives `1.5`, not `2`. Pass `{ method }` to change the type.
|
|
53
|
+
- **`kurtosis()` now defaults to the bias-corrected excess estimator `G2`**,
|
|
54
|
+
`G2 = ((n - 1) / ((n - 2)(n - 3))) · ((n + 1)g2 + 6)`, matching Excel
|
|
55
|
+
`KURT` and pandas `kurt`, instead of the biased `g2 = m4 / m2² - 3`. On
|
|
56
|
+
`[1,2,3,4]` it returns `-1.2` where it returned `-1.36`; pass
|
|
57
|
+
`{ estimator: "g2" }` for the old value. `{ excess: false }` adds three back
|
|
58
|
+
and reports the non-excess fourth standardised moment.
|
|
59
|
+
- **`skewness()` now defaults to the bias-corrected `G1`**,
|
|
60
|
+
`G1 = √(n(n - 1))/(n - 2) · g1`, matching Excel `SKEW`, pandas `skew` and
|
|
61
|
+
SPSS, instead of the biased `g1 = m3 / m2^(3/2)`; pass
|
|
62
|
+
`{ estimator: "g1" }` to restore `g1`.
|
|
63
|
+
- **`variance()` and `standardDeviation()` now divide by `n - 1`** (Bessel's
|
|
64
|
+
correction), matching R `var`/`sd`, pandas and NumPy `var(ddof=1)`, instead
|
|
65
|
+
of `n`. On `[1,2,3,4]` the variance is `5/3` where it was `5/4`; pass
|
|
66
|
+
`{ ddof: 0 }` for the previous population value. `standardDeviation` is the
|
|
67
|
+
square root of that variance, so it remains very slightly biased even under
|
|
68
|
+
normality (Jensen's inequality).
|
|
69
|
+
- **Small samples now return an empty `Optional` instead of `0` or `NaN`.**
|
|
70
|
+
`G2` is undefined below four observations, `G1` below three, and the sample
|
|
71
|
+
variance and standard deviation below two; every statistic on an empty view
|
|
72
|
+
is undefined too, as are skewness and kurtosis on a constant sample. For
|
|
73
|
+
example, with three observations the default `kurtosis()` is empty while
|
|
74
|
+
`{ estimator: "g2" }` is defined, and with two observations `skewness()` is
|
|
75
|
+
empty while `{ estimator: "g1" }` is `0`. Bigint views return the same
|
|
76
|
+
empties; with `{ ddof: 0 }` a single observation still has a defined
|
|
77
|
+
variance of zero.
|
|
78
|
+
- **`variance()` and `standardDeviation()` now use a two-pass computation**
|
|
79
|
+
(mean first, then squared deviations) instead of the collector's
|
|
80
|
+
`sum(x²) - sum(x)²/n` form, which suffers catastrophic cancellation when the
|
|
81
|
+
standard deviation is small relative to the mean.
|
|
82
|
+
- **`skewness` and `kurtosis` gained closed-form standard errors.**
|
|
83
|
+
`skewnessStandardError()` and `kurtosisStandardError()` on the numeric
|
|
84
|
+
statistics views return `√(6n(n - 1)/((n - 2)(n + 1)(n + 3)))` and
|
|
85
|
+
`√(24n(n - 1)²/((n - 3)(n - 2)(n + 3)(n + 5)))`, the SAS/SPSS and
|
|
86
|
+
`e1071::skewness`/`e1071::kurtosis` forms. They require three and four
|
|
87
|
+
observations respectively. The bigint views omit them because rounding a
|
|
88
|
+
standard error to an integer would report zero for most samples.
|
|
89
|
+
- **These methods now return `Optional`.** `variance`, `standardDeviation`,
|
|
90
|
+
`quantile`, `interquartileRange`, `skewness` and `kurtosis` all wrap their
|
|
91
|
+
result, so callers must unwrap with `.get()`, `.orElse(...)` or test
|
|
92
|
+
`.isPresent()`. The bigint view still rounds each result to a whole bigint.
|
|
93
|
+
- **Reconciliation.** The new defaults reproduce the published results:
|
|
94
|
+
`[1,2,3,4]` gives `variance(ddof = 1) = 5/3`, `G2 = -1.2`, `g2 = -1.36`,
|
|
95
|
+
`G1 = g1 = 0`; `[1..8]` at `p = 0.75` gives type 7 `6.25` and type 1 `6`;
|
|
96
|
+
the Wikipedia kurtosis example (`n = 20`) gives `g1 = 4.129251`,
|
|
97
|
+
`G1 = 4.471885`, `g2 = 15.051427`, `G2 = 19.998429`, and standard errors
|
|
98
|
+
`0.512103` and `0.992384`. These match R, NumPy, pandas and Excel to the
|
|
99
|
+
published precision.
|
|
100
|
+
|
|
101
|
+
**Signal analysis now uses the physical power and DFT-even conventions**
|
|
102
|
+
|
|
103
|
+
These are also deliberate, owner-approved breaks: the old definitions mixed
|
|
104
|
+
amplitude and power or assumed that only complete frames exist, so they returned
|
|
105
|
+
systematically biased levels and time-frequency frames.
|
|
106
|
+
|
|
107
|
+
- **`decibel` is removed and split into `amplitudeDecibel` and
|
|
108
|
+
`powerDecibel`.** `amplitudeDecibel` keeps the old `20·log10` convention for
|
|
109
|
+
amplitude-like ratios; `powerDecibel` applies `10·log10` for power, energy,
|
|
110
|
+
mean square and power spectral density. Power `0.25` is `−6.02 dB` under
|
|
111
|
+
`powerDecibel`, while the old function reported `−12.04 dB`. `Bin.decibel` and
|
|
112
|
+
`Spectrum.decibelOf` remain amplitude levels; `Spectrum.powerDecibelOf` is the
|
|
113
|
+
matching power level.
|
|
114
|
+
- **`Spectrum.bandEnergy(low, high)` now defaults to the one-sided reading.**
|
|
115
|
+
A real spectrum's conjugate half is folded into the non-negative axis, with
|
|
116
|
+
DC and Nyquist counted once and every interior bin counted twice, so a band
|
|
117
|
+
that covers the whole one-sided axis satisfies Parseval (`Σ|X|² = N·Σx²`).
|
|
118
|
+
The old raw sum, which counted only the positive half of a band below Nyquist
|
|
119
|
+
(−3.01 dB), remains available as `bandEnergy(low, high, "two-sided")`; use it
|
|
120
|
+
for complex spectra.
|
|
121
|
+
- **`Spectrum.flatness()` now measures the one-sided power spectrum.** The old
|
|
122
|
+
method took the geometric/arithmetic mean of magnitudes over both complex
|
|
123
|
+
halves. The result is now computed from `power()`, over bins `0` through
|
|
124
|
+
`floor(count/2)`, without the display-only amplitude doubling of
|
|
125
|
+
`oneSided()`; a zero bin still reports `0`.
|
|
126
|
+
- **`Sampler.shortTimeFourierTransform` and `Sampler.spectrogram` now default
|
|
127
|
+
to the periodic Hann window, `boundary: "zeros"` and `padded: true`.** The
|
|
128
|
+
symmetric Hann window and the old "complete frames only" path (`7` frames for
|
|
129
|
+
`64` samples, frame `16`, hop `8`) remain reachable with
|
|
130
|
+
`useHannWindow`/`useHannPeriodicWindow` and
|
|
131
|
+
`{ boundary: "none", padded: false }`; the default now returns `9` frames,
|
|
132
|
+
loses no tail samples, and matches SciPy's `stft` defaults. The new optional
|
|
133
|
+
fifth argument takes `{ boundary, padded }`.
|
|
134
|
+
- **`Spectrogram` frame times are now frame centres.** `getTime(k)` returns
|
|
135
|
+
`(k·hop + frameSize/2)/rate` for an unextended view and
|
|
136
|
+
`(k·hop + (frameSize mod 2)/2)/rate` for an extended one, instead of the frame
|
|
137
|
+
start. `getDuration()` and `toFrame()` also trim the boundary extension.
|
|
138
|
+
The constructor gained an optional fourth argument, the boundary mode, which
|
|
139
|
+
defaults to `"none"`.
|
|
140
|
+
|
|
141
|
+
### Added
|
|
142
|
+
|
|
143
|
+
**Collection families**
|
|
144
|
+
|
|
145
|
+
- **`OrderedSet` / `UnorderedSet`**, each in synchronous and asynchronous form.
|
|
146
|
+
`OrderedSet` decides uniqueness and iteration order by a comparator (defaulting
|
|
147
|
+
to `useCompare`); `UnorderedSet` buckets by `useHash` and compares with
|
|
148
|
+
SameValueZero. Iteration order is part of the contract for the ordered variant
|
|
149
|
+
and explicitly unspecified for the unordered one.
|
|
150
|
+
- **`OrderedLRUSet` / `UnorderedLRUSet`** and **`OrderedSkipSet` /
|
|
151
|
+
`UnorderedSkipSet`**, closing the gap where the LRU and SKIP families offered
|
|
152
|
+
ordered and unordered maps but only an undifferentiated set.
|
|
153
|
+
- **`OrderedMap` / `UnorderedMap`** promoted to independent root interfaces. The
|
|
154
|
+
former common base is gone, so neither variant inherits ordering promises from
|
|
155
|
+
the other.
|
|
156
|
+
|
|
157
|
+
**Error model**
|
|
158
|
+
|
|
159
|
+
- A typed error hierarchy in `structure/error.ts`: fifteen classes covering
|
|
160
|
+
validation, indexing, capacity, state, concurrency, collection protocol,
|
|
161
|
+
serialisation, numeric, phase, and configuration failures. Each carries a
|
|
162
|
+
stable `name`, an optional `cause` for the originating error, and an optional
|
|
163
|
+
`context` bag for diagnostics, and each has a brand guard.
|
|
164
|
+
- **`SemanticRangeError`**, an alias for the exported `RangeError` class. Both
|
|
165
|
+
names denote one class, so `instanceof` checks hold across them. The class
|
|
166
|
+
keeps its historical name — no library module imports it implicitly, so a bare
|
|
167
|
+
`new RangeError(...)` still reaches the global constructor — but a consumer that
|
|
168
|
+
writes `import { RangeError }` shadows that global for the whole module,
|
|
169
|
+
turning an incidental `new RangeError(...)` in the same file into a library
|
|
170
|
+
error. Importing `SemanticRangeError` instead leaves the global untouched.
|
|
171
|
+
|
|
172
|
+
**Module layout**
|
|
173
|
+
|
|
174
|
+
- **Collector factories moved to `collectors.ts`.** `collector.ts` now declares
|
|
175
|
+
only `SynchronousCollector` and `AsynchronousCollector` (about 340 and 350
|
|
176
|
+
lines); the fifty-three `useSynchronousXxx` and fifty-three `useAsynchronousXxx`
|
|
177
|
+
factories live in `synchronous/collectors.ts` and `asynchronous/collectors.ts`.
|
|
178
|
+
The dependency runs one way — `collectors.ts` imports `collector.ts`, never the
|
|
179
|
+
reverse — and `factory.ts` remains the module that builds `Semantic` values, so
|
|
180
|
+
creating a `Semantic` and creating a collector are now separate jobs.
|
|
181
|
+
- **Forests get their own module.** `rootedForest` and `unionFindForest` left
|
|
182
|
+
`structure/tree/` for `structure/forest/`, with `forest/index.ts` and a
|
|
183
|
+
`structure/forest.ts` barrel beside the existing `structure/tree.ts`. The
|
|
184
|
+
binomial and Fibonacci heaps, the breadth-first and depth-first search trees
|
|
185
|
+
and the minimum spanning tree import the rooted forest from the new path, as
|
|
186
|
+
does the tree-API boundary type test.
|
|
187
|
+
|
|
188
|
+
**Phase rings**
|
|
189
|
+
|
|
190
|
+
- `PhaseField` and `useField` in `mathematics/field.ts`: a bounded score in
|
|
191
|
+
`[-1, 1]` defined as a truncated cosine series. The constructor enforces
|
|
192
|
+
`|offset| + Σ|weight| ≤ 1`, so the bound is a consequence of the construction
|
|
193
|
+
rather than a clamp applied afterwards.
|
|
194
|
+
- `Cycle` now reports its own state: `purity()`, `sequences()`,
|
|
195
|
+
`zeroSequence()`, `isBalanced()`, `resultant()`, `relativeAt()`, `viewAt()`,
|
|
196
|
+
`viewsAt()`, `jetAt()`, `windingAt()`, `errorIntegralAt()`, `scoreAt()`,
|
|
197
|
+
`scoresAt()`, `analyse()`, and `toSpectrum()`.
|
|
198
|
+
- `combineCycles(a, b)` joins two rings on their least common multiple and
|
|
199
|
+
reports the pair-compatibility condition, so the joint ring is a pullback
|
|
200
|
+
rather than a product.
|
|
201
|
+
- `useAngularSpectrum(cycle, instants, plan)` builds the two-dimensional
|
|
202
|
+
`(ω, n)` plane, one column per spatial mode.
|
|
203
|
+
- `BlobLike`, a structural description of the bytes `useBlob` needs, so the
|
|
204
|
+
published declarations no longer depend on the DOM library being present in the
|
|
205
|
+
consumer's compilation.
|
|
206
|
+
|
|
207
|
+
**Signal analysis**
|
|
208
|
+
|
|
209
|
+
- **Periodic, DFT-even windows**: `useHannPeriodicWindow`,
|
|
210
|
+
`useHammingPeriodicWindow`, `useBlackmanPeriodicWindow`,
|
|
211
|
+
`useNuttallPeriodicWindow`, `useFlatTopPeriodicWindow` and
|
|
212
|
+
`useKaiserPeriodicWindow(beta)`. They evaluate the same shapes as the
|
|
213
|
+
symmetric windows against `count` rather than `count - 1`, so a periodic Hann
|
|
214
|
+
window has a constant overlap-add sum of `1.000000` at a half-frame hop for
|
|
215
|
+
every length, while the symmetric form ripples by `0.841 dB` at `N = 16` and
|
|
216
|
+
still by `0.013 dB` at `N = 1024`. The existing symmetric exports are
|
|
217
|
+
unchanged.
|
|
218
|
+
- **`Spectrum.powerDecibelOf(index, normalization?, reference?)`**, the power
|
|
219
|
+
counterpart of `decibelOf`, returning `10·log10(power / reference)`.
|
|
220
|
+
- **`BandSidedness`** (`"one-sided" | "two-sided"`), the explicit argument type
|
|
221
|
+
of the corrected `Spectrum.bandEnergy`.
|
|
222
|
+
- **`TimeFrequencyOptions`**, the `{ boundary?, padded? }` options of
|
|
223
|
+
`shortTimeFourierTransform` and `spectrogram`, and the `BoundaryExtension`
|
|
224
|
+
(`"zeros" | "constant" | "none"`) type they use.
|
|
225
|
+
- **`Spectrogram.getBoundary()`** and **`Sampler.spectrogram(..., options)`**,
|
|
226
|
+
so a spectrogram retains the extension mode and trims it during `toFrame`.
|
|
227
|
+
|
|
228
|
+
**Public modules**
|
|
229
|
+
|
|
230
|
+
- **`statistics.ts`, `window.ts`, `signal.ts` and `distribution.ts` are now the
|
|
231
|
+
home of their API**, in both `synchronous/` and `asynchronous/`. The classes
|
|
232
|
+
and value objects they own are re-exported by `semantic.ts`, so the historical
|
|
233
|
+
import path `#semantic/synchronous/semantic` (and its asynchronous twin) keeps
|
|
234
|
+
exposing them while the duplicate definitions are gone.
|
|
235
|
+
- **New named exports**: `SynchronousStatistics`, `SynchronousBigIntStatistics`,
|
|
236
|
+
`SynchronousNumericStatistics`, `SynchronousWindowCollectable`,
|
|
237
|
+
`SynchronousWindowArrayCollectable`, `SynchronousSignalCollectable`,
|
|
238
|
+
`SynchronousDistributionCollectable` and their `Asynchronous*` counterparts,
|
|
239
|
+
plus the distribution value objects (`Histogram`, `HistogramBin`,
|
|
240
|
+
`EmpiricalDistribution`, `MomentSummary`, `RobustSummary`, `DensityEstimate`)
|
|
241
|
+
and `SpectralDensity`. Every class carries the synchronous/asynchronous prefix
|
|
242
|
+
the rest of the library uses, because an unprefixed pair would collide in the
|
|
243
|
+
package barrel.
|
|
244
|
+
- **Deep imports**: `package.json` now maps `semantic-typescript/signal`,
|
|
245
|
+
`semantic-typescript/statistics`, `semantic-typescript/window` and
|
|
246
|
+
`semantic-typescript/distribution` to the synchronous module of the same name,
|
|
247
|
+
with its declaration file, so a consumer can import one analysis module
|
|
248
|
+
without loading the whole barrel.
|
|
249
|
+
- **`SynchronousWindowArrayCollectable`** (and its asynchronous twin) materialises
|
|
250
|
+
`slide` / `tumble` into arrays. `toWindow()` keeps returning
|
|
251
|
+
`SynchronousWindowCollectable`, the lazy pipeline form the README documents, so
|
|
252
|
+
a window can still be transformed before it is consumed.
|
|
253
|
+
|
|
254
|
+
**Project**
|
|
255
|
+
|
|
256
|
+
- README rewritten in nine languages on a shared thirteen-section outline, with a
|
|
257
|
+
new section on periodic analysis.
|
|
258
|
+
- `.vscode/settings.json` so editor auto-imports prefer the project's path alias
|
|
259
|
+
over relative specifiers.
|
|
260
|
+
|
|
261
|
+
### Changed
|
|
262
|
+
|
|
263
|
+
- **`Cycle.frequency` is the ambient rotation rate**, not a phase step between
|
|
264
|
+
positions. The environment advances every phasor by the same angle and therefore
|
|
265
|
+
cannot break the intrinsic pattern. Position phases are now derived from the
|
|
266
|
+
exact residue `i mod n`, which makes `phaseAt(i)` and `phaseAt(i + n)`
|
|
267
|
+
identical to the bit rather than merely close.
|
|
268
|
+
- **`useText` slices by code point** rather than by UTF-16 index, so astral
|
|
269
|
+
characters stay whole; inverted bounds are still swapped and negative positions
|
|
270
|
+
still clamped to zero, matching the documented slice behaviour.
|
|
271
|
+
- **`useRange` accepts descending ranges** when the step is negative, and rejects
|
|
272
|
+
a step whose numeric kind differs from the bounds' kind instead of coercing
|
|
273
|
+
between `number` and `bigint`.
|
|
274
|
+
- The JSDoc for every factory in `factory.ts` and every hook in `hook.ts` was
|
|
275
|
+
rewritten to document actual behaviour, including the overloads.
|
|
276
|
+
- Every one of the 296 interfaces exported from `structure/tree/` now carries an
|
|
277
|
+
interface JSDoc block that states its contract, defaults and cost. Both
|
|
278
|
+
`collectors.ts` modules document their thirty-four factory interfaces and every
|
|
279
|
+
overload in the same way.
|
|
280
|
+
|
|
281
|
+
### Removed
|
|
282
|
+
|
|
283
|
+
- **`SynchronousSet` / `AsynchronousSet` / `SynchronousMap` / `AsynchronousMap`**,
|
|
284
|
+
together with their brand symbols and guards. Use the ordered or unordered
|
|
285
|
+
variant that matches the semantics you need. There is no compatibility alias.
|
|
286
|
+
- The `Collector` base types of the map family, which are replaced by internal,
|
|
287
|
+
unbranded contracts used only to compose the LRU and SKIP families.
|
|
288
|
+
- **The `structure/tree/rootedForest` and `structure/tree/unionFindForest` entry
|
|
289
|
+
points**, together with their re-exports from `tree/index.ts`. Both contracts
|
|
290
|
+
now live under `structure/forest/`; no compatibility re-export remains at the
|
|
291
|
+
old path.
|
|
292
|
+
|
|
293
|
+
### Fixed
|
|
294
|
+
|
|
295
|
+
- **`useSubscription` no longer leaks its subscription.** Teardown is idempotent
|
|
296
|
+
and runs on every exit path: the consumer asking to stop, the consumer throwing,
|
|
297
|
+
a subscription failing partway through, and an event arriving after the run has
|
|
298
|
+
ended. Every recorded `unsubscribe` is attempted even when an earlier one
|
|
299
|
+
throws, and `unmount` is attempted even when an unsubscribe threw, so one
|
|
300
|
+
failing host method cannot strand the others. Errors raised during teardown are
|
|
301
|
+
swallowed rather than masking the error that caused the teardown.
|
|
302
|
+
- **`useSubscription` completes at the accepted limit** rather than waiting for
|
|
303
|
+
one more event, and an empty event name list now completes immediately instead
|
|
304
|
+
of never settling. A host that fires the handler synchronously from `subscribe`
|
|
305
|
+
is also handled: the handler is unsubscribed once registration returns.
|
|
306
|
+
- **Event names are no longer restricted to strings.** A symbol or a number is
|
|
307
|
+
accepted as a single event name; previously it was rejected even though such
|
|
308
|
+
keys are ordinary property keys.
|
|
309
|
+
- **`useInterval` clears both of its handles.** A consumer that throws used to
|
|
310
|
+
leave the timer running forever, and a pending initial delay was not tracked at
|
|
311
|
+
all. Both are now cleared as soon as the run stops, and the consumer's error is
|
|
312
|
+
propagated unchanged.
|
|
313
|
+
- **`usePromise` no longer hangs.** The asynchronous executor that swallowed
|
|
314
|
+
rejections is gone: a rejected source and a throwing consumer both reject the
|
|
315
|
+
collection with the original reason.
|
|
316
|
+
- **`useBlob` cancels the stream on the error path.** It previously released the
|
|
317
|
+
reader's lock without cancelling the stream, leaving the underlying source
|
|
318
|
+
producing into a discarded buffer.
|
|
319
|
+
- **The flat-top window keeps its negative lobe.** `useFlatTopWindow` clamped
|
|
320
|
+
every weight at zero with `Math.max(0, ...)`, but a flat-top window is defined
|
|
321
|
+
to be partially negative: at `N = 1024` the unclamped symmetric window has
|
|
322
|
+
`578` negative samples (minimum `−0.070560`), coherent gain `0.215368` and
|
|
323
|
+
noise bandwidth `3.773946` bins, where the clamped version reported `0.233280`
|
|
324
|
+
and `3.199558`. Scalloping loss recovers from `−0.3087 dB` to `−0.0097 dB`
|
|
325
|
+
(about 32× better), and the periodic form matches the research target
|
|
326
|
+
(`CG 0.215579`, `ENBW 3.7702`, `HPBW 3.7247`, `−0.0098 dB`, `577` negative
|
|
327
|
+
samples).
|
|
328
|
+
- **The short-time transform no longer drops the signal tail.** The default
|
|
329
|
+
`boundary: "zeros"` and `padded: true` extend the signal by half a frame at
|
|
330
|
+
each end and zero-pad the tail, so `64` samples at frame `16` and hop `8`
|
|
331
|
+
produce `9` frames instead of `7` and every source sample is covered; a
|
|
332
|
+
`1000`-sample signal at frame `256` and hop `128` produces `9` frames instead
|
|
333
|
+
of `6` (232 samples were previously unreachable).
|
|
334
|
+
- **The short-time transform uses a periodic window by default.** The symmetric
|
|
335
|
+
Hann window does not satisfy constant-overlap-add: at 50 per cent overlap its
|
|
336
|
+
overlap-add sum ripples by `0.841 dB` at `N = 16` and `0.013 dB` at
|
|
337
|
+
`N = 1024`, whereas the new default `useHannPeriodicWindow` sums to
|
|
338
|
+
`1.000000` at every length.
|
|
339
|
+
- **`Spectrum.flatness()` uses the power spectrum.** The old method took the
|
|
340
|
+
geometric/arithmetic mean of magnitudes over the full two-sided spectrum; it
|
|
341
|
+
now uses `power()` over the one-sided half. Two bins with powers `4` and `1`
|
|
342
|
+
report `0.8` where the amplitude reading gave `0.9428`, and a unit impulse
|
|
343
|
+
reports `1`.
|
|
344
|
+
- **`Spectrum.bandEnergy()` no longer halves a band below Nyquist.** The old raw
|
|
345
|
+
two-sided sum counted only the positive half of a real spectrum: a unit cosine
|
|
346
|
+
at bin `1` of an `8`-point spectrum read `16` over `[0, 2)` although its total
|
|
347
|
+
power is `32`. The default one-sided reading folds the conjugate half (DC and
|
|
348
|
+
Nyquist once, interior bins twice) and now reads `32`, satisfying Parseval;
|
|
349
|
+
`"two-sided"` preserves the raw sum.
|
|
350
|
+
|
|
351
|
+
### Tests
|
|
352
|
+
|
|
353
|
+
- 684 assertions, all passing, with `tsc` reporting no diagnostics. New files
|
|
354
|
+
cover the ordered and unordered sets, the error hierarchy, forest
|
|
355
|
+
construction, and the 2.0.0 statistics definitions: all nine Hyndman–Fan
|
|
356
|
+
quantile types, `G1`/`G2` against `g1`/`g2`, `ddof`, the closed-form
|
|
357
|
+
standard errors, and the small-sample empty optionals across the
|
|
358
|
+
synchronous, asynchronous, numeric and bigint views.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## [1.2.0] - 2026-09-11
|
|
363
|
+
|
|
364
|
+
This release redrew the **division of responsibility in the index model**: a
|
|
365
|
+
pipeline performs only cheap, lazy index rewriting, and index tidying is left
|
|
366
|
+
entirely to the collectable. `translate` returns to a pure shift, `findAt` and
|
|
367
|
+
`findNegativeAt` address materialised order, and four asynchronous and boundary
|
|
368
|
+
defects are fixed.
|
|
369
|
+
|
|
370
|
+
### Changed
|
|
371
|
+
|
|
372
|
+
- **`translate` is a pure lazy index shift again.** Both the numeric and the
|
|
373
|
+
functional overload now do only `i + offset` and `i + mapper(element, i)`, and
|
|
374
|
+
no longer materialise the stream (in 1.1.0 the numeric overload buffered
|
|
375
|
+
everything before taking the remainder). `translate` can therefore be used on an
|
|
376
|
+
infinite stream followed by `limit`.
|
|
377
|
+
- **The ordered collectable normalises indices.** `toOrdered()` rewrites every
|
|
378
|
+
index to `((i mod n) + n) mod n`, where `n` is the element count, and then sorts
|
|
379
|
+
by index. The rotation, reversal and shuffling produced by `reverse`,
|
|
380
|
+
`translate` and `shuffle` only become visible at this step — `translate(7)` and
|
|
381
|
+
`translate(2)` are equivalent on five elements.
|
|
382
|
+
- **The unordered collectable does not tidy indices**, as a performance contract.
|
|
383
|
+
`toUnordered()` stores the raw index in a `Map` without normalisation or
|
|
384
|
+
sorting, keeping O(n) throughput; `translate(2)` collected unordered still
|
|
385
|
+
reports indices `2n, 3n, 4n, …`.
|
|
386
|
+
- **`findAt(k)` and `findNegativeAt(k)` address materialised order.** `findAt(1n)`
|
|
387
|
+
is always the second element of the materialised sequence and
|
|
388
|
+
`findNegativeAt(-1n)` always the last, whatever index rewriting happened
|
|
389
|
+
upstream. Both stop early, at O(k) and O(n − k) respectively.
|
|
390
|
+
- **`reverse()` is `-index - 1n`** rather than `-index`. Under remainder
|
|
391
|
+
normalisation `-index` pins the first element in place, because `-0n === 0n`;
|
|
392
|
+
only `-index - 1n` reverses.
|
|
393
|
+
- **`redirect` is the sole reordering mechanism.** `reverse`, `translate` and
|
|
394
|
+
`shuffle` are preset strategies over it, and all of them require `toOrdered()`
|
|
395
|
+
to take effect; an unordered collectable promises arrival order only.
|
|
396
|
+
|
|
397
|
+
### Fixed
|
|
398
|
+
|
|
399
|
+
- An asynchronous `translate` failed to chain onto the upstream promise, losing
|
|
400
|
+
elements or returning nothing (there was no such defect on the synchronous
|
|
401
|
+
side).
|
|
402
|
+
- The asynchronous ordered collectable omitted the remainder normalisation and
|
|
403
|
+
disagreed with the synchronous side; `translate(2).toOrdered()` returned an
|
|
404
|
+
unrotated sequence.
|
|
405
|
+
- Asynchronous `flatMap` resolved after the first inner iterable and silently
|
|
406
|
+
dropped the rest.
|
|
407
|
+
- `dropWhile` discarded the first element that failed the predicate, in both
|
|
408
|
+
families: `[1,2,3,4,1].dropWhile(n < 3)` returned `[4,1]` instead of `[3,4,1]`.
|
|
409
|
+
|
|
410
|
+
### Documentation
|
|
411
|
+
|
|
412
|
+
- README rewritten in full (English as the reference edition, in British
|
|
413
|
+
English). Every factory, operator, collectable and terminal now states its time
|
|
414
|
+
and space cost, and the design rationale, architecture and data flow have their
|
|
415
|
+
own chapters.
|
|
416
|
+
- The index-model chapter was rewritten around the split between lazy pipeline
|
|
417
|
+
rewriting and collectable tidying.
|
|
418
|
+
- All nine language editions were regenerated: the Simplified Chinese and
|
|
419
|
+
Japanese tables of contents were left untranslated and the Russian edition was
|
|
420
|
+
missing. Every code block is byte-identical to the English edition.
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## [1.1.0] - 2026-09-11
|
|
425
|
+
|
|
426
|
+
A **comprehensive defect release**: it fixes sixteen blocking defects introduced
|
|
427
|
+
in 1.0.0 — among them "the published package cannot be imported from Node", "index
|
|
428
|
+
reordering has no effect" and "the asynchronous chain returns nothing or hangs
|
|
429
|
+
forever" — and introduces regression tests for the first time. Three factories
|
|
430
|
+
changed their return type; read "Changed" before upgrading.
|
|
431
|
+
|
|
432
|
+
### Changed
|
|
433
|
+
|
|
434
|
+
- **`useBlob(...)` returns `AsynchronousSemantic`** (was `SynchronousSemantic`).
|
|
435
|
+
Reading a blob is inherently asynchronous, so a synchronous collectable saw an
|
|
436
|
+
empty array.
|
|
437
|
+
- **`useInterval(...)` returns `AsynchronousSemantic`** (was
|
|
438
|
+
`SynchronousSemantic`). The data is produced by a timer, and a synchronous
|
|
439
|
+
collectable finished before the first tick.
|
|
440
|
+
- **`useFrom(AsyncIterable)` returns `AsynchronousSemantic`** (was
|
|
441
|
+
`SynchronousSemantic`). The previous implementation silently returned `[]`.
|
|
442
|
+
- **`translate(offset)` became a cyclic shift**, matching README example 5
|
|
443
|
+
(positive rotates right, negative rotates left). The numeric overload needs the
|
|
444
|
+
stream length and therefore materialises it; the functional overload
|
|
445
|
+
`translate(mapper)` remains element-wise and lazy.
|
|
446
|
+
- **`partition(count)` is defined as bucket selection by element index**, that is
|
|
447
|
+
`partitionBy((_element, index) => index % count)`.
|
|
448
|
+
- **`shuffle()` is genuinely random.** The previous implementation derived indices
|
|
449
|
+
from element hashes, so the same input produced the same order every run.
|
|
450
|
+
|
|
451
|
+
### Fixed
|
|
452
|
+
|
|
453
|
+
**Packaging and tooling**
|
|
454
|
+
|
|
455
|
+
- The published artefact could not be loaded from Node: `tsconfig` moved to
|
|
456
|
+
`module`/`moduleResolution: NodeNext` and sixty relative imports in the source
|
|
457
|
+
gained their `.js` extension. Both ESM and CJS consumers used to fail with
|
|
458
|
+
`ERR_MODULE_NOT_FOUND`; only bundlers could resolve the package.
|
|
459
|
+
- `engines.node` corrected from `>=14.0.0` to `>=18.17.0`, matching the ES2022
|
|
460
|
+
target and the use of `Blob` and `WritableStream` in the types.
|
|
461
|
+
- `devDependencies.typescript` was missing, so `npm run build` failed on any fresh
|
|
462
|
+
clone.
|
|
463
|
+
|
|
464
|
+
**Indices and collectables**
|
|
465
|
+
|
|
466
|
+
- `toOrdered()` lost the real index of each element, having faked it from the
|
|
467
|
+
array position; `redirect`, `reverse`, `translate` and `shuffle` now reorder
|
|
468
|
+
correctly.
|
|
469
|
+
- Added the `toOrdered(comparator)` overload, which sorts by value and renumbers
|
|
470
|
+
the indices in sequence (the statistics collectables depend on that).
|
|
471
|
+
- The unordered collectable falls back to a spare key on a duplicate index rather
|
|
472
|
+
than silently dropping data; `useText("a,b,c", ",")` used to return only
|
|
473
|
+
`["c"]`.
|
|
474
|
+
|
|
475
|
+
**Asynchronous chain**
|
|
476
|
+
|
|
477
|
+
- The asynchronous ordered collectable defined `buffer` as a read-only property at
|
|
478
|
+
construction, so assigning it from the `then` callback threw a `TypeError`; the
|
|
479
|
+
symptom was `toOrdered()` and the statistics collectables returning `[]`, or
|
|
480
|
+
`.summate()` hanging forever.
|
|
481
|
+
- `source()` resolved without waiting for the data to be ready, which is why
|
|
482
|
+
`useInterval` was always empty.
|
|
483
|
+
- Added `settled()`: `findFirst`, `findLast`, `findAny`, `findAt`, `findMaximum`
|
|
484
|
+
and `findMinimum` now wait or reject correctly instead of hanging forever when
|
|
485
|
+
the stream is unfinished or empty.
|
|
486
|
+
- `findMaximum` and `findMinimum` compare by element value when no comparator is
|
|
487
|
+
given, rather than by index.
|
|
488
|
+
|
|
489
|
+
**Terminal operations**
|
|
490
|
+
|
|
491
|
+
- `findFirst`, `findLast`, `findAny`, `findMaximum` and `findMinimum` always
|
|
492
|
+
returned an empty value.
|
|
493
|
+
- `reduce(accumulator)`, the overload without an identity, always returned an
|
|
494
|
+
empty `Optional`.
|
|
495
|
+
- `numericStatistics.range()` consequently always returned `0`, because it depends
|
|
496
|
+
on `findFirst` and `findLast`.
|
|
497
|
+
- `nonMatch()` returned the exact opposite of the truth: the collectable finisher
|
|
498
|
+
negated one time too many.
|
|
499
|
+
|
|
500
|
+
**Operators and factories**
|
|
501
|
+
|
|
502
|
+
- `partition` threw `RangeError: Division by zero` on the first element.
|
|
503
|
+
- `partitionBy` used the element index rather than the classifier, raising a
|
|
504
|
+
`TypeError`.
|
|
505
|
+
- `sub(start, end)` deadlocked its counter and never produced an element.
|
|
506
|
+
- `useGenerate(supplier, interrupt)` shadowed its second parameter with an
|
|
507
|
+
identically named local, so the stop condition never applied.
|
|
508
|
+
- `useIterate` produced only the first element of an asynchronous iterable (a
|
|
509
|
+
stray `break`) and never advanced its index.
|
|
510
|
+
- `useText` gained the single-argument overload (splitting by Unicode code point,
|
|
511
|
+
so emoji are handled) and no longer loses data in the delimiter branch, where
|
|
512
|
+
the index failed to advance.
|
|
513
|
+
- `useStringify` re-entered serialisation recursively inside the replacer and threw
|
|
514
|
+
a `TypeError` on a cyclic reference.
|
|
515
|
+
- `useRandom` looped forever with probability about 15/16 on wide bigint ranges,
|
|
516
|
+
because rejection sampling reused one sample; the low three bits of a random
|
|
517
|
+
bigint were always zero, so `useRandom(1n, 10n)` returned only `1` or `9`.
|
|
518
|
+
- `useBlob` pointed every chunk at the same in-place buffer, so chunks overwrote
|
|
519
|
+
one another.
|
|
520
|
+
- `useInterval` checked the interrupt after `accept`, leaking the boundary
|
|
521
|
+
element.
|
|
522
|
+
- `useSubscription` unsubscribed twice when the boundary was reached.
|
|
523
|
+
- `toWindow().slide()` and `tumble()` produced zero windows on an asynchronous
|
|
524
|
+
stream, reading the buffer before it was ready.
|
|
525
|
+
|
|
526
|
+
**Statistics**
|
|
527
|
+
|
|
528
|
+
- The numeric kurtosis formula is corrected from `sum(z⁴)/n² - 3` to
|
|
529
|
+
`sum(z⁴)/n - 3`: `[1,2,3,4]` changes from `-2.59` to `-1.36`.
|
|
530
|
+
- Bigint statistics: `standardDeviation`, `skewness` and `kurtosis` threw because
|
|
531
|
+
`BigInt(Math.sqrt(...))` rejects a non-integral square root, and variance and
|
|
532
|
+
standard deviation suffered integer-division truncation (`[1,2,3,4]` reported a
|
|
533
|
+
variance of `3`). The statistics are now computed in floating point and rounded
|
|
534
|
+
back to `bigint`, matching the numeric editions.
|
|
535
|
+
|
|
536
|
+
**Other**
|
|
537
|
+
|
|
538
|
+
- `useHash`, `register`, `unregister` and `maskOf` were not exported, because
|
|
539
|
+
`src/index.ts` omitted `./hash`.
|
|
540
|
+
- The synchronous and asynchronous statistics brands shared one `Symbol.for` key,
|
|
541
|
+
and two guard functions mis-spelled their field names;
|
|
542
|
+
`isSynchronousNumericStatistics` returned `false` for a numeric statistics
|
|
543
|
+
object.
|
|
544
|
+
- `useTraverse` pushed onto its path without ever popping, so the path accumulated
|
|
545
|
+
across sibling branches.
|
|
546
|
+
- The primitive hash cache gained a ceiling (cleared beyond a hundred thousand
|
|
547
|
+
entries) so a long-running process does not grow without bound.
|
|
548
|
+
|
|
549
|
+
### Added
|
|
550
|
+
|
|
551
|
+
- **Regression tests**: `test/semantic.test.mjs`, 55 assertions covering every
|
|
552
|
+
fixed defect, the normal paths, the window operators and the asynchronous chain.
|
|
553
|
+
They use the built-in `node:test`, adding no runtime dependency.
|
|
554
|
+
- **`npm test`**: `npm run build && node --test`, ready for CI.
|
|
555
|
+
- **`CHANGELOG.md`**: this file.
|
|
556
|
+
- **`FIXES.md`**: a defect-by-defect account with root causes, the list of
|
|
557
|
+
breaking changes and follow-up scheduling.
|
|
558
|
+
|
|
559
|
+
### Changed (tooling)
|
|
560
|
+
|
|
561
|
+
- `package.json` gained `"sideEffects": false` so bundlers can tree-shake.
|
|
562
|
+
- The `dist/` artefacts joined `.gitignore`; they are built by `prepublishOnly`.
|
|
563
|
+
|
|
564
|
+
### Acknowledgements
|
|
565
|
+
|
|
566
|
+
Thanks to issues `#1` to `#5`. This release adopts their findings on build
|
|
567
|
+
artefacts, naming and extensibility, and keeps the remainder on the schedule
|
|
568
|
+
described in section four of `FIXES.md`.
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Earlier versions
|
|
573
|
+
|
|
574
|
+
- **[1.0.0] - 2026-04-07**: the latest version previously on npm. It carries the
|
|
575
|
+
sixteen blocking defects listed above, so **upgrading straight to 2.0.0 is
|
|
576
|
+
recommended**. The repository `package.json` was still at `0.7.1` when it was
|
|
577
|
+
published, so the repository and the published artefact were briefly out of
|
|
578
|
+
step.
|
|
579
|
+
- **0.6.0 and earlier**: every version before 0.6.0 is marked deprecated on npm
|
|
580
|
+
(`< 0.5.0` lacks the event-stream API, and `0.5.x` has circular dependencies).
|
|
581
|
+
- The repository had no git tags; `.github/workflows/publish.yml` triggers on
|
|
582
|
+
`v*` tags, and the `v1.1.0` tag was added with that release.
|
|
583
|
+
|
|
584
|
+
[2.0.0]: https://github.com/eloyhere/semantic-typescript/releases/tag/v2.0.0
|
|
585
|
+
[1.2.0]: https://github.com/eloyhere/semantic-typescript/releases/tag/v1.2.0
|
|
586
|
+
[1.1.0]: https://github.com/eloyhere/semantic-typescript/releases/tag/v1.1.0
|
|
587
|
+
[1.0.0]: https://www.npmjs.com/package/semantic-typescript/v/1.0.0
|