@xmachines/play-router 3.0.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 +99 -115
- 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 +22 -4
- 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 +6 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -11
- package/dist/index.js.map +1 -1
- package/dist/provider-lifecycle.d.ts +10 -6
- package/dist/provider-lifecycle.d.ts.map +1 -1
- package/dist/provider-lifecycle.js +1 -1
- 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 +249 -76
- 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/README.md
CHANGED
|
@@ -2,51 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
Route tree extraction from XState v5 state machines. Part of [@xmachines/play](../play/README.md) Universal Player Architecture.
|
|
4
4
|
|
|
5
|
-
[](https://opensource.org/licenses/MIT) [](https://opensource.org/licenses/MIT) [](https://www.npmjs.com/package/@xmachines/play-router)
|
|
6
6
|
|
|
7
7
|
This package extracts the routes from a machine graph and looks them up in both directions. The Actor therefore keeps the authority over the navigation.
|
|
8
8
|
|
|
9
9
|
> **Browser floor: Chrome 110, Firefox 115, Safari 16.4.** This package calls the ES2023
|
|
10
10
|
> change-by-copy array methods, so a browser below that floor throws
|
|
11
|
-
> `TypeError: ... is not a function` at the extraction of the routes.
|
|
12
|
-
>
|
|
13
|
-
> `build.target` when you bundle for the browser. The root README carries the table.
|
|
14
|
-
>
|
|
15
|
-
> A **parameterized route** raises Firefox to **117**, which is the version that has the
|
|
16
|
-
> URLPattern API. Load the `urlpattern-polyfill` for an older target, as the Installation
|
|
17
|
-
> section below says.
|
|
11
|
+
> `TypeError: ... is not a function` at the extraction of the routes. The root README
|
|
12
|
+
> carries the table.
|
|
18
13
|
|
|
19
14
|
## Installation
|
|
20
15
|
|
|
21
16
|
```bash
|
|
22
|
-
pnpm add xstate@^5.
|
|
17
|
+
pnpm add xstate@^5.33.0
|
|
23
18
|
pnpm add @xmachines/play-router
|
|
24
19
|
```
|
|
25
20
|
|
|
26
21
|
**Peer dependencies:**
|
|
27
22
|
|
|
28
|
-
- `xstate` ^5.
|
|
29
|
-
|
|
30
|
-
**URLPattern polyfill (Node.js < 24 / older browsers):**
|
|
31
|
-
|
|
32
|
-
`@xmachines/play-router` matches each dynamic route with the [URLPattern API](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern). URLPattern is native in Node.js 24+ and in a modern browser (Chrome 95+, Firefox 117+, Safari 16.4+).
|
|
33
|
-
|
|
34
|
-
In an environment without the native API, load a polyfill **before** you import this package:
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
// Entry point — must run before any @xmachines/play-router import
|
|
38
|
-
import "urlpattern-polyfill";
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Install the polyfill:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
pnpm add urlpattern-polyfill
|
|
45
|
-
```
|
|
23
|
+
- `xstate` ^5.33.0 — XState v5 state machine runtime (an OPTIONAL peer: the `@xmachines/play-router/xstate` subpath alone reads it)
|
|
46
24
|
|
|
47
|
-
|
|
25
|
+
**URLPattern:** this package matches each route with the [URLPattern API](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern). It uses the native API when the runtime has one, and it falls back to `urlpattern-polyfill`, which it carries as an ordinary dependency. **You install nothing and you load nothing.**
|
|
48
26
|
|
|
49
|
-
|
|
27
|
+
The [routing guide](../docs/guides/routing.md) states the pattern language: the forms, the modifiers, the prefix rule, and the one divergence from the standard.
|
|
50
28
|
|
|
51
29
|
## Usage
|
|
52
30
|
|
|
@@ -54,7 +32,7 @@ pnpm add urlpattern-polyfill
|
|
|
54
32
|
|
|
55
33
|
```typescript
|
|
56
34
|
import { createMachine } from "xstate";
|
|
57
|
-
import { extractMachineRoutes, createRouteMap } from "@xmachines/play-router";
|
|
35
|
+
import { extractMachineRoutes, createRouteMap } from "@xmachines/play-router/xstate";
|
|
58
36
|
|
|
59
37
|
const machine = createMachine({
|
|
60
38
|
id: "app",
|
|
@@ -302,7 +280,7 @@ To register the routes of the machine in a host router that declares real route
|
|
|
302
280
|
objects, ask for the list — and drop it again when the machine unloads:
|
|
303
281
|
|
|
304
282
|
```typescript
|
|
305
|
-
import { extractMachineRoutes, getRouteMappings } from "@xmachines/play-router";
|
|
283
|
+
import { extractMachineRoutes, getRouteMappings } from "@xmachines/play-router/xstate";
|
|
306
284
|
|
|
307
285
|
const tree = extractMachineRoutes(machine);
|
|
308
286
|
|
|
@@ -325,25 +303,25 @@ event always carries the prefixed form.
|
|
|
325
303
|
> matched a route of the HOST by construction, because the machine owns the suffix of
|
|
326
304
|
> the path only. Those params therefore describe the route of the machine never, even
|
|
327
305
|
> when a name collides — a collision carries the value of the HOST. Both adapters
|
|
328
|
-
> resolve each param from the stripped path with `URLPattern` instead
|
|
329
|
-
> therefore need a polyfill on an older runtime when they are mounted.
|
|
306
|
+
> resolve each param from the stripped path with `URLPattern` instead.
|
|
330
307
|
>
|
|
331
|
-
> Without a prefix both adapters keep the parse of their framework, with its decoding
|
|
332
|
-
>
|
|
333
|
-
>
|
|
334
|
-
>
|
|
308
|
+
> Without a prefix both adapters keep the parse of their framework, with its decoding,
|
|
309
|
+
> but restricted to the names that the pattern of the machine declares. A splat of a
|
|
310
|
+
> catch-all, and a param of a wrapper route, reach the actor never. A name that the
|
|
311
|
+
> pattern makes OPTIONAL is covered whether the framework reports it or not: a part that
|
|
312
|
+
> did not match has no value, and that is a complete answer.
|
|
335
313
|
>
|
|
336
|
-
> A location that fills NO optional
|
|
337
|
-
>
|
|
338
|
-
>
|
|
339
|
-
> pattern still needed URLPattern when it was built.
|
|
314
|
+
> A location that fills NO optional part runs no match at all. `/settings` is the bare
|
|
315
|
+
> form of `/settings/:section?`, so the params are `{}`, and the adapters read that from
|
|
316
|
+
> the path alone rather than from their framework.
|
|
340
317
|
|
|
341
318
|
### How to write a `RouterBridgeBase` adapter
|
|
342
319
|
|
|
343
320
|
Extend `RouterBridgeBase`, then implement the three abstract methods for your framework:
|
|
344
321
|
|
|
345
322
|
```typescript
|
|
346
|
-
import { RouterBridgeBase
|
|
323
|
+
import { RouterBridgeBase } from "@xmachines/play-router";
|
|
324
|
+
import { createRouteMap } from "@xmachines/play-router/xstate";
|
|
347
325
|
import type { RoutableActor } from "@xmachines/play-router";
|
|
348
326
|
|
|
349
327
|
// Shape of your framework's router — adjust to its real API
|
|
@@ -401,13 +379,14 @@ bridge.disconnect();
|
|
|
401
379
|
|
|
402
380
|
### Route Extraction
|
|
403
381
|
|
|
404
|
-
| Export | Description
|
|
405
|
-
| ---------------------------------------- |
|
|
406
|
-
| `
|
|
407
|
-
| `
|
|
408
|
-
| `
|
|
409
|
-
|
|
410
|
-
|
|
382
|
+
| Export | Description |
|
|
383
|
+
| ---------------------------------------- | ----------------------------------------------------------------------- |
|
|
384
|
+
| `buildRouteTree(routes)` | Builds a `RouteTree` from an array of `RouteInfo` objects |
|
|
385
|
+
| `createRouteMapFromTree(tree, options?)` | Builds a `RouteMap` from a `RouteTree` that you extracted before |
|
|
386
|
+
| `ROOT_NODE_ID` | The ID of the synthetic root node. A walk of a tree must skip that node |
|
|
387
|
+
|
|
388
|
+
The MAIN entry point reads no state machine. The machine half is
|
|
389
|
+
`@xmachines/play-router/xstate`, below.
|
|
411
390
|
|
|
412
391
|
### Route Matching
|
|
413
392
|
|
|
@@ -417,16 +396,32 @@ bridge.disconnect();
|
|
|
417
396
|
| `findRouteById(tree, id)` | Finds a `RouteNode` by its state ID |
|
|
418
397
|
| `findRouteByPath(tree, path)` | Finds a `RouteNode` by its URL path. It also matches a dynamic pattern |
|
|
419
398
|
|
|
420
|
-
###
|
|
399
|
+
### The machine half — subpath `@xmachines/play-router/xstate`
|
|
400
|
+
|
|
401
|
+
A route of XMachines is a fact about a STATE. This entry point reads that fact out of an
|
|
402
|
+
XState v5 machine. The main entry point reads it never, so `xstate` is an OPTIONAL peer
|
|
403
|
+
dependency of this package, and a bundler drops `@statelyai/graph` for a consumer that
|
|
404
|
+
imports this entry point nowhere.
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
import { createRouteMap, extractMachineRoutes } from "@xmachines/play-router/xstate";
|
|
408
|
+
```
|
|
421
409
|
|
|
422
410
|
| Export | Description |
|
|
423
411
|
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
412
|
+
| `extractMachineRoutes(machine)` | Converts an XState machine into a `RouteTree` with the state ID ↔ path maps |
|
|
413
|
+
| `createRouteMap(machine, options?)` | Builds a `RouteMap` directly from a machine. An adapter uses this form |
|
|
414
|
+
| `machineToGraph(machine)` | Converts a machine into a typed `@statelyai/graph` `Graph`, for a graph algorithm |
|
|
424
415
|
| `getRoutableRoutes(tree)` | Returns every routable `RouteNode` in one flat array |
|
|
425
416
|
| `getNavigableRoutes(tree, stateId)` | Returns the child routes that a state can reach, through the hierarchy and through a transition |
|
|
426
417
|
| `routeExists(tree, path)` | Tells you if the tree holds a path |
|
|
427
418
|
| `getRouteMappings(tree, options?)` | The `{ stateId, path }` entries for a route table of a host, with an optional prefix |
|
|
428
419
|
| `getTransitionReachableRoutes(graph, stateId)` | Returns the route paths that a state can reach through an XState transition |
|
|
429
420
|
| `isRouteReachable(graph, fromStateId, toStateId)` | Tells you if a transition path is present between two states |
|
|
421
|
+
| `MachineGraph` | The typed `@statelyai/graph` Graph, with `MachineNodeData` and `MachineEdgeData` |
|
|
422
|
+
|
|
423
|
+
No framework router adapter re-exports `createRouteMap`. Each one names no state machine,
|
|
424
|
+
so a consumer of an adapter imports the function from `@xmachines/play-router/xstate`.
|
|
430
425
|
|
|
431
426
|
### Router Bridge
|
|
432
427
|
|
|
@@ -498,43 +493,40 @@ props that a framework decides, which is why it is a type parameter.
|
|
|
498
493
|
|
|
499
494
|
### Key Types
|
|
500
495
|
|
|
501
|
-
| Export
|
|
502
|
-
|
|
|
503
|
-
| `RouterBridge`
|
|
504
|
-
| `MountableRouterBridge`
|
|
505
|
-
| `RouteTree`
|
|
506
|
-
| `RouteNode`
|
|
507
|
-
| `RouteInfo`
|
|
508
|
-
| `PlayRouteEvent`
|
|
509
|
-
| `
|
|
510
|
-
| `
|
|
511
|
-
| `RouteMapping`
|
|
512
|
-
| `
|
|
513
|
-
| `
|
|
514
|
-
| `
|
|
515
|
-
| `
|
|
496
|
+
| Export | Description |
|
|
497
|
+
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
498
|
+
| `RouterBridge` | The interface of the `connect()` and `disconnect()` lifecycle |
|
|
499
|
+
| `MountableRouterBridge` | A `RouterBridge` whose mount can move — it adds `basePath` and `setBasePath()` |
|
|
500
|
+
| `RouteTree` | The hierarchical tree, with `root`, `byStateId`, `byPath`, and an optional `graph` |
|
|
501
|
+
| `RouteNode` | One node of the tree, with `id`, `path`, `fullPath`, `stateId`, `children`, and `parent` |
|
|
502
|
+
| `RouteInfo` | The flat route descriptor that comes from a state node |
|
|
503
|
+
| `PlayRouteEvent` | Routing event `{ type: "play.route", to, params?, query?, data? }` |
|
|
504
|
+
| `Routable` | The optional routing capability of an actor: `currentRoute` and `initialRoute` |
|
|
505
|
+
| `RoutableActor` | The actor interface that `RouterBridgeBase` and `PlayRouterProvider` require: `currentRoute`, `initialRoute`, and `send(PlayRouteEvent)` |
|
|
506
|
+
| `RouteMapping` | The `{ stateId, path }` pair that builds a `RouteMap` |
|
|
507
|
+
| `RouteObject` | The object form of `meta.route`: `path`, and the `handler`, `reenter` and `data` fields |
|
|
508
|
+
| `RouteMetadata` | The union of the two forms of `meta.route`: the path string, or a `RouteObject` |
|
|
509
|
+
| `RouteData` | The resolved extra data of a route, which reaches the machine as `context.data` |
|
|
510
|
+
| `RouteDataResolver` | The function form of `RouteObject.data`: `({ context, event }) => RouteData` |
|
|
511
|
+
| `WindowLike` | The minimal `window` interface that you can inject for SSR and for a test |
|
|
512
|
+
| `LocationLike` | The minimal `location` interface that you can inject for SSR and for a test |
|
|
516
513
|
|
|
517
514
|
### Errors (subpath `@xmachines/play-router/errors`)
|
|
518
515
|
|
|
519
|
-
| Class
|
|
520
|
-
|
|
|
521
|
-
| `RouterSyncError`
|
|
522
|
-
| `DuplicateBridgeError`
|
|
523
|
-
| `
|
|
524
|
-
| `
|
|
525
|
-
| `
|
|
526
|
-
| `
|
|
527
|
-
| `
|
|
528
|
-
| `
|
|
529
|
-
| `
|
|
530
|
-
| `MissingBasePathParamError` | `PLAY_ROUTER_MISSING_BASE_PATH_PARAM` | A `:param` of a `basePath` has no value in `basePathParams` |
|
|
516
|
+
| Class | Code | When thrown |
|
|
517
|
+
| --------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
518
|
+
| `RouterSyncError` | `PLAY_ROUTER_SYNC_FAILED` | `syncActorFromRouter()` cannot send a `play.route` event |
|
|
519
|
+
| `DuplicateBridgeError` | `PLAY_ROUTER_DUPLICATE_BRIDGE` | A second bridge tries to connect to an actor that already has one |
|
|
520
|
+
| `InvalidRoutePatternError` | `PLAY_ROUTE_MAP_INVALID_PATTERN` | A route pattern does not compile, or two of its params land on one URLPattern group |
|
|
521
|
+
| `EmptyRoutePathError` | `PLAY_ROUTE_EMPTY_PATH` | A state declares `meta.route: ""` |
|
|
522
|
+
| `InvalidStateIdError` | `PLAY_ROUTE_INVALID_STATE_ID` | A route names a state ID that the machine graph does not hold |
|
|
523
|
+
| `DuplicateRoutePathError` | `PLAY_ROUTE_DUPLICATE_PATH` | Two or more states share the same URL path |
|
|
524
|
+
| `UnknownStateTypeError` | `PLAY_ROUTE_UNKNOWN_STATE_TYPE` | A state node has an XState `.type` value that the package does not know |
|
|
525
|
+
| `InvalidBasePathError` | `PLAY_ROUTER_INVALID_BASE_PATH` | A `basePath` resolves to one concrete prefix never (`*`, `:p?`, `$p`, `?`, `#`, a scheme, `.`/`..`, whitespace) |
|
|
526
|
+
| `MissingBasePathParamError` | `PLAY_ROUTER_MISSING_BASE_PATH_PARAM` | A `:param` of a `basePath` has no value in `basePathParams` |
|
|
531
527
|
|
|
532
528
|
```typescript
|
|
533
|
-
import {
|
|
534
|
-
RouterSyncError,
|
|
535
|
-
DuplicateBridgeError,
|
|
536
|
-
URLPatternUnavailableError,
|
|
537
|
-
} from "@xmachines/play-router/errors";
|
|
529
|
+
import { RouterSyncError, DuplicateBridgeError } from "@xmachines/play-router/errors";
|
|
538
530
|
|
|
539
531
|
// bridge from the adapter example above
|
|
540
532
|
try {
|
|
@@ -575,6 +567,28 @@ states: {
|
|
|
575
567
|
}
|
|
576
568
|
```
|
|
577
569
|
|
|
570
|
+
### The object form
|
|
571
|
+
|
|
572
|
+
The object form carries the path and any metadata of your own, such as a title or a
|
|
573
|
+
breadcrumb. It also carries three fields that the routing layer reads:
|
|
574
|
+
|
|
575
|
+
| Field | Default | What it does |
|
|
576
|
+
| --------- | -------- | ------------------------------------------------------------------------------- |
|
|
577
|
+
| `path` | required | The template of the route path |
|
|
578
|
+
| `handler` | `"root"` | Where the generated `play.route` transition sits: `"root"`, `"local"`, `"both"` |
|
|
579
|
+
| `reenter` | `false` | Whether the transition re-enters its own domain. See the note below. |
|
|
580
|
+
| `data` | none | The extra data of the route: a literal value, or a function of the event |
|
|
581
|
+
|
|
582
|
+
`@xmachines/play-xstate` reads `handler`, `reenter`, and `data` when it generates the
|
|
583
|
+
transitions. See the README of that package for what each value does.
|
|
584
|
+
|
|
585
|
+
**The four names are RESERVED, and this is a change of behaviour.** An earlier release
|
|
586
|
+
read `path` alone, so a state could put any name of its own beside it. A state that
|
|
587
|
+
carries its own `handler` value now throws an `InvalidRouteHandlerError` at the format
|
|
588
|
+
time, and the machine builds never; a state that carries its own `data` value now writes
|
|
589
|
+
that value to `context.data`, where the `/context` projection of every view reads it.
|
|
590
|
+
Give such a field another name.
|
|
591
|
+
|
|
578
592
|
### Relative vs absolute paths
|
|
579
593
|
|
|
580
594
|
A child route that starts with `/` is absolute, and it does not inherit the path of its parent. A child route without the first `/` is relative to its nearest routable ancestor:
|
|
@@ -600,47 +614,17 @@ states: {
|
|
|
600
614
|
|
|
601
615
|
Always use `node.fullPath` to match a browser URL and to build a route map. Never use `node.path` for this.
|
|
602
616
|
|
|
603
|
-
## Testing
|
|
604
|
-
|
|
605
|
-
```bash
|
|
606
|
-
# Run tests for this package
|
|
607
|
-
pnpm --filter @xmachines/play-router test
|
|
608
|
-
|
|
609
|
-
# Watch mode
|
|
610
|
-
pnpm --filter @xmachines/play-router run test:watch
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
`@xmachines/play-router-shared` holds a contract test suite of the router bridge, for the
|
|
614
|
-
author of an adapter. That suite drives a real actor. Therefore it is one layer above this
|
|
615
|
-
package, and `@xmachines/play-router` keeps no dependency on an actor runtime.
|
|
616
|
-
`@xmachines/play-router-shared` is a private workspace package. Thus only an adapter author
|
|
617
|
-
in this repository can use the suite:
|
|
618
|
-
|
|
619
|
-
```typescript
|
|
620
|
-
import { runBridgeContractTests } from "@xmachines/play-router-shared/test/router-bridge-contract.js";
|
|
621
|
-
|
|
622
|
-
runBridgeContractTests({
|
|
623
|
-
name: "MyRouterBridge",
|
|
624
|
-
createHarness(initialPath) {
|
|
625
|
-
// return ContractHarness with bridge, actor, simulateNavigation, getLastNavigatedPath
|
|
626
|
-
},
|
|
627
|
-
createRestoredHarness(routedPath) {
|
|
628
|
-
// return ContractHarness whose actor is restored to routedPath
|
|
629
|
-
// while the mock router starts at the machine's initial route
|
|
630
|
-
},
|
|
631
|
-
});
|
|
632
|
-
```
|
|
633
|
-
|
|
634
617
|
## Related Packages
|
|
635
618
|
|
|
636
619
|
- **[@xmachines/play](../play/README.md)** — Core protocol types (`PlayEvent`, `PlayError`)
|
|
637
|
-
- **[@xmachines/play-actor](../play-actor/README.md)** — the
|
|
620
|
+
- **[@xmachines/play-actor](../play-actor/README.md)** — the actor contract (`PlayActor`). An actor that adds `Routable` of this package satisfies `RoutableActor` structurally
|
|
621
|
+
- **[@xmachines/play-url](../play-url/README.md)** — the URL language. This package re-exports its base path and its framework params, for an adapter on `RouterBridgeBase`
|
|
638
622
|
- **[@xmachines/play-signals](../play-signals/README.md)** — the TC39 Signals polyfill that observes the actor route
|
|
639
623
|
- **[@xmachines/play-xstate](../play-xstate/README.md)** — the XState v5 logic adapter, which works with a route tree
|
|
640
624
|
- **[@xmachines/play-tanstack-router](../play-tanstack-router/README.md)** — Shared TanStack Router bridge base (framework-agnostic)
|
|
641
625
|
- **[@xmachines/play-tanstack-react-router](../play-tanstack-react-router/README.md)** — TanStack Router adapter (React)
|
|
642
626
|
- **[@xmachines/play-tanstack-solid-router](../play-tanstack-solid-router/README.md)** — TanStack Router adapter (SolidJS)
|
|
643
|
-
- **[@xmachines/play-react-router](../play-react-router/README.md)** — React Router
|
|
627
|
+
- **[@xmachines/play-react-router](../play-react-router/README.md)** — React Router 7/8 adapter
|
|
644
628
|
- **[@xmachines/play-vue-router](../play-vue-router/README.md)** — Vue Router adapter
|
|
645
629
|
- **[@xmachines/play-solid-router](../play-solid-router/README.md)** — SolidJS Router adapter
|
|
646
630
|
|
package/dist/base-route-map.d.ts
CHANGED
|
@@ -45,11 +45,17 @@ export interface RouteMapping {
|
|
|
45
45
|
* - The class keeps each result of a first match in an LRU cache. The default size
|
|
46
46
|
* is 500 entries, and the `cacheSize` constructor option changes it
|
|
47
47
|
*
|
|
48
|
-
* **The syntax of a pattern
|
|
48
|
+
* **The syntax of a pattern:** the whole URLPattern pathname grammar. The forms used most
|
|
49
|
+
* often are:
|
|
49
50
|
* - `:param` — a necessary segment. It matches exactly one segment without a `/`
|
|
50
51
|
* - `:param?` — an optional segment. It matches zero segments or one segment without a `/`
|
|
51
52
|
* - `*` — a wildcard. It matches each number of segments, as URLPattern defines
|
|
52
53
|
*
|
|
54
|
+
* A `{…}` group, a `:param(\d+)` constraint, a `+` modifier and a `\:` escape are read
|
|
55
|
+
* too. The [routing guide](../../docs/guides/routing.md) states every form, the prefix
|
|
56
|
+
* rule, and the one divergence from the standard: a param name of this library can hold a
|
|
57
|
+
* hyphen.
|
|
58
|
+
*
|
|
53
59
|
* **The forms of a stateId:** you can register a stateId, and you can look one up,
|
|
54
60
|
* in the form `"#stateId"` or in the form `"stateId"`. `RouteMap` makes the
|
|
55
61
|
* canonical form itself. `getStateIdByPath` returns the stateId exactly as you
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-route-map.d.ts","sourceRoot":"","sources":["../src/base-route-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA0BH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,YAAY;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uGAAuG;IACvG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED
|
|
1
|
+
{"version":3,"file":"base-route-map.d.ts","sourceRoot":"","sources":["../src/base-route-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA0BH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,YAAY;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uGAAuG;IACvG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,QAAQ;IACpB,8EAA8E;IAC9E,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,cAAc,CAGpB;IACF,OAAO,CAAC,cAAc,CAAkC;IAExD;;;;;;;;;;;;;;;;;OAiBG;gBACS,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,SAAe,EAAE,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO;IA0CtF;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA4B7C;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAGhD"}
|
package/dist/base-route-map.js
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* segment, and that number is much smaller than the number of all the routes. The
|
|
11
11
|
* class matches a parameterized route with URLPattern.
|
|
12
12
|
*/
|
|
13
|
+
import { firstMarkIndex, getCandidates, getCompiledPattern, getIndexKey, parsePattern, } from "@xmachines/play-url";
|
|
13
14
|
import QuickLRU from "quick-lru";
|
|
14
|
-
import {
|
|
15
|
-
import { URLPatternUnavailableError, InvalidRoutePatternError } from "./errors.js";
|
|
15
|
+
import { InvalidRoutePatternError } from "./errors.js";
|
|
16
16
|
/**
|
|
17
17
|
* The canonical key of a stateId: the bare form, without a `#` at its start.
|
|
18
18
|
*
|
|
@@ -38,11 +38,17 @@ function canonicalStateIdKey(stateId) {
|
|
|
38
38
|
* - The class keeps each result of a first match in an LRU cache. The default size
|
|
39
39
|
* is 500 entries, and the `cacheSize` constructor option changes it
|
|
40
40
|
*
|
|
41
|
-
* **The syntax of a pattern
|
|
41
|
+
* **The syntax of a pattern:** the whole URLPattern pathname grammar. The forms used most
|
|
42
|
+
* often are:
|
|
42
43
|
* - `:param` — a necessary segment. It matches exactly one segment without a `/`
|
|
43
44
|
* - `:param?` — an optional segment. It matches zero segments or one segment without a `/`
|
|
44
45
|
* - `*` — a wildcard. It matches each number of segments, as URLPattern defines
|
|
45
46
|
*
|
|
47
|
+
* A `{…}` group, a `:param(\d+)` constraint, a `+` modifier and a `\:` escape are read
|
|
48
|
+
* too. The [routing guide](../../docs/guides/routing.md) states every form, the prefix
|
|
49
|
+
* rule, and the one divergence from the standard: a param name of this library can hold a
|
|
50
|
+
* hyphen.
|
|
51
|
+
*
|
|
46
52
|
* **The forms of a stateId:** you can register a stateId, and you can look one up,
|
|
47
53
|
* in the form `"#stateId"` or in the form `"stateId"`. `RouteMap` makes the
|
|
48
54
|
* canonical form itself. `getStateIdByPath` returns the stateId exactly as you
|
|
@@ -104,16 +110,18 @@ export class RouteMap {
|
|
|
104
110
|
// "#stateId" and also "stateId". The map keeps the registered form for its return
|
|
105
111
|
// values.
|
|
106
112
|
this.stateIdToPath.set(canonicalStateIdKey(stateId), path);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
// ONE parse answers both questions: is the path a pattern, and which bucket does
|
|
114
|
+
// it belong to. The key comes from that parse, and not from a split of the raw
|
|
115
|
+
// string. A pattern such as `/books{/:id}?` keeps the literal first segment
|
|
116
|
+
// `books`, and a split on `/` read the key `books{` and put the route in a bucket
|
|
117
|
+
// that the path `/books/1` reaches never.
|
|
118
|
+
const parsed = parsePattern(path);
|
|
119
|
+
if (parsed.parameterized) {
|
|
120
|
+
const bucketKey = parsed.indexKey;
|
|
113
121
|
const bucket = this.patternBuckets.get(bucketKey) ?? [];
|
|
114
122
|
try {
|
|
115
123
|
bucket.push({
|
|
116
|
-
pattern: getCompiledPattern(path
|
|
124
|
+
pattern: getCompiledPattern(path),
|
|
117
125
|
stateId,
|
|
118
126
|
order: patternOrder++,
|
|
119
127
|
});
|
|
@@ -150,8 +158,13 @@ export class RouteMap {
|
|
|
150
158
|
* ```
|
|
151
159
|
*/
|
|
152
160
|
getStateIdByPath(path) {
|
|
153
|
-
// Remove the query string and the hash fragment before the match
|
|
154
|
-
|
|
161
|
+
// Remove the query string and the hash fragment before the match. `firstMarkIndex`
|
|
162
|
+
// is the ONE answer to "where does a pathname end", and `RouterBridgeBase` and
|
|
163
|
+
// `framework-params.ts` read it too, so the three cannot disagree. Two splits
|
|
164
|
+
// allocated two arrays of every part on the hottest lookup of the library, and this
|
|
165
|
+
// function then read one element of each.
|
|
166
|
+
const mark = firstMarkIndex(path);
|
|
167
|
+
const cleanPath = mark === -1 ? path : path.slice(0, mark);
|
|
155
168
|
const exactMatch = this.pathToStateId.get(cleanPath);
|
|
156
169
|
if (exactMatch !== undefined)
|
|
157
170
|
return exactMatch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-route-map.js","sourceRoot":"","sources":["../src/base-route-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,
|
|
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
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { RouteInfo, RouteTree } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The ID and the state ID of the synthetic root node of every `RouteTree`.
|
|
4
|
+
*
|
|
5
|
+
* `buildRouteTree` always makes this node, and no state of a machine declares it. It
|
|
6
|
+
* gives the tree one parent for each absolute route, and it holds `routable: false`.
|
|
7
|
+
*
|
|
8
|
+
* A consumer that walks a tree must SKIP this node. `createRouteMapFromTree` skips it,
|
|
9
|
+
* and `getRoutableRoutes` of `@xmachines/play-router/xstate` skips it. A walk that keeps
|
|
10
|
+
* it maps the path `/` to a state that the machine does not hold.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ROOT_NODE_ID = "__root__";
|
|
2
13
|
/**
|
|
3
14
|
* Builds the hierarchical route tree from the flat list of the routes
|
|
4
15
|
*
|
|
@@ -13,9 +24,13 @@ import type { RouteInfo, RouteTree } from "./types.js";
|
|
|
13
24
|
* strings that resolve to the same complete path are not: those two overwrite each
|
|
14
25
|
* other in `byPath` in silence.
|
|
15
26
|
*
|
|
27
|
+
* `TGraph` names the type of the graph that a CALLER attaches afterwards. The builder
|
|
28
|
+
* attaches none: it reads a list of routes and writes the maps of the tree.
|
|
29
|
+
* `extractMachineRoutes` of `@xmachines/play-router/xstate` binds it to `MachineGraph`.
|
|
30
|
+
*
|
|
16
31
|
* @param routes - The flat list of the RouteInfo objects, from the extraction
|
|
17
32
|
* @returns The RouteTree, with its root, its byStateId map, and its byPath map
|
|
18
33
|
* @throws {DuplicateRoutePathError} When two states resolve to the same complete path
|
|
19
34
|
*/
|
|
20
|
-
export declare const buildRouteTree: (routes: RouteInfo[]) => RouteTree
|
|
35
|
+
export declare const buildRouteTree: <TGraph = unknown>(routes: RouteInfo[]) => RouteTree<TGraph>;
|
|
21
36
|
//# 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,EAAa,SAAS,EAAE,MAAM,YAAY,CAAC;AAGlE;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,GAAG,OAAO,EAAE,QAAQ,SAAS,EAAE,KAAG,SAAS,CAAC,MAAM,CA0EtF,CAAC"}
|
package/dist/build-tree.js
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { detectDuplicateRoutes } from "./validate-routes.js";
|
|
2
|
+
/**
|
|
3
|
+
* The ID and the state ID of the synthetic root node of every `RouteTree`.
|
|
4
|
+
*
|
|
5
|
+
* `buildRouteTree` always makes this node, and no state of a machine declares it. It
|
|
6
|
+
* gives the tree one parent for each absolute route, and it holds `routable: false`.
|
|
7
|
+
*
|
|
8
|
+
* A consumer that walks a tree must SKIP this node. `createRouteMapFromTree` skips it,
|
|
9
|
+
* and `getRoutableRoutes` of `@xmachines/play-router/xstate` skips it. A walk that keeps
|
|
10
|
+
* it maps the path `/` to a state that the machine does not hold.
|
|
11
|
+
*/
|
|
12
|
+
export const ROOT_NODE_ID = "__root__";
|
|
2
13
|
/**
|
|
3
14
|
* Builds the hierarchical route tree from the flat list of the routes
|
|
4
15
|
*
|
|
@@ -13,6 +24,10 @@ import { detectDuplicateRoutes } from "./validate-routes.js";
|
|
|
13
24
|
* strings that resolve to the same complete path are not: those two overwrite each
|
|
14
25
|
* other in `byPath` in silence.
|
|
15
26
|
*
|
|
27
|
+
* `TGraph` names the type of the graph that a CALLER attaches afterwards. The builder
|
|
28
|
+
* attaches none: it reads a list of routes and writes the maps of the tree.
|
|
29
|
+
* `extractMachineRoutes` of `@xmachines/play-router/xstate` binds it to `MachineGraph`.
|
|
30
|
+
*
|
|
16
31
|
* @param routes - The flat list of the RouteInfo objects, from the extraction
|
|
17
32
|
* @returns The RouteTree, with its root, its byStateId map, and its byPath map
|
|
18
33
|
* @throws {DuplicateRoutePathError} When two states resolve to the same complete path
|
|
@@ -20,10 +35,10 @@ import { detectDuplicateRoutes } from "./validate-routes.js";
|
|
|
20
35
|
export const buildRouteTree = (routes) => {
|
|
21
36
|
// 1. Create the root node
|
|
22
37
|
const root = {
|
|
23
|
-
id:
|
|
38
|
+
id: ROOT_NODE_ID,
|
|
24
39
|
path: "/",
|
|
25
40
|
fullPath: "/",
|
|
26
|
-
stateId:
|
|
41
|
+
stateId: ROOT_NODE_ID,
|
|
27
42
|
routable: false, // The root is a state without a route
|
|
28
43
|
children: [],
|
|
29
44
|
parent: null,
|
|
@@ -44,8 +59,11 @@ export const buildRouteTree = (routes) => {
|
|
|
44
59
|
let parentNode = root;
|
|
45
60
|
for (let i = route.statePath.length - 2; i >= 0; i--) {
|
|
46
61
|
const parentStateId = route.statePath[i]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
47
|
-
if (
|
|
48
|
-
|
|
62
|
+
if (parentStateId === undefined)
|
|
63
|
+
continue;
|
|
64
|
+
const candidate = byStateId.get(parentStateId);
|
|
65
|
+
if (candidate !== undefined) {
|
|
66
|
+
parentNode = candidate;
|
|
49
67
|
break;
|
|
50
68
|
}
|
|
51
69
|
}
|
package/dist/build-tree.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-tree.js","sourceRoot":"","sources":["../src/build-tree.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D
|
|
1
|
+
{"version":3,"file":"build-tree.js","sourceRoot":"","sources":["../src/build-tree.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { RouteTree } from "./types.js";
|
|
1
|
+
import type { RouteTree, RouteMapOptions } from "./types.js";
|
|
2
2
|
import { RouteMap } from "./base-route-map.js";
|
|
3
|
-
import type { RouteMapOptions } from "./create-route-map.js";
|
|
4
3
|
/**
|
|
5
4
|
* Creates a `RouteMap` from the node structure of a `RouteTree`.
|
|
6
5
|
*
|
|
7
|
-
* A framework router adapter uses this function when it
|
|
8
|
-
* `extractMachineRoutes()`, and not when it calls
|
|
6
|
+
* A framework router adapter uses this function when it holds a `RouteTree`, for example
|
|
7
|
+
* from `extractMachineRoutes()` of `@xmachines/play-router/xstate`, and not when it calls
|
|
8
|
+
* `createRouteMap()` of that package directly.
|
|
9
9
|
*
|
|
10
10
|
* The function walks every node, and it collects the pairs
|
|
11
11
|
* `{ stateId: node.id, path: node.fullPath }`. `node.fullPath` is always the
|
|
@@ -13,6 +13,11 @@ import type { RouteMapOptions } from "./create-route-map.js";
|
|
|
13
13
|
* that path for the match of a browser URL. `createRouteMap(machine)` behaves in the
|
|
14
14
|
* same way, because it also uses `node.fullPath`.
|
|
15
15
|
*
|
|
16
|
+
* The walk SKIPS the synthetic root node. `buildRouteTree` makes that node to hold each
|
|
17
|
+
* absolute route, and no state of a machine declares it. `createRouteMap` skips it as
|
|
18
|
+
* well, through `getRoutableRoutes`, and the two functions therefore answer the same map
|
|
19
|
+
* for the same tree.
|
|
20
|
+
*
|
|
16
21
|
* @param routeTree - A `RouteTree`, as `extractMachineRoutes()` returns it.
|
|
17
22
|
* @param options - The optional configuration, for example `{ cacheSize }` to change the size of the LRU cache.
|
|
18
23
|
* @returns A `RouteMap` for each adapter on `RouterBridgeBase`.
|
|
@@ -20,11 +25,12 @@ import type { RouteMapOptions } from "./create-route-map.js";
|
|
|
20
25
|
* @example
|
|
21
26
|
* ```typescript
|
|
22
27
|
* // The preferred form — one call for an XState machine:
|
|
23
|
-
* import { createRouteMap } from '@xmachines/play-router';
|
|
28
|
+
* import { createRouteMap } from '@xmachines/play-router/xstate';
|
|
24
29
|
* const routeMap = createRouteMap(machine); // it takes an AnyStateMachine
|
|
25
30
|
*
|
|
26
31
|
* // The two-step form, for a framework adapter that works with a route tree:
|
|
27
|
-
* import {
|
|
32
|
+
* import { createRouteMapFromTree } from '@xmachines/play-router';
|
|
33
|
+
* import { extractMachineRoutes } from '@xmachines/play-router/xstate';
|
|
28
34
|
* const routeTree = extractMachineRoutes(machine);
|
|
29
35
|
* const routeMap = createRouteMapFromTree(routeTree); // it uses node.fullPath, which is absolute
|
|
30
36
|
* ```
|
|
@@ -1 +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;
|
|
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,eAAe,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,QAAQ,CAchG"}
|