synstate 6.1.0 → 6.2.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 (151) hide show
  1. package/README.md +4 -4
  2. package/dist/core/authoring.d.mts +3 -3
  3. package/dist/core/class/child-observable-class.d.mts +24 -25
  4. package/dist/core/class/child-observable-class.d.mts.map +1 -1
  5. package/dist/core/class/child-observable-class.mjs +41 -42
  6. package/dist/core/class/child-observable-class.mjs.map +1 -1
  7. package/dist/core/class/create-child-observable.d.mts +27 -29
  8. package/dist/core/class/create-child-observable.d.mts.map +1 -1
  9. package/dist/core/class/create-child-observable.mjs.map +1 -1
  10. package/dist/core/class/create-root-observable.d.mts +11 -11
  11. package/dist/core/class/manager-observable-class.d.mts +6 -6
  12. package/dist/core/class/manager-observable-class.d.mts.map +1 -1
  13. package/dist/core/class/manager-observable-class.mjs +6 -0
  14. package/dist/core/class/manager-observable-class.mjs.map +1 -1
  15. package/dist/core/class/observable-base-class.d.mts +32 -26
  16. package/dist/core/class/observable-base-class.d.mts.map +1 -1
  17. package/dist/core/class/observable-base-class.mjs +16 -3
  18. package/dist/core/class/observable-base-class.mjs.map +1 -1
  19. package/dist/core/class/observable-node.d.mts +3 -4
  20. package/dist/core/class/observable-node.d.mts.map +1 -1
  21. package/dist/core/class/observable-node.mjs +0 -1
  22. package/dist/core/class/observable-node.mjs.map +1 -1
  23. package/dist/core/class/propagation-state.d.mts +10 -9
  24. package/dist/core/class/propagation-state.d.mts.map +1 -1
  25. package/dist/core/class/propagation-state.mjs +4 -2
  26. package/dist/core/class/propagation-state.mjs.map +1 -1
  27. package/dist/core/class/root-observable-class.d.mts +4 -4
  28. package/dist/core/combine/derive.d.mts +7 -8
  29. package/dist/core/combine/derive.d.mts.map +1 -1
  30. package/dist/core/combine/derive.mjs +0 -1
  31. package/dist/core/combine/derive.mjs.map +1 -1
  32. package/dist/core/combine/merge.mjs.map +1 -1
  33. package/dist/core/combine/zip.d.mts +3 -3
  34. package/dist/core/combine/zip.mjs.map +1 -1
  35. package/dist/core/create/counter.d.mts +3 -3
  36. package/dist/core/create/counter.mjs.map +1 -1
  37. package/dist/core/create/from-abortable-promise.mjs.map +1 -1
  38. package/dist/core/create/from-promise.mjs.map +1 -1
  39. package/dist/core/create/from-subscribable.mjs.map +1 -1
  40. package/dist/core/create/source.mjs.map +1 -1
  41. package/dist/core/create/timer.mjs.map +1 -1
  42. package/dist/core/operators/audit.mjs.map +1 -1
  43. package/dist/core/operators/debounce.mjs.map +1 -1
  44. package/dist/core/operators/filter.mjs.map +1 -1
  45. package/dist/core/operators/keep-equal-parts.d.mts +14 -15
  46. package/dist/core/operators/keep-equal-parts.d.mts.map +1 -1
  47. package/dist/core/operators/keep-equal-parts.mjs +0 -1
  48. package/dist/core/operators/keep-equal-parts.mjs.map +1 -1
  49. package/dist/core/operators/map.mjs.map +1 -1
  50. package/dist/core/operators/merge-map.d.mts +3 -3
  51. package/dist/core/operators/merge-map.mjs.map +1 -1
  52. package/dist/core/operators/pairwise.mjs.map +1 -1
  53. package/dist/core/operators/scan.mjs.map +1 -1
  54. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  55. package/dist/core/operators/skip-until.mjs.map +1 -1
  56. package/dist/core/operators/skip-while.mjs.map +1 -1
  57. package/dist/core/operators/switch-map.mjs.map +1 -1
  58. package/dist/core/operators/take-until.mjs.map +1 -1
  59. package/dist/core/operators/take-while.mjs.map +1 -1
  60. package/dist/core/operators/take.mjs.map +1 -1
  61. package/dist/core/operators/throttle.mjs.map +1 -1
  62. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  63. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  64. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  65. package/dist/core/predefined/operators/attach-index.mjs.map +1 -1
  66. package/dist/core/predefined/operators/map-to.d.mts +3 -4
  67. package/dist/core/predefined/operators/map-to.d.mts.map +1 -1
  68. package/dist/core/predefined/operators/map-to.mjs +0 -1
  69. package/dist/core/predefined/operators/map-to.mjs.map +1 -1
  70. package/dist/core/scope/scope.d.mts +4 -4
  71. package/dist/core/types/id.d.mts +2 -1
  72. package/dist/core/types/id.d.mts.map +1 -1
  73. package/dist/core/types/observable-family.d.mts.map +1 -1
  74. package/dist/core/types/observable-family.mjs.map +1 -1
  75. package/dist/core/types/observable.d.mts +7 -6
  76. package/dist/core/types/observable.d.mts.map +1 -1
  77. package/dist/core/types/observable.mjs.map +1 -1
  78. package/dist/core/utils/current-scope.d.mts +6 -6
  79. package/dist/core/utils/id-maker.d.mts +7 -0
  80. package/dist/core/utils/id-maker.d.mts.map +1 -1
  81. package/dist/core/utils/id-maker.mjs +9 -0
  82. package/dist/core/utils/id-maker.mjs.map +1 -1
  83. package/dist/core/utils/observable-brand.d.mts +5 -5
  84. package/dist/utils/create-boolean-state.d.mts +2 -2
  85. package/dist/utils/create-reducer.d.mts +20 -20
  86. package/dist/utils/create-reducer.d.mts.map +1 -1
  87. package/dist/utils/create-reducer.mjs +4 -16
  88. package/dist/utils/create-reducer.mjs.map +1 -1
  89. package/dist/utils/create-state.d.mts +3 -3
  90. package/dist/utils/create-state.d.mts.map +1 -1
  91. package/dist/utils/create-state.mjs +10 -13
  92. package/dist/utils/create-state.mjs.map +1 -1
  93. package/dist/utils/state-source.d.mts +19 -0
  94. package/dist/utils/state-source.d.mts.map +1 -0
  95. package/dist/utils/state-source.mjs +31 -0
  96. package/dist/utils/state-source.mjs.map +1 -0
  97. package/package.json +10 -10
  98. package/src/core/authoring.mts +3 -3
  99. package/src/core/class/child-observable-class.mts +86 -87
  100. package/src/core/class/circular-dependency-comparison.test.mts +2 -2
  101. package/src/core/class/create-child-observable.mts +27 -29
  102. package/src/core/class/create-root-observable.mts +11 -11
  103. package/src/core/class/manager-observable-class.mts +16 -9
  104. package/src/core/class/observable-base-class.mts +48 -30
  105. package/src/core/class/observable-node.mts +3 -4
  106. package/src/core/class/propagation-state.mts +31 -29
  107. package/src/core/class/remove-completed.test.mts +2 -2
  108. package/src/core/class/root-observable-class.mts +9 -9
  109. package/src/core/class/unobserved-write.test.mts +194 -0
  110. package/src/core/combine/derive.mts +10 -11
  111. package/src/core/combine/merge.mts +2 -2
  112. package/src/core/combine/zip.mts +7 -7
  113. package/src/core/create/counter.mts +5 -5
  114. package/src/core/create/from-abortable-promise.mts +2 -2
  115. package/src/core/create/from-promise.mts +2 -2
  116. package/src/core/create/from-subscribable.mts +2 -2
  117. package/src/core/create/source.mts +5 -5
  118. package/src/core/create/timer.mts +2 -2
  119. package/src/core/operators/audit.mts +2 -2
  120. package/src/core/operators/debounce.mts +2 -2
  121. package/src/core/operators/filter.mts +4 -4
  122. package/src/core/operators/keep-equal-parts.mts +16 -17
  123. package/src/core/operators/map.mts +2 -2
  124. package/src/core/operators/merge-map.mts +5 -5
  125. package/src/core/operators/pairwise.mts +4 -4
  126. package/src/core/operators/scan.mts +2 -2
  127. package/src/core/operators/skip-if-no-change.mts +4 -4
  128. package/src/core/operators/skip-until.mts +4 -4
  129. package/src/core/operators/skip-while.mts +2 -2
  130. package/src/core/operators/switch-map.mts +5 -5
  131. package/src/core/operators/take-until.mts +2 -2
  132. package/src/core/operators/take-while.mts +2 -2
  133. package/src/core/operators/take.mts +2 -2
  134. package/src/core/operators/throttle.mts +2 -2
  135. package/src/core/operators/with-buffered-from.mts +2 -2
  136. package/src/core/operators/with-current-value-from.mts +2 -2
  137. package/src/core/operators/with-initial-value.mts +2 -2
  138. package/src/core/predefined/operators/attach-index.mts +2 -2
  139. package/src/core/predefined/operators/map-to.mts +3 -4
  140. package/src/core/scope/scope.mts +6 -6
  141. package/src/core/types/id.mts +2 -1
  142. package/src/core/types/observable-family.mts +4 -5
  143. package/src/core/types/observable.mts +9 -8
  144. package/src/core/utils/current-scope.mts +8 -8
  145. package/src/core/utils/id-maker.mts +10 -0
  146. package/src/core/utils/observable-brand.mts +5 -5
  147. package/src/utils/create-boolean-state.mts +2 -2
  148. package/src/utils/create-reducer.mts +27 -42
  149. package/src/utils/create-state.mts +14 -31
  150. package/src/utils/create-state.test.mts +20 -2
  151. package/src/utils/state-source.mts +48 -0
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -79,9 +79,9 @@ class SourceObservableClass<A>
79
79
  });
80
80
  }
81
81
 
82
- // Returns the value held after the call: `nextValue`, or, once completed,
83
- // the value already there — `undefined` only on a source that never had
84
- // one, whose `next` is typed `void`.
82
+ // Returns the value held after the call: `nextValue`, or, once completed, the
83
+ // value already there — `undefined` only on a source that never had one,
84
+ // whose `next` is typed `void`.
85
85
  next(nextValue: A): A | undefined {
86
86
  if (this.isCompleted) {
87
87
  return Optional.unwrap(this.getSnapshot());
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -175,8 +175,8 @@ if (import.meta.vitest !== undefined) {
175
175
 
176
176
  expectType<typeof _inferred, Observable<number>>('=');
177
177
 
178
- // A generic guard is what a single signature with a union parameter
179
- // loses (it infers `unknown`), and why this set stays overloaded.
178
+ // A generic guard is what a single signature with a union parameter loses
179
+ // (it infers `unknown`), and why this set stays overloaded.
180
180
  const _generic = s.pipe(filter(isNotUndefined));
181
181
 
182
182
  expectType<typeof _generic, Observable<number>>('=');
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -20,19 +20,19 @@ import type {
20
20
 
21
21
  /**
22
22
  * Passes on each value with every part deeply equal to the same part of the
23
- * value passed on before replaced by that part, and skips a value deeply
24
- * equal to it altogether (structural sharing). A reader of a part that did
25
- * not change keeps the object it has, so `skipIfNoChange()` with `Object.is`
26
- * stops it. Superset of `skipIfNoChange(fastDeepEqual)`.
23
+ * value passed on before replaced by that part, and skips a value deeply equal
24
+ * to it altogether (structural sharing). A reader of a part that did not change
25
+ * keeps the object it has, so `skipIfNoChange()` with `Object.is` stops it.
26
+ * Superset of `skipIfNoChange(fastDeepEqual)`.
27
27
  *
28
28
  * **Prefer keeping references where the value is written** — compare before
29
- * `setState`, and skip it when nothing changed — so that nothing downstream
30
- * has anything to undo. The `keepEqualParts` option of `createState` and
31
- * `createReducer` does it for a state written whole, and `replaceEqualDeep`
32
- * of ts-data-forge does it for any other write. This operator lets every
33
- * update that changes nothing reach the source and everything up to it, and
34
- * walks the whole value again on each one; reach for it when the source is
35
- * not yours to change (a stream that arrives whole from outside).
29
+ * `setState`, and skip it when nothing changed — so that nothing downstream has
30
+ * anything to undo. The `keepEqualParts` option of `createState` and
31
+ * `createReducer` does it for a state written whole, and `replaceEqualDeep` of
32
+ * ts-data-forge does it for any other write. This operator lets every update
33
+ * that changes nothing reach the source and everything up to it, and walks the
34
+ * whole value again on each one; reach for it when the source is not yours to
35
+ * change (a stream that arrives whole from outside).
36
36
  *
37
37
  * Array items are matched by index; pass `{ key }` to match them by key, an
38
38
  * item for which `key` returns `undefined` being matched by index. Only plain
@@ -51,10 +51,9 @@ import type {
51
51
  * cards: { id: number; text: string }[];
52
52
  * }>;
53
53
  *
54
- * // A stream that arrives whole from outside (a WebSocket, say), each
55
- * // message a new object even when nothing changed. A state you write
56
- * // yourself takes `createState(initial, { keepEqualParts: true })`
57
- * // instead.
54
+ * // A stream that arrives whole from outside (a WebSocket, say), each message
55
+ * // a new object even when nothing changed. A state you write yourself takes
56
+ * // `createState(initial, { keepEqualParts: true })` instead.
58
57
  * const message$ = source<Board>();
59
58
  *
60
59
  * const board$ = message$.pipe(keepEqualParts());
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -22,9 +22,9 @@ import type {
22
22
  * Unlike `switchMap`, does not cancel previous inner observables.
23
23
  *
24
24
  * Each projection runs in a scope of its own (see `createScope`): what it
25
- * creates is disposed when `mergeMap` completes. An observable it only
26
- * returns — one created outside the projection and shared with others — is
27
- * unsubscribed and left running.
25
+ * creates is disposed when `mergeMap` completes. An observable it only returns
26
+ * — one created outside the projection and shared with others — is unsubscribed
27
+ * and left running.
28
28
  *
29
29
  * @template A - The type of values from the source
30
30
  * @template B - The type of values from the projected observable
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -90,8 +90,8 @@ class PairwiseObservableClass<A>
90
90
  initialValue: Optional.none,
91
91
  });
92
92
 
93
- // parentObservable.snapshot has value
94
- // if parentObservable is InitializedObservable
93
+ // parentObservable.snapshot has value if parentObservable is
94
+ // InitializedObservable
95
95
  this.#mut_previousValue = parentObservable.getSnapshot();
96
96
 
97
97
  this.attach();
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -104,8 +104,8 @@ class SkipIfNoChangeObservableClass<A>
104
104
  initialValue: parentObservable.getSnapshot(),
105
105
  });
106
106
 
107
- // parentObservable.snapshot has value
108
- // if parentObservable is InitializedObservable
107
+ // parentObservable.snapshot has value if parentObservable is
108
+ // InitializedObservable
109
109
  this.#mut_previousValue = parentObservable.getSnapshot();
110
110
 
111
111
  this.#eq = eq;
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -83,8 +83,8 @@ class SkipUntilObservableClass<A>
83
83
  initialValue: Optional.none,
84
84
  });
85
85
 
86
- // A notifier that already holds a value, or has completed, would stop
87
- // the skipping inside `subscribe`, before the subscription is stored.
86
+ // A notifier that already holds a value, or has completed, would stop the
87
+ // skipping inside `subscribe`, before the subscription is stored.
88
88
  this.#mut_isSkipping =
89
89
  Optional.isNone(notifier.getSnapshot()) && !notifier.isCompleted;
90
90
 
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -126,9 +126,9 @@ class SwitchMapObservableClass<A, B>
126
126
  readonly #mapToObservable: (curr: A) => Observable<B>;
127
127
 
128
128
  /**
129
- * The scope the operator was created in, so that each inner scope is
130
- * disposed with it; the projection itself runs during propagation, when the
131
- * current scope is whatever happens to be running.
129
+ * The scope the operator was created in, so that each inner scope is disposed
130
+ * with it; the projection itself runs during propagation, when the current
131
+ * scope is whatever happens to be running.
132
132
  */
133
133
  readonly #ownerScope: Scope | undefined;
134
134
 
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -1,6 +1,6 @@
1
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).
2
+ // `mut_` binding; an observable is a class (`ObservableBaseClass` says why), so
3
+ // those rules are waived here (D-63).
4
4
  // @sumi-expect-error-file classes/no-class
5
5
  // @sumi-expect-error-file banned-syntax/no-this
6
6
  // @sumi-expect-error-file functions/prefer-arrow-function
@@ -4,10 +4,9 @@ import type { KeepInitialValueOperator } from '../../types/index.mjs';
4
4
  /**
5
5
  * Maps all emitted values to a constant value, ignoring the source values.
6
6
  * Emits on every source value although the value never changes — where
7
- * `map(() => value)` would stop every result after the first as equal — so
8
- * it is the one for turning events into a value. The value's type is
9
- * inferred as written, as with `as const`: `mapTo('reset')` gives
10
- * `'reset'`, not `string`.
7
+ * `map(() => value)` would stop every result after the first as equal — so it
8
+ * is the one for turning events into a value. The value's type is inferred as
9
+ * written, as with `as const`: `mapTo('reset')` gives `'reset'`, not `string`.
11
10
  *
12
11
  * @template A - The type of values from the source
13
12
  * @template B - The type of the constant value
@@ -23,8 +23,8 @@ import {
23
23
  * disposed gives a scope that is born disposed, with a warning.
24
24
  *
25
25
  * Intended for authors of libraries built on synstate rather than for
26
- * application code; state defined at module level belongs to no scope and
27
- * lives as long as the page.
26
+ * application code; state defined at module level belongs to no scope and lives
27
+ * as long as the page.
28
28
  *
29
29
  * `run` and `dispose` read the scope they are called on, so call them on it
30
30
  * (`scope.dispose()`) rather than taking them off it.
@@ -50,8 +50,8 @@ export const getCurrentScope = (): Scope | undefined =>
50
50
 
51
51
  /**
52
52
  * Registers `cleanup` to be called when the current scope is disposed. Cleanups
53
- * run after the child scopes are disposed and before the owned observables
54
- * are, newest first.
53
+ * run after the child scopes are disposed and before the owned observables are,
54
+ * newest first.
55
55
  *
56
56
  * Outside every scope it warns and registers nothing.
57
57
  *
@@ -85,8 +85,8 @@ export const untracked = <R,>(body: () => R): R =>
85
85
  * A scope is created for every row and branch of a UI, so creating one has to
86
86
  * be cheap. It used to be a set of closures with a `Set` of children, a `Set`
87
87
  * of owned observables and a record in a `WeakMap`; it is now one object whose
88
- * methods live on the prototype and whose lists are arrays made when the
89
- * first entry arrives.
88
+ * methods live on the prototype and whose lists are arrays made when the first
89
+ * entry arrives.
90
90
  *
91
91
  * Whatever leaves a list on its own (a child scope disposed by itself, an
92
92
  * observable that completed) is not looked up and spliced out: it only counts
@@ -2,6 +2,7 @@ import type { Brand, UnknownRecord } from 'ts-type-forge';
2
2
 
3
3
  /**
4
4
  * Identifies one update. Opaque: an object issued per update, which is also
5
- * that update's queue.
5
+ * that update's queue — except for a write nothing observes, which opens no
6
+ * update and is issued a token with no queue behind it.
6
7
  */
7
8
  export type UpdateToken = Brand<UnknownRecord, 'update-token'>;
@@ -65,11 +65,10 @@ export type ScanOperatorObservable<A, B> = InitializedSyncChildObservable<
65
65
 
66
66
  // SyncChildObservable
67
67
 
68
- // The helpers stay in a namespace so their names do not crowd the module
69
- // scope. A namespace holding only types is erasable, so it passes
70
- // `erasableSyntaxOnly` (TS1294); the `expectType` assertions are call
71
- // statements, which is why they sit below it rather than beside the types
72
- // they check.
68
+ // The helpers stay in a namespace so their names do not crowd the module scope.
69
+ // A namespace holding only types is erasable, so it passes `erasableSyntaxOnly`
70
+ // (TS1294); the `expectType` assertions are call statements, which is why they
71
+ // sit below it rather than beside the types they check.
73
72
  namespace SynStateInternals {
74
73
  type Cast<A> = A extends NonEmptyUnknownList ? A : never;
75
74
 
@@ -32,8 +32,8 @@ type CreateObservableType<A, Kind extends ObservableKind> = Readonly<{
32
32
 
33
33
  /**
34
34
  * One more than the deepest observable this one is derived from; 0 for a
35
- * root. An update reaches observables in ascending depth, so every parent
36
- * has emitted before its child reads it.
35
+ * root. An update reaches observables in ascending depth, so every parent has
36
+ * emitted before its child reads it.
37
37
  */
38
38
  depth: Kind extends 'root' ? 0 : number;
39
39
 
@@ -44,7 +44,8 @@ type CreateObservableType<A, Kind extends ObservableKind> = Readonly<{
44
44
  * The token of the update in which this observable last emitted. A child's
45
45
  * `tryUpdate` receives the token of the update now propagating; a parent
46
46
  * whose token differs did not emit in it. The token is opaque: compare it,
47
- * store it, or pass it on to `setNext`.
47
+ * store it, or pass the one `tryUpdate` received on to `setNext`. A write
48
+ * nothing observes opens no update, and its token has no queue behind it.
48
49
  */
49
50
  updateToken: UpdateToken;
50
51
 
@@ -172,9 +173,9 @@ export type Operator<A, B> =
172
173
  | KeepInitialValueOperator<A, B>;
173
174
 
174
175
  /**
175
- * Tells an observable made by synstate from any other value, by the brand
176
- * every observable carries. Checking for a `subscribe` method instead would
177
- * also accept plain values that happen to have one.
176
+ * Tells an observable made by synstate from any other value, by the brand every
177
+ * observable carries. Checking for a `subscribe` method instead would also
178
+ * accept plain values that happen to have one.
178
179
  *
179
180
  * @example
180
181
  *
@@ -222,8 +223,8 @@ export type WrapInitialized<A extends readonly unknown[]> = Readonly<{
222
223
  // type GetDestTypeOfOperator<Op extends Operator<unknown, unknown>> =
223
224
  // Op extends Operator<unknown, infer B> ? B : never;
224
225
 
225
- // Only the members meant for users are public; the rest live on the
226
- // internal node types in `core/class` (#2117).
226
+ // Only the members meant for users are public; the rest live on the internal
227
+ // node types in `core/class` (#2117).
227
228
  expectType<
228
229
  keyof Observable<unknown>,
229
230
  | typeof observableBrand
@@ -7,10 +7,10 @@ export type ScopeMember = Readonly<{
7
7
  }>;
8
8
 
9
9
  /**
10
- * The side of a scope the rest of the core talks to, on top of its public
11
- * face {@link Scope}. Kept out of the public API (`core/utils/**` is excluded
12
- * from index generation), so that only `createScope` and its siblings decide
13
- * what a scope owns.
10
+ * The side of a scope the rest of the core talks to, on top of its public face
11
+ * {@link Scope}. Kept out of the public API (`core/utils/**` is excluded from
12
+ * index generation), so that only `createScope` and its siblings decide what a
13
+ * scope owns.
14
14
  */
15
15
  export type ScopeInternals = Scope &
16
16
  Readonly<{
@@ -18,8 +18,8 @@ export type ScopeInternals = Scope &
18
18
  adopt: (node: ScopeMember) => void;
19
19
 
20
20
  /**
21
- * Tells the scope that one of the nodes it adopted completed on its own,
22
- * so that the scope can drop it and keep no reference to it. The node is
21
+ * Tells the scope that one of the nodes it adopted completed on its own, so
22
+ * that the scope can drop it and keep no reference to it. The node is
23
23
  * completed (`isCompleted`) by the time it calls this.
24
24
  */
25
25
  release: () => void;
@@ -28,8 +28,8 @@ export type ScopeInternals = Scope &
28
28
  }>;
29
29
 
30
30
  /**
31
- * The scope whose `run` is executing. A field rather than a module-level
32
- * `let`, so that the one place writing it is visibly this object.
31
+ * The scope whose `run` is executing. A field rather than a module-level `let`,
32
+ * so that the one place writing it is visibly this object.
33
33
  */
34
34
  const mut_slot: { current: ScopeInternals | undefined } = {
35
35
  current: undefined,
@@ -8,3 +8,13 @@ import type { UpdateToken } from '../types/index.mjs';
8
8
  export const notUpdatedYet: UpdateToken =
9
9
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
10
10
  Object.freeze({}) as UpdateToken;
11
+
12
+ /**
13
+ * Issues the token of a write that opens no update, because nothing observes
14
+ * the observable written to (`setNextIfUnobserved`). Nothing is ever queued
15
+ * with it, so it is a token and not a queue, unlike the tokens `openUpdate`
16
+ * issues.
17
+ */
18
+ export const issueUnqueuedToken = (): UpdateToken =>
19
+ // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
20
+ ({}) as UpdateToken;
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * The key every observable carries, set to `true` by `assembleObservable`. It
3
- * lets `isObservable` tell an observable from any other value at run time —
4
- * a `subscribe` method is not enough, since plain values may have one — and,
5
- * as a type, makes the public observable types impossible to satisfy with an
6
- * object literal: an imitation passed to an operator would lack the internal
7
- * members propagation reads and fail at run time instead of at compile time.
3
+ * lets `isObservable` tell an observable from any other value at run time — a
4
+ * `subscribe` method is not enough, since plain values may have one — and, as a
5
+ * type, makes the public observable types impossible to satisfy with an object
6
+ * literal: an imitation passed to an operator would lack the internal members
7
+ * propagation reads and fail at run time instead of at compile time.
8
8
  *
9
9
  * `Symbol.for`, so that an observable made by another copy of synstate in the
10
10
  * same program is still recognized.
@@ -18,8 +18,8 @@ import { createState } from './create-state.mjs';
18
18
  * import { useObservableValue } from 'synstate-react-hooks';
19
19
  *
20
20
  * // Menu drawer open/close state.
21
- * // setTrue and setFalse can be passed directly as callbacks
22
- * // — no need to create wrapper functions like `() => setState(true)`.
21
+ * // setTrue and setFalse can be passed directly as callbacks — no need to
22
+ * // create wrapper functions like `() => setState(true)`.
23
23
  * const [menuOpen$, { setTrue: openMenu, setFalse: closeMenu }] =
24
24
  * createBooleanState(false);
25
25
  *