synstate 6.1.1 → 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 (134) hide show
  1. package/README.md +2 -2
  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.mjs.map +1 -1
  13. package/dist/core/class/observable-base-class.d.mts +29 -31
  14. package/dist/core/class/observable-base-class.d.mts.map +1 -1
  15. package/dist/core/class/observable-base-class.mjs +0 -2
  16. package/dist/core/class/observable-base-class.mjs.map +1 -1
  17. package/dist/core/class/observable-node.d.mts +3 -4
  18. package/dist/core/class/observable-node.d.mts.map +1 -1
  19. package/dist/core/class/observable-node.mjs +0 -1
  20. package/dist/core/class/observable-node.mjs.map +1 -1
  21. package/dist/core/class/propagation-state.d.mts +6 -8
  22. package/dist/core/class/propagation-state.d.mts.map +1 -1
  23. package/dist/core/class/propagation-state.mjs +0 -2
  24. package/dist/core/class/propagation-state.mjs.map +1 -1
  25. package/dist/core/class/root-observable-class.d.mts +4 -4
  26. package/dist/core/combine/derive.d.mts +7 -8
  27. package/dist/core/combine/derive.d.mts.map +1 -1
  28. package/dist/core/combine/derive.mjs +0 -1
  29. package/dist/core/combine/derive.mjs.map +1 -1
  30. package/dist/core/combine/merge.mjs.map +1 -1
  31. package/dist/core/combine/zip.d.mts +3 -3
  32. package/dist/core/combine/zip.mjs.map +1 -1
  33. package/dist/core/create/counter.d.mts +3 -3
  34. package/dist/core/create/counter.mjs.map +1 -1
  35. package/dist/core/create/from-abortable-promise.mjs.map +1 -1
  36. package/dist/core/create/from-promise.mjs.map +1 -1
  37. package/dist/core/create/from-subscribable.mjs.map +1 -1
  38. package/dist/core/create/source.mjs.map +1 -1
  39. package/dist/core/create/timer.mjs.map +1 -1
  40. package/dist/core/operators/audit.mjs.map +1 -1
  41. package/dist/core/operators/debounce.mjs.map +1 -1
  42. package/dist/core/operators/filter.mjs.map +1 -1
  43. package/dist/core/operators/keep-equal-parts.d.mts +14 -15
  44. package/dist/core/operators/keep-equal-parts.d.mts.map +1 -1
  45. package/dist/core/operators/keep-equal-parts.mjs +0 -1
  46. package/dist/core/operators/keep-equal-parts.mjs.map +1 -1
  47. package/dist/core/operators/map.mjs.map +1 -1
  48. package/dist/core/operators/merge-map.d.mts +3 -3
  49. package/dist/core/operators/merge-map.mjs.map +1 -1
  50. package/dist/core/operators/pairwise.mjs.map +1 -1
  51. package/dist/core/operators/scan.mjs.map +1 -1
  52. package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
  53. package/dist/core/operators/skip-until.mjs.map +1 -1
  54. package/dist/core/operators/skip-while.mjs.map +1 -1
  55. package/dist/core/operators/switch-map.mjs.map +1 -1
  56. package/dist/core/operators/take-until.mjs.map +1 -1
  57. package/dist/core/operators/take-while.mjs.map +1 -1
  58. package/dist/core/operators/take.mjs.map +1 -1
  59. package/dist/core/operators/throttle.mjs.map +1 -1
  60. package/dist/core/operators/with-buffered-from.mjs.map +1 -1
  61. package/dist/core/operators/with-current-value-from.mjs.map +1 -1
  62. package/dist/core/operators/with-initial-value.mjs.map +1 -1
  63. package/dist/core/predefined/operators/attach-index.mjs.map +1 -1
  64. package/dist/core/predefined/operators/map-to.d.mts +3 -4
  65. package/dist/core/predefined/operators/map-to.d.mts.map +1 -1
  66. package/dist/core/predefined/operators/map-to.mjs +0 -1
  67. package/dist/core/predefined/operators/map-to.mjs.map +1 -1
  68. package/dist/core/scope/scope.d.mts +4 -4
  69. package/dist/core/types/observable-family.d.mts.map +1 -1
  70. package/dist/core/types/observable-family.mjs.map +1 -1
  71. package/dist/core/types/observable.d.mts +5 -5
  72. package/dist/core/types/observable.mjs.map +1 -1
  73. package/dist/core/utils/current-scope.d.mts +6 -6
  74. package/dist/core/utils/id-maker.d.mts +2 -2
  75. package/dist/core/utils/observable-brand.d.mts +5 -5
  76. package/dist/utils/create-boolean-state.d.mts +2 -2
  77. package/dist/utils/create-reducer.d.mts +18 -18
  78. package/dist/utils/create-state.d.mts +2 -2
  79. package/dist/utils/create-state.mjs.map +1 -1
  80. package/dist/utils/state-source.d.mts +3 -3
  81. package/package.json +9 -9
  82. package/src/core/authoring.mts +3 -3
  83. package/src/core/class/child-observable-class.mts +86 -87
  84. package/src/core/class/circular-dependency-comparison.test.mts +2 -2
  85. package/src/core/class/create-child-observable.mts +27 -29
  86. package/src/core/class/create-root-observable.mts +11 -11
  87. package/src/core/class/manager-observable-class.mts +12 -12
  88. package/src/core/class/observable-base-class.mts +33 -35
  89. package/src/core/class/observable-node.mts +3 -4
  90. package/src/core/class/propagation-state.mts +26 -28
  91. package/src/core/class/remove-completed.test.mts +2 -2
  92. package/src/core/class/root-observable-class.mts +9 -9
  93. package/src/core/class/unobserved-write.test.mts +4 -4
  94. package/src/core/combine/derive.mts +10 -11
  95. package/src/core/combine/merge.mts +2 -2
  96. package/src/core/combine/zip.mts +7 -7
  97. package/src/core/create/counter.mts +5 -5
  98. package/src/core/create/from-abortable-promise.mts +2 -2
  99. package/src/core/create/from-promise.mts +2 -2
  100. package/src/core/create/from-subscribable.mts +2 -2
  101. package/src/core/create/source.mts +5 -5
  102. package/src/core/create/timer.mts +2 -2
  103. package/src/core/operators/audit.mts +2 -2
  104. package/src/core/operators/debounce.mts +2 -2
  105. package/src/core/operators/filter.mts +4 -4
  106. package/src/core/operators/keep-equal-parts.mts +16 -17
  107. package/src/core/operators/map.mts +2 -2
  108. package/src/core/operators/merge-map.mts +5 -5
  109. package/src/core/operators/pairwise.mts +4 -4
  110. package/src/core/operators/scan.mts +2 -2
  111. package/src/core/operators/skip-if-no-change.mts +4 -4
  112. package/src/core/operators/skip-until.mts +4 -4
  113. package/src/core/operators/skip-while.mts +2 -2
  114. package/src/core/operators/switch-map.mts +5 -5
  115. package/src/core/operators/take-until.mts +2 -2
  116. package/src/core/operators/take-while.mts +2 -2
  117. package/src/core/operators/take.mts +2 -2
  118. package/src/core/operators/throttle.mts +2 -2
  119. package/src/core/operators/with-buffered-from.mts +2 -2
  120. package/src/core/operators/with-current-value-from.mts +2 -2
  121. package/src/core/operators/with-initial-value.mts +2 -2
  122. package/src/core/predefined/operators/attach-index.mts +2 -2
  123. package/src/core/predefined/operators/map-to.mts +3 -4
  124. package/src/core/scope/scope.mts +6 -6
  125. package/src/core/types/observable-family.mts +4 -5
  126. package/src/core/types/observable.mts +7 -7
  127. package/src/core/utils/current-scope.mts +8 -8
  128. package/src/core/utils/id-maker.mts +2 -2
  129. package/src/core/utils/observable-brand.mts +5 -5
  130. package/src/utils/create-boolean-state.mts +2 -2
  131. package/src/utils/create-reducer.mts +18 -18
  132. package/src/utils/create-state.mts +4 -4
  133. package/src/utils/create-state.test.mts +2 -2
  134. package/src/utils/state-source.mts +3 -3
@@ -30,11 +30,11 @@ type ChildObservableConfig<A, P extends NonEmptyUnknownList> = Readonly<{
30
30
  parents: Wrap<P>;
31
31
 
32
32
  /**
33
- * Defaults to one more than the deepest parent. An update reaches
34
- * observables in ascending depth, so an observable `tryUpdate` reads with
35
- * `getSnapshot` without being its child (`withCurrentValueFrom`'s second
36
- * source) has to be shallower than this one too, or this one reads its value
37
- * from before the update: pass `1 + Math.max(...)` over both then.
33
+ * Defaults to one more than the deepest parent. An update reaches observables
34
+ * in ascending depth, so an observable `tryUpdate` reads with `getSnapshot`
35
+ * without being its child (`withCurrentValueFrom`'s second source) has to be
36
+ * shallower than this one too, or this one reads its value from before the
37
+ * update: pass `1 + Math.max(...)` over both then.
38
38
  */
39
39
  depth?: number;
40
40
 
@@ -45,9 +45,9 @@ type ChildObservableConfig<A, P extends NonEmptyUnknownList> = Readonly<{
45
45
  * An observable derived from `parents` that emits, if at all, in the same
46
46
  * update as they do (`map`, `filter`, `combine`, …).
47
47
  *
48
- * A subclass overrides `tryUpdate`, and, when it holds something to
49
- * release, `teardown`; its constructor ends with `this.attach()`, once
50
- * everything `tryUpdate` and `teardown` read is in place.
48
+ * A subclass overrides `tryUpdate`, and, when it holds something to release,
49
+ * `teardown`; its constructor ends with `this.attach()`, once everything
50
+ * `tryUpdate` and `teardown` read is in place.
51
51
  */
52
52
  export class SyncChildObservableClass<A, const P extends NonEmptyUnknownList>
53
53
  extends ObservableBaseClass<A, 'sync child', number>
@@ -107,10 +107,9 @@ export class SyncChildObservableClass<A, const P extends NonEmptyUnknownList>
107
107
  }
108
108
 
109
109
  /**
110
- * Whether this observable can emit nothing more although some parent is
111
- * still live, asked whenever a parent completes. `true` completes it then,
112
- * as all parents completing does (`zip` once a completed source's queue is
113
- * empty).
110
+ * Whether this observable can emit nothing more although some parent is still
111
+ * live, asked whenever a parent completes. `true` completes it then, as all
112
+ * parents completing does (`zip` once a completed source's queue is empty).
114
113
  */
115
114
  // eslint-disable-next-line @typescript-eslint/class-methods-use-this
116
115
  canEmitNoMore(): boolean {
@@ -118,8 +117,8 @@ export class SyncChildObservableClass<A, const P extends NonEmptyUnknownList>
118
117
  }
119
118
 
120
119
  /**
121
- * Completes this observable once the update now propagating has reached
122
- * every descendant, so that they see the value just passed on first.
120
+ * Completes this observable once the update now propagating has reached every
121
+ * descendant, so that they see the value just passed on first.
123
122
  */
124
123
  protected completeAfterPropagation(): void {
125
124
  runAfterPropagation(() => {
@@ -129,8 +128,8 @@ export class SyncChildObservableClass<A, const P extends NonEmptyUnknownList>
129
128
  }
130
129
 
131
130
  /**
132
- * An observable derived from `parents` that may emit later, in an update of
133
- * its own, through `startUpdate` (`debounce`, `switchMap`). It may also emit
131
+ * An observable derived from `parents` that may emit later, in an update of its
132
+ * own, through `startUpdate` (`debounce`, `switchMap`). It may also emit
134
133
  * synchronously with `setNext`, as a sync child does. A subclass may also
135
134
  * override `flush`, to pass on at completion what it still holds.
136
135
  */
@@ -204,13 +203,13 @@ export class AsyncChildObservableClass<A, const P extends NonEmptyUnknownList>
204
203
  * `mergeMap` returned.
205
204
  *
206
205
  * If the inner observable already holds a value (`just(x)`, a state), it
207
- * emits that value synchronously while being subscribed. That first value
208
- * is emitted with `updateToken`, the token of the update that ran the
209
- * projection, so it joins the propagation in progress like a sync
210
- * operator's value would. Starting an update of its own instead would
211
- * reach the nodes below before the current update reached this
212
- * observable's siblings: a node reading both would see the new inner value
213
- * beside stale sibling values (a glitch), and would emit twice.
206
+ * emits that value synchronously while being subscribed. That first value is
207
+ * emitted with `updateToken`, the token of the update that ran the
208
+ * projection, so it joins the propagation in progress like a sync operator's
209
+ * value would. Starting an update of its own instead would reach the nodes
210
+ * below before the current update reached this observable's siblings: a node
211
+ * reading both would see the new inner value beside stale sibling values (a
212
+ * glitch), and would emit twice.
214
213
  *
215
214
  * Values the inner observable emits later start updates of their own.
216
215
  */
@@ -236,8 +235,8 @@ export class AsyncChildObservableClass<A, const P extends NonEmptyUnknownList>
236
235
 
237
236
  /**
238
237
  * A sync child that always holds a value: a subclass passes a `Some` as its
239
- * `initialValue`. It differs from its base only in the types of
240
- * `getSnapshot` and `pipe`.
238
+ * `initialValue`. It differs from its base only in the types of `getSnapshot`
239
+ * and `pipe`.
241
240
  */
242
241
  export class InitializedSyncChildObservableClass<
243
242
  A,
@@ -266,8 +265,8 @@ export class InitializedSyncChildObservableClass<
266
265
  /* helpers */
267
266
 
268
267
  /**
269
- * Called by a parent that has completed: whether no live parent is left, or
270
- * no value can come from the live ones.
268
+ * Called by a parent that has completed: whether no live parent is left, or no
269
+ * value can come from the live ones.
271
270
  */
272
271
  const shouldComplete = (
273
272
  child: ChildNode & Readonly<{ canEmitNoMore: () => boolean }>,
@@ -275,6 +274,63 @@ const shouldComplete = (
275
274
  !child.isCompleted &&
276
275
  (child.parents.every((p) => p.isCompleted) || child.canEmitNoMore());
277
276
 
277
+ const hasCircularDependencyFrom = (
278
+ node: Observable<unknown>,
279
+ mut_visited: MutableSet<Observable<unknown>>,
280
+ mut_inPath: MutableSet<Observable<unknown>>,
281
+ ): boolean => {
282
+ if (mut_inPath.has(node)) {
283
+ return true;
284
+ }
285
+
286
+ if (mut_visited.has(node)) {
287
+ return false;
288
+ }
289
+
290
+ mut_visited.add(node);
291
+
292
+ mut_inPath.add(node);
293
+
294
+ if (node.kind !== 'root') {
295
+ for (const parent of node.parents) {
296
+ if (hasCircularDependencyFrom(parent, mut_visited, mut_inPath)) {
297
+ return true;
298
+ }
299
+ }
300
+ }
301
+
302
+ mut_inPath.delete(node);
303
+
304
+ return false;
305
+ };
306
+
307
+ /**
308
+ * Detects circular dependencies by walking the full ancestor chain of the
309
+ * child's parents and checking whether the child already appears among them.
310
+ *
311
+ * @throws {Error} if a circular dependency is detected
312
+ */
313
+ const detectCircularDependency = (child: ChildNode): void => {
314
+ const mut_visited = new Set<Observable<unknown>>();
315
+
316
+ const mut_inPath = new Set<Observable<unknown>>([
317
+ // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
318
+ child as Observable<unknown>,
319
+ ]);
320
+
321
+ for (const parent of child.parents) {
322
+ if (hasCircularDependencyFrom(parent, mut_visited, mut_inPath)) {
323
+ // A programming error (invariant violation), not a recoverable failure.
324
+ // `panic` marks the error it throws, so the `Result` / `AsyncResult`
325
+ // boundaries rethrow it rather than turning an invariant violation into
326
+ // an `Err` a caller might handle (Sumi D-48 / D-53).
327
+ panic(
328
+ 'Circular dependency detected in observable graph: a child observable cannot be its own ancestor.',
329
+ );
330
+ }
331
+ }
332
+ };
333
+
278
334
  /** Registers a child to its parents. */
279
335
  const registerChild = (child: ChildNode): void => {
280
336
  if (checksCircularDependency) {
@@ -287,9 +343,9 @@ const registerChild = (child: ChildNode): void => {
287
343
  };
288
344
 
289
345
  /**
290
- * Undoes {@link registerChild} for a completed child: its parents forget it,
291
- * so that no update puts it in its queue again. Without this a completed
292
- * node stayed reachable for as long as its root lived (#2134).
346
+ * Undoes {@link registerChild} for a completed child: its parents forget it, so
347
+ * that no update puts it in its queue again. Without this a completed node
348
+ * stayed reachable for as long as its root lived (#2134).
293
349
  */
294
350
  const unregisterChild = (child: ChildNode): void => {
295
351
  for (const p of child.parents) {
@@ -320,60 +376,3 @@ const isDevelopmentProcess = (): boolean => {
320
376
  * bundle).
321
377
  */
322
378
  export const checksCircularDependency: boolean = isDevelopmentProcess();
323
-
324
- /**
325
- * Detects circular dependencies by walking the full ancestor chain of the
326
- * child's parents and checking whether the child already appears among them.
327
- *
328
- * @throws {Error} if a circular dependency is detected
329
- */
330
- const detectCircularDependency = (child: ChildNode): void => {
331
- const mut_visited = new Set<Observable<unknown>>();
332
-
333
- const mut_inPath = new Set<Observable<unknown>>([
334
- // @sumi-expect-error banned-syntax/no-unsafe-type-assertion
335
- child as Observable<unknown>,
336
- ]);
337
-
338
- for (const parent of child.parents) {
339
- if (hasCircularDependencyFrom(parent, mut_visited, mut_inPath)) {
340
- // A programming error (invariant violation), not a recoverable
341
- // failure. `panic` marks the error it throws, so the `Result` /
342
- // `AsyncResult` boundaries rethrow it rather than turning an invariant
343
- // violation into an `Err` a caller might handle (Sumi D-48 / D-53).
344
- panic(
345
- 'Circular dependency detected in observable graph: a child observable cannot be its own ancestor.',
346
- );
347
- }
348
- }
349
- };
350
-
351
- const hasCircularDependencyFrom = (
352
- node: Observable<unknown>,
353
- mut_visited: MutableSet<Observable<unknown>>,
354
- mut_inPath: MutableSet<Observable<unknown>>,
355
- ): boolean => {
356
- if (mut_inPath.has(node)) {
357
- return true;
358
- }
359
-
360
- if (mut_visited.has(node)) {
361
- return false;
362
- }
363
-
364
- mut_visited.add(node);
365
-
366
- mut_inPath.add(node);
367
-
368
- if (node.kind !== 'root') {
369
- for (const parent of node.parents) {
370
- if (hasCircularDependencyFrom(parent, mut_visited, mut_inPath)) {
371
- return true;
372
- }
373
- }
374
- }
375
-
376
- mut_inPath.delete(node);
377
-
378
- return false;
379
- };
@@ -49,8 +49,8 @@ describe('circular dependency comparison', () => {
49
49
  );
50
50
 
51
51
  // Simulate a cycle: mut_childA → childB → mut_childA
52
- // In normal usage this is impossible — the check runs in every
53
- // child constructor before the reference becomes available.
52
+ // In normal usage this is impossible — the check runs in every child
53
+ // constructor before the reference becomes available.
54
54
  Object.defineProperty(mut_childA, 'parents', {
55
55
  value: [childB],
56
56
  writable: false,
@@ -31,17 +31,16 @@ export type SyncChildObservableTools<A> = Readonly<{
31
31
  complete: () => void;
32
32
 
33
33
  /**
34
- * Completes this observable once the update now propagating has reached
35
- * every descendant, so that they see the value just passed on first.
34
+ * Completes this observable once the update now propagating has reached every
35
+ * descendant, so that they see the value just passed on first.
36
36
  */
37
37
  completeAfterPropagation: () => void;
38
38
 
39
39
  /**
40
40
  * Registers a teardown (clear timers, unsubscribe inner observables, …) to
41
- * run when this observable completes or is disposed, in the order
42
- * registered. Called from `init`, it lets the teardown close over what
43
- * `init` creates. Registered once the observable has completed, the
44
- * teardown runs at once.
41
+ * run when this observable completes or is disposed, in the order registered.
42
+ * Called from `init`, it lets the teardown close over what `init` creates.
43
+ * Registered once the observable has completed, the teardown runs at once.
45
44
  */
46
45
  onComplete: (teardown: () => void) => void;
47
46
  }>;
@@ -57,21 +56,20 @@ export type AsyncChildObservableTools<A> = Readonly<{
57
56
  SyncChildObservableTools<A>;
58
57
 
59
58
  /**
60
- * What a sync child's `init` may return instead of `tryUpdate` alone: the
61
- * hooks the factory calls, which read the state `init` creates.
59
+ * What a sync child's `init` may return instead of `tryUpdate` alone: the hooks
60
+ * the factory calls, which read the state `init` creates.
62
61
  */
63
62
  export type SyncChildObservableHooks = Readonly<{
64
63
  /**
65
- * Called with the token of every update in which a parent of this
66
- * observable emitted.
64
+ * Called with the token of every update in which a parent of this observable
65
+ * emitted.
67
66
  */
68
67
  tryUpdate: (updateToken: UpdateToken) => void;
69
68
 
70
69
  /**
71
- * Whether this observable can emit nothing more although some parent is
72
- * still live, asked whenever a parent completes. `true` completes it then,
73
- * as all parents completing does (`zip` once a completed source's queue is
74
- * empty).
70
+ * Whether this observable can emit nothing more although some parent is still
71
+ * live, asked whenever a parent completes. `true` completes it then, as all
72
+ * parents completing does (`zip` once a completed source's queue is empty).
75
73
  */
76
74
  canEmitNoMore?: () => boolean;
77
75
  }>;
@@ -84,8 +82,8 @@ export type SyncChildObservableHooks = Readonly<{
84
82
  export type AsyncChildObservableHooks = SyncChildObservableHooks &
85
83
  Readonly<{
86
84
  /**
87
- * Run at the beginning of `complete()`, before the teardowns, and never
88
- * by `dispose()`: passes on what this observable still holds through
85
+ * Run at the beginning of `complete()`, before the teardowns, and never by
86
+ * `dispose()`: passes on what this observable still holds through
89
87
  * `startUpdate`, so that its subscribers see it before they see the
90
88
  * completion. A disposed observable has no one left to tell.
91
89
  */
@@ -96,11 +94,11 @@ type ChildObservableConfigBase<P extends NonEmptyUnknownList> = Readonly<{
96
94
  parents: Wrap<P>;
97
95
 
98
96
  /**
99
- * Defaults to one more than the deepest parent. An update reaches
100
- * observables in ascending depth, so an observable `tryUpdate` reads with
101
- * `getSnapshot` without being its child (`withCurrentValueFrom`'s second
102
- * source) has to be shallower than this one too, or this one reads its value
103
- * from before the update: pass `1 + Math.max(...)` over both then.
97
+ * Defaults to one more than the deepest parent. An update reaches observables
98
+ * in ascending depth, so an observable `tryUpdate` reads with `getSnapshot`
99
+ * without being its child (`withCurrentValueFrom`'s second source) has to be
100
+ * shallower than this one too, or this one reads its value from before the
101
+ * update: pass `1 + Math.max(...)` over both then.
104
102
  */
105
103
  depth?: number;
106
104
  }>;
@@ -122,15 +120,15 @@ export type InitializedChildObservableConfig<
122
120
  }>;
123
121
 
124
122
  /**
125
- * Creates a sync-child observable: one derived from `parents` that emits, if
126
- * at all, in the same update as they do. `map`, `filter`, `combine` and the
127
- * other synchronous operators are built with it.
123
+ * Creates a sync-child observable: one derived from `parents` that emits, if at
124
+ * all, in the same update as they do. `map`, `filter`, `combine` and the other
125
+ * synchronous operators are built with it.
128
126
  *
129
127
  * `init` runs during construction and receives the tools. It returns
130
128
  * `tryUpdate`, which is called with the token of every update in which some
131
- * parent of this observable emitted — a parent that did not emit in that
132
- * update has a different `updateToken`; to emit, call `setNext` with the
133
- * token received — or an object holding `tryUpdate` and the other hooks
129
+ * parent of this observable emitted — a parent that did not emit in that update
130
+ * has a different `updateToken`; to emit, call `setNext` with the token
131
+ * received — or an object holding `tryUpdate` and the other hooks
134
132
  * ({@link SyncChildObservableHooks}). State the hooks share can live inside
135
133
  * `init`, next to the teardown it registers with the `onComplete` tool.
136
134
  * `init` may complete the observable; it is then never registered to its
@@ -211,8 +209,8 @@ export const createInitializedSyncChildObservable = <
211
209
  * Creates an async-child observable: one derived from `parents` that may emit
212
210
  * later, in an update of its own, through `startUpdate` (`debounce`,
213
211
  * `switchMap`). It may also emit synchronously with `setNext`, as a sync child
214
- * does. See {@link createSyncChildObservable} for the `init` contract; an
215
- * async child's `init` may also return a `flush` hook
212
+ * does. See {@link createSyncChildObservable} for the `init` contract; an async
213
+ * child's `init` may also return a `flush` hook
216
214
  * ({@link AsyncChildObservableHooks}).
217
215
  */
218
216
  export const createAsyncChildObservable = <A, P extends NonEmptyUnknownList>(
@@ -8,8 +8,8 @@ import type { RootObservable } from '../types/index.mjs';
8
8
  import { RootObservableClass } from './root-observable-class.mjs';
9
9
 
10
10
  /**
11
- * The tools a custom root's `init` receives: the `protected` methods a
12
- * subclass of `RootObservableClass` inherits.
11
+ * The tools a custom root's `init` receives: the `protected` methods a subclass
12
+ * of `RootObservableClass` inherits.
13
13
  */
14
14
  export type RootObservableTools<A> = Readonly<{
15
15
  /** Emits `nextValue` and propagates the update to all descendants. */
@@ -23,9 +23,9 @@ export type RootObservableTools<A> = Readonly<{
23
23
  complete: () => void;
24
24
 
25
25
  /**
26
- * Registers a teardown (clear timers, abort requests, remove listeners, …)
27
- * to run at the beginning of `complete()`, in the order registered. Called
28
- * from `init`, it lets the teardown close over what `init` creates.
26
+ * Registers a teardown (clear timers, abort requests, remove listeners, …) to
27
+ * run at the beginning of `complete()`, in the order registered. Called from
28
+ * `init`, it lets the teardown close over what `init` creates.
29
29
  * Registered once the observable has completed — `init` may complete it
30
30
  * synchronously first — the teardown runs at once.
31
31
  */
@@ -37,13 +37,13 @@ export type RootObservableConfig<A> = Readonly<{
37
37
  }>;
38
38
 
39
39
  /**
40
- * Creates a root observable, for a custom creator written without a class
41
- * of its own.
40
+ * Creates a root observable, for a custom creator written without a class of
41
+ * its own.
42
42
  *
43
- * `init` runs during construction, receives the tools, and returns extra
44
- * public members to merge into the observable (e.g. `next` for a source,
45
- * `start` for a timer). It may register asynchronous callbacks that use the
46
- * tools, and may call `complete` synchronously.
43
+ * `init` runs during construction, receives the tools, and returns extra public
44
+ * members to merge into the observable (e.g. `next` for a source, `start` for a
45
+ * timer). It may register asynchronous callbacks that use the tools, and may
46
+ * call `complete` synchronously.
47
47
  */
48
48
  export const createRootObservable = <
49
49
  A,
@@ -12,12 +12,12 @@ import {
12
12
  } from './propagation-state.mjs';
13
13
 
14
14
  /**
15
- * The base of the observables that start updates of their own: a root, and
16
- * an async child (`debounce`, `switchMap`), which emits later than its
17
- * parents do. Its update visits, shallowest first, the nodes its value
18
- * reaches: each node that emits puts its children in the update's queue
19
- * (`propagation-state.mts`), so that each sees its parents' values of that
20
- * update (no glitch) and a node no value reached is not visited.
15
+ * The base of the observables that start updates of their own: a root, and an
16
+ * async child (`debounce`, `switchMap`), which emits later than its parents do.
17
+ * Its update visits, shallowest first, the nodes its value reaches: each node
18
+ * that emits puts its children in the update's queue (`propagation-state.mts`),
19
+ * so that each sees its parents' values of that update (no glitch) and a node
20
+ * no value reached is not visited.
21
21
  */
22
22
  export class ManagerObservableClass<
23
23
  A,
@@ -26,9 +26,9 @@ export class ManagerObservableClass<
26
26
  > extends ObservableBaseClass<A, Kind, Depth> {
27
27
  /** Emits `nextValue` and propagates it to the descendants. */
28
28
  protected startUpdate(nextValue: A): void {
29
- // Nothing to propagate to (a branch no `switchMap` follows, a state
30
- // written before anything subscribes): the update is the value alone,
31
- // and opening one would cost more than storing it.
29
+ // Nothing to propagate to (a branch no `switchMap` follows, a state written
30
+ // before anything subscribes): the update is the value alone, and opening
31
+ // one would cost more than storing it.
32
32
  if (this.setNextIfUnobserved(nextValue)) {
33
33
  return;
34
34
  }
@@ -37,9 +37,9 @@ export class ManagerObservableClass<
37
37
 
38
38
  beginPropagation(updateToken);
39
39
 
40
- // A subscriber or projection may throw, and the depth has to come back
41
- // down regardless, or every later write would warn. The exception itself
42
- // is not caught: it reaches the caller of `next` as it always has.
40
+ // A subscriber or projection may throw, and the depth has to come back down
41
+ // regardless, or every later write would warn. The exception itself is not
42
+ // caught: it reaches the caller of `next` as it always has.
43
43
  // @sumi-expect-error exceptions/no-try
44
44
  try {
45
45
  this.setNext(nextValue, updateToken);
@@ -1,6 +1,6 @@
1
1
  // Sumi bans classes, `this`, method syntax and writes to `this` outside a
2
- // `mut_` binding. The observables are classes (why is on
3
- // `ObservableBaseClass` below), so those four rules are waived here (D-63).
2
+ // `mut_` binding. The observables are classes (why is on `ObservableBaseClass`
3
+ // below), so those four 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
@@ -35,25 +35,23 @@ import { enqueueChildren } from './propagation-state.mjs';
35
35
  /**
36
36
  * The base of every observable, and the reason an observable is a class.
37
37
  *
38
- * A node is created for every derived value of a UI, so creating one has to
39
- * be cheap, and most of its cost was its methods: each observable used to be
40
- * a set of closures made for it, a dozen or more per node (#2421). Sharing
41
- * the methods among all nodes removes that cost, and a shared method has to
42
- * read the node it is called on from `this`. Once `this` is unavoidable, a
43
- * class is the plainest way to say it: the methods live once on the
44
- * prototype, `this` is typed, a creator or operator is a subclass that
45
- * overrides `tryUpdate` (and `flush` / `teardown` where it holds something),
46
- * and assigning every field in the constructor gives the nodes of one class
47
- * one shape for V8. The collections (`children`, subscribers) are made when
48
- * the first one arrives.
38
+ * A node is created for every derived value of a UI, so creating one has to be
39
+ * cheap, and most of its cost was its methods: each observable used to be a set
40
+ * of closures made for it, a dozen or more per node (#2421). Sharing the
41
+ * methods among all nodes removes that cost, and a shared method has to read
42
+ * the node it is called on from `this`. Once `this` is unavoidable, a class is
43
+ * the plainest way to say it: the methods live once on the prototype, `this` is
44
+ * typed, a creator or operator is a subclass that overrides `tryUpdate` (and
45
+ * `flush` / `teardown` where it holds something), and assigning every field in
46
+ * the constructor gives the nodes of one class one shape for V8. The
47
+ * collections (`children`, subscribers) are made when the first one arrives.
49
48
  *
50
49
  * The methods read the observable they are called on, so taking one off it
51
50
  * (`const { subscribe } = obs$`) is not supported.
52
51
  *
53
- * A node reaches another node only through its methods and its public
54
- * fields, never through a `#private` one: the other node may be an instance
55
- * of another copy of synstate in the same program, whose classes are not
56
- * these.
52
+ * A node reaches another node only through its methods and its public fields,
53
+ * never through a `#private` one: the other node may be an instance of another
54
+ * copy of synstate in the same program, whose classes are not these.
57
55
  */
58
56
  export class ObservableBaseClass<
59
57
  A,
@@ -144,8 +142,8 @@ export class ObservableBaseClass<
144
142
  }
145
143
 
146
144
  addChild(child: ChildNode): void {
147
- // A set, not an array: a completed child removes itself, and that has to
148
- // be O(1) for a UI that creates and completes derived nodes on every mount.
145
+ // A set, not an array: a completed child removes itself, and that has to be
146
+ // O(1) for a UI that creates and completes derived nodes on every mount.
149
147
  if (this.#mut_children === undefined) {
150
148
  this.#mut_children = new Set<ChildNode>([child]);
151
149
  } else {
@@ -158,10 +156,10 @@ export class ObservableBaseClass<
158
156
  }
159
157
 
160
158
  /**
161
- * Stores `nextValue` as the current value, queues the children for the
162
- * update `updateToken`, and notifies subscribers. The children are queued
163
- * first, so that a child a subscriber creates, which starts from this
164
- * value, is not visited for it again.
159
+ * Stores `nextValue` as the current value, queues the children for the update
160
+ * `updateToken`, and notifies subscribers. The children are queued first, so
161
+ * that a child a subscriber creates, which starts from this value, is not
162
+ * visited for it again.
165
163
  */
166
164
  protected setNext(nextValue: A, updateToken: UpdateToken): void {
167
165
  this.#mut_updateToken = updateToken;
@@ -180,11 +178,11 @@ export class ObservableBaseClass<
180
178
  }
181
179
 
182
180
  /**
183
- * Stores `nextValue` and returns `true` when nothing observes this
184
- * observable — no child to queue and no subscriber to call — so that the
185
- * caller need not open an update; returns `false`, storing nothing,
186
- * otherwise. The value still gets a token of its own, so that whoever
187
- * stored the last one sees that it emitted.
181
+ * Stores `nextValue` and returns `true` when nothing observes this observable
182
+ * — no child to queue and no subscriber to call — so that the caller need not
183
+ * open an update; returns `false`, storing nothing, otherwise. The value
184
+ * still gets a token of its own, so that whoever stored the last one sees
185
+ * that it emitted.
188
186
  */
189
187
  protected setNextIfUnobserved(nextValue: A): boolean {
190
188
  if (this.hasChild || this.hasSubscriber) {
@@ -220,9 +218,9 @@ export class ObservableBaseClass<
220
218
 
221
219
  /**
222
220
  * Completes the observable: an async child first passes on what it still
223
- * holds (`flush`), then it is disposed. Completing never reaches the
224
- * parents: an upstream observable may be shared, and only whoever owns it
225
- * decides when it ends (#2133).
221
+ * holds (`flush`), then it is disposed. Completing never reaches the parents:
222
+ * an upstream observable may be shared, and only whoever owns it decides when
223
+ * it ends (#2133).
226
224
  */
227
225
  complete(): void {
228
226
  if (this.#mut_isCompleted) {
@@ -235,8 +233,8 @@ export class ObservableBaseClass<
235
233
  }
236
234
 
237
235
  /**
238
- * Completes the observable without passing on anything it still holds,
239
- * runs its teardown, and takes it out of the graph.
236
+ * Completes the observable without passing on anything it still holds, runs
237
+ * its teardown, and takes it out of the graph.
240
238
  */
241
239
  dispose(): void {
242
240
  // A completed node is reached again through every parent that completes
@@ -275,8 +273,8 @@ export class ObservableBaseClass<
275
273
  }
276
274
 
277
275
  /**
278
- * Passes on what the observable still holds, at the beginning of
279
- * `complete()` and never in `dispose()` (`debounce`'s pending value).
276
+ * Passes on what the observable still holds, at the beginning of `complete()`
277
+ * and never in `dispose()` (`debounce`'s pending value).
280
278
  */
281
279
  // eslint-disable-next-line @typescript-eslint/class-methods-use-this
282
280
  protected flush(): void {}
@@ -38,10 +38,9 @@ export type ChildNode = NodeInternals &
38
38
  }>;
39
39
 
40
40
  /**
41
- * The one place a public observable is seen as the node it is. Every
42
- * observable is built by a synstate class, and the public types carry a
43
- * brand an object literal cannot supply, so this holds for every value of
44
- * those types.
41
+ * The one place a public observable is seen as the node it is. Every observable
42
+ * is built by a synstate class, and the public types carry a brand an object
43
+ * literal cannot supply, so this holds for every value of those types.
45
44
  */
46
45
  export const toNode = <A,>(observable: Observable<A>): ObservableNode<A> =>
47
46
  // @sumi-expect-error banned-syntax/no-unsafe-type-assertion