@avstantso/react-router-utils 0.1.2 → 0.2.1
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/CHANGELOG.md +21 -0
- package/README.md +168 -0
- package/dist/core/binded-path.d.ts +1 -0
- package/dist/impl/is-url.d.ts +2 -2
- package/dist/impl/links.d.ts +2 -2
- package/dist/impl/navigates.d.ts +2 -2
- package/dist/impl/tree-factory.d.ts +1 -0
- package/dist/index.js +82 -38
- package/dist/index.js.map +1 -1
- package/dist/types/is-url.d.ts +17 -9
- package/dist/types/links.d.ts +16 -12
- package/dist/types/navigates.d.ts +31 -19
- package/dist/types/route-creator.d.ts +17 -6
- package/dist/types/urls-tree.d.ts +124 -4
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.1] - 2026-02-07
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Updated README with comprehensive documentation for `AT` methods
|
|
8
|
+
- Updated README with documentation for RouteCreator callback syntax
|
|
9
|
+
- **RouteCreator callback syntax**: Nested routes now automatically use relative paths (`type='name'`), ensuring valid react-router nested route structures
|
|
10
|
+
- RouteCreator callback syntax is now stable (no longer experimental)
|
|
11
|
+
|
|
12
|
+
### Performance
|
|
13
|
+
|
|
14
|
+
- RouteCreator: Added WeakMap caching for nested trees, improving performance when callbacks are invoked multiple times on the same route
|
|
15
|
+
|
|
16
|
+
## [0.2.0] - 2026-02-05
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- `AT` methods for `isUrl`, `isSubUrl`, `Links`, `NavLinks`, `Navigates` and `Navigates.useNavigate()`
|
|
21
|
+
- New types internal structure based on `TypeMap`
|
|
22
|
+
- RouteCreator: +`makeRouteObjectCallback` experimental overload
|
|
23
|
+
|
|
3
24
|
## [0.1.2] - 2026-02-05
|
|
4
25
|
|
|
5
26
|
### Fixed
|
package/README.md
CHANGED
|
@@ -174,6 +174,35 @@ Each link component has an `id` property derived from the route path, useful for
|
|
|
174
174
|
console.log(Links.Profile.Settings.id); // HTML-safe id derived from "profile/settings"
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
+
### AT Method (Direct Node Access)
|
|
178
|
+
|
|
179
|
+
The `AT` method provides direct access to any node in the tree by passing a URL tree node reference. This is useful when you need to dynamically select routes or work with node references:
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
const { Links, NavLinks } = ReactRouterTree(urlsTree);
|
|
183
|
+
|
|
184
|
+
// Access a specific node directly
|
|
185
|
+
const AboutLink = Links.AT(urlsTree.about);
|
|
186
|
+
<AboutLink>About</AboutLink>
|
|
187
|
+
|
|
188
|
+
// Access nested nodes
|
|
189
|
+
const SettingsLink = Links.AT(urlsTree.profile.settings);
|
|
190
|
+
<SettingsLink>Settings</SettingsLink>
|
|
191
|
+
|
|
192
|
+
// Access parameterized nodes
|
|
193
|
+
const UserLink = Links.AT(urlsTree.profile[':userId']);
|
|
194
|
+
<UserLink params={{ userId: '42' }}>User</UserLink>
|
|
195
|
+
|
|
196
|
+
// The returned node preserves its children
|
|
197
|
+
const ProfileNode = Links.AT(urlsTree.profile);
|
|
198
|
+
<ProfileNode.Settings>Settings</ProfileNode.Settings>
|
|
199
|
+
<ProfileNode.$UserId params={{ userId: '99' }}>User</ProfileNode.$UserId>
|
|
200
|
+
|
|
201
|
+
// Works the same for NavLinks
|
|
202
|
+
const AboutNavLink = NavLinks.AT(urlsTree.about);
|
|
203
|
+
<AboutNavLink>About</AboutNavLink>
|
|
204
|
+
```
|
|
205
|
+
|
|
177
206
|
---
|
|
178
207
|
|
|
179
208
|
## Navigates
|
|
@@ -212,6 +241,27 @@ The `preserve` prop saves the current `search` and `hash` when redirecting:
|
|
|
212
241
|
<Navigates.About preserve />
|
|
213
242
|
```
|
|
214
243
|
|
|
244
|
+
#### AT Method (Direct Node Access)
|
|
245
|
+
|
|
246
|
+
The `AT` method provides direct access to navigate components by node reference:
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
const { Navigates } = ReactRouterTree(urlsTree);
|
|
250
|
+
|
|
251
|
+
// Access a specific node directly
|
|
252
|
+
const AboutNav = Navigates.AT(urlsTree.about);
|
|
253
|
+
<AboutNav />
|
|
254
|
+
|
|
255
|
+
// Access nested nodes
|
|
256
|
+
const SettingsNav = Navigates.AT(urlsTree.profile.settings);
|
|
257
|
+
<SettingsNav />
|
|
258
|
+
|
|
259
|
+
// The returned node preserves its children
|
|
260
|
+
const ProfileNav = Navigates.AT(urlsTree.profile);
|
|
261
|
+
<ProfileNav.Settings />
|
|
262
|
+
<ProfileNav.$UserId params={{ userId: '42' }} />
|
|
263
|
+
```
|
|
264
|
+
|
|
215
265
|
### useNavigate Hook
|
|
216
266
|
|
|
217
267
|
A proxy-enhanced `useNavigate` hook that provides the same tree-based navigation as the components, but as callable functions.
|
|
@@ -257,6 +307,35 @@ function MyComponent() {
|
|
|
257
307
|
}
|
|
258
308
|
```
|
|
259
309
|
|
|
310
|
+
#### AT Method (Direct Node Access)
|
|
311
|
+
|
|
312
|
+
The `AT` method works with the `useNavigate` hook as well, allowing navigation by node reference:
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
function MyComponent() {
|
|
316
|
+
const nav = Navigates.useNavigate();
|
|
317
|
+
|
|
318
|
+
return (
|
|
319
|
+
<div>
|
|
320
|
+
{/* Navigate using direct node access */}
|
|
321
|
+
<button onClick={() => nav.AT(urlsTree.about)()}>
|
|
322
|
+
Go to About
|
|
323
|
+
</button>
|
|
324
|
+
|
|
325
|
+
{/* With params */}
|
|
326
|
+
<button onClick={() => nav.AT(urlsTree.profile[':userId'])({ userId: '42' })}>
|
|
327
|
+
Go to User 42
|
|
328
|
+
</button>
|
|
329
|
+
|
|
330
|
+
{/* The returned node preserves its children */}
|
|
331
|
+
<button onClick={() => nav.AT(urlsTree.profile).Settings()}>
|
|
332
|
+
Go to Profile Settings
|
|
333
|
+
</button>
|
|
334
|
+
</div>
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
260
339
|
---
|
|
261
340
|
|
|
262
341
|
## isUrl & isSubUrl
|
|
@@ -324,6 +403,29 @@ isSubUrl.Profile('/about'); // false
|
|
|
324
403
|
isSubUrl.Home('/anything'); // true
|
|
325
404
|
```
|
|
326
405
|
|
|
406
|
+
### AT Method (Direct Node Access)
|
|
407
|
+
|
|
408
|
+
Both `isUrl` and `isSubUrl` support the `AT` method for direct node access:
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
const { isUrl, isSubUrl } = ReactRouterTree(urlsTree);
|
|
412
|
+
|
|
413
|
+
// Access nodes directly
|
|
414
|
+
isUrl.AT(urlsTree.about)('/about'); // true
|
|
415
|
+
isUrl.AT(urlsTree.profile.settings)('/profile/settings'); // true
|
|
416
|
+
isUrl.AT(urlsTree.profile[':userId'])('/profile/123'); // true
|
|
417
|
+
|
|
418
|
+
// The returned function preserves children
|
|
419
|
+
const profile = isUrl.AT(urlsTree.profile);
|
|
420
|
+
profile.Settings('/profile/settings'); // true
|
|
421
|
+
profile.$UserId('/profile/123'); // true
|
|
422
|
+
profile.$UserId.Posts('/profile/42/posts'); // true
|
|
423
|
+
|
|
424
|
+
// Works the same for isSubUrl
|
|
425
|
+
isSubUrl.AT(urlsTree.profile)('/profile'); // true
|
|
426
|
+
isSubUrl.AT(urlsTree.profile)('/profile/settings'); // true
|
|
427
|
+
```
|
|
428
|
+
|
|
327
429
|
---
|
|
328
430
|
|
|
329
431
|
## RouteCreator
|
|
@@ -386,6 +488,72 @@ route2.About({ element: <AboutPage /> });
|
|
|
386
488
|
// { element: <AboutPage />, path: '/about' }
|
|
387
489
|
```
|
|
388
490
|
|
|
491
|
+
### Callback Syntax
|
|
492
|
+
|
|
493
|
+
RouteCreator supports a callback syntax for defining nested children routes. When using callbacks, **nested routes automatically use relative paths** (equivalent to `type='name'`), regardless of the parent's type setting.
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
const route = RouteCreator('name');
|
|
497
|
+
|
|
498
|
+
const profileRoute = route.Profile((RouteCreator) => ({
|
|
499
|
+
element: <ProfilePage />,
|
|
500
|
+
children: [
|
|
501
|
+
RouteCreator[':userId']((RouteCreator) => ({
|
|
502
|
+
element: <UserPage />,
|
|
503
|
+
children: [
|
|
504
|
+
RouteCreator.Posts({
|
|
505
|
+
element: <PostsPage />
|
|
506
|
+
})
|
|
507
|
+
]
|
|
508
|
+
}))
|
|
509
|
+
]
|
|
510
|
+
}));
|
|
511
|
+
|
|
512
|
+
// Produces:
|
|
513
|
+
// {
|
|
514
|
+
// path: 'profile',
|
|
515
|
+
// element: <ProfilePage />,
|
|
516
|
+
// children: [
|
|
517
|
+
// {
|
|
518
|
+
// path: ':userId',
|
|
519
|
+
// element: <UserPage />,
|
|
520
|
+
// children: [
|
|
521
|
+
// { path: 'posts', element: <PostsPage /> }
|
|
522
|
+
// ]
|
|
523
|
+
// }
|
|
524
|
+
// ]
|
|
525
|
+
// }
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
#### Mixing Types
|
|
529
|
+
|
|
530
|
+
The parent route respects the `type` parameter, but children always use relative paths:
|
|
531
|
+
|
|
532
|
+
```typescript
|
|
533
|
+
const route = RouteCreator('url');
|
|
534
|
+
|
|
535
|
+
const profileRoute = route.Profile((RouteCreator) => ({
|
|
536
|
+
element: <ProfilePage />,
|
|
537
|
+
children: [
|
|
538
|
+
RouteCreator.Settings({ element: <SettingsPage /> })
|
|
539
|
+
]
|
|
540
|
+
}));
|
|
541
|
+
|
|
542
|
+
// Produces:
|
|
543
|
+
// {
|
|
544
|
+
// path: '/profile', // Parent uses 'url' type
|
|
545
|
+
// element: <ProfilePage />,
|
|
546
|
+
// children: [
|
|
547
|
+
// {
|
|
548
|
+
// path: 'settings', // Child forced to relative path
|
|
549
|
+
// element: <SettingsPage />
|
|
550
|
+
// }
|
|
551
|
+
// ]
|
|
552
|
+
// }
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
This ensures nested routes are always valid for react-router's nested route structure.
|
|
556
|
+
|
|
389
557
|
---
|
|
390
558
|
|
|
391
559
|
## Type Definitions
|
|
@@ -5,6 +5,7 @@ export type BindProps<T extends {
|
|
|
5
5
|
to?: To;
|
|
6
6
|
}> = TS.ReplaceKeyOpt<'to', T, Partial<BindedPath>>;
|
|
7
7
|
export declare function resolveParams(url: string, params?: object): string;
|
|
8
|
+
export declare function Parts(url: string): string[];
|
|
8
9
|
export declare function BindProps<P extends string, T extends {
|
|
9
10
|
to?: To;
|
|
10
11
|
}>(pathname: P, props: {
|
package/dist/impl/is-url.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export declare function IsUrlTreeFactory<TTree extends
|
|
1
|
+
import type { UrlsTree, IsUrlTree } from '../types';
|
|
2
|
+
export declare function IsUrlTreeFactory<TTree extends UrlsTree>(urlsTree: TTree): IsUrlTree.Methods<TTree>;
|
package/dist/impl/links.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export declare function LinksFactory<TTree extends
|
|
1
|
+
import type { UrlsTree, LinksTree } from '../types';
|
|
2
|
+
export declare function LinksFactory<TTree extends UrlsTree>(urlsTree: TTree): LinksTree.Set<TTree>;
|
package/dist/impl/navigates.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export declare function NavigatesTreeFactory<TTree extends
|
|
1
|
+
import type { UrlsTree, NavigatesTree } from '../types';
|
|
2
|
+
export declare function NavigatesTreeFactory<TTree extends UrlsTree>(urlsTree: TTree): NavigatesTree<TTree>;
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,30 @@ var utilsMisc = require('@avstantso/utils-misc');
|
|
|
5
5
|
var require$$0 = require('react');
|
|
6
6
|
var reactRouterDom = require('react-router-dom');
|
|
7
7
|
|
|
8
|
+
var JS$4 = AVStantso.JS;
|
|
9
|
+
const PARAMS_REPLACE_REGEXP = /:([^/]+)($|\/)/g;
|
|
10
|
+
function resolveParams(url, params) {
|
|
11
|
+
return !params
|
|
12
|
+
? url
|
|
13
|
+
: url.replace(PARAMS_REPLACE_REGEXP, (m, g, trail) => {
|
|
14
|
+
return `${g in params ? `${params[g]}` : `:${g}`}${trail}`;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function Parts(url) {
|
|
18
|
+
return url.split('/').pack();
|
|
19
|
+
}
|
|
20
|
+
function BindProps(pathname, props, params) {
|
|
21
|
+
const { to: outerTo, ...rest } = props;
|
|
22
|
+
const pn = resolveParams(pathname, params);
|
|
23
|
+
const to = !outerTo || JS$4.is.string(outerTo)
|
|
24
|
+
? pn
|
|
25
|
+
: {
|
|
26
|
+
...outerTo,
|
|
27
|
+
pathname: pn
|
|
28
|
+
};
|
|
29
|
+
return Object.assign(rest, { to });
|
|
30
|
+
}
|
|
31
|
+
|
|
8
32
|
var JS$3 = AVStantso.JS;
|
|
9
33
|
var Func = AVStantso.Func;
|
|
10
34
|
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type */
|
|
@@ -38,10 +62,19 @@ function recursiveCreateCmpByRoute(node, options, level = 0) {
|
|
|
38
62
|
function TreeFactory(urlsTree, options) {
|
|
39
63
|
return recursiveCreateCmpByRoute(urlsTree, options);
|
|
40
64
|
}
|
|
65
|
+
function TreeAT(tree, node) {
|
|
66
|
+
let current = tree;
|
|
67
|
+
for (const part of Parts(node._url))
|
|
68
|
+
current = current[part.startsWith(':')
|
|
69
|
+
? PP$Camel.paramProcessor(part)
|
|
70
|
+
: utilsMisc.Cases.pascal(part)];
|
|
71
|
+
return current;
|
|
72
|
+
}
|
|
41
73
|
|
|
42
74
|
var JS$2 = AVStantso.JS;
|
|
43
75
|
function CheckUrlFactory(urlsTree, callback) {
|
|
44
|
-
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
77
|
+
const tree = TreeFactory(urlsTree, {
|
|
45
78
|
nodeFactory: (node) => (pathnameOrLocation, params) => {
|
|
46
79
|
const pathname = JS$2.is.string(pathnameOrLocation)
|
|
47
80
|
? pathnameOrLocation
|
|
@@ -50,9 +83,8 @@ function CheckUrlFactory(urlsTree, callback) {
|
|
|
50
83
|
},
|
|
51
84
|
...PP$Camel
|
|
52
85
|
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return url.split('/').pack();
|
|
86
|
+
tree.AT = (node) => TreeAT(tree, node);
|
|
87
|
+
return tree;
|
|
56
88
|
}
|
|
57
89
|
function DoIsUrl(strictMatch) {
|
|
58
90
|
return (node, pathname, params) => {
|
|
@@ -1449,29 +1481,9 @@ function requireJsxRuntime () {
|
|
|
1449
1481
|
|
|
1450
1482
|
var jsxRuntimeExports = requireJsxRuntime();
|
|
1451
1483
|
|
|
1452
|
-
var JS$1 = AVStantso.JS;
|
|
1453
|
-
const PARAMS_REPLACE_REGEXP = /:([^/]+)($|\/)/g;
|
|
1454
|
-
function resolveParams(url, params) {
|
|
1455
|
-
return !params
|
|
1456
|
-
? url
|
|
1457
|
-
: url.replace(PARAMS_REPLACE_REGEXP, (m, g, trail) => {
|
|
1458
|
-
return `${g in params ? `${params[g]}` : `:${g}`}${trail}`;
|
|
1459
|
-
});
|
|
1460
|
-
}
|
|
1461
|
-
function BindProps(pathname, props, params) {
|
|
1462
|
-
const { to: outerTo, ...rest } = props;
|
|
1463
|
-
const pn = resolveParams(pathname, params);
|
|
1464
|
-
const to = !outerTo || JS$1.is.string(outerTo)
|
|
1465
|
-
? pn
|
|
1466
|
-
: {
|
|
1467
|
-
...outerTo,
|
|
1468
|
-
pathname: pn
|
|
1469
|
-
};
|
|
1470
|
-
return Object.assign(rest, { to });
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
1484
|
function LinksKindFactory(urlsTree, Component) {
|
|
1474
|
-
|
|
1485
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1486
|
+
const tree = TreeFactory(urlsTree, {
|
|
1475
1487
|
nodeFactory(node) {
|
|
1476
1488
|
const id = utilsMisc.HTMLUtils.str2ValidId(node._path);
|
|
1477
1489
|
return Object.assign(function BindedLink({ id: outerId, params, ...rest }) {
|
|
@@ -1480,6 +1492,8 @@ function LinksKindFactory(urlsTree, Component) {
|
|
|
1480
1492
|
},
|
|
1481
1493
|
...PP$Camel
|
|
1482
1494
|
});
|
|
1495
|
+
tree.AT = (node) => TreeAT(tree, node);
|
|
1496
|
+
return tree;
|
|
1483
1497
|
}
|
|
1484
1498
|
function LinksFactory(urlsTree) {
|
|
1485
1499
|
return {
|
|
@@ -1488,9 +1502,10 @@ function LinksFactory(urlsTree) {
|
|
|
1488
1502
|
};
|
|
1489
1503
|
}
|
|
1490
1504
|
|
|
1491
|
-
var JS = AVStantso.JS;
|
|
1505
|
+
var JS$1 = AVStantso.JS;
|
|
1492
1506
|
function NavigatesTreeFactory(urlsTree) {
|
|
1493
|
-
|
|
1507
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1508
|
+
const componentTree = TreeFactory(urlsTree, {
|
|
1494
1509
|
nodeFactory(node) {
|
|
1495
1510
|
/**
|
|
1496
1511
|
* @avstantso: Reimplementation `Navigate` with `preserve`
|
|
@@ -1511,18 +1526,25 @@ function NavigatesTreeFactory(urlsTree) {
|
|
|
1511
1526
|
return BindedNavigates;
|
|
1512
1527
|
},
|
|
1513
1528
|
...PP$Camel
|
|
1514
|
-
})
|
|
1529
|
+
});
|
|
1530
|
+
componentTree.AT = (node) => TreeAT(componentTree, node);
|
|
1531
|
+
return Object.assign(componentTree, {
|
|
1515
1532
|
useNavigate() {
|
|
1516
1533
|
const navigate = reactRouterDom.useNavigate();
|
|
1517
1534
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1518
1535
|
function createNavProxy(node, hasParams) {
|
|
1519
1536
|
return new Proxy(navigate, {
|
|
1520
1537
|
get(target, p) {
|
|
1538
|
+
if ('AT' === p)
|
|
1539
|
+
return (atNode) => {
|
|
1540
|
+
const hp = atNode._url.split('/').some((s) => s.startsWith(':'));
|
|
1541
|
+
return createNavProxy(atNode, hp);
|
|
1542
|
+
};
|
|
1521
1543
|
const r = Reflect.get(target, p);
|
|
1522
1544
|
if (undefined !== r)
|
|
1523
1545
|
return r;
|
|
1524
1546
|
for (const [k, v] of Object.entries(node))
|
|
1525
|
-
if (JS.is.structure(v)) {
|
|
1547
|
+
if (JS$1.is.structure(v)) {
|
|
1526
1548
|
const hp = k.startsWith(':');
|
|
1527
1549
|
if (hp
|
|
1528
1550
|
? PP$Camel.paramProcessor(k) === p
|
|
@@ -1537,13 +1559,13 @@ function NavigatesTreeFactory(urlsTree) {
|
|
|
1537
1559
|
const i = hasParams ? 1 : 0;
|
|
1538
1560
|
const params = argArray[i - 1];
|
|
1539
1561
|
const pathname = resolveParams(node._url, params);
|
|
1540
|
-
const hasTo = JS.switch(argArray[i], {
|
|
1562
|
+
const hasTo = JS$1.switch(argArray[i], {
|
|
1541
1563
|
string: true,
|
|
1542
1564
|
object: (o) => 'search' in o || 'hash' in o
|
|
1543
1565
|
});
|
|
1544
1566
|
return Reflect.apply(target, thisArg, hasTo
|
|
1545
1567
|
? [
|
|
1546
|
-
JS.is.object(argArray[i]) ? { ...argArray[i], pathname } : pathname,
|
|
1568
|
+
JS$1.is.object(argArray[i]) ? { ...argArray[i], pathname } : pathname,
|
|
1547
1569
|
argArray[i + 1]
|
|
1548
1570
|
]
|
|
1549
1571
|
: [
|
|
@@ -1558,12 +1580,34 @@ function NavigatesTreeFactory(urlsTree) {
|
|
|
1558
1580
|
});
|
|
1559
1581
|
}
|
|
1560
1582
|
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1583
|
+
var JS = AVStantso.JS;
|
|
1584
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1585
|
+
const RouteCreatorFactory = (urlsTree) => (type, commonProps) => {
|
|
1586
|
+
const nestedTreeCache = new WeakMap();
|
|
1587
|
+
const MetaFactory = (useCache, nodeField = type) => (rootNode) => {
|
|
1588
|
+
if (useCache) {
|
|
1589
|
+
const cached = nestedTreeCache.get(rootNode);
|
|
1590
|
+
if (cached)
|
|
1591
|
+
return cached;
|
|
1592
|
+
}
|
|
1593
|
+
const tree = TreeFactory(rootNode, {
|
|
1594
|
+
nodeFactory: (node) => {
|
|
1595
|
+
const RouteCreate = (param) => ({
|
|
1596
|
+
...commonProps,
|
|
1597
|
+
...(JS.is.function(param) ? param(createNestedTree(node)) : param),
|
|
1598
|
+
path: node[`_${nodeField}`]
|
|
1599
|
+
});
|
|
1600
|
+
return RouteCreate;
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
if (useCache)
|
|
1604
|
+
nestedTreeCache.set(rootNode, tree);
|
|
1605
|
+
return tree;
|
|
1606
|
+
};
|
|
1607
|
+
const createNestedTree = MetaFactory(true, 'name');
|
|
1608
|
+
const treeFactory = MetaFactory();
|
|
1609
|
+
return treeFactory(urlsTree);
|
|
1610
|
+
};
|
|
1567
1611
|
|
|
1568
1612
|
function ReactRouterTree(urlsTree) {
|
|
1569
1613
|
return {
|