synstate 2.0.2 → 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.
Files changed (230) hide show
  1. package/README.md +2 -2
  2. package/dist/core/base/create-child-observable.d.mts +65 -0
  3. package/dist/core/base/create-child-observable.d.mts.map +1 -0
  4. package/dist/core/base/create-child-observable.mjs +181 -0
  5. package/dist/core/base/create-child-observable.mjs.map +1 -0
  6. package/dist/core/base/create-observable-base.d.mts +82 -0
  7. package/dist/core/base/create-observable-base.d.mts.map +1 -0
  8. package/dist/core/base/create-observable-base.mjs +156 -0
  9. package/dist/core/base/create-observable-base.mjs.map +1 -0
  10. package/dist/core/base/create-root-observable.d.mts +37 -0
  11. package/dist/core/base/create-root-observable.d.mts.map +1 -0
  12. package/dist/core/base/create-root-observable.mjs +50 -0
  13. package/dist/core/base/create-root-observable.mjs.map +1 -0
  14. package/dist/core/base/index.d.mts +3 -0
  15. package/dist/core/base/index.d.mts.map +1 -0
  16. package/dist/core/base/index.mjs +3 -0
  17. package/dist/core/base/index.mjs.map +1 -0
  18. package/dist/core/combine/combine.d.mts.map +1 -1
  19. package/dist/core/combine/combine.mjs +132 -39
  20. package/dist/core/combine/combine.mjs.map +1 -1
  21. package/dist/core/combine/index.mjs +4 -4
  22. package/dist/core/combine/index.mjs.map +1 -1
  23. package/dist/core/combine/merge.d.mts.map +1 -1
  24. package/dist/core/combine/merge.mjs +78 -29
  25. package/dist/core/combine/merge.mjs.map +1 -1
  26. package/dist/core/combine/zip.d.mts.map +1 -1
  27. package/dist/core/combine/zip.mjs +124 -42
  28. package/dist/core/combine/zip.mjs.map +1 -1
  29. package/dist/core/create/counter.d.mts.map +1 -1
  30. package/dist/core/create/counter.mjs +82 -57
  31. package/dist/core/create/counter.mjs.map +1 -1
  32. package/dist/core/create/from-abortable-promise.d.mts.map +1 -1
  33. package/dist/core/create/from-abortable-promise.mjs +62 -36
  34. package/dist/core/create/from-abortable-promise.mjs.map +1 -1
  35. package/dist/core/create/from-promise.d.mts.map +1 -1
  36. package/dist/core/create/from-promise.mjs +67 -25
  37. package/dist/core/create/from-promise.mjs.map +1 -1
  38. package/dist/core/create/from-subscribable.d.mts.map +1 -1
  39. package/dist/core/create/from-subscribable.mjs +72 -28
  40. package/dist/core/create/from-subscribable.mjs.map +1 -1
  41. package/dist/core/create/index.mjs +8 -8
  42. package/dist/core/create/index.mjs.map +1 -1
  43. package/dist/core/create/just.d.mts.map +1 -1
  44. package/dist/core/create/just.mjs +36 -12
  45. package/dist/core/create/just.mjs.map +1 -1
  46. package/dist/core/create/source.mjs +15 -20
  47. package/dist/core/create/source.mjs.map +1 -1
  48. package/dist/core/create/timer.d.mts.map +1 -1
  49. package/dist/core/create/timer.mjs +67 -44
  50. package/dist/core/create/timer.mjs.map +1 -1
  51. package/dist/core/index.d.mts +0 -1
  52. package/dist/core/index.d.mts.map +1 -1
  53. package/dist/core/index.mjs +6 -44
  54. package/dist/core/index.mjs.map +1 -1
  55. package/dist/core/operators/audit.d.mts.map +1 -1
  56. package/dist/core/operators/audit.mjs +127 -48
  57. package/dist/core/operators/audit.mjs.map +1 -1
  58. package/dist/core/operators/debounce.d.mts.map +1 -1
  59. package/dist/core/operators/debounce.mjs +115 -45
  60. package/dist/core/operators/debounce.mjs.map +1 -1
  61. package/dist/core/operators/filter.d.mts.map +1 -1
  62. package/dist/core/operators/filter.mjs +43 -32
  63. package/dist/core/operators/filter.mjs.map +1 -1
  64. package/dist/core/operators/index.mjs +18 -18
  65. package/dist/core/operators/index.mjs.map +1 -1
  66. package/dist/core/operators/map.d.mts.map +1 -1
  67. package/dist/core/operators/map.mjs +79 -38
  68. package/dist/core/operators/map.mjs.map +1 -1
  69. package/dist/core/operators/merge-map.d.mts.map +1 -1
  70. package/dist/core/operators/merge-map.mjs +131 -47
  71. package/dist/core/operators/merge-map.mjs.map +1 -1
  72. package/dist/core/operators/pairwise.d.mts.map +1 -1
  73. package/dist/core/operators/pairwise.mjs +79 -31
  74. package/dist/core/operators/pairwise.mjs.map +1 -1
  75. package/dist/core/operators/scan.d.mts.map +1 -1
  76. package/dist/core/operators/scan.mjs +64 -25
  77. package/dist/core/operators/scan.mjs.map +1 -1
  78. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
  79. package/dist/core/operators/skip-if-no-change.mjs +93 -39
  80. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  81. package/dist/core/operators/skip-until.d.mts.map +1 -1
  82. package/dist/core/operators/skip-until.mjs +73 -32
  83. package/dist/core/operators/skip-until.mjs.map +1 -1
  84. package/dist/core/operators/skip-while.d.mts.map +1 -1
  85. package/dist/core/operators/skip-while.mjs +85 -38
  86. package/dist/core/operators/skip-while.mjs.map +1 -1
  87. package/dist/core/operators/switch-map.d.mts.map +1 -1
  88. package/dist/core/operators/switch-map.mjs +121 -40
  89. package/dist/core/operators/switch-map.mjs.map +1 -1
  90. package/dist/core/operators/take-until.d.mts.map +1 -1
  91. package/dist/core/operators/take-until.mjs +71 -36
  92. package/dist/core/operators/take-until.mjs.map +1 -1
  93. package/dist/core/operators/take-while.d.mts.map +1 -1
  94. package/dist/core/operators/take-while.mjs +103 -35
  95. package/dist/core/operators/take-while.mjs.map +1 -1
  96. package/dist/core/operators/throttle.d.mts.map +1 -1
  97. package/dist/core/operators/throttle.mjs +109 -47
  98. package/dist/core/operators/throttle.mjs.map +1 -1
  99. package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
  100. package/dist/core/operators/with-buffered-from.mjs +93 -46
  101. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  102. package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
  103. package/dist/core/operators/with-current-value-from.mjs +84 -34
  104. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  105. package/dist/core/operators/with-initial-value.d.mts.map +1 -1
  106. package/dist/core/operators/with-initial-value.mjs +68 -21
  107. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  108. package/dist/core/predefined/index.mjs +2 -12
  109. package/dist/core/predefined/index.mjs.map +1 -1
  110. package/dist/core/predefined/operators/attach-index.mjs +55 -7
  111. package/dist/core/predefined/operators/attach-index.mjs.map +1 -1
  112. package/dist/core/predefined/operators/index.mjs +12 -12
  113. package/dist/core/predefined/operators/index.mjs.map +1 -1
  114. package/dist/core/predefined/operators/map-optional.mjs +48 -5
  115. package/dist/core/predefined/operators/map-optional.mjs.map +1 -1
  116. package/dist/core/predefined/operators/map-result-err.mjs +48 -5
  117. package/dist/core/predefined/operators/map-result-err.mjs.map +1 -1
  118. package/dist/core/predefined/operators/map-result-ok.mjs +48 -5
  119. package/dist/core/predefined/operators/map-result-ok.mjs.map +1 -1
  120. package/dist/core/predefined/operators/map-to.mjs +41 -6
  121. package/dist/core/predefined/operators/map-to.mjs.map +1 -1
  122. package/dist/core/predefined/operators/pluck.mjs +45 -7
  123. package/dist/core/predefined/operators/pluck.mjs.map +1 -1
  124. package/dist/core/predefined/operators/skip.mjs +49 -6
  125. package/dist/core/predefined/operators/skip.mjs.map +1 -1
  126. package/dist/core/predefined/operators/take.mjs +42 -6
  127. package/dist/core/predefined/operators/take.mjs.map +1 -1
  128. package/dist/core/predefined/operators/unwrap-optional.mjs +43 -8
  129. package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -1
  130. package/dist/core/predefined/operators/unwrap-result-err.mjs +41 -5
  131. package/dist/core/predefined/operators/unwrap-result-err.mjs.map +1 -1
  132. package/dist/core/predefined/operators/unwrap-result-ok.mjs +43 -8
  133. package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -1
  134. package/dist/core/types/id.mjs +2 -2
  135. package/dist/core/types/id.mjs.map +1 -1
  136. package/dist/core/types/index.mjs +7 -3
  137. package/dist/core/types/index.mjs.map +1 -1
  138. package/dist/core/types/observable-family.mjs +14 -2
  139. package/dist/core/types/observable-family.mjs.map +1 -1
  140. package/dist/core/types/observable-kind.mjs +2 -2
  141. package/dist/core/types/observable-kind.mjs.map +1 -1
  142. package/dist/core/types/observable.mjs +14 -6
  143. package/dist/core/types/observable.mjs.map +1 -1
  144. package/dist/core/types/timer.mjs +2 -2
  145. package/dist/core/types/timer.mjs.map +1 -1
  146. package/dist/core/types/types.mjs +9 -2
  147. package/dist/core/types/types.mjs.map +1 -1
  148. package/dist/core/utils/id-maker.mjs +10 -11
  149. package/dist/core/utils/id-maker.mjs.map +1 -1
  150. package/dist/core/utils/index.mjs +5 -5
  151. package/dist/core/utils/index.mjs.map +1 -1
  152. package/dist/core/utils/max-depth.mjs +7 -4
  153. package/dist/core/utils/max-depth.mjs.map +1 -1
  154. package/dist/core/utils/observable-utils.mjs +4 -7
  155. package/dist/core/utils/observable-utils.mjs.map +1 -1
  156. package/dist/core/utils/utils.mjs +32 -28
  157. package/dist/core/utils/utils.mjs.map +1 -1
  158. package/dist/entry-point.mjs +2 -49
  159. package/dist/entry-point.mjs.map +1 -1
  160. package/dist/index.mjs +3 -49
  161. package/dist/index.mjs.map +1 -1
  162. package/dist/utils/collect-to-array.mjs +8 -13
  163. package/dist/utils/collect-to-array.mjs.map +1 -1
  164. package/dist/utils/create-boolean-state.mjs +47 -22
  165. package/dist/utils/create-boolean-state.mjs.map +1 -1
  166. package/dist/utils/create-event-emitter.mjs +67 -19
  167. package/dist/utils/create-event-emitter.mjs.map +1 -1
  168. package/dist/utils/create-reducer.mjs +54 -16
  169. package/dist/utils/create-reducer.mjs.map +1 -1
  170. package/dist/utils/create-state.mjs +54 -27
  171. package/dist/utils/create-state.mjs.map +1 -1
  172. package/dist/utils/index.mjs +6 -6
  173. package/dist/utils/index.mjs.map +1 -1
  174. package/package.json +17 -19
  175. package/src/core/{class → base}/circular-dependency-comparison.test.mts +28 -18
  176. package/src/core/base/circular-dependency.test.mts +322 -0
  177. package/src/core/base/create-child-observable.mts +340 -0
  178. package/src/core/base/create-observable-base.mts +358 -0
  179. package/src/core/base/create-root-observable.mts +102 -0
  180. package/src/core/base/index.mts +2 -0
  181. package/src/core/{class/observable.class.test.mts → base/observable-base.test.mts} +25 -17
  182. package/src/core/combine/combine.mts +51 -53
  183. package/src/core/combine/merge.mts +21 -23
  184. package/src/core/combine/zip.mts +54 -58
  185. package/src/core/create/counter.mts +42 -59
  186. package/src/core/create/from-abortable-promise.mts +38 -45
  187. package/src/core/create/from-promise.mts +25 -28
  188. package/src/core/create/from-subscribable.mts +23 -27
  189. package/src/core/create/just.mts +5 -4
  190. package/src/core/create/source.mts +11 -17
  191. package/src/core/create/timer.mts +32 -47
  192. package/src/core/index.mts +0 -1
  193. package/src/core/operators/audit.mts +43 -57
  194. package/src/core/operators/debounce.mts +35 -45
  195. package/src/core/operators/filter.mts +31 -39
  196. package/src/core/operators/map.mts +32 -40
  197. package/src/core/operators/merge-map.mts +44 -59
  198. package/src/core/operators/pairwise.mts +30 -33
  199. package/src/core/operators/scan.mts +24 -35
  200. package/src/core/operators/skip-if-no-change.mts +31 -36
  201. package/src/core/operators/skip-until.mts +32 -35
  202. package/src/core/operators/skip-while.mts +31 -40
  203. package/src/core/operators/switch-map.mts +36 -48
  204. package/src/core/operators/take-until.mts +31 -29
  205. package/src/core/operators/take-while.mts +33 -41
  206. package/src/core/operators/throttle.mts +37 -51
  207. package/src/core/operators/with-buffered-from.mts +35 -30
  208. package/src/core/operators/with-current-value-from.mts +23 -28
  209. package/src/core/operators/with-initial-value.mts +21 -22
  210. package/dist/core/class/child-observable-class.d.mts +0 -39
  211. package/dist/core/class/child-observable-class.d.mts.map +0 -1
  212. package/dist/core/class/child-observable-class.mjs +0 -173
  213. package/dist/core/class/child-observable-class.mjs.map +0 -1
  214. package/dist/core/class/index.d.mts +0 -4
  215. package/dist/core/class/index.d.mts.map +0 -1
  216. package/dist/core/class/index.mjs +0 -4
  217. package/dist/core/class/index.mjs.map +0 -1
  218. package/dist/core/class/observable-base-class.d.mts +0 -28
  219. package/dist/core/class/observable-base-class.d.mts.map +0 -1
  220. package/dist/core/class/observable-base-class.mjs +0 -120
  221. package/dist/core/class/observable-base-class.mjs.map +0 -1
  222. package/dist/core/class/root-observable-class.d.mts +0 -14
  223. package/dist/core/class/root-observable-class.d.mts.map +0 -1
  224. package/dist/core/class/root-observable-class.mjs +0 -43
  225. package/dist/core/class/root-observable-class.mjs.map +0 -1
  226. package/src/core/class/child-observable-class.mts +0 -286
  227. package/src/core/class/circular-dependency.test.mts +0 -251
  228. package/src/core/class/index.mts +0 -3
  229. package/src/core/class/observable-base-class.mts +0 -187
  230. package/src/core/class/root-observable-class.mts +0 -73
@@ -1,6 +1,6 @@
1
1
  import { Optional, expectType } from 'ts-data-forge';
2
2
  import { type ArrayElement, type NonEmptyTuple } from 'ts-type-forge';
3
- import { SyncChildObservableClass } from '../class/index.mjs';
3
+ import { createSyncChildObservable } from '../base/index.mjs';
4
4
  import { source } from '../create/index.mjs';
5
5
  import {
6
6
  type MergeObservable,
@@ -8,7 +8,6 @@ import {
8
8
  type NonEmptyUnknownList,
9
9
  type Observable,
10
10
  type SyncChildObservable,
11
- type UpdateToken,
12
11
  type Wrap,
13
12
  } from '../types/index.mjs';
14
13
 
@@ -67,33 +66,32 @@ export const merge = <const OS extends NonEmptyTuple<Observable<unknown>>>(
67
66
  parents: OS,
68
67
  ): MergeObservableRefined<OS> =>
69
68
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
70
- new MergeObservableClass(parents) as MergeObservableRefined<OS>;
69
+ createMergeObservable(parents) as MergeObservableRefined<OS>;
71
70
 
72
- class MergeObservableClass<const P extends NonEmptyUnknownList>
73
- extends SyncChildObservableClass<ArrayElement<P>, P>
74
- implements MergeObservable<P>
75
- {
76
- constructor(parents: Wrap<P>) {
77
- super({
71
+ const createMergeObservable = <const P extends NonEmptyUnknownList>(
72
+ parents: Wrap<P>,
73
+ ): MergeObservable<P> =>
74
+ createSyncChildObservable<ArrayElement<P>, P>(
75
+ {
78
76
  parents,
79
77
  initialValue: Optional.none,
80
- });
81
- }
78
+ },
79
+ ({ setNext }) =>
80
+ (updateToken) => {
81
+ const parentToUse = parents.find(
82
+ (o) =>
83
+ o.updateToken === updateToken && Optional.isSome(o.getSnapshot()),
84
+ );
82
85
 
83
- override tryUpdate(updateToken: UpdateToken): void {
84
- const parentToUse = this.parents.find(
85
- (o) => o.updateToken === updateToken && Optional.isSome(o.getSnapshot()),
86
- );
86
+ if (parentToUse === undefined) return;
87
87
 
88
- if (parentToUse === undefined) return;
88
+ const nextValue =
89
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
90
+ Optional.unwrap(parentToUse.getSnapshot()) as ArrayElement<P>;
89
91
 
90
- const nextValue =
91
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
92
- Optional.unwrap(parentToUse.getSnapshot()) as ArrayElement<P>;
93
-
94
- this.setNext(nextValue, updateToken);
95
- }
96
- }
92
+ setNext(nextValue, updateToken);
93
+ },
94
+ );
97
95
 
98
96
  if (import.meta.vitest !== undefined) {
99
97
  test('type test', () => {
@@ -1,6 +1,6 @@
1
1
  import { Arr, Optional, createQueue, expectType } from 'ts-data-forge';
2
2
  import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
3
- import { SyncChildObservableClass } from '../class/index.mjs';
3
+ import { createSyncChildObservable } from '../base/index.mjs';
4
4
  import { source } from '../create/index.mjs';
5
5
  import { withInitialValue } from '../operators/index.mjs';
6
6
  import {
@@ -10,7 +10,6 @@ import {
10
10
  type Observable,
11
11
  type SyncChildObservable,
12
12
  type TupleToQueueTuple,
13
- type UpdateToken,
14
13
  type Wrap,
15
14
  type ZipObservable,
16
15
  type ZipObservableRefined,
@@ -69,63 +68,60 @@ export const zip = <const OS extends NonEmptyTuple<Observable<unknown>>>(
69
68
  parents: OS,
70
69
  ): ZipObservableRefined<OS> =>
71
70
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
72
- new ZipObservableClass(parents) as unknown as ZipObservableRefined<OS>;
73
-
74
- class ZipObservableClass<const A extends NonEmptyUnknownList>
75
- extends SyncChildObservableClass<A, A>
76
- implements ZipObservable<A>
77
- {
78
- readonly #queues: TupleToQueueTuple<A>;
79
-
80
- constructor(parents: Wrap<A>) {
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;
98
-
99
- super({
71
+ createZipObservable(parents) as unknown as ZipObservableRefined<OS>;
72
+
73
+ const createZipObservable = <const A extends NonEmptyUnknownList>(
74
+ parents: Wrap<A>,
75
+ ): ZipObservable<A> => {
76
+ const parentsValues: Tuple.MapTo<Optional<A[number]>, A> = Arr.map(
77
+ parents,
78
+ (p) => p.getSnapshot(),
79
+ );
80
+
81
+ // The annotation on `initialValue` is what replaces the type assertion.
82
+ // `Arr.map` carries a single result element type, so it reports `A[number]`
83
+ // at every position, and `Tuple.MapTo<A[number], A>` — the uniform mapping
84
+ // — is *not* assignable back to `A`. The positional
85
+ // `Readonly<{ [K in keyof A]: A[K] }>` is, and TypeScript accepts the
86
+ // uniform result into it because the two mapped types share `keyof A`. So
87
+ // it is the annotation, not an assertion, that records the position-wise
88
+ // fact the checker cannot derive on its own.
89
+ const initialValue: Optional<Readonly<{ [K in keyof A]: A[K] }>> = Arr.every(
90
+ parentsValues,
91
+ Optional.isSome,
92
+ )
93
+ ? Optional.some(Arr.map(parentsValues, (c) => c.value))
94
+ : Optional.none;
95
+
96
+ const queues: TupleToQueueTuple<A> = Arr.map(parents, () => createQueue());
97
+
98
+ return createSyncChildObservable<A, A>(
99
+ {
100
100
  parents,
101
101
  initialValue,
102
- });
103
-
104
- this.#queues = Arr.map(parents, () => createQueue());
105
- }
106
-
107
- override tryUpdate(updateToken: UpdateToken): void {
108
- const queues = this.#queues;
109
-
110
- for (const [index, par] of this.parents.entries()) {
111
- const sn = par.getSnapshot();
112
-
113
- if (par.updateToken === updateToken && Optional.isSome(sn)) {
114
- queues[index]?.enqueue(sn.value);
115
- }
116
- }
117
-
118
- if (queues.every((list) => !list.isEmpty)) {
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]`.
122
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
123
- Arr.map(queues, (q) => Optional.unwrap(q.dequeue())) as A;
124
-
125
- this.setNext(nextValue, updateToken);
126
- }
127
- }
128
- }
102
+ },
103
+ ({ setNext }) =>
104
+ (updateToken) => {
105
+ for (const [index, par] of parents.entries()) {
106
+ const sn = par.getSnapshot();
107
+
108
+ if (par.updateToken === updateToken && Optional.isSome(sn)) {
109
+ queues[index]?.enqueue(sn.value);
110
+ }
111
+ }
112
+
113
+ if (queues.every((list) => !list.isEmpty)) {
114
+ const nextValue =
115
+ // `Arr.map` has a single result element type, so it reports
116
+ // `A[number] | undefined` per position rather than `A[P]`.
117
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
118
+ Arr.map(queues, (q) => Optional.unwrap(q.dequeue())) as A;
119
+
120
+ setNext(nextValue, updateToken);
121
+ }
122
+ },
123
+ );
124
+ };
129
125
 
130
126
  if (import.meta.vitest !== undefined) {
131
127
  test('type test', () => {
@@ -176,7 +172,7 @@ if (import.meta.vitest !== undefined) {
176
172
  const _zi = zip([
177
173
  r1.pipe(withInitialValue(0)),
178
174
  r2.pipe(withInitialValue('0')),
179
- ] as const);
175
+ ]);
180
176
 
181
177
  expectType<typeof _z, SyncChildObservable<readonly [number, string]>>('<=');
182
178
 
@@ -1,5 +1,5 @@
1
1
  import { asSafeUint, Optional, SafeUint } from 'ts-data-forge';
2
- import { RootObservableClass } from '../class/index.mjs';
2
+ import { createRootObservable } from '../base/index.mjs';
3
3
  import { type CounterObservable, type TimerId } from '../types/index.mjs';
4
4
 
5
5
  /**
@@ -50,79 +50,62 @@ export const counter = (
50
50
  options?: Readonly<{
51
51
  startManually?: boolean;
52
52
  }>,
53
- ): CounterObservable =>
54
- new CounterObservableClass(
55
- intervalMilliSeconds,
56
- options?.startManually ?? false,
57
- );
58
-
59
- class CounterObservableClass
60
- extends RootObservableClass<SafeUint>
61
- implements CounterObservable
62
- {
63
- readonly #intervalMilliSeconds: number;
64
- #mut_counter: SafeUint;
65
- #mut_timerId0: TimerId | undefined;
66
- #mut_timerId: TimerId | undefined;
67
- #mut_isStarted: boolean;
68
-
69
- constructor(intervalMilliSeconds: number, startManually: boolean) {
70
- super({ initialValue: Optional.none });
71
-
72
- this.#intervalMilliSeconds = intervalMilliSeconds;
73
-
74
- this.#mut_counter = asSafeUint(0);
53
+ ): CounterObservable => {
54
+ let mut_counter: SafeUint = asSafeUint(0);
75
55
 
76
- this.#mut_timerId0 = undefined;
56
+ let mut_timerId0: TimerId | undefined = undefined;
77
57
 
78
- this.#mut_timerId = undefined;
58
+ let mut_timerId: TimerId | undefined = undefined;
79
59
 
80
- this.#mut_isStarted = false;
60
+ let mut_isStarted = false;
81
61
 
82
- if (!startManually) {
83
- this.start();
84
- }
85
- }
86
-
87
- #resetTimer(): void {
88
- if (this.#mut_timerId0 === undefined || this.#mut_timerId === undefined) {
62
+ const resetTimer = (): void => {
63
+ if (mut_timerId0 === undefined || mut_timerId === undefined) {
89
64
  return;
90
65
  }
91
66
 
92
- clearInterval(this.#mut_timerId0);
67
+ clearInterval(mut_timerId0);
93
68
 
94
- clearInterval(this.#mut_timerId);
95
- }
69
+ clearInterval(mut_timerId);
70
+ };
96
71
 
97
- start(): void {
98
- if (this.#mut_isStarted) {
99
- console.warn('cannot start twice');
72
+ const observable = createRootObservable<
73
+ SafeUint,
74
+ Readonly<{ start: () => void }>
75
+ >(
76
+ { initialValue: Optional.none, onComplete: resetTimer },
77
+ ({ startUpdate, isCompleted }) => ({
78
+ start: () => {
79
+ if (mut_isStarted) {
80
+ console.warn('cannot start twice');
100
81
 
101
- return;
102
- }
82
+ return;
83
+ }
103
84
 
104
- this.#mut_isStarted = true;
85
+ mut_isStarted = true;
105
86
 
106
- if (this.isCompleted) {
107
- console.warn('cannot restart stopped CounterObservable');
108
-
109
- return;
110
- }
87
+ if (isCompleted()) {
88
+ console.warn('cannot restart stopped CounterObservable');
111
89
 
112
- this.#mut_timerId0 = setTimeout(() => {
113
- this.startUpdate(this.#mut_counter);
114
- }, 0);
90
+ return;
91
+ }
115
92
 
116
- this.#mut_timerId = setInterval(() => {
117
- this.#mut_counter = SafeUint.add(1, this.#mut_counter);
93
+ mut_timerId0 = setTimeout(() => {
94
+ startUpdate(mut_counter);
95
+ }, 0);
118
96
 
119
- this.startUpdate(this.#mut_counter);
120
- }, this.#intervalMilliSeconds);
121
- }
97
+ mut_timerId = setInterval(() => {
98
+ mut_counter = SafeUint.add(1, mut_counter);
122
99
 
123
- override complete(): void {
124
- this.#resetTimer();
100
+ startUpdate(mut_counter);
101
+ }, intervalMilliSeconds);
102
+ },
103
+ }),
104
+ );
125
105
 
126
- super.complete();
106
+ if (!(options?.startManually ?? false)) {
107
+ observable.start();
127
108
  }
128
- }
109
+
110
+ return observable;
111
+ };
@@ -1,5 +1,5 @@
1
1
  import { Optional, Result } from 'ts-data-forge';
2
- import { RootObservableClass } from '../class/index.mjs';
2
+ import { createRootObservable } from '../base/index.mjs';
3
3
  import { type FromPromiseObservable } from '../types/index.mjs';
4
4
 
5
5
  /**
@@ -31,53 +31,46 @@ import { type FromPromiseObservable } from '../types/index.mjs';
31
31
  export const fromAbortablePromise = <A, E = unknown>(
32
32
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
33
33
  factory: (signal: AbortSignal) => Promise<A>,
34
- ): FromPromiseObservable<A, E> =>
35
- new FromAbortablePromiseObservableClass(factory);
34
+ ): FromPromiseObservable<A, E> => {
35
+ const abortController = new AbortController();
36
36
 
37
- class FromAbortablePromiseObservableClass<A, E = unknown>
38
- extends RootObservableClass<Result<A, E>>
39
- implements FromPromiseObservable<A, E>
40
- {
41
- readonly #abortController: AbortController;
37
+ return createRootObservable<Result<A, E>>(
38
+ {
39
+ initialValue: Optional.none,
40
+ onComplete: () => {
41
+ abortController.abort();
42
+ },
43
+ },
44
+ ({ startUpdate, isCompleted, complete }) => {
45
+ const promise = factory(abortController.signal);
42
46
 
43
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
44
- constructor(factory: (signal: AbortSignal) => Promise<A>) {
45
- super({ initialValue: Optional.none });
46
-
47
- this.#abortController = new AbortController();
48
-
49
- const promise = factory(this.#abortController.signal);
50
-
51
- promise
52
- .then((value) => {
53
- if (this.isCompleted) return;
54
-
55
- this.startUpdate(Result.ok(value));
56
- })
57
- .catch((error: unknown) => {
58
- if (this.isCompleted) return;
47
+ promise
48
+ .then((value) => {
49
+ if (isCompleted()) return;
59
50
 
60
- // Silently ignore AbortError — it means the observable was
61
- // intentionally completed (e.g., by switchMap).
62
- if (error instanceof DOMException && error.name === 'AbortError') {
63
- return;
64
- }
51
+ startUpdate(Result.ok(value));
52
+ })
53
+ .catch((error: unknown) => {
54
+ if (isCompleted()) return;
65
55
 
66
- this.startUpdate(
67
- Result.err(
68
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
69
- error as E,
70
- ),
71
- );
72
- })
73
- .finally(() => {
74
- this.complete();
75
- });
76
- }
56
+ // Silently ignore AbortError — it means the observable was
57
+ // intentionally completed (e.g., by switchMap).
58
+ if (error instanceof DOMException && error.name === 'AbortError') {
59
+ return;
60
+ }
77
61
 
78
- override complete(): void {
79
- this.#abortController.abort();
62
+ startUpdate(
63
+ Result.err(
64
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
65
+ error as E,
66
+ ),
67
+ );
68
+ })
69
+ .finally(() => {
70
+ complete();
71
+ });
80
72
 
81
- super.complete();
82
- }
83
- }
73
+ return {};
74
+ },
75
+ );
76
+ };
@@ -1,5 +1,5 @@
1
1
  import { Optional, Result } from 'ts-data-forge';
2
- import { RootObservableClass } from '../class/index.mjs';
2
+ import { createRootObservable } from '../base/index.mjs';
3
3
  import { type FromPromiseObservable } from '../types/index.mjs';
4
4
 
5
5
  /**
@@ -51,33 +51,30 @@ import { type FromPromiseObservable } from '../types/index.mjs';
51
51
  */
52
52
  export const fromPromise = <A, E = unknown>(
53
53
  promise: Promise<A>,
54
- ): FromPromiseObservable<A, E> => new FromPromiseObservableClass(promise);
54
+ ): FromPromiseObservable<A, E> =>
55
+ createRootObservable<Result<A, E>>(
56
+ { initialValue: Optional.none },
57
+ ({ startUpdate, isCompleted, complete }) => {
58
+ promise
59
+ .then((value) => {
60
+ if (isCompleted()) return;
55
61
 
56
- class FromPromiseObservableClass<A, E = unknown>
57
- extends RootObservableClass<Result<A, E>>
58
- implements FromPromiseObservable<A, E>
59
- {
60
- constructor(promise: Promise<A>) {
61
- super({ initialValue: Optional.none });
62
+ startUpdate(Result.ok(value));
63
+ })
64
+ .catch((error: unknown) => {
65
+ if (isCompleted()) return;
62
66
 
63
- promise
64
- .then((value) => {
65
- if (this.isCompleted) return;
67
+ startUpdate(
68
+ Result.err(
69
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
70
+ error as E,
71
+ ),
72
+ );
73
+ })
74
+ .finally(() => {
75
+ complete();
76
+ });
66
77
 
67
- this.startUpdate(Result.ok(value));
68
- })
69
- .catch((error: unknown) => {
70
- if (this.isCompleted) return;
71
-
72
- this.startUpdate(
73
- Result.err(
74
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
75
- error as E,
76
- ),
77
- );
78
- })
79
- .finally(() => {
80
- this.complete();
81
- });
82
- }
83
- }
78
+ return {};
79
+ },
80
+ );
@@ -1,5 +1,5 @@
1
1
  import { Optional, Result } from 'ts-data-forge';
2
- import { RootObservableClass } from '../class/index.mjs';
2
+ import { createRootObservable } from '../base/index.mjs';
3
3
  import {
4
4
  type FromSubscribableObservable,
5
5
  type Subscribable,
@@ -66,30 +66,26 @@ import {
66
66
  export const fromSubscribable = <A, E = unknown>(
67
67
  subscribable: Subscribable<A>,
68
68
  ): FromSubscribableObservable<A, E> =>
69
- new FromSubscribableObservableClass(subscribable);
69
+ createRootObservable<Result<A, E>>(
70
+ { initialValue: Optional.none },
71
+ ({ startUpdate, complete }) => {
72
+ subscribable.subscribe(
73
+ (nextValue) => {
74
+ startUpdate(Result.ok(nextValue));
75
+ },
76
+ (error?: unknown) => {
77
+ startUpdate(
78
+ Result.err(
79
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
80
+ error as E,
81
+ ),
82
+ );
83
+ },
84
+ () => {
85
+ complete();
86
+ },
87
+ );
70
88
 
71
- class FromSubscribableObservableClass<A, E = unknown>
72
- extends RootObservableClass<Result<A, E>>
73
- implements FromSubscribableObservable<A, E>
74
- {
75
- constructor(subscribable: Subscribable<A>) {
76
- super({ initialValue: Optional.none });
77
-
78
- subscribable.subscribe(
79
- (nextValue) => {
80
- this.startUpdate(Result.ok(nextValue));
81
- },
82
- (error?: unknown) => {
83
- this.startUpdate(
84
- Result.err(
85
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
86
- error as E,
87
- ),
88
- );
89
- },
90
- () => {
91
- this.complete();
92
- },
93
- );
94
- }
95
- }
89
+ return {};
90
+ },
91
+ );
@@ -1,5 +1,5 @@
1
1
  import { Optional } from 'ts-data-forge';
2
- import { RootObservableClass } from '../class/index.mjs';
2
+ import { createRootObservable } from '../base/index.mjs';
3
3
  import { type InitializedRootObservable } from '../types/index.mjs';
4
4
 
5
5
  /**
@@ -32,9 +32,10 @@ import { type InitializedRootObservable } from '../types/index.mjs';
32
32
  * ```
33
33
  */
34
34
  export const just = <const A,>(value: A): InitializedRootObservable<A> => {
35
- const obs = new RootObservableClass<A>({
36
- initialValue: Optional.some(value),
37
- });
35
+ const obs = createRootObservable<A>(
36
+ { initialValue: Optional.some(value) },
37
+ () => ({}),
38
+ );
38
39
 
39
40
  obs.complete();
40
41
 
@@ -1,5 +1,5 @@
1
1
  import { Arr, Optional } from 'ts-data-forge';
2
- import { RootObservableClass } from '../class/index.mjs';
2
+ import { createRootObservable } from '../base/index.mjs';
3
3
  import {
4
4
  type InitializedSourceObservable,
5
5
  type SourceObservable,
@@ -51,24 +51,18 @@ export function source<const A>(
51
51
  export function source<const A>(): SourceObservable<A>;
52
52
 
53
53
  export function source<const A>(...args: readonly A[]): SourceObservable<A> {
54
- return new SourceObservableClass<A>(...args);
55
- }
56
-
57
- class SourceObservableClass<A>
58
- extends RootObservableClass<A>
59
- implements SourceObservable<A>
60
- {
61
- constructor(...args: readonly A[]) {
62
- super({
54
+ return createRootObservable<A, Readonly<{ next: (nextValue: A) => void }>>(
55
+ {
63
56
  initialValue: Arr.isNonEmpty(args)
64
57
  ? Optional.some(args[0])
65
58
  : Optional.none,
66
- });
67
- }
68
-
69
- next(nextValue: A): void {
70
- if (this.isCompleted) return;
59
+ },
60
+ ({ startUpdate, isCompleted }) => ({
61
+ next: (nextValue: A) => {
62
+ if (isCompleted()) return;
71
63
 
72
- this.startUpdate(nextValue);
73
- }
64
+ startUpdate(nextValue);
65
+ },
66
+ }),
67
+ );
74
68
  }