synstate 1.0.1 → 2.0.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.
Files changed (194) hide show
  1. package/README.md +9 -10
  2. package/dist/core/class/child-observable-class.d.mts.map +1 -1
  3. package/dist/core/class/child-observable-class.mjs +148 -140
  4. package/dist/core/class/child-observable-class.mjs.map +1 -1
  5. package/dist/core/class/observable-base-class.d.mts.map +1 -1
  6. package/dist/core/class/observable-base-class.mjs +111 -107
  7. package/dist/core/class/observable-base-class.mjs.map +1 -1
  8. package/dist/core/class/root-observable-class.d.mts.map +1 -1
  9. package/dist/core/class/root-observable-class.mjs +32 -24
  10. package/dist/core/class/root-observable-class.mjs.map +1 -1
  11. package/dist/core/combine/combine.d.mts +3 -3
  12. package/dist/core/combine/combine.d.mts.map +1 -1
  13. package/dist/core/combine/combine.mjs +31 -113
  14. package/dist/core/combine/combine.mjs.map +1 -1
  15. package/dist/core/combine/merge.d.mts +2 -2
  16. package/dist/core/combine/merge.d.mts.map +1 -1
  17. package/dist/core/combine/merge.mjs +21 -69
  18. package/dist/core/combine/merge.mjs.map +1 -1
  19. package/dist/core/combine/zip.d.mts +2 -2
  20. package/dist/core/combine/zip.d.mts.map +1 -1
  21. package/dist/core/combine/zip.mjs +34 -79
  22. package/dist/core/combine/zip.mjs.map +1 -1
  23. package/dist/core/create/counter.d.mts +1 -1
  24. package/dist/core/create/counter.d.mts.map +1 -1
  25. package/dist/core/create/counter.mjs +45 -84
  26. package/dist/core/create/counter.mjs.map +1 -1
  27. package/dist/core/create/from-abortable-promise.d.mts.map +1 -1
  28. package/dist/core/create/from-abortable-promise.mjs +29 -61
  29. package/dist/core/create/from-abortable-promise.mjs.map +1 -1
  30. package/dist/core/create/from-promise.d.mts.map +1 -1
  31. package/dist/core/create/from-promise.mjs +17 -66
  32. package/dist/core/create/from-promise.mjs.map +1 -1
  33. package/dist/core/create/from-subscribable.d.mts.map +1 -1
  34. package/dist/core/create/from-subscribable.mjs +18 -69
  35. package/dist/core/create/from-subscribable.mjs.map +1 -1
  36. package/dist/core/create/just.d.mts.map +1 -1
  37. package/dist/core/create/just.mjs +5 -35
  38. package/dist/core/create/just.mjs.map +1 -1
  39. package/dist/core/create/source.mjs +10 -13
  40. package/dist/core/create/source.mjs.map +1 -1
  41. package/dist/core/create/timer.d.mts.map +1 -1
  42. package/dist/core/create/timer.mjs +32 -68
  43. package/dist/core/create/timer.mjs.map +1 -1
  44. package/dist/core/operators/audit.d.mts.map +1 -1
  45. package/dist/core/operators/audit.mjs +39 -133
  46. package/dist/core/operators/audit.mjs.map +1 -1
  47. package/dist/core/operators/debounce.d.mts.map +1 -1
  48. package/dist/core/operators/debounce.mjs +36 -119
  49. package/dist/core/operators/debounce.mjs.map +1 -1
  50. package/dist/core/operators/filter.mjs +22 -25
  51. package/dist/core/operators/filter.mjs.map +1 -1
  52. package/dist/core/operators/map.d.mts.map +1 -1
  53. package/dist/core/operators/map.mjs +28 -61
  54. package/dist/core/operators/map.mjs.map +1 -1
  55. package/dist/core/operators/merge-map.d.mts +1 -1
  56. package/dist/core/operators/merge-map.d.mts.map +1 -1
  57. package/dist/core/operators/merge-map.mjs +34 -130
  58. package/dist/core/operators/merge-map.mjs.map +1 -1
  59. package/dist/core/operators/pairwise.d.mts +3 -2
  60. package/dist/core/operators/pairwise.d.mts.map +1 -1
  61. package/dist/core/operators/pairwise.mjs +19 -75
  62. package/dist/core/operators/pairwise.mjs.map +1 -1
  63. package/dist/core/operators/scan.d.mts.map +1 -1
  64. package/dist/core/operators/scan.mjs +16 -67
  65. package/dist/core/operators/scan.mjs.map +1 -1
  66. package/dist/core/operators/skip-if-no-change.d.mts +1 -1
  67. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
  68. package/dist/core/operators/skip-if-no-change.mjs +28 -92
  69. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  70. package/dist/core/operators/skip-until.d.mts.map +1 -1
  71. package/dist/core/operators/skip-until.mjs +23 -72
  72. package/dist/core/operators/skip-until.mjs.map +1 -1
  73. package/dist/core/operators/skip-while.d.mts.map +1 -1
  74. package/dist/core/operators/skip-while.mjs +26 -88
  75. package/dist/core/operators/skip-while.mjs.map +1 -1
  76. package/dist/core/operators/switch-map.d.mts.map +1 -1
  77. package/dist/core/operators/switch-map.mjs +31 -124
  78. package/dist/core/operators/switch-map.mjs.map +1 -1
  79. package/dist/core/operators/take-until.d.mts.map +1 -1
  80. package/dist/core/operators/take-until.mjs +28 -69
  81. package/dist/core/operators/take-until.mjs.map +1 -1
  82. package/dist/core/operators/take-while.d.mts.map +1 -1
  83. package/dist/core/operators/take-while.mjs +23 -83
  84. package/dist/core/operators/take-while.mjs.map +1 -1
  85. package/dist/core/operators/throttle.d.mts.map +1 -1
  86. package/dist/core/operators/throttle.mjs +38 -115
  87. package/dist/core/operators/throttle.mjs.map +1 -1
  88. package/dist/core/operators/with-buffered-from.d.mts +1 -1
  89. package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
  90. package/dist/core/operators/with-buffered-from.mjs +37 -90
  91. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  92. package/dist/core/operators/with-current-value-from.d.mts +1 -1
  93. package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
  94. package/dist/core/operators/with-current-value-from.mjs +23 -84
  95. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  96. package/dist/core/operators/with-initial-value.d.mts.map +1 -1
  97. package/dist/core/operators/with-initial-value.mjs +13 -58
  98. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  99. package/dist/core/predefined/operators/attach-index.d.mts +1 -1
  100. package/dist/core/predefined/operators/attach-index.d.mts.map +1 -1
  101. package/dist/core/predefined/operators/attach-index.mjs +0 -53
  102. package/dist/core/predefined/operators/attach-index.mjs.map +1 -1
  103. package/dist/core/predefined/operators/map-optional.d.mts.map +1 -1
  104. package/dist/core/predefined/operators/map-optional.mjs +1 -48
  105. package/dist/core/predefined/operators/map-optional.mjs.map +1 -1
  106. package/dist/core/predefined/operators/map-result-err.d.mts.map +1 -1
  107. package/dist/core/predefined/operators/map-result-err.mjs +1 -48
  108. package/dist/core/predefined/operators/map-result-err.mjs.map +1 -1
  109. package/dist/core/predefined/operators/map-result-ok.d.mts.map +1 -1
  110. package/dist/core/predefined/operators/map-result-ok.mjs +1 -48
  111. package/dist/core/predefined/operators/map-result-ok.mjs.map +1 -1
  112. package/dist/core/predefined/operators/map-to.d.mts.map +1 -1
  113. package/dist/core/predefined/operators/map-to.mjs +0 -40
  114. package/dist/core/predefined/operators/map-to.mjs.map +1 -1
  115. package/dist/core/predefined/operators/pluck.d.mts +1 -1
  116. package/dist/core/predefined/operators/pluck.d.mts.map +1 -1
  117. package/dist/core/predefined/operators/pluck.mjs +0 -43
  118. package/dist/core/predefined/operators/pluck.mjs.map +1 -1
  119. package/dist/core/predefined/operators/skip.d.mts.map +1 -1
  120. package/dist/core/predefined/operators/skip.mjs +0 -47
  121. package/dist/core/predefined/operators/skip.mjs.map +1 -1
  122. package/dist/core/predefined/operators/take.d.mts.map +1 -1
  123. package/dist/core/predefined/operators/take.mjs +0 -41
  124. package/dist/core/predefined/operators/take.mjs.map +1 -1
  125. package/dist/core/predefined/operators/unwrap-optional.mjs +4 -43
  126. package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -1
  127. package/dist/core/predefined/operators/unwrap-result-err.mjs +0 -40
  128. package/dist/core/predefined/operators/unwrap-result-err.mjs.map +1 -1
  129. package/dist/core/predefined/operators/unwrap-result-ok.mjs +4 -43
  130. package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -1
  131. package/dist/core/types/observable-family.d.mts +10 -10
  132. package/dist/core/types/observable-family.d.mts.map +1 -1
  133. package/dist/core/types/observable.d.mts.map +1 -1
  134. package/dist/core/types/observable.mjs +3 -5
  135. package/dist/core/types/observable.mjs.map +1 -1
  136. package/dist/core/types/types.d.mts +2 -1
  137. package/dist/core/types/types.d.mts.map +1 -1
  138. package/dist/core/utils/id-maker.mjs +5 -6
  139. package/dist/core/utils/id-maker.mjs.map +1 -1
  140. package/dist/core/utils/max-depth.d.mts.map +1 -1
  141. package/dist/core/utils/max-depth.mjs +1 -3
  142. package/dist/core/utils/max-depth.mjs.map +1 -1
  143. package/dist/core/utils/observable-utils.d.mts.map +1 -1
  144. package/dist/core/utils/observable-utils.mjs +3 -2
  145. package/dist/core/utils/observable-utils.mjs.map +1 -1
  146. package/dist/core/utils/utils.d.mts.map +1 -1
  147. package/dist/core/utils/utils.mjs +23 -30
  148. package/dist/core/utils/utils.mjs.map +1 -1
  149. package/dist/utils/collect-to-array.d.mts.map +1 -1
  150. package/dist/utils/collect-to-array.mjs +9 -6
  151. package/dist/utils/collect-to-array.mjs.map +1 -1
  152. package/dist/utils/create-boolean-state.d.mts +1 -1
  153. package/dist/utils/create-boolean-state.d.mts.map +1 -1
  154. package/dist/utils/create-boolean-state.mjs +18 -46
  155. package/dist/utils/create-boolean-state.mjs.map +1 -1
  156. package/dist/utils/create-event-emitter.mjs +10 -64
  157. package/dist/utils/create-event-emitter.mjs.map +1 -1
  158. package/dist/utils/create-reducer.d.mts +1 -1
  159. package/dist/utils/create-reducer.d.mts.map +1 -1
  160. package/dist/utils/create-reducer.mjs +8 -52
  161. package/dist/utils/create-reducer.mjs.map +1 -1
  162. package/dist/utils/create-state.d.mts +1 -1
  163. package/dist/utils/create-state.d.mts.map +1 -1
  164. package/dist/utils/create-state.mjs +23 -53
  165. package/dist/utils/create-state.mjs.map +1 -1
  166. package/package.json +16 -16
  167. package/src/core/class/child-observable-class.mts +1 -1
  168. package/src/core/class/observable-base-class.mts +16 -16
  169. package/src/core/combine/combine.mts +38 -16
  170. package/src/core/combine/merge.mts +3 -3
  171. package/src/core/combine/zip.mts +24 -13
  172. package/src/core/create/counter.mts +11 -9
  173. package/src/core/create/counter.test.mts +11 -0
  174. package/src/core/create/timer.mts +6 -6
  175. package/src/core/create/timer.test.mts +11 -0
  176. package/src/core/operators/audit-throttle-teardown.test.mts +21 -0
  177. package/src/core/operators/audit.mts +6 -6
  178. package/src/core/operators/debounce.mts +6 -6
  179. package/src/core/operators/pairwise.mts +10 -5
  180. package/src/core/operators/skip-while.mts +1 -5
  181. package/src/core/operators/skip-while.test.mts +20 -0
  182. package/src/core/operators/throttle.mts +6 -6
  183. package/src/core/operators/with-buffered-from.mts +4 -4
  184. package/src/core/predefined/operators/map-optional.mts +1 -2
  185. package/src/core/predefined/operators/map-result-err.mts +1 -1
  186. package/src/core/predefined/operators/map-result-ok.mts +1 -1
  187. package/src/core/types/observable-family.mts +12 -11
  188. package/src/core/types/observable.mts +5 -7
  189. package/src/core/types/types.mts +2 -1
  190. package/src/core/utils/max-depth.mts +5 -1
  191. package/src/core/utils/utils.mts +1 -1
  192. package/src/utils/create-boolean-state.mts +1 -1
  193. package/src/utils/create-reducer.mts +1 -1
  194. package/src/utils/create-state.mts +1 -1
@@ -32,7 +32,7 @@ import { type InitializedObservable } from '../core/index.mjs';
32
32
  * assert.deepStrictEqual(stateHistory, [0, 10, 11, 0]);
33
33
  * ```
34
34
  */
35
- export declare const createState: <S>(initialState: S) => readonly [state: InitializedObservable<S>, setState: (v: S) => S, Readonly<{
35
+ export declare const createState: <S>(initialState: S) => readonly [state: InitializedObservable<S>, setState: (v: S) => S, utils: Readonly<{
36
36
  updateState: (updateFn: (prev: S) => S) => S;
37
37
  resetState: () => S;
38
38
  getSnapshot: () => S;
@@ -1 +1 @@
1
- {"version":3,"file":"create-state.d.mts","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAwB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,EAC3B,cAAc,CAAC,KACd,SAAS,CACV,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EACrB,QAAQ,CAAC;IACP,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CAyBH,CAAC"}
1
+ {"version":3,"file":"create-state.d.mts","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAwB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,gBACb,CAAC,KACd,SAAS,CACV,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAC/B,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EACrB,KAAK,EAAE,QAAQ,CAAC;IACd,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CAyBH,CAAC"}
@@ -1,61 +1,31 @@
1
1
  import { createReducer } from './create-reducer.mjs';
2
2
 
3
3
  const reducer = (state, action) => {
4
- switch (action.type) {
5
- case 'set':
6
- return action.nextState;
7
- case 'update':
8
- return action.updateFn(state);
9
- }
4
+ switch (action.type) {
5
+ case "set":
6
+ return action.nextState;
7
+ case "update":
8
+ return action.updateFn(state);
9
+ }
10
10
  };
11
- /**
12
- * Creates a reactive state container with getter and setter methods.
13
- * Provides a simple state management solution with observable state.
14
- *
15
- * @template S - The type of the state
16
- * @param initialState - The initial value of the state
17
- * @returns A 3-element tuple: `[state, setState, { updateState, resetState, getSnapshot, initialState }]`
18
- *
19
- * @example
20
- * ```ts
21
- * const [state, setState, { updateState, resetState }] = createState(0);
22
- *
23
- * const stateHistory: number[] = [];
24
- *
25
- * state.subscribe((value: number) => {
26
- * stateHistory.push(value);
27
- * });
28
- *
29
- * assert.deepStrictEqual(stateHistory, [0]);
30
- *
31
- * setState(10); // logs: 10
32
- *
33
- * assert.deepStrictEqual(stateHistory, [0, 10]);
34
- *
35
- * updateState((prev: number) => prev + 1); // logs: 11
36
- *
37
- * assert.deepStrictEqual(stateHistory, [0, 10, 11]);
38
- *
39
- * resetState(); // logs: 0
40
- *
41
- * assert.deepStrictEqual(stateHistory, [0, 10, 11, 0]);
42
- * ```
43
- */
44
11
  const createState = (initialState) => {
45
- const [state, dispatch, { getSnapshot }] = createReducer(reducer, initialState);
46
- const updateState = (updateFn) => dispatch({ type: 'update', updateFn });
47
- const setState = (nextState) => dispatch({ type: 'set', nextState });
48
- const resetState = () => dispatch({ type: 'set', nextState: initialState });
49
- return [
50
- state,
51
- setState,
52
- {
53
- updateState,
54
- resetState,
55
- getSnapshot,
56
- initialState,
57
- },
58
- ];
12
+ const [state, dispatch, { getSnapshot }] = createReducer(
13
+ reducer,
14
+ initialState
15
+ );
16
+ const updateState = (updateFn) => dispatch({ type: "update", updateFn });
17
+ const setState = (nextState) => dispatch({ type: "set", nextState });
18
+ const resetState = () => dispatch({ type: "set", nextState: initialState });
19
+ return [
20
+ state,
21
+ setState,
22
+ {
23
+ updateState,
24
+ resetState,
25
+ getSnapshot,
26
+ initialState
27
+ }
28
+ ];
59
29
  };
60
30
 
61
31
  export { createState };
@@ -1 +1 @@
1
- {"version":3,"file":"create-state.mjs","sources":["../../src/utils/create-state.mts"],"sourcesContent":[null],"names":[],"mappings":";;AAcA,MAAM,OAAO,GAAG,CAAK,KAAQ,EAAE,MAAiB,KAAO;AACrD,IAAA,QAAQ,MAAM,CAAC,IAAI;AACjB,QAAA,KAAK,KAAK;YACR,OAAO,MAAM,CAAC,SAAS;AAEzB,QAAA,KAAK,QAAQ;AACX,YAAA,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;;AAEnC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCG;AACI,MAAM,WAAW,GAAG,CACzB,YAAe,KAUb;AACF,IAAA,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,aAAa,CACtD,OAAO,EACP,YAAY,CACb;AAED,IAAA,MAAM,WAAW,GAAG,CAAC,QAAwB,KAC3C,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAExC,IAAA,MAAM,QAAQ,GAAG,CAAC,SAAY,KAAQ,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAE1E,IAAA,MAAM,UAAU,GAAG,MACjB,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;IAEpD,OAAO;QACL,KAAK;QACL,QAAQ;AACR,QAAA;YACE,WAAW;YACX,UAAU;YACV,WAAW;YACX,YAAY;AACb,SAAA;KACO;AACZ;;;;"}
1
+ {"version":3,"file":"create-state.mjs","sources":["../../src/utils/create-state.mts"],"sourcesContent":["import { type InitializedObservable } from '../core/index.mjs';\nimport { createReducer } from './create-reducer.mjs';\n\ntype Action<S> = Readonly<\n | {\n type: 'set';\n nextState: S;\n }\n | {\n type: 'update';\n updateFn: (a: S) => S;\n }\n>;\n\nconst reducer = <S,>(state: S, action: Action<S>): S => {\n switch (action.type) {\n case 'set':\n return action.nextState;\n\n case 'update':\n return action.updateFn(state);\n }\n};\n\n/**\n * Creates a reactive state container with getter and setter methods.\n * Provides a simple state management solution with observable state.\n *\n * @template S - The type of the state\n * @param initialState - The initial value of the state\n * @returns A 3-element tuple: `[state, setState, { updateState, resetState, getSnapshot, initialState }]`\n *\n * @example\n * ```ts\n * const [state, setState, { updateState, resetState }] = createState(0);\n *\n * const stateHistory: number[] = [];\n *\n * state.subscribe((value: number) => {\n * stateHistory.push(value);\n * });\n *\n * assert.deepStrictEqual(stateHistory, [0]);\n *\n * setState(10); // logs: 10\n *\n * assert.deepStrictEqual(stateHistory, [0, 10]);\n *\n * updateState((prev: number) => prev + 1); // logs: 11\n *\n * assert.deepStrictEqual(stateHistory, [0, 10, 11]);\n *\n * resetState(); // logs: 0\n *\n * assert.deepStrictEqual(stateHistory, [0, 10, 11, 0]);\n * ```\n */\nexport const createState = <S,>(\n initialState: S,\n): readonly [\n state: InitializedObservable<S>,\n setState: (v: S) => S,\n utils: Readonly<{\n updateState: (updateFn: (prev: S) => S) => S;\n resetState: () => S;\n getSnapshot: () => S;\n initialState: S;\n }>,\n] => {\n const [state, dispatch, { getSnapshot }] = createReducer<S, Action<S>>(\n reducer,\n initialState,\n );\n\n const updateState = (updateFn: (prev: S) => S): S =>\n dispatch({ type: 'update', updateFn });\n\n const setState = (nextState: S): S => dispatch({ type: 'set', nextState });\n\n const resetState = (): S =>\n dispatch({ type: 'set', nextState: initialState });\n\n return [\n state,\n setState,\n {\n updateState,\n resetState,\n getSnapshot,\n initialState,\n },\n ] as const;\n};\n"],"names":[],"mappings":";;AAcA,MAAM,OAAA,GAAU,CAAK,KAAA,EAAU,MAAA,KAAyB;AACtD,EAAA,QAAQ,OAAO,IAAA;AAAM,IACnB,KAAK,KAAA;AACH,MAAA,OAAO,MAAA,CAAO,SAAA;AAAA,IAEhB,KAAK,QAAA;AACH,MAAA,OAAO,MAAA,CAAO,SAAS,KAAK,CAAA;AAAA;AAElC,CAAA;AAmCO,MAAM,WAAA,GAAc,CACzB,YAAA,KAUG;AACH,EAAA,MAAM,CAAC,KAAA,EAAO,QAAA,EAAU,EAAE,WAAA,EAAa,CAAA,GAAI,aAAA;AAAA,IACzC,OAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,QAAA,KACnB,QAAA,CAAS,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,CAAA;AAEvC,EAAA,MAAM,QAAA,GAAW,CAAC,SAAA,KAAoB,QAAA,CAAS,EAAE,IAAA,EAAM,KAAA,EAAO,WAAW,CAAA;AAEzE,EAAA,MAAM,UAAA,GAAa,MACjB,QAAA,CAAS,EAAE,MAAM,KAAA,EAAO,SAAA,EAAW,cAAc,CAAA;AAEnD,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,MACE,WAAA;AAAA,MACA,UAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACF;AACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synstate",
3
- "version": "1.0.1",
3
+ "version": "2.0.0",
4
4
  "description": "Type-safe State Management Library for TypeScript/JavaScript",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,20 +28,20 @@
28
28
  "LICENSE"
29
29
  ],
30
30
  "dependencies": {
31
- "ts-data-forge": "6.9.4",
32
- "ts-type-forge": "3.0.0"
31
+ "ts-data-forge": "^14.2.0",
32
+ "ts-type-forge": "^9.2.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@reduxjs/toolkit": "2.11.2",
35
+ "@reduxjs/toolkit": "2.12.0",
36
36
  "@types/argparse": "2.0.17",
37
- "@types/react": "19.2.14",
38
- "argparse": "2.0.1",
39
- "jotai": "2.19.1",
40
- "mobx": "6.15.0",
41
- "react": "19.2.5",
37
+ "@types/react": "19.2.18",
38
+ "argparse": "3.0.0",
39
+ "jotai": "2.20.2",
40
+ "mobx": "7.0.0",
41
+ "react": "19.2.8",
42
42
  "rxjs": "7.8.2",
43
- "valtio": "2.3.1",
44
- "zustand": "5.0.12"
43
+ "valtio": "2.3.2",
44
+ "zustand": "5.0.14"
45
45
  },
46
46
  "scripts": {
47
47
  "benchmark": "tsx ./scripts/cmd/run-benchmark.mts",
@@ -55,7 +55,8 @@
55
55
  "doc:embed": "tsx ./scripts/cmd/embed-examples.mts",
56
56
  "doc:embed:jsdoc": "tsx ./scripts/cmd/embed-examples-in-jsdoc.mts",
57
57
  "doc:gen-sample-diffs": "tsx ./scripts/cmd/generate-sample-diffs.mts",
58
- "fmt": "format-uncommitted",
58
+ "fmt": "format-uncommitted --cwd .",
59
+ "fmt:diff": "format-diff-from origin/main --cwd .",
59
60
  "fmt:full": "pnpm run z:prettier .",
60
61
  "gi": "run-s gi:src fmt",
61
62
  "gi:src": "gen-index-ts ./src --index-ext .mts --export-ext .mjs --target-ext .mts --target-ext .tsx --exclude entry-point.mts --exclude \"core/utils/**\"",
@@ -67,10 +68,9 @@
67
68
  "test:cov:ui": "vite preview --outDir ./coverage",
68
69
  "test:ui": "pnpm run z:vitest:node --ui",
69
70
  "testw": "pnpm run z:vitest:node watch",
70
- "tsc": "tsc --noEmit",
71
- "tscw": "tsc --noEmit --watch",
72
- "type-check": "tsc --noEmit",
73
- "update-packages": "pnpm update --latest",
71
+ "tsc": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
72
+ "tscw": "node ../../node_modules/typescript-native/bin/tsc --noEmit --watch",
73
+ "type-check": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
74
74
  "z:prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --ignore-path ../../.gitignore --ignore-unknown --no-error-on-unmatched-pattern --write",
75
75
  "z:vitest": "vitest --config ./configs/vitest.config.mts",
76
76
  "z:vitest:node": "pnpm run z:vitest --project='Node.js'",
@@ -128,8 +128,8 @@ export class AsyncChildObservableClass<A, const P extends NonEmptyUnknownList>
128
128
  extends ObservableBaseClass<A, 'async child', number>
129
129
  implements AsyncChildObservable<A, P>
130
130
  {
131
- readonly parents;
132
131
  #mut_propagationOrder: readonly ChildObservable<unknown>[];
132
+ readonly parents;
133
133
  protected readonly descendantsIdSet: MutableSet<ObservableId>;
134
134
 
135
135
  constructor({
@@ -24,14 +24,14 @@ export class ObservableBaseClass<
24
24
  Kind extends ObservableBase<A>['kind'],
25
25
  Depth extends ObservableBase<A>['depth'],
26
26
  > implements ObservableBase<A> {
27
- readonly id;
28
- readonly kind: Kind;
29
- readonly depth: Depth;
30
27
  #mut_children: readonly ChildObservable<unknown>[];
31
28
  readonly #subscribers: MutableMap<SubscriberId, Subscriber<A>>;
32
29
  #mut_currentValue: ReturnType<ObservableBase<A>['getSnapshot']>;
33
30
  #mut_isCompleted: ObservableBase<A>['isCompleted'];
34
31
  #mut_updateToken: ObservableBase<A>['updateToken'];
32
+ readonly id;
33
+ readonly kind: Kind;
34
+ readonly depth: Depth;
35
35
 
36
36
  constructor({
37
37
  kind,
@@ -59,6 +59,19 @@ export class ObservableBaseClass<
59
59
  this.#mut_updateToken = issueUpdateToken();
60
60
  }
61
61
 
62
+ #addSubscriber(s: Subscriber<A>): SubscriberId {
63
+ // return the id of added subscriber
64
+ const id = issueSubscriberId();
65
+
66
+ this.#subscribers.set(id, s);
67
+
68
+ return id;
69
+ }
70
+
71
+ #removeSubscriber(id: SubscriberId): void {
72
+ this.#subscribers.delete(id);
73
+ }
74
+
62
75
  addChild<B>(child: ChildObservable<B>): void {
63
76
  this.#mut_children = Arr.toPushed(
64
77
  this.#mut_children,
@@ -171,17 +184,4 @@ export class ObservableBaseClass<
171
184
  },
172
185
  };
173
186
  }
174
-
175
- #addSubscriber(s: Subscriber<A>): SubscriberId {
176
- // return the id of added subscriber
177
- const id = issueSubscriberId();
178
-
179
- this.#subscribers.set(id, s);
180
-
181
- return id;
182
- }
183
-
184
- #removeSubscriber(id: SubscriberId): void {
185
- this.#subscribers.delete(id);
186
- }
187
187
  }
@@ -1,5 +1,5 @@
1
- import { Arr, Optional, expectType } from 'ts-data-forge';
2
- import { type NonEmptyArray } from 'ts-type-forge';
1
+ import { Arr, expectType, Optional } from 'ts-data-forge';
2
+ import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
3
3
  import { SyncChildObservableClass } from '../class/index.mjs';
4
4
  import { source } from '../create/index.mjs';
5
5
  import { withInitialValue } from '../operators/index.mjs';
@@ -72,7 +72,7 @@ import {
72
72
  * ]);
73
73
  * ```
74
74
  */
75
- export const combine = <const OS extends NonEmptyArray<Observable<unknown>>>(
75
+ export const combine = <const OS extends NonEmptyTuple<Observable<unknown>>>(
76
76
  parents: OS,
77
77
  ): CombineObservableRefined<OS> =>
78
78
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
@@ -91,35 +91,57 @@ class CombineObservableClass<const A extends NonEmptyUnknownList>
91
91
  implements CombineObservable<A>
92
92
  {
93
93
  constructor(parents: Wrap<A>) {
94
- const parentsValues = parents.map((p) => p.getSnapshot());
94
+ const parentsValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
95
+ parents,
96
+ (p) => p.getSnapshot(),
97
+ );
98
+
99
+ // The annotation on `initialValue` is what replaces the type assertion.
100
+ // `Arr.map` carries a single result element type, so it reports `A[number]`
101
+ // at every position, and `Tuple.MapTo<A[number], A>` — the uniform mapping
102
+ // — is *not* assignable back to `A`. The positional
103
+ // `Readonly<{ [K in keyof A]: A[K] }>` is, and TypeScript accepts the
104
+ // uniform result into it because the two mapped types share `keyof A`. So
105
+ // it is the annotation, not an assertion, that records the position-wise
106
+ // fact the checker cannot derive on its own.
107
+ const initialValue: Optional<Readonly<{ [K in keyof A]: A[K] }>> =
108
+ Arr.every(parentsValues, Optional.isSome)
109
+ ? Optional.some(Arr.map(parentsValues, (c) => c.value))
110
+ : Optional.none;
95
111
 
96
112
  super({
97
113
  parents,
98
- initialValue: parentsValues.every(Optional.isSome)
99
- ? Optional.some(
100
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
101
- Arr.map(parentsValues, (c) => c.value) as A,
102
- )
103
- : Optional.none,
114
+ initialValue,
104
115
  });
105
116
  }
106
117
 
107
118
  override tryUpdate(updateToken: UpdateToken): void {
108
119
  if (this.parents.every((o) => o.updateToken !== updateToken)) return; // all parents are skipped
109
120
 
110
- const parentValues = this.parents.map((a) => a.getSnapshot());
121
+ // Same shape-preserving chain as the constructor: `Arr.map` (not the
122
+ // native one, which drops the tuple shape) into the uniform
123
+ // `Tuple.MapTo`, then a positional annotation to get back to `A`.
124
+ const parentValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
125
+ this.parents,
126
+ (a) => a.getSnapshot(),
127
+ );
111
128
 
112
- if (parentValues.every(Optional.isSome)) {
113
- const nextValue =
114
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
115
- Arr.map(parentValues, (a) => a.value) as A;
129
+ if (Arr.every(parentValues, Optional.isSome)) {
130
+ const nextValue: Readonly<{ [K in keyof A]: A[K] }> = Arr.map(
131
+ parentValues,
132
+ (a) => a.value,
133
+ );
116
134
 
117
135
  this.setNext(nextValue, updateToken);
118
136
  }
119
137
  }
120
138
  }
121
139
 
122
- {
140
+ if (import.meta.vitest !== undefined) {
141
+ test('type test', () => {
142
+ expect(1).toBe(1); // dummy
143
+ });
144
+
123
145
  {
124
146
  const s1: Observable<1> = source<1>();
125
147
 
@@ -1,5 +1,5 @@
1
1
  import { Optional, expectType } from 'ts-data-forge';
2
- import { type ArrayElement, type NonEmptyArray } from 'ts-type-forge';
2
+ import { type ArrayElement, type NonEmptyTuple } from 'ts-type-forge';
3
3
  import { SyncChildObservableClass } from '../class/index.mjs';
4
4
  import { source } from '../create/index.mjs';
5
5
  import {
@@ -63,7 +63,7 @@ import {
63
63
  * @note To improve code readability, consider using `createState` instead of `merge`,
64
64
  * subscribing to `parents` and calling `setState` within it.
65
65
  */
66
- export const merge = <const OS extends NonEmptyArray<Observable<unknown>>>(
66
+ export const merge = <const OS extends NonEmptyTuple<Observable<unknown>>>(
67
67
  parents: OS,
68
68
  ): MergeObservableRefined<OS> =>
69
69
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
@@ -104,7 +104,7 @@ if (import.meta.vitest !== undefined) {
104
104
 
105
105
  const r2 = source('a');
106
106
 
107
- const _m = merge([r1, r2] as const);
107
+ const _m = merge([r1, r2]);
108
108
 
109
109
  expectType<typeof _m, SyncChildObservable<number | string>>('<=');
110
110
  }
@@ -1,5 +1,5 @@
1
1
  import { Arr, Optional, createQueue, expectType } from 'ts-data-forge';
2
- import { type NonEmptyArray } from 'ts-type-forge';
2
+ import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
3
3
  import { SyncChildObservableClass } from '../class/index.mjs';
4
4
  import { source } from '../create/index.mjs';
5
5
  import { withInitialValue } from '../operators/index.mjs';
@@ -65,7 +65,7 @@ import {
65
65
  * ]);
66
66
  * ```
67
67
  */
68
- export const zip = <const OS extends NonEmptyArray<Observable<unknown>>>(
68
+ export const zip = <const OS extends NonEmptyTuple<Observable<unknown>>>(
69
69
  parents: OS,
70
70
  ): ZipObservableRefined<OS> =>
71
71
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
@@ -78,21 +78,30 @@ class ZipObservableClass<const A extends NonEmptyUnknownList>
78
78
  readonly #queues: TupleToQueueTuple<A>;
79
79
 
80
80
  constructor(parents: Wrap<A>) {
81
- const parentsValues = parents.map((p) => p.getSnapshot());
81
+ const parentsValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
82
+ parents,
83
+ (p) => p.getSnapshot(),
84
+ );
85
+
86
+ // The annotation on `initialValue` is what replaces the type assertion.
87
+ // `Arr.map` carries a single result element type, so it reports `A[number]`
88
+ // at every position, and `Tuple.MapTo<A[number], A>` — the uniform mapping
89
+ // — is *not* assignable back to `A`. The positional
90
+ // `Readonly<{ [K in keyof A]: A[K] }>` is, and TypeScript accepts the
91
+ // uniform result into it because the two mapped types share `keyof A`. So
92
+ // it is the annotation, not an assertion, that records the position-wise
93
+ // fact the checker cannot derive on its own.
94
+ const initialValue: Optional<Readonly<{ [K in keyof A]: A[K] }>> =
95
+ Arr.every(parentsValues, Optional.isSome)
96
+ ? Optional.some(Arr.map(parentsValues, (c) => c.value))
97
+ : Optional.none;
82
98
 
83
99
  super({
84
100
  parents,
85
- initialValue: parentsValues.every(Optional.isSome)
86
- ? Optional.some(
87
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
88
- Arr.map(parentsValues, (c) => c.value) as A,
89
- )
90
- : Optional.none,
101
+ initialValue,
91
102
  });
92
103
 
93
- this.#queues = Arr.map(parents, () =>
94
- createQueue(),
95
- ) satisfies TupleToQueueTuple<A>;
104
+ this.#queues = Arr.map(parents, () => createQueue());
96
105
  }
97
106
 
98
107
  override tryUpdate(updateToken: UpdateToken): void {
@@ -108,6 +117,8 @@ class ZipObservableClass<const A extends NonEmptyUnknownList>
108
117
 
109
118
  if (queues.every((list) => !list.isEmpty)) {
110
119
  const nextValue =
120
+ // `Arr.map` has a single result element type, so it reports
121
+ // `A[number] | undefined` per position rather than `A[P]`.
111
122
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
112
123
  Arr.map(queues, (q) => Optional.unwrap(q.dequeue())) as A;
113
124
 
@@ -160,7 +171,7 @@ if (import.meta.vitest !== undefined) {
160
171
 
161
172
  const r2 = source('a');
162
173
 
163
- const _z = zip([r1, r2] as const);
174
+ const _z = zip([r1, r2]);
164
175
 
165
176
  const _zi = zip([
166
177
  r1.pipe(withInitialValue(0)),
@@ -36,7 +36,7 @@ import { type CounterObservable, type TimerId } from '../types/index.mjs';
36
36
  *
37
37
  * subscription.unsubscribe();
38
38
  *
39
- * assert.isTrue(Arr.isArrayAtLeastLength(valueHistory, 3));
39
+ * assert.isTrue(Arr.isMinLengthArray(3, valueHistory));
40
40
  *
41
41
  * assert.deepStrictEqual(valueHistory[0], 0);
42
42
  *
@@ -84,6 +84,16 @@ class CounterObservableClass
84
84
  }
85
85
  }
86
86
 
87
+ #resetTimer(): void {
88
+ if (this.#mut_timerId0 === undefined || this.#mut_timerId === undefined) {
89
+ return;
90
+ }
91
+
92
+ clearInterval(this.#mut_timerId0);
93
+
94
+ clearInterval(this.#mut_timerId);
95
+ }
96
+
87
97
  start(): void {
88
98
  if (this.#mut_isStarted) {
89
99
  console.warn('cannot start twice');
@@ -110,14 +120,6 @@ class CounterObservableClass
110
120
  }, this.#intervalMilliSeconds);
111
121
  }
112
122
 
113
- #resetTimer(): void {
114
- if (this.#mut_timerId0 !== undefined && this.#mut_timerId !== undefined) {
115
- clearInterval(this.#mut_timerId0);
116
-
117
- clearInterval(this.#mut_timerId);
118
- }
119
- }
120
-
121
123
  override complete(): void {
122
124
  this.#resetTimer();
123
125
 
@@ -0,0 +1,11 @@
1
+ import { counter } from './counter.mjs';
2
+
3
+ describe(counter, () => {
4
+ test('completing before start() tears down without touching the timers', () => {
5
+ const counter$ = counter(10, { startManually: true });
6
+
7
+ counter$.complete();
8
+
9
+ assert.isTrue(counter$.isCompleted);
10
+ });
11
+ });
@@ -68,6 +68,12 @@ class TimerObservableClass
68
68
  }
69
69
  }
70
70
 
71
+ #resetTimer(): void {
72
+ if (this.#mut_timerId !== undefined) {
73
+ clearTimeout(this.#mut_timerId);
74
+ }
75
+ }
76
+
71
77
  start(): void {
72
78
  if (this.#mut_isStarted) {
73
79
  console.warn('cannot start twice');
@@ -90,12 +96,6 @@ class TimerObservableClass
90
96
  }, this.#milliSeconds);
91
97
  }
92
98
 
93
- #resetTimer(): void {
94
- if (this.#mut_timerId !== undefined) {
95
- clearTimeout(this.#mut_timerId);
96
- }
97
- }
98
-
99
99
  override complete(): void {
100
100
  this.#resetTimer();
101
101
 
@@ -0,0 +1,11 @@
1
+ import { timer } from './timer.mjs';
2
+
3
+ describe(timer, () => {
4
+ test('completing before start() tears down without touching the timer', () => {
5
+ const timer$ = timer(10, { startManually: true });
6
+
7
+ timer$.complete();
8
+
9
+ assert.isTrue(timer$.isCompleted);
10
+ });
11
+ });
@@ -0,0 +1,21 @@
1
+ import { source } from '../create/index.mjs';
2
+ import { audit } from './audit.mjs';
3
+ import { throttle } from './throttle.mjs';
4
+
5
+ describe('completing before any emission', () => {
6
+ test('audit tears down without a pending timer', () => {
7
+ const audited$ = source<number>().pipe(audit(10));
8
+
9
+ audited$.complete();
10
+
11
+ assert.isTrue(audited$.isCompleted);
12
+ });
13
+
14
+ test('throttle tears down without a pending timer', () => {
15
+ const throttled$ = source<number>().pipe(throttle(10));
16
+
17
+ throttled$.complete();
18
+
19
+ assert.isTrue(throttled$.isCompleted);
20
+ });
21
+ });
@@ -133,6 +133,12 @@ class AuditObservableClass<A>
133
133
  this.#milliSeconds = milliSeconds;
134
134
  }
135
135
 
136
+ #resetTimer(): void {
137
+ if (this.#mut_timerId !== undefined) {
138
+ clearTimeout(this.#mut_timerId);
139
+ }
140
+ }
141
+
136
142
  override tryUpdate(updateToken: UpdateToken): void {
137
143
  const par = this.parents[0];
138
144
 
@@ -158,12 +164,6 @@ class AuditObservableClass<A>
158
164
  }, this.#milliSeconds);
159
165
  }
160
166
 
161
- #resetTimer(): void {
162
- if (this.#mut_timerId !== undefined) {
163
- clearTimeout(this.#mut_timerId);
164
- }
165
- }
166
-
167
167
  override complete(): void {
168
168
  this.#resetTimer();
169
169
 
@@ -121,6 +121,12 @@ class DebounceObservableClass<A>
121
121
  this.#milliSeconds = milliSeconds;
122
122
  }
123
123
 
124
+ #resetTimer(): void {
125
+ if (this.#mut_timerId !== undefined) {
126
+ clearTimeout(this.#mut_timerId);
127
+ }
128
+ }
129
+
124
130
  override tryUpdate(updateToken: UpdateToken): void {
125
131
  const par = this.parents[0];
126
132
 
@@ -140,12 +146,6 @@ class DebounceObservableClass<A>
140
146
  }, this.#milliSeconds);
141
147
  }
142
148
 
143
- #resetTimer(): void {
144
- if (this.#mut_timerId !== undefined) {
145
- clearTimeout(this.#mut_timerId);
146
- }
147
- }
148
-
149
149
  override complete(): void {
150
150
  this.#resetTimer();
151
151
 
@@ -1,4 +1,5 @@
1
1
  import { Optional } from 'ts-data-forge';
2
+ import { type FixedLengthTuple } from 'ts-type-forge';
2
3
  import { SyncChildObservableClass } from '../class/index.mjs';
3
4
  import {
4
5
  type DropInitialValueOperator,
@@ -30,7 +31,7 @@ import {
30
31
  *
31
32
  * const pairs$ = num$.pipe(pairwise());
32
33
  *
33
- * const valueHistory: (readonly [number, number])[] = [];
34
+ * const valueHistory: FixedLengthTuple<2, number>[] = [];
34
35
  *
35
36
  * pairs$.subscribe(([prev, curr]) => {
36
37
  * valueHistory.push([prev, curr]);
@@ -60,14 +61,18 @@ import {
60
61
  * ]);
61
62
  * ```
62
63
  */
63
- export const pairwise = <A,>(): DropInitialValueOperator<A, readonly [A, A]> =>
64
- f;
64
+ export const pairwise = <A,>(): DropInitialValueOperator<
65
+ A,
66
+ FixedLengthTuple<2, A>
67
+ > => f;
65
68
 
66
- const f = <A,>(parentObservable: Observable<A>): Observable<readonly [A, A]> =>
69
+ const f = <A,>(
70
+ parentObservable: Observable<A>,
71
+ ): Observable<FixedLengthTuple<2, A>> =>
67
72
  new PairwiseObservableClass(parentObservable);
68
73
 
69
74
  class PairwiseObservableClass<A>
70
- extends SyncChildObservableClass<readonly [A, A], readonly [A]>
75
+ extends SyncChildObservableClass<FixedLengthTuple<2, A>, readonly [A]>
71
76
  implements PairwiseOperatorObservable<A>
72
77
  {
73
78
  #mut_previousValue: Optional<A>;
@@ -89,11 +89,7 @@ class SkipWhileObservableClass<A>
89
89
  super({
90
90
  parents: [parentObservable],
91
91
  initialValue: pipe(parentObservable.getSnapshot()).map((sn) =>
92
- Optional.isNone(sn)
93
- ? Optional.none
94
- : predicate(sn.value, -1)
95
- ? Optional.none
96
- : sn,
92
+ Optional.isNone(sn) || predicate(sn.value, -1) ? Optional.none : sn,
97
93
  ).value,
98
94
  });
99
95