synstate 3.3.0 → 4.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 (307) hide show
  1. package/README.md +14 -9
  2. package/dist/core/authoring.d.mts +7 -0
  3. package/dist/core/authoring.d.mts.map +1 -0
  4. package/dist/core/authoring.mjs +7 -0
  5. package/dist/core/authoring.mjs.map +1 -0
  6. package/dist/core/class/child-observable-class.d.mts +93 -0
  7. package/dist/core/class/child-observable-class.d.mts.map +1 -0
  8. package/dist/core/class/child-observable-class.mjs +248 -0
  9. package/dist/core/class/child-observable-class.mjs.map +1 -0
  10. package/dist/core/class/create-child-observable.d.mts +159 -0
  11. package/dist/core/class/create-child-observable.d.mts.map +1 -0
  12. package/dist/core/class/create-child-observable.mjs +183 -0
  13. package/dist/core/class/create-child-observable.mjs.map +1 -0
  14. package/dist/core/class/create-root-observable.d.mts +37 -0
  15. package/dist/core/class/create-root-observable.d.mts.map +1 -0
  16. package/dist/core/class/create-root-observable.mjs +52 -0
  17. package/dist/core/class/create-root-observable.mjs.map +1 -0
  18. package/dist/core/class/index.d.mts +9 -0
  19. package/dist/core/class/index.d.mts.map +1 -0
  20. package/dist/core/class/index.mjs +9 -0
  21. package/dist/core/class/index.mjs.map +1 -0
  22. package/dist/core/class/manager-observable-class.d.mts +26 -0
  23. package/dist/core/class/manager-observable-class.d.mts.map +1 -0
  24. package/dist/core/class/manager-observable-class.mjs +116 -0
  25. package/dist/core/class/manager-observable-class.mjs.map +1 -0
  26. package/dist/core/class/observable-base-class.d.mts +97 -0
  27. package/dist/core/class/observable-base-class.d.mts.map +1 -0
  28. package/dist/core/class/observable-base-class.mjs +219 -0
  29. package/dist/core/class/observable-base-class.mjs.map +1 -0
  30. package/dist/core/class/observable-node.d.mts +40 -0
  31. package/dist/core/class/observable-node.d.mts.map +1 -0
  32. package/dist/core/class/observable-node.mjs +10 -0
  33. package/dist/core/class/observable-node.mjs.map +1 -0
  34. package/dist/core/class/propagation-state.d.mts +24 -0
  35. package/dist/core/class/propagation-state.d.mts.map +1 -0
  36. package/dist/core/class/propagation-state.mjs +66 -0
  37. package/dist/core/class/propagation-state.mjs.map +1 -0
  38. package/dist/core/class/root-observable-class.d.mts +23 -0
  39. package/dist/core/class/root-observable-class.d.mts.map +1 -0
  40. package/dist/core/class/root-observable-class.mjs +58 -0
  41. package/dist/core/class/root-observable-class.mjs.map +1 -0
  42. package/dist/core/combine/combine.d.mts.map +1 -1
  43. package/dist/core/combine/combine.mjs +25 -14
  44. package/dist/core/combine/combine.mjs.map +1 -1
  45. package/dist/core/combine/merge.d.mts +0 -3
  46. package/dist/core/combine/merge.d.mts.map +1 -1
  47. package/dist/core/combine/merge.mjs +24 -15
  48. package/dist/core/combine/merge.mjs.map +1 -1
  49. package/dist/core/combine/zip.d.mts +4 -2
  50. package/dist/core/combine/zip.d.mts.map +1 -1
  51. package/dist/core/combine/zip.mjs +54 -18
  52. package/dist/core/combine/zip.mjs.map +1 -1
  53. package/dist/core/create/counter.d.mts +9 -3
  54. package/dist/core/create/counter.d.mts.map +1 -1
  55. package/dist/core/create/counter.mjs +69 -35
  56. package/dist/core/create/counter.mjs.map +1 -1
  57. package/dist/core/create/from-abortable-promise.d.mts.map +1 -1
  58. package/dist/core/create/from-abortable-promise.mjs +26 -18
  59. package/dist/core/create/from-abortable-promise.mjs.map +1 -1
  60. package/dist/core/create/from-promise.d.mts.map +1 -1
  61. package/dist/core/create/from-promise.mjs +30 -21
  62. package/dist/core/create/from-promise.mjs.map +1 -1
  63. package/dist/core/create/from-subscribable.d.mts.map +1 -1
  64. package/dist/core/create/from-subscribable.mjs +48 -12
  65. package/dist/core/create/from-subscribable.mjs.map +1 -1
  66. package/dist/core/create/just.d.mts.map +1 -1
  67. package/dist/core/create/just.mjs +4 -2
  68. package/dist/core/create/just.mjs.map +1 -1
  69. package/dist/core/create/source.d.mts +7 -0
  70. package/dist/core/create/source.d.mts.map +1 -1
  71. package/dist/core/create/source.mjs +27 -13
  72. package/dist/core/create/source.mjs.map +1 -1
  73. package/dist/core/create/timer.d.mts.map +1 -1
  74. package/dist/core/create/timer.mjs +40 -25
  75. package/dist/core/create/timer.mjs.map +1 -1
  76. package/dist/core/index.d.mts +2 -0
  77. package/dist/core/index.d.mts.map +1 -1
  78. package/dist/core/index.mjs +2 -0
  79. package/dist/core/index.mjs.map +1 -1
  80. package/dist/core/operators/audit.d.mts +3 -0
  81. package/dist/core/operators/audit.d.mts.map +1 -1
  82. package/dist/core/operators/audit.mjs +56 -28
  83. package/dist/core/operators/audit.mjs.map +1 -1
  84. package/dist/core/operators/debounce.d.mts +3 -0
  85. package/dist/core/operators/debounce.d.mts.map +1 -1
  86. package/dist/core/operators/debounce.mjs +57 -26
  87. package/dist/core/operators/debounce.mjs.map +1 -1
  88. package/dist/core/operators/filter.d.mts.map +1 -1
  89. package/dist/core/operators/filter.mjs +35 -21
  90. package/dist/core/operators/filter.mjs.map +1 -1
  91. package/dist/core/operators/index.d.mts +1 -0
  92. package/dist/core/operators/index.d.mts.map +1 -1
  93. package/dist/core/operators/index.mjs +1 -0
  94. package/dist/core/operators/index.mjs.map +1 -1
  95. package/dist/core/operators/map.d.mts.map +1 -1
  96. package/dist/core/operators/map.mjs +31 -17
  97. package/dist/core/operators/map.mjs.map +1 -1
  98. package/dist/core/operators/merge-map.d.mts +5 -3
  99. package/dist/core/operators/merge-map.d.mts.map +1 -1
  100. package/dist/core/operators/merge-map.mjs +49 -26
  101. package/dist/core/operators/merge-map.mjs.map +1 -1
  102. package/dist/core/operators/pairwise.d.mts.map +1 -1
  103. package/dist/core/operators/pairwise.mjs +31 -20
  104. package/dist/core/operators/pairwise.mjs.map +1 -1
  105. package/dist/core/operators/scan.d.mts.map +1 -1
  106. package/dist/core/operators/scan.mjs +27 -14
  107. package/dist/core/operators/scan.mjs.map +1 -1
  108. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
  109. package/dist/core/operators/skip-if-no-change.mjs +33 -19
  110. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  111. package/dist/core/operators/skip-until.d.mts.map +1 -1
  112. package/dist/core/operators/skip-until.mjs +43 -20
  113. package/dist/core/operators/skip-until.mjs.map +1 -1
  114. package/dist/core/operators/skip-while.d.mts.map +1 -1
  115. package/dist/core/operators/skip-while.mjs +35 -20
  116. package/dist/core/operators/skip-while.mjs.map +1 -1
  117. package/dist/core/operators/switch-map.d.mts +5 -3
  118. package/dist/core/operators/switch-map.d.mts.map +1 -1
  119. package/dist/core/operators/switch-map.mjs +53 -25
  120. package/dist/core/operators/switch-map.mjs.map +1 -1
  121. package/dist/core/operators/take-until.d.mts.map +1 -1
  122. package/dist/core/operators/take-until.mjs +38 -19
  123. package/dist/core/operators/take-until.mjs.map +1 -1
  124. package/dist/core/operators/take-while.d.mts.map +1 -1
  125. package/dist/core/operators/take-while.mjs +36 -22
  126. package/dist/core/operators/take-while.mjs.map +1 -1
  127. package/dist/core/{predefined/operators → operators}/take.d.mts +7 -3
  128. package/dist/core/operators/take.d.mts.map +1 -0
  129. package/dist/core/operators/take.mjs +102 -0
  130. package/dist/core/operators/take.mjs.map +1 -0
  131. package/dist/core/operators/throttle.d.mts.map +1 -1
  132. package/dist/core/operators/throttle.mjs +41 -26
  133. package/dist/core/operators/throttle.mjs.map +1 -1
  134. package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
  135. package/dist/core/operators/with-buffered-from.mjs +44 -31
  136. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  137. package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
  138. package/dist/core/operators/with-current-value-from.mjs +36 -21
  139. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  140. package/dist/core/operators/with-initial-value.d.mts.map +1 -1
  141. package/dist/core/operators/with-initial-value.mjs +24 -12
  142. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  143. package/dist/core/predefined/operators/index.d.mts +0 -1
  144. package/dist/core/predefined/operators/index.d.mts.map +1 -1
  145. package/dist/core/predefined/operators/index.mjs +0 -1
  146. package/dist/core/predefined/operators/index.mjs.map +1 -1
  147. package/dist/core/scope/index.d.mts +2 -0
  148. package/dist/core/scope/index.d.mts.map +1 -0
  149. package/dist/core/scope/index.mjs +2 -0
  150. package/dist/core/scope/index.mjs.map +1 -0
  151. package/dist/core/scope/scope.d.mts +51 -0
  152. package/dist/core/scope/scope.d.mts.map +1 -0
  153. package/dist/core/scope/scope.mjs +194 -0
  154. package/dist/core/scope/scope.mjs.map +1 -0
  155. package/dist/core/types/id.d.mts +0 -2
  156. package/dist/core/types/id.d.mts.map +1 -1
  157. package/dist/core/types/index.d.mts +1 -0
  158. package/dist/core/types/index.d.mts.map +1 -1
  159. package/dist/core/types/index.mjs +1 -0
  160. package/dist/core/types/index.mjs.map +1 -1
  161. package/dist/core/types/observable-family.d.mts +6 -1
  162. package/dist/core/types/observable-family.d.mts.map +1 -1
  163. package/dist/core/types/observable-family.mjs.map +1 -1
  164. package/dist/core/types/observable.d.mts +40 -28
  165. package/dist/core/types/observable.d.mts.map +1 -1
  166. package/dist/core/types/observable.mjs +24 -0
  167. package/dist/core/types/observable.mjs.map +1 -1
  168. package/dist/core/types/scope.d.mts +27 -0
  169. package/dist/core/types/scope.d.mts.map +1 -0
  170. package/dist/core/types/scope.mjs +2 -0
  171. package/dist/core/types/scope.mjs.map +1 -0
  172. package/dist/core/utils/current-scope.d.mts +30 -0
  173. package/dist/core/utils/current-scope.d.mts.map +1 -0
  174. package/dist/core/utils/current-scope.mjs +26 -0
  175. package/dist/core/utils/current-scope.mjs.map +1 -0
  176. package/dist/core/utils/id-maker.d.mts +14 -3
  177. package/dist/core/utils/id-maker.d.mts.map +1 -1
  178. package/dist/core/utils/id-maker.mjs +18 -14
  179. package/dist/core/utils/id-maker.mjs.map +1 -1
  180. package/dist/core/utils/index.d.mts +2 -1
  181. package/dist/core/utils/index.d.mts.map +1 -1
  182. package/dist/core/utils/index.mjs +2 -1
  183. package/dist/core/utils/index.mjs.map +1 -1
  184. package/dist/core/utils/max-depth.d.mts +1 -0
  185. package/dist/core/utils/max-depth.d.mts.map +1 -1
  186. package/dist/core/utils/max-depth.mjs +9 -7
  187. package/dist/core/utils/max-depth.mjs.map +1 -1
  188. package/dist/core/utils/observable-brand.d.mts +13 -0
  189. package/dist/core/utils/observable-brand.d.mts.map +1 -0
  190. package/dist/core/utils/observable-brand.mjs +13 -0
  191. package/dist/core/utils/observable-brand.mjs.map +1 -0
  192. package/dist/utils/create-boolean-state.d.mts +2 -2
  193. package/dist/utils/create-event-emitter.d.mts +2 -2
  194. package/dist/utils/create-reducer.d.mts +17 -8
  195. package/dist/utils/create-reducer.d.mts.map +1 -1
  196. package/dist/utils/create-reducer.mjs +14 -6
  197. package/dist/utils/create-reducer.mjs.map +1 -1
  198. package/dist/utils/create-state.d.mts +9 -2
  199. package/dist/utils/create-state.d.mts.map +1 -1
  200. package/dist/utils/create-state.mjs +7 -0
  201. package/dist/utils/create-state.mjs.map +1 -1
  202. package/package.json +16 -16
  203. package/src/core/authoring.mts +19 -0
  204. package/src/core/class/child-observable-class.mts +374 -0
  205. package/src/core/{base → class}/circular-dependency-comparison.test.mts +46 -38
  206. package/src/core/{base → class}/circular-dependency.test.mts +38 -2
  207. package/src/core/class/complete-propagation.test.mts +264 -0
  208. package/src/core/class/create-child-observable.mts +370 -0
  209. package/src/core/class/create-root-observable.mts +107 -0
  210. package/src/core/class/index.mts +8 -0
  211. package/src/core/class/manager-observable-class.mts +166 -0
  212. package/src/core/class/observable-base-class.mts +315 -0
  213. package/src/core/{base → class}/observable-base.test.mts +1 -1
  214. package/src/core/class/observable-node.mts +54 -0
  215. package/src/core/class/propagation-order.test.mts +92 -0
  216. package/src/core/class/propagation-state.mts +80 -0
  217. package/src/core/class/remove-completed.test.mts +369 -0
  218. package/src/core/class/root-observable-class.mts +85 -0
  219. package/src/core/class/write-during-propagation.test.mts +234 -0
  220. package/src/core/combine/combine.mts +67 -55
  221. package/src/core/combine/merge.mts +33 -26
  222. package/src/core/combine/zip.mts +103 -58
  223. package/src/core/create/counter.mts +105 -54
  224. package/src/core/create/counter.test.mts +82 -0
  225. package/src/core/create/from-abortable-promise.mts +54 -42
  226. package/src/core/create/from-promise.mts +38 -29
  227. package/src/core/create/from-subscribable.mts +68 -23
  228. package/src/core/create/from-subscribable.test.mts +134 -0
  229. package/src/core/create/just.mts +4 -5
  230. package/src/core/create/source.mts +37 -13
  231. package/src/core/create/source.test.mts +41 -0
  232. package/src/core/create/timer.mts +51 -32
  233. package/src/core/index.mts +2 -0
  234. package/src/core/operators/audit.mts +79 -45
  235. package/src/core/operators/debounce-audit-complete.test.mts +121 -0
  236. package/src/core/operators/debounce.mts +81 -40
  237. package/src/core/operators/filter.mts +48 -31
  238. package/src/core/operators/index.mts +1 -0
  239. package/src/core/operators/inner-ownership.test.mts +280 -0
  240. package/src/core/operators/map.mts +49 -32
  241. package/src/core/operators/merge-map.mts +81 -46
  242. package/src/core/operators/pairwise.mts +40 -30
  243. package/src/core/operators/scan.mts +41 -24
  244. package/src/core/operators/skip-if-no-change.mts +45 -31
  245. package/src/core/operators/skip-until.mts +59 -33
  246. package/src/core/operators/skip-while.mts +49 -31
  247. package/src/core/operators/switch-map.mts +74 -38
  248. package/src/core/operators/take-until-skip-until-teardown.test.mts +133 -0
  249. package/src/core/operators/take-until.mts +49 -31
  250. package/src/core/operators/take-while.mts +50 -33
  251. package/src/core/operators/take.mts +138 -0
  252. package/src/core/operators/throttle.mts +55 -38
  253. package/src/core/operators/with-buffered-from.mts +45 -35
  254. package/src/core/operators/with-buffered-from.test.mts +57 -0
  255. package/src/core/operators/with-current-value-from.mts +39 -25
  256. package/src/core/operators/with-initial-value.mts +30 -21
  257. package/src/core/predefined/operators/index.mts +0 -1
  258. package/src/core/scope/index.mts +1 -0
  259. package/src/core/scope/scope.mts +260 -0
  260. package/src/core/scope/scope.test.mts +462 -0
  261. package/src/core/types/id.mts +0 -4
  262. package/src/core/types/index.mts +1 -0
  263. package/src/core/types/observable-family.mts +7 -1
  264. package/src/core/types/observable.mts +77 -42
  265. package/src/core/types/scope.mts +27 -0
  266. package/src/core/utils/current-scope.mts +61 -0
  267. package/src/core/utils/id-maker.mts +20 -30
  268. package/src/core/utils/index.mts +2 -1
  269. package/src/core/utils/max-depth.mts +12 -9
  270. package/src/core/utils/observable-brand.mts +12 -0
  271. package/src/utils/create-boolean-state.mts +2 -2
  272. package/src/utils/create-boolean-state.test.mts +18 -4
  273. package/src/utils/create-event-emitter.mts +2 -2
  274. package/src/utils/create-reducer.mts +22 -16
  275. package/src/utils/create-reducer.test.mts +43 -14
  276. package/src/utils/create-state.mts +9 -2
  277. package/src/utils/create-state.test.mts +32 -14
  278. package/dist/core/base/create-child-observable.d.mts +0 -65
  279. package/dist/core/base/create-child-observable.d.mts.map +0 -1
  280. package/dist/core/base/create-child-observable.mjs +0 -267
  281. package/dist/core/base/create-child-observable.mjs.map +0 -1
  282. package/dist/core/base/create-observable-base.d.mts +0 -147
  283. package/dist/core/base/create-observable-base.d.mts.map +0 -1
  284. package/dist/core/base/create-observable-base.mjs +0 -255
  285. package/dist/core/base/create-observable-base.mjs.map +0 -1
  286. package/dist/core/base/create-root-observable.d.mts +0 -37
  287. package/dist/core/base/create-root-observable.d.mts.map +0 -1
  288. package/dist/core/base/create-root-observable.mjs +0 -57
  289. package/dist/core/base/create-root-observable.mjs.map +0 -1
  290. package/dist/core/base/index.d.mts +0 -3
  291. package/dist/core/base/index.d.mts.map +0 -1
  292. package/dist/core/base/index.mjs +0 -3
  293. package/dist/core/base/index.mjs.map +0 -1
  294. package/dist/core/predefined/operators/take.d.mts.map +0 -1
  295. package/dist/core/predefined/operators/take.mjs +0 -44
  296. package/dist/core/predefined/operators/take.mjs.map +0 -1
  297. package/dist/core/utils/utils.d.mts +0 -6
  298. package/dist/core/utils/utils.d.mts.map +0 -1
  299. package/dist/core/utils/utils.mjs +0 -37
  300. package/dist/core/utils/utils.mjs.map +0 -1
  301. package/src/core/base/create-child-observable.mts +0 -457
  302. package/src/core/base/create-observable-base.mts +0 -548
  303. package/src/core/base/create-root-observable.mts +0 -113
  304. package/src/core/base/index.mts +0 -2
  305. package/src/core/predefined/operators/take.mts +0 -48
  306. package/src/core/utils/utils.mts +0 -56
  307. package/src/core/utils/utils.test.mts +0 -88
@@ -1,10 +1,18 @@
1
+ // Sumi bans classes, `this`, method syntax and writes to `this` outside a
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why),
3
+ // so those rules are waived here (D-63).
4
+ // @sumi-expect-error-file classes/no-class
5
+ // @sumi-expect-error-file banned-syntax/no-this
6
+ // @sumi-expect-error-file functions/prefer-arrow-function
7
+ // @sumi-expect-error-file mutation/no-mutation-without-mut-prefix
1
8
  import { Optional } from 'ts-data-forge';
2
- import { createSyncChildObservable } from '../base/index.mjs';
9
+ import { SyncChildObservableClass } from '../class/index.mjs';
3
10
  import type {
4
11
  KeepInitialValueOperator,
5
12
  Observable,
6
13
  ThrottleOperatorObservable,
7
14
  TimerId,
15
+ UpdateToken,
8
16
  } from '../types/index.mjs';
9
17
 
10
18
  /**
@@ -90,51 +98,60 @@ export const throttle = <A,>(
90
98
  ): KeepInitialValueOperator<A, A> =>
91
99
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
92
100
  ((parentObservable) =>
93
- createThrottleObservable(
101
+ new ThrottleObservableClass(
94
102
  parentObservable,
95
103
  milliSeconds,
96
104
  )) as KeepInitialValueOperator<A, A>;
97
105
 
98
- const createThrottleObservable = <A,>(
99
- parentObservable: Observable<A>,
100
- milliSeconds: number,
101
- ): ThrottleOperatorObservable<A> => {
102
- let mut_timerId: TimerId | undefined = undefined;
103
-
104
- let mut_isSkipping = false;
105
-
106
- const resetTimer = (): void => {
107
- if (mut_timerId !== undefined) {
108
- clearTimeout(mut_timerId);
109
- }
110
- };
106
+ class ThrottleObservableClass<A>
107
+ extends SyncChildObservableClass<A, readonly [A]>
108
+ implements ThrottleOperatorObservable<A>
109
+ {
110
+ readonly #milliSeconds: number;
111
+ #mut_timerId: TimerId | undefined;
112
+ #mut_isSkipping: boolean;
111
113
 
112
- return createSyncChildObservable(
113
- {
114
+ constructor(parentObservable: Observable<A>, milliSeconds: number) {
115
+ super({
114
116
  parents: [parentObservable],
115
117
  initialValue: parentObservable.getSnapshot(),
116
- onComplete: resetTimer,
117
- },
118
- ({ setNext }) =>
119
- (updateToken) => {
120
- const sn = parentObservable.getSnapshot();
118
+ });
119
+
120
+ this.#mut_timerId = undefined;
121
+
122
+ this.#mut_isSkipping = false;
123
+
124
+ this.#milliSeconds = milliSeconds;
121
125
 
122
- if (
123
- mut_isSkipping ||
124
- parentObservable.updateToken !== updateToken ||
125
- Optional.isNone(sn)
126
- ) {
127
- return; // skip update
128
- }
126
+ this.attach();
127
+ }
129
128
 
130
- setNext(sn.value, updateToken);
129
+ override tryUpdate(updateToken: UpdateToken): void {
130
+ const par = this.parents[0];
131
131
 
132
- mut_isSkipping = true;
132
+ const sn = par.getSnapshot();
133
133
 
134
- // set timer
135
- mut_timerId = setTimeout(() => {
136
- mut_isSkipping = false;
137
- }, milliSeconds);
138
- },
139
- );
140
- };
134
+ if (
135
+ this.#mut_isSkipping ||
136
+ par.updateToken !== updateToken ||
137
+ Optional.isNone(sn)
138
+ ) {
139
+ return; // skip update
140
+ }
141
+
142
+ this.setNext(sn.value, updateToken);
143
+
144
+ this.#mut_isSkipping = true;
145
+
146
+ // set timer
147
+ this.#mut_timerId = setTimeout(() => {
148
+ this.#mut_isSkipping = false;
149
+ }, this.#milliSeconds);
150
+ }
151
+
152
+ protected override teardown(): void {
153
+ if (this.#mut_timerId !== undefined) {
154
+ clearTimeout(this.#mut_timerId);
155
+ }
156
+ }
157
+ }
@@ -1,8 +1,17 @@
1
+ // Sumi bans classes, `this`, method syntax and writes to `this` outside a
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why),
3
+ // so those rules are waived here (D-63).
4
+ // @sumi-expect-error-file classes/no-class
5
+ // @sumi-expect-error-file banned-syntax/no-this
6
+ // @sumi-expect-error-file functions/prefer-arrow-function
7
+ // @sumi-expect-error-file mutation/no-mutation-without-mut-prefix
1
8
  import { Arr, Optional, pipe } from 'ts-data-forge';
2
- import { createSyncChildObservable } from '../base/index.mjs';
9
+ import { SyncChildObservableClass } from '../class/index.mjs';
3
10
  import type {
4
11
  KeepInitialValueOperator,
5
12
  Observable,
13
+ Subscription,
14
+ UpdateToken,
6
15
  WithBufferedFromOperatorObservable,
7
16
  } from '../types/index.mjs';
8
17
  import { maxDepth } from '../utils/index.mjs';
@@ -65,7 +74,7 @@ export const withBufferedFrom = <A, B>(
65
74
  ): KeepInitialValueOperator<A, readonly [A, readonly B[]]> =>
66
75
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
67
76
  ((parentObservable) =>
68
- createWithBufferedFromObservable(
77
+ new WithBufferedFromObservableClass(
69
78
  parentObservable,
70
79
  observable,
71
80
  )) as KeepInitialValueOperator<A, readonly [A, readonly B[]]>;
@@ -76,21 +85,15 @@ export const withBufferedFrom = <A, B>(
76
85
  */
77
86
  export const withBuffered = withBufferedFrom;
78
87
 
79
- const createWithBufferedFromObservable = <A, B>(
80
- parentObservable: Observable<A>,
81
- observable: Observable<B>,
82
- ): WithBufferedFromOperatorObservable<A, B> => {
83
- let mut_bufferedValues: readonly B[] = [];
84
-
85
- const clearBuffer = (): void => {
86
- mut_bufferedValues = [];
87
- };
88
+ class WithBufferedFromObservableClass<A, B>
89
+ extends SyncChildObservableClass<readonly [A, readonly B[]], readonly [A]>
90
+ implements WithBufferedFromOperatorObservable<A, B>
91
+ {
92
+ readonly #subscription: Subscription;
93
+ #mut_bufferedValues: readonly B[];
88
94
 
89
- const result = createSyncChildObservable<
90
- readonly [A, readonly B[]],
91
- readonly [A]
92
- >(
93
- {
95
+ constructor(parentObservable: Observable<A>, observable: Observable<B>) {
96
+ super({
94
97
  parents: [parentObservable],
95
98
  depth: 1 + maxDepth([parentObservable, observable]),
96
99
  initialValue: pipe({
@@ -104,27 +107,34 @@ const createWithBufferedFromObservable = <A, B>(
104
107
  Optional.isNone(me) ? [] : [me.value],
105
108
  ] as const),
106
109
  ).value,
107
- },
108
- ({ setNext }) =>
109
- (updateToken) => {
110
- const sn = parentObservable.getSnapshot();
110
+ });
111
+
112
+ this.#mut_bufferedValues = [];
113
+
114
+ this.#subscription = observable.subscribe((value) => {
115
+ this.#mut_bufferedValues = Arr.toPushed(this.#mut_bufferedValues, value);
116
+ });
117
+
118
+ this.attach();
119
+ }
120
+
121
+ override tryUpdate(updateToken: UpdateToken): void {
122
+ const par = this.parents[0];
123
+
124
+ const sn = par.getSnapshot();
111
125
 
112
- if (
113
- parentObservable.updateToken !== updateToken ||
114
- Optional.isNone(sn)
115
- ) {
116
- return; // skip update
117
- }
126
+ if (par.updateToken !== updateToken || Optional.isNone(sn)) {
127
+ return; // skip update
128
+ }
118
129
 
119
- setNext([sn.value, mut_bufferedValues], updateToken);
130
+ this.setNext([sn.value, this.#mut_bufferedValues], updateToken);
120
131
 
121
- clearBuffer();
122
- },
123
- );
132
+ this.#mut_bufferedValues = [];
133
+ }
124
134
 
125
- observable.subscribe((value) => {
126
- mut_bufferedValues = Arr.toPushed(mut_bufferedValues, value);
127
- });
135
+ protected override teardown(): void {
136
+ this.#subscription.unsubscribe();
128
137
 
129
- return result;
130
- };
138
+ this.#mut_bufferedValues = [];
139
+ }
140
+ }
@@ -0,0 +1,57 @@
1
+ import { toNode } from '../class/index.mjs';
2
+ import { source } from '../create/index.mjs';
3
+ import { withBufferedFrom } from './with-buffered-from.mjs';
4
+
5
+ describe('withBufferedFrom teardown', () => {
6
+ test('unsubscribes from the buffered observable on complete', () => {
7
+ const data$ = source<string>();
8
+
9
+ const trigger$ = source<number>();
10
+
11
+ const result$ = trigger$.pipe(withBufferedFrom(data$));
12
+
13
+ assert.isTrue(toNode(data$).hasSubscriber);
14
+
15
+ result$.complete();
16
+
17
+ assert.isTrue(result$.isCompleted);
18
+
19
+ assert.isFalse(toNode(data$).hasSubscriber);
20
+ });
21
+
22
+ test('unsubscribes from the buffered observable when the parent completes', () => {
23
+ const data$ = source<string>();
24
+
25
+ const trigger$ = source<number>();
26
+
27
+ const result$ = trigger$.pipe(withBufferedFrom(data$));
28
+
29
+ trigger$.complete();
30
+
31
+ assert.isTrue(result$.isCompleted);
32
+
33
+ assert.isFalse(toNode(data$).hasSubscriber);
34
+ });
35
+
36
+ test('keeps buffering while subscribed', () => {
37
+ const data$ = source<string>();
38
+
39
+ const trigger$ = source<number>();
40
+
41
+ const result$ = trigger$.pipe(withBufferedFrom(data$));
42
+
43
+ const mut_history: (readonly [number, readonly string[]])[] = [];
44
+
45
+ result$.subscribe((v) => {
46
+ mut_history.push(v);
47
+ });
48
+
49
+ data$.next('A');
50
+
51
+ data$.next('B');
52
+
53
+ trigger$.next(1);
54
+
55
+ assert.deepStrictEqual(mut_history, [[1, ['A', 'B']]]);
56
+ });
57
+ });
@@ -1,8 +1,16 @@
1
+ // Sumi bans classes, `this`, method syntax and writes to `this` outside a
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why),
3
+ // so those rules are waived here (D-63).
4
+ // @sumi-expect-error-file classes/no-class
5
+ // @sumi-expect-error-file banned-syntax/no-this
6
+ // @sumi-expect-error-file functions/prefer-arrow-function
7
+ // @sumi-expect-error-file mutation/no-mutation-without-mut-prefix
1
8
  import { Optional, pipe } from 'ts-data-forge';
2
- import { createSyncChildObservable } from '../base/index.mjs';
9
+ import { SyncChildObservableClass } from '../class/index.mjs';
3
10
  import type {
4
11
  DropInitialValueOperator,
5
12
  Observable,
13
+ UpdateToken,
6
14
  WithCurrentValueFromOperatorObservable,
7
15
  } from '../types/index.mjs';
8
16
  import { maxDepth } from '../utils/index.mjs';
@@ -68,7 +76,7 @@ export const withCurrentValueFrom =
68
76
  observable: Observable<B>,
69
77
  ): DropInitialValueOperator<A, readonly [A, B]> =>
70
78
  (parentObservable) =>
71
- createWithCurrentValueFromObservable(parentObservable, observable);
79
+ new WithCurrentValueFromObservableClass(parentObservable, observable);
72
80
 
73
81
  /**
74
82
  * Alias for `withCurrentValueFrom`.
@@ -76,12 +84,14 @@ export const withCurrentValueFrom =
76
84
  */
77
85
  export const withLatestFrom = withCurrentValueFrom;
78
86
 
79
- const createWithCurrentValueFromObservable = <A, B>(
80
- parentObservable: Observable<A>,
81
- observable: Observable<B>,
82
- ): WithCurrentValueFromOperatorObservable<A, B> =>
83
- createSyncChildObservable<readonly [A, B], readonly [A]>(
84
- {
87
+ class WithCurrentValueFromObservableClass<A, B>
88
+ extends SyncChildObservableClass<readonly [A, B], readonly [A]>
89
+ implements WithCurrentValueFromOperatorObservable<A, B>
90
+ {
91
+ readonly #observable: Observable<B>;
92
+
93
+ constructor(parentObservable: Observable<A>, observable: Observable<B>) {
94
+ super({
85
95
  parents: [parentObservable],
86
96
  depth: 1 + maxDepth([parentObservable, observable]),
87
97
  initialValue: pipe({
@@ -92,24 +102,28 @@ const createWithCurrentValueFromObservable = <A, B>(
92
102
  ? Optional.none
93
103
  : Optional.some([par.value, me.value] as const),
94
104
  ).value,
95
- },
96
- ({ setNext }) =>
97
- (updateToken) => {
98
- const ps = parentObservable.getSnapshot();
105
+ });
106
+
107
+ this.#observable = observable;
108
+
109
+ this.attach();
110
+ }
111
+
112
+ override tryUpdate(updateToken: UpdateToken): void {
113
+ const par = this.parents[0];
114
+
115
+ const ps = par.getSnapshot();
99
116
 
100
- if (
101
- parentObservable.updateToken !== updateToken ||
102
- Optional.isNone(ps)
103
- ) {
104
- return; // skip update
105
- }
117
+ if (par.updateToken !== updateToken || Optional.isNone(ps)) {
118
+ return; // skip update
119
+ }
106
120
 
107
- const curr = observable.getSnapshot();
121
+ const curr = this.#observable.getSnapshot();
108
122
 
109
- if (Optional.isNone(curr)) {
110
- return; // skip update
111
- }
123
+ if (Optional.isNone(curr)) {
124
+ return; // skip update
125
+ }
112
126
 
113
- setNext([ps.value, curr.value], updateToken);
114
- },
115
- );
127
+ this.setNext([ps.value, curr.value], updateToken);
128
+ }
129
+ }
@@ -1,9 +1,16 @@
1
+ // Sumi bans classes, `this`, method syntax and writes to `this` outside a
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why),
3
+ // so those rules are waived here (D-63).
4
+ // @sumi-expect-error-file classes/no-class
5
+ // @sumi-expect-error-file banned-syntax/no-this
6
+ // @sumi-expect-error-file functions/prefer-arrow-function
1
7
  import { expectType, Optional } from 'ts-data-forge';
2
- import { createInitializedSyncChildObservable } from '../base/index.mjs';
8
+ import { InitializedSyncChildObservableClass } from '../class/index.mjs';
3
9
  import { source } from '../create/index.mjs';
4
10
  import type {
5
11
  InitializedObservable,
6
12
  Observable,
13
+ UpdateToken,
7
14
  WithInitialValueOperator,
8
15
  WithInitialValueOperatorObservable,
9
16
  } from '../types/index.mjs';
@@ -56,31 +63,33 @@ import type {
56
63
  export const withInitialValue =
57
64
  <A, I = A>(initialValue: I): WithInitialValueOperator<A, A | I> =>
58
65
  (parentObservable) =>
59
- createWithInitialValueObservable(parentObservable, initialValue);
66
+ new WithInitialValueObservableClass(parentObservable, initialValue);
60
67
 
61
- const createWithInitialValueObservable = <A, I>(
62
- parentObservable: Observable<A>,
63
- initialValue: I,
64
- ): WithInitialValueOperatorObservable<A, I> =>
65
- createInitializedSyncChildObservable<A | I, readonly [A]>(
66
- {
68
+ class WithInitialValueObservableClass<A, I>
69
+ extends InitializedSyncChildObservableClass<A | I, readonly [A]>
70
+ implements WithInitialValueOperatorObservable<A, I>
71
+ {
72
+ constructor(parentObservable: Observable<A>, initialValue: I) {
73
+ super({
67
74
  parents: [parentObservable],
68
75
  initialValue: Optional.some(initialValue),
69
- },
70
- ({ setNext }) =>
71
- (updateToken) => {
72
- const sn = parentObservable.getSnapshot();
76
+ });
73
77
 
74
- if (
75
- parentObservable.updateToken !== updateToken ||
76
- Optional.isNone(sn)
77
- ) {
78
- return; // skip update
79
- }
78
+ this.attach();
79
+ }
80
+
81
+ override tryUpdate(updateToken: UpdateToken): void {
82
+ const par = this.parents[0];
83
+
84
+ const sn = par.getSnapshot();
80
85
 
81
- setNext(sn.value, updateToken);
82
- },
83
- );
86
+ if (par.updateToken !== updateToken || Optional.isNone(sn)) {
87
+ return; // skip update
88
+ }
89
+
90
+ this.setNext(sn.value, updateToken);
91
+ }
92
+ }
84
93
 
85
94
  if (import.meta.vitest !== undefined) {
86
95
  test('type test', () => {
@@ -5,7 +5,6 @@ export * from './map-result-ok.mjs';
5
5
  export * from './map-to.mjs';
6
6
  export * from './pluck.mjs';
7
7
  export * from './skip.mjs';
8
- export * from './take.mjs';
9
8
  export * from './unwrap-optional.mjs';
10
9
  export * from './unwrap-result-err.mjs';
11
10
  export * from './unwrap-result-ok.mjs';
@@ -0,0 +1 @@
1
+ export * from './scope.mjs';