@xmachines/play-router 1.0.0-beta.2 → 1.0.0-beta.21
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 +169 -47
- package/dist/base-route-map.d.ts +116 -0
- package/dist/base-route-map.d.ts.map +1 -0
- package/dist/base-route-map.js +206 -0
- package/dist/base-route-map.js.map +1 -0
- package/dist/build-tree.d.ts.map +1 -1
- package/dist/build-tree.js +6 -5
- package/dist/build-tree.js.map +1 -1
- package/dist/connect-router.d.ts.map +1 -1
- package/dist/connect-router.js +35 -45
- package/dist/connect-router.js.map +1 -1
- package/dist/create-browser-history.d.ts +38 -5
- package/dist/create-browser-history.d.ts.map +1 -1
- package/dist/create-browser-history.js +43 -17
- package/dist/create-browser-history.js.map +1 -1
- package/dist/create-route-map.d.ts +21 -1
- package/dist/create-route-map.d.ts.map +1 -1
- package/dist/create-route-map.js +73 -22
- package/dist/create-route-map.js.map +1 -1
- package/dist/errors.d.ts +75 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +85 -0
- package/dist/errors.js.map +1 -0
- package/dist/extract-routes.d.ts +5 -31
- package/dist/extract-routes.d.ts.map +1 -1
- package/dist/extract-routes.js +70 -49
- package/dist/extract-routes.js.map +1 -1
- package/dist/find-route.d.ts +44 -0
- package/dist/find-route.d.ts.map +1 -0
- package/dist/find-route.js +126 -0
- package/dist/find-route.js.map +1 -0
- package/dist/index.d.ts +9 -48
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -131
- package/dist/index.js.map +1 -1
- package/dist/machine-to-graph.d.ts +17 -0
- package/dist/machine-to-graph.d.ts.map +1 -0
- package/dist/machine-to-graph.js +115 -0
- package/dist/machine-to-graph.js.map +1 -0
- package/dist/query.d.ts +44 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +80 -3
- package/dist/query.js.map +1 -1
- package/dist/router-bridge-base.d.ts +49 -19
- package/dist/router-bridge-base.d.ts.map +1 -1
- package/dist/router-bridge-base.js +120 -56
- package/dist/router-bridge-base.js.map +1 -1
- package/dist/router-sync.d.ts +62 -0
- package/dist/router-sync.d.ts.map +1 -0
- package/dist/router-sync.js +87 -0
- package/dist/router-sync.js.map +1 -0
- package/dist/types.d.ts +73 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/validate-routes.d.ts +9 -9
- package/dist/validate-routes.d.ts.map +1 -1
- package/dist/validate-routes.js +12 -11
- package/dist/validate-routes.js.map +1 -1
- package/package.json +36 -18
- package/dist/crawl-machine.d.ts +0 -74
- package/dist/crawl-machine.d.ts.map +0 -1
- package/dist/crawl-machine.js +0 -95
- package/dist/crawl-machine.js.map +0 -1
- package/dist/extract-route.d.ts +0 -25
- package/dist/extract-route.d.ts.map +0 -1
- package/dist/extract-route.js +0 -63
- package/dist/extract-route.js.map +0 -1
package/dist/create-route-map.js
CHANGED
|
@@ -1,14 +1,66 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { URLPatternUnavailableError, InvalidRoutePatternError } from "./errors.js";
|
|
2
|
+
function getURLPatternCtor() {
|
|
3
|
+
return globalThis["URLPattern"];
|
|
4
|
+
}
|
|
5
|
+
function getIndexKey(path) {
|
|
6
|
+
const trimmed = path.startsWith("/") ? path.slice(1) : path;
|
|
7
|
+
if (trimmed.length === 0)
|
|
8
|
+
return "/";
|
|
9
|
+
const segment = trimmed.split("/")[0];
|
|
10
|
+
if (segment === undefined || segment.startsWith(":"))
|
|
11
|
+
return "*";
|
|
12
|
+
return segment;
|
|
13
|
+
}
|
|
14
|
+
function getCandidates(patternBuckets, indexKey) {
|
|
15
|
+
const bucket = patternBuckets.get(indexKey) ?? [];
|
|
16
|
+
const wildcardBucket = patternBuckets.get("*") ?? [];
|
|
17
|
+
if (bucket.length === 0)
|
|
18
|
+
return wildcardBucket;
|
|
19
|
+
if (wildcardBucket.length === 0)
|
|
20
|
+
return bucket;
|
|
21
|
+
const merged = [];
|
|
22
|
+
let b = 0;
|
|
23
|
+
let w = 0;
|
|
24
|
+
while (b < bucket.length && w < wildcardBucket.length) {
|
|
25
|
+
if (bucket[b].order < wildcardBucket[w].order) {
|
|
26
|
+
merged.push(bucket[b]);
|
|
27
|
+
b += 1;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
merged.push(wildcardBucket[w]);
|
|
31
|
+
w += 1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
while (b < bucket.length) {
|
|
35
|
+
merged.push(bucket[b]);
|
|
36
|
+
b += 1;
|
|
37
|
+
}
|
|
38
|
+
while (w < wildcardBucket.length) {
|
|
39
|
+
merged.push(wildcardBucket[w]);
|
|
40
|
+
w += 1;
|
|
41
|
+
}
|
|
42
|
+
return merged;
|
|
43
|
+
}
|
|
2
44
|
/**
|
|
3
45
|
* Create a RouteMap from a RouteTree for efficient path lookups.
|
|
4
46
|
*
|
|
5
47
|
* Architecture:
|
|
6
48
|
* - Pure function - no side effects
|
|
7
49
|
* - O(1) lookups for exact matches via Map
|
|
8
|
-
* - O(
|
|
50
|
+
* - O(k) bucket-indexed pattern matching with URLPattern, where k = routes in the
|
|
51
|
+
* first-segment bucket (typically << total routes)
|
|
9
52
|
* - Returns formatted state IDs (with # prefix)
|
|
10
53
|
* - Extracts params from matched patterns
|
|
11
54
|
*
|
|
55
|
+
* **URLPattern requirement:** Dynamic route pattern matching requires `URLPattern`
|
|
56
|
+
* to be available on `globalThis`. On Node.js < 24 and older browsers, load a polyfill
|
|
57
|
+
* before calling this function:
|
|
58
|
+
* ```typescript
|
|
59
|
+
* import "urlpattern-polyfill"; // before importing @xmachines/play-router
|
|
60
|
+
* ```
|
|
61
|
+
* If `URLPattern` is unavailable, a `URLPatternUnavailableError` is thrown.
|
|
62
|
+
* Static (exact) routes are unaffected by URLPattern availability.
|
|
63
|
+
*
|
|
12
64
|
* Usage:
|
|
13
65
|
* ```typescript
|
|
14
66
|
* const routeTree = extractMachineRoutes(machine);
|
|
@@ -21,18 +73,24 @@ import { URLPattern } from "urlpattern-polyfill";
|
|
|
21
73
|
* ```
|
|
22
74
|
*/
|
|
23
75
|
export function createRouteMap(routeTree) {
|
|
24
|
-
// Build pattern matchers for routes with dynamic segments
|
|
25
|
-
const
|
|
26
|
-
|
|
76
|
+
// Build bucket-indexed pattern matchers for routes with dynamic segments
|
|
77
|
+
const patternBuckets = new Map();
|
|
78
|
+
let patternOrder = 0;
|
|
79
|
+
const URLPatternCtor = getURLPatternCtor();
|
|
27
80
|
function collectPatterns(node) {
|
|
28
81
|
if (node.routable && node.pattern) {
|
|
82
|
+
if (!URLPatternCtor) {
|
|
83
|
+
throw new URLPatternUnavailableError();
|
|
84
|
+
}
|
|
29
85
|
try {
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
86
|
+
const urlPattern = new URLPatternCtor({ pathname: node.pattern });
|
|
87
|
+
const bucketKey = getIndexKey(node.pattern);
|
|
88
|
+
const bucket = patternBuckets.get(bucketKey) ?? [];
|
|
89
|
+
bucket.push({ pattern: urlPattern, node, order: patternOrder++ });
|
|
90
|
+
patternBuckets.set(bucketKey, bucket);
|
|
33
91
|
}
|
|
34
92
|
catch (err) {
|
|
35
|
-
|
|
93
|
+
throw new InvalidRoutePatternError(node.pattern, { cause: err });
|
|
36
94
|
}
|
|
37
95
|
}
|
|
38
96
|
for (const child of node.children) {
|
|
@@ -42,30 +100,23 @@ export function createRouteMap(routeTree) {
|
|
|
42
100
|
collectPatterns(routeTree.root);
|
|
43
101
|
return {
|
|
44
102
|
resolve(path) {
|
|
45
|
-
//
|
|
103
|
+
// O(1) exact match via routeTree.byPath Map (unchanged)
|
|
46
104
|
const exactMatch = routeTree.byPath.get(path);
|
|
47
105
|
if (exactMatch?.routable) {
|
|
48
|
-
return {
|
|
49
|
-
to: `#${exactMatch.id}`,
|
|
50
|
-
params: {},
|
|
51
|
-
};
|
|
106
|
+
return { to: `#${exactMatch.id}`, params: {} };
|
|
52
107
|
}
|
|
53
|
-
//
|
|
54
|
-
|
|
108
|
+
// Bucket-indexed pattern match: only scan candidates for this path's first segment
|
|
109
|
+
const candidates = getCandidates(patternBuckets, getIndexKey(path));
|
|
110
|
+
for (const { pattern, node } of candidates) {
|
|
55
111
|
const match = pattern.exec({ pathname: path });
|
|
56
112
|
if (match) {
|
|
57
|
-
// Extract pathname params (e.g., { section: "account" })
|
|
58
113
|
const params = {};
|
|
59
114
|
if (match.pathname.groups) {
|
|
60
115
|
Object.assign(params, match.pathname.groups);
|
|
61
116
|
}
|
|
62
|
-
return {
|
|
63
|
-
to: `#${node.id}`,
|
|
64
|
-
params,
|
|
65
|
-
};
|
|
117
|
+
return { to: `#${node.id}`, params };
|
|
66
118
|
}
|
|
67
119
|
}
|
|
68
|
-
// No match found
|
|
69
120
|
return { to: null, params: {} };
|
|
70
121
|
},
|
|
71
122
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-route-map.js","sourceRoot":"","sources":["../src/create-route-map.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"create-route-map.js","sourceRoot":"","sources":["../src/create-route-map.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { PlayError } from "@xmachines/play";
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when `RouterBridgeBase.syncActorFromRouter()` fails to process a router
|
|
4
|
+
* location change and send the corresponding `play.route` event to the actor.
|
|
5
|
+
*
|
|
6
|
+
* The `cause` property wraps the original error.
|
|
7
|
+
*
|
|
8
|
+
* **Error code:** `PLAY_ROUTER_SYNC_FAILED`
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { RouterSyncError } from "@xmachines/play-router/errors";
|
|
13
|
+
*
|
|
14
|
+
* try {
|
|
15
|
+
* bridge.connect();
|
|
16
|
+
* } catch (err) {
|
|
17
|
+
* if (err instanceof RouterSyncError) {
|
|
18
|
+
* console.error("Router sync failed:", err.message, err.cause);
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare class RouterSyncError extends PlayError {
|
|
24
|
+
constructor(message: string, options?: ErrorOptions);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Thrown by `createRouteMap()` when the `URLPattern` API is not available in the
|
|
28
|
+
* current runtime environment and no polyfill has been loaded.
|
|
29
|
+
*
|
|
30
|
+
* **How to fix:** Load `urlpattern-polyfill` at your application entry point, before
|
|
31
|
+
* any import of `@xmachines/play-router`:
|
|
32
|
+
*
|
|
33
|
+
* ```typescript
|
|
34
|
+
* // app entry point — must run first
|
|
35
|
+
* import "urlpattern-polyfill";
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* URLPattern is natively available on Node.js ≥ 24 and modern browsers
|
|
39
|
+
* (Chrome 95+, Firefox 117+, Safari 16.4+). Use the polyfill on older targets.
|
|
40
|
+
*
|
|
41
|
+
* **Error code:** `PLAY_ROUTE_MAP_URLPATTERN_UNAVAILABLE`
|
|
42
|
+
*/
|
|
43
|
+
export declare class URLPatternUnavailableError extends PlayError {
|
|
44
|
+
constructor();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Thrown by `createRouteMap()` when a route pattern string cannot be compiled by
|
|
48
|
+
* `URLPattern`. The `pattern` field contains the rejected string; `cause` wraps the
|
|
49
|
+
* original `URLPattern` constructor error.
|
|
50
|
+
*
|
|
51
|
+
* Common causes:
|
|
52
|
+
* - Unmatched parentheses or brackets in the pattern string
|
|
53
|
+
* - Characters that are invalid in a URL pathname pattern
|
|
54
|
+
*
|
|
55
|
+
* **Error code:** `PLAY_ROUTE_MAP_INVALID_PATTERN`
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* import { InvalidRoutePatternError } from "@xmachines/play-router/errors";
|
|
60
|
+
*
|
|
61
|
+
* try {
|
|
62
|
+
* const routeMap = createRouteMap(tree);
|
|
63
|
+
* } catch (err) {
|
|
64
|
+
* if (err instanceof InvalidRoutePatternError) {
|
|
65
|
+
* console.error(`Bad route pattern: "${err.pattern}"`, err.cause);
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare class InvalidRoutePatternError extends PlayError {
|
|
71
|
+
/** The route pattern string that could not be compiled by URLPattern. */
|
|
72
|
+
readonly pattern: string;
|
|
73
|
+
constructor(pattern: string, options?: ErrorOptions);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,eAAgB,SAAQ,SAAS;gBACjC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAInD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,0BAA2B,SAAQ,SAAS;;CASxD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,wBAAyB,SAAQ,SAAS;IACtD,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAUnD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { PlayError } from "@xmachines/play";
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when `RouterBridgeBase.syncActorFromRouter()` fails to process a router
|
|
4
|
+
* location change and send the corresponding `play.route` event to the actor.
|
|
5
|
+
*
|
|
6
|
+
* The `cause` property wraps the original error.
|
|
7
|
+
*
|
|
8
|
+
* **Error code:** `PLAY_ROUTER_SYNC_FAILED`
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { RouterSyncError } from "@xmachines/play-router/errors";
|
|
13
|
+
*
|
|
14
|
+
* try {
|
|
15
|
+
* bridge.connect();
|
|
16
|
+
* } catch (err) {
|
|
17
|
+
* if (err instanceof RouterSyncError) {
|
|
18
|
+
* console.error("Router sync failed:", err.message, err.cause);
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class RouterSyncError extends PlayError {
|
|
24
|
+
constructor(message, options) {
|
|
25
|
+
super("RouterBridgeBase", "PLAY_ROUTER_SYNC_FAILED", message, options);
|
|
26
|
+
this.name = "RouterSyncError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown by `createRouteMap()` when the `URLPattern` API is not available in the
|
|
31
|
+
* current runtime environment and no polyfill has been loaded.
|
|
32
|
+
*
|
|
33
|
+
* **How to fix:** Load `urlpattern-polyfill` at your application entry point, before
|
|
34
|
+
* any import of `@xmachines/play-router`:
|
|
35
|
+
*
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // app entry point — must run first
|
|
38
|
+
* import "urlpattern-polyfill";
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* URLPattern is natively available on Node.js ≥ 24 and modern browsers
|
|
42
|
+
* (Chrome 95+, Firefox 117+, Safari 16.4+). Use the polyfill on older targets.
|
|
43
|
+
*
|
|
44
|
+
* **Error code:** `PLAY_ROUTE_MAP_URLPATTERN_UNAVAILABLE`
|
|
45
|
+
*/
|
|
46
|
+
export class URLPatternUnavailableError extends PlayError {
|
|
47
|
+
constructor() {
|
|
48
|
+
super("RouteMap", "PLAY_ROUTE_MAP_URLPATTERN_UNAVAILABLE", "URLPattern is not available. Load a polyfill (e.g. urlpattern-polyfill) before using @xmachines/play-router on Node < 24 or older browsers.");
|
|
49
|
+
this.name = "URLPatternUnavailableError";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Thrown by `createRouteMap()` when a route pattern string cannot be compiled by
|
|
54
|
+
* `URLPattern`. The `pattern` field contains the rejected string; `cause` wraps the
|
|
55
|
+
* original `URLPattern` constructor error.
|
|
56
|
+
*
|
|
57
|
+
* Common causes:
|
|
58
|
+
* - Unmatched parentheses or brackets in the pattern string
|
|
59
|
+
* - Characters that are invalid in a URL pathname pattern
|
|
60
|
+
*
|
|
61
|
+
* **Error code:** `PLAY_ROUTE_MAP_INVALID_PATTERN`
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* import { InvalidRoutePatternError } from "@xmachines/play-router/errors";
|
|
66
|
+
*
|
|
67
|
+
* try {
|
|
68
|
+
* const routeMap = createRouteMap(tree);
|
|
69
|
+
* } catch (err) {
|
|
70
|
+
* if (err instanceof InvalidRoutePatternError) {
|
|
71
|
+
* console.error(`Bad route pattern: "${err.pattern}"`, err.cause);
|
|
72
|
+
* }
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export class InvalidRoutePatternError extends PlayError {
|
|
77
|
+
/** The route pattern string that could not be compiled by URLPattern. */
|
|
78
|
+
pattern;
|
|
79
|
+
constructor(pattern, options) {
|
|
80
|
+
super("RouteMap", "PLAY_ROUTE_MAP_INVALID_PATTERN", `Invalid route pattern: "${pattern}"`, options);
|
|
81
|
+
this.name = "InvalidRoutePatternError";
|
|
82
|
+
this.pattern = pattern;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,eAAgB,SAAQ,SAAS;IAC7C,YAAY,OAAe,EAAE,OAAsB;QAClD,KAAK,CAAC,kBAAkB,EAAE,yBAAyB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAC/B,CAAC;CACD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,0BAA2B,SAAQ,SAAS;IACxD;QACC,KAAK,CACJ,UAAU,EACV,uCAAuC,EACvC,6IAA6I,CAC7I,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC1C,CAAC;CACD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,OAAO,wBAAyB,SAAQ,SAAS;IACtD,yEAAyE;IAChE,OAAO,CAAS;IAEzB,YAAY,OAAe,EAAE,OAAsB;QAClD,KAAK,CACJ,UAAU,EACV,gCAAgC,EAChC,2BAA2B,OAAO,GAAG,EACrC,OAAO,CACP,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;CACD"}
|
package/dist/extract-routes.d.ts
CHANGED
|
@@ -3,39 +3,13 @@ import type { RouteTree } from "./types.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Extract complete route tree from state machine graph
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* and
|
|
6
|
+
* Converts the XState machine to a @statelyai/graph Graph via machineToGraph(),
|
|
7
|
+
* then walks graph nodes to extract route metadata, validate route references,
|
|
8
|
+
* and build a hierarchical RouteTree. The graph is attached to the returned
|
|
9
|
+
* RouteTree for downstream transition-aware queries.
|
|
9
10
|
*
|
|
10
11
|
* @param machine - XState v5 state machine
|
|
11
|
-
* @returns Route tree with root, byStateId map,
|
|
12
|
-
* @throws {Error} If route references non-existent state
|
|
13
|
-
* @throws {Error} If route path is malformed (doesn't start with /)
|
|
14
|
-
* @throws {Error} If parallel states define conflicting routes
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```typescript
|
|
18
|
-
* import { createMachine } from 'xstate';
|
|
19
|
-
* import { extractMachineRoutes } from '@xmachines/play-router';
|
|
20
|
-
*
|
|
21
|
-
* const machine = createMachine({
|
|
22
|
-
* initial: 'home',
|
|
23
|
-
* states: {
|
|
24
|
-
* home: { id: 'home', meta: { route: '/' } },
|
|
25
|
-
* dashboard: {
|
|
26
|
-
* id: 'dashboard',
|
|
27
|
-
* meta: { route: '/dashboard' },
|
|
28
|
-
* initial: 'overview',
|
|
29
|
-
* states: {
|
|
30
|
-
* overview: { id: 'overview', meta: { route: '/overview' } }
|
|
31
|
-
* }
|
|
32
|
-
* }
|
|
33
|
-
* }
|
|
34
|
-
* });
|
|
35
|
-
*
|
|
36
|
-
* const tree = extractMachineRoutes(machine);
|
|
37
|
-
* console.log(tree.byPath.get('/dashboard/overview'));
|
|
38
|
-
* ```
|
|
12
|
+
* @returns Route tree with root, byStateId map, byPath map, and graph
|
|
39
13
|
*/
|
|
40
14
|
export declare const extractMachineRoutes: (machine: AnyStateMachine) => RouteTree;
|
|
41
15
|
//# sourceMappingURL=extract-routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-routes.d.ts","sourceRoot":"","sources":["../src/extract-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"extract-routes.d.ts","sourceRoot":"","sources":["../src/extract-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAA6C,MAAM,YAAY,CAAC;AA+EvF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,eAAe,KAAG,SAmB/D,CAAC"}
|
package/dist/extract-routes.js
CHANGED
|
@@ -1,61 +1,82 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { detectDuplicateRoutes } from "./validate-routes.js";
|
|
1
|
+
import { machineToGraph } from "./machine-to-graph.js";
|
|
2
|
+
import { validateRouteFormat, validateStateExists, detectDuplicateRoutes, } from "./validate-routes.js";
|
|
4
3
|
import { buildRouteTree } from "./build-tree.js";
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Crawls machine starting from root, visits all state nodes (including nested
|
|
9
|
-
* and parallel), extracts meta.route metadata, validates route references,
|
|
10
|
-
* and builds hierarchical tree.
|
|
5
|
+
* Build statePath for a graph node by walking the parentId chain.
|
|
11
6
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @throws {Error} If route references non-existent state
|
|
15
|
-
* @throws {Error} If route path is malformed (doesn't start with /)
|
|
16
|
-
* @throws {Error} If parallel states define conflicting routes
|
|
7
|
+
* Produces an array of stateId segments from root to this node (excluding root),
|
|
8
|
+
* matching the format expected by buildRouteTree's parent lookup.
|
|
17
9
|
*
|
|
18
|
-
* @
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
|
|
10
|
+
* @param graphNode - The node to build a path for
|
|
11
|
+
* @param graphNodeMap - Map from node id to GraphNode for O(1) parent lookup
|
|
12
|
+
* @returns Array of stateId segments (e.g. ["dashboard", "overview"])
|
|
13
|
+
*/
|
|
14
|
+
const buildStatePath = (graphNode, graphNodeMap) => {
|
|
15
|
+
const path = [];
|
|
16
|
+
let current = graphNode;
|
|
17
|
+
while (current && current.parentId !== undefined && current.parentId !== null) {
|
|
18
|
+
path.unshift(current.data.stateId);
|
|
19
|
+
current = graphNodeMap.get(current.parentId);
|
|
20
|
+
}
|
|
21
|
+
return path;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Extract route info from a graph node's MachineNodeData.
|
|
25
|
+
* Returns null if the node has no route (not routable).
|
|
26
|
+
*/
|
|
27
|
+
const extractRouteFromNode = (graphNode, stateIds, graphNodeMap) => {
|
|
28
|
+
const { stateId, route, meta } = graphNode.data;
|
|
29
|
+
// Node has no route — not routable
|
|
30
|
+
if (!route)
|
|
31
|
+
return null;
|
|
32
|
+
// Validate format (must start with /)
|
|
33
|
+
validateRouteFormat(route, stateId);
|
|
34
|
+
// Validate state exists in graph (redundant but guards against corruption)
|
|
35
|
+
validateStateExists(stateId, stateIds);
|
|
36
|
+
// Build statePath from parentId chain (works for both explicit IDs and auto-generated)
|
|
37
|
+
const statePath = buildStatePath(graphNode, graphNodeMap);
|
|
38
|
+
const pattern = route.includes(":") ? route : undefined;
|
|
39
|
+
// Reconstruct original metadata shape from graph data
|
|
40
|
+
const metadata = meta && typeof meta === "object" && "route" in meta
|
|
41
|
+
? meta["route"]
|
|
42
|
+
: route;
|
|
43
|
+
const result = {
|
|
44
|
+
stateId,
|
|
45
|
+
statePath,
|
|
46
|
+
routePath: route,
|
|
47
|
+
isAbsolute: route.startsWith("/"),
|
|
48
|
+
routable: true,
|
|
49
|
+
metadata,
|
|
50
|
+
};
|
|
51
|
+
if (pattern)
|
|
52
|
+
result.pattern = pattern;
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Extract complete route tree from state machine graph
|
|
22
57
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* dashboard: {
|
|
28
|
-
* id: 'dashboard',
|
|
29
|
-
* meta: { route: '/dashboard' },
|
|
30
|
-
* initial: 'overview',
|
|
31
|
-
* states: {
|
|
32
|
-
* overview: { id: 'overview', meta: { route: '/overview' } }
|
|
33
|
-
* }
|
|
34
|
-
* }
|
|
35
|
-
* }
|
|
36
|
-
* });
|
|
58
|
+
* Converts the XState machine to a @statelyai/graph Graph via machineToGraph(),
|
|
59
|
+
* then walks graph nodes to extract route metadata, validate route references,
|
|
60
|
+
* and build a hierarchical RouteTree. The graph is attached to the returned
|
|
61
|
+
* RouteTree for downstream transition-aware queries.
|
|
37
62
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* ```
|
|
63
|
+
* @param machine - XState v5 state machine
|
|
64
|
+
* @returns Route tree with root, byStateId map, byPath map, and graph
|
|
41
65
|
*/
|
|
42
66
|
export const extractMachineRoutes = (machine) => {
|
|
43
|
-
// 1.
|
|
44
|
-
const
|
|
45
|
-
// 2. Build state map for
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// 3. Extract routes with validation
|
|
53
|
-
const routes = visits
|
|
54
|
-
.map((visit) => extractRoute(visit.node, visit.path, stateMap))
|
|
55
|
-
.filter((route) => route !== null);
|
|
67
|
+
// 1. Convert machine to graph
|
|
68
|
+
const graph = machineToGraph(machine);
|
|
69
|
+
// 2. Build state ID set for validation and node map for O(1) parent lookup
|
|
70
|
+
const stateIds = new Set(graph.nodes.map((n) => n.data.stateId));
|
|
71
|
+
const graphNodeMap = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
72
|
+
// 3. Extract routes from graph nodes
|
|
73
|
+
const routes = graph.nodes
|
|
74
|
+
.map((node) => extractRouteFromNode(node, stateIds, graphNodeMap))
|
|
75
|
+
.filter((r) => r !== null);
|
|
56
76
|
// 4. Detect duplicate routes
|
|
57
77
|
detectDuplicateRoutes(routes);
|
|
58
|
-
// 5. Build hierarchical tree
|
|
59
|
-
|
|
78
|
+
// 5. Build hierarchical tree and attach graph
|
|
79
|
+
const tree = buildRouteTree(routes);
|
|
80
|
+
return { ...tree, graph };
|
|
60
81
|
};
|
|
61
82
|
//# sourceMappingURL=extract-routes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-routes.js","sourceRoot":"","sources":["../src/extract-routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extract-routes.js","sourceRoot":"","sources":["../src/extract-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { RouteTree, RouteNode } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Find route node by state ID
|
|
4
|
+
*
|
|
5
|
+
* Looks up route node using the state's ID property. Used to get URL path
|
|
6
|
+
* from state ID for browser URL sync after play.route transitions.
|
|
7
|
+
*
|
|
8
|
+
* @param tree - Route tree from extractMachineRoutes
|
|
9
|
+
* @param id - State ID (e.g., 'dashboard', 'settings.profile')
|
|
10
|
+
* @returns Route node if found, undefined otherwise
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const tree = extractMachineRoutes(machine);
|
|
15
|
+
* const node = findRouteById(tree, 'dashboard');
|
|
16
|
+
* if (node) {
|
|
17
|
+
* console.log(node.fullPath); // '/dashboard'
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare const findRouteById: (tree: RouteTree, id: string) => RouteNode | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Find route node by URL path
|
|
24
|
+
*
|
|
25
|
+
* Looks up route node using the URL path. Used to get state ID from browser
|
|
26
|
+
* URL for sending play.route events on navigation.
|
|
27
|
+
*
|
|
28
|
+
* When multiple states share the same path (e.g., root and a state both at "/"),
|
|
29
|
+
* prefers routable nodes (with meta.route) over non-routable nodes.
|
|
30
|
+
*
|
|
31
|
+
* Supports pattern matching for dynamic routes (e.g., '/settings/:section?').
|
|
32
|
+
*
|
|
33
|
+
* @param tree - Route tree from extractMachineRoutes
|
|
34
|
+
* @param path - URL path (e.g., '/dashboard', '/settings/profile')
|
|
35
|
+
* @returns Route node if found, undefined otherwise
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const tree = extractMachineRoutes(machine);
|
|
40
|
+
* const node = findRouteByPath(tree, '/dashboard');
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare const findRouteByPath: (tree: RouteTree, path: string) => RouteNode | undefined;
|
|
44
|
+
//# sourceMappingURL=find-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-route.d.ts","sourceRoot":"","sources":["../src/find-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAuEvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,SAAS,EAAE,IAAI,MAAM,KAAG,SAAS,GAAG,SAEvE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,SAAS,EAAE,MAAM,MAAM,KAAG,SAAS,GAAG,SAyB3E,CAAC"}
|