@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,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RouteMap — Shared bidirectional route mapping base class
|
|
3
|
+
*
|
|
4
|
+
* Provides bucket-based pattern matching shared across all framework adapters.
|
|
5
|
+
* Adapters extend this class rather than duplicating the pattern-match logic.
|
|
6
|
+
*
|
|
7
|
+
* Algorithm: O(1) exact match via Map, then bucket-based O(k) pattern match
|
|
8
|
+
* where k = routes in the first-segment bucket (typically << total routes).
|
|
9
|
+
* Uses URLPattern for parameterized route matching.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* A single state ID ↔ path mapping entry.
|
|
13
|
+
*
|
|
14
|
+
* Both fields are `readonly` — mappings are immutable once passed to `RouteMap`.
|
|
15
|
+
* Adapter packages re-export a structurally compatible `RouteMapping` type under
|
|
16
|
+
* their own name. This type is published from `@xmachines/play-router` as
|
|
17
|
+
* `RouteMapping` to avoid name collisions with those adapter-local types.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const mapping: RouteMapping = { stateId: "home", path: "/" };
|
|
22
|
+
* const paramMapping: RouteMapping = { stateId: "profile", path: "/profile/:userId" };
|
|
23
|
+
* const optionalMapping: RouteMapping = { stateId: "settings", path: "/settings/:section?" };
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export interface RouteMapping {
|
|
27
|
+
/** State machine state ID (e.g., `"home"`, `"#profile"`) */
|
|
28
|
+
readonly stateId: string;
|
|
29
|
+
/** URL path pattern (e.g., `"/"`, `"/profile/:userId"`, `"/settings/:section?"`) */
|
|
30
|
+
readonly path: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Shared bidirectional route map base class.
|
|
34
|
+
*
|
|
35
|
+
* All framework adapters use this class as their route map — they add no logic of their
|
|
36
|
+
* own and inherit the full public API from here.
|
|
37
|
+
*
|
|
38
|
+
* **Lookup strategy:**
|
|
39
|
+
* - Static paths (no `:param`) → O(1) `Map` lookup
|
|
40
|
+
* - Dynamic paths → O(k) bucket-indexed scan using `URLPattern`, where `k` is the number
|
|
41
|
+
* of routes sharing the same first path segment
|
|
42
|
+
* - Results are cached after the first match in an LRU cache (default 500 entries,
|
|
43
|
+
* configurable via the `cacheSize` constructor option)
|
|
44
|
+
*
|
|
45
|
+
* **Pattern syntax** (`:param` / `:param?` / `*`):
|
|
46
|
+
* - `:param` — required segment, matches exactly one non-`/` segment
|
|
47
|
+
* - `:param?` — optional segment, matches zero or one non-`/` segment
|
|
48
|
+
* - `*` — wildcard, matches any number of segments (URLPattern semantics)
|
|
49
|
+
*
|
|
50
|
+
* **StateId forms:** stateIds may be registered and looked up in either
|
|
51
|
+
* `"#stateId"` or `"stateId"` form — `RouteMap` canonicalizes internally.
|
|
52
|
+
* `getStateIdByPath` returns the stateId exactly as registered;
|
|
53
|
+
* `getPathByStateId` accepts both forms. Registering the same stateId in both
|
|
54
|
+
* forms refers to one entry (the later registration wins for reverse lookup).
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* import { RouteMap } from "@xmachines/play-router";
|
|
59
|
+
*
|
|
60
|
+
* const map = new RouteMap([
|
|
61
|
+
* { stateId: "home", path: "/" },
|
|
62
|
+
* { stateId: "profile", path: "/profile/:userId" },
|
|
63
|
+
* { stateId: "settings", path: "/settings/:section?" },
|
|
64
|
+
* ]);
|
|
65
|
+
*
|
|
66
|
+
* map.getStateIdByPath("/"); // "home"
|
|
67
|
+
* map.getStateIdByPath("/profile/123"); // "profile"
|
|
68
|
+
* map.getStateIdByPath("/settings"); // "settings"
|
|
69
|
+
* map.getStateIdByPath("/unknown"); // null
|
|
70
|
+
*
|
|
71
|
+
* map.getPathByStateId("profile"); // "/profile/:userId"
|
|
72
|
+
* map.getPathByStateId("missing"); // null
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare class RouteMap {
|
|
76
|
+
/** Keyed on the canonical (bare, `#`-stripped) stateId form. */
|
|
77
|
+
private stateIdToPath;
|
|
78
|
+
private pathToStateId;
|
|
79
|
+
private patternBuckets;
|
|
80
|
+
private pathMatchCache;
|
|
81
|
+
/**
|
|
82
|
+
* Build a route map from an array of state ID ↔ path mappings.
|
|
83
|
+
*
|
|
84
|
+
* Static paths (no `:param`) are indexed in an O(1) `Map`.
|
|
85
|
+
* Parameterized paths are compiled to `URLPattern` and grouped into first-segment
|
|
86
|
+
* buckets for efficient candidate selection.
|
|
87
|
+
*
|
|
88
|
+
* @param mappings - Array of `{ stateId, path }` entries. Order determines
|
|
89
|
+
* priority when multiple patterns could match the same path.
|
|
90
|
+
* @param options - Optional configuration.
|
|
91
|
+
* `options.cacheSize`: Maximum number of resolved parameterized path lookups
|
|
92
|
+
* to cache. Defaults to `500`. Increase for applications with many unique
|
|
93
|
+
* parameterized URL values (e.g. user profile pages with thousands of distinct IDs).
|
|
94
|
+
* After eviction the path falls back to the O(k) bucket pattern scan — correct
|
|
95
|
+
* but slower. Minimum effective value is `1` (QuickLRU constraint).
|
|
96
|
+
*/
|
|
97
|
+
constructor(mappings: RouteMapping[], { cacheSize }?: {
|
|
98
|
+
cacheSize?: number;
|
|
99
|
+
});
|
|
100
|
+
/**
|
|
101
|
+
* Resolve a URL path to its mapped state ID.
|
|
102
|
+
*
|
|
103
|
+
* Strips query strings and hash fragments before matching. Tries an O(1) exact
|
|
104
|
+
* lookup first, then falls back to bucket-indexed pattern matching. Results are
|
|
105
|
+
* cached after the first pattern match.
|
|
106
|
+
*
|
|
107
|
+
* @param path - URL pathname, optionally including query/hash (e.g., `"/profile/123?ref=nav"`)
|
|
108
|
+
* @returns The mapped state ID, or `null` if no route matches
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* map.getStateIdByPath("/profile/123"); // "profile"
|
|
113
|
+
* map.getStateIdByPath("/unknown"); // null
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
getStateIdByPath(path: string): string | null;
|
|
117
|
+
/**
|
|
118
|
+
* Look up the path pattern registered for a state ID.
|
|
119
|
+
*
|
|
120
|
+
* Accepts the stateId in either `"#stateId"` or `"stateId"` form regardless of
|
|
121
|
+
* which form was used at registration — lookups are canonicalized internally,
|
|
122
|
+
* so consumers never need to try both forms.
|
|
123
|
+
*
|
|
124
|
+
* @param stateId - State machine state ID (e.g., `"profile"`, `"#settings"`)
|
|
125
|
+
* @returns The registered path pattern, or `null` if the state ID is unknown
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* map.getPathByStateId("profile"); // "/profile/:userId"
|
|
130
|
+
* map.getPathByStateId("#profile"); // "/profile/:userId" (same entry)
|
|
131
|
+
* map.getPathByStateId("missing"); // null
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
getPathByStateId(stateId: string): string | null;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=base-route-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-route-map.d.ts","sourceRoot":"","sources":["../src/base-route-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA0BH;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBAAa,QAAQ;IACpB,gEAAgE;IAChE,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,cAAc,CAGpB;IACF,OAAO,CAAC,cAAc,CAAkC;IAExD;;;;;;;;;;;;;;;OAeG;gBACS,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,SAAe,EAAE,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO;IAmCtF;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAuB7C;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAGhD"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RouteMap — Shared bidirectional route mapping base class
|
|
3
|
+
*
|
|
4
|
+
* Provides bucket-based pattern matching shared across all framework adapters.
|
|
5
|
+
* Adapters extend this class rather than duplicating the pattern-match logic.
|
|
6
|
+
*
|
|
7
|
+
* Algorithm: O(1) exact match via Map, then bucket-based O(k) pattern match
|
|
8
|
+
* where k = routes in the first-segment bucket (typically << total routes).
|
|
9
|
+
* Uses URLPattern for parameterized route matching.
|
|
10
|
+
*/
|
|
11
|
+
import QuickLRU from "quick-lru";
|
|
12
|
+
import { getURLPatternCtor, getCompiledPattern, getIndexKey, getCandidates, isParameterizedPattern, } from "./url-pattern-utils.js";
|
|
13
|
+
import { URLPatternUnavailableError, InvalidRoutePatternError } from "./errors.js";
|
|
14
|
+
/**
|
|
15
|
+
* Canonical stateId key: the bare form with any leading `#` stripped.
|
|
16
|
+
*
|
|
17
|
+
* `RouteMap` accepts stateIds in both `"#stateId"` and `"stateId"` form on insert
|
|
18
|
+
* and on lookup. Internally every stateId is keyed on this canonical bare form so
|
|
19
|
+
* consumers never need to re-implement dual-form handling. The *registered* form
|
|
20
|
+
* is preserved and returned by `getStateIdByPath` so the map is transparent about
|
|
21
|
+
* how routes were declared.
|
|
22
|
+
*/
|
|
23
|
+
function canonicalStateIdKey(stateId) {
|
|
24
|
+
return stateId.startsWith("#") ? stateId.slice(1) : stateId;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Shared bidirectional route map base class.
|
|
28
|
+
*
|
|
29
|
+
* All framework adapters use this class as their route map — they add no logic of their
|
|
30
|
+
* own and inherit the full public API from here.
|
|
31
|
+
*
|
|
32
|
+
* **Lookup strategy:**
|
|
33
|
+
* - Static paths (no `:param`) → O(1) `Map` lookup
|
|
34
|
+
* - Dynamic paths → O(k) bucket-indexed scan using `URLPattern`, where `k` is the number
|
|
35
|
+
* of routes sharing the same first path segment
|
|
36
|
+
* - Results are cached after the first match in an LRU cache (default 500 entries,
|
|
37
|
+
* configurable via the `cacheSize` constructor option)
|
|
38
|
+
*
|
|
39
|
+
* **Pattern syntax** (`:param` / `:param?` / `*`):
|
|
40
|
+
* - `:param` — required segment, matches exactly one non-`/` segment
|
|
41
|
+
* - `:param?` — optional segment, matches zero or one non-`/` segment
|
|
42
|
+
* - `*` — wildcard, matches any number of segments (URLPattern semantics)
|
|
43
|
+
*
|
|
44
|
+
* **StateId forms:** stateIds may be registered and looked up in either
|
|
45
|
+
* `"#stateId"` or `"stateId"` form — `RouteMap` canonicalizes internally.
|
|
46
|
+
* `getStateIdByPath` returns the stateId exactly as registered;
|
|
47
|
+
* `getPathByStateId` accepts both forms. Registering the same stateId in both
|
|
48
|
+
* forms refers to one entry (the later registration wins for reverse lookup).
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* import { RouteMap } from "@xmachines/play-router";
|
|
53
|
+
*
|
|
54
|
+
* const map = new RouteMap([
|
|
55
|
+
* { stateId: "home", path: "/" },
|
|
56
|
+
* { stateId: "profile", path: "/profile/:userId" },
|
|
57
|
+
* { stateId: "settings", path: "/settings/:section?" },
|
|
58
|
+
* ]);
|
|
59
|
+
*
|
|
60
|
+
* map.getStateIdByPath("/"); // "home"
|
|
61
|
+
* map.getStateIdByPath("/profile/123"); // "profile"
|
|
62
|
+
* map.getStateIdByPath("/settings"); // "settings"
|
|
63
|
+
* map.getStateIdByPath("/unknown"); // null
|
|
64
|
+
*
|
|
65
|
+
* map.getPathByStateId("profile"); // "/profile/:userId"
|
|
66
|
+
* map.getPathByStateId("missing"); // null
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export class RouteMap {
|
|
70
|
+
/** Keyed on the canonical (bare, `#`-stripped) stateId form. */
|
|
71
|
+
stateIdToPath;
|
|
72
|
+
pathToStateId;
|
|
73
|
+
patternBuckets;
|
|
74
|
+
pathMatchCache;
|
|
75
|
+
/**
|
|
76
|
+
* Build a route map from an array of state ID ↔ path mappings.
|
|
77
|
+
*
|
|
78
|
+
* Static paths (no `:param`) are indexed in an O(1) `Map`.
|
|
79
|
+
* Parameterized paths are compiled to `URLPattern` and grouped into first-segment
|
|
80
|
+
* buckets for efficient candidate selection.
|
|
81
|
+
*
|
|
82
|
+
* @param mappings - Array of `{ stateId, path }` entries. Order determines
|
|
83
|
+
* priority when multiple patterns could match the same path.
|
|
84
|
+
* @param options - Optional configuration.
|
|
85
|
+
* `options.cacheSize`: Maximum number of resolved parameterized path lookups
|
|
86
|
+
* to cache. Defaults to `500`. Increase for applications with many unique
|
|
87
|
+
* parameterized URL values (e.g. user profile pages with thousands of distinct IDs).
|
|
88
|
+
* After eviction the path falls back to the O(k) bucket pattern scan — correct
|
|
89
|
+
* but slower. Minimum effective value is `1` (QuickLRU constraint).
|
|
90
|
+
*/
|
|
91
|
+
constructor(mappings, { cacheSize = 500 } = {}) {
|
|
92
|
+
this.stateIdToPath = new Map();
|
|
93
|
+
this.pathToStateId = new Map();
|
|
94
|
+
this.patternBuckets = new Map();
|
|
95
|
+
this.pathMatchCache = new QuickLRU({ maxSize: Math.max(1, cacheSize) });
|
|
96
|
+
let patternOrder = 0;
|
|
97
|
+
for (const { stateId, path } of mappings) {
|
|
98
|
+
// Key on the canonical (bare) form so getPathByStateId accepts both
|
|
99
|
+
// "#stateId" and "stateId". The registered form is kept for returns.
|
|
100
|
+
this.stateIdToPath.set(canonicalStateIdKey(stateId), path);
|
|
101
|
+
if (isParameterizedPattern(path)) {
|
|
102
|
+
const URLPatternCtorFn = getURLPatternCtor();
|
|
103
|
+
if (!URLPatternCtorFn) {
|
|
104
|
+
throw new URLPatternUnavailableError();
|
|
105
|
+
}
|
|
106
|
+
const bucketKey = getIndexKey(path);
|
|
107
|
+
const bucket = this.patternBuckets.get(bucketKey) ?? [];
|
|
108
|
+
try {
|
|
109
|
+
bucket.push({
|
|
110
|
+
pattern: getCompiledPattern(path, URLPatternCtorFn),
|
|
111
|
+
stateId,
|
|
112
|
+
order: patternOrder++,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
throw new InvalidRoutePatternError(path, { cause: err });
|
|
117
|
+
}
|
|
118
|
+
this.patternBuckets.set(bucketKey, bucket);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
this.pathToStateId.set(path, stateId);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Resolve a URL path to its mapped state ID.
|
|
127
|
+
*
|
|
128
|
+
* Strips query strings and hash fragments before matching. Tries an O(1) exact
|
|
129
|
+
* lookup first, then falls back to bucket-indexed pattern matching. Results are
|
|
130
|
+
* cached after the first pattern match.
|
|
131
|
+
*
|
|
132
|
+
* @param path - URL pathname, optionally including query/hash (e.g., `"/profile/123?ref=nav"`)
|
|
133
|
+
* @returns The mapped state ID, or `null` if no route matches
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* map.getStateIdByPath("/profile/123"); // "profile"
|
|
138
|
+
* map.getStateIdByPath("/unknown"); // null
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
getStateIdByPath(path) {
|
|
142
|
+
// Strip query string and hash fragment for matching
|
|
143
|
+
const cleanPath = path.split("?")[0].split("#")[0];
|
|
144
|
+
const exactMatch = this.pathToStateId.get(cleanPath);
|
|
145
|
+
if (exactMatch !== undefined)
|
|
146
|
+
return exactMatch;
|
|
147
|
+
const cachedMatch = this.pathMatchCache.get(cleanPath);
|
|
148
|
+
if (cachedMatch !== undefined)
|
|
149
|
+
return cachedMatch;
|
|
150
|
+
const candidates = getCandidates(this.patternBuckets, getIndexKey(cleanPath));
|
|
151
|
+
for (const { pattern, stateId } of candidates) {
|
|
152
|
+
const match = pattern.exec({ pathname: cleanPath });
|
|
153
|
+
if (match) {
|
|
154
|
+
this.pathMatchCache.set(cleanPath, stateId);
|
|
155
|
+
return stateId;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
this.pathMatchCache.set(cleanPath, null);
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Look up the path pattern registered for a state ID.
|
|
163
|
+
*
|
|
164
|
+
* Accepts the stateId in either `"#stateId"` or `"stateId"` form regardless of
|
|
165
|
+
* which form was used at registration — lookups are canonicalized internally,
|
|
166
|
+
* so consumers never need to try both forms.
|
|
167
|
+
*
|
|
168
|
+
* @param stateId - State machine state ID (e.g., `"profile"`, `"#settings"`)
|
|
169
|
+
* @returns The registered path pattern, or `null` if the state ID is unknown
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* map.getPathByStateId("profile"); // "/profile/:userId"
|
|
174
|
+
* map.getPathByStateId("#profile"); // "/profile/:userId" (same entry)
|
|
175
|
+
* map.getPathByStateId("missing"); // null
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
getPathByStateId(stateId) {
|
|
179
|
+
return this.stateIdToPath.get(canonicalStateIdKey(stateId)) ?? null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=base-route-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-route-map.js","sourceRoot":"","sources":["../src/base-route-map.ts"],"names":[],"mappings":"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"}
|
package/dist/build-tree.d.ts
CHANGED
|
@@ -6,8 +6,15 @@ import type { RouteInfo, RouteTree } from "./types.js";
|
|
|
6
6
|
* Absolute routes become top-level, relative routes nest under parents.
|
|
7
7
|
* Creates bidirectional maps for state ID ↔ path lookup.
|
|
8
8
|
*
|
|
9
|
+
* Duplicate detection runs here — after relative routes are resolved against
|
|
10
|
+
* their parent's full path — so two relative routes with the same raw string
|
|
11
|
+
* under different parents are valid, while distinct raw strings that resolve to
|
|
12
|
+
* the same full path (which would silently overwrite each other in `byPath`)
|
|
13
|
+
* are rejected.
|
|
14
|
+
*
|
|
9
15
|
* @param routes - Flat list of RouteInfo from extraction
|
|
10
16
|
* @returns RouteTree with root, byStateId map, and byPath map
|
|
17
|
+
* @throws {DuplicateRoutePathError} If two states resolve to the same full path
|
|
11
18
|
*/
|
|
12
19
|
export declare const buildRouteTree: (routes: RouteInfo[]) => RouteTree;
|
|
13
20
|
//# sourceMappingURL=build-tree.d.ts.map
|
package/dist/build-tree.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-tree.d.ts","sourceRoot":"","sources":["../src/build-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"build-tree.d.ts","sourceRoot":"","sources":["../src/build-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAA4B,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,SAAS,EAAE,KAAG,SAwEpD,CAAC"}
|
package/dist/build-tree.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { detectDuplicateRoutes } from "./validate-routes.js";
|
|
1
2
|
/**
|
|
2
3
|
* Build hierarchical route tree from flat route list
|
|
3
4
|
*
|
|
@@ -5,8 +6,15 @@
|
|
|
5
6
|
* Absolute routes become top-level, relative routes nest under parents.
|
|
6
7
|
* Creates bidirectional maps for state ID ↔ path lookup.
|
|
7
8
|
*
|
|
9
|
+
* Duplicate detection runs here — after relative routes are resolved against
|
|
10
|
+
* their parent's full path — so two relative routes with the same raw string
|
|
11
|
+
* under different parents are valid, while distinct raw strings that resolve to
|
|
12
|
+
* the same full path (which would silently overwrite each other in `byPath`)
|
|
13
|
+
* are rejected.
|
|
14
|
+
*
|
|
8
15
|
* @param routes - Flat list of RouteInfo from extraction
|
|
9
16
|
* @returns RouteTree with root, byStateId map, and byPath map
|
|
17
|
+
* @throws {DuplicateRoutePathError} If two states resolve to the same full path
|
|
10
18
|
*/
|
|
11
19
|
export const buildRouteTree = (routes) => {
|
|
12
20
|
// 1. Create root node
|
|
@@ -18,20 +26,23 @@ export const buildRouteTree = (routes) => {
|
|
|
18
26
|
routable: false, // Root is not a routable state
|
|
19
27
|
children: [],
|
|
20
28
|
parent: null,
|
|
21
|
-
metadata:
|
|
29
|
+
metadata: "", // Synthetic non-routable root — no real route metadata
|
|
22
30
|
};
|
|
23
31
|
// 2. Initialize maps
|
|
24
32
|
const byStateId = new Map([[root.stateId, root]]);
|
|
25
33
|
const byPath = new Map([[root.fullPath, root]]);
|
|
26
34
|
// 3. Sort routes by depth (shallowest first for proper parent linking)
|
|
35
|
+
// oxlint-disable-next-line unicorn/no-array-sort
|
|
27
36
|
const sorted = routes.slice().sort((a, b) => a.statePath.length - b.statePath.length);
|
|
28
|
-
// 4. Build tree
|
|
37
|
+
// 4. Build tree, collecting inserted nodes for resolved-path duplicate detection
|
|
38
|
+
const insertedNodes = [];
|
|
29
39
|
for (const route of sorted) {
|
|
30
|
-
// Find parent by walking up state path
|
|
40
|
+
// Find parent by walking up state path.
|
|
41
|
+
// Each entry in statePath is a full dotted stateId (e.g., "chain.app.section"),
|
|
42
|
+
// so we check each ancestor stateId directly from the end of the list.
|
|
31
43
|
let parentNode = root;
|
|
32
|
-
for (let i = route.statePath.length -
|
|
33
|
-
const
|
|
34
|
-
const parentStateId = parentPath.join(".");
|
|
44
|
+
for (let i = route.statePath.length - 2; i >= 0; i--) {
|
|
45
|
+
const parentStateId = route.statePath[i]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
35
46
|
if (byStateId.has(parentStateId)) {
|
|
36
47
|
parentNode = byStateId.get(parentStateId);
|
|
37
48
|
break;
|
|
@@ -61,7 +72,11 @@ export const buildRouteTree = (routes) => {
|
|
|
61
72
|
// Add to maps for bidirectional lookup
|
|
62
73
|
byStateId.set(node.stateId, node);
|
|
63
74
|
byPath.set(node.fullPath, node);
|
|
75
|
+
insertedNodes.push(node);
|
|
64
76
|
}
|
|
77
|
+
// 5. Reject resolved full-path collisions — a silent byPath overwrite would
|
|
78
|
+
// leave one state unreachable by URL.
|
|
79
|
+
detectDuplicateRoutes(insertedNodes);
|
|
65
80
|
return { root, byStateId, byPath };
|
|
66
81
|
};
|
|
67
82
|
//# sourceMappingURL=build-tree.js.map
|
package/dist/build-tree.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-tree.js","sourceRoot":"","sources":["../src/build-tree.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build-tree.js","sourceRoot":"","sources":["../src/build-tree.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAmB,EAAa,EAAE;IAChE,sBAAsB;IACtB,MAAM,IAAI,GAAc;QACvB,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,GAAG;QACb,OAAO,EAAE,UAAU;QACnB,QAAQ,EAAE,KAAK,EAAE,+BAA+B;QAChD,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,EAAmB,EAAE,uDAAuD;KACtF,CAAC;IAEF,qBAAqB;IACrB,MAAM,SAAS,GAAG,IAAI,GAAG,CAAoB,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAoB,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAEnE,uEAAuE;IACvE,iDAAiD;IACjD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAEtF,iFAAiF;IACjF,MAAM,aAAa,GAAgB,EAAE,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,wCAAwC;QACxC,gFAAgF;QAChF,uEAAuE;QACvE,IAAI,UAAU,GAAG,IAAI,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACtD,MAAM,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,mDAAmD;YAC7F,IAAI,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;gBAClC,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,aAAa,CAAE,CAAC;gBAC3C,MAAM;YACP,CAAC;QACF,CAAC;QAED,kBAAkB;QAClB,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU;YAChC,CAAC,CAAC,KAAK,CAAC,SAAS;YACjB,CAAC,CAAC,GAAG,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAEpE,cAAc;QACd,MAAM,IAAI,GAAc;YACvB,EAAE,EAAE,KAAK,CAAC,OAAO;YACjB,IAAI,EAAE,KAAK,CAAC,SAAS;YACrB,QAAQ;YACR,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,EAAE;YACZ,MAAM,EAAE,UAAU;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACxB,CAAC;QAEF,2BAA2B;QAC3B,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC9B,CAAC;QAED,iBAAiB;QACjB,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE/B,uCAAuC;QACvC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAChC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,4EAA4E;IAC5E,sCAAsC;IACtC,qBAAqB,CAAC,aAAa,CAAC,CAAC;IAErC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACpC,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { RouteTree } from "./types.js";
|
|
2
|
+
import { RouteMap } from "./base-route-map.js";
|
|
3
|
+
import type { RouteMapOptions } from "./create-route-map.js";
|
|
4
|
+
/**
|
|
5
|
+
* Create a `RouteMap` from a `RouteTree` node structure.
|
|
6
|
+
*
|
|
7
|
+
* Used by framework-router adapters that pass a
|
|
8
|
+
* `RouteTree` produced by `extractMachineRoutes()` rather than calling
|
|
9
|
+
* `createRouteMap()` directly.
|
|
10
|
+
*
|
|
11
|
+
* Traverses all nodes collecting `{ stateId: node.id, path: node.fullPath }` pairs.
|
|
12
|
+
* `node.fullPath` is always the absolute resolved path (e.g. `"/dashboard/overview"`),
|
|
13
|
+
* which is what `RouteMap` needs for browser URL matching. This matches the
|
|
14
|
+
* behaviour of `createRouteMap(machine)`, which also uses `node.fullPath`.
|
|
15
|
+
*
|
|
16
|
+
* @param routeTree - A `RouteTree` as returned by `extractMachineRoutes()`.
|
|
17
|
+
* @param options - Optional configuration (e.g. `{ cacheSize }` to override the LRU cache size).
|
|
18
|
+
* @returns A `RouteMap` for use with any `RouterBridgeBase`-based adapter.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* // Preferred — single call for XState machines:
|
|
23
|
+
* import { createRouteMap } from '@xmachines/play-router';
|
|
24
|
+
* const routeMap = createRouteMap(machine); // takes AnyStateMachine
|
|
25
|
+
*
|
|
26
|
+
* // Two-step form used by framework adapters that work with route trees:
|
|
27
|
+
* import { extractMachineRoutes, createRouteMapFromTree } from '@xmachines/play-router';
|
|
28
|
+
* const routeTree = extractMachineRoutes(machine);
|
|
29
|
+
* const routeMap = createRouteMapFromTree(routeTree); // uses node.fullPath (absolute)
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function createRouteMapFromTree(routeTree: RouteTree, options?: RouteMapOptions): RouteMap;
|
|
33
|
+
//# sourceMappingURL=create-route-map-from-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-route-map-from-tree.d.ts","sourceRoot":"","sources":["../src/create-route-map-from-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,QAAQ,CAchG"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { RouteMap } from "./base-route-map.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a `RouteMap` from a `RouteTree` node structure.
|
|
4
|
+
*
|
|
5
|
+
* Used by framework-router adapters that pass a
|
|
6
|
+
* `RouteTree` produced by `extractMachineRoutes()` rather than calling
|
|
7
|
+
* `createRouteMap()` directly.
|
|
8
|
+
*
|
|
9
|
+
* Traverses all nodes collecting `{ stateId: node.id, path: node.fullPath }` pairs.
|
|
10
|
+
* `node.fullPath` is always the absolute resolved path (e.g. `"/dashboard/overview"`),
|
|
11
|
+
* which is what `RouteMap` needs for browser URL matching. This matches the
|
|
12
|
+
* behaviour of `createRouteMap(machine)`, which also uses `node.fullPath`.
|
|
13
|
+
*
|
|
14
|
+
* @param routeTree - A `RouteTree` as returned by `extractMachineRoutes()`.
|
|
15
|
+
* @param options - Optional configuration (e.g. `{ cacheSize }` to override the LRU cache size).
|
|
16
|
+
* @returns A `RouteMap` for use with any `RouterBridgeBase`-based adapter.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Preferred — single call for XState machines:
|
|
21
|
+
* import { createRouteMap } from '@xmachines/play-router';
|
|
22
|
+
* const routeMap = createRouteMap(machine); // takes AnyStateMachine
|
|
23
|
+
*
|
|
24
|
+
* // Two-step form used by framework adapters that work with route trees:
|
|
25
|
+
* import { extractMachineRoutes, createRouteMapFromTree } from '@xmachines/play-router';
|
|
26
|
+
* const routeTree = extractMachineRoutes(machine);
|
|
27
|
+
* const routeMap = createRouteMapFromTree(routeTree); // uses node.fullPath (absolute)
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function createRouteMapFromTree(routeTree, options) {
|
|
31
|
+
const routes = [];
|
|
32
|
+
function traverse(node) {
|
|
33
|
+
if (node.id && node.fullPath) {
|
|
34
|
+
routes.push({ stateId: node.id, path: node.fullPath });
|
|
35
|
+
}
|
|
36
|
+
if (node.children) {
|
|
37
|
+
node.children.forEach(traverse);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
traverse(routeTree.root);
|
|
41
|
+
return new RouteMap(routes, options);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=create-route-map-from-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-route-map-from-tree.js","sourceRoot":"","sources":["../src/create-route-map-from-tree.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAoB,EAAE,OAAyB;IACrF,MAAM,MAAM,GAA6C,EAAE,CAAC;IAE5D,SAAS,QAAQ,CAAC,IAAe;QAChC,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;IACF,CAAC;IAED,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -1,46 +1,42 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { AnyStateMachine } from "xstate";
|
|
2
|
+
import { RouteMap } from "./base-route-map.js";
|
|
3
|
+
/**
|
|
4
|
+
* Options for `createRouteMap` and `createRouteMapFromTree`.
|
|
5
|
+
*/
|
|
6
|
+
export interface RouteMapOptions {
|
|
3
7
|
/**
|
|
4
|
-
*
|
|
8
|
+
* Maximum number of resolved parameterized path lookups to cache.
|
|
5
9
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
10
|
+
* `RouteMap.getStateIdByPath()` resolves parameterized patterns (e.g.
|
|
11
|
+
* `/profile/:userId`) via URLPattern on every call. Frequently visited
|
|
12
|
+
* paths are cached in an LRU so subsequent lookups are O(1).
|
|
8
13
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* const { to, params } = routeMap.resolve('/settings/account');
|
|
12
|
-
* // { to: "#settings", params: { section: "account" } }
|
|
13
|
-
*
|
|
14
|
-
* if (to) {
|
|
15
|
-
* actor.send({ type: 'play.route', to, params });
|
|
16
|
-
* }
|
|
17
|
-
* ```
|
|
14
|
+
* Increase this value for applications with large parameterized route sets
|
|
15
|
+
* or high navigation frequency. Default: `500`.
|
|
18
16
|
*/
|
|
19
|
-
|
|
20
|
-
to: string | null;
|
|
21
|
-
params: Record<string, string>;
|
|
22
|
-
};
|
|
17
|
+
cacheSize?: number;
|
|
23
18
|
}
|
|
24
19
|
/**
|
|
25
|
-
* Create a RouteMap from
|
|
20
|
+
* Create a `RouteMap` from an XState state machine.
|
|
21
|
+
*
|
|
22
|
+
* Extracts all routable states (those with `meta.route`) and builds a bidirectional
|
|
23
|
+
* path ↔ stateId lookup structure. The returned map is used by `RouterBridgeBase`
|
|
24
|
+
* subclasses to translate browser URL changes into `play.route` actor events and
|
|
25
|
+
* vice-versa.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
* -
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* - Returns formatted state IDs (with # prefix)
|
|
32
|
-
* - Extracts params from matched patterns
|
|
27
|
+
* @param machine - XState v5 state machine with `meta.route` annotations on states.
|
|
28
|
+
* @param options - Optional configuration. Pass `{ cacheSize }` to override the
|
|
29
|
+
* default LRU cache size for parameterized path lookups.
|
|
30
|
+
* @returns A `RouteMap` for passing to any `RouterBridgeBase`-based adapter.
|
|
33
31
|
*
|
|
34
|
-
*
|
|
32
|
+
* @example
|
|
35
33
|
* ```typescript
|
|
36
|
-
*
|
|
37
|
-
*
|
|
34
|
+
* import { createRouteMap } from '@xmachines/play-router';
|
|
35
|
+
* import { connectRouter } from '@xmachines/play-dom-router';
|
|
38
36
|
*
|
|
39
|
-
* const
|
|
40
|
-
*
|
|
41
|
-
* actor.send({ type: 'play.route', to, params });
|
|
42
|
-
* }
|
|
37
|
+
* const routeMap = createRouteMap(myMachine);
|
|
38
|
+
* const disconnect = connectRouter({ actor, router, routeMap });
|
|
43
39
|
* ```
|
|
44
40
|
*/
|
|
45
|
-
export declare function createRouteMap(
|
|
41
|
+
export declare function createRouteMap(machine: AnyStateMachine, options?: RouteMapOptions): RouteMap;
|
|
46
42
|
//# sourceMappingURL=create-route-map.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-route-map.d.ts","sourceRoot":"","sources":["../src/create-route-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"create-route-map.d.ts","sourceRoot":"","sources":["../src/create-route-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAG9C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,QAAQ,CAU5F"}
|