@xmachines/play-router 3.0.0 → 5.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 +111 -116
- package/dist/base-route-map.d.ts +24 -13
- package/dist/base-route-map.d.ts.map +1 -1
- package/dist/base-route-map.js +116 -27
- 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 +22 -4
- package/dist/build-tree.js.map +1 -1
- package/dist/create-route-map-from-tree.d.ts +13 -7
- package/dist/create-route-map-from-tree.d.ts.map +1 -1
- package/dist/create-route-map-from-tree.js +14 -6
- 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 +13 -1
- package/dist/find-route.d.ts.map +1 -1
- package/dist/find-route.js +33 -26
- package/dist/find-route.js.map +1 -1
- package/dist/index.d.ts +8 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -12
- package/dist/index.js.map +1 -1
- package/dist/provider-lifecycle.d.ts +18 -6
- package/dist/provider-lifecycle.d.ts.map +1 -1
- package/dist/provider-lifecycle.js +10 -5
- package/dist/provider-lifecycle.js.map +1 -1
- package/dist/router-bridge-base.d.ts +73 -38
- package/dist/router-bridge-base.d.ts.map +1 -1
- package/dist/router-bridge-base.js +304 -124
- package/dist/router-bridge-base.js.map +1 -1
- package/dist/router-sync.d.ts +3 -27
- package/dist/router-sync.d.ts.map +1 -1
- package/dist/router-sync.js +27 -45
- package/dist/router-sync.js.map +1 -1
- package/dist/types.d.ts +206 -102
- package/dist/types.d.ts.map +1 -1
- package/dist/xstate/create-route-map.d.ts +30 -0
- package/dist/xstate/create-route-map.d.ts.map +1 -0
- package/dist/{create-route-map.js → xstate/create-route-map.js} +11 -6
- package/dist/xstate/create-route-map.js.map +1 -0
- package/dist/{extract-routes.d.ts → xstate/extract-routes.d.ts} +4 -2
- package/dist/xstate/extract-routes.d.ts.map +1 -0
- package/dist/{extract-routes.js → xstate/extract-routes.js} +11 -6
- 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 +30 -21
- 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 +0 -44
- 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/types.d.ts
CHANGED
|
@@ -1,48 +1,146 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type { Signal } from "@xmachines/play-signals";
|
|
4
|
-
import type { PlaySpec } from "@xmachines/play-actor";
|
|
1
|
+
import type { BasePathOptions, CompileOptions, PatternCache } from "@xmachines/play-url";
|
|
2
|
+
import type { ReadonlyAtom } from "@xmachines/play-atom";
|
|
5
3
|
/**
|
|
6
|
-
* The
|
|
7
|
-
*
|
|
4
|
+
* The type definitions of the routing protocol of @xmachines/play-router
|
|
5
|
+
*
|
|
6
|
+
* PlayRouteEvent, RouterBridge, RouteMetadata, and RouteObject are here. The routing
|
|
7
|
+
* therefore stays separate from the base event protocol of @xmachines/play.
|
|
8
8
|
*/
|
|
9
|
-
export interface MachineNodeData {
|
|
10
|
-
/** The XState state ID, for example "test.dashboard.overview" */
|
|
11
|
-
stateId: string;
|
|
12
|
-
/** The state type of XState */
|
|
13
|
-
type: "atomic" | "compound" | "parallel" | "final" | "history";
|
|
14
|
-
/** The original meta object of the state */
|
|
15
|
-
meta?: Record<string, unknown>;
|
|
16
|
-
/** The route path of meta.route, in its string form */
|
|
17
|
-
route?: string;
|
|
18
|
-
}
|
|
19
9
|
/**
|
|
20
|
-
* The data
|
|
21
|
-
*
|
|
10
|
+
* The resolved extra data of a route. It reaches the consumer on the `data` field of a
|
|
11
|
+
* `play.route` event.
|
|
22
12
|
*/
|
|
23
|
-
export
|
|
24
|
-
/** The event type that starts this transition */
|
|
25
|
-
eventType: string;
|
|
26
|
-
/**
|
|
27
|
-
* The guard as a string, when a guard is present
|
|
28
|
-
*
|
|
29
|
-
* @deprecated Will be removed in the next major.
|
|
30
|
-
*/
|
|
31
|
-
guardType?: string;
|
|
32
|
-
}
|
|
13
|
+
export type RouteData = Record<string, unknown>;
|
|
33
14
|
/**
|
|
34
|
-
* The
|
|
15
|
+
* The function form of {@link RouteObject.data}.
|
|
35
16
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
17
|
+
* The signature mirrors `WithDynamicParams` of XState: the resolver reads the context
|
|
18
|
+
* of the machine and the event that asks for the route, and it returns the data.
|
|
19
|
+
*
|
|
20
|
+
* The resolver reads every field of the event, and `event.data` among them: that field
|
|
21
|
+
* carries what the SENDER of the event supplied, and the resolver decides how it
|
|
22
|
+
* combines with what the state declares. The `data` that the resolver RETURNS goes to
|
|
23
|
+
* `context.data`, and it does not go back onto the event.
|
|
38
24
|
*/
|
|
25
|
+
export type RouteDataResolver = (args: {
|
|
26
|
+
context: unknown;
|
|
27
|
+
event: PlayRouteEvent;
|
|
28
|
+
}) => RouteData;
|
|
39
29
|
/**
|
|
40
30
|
* A route object, with more metadata.
|
|
41
31
|
*/
|
|
42
32
|
export interface RouteObject {
|
|
43
|
-
/** The template of the route path, for example
|
|
33
|
+
/** The template of the route path, for example `"/user/:id"`. */
|
|
44
34
|
path: string;
|
|
45
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* The `reenter` flag of the generated `play.route` transition.
|
|
37
|
+
*
|
|
38
|
+
* The default is `false`, which is also the default of XState.
|
|
39
|
+
*
|
|
40
|
+
* The flag spares the DOMAIN of the transition, and not every ancestor that stays
|
|
41
|
+
* active. Under the default placement `handler: "root"` the domain is the root of
|
|
42
|
+
* the machine, so `false` spares the root alone: each ancestor BETWEEN the root and
|
|
43
|
+
* the target still runs its `exit` and its `entry` actions, because XState re-enters
|
|
44
|
+
* every descendant of the domain that lies on the path to the target. A move between
|
|
45
|
+
* two siblings therefore still runs the `entry` action of their shared parent.
|
|
46
|
+
*
|
|
47
|
+
* {@link RouteObject.handler} is the field that spares those intermediate ancestors:
|
|
48
|
+
* `"local"` and `"both"` move the domain down to the parent of the state. Use the
|
|
49
|
+
* two fields together where an `entry` action must run one time for each state that
|
|
50
|
+
* the actor really enters.
|
|
51
|
+
*
|
|
52
|
+
* Set the field to `true` where the domain must run its `entry` actions again on
|
|
53
|
+
* every route to a descendant.
|
|
54
|
+
*
|
|
55
|
+
* The flag does not decide the destination. The value of the machine after a route
|
|
56
|
+
* is identical under both settings. A route to a state that has children still
|
|
57
|
+
* enters the `initial` child of that state, because the generated transition targets
|
|
58
|
+
* the state by its id, and XState enters the initial child of an id target under
|
|
59
|
+
* both settings.
|
|
60
|
+
*
|
|
61
|
+
* @see [Play RFC](../../docs/rfc/play.md)
|
|
62
|
+
*/
|
|
63
|
+
reenter?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Where the generated `play.route` transition sits.
|
|
66
|
+
*
|
|
67
|
+
* `"root"` is the default, and it is what XState does: `formatRouteTransitions`
|
|
68
|
+
* installs every route transition on the ROOT of the machine, and each one targets
|
|
69
|
+
* its state by the ID. A route from any state therefore reaches this state. The cost
|
|
70
|
+
* is that the root is the domain of the transition, so XState re-enters each
|
|
71
|
+
* ancestor on the path to the target, and those ancestors run their `entry` actions
|
|
72
|
+
* again although they stay active.
|
|
73
|
+
*
|
|
74
|
+
* `"local"` installs the transition on the PARENT of this state instead, and it
|
|
75
|
+
* targets this state relatively. XState offers the transitions of the deepest active
|
|
76
|
+
* state node first, so the parent answers the event itself and runs its `exit` and
|
|
77
|
+
* its `entry` actions NOT again.
|
|
78
|
+
*
|
|
79
|
+
* `"both"` installs one transition in each place. The local one answers while the
|
|
80
|
+
* parent is active, and the root one answers a route that arrives from outside the
|
|
81
|
+
* parent. Use `"both"` where an ancestor holds an `entry` action that must run one
|
|
82
|
+
* time for each real entry, such as an analytics event or an audit record.
|
|
83
|
+
*
|
|
84
|
+
* CAUTION: `"local"` makes this state reachable by a route ONLY while its parent is
|
|
85
|
+
* active. A `play.route` event that arrives from anywhere else matches no transition
|
|
86
|
+
* and the actor does not move. A browser URL for this state therefore leaves the URL
|
|
87
|
+
* and the actor divergent. Choose `"local"` to SCOPE a route on purpose, for example
|
|
88
|
+
* a step that a person reaches only inside its wizard. Choose `"both"` where the
|
|
89
|
+
* state must stay reachable from everywhere.
|
|
90
|
+
*
|
|
91
|
+
* The field has no effect on a state whose parent IS the root: the root transition
|
|
92
|
+
* of such a state is already local to its parent, so all three values agree.
|
|
93
|
+
*/
|
|
94
|
+
handler?: "root" | "local" | "both";
|
|
95
|
+
/**
|
|
96
|
+
* The extra data that the state threads into its `play.route` event.
|
|
97
|
+
*
|
|
98
|
+
* The shape follows `WithDynamicParams` of XState, which is how XState itself
|
|
99
|
+
* parameterizes an action and a guard: the field holds a literal value, OR a
|
|
100
|
+
* function of `{ context, event }` that returns one.
|
|
101
|
+
*
|
|
102
|
+
* ```ts
|
|
103
|
+
* // The literal form. It survives a serialization of the machine.
|
|
104
|
+
* meta: { route: { path: "/doc/:docId", data: { titleKey: "doc.view" } } }
|
|
105
|
+
*
|
|
106
|
+
* // The function form, for a value that depends on the route.
|
|
107
|
+
* meta: {
|
|
108
|
+
* route: {
|
|
109
|
+
* path: "/doc/:docId",
|
|
110
|
+
* data: ({ event }) => ({ title: `Document ${event.params?.docId}` }),
|
|
111
|
+
* },
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* The generated transition resolves the value and assigns it to the `data` field of
|
|
116
|
+
* the context, beside `params` and `query`. The data of a state does NOT merge with
|
|
117
|
+
* the data of its ancestors: each state declares the whole value that its own route
|
|
118
|
+
* carries.
|
|
119
|
+
*
|
|
120
|
+
* This field and {@link PlayRouteEvent.data} are two different things, and they meet
|
|
121
|
+
* in the resolver. This field is what the STATE declares, in its machine.
|
|
122
|
+
* `PlayRouteEvent.data` is what the SENDER of the event supplies, such as a router
|
|
123
|
+
* bridge or the code of an application. A resolver reads `event.data` and returns
|
|
124
|
+
* whatever mix of the two the state needs.
|
|
125
|
+
*
|
|
126
|
+
* CAUTION: the function form holds a function inside `meta`, and a function does not
|
|
127
|
+
* survive `JSON.stringify`. A machine that Stately Studio reads, or that a process
|
|
128
|
+
* sends over a wire, must use the literal form.
|
|
129
|
+
*/
|
|
130
|
+
data?: RouteData | RouteDataResolver;
|
|
131
|
+
/**
|
|
132
|
+
* The additional metadata of the route: a title, a breadcrumb, and so on.
|
|
133
|
+
*
|
|
134
|
+
* CAUTION: `path`, `handler`, `reenter` and `data` are RESERVED. The routing layer
|
|
135
|
+
* reads those four names, and a release before this one read `path` alone. A state
|
|
136
|
+
* that carries its own `handler` value now throws an `InvalidRouteHandlerError` from
|
|
137
|
+
* `formatPlayRouteTransitions`, so the machine builds never; a state that carries its
|
|
138
|
+
* own `data` value now writes that value to `context.data`, where the `/context`
|
|
139
|
+
* projection of every view reads it. A `reenter` value is read as the FLAG of the
|
|
140
|
+
* generated transition, and the literal `true` alone turns the reentry on: the
|
|
141
|
+
* default is `false`, and a release before this one generated every transition with
|
|
142
|
+
* `reenter: true`. Give such a field another name.
|
|
143
|
+
*/
|
|
46
144
|
[key: string]: unknown;
|
|
47
145
|
}
|
|
48
146
|
/**
|
|
@@ -112,7 +210,7 @@ export interface RouteNode {
|
|
|
112
210
|
* - byStateId: it maps each state ID to its route node, for the target of a play.route event
|
|
113
211
|
* - byPath: it maps each URL path to its route node, for the browser navigation
|
|
114
212
|
*/
|
|
115
|
-
export interface RouteTree {
|
|
213
|
+
export interface RouteTree<TGraph = unknown> {
|
|
116
214
|
/** The root node of the routes */
|
|
117
215
|
root: RouteNode;
|
|
118
216
|
/**
|
|
@@ -127,17 +225,20 @@ export interface RouteTree {
|
|
|
127
225
|
byPath: Map<string, RouteNode>;
|
|
128
226
|
/**
|
|
129
227
|
* The graph of the state machine, for an advanced query.
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
228
|
+
*
|
|
229
|
+
* `TGraph` carries its type, and this package names none: a route tree is a map from a
|
|
230
|
+
* path to a state, and the graph of a MACHINE belongs to the package that reads a
|
|
231
|
+
* machine. `extractMachineRoutes` of `@xmachines/play-router/xstate` answers
|
|
232
|
+
* `RouteTree<MachineGraph>`, so a consumer of that function loses no type.
|
|
133
233
|
*
|
|
134
234
|
* @example
|
|
135
235
|
* ```typescript
|
|
136
236
|
* import { getSuccessors, hasPath } from "@statelyai/graph";
|
|
237
|
+
* // `tree` comes from `extractMachineRoutes` of `@xmachines/play-router/xstate`
|
|
137
238
|
* const successors = getSuccessors(tree.graph!, "myMachine.home");
|
|
138
239
|
* ```
|
|
139
240
|
*/
|
|
140
|
-
graph?:
|
|
241
|
+
graph?: TGraph;
|
|
141
242
|
}
|
|
142
243
|
/**
|
|
143
244
|
* The routing event, with its parameters and its query
|
|
@@ -231,23 +332,43 @@ export interface PlayRouteEvent {
|
|
|
231
332
|
readonly to: string;
|
|
232
333
|
readonly params?: Record<string, string>;
|
|
233
334
|
readonly query?: Record<string, string>;
|
|
335
|
+
/**
|
|
336
|
+
* The extra data that the SENDER of this event supplies: a router bridge, or the
|
|
337
|
+
* code of an application. It is not what the target state declares — that is
|
|
338
|
+
* {@link RouteObject.data}, and a resolver there reads this field.
|
|
339
|
+
*/
|
|
340
|
+
readonly data?: RouteData;
|
|
234
341
|
readonly match?: unknown;
|
|
235
|
-
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* An optional capability: the routing support
|
|
345
|
+
*/
|
|
346
|
+
export interface Routable {
|
|
347
|
+
readonly currentRoute: ReadonlyAtom<string | null>;
|
|
348
|
+
readonly initialRoute: string | null;
|
|
236
349
|
}
|
|
237
350
|
/**
|
|
238
351
|
* The minimal actor interface that `RouterBridgeBase` and every framework router
|
|
239
352
|
* adapter require.
|
|
240
353
|
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
354
|
+
* It names `send` itself, and it therefore gives `RouterBridgeBase.actor.send` a type that
|
|
355
|
+
* accepts a `PlayRouteEvent` directly. That removes the unsafe cast
|
|
356
|
+
* `(actor.send as (e: PlayRouteEvent) => void)`.
|
|
357
|
+
*
|
|
358
|
+
* It is {@link Routable} with `send`. The two members of the capability are declared once,
|
|
359
|
+
* in `Routable`, and this interface extends it. A copy of them here drifts the day that
|
|
360
|
+
* one of the two files changes.
|
|
245
361
|
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
362
|
+
* **It names the view NOWHERE. Routing implies no rendering.** No file of this package,
|
|
363
|
+
* and no file of any of the eight router adapters, ever reads `currentView`. A provider
|
|
364
|
+
* whose renderer callback reads the view binds its own `TActor`, and a constraint keeps
|
|
365
|
+
* the concrete type of the actor whole, so that callback still reads the exact spec of
|
|
366
|
+
* that actor.
|
|
367
|
+
*
|
|
368
|
+
* Every `PlayActor` of `@xmachines/play-actor` that also implements `Routable`, and whose
|
|
369
|
+
* event union holds `PlayRouteEvent`, satisfies this interface structurally. A machine
|
|
370
|
+
* that declares no route event does NOT satisfy it, and that refusal is correct: a bridge
|
|
371
|
+
* cannot navigate an actor that receives no route event.
|
|
251
372
|
*
|
|
252
373
|
* @example
|
|
253
374
|
* ```typescript
|
|
@@ -260,84 +381,43 @@ export interface PlayRouteEvent {
|
|
|
260
381
|
* }
|
|
261
382
|
* ```
|
|
262
383
|
*/
|
|
263
|
-
export interface RoutableActor {
|
|
264
|
-
/** The TC39 Signal of the current URL path of the actor, or of its state ID. */
|
|
265
|
-
readonly currentRoute: Signal.Computed<string | null>;
|
|
266
|
-
/**
|
|
267
|
-
* The route of the initial state of the machine. The constructor fixes it.
|
|
268
|
-
* A router bridge compares it with the browser URL. It therefore separates a deep
|
|
269
|
-
* link, where the router wins, from a restore of a session, where the actor wins.
|
|
270
|
-
*/
|
|
271
|
-
readonly initialRoute: string | null;
|
|
384
|
+
export interface RoutableActor extends Routable {
|
|
272
385
|
/** Sends a route navigation event to the actor. */
|
|
273
386
|
send(event: PlayRouteEvent): void;
|
|
274
387
|
}
|
|
275
|
-
/**
|
|
276
|
-
* The complete actor shape of the `PlayRouterProvider` component of each framework
|
|
277
|
-
* adapter: `play-solid-router`, `play-vue-router`, `play-react-router`, and each
|
|
278
|
-
* adapter on the shared framework router bridge bases.
|
|
279
|
-
*
|
|
280
|
-
* The shape extends `RoutableActor` with `currentView`, because the provider renders
|
|
281
|
-
* the current view spec and also keeps the routes in step. It therefore needs both
|
|
282
|
-
* capabilities.
|
|
283
|
-
*
|
|
284
|
-
* - Use `RoutableActor` when you need the routing alone, for example in a
|
|
285
|
-
* `RouterBridgeBase` subclass, or in `connectRouter`.
|
|
286
|
-
* - Use `PlayActor` when the component also renders the current view spec, for
|
|
287
|
-
* example for the renderer callback parameter of `PlayRouterProvider`, and in
|
|
288
|
-
* `PlayRenderer`.
|
|
289
|
-
*
|
|
290
|
-
* Every `AbstractActor` subclass that implements both `Routable` and `Viewable`
|
|
291
|
-
* satisfies this interface structurally.
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* ```typescript
|
|
295
|
-
* import type { PlayActor } from "@xmachines/play-router";
|
|
296
|
-
*
|
|
297
|
-
* function MyRouterProvider({ actor }: { actor: PlayActor }) {
|
|
298
|
-
* // it reads actor.currentRoute for the routing, and actor.currentView for the render
|
|
299
|
-
* }
|
|
300
|
-
* ```
|
|
301
|
-
*/
|
|
302
|
-
export interface PlayActor extends RoutableActor {
|
|
303
|
-
/** The TC39 Signal of the current view spec of the actor, or `null` when no view is active. */
|
|
304
|
-
readonly currentView: Signal.State<PlaySpec | null>;
|
|
305
|
-
}
|
|
306
388
|
/**
|
|
307
389
|
* The RouterBridge interface of a runtime infrastructure adapter
|
|
308
390
|
*
|
|
309
391
|
* The interface defines the connection of the lifecycle between the infrastructure,
|
|
310
392
|
* for example a framework router, and the Actor. The infrastructure builds a "bridge"
|
|
311
|
-
* to the Actor: it observes the
|
|
393
|
+
* to the Actor: it observes the atoms of the Actor, and it manages its own
|
|
312
394
|
* lifecycle accordingly.
|
|
313
395
|
*
|
|
314
396
|
* **Architectural context:** the interface implements **Passive Infrastructure
|
|
315
397
|
* (INV-04)**, because it gives an observation in one direction. The infrastructure
|
|
316
|
-
* connects to observe the
|
|
398
|
+
* connects to observe the atoms of the Actor (currentRoute, currentView, and
|
|
317
399
|
* state), and it reflects each change. It makes no decision about the state.
|
|
318
400
|
*
|
|
319
401
|
* @example
|
|
320
402
|
* The implementation of a framework router bridge
|
|
321
403
|
* ```typescript
|
|
322
404
|
* import type { RouterBridge } from "@xmachines/play-router";
|
|
323
|
-
* import {
|
|
405
|
+
* import { watchAtom, type Cleanup } from "@xmachines/play-atom";
|
|
324
406
|
*
|
|
325
407
|
* class MyRouterBridge implements RouterBridge {
|
|
326
|
-
* private
|
|
408
|
+
* private stop: Cleanup | null = null;
|
|
327
409
|
*
|
|
328
410
|
* async connect(): Promise<void> {
|
|
329
|
-
* // Start the observation of the actor.currentRoute
|
|
330
|
-
* this.
|
|
331
|
-
* const route = actor.currentRoute.get();
|
|
411
|
+
* // Start the observation of the actor.currentRoute atom
|
|
412
|
+
* this.stop = watchAtom(actor.currentRoute, (route) => {
|
|
332
413
|
* if (route) router.navigate(route);
|
|
333
414
|
* });
|
|
334
|
-
* this.watcher.watch(actor.currentRoute);
|
|
335
415
|
* }
|
|
336
416
|
*
|
|
337
417
|
* async disconnect(): Promise<void> {
|
|
338
|
-
* // Stop the observation, and
|
|
339
|
-
* this.
|
|
340
|
-
* this.
|
|
418
|
+
* // Stop the observation, and release the subscription
|
|
419
|
+
* this.stop?.();
|
|
420
|
+
* this.stop = null;
|
|
341
421
|
* }
|
|
342
422
|
* }
|
|
343
423
|
* ```
|
|
@@ -349,7 +429,7 @@ export interface RouterBridge {
|
|
|
349
429
|
* Connects the router bridge to the Actor
|
|
350
430
|
*
|
|
351
431
|
* The infrastructure calls it when it must start the observation of the Actor
|
|
352
|
-
*
|
|
432
|
+
* atoms, and when it must bring its own state, for example the browser URL, in line
|
|
353
433
|
* with the Actor state.
|
|
354
434
|
*
|
|
355
435
|
* @returns The promise that resolves after the connection, or void for a synchronous connection
|
|
@@ -358,7 +438,7 @@ export interface RouterBridge {
|
|
|
358
438
|
* ```typescript
|
|
359
439
|
* const bridge: RouterBridge = createBridge(actor, router);
|
|
360
440
|
* await bridge.connect();
|
|
361
|
-
* // The bridge observes the actor.currentRoute
|
|
441
|
+
* // The bridge observes the actor.currentRoute atom now
|
|
362
442
|
* ```
|
|
363
443
|
*/
|
|
364
444
|
connect(): void | Promise<void>;
|
|
@@ -366,7 +446,7 @@ export interface RouterBridge {
|
|
|
366
446
|
* Disconnects the router bridge from the Actor
|
|
367
447
|
*
|
|
368
448
|
* The infrastructure calls it when it must stop the observation and free its
|
|
369
|
-
* resources, for example
|
|
449
|
+
* resources, for example an atom watcher and an event listener.
|
|
370
450
|
*
|
|
371
451
|
* @returns The promise that resolves after the disconnection, or void for a synchronous disconnection
|
|
372
452
|
*
|
|
@@ -462,4 +542,28 @@ export interface LocationLike {
|
|
|
462
542
|
readonly pathname: string;
|
|
463
543
|
readonly search: string;
|
|
464
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* The options of `createRouteMap` and of `createRouteMapFromTree`.
|
|
547
|
+
*/
|
|
548
|
+
export interface RouteMapOptions extends CompileOptions {
|
|
549
|
+
/**
|
|
550
|
+
* The cache of the state that a VISITED PATH resolves to, or `null` for a path that
|
|
551
|
+
* resolves to none.
|
|
552
|
+
*
|
|
553
|
+
* The default is a cache of this map alone, of 500 entries in each of two generations.
|
|
554
|
+
* Pass one to raise that bound, to share the resolution across maps, or to give it an
|
|
555
|
+
* eviction policy of your own: `createPatternCache(5000)` builds one, and so does any
|
|
556
|
+
* object with a `get` and a `set`.
|
|
557
|
+
*
|
|
558
|
+
* A cache that a caller passes is keyed by the ROUTE TABLE. Two maps built from the
|
|
559
|
+
* same mappings, in the same order, therefore read each other's answers — which is
|
|
560
|
+
* what a server that rebuilds its map for each request wants — and two maps built from
|
|
561
|
+
* different mappings never do, because a map with no route for a path writes `null`
|
|
562
|
+
* for it and a map that holds one must not read that.
|
|
563
|
+
*
|
|
564
|
+
* The keys are the paths that a visitor reaches, so the key space is unbounded: a
|
|
565
|
+
* cache with no bound of its own grows for the life of the process.
|
|
566
|
+
*/
|
|
567
|
+
pathCache?: PatternCache<string | null>;
|
|
568
|
+
}
|
|
465
569
|
//# 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":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AnyStateMachine } from "xstate";
|
|
2
|
+
import { RouteMap } from "../base-route-map.js";
|
|
3
|
+
import type { RouteMapOptions } from "../types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a `RouteMap` from an XState state machine.
|
|
6
|
+
*
|
|
7
|
+
* The function reads every state with a route, which means each state with a
|
|
8
|
+
* `meta.route` field. It keeps the routable states alone, and it drops the synthetic
|
|
9
|
+
* root of the tree. `createRouteMapFromTree` of the main entry point drops the same
|
|
10
|
+
* node, and the two functions therefore answer the same map for the same machine. It then builds the lookup structure between a path and a
|
|
11
|
+
* stateId, for both directions. A subclass of `RouterBridgeBase` uses the map: it
|
|
12
|
+
* converts each change of the browser URL into a `play.route` actor event, and each
|
|
13
|
+
* actor route into a URL.
|
|
14
|
+
*
|
|
15
|
+
* @param machine - The XState v5 state machine, with a `meta.route` annotation on each state with a route.
|
|
16
|
+
* @param options - The optional configuration. Give `{ pathCache }` to replace the
|
|
17
|
+
* default LRU cache of the parameterized path lookups with one that you own.
|
|
18
|
+
* @returns A `RouteMap` for each adapter on `RouterBridgeBase`.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { createRouteMap } from '@xmachines/play-router/xstate';
|
|
23
|
+
* import { connectRouter } from '@xmachines/play-dom-router';
|
|
24
|
+
*
|
|
25
|
+
* const routeMap = createRouteMap(myMachine);
|
|
26
|
+
* const disconnect = connectRouter({ actor, router, routeMap });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function createRouteMap(machine: AnyStateMachine, options?: RouteMapOptions): RouteMap;
|
|
30
|
+
//# sourceMappingURL=create-route-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-route-map.d.ts","sourceRoot":"","sources":["../../src/xstate/create-route-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAG9C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,QAAQ,CAa5F"}
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import { extractMachineRoutes } from "./extract-routes.js";
|
|
2
2
|
import { getRoutableRoutes } from "./query.js";
|
|
3
|
-
import { RouteMap } from "
|
|
3
|
+
import { RouteMap } from "../base-route-map.js";
|
|
4
4
|
/**
|
|
5
5
|
* Creates a `RouteMap` from an XState state machine.
|
|
6
6
|
*
|
|
7
7
|
* The function reads every state with a route, which means each state with a
|
|
8
|
-
* `meta.route` field. It
|
|
8
|
+
* `meta.route` field. It keeps the routable states alone, and it drops the synthetic
|
|
9
|
+
* root of the tree. `createRouteMapFromTree` of the main entry point drops the same
|
|
10
|
+
* node, and the two functions therefore answer the same map for the same machine. It then builds the lookup structure between a path and a
|
|
9
11
|
* stateId, for both directions. A subclass of `RouterBridgeBase` uses the map: it
|
|
10
12
|
* converts each change of the browser URL into a `play.route` actor event, and each
|
|
11
13
|
* actor route into a URL.
|
|
12
14
|
*
|
|
13
15
|
* @param machine - The XState v5 state machine, with a `meta.route` annotation on each state with a route.
|
|
14
|
-
* @param options - The optional configuration. Give `{
|
|
15
|
-
* default
|
|
16
|
+
* @param options - The optional configuration. Give `{ pathCache }` to replace the
|
|
17
|
+
* default LRU cache of the parameterized path lookups with one that you own.
|
|
16
18
|
* @returns A `RouteMap` for each adapter on `RouterBridgeBase`.
|
|
17
19
|
*
|
|
18
20
|
* @example
|
|
19
21
|
* ```typescript
|
|
20
|
-
* import { createRouteMap } from '@xmachines/play-router';
|
|
22
|
+
* import { createRouteMap } from '@xmachines/play-router/xstate';
|
|
21
23
|
* import { connectRouter } from '@xmachines/play-dom-router';
|
|
22
24
|
*
|
|
23
25
|
* const routeMap = createRouteMap(myMachine);
|
|
@@ -25,7 +27,10 @@ import { RouteMap } from "./base-route-map.js";
|
|
|
25
27
|
* ```
|
|
26
28
|
*/
|
|
27
29
|
export function createRouteMap(machine, options) {
|
|
28
|
-
|
|
30
|
+
// The options reach the EXTRACTION too. `extractMachineRoutes` parses the route of
|
|
31
|
+
// every node, so a caller that passes a cache for the isolation of a tenant would
|
|
32
|
+
// otherwise write each of those patterns into the shared default cache.
|
|
33
|
+
const routeTree = extractMachineRoutes(machine, options);
|
|
29
34
|
const routes = getRoutableRoutes(routeTree);
|
|
30
35
|
return new RouteMap(routes.map((node) => ({
|
|
31
36
|
stateId: node.stateId,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-route-map.js","sourceRoot":"","sources":["../../src/xstate/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,sBAAsB,CAAC;AAGhD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,cAAc,CAAC,OAAwB,EAAE,OAAyB;IACjF,mFAAmF;IACnF,kFAAkF;IAClF,wEAAwE;IACxE,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACzD,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,5 +1,7 @@
|
|
|
1
|
+
import type { ParseOptions } from "@xmachines/play-url";
|
|
1
2
|
import type { AnyStateMachine } from "xstate";
|
|
2
|
-
import type { RouteTree } from "
|
|
3
|
+
import type { RouteTree } from "../types.js";
|
|
4
|
+
import { type MachineGraph } from "./machine-to-graph.js";
|
|
3
5
|
/**
|
|
4
6
|
* Reads the complete route tree from the graph of a state machine
|
|
5
7
|
*
|
|
@@ -12,5 +14,5 @@ import type { RouteTree } from "./types.js";
|
|
|
12
14
|
* @param machine - The XState v5 state machine
|
|
13
15
|
* @returns The route tree, with its root, its byStateId map, its byPath map, and its graph
|
|
14
16
|
*/
|
|
15
|
-
export declare const extractMachineRoutes: (machine: AnyStateMachine) => RouteTree
|
|
17
|
+
export declare const extractMachineRoutes: (machine: AnyStateMachine, options?: ParseOptions) => RouteTree<MachineGraph>;
|
|
16
18
|
//# sourceMappingURL=extract-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-routes.d.ts","sourceRoot":"","sources":["../../src/xstate/extract-routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,KAAK,EAAE,SAAS,EAA4B,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAiF1E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,SAAS,eAAe,EACxB,UAAU,YAAY,KACpB,SAAS,CAAC,YAAY,CAoBxB,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { parsePattern } from "@xmachines/play-url";
|
|
1
2
|
import { machineToGraph } from "./machine-to-graph.js";
|
|
2
|
-
import { validateRouteFormat, validateStateExists } from "
|
|
3
|
-
import { buildRouteTree } from "
|
|
3
|
+
import { validateRouteFormat, validateStateExists } from "../validate-routes.js";
|
|
4
|
+
import { buildRouteTree } from "../build-tree.js";
|
|
4
5
|
/**
|
|
5
6
|
* Builds the statePath of a graph node, and it walks the chain of the parentId
|
|
6
7
|
* values.
|
|
@@ -26,7 +27,7 @@ const buildStatePath = (graphNode, graphNodeMap) => {
|
|
|
26
27
|
* Reads the route information of the MachineNodeData object of a graph node.
|
|
27
28
|
* The function returns null when the node has no route.
|
|
28
29
|
*/
|
|
29
|
-
const extractRouteFromNode = (graphNode, stateIds, graphNodeMap) => {
|
|
30
|
+
const extractRouteFromNode = (graphNode, stateIds, graphNodeMap, options) => {
|
|
30
31
|
const { stateId, route, meta } = graphNode.data;
|
|
31
32
|
// The node has no route
|
|
32
33
|
if (!route)
|
|
@@ -37,7 +38,11 @@ const extractRouteFromNode = (graphNode, stateIds, graphNodeMap) => {
|
|
|
37
38
|
validateStateExists(stateId, stateIds);
|
|
38
39
|
// Build the statePath from the chain of the parentId values. This works for an explicit ID and also for a generated one
|
|
39
40
|
const statePath = buildStatePath(graphNode, graphNodeMap);
|
|
40
|
-
|
|
41
|
+
// The parse answers this, and not a search for a ":". `route.includes(":")` was the
|
|
42
|
+
// last expression that read the grammar on its own: it reported no pattern for
|
|
43
|
+
// `/docs/*`, for `/books{/:id}?` and for an escaped literal, so a consumer that reads
|
|
44
|
+
// `node.pattern` learned that a parameterized route is a literal path.
|
|
45
|
+
const pattern = parsePattern(route, options).parameterized ? route : undefined;
|
|
41
46
|
// Build the original shape of the metadata again, from the data of the graph
|
|
42
47
|
const metadata = meta && typeof meta === "object" && "route" in meta
|
|
43
48
|
? meta["route"]
|
|
@@ -66,7 +71,7 @@ const extractRouteFromNode = (graphNode, stateIds, graphNodeMap) => {
|
|
|
66
71
|
* @param machine - The XState v5 state machine
|
|
67
72
|
* @returns The route tree, with its root, its byStateId map, its byPath map, and its graph
|
|
68
73
|
*/
|
|
69
|
-
export const extractMachineRoutes = (machine) => {
|
|
74
|
+
export const extractMachineRoutes = (machine, options) => {
|
|
70
75
|
// 1. Convert the machine into a graph
|
|
71
76
|
const graph = machineToGraph(machine);
|
|
72
77
|
// 2. Build the set of the state IDs, for the check, and the node map, for a parent lookup in O(1)
|
|
@@ -74,7 +79,7 @@ export const extractMachineRoutes = (machine) => {
|
|
|
74
79
|
const graphNodeMap = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
75
80
|
// 3. Read the routes of the graph nodes
|
|
76
81
|
const routes = graph.nodes
|
|
77
|
-
.map((node) => extractRouteFromNode(node, stateIds, graphNodeMap))
|
|
82
|
+
.map((node) => extractRouteFromNode(node, stateIds, graphNodeMap, options))
|
|
78
83
|
.filter((r) => r !== null);
|
|
79
84
|
// 4. Build the hierarchical tree, and attach the graph.
|
|
80
85
|
// buildRouteTree finds each duplicate route, AFTER it resolved each relative route
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-routes.js","sourceRoot":"","sources":["../../src/xstate/extract-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@xmachines/play-router/xstate` - the routes of an XState machine
|
|
3
|
+
*
|
|
4
|
+
* A route of XMachines is a fact about a STATE. This entry point reads that fact out of an
|
|
5
|
+
* XState v5 machine: it walks the machine, collects each `meta.route`, builds the route
|
|
6
|
+
* tree, and answers the questions that the tree can be asked — which routes are reachable,
|
|
7
|
+
* which are navigable from a state, and which path maps to which state id.
|
|
8
|
+
*
|
|
9
|
+
* The MAIN entry point holds what happens AFTERWARDS: the route map, the match of a
|
|
10
|
+
* location, the bridge, and the provider lifecycle. It names no machine, and it reads this
|
|
11
|
+
* module never. `xstate` is therefore an OPTIONAL peer of this package, and a bundler drops
|
|
12
|
+
* `@statelyai/graph` for a consumer that imports this entry point nowhere.
|
|
13
|
+
*
|
|
14
|
+
* This is the same shape as `@xmachines/play-xstate/routing` and
|
|
15
|
+
* `@xmachines/play-xstate/view`: an optional capability behind its own entry point, with
|
|
16
|
+
* its own dependency.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { createRouteMap } from "@xmachines/play-router/xstate";
|
|
21
|
+
* import { connectRouter } from "@xmachines/play-dom-router";
|
|
22
|
+
*
|
|
23
|
+
* const routeMap = createRouteMap(myMachine);
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @packageDocumentation
|
|
27
|
+
* @see [Routing guide](../../../docs/guides/routing.md)
|
|
28
|
+
*/
|
|
29
|
+
export { extractMachineRoutes } from "./extract-routes.js";
|
|
30
|
+
export { createRouteMap } from "./create-route-map.js";
|
|
31
|
+
export { machineToGraph } from "./machine-to-graph.js";
|
|
32
|
+
export type { MachineGraph } from "./machine-to-graph.js";
|
|
33
|
+
export type { MachineNodeData, MachineEdgeData } from "./machine-types.js";
|
|
34
|
+
export { getNavigableRoutes, getRoutableRoutes, routeExists, getTransitionReachableRoutes, isRouteReachable, getRouteMappings, } from "./query.js";
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/xstate/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EACN,kBAAkB,EAClB,iBAAiB,EACjB,WAAW,EACX,4BAA4B,EAC5B,gBAAgB,EAChB,gBAAgB,GAChB,MAAM,YAAY,CAAC"}
|