@vaadin/hilla-file-router 24.4.0-alpha21 → 24.4.0-alpha22

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.
Files changed (44) hide show
  1. package/package.json +3 -3
  2. package/runtime/RouterConfigurationBuilder.d.ts +14 -4
  3. package/runtime/RouterConfigurationBuilder.d.ts.map +1 -1
  4. package/runtime/RouterConfigurationBuilder.js +86 -55
  5. package/runtime/RouterConfigurationBuilder.js.map +2 -2
  6. package/runtime/createMenuItems.d.ts +3 -1
  7. package/runtime/createMenuItems.d.ts.map +1 -1
  8. package/runtime/createMenuItems.js +7 -2
  9. package/runtime/createMenuItems.js.map +2 -2
  10. package/runtime.d.ts +0 -1
  11. package/runtime.d.ts.map +1 -1
  12. package/runtime.js +0 -1
  13. package/runtime.js.map +2 -2
  14. package/shared/convertComponentNameToTitle.d.ts +1 -1
  15. package/shared/convertComponentNameToTitle.d.ts.map +1 -1
  16. package/shared/convertComponentNameToTitle.js +4 -7
  17. package/shared/convertComponentNameToTitle.js.map +2 -2
  18. package/shared/transformTree.d.ts +1 -11
  19. package/shared/transformTree.d.ts.map +1 -1
  20. package/shared/transformTree.js +3 -15
  21. package/shared/transformTree.js.map +2 -2
  22. package/types.d.ts +3 -3
  23. package/vite-plugin/collectRoutesFromFS.d.ts +3 -3
  24. package/vite-plugin/collectRoutesFromFS.d.ts.map +1 -1
  25. package/vite-plugin/collectRoutesFromFS.js +46 -34
  26. package/vite-plugin/collectRoutesFromFS.js.map +2 -2
  27. package/vite-plugin/createRoutesFromMeta.d.ts +1 -1
  28. package/vite-plugin/createRoutesFromMeta.d.ts.map +1 -1
  29. package/vite-plugin/createRoutesFromMeta.js +30 -25
  30. package/vite-plugin/createRoutesFromMeta.js.map +2 -2
  31. package/vite-plugin/createViewConfigJson.d.ts +1 -1
  32. package/vite-plugin/createViewConfigJson.d.ts.map +1 -1
  33. package/vite-plugin/createViewConfigJson.js +51 -38
  34. package/vite-plugin/createViewConfigJson.js.map +2 -2
  35. package/vite-plugin/generateRuntimeFiles.d.ts.map +1 -1
  36. package/vite-plugin/generateRuntimeFiles.js +0 -5
  37. package/vite-plugin/generateRuntimeFiles.js.map +2 -2
  38. package/vite-plugin.d.ts.map +1 -1
  39. package/vite-plugin.js +17 -6
  40. package/vite-plugin.js.map +2 -2
  41. package/runtime/toReactRouter.d.ts +0 -11
  42. package/runtime/toReactRouter.d.ts.map +0 -1
  43. package/runtime/toReactRouter.js +0 -31
  44. package/runtime/toReactRouter.js.map +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/hilla-file-router",
3
- "version": "24.4.0-alpha21",
3
+ "version": "24.4.0-alpha22",
4
4
  "description": "Hilla file-based router",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -80,8 +80,8 @@
80
80
  "type-fest": "^4.9.0"
81
81
  },
82
82
  "dependencies": {
83
- "@vaadin/hilla-generator-utils": "24.4.0-alpha21",
84
- "@vaadin/hilla-react-auth": "24.4.0-alpha21",
83
+ "@vaadin/hilla-generator-utils": "24.4.0-alpha22",
84
+ "@vaadin/hilla-react-auth": "24.4.0-alpha22",
85
85
  "react": "^18.2.0",
86
86
  "rollup": "^4.12.0",
87
87
  "typescript": "5.3.2"
@@ -1,6 +1,11 @@
1
1
  import { type ComponentType } from 'react';
2
2
  import { type RouteObject } from 'react-router-dom';
3
- import type { AgnosticRoute, RouterConfiguration } from '../types.js';
3
+ import type { AgnosticRoute, RouterConfiguration, ViewConfig } from '../types.js';
4
+ interface RouteBase {
5
+ path?: string;
6
+ children?: readonly this[];
7
+ }
8
+ type RouteTransformer<T> = (original: RouteObject | undefined, overriding: T | undefined, children?: readonly RouteObject[]) => RouteObject;
4
9
  /**
5
10
  * A builder for creating a Vaadin-specific router for React with
6
11
  * authentication and server routes support.
@@ -13,7 +18,7 @@ export declare class RouterConfigurationBuilder {
13
18
  *
14
19
  * @param routes - A list of routes to add to the current list.
15
20
  */
16
- withReactRoutes(...routes: readonly RouteObject[]): this;
21
+ withReactRoutes(routes: readonly RouteObject[]): this;
17
22
  /**
18
23
  * Adds the given file routes to the current list of routes. All the routes
19
24
  * are transformed to React RouterObjects and deeply merged to preserve the
@@ -21,15 +26,17 @@ export declare class RouterConfigurationBuilder {
21
26
  *
22
27
  * @param routes - A list of routes to add to the current list.
23
28
  */
24
- withFileRoutes(...routes: readonly AgnosticRoute[]): this;
29
+ withFileRoutes(routes: readonly AgnosticRoute[]): this;
25
30
  /**
26
31
  * Adds the given server route element to each branch of the current list of
27
32
  * routes.
28
33
  *
29
34
  * @param component - The React component to add to each branch of the
30
35
  * current list of routes.
36
+ * @param config - An optional configuration that will be applied to
37
+ * each fallback component.
31
38
  */
32
- withFallback(component: ComponentType): this;
39
+ withFallback(component: ComponentType, config?: ViewConfig): this;
33
40
  /**
34
41
  * Protects all the routes that require authentication. For more details see
35
42
  * {@link @vaadin/hilla-react-auth#protectRoutes} function.
@@ -38,9 +45,12 @@ export declare class RouterConfigurationBuilder {
38
45
  * and the user is not authenticated.
39
46
  */
40
47
  protect(redirectPath?: string): this;
48
+ update<T extends RouteBase>(routes: undefined, callback: RouteTransformer<undefined>): this;
49
+ update<T extends RouteBase>(routes: readonly T[], callback?: RouteTransformer<T>): this;
41
50
  /**
42
51
  * Builds the router with the current list of routes.
43
52
  */
44
53
  build(): RouterConfiguration;
45
54
  }
55
+ export {};
46
56
  //# sourceMappingURL=RouterConfigurationBuilder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RouterConfigurationBuilder.d.ts","sourceRoot":"","sources":["../src/runtime/RouterConfigurationBuilder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAAoC,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AA4BtE;;;GAGG;AACH,qBAAa,0BAA0B;;IAIrC;;;;;OAKG;IACH,eAAe,CAAC,GAAG,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,IAAI;IAYxD;;;;;;OAMG;IACH,cAAc,CAAC,GAAG,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI;IAazD;;;;;;OAMG;IACH,YAAY,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI;IA2B5C;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAKpC;;OAEG;IACH,KAAK,IAAI,mBAAmB;CAS7B"}
1
+ {"version":3,"file":"RouterConfigurationBuilder.d.ts","sourceRoot":"","sources":["../src/runtime/RouterConfigurationBuilder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGzE,OAAO,KAAK,EAAE,aAAa,EAAuB,mBAAmB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEvG,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;CAC5B;AAQD,KAAK,gBAAgB,CAAC,CAAC,IAAI,CACzB,QAAQ,EAAE,WAAW,GAAG,SAAS,EACjC,UAAU,EAAE,CAAC,GAAG,SAAS,EACzB,QAAQ,CAAC,EAAE,SAAS,WAAW,EAAE,KAC9B,WAAW,CAAC;AAEjB;;;GAGG;AACH,qBAAa,0BAA0B;;IAGrC;;;;;OAKG;IACH,eAAe,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,IAAI;IAIrD;;;;;;OAMG;IACH,cAAc,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI;IA0BtD;;;;;;;;OAQG;IACH,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI;IAuBjE;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAUpC,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,SAAS,CAAC,GAAG,IAAI;IAC3F,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,IAAI;IAkDvF;;OAEG;IACH,KAAK,IAAI,mBAAmB;CAS7B"}
@@ -1,40 +1,21 @@
1
- import { protectRoutes } from "@vaadin/hilla-react-auth";
1
+ import { protectRoute } from "@vaadin/hilla-react-auth";
2
2
  import { createElement } from "react";
3
3
  import { createBrowserRouter } from "react-router-dom";
4
- import { transformTreeSync } from "../shared/transformTree.js";
5
- import { toReactRouter } from "./toReactRouter.js";
6
- function mergeRoutes(a, b) {
7
- return b.reduce(
8
- (result, route) => {
9
- const existingRoute = result.find((r) => r.path === route.path);
10
- if (existingRoute) {
11
- Object.assign(existingRoute, route);
12
- existingRoute.children = existingRoute.children ? mergeRoutes(existingRoute.children, route.children ?? []) : route.children;
13
- } else {
14
- result.push(route);
15
- }
16
- return result;
17
- },
18
- [...a]
19
- );
4
+ import { convertComponentNameToTitle } from "../shared/convertComponentNameToTitle.js";
5
+ import { transformTree } from "../shared/transformTree.js";
6
+ function isReactRouteModule(module) {
7
+ return module ? "default" in module && typeof module.default === "function" : true;
20
8
  }
21
9
  class RouterConfigurationBuilder {
22
- #initializers = [];
23
- #finalizers = [];
10
+ #modifiers = [];
24
11
  /**
25
12
  * Adds the given routes to the current list of routes. All the routes are
26
13
  * deeply merged to preserve the path uniqueness.
27
14
  *
28
15
  * @param routes - A list of routes to add to the current list.
29
16
  */
30
- withReactRoutes(...routes) {
31
- this.#initializers.push((existingRoutes) => {
32
- if (!existingRoutes.length) {
33
- return routes;
34
- }
35
- return mergeRoutes(existingRoutes, routes);
36
- });
37
- return this;
17
+ withReactRoutes(routes) {
18
+ return this.update(routes);
38
19
  }
39
20
  /**
40
21
  * Adds the given file routes to the current list of routes. All the routes
@@ -43,15 +24,27 @@ class RouterConfigurationBuilder {
43
24
  *
44
25
  * @param routes - A list of routes to add to the current list.
45
26
  */
46
- withFileRoutes(...routes) {
47
- this.#initializers.push((existingRoutes) => {
48
- const reactRoutes = routes.map(toReactRouter);
49
- if (!existingRoutes.length) {
50
- return reactRoutes;
27
+ withFileRoutes(routes) {
28
+ return this.update(routes, (original, added, children) => {
29
+ if (added) {
30
+ const { module, path } = added;
31
+ if (!isReactRouteModule(module)) {
32
+ throw new Error(`The module for the "${path}" section doesn't have the React component exported by default`);
33
+ }
34
+ const title = module?.config?.title ?? convertComponentNameToTitle(module?.default);
35
+ return {
36
+ ...original,
37
+ path: module?.config?.route ?? path,
38
+ element: module?.default ? createElement(module.default) : void 0,
39
+ children,
40
+ handle: {
41
+ ...module?.config,
42
+ title
43
+ }
44
+ };
51
45
  }
52
- return mergeRoutes(existingRoutes, reactRoutes);
46
+ return original;
53
47
  });
54
- return this;
55
48
  }
56
49
  /**
57
50
  * Adds the given server route element to each branch of the current list of
@@ -59,25 +52,22 @@ class RouterConfigurationBuilder {
59
52
  *
60
53
  * @param component - The React component to add to each branch of the
61
54
  * current list of routes.
55
+ * @param config - An optional configuration that will be applied to
56
+ * each fallback component.
62
57
  */
63
- withFallback(component) {
64
- this.#finalizers.push((existingRoutes) => {
65
- const createServerRoute = () => ({ path: "*", element: createElement(component) });
66
- const newRoutes = existingRoutes.map(
67
- (route) => transformTreeSync(
68
- route,
69
- (r) => r.children?.values(),
70
- (r, children) => children ? (
71
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
72
- {
73
- ...r,
74
- children: [...children, createServerRoute()]
75
- }
76
- ) : r
77
- )
78
- );
79
- newRoutes.push(createServerRoute());
80
- return newRoutes;
58
+ withFallback(component, config) {
59
+ const fallbackRoutes = [
60
+ { path: "*", element: createElement(component), handle: config },
61
+ { index: true, element: createElement(component), handle: config }
62
+ ];
63
+ this.update(fallbackRoutes, (original, added, children) => {
64
+ if (original) {
65
+ return children ? {
66
+ ...original,
67
+ children: [...children, ...fallbackRoutes]
68
+ } : original;
69
+ }
70
+ return added;
81
71
  });
82
72
  return this;
83
73
  }
@@ -89,15 +79,56 @@ class RouterConfigurationBuilder {
89
79
  * and the user is not authenticated.
90
80
  */
91
81
  protect(redirectPath) {
92
- this.#finalizers.push((existingRoutes) => protectRoutes(existingRoutes, redirectPath));
82
+ this.update(void 0, (route, _, children) => {
83
+ const finalRoute = protectRoute(route, redirectPath);
84
+ finalRoute.children = children;
85
+ return finalRoute;
86
+ });
87
+ return this;
88
+ }
89
+ update(routes, callback = (original, overriding, children) => ({
90
+ ...original,
91
+ ...overriding,
92
+ children
93
+ })) {
94
+ this.#modifiers.push(
95
+ (existingRoutes) => transformTree(
96
+ [existingRoutes, routes],
97
+ ([original, added], next) => {
98
+ if (original && added) {
99
+ const originalMap = new Map(original.map((route) => [route.path, route]));
100
+ const addedMap = new Map(added.map((route) => [route.path, route]));
101
+ const paths = /* @__PURE__ */ new Set([...originalMap.keys(), ...addedMap.keys()]);
102
+ for (const path of paths) {
103
+ const originalRoute = originalMap.get(path);
104
+ const addedRoute = addedMap.get(path);
105
+ let route;
106
+ if (originalRoute && addedRoute) {
107
+ route = callback(originalRoute, addedRoute, next(originalRoute.children, addedRoute.children));
108
+ } else if (originalRoute) {
109
+ route = callback(originalRoute, void 0, next(originalRoute.children, void 0));
110
+ } else {
111
+ route = callback(void 0, addedRoute, next(void 0, addedRoute.children));
112
+ }
113
+ originalMap.set(path, route);
114
+ }
115
+ return [...originalMap.values()];
116
+ } else if (original) {
117
+ return original.map((route) => callback(route, void 0, next(route.children, void 0)));
118
+ } else if (added) {
119
+ return added.map((route) => callback(void 0, route, next(void 0, route.children)));
120
+ }
121
+ return void 0;
122
+ }
123
+ )
124
+ );
93
125
  return this;
94
126
  }
95
127
  /**
96
128
  * Builds the router with the current list of routes.
97
129
  */
98
130
  build() {
99
- let routes = this.#initializers.reduce((acc, callback) => callback(acc), []);
100
- routes = this.#finalizers.reduce((acc, callback) => callback(acc), routes);
131
+ const routes = this.#modifiers.reduce((acc, mod) => mod(acc) ?? acc, void 0) ?? [];
101
132
  return {
102
133
  routes,
103
134
  router: createBrowserRouter([...routes])
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/runtime/RouterConfigurationBuilder.ts"],
4
- "sourcesContent": ["import { protectRoutes, type RouteObjectWithAuth } from '@vaadin/hilla-react-auth';\nimport { type ComponentType, createElement, type ReactElement } from 'react';\nimport { createBrowserRouter, type RouteObject } from 'react-router-dom';\nimport { transformTreeSync } from '../shared/transformTree.js';\nimport type { AgnosticRoute, RouterConfiguration } from '../types.js';\nimport { toReactRouter } from './toReactRouter.js';\n\n/**\n * Deeply merges two lists of routes. If the specific path is already present,\n * the route is merged, otherwise the new routes are added to the list.\n *\n * @param a - The first list of routes.\n * @param b - The second list of routes.\n */\nfunction mergeRoutes(a: readonly RouteObject[], b: readonly RouteObject[]): RouteObject[] {\n return b.reduce(\n (result, route) => {\n const existingRoute = result.find((r) => r.path === route.path);\n if (existingRoute) {\n Object.assign(existingRoute, route);\n existingRoute.children = existingRoute.children\n ? mergeRoutes(existingRoute.children, route.children ?? [])\n : route.children;\n } else {\n result.push(route);\n }\n return result;\n },\n [...a],\n );\n}\n\n/**\n * A builder for creating a Vaadin-specific router for React with\n * authentication and server routes support.\n */\nexport class RouterConfigurationBuilder {\n readonly #initializers: Array<(routes: readonly RouteObject[]) => readonly RouteObject[]> = [];\n readonly #finalizers: Array<(routes: readonly RouteObject[]) => readonly RouteObject[]> = [];\n\n /**\n * Adds the given routes to the current list of routes. All the routes are\n * deeply merged to preserve the path uniqueness.\n *\n * @param routes - A list of routes to add to the current list.\n */\n withReactRoutes(...routes: readonly RouteObject[]): this {\n this.#initializers.push((existingRoutes) => {\n if (!existingRoutes.length) {\n return routes;\n }\n\n return mergeRoutes(existingRoutes, routes);\n });\n\n return this;\n }\n\n /**\n * Adds the given file routes to the current list of routes. All the routes\n * are transformed to React RouterObjects and deeply merged to preserve the\n * path uniqueness.\n *\n * @param routes - A list of routes to add to the current list.\n */\n withFileRoutes(...routes: readonly AgnosticRoute[]): this {\n this.#initializers.push((existingRoutes) => {\n const reactRoutes = routes.map(toReactRouter);\n\n if (!existingRoutes.length) {\n return reactRoutes;\n }\n\n return mergeRoutes(existingRoutes, reactRoutes);\n });\n return this;\n }\n\n /**\n * Adds the given server route element to each branch of the current list of\n * routes.\n *\n * @param component - The React component to add to each branch of the\n * current list of routes.\n */\n withFallback(component: ComponentType): this {\n this.#finalizers.push((existingRoutes) => {\n const createServerRoute = () => ({ path: '*', element: createElement(component) });\n\n const newRoutes = existingRoutes.map((route) =>\n transformTreeSync<RouteObject, RouteObject>(\n route,\n (r) => r.children?.values(),\n (r, children) =>\n children\n ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n ({\n ...r,\n children: [...children, createServerRoute()],\n } as RouteObject)\n : r,\n ),\n );\n\n newRoutes.push(createServerRoute());\n\n return newRoutes;\n });\n\n return this;\n }\n\n /**\n * Protects all the routes that require authentication. For more details see\n * {@link @vaadin/hilla-react-auth#protectRoutes} function.\n *\n * @param redirectPath - the path to redirect to if the route is protected\n * and the user is not authenticated.\n */\n protect(redirectPath?: string): this {\n this.#finalizers.push((existingRoutes) => protectRoutes(existingRoutes as RouteObjectWithAuth[], redirectPath));\n return this;\n }\n\n /**\n * Builds the router with the current list of routes.\n */\n build(): RouterConfiguration {\n let routes = this.#initializers.reduce<readonly RouteObject[]>((acc, callback) => callback(acc), []);\n routes = this.#finalizers.reduce<readonly RouteObject[]>((acc, callback) => callback(acc), routes);\n\n return {\n routes,\n router: createBrowserRouter([...routes]),\n };\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,qBAA+C;AACxD,SAA6B,qBAAwC;AACrE,SAAS,2BAA6C;AACtD,SAAS,yBAAyB;AAElC,SAAS,qBAAqB;AAS9B,SAAS,YAAY,GAA2B,GAA0C;AACxF,SAAO,EAAE;AAAA,IACP,CAAC,QAAQ,UAAU;AACjB,YAAM,gBAAgB,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IAAI;AAC9D,UAAI,eAAe;AACjB,eAAO,OAAO,eAAe,KAAK;AAClC,sBAAc,WAAW,cAAc,WACnC,YAAY,cAAc,UAAU,MAAM,YAAY,CAAC,CAAC,IACxD,MAAM;AAAA,MACZ,OAAO;AACL,eAAO,KAAK,KAAK;AAAA,MACnB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,GAAG,CAAC;AAAA,EACP;AACF;AAMO,MAAM,2BAA2B;AAAA,EAC7B,gBAAmF,CAAC;AAAA,EACpF,cAAiF,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ3F,mBAAmB,QAAsC;AACvD,SAAK,cAAc,KAAK,CAAC,mBAAmB;AAC1C,UAAI,CAAC,eAAe,QAAQ;AAC1B,eAAO;AAAA,MACT;AAEA,aAAO,YAAY,gBAAgB,MAAM;AAAA,IAC3C,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,kBAAkB,QAAwC;AACxD,SAAK,cAAc,KAAK,CAAC,mBAAmB;AAC1C,YAAM,cAAc,OAAO,IAAI,aAAa;AAE5C,UAAI,CAAC,eAAe,QAAQ;AAC1B,eAAO;AAAA,MACT;AAEA,aAAO,YAAY,gBAAgB,WAAW;AAAA,IAChD,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAa,WAAgC;AAC3C,SAAK,YAAY,KAAK,CAAC,mBAAmB;AACxC,YAAM,oBAAoB,OAAO,EAAE,MAAM,KAAK,SAAS,cAAc,SAAS,EAAE;AAEhF,YAAM,YAAY,eAAe;AAAA,QAAI,CAAC,UACpC;AAAA,UACE;AAAA,UACA,CAAC,MAAM,EAAE,UAAU,OAAO;AAAA,UAC1B,CAAC,GAAG,aACF;AAAA;AAAA,YAEK;AAAA,cACC,GAAG;AAAA,cACH,UAAU,CAAC,GAAG,UAAU,kBAAkB,CAAC;AAAA,YAC7C;AAAA,cACA;AAAA,QACR;AAAA,MACF;AAEA,gBAAU,KAAK,kBAAkB,CAAC;AAElC,aAAO;AAAA,IACT,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,QAAQ,cAA6B;AACnC,SAAK,YAAY,KAAK,CAAC,mBAAmB,cAAc,gBAAyC,YAAY,CAAC;AAC9G,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,QAA6B;AAC3B,QAAI,SAAS,KAAK,cAAc,OAA+B,CAAC,KAAK,aAAa,SAAS,GAAG,GAAG,CAAC,CAAC;AACnG,aAAS,KAAK,YAAY,OAA+B,CAAC,KAAK,aAAa,SAAS,GAAG,GAAG,MAAM;AAEjG,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,oBAAoB,CAAC,GAAG,MAAM,CAAC;AAAA,IACzC;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/consistent-type-assertions */\nimport { protectRoute } from '@vaadin/hilla-react-auth';\nimport { type ComponentType, createElement } from 'react';\nimport { createBrowserRouter, type RouteObject } from 'react-router-dom';\nimport { convertComponentNameToTitle } from '../shared/convertComponentNameToTitle.js';\nimport { transformTree } from '../shared/transformTree.js';\nimport type { AgnosticRoute, Module, RouteModule, RouterConfiguration, ViewConfig } from '../types.js';\n\ninterface RouteBase {\n path?: string;\n children?: readonly this[];\n}\n\ntype RoutesModifier = (routes: readonly RouteObject[] | undefined) => readonly RouteObject[] | undefined;\n\nfunction isReactRouteModule(module?: Module): module is RouteModule<ComponentType> | undefined {\n return module ? 'default' in module && typeof module.default === 'function' : true;\n}\n\ntype RouteTransformer<T> = (\n original: RouteObject | undefined,\n overriding: T | undefined,\n children?: readonly RouteObject[],\n) => RouteObject;\n\n/**\n * A builder for creating a Vaadin-specific router for React with\n * authentication and server routes support.\n */\nexport class RouterConfigurationBuilder {\n readonly #modifiers: RoutesModifier[] = [];\n\n /**\n * Adds the given routes to the current list of routes. All the routes are\n * deeply merged to preserve the path uniqueness.\n *\n * @param routes - A list of routes to add to the current list.\n */\n withReactRoutes(routes: readonly RouteObject[]): this {\n return this.update(routes);\n }\n\n /**\n * Adds the given file routes to the current list of routes. All the routes\n * are transformed to React RouterObjects and deeply merged to preserve the\n * path uniqueness.\n *\n * @param routes - A list of routes to add to the current list.\n */\n withFileRoutes(routes: readonly AgnosticRoute[]): this {\n return this.update(routes, (original, added, children) => {\n if (added) {\n const { module, path } = added;\n if (!isReactRouteModule(module)) {\n throw new Error(`The module for the \"${path}\" section doesn't have the React component exported by default`);\n }\n\n const title = module?.config?.title ?? convertComponentNameToTitle(module?.default);\n\n return {\n ...original,\n path: module?.config?.route ?? path,\n element: module?.default ? createElement(module.default) : undefined,\n children: children as RouteObject[] | undefined,\n handle: {\n ...module?.config,\n title,\n },\n } as RouteObject;\n }\n\n return original!;\n });\n }\n\n /**\n * Adds the given server route element to each branch of the current list of\n * routes.\n *\n * @param component - The React component to add to each branch of the\n * current list of routes.\n * @param config - An optional configuration that will be applied to\n * each fallback component.\n */\n withFallback(component: ComponentType, config?: ViewConfig): this {\n // Fallback adds two routes, so that the index (empty path) has a fallback too\n const fallbackRoutes = [\n { path: '*', element: createElement(component), handle: config },\n { index: true, element: createElement(component), handle: config },\n ];\n\n this.update(fallbackRoutes, (original, added, children) => {\n if (original) {\n return children\n ? ({\n ...original,\n children: [...children, ...fallbackRoutes],\n } as RouteObject)\n : original;\n }\n\n return added!;\n });\n\n return this;\n }\n\n /**\n * Protects all the routes that require authentication. For more details see\n * {@link @vaadin/hilla-react-auth#protectRoutes} function.\n *\n * @param redirectPath - the path to redirect to if the route is protected\n * and the user is not authenticated.\n */\n protect(redirectPath?: string): this {\n this.update(undefined, (route, _, children) => {\n const finalRoute = protectRoute(route!, redirectPath);\n finalRoute.children = children as RouteObject[] | undefined;\n return finalRoute;\n });\n\n return this;\n }\n\n update<T extends RouteBase>(routes: undefined, callback: RouteTransformer<undefined>): this;\n update<T extends RouteBase>(routes: readonly T[], callback?: RouteTransformer<T>): this;\n update<T extends RouteBase>(\n routes: readonly T[] | undefined,\n callback: RouteTransformer<T | undefined> = (original, overriding, children) =>\n ({\n ...original,\n ...overriding,\n children,\n }) as RouteObject,\n ): this {\n this.#modifiers.push((existingRoutes) =>\n transformTree<[readonly RouteObject[] | undefined, readonly T[] | undefined], readonly RouteObject[] | undefined>(\n [existingRoutes, routes],\n ([original, added], next) => {\n if (original && added) {\n const originalMap = new Map(original.map((route) => [route.path, route]));\n const addedMap = new Map(added.map((route) => [route.path, route]));\n\n const paths = new Set([...originalMap.keys(), ...addedMap.keys()]);\n\n for (const path of paths) {\n const originalRoute = originalMap.get(path);\n const addedRoute = addedMap.get(path);\n\n let route: RouteObject;\n if (originalRoute && addedRoute) {\n route = callback(originalRoute, addedRoute, next(originalRoute.children, addedRoute.children));\n } else if (originalRoute) {\n route = callback(originalRoute, undefined, next(originalRoute.children, undefined));\n } else {\n route = callback(undefined, addedRoute, next(undefined, addedRoute!.children));\n }\n\n originalMap.set(path, route);\n }\n\n return [...originalMap.values()];\n } else if (original) {\n return original.map((route) => callback(route, undefined, next(route.children, undefined)));\n } else if (added) {\n return added.map((route) => callback(undefined, route, next(undefined, route.children)));\n }\n\n return undefined;\n },\n ),\n );\n return this;\n }\n\n /**\n * Builds the router with the current list of routes.\n */\n build(): RouterConfiguration {\n const routes =\n this.#modifiers.reduce<readonly RouteObject[] | undefined>((acc, mod) => mod(acc) ?? acc, undefined) ?? [];\n\n return {\n routes,\n router: createBrowserRouter([...routes]),\n };\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,9 @@
1
1
  import type { MenuItem } from '../types.js';
2
2
  /**
3
3
  * Creates menu items from the views provided by the server. The views are sorted according to the
4
- * {@link ViewConfig.menu.order} and filtered out if they are explicitly excluded via {@link ViewConfig.menu.exclude}.
4
+ * {@link ViewConfig.menu.order}, filtered out if they are explicitly excluded via {@link ViewConfig.menu.exclude}.
5
+ * Note that views with no order are put below views with an order. Ties are resolved based on the path string
6
+ * comparison.
5
7
  *
6
8
  * @param vaadinObject - The Vaadin object containing the server views.
7
9
  * @returns A list of menu items.
@@ -1 +1 @@
1
- {"version":3,"file":"createMenuItems.d.ts","sourceRoot":"","sources":["../src/runtime/createMenuItems.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY;;;;cAAkC,GAAG,SAAS,QAAQ,EAAE,CAwBnG"}
1
+ {"version":3,"file":"createMenuItems.d.ts","sourceRoot":"","sources":["../src/runtime/createMenuItems.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,aAAa,CAAC;AAExD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,YAAY;;;;cAAkC,GAAG,SAAS,QAAQ,EAAE,CA6BnG"}
@@ -1,14 +1,19 @@
1
1
  import { RouteParamType } from "../shared/routeParamType.js";
2
2
  function createMenuItems(vaadinObject = window.Vaadin) {
3
+ const collator = new Intl.Collator("en-US");
3
4
  return vaadinObject?.server?.views ? Object.entries(vaadinObject.server.views).filter(
4
5
  ([_key, value]) => !value.menu?.exclude && !(value.params && Object.values(value.params).some((p) => p === RouteParamType.Required))
5
- ).sort(([_a, a], [_b, b]) => (a.menu?.order ?? 0) - (b.menu?.order ?? 0)).map(([path, config]) => {
6
+ ).map(([path, config]) => {
6
7
  const _path = config.params ? Object.keys(config.params).reduce((acc, key) => acc.replaceAll(key, ""), path) : path;
7
8
  return {
8
9
  to: _path,
9
10
  icon: config.menu?.icon,
10
- title: config.menu?.title ?? config.title
11
+ title: config.menu?.title ?? config.title,
12
+ order: config.menu?.order
11
13
  };
14
+ }).sort((menuA, menuB) => {
15
+ const ordersDiff = (menuA.order ?? Number.MAX_VALUE) - (menuB.order ?? Number.MAX_VALUE);
16
+ return ordersDiff !== 0 ? ordersDiff : collator.compare(menuA.to, menuB.to);
12
17
  }) : [];
13
18
  }
14
19
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/runtime/createMenuItems.ts"],
4
- "sourcesContent": ["import type { VaadinWindow } from '../shared/internal.js';\nimport { RouteParamType } from '../shared/routeParamType.js';\nimport type { MenuItem, ViewConfig } from '../types.js';\n\n/**\n * Creates menu items from the views provided by the server. The views are sorted according to the\n * {@link ViewConfig.menu.order} and filtered out if they are explicitly excluded via {@link ViewConfig.menu.exclude}.\n *\n * @param vaadinObject - The Vaadin object containing the server views.\n * @returns A list of menu items.\n */\nexport function createMenuItems(vaadinObject = (window as VaadinWindow).Vaadin): readonly MenuItem[] {\n return vaadinObject?.server?.views\n ? Object.entries(vaadinObject.server.views)\n // Filter out the views that are explicitly excluded from the menu.\n .filter(\n ([_key, value]) =>\n !value.menu?.exclude &&\n !(value.params && Object.values(value.params).some((p) => p === RouteParamType.Required)),\n )\n // Sort views according to the order specified in the view configuration.\n .sort(([_a, a], [_b, b]) => (a.menu?.order ?? 0) - (b.menu?.order ?? 0))\n // Map the views to menu items.\n .map(([path, config]) => {\n const _path = config.params\n ? Object.keys(config.params).reduce((acc, key) => acc.replaceAll(key, ''), path)\n : path;\n\n return {\n to: _path,\n icon: config.menu?.icon,\n title: config.menu?.title ?? config.title,\n };\n })\n : [];\n}\n"],
5
- "mappings": "AACA,SAAS,sBAAsB;AAUxB,SAAS,gBAAgB,eAAgB,OAAwB,QAA6B;AACnG,SAAO,cAAc,QAAQ,QACzB,OAAO,QAAQ,aAAa,OAAO,KAAK,EAErC;AAAA,IACC,CAAC,CAAC,MAAM,KAAK,MACX,CAAC,MAAM,MAAM,WACb,EAAE,MAAM,UAAU,OAAO,OAAO,MAAM,MAAM,EAAE,KAAK,CAAC,MAAM,MAAM,eAAe,QAAQ;AAAA,EAC3F,EAEC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,SAAS,MAAM,EAAE,MAAM,SAAS,EAAE,EAEtE,IAAI,CAAC,CAAC,MAAM,MAAM,MAAM;AACvB,UAAM,QAAQ,OAAO,SACjB,OAAO,KAAK,OAAO,MAAM,EAAE,OAAO,CAAC,KAAK,QAAQ,IAAI,WAAW,KAAK,EAAE,GAAG,IAAI,IAC7E;AAEJ,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM,OAAO,MAAM;AAAA,MACnB,OAAO,OAAO,MAAM,SAAS,OAAO;AAAA,IACtC;AAAA,EACF,CAAC,IACH,CAAC;AACP;",
4
+ "sourcesContent": ["import type { VaadinWindow } from '../shared/internal.js';\nimport { RouteParamType } from '../shared/routeParamType.js';\nimport type { MenuItem, ViewConfig } from '../types.js';\n\n/**\n * Creates menu items from the views provided by the server. The views are sorted according to the\n * {@link ViewConfig.menu.order}, filtered out if they are explicitly excluded via {@link ViewConfig.menu.exclude}.\n * Note that views with no order are put below views with an order. Ties are resolved based on the path string\n * comparison.\n *\n * @param vaadinObject - The Vaadin object containing the server views.\n * @returns A list of menu items.\n */\nexport function createMenuItems(vaadinObject = (window as VaadinWindow).Vaadin): readonly MenuItem[] {\n const collator = new Intl.Collator('en-US');\n return vaadinObject?.server?.views\n ? Object.entries(vaadinObject.server.views)\n // Filter out the views that are explicitly excluded from the menu.\n .filter(\n ([_key, value]) =>\n !value.menu?.exclude &&\n !(value.params && Object.values(value.params).some((p) => p === RouteParamType.Required)),\n )\n // Map the views to menu items.\n .map(([path, config]) => {\n const _path = config.params\n ? Object.keys(config.params).reduce((acc, key) => acc.replaceAll(key, ''), path)\n : path;\n\n return {\n to: _path,\n icon: config.menu?.icon,\n title: config.menu?.title ?? config.title,\n order: config.menu?.order,\n };\n })\n // Sort views according to the order specified in the view configuration.\n .sort((menuA, menuB) => {\n const ordersDiff = (menuA.order ?? Number.MAX_VALUE) - (menuB.order ?? Number.MAX_VALUE);\n return ordersDiff !== 0 ? ordersDiff : collator.compare(menuA.to, menuB.to);\n })\n : [];\n}\n"],
5
+ "mappings": "AACA,SAAS,sBAAsB;AAYxB,SAAS,gBAAgB,eAAgB,OAAwB,QAA6B;AACnG,QAAM,WAAW,IAAI,KAAK,SAAS,OAAO;AAC1C,SAAO,cAAc,QAAQ,QACzB,OAAO,QAAQ,aAAa,OAAO,KAAK,EAErC;AAAA,IACC,CAAC,CAAC,MAAM,KAAK,MACX,CAAC,MAAM,MAAM,WACb,EAAE,MAAM,UAAU,OAAO,OAAO,MAAM,MAAM,EAAE,KAAK,CAAC,MAAM,MAAM,eAAe,QAAQ;AAAA,EAC3F,EAEC,IAAI,CAAC,CAAC,MAAM,MAAM,MAAM;AACvB,UAAM,QAAQ,OAAO,SACjB,OAAO,KAAK,OAAO,MAAM,EAAE,OAAO,CAAC,KAAK,QAAQ,IAAI,WAAW,KAAK,EAAE,GAAG,IAAI,IAC7E;AAEJ,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,MAAM,OAAO,MAAM;AAAA,MACnB,OAAO,OAAO,MAAM,SAAS,OAAO;AAAA,MACpC,OAAO,OAAO,MAAM;AAAA,IACtB;AAAA,EACF,CAAC,EAEA,KAAK,CAAC,OAAO,UAAU;AACtB,UAAM,cAAc,MAAM,SAAS,OAAO,cAAc,MAAM,SAAS,OAAO;AAC9E,WAAO,eAAe,IAAI,aAAa,SAAS,QAAQ,MAAM,IAAI,MAAM,EAAE;AAAA,EAC5E,CAAC,IACH,CAAC;AACP;",
6
6
  "names": []
7
7
  }
package/runtime.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from './runtime/createRoute.js';
2
- export * from './runtime/toReactRouter.js';
3
2
  export * from './runtime/RouterConfigurationBuilder.js';
4
3
  export * from './runtime/useViewConfig.js';
5
4
  export * from './runtime/createMenuItems.js';
package/runtime.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["src/runtime.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yCAAyC,CAAC;AACxD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["src/runtime.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,yCAAyC,CAAC;AACxD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC"}
package/runtime.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./runtime/createRoute.js";
2
- export * from "./runtime/toReactRouter.js";
3
2
  export * from "./runtime/RouterConfigurationBuilder.js";
4
3
  export * from "./runtime/useViewConfig.js";
5
4
  export * from "./runtime/createMenuItems.js";
package/runtime.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["src/runtime.ts"],
4
- "sourcesContent": ["export * from './runtime/createRoute.js';\nexport * from './runtime/toReactRouter.js';\nexport * from './runtime/RouterConfigurationBuilder.js';\nexport * from './runtime/useViewConfig.js';\nexport * from './runtime/createMenuItems.js';\n"],
5
- "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * from './runtime/createRoute.js';\nexport * from './runtime/RouterConfigurationBuilder.js';\nexport * from './runtime/useViewConfig.js';\nexport * from './runtime/createMenuItems.js';\n"],
5
+ "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
6
  "names": []
7
7
  }
@@ -5,5 +5,5 @@
5
5
  *
6
6
  * @returns The page title.
7
7
  */
8
- export declare function convertComponentNameToTitle(component?: unknown): string | undefined;
8
+ export declare function convertComponentNameToTitle(component: unknown): string;
9
9
  //# sourceMappingURL=convertComponentNameToTitle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convertComponentNameToTitle.d.ts","sourceRoot":"","sources":["../src/shared/convertComponentNameToTitle.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAmBnF"}
1
+ {"version":3,"file":"convertComponentNameToTitle.d.ts","sourceRoot":"","sources":["../src/shared/convertComponentNameToTitle.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAetE"}
@@ -2,15 +2,12 @@ const viewPattern = /view/giu;
2
2
  const upperCaseSplitPattern = /(?=[A-Z])/gu;
3
3
  function convertComponentNameToTitle(component) {
4
4
  let name;
5
- if (typeof component === "string") {
6
- name = component;
7
- } else if (component && (typeof component === "object" || typeof component === "function") && "name" in component && typeof component.name === "string") {
5
+ if (component && (typeof component === "object" || typeof component === "function") && "name" in component && typeof component.name === "string") {
8
6
  ({ name } = component);
7
+ } else {
8
+ name = String(component);
9
9
  }
10
- if (name) {
11
- return name.replace(viewPattern, "").split(upperCaseSplitPattern).join(" ");
12
- }
13
- return void 0;
10
+ return name.replace(viewPattern, "").split(upperCaseSplitPattern).join(" ");
14
11
  }
15
12
  export {
16
13
  convertComponentNameToTitle
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/shared/convertComponentNameToTitle.ts"],
4
- "sourcesContent": ["const viewPattern = /view/giu;\nconst upperCaseSplitPattern = /(?=[A-Z])/gu;\n\n/**\n * Converts the name of the component to a page title.\n *\n * @param component - The component to convert the name from.\n *\n * @returns The page title.\n */\nexport function convertComponentNameToTitle(component?: unknown): string | undefined {\n let name: string | undefined;\n\n if (typeof component === 'string') {\n name = component;\n } else if (\n component &&\n (typeof component === 'object' || typeof component === 'function') &&\n 'name' in component &&\n typeof component.name === 'string'\n ) {\n ({ name } = component);\n }\n\n if (name) {\n return name.replace(viewPattern, '').split(upperCaseSplitPattern).join(' ');\n }\n\n return undefined;\n}\n"],
5
- "mappings": "AAAA,MAAM,cAAc;AACpB,MAAM,wBAAwB;AASvB,SAAS,4BAA4B,WAAyC;AACnF,MAAI;AAEJ,MAAI,OAAO,cAAc,UAAU;AACjC,WAAO;AAAA,EACT,WACE,cACC,OAAO,cAAc,YAAY,OAAO,cAAc,eACvD,UAAU,aACV,OAAO,UAAU,SAAS,UAC1B;AACA,KAAC,EAAE,KAAK,IAAI;AAAA,EACd;AAEA,MAAI,MAAM;AACR,WAAO,KAAK,QAAQ,aAAa,EAAE,EAAE,MAAM,qBAAqB,EAAE,KAAK,GAAG;AAAA,EAC5E;AAEA,SAAO;AACT;",
4
+ "sourcesContent": ["const viewPattern = /view/giu;\nconst upperCaseSplitPattern = /(?=[A-Z])/gu;\n\n/**\n * Converts the name of the component to a page title.\n *\n * @param component - The component to convert the name from.\n *\n * @returns The page title.\n */\nexport function convertComponentNameToTitle(component: unknown): string {\n let name: string;\n\n if (\n component &&\n (typeof component === 'object' || typeof component === 'function') &&\n 'name' in component &&\n typeof component.name === 'string'\n ) {\n ({ name } = component);\n } else {\n name = String(component);\n }\n\n return name.replace(viewPattern, '').split(upperCaseSplitPattern).join(' ');\n}\n"],
5
+ "mappings": "AAAA,MAAM,cAAc;AACpB,MAAM,wBAAwB;AASvB,SAAS,4BAA4B,WAA4B;AACtE,MAAI;AAEJ,MACE,cACC,OAAO,cAAc,YAAY,OAAO,cAAc,eACvD,UAAU,aACV,OAAO,UAAU,SAAS,UAC1B;AACA,KAAC,EAAE,KAAK,IAAI;AAAA,EACd,OAAO;AACL,WAAO,OAAO,SAAS;AAAA,EACzB;AAEA,SAAO,KAAK,QAAQ,aAAa,EAAE,EAAE,MAAM,qBAAqB,EAAE,KAAK,GAAG;AAC5E;",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,2 @@
1
- /**
2
- * Transforms the whole route tree into a new format.
3
- *
4
- * @param node - The route to transform.
5
- * @param getChildren - A function that returns the children of the route.
6
- * @param transformer - A function that transforms the route and its children.
7
- *
8
- * @returns The transformed route.
9
- */
10
- export declare function transformTreeSync<T, U>(node: T, getChildren: (node: T) => IterableIterator<T> | null | undefined, transformer: (node: T, children?: readonly U[]) => U): U;
11
- export declare function transformTree<T, U>(node: T, getChildren: (node: T) => IterableIterator<T> | null | undefined, transformer: (node: T, children?: readonly U[]) => Promise<U>): Promise<U>;
1
+ export declare function transformTree<T extends readonly unknown[], U>(nodes: T, transformer: (nodes: T, next: (...nodes: T) => U) => U): U;
12
2
  //# sourceMappingURL=transformTree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transformTree.d.ts","sourceRoot":"","sources":["../src/shared/transformTree.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,CAAC,EACpC,IAAI,EAAE,CAAC,EACP,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,EAChE,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,GACnD,CAAC,CAOH;AAED,wBAAsB,aAAa,CAAC,CAAC,EAAE,CAAC,EACtC,IAAI,EAAE,CAAC,EACP,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,EAChE,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GAC5D,OAAO,CAAC,CAAC,CAAC,CASZ"}
1
+ {"version":3,"file":"transformTree.d.ts","sourceRoot":"","sources":["../src/shared/transformTree.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,CAAC,SAAS,SAAS,OAAO,EAAE,EAAE,CAAC,EAC3D,KAAK,EAAE,CAAC,EACR,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GACrD,CAAC,CAEH"}
@@ -1,19 +1,7 @@
1
- function transformTreeSync(node, getChildren, transformer) {
2
- const children = getChildren(node);
3
- return transformer(
4
- node,
5
- children ? Array.from(children, (child) => transformTreeSync(child, getChildren, transformer)) : void 0
6
- );
7
- }
8
- async function transformTree(node, getChildren, transformer) {
9
- const children = getChildren(node);
10
- return transformer(
11
- node,
12
- children ? await Promise.all(Array.from(children, async (child) => transformTree(child, getChildren, transformer))) : void 0
13
- );
1
+ function transformTree(nodes, transformer) {
2
+ return transformer(nodes, (...n) => transformTree(n, transformer));
14
3
  }
15
4
  export {
16
- transformTree,
17
- transformTreeSync
5
+ transformTree
18
6
  };
19
7
  //# sourceMappingURL=transformTree.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/shared/transformTree.ts"],
4
- "sourcesContent": ["/**\n * Transforms the whole route tree into a new format.\n *\n * @param node - The route to transform.\n * @param getChildren - A function that returns the children of the route.\n * @param transformer - A function that transforms the route and its children.\n *\n * @returns The transformed route.\n */\nexport function transformTreeSync<T, U>(\n node: T,\n getChildren: (node: T) => IterableIterator<T> | null | undefined,\n transformer: (node: T, children?: readonly U[]) => U,\n): U {\n const children = getChildren(node);\n\n return transformer(\n node,\n children ? Array.from(children, (child) => transformTreeSync(child, getChildren, transformer)) : undefined,\n );\n}\n\nexport async function transformTree<T, U>(\n node: T,\n getChildren: (node: T) => IterableIterator<T> | null | undefined,\n transformer: (node: T, children?: readonly U[]) => Promise<U>,\n): Promise<U> {\n const children = getChildren(node);\n\n return transformer(\n node,\n children\n ? await Promise.all(Array.from(children, async (child) => transformTree(child, getChildren, transformer)))\n : undefined,\n );\n}\n"],
5
- "mappings": "AASO,SAAS,kBACd,MACA,aACA,aACG;AACH,QAAM,WAAW,YAAY,IAAI;AAEjC,SAAO;AAAA,IACL;AAAA,IACA,WAAW,MAAM,KAAK,UAAU,CAAC,UAAU,kBAAkB,OAAO,aAAa,WAAW,CAAC,IAAI;AAAA,EACnG;AACF;AAEA,eAAsB,cACpB,MACA,aACA,aACY;AACZ,QAAM,WAAW,YAAY,IAAI;AAEjC,SAAO;AAAA,IACL;AAAA,IACA,WACI,MAAM,QAAQ,IAAI,MAAM,KAAK,UAAU,OAAO,UAAU,cAAc,OAAO,aAAa,WAAW,CAAC,CAAC,IACvG;AAAA,EACN;AACF;",
4
+ "sourcesContent": ["export function transformTree<T extends readonly unknown[], U>(\n nodes: T,\n transformer: (nodes: T, next: (...nodes: T) => U) => U,\n): U {\n return transformer(nodes, (...n) => transformTree(n, transformer));\n}\n"],
5
+ "mappings": "AAAO,SAAS,cACd,OACA,aACG;AACH,SAAO,YAAY,OAAO,IAAI,MAAM,cAAc,GAAG,WAAW,CAAC;AACnE;",
6
6
  "names": []
7
7
  }
package/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { createBrowserRouter } from 'react-router-dom';
1
+ import type { createBrowserRouter, RouteObject } from 'react-router-dom';
2
2
 
3
3
  export type ViewConfig = Readonly<{
4
4
  /**
@@ -70,7 +70,7 @@ export type RouteModule<C = unknown> = Module &
70
70
  export type AgnosticRoute = Readonly<{
71
71
  path: string;
72
72
  module?: Module;
73
- children?: ReadonlyArray<AgnosticRoute<T>>;
73
+ children?: readonly AgnosticRoute[];
74
74
  }>;
75
75
 
76
76
  /**
@@ -83,6 +83,6 @@ export type MenuItem = Readonly<{
83
83
  }>;
84
84
 
85
85
  export type RouterConfiguration = Readonly<{
86
- routes: readonly RouterObject[];
86
+ routes: readonly RouteObject[];
87
87
  router: ReturnType<typeof createBrowserRouter>;
88
88
  }>;
@@ -3,7 +3,7 @@ export type RouteMeta = Readonly<{
3
3
  path: string;
4
4
  file?: URL;
5
5
  layout?: URL;
6
- children?: RouteMeta[];
6
+ children?: readonly RouteMeta[];
7
7
  }>;
8
8
  /**
9
9
  * Routes collector options.
@@ -35,7 +35,7 @@ export type CollectRoutesOptions = Readonly<{
35
35
  * @param dir - The directory to collect routes from.
36
36
  * @param options - The options object.
37
37
  *
38
- * @returns The route metadata tree.
38
+ * @returns The route metadata array.
39
39
  */
40
- export default function collectRoutesFromFS(dir: URL, { extensions, logger, parent }: CollectRoutesOptions): Promise<RouteMeta>;
40
+ export default function collectRoutesFromFS(dir: URL, { extensions, logger, parent }: CollectRoutesOptions): Promise<readonly RouteMeta[]>;
41
41
  //# sourceMappingURL=collectRoutesFromFS.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collectRoutesFromFS.d.ts","sourceRoot":"","sources":["../src/vite-plugin/collectRoutesFromFS.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;CACxB,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C;;OAEG;IACH,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,GAAG,CAAC;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAoBH;;;;;;;;;;;;;GAaG;AACH,wBAA8B,mBAAmB,CAC/C,GAAG,EAAE,GAAG,EACR,EAAE,UAAU,EAAE,MAAM,EAAE,MAAY,EAAE,EAAE,oBAAoB,GACzD,OAAO,CAAC,SAAS,CAAC,CA0DpB"}
1
+ {"version":3,"file":"collectRoutesFromFS.d.ts","sourceRoot":"","sources":["../src/vite-plugin/collectRoutesFromFS.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,QAAQ,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;CACjC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C;;OAEG;IACH,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,GAAG,CAAC;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAoBH;;;;;;;;;;;;;GAaG;AACH,wBAA8B,mBAAmB,CAC/C,GAAG,EAAE,GAAG,EACR,EAAE,UAAU,EAAE,MAAM,EAAE,MAAY,EAAE,EAAE,oBAAoB,GACzD,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC,CA2E/B"}