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.
- package/README.md +4 -4
- package/dist/core/authoring.d.mts +3 -3
- package/dist/core/class/child-observable-class.d.mts +24 -25
- package/dist/core/class/child-observable-class.d.mts.map +1 -1
- package/dist/core/class/child-observable-class.mjs +41 -42
- package/dist/core/class/child-observable-class.mjs.map +1 -1
- package/dist/core/class/create-child-observable.d.mts +27 -29
- package/dist/core/class/create-child-observable.d.mts.map +1 -1
- package/dist/core/class/create-child-observable.mjs.map +1 -1
- package/dist/core/class/create-root-observable.d.mts +11 -11
- package/dist/core/class/manager-observable-class.d.mts +6 -6
- package/dist/core/class/manager-observable-class.d.mts.map +1 -1
- package/dist/core/class/manager-observable-class.mjs +6 -0
- package/dist/core/class/manager-observable-class.mjs.map +1 -1
- package/dist/core/class/observable-base-class.d.mts +32 -26
- package/dist/core/class/observable-base-class.d.mts.map +1 -1
- package/dist/core/class/observable-base-class.mjs +16 -3
- package/dist/core/class/observable-base-class.mjs.map +1 -1
- package/dist/core/class/observable-node.d.mts +3 -4
- package/dist/core/class/observable-node.d.mts.map +1 -1
- package/dist/core/class/observable-node.mjs +0 -1
- package/dist/core/class/observable-node.mjs.map +1 -1
- package/dist/core/class/propagation-state.d.mts +10 -9
- package/dist/core/class/propagation-state.d.mts.map +1 -1
- package/dist/core/class/propagation-state.mjs +4 -2
- package/dist/core/class/propagation-state.mjs.map +1 -1
- package/dist/core/class/root-observable-class.d.mts +4 -4
- package/dist/core/combine/derive.d.mts +7 -8
- package/dist/core/combine/derive.d.mts.map +1 -1
- package/dist/core/combine/derive.mjs +0 -1
- package/dist/core/combine/derive.mjs.map +1 -1
- package/dist/core/combine/merge.mjs.map +1 -1
- package/dist/core/combine/zip.d.mts +3 -3
- package/dist/core/combine/zip.mjs.map +1 -1
- package/dist/core/create/counter.d.mts +3 -3
- package/dist/core/create/counter.mjs.map +1 -1
- package/dist/core/create/from-abortable-promise.mjs.map +1 -1
- package/dist/core/create/from-promise.mjs.map +1 -1
- package/dist/core/create/from-subscribable.mjs.map +1 -1
- package/dist/core/create/source.mjs.map +1 -1
- package/dist/core/create/timer.mjs.map +1 -1
- package/dist/core/operators/audit.mjs.map +1 -1
- package/dist/core/operators/debounce.mjs.map +1 -1
- package/dist/core/operators/filter.mjs.map +1 -1
- package/dist/core/operators/keep-equal-parts.d.mts +14 -15
- package/dist/core/operators/keep-equal-parts.d.mts.map +1 -1
- package/dist/core/operators/keep-equal-parts.mjs +0 -1
- package/dist/core/operators/keep-equal-parts.mjs.map +1 -1
- package/dist/core/operators/map.mjs.map +1 -1
- package/dist/core/operators/merge-map.d.mts +3 -3
- package/dist/core/operators/merge-map.mjs.map +1 -1
- package/dist/core/operators/pairwise.mjs.map +1 -1
- package/dist/core/operators/scan.mjs.map +1 -1
- package/dist/core/operators/skip-if-no-change.mjs.map +1 -1
- package/dist/core/operators/skip-until.mjs.map +1 -1
- package/dist/core/operators/skip-while.mjs.map +1 -1
- package/dist/core/operators/switch-map.mjs.map +1 -1
- package/dist/core/operators/take-until.mjs.map +1 -1
- package/dist/core/operators/take-while.mjs.map +1 -1
- package/dist/core/operators/take.mjs.map +1 -1
- package/dist/core/operators/throttle.mjs.map +1 -1
- package/dist/core/operators/with-buffered-from.mjs.map +1 -1
- package/dist/core/operators/with-current-value-from.mjs.map +1 -1
- package/dist/core/operators/with-initial-value.mjs.map +1 -1
- package/dist/core/predefined/operators/attach-index.mjs.map +1 -1
- package/dist/core/predefined/operators/map-to.d.mts +3 -4
- package/dist/core/predefined/operators/map-to.d.mts.map +1 -1
- package/dist/core/predefined/operators/map-to.mjs +0 -1
- package/dist/core/predefined/operators/map-to.mjs.map +1 -1
- package/dist/core/scope/scope.d.mts +4 -4
- package/dist/core/types/id.d.mts +2 -1
- package/dist/core/types/id.d.mts.map +1 -1
- package/dist/core/types/observable-family.d.mts.map +1 -1
- package/dist/core/types/observable-family.mjs.map +1 -1
- package/dist/core/types/observable.d.mts +7 -6
- package/dist/core/types/observable.d.mts.map +1 -1
- package/dist/core/types/observable.mjs.map +1 -1
- package/dist/core/utils/current-scope.d.mts +6 -6
- package/dist/core/utils/id-maker.d.mts +7 -0
- package/dist/core/utils/id-maker.d.mts.map +1 -1
- package/dist/core/utils/id-maker.mjs +9 -0
- package/dist/core/utils/id-maker.mjs.map +1 -1
- package/dist/core/utils/observable-brand.d.mts +5 -5
- package/dist/utils/create-boolean-state.d.mts +2 -2
- package/dist/utils/create-reducer.d.mts +20 -20
- package/dist/utils/create-reducer.d.mts.map +1 -1
- package/dist/utils/create-reducer.mjs +4 -16
- package/dist/utils/create-reducer.mjs.map +1 -1
- package/dist/utils/create-state.d.mts +3 -3
- package/dist/utils/create-state.d.mts.map +1 -1
- package/dist/utils/create-state.mjs +10 -13
- package/dist/utils/create-state.mjs.map +1 -1
- package/dist/utils/state-source.d.mts +19 -0
- package/dist/utils/state-source.d.mts.map +1 -0
- package/dist/utils/state-source.mjs +31 -0
- package/dist/utils/state-source.mjs.map +1 -0
- package/package.json +10 -10
- package/src/core/authoring.mts +3 -3
- package/src/core/class/child-observable-class.mts +86 -87
- package/src/core/class/circular-dependency-comparison.test.mts +2 -2
- package/src/core/class/create-child-observable.mts +27 -29
- package/src/core/class/create-root-observable.mts +11 -11
- package/src/core/class/manager-observable-class.mts +16 -9
- package/src/core/class/observable-base-class.mts +48 -30
- package/src/core/class/observable-node.mts +3 -4
- package/src/core/class/propagation-state.mts +31 -29
- package/src/core/class/remove-completed.test.mts +2 -2
- package/src/core/class/root-observable-class.mts +9 -9
- package/src/core/class/unobserved-write.test.mts +194 -0
- package/src/core/combine/derive.mts +10 -11
- package/src/core/combine/merge.mts +2 -2
- package/src/core/combine/zip.mts +7 -7
- package/src/core/create/counter.mts +5 -5
- package/src/core/create/from-abortable-promise.mts +2 -2
- package/src/core/create/from-promise.mts +2 -2
- package/src/core/create/from-subscribable.mts +2 -2
- package/src/core/create/source.mts +5 -5
- package/src/core/create/timer.mts +2 -2
- package/src/core/operators/audit.mts +2 -2
- package/src/core/operators/debounce.mts +2 -2
- package/src/core/operators/filter.mts +4 -4
- package/src/core/operators/keep-equal-parts.mts +16 -17
- package/src/core/operators/map.mts +2 -2
- package/src/core/operators/merge-map.mts +5 -5
- package/src/core/operators/pairwise.mts +4 -4
- package/src/core/operators/scan.mts +2 -2
- package/src/core/operators/skip-if-no-change.mts +4 -4
- package/src/core/operators/skip-until.mts +4 -4
- package/src/core/operators/skip-while.mts +2 -2
- package/src/core/operators/switch-map.mts +5 -5
- package/src/core/operators/take-until.mts +2 -2
- package/src/core/operators/take-while.mts +2 -2
- package/src/core/operators/take.mts +2 -2
- package/src/core/operators/throttle.mts +2 -2
- package/src/core/operators/with-buffered-from.mts +2 -2
- package/src/core/operators/with-current-value-from.mts +2 -2
- package/src/core/operators/with-initial-value.mts +2 -2
- package/src/core/predefined/operators/attach-index.mts +2 -2
- package/src/core/predefined/operators/map-to.mts +3 -4
- package/src/core/scope/scope.mts +6 -6
- package/src/core/types/id.mts +2 -1
- package/src/core/types/observable-family.mts +4 -5
- package/src/core/types/observable.mts +9 -8
- package/src/core/utils/current-scope.mts +8 -8
- package/src/core/utils/id-maker.mts +10 -0
- package/src/core/utils/observable-brand.mts +5 -5
- package/src/utils/create-boolean-state.mts +2 -2
- package/src/utils/create-reducer.mts +27 -42
- package/src/utils/create-state.mts +14 -31
- package/src/utils/create-state.test.mts +20 -2
- package/src/utils/state-source.mts +48 -0
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const reducer = (state, action) => {
|
|
3
|
-
switch (action.type) {
|
|
4
|
-
case 'set':
|
|
5
|
-
return action.nextState;
|
|
6
|
-
case 'update':
|
|
7
|
-
return action.updateFn(state);
|
|
8
|
-
}
|
|
9
|
-
};
|
|
1
|
+
import { createStateSource } from './state-source.mjs';
|
|
10
2
|
|
|
11
3
|
|
|
12
4
|
|
|
@@ -134,10 +126,15 @@ const reducer = (state, action) => {
|
|
|
134
126
|
|
|
135
127
|
|
|
136
128
|
export const createState = (initialState, options) => {
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
129
|
+
const { state, getSnapshot, commit } = createStateSource(initialState, options);
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
const updateState = (updateFn) => {
|
|
133
|
+
const currentState = getSnapshot();
|
|
134
|
+
return commit(currentState, updateFn(currentState));
|
|
135
|
+
};
|
|
136
|
+
const setState = (nextState) => commit(getSnapshot(), nextState);
|
|
137
|
+
const resetState = () => commit(getSnapshot(), initialState);
|
|
141
138
|
return [
|
|
142
139
|
state,
|
|
143
140
|
setState,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-state.mjs","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create-state.mjs","sourceRoot":"","sources":["../../src/utils/create-state.mts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6HG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,YAAe,EACf,OAAkC,EAUlC,EAAE;IACF,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,iBAAiB,CACtD,YAAY,EACZ,OAAO,CACR,CAAC;IAEF,2EAA2E;IAC3E,iCAAiC;IACjC,MAAM,WAAW,GAAG,CAAC,QAAwB,EAAK,EAAE;QAClD,MAAM,YAAY,GAAG,WAAW,EAAE,CAAC;QAEnC,OAAO,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,CAAC,SAAY,EAAK,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,SAAS,CAAC,CAAC;IAEvE,MAAM,UAAU,GAAG,GAAM,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,YAAY,CAAC,CAAC;IAEhE,OAAO;QACL,KAAK;QACL,QAAQ;QACR;YACE,WAAW;YACX,UAAU;YACV,WAAW;YACX,YAAY;SACb;KACO,CAAC;AACb,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type InitializedSourceObservable } from '../core/index.mjs';
|
|
2
|
+
import type { StateOptions } from './create-reducer.mjs';
|
|
3
|
+
/**
|
|
4
|
+
* What `createState` and `createReducer` are both built on: the source holding
|
|
5
|
+
* the state, its current value, and `commit`, the one way either writes it.
|
|
6
|
+
* `commit` writes `reduced` unless `equals` finds it the same as
|
|
7
|
+
* `currentState`, after keeping the parts of `currentState` it did not change
|
|
8
|
+
* when `keepEqualParts` asks for that, and returns the state written, or
|
|
9
|
+
* `currentState` when nothing was.
|
|
10
|
+
*
|
|
11
|
+
* Not part of the package's API: `gen:index:src` leaves this file out of the
|
|
12
|
+
* barrel.
|
|
13
|
+
*/
|
|
14
|
+
export declare const createStateSource: <S>(initialState: S, options: StateOptions<S> | undefined) => Readonly<{
|
|
15
|
+
state: InitializedSourceObservable<S>;
|
|
16
|
+
getSnapshot: () => S;
|
|
17
|
+
commit: (currentState: S, reduced: S) => S;
|
|
18
|
+
}>;
|
|
19
|
+
//# sourceMappingURL=state-source.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-source.d.mts","sourceRoot":"","sources":["../../src/utils/state-source.mts"],"names":[],"mappings":"AACA,OAAO,EAAU,KAAK,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,gBACnB,CAAC,WACN,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,KACnC,QAAQ,CAAC;IACV,KAAK,EAAE,2BAA2B,CAAC,CAAC,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;CAC5C,CAyBA,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { replaceEqualDeep } from 'ts-data-forge';
|
|
2
|
+
import { source } from '../core/index.mjs';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export const createStateSource = (initialState, options) => {
|
|
15
|
+
const state = source(initialState);
|
|
16
|
+
const getSnapshot = () => state.getSnapshot().value;
|
|
17
|
+
const equals = options?.equals ?? Object.is;
|
|
18
|
+
const keepEqualParts = options?.keepEqualParts ?? false;
|
|
19
|
+
const keepOptions = typeof keepEqualParts === 'boolean' ? undefined : keepEqualParts;
|
|
20
|
+
const commit = (currentState, reduced) => {
|
|
21
|
+
const nextState = keepEqualParts === false
|
|
22
|
+
? reduced
|
|
23
|
+
: replaceEqualDeep(currentState, reduced, keepOptions);
|
|
24
|
+
|
|
25
|
+
return equals(currentState, nextState)
|
|
26
|
+
? currentState
|
|
27
|
+
: state.next(nextState);
|
|
28
|
+
};
|
|
29
|
+
return { state, getSnapshot, commit };
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=state-source.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-source.mjs","sourceRoot":"","sources":["../../src/utils/state-source.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,MAAM,EAAoC,MAAM,mBAAmB,CAAC;AAG7E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,YAAe,EACf,OAAoC,EAKnC,EAAE;IACH,MAAM,KAAK,GAAG,MAAM,CAAI,YAAY,CAAC,CAAC;IAEtC,MAAM,WAAW,GAAG,GAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC;IAEvD,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC;IAE5C,MAAM,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,KAAK,CAAC;IAExD,MAAM,WAAW,GACf,OAAO,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC;IAEnE,MAAM,MAAM,GAAG,CAAC,YAAe,EAAE,OAAU,EAAK,EAAE;QAChD,MAAM,SAAS,GACb,cAAc,KAAK,KAAK;YACtB,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,gBAAgB,CAAC,YAAY,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QAE3D,8DAA8D;QAC9D,OAAO,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC;YACpC,CAAC,CAAC,YAAY;YACd,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC,CAAC;IAEF,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "synstate",
|
|
3
|
-
"version": "6.1
|
|
3
|
+
"version": "6.2.1",
|
|
4
4
|
"description": "Type-safe State Management Library for TypeScript/JavaScript",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,21 +29,21 @@
|
|
|
29
29
|
"LICENSE"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"ts-data-forge": "^14.10.
|
|
32
|
+
"ts-data-forge": "^14.10.2",
|
|
33
33
|
"ts-std-forge": "^0.5.2",
|
|
34
34
|
"ts-type-forge": "^9.2.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@preact/signals-core": "1.14.4",
|
|
38
38
|
"@reduxjs/toolkit": "2.13.0",
|
|
39
|
-
"@sumi-lang/cli": "0.1.
|
|
39
|
+
"@sumi-lang/cli": "0.1.5",
|
|
40
40
|
"@types/react": "19.3.0",
|
|
41
41
|
"@vitest/browser-playwright": "5.0.5",
|
|
42
42
|
"argparse": "3.0.3",
|
|
43
|
-
"eslint-config-typed": "
|
|
44
|
-
"eslint-plugin-ts-data-forge": "0.10.
|
|
45
|
-
"eslint-plugin-ts-fortress": "1.3.
|
|
46
|
-
"eslint-plugin-ts-type-forge": "0.8.
|
|
43
|
+
"eslint-config-typed": "7.3.1",
|
|
44
|
+
"eslint-plugin-ts-data-forge": "0.10.8",
|
|
45
|
+
"eslint-plugin-ts-fortress": "1.3.12",
|
|
46
|
+
"eslint-plugin-ts-type-forge": "0.8.17",
|
|
47
47
|
"jotai": "3.0.1",
|
|
48
48
|
"mobx": "7.1.0",
|
|
49
49
|
"playwright": "1.64.1",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"react": "19.3.1",
|
|
54
54
|
"rxjs": "7.8.2",
|
|
55
55
|
"solid-js": "1.9.17",
|
|
56
|
-
"synstate-react-hooks": "6.1
|
|
57
|
-
"synstate-react-hooks-compat": "6.1
|
|
56
|
+
"synstate-react-hooks": "6.2.1",
|
|
57
|
+
"synstate-react-hooks-compat": "6.2.1",
|
|
58
58
|
"ts-repo-utils": "10.7.1",
|
|
59
59
|
"valtio": "2.3.2",
|
|
60
60
|
"zustand": "5.0.15"
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"fmt": "pnpm run fix:fmt",
|
|
86
86
|
"gen": "run-s gen:index gen:readme gen:jsdoc gen:sample-diffs",
|
|
87
87
|
"gen:index": "run-s gen:index:src fix:fmt",
|
|
88
|
-
"gen:index:src": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/gen-index-ts.mts ./src --index-ext .mts --export-ext .mjs --target-ext .mts --target-ext .tsx --exclude entry-point.mts --exclude \"core/class/**\" --exclude \"core/utils/**\"",
|
|
88
|
+
"gen:index:src": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ../../libs/ts-repo-utils/src/cmd/gen-index-ts.mts ./src --index-ext .mts --export-ext .mjs --target-ext .mts --target-ext .tsx --exclude entry-point.mts --exclude \"core/class/**\" --exclude \"core/utils/**\" --exclude utils/state-source.mts",
|
|
89
89
|
"gen:jsdoc": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/embed-examples-in-jsdoc.mts",
|
|
90
90
|
"gen:readme": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/embed-examples.mts",
|
|
91
91
|
"gen:sample-diffs": "tsx --tsconfig ../../tools/configs/tsconfig.tsx.json ./scripts/cmd/generate-sample-diffs.mts",
|
package/src/core/authoring.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What custom creators and operators are written with:
|
|
3
|
-
* built-in
|
|
4
|
-
* internal.
|
|
2
|
+
* What custom creators and operators are written with: factories that wrap the
|
|
3
|
+
* base classes the built-in observables extend (#2117). The rest of `core/base`
|
|
4
|
+
* stays internal.
|
|
5
5
|
*/
|
|
6
6
|
export {
|
|
7
7
|
createAsyncChildObservable,
|
|
@@ -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
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
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
|
-
*
|
|
50
|
-
*
|
|
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
|
-
*
|
|
112
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
209
|
-
* projection, so it joins the propagation in progress like a sync
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
292
|
-
*
|
|
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
|
-
//
|
|
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
|
-
*
|
|
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
|
-
*
|
|
43
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
73
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
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
|
-
*
|
|
127
|
-
*
|
|
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
|
-
*
|
|
133
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
28
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
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
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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,13 +26,20 @@ 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 written
|
|
30
|
+
// before anything subscribes): the update is the value alone, and opening
|
|
31
|
+
// one would cost more than storing it.
|
|
32
|
+
if (this.setNextIfUnobserved(nextValue)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
const updateToken = openUpdate(this.depth);
|
|
30
37
|
|
|
31
38
|
beginPropagation(updateToken);
|
|
32
39
|
|
|
33
|
-
// A subscriber or projection may throw, and the depth has to come back
|
|
34
|
-
//
|
|
35
|
-
//
|
|
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.
|
|
36
43
|
// @sumi-expect-error exceptions/no-try
|
|
37
44
|
try {
|
|
38
45
|
this.setNext(nextValue, updateToken);
|