@xmachines/play-router 1.0.0-beta.8 → 1.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/LICENSE +21 -0
- package/README.md +259 -335
- package/dist/base-route-map.d.ts +136 -0
- package/dist/base-route-map.d.ts.map +1 -0
- package/dist/base-route-map.js +182 -0
- package/dist/base-route-map.js.map +1 -0
- package/dist/build-tree.d.ts +7 -0
- package/dist/build-tree.d.ts.map +1 -1
- package/dist/build-tree.js +21 -6
- package/dist/build-tree.js.map +1 -1
- package/dist/create-route-map-from-tree.d.ts +33 -0
- package/dist/create-route-map-from-tree.d.ts.map +1 -0
- package/dist/create-route-map-from-tree.js +43 -0
- package/dist/create-route-map-from-tree.js.map +1 -0
- package/dist/create-route-map.d.ts +29 -33
- package/dist/create-route-map.d.ts.map +1 -1
- package/dist/create-route-map.js +25 -64
- package/dist/create-route-map.js.map +1 -1
- package/dist/errors.d.ts +152 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +186 -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 +73 -51
- 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 +103 -0
- package/dist/find-route.js.map +1 -0
- package/dist/index.d.ts +13 -51
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -133
- 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 +49 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +98 -3
- package/dist/query.js.map +1 -1
- package/dist/router-bridge-base.d.ts +196 -32
- package/dist/router-bridge-base.d.ts.map +1 -1
- package/dist/router-bridge-base.js +319 -85
- package/dist/router-bridge-base.js.map +1 -1
- package/dist/router-sync.d.ts +95 -0
- package/dist/router-sync.d.ts.map +1 -0
- package/dist/router-sync.js +161 -0
- package/dist/router-sync.js.map +1 -0
- package/dist/types.d.ts +163 -22
- package/dist/types.d.ts.map +1 -1
- package/dist/url-pattern-utils.d.ts +117 -0
- package/dist/url-pattern-utils.d.ts.map +1 -0
- package/dist/url-pattern-utils.js +176 -0
- package/dist/url-pattern-utils.js.map +1 -0
- package/dist/validate-routes.d.ts +32 -14
- package/dist/validate-routes.d.ts.map +1 -1
- package/dist/validate-routes.js +28 -21
- package/dist/validate-routes.js.map +1 -1
- package/package.json +42 -14
- package/dist/connect-router.d.ts +0 -56
- package/dist/connect-router.d.ts.map +0 -1
- package/dist/connect-router.js +0 -119
- package/dist/connect-router.js.map +0 -1
- 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/create-browser-history.d.ts +0 -68
- package/dist/create-browser-history.d.ts.map +0 -1
- package/dist/create-browser-history.js +0 -94
- package/dist/create-browser-history.js.map +0 -1
- package/dist/create-router.d.ts +0 -73
- package/dist/create-router.d.ts.map +0 -1
- package/dist/create-router.js +0 -63
- package/dist/create-router.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
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { PlayRouteEvent } from "./types.js";
|
|
2
|
+
export interface RouteMatch {
|
|
3
|
+
to: string | null | undefined;
|
|
4
|
+
params?: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
export interface BuildPlayRouteEventOptions {
|
|
7
|
+
pathname: string;
|
|
8
|
+
search?: string | undefined;
|
|
9
|
+
match: (sanitizedPathname: string) => RouteMatch;
|
|
10
|
+
}
|
|
11
|
+
export interface RouterStateIdMap {
|
|
12
|
+
getStateIdByPath(path: string): string | null | undefined;
|
|
13
|
+
getPathByStateId(id: string): string | null | undefined;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Match a sanitized pathname against a route map and extract any matched params.
|
|
17
|
+
*
|
|
18
|
+
* Shared by low-level and framework router sync paths to keep route-map matching
|
|
19
|
+
* semantics aligned.
|
|
20
|
+
*/
|
|
21
|
+
export declare function matchRouteMap(pathname: string, routeMap: RouterStateIdMap, extractParams: (pathname: string, stateId: string) => Record<string, string>): RouteMatch;
|
|
22
|
+
/**
|
|
23
|
+
* Normalize a pathname before route-map lookup.
|
|
24
|
+
*
|
|
25
|
+
* This strips query/hash fragments, collapses duplicate slashes, and rejects
|
|
26
|
+
* implausibly long paths that should never enter route resolution.
|
|
27
|
+
*
|
|
28
|
+
* Returns `null` for paths exceeding 2048 characters (malformed/adversarial input).
|
|
29
|
+
* Adapters that bypass `RouterBridgeBase.syncActorFromRouter()` (e.g. `VueRouterBridge`)
|
|
30
|
+
* must call this function directly and return early on `null` to apply the same
|
|
31
|
+
* defense-in-depth security guarantee as the shared base class.
|
|
32
|
+
*
|
|
33
|
+
* @param pathname - Raw path string from router navigation event.
|
|
34
|
+
* @returns Normalized path string, or `null` if the path is malformed/too long.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { sanitizePathname } from "@xmachines/play-router";
|
|
39
|
+
*
|
|
40
|
+
* const clean = sanitizePathname(to.path);
|
|
41
|
+
* if (clean === null) return; // reject malformed path
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function sanitizePathname(pathname: string): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Extract named path parameters from a URL using the URLPattern API.
|
|
47
|
+
*
|
|
48
|
+
* Takes the pattern string directly — use this when the pattern is already known.
|
|
49
|
+
* For extraction via a state ID lookup, see `RouterBridgeBase.extractParams`.
|
|
50
|
+
*
|
|
51
|
+
* Undefined values (unmatched optional segments, e.g. `/settings` against
|
|
52
|
+
* `/settings/:section?`) are omitted from the returned object.
|
|
53
|
+
*
|
|
54
|
+
* The pattern is normalized with the same rules `RouteMap` uses for matching
|
|
55
|
+
* (hyphenated names like `:cat-id` become `:cat_id` for URLPattern), and the
|
|
56
|
+
* extracted group names are mapped back to the original param names, so
|
|
57
|
+
* `/docs/123` against `/docs/:cat-id` yields `{ "cat-id": "123" }`.
|
|
58
|
+
*
|
|
59
|
+
* Values are percent-decoded (`john%20doe` → `john doe`), matching framework
|
|
60
|
+
* router semantics (e.g. vue-router). Malformed sequences are kept raw.
|
|
61
|
+
*
|
|
62
|
+
* @param pathname - The concrete URL pathname (e.g. `/profile/alice`)
|
|
63
|
+
* @param pattern - The URL pattern template (e.g. `/profile/:username`)
|
|
64
|
+
* @returns A record of extracted parameter values, or `{}` for static patterns.
|
|
65
|
+
* @throws {URLPatternUnavailableError} When `URLPattern` is absent and the pattern is parameterized.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* import { extractRouteParams } from "@xmachines/play-router";
|
|
70
|
+
*
|
|
71
|
+
* extractRouteParams("/profile/alice", "/profile/:username")
|
|
72
|
+
* // → { username: "alice" }
|
|
73
|
+
*
|
|
74
|
+
* extractRouteParams("/settings", "/settings/:section?")
|
|
75
|
+
* // → {} (optional param absent — not included)
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function extractRouteParams(pathname: string, pattern: string): Record<string, string>;
|
|
79
|
+
/**
|
|
80
|
+
* Parse a URL search string into the plain object shape expected by
|
|
81
|
+
* `play.route` events.
|
|
82
|
+
*/
|
|
83
|
+
export declare function extractQuery(search: string): Record<string, string>;
|
|
84
|
+
/**
|
|
85
|
+
* Build a normalized `play.route` event from raw router/browser input.
|
|
86
|
+
*
|
|
87
|
+
* Both `connectRouter()` (from `@xmachines/play-dom-router`) and `RouterBridgeBase`
|
|
88
|
+
* use this helper so low-level and framework adapters share the same pathname
|
|
89
|
+
* sanitization, route matching, and query extraction behavior.
|
|
90
|
+
*/
|
|
91
|
+
export declare function buildPlayRouteEvent(options: BuildPlayRouteEventOptions): {
|
|
92
|
+
pathname: string;
|
|
93
|
+
event: PlayRouteEvent;
|
|
94
|
+
} | null;
|
|
95
|
+
//# sourceMappingURL=router-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-sync.d.ts","sourceRoot":"","sources":["../src/router-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAWjD,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,UAAU,CAAC;CACjD;AAED,MAAM,WAAW,gBAAgB;IAChC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1D,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACxD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC5B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,gBAAgB,EAC1B,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1E,UAAU,CAUZ;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKhE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmB5F;AAcD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUnE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,0BAA0B,GACjC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,GAAG,IAAI,CAqBpD"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { getURLPatternCtor, getNormalizedParamNameMap, getCompiledPattern, isParameterizedPattern, } from "./url-pattern-utils.js";
|
|
2
|
+
import { URLPatternUnavailableError } from "./errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* Match a sanitized pathname against a route map and extract any matched params.
|
|
5
|
+
*
|
|
6
|
+
* Shared by low-level and framework router sync paths to keep route-map matching
|
|
7
|
+
* semantics aligned.
|
|
8
|
+
*/
|
|
9
|
+
export function matchRouteMap(pathname, routeMap, extractParams) {
|
|
10
|
+
const stateId = routeMap.getStateIdByPath(pathname);
|
|
11
|
+
if (!stateId) {
|
|
12
|
+
return { to: null, params: {} };
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
to: stateId,
|
|
16
|
+
params: extractParams(pathname, stateId),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Normalize a pathname before route-map lookup.
|
|
21
|
+
*
|
|
22
|
+
* This strips query/hash fragments, collapses duplicate slashes, and rejects
|
|
23
|
+
* implausibly long paths that should never enter route resolution.
|
|
24
|
+
*
|
|
25
|
+
* Returns `null` for paths exceeding 2048 characters (malformed/adversarial input).
|
|
26
|
+
* Adapters that bypass `RouterBridgeBase.syncActorFromRouter()` (e.g. `VueRouterBridge`)
|
|
27
|
+
* must call this function directly and return early on `null` to apply the same
|
|
28
|
+
* defense-in-depth security guarantee as the shared base class.
|
|
29
|
+
*
|
|
30
|
+
* @param pathname - Raw path string from router navigation event.
|
|
31
|
+
* @returns Normalized path string, or `null` if the path is malformed/too long.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import { sanitizePathname } from "@xmachines/play-router";
|
|
36
|
+
*
|
|
37
|
+
* const clean = sanitizePathname(to.path);
|
|
38
|
+
* if (clean === null) return; // reject malformed path
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function sanitizePathname(pathname) {
|
|
42
|
+
if (pathname.length > 2048)
|
|
43
|
+
return null;
|
|
44
|
+
const withoutQuery = pathname.split("?")[0];
|
|
45
|
+
const withoutHash = withoutQuery.split("#")[0];
|
|
46
|
+
return withoutHash.replace(/\/+/g, "/");
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Extract named path parameters from a URL using the URLPattern API.
|
|
50
|
+
*
|
|
51
|
+
* Takes the pattern string directly — use this when the pattern is already known.
|
|
52
|
+
* For extraction via a state ID lookup, see `RouterBridgeBase.extractParams`.
|
|
53
|
+
*
|
|
54
|
+
* Undefined values (unmatched optional segments, e.g. `/settings` against
|
|
55
|
+
* `/settings/:section?`) are omitted from the returned object.
|
|
56
|
+
*
|
|
57
|
+
* The pattern is normalized with the same rules `RouteMap` uses for matching
|
|
58
|
+
* (hyphenated names like `:cat-id` become `:cat_id` for URLPattern), and the
|
|
59
|
+
* extracted group names are mapped back to the original param names, so
|
|
60
|
+
* `/docs/123` against `/docs/:cat-id` yields `{ "cat-id": "123" }`.
|
|
61
|
+
*
|
|
62
|
+
* Values are percent-decoded (`john%20doe` → `john doe`), matching framework
|
|
63
|
+
* router semantics (e.g. vue-router). Malformed sequences are kept raw.
|
|
64
|
+
*
|
|
65
|
+
* @param pathname - The concrete URL pathname (e.g. `/profile/alice`)
|
|
66
|
+
* @param pattern - The URL pattern template (e.g. `/profile/:username`)
|
|
67
|
+
* @returns A record of extracted parameter values, or `{}` for static patterns.
|
|
68
|
+
* @throws {URLPatternUnavailableError} When `URLPattern` is absent and the pattern is parameterized.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* import { extractRouteParams } from "@xmachines/play-router";
|
|
73
|
+
*
|
|
74
|
+
* extractRouteParams("/profile/alice", "/profile/:username")
|
|
75
|
+
* // → { username: "alice" }
|
|
76
|
+
*
|
|
77
|
+
* extractRouteParams("/settings", "/settings/:section?")
|
|
78
|
+
* // → {} (optional param absent — not included)
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function extractRouteParams(pathname, pattern) {
|
|
82
|
+
const Ctor = getURLPatternCtor();
|
|
83
|
+
if (!Ctor)
|
|
84
|
+
throw new URLPatternUnavailableError();
|
|
85
|
+
if (!isParameterizedPattern(pattern))
|
|
86
|
+
return {};
|
|
87
|
+
// Compile with the SAME normalization RouteMap uses for matching — otherwise
|
|
88
|
+
// URLPattern parses ":cat-id" as group ":cat" + literal "-id" and extraction
|
|
89
|
+
// disagrees with the map that matched the path in the first place.
|
|
90
|
+
const urlPattern = getCompiledPattern(pattern, Ctor);
|
|
91
|
+
const match = urlPattern.exec({ pathname });
|
|
92
|
+
if (!match?.pathname.groups)
|
|
93
|
+
return {};
|
|
94
|
+
// Map normalized group names (":cat_id") back to the original param names ("cat-id").
|
|
95
|
+
const nameMap = getNormalizedParamNameMap(pattern);
|
|
96
|
+
const params = {};
|
|
97
|
+
for (const [key, value] of Object.entries(match.pathname.groups)) {
|
|
98
|
+
if (value !== undefined) {
|
|
99
|
+
params[nameMap.get(key) ?? key] = decodeParamValue(value); // nosemgrep: gitlab.eslint.detect-object-injection
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return params;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Percent-decode a URLPattern group value, keeping the raw value when the
|
|
106
|
+
* sequence is malformed (`decodeURIComponent` would throw `URIError`).
|
|
107
|
+
*/
|
|
108
|
+
function decodeParamValue(value) {
|
|
109
|
+
try {
|
|
110
|
+
return decodeURIComponent(value);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Parse a URL search string into the plain object shape expected by
|
|
118
|
+
* `play.route` events.
|
|
119
|
+
*/
|
|
120
|
+
export function extractQuery(search) {
|
|
121
|
+
try {
|
|
122
|
+
const params = {};
|
|
123
|
+
new URLSearchParams(search).forEach((value, key) => {
|
|
124
|
+
params[key] = value; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
125
|
+
});
|
|
126
|
+
return params;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return {};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Build a normalized `play.route` event from raw router/browser input.
|
|
134
|
+
*
|
|
135
|
+
* Both `connectRouter()` (from `@xmachines/play-dom-router`) and `RouterBridgeBase`
|
|
136
|
+
* use this helper so low-level and framework adapters share the same pathname
|
|
137
|
+
* sanitization, route matching, and query extraction behavior.
|
|
138
|
+
*/
|
|
139
|
+
export function buildPlayRouteEvent(options) {
|
|
140
|
+
const pathname = sanitizePathname(options.pathname);
|
|
141
|
+
if (pathname === null)
|
|
142
|
+
return null;
|
|
143
|
+
const match = options.match(pathname);
|
|
144
|
+
if (!match.to)
|
|
145
|
+
return null;
|
|
146
|
+
// Single canonicalization point for the emitted event shape: `play.route`
|
|
147
|
+
// events always carry a '#'-prefixed target. Route maps may legitimately
|
|
148
|
+
// register (and return) bare stateIds — RouteMap preserves the registered
|
|
149
|
+
// form — so the event target is formatted here, and only here.
|
|
150
|
+
const to = match.to.startsWith("#") ? match.to : `#${match.to}`;
|
|
151
|
+
return {
|
|
152
|
+
pathname,
|
|
153
|
+
event: {
|
|
154
|
+
type: "play.route",
|
|
155
|
+
to,
|
|
156
|
+
params: match.params ?? {},
|
|
157
|
+
query: extractQuery(options.search ?? ""),
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=router-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-sync.js","sourceRoot":"","sources":["../src/router-sync.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,30 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Graph } from "@statelyai/graph";
|
|
2
|
+
import type { Signal } from "@xmachines/play-signals";
|
|
3
|
+
import type { PlaySpec } from "@xmachines/play-actor";
|
|
4
|
+
/**
|
|
5
|
+
* Data attached to each node in the machine graph representation.
|
|
6
|
+
* Captures the essential state metadata needed for route extraction and queries.
|
|
7
|
+
*/
|
|
8
|
+
export interface MachineNodeData {
|
|
9
|
+
/** XState state ID (e.g., "test.dashboard.overview") */
|
|
10
|
+
stateId: string;
|
|
11
|
+
/** State type from XState */
|
|
12
|
+
type: "atomic" | "compound" | "parallel" | "final" | "history";
|
|
13
|
+
/** Original state meta object */
|
|
14
|
+
meta?: Record<string, unknown>;
|
|
15
|
+
/** Extracted route path from meta.route (string form) */
|
|
16
|
+
route?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Data attached to each edge in the machine graph representation.
|
|
20
|
+
* Captures transition event and guard information.
|
|
21
|
+
*/
|
|
22
|
+
export interface MachineEdgeData {
|
|
23
|
+
/** The event type that triggers this transition */
|
|
24
|
+
eventType: string;
|
|
25
|
+
/** String representation of guard (if any) */
|
|
26
|
+
guardType?: string;
|
|
27
|
+
}
|
|
2
28
|
/**
|
|
3
29
|
* Routing protocol type definitions for @xmachines/play-router
|
|
4
30
|
*
|
|
@@ -18,17 +44,6 @@ export interface RouteObject {
|
|
|
18
44
|
* Route metadata from state machine `meta.route` field.
|
|
19
45
|
*/
|
|
20
46
|
export type RouteMetadata = string | RouteObject;
|
|
21
|
-
/**
|
|
22
|
-
* Represents a visit to a state node during graph crawling
|
|
23
|
-
*/
|
|
24
|
-
export interface StateVisit {
|
|
25
|
-
/** The state node being visited */
|
|
26
|
-
node: StateNode;
|
|
27
|
-
/** Path from root to this state (e.g., ['dashboard', 'overview']) */
|
|
28
|
-
path: string[];
|
|
29
|
-
/** Parent state node (null for root) */
|
|
30
|
-
parent: StateNode | null;
|
|
31
|
-
}
|
|
32
47
|
/**
|
|
33
48
|
* Extracted route information from a state node
|
|
34
49
|
*/
|
|
@@ -57,9 +72,16 @@ export interface RouteInfo {
|
|
|
57
72
|
export interface RouteNode {
|
|
58
73
|
/** Unique identifier (state ID) */
|
|
59
74
|
id: string;
|
|
60
|
-
/**
|
|
75
|
+
/**
|
|
76
|
+
* The raw route path segment as declared in `meta.route` — may be relative (e.g. `"overview"`)
|
|
77
|
+
* or absolute (e.g. `"/dashboard"`). Do not use this for URL matching; use `fullPath` instead.
|
|
78
|
+
*/
|
|
61
79
|
path: string;
|
|
62
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* The fully resolved absolute path from the root (e.g. `"/dashboard/overview"`).
|
|
82
|
+
* Always use `fullPath` for browser URL matching and route map construction.
|
|
83
|
+
* `createRouteMapFromTree` and `createRouteMap` both use this field.
|
|
84
|
+
*/
|
|
63
85
|
fullPath: string;
|
|
64
86
|
/** Route pattern with parameters (e.g., /profile/:userId) if path contains params */
|
|
65
87
|
pattern?: string;
|
|
@@ -75,7 +97,7 @@ export interface RouteNode {
|
|
|
75
97
|
/** Parent route (null for root) */
|
|
76
98
|
parent: RouteNode | null;
|
|
77
99
|
/** Original meta.route metadata */
|
|
78
|
-
metadata:
|
|
100
|
+
metadata: RouteMetadata;
|
|
79
101
|
}
|
|
80
102
|
/**
|
|
81
103
|
* Complete route tree with lookup maps
|
|
@@ -97,6 +119,18 @@ export interface RouteTree {
|
|
|
97
119
|
* Used to look up state ID from URL path for play.route event targeting
|
|
98
120
|
*/
|
|
99
121
|
byPath: Map<string, RouteNode>;
|
|
122
|
+
/**
|
|
123
|
+
* Graph representation of the state machine for advanced queries.
|
|
124
|
+
* Populated by extractMachineRoutes() — use for hierarchy queries, reachability checks,
|
|
125
|
+
* and transition-aware navigation via @statelyai/graph algorithms.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* import { getSuccessors, hasPath } from "@statelyai/graph";
|
|
130
|
+
* const successors = getSuccessors(tree.graph!, "myMachine.home");
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
graph?: Graph<MachineNodeData, MachineEdgeData>;
|
|
100
134
|
}
|
|
101
135
|
/**
|
|
102
136
|
* Enhanced routing event with parameter and query support
|
|
@@ -116,7 +150,7 @@ export interface RouteTree {
|
|
|
116
150
|
*
|
|
117
151
|
* @param type - Event discriminator (always "play.route")
|
|
118
152
|
* @param to - Target state ID with # prefix (e.g., '#home', '#profile')
|
|
119
|
-
* @param params -
|
|
153
|
+
* @param params - Path-only route parameters extracted from the URL path (e.g., `{ userId: '123' }` from `/profile/123`). Query parameters are kept separate in `query`.
|
|
120
154
|
* @param query - Query parameters only (isolated from path params)
|
|
121
155
|
* @param match - Full URLPattern match result for debugging/observability (optional)
|
|
122
156
|
*
|
|
@@ -165,14 +199,14 @@ export interface RouteTree {
|
|
|
165
199
|
* const event: PlayRouteEvent = {
|
|
166
200
|
* type: 'play.route',
|
|
167
201
|
* to: '#settings',
|
|
168
|
-
* params: { section: 'profile' }, //
|
|
202
|
+
* params: { section: 'profile' }, // Path-only route parameter
|
|
169
203
|
* query: { tab: 'security' } // Query-only
|
|
170
204
|
* };
|
|
171
205
|
* actor.send(event);
|
|
172
206
|
* // Resolves to route: /settings/profile?tab=security
|
|
173
207
|
* ```
|
|
174
208
|
*
|
|
175
|
-
* @see
|
|
209
|
+
* @see [Play RFC](../../docs/rfc/play.md)
|
|
176
210
|
*
|
|
177
211
|
* @remarks
|
|
178
212
|
* Use `play.route` when you need parameter-aware navigation with the `route: {}`
|
|
@@ -187,10 +221,76 @@ export interface PlayRouteEvent {
|
|
|
187
221
|
readonly match?: unknown;
|
|
188
222
|
[key: string]: unknown;
|
|
189
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Minimal actor interface required by `RouterBridgeBase` and all framework router
|
|
226
|
+
* adapters.
|
|
227
|
+
*
|
|
228
|
+
* Using this interface instead of `AbstractActor<AnyActorLogic> & Routable` lets
|
|
229
|
+
* `RouterBridgeBase.actor.send` be typed to accept `PlayRouteEvent` directly —
|
|
230
|
+
* eliminating the unsafe `(actor.send as (e: PlayRouteEvent) => void)` cast that
|
|
231
|
+
* existed when the actor was typed with the weaker `EventObject` constraint.
|
|
232
|
+
*
|
|
233
|
+
* All `AbstractActor` subclasses satisfy this interface structurally because:
|
|
234
|
+
* - `AbstractActor` implements `send(event: TEvent): void` where `TEvent` accepts
|
|
235
|
+
* any `EventObject`, so `PlayRouteEvent` (a subtype) is always accepted.
|
|
236
|
+
* - `Routable` provides `currentRoute` and `initialRoute`.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* import type { RoutableActor } from "@xmachines/play-router";
|
|
241
|
+
*
|
|
242
|
+
* class MyBridge extends RouterBridgeBase {
|
|
243
|
+
* constructor(actor: RoutableActor, routeMap: RouteMap) {
|
|
244
|
+
* super(actor, routeMap);
|
|
245
|
+
* }
|
|
246
|
+
* }
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
export interface RoutableActor {
|
|
250
|
+
/** TC39 Signal exposing the actor's current URL path (or state ID). */
|
|
251
|
+
readonly currentRoute: Signal.Computed<string | null>;
|
|
252
|
+
/**
|
|
253
|
+
* The route derived from the machine's initial state — fixed at construction.
|
|
254
|
+
* Router bridges compare this against the browser URL to distinguish a deep-link
|
|
255
|
+
* (router wins) from a session restore (actor wins).
|
|
256
|
+
*/
|
|
257
|
+
readonly initialRoute: string | null;
|
|
258
|
+
/** Send a route navigation event to the actor. */
|
|
259
|
+
send(event: PlayRouteEvent): void;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Full actor shape used by `PlayRouterProvider` components across all framework
|
|
263
|
+
* adapters (`play-solid-router`, `play-vue-router`, `play-react-router`, and the
|
|
264
|
+
* adapters built on the shared framework-router bridge bases).
|
|
265
|
+
*
|
|
266
|
+
* Extends `RoutableActor` with `currentView` — the provider renders the current
|
|
267
|
+
* view spec in addition to synchronizing routes, so it needs both capabilities.
|
|
268
|
+
*
|
|
269
|
+
* - Use `RoutableActor` when only routing is needed (e.g. `RouterBridgeBase` subclasses,
|
|
270
|
+
* `connectRouter`).
|
|
271
|
+
* - Use `PlayActor` when the component also renders the current view spec
|
|
272
|
+
* (e.g. `PlayRouterProvider` renderer callback parameter, `PlayRenderer`).
|
|
273
|
+
*
|
|
274
|
+
* All `AbstractActor` subclasses that implement both `Routable` and `Viewable`
|
|
275
|
+
* satisfy this interface structurally.
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```typescript
|
|
279
|
+
* import type { PlayActor } from "@xmachines/play-router";
|
|
280
|
+
*
|
|
281
|
+
* function MyRouterProvider({ actor }: { actor: PlayActor }) {
|
|
282
|
+
* // access actor.currentRoute (routing) and actor.currentView (rendering)
|
|
283
|
+
* }
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
export interface PlayActor extends RoutableActor {
|
|
287
|
+
/** TC39 Signal exposing the actor's current view spec, or `null` when inactive. */
|
|
288
|
+
readonly currentView: Signal.State<PlaySpec | null>;
|
|
289
|
+
}
|
|
190
290
|
/**
|
|
191
291
|
* RouterBridge interface for runtime infrastructure adapters
|
|
192
292
|
*
|
|
193
|
-
* Defines the lifecycle connection between Infrastructure (e.g.,
|
|
293
|
+
* Defines the lifecycle connection between Infrastructure (e.g., a framework router) and
|
|
194
294
|
* the Actor. Infrastructure "bridges" to the Actor by observing its signals and
|
|
195
295
|
* managing its own lifecycle accordingly.
|
|
196
296
|
*
|
|
@@ -199,12 +299,12 @@ export interface PlayRouteEvent {
|
|
|
199
299
|
* (currentRoute, currentView, state) and reflects changes without making state decisions.
|
|
200
300
|
*
|
|
201
301
|
* @example
|
|
202
|
-
*
|
|
302
|
+
* Framework router bridge implementation
|
|
203
303
|
* ```typescript
|
|
204
304
|
* import type { RouterBridge } from "@xmachines/play-router";
|
|
205
305
|
* import { Signal } from "@xmachines/play-signals";
|
|
206
306
|
*
|
|
207
|
-
* class
|
|
307
|
+
* class MyRouterBridge implements RouterBridge {
|
|
208
308
|
* private watcher: Signal.Watcher | null = null;
|
|
209
309
|
*
|
|
210
310
|
* async connect(): Promise<void> {
|
|
@@ -224,7 +324,7 @@ export interface PlayRouteEvent {
|
|
|
224
324
|
* }
|
|
225
325
|
* ```
|
|
226
326
|
*
|
|
227
|
-
* @see
|
|
327
|
+
* @see [Play RFC](../../docs/rfc/play.md) - Invariant INV-04
|
|
228
328
|
*/
|
|
229
329
|
export interface RouterBridge {
|
|
230
330
|
/**
|
|
@@ -259,4 +359,45 @@ export interface RouterBridge {
|
|
|
259
359
|
*/
|
|
260
360
|
disconnect(): void | Promise<void>;
|
|
261
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* Minimal window interface required by adapters that subscribe to DOM events
|
|
364
|
+
* (e.g. `hashchange`). Injectable for SSR and testing — pass a mock instead of
|
|
365
|
+
* the global `window` when the DOM is unavailable.
|
|
366
|
+
*
|
|
367
|
+
* Defined structurally (no `Window` reference) so this package compiles without
|
|
368
|
+
* the DOM lib.
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* ```typescript
|
|
372
|
+
* // Normal usage — global window (default)
|
|
373
|
+
* connectRouter({ actor, routeMap });
|
|
374
|
+
*
|
|
375
|
+
* // SSR / test — injected mock
|
|
376
|
+
* const mockWin: WindowLike = { addEventListener: vi.fn(), removeEventListener: vi.fn() };
|
|
377
|
+
* connectRouter({ actor, routeMap, window: mockWin });
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
export interface WindowLike {
|
|
381
|
+
addEventListener(type: string, listener: (event: Event) => void): void;
|
|
382
|
+
removeEventListener(type: string, listener: (event: Event) => void): void;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Minimal location interface required by adapters that read the current URL at
|
|
386
|
+
* `connect()` time. Injectable for SSR and testing — pass a mock instead of the
|
|
387
|
+
* global `location` when the DOM is unavailable.
|
|
388
|
+
*
|
|
389
|
+
* Defined structurally (no `Location` reference) so this package compiles without
|
|
390
|
+
* the DOM lib.
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* ```typescript
|
|
394
|
+
* // SSR / test — injected mock
|
|
395
|
+
* const mockLoc: LocationLike = { pathname: "/dashboard", search: "?tab=posts" };
|
|
396
|
+
* connectRouter({ actor, routeMap, location: mockLoc });
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
export interface LocationLike {
|
|
400
|
+
readonly pathname: string;
|
|
401
|
+
readonly search: string;
|
|
402
|
+
}
|
|
262
403
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;IAC/D,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,EAAE,aAAa,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,mCAAmC;IACnC,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,mBAAmB;IACnB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,mCAAmC;IACnC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,mCAAmC;IACnC,QAAQ,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACzB,sBAAsB;IACtB,IAAI,EAAE,SAAS,CAAC;IAChB;;;OAGG;IACH,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC;;;OAGG;IACH,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/B;;;;;;;;;;OAUG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgFG;AACH,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,aAAa;IAC7B,uEAAuE;IACvE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtD;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,kDAAkD;IAClD,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,SAAU,SAAQ,aAAa;IAC/C,mFAAmF;IACnF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CACpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;;;;;;;;;;;;OAaG;IACH,UAAU,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU;IAC1B,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IACvE,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;CAC1E;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared URLPattern utilities — internal module, NOT exported from index.ts
|
|
3
|
+
*
|
|
4
|
+
* Provides the common URLPattern plumbing shared by:
|
|
5
|
+
* - `create-route-map.ts`
|
|
6
|
+
* - `base-route-map.ts`
|
|
7
|
+
* - `find-route.ts`
|
|
8
|
+
* - `router-bridge-base.ts`
|
|
9
|
+
*
|
|
10
|
+
* URLPattern is accessed via globalThis — consumers must load a polyfill on
|
|
11
|
+
* environments without native support (Node < 24, older browsers).
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Minimal structural type for the subset of URLPattern we use.
|
|
17
|
+
* Avoids a hard dependency on the full URLPattern type declaration.
|
|
18
|
+
*/
|
|
19
|
+
export type URLPatternLike = {
|
|
20
|
+
exec(input: {
|
|
21
|
+
pathname: string;
|
|
22
|
+
}): {
|
|
23
|
+
pathname: {
|
|
24
|
+
groups: Record<string, string | undefined>;
|
|
25
|
+
};
|
|
26
|
+
} | null;
|
|
27
|
+
test(input: {
|
|
28
|
+
pathname: string;
|
|
29
|
+
}): boolean;
|
|
30
|
+
};
|
|
31
|
+
/** Constructor type for URLPatternLike instances. */
|
|
32
|
+
export type URLPatternCtor = new (init: {
|
|
33
|
+
pathname: string;
|
|
34
|
+
}) => URLPatternLike;
|
|
35
|
+
/**
|
|
36
|
+
* Retrieve the URLPattern constructor from `globalThis`, or `undefined` if
|
|
37
|
+
* it is not available (Node < 24, older browsers without a polyfill).
|
|
38
|
+
*/
|
|
39
|
+
export declare function getURLPatternCtor(): URLPatternCtor | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Check whether a route path is a parameterized pattern rather than a concrete URL.
|
|
42
|
+
*
|
|
43
|
+
* A pattern contains `:param` segments (required or optional) and/or the `*`
|
|
44
|
+
* wildcard — both require URLPattern matching and carry no concrete values, so
|
|
45
|
+
* they can never be pushed to a browser URL verbatim.
|
|
46
|
+
*
|
|
47
|
+
* This is THE single source of truth for "is this path a pattern?" — used by
|
|
48
|
+
* `RouteMap` to decide static-map vs pattern-bucket indexing and by
|
|
49
|
+
* `RouterBridgeBase.resolveNavigationPath` to skip non-navigable routes, so the
|
|
50
|
+
* two checks can never drift apart.
|
|
51
|
+
*
|
|
52
|
+
* @param path - URL path or route pattern string (e.g. `/profile/:userId`, `/docs/*`)
|
|
53
|
+
* @returns `true` if the path contains `:param` or `*` pattern syntax
|
|
54
|
+
*/
|
|
55
|
+
export declare function isParameterizedPattern(path: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Normalize a route path so its parameter names are valid URLPattern identifiers.
|
|
58
|
+
*
|
|
59
|
+
* URLPattern requires parameter names to be valid JS identifiers (no hyphens).
|
|
60
|
+
* Hyphenated names like `:cat-id` are replaced with underscored equivalents
|
|
61
|
+
* (`:cat_id`) for the URLPattern compilation step. Callers that need the captured
|
|
62
|
+
* group values (not just a match test) must map the normalized group names back to
|
|
63
|
+
* the original param names via {@link getNormalizedParamNameMap}.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* normalizeParamNames("/docs/:cat-id/:page-num?")
|
|
67
|
+
* // → "/docs/:cat_id/:page_num?"
|
|
68
|
+
*/
|
|
69
|
+
export declare function normalizeParamNames(path: string): string;
|
|
70
|
+
/**
|
|
71
|
+
* Build a map from normalized URLPattern group names back to the original
|
|
72
|
+
* (hyphenated) param names for a route pattern.
|
|
73
|
+
*
|
|
74
|
+
* Only params rewritten by {@link normalizeParamNames} appear in the map —
|
|
75
|
+
* params that are already valid identifiers keep their own name and need no entry.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* getNormalizedParamNameMap("/docs/:cat-id/:plain")
|
|
79
|
+
* // → Map { "cat_id" → "cat-id" }
|
|
80
|
+
*/
|
|
81
|
+
export declare function getNormalizedParamNameMap(path: string): Map<string, string>;
|
|
82
|
+
/**
|
|
83
|
+
* Compile a route pattern to a `URLPattern`, reusing the module-level cache.
|
|
84
|
+
*
|
|
85
|
+
* The pattern is normalized with {@link normalizeParamNames} before compilation
|
|
86
|
+
* so hyphenated param names (`:cat-id`) become valid URLPattern identifiers
|
|
87
|
+
* (`:cat_id`). Callers that extract group values must map the normalized names
|
|
88
|
+
* back via {@link getNormalizedParamNameMap}.
|
|
89
|
+
*
|
|
90
|
+
* Compilation errors from the URLPattern constructor propagate as-is — callers
|
|
91
|
+
* that need a typed error wrap this in `InvalidRoutePatternError`.
|
|
92
|
+
*
|
|
93
|
+
* @param pattern - Route pattern string (e.g. `/profile/:userId`)
|
|
94
|
+
* @param Ctor - URLPattern constructor retrieved via {@link getURLPatternCtor}
|
|
95
|
+
*/
|
|
96
|
+
export declare function getCompiledPattern(pattern: string, Ctor: URLPatternCtor): URLPatternLike;
|
|
97
|
+
/**
|
|
98
|
+
* Compute the bucket index key for a given path or pattern.
|
|
99
|
+
*
|
|
100
|
+
* The key is the first path segment (e.g. `"settings"` for `"/settings/:id"`).
|
|
101
|
+
* Parameterised first segments (`:lang`) fall into the `"*"` wildcard bucket.
|
|
102
|
+
* The root path `"/"` maps to the key `"/"`.
|
|
103
|
+
*
|
|
104
|
+
* @param path - URL path or route pattern string
|
|
105
|
+
*/
|
|
106
|
+
export declare function getIndexKey(path: string): string;
|
|
107
|
+
/**
|
|
108
|
+
* Merge the named-segment bucket and the wildcard bucket for a given index key,
|
|
109
|
+
* preserving insertion order (by `order` field).
|
|
110
|
+
*
|
|
111
|
+
* @param patternBuckets - Map of bucket key → ordered pattern entries
|
|
112
|
+
* @param indexKey - First-segment key computed by `getIndexKey`
|
|
113
|
+
*/
|
|
114
|
+
export declare function getCandidates<T extends {
|
|
115
|
+
order: number;
|
|
116
|
+
}>(patternBuckets: Map<string, T[]>, indexKey: string): T[];
|
|
117
|
+
//# sourceMappingURL=url-pattern-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-pattern-utils.d.ts","sourceRoot":"","sources":["../src/url-pattern-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,IAAI,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG;QAClC,QAAQ,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;SAAE,CAAC;KACzD,GAAG,IAAI,CAAC;IACT,IAAI,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;CAC3C,CAAC;AAEF,qDAAqD;AACrD,MAAM,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAK,cAAc,CAAC;AAEhF;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAO3E;AAeD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,cAAc,CAWxF;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EACxD,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAChC,QAAQ,EAAE,MAAM,GACd,CAAC,EAAE,CA2BL"}
|