@xmachines/play-router 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 +93 -76
- package/dist/base-route-map.d.ts +63 -57
- package/dist/base-route-map.d.ts.map +1 -1
- package/dist/base-route-map.js +65 -59
- package/dist/base-route-map.js.map +1 -1
- package/dist/build-tree.d.ts +13 -12
- package/dist/build-tree.d.ts.map +1 -1
- package/dist/build-tree.js +30 -28
- package/dist/build-tree.js.map +1 -1
- package/dist/create-route-map-from-tree.d.ts +15 -15
- package/dist/create-route-map-from-tree.js +15 -15
- package/dist/create-route-map.d.ts +18 -16
- package/dist/create-route-map.d.ts.map +1 -1
- package/dist/create-route-map.js +10 -9
- package/dist/create-route-map.js.map +1 -1
- package/dist/errors.d.ts +40 -38
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +40 -38
- package/dist/errors.js.map +1 -1
- package/dist/extract-routes.d.ts +8 -7
- package/dist/extract-routes.d.ts.map +1 -1
- package/dist/extract-routes.js +31 -27
- package/dist/extract-routes.js.map +1 -1
- package/dist/find-route.d.ts +18 -15
- package/dist/find-route.d.ts.map +1 -1
- package/dist/find-route.js +42 -38
- package/dist/find-route.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -10
- package/dist/index.js.map +1 -1
- package/dist/machine-to-graph.d.ts +3 -2
- package/dist/machine-to-graph.d.ts.map +1 -1
- package/dist/machine-to-graph.js +20 -19
- package/dist/machine-to-graph.js.map +1 -1
- package/dist/query.d.ts +39 -37
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +62 -57
- package/dist/query.js.map +1 -1
- package/dist/router-bridge-base.d.ts +208 -190
- package/dist/router-bridge-base.d.ts.map +1 -1
- package/dist/router-bridge-base.js +235 -211
- package/dist/router-bridge-base.js.map +1 -1
- package/dist/router-sync.d.ts +41 -35
- package/dist/router-sync.d.ts.map +1 -1
- package/dist/router-sync.js +53 -45
- package/dist/router-sync.js.map +1 -1
- package/dist/types.d.ts +165 -147
- package/dist/types.d.ts.map +1 -1
- package/dist/url-pattern-utils.d.ts +53 -47
- package/dist/url-pattern-utils.d.ts.map +1 -1
- package/dist/url-pattern-utils.js +61 -55
- package/dist/url-pattern-utils.js.map +1 -1
- package/dist/validate-routes.d.ts +32 -31
- package/dist/validate-routes.d.ts.map +1 -1
- package/dist/validate-routes.js +30 -29
- package/dist/validate-routes.js.map +1 -1
- package/package.json +6 -5
package/dist/find-route.js
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import { getURLPatternCtor, getCompiledPattern } from "./url-pattern-utils.js";
|
|
2
2
|
import { URLPatternUnavailableError, InvalidRoutePatternError } from "./errors.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Tells you if a URL path matches a route pattern, with URLPattern.
|
|
5
5
|
*
|
|
6
|
-
* For static
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* For a static pattern, which holds no `:param`, the function makes a direct
|
|
7
|
+
* equality test. Therefore an environment with static routes only needs URLPattern
|
|
8
|
+
* never, and it needs no polyfill.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* The function uses the compiled-pattern cache of the module level
|
|
11
|
+
* (`getCompiledPattern`). A repeated lookup therefore compiles the same pattern
|
|
12
|
+
* never again. The cache also normalizes a param name with a hyphen (`:cat-id`)
|
|
13
|
+
* exactly like `RouteMap`: one match engine is below both.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* and
|
|
17
|
-
*
|
|
15
|
+
* The function throws a `URLPatternUnavailableError` when it tests a parameterized
|
|
16
|
+
* pattern and `globalThis` holds no URLPattern.
|
|
17
|
+
* It throws an `InvalidRoutePatternError` when URLPattern cannot compile the
|
|
18
|
+
* pattern.
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
+
* This function is private. The public API of the package does not export it.
|
|
20
21
|
*
|
|
21
|
-
* @param path - URL path
|
|
22
|
-
* @param pattern -
|
|
23
|
-
* @returns True
|
|
22
|
+
* @param path - The URL path, for example '/settings' or '/settings/billing'
|
|
23
|
+
* @param pattern - The route pattern, for example '/settings/:section?'
|
|
24
|
+
* @returns True when the path matches the pattern
|
|
24
25
|
*/
|
|
25
26
|
function matchesPattern(path, pattern) {
|
|
26
27
|
if (!pattern.includes(":"))
|
|
@@ -36,14 +37,15 @@ function matchesPattern(path, pattern) {
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
|
-
*
|
|
40
|
+
* Finds a route node by its state ID
|
|
40
41
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
42
|
+
* The function looks the route node up by the ID property of the state. It gives you
|
|
43
|
+
* the URL path of a state ID, for the update of the browser URL after a `play.route`
|
|
44
|
+
* transition.
|
|
43
45
|
*
|
|
44
|
-
* @param tree -
|
|
45
|
-
* @param id -
|
|
46
|
-
* @returns
|
|
46
|
+
* @param tree - The route tree, from extractMachineRoutes
|
|
47
|
+
* @param id - The state ID, for example 'dashboard' or 'settings.profile'
|
|
48
|
+
* @returns The route node, or undefined when the function finds none
|
|
47
49
|
*
|
|
48
50
|
* @example
|
|
49
51
|
* ```typescript
|
|
@@ -58,19 +60,21 @@ export const findRouteById = (tree, id) => {
|
|
|
58
60
|
return tree.byStateId.get(id);
|
|
59
61
|
};
|
|
60
62
|
/**
|
|
61
|
-
*
|
|
63
|
+
* Finds a route node by its URL path
|
|
62
64
|
*
|
|
63
|
-
*
|
|
64
|
-
* URL for
|
|
65
|
+
* The function looks the route node up by the URL path. It gives you the state ID of
|
|
66
|
+
* a browser URL, for the `play.route` event of a navigation.
|
|
65
67
|
*
|
|
66
|
-
* When
|
|
67
|
-
* prefers
|
|
68
|
+
* When more than one state holds the same path, for example the root and a second
|
|
69
|
+
* state both at "/", the function prefers a node with a route, which means a node
|
|
70
|
+
* with a `meta.route` field, over a node without one.
|
|
68
71
|
*
|
|
69
|
-
*
|
|
72
|
+
* The function also matches a pattern of a dynamic route, for example
|
|
73
|
+
* '/settings/:section?'.
|
|
70
74
|
*
|
|
71
|
-
* @param tree -
|
|
72
|
-
* @param path - URL path
|
|
73
|
-
* @returns
|
|
75
|
+
* @param tree - The route tree, from extractMachineRoutes
|
|
76
|
+
* @param path - The URL path, for example '/dashboard' or '/settings/profile'
|
|
77
|
+
* @returns The route node, or undefined when the function finds none
|
|
74
78
|
*
|
|
75
79
|
* @example
|
|
76
80
|
* ```typescript
|
|
@@ -79,25 +83,25 @@ export const findRouteById = (tree, id) => {
|
|
|
79
83
|
* ```
|
|
80
84
|
*/
|
|
81
85
|
export const findRouteByPath = (tree, path) => {
|
|
82
|
-
// 1. Try exact match first
|
|
86
|
+
// 1. Try the exact match first. This is the fast path of a static route
|
|
83
87
|
const node = tree.byPath.get(path);
|
|
84
88
|
if (node?.routable) {
|
|
85
89
|
return node;
|
|
86
90
|
}
|
|
87
|
-
// 2.
|
|
88
|
-
// This handles:
|
|
89
|
-
// -
|
|
90
|
-
// -
|
|
91
|
+
// 2. Without an exact match, and for a node without a route, try the pattern match.
|
|
92
|
+
// This handles three cases:
|
|
93
|
+
// - a route with a parameter, for example '/settings/:section?'
|
|
94
|
+
// - more than one state at the same path, where a state with a route wins
|
|
91
95
|
for (const candidate of tree.byStateId.values()) {
|
|
92
96
|
if (!candidate.routable) {
|
|
93
|
-
continue; // Skip
|
|
97
|
+
continue; // Skip each node without a route
|
|
94
98
|
}
|
|
95
|
-
//
|
|
99
|
+
// Test the path against the pattern of this node
|
|
96
100
|
if (matchesPattern(path, candidate.fullPath)) {
|
|
97
101
|
return candidate;
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
|
-
// 3.
|
|
104
|
+
// 3. The fallback: return the exact match of a node without a route, when one is present
|
|
101
105
|
return node;
|
|
102
106
|
};
|
|
103
107
|
//# sourceMappingURL=find-route.js.map
|
package/dist/find-route.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-route.js","sourceRoot":"","sources":["../src/find-route.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEnF
|
|
1
|
+
{"version":3,"file":"find-route.js","sourceRoot":"","sources":["../src/find-route.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAEnF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAS,cAAc,CAAC,IAAY,EAAE,OAAe;IACpD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,KAAK,OAAO,CAAC;IACpD,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC;IACjC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,0BAA0B,EAAE,CAAC;IAClD,IAAI,CAAC;QACJ,OAAO,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,IAAI,wBAAwB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7D,CAAC;AACF,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAe,EAAE,EAAU,EAAyB,EAAE;IACnF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAe,EAAE,IAAY,EAAyB,EAAE;IACvF,wEAAwE;IACxE,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,IAAI,EAAE,QAAQ,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,oFAAoF;IACpF,4BAA4B;IAC5B,gEAAgE;IAChE,0EAA0E;IAC1E,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QACjD,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACzB,SAAS,CAAC,iCAAiC;QAC5C,CAAC;QAED,iDAAiD;QACjD,IAAI,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9C,OAAO,SAAS,CAAC;QAClB,CAAC;IACF,CAAC;IAED,yFAAyF;IACzF,OAAO,IAAI,CAAC;AACb,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RouteMapping } from "./base-route-map.js";
|
|
1
2
|
export { RouterBridgeBase } from "./router-bridge-base.js";
|
|
2
3
|
export type { RouteWatcherHandle } from "./router-bridge-base.js";
|
|
3
4
|
export { sanitizePathname, buildPlayRouteEvent, extractQuery, extractRouteParams, } from "./router-sync.js";
|
|
@@ -10,7 +11,11 @@ export { getNavigableRoutes, getRoutableRoutes, routeExists, getTransitionReacha
|
|
|
10
11
|
export { machineToGraph } from "./machine-to-graph.js";
|
|
11
12
|
export type { MachineGraph } from "./machine-to-graph.js";
|
|
12
13
|
export type { RouteInfo, RouteNode, RouteTree, RouteObject, RouteMetadata, PlayRouteEvent, RoutableActor, PlayActor, RouterBridge, MachineNodeData, MachineEdgeData, WindowLike, LocationLike, } from "./types.js";
|
|
13
|
-
export { RouteMap, type RouteMapping
|
|
14
|
+
export { RouteMap, type RouteMapping } from "./base-route-map.js";
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated Use {@link RouteMapping}. Will be removed in the next major.
|
|
17
|
+
*/
|
|
18
|
+
export type BaseRouteMapping = RouteMapping;
|
|
14
19
|
export { createRouteMap } from "./create-route-map.js";
|
|
15
20
|
export type { RouteMapOptions } from "./create-route-map.js";
|
|
16
21
|
export { createRouteMapFromTree } from "./create-route-map-from-tree.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAGlE,OAAO,EACN,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,GAClB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAG/E,OAAO,EACN,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EACN,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,4BAA4B,EAC5B,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,YAAY,EACX,SAAS,EACT,SAAS,EACT,SAAS,EACT,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,SAAS,EACT,YAAY,EACZ,eAAe,EACf,eAAe,EACf,UAAU,EACV,YAAY,GACZ,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAI5C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAGzE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
// RouterBridgeBase — public API
|
|
1
|
+
// RouterBridgeBase — the public API of an adapter of the community
|
|
2
2
|
export { RouterBridgeBase } from "./router-bridge-base.js";
|
|
3
|
-
//
|
|
3
|
+
// The router sync utilities — play-dom-router uses them, and also each adapter that passes around syncActorFromRouter()
|
|
4
4
|
export { sanitizePathname, buildPlayRouteEvent, extractQuery, extractRouteParams, } from "./router-sync.js";
|
|
5
|
-
//
|
|
5
|
+
// The route utilities
|
|
6
6
|
export { validateRouteFormat, validateStateExists, detectDuplicateRoutes, } from "./validate-routes.js";
|
|
7
7
|
export { buildRouteTree } from "./build-tree.js";
|
|
8
8
|
export { extractMachineRoutes } from "./extract-routes.js";
|
|
9
9
|
export { getNavigableRoutes, getRoutableRoutes, routeExists, getTransitionReachableRoutes, isRouteReachable, } from "./query.js";
|
|
10
|
-
//
|
|
10
|
+
// The graph adapter — it converts an XState machine into a Graph of @statelyai/graph
|
|
11
11
|
export { machineToGraph } from "./machine-to-graph.js";
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
//
|
|
12
|
+
// The shared base class of the route map for both directions.
|
|
13
|
+
// This module exports RouteMapping directly. BaseRouteMapping stays as an alias, for
|
|
14
|
+
// the compatibility.
|
|
15
|
+
export { RouteMap } from "./base-route-map.js";
|
|
16
|
+
// The factories: each one creates a RouteMap from a machine or from a route tree.
|
|
17
|
+
// Every RouterBridgeBase adapter uses them, and it writes no factory of its own.
|
|
17
18
|
export { createRouteMap } from "./create-route-map.js";
|
|
18
19
|
export { createRouteMapFromTree } from "./create-route-map-from-tree.js";
|
|
19
|
-
//
|
|
20
|
+
// The helpers of a route lookup. matchesPattern stays private inside find-route.ts
|
|
20
21
|
export { findRouteById, findRouteByPath } from "./find-route.js";
|
|
21
22
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,mEAAmE;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG3D,wHAAwH;AACxH,OAAO,EACN,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,sBAAsB;AACtB,OAAO,EACN,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,GACrB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EACN,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,4BAA4B,EAC5B,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,qFAAqF;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAmBvD,8DAA8D;AAC9D,qFAAqF;AACrF,qBAAqB;AACrB,OAAO,EAAE,QAAQ,EAAqB,MAAM,qBAAqB,CAAC;AAOlE,kFAAkF;AAClF,iFAAiF;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAEzE,mFAAmF;AACnF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -2,8 +2,9 @@ import type { AnyStateMachine } from "xstate";
|
|
|
2
2
|
import { type Graph } from "@statelyai/graph";
|
|
3
3
|
import type { MachineNodeData, MachineEdgeData } from "./types.js";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* The typed Graph of @statelyai/graph that represents a state machine.
|
|
6
|
+
* It gives you the queries of the hierarchy, the algorithms of a walk, and the tests
|
|
7
|
+
* of the reachability.
|
|
7
8
|
*
|
|
8
9
|
* @example
|
|
9
10
|
* ```typescript
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machine-to-graph.d.ts","sourceRoot":"","sources":["../src/machine-to-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGnE
|
|
1
|
+
{"version":3,"file":"machine-to-graph.d.ts","sourceRoot":"","sources":["../src/machine-to-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGnE;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;AAsDnE,eAAO,MAAM,cAAc,GAAI,SAAS,eAAe,KAAG,YAwEzD,CAAC"}
|
package/dist/machine-to-graph.js
CHANGED
|
@@ -2,21 +2,21 @@ import { toDirectedGraph } from "xstate/graph";
|
|
|
2
2
|
import { createGraph } from "@statelyai/graph";
|
|
3
3
|
import { UnknownStateTypeError } from "./errors.js";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Converts an XState v5 state machine into a typed Graph of @statelyai/graph.
|
|
6
6
|
*
|
|
7
|
-
* The conversion
|
|
8
|
-
* `XState Machine → toDirectedGraph() →
|
|
7
|
+
* The pipeline of the conversion is:
|
|
8
|
+
* `XState Machine → toDirectedGraph() → the hierarchy of the DirectedGraphNode objects → createGraph() → Graph`
|
|
9
9
|
*
|
|
10
|
-
* The
|
|
11
|
-
* - **
|
|
12
|
-
* - **
|
|
13
|
-
* - **
|
|
10
|
+
* The graph of the result holds three things:
|
|
11
|
+
* - **The hierarchy**: the parentId of a node shows the compound nesting and the parallel nesting of XState
|
|
12
|
+
* - **The edges**: every transition, with its event types and with its optional guard types
|
|
13
|
+
* - **The metadata**: the state type, the meta object, and the route path from the extraction
|
|
14
14
|
*
|
|
15
|
-
* @param machine - XState v5 state machine
|
|
16
|
-
* @returns
|
|
15
|
+
* @param machine - The XState v5 state machine, in each shape
|
|
16
|
+
* @returns The typed directed graph, with a MachineNodeData object on each node and a MachineEdgeData object on each edge
|
|
17
17
|
*
|
|
18
18
|
* @example
|
|
19
|
-
*
|
|
19
|
+
* The conversion of a simple machine, and a query of its routes
|
|
20
20
|
* ```typescript
|
|
21
21
|
* import { createMachine } from "xstate";
|
|
22
22
|
* import { getChildren, getSuccessors } from "@statelyai/graph";
|
|
@@ -36,13 +36,14 @@ import { UnknownStateTypeError } from "./errors.js";
|
|
|
36
36
|
* const successors = getSuccessors(graph, "app.home"); // [about]
|
|
37
37
|
* ```
|
|
38
38
|
*
|
|
39
|
-
* @see {@link MachineNodeData} for
|
|
40
|
-
* @see {@link MachineEdgeData} for
|
|
41
|
-
* @see https://github.com/statelyai/graph for @statelyai/graph
|
|
39
|
+
* @see {@link MachineNodeData} for the shape of the data of a node
|
|
40
|
+
* @see {@link MachineEdgeData} for the shape of the data of an edge
|
|
41
|
+
* @see https://github.com/statelyai/graph for the API reference of @statelyai/graph
|
|
42
42
|
*/
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
44
|
+
* The set of the valid XState state types, for the check at run time.
|
|
45
|
+
* It guards against a later change of XState, and against a machine shape that the
|
|
46
|
+
* package does not expect.
|
|
46
47
|
*/
|
|
47
48
|
const VALID_STATE_TYPES = new Set([
|
|
48
49
|
"atomic",
|
|
@@ -53,7 +54,7 @@ const VALID_STATE_TYPES = new Set([
|
|
|
53
54
|
]);
|
|
54
55
|
export const machineToGraph = (machine) => {
|
|
55
56
|
const dg = toDirectedGraph(machine);
|
|
56
|
-
//
|
|
57
|
+
// Convert the hierarchy of the DirectedGraphNode objects into a flat array of nodes and a flat array of edges
|
|
57
58
|
const nodes = [];
|
|
58
59
|
const edges = [];
|
|
59
60
|
let edgeCounter = 0;
|
|
@@ -66,7 +67,7 @@ export const machineToGraph = (machine) => {
|
|
|
66
67
|
: typeof metaRoute === "object" && metaRoute !== null && "path" in metaRoute
|
|
67
68
|
? metaRoute.path
|
|
68
69
|
: undefined;
|
|
69
|
-
//
|
|
70
|
+
// An assertion at run time: check the state type before the cast
|
|
70
71
|
if (!VALID_STATE_TYPES.has(sn.type)) {
|
|
71
72
|
throw new UnknownStateTypeError(sn.type, sn.id, [...VALID_STATE_TYPES]);
|
|
72
73
|
}
|
|
@@ -84,7 +85,7 @@ export const machineToGraph = (machine) => {
|
|
|
84
85
|
else {
|
|
85
86
|
nodes.push({ id: dgNode.id, data: nodeData });
|
|
86
87
|
}
|
|
87
|
-
// Collect edges
|
|
88
|
+
// Collect the edges of THIS node. An edge is on its source node, and not on the root of the graph
|
|
88
89
|
for (const edge of dgNode.edges) {
|
|
89
90
|
const edgeData = {
|
|
90
91
|
eventType: edge.label.text,
|
|
@@ -99,7 +100,7 @@ export const machineToGraph = (machine) => {
|
|
|
99
100
|
data: edgeData,
|
|
100
101
|
});
|
|
101
102
|
}
|
|
102
|
-
//
|
|
103
|
+
// Walk into the children, with this node as their parent
|
|
103
104
|
for (const child of dgNode.children) {
|
|
104
105
|
walk(child, dgNode.id);
|
|
105
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machine-to-graph.js","sourceRoot":"","sources":["../src/machine-to-graph.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAA0B,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"machine-to-graph.js","sourceRoot":"","sources":["../src/machine-to-graph.ts"],"names":[],"mappings":"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"}
|
package/dist/query.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { Graph } from "@statelyai/graph";
|
|
2
2
|
import type { RouteTree, RouteNode, MachineNodeData, MachineEdgeData } from "./types.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Returns every route of a navigation from the given state
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* The function returns the child routes of the state. A later version also returns
|
|
7
|
+
* the sibling routes of a transition.
|
|
8
8
|
*
|
|
9
|
-
* @param tree -
|
|
10
|
-
* @param stateId -
|
|
11
|
-
* @returns
|
|
9
|
+
* @param tree - The route tree, from extractMachineRoutes()
|
|
10
|
+
* @param stateId - The ID of the current state
|
|
11
|
+
* @returns The array of the route nodes that the state can reach
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```typescript
|
|
@@ -19,14 +19,14 @@ import type { RouteTree, RouteNode, MachineNodeData, MachineEdgeData } from "./t
|
|
|
19
19
|
*/
|
|
20
20
|
export declare const getNavigableRoutes: (tree: RouteTree, stateId: string) => RouteNode[];
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Returns every route of the tree that has a route, in one flat array
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* The function returns each route with a `meta.route` field. It returns no state
|
|
25
|
+
* without a route, and no synthetic root node. Use it to generate a router
|
|
26
|
+
* configuration in a framework adapter dynamically.
|
|
27
27
|
*
|
|
28
|
-
* @param tree -
|
|
29
|
-
* @returns
|
|
28
|
+
* @param tree - The route tree, from extractMachineRoutes()
|
|
29
|
+
* @returns The array of the route nodes with a route, with their path and their stateId
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* ```typescript
|
|
@@ -41,58 +41,60 @@ export declare const getNavigableRoutes: (tree: RouteTree, stateId: string) => R
|
|
|
41
41
|
*/
|
|
42
42
|
export declare const getRoutableRoutes: (tree: RouteTree) => RouteNode[];
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
44
|
+
* Tells you if a route path is in the tree
|
|
45
45
|
*
|
|
46
|
-
*
|
|
46
|
+
* The function tests if the path has a state with a `meta.route` field.
|
|
47
47
|
*
|
|
48
|
-
* @param tree -
|
|
49
|
-
* @param path -
|
|
50
|
-
* @returns true
|
|
48
|
+
* @param tree - The route tree, from extractMachineRoutes()
|
|
49
|
+
* @param path - The complete route path, for example '/dashboard/settings'
|
|
50
|
+
* @returns true when the tree holds the path. In every other case, false
|
|
51
51
|
*/
|
|
52
52
|
export declare const routeExists: (tree: RouteTree, path: string) => boolean;
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* Returns the routes that a transition from the current state can reach
|
|
55
55
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
56
|
+
* The function uses the successor algorithm of @statelyai/graph. It finds every
|
|
57
|
+
* state of a direct transition edge from the given state, then it keeps the states
|
|
58
|
+
* with a route.
|
|
59
59
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* `tree.byPath
|
|
63
|
-
* resolves
|
|
60
|
+
* The values of the return are the RAW `meta.route` strings of the machine. The
|
|
61
|
+
* function does NOT resolve a relative route, for example `"detail"`, to a complete
|
|
62
|
+
* path, and such a value is therefore no key of `tree.byPath`. For a resolved
|
|
63
|
+
* `RouteNode`, use `getNavigableRoutes`: that function resolves each state that the
|
|
64
|
+
* transition reaches through `tree.byStateId`.
|
|
64
65
|
*
|
|
65
|
-
* @param graph -
|
|
66
|
-
* @param stateId -
|
|
67
|
-
* @returns
|
|
66
|
+
* @param graph - The machine graph, from RouteTree.graph
|
|
67
|
+
* @param stateId - The ID of the current state, for example "test.home"
|
|
68
|
+
* @returns The array of the raw route strings that a transition can reach
|
|
68
69
|
*
|
|
69
70
|
* @example
|
|
70
71
|
* ```typescript
|
|
71
72
|
* const tree = extractMachineRoutes(machine);
|
|
72
73
|
* if (tree.graph) {
|
|
73
74
|
* const reachable = getTransitionReachableRoutes(tree.graph, 'auth.loggedIn');
|
|
74
|
-
* // ['/dashboard', '/settings'] — routes
|
|
75
|
+
* // ['/dashboard', '/settings'] — the routes that a transition can reach
|
|
75
76
|
* }
|
|
76
77
|
* ```
|
|
77
78
|
*/
|
|
78
79
|
export declare const getTransitionReachableRoutes: (graph: Graph<MachineNodeData, MachineEdgeData>, stateId: string) => string[];
|
|
79
80
|
/**
|
|
80
|
-
*
|
|
81
|
+
* Tells you if a transition from the current state can reach a route
|
|
81
82
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
83
|
+
* The function uses the path search of @statelyai/graph. It decides if a chain of
|
|
84
|
+
* transition edges is present from the state of the origin to the state of the
|
|
85
|
+
* target.
|
|
84
86
|
*
|
|
85
|
-
* @param graph -
|
|
86
|
-
* @param fromStateId -
|
|
87
|
-
* @param toStateId -
|
|
88
|
-
* @returns true
|
|
87
|
+
* @param graph - The machine graph, from RouteTree.graph
|
|
88
|
+
* @param fromStateId - The ID of the state of the origin
|
|
89
|
+
* @param toStateId - The ID of the state of the target
|
|
90
|
+
* @returns true when a transition path is present. In every other case, false
|
|
89
91
|
*
|
|
90
92
|
* @example
|
|
91
93
|
* ```typescript
|
|
92
94
|
* const tree = extractMachineRoutes(machine);
|
|
93
95
|
* if (tree.graph) {
|
|
94
96
|
* const canReach = isRouteReachable(tree.graph, 'auth.login', 'auth.dashboard');
|
|
95
|
-
* // true
|
|
97
|
+
* // it is true when a transition path from login to dashboard is present
|
|
96
98
|
* }
|
|
97
99
|
* ```
|
|
98
100
|
*/
|
package/dist/query.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAa,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqBzF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,EAAE,SAAS,MAAM,KAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAa,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqBzF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,EAAE,SAAS,MAAM,KAAG,SAAS,EA0B9E,CAAC;AAkBF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,SAAS,KAAG,SAAS,EAW5D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,SAAS,EAAE,MAAM,MAAM,KAAG,OAE3D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,4BAA4B,GACxC,OAAO,KAAK,CAAC,eAAe,EAAE,eAAe,CAAC,EAC9C,SAAS,MAAM,KACb,MAAM,EAER,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,gBAAgB,GAC5B,OAAO,KAAK,CAAC,eAAe,EAAE,eAAe,CAAC,EAC9C,aAAa,MAAM,EACnB,WAAW,MAAM,KACf,OAKF,CAAC"}
|