@xmachines/play-actor 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -54
- package/dist/abstract-actor.d.ts +97 -89
- package/dist/abstract-actor.d.ts.map +1 -1
- package/dist/abstract-actor.js +34 -33
- package/dist/abstract-actor.js.map +1 -1
- package/dist/context-projection.d.ts +74 -67
- package/dist/context-projection.d.ts.map +1 -1
- package/dist/context-projection.js +90 -82
- package/dist/context-projection.js.map +1 -1
- package/dist/index.d.ts +11 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -9
- package/dist/index.js.map +1 -1
- package/dist/provider-guards.d.ts +37 -33
- package/dist/provider-guards.d.ts.map +1 -1
- package/dist/provider-guards.js +34 -30
- package/dist/provider-guards.js.map +1 -1
- package/dist/view-store-lifecycle.d.ts +46 -41
- package/dist/view-store-lifecycle.d.ts.map +1 -1
- package/dist/view-store-lifecycle.js +28 -25
- package/dist/view-store-lifecycle.js.map +1 -1
- package/package.json +4 -3
|
@@ -1,109 +1,116 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* view state store.
|
|
2
|
+
* The context projection — the machine context as the read-only `/context`
|
|
3
|
+
* subtree of the view state store.
|
|
4
4
|
*
|
|
5
|
-
* `deriveCurrentView` composes each emitted view
|
|
6
|
-
* `{ ...meta.view.state, context: <slice> }
|
|
7
|
-
* its `state`
|
|
8
|
-
* `visible.$state`, `$state`
|
|
9
|
-
* through the ordinary `{ $state: "/context/…" }` grammar.
|
|
5
|
+
* `deriveCurrentView` composes the `state` field of each emitted view as
|
|
6
|
+
* `{ ...meta.view.state, context: <slice> }`. The spec is therefore consistent with
|
|
7
|
+
* itself: its `state` field describes the contents of the store correctly, and
|
|
8
|
+
* `repeat.statePath`, `visible.$state`, a `$state` prop, and a validator all read
|
|
9
|
+
* the machine context through the ordinary `{ $state: "/context/…" }` grammar.
|
|
10
10
|
*
|
|
11
|
-
* The subtree is read-only **to the spec, not to the machinery**:
|
|
12
|
-
*
|
|
13
|
-
* {@link guardContextWrites},
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* The subtree is read-only **to the spec, and not to the machinery**: a provider
|
|
12
|
+
* gives the bindings and the action handlers a store with the wrapper of
|
|
13
|
+
* {@link guardContextWrites}, and it refreshes the projection through the store
|
|
14
|
+
* below that wrapper, which has no guard. The context changes through a machine
|
|
15
|
+
* event only. Therefore a write under `/context` is always a fault of the spec, and
|
|
16
|
+
* the guard says so.
|
|
16
17
|
*
|
|
17
18
|
* @packageDocumentation
|
|
18
19
|
*/
|
|
19
20
|
import type { StateStore } from "@xmachines/json-render-core";
|
|
20
21
|
import type { PlaySpec } from "./abstract-actor.js";
|
|
21
22
|
/**
|
|
22
|
-
* The reserved top-level state key the projection
|
|
23
|
+
* The reserved top-level state key of the projection.
|
|
23
24
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* warning
|
|
25
|
+
* The `spec.state` object of a view must not declare this key. When it does, the
|
|
26
|
+
* derivation skips the projection for that view, the authored state wins, and the
|
|
27
|
+
* code writes a warning in development. See {@link composePlayState}.
|
|
27
28
|
*/
|
|
28
29
|
export declare const CONTEXT_STATE_KEY = "context";
|
|
29
30
|
/**
|
|
30
|
-
*
|
|
31
|
+
* The shallow equality of the own keys, with `Object.is`. It can ignore one key on
|
|
31
32
|
* both sides.
|
|
32
33
|
*
|
|
33
|
-
*
|
|
34
|
-
* equality and the
|
|
35
|
-
* `viewSpecsEquivalent
|
|
34
|
+
* This is the one comparison rule behind every decision of the emission dedup: the
|
|
35
|
+
* equality of a slice, and also the emit gate of the player, which compares the
|
|
36
|
+
* spec fields in `viewSpecsEquivalent` and reuses the composed state in
|
|
37
|
+
* {@link reuseComposedState}.
|
|
36
38
|
*/
|
|
37
39
|
export declare function shallowEqualExcept(a: object, b: object, except?: string): boolean;
|
|
38
40
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
+
* Reuses the composed `state` of the previous emission, or the complete previous
|
|
42
|
+
* spec, when the value of the projection did not change.
|
|
41
43
|
*
|
|
42
|
-
* `deriveCurrentView` composes `state: { ...meta.view.state, context: slice }`
|
|
43
|
-
*
|
|
44
|
-
* every event
|
|
45
|
-
* reference and the
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* references are stable
|
|
44
|
+
* `deriveCurrentView` composes `state: { ...meta.view.state, context: slice }` new
|
|
45
|
+
* on each call, and the XState function `assign` makes a new context object on
|
|
46
|
+
* every event. Without this reuse, every event therefore presents a new `state`
|
|
47
|
+
* reference, and the `Object.is` test of each field in the emit gate emits the view
|
|
48
|
+
* again and remounts it, without an end. The function compares the slices field by
|
|
49
|
+
* field ({@link shallowEqualExcept}), because the XState function `assign` makes a
|
|
50
|
+
* new context object for each event, and a test of the identity of the whole object
|
|
51
|
+
* therefore reports a change every time. The authored fields come from the static
|
|
52
|
+
* `meta.view.state` through a spread. Therefore their references are stable for an
|
|
53
|
+
* unchanged `viewKey`, and a plain `Object.is` test is correct for them.
|
|
51
54
|
*
|
|
52
|
-
*
|
|
53
|
-
* - `prev` itself when nothing observable changed
|
|
54
|
-
*
|
|
55
|
-
* - `{ ...next, state: prev.state }
|
|
56
|
-
*
|
|
57
|
-
* - `next
|
|
55
|
+
* The function returns one of three values, in this order of preference:
|
|
56
|
+
* - `prev` itself, when nothing observable changed. The emit gate then stops at the
|
|
57
|
+
* identity of the reference, and it walks no element;
|
|
58
|
+
* - `{ ...next, state: prev.state }`, when the value of the state did not change
|
|
59
|
+
* but another top-level field is different;
|
|
60
|
+
* - `next`, when something changed.
|
|
58
61
|
*/
|
|
59
62
|
export declare function reuseComposedState(prev: PlaySpec | null, next: PlaySpec | null): PlaySpec | null;
|
|
60
63
|
/**
|
|
61
|
-
*
|
|
64
|
+
* Wraps a StateStore, and the wrapper refuses each write under `/context`.
|
|
62
65
|
*
|
|
63
|
-
*
|
|
64
|
-
* (`$bindState`, `setState`, chained `set`). The provider
|
|
65
|
-
* store
|
|
66
|
-
* to the machinery.
|
|
66
|
+
* A provider applies it to the store that it gives to the bindings and to the
|
|
67
|
+
* action handlers (`$bindState`, `setState`, and a chained `set`). The provider
|
|
68
|
+
* keeps the store without the wrapper, and it refreshes the projection through that
|
|
69
|
+
* store. The subtree is therefore read-only to the spec, and not to the machinery.
|
|
67
70
|
*
|
|
68
|
-
* A write
|
|
69
|
-
*
|
|
70
|
-
* the whole object back
|
|
71
|
-
* round
|
|
72
|
-
*
|
|
71
|
+
* A write with a value that is **identical** to the current value passes in
|
|
72
|
+
* silence. A handler in the style of `setState` reads the complete snapshot,
|
|
73
|
+
* changes it, and writes the whole object back. The `context` key that goes through
|
|
74
|
+
* that round trip without a change is no attempt of a mutation. Only a write that
|
|
75
|
+
* changes the subtree throws.
|
|
73
76
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* is
|
|
79
|
-
*
|
|
77
|
+
* Each read passes through without a change. The wrapper delegates every member
|
|
78
|
+
* explicitly, and it does not use a spread: a store from a consumer can be an
|
|
79
|
+
* instance of a class, and the methods of that instance are on the prototype. Those
|
|
80
|
+
* methods do not survive `{ ...store }`, and the first render then fails with
|
|
81
|
+
* `store.getSnapshot is not a function`. The code builds the wrapper one time for
|
|
82
|
+
* each resolved store. Therefore the identity of the delegating `getSnapshot` and
|
|
83
|
+
* of the delegating `subscribe` stays stable for a consumer in the style of
|
|
84
|
+
* `useSyncExternalStore`.
|
|
80
85
|
*
|
|
81
|
-
* @param store - The
|
|
82
|
-
* @returns A store with
|
|
86
|
+
* @param store - The store below the wrapper.
|
|
87
|
+
* @returns A store with a guard on `set` and on `update`.
|
|
83
88
|
*/
|
|
84
89
|
export declare function guardContextWrites(store: StateStore): StateStore;
|
|
85
90
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
+
* Refreshes the `/context` subtree of a live store from the composed state of a
|
|
92
|
+
* derived view. An emission with the same `viewKey` means that only the projection
|
|
93
|
+
* changed. The function therefore replaces the complete subtree, and it never
|
|
94
|
+
* merges it field by field, because `update` cannot delete a key. Every ephemeral
|
|
95
|
+
* value at the root level stays. The function does nothing when the view carries no
|
|
96
|
+
* slice, or when the store holds the slice already.
|
|
91
97
|
*
|
|
92
|
-
* @param store - The
|
|
93
|
-
* @param view - The derived view
|
|
98
|
+
* @param store - The store WITHOUT the guard. A provider refreshes through it.
|
|
99
|
+
* @param view - The derived view. Its `state.context` field carries the slice.
|
|
94
100
|
*/
|
|
95
101
|
export declare function refreshContextSubtree(store: StateStore, view: {
|
|
96
102
|
state?: unknown;
|
|
97
103
|
}): void;
|
|
98
104
|
/**
|
|
99
|
-
*
|
|
105
|
+
* Composes the effective state of a view: the authored `spec.state` and the
|
|
100
106
|
* `/context` slice.
|
|
101
107
|
*
|
|
102
|
-
* When the authored state
|
|
103
|
-
*
|
|
108
|
+
* When the authored state declares the reserved key already, the function skips the
|
|
109
|
+
* projection, the authored state wins, and the code writes a warning in
|
|
110
|
+
* development. No spec that exists now therefore fails.
|
|
104
111
|
*
|
|
105
|
-
* @param authoredState - The raw `meta.view.state`
|
|
106
|
-
* @param slice - The machine
|
|
112
|
+
* @param authoredState - The raw `meta.view.state` value. It can be anything, and the caller or toAtomState cleans it.
|
|
113
|
+
* @param slice - The context of the machine, as one complete value.
|
|
107
114
|
*/
|
|
108
115
|
export declare function composePlayState(authoredState: Record<string, unknown> | undefined, slice: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
|
|
109
116
|
//# sourceMappingURL=context-projection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-projection.d.ts","sourceRoot":"","sources":["../src/context-projection.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"context-projection.d.ts","sourceRoot":"","sources":["../src/context-projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAiB3C;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAUjF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,CAiBhG;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CA8ChE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAKxF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC/B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAClD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACxC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAcrC"}
|
|
@@ -1,36 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* view state store.
|
|
2
|
+
* The context projection — the machine context as the read-only `/context`
|
|
3
|
+
* subtree of the view state store.
|
|
4
4
|
*
|
|
5
|
-
* `deriveCurrentView` composes each emitted view
|
|
6
|
-
* `{ ...meta.view.state, context: <slice> }
|
|
7
|
-
* its `state`
|
|
8
|
-
* `visible.$state`, `$state`
|
|
9
|
-
* through the ordinary `{ $state: "/context/…" }` grammar.
|
|
5
|
+
* `deriveCurrentView` composes the `state` field of each emitted view as
|
|
6
|
+
* `{ ...meta.view.state, context: <slice> }`. The spec is therefore consistent with
|
|
7
|
+
* itself: its `state` field describes the contents of the store correctly, and
|
|
8
|
+
* `repeat.statePath`, `visible.$state`, a `$state` prop, and a validator all read
|
|
9
|
+
* the machine context through the ordinary `{ $state: "/context/…" }` grammar.
|
|
10
10
|
*
|
|
11
|
-
* The subtree is read-only **to the spec, not to the machinery**:
|
|
12
|
-
*
|
|
13
|
-
* {@link guardContextWrites},
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* The subtree is read-only **to the spec, and not to the machinery**: a provider
|
|
12
|
+
* gives the bindings and the action handlers a store with the wrapper of
|
|
13
|
+
* {@link guardContextWrites}, and it refreshes the projection through the store
|
|
14
|
+
* below that wrapper, which has no guard. The context changes through a machine
|
|
15
|
+
* event only. Therefore a write under `/context` is always a fault of the spec, and
|
|
16
|
+
* the guard says so.
|
|
16
17
|
*
|
|
17
18
|
* @packageDocumentation
|
|
18
19
|
*/
|
|
19
20
|
/**
|
|
20
|
-
* The reserved top-level state key the projection
|
|
21
|
+
* The reserved top-level state key of the projection.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* warning
|
|
23
|
+
* The `spec.state` object of a view must not declare this key. When it does, the
|
|
24
|
+
* derivation skips the projection for that view, the authored state wins, and the
|
|
25
|
+
* code writes a warning in development. See {@link composePlayState}.
|
|
25
26
|
*/
|
|
26
27
|
export const CONTEXT_STATE_KEY = "context";
|
|
27
28
|
/**
|
|
28
|
-
*
|
|
29
|
-
* property of the authored meta.view
|
|
30
|
-
* between events
|
|
31
|
-
*
|
|
32
|
-
* the
|
|
33
|
-
* with
|
|
29
|
+
* The record that reports each diagnostic one time for each spec. The condition
|
|
30
|
+
* here is a static property of the authored meta.view, because its `state` object
|
|
31
|
+
* never changes between two events. `deriveCurrentView` runs on every machine
|
|
32
|
+
* snapshot, and a report for each derivation therefore floods the console at the
|
|
33
|
+
* rate of the events. The key is the identity of the static object. Each spec
|
|
34
|
+
* therefore reports one time, and a test with a new literal stays separate.
|
|
34
35
|
*/
|
|
35
36
|
const reportedDiagnostics = new WeakSet();
|
|
36
37
|
function warnOnce(anchor, message) {
|
|
@@ -40,12 +41,13 @@ function warnOnce(anchor, message) {
|
|
|
40
41
|
console.warn(message);
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
43
|
-
*
|
|
44
|
+
* The shallow equality of the own keys, with `Object.is`. It can ignore one key on
|
|
44
45
|
* both sides.
|
|
45
46
|
*
|
|
46
|
-
*
|
|
47
|
-
* equality and the
|
|
48
|
-
* `viewSpecsEquivalent
|
|
47
|
+
* This is the one comparison rule behind every decision of the emission dedup: the
|
|
48
|
+
* equality of a slice, and also the emit gate of the player, which compares the
|
|
49
|
+
* spec fields in `viewSpecsEquivalent` and reuses the composed state in
|
|
50
|
+
* {@link reuseComposedState}.
|
|
49
51
|
*/
|
|
50
52
|
export function shallowEqualExcept(a, b, except) {
|
|
51
53
|
const aEntries = Object.entries(a).filter(([key]) => key !== except);
|
|
@@ -61,25 +63,26 @@ export function shallowEqualExcept(a, b, except) {
|
|
|
61
63
|
return true;
|
|
62
64
|
}
|
|
63
65
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
+
* Reuses the composed `state` of the previous emission, or the complete previous
|
|
67
|
+
* spec, when the value of the projection did not change.
|
|
66
68
|
*
|
|
67
|
-
* `deriveCurrentView` composes `state: { ...meta.view.state, context: slice }`
|
|
68
|
-
*
|
|
69
|
-
* every event
|
|
70
|
-
* reference and the
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* references are stable
|
|
69
|
+
* `deriveCurrentView` composes `state: { ...meta.view.state, context: slice }` new
|
|
70
|
+
* on each call, and the XState function `assign` makes a new context object on
|
|
71
|
+
* every event. Without this reuse, every event therefore presents a new `state`
|
|
72
|
+
* reference, and the `Object.is` test of each field in the emit gate emits the view
|
|
73
|
+
* again and remounts it, without an end. The function compares the slices field by
|
|
74
|
+
* field ({@link shallowEqualExcept}), because the XState function `assign` makes a
|
|
75
|
+
* new context object for each event, and a test of the identity of the whole object
|
|
76
|
+
* therefore reports a change every time. The authored fields come from the static
|
|
77
|
+
* `meta.view.state` through a spread. Therefore their references are stable for an
|
|
78
|
+
* unchanged `viewKey`, and a plain `Object.is` test is correct for them.
|
|
76
79
|
*
|
|
77
|
-
*
|
|
78
|
-
* - `prev` itself when nothing observable changed
|
|
79
|
-
*
|
|
80
|
-
* - `{ ...next, state: prev.state }
|
|
81
|
-
*
|
|
82
|
-
* - `next
|
|
80
|
+
* The function returns one of three values, in this order of preference:
|
|
81
|
+
* - `prev` itself, when nothing observable changed. The emit gate then stops at the
|
|
82
|
+
* identity of the reference, and it walks no element;
|
|
83
|
+
* - `{ ...next, state: prev.state }`, when the value of the state did not change
|
|
84
|
+
* but another top-level field is different;
|
|
85
|
+
* - `next`, when something changed.
|
|
83
86
|
*/
|
|
84
87
|
export function reuseComposedState(prev, next) {
|
|
85
88
|
if (!prev || !next || prev.viewKey !== next.viewKey)
|
|
@@ -106,40 +109,42 @@ export function reuseComposedState(prev, next) {
|
|
|
106
109
|
return shallowEqualExcept(prev, next, "state") ? prev : next;
|
|
107
110
|
}
|
|
108
111
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* JSON
|
|
112
|
+
* The paths of the reserved subtree: `"/context"` itself, and every path below it.
|
|
113
|
+
* An update map of the store can hold a bare top-level key ("context") and also a
|
|
114
|
+
* JSON Pointer ("/context/…"). Both forms address the same subtree.
|
|
112
115
|
*/
|
|
113
116
|
function toPointer(path) {
|
|
114
117
|
return path.startsWith("/") ? path : `/${path}`;
|
|
115
118
|
}
|
|
116
|
-
/**
|
|
119
|
+
/** This function expects a NORMALIZED pointer from {@link toPointer}. */
|
|
117
120
|
function isContextPointer(pointer) {
|
|
118
121
|
return pointer === `/${CONTEXT_STATE_KEY}` || pointer.startsWith(`/${CONTEXT_STATE_KEY}/`);
|
|
119
122
|
}
|
|
120
123
|
/**
|
|
121
|
-
*
|
|
124
|
+
* Wraps a StateStore, and the wrapper refuses each write under `/context`.
|
|
122
125
|
*
|
|
123
|
-
*
|
|
124
|
-
* (`$bindState`, `setState`, chained `set`). The provider
|
|
125
|
-
* store
|
|
126
|
-
* to the machinery.
|
|
126
|
+
* A provider applies it to the store that it gives to the bindings and to the
|
|
127
|
+
* action handlers (`$bindState`, `setState`, and a chained `set`). The provider
|
|
128
|
+
* keeps the store without the wrapper, and it refreshes the projection through that
|
|
129
|
+
* store. The subtree is therefore read-only to the spec, and not to the machinery.
|
|
127
130
|
*
|
|
128
|
-
* A write
|
|
129
|
-
*
|
|
130
|
-
* the whole object back
|
|
131
|
-
* round
|
|
132
|
-
*
|
|
131
|
+
* A write with a value that is **identical** to the current value passes in
|
|
132
|
+
* silence. A handler in the style of `setState` reads the complete snapshot,
|
|
133
|
+
* changes it, and writes the whole object back. The `context` key that goes through
|
|
134
|
+
* that round trip without a change is no attempt of a mutation. Only a write that
|
|
135
|
+
* changes the subtree throws.
|
|
133
136
|
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* is
|
|
139
|
-
*
|
|
137
|
+
* Each read passes through without a change. The wrapper delegates every member
|
|
138
|
+
* explicitly, and it does not use a spread: a store from a consumer can be an
|
|
139
|
+
* instance of a class, and the methods of that instance are on the prototype. Those
|
|
140
|
+
* methods do not survive `{ ...store }`, and the first render then fails with
|
|
141
|
+
* `store.getSnapshot is not a function`. The code builds the wrapper one time for
|
|
142
|
+
* each resolved store. Therefore the identity of the delegating `getSnapshot` and
|
|
143
|
+
* of the delegating `subscribe` stays stable for a consumer in the style of
|
|
144
|
+
* `useSyncExternalStore`.
|
|
140
145
|
*
|
|
141
|
-
* @param store - The
|
|
142
|
-
* @returns A store with
|
|
146
|
+
* @param store - The store below the wrapper.
|
|
147
|
+
* @returns A store with a guard on `set` and on `update`.
|
|
143
148
|
*/
|
|
144
149
|
export function guardContextWrites(store) {
|
|
145
150
|
const reject = (path) => {
|
|
@@ -150,8 +155,9 @@ export function guardContextWrites(store) {
|
|
|
150
155
|
const pointer = toPointer(path);
|
|
151
156
|
if (!isContextPointer(pointer))
|
|
152
157
|
return true;
|
|
153
|
-
//
|
|
154
|
-
//
|
|
158
|
+
// A round trip without a change, which is a read-modify-write of the complete
|
|
159
|
+
// snapshot, does nothing to this subtree, and it is no mutation. Drop the key in
|
|
160
|
+
// silence.
|
|
155
161
|
if (Object.is(store.get(pointer), value))
|
|
156
162
|
return false;
|
|
157
163
|
return reject(path);
|
|
@@ -178,9 +184,9 @@ export function guardContextWrites(store) {
|
|
|
178
184
|
store.update(dropped ? allowed : updates);
|
|
179
185
|
},
|
|
180
186
|
};
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
187
|
+
// The contract makes this member optional, and its absence has a meaning:
|
|
188
|
+
// json-render-core uses `getSnapshot` when the key is absent. Therefore the wrapper
|
|
189
|
+
// must build no member that returns `undefined`.
|
|
184
190
|
const { getServerSnapshot } = store;
|
|
185
191
|
if (getServerSnapshot) {
|
|
186
192
|
guarded.getServerSnapshot = () => getServerSnapshot.call(store);
|
|
@@ -188,14 +194,15 @@ export function guardContextWrites(store) {
|
|
|
188
194
|
return guarded;
|
|
189
195
|
}
|
|
190
196
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
197
|
+
* Refreshes the `/context` subtree of a live store from the composed state of a
|
|
198
|
+
* derived view. An emission with the same `viewKey` means that only the projection
|
|
199
|
+
* changed. The function therefore replaces the complete subtree, and it never
|
|
200
|
+
* merges it field by field, because `update` cannot delete a key. Every ephemeral
|
|
201
|
+
* value at the root level stays. The function does nothing when the view carries no
|
|
202
|
+
* slice, or when the store holds the slice already.
|
|
196
203
|
*
|
|
197
|
-
* @param store - The
|
|
198
|
-
* @param view - The derived view
|
|
204
|
+
* @param store - The store WITHOUT the guard. A provider refreshes through it.
|
|
205
|
+
* @param view - The derived view. Its `state.context` field carries the slice.
|
|
199
206
|
*/
|
|
200
207
|
export function refreshContextSubtree(store, view) {
|
|
201
208
|
const slice = view.state?.[CONTEXT_STATE_KEY];
|
|
@@ -204,14 +211,15 @@ export function refreshContextSubtree(store, view) {
|
|
|
204
211
|
}
|
|
205
212
|
}
|
|
206
213
|
/**
|
|
207
|
-
*
|
|
214
|
+
* Composes the effective state of a view: the authored `spec.state` and the
|
|
208
215
|
* `/context` slice.
|
|
209
216
|
*
|
|
210
|
-
* When the authored state
|
|
211
|
-
*
|
|
217
|
+
* When the authored state declares the reserved key already, the function skips the
|
|
218
|
+
* projection, the authored state wins, and the code writes a warning in
|
|
219
|
+
* development. No spec that exists now therefore fails.
|
|
212
220
|
*
|
|
213
|
-
* @param authoredState - The raw `meta.view.state`
|
|
214
|
-
* @param slice - The machine
|
|
221
|
+
* @param authoredState - The raw `meta.view.state` value. It can be anything, and the caller or toAtomState cleans it.
|
|
222
|
+
* @param slice - The context of the machine, as one complete value.
|
|
215
223
|
*/
|
|
216
224
|
export function composePlayState(authoredState, slice) {
|
|
217
225
|
if (authoredState !== undefined && Object.hasOwn(authoredState, CONTEXT_STATE_KEY)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-projection.js","sourceRoot":"","sources":["../src/context-projection.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"context-projection.js","sourceRoot":"","sources":["../src/context-projection.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @xmachines/play-actor -
|
|
2
|
+
* @xmachines/play-actor - the abstract Actor base class of the Play Architecture
|
|
3
3
|
*
|
|
4
|
-
* This package
|
|
5
|
-
*
|
|
4
|
+
* This package gives you AbstractActor, a minimal base class. It extends the XState
|
|
5
|
+
* Actor class, and it enforces the signal protocol of the Play Architecture (RFC
|
|
6
|
+
* section 5.3).
|
|
6
7
|
*
|
|
7
|
-
* The core protocol is minimal
|
|
8
|
-
*
|
|
9
|
-
* - Routable:
|
|
10
|
-
* - Viewable:
|
|
8
|
+
* The core protocol is minimal: state and send. Two interfaces give the optional
|
|
9
|
+
* capabilities:
|
|
10
|
+
* - Routable: for an actor with a routing support
|
|
11
|
+
* - Viewable: for an actor with a view rendering
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
* reactive signals
|
|
13
|
+
* The class keeps the compatibility with the XState ecosystem, such as the
|
|
14
|
+
* inspection and the devtools. It also exposes the reactive signals of the
|
|
15
|
+
* communication with the infrastructure layer.
|
|
14
16
|
*
|
|
15
17
|
* @packageDocumentation
|
|
16
18
|
* @see [Play RFC](../../docs/rfc/play.md)
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EACN,aAAa,EACb,SAAS,EACT,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,GACzB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,OAAO,EACN,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,GAClB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,YAAY,EACX,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,GACvB,MAAM,2BAA2B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @xmachines/play-actor -
|
|
2
|
+
* @xmachines/play-actor - the abstract Actor base class of the Play Architecture
|
|
3
3
|
*
|
|
4
|
-
* This package
|
|
5
|
-
*
|
|
4
|
+
* This package gives you AbstractActor, a minimal base class. It extends the XState
|
|
5
|
+
* Actor class, and it enforces the signal protocol of the Play Architecture (RFC
|
|
6
|
+
* section 5.3).
|
|
6
7
|
*
|
|
7
|
-
* The core protocol is minimal
|
|
8
|
-
*
|
|
9
|
-
* - Routable:
|
|
10
|
-
* - Viewable:
|
|
8
|
+
* The core protocol is minimal: state and send. Two interfaces give the optional
|
|
9
|
+
* capabilities:
|
|
10
|
+
* - Routable: for an actor with a routing support
|
|
11
|
+
* - Viewable: for an actor with a view rendering
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
* reactive signals
|
|
13
|
+
* The class keeps the compatibility with the XState ecosystem, such as the
|
|
14
|
+
* inspection and the devtools. It also exposes the reactive signals of the
|
|
15
|
+
* communication with the infrastructure layer.
|
|
14
16
|
*
|
|
15
17
|
* @packageDocumentation
|
|
16
18
|
* @see [Play RFC](../../docs/rfc/play.md)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EACN,aAAa,EACb,SAAS,GAMT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,OAAO,EACN,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,GAClB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC"}
|