@real-router/route-utils 0.1.3 → 0.1.5
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 +63 -115
- package/dist/cjs/metafile-cjs.json +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,97 +1,58 @@
|
|
|
1
1
|
# @real-router/route-utils
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@real-router/route-utils)
|
|
4
|
+
[](https://www.npmjs.com/package/@real-router/route-utils)
|
|
5
|
+
[](https://bundlejs.com/?q=@real-router/route-utils&treeshake=[*])
|
|
6
|
+
[](../../LICENSE)
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
> Cached read-only query API for [Real-Router](https://github.com/greydragon888/real-router) route tree structure. Pre-computed ancestor chains, sibling lookups, and regex-based segment testers.
|
|
7
9
|
|
|
8
10
|
## Installation
|
|
9
11
|
|
|
10
12
|
```bash
|
|
11
13
|
npm install @real-router/route-utils
|
|
12
|
-
# or
|
|
13
|
-
pnpm add @real-router/route-utils
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Quick Start
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
|
-
import { createRouter
|
|
19
|
+
import { createRouter } from "@real-router/core";
|
|
20
|
+
import { getPluginApi } from "@real-router/core/api";
|
|
20
21
|
import { getRouteUtils, startsWithSegment } from "@real-router/route-utils";
|
|
21
22
|
|
|
22
23
|
const router = createRouter([
|
|
23
24
|
{ name: "home", path: "/" },
|
|
24
|
-
{
|
|
25
|
-
name: "
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
path: "/:id",
|
|
31
|
-
children: [{ name: "edit", path: "/edit" }],
|
|
32
|
-
},
|
|
33
|
-
{ name: "settings", path: "/settings" },
|
|
34
|
-
],
|
|
35
|
-
},
|
|
25
|
+
{ name: "users", path: "/users", children: [
|
|
26
|
+
{ name: "profile", path: "/:id", children: [
|
|
27
|
+
{ name: "edit", path: "/edit" },
|
|
28
|
+
]},
|
|
29
|
+
{ name: "settings", path: "/settings" },
|
|
30
|
+
]},
|
|
36
31
|
{ name: "admin", path: "/admin" },
|
|
37
32
|
]);
|
|
38
33
|
|
|
39
34
|
const utils = getRouteUtils(getPluginApi(router).getTree());
|
|
40
35
|
|
|
41
|
-
utils.getChain("users.profile");
|
|
42
|
-
utils.getSiblings("users");
|
|
43
|
-
utils.isDescendantOf("users.profile", "users");
|
|
36
|
+
utils.getChain("users.profile"); // ["users", "users.profile"]
|
|
37
|
+
utils.getSiblings("users"); // ["home", "admin"]
|
|
38
|
+
utils.isDescendantOf("users.profile", "users"); // true
|
|
44
39
|
|
|
45
|
-
startsWithSegment("users.profile", "users");
|
|
40
|
+
startsWithSegment("users.profile", "users"); // true
|
|
46
41
|
```
|
|
47
42
|
|
|
48
|
-
|
|
43
|
+
## RouteUtils
|
|
49
44
|
|
|
50
|
-
|
|
45
|
+
Pre-computes all route tree data in the constructor. Subsequent lookups are O(1) Map reads.
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
[
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
#### `new RouteUtils(root: RouteTreeNode)`
|
|
59
|
-
|
|
60
|
-
Creates a new instance. All ancestor chains and sibling lists are frozen during construction.
|
|
61
|
-
|
|
62
|
-
#### `utils.getChain(name): readonly string[] | undefined`
|
|
63
|
-
|
|
64
|
-
Returns the cumulative ancestor chain for a route. Root returns `[""]`; other routes exclude root.
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
utils.getChain("users.profile.edit");
|
|
68
|
-
// → ["users", "users.profile", "users.profile.edit"]
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
#### `utils.getSiblings(name): readonly string[] | undefined`
|
|
72
|
-
|
|
73
|
-
Returns non-absolute siblings of a route (excluding itself). Root returns `undefined`.
|
|
74
|
-
|
|
75
|
-
#### `utils.isDescendantOf(child, parent): boolean`
|
|
76
|
-
|
|
77
|
-
O(k) string prefix check. Does not perform tree lookup.
|
|
78
|
-
|
|
79
|
-
#### Static Facade
|
|
80
|
-
|
|
81
|
-
`RouteUtils` exposes segment testers as `static readonly` properties — delegates to standalone functions:
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
RouteUtils.startsWithSegment("users.list", "users"); // true
|
|
85
|
-
RouteUtils.endsWithSegment("users.profile.edit", "edit"); // true
|
|
86
|
-
RouteUtils.includesSegment("a.b.c.d", "b.c"); // true
|
|
87
|
-
RouteUtils.areRoutesRelated("users", "users.profile"); // true
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
---
|
|
47
|
+
| Method | Returns | Description |
|
|
48
|
+
|--------|---------|-------------|
|
|
49
|
+
| `getChain(name)` | `readonly string[] \| undefined` | Ancestor chain (e.g., `["users", "users.profile", "users.profile.edit"]`) |
|
|
50
|
+
| `getSiblings(name)` | `readonly string[] \| undefined` | Sibling routes (excluding itself) |
|
|
51
|
+
| `isDescendantOf(child, parent)` | `boolean` | O(k) string prefix check |
|
|
91
52
|
|
|
92
53
|
### `getRouteUtils(root): RouteUtils`
|
|
93
54
|
|
|
94
|
-
WeakMap-cached factory
|
|
55
|
+
WeakMap-cached factory — same tree reference returns the same instance:
|
|
95
56
|
|
|
96
57
|
```typescript
|
|
97
58
|
const utils1 = getRouteUtils(tree);
|
|
@@ -99,77 +60,64 @@ const utils2 = getRouteUtils(tree);
|
|
|
99
60
|
utils1 === utils2; // true
|
|
100
61
|
```
|
|
101
62
|
|
|
102
|
-
|
|
63
|
+
## Segment Testers
|
|
103
64
|
|
|
104
|
-
|
|
65
|
+
Standalone functions for testing dot-separated route name segments. Each supports direct, curried, and `State` object calling patterns.
|
|
105
66
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
67
|
+
| Function | Description |
|
|
68
|
+
|----------|-------------|
|
|
69
|
+
| `startsWithSegment(route, segment?)` | Route starts with segment (dot-bounded) |
|
|
70
|
+
| `endsWithSegment(route, segment?)` | Route ends with segment |
|
|
71
|
+
| `includesSegment(route, segment?)` | Route includes segment anywhere (contiguous) |
|
|
72
|
+
| `areRoutesRelated(route1, route2)` | Routes are same, parent-child, or child-parent |
|
|
111
73
|
|
|
112
74
|
```typescript
|
|
113
|
-
startsWithSegment("users.list", "users");
|
|
114
|
-
startsWithSegment("users2.list", "users");
|
|
75
|
+
startsWithSegment("users.list", "users"); // true
|
|
76
|
+
startsWithSegment("users2.list", "users"); // false (dot boundary)
|
|
77
|
+
endsWithSegment("users.profile.edit", "edit"); // true
|
|
78
|
+
includesSegment("a.b.c.d", "b.c"); // true
|
|
79
|
+
areRoutesRelated("users", "users.profile"); // true
|
|
115
80
|
|
|
116
|
-
// Curried form
|
|
81
|
+
// Curried form — first arg is route, returns tester for segments
|
|
117
82
|
const tester = startsWithSegment("users.list");
|
|
118
|
-
tester("users");
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
#### `endsWithSegment(route, segment?)`
|
|
122
|
-
|
|
123
|
-
Tests if a route name ends with the given segment. [Wiki](https://github.com/greydragon888/real-router/wiki/route-utils#endswithsegmentroute-segment)
|
|
124
|
-
|
|
125
|
-
#### `includesSegment(route, segment?)`
|
|
126
|
-
|
|
127
|
-
Tests if a route name includes the given segment anywhere (contiguous, dot-bounded). [Wiki](https://github.com/greydragon888/real-router/wiki/route-utils#includessegmentroute-segment)
|
|
128
|
-
|
|
129
|
-
#### `areRoutesRelated(route1, route2): boolean`
|
|
130
|
-
|
|
131
|
-
Checks if two routes are related in the hierarchy (same, parent-child, or child-parent). [Wiki](https://github.com/greydragon888/real-router/wiki/route-utils#areroutesrelatedroute1-route2)
|
|
132
|
-
|
|
133
|
-
---
|
|
83
|
+
tester("users"); // true
|
|
134
84
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
import type { SegmentTestFunction } from "@real-router/route-utils";
|
|
85
|
+
// Static access via RouteUtils
|
|
86
|
+
RouteUtils.startsWithSegment("users.list", "users"); // true
|
|
139
87
|
```
|
|
140
88
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Segment Validation
|
|
146
|
-
|
|
147
|
-
All segment testers validate input:
|
|
89
|
+
### Input Validation
|
|
148
90
|
|
|
149
91
|
- **Max length**: 10,000 characters (`RangeError`)
|
|
150
92
|
- **Allowed characters**: `a-z`, `A-Z`, `0-9`, `.`, `-`, `_` (`TypeError`)
|
|
151
93
|
- **Empty / null segment**: returns `false` (no error)
|
|
152
94
|
|
|
153
|
-
---
|
|
154
|
-
|
|
155
95
|
## Performance
|
|
156
96
|
|
|
157
|
-
| Operation
|
|
158
|
-
|
|
159
|
-
| Construction
|
|
160
|
-
| `getChain` / `getSiblings`
|
|
161
|
-
| `isDescendantOf`
|
|
162
|
-
| `getRouteUtils` (cache hit) | O(1)
|
|
163
|
-
| Segment
|
|
97
|
+
| Operation | Complexity | Notes |
|
|
98
|
+
|-----------|------------|-------|
|
|
99
|
+
| Construction | O(n) | Single DFS, n = number of routes |
|
|
100
|
+
| `getChain` / `getSiblings` | O(1) | Frozen cached arrays |
|
|
101
|
+
| `isDescendantOf` | O(k) | String prefix check |
|
|
102
|
+
| `getRouteUtils` (cache hit) | O(1) | WeakMap lookup |
|
|
103
|
+
| Segment testers | O(k) | Regex test, cached |
|
|
104
|
+
|
|
105
|
+
## Documentation
|
|
164
106
|
|
|
165
|
-
|
|
107
|
+
Full documentation: [Wiki — route-utils](https://github.com/greydragon888/real-router/wiki/route-utils)
|
|
166
108
|
|
|
167
109
|
## Related Packages
|
|
168
110
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
111
|
+
| Package | Description |
|
|
112
|
+
|---------|-------------|
|
|
113
|
+
| [@real-router/core](https://www.npmjs.com/package/@real-router/core) | Core router |
|
|
114
|
+
| [@real-router/react](https://www.npmjs.com/package/@real-router/react) | React integration (`useRouteUtils` hook) |
|
|
115
|
+
| [@real-router/sources](https://www.npmjs.com/package/@real-router/sources) | Subscription layer (uses route-utils internally) |
|
|
116
|
+
|
|
117
|
+
## Contributing
|
|
118
|
+
|
|
119
|
+
See [contributing guidelines](../../CONTRIBUTING.md) for development setup and PR process.
|
|
172
120
|
|
|
173
121
|
## License
|
|
174
122
|
|
|
175
|
-
MIT © [Oleg Ivanov](https://github.com/greydragon888)
|
|
123
|
+
[MIT](../../LICENSE) © [Oleg Ivanov](https://github.com/greydragon888)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.
|
|
1
|
+
{"inputs":{"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js":{"bytes":569,"imports":[],"format":"esm"},"src/routeRelation.ts":{"bytes":994,"imports":[{"path":"/home/runner/work/real-router/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/constants.ts":{"bytes":515,"imports":[{"path":"/home/runner/work/real-router/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/segmentTesters.ts":{"bytes":8570,"imports":[{"path":"src/constants.ts","kind":"import-statement","original":"./constants"},{"path":"/home/runner/work/real-router/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/RouteUtils.ts":{"bytes":4807,"imports":[{"path":"src/routeRelation.ts","kind":"import-statement","original":"./routeRelation.js"},{"path":"src/segmentTesters.ts","kind":"import-statement","original":"./segmentTesters.js"},{"path":"/home/runner/work/real-router/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/getRouteUtils.ts":{"bytes":365,"imports":[{"path":"src/RouteUtils.ts","kind":"import-statement","original":"./RouteUtils.js"},{"path":"/home/runner/work/real-router/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":310,"imports":[{"path":"src/RouteUtils.ts","kind":"import-statement","original":"./RouteUtils.js"},{"path":"src/getRouteUtils.ts","kind":"import-statement","original":"./getRouteUtils.js"},{"path":"src/segmentTesters.ts","kind":"import-statement","original":"./segmentTesters.js"},{"path":"src/routeRelation.ts","kind":"import-statement","original":"./routeRelation.js"},{"path":"/home/runner/work/real-router/real-router/node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"dist/cjs/index.js.map":{"imports":[],"exports":[],"inputs":{},"bytes":19261},"dist/cjs/index.js":{"imports":[],"exports":["RouteUtils","areRoutesRelated","endsWithSegment","getRouteUtils","includesSegment","startsWithSegment"],"entryPoint":"src/index.ts","inputs":{"src/routeRelation.ts":{"bytesInOutput":144},"src/constants.ts":{"bytesInOutput":105},"src/segmentTesters.ts":{"bytesInOutput":1998},"src/RouteUtils.ts":{"bytesInOutput":3845},"src/index.ts":{"bytesInOutput":0},"src/getRouteUtils.ts":{"bytesInOutput":215}},"bytes":6546}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@real-router/route-utils",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"description": "Cached read-only query API for route tree structure",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -42,16 +42,17 @@
|
|
|
42
42
|
"sideEffects": false,
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"mitata": "1.0.34",
|
|
45
|
-
"route-tree": "^0.3.
|
|
45
|
+
"route-tree": "^0.3.4"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@real-router/types": "^0.
|
|
48
|
+
"@real-router/types": "^0.24.0"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "tsup",
|
|
52
52
|
"type-check": "tsc --noEmit",
|
|
53
53
|
"lint": "eslint --cache --ext .ts src/ tests/ --fix --max-warnings 0 --no-error-on-unmatched-pattern",
|
|
54
54
|
"test": "vitest run",
|
|
55
|
+
"test:properties": "vitest --config vitest.config.properties.mts --run",
|
|
55
56
|
"bench": "NODE_OPTIONS='--expose-gc --max-old-space-size=4096' npx tsx tests/benchmarks/index.ts"
|
|
56
57
|
}
|
|
57
58
|
}
|