@xmachines/play-router 2.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -109
- package/dist/base-route-map.d.ts +7 -1
- package/dist/base-route-map.d.ts.map +1 -1
- package/dist/base-route-map.js +25 -12
- package/dist/base-route-map.js.map +1 -1
- package/dist/build-tree.d.ts +16 -1
- package/dist/build-tree.d.ts.map +1 -1
- package/dist/build-tree.js +23 -6
- package/dist/build-tree.js.map +1 -1
- package/dist/create-route-map-from-tree.d.ts +12 -6
- package/dist/create-route-map-from-tree.d.ts.map +1 -1
- package/dist/create-route-map-from-tree.js +13 -5
- package/dist/create-route-map-from-tree.js.map +1 -1
- package/dist/errors.d.ts +2 -134
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +11 -151
- package/dist/errors.js.map +1 -1
- package/dist/find-route.d.ts.map +1 -1
- package/dist/find-route.js +14 -19
- package/dist/find-route.js.map +1 -1
- package/dist/index.d.ts +7 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -11
- package/dist/index.js.map +1 -1
- package/dist/provider-lifecycle.d.ts +28 -6
- package/dist/provider-lifecycle.d.ts.map +1 -1
- package/dist/provider-lifecycle.js +16 -2
- package/dist/provider-lifecycle.js.map +1 -1
- package/dist/router-bridge-base.d.ts +42 -23
- package/dist/router-bridge-base.d.ts.map +1 -1
- package/dist/router-bridge-base.js +257 -84
- package/dist/router-bridge-base.js.map +1 -1
- package/dist/router-sync.d.ts +1 -1
- package/dist/router-sync.d.ts.map +1 -1
- package/dist/router-sync.js +28 -13
- package/dist/router-sync.js.map +1 -1
- package/dist/types.d.ts +186 -87
- package/dist/types.d.ts.map +1 -1
- package/dist/{create-route-map.d.ts → xstate/create-route-map.d.ts} +6 -20
- package/dist/xstate/create-route-map.d.ts.map +1 -0
- package/dist/{create-route-map.js → xstate/create-route-map.js} +5 -3
- package/dist/xstate/create-route-map.js.map +1 -0
- package/dist/{extract-routes.d.ts → xstate/extract-routes.d.ts} +3 -2
- package/dist/xstate/extract-routes.d.ts.map +1 -0
- package/dist/{extract-routes.js → xstate/extract-routes.js} +8 -3
- package/dist/xstate/extract-routes.js.map +1 -0
- package/dist/xstate/index.d.ts +35 -0
- package/dist/xstate/index.d.ts.map +1 -0
- package/dist/xstate/index.js +33 -0
- package/dist/xstate/index.js.map +1 -0
- package/dist/{machine-to-graph.d.ts → xstate/machine-to-graph.d.ts} +1 -1
- package/dist/xstate/machine-to-graph.d.ts.map +1 -0
- package/dist/{machine-to-graph.js → xstate/machine-to-graph.js} +2 -2
- package/dist/xstate/machine-to-graph.js.map +1 -0
- package/dist/xstate/machine-types.d.ts +42 -0
- package/dist/xstate/machine-types.d.ts.map +1 -0
- package/dist/xstate/machine-types.js +2 -0
- package/dist/xstate/machine-types.js.map +1 -0
- package/dist/{query.d.ts → xstate/query.d.ts} +6 -4
- package/dist/xstate/query.d.ts.map +1 -0
- package/dist/{query.js → xstate/query.js} +3 -2
- package/dist/xstate/query.js.map +1 -0
- package/package.json +26 -20
- package/dist/base-path.d.ts +0 -209
- package/dist/base-path.d.ts.map +0 -1
- package/dist/base-path.js +0 -418
- package/dist/base-path.js.map +0 -1
- package/dist/create-route-map.d.ts.map +0 -1
- package/dist/create-route-map.js.map +0 -1
- package/dist/extract-routes.d.ts.map +0 -1
- package/dist/extract-routes.js.map +0 -1
- package/dist/framework-params.d.ts +0 -144
- package/dist/framework-params.d.ts.map +0 -1
- package/dist/framework-params.js +0 -291
- package/dist/framework-params.js.map +0 -1
- package/dist/machine-to-graph.d.ts.map +0 -1
- package/dist/machine-to-graph.js.map +0 -1
- package/dist/query.d.ts.map +0 -1
- package/dist/query.js.map +0 -1
- package/dist/url-pattern-utils.d.ts +0 -93
- package/dist/url-pattern-utils.d.ts.map +0 -1
- package/dist/url-pattern-utils.js +0 -233
- package/dist/url-pattern-utils.js.map +0 -1
package/dist/base-path.js
DELETED
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The base-path support — it mounts the routes of a machine under a URL prefix.
|
|
3
|
-
*
|
|
4
|
-
* A host application often owns a part of its own URL space, and it wants a machine
|
|
5
|
-
* to own the rest of that space, inside the SAME router. A URL such as
|
|
6
|
-
* `/:machineId/play/dashboard` has two halves: `/:machineId/play` belongs to the
|
|
7
|
-
* host, which resolves `:machineId` in a loader, and `/dashboard` belongs to the
|
|
8
|
-
* `meta.route` tree of the machine.
|
|
9
|
-
*
|
|
10
|
-
* This module is the boundary between those two halves:
|
|
11
|
-
* - {@link resolveBasePath} makes the concrete prefix that the browser URL carries,
|
|
12
|
-
* from a base-path pattern and its params.
|
|
13
|
-
* - {@link stripBasePath} removes that prefix from an inbound location of the router,
|
|
14
|
-
* and it reports a location OUTSIDE the prefix as foreign, so that the bridge stays
|
|
15
|
-
* out of it.
|
|
16
|
-
* - {@link joinBasePath} adds the prefix again to an outbound path of the machine.
|
|
17
|
-
*
|
|
18
|
-
* The prefix lives on the BRIDGE, and not on the `RouteMap`. A route map is static,
|
|
19
|
-
* it is shared, and it holds an LRU cache inside, while a mount point is dynamic. One
|
|
20
|
-
* route map therefore serves every `machineId` without a rebuild.
|
|
21
|
-
*
|
|
22
|
-
* @internal The package exports these primitives for an adapter and for a host, but
|
|
23
|
-
* a consumer normally uses the `basePath` option of a bridge instead.
|
|
24
|
-
*/
|
|
25
|
-
import { InvalidBasePathError, MissingBasePathParamError } from "./errors.js";
|
|
26
|
-
/**
|
|
27
|
-
* The base path of a bridge that has no `basePath` option.
|
|
28
|
-
*
|
|
29
|
-
* The object is FROZEN, and both levels of it: {@link resolveBasePath} returns this
|
|
30
|
-
* exact instance for every bridge with no mount, and
|
|
31
|
-
* `RouterBridgeBase.basePathParams` hands its `params` to the caller.
|
|
32
|
-
* `Readonly<Record<string, string>>` is gone at run time, so without the freeze one
|
|
33
|
-
* write in consumer code would leak that key into every other unmounted bridge in
|
|
34
|
-
* the process.
|
|
35
|
-
*/
|
|
36
|
-
export const NO_BASE_PATH = Object.freeze({
|
|
37
|
-
path: "",
|
|
38
|
-
params: Object.freeze({}),
|
|
39
|
-
});
|
|
40
|
-
/**
|
|
41
|
-
* Normalizes a base path, and it substitutes no `:param` segment of that path.
|
|
42
|
-
*
|
|
43
|
-
* Use this function when you want the form of the pattern, for example to declare
|
|
44
|
-
* the routes of a machine in a route config of a host that substitutes each param
|
|
45
|
-
* itself. {@link resolveBasePath} gives the form that a bridge needs.
|
|
46
|
-
*
|
|
47
|
-
* @param basePath - The prefix, as a pattern or as a concrete path. An absent value,
|
|
48
|
-
* `""`, and `"/"` all give `""`.
|
|
49
|
-
* @returns The normalized prefix. It starts with `/`, and it carries no trailing `/`.
|
|
50
|
-
* @throws {InvalidBasePathError} For a wildcard segment, for an optional `:param?`
|
|
51
|
-
* segment, for a `$param` segment, for a query string or a hash fragment, for a URL
|
|
52
|
-
* scheme, for a dot segment (`.`, `..`, and their percent-encoded forms), and for any
|
|
53
|
-
* segment that a browser rewrites — one that holds whitespace, a backslash, or a
|
|
54
|
-
* character that a URL percent-encodes.
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
* ```typescript
|
|
58
|
-
* normalizeBasePath("/:machineId/play/"); // "/:machineId/play"
|
|
59
|
-
* normalizeBasePath("admin"); // "/admin"
|
|
60
|
-
* normalizeBasePath("/"); // ""
|
|
61
|
-
* ```
|
|
62
|
-
*/
|
|
63
|
-
export function normalizeBasePath(basePath) {
|
|
64
|
-
if (basePath === undefined || basePath === null || basePath === "")
|
|
65
|
-
return "";
|
|
66
|
-
// A base path is a PATHNAME, so refuse a whole URL before the slash collapse hides
|
|
67
|
-
// the mistake. "https://host/admin" collapses to "/https:/host/admin", whose every
|
|
68
|
-
// segment passes the segment guards below. The bridge would take that mount, then
|
|
69
|
-
// strip no real router location under it: the machine would go permanently silent,
|
|
70
|
-
// exactly as it does for a query or a hash.
|
|
71
|
-
assertNoScheme(basePath);
|
|
72
|
-
// Collapse each duplicate slash, add the leading slash, and drop the trailing one.
|
|
73
|
-
// The result therefore concatenates cleanly with a machine path, which always
|
|
74
|
-
// starts with "/", and it compares cleanly with a sanitized router location, which
|
|
75
|
-
// sanitizePathname() has already collapsed.
|
|
76
|
-
const collapsed = `/${basePath}`.replace(/\/+/g, "/").replace(/\/$/, "");
|
|
77
|
-
if (collapsed === "")
|
|
78
|
-
return "";
|
|
79
|
-
for (const segment of collapsed.slice(1).split("/")) {
|
|
80
|
-
assertBasePathSegment(segment, basePath);
|
|
81
|
-
}
|
|
82
|
-
return collapsed;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Resolves a base path and its params to the concrete prefix that a browser URL
|
|
86
|
-
* carries.
|
|
87
|
-
*
|
|
88
|
-
* A bridge calls this function one time, and again on each `setBasePath()` call. The
|
|
89
|
-
* result is always concrete. {@link stripBasePath} therefore compares a literal
|
|
90
|
-
* prefix, and no URLPattern match runs on the hot path of a navigation.
|
|
91
|
-
*
|
|
92
|
-
* @param basePath - The prefix, as a pattern or as a concrete path.
|
|
93
|
-
* @param params - The values of the `:param` segments of `basePath`.
|
|
94
|
-
* @returns The concrete prefix, and the values of each param for a `play.route` event.
|
|
95
|
-
* @throws {InvalidBasePathError} For a wildcard segment, for an optional `:param?`
|
|
96
|
-
* segment, for a `$param` segment, for a query string or a hash fragment, for a URL
|
|
97
|
-
* scheme, for a dot segment (`.`, `..`, and their percent-encoded forms), and for any
|
|
98
|
-
* segment that a browser rewrites — one that holds whitespace, a backslash, or a
|
|
99
|
-
* character that a URL percent-encodes.
|
|
100
|
-
* @throws {MissingBasePathParamError} When a `:param` of the prefix has no value.
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```typescript
|
|
104
|
-
* resolveBasePath("/:machineId/play", { machineId: "abc123" });
|
|
105
|
-
* // → { path: "/abc123/play", params: { machineId: "abc123" } }
|
|
106
|
-
*
|
|
107
|
-
* resolveBasePath("/admin");
|
|
108
|
-
* // → { path: "/admin", params: {} }
|
|
109
|
-
* ```
|
|
110
|
-
*/
|
|
111
|
-
export function resolveBasePath(basePath, params) {
|
|
112
|
-
const normalized = normalizeBasePath(basePath);
|
|
113
|
-
if (normalized === "")
|
|
114
|
-
return NO_BASE_PATH;
|
|
115
|
-
if (!normalized.includes(":")) {
|
|
116
|
-
return Object.freeze({
|
|
117
|
-
path: normalized,
|
|
118
|
-
params: Object.freeze({}),
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
// A null prototype, for both directions of the lookup. A plain `{}` accumulator
|
|
122
|
-
// turns `resolvedParams["__proto__"] = value` into a write of the PROTOTYPE, so a
|
|
123
|
-
// param of that name would vanish from the result.
|
|
124
|
-
const resolvedParams = Object.create(null);
|
|
125
|
-
const segments = normalized
|
|
126
|
-
.slice(1)
|
|
127
|
-
.split("/")
|
|
128
|
-
.map((segment) => {
|
|
129
|
-
if (!segment.startsWith(":"))
|
|
130
|
-
return segment;
|
|
131
|
-
const name = segment.slice(1);
|
|
132
|
-
// `Object.hasOwn`, and not a bare read: `params[name]` walks the prototype
|
|
133
|
-
// chain, so ":constructor" with no value of its own found
|
|
134
|
-
// `Object.prototype.constructor` and resolved the prefix to the source text of
|
|
135
|
-
// a function. `stripBasePath` then read EVERY location as foreign, and the
|
|
136
|
-
// machine went silent for ever instead of failing loudly here.
|
|
137
|
-
const value = params !== undefined && Object.hasOwn(params, name)
|
|
138
|
-
? params[name] // nosemgrep: gitlab.eslint.detect-object-injection
|
|
139
|
-
: undefined;
|
|
140
|
-
if (value === undefined || value === null || value === "") {
|
|
141
|
-
throw new MissingBasePathParamError(name, basePath ?? "");
|
|
142
|
-
}
|
|
143
|
-
const text = String(value);
|
|
144
|
-
const encoded = encodeBasePathValue(text);
|
|
145
|
-
// The guards of `assertBasePathSegment` run on the PATTERN, before this
|
|
146
|
-
// substitution, so they see ":id" and never the value that replaces it. A value
|
|
147
|
-
// of "." or ".." therefore passed every one of them and resolved away in the
|
|
148
|
-
// browser: "/m/../play" comes back as "/play", `stripBasePath` reads every
|
|
149
|
-
// location as foreign, and the machine goes permanently silent with no error —
|
|
150
|
-
// the exact failure the dot-segment guard exists to prevent. Test the RESOLVED
|
|
151
|
-
// segment here.
|
|
152
|
-
if (!isStableSegment(encoded)) {
|
|
153
|
-
throw new InvalidBasePathError(basePath ?? "", `the value "${text}" of ":${name}" resolves to the segment "${encoded}", which a browser rewrites, so the prefix that comes back is not the prefix that went out.`);
|
|
154
|
-
}
|
|
155
|
-
resolvedParams[name] = text; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
156
|
-
return encoded;
|
|
157
|
-
});
|
|
158
|
-
// FROZEN, both levels, for the same reason NO_BASE_PATH is: `RouterBridgeBase`
|
|
159
|
-
// returns `this.mount.params` BY REFERENCE from its accessor, and
|
|
160
|
-
// `Readonly<Record<string, string>>` is gone at run time. One write in consumer code
|
|
161
|
-
// would change what the bridge reports for the rest of its life, while `basePath`
|
|
162
|
-
// still holds the real prefix — the staleness the accessor promises cannot happen.
|
|
163
|
-
// Spread, and not the null-prototype record itself: a spread creates OWN properties,
|
|
164
|
-
// so a param named "__proto__" stays a key AND the value keeps a normal prototype.
|
|
165
|
-
// Handing the bare record out made `bridge.basePathParams.hasOwnProperty(…)` throw,
|
|
166
|
-
// on a value the docs describe as a `Readonly<Record<string, string>>`.
|
|
167
|
-
return Object.freeze({
|
|
168
|
-
path: `/${segments.join("/")}`,
|
|
169
|
-
params: Object.freeze({ ...resolvedParams }),
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Removes the base path from an inbound location of the router.
|
|
174
|
-
*
|
|
175
|
-
* The return value separates the two cases that make a shared router work:
|
|
176
|
-
* - A string is the MACHINE half of the location, for example `"/dashboard"` of
|
|
177
|
-
* `"/abc123/play/dashboard"`. The bridge matches it against the route map.
|
|
178
|
-
* - `null` means that the location is FOREIGN: it lies outside the mount, so it
|
|
179
|
-
* belongs to the host. The bridge sends no `play.route` event, AND it runs no
|
|
180
|
-
* corrective navigation. A correction here would drag the user off a page of the
|
|
181
|
-
* host.
|
|
182
|
-
*
|
|
183
|
-
* The match is exact, and it respects each segment boundary. `"/abc/playground"` is
|
|
184
|
-
* therefore foreign to the mount `"/abc/play"`.
|
|
185
|
-
*
|
|
186
|
-
* @param pathname - A sanitized pathname of the router, with no query and no duplicate slash.
|
|
187
|
-
* @param basePath - The concrete prefix of {@link resolveBasePath}. `""` removes nothing.
|
|
188
|
-
* @returns The machine half of the path, or `null` when the location is foreign.
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* ```typescript
|
|
192
|
-
* stripBasePath("/abc123/play/dashboard", "/abc123/play"); // "/dashboard"
|
|
193
|
-
* stripBasePath("/abc123/play", "/abc123/play"); // "/"
|
|
194
|
-
* stripBasePath("/settings", "/abc123/play"); // null — the host owns it
|
|
195
|
-
* ```
|
|
196
|
-
*/
|
|
197
|
-
export function stripBasePath(pathname, basePath) {
|
|
198
|
-
if (basePath === "")
|
|
199
|
-
return pathname;
|
|
200
|
-
if (pathname === basePath)
|
|
201
|
-
return "/";
|
|
202
|
-
if (pathname.startsWith(`${basePath}/`))
|
|
203
|
-
return pathname.slice(basePath.length);
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Adds the base path to an outbound path of the machine.
|
|
208
|
-
*
|
|
209
|
-
* The function joins the PATHNAME only. A query string and a hash fragment of the
|
|
210
|
-
* path of the machine stay at the end, because the prefix belongs in front of the
|
|
211
|
-
* path.
|
|
212
|
-
*
|
|
213
|
-
* @param basePath - The concrete prefix of {@link resolveBasePath}. `""` adds nothing.
|
|
214
|
-
* @param path - The path of the machine, for example `"/dashboard"` or `"/dates?trip=one-way"`.
|
|
215
|
-
* @returns The location for the router of the host.
|
|
216
|
-
*
|
|
217
|
-
* @example
|
|
218
|
-
* ```typescript
|
|
219
|
-
* joinBasePath("/abc123/play", "/dashboard"); // "/abc123/play/dashboard"
|
|
220
|
-
* joinBasePath("/abc123/play", "/"); // "/abc123/play"
|
|
221
|
-
* joinBasePath("/abc123/play", "/x?tab=a"); // "/abc123/play/x?tab=a"
|
|
222
|
-
* joinBasePath("", "/dashboard"); // "/dashboard"
|
|
223
|
-
* ```
|
|
224
|
-
*/
|
|
225
|
-
export function joinBasePath(basePath, path) {
|
|
226
|
-
if (basePath === "")
|
|
227
|
-
return path;
|
|
228
|
-
const mark = firstMarkIndex(path);
|
|
229
|
-
const pathname = mark === -1 ? path : path.slice(0, mark);
|
|
230
|
-
const suffix = mark === -1 ? "" : path.slice(mark);
|
|
231
|
-
// The root of the machine IS the mount point: "/" must not append a trailing slash,
|
|
232
|
-
// because the router callback reports "/abc123/play" and a mismatch there would
|
|
233
|
-
// defeat the echo suppression of the bridge.
|
|
234
|
-
const joined = pathname === "" || pathname === "/"
|
|
235
|
-
? basePath
|
|
236
|
-
: `${basePath}${pathname.startsWith("/") ? "" : "/"}${pathname}`;
|
|
237
|
-
return `${joined}${suffix}`;
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Gives the index of the first query mark or fragment mark of a path, or `-1`.
|
|
241
|
-
*
|
|
242
|
-
* The names say `At`, because both values are an INDEX. A name such as `hash` reads
|
|
243
|
-
* as a digest to a reader and to a scanner both: `gitlab.eslint.detect-possible-timing-attacks`
|
|
244
|
-
* fires on a `===` test against an identifier of that name, and it cannot see that
|
|
245
|
-
* the operands here are two numbers.
|
|
246
|
-
*
|
|
247
|
-
* @internal `RouterBridgeBase` splits a location on the same boundary, to read the
|
|
248
|
-
* pathname half of an actor route. One function, so the two sides cannot disagree
|
|
249
|
-
* about where a pathname ends.
|
|
250
|
-
*/
|
|
251
|
-
export function firstMarkIndex(path) {
|
|
252
|
-
const queryAt = path.indexOf("?");
|
|
253
|
-
const fragmentAt = path.indexOf("#");
|
|
254
|
-
if (queryAt === -1)
|
|
255
|
-
return fragmentAt;
|
|
256
|
-
if (fragmentAt === -1)
|
|
257
|
-
return queryAt;
|
|
258
|
-
return Math.min(queryAt, fragmentAt);
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Refuses each segment of a base path that resolves to ONE concrete prefix never.
|
|
262
|
-
*
|
|
263
|
-
* A bridge writes a real browser URL from its prefix. A wildcard and an optional
|
|
264
|
-
* segment each describe a SET of prefixes, so neither of them holds a value to write,
|
|
265
|
-
* and a silent pass would put a literal `*` or `:section?` into the address bar.
|
|
266
|
-
*/
|
|
267
|
-
function assertBasePathSegment(segment, basePath) {
|
|
268
|
-
if (segment.includes("*")) {
|
|
269
|
-
throw new InvalidBasePathError(basePath, 'a wildcard segment cannot resolve to one concrete prefix. Drop the splat segment: mount on the prefix itself, for example "/:machineId/play" for the route "/$machineId/play/$".');
|
|
270
|
-
}
|
|
271
|
-
if (segment.startsWith("$")) {
|
|
272
|
-
throw new InvalidBasePathError(basePath, `"${segment}" looks like a route param of TanStack Router. A base path declares a param as ":${segment.slice(1)}", and its value goes in basePathParams.`);
|
|
273
|
-
}
|
|
274
|
-
if (segment.startsWith(":") && segment.endsWith("?")) {
|
|
275
|
-
throw new InvalidBasePathError(basePath, `the optional segment "${segment}" cannot resolve to one concrete prefix. Give a required ":${segment.slice(1, -1)}" param, or mount on the shorter prefix.`);
|
|
276
|
-
}
|
|
277
|
-
if (segment === ":") {
|
|
278
|
-
throw new InvalidBasePathError(basePath, "a param segment needs a name.");
|
|
279
|
-
}
|
|
280
|
-
// A browser resolves "." and ".." out of a location, so the prefix that
|
|
281
|
-
// `navigateRouter` writes is not the prefix that comes back: "/../admin/about"
|
|
282
|
-
// becomes "/admin/about", which no longer starts with the mount. Every later location
|
|
283
|
-
// would read as foreign and the machine would go permanently silent.
|
|
284
|
-
//
|
|
285
|
-
// The PERCENT-ENCODED forms resolve away exactly the same. The WHATWG URL standard
|
|
286
|
-
// reads "%2e" as a single-dot segment and ".%2e", "%2e." and "%2e%2e" as double-dot
|
|
287
|
-
// segments, each test case-insensitive, so "/a/%2e%2e/admin" also comes back as
|
|
288
|
-
// "/admin". A guard on the two literal forms alone let that mount through.
|
|
289
|
-
if (isDotSegment(segment)) {
|
|
290
|
-
throw new InvalidBasePathError(basePath, `the segment "${segment}" resolves away in a browser, so the prefix that comes back is not the prefix that went out. Give the path that it resolves to.`);
|
|
291
|
-
}
|
|
292
|
-
// A browser percent-encodes a space, a tab and a newline of a pathname, so the prefix
|
|
293
|
-
// that comes back is not the prefix that went out — the same failure as a dot segment,
|
|
294
|
-
// and the same silence. `assertNoScheme` also reads the RAW value, and a leading space
|
|
295
|
-
// hid a whole URL from it: " https://host/admin" collapsed to "/ https:/host/admin".
|
|
296
|
-
if (/\s/.test(segment)) {
|
|
297
|
-
throw new InvalidBasePathError(basePath, `the segment "${segment}" holds whitespace, which a browser percent-encodes, so the prefix that comes back is not the prefix that went out. Give the path with no whitespace in it.`);
|
|
298
|
-
}
|
|
299
|
-
// A base path is a PATHNAME. A query or a hash in it would survive normalization,
|
|
300
|
-
// then never match a router location — `sanitizePathname` has already removed both
|
|
301
|
-
// by the time `stripBasePath` compares — so every location would read as foreign
|
|
302
|
-
// and the machine would go permanently silent. Refuse it here instead.
|
|
303
|
-
if (segment.includes("?") || segment.includes("#")) {
|
|
304
|
-
throw new InvalidBasePathError(basePath, "a base path is a pathname only: it can carry no query string and no hash fragment. Put a query on the machine's own route instead.");
|
|
305
|
-
}
|
|
306
|
-
// The general form of the three guards above, and the one that catches the rest. A
|
|
307
|
-
// browser reads a "\" as a "/", so "/adm\in" arrives as two segments and "/a\..\x"
|
|
308
|
-
// arrives as "/x"; it percent-encodes a non-ASCII character and the characters '"',
|
|
309
|
-
// '<', '>', '{', '}', '^' and '`', so "/café" arrives as "/caf%C3%A9". Each one gives
|
|
310
|
-
// the same silence as a dot segment: no location matches the mount, and no error says
|
|
311
|
-
// so. The guards above stay, because each one names the mistake it found.
|
|
312
|
-
if (!isStableSegment(segment)) {
|
|
313
|
-
throw new InvalidBasePathError(basePath, `a browser rewrites the segment "${segment}", so the prefix that comes back is not the prefix that went out. Give the segment in the form that a URL carries, for example "caf%C3%A9" for "café".`);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
/** The origin of the probe of {@link isStableSegment}. It reaches no network. */
|
|
317
|
-
const PROBE_ORIGIN = "http://probe.invalid";
|
|
318
|
-
/**
|
|
319
|
-
* Tells you whether a browser writes a path segment back exactly as it went out.
|
|
320
|
-
*
|
|
321
|
-
* The WHATWG URL parser rewrites a segment in several ways: it resolves "." and ".."
|
|
322
|
-
* away, it reads a "\" as a "/", and it percent-encodes whitespace, a non-ASCII
|
|
323
|
-
* character, and the characters '"', '<', '>', '{', '}', '^' and '`'. Every one of them
|
|
324
|
-
* gives one failure: the prefix that `navigateRouter` writes is not the prefix that
|
|
325
|
-
* comes back, so `stripBasePath` reads every location as foreign and the machine goes
|
|
326
|
-
* permanently silent, with no error raised.
|
|
327
|
-
*
|
|
328
|
-
* The function asks the URL parser, and it lists no character, because that list
|
|
329
|
-
* belongs to the standard and not to this file.
|
|
330
|
-
*/
|
|
331
|
-
function isStableSegment(segment) {
|
|
332
|
-
try {
|
|
333
|
-
return new URL(`/${segment}`, PROBE_ORIGIN).pathname === `/${segment}`;
|
|
334
|
-
}
|
|
335
|
-
catch {
|
|
336
|
-
return false;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Tells you whether a segment is a single-dot or a double-dot path segment.
|
|
341
|
-
*
|
|
342
|
-
* The WHATWG URL standard names six forms, and a browser resolves every one of them out
|
|
343
|
-
* of a location: "." and "%2e" for the single dot, and "..", ".%2e", "%2e." and "%2e%2e"
|
|
344
|
-
* for the double dot. Each percent test is case-insensitive.
|
|
345
|
-
*/
|
|
346
|
-
function isDotSegment(segment) {
|
|
347
|
-
const decoded = segment.toLowerCase().replaceAll("%2e", ".");
|
|
348
|
-
return decoded === "." || decoded === "..";
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Refuses a base path that carries a URL scheme.
|
|
352
|
-
*
|
|
353
|
-
* The test runs on the RAW value, because the slash collapse of
|
|
354
|
-
* {@link normalizeBasePath} turns the form into a path that looks legal. It also runs
|
|
355
|
-
* on the TRIMMED value, because a browser drops the leading whitespace of a URL: a
|
|
356
|
-
* scheme behind a space is still a scheme. And it runs at every segment boundary,
|
|
357
|
-
* because a scheme that a caller joined behind a prefix of its own is still a scheme.
|
|
358
|
-
*
|
|
359
|
-
* A protocol-relative `//host/path` is NOT refused: it is indistinguishable from a
|
|
360
|
-
* sloppy `//a//b`, which the collapse deliberately forgives.
|
|
361
|
-
*
|
|
362
|
-
* @throws {InvalidBasePathError} For `scheme://host/path`.
|
|
363
|
-
*/
|
|
364
|
-
function assertNoScheme(basePath) {
|
|
365
|
-
// RFC 3986: a scheme starts with a letter, then holds letters, digits, "+", "-"
|
|
366
|
-
// and ".". A leading "//" with no scheme is the protocol-relative form.
|
|
367
|
-
// The test runs at EVERY segment boundary, and not at the start alone. A caller that
|
|
368
|
-
// joins a prefix onto a base writes "/https://app.example.com/admin", and also
|
|
369
|
-
// "/tenant/https://app.example.com/admin": the collapse then makes
|
|
370
|
-
// "/tenant/https:/app.example.com/admin", whose every segment is legal, so the bridge
|
|
371
|
-
// mounts where no real location starts and the machine goes permanently silent. A
|
|
372
|
-
// guard that stripped the LEADING slashes alone caught the first form and missed the
|
|
373
|
-
// second.
|
|
374
|
-
if (/(?:^|\/)[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(basePath.trim())) {
|
|
375
|
-
throw new InvalidBasePathError(basePath, 'a base path is a pathname only: it can carry no scheme and no host. Give the path part alone, for example "/admin" for "https://app.example.com/admin".');
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Escapes the value of a base-path param for a URL segment.
|
|
380
|
-
*
|
|
381
|
-
* `encodeURIComponent` leaves a `*` alone, and that is correct here: a `*` is a legal
|
|
382
|
-
* path character, and a browser reports it literally. An escape to `%2A` resolved a
|
|
383
|
-
* mount that no real location matches, so `stripBasePath` read every location as
|
|
384
|
-
* foreign and the machine went permanently silent, with no error raised.
|
|
385
|
-
*
|
|
386
|
-
* The `*` of "a pattern of no navigation" never reaches this value.
|
|
387
|
-
* `resolveNavigationPath` tests the MACHINE half of the route, and `joinBasePath` adds
|
|
388
|
-
* the prefix after that test — see the one `navigateRouter` call in
|
|
389
|
-
* `pushResolvedRoute`.
|
|
390
|
-
*/
|
|
391
|
-
function encodeBasePathValue(value) {
|
|
392
|
-
// `encodeURIComponent` encodes for a QUERY component, so it escapes eight characters
|
|
393
|
-
// that RFC 3986 lets a path segment hold raw: the sub-delims "$&+,;=" and ":" and
|
|
394
|
-
// "@". Every router reports those raw in a pathname, so an escape resolves a mount
|
|
395
|
-
// that no real location matches — `stripBasePath` reads every location as foreign and
|
|
396
|
-
// the machine goes permanently silent, with no error raised.
|
|
397
|
-
//
|
|
398
|
-
// Escape for a segment instead: put those characters back, and keep the escape of
|
|
399
|
-
// everything that would change the SHAPE of the path — "/", "?", "#" and "%" among
|
|
400
|
-
// them — because a value must forge no path and no query.
|
|
401
|
-
return encodeURIComponent(value).replace(/%(?:24|26|2B|2C|3A|3B|3D|40)/g, (escaped) => PATH_SEGMENT_SAFE.get(escaped) ?? escaped);
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* The escapes that {@link encodeBasePathValue} undoes: the characters a path segment
|
|
405
|
-
* holds raw, which `encodeURIComponent` escapes because it encodes for a query.
|
|
406
|
-
*/
|
|
407
|
-
/** A Map, and not an object: a dynamic key reaches no prototype through one. */
|
|
408
|
-
const PATH_SEGMENT_SAFE = new Map([
|
|
409
|
-
["%24", "$"],
|
|
410
|
-
["%26", "&"],
|
|
411
|
-
["%2B", "+"],
|
|
412
|
-
["%2C", ","],
|
|
413
|
-
["%3A", ":"],
|
|
414
|
-
["%3B", ";"],
|
|
415
|
-
["%3D", "="],
|
|
416
|
-
["%40", "@"],
|
|
417
|
-
]);
|
|
418
|
-
//# sourceMappingURL=base-path.js.map
|
package/dist/base-path.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"base-path.js","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
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;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,QAAQ,CAU5F"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"create-route-map.js","sourceRoot":"","sources":["../src/create-route-map.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAoB/C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,cAAc,CAAC,OAAwB,EAAE,OAAyB;IACjF,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC5C,OAAO,IAAI,QAAQ,CAClB,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACrB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,IAAI,CAAC,QAAQ;KACnB,CAAC,CAAC,EACH,OAAO,CACP,CAAC;AACH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
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;AA6EvF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,eAAe,KAAG,SAoB/D,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"extract-routes.js","sourceRoot":"","sources":["../src/extract-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The params of a framework router, reconciled with the pattern of the machine.
|
|
3
|
-
*
|
|
4
|
-
* A framework that parses the params itself — Vue Router and SolidJS Router both do —
|
|
5
|
-
* lets a bridge keep that parse instead of running URLPattern again. The decision that
|
|
6
|
-
* makes it safe is the same in each of them, and the source of the params is the one
|
|
7
|
-
* thing that differs, so the decision lives here and each bridge supplies its source.
|
|
8
|
-
*
|
|
9
|
-
* @see [Multi-router integration](../../docs/examples/multi-router-integration.md)
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Reads the names of every `:param` of a route pattern of the route map.
|
|
13
|
-
*
|
|
14
|
-
* @param pattern - A route pattern, for example `/profile/:userId`.
|
|
15
|
-
* @returns The names, in the order that the pattern declares them. A fresh array, because
|
|
16
|
-
* `readPatternParams` caches the one it holds.
|
|
17
|
-
*/
|
|
18
|
-
export declare function getPatternParamNames(pattern: string): string[];
|
|
19
|
-
/**
|
|
20
|
-
* The names of every param the pattern REQUIRES, so `:name?` is left out.
|
|
21
|
-
*
|
|
22
|
-
* An optional segment that did not match has no value, and a framework reports none.
|
|
23
|
-
* That is a complete answer and not a partial one, so a MIXED pattern such as
|
|
24
|
-
* `/profile/:userId/:tab?` keeps the parse of the framework when only `:tab` is absent.
|
|
25
|
-
* A caller that counted that absence as a gap would fall back to the URLPattern
|
|
26
|
-
* extraction, which THROWS on a runtime with no URLPattern — for a route the framework
|
|
27
|
-
* had already answered.
|
|
28
|
-
*
|
|
29
|
-
* A pattern whose params are ALL optional reports nothing at all, which reads the same
|
|
30
|
-
* as "the framework matched another route", so {@link pickOwnParams} falls back for it.
|
|
31
|
-
* {@link resolveFrameworkParams} settles that case from the PATH instead, and it needs
|
|
32
|
-
* no URLPattern to do it.
|
|
33
|
-
*
|
|
34
|
-
* @param pattern - A route pattern, for example `/profile/:userId/:tab?`.
|
|
35
|
-
* @returns The required names, in the order that the pattern declares them. A fresh
|
|
36
|
-
* array, because `readPatternParams` caches the one it holds.
|
|
37
|
-
*/
|
|
38
|
-
export declare function getRequiredPatternParamNames(pattern: string): string[];
|
|
39
|
-
/**
|
|
40
|
-
* Keeps the entries of `params` whose name the pattern of the machine declares, and
|
|
41
|
-
* only when the result covers EVERY name of that pattern.
|
|
42
|
-
*
|
|
43
|
-
* A complete pick is an answer, and a partial pick is not: a wrapper route of the host
|
|
44
|
-
* can declare a subset of the params of the machine — a tenant segment, for example,
|
|
45
|
-
* but not the document one — and keeping that subset drops the rest from a route that
|
|
46
|
-
* declares them. The caller falls back to its own extraction for `null`.
|
|
47
|
-
*
|
|
48
|
-
* The result has a null prototype, so a param named `__proto__` stays an own key.
|
|
49
|
-
*
|
|
50
|
-
* An OPTIONAL name of the pattern (`:name?`) is covered whether the framework reports
|
|
51
|
-
* it or not: a segment that did not match has no value, and that is a complete answer.
|
|
52
|
-
* At least one declared name must come back, though — a framework that reports none
|
|
53
|
-
* matched another route, and the path may still hold a value that only the fallback
|
|
54
|
-
* reads. A pattern whose params are ALL optional therefore always answers `null` here
|
|
55
|
-
* when the framework reports nothing; {@link resolveFrameworkParams} then reads the PATH,
|
|
56
|
-
* which settles the question without the framework and without URLPattern.
|
|
57
|
-
*
|
|
58
|
-
* @param params - The params of the framework router. {@link cleanFrameworkParams}
|
|
59
|
-
* removes each empty value already, and one that reaches here anyway counts as
|
|
60
|
-
* absent: an empty value says that the segment did not match, and never that the
|
|
61
|
-
* path carries the empty string.
|
|
62
|
-
* @param names - The names that the pattern of the machine declares.
|
|
63
|
-
* @param requiredNames - The names the pattern REQUIRES. The default treats every name
|
|
64
|
-
* as required, so a two-argument call keeps the strict test.
|
|
65
|
-
* @returns The params of the machine, or `null` when the framework covers them not.
|
|
66
|
-
*/
|
|
67
|
-
export declare function pickOwnParams(params: Record<string, string>, names: string[], requiredNames?: string[]): Record<string, string> | null;
|
|
68
|
-
/**
|
|
69
|
-
* The params of a framework router, in the shape that {@link pickOwnParams} reads.
|
|
70
|
-
*
|
|
71
|
-
* Every framework reports a param that its own route DECLARES and that the location
|
|
72
|
-
* did not fill: Vue Router gives `undefined` or `""`, and SolidJS Router does the
|
|
73
|
-
* same. Such an entry is not an answer, and a pick that kept it would send an empty
|
|
74
|
-
* value to the actor as though the path carried one. Drop it here instead, one time,
|
|
75
|
-
* because the rule belongs to the decision of {@link resolveFrameworkParams} and not
|
|
76
|
-
* to a bridge: `VueRouterBridge` and `SolidRouterBridge` held one copy each.
|
|
77
|
-
*
|
|
78
|
-
* A value of an array — the splat of a catch-all route of Vue Router — becomes its
|
|
79
|
-
* `String()` form, exactly as a single value does.
|
|
80
|
-
*
|
|
81
|
-
* The result has a null prototype, for the same reason {@link pickOwnParams} gives: a
|
|
82
|
-
* plain `{}` accumulator turns `cleaned["__proto__"] = value` into a write of the
|
|
83
|
-
* PROTOTYPE setter, which drops a string value in silence. `pickOwnParams` then read
|
|
84
|
-
* `Object.hasOwn(params, "__proto__")` as `false`, called the pick incomplete, and fell
|
|
85
|
-
* back to the URLPattern extraction — which THROWS on a runtime with no URLPattern, for
|
|
86
|
-
* a route the framework had answered already.
|
|
87
|
-
*
|
|
88
|
-
* @param params - The raw params of the framework router.
|
|
89
|
-
* @returns The params with no absent value, each one a string.
|
|
90
|
-
*/
|
|
91
|
-
export declare function cleanFrameworkParams(params: Record<string, unknown>): Record<string, string>;
|
|
92
|
-
/** What {@link resolveFrameworkParams} needs from the bridge that calls it. */
|
|
93
|
-
export interface FrameworkParamsSource {
|
|
94
|
-
/** The route pattern of the match, from `routeMap.getPathByStateId`. */
|
|
95
|
-
pattern: string | null | undefined;
|
|
96
|
-
/** The resolved prefix of the mount. `""` means that the machine owns the router. */
|
|
97
|
-
basePath: string;
|
|
98
|
-
/**
|
|
99
|
-
* The machine-side path of the location, with the mount prefix already removed.
|
|
100
|
-
*
|
|
101
|
-
* The field is OPTIONAL, so a caller that was written before it keeps its behaviour:
|
|
102
|
-
* the one branch that reads it falls back without it, exactly as it did.
|
|
103
|
-
*/
|
|
104
|
-
pathname?: string;
|
|
105
|
-
/** The params of the framework router, read lazily and cleaned of empty values. */
|
|
106
|
-
frameworkParams(): Record<string, string>;
|
|
107
|
-
/** The URLPattern extraction of the base class, read lazily. */
|
|
108
|
-
fallback(): Record<string, string>;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Decides which params describe the route of the machine.
|
|
112
|
-
*
|
|
113
|
-
* The three branches, in the order that they apply:
|
|
114
|
-
*
|
|
115
|
-
* - **The pattern declares no name** — a static path, a bare `*` wildcard, or an
|
|
116
|
-
* unknown stateId. The answer is `{}`. The params of the framework must NOT travel
|
|
117
|
-
* here: under a catch-all they hold the splat of the host, and that value would reach
|
|
118
|
-
* the actor as a param of the machine. This branch also reaches no URLPattern, which
|
|
119
|
-
* matters: the extraction needs the constructor even for a pattern with no parameter,
|
|
120
|
-
* so a delegation would throw on a runtime without the API.
|
|
121
|
-
* - **The bridge sits under a mount** — the framework matched a route of the HOST by
|
|
122
|
-
* construction, because the machine owns the suffix of the path only. Its params
|
|
123
|
-
* therefore describe this pattern never, whatever they are named, and a name that
|
|
124
|
-
* happens to collide carries the value of the host. Read the params of the machine
|
|
125
|
-
* from its own pattern instead.
|
|
126
|
-
* - **The framework covers every REQUIRED name** — it matched the machine route. Keep
|
|
127
|
-
* its parse, together with its decoding. An optional `:name?` that the framework
|
|
128
|
-
* reports not is covered too: a segment that did not match has no value. A gap in a
|
|
129
|
-
* required name falls back, because keeping it would drop a name the route declares.
|
|
130
|
-
* - **The path IS the bare form of the pattern** — every optional segment is absent, so
|
|
131
|
-
* `{}` is the complete answer. The branch reads the path and trusts the framework with
|
|
132
|
-
* nothing, which is what makes it safe under a catch-all of the host, and it calls
|
|
133
|
-
* URLPattern for a location that needs none.
|
|
134
|
-
*
|
|
135
|
-
* None of this decides whether the APPLICATION needs a URLPattern polyfill. A `RouteMap`
|
|
136
|
-
* that holds one parameterized route compiles it in the CONSTRUCTOR, and it throws a
|
|
137
|
-
* `URLPatternUnavailableError` there when the runtime has no URLPattern. The polyfill
|
|
138
|
-
* question is therefore settled at startup: only a route map of static paths alone
|
|
139
|
-
* escapes it. What these branches decide is whether a NAVIGATION calls URLPattern again.
|
|
140
|
-
*
|
|
141
|
-
* @returns The path parameters of the machine route, or `{}`.
|
|
142
|
-
*/
|
|
143
|
-
export declare function resolveFrameworkParams({ pattern, basePath, pathname, frameworkParams, fallback, }: FrameworkParamsSource): Record<string, string>;
|
|
144
|
-
//# sourceMappingURL=framework-params.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"framework-params.d.ts","sourceRoot":"","sources":["../src/framework-params.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9D;AAqCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAEtE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,aAAa,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,GAAE,MAAM,EAAU,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAoC/B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAc5F;AAkDD,+EAA+E;AAC/E,MAAM,WAAW,qBAAqB;IACrC,wEAAwE;IACxE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,gEAAgE;IAChE,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,sBAAsB,CAAC,EACtC,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,eAAe,EACf,QAAQ,GACR,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqBhD"}
|