synstate 3.0.6 → 3.2.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 (218) hide show
  1. package/README.md +59 -1
  2. package/dist/core/base/create-child-observable.d.mts.map +1 -1
  3. package/dist/core/base/create-child-observable.mjs +0 -1
  4. package/dist/core/base/create-child-observable.mjs.map +1 -1
  5. package/dist/core/base/create-observable-base.d.mts +2 -2
  6. package/dist/core/base/create-observable-base.d.mts.map +1 -1
  7. package/dist/core/base/create-observable-base.mjs +0 -1
  8. package/dist/core/base/create-observable-base.mjs.map +1 -1
  9. package/dist/core/base/create-root-observable.d.mts +1 -1
  10. package/dist/core/base/create-root-observable.d.mts.map +1 -1
  11. package/dist/core/combine/combine.d.mts +2 -2
  12. package/dist/core/combine/combine.d.mts.map +1 -1
  13. package/dist/core/combine/combine.mjs +0 -1
  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 +0 -2
  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 +0 -2
  22. package/dist/core/combine/zip.mjs.map +1 -1
  23. package/dist/core/create/counter.d.mts +11 -3
  24. package/dist/core/create/counter.d.mts.map +1 -1
  25. package/dist/core/create/counter.mjs +17 -7
  26. package/dist/core/create/counter.mjs.map +1 -1
  27. package/dist/core/create/from-abortable-promise.d.mts +1 -1
  28. package/dist/core/create/from-abortable-promise.d.mts.map +1 -1
  29. package/dist/core/create/from-abortable-promise.mjs +0 -2
  30. package/dist/core/create/from-abortable-promise.mjs.map +1 -1
  31. package/dist/core/create/from-promise.d.mts +1 -1
  32. package/dist/core/create/from-promise.d.mts.map +1 -1
  33. package/dist/core/create/from-promise.mjs +0 -1
  34. package/dist/core/create/from-promise.mjs.map +1 -1
  35. package/dist/core/create/from-subscribable.d.mts +1 -1
  36. package/dist/core/create/from-subscribable.d.mts.map +1 -1
  37. package/dist/core/create/from-subscribable.mjs +0 -1
  38. package/dist/core/create/from-subscribable.mjs.map +1 -1
  39. package/dist/core/create/just.d.mts +1 -1
  40. package/dist/core/create/just.d.mts.map +1 -1
  41. package/dist/core/create/just.mjs +0 -1
  42. package/dist/core/create/just.mjs.map +1 -1
  43. package/dist/core/create/source.d.mts +1 -1
  44. package/dist/core/create/source.d.mts.map +1 -1
  45. package/dist/core/create/timer.d.mts +1 -1
  46. package/dist/core/create/timer.d.mts.map +1 -1
  47. package/dist/core/operators/audit.d.mts +1 -1
  48. package/dist/core/operators/audit.d.mts.map +1 -1
  49. package/dist/core/operators/audit.mjs +0 -1
  50. package/dist/core/operators/audit.mjs.map +1 -1
  51. package/dist/core/operators/debounce.d.mts +1 -1
  52. package/dist/core/operators/debounce.d.mts.map +1 -1
  53. package/dist/core/operators/debounce.mjs +0 -1
  54. package/dist/core/operators/debounce.mjs.map +1 -1
  55. package/dist/core/operators/filter.d.mts +1 -1
  56. package/dist/core/operators/filter.d.mts.map +1 -1
  57. package/dist/core/operators/filter.mjs +19 -0
  58. package/dist/core/operators/filter.mjs.map +1 -1
  59. package/dist/core/operators/map.d.mts +1 -1
  60. package/dist/core/operators/map.d.mts.map +1 -1
  61. package/dist/core/operators/map.mjs +0 -1
  62. package/dist/core/operators/map.mjs.map +1 -1
  63. package/dist/core/operators/merge-map.d.mts +1 -1
  64. package/dist/core/operators/merge-map.d.mts.map +1 -1
  65. package/dist/core/operators/pairwise.d.mts +2 -2
  66. package/dist/core/operators/pairwise.d.mts.map +1 -1
  67. package/dist/core/operators/scan.d.mts +1 -1
  68. package/dist/core/operators/scan.d.mts.map +1 -1
  69. package/dist/core/operators/skip-if-no-change.d.mts +1 -1
  70. package/dist/core/operators/skip-if-no-change.d.mts.map +1 -1
  71. package/dist/core/operators/skip-if-no-change.mjs +0 -1
  72. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  73. package/dist/core/operators/skip-until.d.mts +1 -1
  74. package/dist/core/operators/skip-until.d.mts.map +1 -1
  75. package/dist/core/operators/skip-while.d.mts +1 -1
  76. package/dist/core/operators/skip-while.d.mts.map +1 -1
  77. package/dist/core/operators/switch-map.d.mts +1 -1
  78. package/dist/core/operators/switch-map.d.mts.map +1 -1
  79. package/dist/core/operators/take-until.d.mts +1 -1
  80. package/dist/core/operators/take-until.d.mts.map +1 -1
  81. package/dist/core/operators/take-until.mjs +0 -1
  82. package/dist/core/operators/take-until.mjs.map +1 -1
  83. package/dist/core/operators/take-while.d.mts +1 -1
  84. package/dist/core/operators/take-while.d.mts.map +1 -1
  85. package/dist/core/operators/throttle.d.mts +1 -1
  86. package/dist/core/operators/throttle.d.mts.map +1 -1
  87. package/dist/core/operators/throttle.mjs +0 -1
  88. package/dist/core/operators/throttle.mjs.map +1 -1
  89. package/dist/core/operators/with-buffered-from.d.mts +1 -1
  90. package/dist/core/operators/with-buffered-from.d.mts.map +1 -1
  91. package/dist/core/operators/with-buffered-from.mjs +0 -1
  92. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  93. package/dist/core/operators/with-current-value-from.d.mts +1 -1
  94. package/dist/core/operators/with-current-value-from.d.mts.map +1 -1
  95. package/dist/core/operators/with-initial-value.d.mts +1 -1
  96. package/dist/core/operators/with-initial-value.d.mts.map +1 -1
  97. package/dist/core/predefined/operators/attach-index.d.mts +2 -2
  98. package/dist/core/predefined/operators/attach-index.d.mts.map +1 -1
  99. package/dist/core/predefined/operators/map-optional.d.mts +1 -1
  100. package/dist/core/predefined/operators/map-optional.d.mts.map +1 -1
  101. package/dist/core/predefined/operators/map-result-err.d.mts +1 -1
  102. package/dist/core/predefined/operators/map-result-err.d.mts.map +1 -1
  103. package/dist/core/predefined/operators/map-result-ok.d.mts +1 -1
  104. package/dist/core/predefined/operators/map-result-ok.d.mts.map +1 -1
  105. package/dist/core/predefined/operators/map-to.d.mts +1 -1
  106. package/dist/core/predefined/operators/map-to.d.mts.map +1 -1
  107. package/dist/core/predefined/operators/pluck.d.mts +1 -1
  108. package/dist/core/predefined/operators/pluck.d.mts.map +1 -1
  109. package/dist/core/predefined/operators/skip.d.mts +2 -2
  110. package/dist/core/predefined/operators/skip.d.mts.map +1 -1
  111. package/dist/core/predefined/operators/take.d.mts +2 -2
  112. package/dist/core/predefined/operators/take.d.mts.map +1 -1
  113. package/dist/core/predefined/operators/unwrap-optional.d.mts +1 -1
  114. package/dist/core/predefined/operators/unwrap-optional.d.mts.map +1 -1
  115. package/dist/core/predefined/operators/unwrap-optional.mjs +0 -1
  116. package/dist/core/predefined/operators/unwrap-optional.mjs.map +1 -1
  117. package/dist/core/predefined/operators/unwrap-result-err.d.mts +1 -1
  118. package/dist/core/predefined/operators/unwrap-result-err.d.mts.map +1 -1
  119. package/dist/core/predefined/operators/unwrap-result-ok.d.mts +1 -1
  120. package/dist/core/predefined/operators/unwrap-result-ok.d.mts.map +1 -1
  121. package/dist/core/predefined/operators/unwrap-result-ok.mjs +0 -1
  122. package/dist/core/predefined/operators/unwrap-result-ok.mjs.map +1 -1
  123. package/dist/core/types/id.d.mts +1 -1
  124. package/dist/core/types/id.d.mts.map +1 -1
  125. package/dist/core/types/observable-family.d.mts +3 -3
  126. package/dist/core/types/observable-family.d.mts.map +1 -1
  127. package/dist/core/types/observable-kind.d.mts +1 -1
  128. package/dist/core/types/observable-kind.d.mts.map +1 -1
  129. package/dist/core/types/observable.d.mts +4 -4
  130. package/dist/core/types/observable.d.mts.map +1 -1
  131. package/dist/core/types/types.d.mts +1 -1
  132. package/dist/core/types/types.d.mts.map +1 -1
  133. package/dist/core/utils/id-maker.d.mts +1 -1
  134. package/dist/core/utils/id-maker.d.mts.map +1 -1
  135. package/dist/core/utils/id-maker.mjs +0 -1
  136. package/dist/core/utils/id-maker.mjs.map +1 -1
  137. package/dist/core/utils/max-depth.d.mts +1 -1
  138. package/dist/core/utils/max-depth.d.mts.map +1 -1
  139. package/dist/core/utils/observable-utils.d.mts +1 -1
  140. package/dist/core/utils/observable-utils.d.mts.map +1 -1
  141. package/dist/core/utils/utils.d.mts +1 -1
  142. package/dist/core/utils/utils.d.mts.map +1 -1
  143. package/dist/core/utils/utils.mjs +0 -1
  144. package/dist/core/utils/utils.mjs.map +1 -1
  145. package/dist/utils/collect-to-array.d.mts +1 -1
  146. package/dist/utils/collect-to-array.d.mts.map +1 -1
  147. package/dist/utils/create-boolean-state.d.mts +17 -14
  148. package/dist/utils/create-boolean-state.d.mts.map +1 -1
  149. package/dist/utils/create-boolean-state.mjs +4 -2
  150. package/dist/utils/create-boolean-state.mjs.map +1 -1
  151. package/dist/utils/create-reducer.d.mts +49 -2
  152. package/dist/utils/create-reducer.d.mts.map +1 -1
  153. package/dist/utils/create-reducer.mjs +31 -2
  154. package/dist/utils/create-reducer.mjs.map +1 -1
  155. package/dist/utils/create-state.d.mts +37 -2
  156. package/dist/utils/create-state.d.mts.map +1 -1
  157. package/dist/utils/create-state.mjs +36 -2
  158. package/dist/utils/create-state.mjs.map +1 -1
  159. package/package.json +13 -13
  160. package/src/core/base/create-child-observable.mts +1 -2
  161. package/src/core/base/create-observable-base.mts +17 -19
  162. package/src/core/base/create-root-observable.mts +1 -1
  163. package/src/core/base/observable-base.test.mts +7 -7
  164. package/src/core/combine/combine.mts +10 -11
  165. package/src/core/combine/merge.mts +8 -10
  166. package/src/core/combine/zip.mts +11 -13
  167. package/src/core/create/counter.mts +21 -11
  168. package/src/core/create/counter.test.mts +183 -0
  169. package/src/core/create/from-abortable-promise.mts +1 -3
  170. package/src/core/create/from-promise.mts +1 -2
  171. package/src/core/create/from-subscribable.mts +3 -4
  172. package/src/core/create/just.mts +1 -2
  173. package/src/core/create/source.mts +3 -3
  174. package/src/core/create/timer.mts +1 -1
  175. package/src/core/operators/audit.mts +5 -6
  176. package/src/core/operators/debounce.mts +5 -6
  177. package/src/core/operators/filter.mts +46 -5
  178. package/src/core/operators/map.mts +5 -6
  179. package/src/core/operators/merge-map.mts +5 -5
  180. package/src/core/operators/pairwise.mts +5 -5
  181. package/src/core/operators/scan.mts +4 -4
  182. package/src/core/operators/skip-if-no-change.mts +4 -5
  183. package/src/core/operators/skip-until.mts +4 -4
  184. package/src/core/operators/skip-while.mts +4 -4
  185. package/src/core/operators/switch-map.mts +5 -5
  186. package/src/core/operators/take-until.mts +4 -5
  187. package/src/core/operators/take-while.mts +5 -5
  188. package/src/core/operators/throttle.mts +5 -6
  189. package/src/core/operators/with-buffered-from.mts +4 -5
  190. package/src/core/operators/with-current-value-from.mts +4 -4
  191. package/src/core/operators/with-initial-value.mts +5 -5
  192. package/src/core/predefined/operators/attach-index.mts +2 -2
  193. package/src/core/predefined/operators/map-optional.mts +1 -1
  194. package/src/core/predefined/operators/map-result-err.mts +1 -1
  195. package/src/core/predefined/operators/map-result-ok.mts +1 -1
  196. package/src/core/predefined/operators/map-to.mts +1 -1
  197. package/src/core/predefined/operators/pluck.mts +1 -1
  198. package/src/core/predefined/operators/skip.mts +2 -2
  199. package/src/core/predefined/operators/take.mts +2 -2
  200. package/src/core/predefined/operators/unwrap-optional.mts +2 -3
  201. package/src/core/predefined/operators/unwrap-result-err.mts +2 -2
  202. package/src/core/predefined/operators/unwrap-result-ok.mts +2 -3
  203. package/src/core/types/id.mts +1 -1
  204. package/src/core/types/observable-family.mts +15 -15
  205. package/src/core/types/observable-kind.mts +1 -1
  206. package/src/core/types/observable.mts +4 -4
  207. package/src/core/types/types.mts +1 -1
  208. package/src/core/utils/id-maker.mts +4 -5
  209. package/src/core/utils/max-depth.mts +1 -1
  210. package/src/core/utils/observable-utils.mts +1 -1
  211. package/src/core/utils/utils.mts +1 -2
  212. package/src/utils/collect-to-array.mts +1 -1
  213. package/src/utils/create-boolean-state.mts +18 -14
  214. package/src/utils/create-boolean-state.test.mts +23 -0
  215. package/src/utils/create-reducer.mts +59 -2
  216. package/src/utils/create-reducer.test.mts +87 -0
  217. package/src/utils/create-state.mts +38 -2
  218. package/src/utils/create-state.test.mts +72 -0
@@ -1,6 +1,6 @@
1
1
  import { Arr, type Optional, type Some } from 'ts-data-forge';
2
2
  import { panic } from 'ts-std-forge';
3
- import { type MutableSet } from 'ts-type-forge';
3
+ import type { MutableSet } from 'ts-type-forge';
4
4
  import {
5
5
  isChildObservable,
6
6
  isManagerObservable,
@@ -161,7 +161,6 @@ export const createInitializedSyncChildObservable = <
161
161
  // `getSnapshot` always returns `Some` here: `initialValue` is a `Some` and
162
162
  // `setNext` only ever stores a `Some`.
163
163
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
164
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
165
164
  observable as InitializedSyncChildObservable<A, P>
166
165
  );
167
166
  };
@@ -1,23 +1,19 @@
1
1
  import { Arr, Optional } from 'ts-data-forge';
2
2
  import { unreachable } from 'ts-std-forge';
3
- import {
4
- type MutableMap,
5
- type MutableSet,
6
- type ReadonlyRecord,
7
- } from 'ts-type-forge';
8
- import {
9
- type ChildObservable,
10
- type InitializedObservable,
11
- type Observable,
12
- type ObservableBase,
13
- type ObservableId,
14
- type ObservableKind,
15
- type Operator,
16
- type Subscriber,
17
- type SubscriberId,
18
- type Subscription,
19
- type UpdateToken,
20
- type WithInitialValueOperator,
3
+ import type { MutableMap, MutableSet, ReadonlyRecord } from 'ts-type-forge';
4
+ import type {
5
+ ChildObservable,
6
+ InitializedObservable,
7
+ Observable,
8
+ ObservableBase,
9
+ ObservableId,
10
+ ObservableKind,
11
+ Operator,
12
+ Subscriber,
13
+ SubscriberId,
14
+ Subscription,
15
+ UpdateToken,
16
+ WithInitialValueOperator,
21
17
  } from '../types/index.mjs';
22
18
  import {
23
19
  binarySearch,
@@ -393,12 +389,14 @@ export const assembleObservable = <
393
389
  operator: WithInitialValueOperator<A, B>,
394
390
  ): InitializedObservable<B>;
395
391
 
392
+ // A `WithInitialValueOperator` is also an `Operator`: nothing at run time
393
+ // tells the two apart, so this set only refines the return type (#1952).
394
+ // @sumi-expect-error functions/no-refinement-overload
396
395
  function pipe<B>(operator: Operator<A, B>): Observable<B>;
397
396
 
398
397
  function pipe<B>(operator: Operator<A, B>): Observable<B> {
399
398
  return operator(
400
399
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
401
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
402
400
  mut_observable as unknown as InitializedObservable<A>,
403
401
  );
404
402
  }
@@ -1,5 +1,5 @@
1
1
  import { Optional } from 'ts-data-forge';
2
- import { type ReadonlyRecord } from 'ts-type-forge';
2
+ import type { ReadonlyRecord } from 'ts-type-forge';
3
3
  import { isRootObservable, type RootObservable } from '../types/index.mjs';
4
4
  import {
5
5
  assembleObservable,
@@ -1,11 +1,11 @@
1
1
  import { expectType, Optional } from 'ts-data-forge';
2
- import {
3
- type AsyncChildObservable,
4
- type ChildObservable,
5
- type Observable,
6
- type ObservableBase,
7
- type RootObservable,
8
- type SyncChildObservable,
2
+ import type {
3
+ AsyncChildObservable,
4
+ ChildObservable,
5
+ Observable,
6
+ ObservableBase,
7
+ RootObservable,
8
+ SyncChildObservable,
9
9
  } from '../types/index.mjs';
10
10
  import {
11
11
  createAsyncChildObservable,
@@ -1,17 +1,17 @@
1
1
  import { Arr, expectType, Optional } from 'ts-data-forge';
2
- import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
2
+ import type { NonEmptyTuple, Tuple } from 'ts-type-forge';
3
3
  import { createSyncChildObservable } from '../base/index.mjs';
4
4
  import { source } from '../create/index.mjs';
5
5
  import { withInitialValue } from '../operators/index.mjs';
6
- import {
7
- type CombineObservable,
8
- type CombineObservableRefined,
9
- type InitializedObservable,
10
- type InitializedSyncChildObservable,
11
- type NonEmptyUnknownList,
12
- type Observable,
13
- type SyncChildObservable,
14
- type Wrap,
6
+ import type {
7
+ CombineObservable,
8
+ CombineObservableRefined,
9
+ InitializedObservable,
10
+ InitializedSyncChildObservable,
11
+ NonEmptyUnknownList,
12
+ Observable,
13
+ SyncChildObservable,
14
+ Wrap,
15
15
  } from '../types/index.mjs';
16
16
 
17
17
  /**
@@ -75,7 +75,6 @@ export const combine = <const OS extends NonEmptyTuple<Observable<unknown>>>(
75
75
  parents: OS,
76
76
  ): CombineObservableRefined<OS> =>
77
77
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
78
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
79
78
  createCombineObservable(parents) as unknown as CombineObservableRefined<OS>;
80
79
 
81
80
  /**
@@ -1,14 +1,14 @@
1
1
  import { Optional, expectType } from 'ts-data-forge';
2
- import { type ArrayElement, type NonEmptyTuple } from 'ts-type-forge';
2
+ import type { ArrayElement, NonEmptyTuple } from 'ts-type-forge';
3
3
  import { createSyncChildObservable } from '../base/index.mjs';
4
4
  import { source } from '../create/index.mjs';
5
- import {
6
- type MergeObservable,
7
- type MergeObservableRefined,
8
- type NonEmptyUnknownList,
9
- type Observable,
10
- type SyncChildObservable,
11
- type Wrap,
5
+ import type {
6
+ MergeObservable,
7
+ MergeObservableRefined,
8
+ NonEmptyUnknownList,
9
+ Observable,
10
+ SyncChildObservable,
11
+ Wrap,
12
12
  } from '../types/index.mjs';
13
13
 
14
14
  /**
@@ -66,7 +66,6 @@ export const merge = <const OS extends NonEmptyTuple<Observable<unknown>>>(
66
66
  parents: OS,
67
67
  ): MergeObservableRefined<OS> =>
68
68
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
69
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
70
69
  createMergeObservable(parents) as MergeObservableRefined<OS>;
71
70
 
72
71
  const createMergeObservable = <const P extends NonEmptyUnknownList>(
@@ -90,7 +89,6 @@ const createMergeObservable = <const P extends NonEmptyUnknownList>(
90
89
 
91
90
  const nextValue =
92
91
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
93
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
94
92
  Optional.unwrap(parentToUse.getSnapshot()) as ArrayElement<P>;
95
93
 
96
94
  setNext(nextValue, updateToken);
@@ -1,18 +1,18 @@
1
1
  import { Arr, Optional, createQueue, expectType } from 'ts-data-forge';
2
- import { type NonEmptyTuple, type Tuple } from 'ts-type-forge';
2
+ import type { NonEmptyTuple, Tuple } from 'ts-type-forge';
3
3
  import { createSyncChildObservable } from '../base/index.mjs';
4
4
  import { source } from '../create/index.mjs';
5
5
  import { withInitialValue } from '../operators/index.mjs';
6
- import {
7
- type InitializedObservable,
8
- type InitializedSyncChildObservable,
9
- type NonEmptyUnknownList,
10
- type Observable,
11
- type SyncChildObservable,
12
- type TupleToQueueTuple,
13
- type Wrap,
14
- type ZipObservable,
15
- type ZipObservableRefined,
6
+ import type {
7
+ InitializedObservable,
8
+ InitializedSyncChildObservable,
9
+ NonEmptyUnknownList,
10
+ Observable,
11
+ SyncChildObservable,
12
+ TupleToQueueTuple,
13
+ Wrap,
14
+ ZipObservable,
15
+ ZipObservableRefined,
16
16
  } from '../types/index.mjs';
17
17
 
18
18
  /**
@@ -68,7 +68,6 @@ export const zip = <const OS extends NonEmptyTuple<Observable<unknown>>>(
68
68
  parents: OS,
69
69
  ): ZipObservableRefined<OS> =>
70
70
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
71
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
72
71
  createZipObservable(parents) as unknown as ZipObservableRefined<OS>;
73
72
 
74
73
  const createZipObservable = <const A extends NonEmptyUnknownList>(
@@ -119,7 +118,6 @@ const createZipObservable = <const A extends NonEmptyUnknownList>(
119
118
  // `Arr.map` has a single result element type, so it reports
120
119
  // `A[number] | undefined` per position rather than `A[P]`.
121
120
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
122
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
123
121
  Arr.map(queues, (q) => Optional.unwrap(q.dequeue())) as A;
124
122
 
125
123
  setNext(nextValue, updateToken);
@@ -1,13 +1,20 @@
1
1
  import { asSafeUint, Optional, SafeUint } from 'ts-data-forge';
2
2
  import { createRootObservable } from '../base/index.mjs';
3
- import { type CounterObservable, type TimerId } from '../types/index.mjs';
3
+ import type { CounterObservable, TimerId } from '../types/index.mjs';
4
4
 
5
5
  /**
6
6
  * Creates an observable that emits incremental numbers at a specified interval.
7
- * Starts with 0 immediately after subscription, then emits 1, 2, 3, ... every interval.
7
+ * Emits 0 in the macrotask right after `start()` (which runs at creation
8
+ * unless `startManually` is set), then 1, 2, 3, ... every interval. A
9
+ * subscriber added after that 0 has been emitted does not receive it.
8
10
  *
9
11
  * @param intervalMilliSeconds - The interval duration in milliseconds
10
- * @param startManually - If true, waits for manual start (default: false)
12
+ * @param options - Optional settings
13
+ * @param options.startManually - If true, waits for `start()` instead of
14
+ * starting at creation (default: false)
15
+ * @param options.emitInitial - If false, skips the 0 emitted right after
16
+ * `start()`, so the first value is 1, one interval later — like RxJS
17
+ * `interval` rather than `timer(0, ms)` (default: true)
11
18
  * @returns An observable that emits sequential numbers
12
19
  *
13
20
  * @example
@@ -49,6 +56,7 @@ export const counter = (
49
56
  intervalMilliSeconds: number,
50
57
  options?: Readonly<{
51
58
  startManually?: boolean;
59
+ emitInitial?: boolean;
52
60
  }>,
53
61
  ): CounterObservable => {
54
62
  let mut_counter: SafeUint = asSafeUint(0);
@@ -60,13 +68,13 @@ export const counter = (
60
68
  let mut_isStarted = false;
61
69
 
62
70
  const resetTimer = (): void => {
63
- if (mut_timerId0 === undefined || mut_timerId === undefined) {
64
- return;
71
+ if (mut_timerId0 !== undefined) {
72
+ clearTimeout(mut_timerId0);
65
73
  }
66
74
 
67
- clearInterval(mut_timerId0);
68
-
69
- clearInterval(mut_timerId);
75
+ if (mut_timerId !== undefined) {
76
+ clearInterval(mut_timerId);
77
+ }
70
78
  };
71
79
 
72
80
  const observable = createRootObservable<
@@ -90,9 +98,11 @@ export const counter = (
90
98
  return;
91
99
  }
92
100
 
93
- mut_timerId0 = setTimeout(() => {
94
- startUpdate(mut_counter);
95
- }, 0);
101
+ if (options?.emitInitial ?? true) {
102
+ mut_timerId0 = setTimeout(() => {
103
+ startUpdate(mut_counter);
104
+ }, 0);
105
+ }
96
106
 
97
107
  mut_timerId = setInterval(() => {
98
108
  mut_counter = SafeUint.add(1, mut_counter);
@@ -1,3 +1,4 @@
1
+ import { Arr } from 'ts-data-forge';
1
2
  import { counter } from './counter.mjs';
2
3
 
3
4
  describe(counter, () => {
@@ -8,4 +9,186 @@ describe(counter, () => {
8
9
 
9
10
  assert.isTrue(counter$.isCompleted);
10
11
  });
12
+
13
+ test('emits 0 right after start(), then 1, 2, … every interval', () => {
14
+ vi.useFakeTimers();
15
+
16
+ const start = Date.now();
17
+
18
+ const counter$ = counter(100);
19
+
20
+ const mut_history: number[] = [];
21
+
22
+ counter$.subscribe((n) => {
23
+ mut_history.push(n);
24
+ });
25
+
26
+ vi.advanceTimersToNextTimer();
27
+
28
+ assert.deepStrictEqual(mut_history, [0]);
29
+
30
+ assert.strictEqual(vi.getMockedSystemTime()?.getTime(), start);
31
+
32
+ vi.advanceTimersToNextTimer().advanceTimersToNextTimer();
33
+
34
+ assert.deepStrictEqual(mut_history, [0, 1, 2]);
35
+
36
+ counter$.complete();
37
+
38
+ vi.useRealTimers();
39
+ });
40
+
41
+ test('emitInitial: false skips the 0 and starts with 1 after one interval', () => {
42
+ vi.useFakeTimers();
43
+
44
+ const start = Date.now();
45
+
46
+ const counter$ = counter(100, { emitInitial: false });
47
+
48
+ const mut_history: number[] = [];
49
+
50
+ counter$.subscribe((n) => {
51
+ mut_history.push(n);
52
+ });
53
+
54
+ vi.advanceTimersToNextTimer();
55
+
56
+ assert.deepStrictEqual(mut_history, [1]);
57
+
58
+ assert.strictEqual(vi.getMockedSystemTime()?.getTime(), start + 100);
59
+
60
+ vi.advanceTimersToNextTimer().advanceTimersToNextTimer();
61
+
62
+ assert.deepStrictEqual(mut_history, [1, 2, 3]);
63
+
64
+ counter$.complete();
65
+
66
+ vi.useRealTimers();
67
+ });
68
+
69
+ test('emitInitial: false still clears the interval on complete', () => {
70
+ vi.useFakeTimers();
71
+
72
+ const counter$ = counter(100, { emitInitial: false });
73
+
74
+ const mut_history: number[] = [];
75
+
76
+ counter$.subscribe((n) => {
77
+ mut_history.push(n);
78
+ });
79
+
80
+ vi.advanceTimersToNextTimer();
81
+
82
+ counter$.complete();
83
+
84
+ assert.strictEqual(vi.getTimerCount(), 0);
85
+
86
+ assert.deepStrictEqual(mut_history, [1]);
87
+
88
+ vi.useRealTimers();
89
+ });
90
+
91
+ test.each([
92
+ { emitInitial: true, expected: [0, 1, 2], firstAt: 0 },
93
+ { emitInitial: false, expected: [1, 2, 3], firstAt: 100 },
94
+ ] as const)(
95
+ 'startManually: false, emitInitial: $emitInitial starts at creation',
96
+ ({ emitInitial, expected, firstAt }) => {
97
+ vi.useFakeTimers();
98
+
99
+ const start = Date.now();
100
+
101
+ const counter$ = counter(100, { startManually: false, emitInitial });
102
+
103
+ const mut_history: number[] = [];
104
+
105
+ counter$.subscribe((n) => {
106
+ mut_history.push(n);
107
+ });
108
+
109
+ vi.advanceTimersToNextTimer();
110
+
111
+ assert.deepStrictEqual<readonly number[]>(
112
+ mut_history,
113
+ Arr.take(expected, 1),
114
+ );
115
+
116
+ assert.strictEqual(vi.getMockedSystemTime()?.getTime(), start + firstAt);
117
+
118
+ vi.advanceTimersToNextTimer().advanceTimersToNextTimer();
119
+
120
+ assert.deepStrictEqual<readonly number[]>(mut_history, expected);
121
+
122
+ counter$.complete();
123
+
124
+ vi.useRealTimers();
125
+ },
126
+ );
127
+
128
+ test.each([
129
+ { emitInitial: true, expected: [0, 1, 2], firstAt: 0 },
130
+ { emitInitial: false, expected: [1, 2, 3], firstAt: 100 },
131
+ ] as const)(
132
+ 'startManually: true, emitInitial: $emitInitial waits for start()',
133
+ ({ emitInitial, expected, firstAt }) => {
134
+ vi.useFakeTimers();
135
+
136
+ const counter$ = counter(100, { startManually: true, emitInitial });
137
+
138
+ const mut_history: number[] = [];
139
+
140
+ counter$.subscribe((n) => {
141
+ mut_history.push(n);
142
+ });
143
+
144
+ assert.strictEqual(vi.getTimerCount(), 0);
145
+
146
+ vi.setSystemTime(Date.now() + 1000);
147
+
148
+ const start = Date.now();
149
+
150
+ counter$.start();
151
+
152
+ vi.advanceTimersToNextTimer();
153
+
154
+ assert.deepStrictEqual<readonly number[]>(
155
+ mut_history,
156
+ Arr.take(expected, 1),
157
+ );
158
+
159
+ assert.strictEqual(vi.getMockedSystemTime()?.getTime(), start + firstAt);
160
+
161
+ vi.advanceTimersToNextTimer().advanceTimersToNextTimer();
162
+
163
+ assert.deepStrictEqual<readonly number[]>(mut_history, expected);
164
+
165
+ counter$.complete();
166
+
167
+ assert.strictEqual(vi.getTimerCount(), 0);
168
+
169
+ vi.useRealTimers();
170
+ },
171
+ );
172
+
173
+ test('completing before the first emission cancels the pending 0', () => {
174
+ vi.useFakeTimers();
175
+
176
+ const counter$ = counter(100);
177
+
178
+ const mut_history: number[] = [];
179
+
180
+ counter$.subscribe((n) => {
181
+ mut_history.push(n);
182
+ });
183
+
184
+ counter$.complete();
185
+
186
+ assert.strictEqual(vi.getTimerCount(), 0);
187
+
188
+ vi.runAllTimers();
189
+
190
+ assert.deepStrictEqual(mut_history, []);
191
+
192
+ vi.useRealTimers();
193
+ });
11
194
  });
@@ -1,6 +1,6 @@
1
1
  import { Optional, Result } from 'ts-data-forge';
2
2
  import { createRootObservable } from '../base/index.mjs';
3
- import { type FromPromiseObservable } from '../types/index.mjs';
3
+ import type { FromPromiseObservable } from '../types/index.mjs';
4
4
 
5
5
  /**
6
6
  * Creates an observable from a Promise factory that receives an `AbortSignal`.
@@ -71,7 +71,6 @@ import { type FromPromiseObservable } from '../types/index.mjs';
71
71
  */
72
72
  export const fromAbortablePromise = <A, E = unknown>(
73
73
  // @sumi-expect-error readonly/require-readonly-parameter
74
- // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
75
74
  factory: (signal: AbortSignal) => Promise<A>,
76
75
  ): FromPromiseObservable<A, E> => {
77
76
  const abortController = new AbortController();
@@ -108,7 +107,6 @@ export const fromAbortablePromise = <A, E = unknown>(
108
107
  startUpdate(
109
108
  Result.err(
110
109
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
111
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
112
110
  error as E,
113
111
  ),
114
112
  );
@@ -1,6 +1,6 @@
1
1
  import { Optional, Result } from 'ts-data-forge';
2
2
  import { createRootObservable } from '../base/index.mjs';
3
- import { type FromPromiseObservable } from '../types/index.mjs';
3
+ import type { FromPromiseObservable } from '../types/index.mjs';
4
4
 
5
5
  /**
6
6
  * Creates an observable from a Promise.
@@ -71,7 +71,6 @@ export const fromPromise = <A, E = unknown>(
71
71
  startUpdate(
72
72
  Result.err(
73
73
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
74
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
75
74
  error as E,
76
75
  ),
77
76
  );
@@ -1,8 +1,8 @@
1
1
  import { Optional, Result } from 'ts-data-forge';
2
2
  import { createRootObservable } from '../base/index.mjs';
3
- import {
4
- type FromSubscribableObservable,
5
- type Subscribable,
3
+ import type {
4
+ FromSubscribableObservable,
5
+ Subscribable,
6
6
  } from '../types/index.mjs';
7
7
 
8
8
  /**
@@ -77,7 +77,6 @@ export const fromSubscribable = <A, E = unknown>(
77
77
  startUpdate(
78
78
  Result.err(
79
79
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
80
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
81
80
  error as E,
82
81
  ),
83
82
  );
@@ -1,6 +1,6 @@
1
1
  import { Optional } from 'ts-data-forge';
2
2
  import { createRootObservable } from '../base/index.mjs';
3
- import { type InitializedRootObservable } from '../types/index.mjs';
3
+ import type { InitializedRootObservable } from '../types/index.mjs';
4
4
 
5
5
  /**
6
6
  * Creates an Observable that holds a single static value and immediately
@@ -40,6 +40,5 @@ export const just = <const A,>(value: A): InitializedRootObservable<A> => {
40
40
  obs.complete();
41
41
 
42
42
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
43
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
44
43
  return obs as InitializedRootObservable<A>;
45
44
  };
@@ -1,8 +1,8 @@
1
1
  import { Arr, Optional } from 'ts-data-forge';
2
2
  import { createRootObservable } from '../base/index.mjs';
3
- import {
4
- type InitializedSourceObservable,
5
- type SourceObservable,
3
+ import type {
4
+ InitializedSourceObservable,
5
+ SourceObservable,
6
6
  } from '../types/index.mjs';
7
7
 
8
8
  /**
@@ -1,6 +1,6 @@
1
1
  import { Optional } from 'ts-data-forge';
2
2
  import { createRootObservable } from '../base/index.mjs';
3
- import { type TimerId, type TimerObservable } from '../types/index.mjs';
3
+ import type { TimerId, TimerObservable } from '../types/index.mjs';
4
4
 
5
5
  /**
6
6
  * Creates an observable that emits 0 after a specified delay and then completes.
@@ -1,10 +1,10 @@
1
1
  import { Optional } from 'ts-data-forge';
2
2
  import { createAsyncChildObservable } from '../base/index.mjs';
3
- import {
4
- type AuditOperatorObservable,
5
- type KeepInitialValueOperator,
6
- type Observable,
7
- type TimerId,
3
+ import type {
4
+ AuditOperatorObservable,
5
+ KeepInitialValueOperator,
6
+ Observable,
7
+ TimerId,
8
8
  } from '../types/index.mjs';
9
9
 
10
10
  /**
@@ -105,7 +105,6 @@ export const audit = <A,>(
105
105
  milliSeconds: number,
106
106
  ): KeepInitialValueOperator<A, A> =>
107
107
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
108
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
109
108
  ((parentObservable) =>
110
109
  createAuditObservable(
111
110
  parentObservable,
@@ -1,10 +1,10 @@
1
1
  import { Optional } from 'ts-data-forge';
2
2
  import { createAsyncChildObservable } from '../base/index.mjs';
3
- import {
4
- type DebounceOperatorObservable,
5
- type KeepInitialValueOperator,
6
- type Observable,
7
- type TimerId,
3
+ import type {
4
+ DebounceOperatorObservable,
5
+ KeepInitialValueOperator,
6
+ Observable,
7
+ TimerId,
8
8
  } from '../types/index.mjs';
9
9
 
10
10
  /**
@@ -96,7 +96,6 @@ export const debounce = <A,>(
96
96
  milliSeconds: number,
97
97
  ): KeepInitialValueOperator<A, A> =>
98
98
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
99
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
100
99
  ((parentObservable) =>
101
100
  createDebounceObservable(
102
101
  parentObservable,