@xmachines/play-router 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 +73 -16
- package/dist/base-route-map.js +240 -270
- package/dist/base-route-map.js.map +1 -1
- package/dist/build-tree.js +84 -96
- package/dist/build-tree.js.map +1 -1
- package/dist/create-route-map-from-tree.js +50 -47
- package/dist/create-route-map-from-tree.js.map +1 -1
- package/dist/errors.js +124 -133
- package/dist/errors.js.map +1 -1
- package/dist/find-route.js +88 -105
- package/dist/find-route.js.map +1 -1
- package/dist/index.js +10 -28
- package/dist/provider-lifecycle.js +109 -143
- package/dist/provider-lifecycle.js.map +1 -1
- package/dist/router-bridge-base.d.ts +4 -4
- package/dist/router-bridge-base.d.ts.map +1 -1
- package/dist/router-bridge-base.js +1026 -1601
- package/dist/router-bridge-base.js.map +1 -1
- package/dist/router-sync.js +107 -139
- package/dist/router-sync.js.map +1 -1
- package/dist/validate-routes.js +58 -66
- package/dist/validate-routes.js.map +1 -1
- package/dist/xstate/create-route-map.js +36 -35
- package/dist/xstate/create-route-map.js.map +1 -1
- package/dist/xstate/extract-routes.js +66 -83
- package/dist/xstate/extract-routes.js.map +1 -1
- package/dist/xstate/index.js +5 -33
- package/dist/xstate/machine-to-graph.js +98 -109
- package/dist/xstate/machine-to-graph.js.map +1 -1
- package/dist/xstate/query.js +190 -212
- package/dist/xstate/query.js.map +1 -1
- package/package.json +16 -16
- package/dist/index.js.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/xstate/index.js.map +0 -1
- package/dist/xstate/machine-types.js +0 -2
- package/dist/xstate/machine-types.js.map +0 -1
package/dist/build-tree.js
CHANGED
|
@@ -1,101 +1,89 @@
|
|
|
1
1
|
import { detectDuplicateRoutes } from "./validate-routes.js";
|
|
2
|
+
//#region packages/play-router/src/build-tree.ts
|
|
2
3
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
* The ID and the state ID of the synthetic root node of every `RouteTree`.
|
|
5
|
+
*
|
|
6
|
+
* `buildRouteTree` always makes this node, and no state of a machine declares it. It
|
|
7
|
+
* gives the tree one parent for each absolute route, and it holds `routable: false`.
|
|
8
|
+
*
|
|
9
|
+
* A consumer that walks a tree must SKIP this node. `createRouteMapFromTree` skips it,
|
|
10
|
+
* and `getRoutableRoutes` of `@xmachines/play-router/xstate` skips it. A walk that keeps
|
|
11
|
+
* it maps the path `/` to a state that the machine does not hold.
|
|
12
|
+
*/
|
|
13
|
+
var ROOT_NODE_ID = "__root__";
|
|
13
14
|
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
};
|
|
85
|
-
// Add the pattern, when one is present
|
|
86
|
-
if (route.pattern) {
|
|
87
|
-
node.pattern = route.pattern;
|
|
88
|
-
}
|
|
89
|
-
// Link the node to its parent
|
|
90
|
-
parentNode.children.push(node);
|
|
91
|
-
// Put the node in the maps, for the lookup in both directions
|
|
92
|
-
byStateId.set(node.stateId, node);
|
|
93
|
-
byPath.set(node.fullPath, node);
|
|
94
|
-
insertedNodes.push(node);
|
|
95
|
-
}
|
|
96
|
-
// 5. Refuse a collision of two resolved complete paths. A silent overwrite in
|
|
97
|
-
// byPath leaves one state without a URL.
|
|
98
|
-
detectDuplicateRoutes(insertedNodes);
|
|
99
|
-
return { root, byStateId, byPath };
|
|
15
|
+
* Builds the hierarchical route tree from the flat list of the routes
|
|
16
|
+
*
|
|
17
|
+
* The function makes a nested tree, and it keeps the parent-child relation of the
|
|
18
|
+
* states. An absolute route becomes a route of the top level, and a relative route
|
|
19
|
+
* goes below its parent. The function also makes the maps of both directions, for
|
|
20
|
+
* the lookup between a state ID and a path.
|
|
21
|
+
*
|
|
22
|
+
* The detection of a duplicate runs here, after the function resolved each relative
|
|
23
|
+
* route against the complete path of its parent. Therefore two relative routes with
|
|
24
|
+
* the same raw string below two different parents are valid, and two different raw
|
|
25
|
+
* strings that resolve to the same complete path are not: those two overwrite each
|
|
26
|
+
* other in `byPath` in silence.
|
|
27
|
+
*
|
|
28
|
+
* `TGraph` names the type of the graph that a CALLER attaches afterwards. The builder
|
|
29
|
+
* attaches none: it reads a list of routes and writes the maps of the tree.
|
|
30
|
+
* `extractMachineRoutes` of `@xmachines/play-router/xstate` binds it to `MachineGraph`.
|
|
31
|
+
*
|
|
32
|
+
* @param routes - The flat list of the RouteInfo objects, from the extraction
|
|
33
|
+
* @returns The RouteTree, with its root, its byStateId map, and its byPath map
|
|
34
|
+
* @throws {DuplicateRoutePathError} When two states resolve to the same complete path
|
|
35
|
+
*/
|
|
36
|
+
var buildRouteTree = (routes) => {
|
|
37
|
+
const root = {
|
|
38
|
+
id: ROOT_NODE_ID,
|
|
39
|
+
path: "/",
|
|
40
|
+
fullPath: "/",
|
|
41
|
+
stateId: ROOT_NODE_ID,
|
|
42
|
+
routable: false,
|
|
43
|
+
children: [],
|
|
44
|
+
parent: null,
|
|
45
|
+
metadata: ""
|
|
46
|
+
};
|
|
47
|
+
const byStateId = /* @__PURE__ */ new Map([[root.stateId, root]]);
|
|
48
|
+
const byPath = /* @__PURE__ */ new Map([[root.fullPath, root]]);
|
|
49
|
+
const sorted = routes.toSorted((a, b) => a.statePath.length - b.statePath.length);
|
|
50
|
+
const insertedNodes = [];
|
|
51
|
+
for (const route of sorted) {
|
|
52
|
+
let parentNode = root;
|
|
53
|
+
for (let i = route.statePath.length - 2; i >= 0; i--) {
|
|
54
|
+
const parentStateId = route.statePath[i];
|
|
55
|
+
if (parentStateId === void 0) continue;
|
|
56
|
+
const candidate = byStateId.get(parentStateId);
|
|
57
|
+
if (candidate !== void 0) {
|
|
58
|
+
parentNode = candidate;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const fullPath = route.isAbsolute ? route.routePath : `${parentNode.fullPath}/${route.routePath}`.replace(/\/+/g, "/");
|
|
63
|
+
const node = {
|
|
64
|
+
id: route.stateId,
|
|
65
|
+
path: route.routePath,
|
|
66
|
+
fullPath,
|
|
67
|
+
stateId: route.stateId,
|
|
68
|
+
routable: route.routable,
|
|
69
|
+
children: [],
|
|
70
|
+
parent: parentNode,
|
|
71
|
+
metadata: route.metadata
|
|
72
|
+
};
|
|
73
|
+
if (route.pattern) node.pattern = route.pattern;
|
|
74
|
+
parentNode.children.push(node);
|
|
75
|
+
byStateId.set(node.stateId, node);
|
|
76
|
+
byPath.set(node.fullPath, node);
|
|
77
|
+
insertedNodes.push(node);
|
|
78
|
+
}
|
|
79
|
+
detectDuplicateRoutes(insertedNodes);
|
|
80
|
+
return {
|
|
81
|
+
root,
|
|
82
|
+
byStateId,
|
|
83
|
+
byPath
|
|
84
|
+
};
|
|
100
85
|
};
|
|
86
|
+
//#endregion
|
|
87
|
+
export { ROOT_NODE_ID, buildRouteTree };
|
|
88
|
+
|
|
101
89
|
//# sourceMappingURL=build-tree.js.map
|
package/dist/build-tree.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-tree.js","
|
|
1
|
+
{"version":3,"file":"build-tree.js","names":[],"sources":["../src/build-tree.ts"],"sourcesContent":["import type { RouteInfo, RouteNode, RouteTree } from \"./types.js\";\nimport { detectDuplicateRoutes } from \"./validate-routes.js\";\n\n/**\n * The ID and the state ID of the synthetic root node of every `RouteTree`.\n *\n * `buildRouteTree` always makes this node, and no state of a machine declares it. It\n * gives the tree one parent for each absolute route, and it holds `routable: false`.\n *\n * A consumer that walks a tree must SKIP this node. `createRouteMapFromTree` skips it,\n * and `getRoutableRoutes` of `@xmachines/play-router/xstate` skips it. A walk that keeps\n * it maps the path `/` to a state that the machine does not hold.\n */\nexport const ROOT_NODE_ID = \"__root__\";\n\n/**\n * Builds the hierarchical route tree from the flat list of the routes\n *\n * The function makes a nested tree, and it keeps the parent-child relation of the\n * states. An absolute route becomes a route of the top level, and a relative route\n * goes below its parent. The function also makes the maps of both directions, for\n * the lookup between a state ID and a path.\n *\n * The detection of a duplicate runs here, after the function resolved each relative\n * route against the complete path of its parent. Therefore two relative routes with\n * the same raw string below two different parents are valid, and two different raw\n * strings that resolve to the same complete path are not: those two overwrite each\n * other in `byPath` in silence.\n *\n * `TGraph` names the type of the graph that a CALLER attaches afterwards. The builder\n * attaches none: it reads a list of routes and writes the maps of the tree.\n * `extractMachineRoutes` of `@xmachines/play-router/xstate` binds it to `MachineGraph`.\n *\n * @param routes - The flat list of the RouteInfo objects, from the extraction\n * @returns The RouteTree, with its root, its byStateId map, and its byPath map\n * @throws {DuplicateRoutePathError} When two states resolve to the same complete path\n */\nexport const buildRouteTree = <TGraph = unknown>(routes: RouteInfo[]): RouteTree<TGraph> => {\n\t// 1. Create the root node\n\tconst root: RouteNode = {\n\t\tid: ROOT_NODE_ID,\n\t\tpath: \"/\",\n\t\tfullPath: \"/\",\n\t\tstateId: ROOT_NODE_ID,\n\t\troutable: false, // The root is a state without a route\n\t\tchildren: [],\n\t\tparent: null,\n\t\tmetadata: \"\", // The synthetic root has no route, and therefore no real route metadata\n\t};\n\n\t// 2. Initialize the maps\n\tconst byStateId = new Map<string, RouteNode>([[root.stateId, root]]);\n\tconst byPath = new Map<string, RouteNode>([[root.fullPath, root]]);\n\n\t// 3. Sort the routes by their depth. The shallowest route comes first, for the link to each parent\n\tconst sorted = routes.toSorted((a, b) => a.statePath.length - b.statePath.length);\n\n\t// 4. Build the tree, and collect each node for the detection of a duplicate resolved path\n\tconst insertedNodes: RouteNode[] = [];\n\tfor (const route of sorted) {\n\t\t// Find the parent, and walk up the state path.\n\t\t// Each entry of statePath is a complete dotted stateId, for example\n\t\t// \"chain.app.section\". Therefore the code tests each ancestor stateId directly,\n\t\t// from the end of the list.\n\t\tlet parentNode = root;\n\t\tfor (let i = route.statePath.length - 2; i >= 0; i--) {\n\t\t\tconst parentStateId = route.statePath[i]; // nosemgrep: gitlab.eslint.detect-object-injection\n\t\t\tif (parentStateId === undefined) continue;\n\t\t\tconst candidate = byStateId.get(parentStateId);\n\t\t\tif (candidate !== undefined) {\n\t\t\t\tparentNode = candidate;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Build the complete path\n\t\tconst fullPath = route.isAbsolute\n\t\t\t? route.routePath\n\t\t\t: `${parentNode.fullPath}/${route.routePath}`.replace(/\\/+/g, \"/\");\n\n\t\t// Create the node\n\t\tconst node: RouteNode = {\n\t\t\tid: route.stateId,\n\t\t\tpath: route.routePath,\n\t\t\tfullPath,\n\t\t\tstateId: route.stateId,\n\t\t\troutable: route.routable,\n\t\t\tchildren: [],\n\t\t\tparent: parentNode,\n\t\t\tmetadata: route.metadata,\n\t\t};\n\n\t\t// Add the pattern, when one is present\n\t\tif (route.pattern) {\n\t\t\tnode.pattern = route.pattern;\n\t\t}\n\n\t\t// Link the node to its parent\n\t\tparentNode.children.push(node);\n\n\t\t// Put the node in the maps, for the lookup in both directions\n\t\tbyStateId.set(node.stateId, node);\n\t\tbyPath.set(node.fullPath, node);\n\t\tinsertedNodes.push(node);\n\t}\n\n\t// 5. Refuse a collision of two resolved complete paths. A silent overwrite in\n\t// byPath leaves one state without a URL.\n\tdetectDuplicateRoutes(insertedNodes);\n\n\treturn { root, byStateId, byPath };\n};\n"],"mappings":";;;;;;;;;;;;AAaA,IAAa,eAAe;;;;;;;;;;;;;;;;;;;;;;;AAwB5B,IAAa,kBAAoC,WAA2C;CAE3F,MAAM,OAAkB;EACvB,IAAI;EACJ,MAAM;EACN,UAAU;EACV,SAAS;EACT,UAAU;EACV,UAAU,CAAC;EACX,QAAQ;EACR,UAAU;CACX;CAGA,MAAM,4BAAY,IAAI,IAAuB,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC;CACnE,MAAM,yBAAS,IAAI,IAAuB,CAAC,CAAC,KAAK,UAAU,IAAI,CAAC,CAAC;CAGjE,MAAM,SAAS,OAAO,UAAU,GAAG,MAAM,EAAE,UAAU,SAAS,EAAE,UAAU,MAAM;CAGhF,MAAM,gBAA6B,CAAC;CACpC,KAAK,MAAM,SAAS,QAAQ;EAK3B,IAAI,aAAa;EACjB,KAAK,IAAI,IAAI,MAAM,UAAU,SAAS,GAAG,KAAK,GAAG,KAAK;GACrD,MAAM,gBAAgB,MAAM,UAAU;GACtC,IAAI,kBAAkB,KAAA,GAAW;GACjC,MAAM,YAAY,UAAU,IAAI,aAAa;GAC7C,IAAI,cAAc,KAAA,GAAW;IAC5B,aAAa;IACb;GACD;EACD;EAGA,MAAM,WAAW,MAAM,aACpB,MAAM,YACN,GAAG,WAAW,SAAS,GAAG,MAAM,YAAY,QAAQ,QAAQ,GAAG;EAGlE,MAAM,OAAkB;GACvB,IAAI,MAAM;GACV,MAAM,MAAM;GACZ;GACA,SAAS,MAAM;GACf,UAAU,MAAM;GAChB,UAAU,CAAC;GACX,QAAQ;GACR,UAAU,MAAM;EACjB;EAGA,IAAI,MAAM,SACT,KAAK,UAAU,MAAM;EAItB,WAAW,SAAS,KAAK,IAAI;EAG7B,UAAU,IAAI,KAAK,SAAS,IAAI;EAChC,OAAO,IAAI,KAAK,UAAU,IAAI;EAC9B,cAAc,KAAK,IAAI;CACxB;CAIA,sBAAsB,aAAa;CAEnC,OAAO;EAAE;EAAM;EAAW;CAAO;AAClC"}
|
|
@@ -1,51 +1,54 @@
|
|
|
1
1
|
import { RouteMap } from "./base-route-map.js";
|
|
2
|
-
import
|
|
2
|
+
import "./build-tree.js";
|
|
3
|
+
//#region packages/play-router/src/create-route-map-from-tree.ts
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return new RouteMap(routes, options);
|
|
5
|
+
* Creates a `RouteMap` from the node structure of a `RouteTree`.
|
|
6
|
+
*
|
|
7
|
+
* A framework router adapter uses this function when it holds a `RouteTree`, for example
|
|
8
|
+
* from `extractMachineRoutes()` of `@xmachines/play-router/xstate`, and not when it calls
|
|
9
|
+
* `createRouteMap()` of that package directly.
|
|
10
|
+
*
|
|
11
|
+
* The function walks every node, and it collects the pairs
|
|
12
|
+
* `{ stateId: node.id, path: node.fullPath }`. `node.fullPath` is always the
|
|
13
|
+
* absolute resolved path, for example `"/dashboard/overview"`, and `RouteMap` needs
|
|
14
|
+
* that path for the match of a browser URL. `createRouteMap(machine)` behaves in the
|
|
15
|
+
* same way, because it also uses `node.fullPath`.
|
|
16
|
+
*
|
|
17
|
+
* The walk SKIPS the synthetic root node. `buildRouteTree` makes that node to hold each
|
|
18
|
+
* absolute route, and no state of a machine declares it. `createRouteMap` skips it as
|
|
19
|
+
* well, through `getRoutableRoutes`, and the two functions therefore answer the same map
|
|
20
|
+
* for the same tree.
|
|
21
|
+
*
|
|
22
|
+
* @param routeTree - A `RouteTree`, as `extractMachineRoutes()` returns it.
|
|
23
|
+
* @param options - The optional configuration, for example `{ pathCache }` to replace the LRU cache of the resolved paths.
|
|
24
|
+
* @returns A `RouteMap` for each adapter on `RouterBridgeBase`.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // The preferred form — one call for an XState machine:
|
|
29
|
+
* import { createRouteMap } from '@xmachines/play-router/xstate';
|
|
30
|
+
* const routeMap = createRouteMap(machine); // it takes an AnyStateMachine
|
|
31
|
+
*
|
|
32
|
+
* // The two-step form, for a framework adapter that works with a route tree:
|
|
33
|
+
* import { createRouteMapFromTree } from '@xmachines/play-router';
|
|
34
|
+
* import { extractMachineRoutes } from '@xmachines/play-router/xstate';
|
|
35
|
+
* const routeTree = extractMachineRoutes(machine);
|
|
36
|
+
* const routeMap = createRouteMapFromTree(routeTree); // it uses node.fullPath, which is absolute
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
function createRouteMapFromTree(routeTree, options) {
|
|
40
|
+
const routes = [];
|
|
41
|
+
function traverse(node) {
|
|
42
|
+
if (node.id && node.fullPath && node.id !== "__root__") routes.push({
|
|
43
|
+
stateId: node.id,
|
|
44
|
+
path: node.fullPath
|
|
45
|
+
});
|
|
46
|
+
if (node.children) node.children.forEach(traverse);
|
|
47
|
+
}
|
|
48
|
+
traverse(routeTree.root);
|
|
49
|
+
return new RouteMap(routes, options);
|
|
50
50
|
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { createRouteMapFromTree };
|
|
53
|
+
|
|
51
54
|
//# sourceMappingURL=create-route-map-from-tree.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-route-map-from-tree.js","
|
|
1
|
+
{"version":3,"file":"create-route-map-from-tree.js","names":[],"sources":["../src/create-route-map-from-tree.ts"],"sourcesContent":["import type { RouteTree, RouteNode, RouteMapOptions } from \"./types.js\";\nimport { RouteMap } from \"./base-route-map.js\";\nimport { ROOT_NODE_ID } from \"./build-tree.js\";\n\n/**\n * Creates a `RouteMap` from the node structure of a `RouteTree`.\n *\n * A framework router adapter uses this function when it holds a `RouteTree`, for example\n * from `extractMachineRoutes()` of `@xmachines/play-router/xstate`, and not when it calls\n * `createRouteMap()` of that package directly.\n *\n * The function walks every node, and it collects the pairs\n * `{ stateId: node.id, path: node.fullPath }`. `node.fullPath` is always the\n * absolute resolved path, for example `\"/dashboard/overview\"`, and `RouteMap` needs\n * that path for the match of a browser URL. `createRouteMap(machine)` behaves in the\n * same way, because it also uses `node.fullPath`.\n *\n * The walk SKIPS the synthetic root node. `buildRouteTree` makes that node to hold each\n * absolute route, and no state of a machine declares it. `createRouteMap` skips it as\n * well, through `getRoutableRoutes`, and the two functions therefore answer the same map\n * for the same tree.\n *\n * @param routeTree - A `RouteTree`, as `extractMachineRoutes()` returns it.\n * @param options - The optional configuration, for example `{ pathCache }` to replace the LRU cache of the resolved paths.\n * @returns A `RouteMap` for each adapter on `RouterBridgeBase`.\n *\n * @example\n * ```typescript\n * // The preferred form — one call for an XState machine:\n * import { createRouteMap } from '@xmachines/play-router/xstate';\n * const routeMap = createRouteMap(machine); // it takes an AnyStateMachine\n *\n * // The two-step form, for a framework adapter that works with a route tree:\n * import { createRouteMapFromTree } from '@xmachines/play-router';\n * import { extractMachineRoutes } from '@xmachines/play-router/xstate';\n * const routeTree = extractMachineRoutes(machine);\n * const routeMap = createRouteMapFromTree(routeTree); // it uses node.fullPath, which is absolute\n * ```\n */\nexport function createRouteMapFromTree(routeTree: RouteTree, options?: RouteMapOptions): RouteMap {\n\tconst routes: Array<{ stateId: string; path: string }> = [];\n\n\tfunction traverse(node: RouteNode): void {\n\t\tif (node.id && node.fullPath && node.id !== ROOT_NODE_ID) {\n\t\t\troutes.push({ stateId: node.id, path: node.fullPath });\n\t\t}\n\t\tif (node.children) {\n\t\t\tnode.children.forEach(traverse);\n\t\t}\n\t}\n\n\ttraverse(routeTree.root);\n\treturn new RouteMap(routes, options);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,uBAAuB,WAAsB,SAAqC;CACjG,MAAM,SAAmD,CAAC;CAE1D,SAAS,SAAS,MAAuB;EACxC,IAAI,KAAK,MAAM,KAAK,YAAY,KAAK,OAAA,YACpC,OAAO,KAAK;GAAE,SAAS,KAAK;GAAI,MAAM,KAAK;EAAS,CAAC;EAEtD,IAAI,KAAK,UACR,KAAK,SAAS,QAAQ,QAAQ;CAEhC;CAEA,SAAS,UAAU,IAAI;CACvB,OAAO,IAAI,SAAS,QAAQ,OAAO;AACpC"}
|
package/dist/errors.js
CHANGED
|
@@ -1,141 +1,132 @@
|
|
|
1
1
|
import { PlayError } from "@xmachines/play/errors";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// routing error from one import, exactly as before the split.
|
|
5
|
-
//
|
|
6
|
-
// The specifier is the `./errors` subpath, and not the root barrel. A consumer that
|
|
7
|
-
// imports `@xmachines/play-router/errors` to name a fault in a `catch` then loads the
|
|
8
|
-
// three classes alone: no pattern parser, no base path, and no `urlpattern-polyfill`. The
|
|
9
|
-
// root barrel of this package reaches the rest of `@xmachines/play-url` for the consumer
|
|
10
|
-
// that needs it.
|
|
11
|
-
export { InvalidRoutePatternError, InvalidBasePathError, MissingBasePathParamError, } from "@xmachines/play-url/errors";
|
|
2
|
+
import { InvalidBasePathError, InvalidRoutePatternError, MissingBasePathParamError } from "@xmachines/play-url/errors";
|
|
3
|
+
//#region packages/play-router/src/errors.ts
|
|
12
4
|
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
5
|
+
* The bridge throws this error when `RouterBridgeBase.syncActorFromRouter()`
|
|
6
|
+
* cannot process a location change of the router and send the `play.route` event to
|
|
7
|
+
* the actor.
|
|
8
|
+
*
|
|
9
|
+
* The `cause` property holds the original error.
|
|
10
|
+
*
|
|
11
|
+
* **Error code:** `PLAY_ROUTER_SYNC_FAILED`
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { RouterSyncError } from "@xmachines/play-router/errors";
|
|
16
|
+
*
|
|
17
|
+
* try {
|
|
18
|
+
* bridge.connect();
|
|
19
|
+
* } catch (err) {
|
|
20
|
+
* if (err instanceof RouterSyncError) {
|
|
21
|
+
* console.error("Router sync failed:", err.message, err.cause);
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
var RouterSyncError = class extends PlayError {
|
|
27
|
+
constructor(message, options) {
|
|
28
|
+
super("RouterBridgeBase", "PLAY_ROUTER_SYNC_FAILED", message, options);
|
|
29
|
+
this.name = "RouterSyncError";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
40
32
|
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
33
|
+
* `RouterBridgeBase.connect()` throws this error when a second bridge connects to an
|
|
34
|
+
* actor with an active bridge connection.
|
|
35
|
+
*
|
|
36
|
+
* One actor can hold one router bridge at a time. Two bridges of the same actor both
|
|
37
|
+
* receive and process every navigation event of the router. They therefore send two
|
|
38
|
+
* `play.route` events to the actor, and their `lastSyncedPath` values of the echo
|
|
39
|
+
* suppression contradict each other.
|
|
40
|
+
*
|
|
41
|
+
* **The remedy:** call `bridge.disconnect()` on the first bridge before you connect
|
|
42
|
+
* the second one. You can also permit one active `connectRouter()` call for each
|
|
43
|
+
* actor at a time.
|
|
44
|
+
*
|
|
45
|
+
* **Error code:** `PLAY_ROUTER_DUPLICATE_BRIDGE`
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* import { DuplicateBridgeError } from "@xmachines/play-router/errors";
|
|
50
|
+
*
|
|
51
|
+
* try {
|
|
52
|
+
* bridge.connect();
|
|
53
|
+
* } catch (err) {
|
|
54
|
+
* if (err instanceof DuplicateBridgeError) {
|
|
55
|
+
* console.error("Actor already has an active router bridge — disconnect first.");
|
|
56
|
+
* }
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
var DuplicateBridgeError = class extends PlayError {
|
|
61
|
+
constructor() {
|
|
62
|
+
super("RouterBridgeBase", "PLAY_ROUTER_DUPLICATE_BRIDGE", "An actor can only be connected to one router bridge at a time. Call disconnect() on the existing bridge before connecting a new one.");
|
|
63
|
+
this.name = "DuplicateBridgeError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
75
66
|
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
67
|
+
* `validateRouteFormat()` throws this error when a state declares a `meta.route`
|
|
68
|
+
* field with an empty string as its path.
|
|
69
|
+
*
|
|
70
|
+
* **Error code:** `PLAY_ROUTE_EMPTY_PATH`
|
|
71
|
+
*/
|
|
72
|
+
var EmptyRoutePathError = class extends PlayError {
|
|
73
|
+
/** The state ID with the empty route path. */
|
|
74
|
+
stateId;
|
|
75
|
+
constructor(stateId) {
|
|
76
|
+
super("RouteMap", "PLAY_ROUTE_EMPTY_PATH", `Empty route path in state "${stateId}": routes must have a non-empty path`);
|
|
77
|
+
this.name = "EmptyRoutePathError";
|
|
78
|
+
this.stateId = stateId;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
90
81
|
/**
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
82
|
+
* `validateStateExists()` throws this error when a route names a state ID that the
|
|
83
|
+
* machine graph does not hold.
|
|
84
|
+
*
|
|
85
|
+
* **Error code:** `PLAY_ROUTE_INVALID_STATE_ID`
|
|
86
|
+
*/
|
|
87
|
+
var InvalidStateIdError = class extends PlayError {
|
|
88
|
+
/** The state ID of the reference. The graph does not hold it. */
|
|
89
|
+
stateId;
|
|
90
|
+
constructor(stateId) {
|
|
91
|
+
super("RouteMap", "PLAY_ROUTE_INVALID_STATE_ID", `Route references non-existent state ID: ${stateId}`);
|
|
92
|
+
this.name = "InvalidStateIdError";
|
|
93
|
+
this.stateId = stateId;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
105
96
|
/**
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
}
|
|
97
|
+
* `detectDuplicateRoutes()` throws this error when two states or more hold the same
|
|
98
|
+
* URL path.
|
|
99
|
+
*
|
|
100
|
+
* **Error code:** `PLAY_ROUTE_DUPLICATE_PATH`
|
|
101
|
+
*/
|
|
102
|
+
var DuplicateRoutePathError = class extends PlayError {
|
|
103
|
+
/** The list of the path → state-ID mappings of the conflict, for a person to read. */
|
|
104
|
+
duplicates;
|
|
105
|
+
constructor(duplicates) {
|
|
106
|
+
super("RouteMap", "PLAY_ROUTE_DUPLICATE_PATH", `Duplicate route paths detected:\n${duplicates.join("\n")}\n\nEach route path must map to exactly one state.\nUse different paths (e.g., /dashboard vs /) or conditional rendering within a single state.`);
|
|
107
|
+
this.name = "DuplicateRoutePathError";
|
|
108
|
+
this.duplicates = duplicates;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
122
111
|
/**
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
112
|
+
* `machineToGraph()` throws this error when an XState state node has a `.type` value
|
|
113
|
+
* that the package does not know.
|
|
114
|
+
*
|
|
115
|
+
* **Error code:** `PLAY_ROUTE_UNKNOWN_STATE_TYPE`
|
|
116
|
+
*/
|
|
117
|
+
var UnknownStateTypeError = class extends PlayError {
|
|
118
|
+
/** The string of the state type that the package does not know. */
|
|
119
|
+
stateType;
|
|
120
|
+
/** The ID of the state node with the unknown type. */
|
|
121
|
+
nodeId;
|
|
122
|
+
constructor(stateType, nodeId, validTypes) {
|
|
123
|
+
super("machineToGraph", "PLAY_ROUTE_UNKNOWN_STATE_TYPE", `Unknown XState state type "${stateType}" on node "${nodeId}". Expected one of: ${validTypes.join(", ")}.`);
|
|
124
|
+
this.name = "UnknownStateTypeError";
|
|
125
|
+
this.stateType = stateType;
|
|
126
|
+
this.nodeId = nodeId;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
//#endregion
|
|
130
|
+
export { DuplicateBridgeError, DuplicateRoutePathError, EmptyRoutePathError, InvalidBasePathError, InvalidRoutePatternError, InvalidStateIdError, MissingBasePathParamError, RouterSyncError, UnknownStateTypeError };
|
|
131
|
+
|
|
141
132
|
//# sourceMappingURL=errors.js.map
|