@xmachines/play-xstate 6.1.0 → 7.0.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 +64 -12
- package/dist/capabilities.js +6 -2
- package/dist/capabilities.js.map +1 -1
- package/dist/define-player.js +8 -8
- package/dist/define-player.js.map +1 -1
- package/dist/errors.js +262 -259
- package/dist/errors.js.map +1 -1
- package/dist/index.js +4 -25
- package/dist/player-actor.js +318 -448
- package/dist/player-actor.js.map +1 -1
- package/dist/routing/build-url.js +74 -108
- package/dist/routing/build-url.js.map +1 -1
- package/dist/routing/derive-current-route.d.ts.map +1 -1
- package/dist/routing/derive-current-route.js +46 -67
- package/dist/routing/derive-current-route.js.map +1 -1
- package/dist/routing/derive-initial-route.js +53 -64
- package/dist/routing/derive-initial-route.js.map +1 -1
- package/dist/routing/derive-route.js +225 -242
- package/dist/routing/derive-route.js.map +1 -1
- package/dist/routing/format-play-route-transitions.js +192 -258
- package/dist/routing/format-play-route-transitions.js.map +1 -1
- package/dist/state-meta.d.ts +56 -25
- package/dist/state-meta.d.ts.map +1 -1
- package/dist/state-meta.js +164 -105
- package/dist/state-meta.js.map +1 -1
- package/dist/view/derive-current-view.d.ts +18 -10
- package/dist/view/derive-current-view.d.ts.map +1 -1
- package/dist/view/derive-current-view.js +243 -221
- package/dist/view/derive-current-view.js.map +1 -1
- package/dist/with-routing.js +94 -136
- package/dist/with-routing.js.map +1 -1
- package/dist/with-view.d.ts.map +1 -1
- package/dist/with-view.js +82 -152
- package/dist/with-view.js.map +1 -1
- package/package.json +19 -19
- package/dist/index.js.map +0 -1
- package/dist/routing/index.js +0 -14
- package/dist/routing/index.js.map +0 -1
- package/dist/routing/types.js +0 -2
- package/dist/routing/types.js.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
package/dist/state-meta.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The walk of the active states, which BOTH capabilities share.
|
|
3
3
|
*
|
|
4
|
-
* `deriveCurrentRoute` folds
|
|
5
|
-
*
|
|
6
|
-
* the
|
|
4
|
+
* `deriveCurrentRoute` folds the meta record of one active branch into a URL.
|
|
5
|
+
* `deriveCurrentView` walks the active tree with the same {@link branchOrder}, so a
|
|
6
|
+
* parallel node tries the region of the URL first for both. The view can still come from
|
|
7
|
+
* another region, when the region of the URL resolves to no view. For a snapshot without
|
|
8
|
+
* a machine tree, both read the flat `getMeta()` record.
|
|
7
9
|
*
|
|
8
|
-
* It lives in its own module, and
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `@xmachines/play-router`. A view-only application therefore loaded the whole route
|
|
12
|
-
* derivation, and the OPTIONAL peer of the routing reached the runtime graph of the view
|
|
13
|
-
* entry point.
|
|
10
|
+
* It lives in its own module, and not beside the route derivation, because it belongs to
|
|
11
|
+
* neither capability. `@xmachines/play-xstate/view` reads it, and a view-only application
|
|
12
|
+
* therefore loads no part of the route derivation.
|
|
14
13
|
*/
|
|
15
14
|
import type { AnyMachineSnapshot } from "xstate";
|
|
16
15
|
/** The part of an XState state node that the walks of this module read. */
|
|
@@ -29,15 +28,37 @@ export declare const activeChildKeys: (value: unknown) => string[];
|
|
|
29
28
|
export declare const activeChildValue: (value: unknown, key: string) => unknown;
|
|
30
29
|
/**
|
|
31
30
|
* The keys of the active children of a node, in the order that a branch walk tries
|
|
32
|
-
* them
|
|
33
|
-
*
|
|
31
|
+
* them. For a parallel node, one region comes first:
|
|
32
|
+
*
|
|
33
|
+
* 1. the first region whose ACTIVE subtree declares a `meta.route`;
|
|
34
|
+
* 2. else the first region that declares a route in any of its states. A region that
|
|
35
|
+
* owns the routes keeps its place while it sits in a state without a route of its
|
|
36
|
+
* own, such as a load;
|
|
37
|
+
* 3. else the first region.
|
|
38
|
+
*
|
|
39
|
+
* The other regions keep the order of the machine.
|
|
34
40
|
*
|
|
35
41
|
* A parallel machine often holds its routes in ONE region, and that region need not be
|
|
36
42
|
* the first one: a menu or a session region can come before it. The route derivation
|
|
37
43
|
* and the view derivation both follow this order, so the URL comes from the routed
|
|
38
|
-
* region, and the view without outlets
|
|
44
|
+
* region, and the view without outlets comes from the region of the URL when that region
|
|
45
|
+
* resolves to a view.
|
|
39
46
|
*/
|
|
40
47
|
export declare const branchOrder: (node: BranchNode, value: unknown) => string[];
|
|
48
|
+
/**
|
|
49
|
+
* Warns one time for each machine whose state ids break a record that is keyed on them.
|
|
50
|
+
*
|
|
51
|
+
* XState does not check that the ids of the states are unique, and a repeated id makes a
|
|
52
|
+
* `#id` target name two states. play-xstate keys the route, the view and its store on the
|
|
53
|
+
* id of a state, so a repeated id gives two states one route entry, one store, and one
|
|
54
|
+
* key. An id that is an array index, such as "42", moves to the front of every record that is
|
|
55
|
+
* keyed on ids, also the `getMeta()` record of XState, so the route of its state loses its
|
|
56
|
+
* place in the branch.
|
|
57
|
+
*
|
|
58
|
+
* The route derivation and the view derivation call this function. A read helper, such
|
|
59
|
+
* as {@link firstActiveBranchMeta}, writes no warning.
|
|
60
|
+
*/
|
|
61
|
+
export declare const warnStateIds: (root: BranchNode) => void;
|
|
41
62
|
/**
|
|
42
63
|
* Collects the `meta` object of the active state nodes of a SINGLE branch, from the
|
|
43
64
|
* root to a leaf. The key of each entry is the state id, and the order is the
|
|
@@ -55,23 +76,33 @@ export declare const branchOrder: (node: BranchNode, value: unknown) => string[]
|
|
|
55
76
|
* Therefore this function walks `snapshot.value`, which holds the real hierarchy of
|
|
56
77
|
* the active states by the state key, against the node tree of the machine. At each
|
|
57
78
|
* level it follows the first key of {@link branchOrder}: for a parallel node, that is
|
|
58
|
-
* the first region whose active subtree declares a route,
|
|
59
|
-
*
|
|
79
|
+
* the first region whose active subtree declares a route, else the first region that
|
|
80
|
+
* declares a route in any state, else the first region. This gives one deterministic
|
|
81
|
+
* branch. It also works with an explicit id,
|
|
60
82
|
* because each node carries its own `id` and its own `meta`.
|
|
61
83
|
*
|
|
62
|
-
* The function returns `null` when the snapshot exposes no machine
|
|
63
|
-
*
|
|
64
|
-
*
|
|
84
|
+
* The function returns `null` when the snapshot exposes no machine tree to walk. This
|
|
85
|
+
* is a defensive measure, because a real XState snapshot always exposes one. The caller
|
|
86
|
+
* then reads the flat `getMeta()` record.
|
|
65
87
|
*/
|
|
66
88
|
export declare const firstActiveBranchMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
|
|
67
89
|
/**
|
|
68
|
-
* Resolves the meta record that the route derivation
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
90
|
+
* Resolves the meta record that the route derivation folds: the single active branch
|
|
91
|
+
* that {@link firstActiveBranchMeta} walks, which is correct for a parallel machine and
|
|
92
|
+
* for an explicit id, or the flat `getMeta()` record when the snapshot has no machine
|
|
93
|
+
* tree to walk.
|
|
94
|
+
*
|
|
95
|
+
* The view derivation does not call this function. It walks the tree with
|
|
96
|
+
* `resolveViewTree`, which shares {@link branchOrder}, so both sides try the routed
|
|
97
|
+
* region of a parallel node first. They can still select different regions: when the
|
|
98
|
+
* routed region resolves to no view, the view comes from the next region that resolves
|
|
99
|
+
* to one, and the route stays in the routed region.
|
|
75
100
|
*/
|
|
76
101
|
export declare const activeStateMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
|
|
102
|
+
/**
|
|
103
|
+
* The flat `getMeta()` record of a snapshot, or `null` when the snapshot gives none. The
|
|
104
|
+
* keys of the ancestors come first. Both derivations read it for a snapshot that exposes
|
|
105
|
+
* no machine tree, so they read it through this one function.
|
|
106
|
+
*/
|
|
107
|
+
export declare const flatStateMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
|
|
77
108
|
//# sourceMappingURL=state-meta.d.ts.map
|
package/dist/state-meta.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-meta.d.ts","sourceRoot":"","sources":["../src/state-meta.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"state-meta.d.ts","sourceRoot":"","sources":["../src/state-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD,2EAA2E;AAC3E,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACpC;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,KAAG,MAAM,EAKhD,CAAC;AAER,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,EAAE,KAAK,MAAM,KAAG,OAGlD,CAAC;AA8Bd;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,UAAU,EAAE,OAAO,OAAO,KAAG,MAAM,EAgBpE,CAAC;AAaF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,UAAU,KAAG,IA2B/C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,qBAAqB,GACjC,UAAU,kBAAkB,KAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAgC5B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,kBAAkB,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAGxF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,UAAU,kBAAkB,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAItF,CAAC"}
|
package/dist/state-meta.js
CHANGED
|
@@ -1,116 +1,175 @@
|
|
|
1
|
+
//#region packages/play-xstate/src/state-meta.ts
|
|
1
2
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
? [value]
|
|
8
|
-
: value !== null && typeof value === "object"
|
|
9
|
-
? Object.keys(value)
|
|
10
|
-
: [];
|
|
3
|
+
* The keys of the active children of a node, from its part of `snapshot.value`: one key
|
|
4
|
+
* for a compound node, one for each region of a parallel node, in the order of the
|
|
5
|
+
* machine, and none for an atomic node.
|
|
6
|
+
*/
|
|
7
|
+
var activeChildKeys = (value) => typeof value === "string" ? [value] : value !== null && typeof value === "object" ? Object.keys(value) : [];
|
|
11
8
|
/** The part of `snapshot.value` that belongs to the active child `key`. */
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
: undefined;
|
|
15
|
-
const declaresRoute = (node) => node.meta !== null &&
|
|
16
|
-
typeof node.meta === "object" &&
|
|
17
|
-
node.meta.route !== undefined;
|
|
9
|
+
var activeChildValue = (value, key) => value !== null && typeof value === "object" ? value[key] : void 0;
|
|
10
|
+
var declaresRoute = (node) => node.meta !== null && typeof node.meta === "object" && node.meta.route !== void 0;
|
|
18
11
|
/** `true` when a state of the active subtree of `node` declares a `meta.route`. */
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
12
|
+
var routeBelow = (node, value) => {
|
|
13
|
+
if (declaresRoute(node)) return true;
|
|
14
|
+
for (const key of activeChildKeys(value)) {
|
|
15
|
+
const child = node.states?.[key];
|
|
16
|
+
if (child && routeBelow(child, activeChildValue(value, key))) return true;
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
};
|
|
20
|
+
var routesByNode = /* @__PURE__ */ new WeakMap();
|
|
21
|
+
var holdsRoutes = (node) => {
|
|
22
|
+
let holds = routesByNode.get(node);
|
|
23
|
+
if (holds === void 0) {
|
|
24
|
+
holds = declaresRoute(node) || Object.values(node.states ?? {}).some(holdsRoutes);
|
|
25
|
+
routesByNode.set(node, holds);
|
|
26
|
+
}
|
|
27
|
+
return holds;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* The keys of the active children of a node, in the order that a branch walk tries
|
|
31
|
+
* them. For a parallel node, one region comes first:
|
|
32
|
+
*
|
|
33
|
+
* 1. the first region whose ACTIVE subtree declares a `meta.route`;
|
|
34
|
+
* 2. else the first region that declares a route in any of its states. A region that
|
|
35
|
+
* owns the routes keeps its place while it sits in a state without a route of its
|
|
36
|
+
* own, such as a load;
|
|
37
|
+
* 3. else the first region.
|
|
38
|
+
*
|
|
39
|
+
* The other regions keep the order of the machine.
|
|
40
|
+
*
|
|
41
|
+
* A parallel machine often holds its routes in ONE region, and that region need not be
|
|
42
|
+
* the first one: a menu or a session region can come before it. The route derivation
|
|
43
|
+
* and the view derivation both follow this order, so the URL comes from the routed
|
|
44
|
+
* region, and the view without outlets comes from the region of the URL when that region
|
|
45
|
+
* resolves to a view.
|
|
46
|
+
*/
|
|
47
|
+
var branchOrder = (node, value) => {
|
|
48
|
+
const keys = activeChildKeys(value);
|
|
49
|
+
if (keys.length < 2) return keys;
|
|
50
|
+
const childOf = (key) => node.states?.[key];
|
|
51
|
+
const routed = keys.find((key) => {
|
|
52
|
+
const child = childOf(key);
|
|
53
|
+
return child !== void 0 && routeBelow(child, activeChildValue(value, key));
|
|
54
|
+
}) ?? keys.find((key) => {
|
|
55
|
+
const child = childOf(key);
|
|
56
|
+
return child !== void 0 && holdsRoutes(child);
|
|
57
|
+
});
|
|
58
|
+
return routed === void 0 || routed === keys[0] ? keys : [routed, ...keys.filter((key) => key !== routed)];
|
|
59
|
+
};
|
|
60
|
+
var checkedMachines = /* @__PURE__ */ new WeakSet();
|
|
61
|
+
/**
|
|
62
|
+
* An id that JavaScript reads as an array index: a whole number from 0 to 2^32 - 2, with
|
|
63
|
+
* no leading zero. An object lists such a key before every other key.
|
|
64
|
+
*/
|
|
65
|
+
var isIndexLike = (id) => /^(0|[1-9]\d*)$/.test(id) && Number(id) < 2 ** 32 - 1;
|
|
66
|
+
/** The ids in quotes, separated by commas, for a warning. */
|
|
67
|
+
var quoted = (ids) => [...ids].map((id) => `"${id}"`).join(", ");
|
|
68
|
+
/**
|
|
69
|
+
* Warns one time for each machine whose state ids break a record that is keyed on them.
|
|
70
|
+
*
|
|
71
|
+
* XState does not check that the ids of the states are unique, and a repeated id makes a
|
|
72
|
+
* `#id` target name two states. play-xstate keys the route, the view and its store on the
|
|
73
|
+
* id of a state, so a repeated id gives two states one route entry, one store, and one
|
|
74
|
+
* key. An id that is an array index, such as "42", moves to the front of every record that is
|
|
75
|
+
* keyed on ids, also the `getMeta()` record of XState, so the route of its state loses its
|
|
76
|
+
* place in the branch.
|
|
77
|
+
*
|
|
78
|
+
* The route derivation and the view derivation call this function. A read helper, such
|
|
79
|
+
* as {@link firstActiveBranchMeta}, writes no warning.
|
|
80
|
+
*/
|
|
81
|
+
var warnStateIds = (root) => {
|
|
82
|
+
if (checkedMachines.has(root)) return;
|
|
83
|
+
checkedMachines.add(root);
|
|
84
|
+
const seen = /* @__PURE__ */ new Set();
|
|
85
|
+
const repeated = /* @__PURE__ */ new Set();
|
|
86
|
+
const indexLike = /* @__PURE__ */ new Set();
|
|
87
|
+
const visit = (node) => {
|
|
88
|
+
if (seen.has(node.id)) repeated.add(node.id);
|
|
89
|
+
seen.add(node.id);
|
|
90
|
+
if (isIndexLike(node.id)) indexLike.add(node.id);
|
|
91
|
+
for (const child of Object.values(node.states ?? {})) visit(child);
|
|
92
|
+
};
|
|
93
|
+
visit(root);
|
|
94
|
+
const faults = [...repeated.size > 0 ? [`it gives two or more states the same id (${quoted(repeated)})`] : [], ...indexLike.size > 0 ? [`it gives a state an id that is an array index (${quoted(indexLike)})`] : []];
|
|
95
|
+
if (faults.length === 0) return;
|
|
96
|
+
console.warn(`[play-xstate] The state ids of the machine "${root.id}" break a rule: ${faults.join("; ")}. play-xstate keys the route, the view and its store on the id of a state. Give each state its own id, and do not use an array index as an id.`);
|
|
28
97
|
};
|
|
29
98
|
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
99
|
+
* Collects the `meta` object of the active state nodes of a SINGLE branch, from the
|
|
100
|
+
* root to a leaf. The key of each entry is the state id, and the order is the
|
|
101
|
+
* ancestors first. {@link deriveRoute} folds this shape.
|
|
102
|
+
*
|
|
103
|
+
* `snapshot.getMeta()` returns a FLAT record of the meta object of every active
|
|
104
|
+
* state. For a machine that is not parallel, that record is one chain of ancestors
|
|
105
|
+
* already. For a PARALLEL machine, it mixes the entries of every active region. A
|
|
106
|
+
* blind fold therefore joins a relative route of one region to an absolute route of
|
|
107
|
+
* a sibling region, and the URL belongs to the tree of neither region. The flat
|
|
108
|
+
* record also cannot go back into a hierarchy: when a state declares an explicit
|
|
109
|
+
* `id`, for example a child with `id: "dashboard-overview"` under `id: "dashboard"`,
|
|
110
|
+
* the meta keys are those ids, and they carry no information about the ancestry.
|
|
111
|
+
*
|
|
112
|
+
* Therefore this function walks `snapshot.value`, which holds the real hierarchy of
|
|
113
|
+
* the active states by the state key, against the node tree of the machine. At each
|
|
114
|
+
* level it follows the first key of {@link branchOrder}: for a parallel node, that is
|
|
115
|
+
* the first region whose active subtree declares a route, else the first region that
|
|
116
|
+
* declares a route in any state, else the first region. This gives one deterministic
|
|
117
|
+
* branch. It also works with an explicit id,
|
|
118
|
+
* because each node carries its own `id` and its own `meta`.
|
|
119
|
+
*
|
|
120
|
+
* The function returns `null` when the snapshot exposes no machine tree to walk. This
|
|
121
|
+
* is a defensive measure, because a real XState snapshot always exposes one. The caller
|
|
122
|
+
* then reads the flat `getMeta()` record.
|
|
123
|
+
*/
|
|
124
|
+
var firstActiveBranchMeta = (snapshot) => {
|
|
125
|
+
const root = snapshot.machine?.root;
|
|
126
|
+
if (!root) return null;
|
|
127
|
+
const ordered = {};
|
|
128
|
+
let node = root;
|
|
129
|
+
let value = snapshot.value;
|
|
130
|
+
while (node) {
|
|
131
|
+
if (node.meta && typeof node.meta === "object") Object.defineProperty(ordered, node.id, {
|
|
132
|
+
value: node.meta,
|
|
133
|
+
enumerable: true,
|
|
134
|
+
writable: true,
|
|
135
|
+
configurable: true
|
|
136
|
+
});
|
|
137
|
+
const key = branchOrder(node, value)[0];
|
|
138
|
+
if (key === void 0) break;
|
|
139
|
+
const child = node.states?.[key];
|
|
140
|
+
if (!child) break;
|
|
141
|
+
value = activeChildValue(value, key);
|
|
142
|
+
node = child;
|
|
143
|
+
}
|
|
144
|
+
return ordered;
|
|
50
145
|
};
|
|
51
146
|
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
* the active states by the state key, against the node tree of the machine. At each
|
|
67
|
-
* level it follows the first key of {@link branchOrder}: for a parallel node, that is
|
|
68
|
-
* the first region whose active subtree declares a route, or the first region when no
|
|
69
|
-
* region does. This gives one deterministic branch. It also works with an explicit id,
|
|
70
|
-
* because each node carries its own `id` and its own `meta`.
|
|
71
|
-
*
|
|
72
|
-
* The function returns `null` when the snapshot exposes no machine and no value to
|
|
73
|
-
* walk. This is a defensive measure, because a real XState snapshot always exposes
|
|
74
|
-
* them. The caller then uses `getMeta()`, as before.
|
|
75
|
-
*/
|
|
76
|
-
export const firstActiveBranchMeta = (snapshot) => {
|
|
77
|
-
const root = snapshot.machine?.root;
|
|
78
|
-
if (!root)
|
|
79
|
-
return null;
|
|
80
|
-
const ordered = {};
|
|
81
|
-
let node = root;
|
|
82
|
-
let value = snapshot.value;
|
|
83
|
-
while (node) {
|
|
84
|
-
if (node.meta && typeof node.meta === "object") {
|
|
85
|
-
ordered[node.id] = node.meta; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
86
|
-
}
|
|
87
|
-
// The key of the active child at this level: the name of an atomic active leaf, the
|
|
88
|
-
// one key of a compound node, or the routed region of a parallel node.
|
|
89
|
-
const key = branchOrder(node, value)[0];
|
|
90
|
-
if (key === undefined)
|
|
91
|
-
break;
|
|
92
|
-
const child = node.states?.[key]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
93
|
-
if (!child)
|
|
94
|
-
break;
|
|
95
|
-
value = activeChildValue(value, key);
|
|
96
|
-
node = child;
|
|
97
|
-
}
|
|
98
|
-
return ordered;
|
|
147
|
+
* Resolves the meta record that the route derivation folds: the single active branch
|
|
148
|
+
* that {@link firstActiveBranchMeta} walks, which is correct for a parallel machine and
|
|
149
|
+
* for an explicit id, or the flat `getMeta()` record when the snapshot has no machine
|
|
150
|
+
* tree to walk.
|
|
151
|
+
*
|
|
152
|
+
* The view derivation does not call this function. It walks the tree with
|
|
153
|
+
* `resolveViewTree`, which shares {@link branchOrder}, so both sides try the routed
|
|
154
|
+
* region of a parallel node first. They can still select different regions: when the
|
|
155
|
+
* routed region resolves to no view, the view comes from the next region that resolves
|
|
156
|
+
* to one, and the route stays in the routed region.
|
|
157
|
+
*/
|
|
158
|
+
var activeStateMeta = (snapshot) => {
|
|
159
|
+
if (!snapshot) return null;
|
|
160
|
+
return firstActiveBranchMeta(snapshot) ?? flatStateMeta(snapshot);
|
|
99
161
|
};
|
|
100
162
|
/**
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
export const activeStateMeta = (snapshot) => {
|
|
110
|
-
if (!snapshot || typeof snapshot.getMeta !== "function") {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
const meta = firstActiveBranchMeta(snapshot) ?? snapshot.getMeta();
|
|
114
|
-
return meta && typeof meta === "object" ? meta : null;
|
|
163
|
+
* The flat `getMeta()` record of a snapshot, or `null` when the snapshot gives none. The
|
|
164
|
+
* keys of the ancestors come first. Both derivations read it for a snapshot that exposes
|
|
165
|
+
* no machine tree, so they read it through this one function.
|
|
166
|
+
*/
|
|
167
|
+
var flatStateMeta = (snapshot) => {
|
|
168
|
+
if (!snapshot || typeof snapshot.getMeta !== "function") return null;
|
|
169
|
+
const meta = snapshot.getMeta();
|
|
170
|
+
return meta && typeof meta === "object" ? meta : null;
|
|
115
171
|
};
|
|
172
|
+
//#endregion
|
|
173
|
+
export { activeChildKeys, activeChildValue, activeStateMeta, branchOrder, firstActiveBranchMeta, flatStateMeta, warnStateIds };
|
|
174
|
+
|
|
116
175
|
//# sourceMappingURL=state-meta.js.map
|
package/dist/state-meta.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-meta.js","sourceRoot":"","sources":["../src/state-meta.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"state-meta.js","names":[],"sources":["../src/state-meta.ts"],"sourcesContent":["/**\n * The walk of the active states, which BOTH capabilities share.\n *\n * `deriveCurrentRoute` folds the meta record of one active branch into a URL.\n * `deriveCurrentView` walks the active tree with the same {@link branchOrder}, so a\n * parallel node tries the region of the URL first for both. The view can still come from\n * another region, when the region of the URL resolves to no view. For a snapshot without\n * a machine tree, both read the flat `getMeta()` record.\n *\n * It lives in its own module, and not beside the route derivation, because it belongs to\n * neither capability. `@xmachines/play-xstate/view` reads it, and a view-only application\n * therefore loads no part of the route derivation.\n */\nimport type { AnyMachineSnapshot } from \"xstate\";\n\n/** The part of an XState state node that the walks of this module read. */\nexport interface BranchNode {\n\tid: string;\n\tmeta?: unknown;\n\tstates?: Record<string, BranchNode>;\n}\n\n/**\n * The keys of the active children of a node, from its part of `snapshot.value`: one key\n * for a compound node, one for each region of a parallel node, in the order of the\n * machine, and none for an atomic node.\n */\nexport const activeChildKeys = (value: unknown): string[] =>\n\ttypeof value === \"string\"\n\t\t? [value]\n\t\t: value !== null && typeof value === \"object\"\n\t\t\t? Object.keys(value)\n\t\t\t: [];\n\n/** The part of `snapshot.value` that belongs to the active child `key`. */\nexport const activeChildValue = (value: unknown, key: string): unknown =>\n\tvalue !== null && typeof value === \"object\"\n\t\t? (value as Record<string, unknown>)[key] // nosemgrep: gitlab.eslint.detect-object-injection\n\t\t: undefined;\n\nconst declaresRoute = (node: BranchNode): boolean =>\n\tnode.meta !== null &&\n\ttypeof node.meta === \"object\" &&\n\t(node.meta as { route?: unknown }).route !== undefined;\n\n/** `true` when a state of the active subtree of `node` declares a `meta.route`. */\nconst routeBelow = (node: BranchNode, value: unknown): boolean => {\n\tif (declaresRoute(node)) return true;\n\tfor (const key of activeChildKeys(value)) {\n\t\tconst child = node.states?.[key]; // nosemgrep: gitlab.eslint.detect-object-injection\n\t\tif (child && routeBelow(child, activeChildValue(value, key))) return true;\n\t}\n\treturn false;\n};\n\n// Whether a state node or one of its descendants declares a `meta.route`, for each\n// node. The state nodes of a machine are static, so one answer holds for its life.\nconst routesByNode = new WeakMap<BranchNode, boolean>();\n\nconst holdsRoutes = (node: BranchNode): boolean => {\n\tlet holds = routesByNode.get(node);\n\tif (holds === undefined) {\n\t\tholds = declaresRoute(node) || Object.values(node.states ?? {}).some(holdsRoutes);\n\t\troutesByNode.set(node, holds);\n\t}\n\treturn holds;\n};\n\n/**\n * The keys of the active children of a node, in the order that a branch walk tries\n * them. For a parallel node, one region comes first:\n *\n * 1. the first region whose ACTIVE subtree declares a `meta.route`;\n * 2. else the first region that declares a route in any of its states. A region that\n * owns the routes keeps its place while it sits in a state without a route of its\n * own, such as a load;\n * 3. else the first region.\n *\n * The other regions keep the order of the machine.\n *\n * A parallel machine often holds its routes in ONE region, and that region need not be\n * the first one: a menu or a session region can come before it. The route derivation\n * and the view derivation both follow this order, so the URL comes from the routed\n * region, and the view without outlets comes from the region of the URL when that region\n * resolves to a view.\n */\nexport const branchOrder = (node: BranchNode, value: unknown): string[] => {\n\tconst keys = activeChildKeys(value);\n\tif (keys.length < 2) return keys;\n\tconst childOf = (key: string): BranchNode | undefined => node.states?.[key]; // nosemgrep: gitlab.eslint.detect-object-injection\n\tconst routed =\n\t\tkeys.find((key) => {\n\t\t\tconst child = childOf(key);\n\t\t\treturn child !== undefined && routeBelow(child, activeChildValue(value, key));\n\t\t}) ??\n\t\tkeys.find((key) => {\n\t\t\tconst child = childOf(key);\n\t\t\treturn child !== undefined && holdsRoutes(child);\n\t\t});\n\treturn routed === undefined || routed === keys[0]\n\t\t? keys\n\t\t: [routed, ...keys.filter((key) => key !== routed)];\n};\n\nconst checkedMachines = new WeakSet<BranchNode>();\n\n/**\n * An id that JavaScript reads as an array index: a whole number from 0 to 2^32 - 2, with\n * no leading zero. An object lists such a key before every other key.\n */\nconst isIndexLike = (id: string): boolean => /^(0|[1-9]\\d*)$/.test(id) && Number(id) < 2 ** 32 - 1;\n\n/** The ids in quotes, separated by commas, for a warning. */\nconst quoted = (ids: Set<string>): string => [...ids].map((id) => `\"${id}\"`).join(\", \");\n\n/**\n * Warns one time for each machine whose state ids break a record that is keyed on them.\n *\n * XState does not check that the ids of the states are unique, and a repeated id makes a\n * `#id` target name two states. play-xstate keys the route, the view and its store on the\n * id of a state, so a repeated id gives two states one route entry, one store, and one\n * key. An id that is an array index, such as \"42\", moves to the front of every record that is\n * keyed on ids, also the `getMeta()` record of XState, so the route of its state loses its\n * place in the branch.\n *\n * The route derivation and the view derivation call this function. A read helper, such\n * as {@link firstActiveBranchMeta}, writes no warning.\n */\nexport const warnStateIds = (root: BranchNode): void => {\n\tif (checkedMachines.has(root)) return;\n\tcheckedMachines.add(root);\n\tconst seen = new Set<string>();\n\tconst repeated = new Set<string>();\n\tconst indexLike = new Set<string>();\n\tconst visit = (node: BranchNode): void => {\n\t\tif (seen.has(node.id)) repeated.add(node.id);\n\t\tseen.add(node.id);\n\t\tif (isIndexLike(node.id)) indexLike.add(node.id);\n\t\tfor (const child of Object.values(node.states ?? {})) visit(child);\n\t};\n\tvisit(root);\n\tconst faults = [\n\t\t...(repeated.size > 0\n\t\t\t? [`it gives two or more states the same id (${quoted(repeated)})`]\n\t\t\t: []),\n\t\t...(indexLike.size > 0\n\t\t\t? [`it gives a state an id that is an array index (${quoted(indexLike)})`]\n\t\t\t: []),\n\t];\n\tif (faults.length === 0) return;\n\tconsole.warn(\n\t\t`[play-xstate] The state ids of the machine \"${root.id}\" break a rule: ` +\n\t\t\t`${faults.join(\"; \")}. play-xstate keys the route, the view and its store on the id ` +\n\t\t\t\"of a state. Give each state its own id, and do not use an array index as an id.\",\n\t);\n};\n\n/**\n * Collects the `meta` object of the active state nodes of a SINGLE branch, from the\n * root to a leaf. The key of each entry is the state id, and the order is the\n * ancestors first. {@link deriveRoute} folds this shape.\n *\n * `snapshot.getMeta()` returns a FLAT record of the meta object of every active\n * state. For a machine that is not parallel, that record is one chain of ancestors\n * already. For a PARALLEL machine, it mixes the entries of every active region. A\n * blind fold therefore joins a relative route of one region to an absolute route of\n * a sibling region, and the URL belongs to the tree of neither region. The flat\n * record also cannot go back into a hierarchy: when a state declares an explicit\n * `id`, for example a child with `id: \"dashboard-overview\"` under `id: \"dashboard\"`,\n * the meta keys are those ids, and they carry no information about the ancestry.\n *\n * Therefore this function walks `snapshot.value`, which holds the real hierarchy of\n * the active states by the state key, against the node tree of the machine. At each\n * level it follows the first key of {@link branchOrder}: for a parallel node, that is\n * the first region whose active subtree declares a route, else the first region that\n * declares a route in any state, else the first region. This gives one deterministic\n * branch. It also works with an explicit id,\n * because each node carries its own `id` and its own `meta`.\n *\n * The function returns `null` when the snapshot exposes no machine tree to walk. This\n * is a defensive measure, because a real XState snapshot always exposes one. The caller\n * then reads the flat `getMeta()` record.\n */\nexport const firstActiveBranchMeta = (\n\tsnapshot: AnyMachineSnapshot,\n): Record<string, unknown> | null => {\n\tconst root = snapshot.machine?.root as BranchNode | undefined;\n\tif (!root) return null;\n\n\tconst ordered: Record<string, unknown> = {};\n\tlet node: BranchNode | undefined = root;\n\tlet value: unknown = snapshot.value;\n\n\twhile (node) {\n\t\tif (node.meta && typeof node.meta === \"object\") {\n\t\t\t// A definition, and not an assignment: an id \"__proto__\" would set the prototype\n\t\t\t// of the record, and the entry would leave Object.entries.\n\t\t\tObject.defineProperty(ordered, node.id, {\n\t\t\t\tvalue: node.meta,\n\t\t\t\tenumerable: true,\n\t\t\t\twritable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t}\n\n\t\t// The key of the active child at this level: the name of an atomic active leaf, the\n\t\t// one key of a compound node, or the routed region of a parallel node.\n\t\tconst key: string | undefined = branchOrder(node, value)[0];\n\t\tif (key === undefined) break;\n\n\t\tconst child: BranchNode | undefined = node.states?.[key]; // nosemgrep: gitlab.eslint.detect-object-injection\n\t\tif (!child) break;\n\t\tvalue = activeChildValue(value, key);\n\t\tnode = child;\n\t}\n\n\treturn ordered;\n};\n\n/**\n * Resolves the meta record that the route derivation folds: the single active branch\n * that {@link firstActiveBranchMeta} walks, which is correct for a parallel machine and\n * for an explicit id, or the flat `getMeta()` record when the snapshot has no machine\n * tree to walk.\n *\n * The view derivation does not call this function. It walks the tree with\n * `resolveViewTree`, which shares {@link branchOrder}, so both sides try the routed\n * region of a parallel node first. They can still select different regions: when the\n * routed region resolves to no view, the view comes from the next region that resolves\n * to one, and the route stays in the routed region.\n */\nexport const activeStateMeta = (snapshot: AnyMachineSnapshot): Record<string, unknown> | null => {\n\tif (!snapshot) return null;\n\treturn firstActiveBranchMeta(snapshot) ?? flatStateMeta(snapshot);\n};\n\n/**\n * The flat `getMeta()` record of a snapshot, or `null` when the snapshot gives none. The\n * keys of the ancestors come first. Both derivations read it for a snapshot that exposes\n * no machine tree, so they read it through this one function.\n */\nexport const flatStateMeta = (snapshot: AnyMachineSnapshot): Record<string, unknown> | null => {\n\tif (!snapshot || typeof snapshot.getMeta !== \"function\") return null;\n\tconst meta: unknown = snapshot.getMeta();\n\treturn meta && typeof meta === \"object\" ? (meta as Record<string, unknown>) : null;\n};\n"],"mappings":"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"}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* The view derivation — the meta.view half of the player pipeline.
|
|
3
3
|
*
|
|
4
4
|
* This file is beside src/routing/, so that player-actor.ts holds the actor
|
|
5
|
-
* itself only: the atoms, the hooks, and the lifecycle. The walk
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* itself only: the atoms, the hooks, and the lifecycle. The walk shares
|
|
6
|
+
* `branchOrder` with the route derivation, so a parallel node tries the region of its
|
|
7
|
+
* URL first. When that region resolves to no view, the view comes from the next region
|
|
8
|
+
* that resolves to one.
|
|
8
9
|
*/
|
|
9
10
|
import type { AnyMachineSnapshot } from "xstate";
|
|
10
11
|
import { type PlaySpec } from "@xmachines/play-view";
|
|
@@ -37,13 +38,20 @@ import { type PlaySpec } from "@xmachines/play-view";
|
|
|
37
38
|
*
|
|
38
39
|
* ### The viewKey
|
|
39
40
|
*
|
|
40
|
-
* The derived spec carries a `viewKey` field. Its value is the
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* the store again, and the same key refreshes `/context` in place. The
|
|
44
|
-
* from the selected
|
|
45
|
-
* parallel machine the
|
|
46
|
-
*
|
|
41
|
+
* The derived spec carries a `viewKey` field. Its value is the id of the state node
|
|
42
|
+
* whose view the walk selected: the outermost state that composes with `outlets`, or
|
|
43
|
+
* the state of the deepest view. A provider uses it as the key of its store lifecycle:
|
|
44
|
+
* a new key seeds the store again, and the same key refreshes `/context` in place. The
|
|
45
|
+
* value comes from the selected view, and not from "the id of the active state",
|
|
46
|
+
* because for a parallel machine the walk can select a view of a different region than
|
|
47
|
+
* the leaf of the routed branch.
|
|
48
|
+
*
|
|
49
|
+
* ### One rule
|
|
50
|
+
*
|
|
51
|
+
* One walk of the active state tree derives every view, and a machine with no
|
|
52
|
+
* `outlets` is its simple case: the deepest view wins. Declare `outlets` on a state to
|
|
53
|
+
* show its view beside the views of its children. A snapshot that exposes no machine
|
|
54
|
+
* tree falls back to its flat `getMeta()` record, as the route derivation does.
|
|
47
55
|
*
|
|
48
56
|
* @param snapshot - The current snapshot of the XState machine.
|
|
49
57
|
* @returns The derived `PlaySpec`, or `null` when the current state has no view metadata.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-current-view.d.ts","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"derive-current-view.d.ts","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAKN,KAAK,QAAQ,EAIb,MAAM,sBAAsB,CAAC;AAqO9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,kBAAkB,KAAG,QAAQ,GAAG,IAmC3E,CAAC"}
|