@vaadin/hilla-file-router 24.6.0-alpha5 → 24.6.0-beta2
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/package.json +4 -4
- package/runtime/RouterConfigurationBuilder.d.ts +5 -2
- package/runtime/RouterConfigurationBuilder.d.ts.map +1 -1
- package/runtime/RouterConfigurationBuilder.js +80 -40
- package/runtime/RouterConfigurationBuilder.js.map +2 -2
- package/runtime/createMenuItems.js +1 -1
- package/runtime/createRoute.d.ts +2 -3
- package/runtime/createRoute.d.ts.map +1 -1
- package/runtime/createRoute.js +2 -3
- package/runtime/createRoute.js.map +2 -2
- package/vite-plugin/createRoutesFromMeta.d.ts.map +1 -1
- package/vite-plugin/createRoutesFromMeta.js +3 -4
- package/vite-plugin/createRoutesFromMeta.js.map +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/hilla-file-router",
|
|
3
|
-
"version": "24.6.0-
|
|
3
|
+
"version": "24.6.0-beta2",
|
|
4
4
|
"description": "Hilla file-based router",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.js",
|
|
@@ -79,9 +79,9 @@
|
|
|
79
79
|
"type-fest": "^4.9.0"
|
|
80
80
|
},
|
|
81
81
|
"dependencies": {
|
|
82
|
-
"@vaadin/hilla-generator-utils": "24.6.0-
|
|
83
|
-
"@vaadin/hilla-react-auth": "24.6.0-
|
|
84
|
-
"@vaadin/hilla-react-signals": "24.6.0-
|
|
82
|
+
"@vaadin/hilla-generator-utils": "24.6.0-beta2",
|
|
83
|
+
"@vaadin/hilla-react-auth": "24.6.0-beta2",
|
|
84
|
+
"@vaadin/hilla-react-signals": "24.6.0-beta2",
|
|
85
85
|
"react": "^18.2.0",
|
|
86
86
|
"rollup": "^4.12.0",
|
|
87
87
|
"typescript": "5.6.2"
|
|
@@ -5,7 +5,10 @@ interface RouteBase {
|
|
|
5
5
|
path?: string;
|
|
6
6
|
children?: readonly this[];
|
|
7
7
|
}
|
|
8
|
-
type
|
|
8
|
+
export type RouteList = readonly RouteObject[];
|
|
9
|
+
export type WritableRouteList = RouteObject[];
|
|
10
|
+
export type RouteTransformer<T> = (original: RouteObject | undefined, overriding: T | undefined, children?: RouteList) => RouteObject | undefined;
|
|
11
|
+
export type RouteListSplittingRule = (route: RouteObject) => boolean;
|
|
9
12
|
/**
|
|
10
13
|
* A builder for creating a Vaadin-specific router for React with
|
|
11
14
|
* authentication and server routes support.
|
|
@@ -18,7 +21,7 @@ export declare class RouterConfigurationBuilder {
|
|
|
18
21
|
*
|
|
19
22
|
* @param routes - A list of routes to add to the current list.
|
|
20
23
|
*/
|
|
21
|
-
withReactRoutes(routes:
|
|
24
|
+
withReactRoutes(routes: RouteList): this;
|
|
22
25
|
/**
|
|
23
26
|
* Adds the given file routes to the current list of routes. All the routes
|
|
24
27
|
* are transformed to React RouterObjects and deeply merged to preserve the
|
|
@@ -1 +1 @@
|
|
|
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,EAIL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;
|
|
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,EAIL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,KAAK,EACV,aAAa,EAGb,kBAAkB,EAClB,mBAAmB,EACnB,UAAU,EACX,MAAM,aAAa,CAAC;AAErB,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC;CAC5B;AAMD,MAAM,MAAM,SAAS,GAAG,SAAS,WAAW,EAAE,CAAC;AAC/C,MAAM,MAAM,iBAAiB,GAAG,WAAW,EAAE,CAAC;AAE9C,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAChC,QAAQ,EAAE,WAAW,GAAG,SAAS,EACjC,UAAU,EAAE,CAAC,GAAG,SAAS,EACzB,QAAQ,CAAC,EAAE,SAAS,KACjB,WAAW,GAAG,SAAS,CAAC;AAE7B,MAAM,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC;AA4DrE;;;GAGG;AACH,qBAAa,0BAA0B;;IAGrC;;;;;OAKG;IACH,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAIxC;;;;;;OAMG;IACH,cAAc,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,IAAI;IAqCtD;;;;;;;;OAQG;IACH,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI;IAqCjE;;;;OAIG;IACH,UAAU,CAAC,eAAe,EAAE,aAAa,GAAG,IAAI;IAgChD;;;;;;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;IAwDvF;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,mBAAmB;CAqDzD"}
|
|
@@ -14,11 +14,44 @@ function createRouteEntry(route) {
|
|
|
14
14
|
var RouteHandleFlags = /* @__PURE__ */ ((RouteHandleFlags2) => {
|
|
15
15
|
RouteHandleFlags2["FLOW_LAYOUT"] = "flowLayout";
|
|
16
16
|
RouteHandleFlags2["IGNORE_FALLBACK"] = "ignoreFallback";
|
|
17
|
+
RouteHandleFlags2["SKIP_LAYOUTS"] = "skipLayouts";
|
|
17
18
|
return RouteHandleFlags2;
|
|
18
19
|
})(RouteHandleFlags || {});
|
|
19
20
|
function hasRouteHandleFlag(route, flag) {
|
|
20
21
|
return typeof route.handle === "object" && flag in route.handle && route.handle[flag];
|
|
21
22
|
}
|
|
23
|
+
const categories = ["default", "match"];
|
|
24
|
+
function split(originalRoutes, rule) {
|
|
25
|
+
return transformTree(
|
|
26
|
+
originalRoutes,
|
|
27
|
+
(routes, next) => (
|
|
28
|
+
// Split a single routes list onto two separate lists.
|
|
29
|
+
routes.reduce(
|
|
30
|
+
(lists, route) => {
|
|
31
|
+
if (rule(route)) {
|
|
32
|
+
lists.match.push(route);
|
|
33
|
+
return lists;
|
|
34
|
+
}
|
|
35
|
+
if (!route.children?.length) {
|
|
36
|
+
lists.default.push(route);
|
|
37
|
+
return lists;
|
|
38
|
+
}
|
|
39
|
+
const childrenLists = next(...route.children);
|
|
40
|
+
for (const category of categories) {
|
|
41
|
+
if (childrenLists[category].length) {
|
|
42
|
+
lists[category].push({
|
|
43
|
+
...route,
|
|
44
|
+
children: childrenLists[category]
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return lists;
|
|
49
|
+
},
|
|
50
|
+
{ match: [], default: [] }
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
22
55
|
class RouterConfigurationBuilder {
|
|
23
56
|
#modifiers = [];
|
|
24
57
|
/**
|
|
@@ -112,57 +145,27 @@ class RouterConfigurationBuilder {
|
|
|
112
145
|
*/
|
|
113
146
|
withLayout(layoutComponent) {
|
|
114
147
|
this.#modifiers.push((originalRoutes) => {
|
|
115
|
-
if (originalRoutes
|
|
148
|
+
if (!originalRoutes) {
|
|
116
149
|
return originalRoutes;
|
|
117
150
|
}
|
|
118
|
-
const
|
|
151
|
+
const { match: serverList, default: clientList } = split(
|
|
119
152
|
originalRoutes,
|
|
120
|
-
(
|
|
121
|
-
// Split single routes list onto two filtered lists
|
|
122
|
-
routes.reduce(
|
|
123
|
-
([serverRoutesList, clientRoutesList], route) => {
|
|
124
|
-
if (hasRouteHandleFlag(route, "flowLayout" /* FLOW_LAYOUT */)) {
|
|
125
|
-
return [[...serverRoutesList ?? [], route], clientRoutesList];
|
|
126
|
-
}
|
|
127
|
-
if (!route.children?.length) {
|
|
128
|
-
return [serverRoutesList, [...clientRoutesList ?? [], route]];
|
|
129
|
-
}
|
|
130
|
-
const [serverRouteSubtree, clientRouteSubtree] = next(...route.children);
|
|
131
|
-
return [
|
|
132
|
-
serverRouteSubtree ? [
|
|
133
|
-
...serverRoutesList ?? [],
|
|
134
|
-
{
|
|
135
|
-
...route,
|
|
136
|
-
children: serverRouteSubtree
|
|
137
|
-
}
|
|
138
|
-
] : serverRoutesList,
|
|
139
|
-
clientRouteSubtree ? [
|
|
140
|
-
...clientRoutesList ?? [],
|
|
141
|
-
{
|
|
142
|
-
...route,
|
|
143
|
-
children: clientRouteSubtree
|
|
144
|
-
}
|
|
145
|
-
] : clientRoutesList
|
|
146
|
-
];
|
|
147
|
-
},
|
|
148
|
-
[void 0, void 0]
|
|
149
|
-
)
|
|
150
|
-
)
|
|
153
|
+
(route) => hasRouteHandleFlag(route, "flowLayout" /* FLOW_LAYOUT */)
|
|
151
154
|
);
|
|
152
155
|
return [
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
...serverList.length ? [
|
|
157
|
+
// The server subtree is wrapped with the server layout component,
|
|
158
|
+
// which applies the top-level server layout to all matches.
|
|
156
159
|
{
|
|
157
160
|
element: createElement(layoutComponent),
|
|
158
|
-
children:
|
|
161
|
+
children: serverList,
|
|
159
162
|
handle: {
|
|
160
163
|
["ignoreFallback" /* IGNORE_FALLBACK */]: true
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
] : [],
|
|
164
167
|
// The client route subtree is preserved without wrapping.
|
|
165
|
-
...
|
|
168
|
+
...clientList
|
|
166
169
|
];
|
|
167
170
|
});
|
|
168
171
|
return this;
|
|
@@ -212,9 +215,9 @@ class RouterConfigurationBuilder {
|
|
|
212
215
|
}
|
|
213
216
|
return [...originalMap.values()];
|
|
214
217
|
} else if (original) {
|
|
215
|
-
return original.map((route) => callback(route, void 0, next(route.children, void 0))).filter(
|
|
218
|
+
return original.map((route) => callback(route, void 0, next(route.children, void 0))).filter((r) => r != null);
|
|
216
219
|
} else if (added) {
|
|
217
|
-
return added.map((route) => callback(void 0, route, next(void 0, route.children))).filter(
|
|
220
|
+
return added.map((route) => callback(void 0, route, next(void 0, route.children))).filter((r) => r != null);
|
|
218
221
|
}
|
|
219
222
|
return void 0;
|
|
220
223
|
}
|
|
@@ -226,12 +229,49 @@ class RouterConfigurationBuilder {
|
|
|
226
229
|
* Builds the router with the current list of routes.
|
|
227
230
|
*/
|
|
228
231
|
build(options) {
|
|
232
|
+
this.#withLayoutSkipping();
|
|
229
233
|
const routes = this.#modifiers.reduce((acc, mod) => mod(acc) ?? acc, void 0) ?? [];
|
|
230
234
|
return {
|
|
231
235
|
routes,
|
|
232
236
|
router: createBrowserRouter([...routes], { basename: new URL(document.baseURI).pathname, ...options })
|
|
233
237
|
};
|
|
234
238
|
}
|
|
239
|
+
#withLayoutSkipping() {
|
|
240
|
+
this.#modifiers.push((originalRoutes) => {
|
|
241
|
+
if (!originalRoutes) {
|
|
242
|
+
return originalRoutes;
|
|
243
|
+
}
|
|
244
|
+
const { match: noLayoutList, default: layoutList } = split(
|
|
245
|
+
originalRoutes,
|
|
246
|
+
(route) => hasRouteHandleFlag(route, "skipLayouts" /* SKIP_LAYOUTS */)
|
|
247
|
+
);
|
|
248
|
+
const finalNoLayoutList = transformTree(
|
|
249
|
+
noLayoutList,
|
|
250
|
+
(routes, next) => routes.map((route) => {
|
|
251
|
+
if (hasRouteHandleFlag(route, "skipLayouts" /* SKIP_LAYOUTS */)) {
|
|
252
|
+
return route;
|
|
253
|
+
}
|
|
254
|
+
const { element, ...rest } = route;
|
|
255
|
+
return route.children?.length ? {
|
|
256
|
+
...rest,
|
|
257
|
+
children: next(...route.children)
|
|
258
|
+
} : rest;
|
|
259
|
+
})
|
|
260
|
+
);
|
|
261
|
+
return [
|
|
262
|
+
...finalNoLayoutList.length ? [
|
|
263
|
+
{
|
|
264
|
+
children: finalNoLayoutList,
|
|
265
|
+
handle: {
|
|
266
|
+
["ignoreFallback" /* IGNORE_FALLBACK */]: true
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
] : [],
|
|
270
|
+
...layoutList
|
|
271
|
+
];
|
|
272
|
+
});
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
235
275
|
}
|
|
236
276
|
export {
|
|
237
277
|
RouterConfigurationBuilder
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/runtime/RouterConfigurationBuilder.ts"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable @typescript-eslint/consistent-type-assertions */\nimport { protectRoute } from '@vaadin/hilla-react-auth';\nimport { type ComponentType, createElement } from 'react';\nimport {\n createBrowserRouter,\n type IndexRouteObject,\n type NonIndexRouteObject,\n type RouteObject,\n} from 'react-router-dom';\nimport { convertComponentNameToTitle } from '../shared/convertComponentNameToTitle.js';\nimport { transformTree } from '../shared/transformTree.js';\nimport type {\n AgnosticRoute,\n Module,\n RouteModule,\n RouterBuildOptions,\n RouterConfiguration,\n ViewConfig,\n} 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 | undefined;\n\nfunction createRouteEntry<T extends RouteBase>(route: T): readonly [key: string, value: T] {\n return [`${route.path ?? ''}-${route.children ? 'n' : 'i'}`, route];\n}\n\nenum RouteHandleFlags {\n FLOW_LAYOUT = 'flowLayout',\n IGNORE_FALLBACK = 'ignoreFallback',\n}\n\nfunction hasRouteHandleFlag<T extends RouteHandleFlags>(\n route: RouteObject,\n flag: T,\n): route is { readonly handle: Readonly<Record<T, boolean>> } {\n return typeof route.handle === 'object' && flag in route.handle && (route.handle as Record<T, boolean>)[flag];\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 #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, flowLayout } = 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 element = module?.default ? createElement(module.default) : undefined;\n const handle = {\n ...module?.config,\n title: module?.config?.title ?? convertComponentNameToTitle(module?.default),\n flowLayout: module?.config?.flowLayout ?? flowLayout,\n };\n\n if (path === '' && !children) {\n return {\n ...original,\n element,\n handle,\n index: true,\n } as IndexRouteObject;\n }\n\n return {\n ...original,\n path: module?.config?.route ?? path,\n element,\n children,\n handle,\n } as NonIndexRouteObject;\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 this.withLayout(component);\n\n // Fallback adds two routes, so that the index (empty path) has a fallback too\n const fallbackRoutes: readonly RouteObject[] = [\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 && !hasRouteHandleFlag(original, RouteHandleFlags.IGNORE_FALLBACK)) {\n if (!children) {\n return original;\n }\n\n const _fallback = [...fallbackRoutes];\n\n if (children.some(({ path }) => path === '*')) {\n _fallback.shift();\n }\n\n if (children.some(({ index: i, path }) => i ?? path?.includes('?'))) {\n _fallback.pop();\n }\n\n return {\n ...original,\n children: [...children, ..._fallback],\n } as RouteObject;\n }\n\n return added!;\n });\n\n return this;\n }\n\n /**\n * Adds the layoutComponent as the parent layout to views with the flowLayouts ViewConfiguration set.\n *\n * @param layoutComponent - layout component to use, usually Flow\n */\n withLayout(layoutComponent: ComponentType): this {\n this.#modifiers.push((originalRoutes: readonly RouteObject[] | undefined) => {\n if (originalRoutes === undefined) {\n return originalRoutes;\n }\n // Split the routes tree onto two subtrees with and without\n // a server layout.\n const [serverRoutesTree, clientRoutesTree]: [RouteObject[] | undefined, RouteObject[] | undefined] =\n transformTree<readonly RouteObject[], [RouteObject[] | undefined, RouteObject[] | undefined]>(\n originalRoutes,\n (\n routes: readonly RouteObject[],\n next: (...nodes: readonly RouteObject[]) => [RouteObject[] | undefined, RouteObject[] | undefined],\n ) =>\n // Split single routes list onto two filtered lists\n routes.reduce<[RouteObject[] | undefined, RouteObject[] | undefined]>(\n ([serverRoutesList, clientRoutesList], route) => {\n if (hasRouteHandleFlag(route, RouteHandleFlags.FLOW_LAYOUT)) {\n // Server layout is explicitly declared: move to the entire\n // route to the server list, taking also all the children.\n return [[...(serverRoutesList ?? []), route], clientRoutesList];\n }\n if (!route.children?.length) {\n // Leaf routes and empty layouts: move to the client list.\n return [serverRoutesList, [...(clientRoutesList ?? []), route]];\n }\n // Nested children: collect server and client subtrees, and\n // copy the current route to either or both the server and\n // the client lists with the respective subtree as children.\n const [serverRouteSubtree, clientRouteSubtree] = next(...route.children);\n return [\n serverRouteSubtree\n ? [\n ...(serverRoutesList ?? []),\n {\n ...route,\n children: serverRouteSubtree,\n },\n ]\n : serverRoutesList,\n clientRouteSubtree\n ? [\n ...(clientRoutesList ?? []),\n {\n ...route,\n children: clientRouteSubtree,\n },\n ]\n : clientRoutesList,\n ];\n },\n [undefined, undefined],\n ),\n );\n\n return [\n // The server subtree is wrapped with the server layout component,\n // which applies the top-level server layout to all matches.\n ...(serverRoutesTree\n ? [\n {\n element: createElement(layoutComponent),\n children: serverRoutesTree,\n handle: {\n [RouteHandleFlags.IGNORE_FALLBACK]: true,\n },\n },\n ]\n : []),\n // The client route subtree is preserved without wrapping.\n ...(clientRoutesTree ?? []),\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) => createRouteEntry(route)));\n const addedMap = new Map(added.map((route) => createRouteEntry(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 | undefined;\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 if (route) {\n originalMap.set(path, route);\n }\n }\n\n return [...originalMap.values()];\n } else if (original) {\n return original\n .map((route) => callback(route, undefined, next(route.children, undefined)))\n .filter(Boolean) as readonly RouteObject[];\n } else if (added) {\n return added\n .map((route) => callback(undefined, route, next(undefined, route.children)))\n .filter(Boolean) as readonly RouteObject[];\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(options?: RouterBuildOptions): 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], { basename: new URL(document.baseURI).pathname, ...options }),\n };\n }\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,oBAAoB;AAC7B,SAA6B,qBAAqB;AAClD;AAAA,EACE;AAAA,OAIK;
|
|
4
|
+
"sourcesContent": ["/* eslint-disable @typescript-eslint/consistent-type-assertions */\nimport { protectRoute } from '@vaadin/hilla-react-auth';\nimport { type ComponentType, createElement } from 'react';\nimport {\n createBrowserRouter,\n type IndexRouteObject,\n type NonIndexRouteObject,\n type RouteObject,\n} from 'react-router-dom';\nimport type { TupleToUnion } from 'type-fest';\nimport { convertComponentNameToTitle } from '../shared/convertComponentNameToTitle.js';\nimport { transformTree } from '../shared/transformTree.js';\nimport type {\n AgnosticRoute,\n Module,\n RouteModule,\n RouterBuildOptions,\n RouterConfiguration,\n ViewConfig,\n} from '../types.js';\n\ninterface RouteBase {\n path?: string;\n children?: readonly this[];\n}\n\nfunction isReactRouteModule(module?: Module): module is RouteModule<ComponentType> | undefined {\n return module ? 'default' in module && typeof module.default === 'function' : true;\n}\n\nexport type RouteList = readonly RouteObject[];\nexport type WritableRouteList = RouteObject[];\n\nexport type RouteTransformer<T> = (\n original: RouteObject | undefined,\n overriding: T | undefined,\n children?: RouteList,\n) => RouteObject | undefined;\n\nexport type RouteListSplittingRule = (route: RouteObject) => boolean;\n\ntype RoutesModifier = (routes: RouteList | undefined) => RouteList | undefined;\n\nfunction createRouteEntry<T extends RouteBase>(route: T): readonly [key: string, value: T] {\n return [`${route.path ?? ''}-${route.children ? 'n' : 'i'}`, route];\n}\n\nenum RouteHandleFlags {\n FLOW_LAYOUT = 'flowLayout',\n IGNORE_FALLBACK = 'ignoreFallback',\n SKIP_LAYOUTS = 'skipLayouts',\n}\n\nfunction hasRouteHandleFlag<T extends RouteHandleFlags>(route: RouteObject, flag: T): boolean {\n return typeof route.handle === 'object' && flag in route.handle && (route.handle as Record<T, boolean>)[flag];\n}\n\nconst categories = ['default', 'match'] as const;\n\ntype Category = TupleToUnion<typeof categories>;\n\nfunction split(originalRoutes: RouteList, rule: RouteListSplittingRule): Readonly<Record<Category, RouteList>> {\n return transformTree<RouteList, Readonly<Record<Category, RouteList>>>(originalRoutes, (routes, next) =>\n // Split a single routes list onto two separate lists.\n routes.reduce<Record<Category, WritableRouteList>>(\n (lists, route) => {\n if (rule(route)) {\n // If the route satisfies the rule, it goes to the first list.\n lists.match.push(route);\n return lists;\n }\n\n if (!route.children?.length) {\n // Leaf routes go to the second list.\n lists.default.push(route);\n return lists;\n }\n\n // Route children: separate them to different subtrees, and copy the\n // current route to either or both the lists with the respective\n // subtree as children.\n const childrenLists = next(...route.children);\n\n for (const category of categories) {\n if (childrenLists[category].length) {\n lists[category].push({\n ...route,\n children: childrenLists[category],\n } as RouteObject);\n }\n }\n\n return lists;\n },\n { match: [], default: [] },\n ),\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 #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: RouteList): 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, flowLayout } = 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 element = module?.default ? createElement(module.default) : undefined;\n const handle = {\n ...module?.config,\n title: module?.config?.title ?? convertComponentNameToTitle(module?.default),\n flowLayout: module?.config?.flowLayout ?? flowLayout,\n };\n\n if (path === '' && !children) {\n return {\n ...original,\n element,\n handle,\n index: true,\n } as IndexRouteObject;\n }\n\n return {\n ...original,\n path: module?.config?.route ?? path,\n element,\n children,\n handle,\n } as NonIndexRouteObject;\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 this.withLayout(component);\n\n // Fallback adds two routes, so that the index (empty path) has a fallback too\n const fallbackRoutes: RouteList = [\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 && !hasRouteHandleFlag(original, RouteHandleFlags.IGNORE_FALLBACK)) {\n if (!children) {\n return original;\n }\n\n const _fallback = [...fallbackRoutes];\n\n if (children.some(({ path }) => path === '*')) {\n _fallback.shift();\n }\n\n if (children.some(({ index: i, path }) => i ?? path?.includes('?'))) {\n _fallback.pop();\n }\n\n return {\n ...original,\n children: [...children, ..._fallback],\n } as RouteObject;\n }\n\n return added!;\n });\n\n return this;\n }\n\n /**\n * Adds the layoutComponent as the parent layout to views with the flowLayouts ViewConfiguration set.\n *\n * @param layoutComponent - layout component to use, usually Flow\n */\n withLayout(layoutComponent: ComponentType): this {\n this.#modifiers.push((originalRoutes) => {\n if (!originalRoutes) {\n return originalRoutes;\n }\n\n const { match: serverList, default: clientList } = split(originalRoutes, (route) =>\n hasRouteHandleFlag(route, RouteHandleFlags.FLOW_LAYOUT),\n );\n\n return [\n ...(serverList.length\n ? [\n // The server subtree is wrapped with the server layout component,\n // which applies the top-level server layout to all matches.\n {\n element: createElement(layoutComponent),\n children: serverList as RouteObject[],\n handle: {\n [RouteHandleFlags.IGNORE_FALLBACK]: true,\n },\n },\n ]\n : []),\n // The client route subtree is preserved without wrapping.\n ...clientList,\n ];\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<[RouteList | undefined, readonly T[] | undefined], RouteList | undefined>(\n [existingRoutes, routes],\n ([original, added], next) => {\n if (original && added) {\n const originalMap = new Map(original.map((route) => createRouteEntry(route)));\n const addedMap = new Map(added.map((route) => createRouteEntry(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 | undefined;\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 if (route) {\n originalMap.set(path, route);\n }\n }\n\n return [...originalMap.values()];\n } else if (original) {\n return original\n .map((route) => callback(route, undefined, next(route.children, undefined)))\n .filter((r) => r != null);\n } else if (added) {\n return added\n .map((route) => callback(undefined, route, next(undefined, route.children)))\n .filter((r) => r != null);\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(options?: RouterBuildOptions): RouterConfiguration {\n this.#withLayoutSkipping();\n const routes = this.#modifiers.reduce<RouteList | undefined>((acc, mod) => mod(acc) ?? acc, undefined) ?? [];\n\n return {\n routes,\n router: createBrowserRouter([...routes], { basename: new URL(document.baseURI).pathname, ...options }),\n };\n }\n\n #withLayoutSkipping(): this {\n this.#modifiers.push((originalRoutes) => {\n if (!originalRoutes) {\n return originalRoutes;\n }\n\n const { match: noLayoutList, default: layoutList } = split(originalRoutes, (route) =>\n hasRouteHandleFlag(route, RouteHandleFlags.SKIP_LAYOUTS),\n );\n\n const finalNoLayoutList = transformTree<RouteList, RouteList>(noLayoutList, (routes, next) =>\n routes.map((route) => {\n if (hasRouteHandleFlag(route, RouteHandleFlags.SKIP_LAYOUTS)) {\n return route;\n }\n\n const { element, ...rest } = route;\n return route.children?.length\n ? ({\n ...rest,\n children: next(...route.children),\n } as RouteObject)\n : rest;\n }),\n );\n\n return [\n ...(finalNoLayoutList.length\n ? [\n {\n children: finalNoLayoutList as RouteObject[],\n handle: {\n [RouteHandleFlags.IGNORE_FALLBACK]: true,\n },\n },\n ]\n : []),\n ...layoutList,\n ];\n });\n\n return this;\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,oBAAoB;AAC7B,SAA6B,qBAAqB;AAClD;AAAA,EACE;AAAA,OAIK;AAEP,SAAS,mCAAmC;AAC5C,SAAS,qBAAqB;AAe9B,SAAS,mBAAmB,QAAmE;AAC7F,SAAO,SAAS,aAAa,UAAU,OAAO,OAAO,YAAY,aAAa;AAChF;AAeA,SAAS,iBAAsC,OAA4C;AACzF,SAAO,CAAC,GAAG,MAAM,QAAQ,EAAE,IAAI,MAAM,WAAW,MAAM,GAAG,IAAI,KAAK;AACpE;AAEA,IAAK,mBAAL,kBAAKA,sBAAL;AACE,EAAAA,kBAAA,iBAAc;AACd,EAAAA,kBAAA,qBAAkB;AAClB,EAAAA,kBAAA,kBAAe;AAHZ,SAAAA;AAAA,GAAA;AAML,SAAS,mBAA+C,OAAoB,MAAkB;AAC5F,SAAO,OAAO,MAAM,WAAW,YAAY,QAAQ,MAAM,UAAW,MAAM,OAA8B,IAAI;AAC9G;AAEA,MAAM,aAAa,CAAC,WAAW,OAAO;AAItC,SAAS,MAAM,gBAA2B,MAAqE;AAC7G,SAAO;AAAA,IAAgE;AAAA,IAAgB,CAAC,QAAQ;AAAA;AAAA,MAE9F,OAAO;AAAA,QACL,CAAC,OAAO,UAAU;AAChB,cAAI,KAAK,KAAK,GAAG;AAEf,kBAAM,MAAM,KAAK,KAAK;AACtB,mBAAO;AAAA,UACT;AAEA,cAAI,CAAC,MAAM,UAAU,QAAQ;AAE3B,kBAAM,QAAQ,KAAK,KAAK;AACxB,mBAAO;AAAA,UACT;AAKA,gBAAM,gBAAgB,KAAK,GAAG,MAAM,QAAQ;AAE5C,qBAAW,YAAY,YAAY;AACjC,gBAAI,cAAc,QAAQ,EAAE,QAAQ;AAClC,oBAAM,QAAQ,EAAE,KAAK;AAAA,gBACnB,GAAG;AAAA,gBACH,UAAU,cAAc,QAAQ;AAAA,cAClC,CAAgB;AAAA,YAClB;AAAA,UACF;AAEA,iBAAO;AAAA,QACT;AAAA,QACA,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,MAC3B;AAAA;AAAA,EACF;AACF;AAMO,MAAM,2BAA2B;AAAA,EAC7B,aAA+B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQzC,gBAAgB,QAAyB;AACvC,WAAO,KAAK,OAAO,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAe,QAAwC;AACrD,WAAO,KAAK,OAAO,QAAQ,CAAC,UAAU,OAAO,aAAa;AACxD,UAAI,OAAO;AACT,cAAM,EAAE,QAAQ,MAAM,WAAW,IAAI;AACrC,YAAI,CAAC,mBAAmB,MAAM,GAAG;AAC/B,gBAAM,IAAI,MAAM,uBAAuB,IAAI,gEAAgE;AAAA,QAC7G;AAEA,cAAM,UAAU,QAAQ,UAAU,cAAc,OAAO,OAAO,IAAI;AAClE,cAAM,SAAS;AAAA,UACb,GAAG,QAAQ;AAAA,UACX,OAAO,QAAQ,QAAQ,SAAS,4BAA4B,QAAQ,OAAO;AAAA,UAC3E,YAAY,QAAQ,QAAQ,cAAc;AAAA,QAC5C;AAEA,YAAI,SAAS,MAAM,CAAC,UAAU;AAC5B,iBAAO;AAAA,YACL,GAAG;AAAA,YACH;AAAA,YACA;AAAA,YACA,OAAO;AAAA,UACT;AAAA,QACF;AAEA,eAAO;AAAA,UACL,GAAG;AAAA,UACH,MAAM,QAAQ,QAAQ,SAAS;AAAA,UAC/B;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAa,WAA0B,QAA2B;AAChE,SAAK,WAAW,SAAS;AAGzB,UAAM,iBAA4B;AAAA,MAChC,EAAE,MAAM,KAAK,SAAS,cAAc,SAAS,GAAG,QAAQ,OAAO;AAAA,MAC/D,EAAE,OAAO,MAAM,SAAS,cAAc,SAAS,GAAG,QAAQ,OAAO;AAAA,IACnE;AAEA,SAAK,OAAO,gBAAgB,CAAC,UAAU,OAAO,aAAa;AACzD,UAAI,YAAY,CAAC,mBAAmB,UAAU,sCAAgC,GAAG;AAC/E,YAAI,CAAC,UAAU;AACb,iBAAO;AAAA,QACT;AAEA,cAAM,YAAY,CAAC,GAAG,cAAc;AAEpC,YAAI,SAAS,KAAK,CAAC,EAAE,KAAK,MAAM,SAAS,GAAG,GAAG;AAC7C,oBAAU,MAAM;AAAA,QAClB;AAEA,YAAI,SAAS,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,MAAM,KAAK,MAAM,SAAS,GAAG,CAAC,GAAG;AACnE,oBAAU,IAAI;AAAA,QAChB;AAEA,eAAO;AAAA,UACL,GAAG;AAAA,UACH,UAAU,CAAC,GAAG,UAAU,GAAG,SAAS;AAAA,QACtC;AAAA,MACF;AAEA,aAAO;AAAA,IACT,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAW,iBAAsC;AAC/C,SAAK,WAAW,KAAK,CAAC,mBAAmB;AACvC,UAAI,CAAC,gBAAgB;AACnB,eAAO;AAAA,MACT;AAEA,YAAM,EAAE,OAAO,YAAY,SAAS,WAAW,IAAI;AAAA,QAAM;AAAA,QAAgB,CAAC,UACxE,mBAAmB,OAAO,8BAA4B;AAAA,MACxD;AAEA,aAAO;AAAA,QACL,GAAI,WAAW,SACX;AAAA;AAAA;AAAA,UAGE;AAAA,YACE,SAAS,cAAc,eAAe;AAAA,YACtC,UAAU;AAAA,YACV,QAAQ;AAAA,cACN,CAAC,sCAAgC,GAAG;AAAA,YACtC;AAAA,UACF;AAAA,QACF,IACA,CAAC;AAAA;AAAA,QAEL,GAAG;AAAA,MACL;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,QAAQ,cAA6B;AACnC,SAAK,OAAO,QAAW,CAAC,OAAO,GAAG,aAAa;AAC7C,YAAM,aAAa,aAAa,OAAQ,YAAY;AACpD,iBAAW,WAAW;AACtB,aAAO;AAAA,IACT,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAIA,OACE,QACA,WAA4C,CAAC,UAAU,YAAY,cAChE;AAAA,IACC,GAAG;AAAA,IACH,GAAG;AAAA,IACH;AAAA,EACF,IACI;AACN,SAAK,WAAW;AAAA,MAAK,CAAC,mBACpB;AAAA,QACE,CAAC,gBAAgB,MAAM;AAAA,QACvB,CAAC,CAAC,UAAU,KAAK,GAAG,SAAS;AAC3B,cAAI,YAAY,OAAO;AACrB,kBAAM,cAAc,IAAI,IAAI,SAAS,IAAI,CAAC,UAAU,iBAAiB,KAAK,CAAC,CAAC;AAC5E,kBAAM,WAAW,IAAI,IAAI,MAAM,IAAI,CAAC,UAAU,iBAAiB,KAAK,CAAC,CAAC;AAEtE,kBAAM,QAAQ,oBAAI,IAAI,CAAC,GAAG,YAAY,KAAK,GAAG,GAAG,SAAS,KAAK,CAAC,CAAC;AAEjE,uBAAW,QAAQ,OAAO;AACxB,oBAAM,gBAAgB,YAAY,IAAI,IAAI;AAC1C,oBAAM,aAAa,SAAS,IAAI,IAAI;AAEpC,kBAAI;AACJ,kBAAI,iBAAiB,YAAY;AAC/B,wBAAQ,SAAS,eAAe,YAAY,KAAK,cAAc,UAAU,WAAW,QAAQ,CAAC;AAAA,cAC/F,WAAW,eAAe;AACxB,wBAAQ,SAAS,eAAe,QAAW,KAAK,cAAc,UAAU,MAAS,CAAC;AAAA,cACpF,OAAO;AACL,wBAAQ,SAAS,QAAW,YAAY,KAAK,QAAW,WAAY,QAAQ,CAAC;AAAA,cAC/E;AAEA,kBAAI,OAAO;AACT,4BAAY,IAAI,MAAM,KAAK;AAAA,cAC7B;AAAA,YACF;AAEA,mBAAO,CAAC,GAAG,YAAY,OAAO,CAAC;AAAA,UACjC,WAAW,UAAU;AACnB,mBAAO,SACJ,IAAI,CAAC,UAAU,SAAS,OAAO,QAAW,KAAK,MAAM,UAAU,MAAS,CAAC,CAAC,EAC1E,OAAO,CAAC,MAAM,KAAK,IAAI;AAAA,UAC5B,WAAW,OAAO;AAChB,mBAAO,MACJ,IAAI,CAAC,UAAU,SAAS,QAAW,OAAO,KAAK,QAAW,MAAM,QAAQ,CAAC,CAAC,EAC1E,OAAO,CAAC,MAAM,KAAK,IAAI;AAAA,UAC5B;AAEA,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAmD;AACvD,SAAK,oBAAoB;AACzB,UAAM,SAAS,KAAK,WAAW,OAA8B,CAAC,KAAK,QAAQ,IAAI,GAAG,KAAK,KAAK,MAAS,KAAK,CAAC;AAE3G,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,oBAAoB,CAAC,GAAG,MAAM,GAAG,EAAE,UAAU,IAAI,IAAI,SAAS,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAC;AAAA,IACvG;AAAA,EACF;AAAA,EAEA,sBAA4B;AAC1B,SAAK,WAAW,KAAK,CAAC,mBAAmB;AACvC,UAAI,CAAC,gBAAgB;AACnB,eAAO;AAAA,MACT;AAEA,YAAM,EAAE,OAAO,cAAc,SAAS,WAAW,IAAI;AAAA,QAAM;AAAA,QAAgB,CAAC,UAC1E,mBAAmB,OAAO,gCAA6B;AAAA,MACzD;AAEA,YAAM,oBAAoB;AAAA,QAAoC;AAAA,QAAc,CAAC,QAAQ,SACnF,OAAO,IAAI,CAAC,UAAU;AACpB,cAAI,mBAAmB,OAAO,gCAA6B,GAAG;AAC5D,mBAAO;AAAA,UACT;AAEA,gBAAM,EAAE,SAAS,GAAG,KAAK,IAAI;AAC7B,iBAAO,MAAM,UAAU,SAClB;AAAA,YACC,GAAG;AAAA,YACH,UAAU,KAAK,GAAG,MAAM,QAAQ;AAAA,UAClC,IACA;AAAA,QACN,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL,GAAI,kBAAkB,SAClB;AAAA,UACE;AAAA,YACE,UAAU;AAAA,YACV,QAAQ;AAAA,cACN,CAAC,sCAAgC,GAAG;AAAA,YACtC;AAAA,UACF;AAAA,QACF,IACA,CAAC;AAAA,QACL,GAAG;AAAA,MACL;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": ["RouteHandleFlags"]
|
|
7
7
|
}
|
|
@@ -2,7 +2,7 @@ function __REGISTER__(feature, vaadinObj = window.Vaadin ??= {}) {
|
|
|
2
2
|
vaadinObj.registrations ??= [];
|
|
3
3
|
vaadinObj.registrations.push({
|
|
4
4
|
is: feature ? `${"@vaadin/hilla-file-router"}/${feature}` : "@vaadin/hilla-file-router",
|
|
5
|
-
version: "24.6.0-
|
|
5
|
+
version: "24.6.0-beta2"
|
|
6
6
|
});
|
|
7
7
|
}
|
|
8
8
|
import { signal } from "@vaadin/hilla-react-signals";
|
package/runtime/createRoute.d.ts
CHANGED
|
@@ -8,7 +8,6 @@ import type { AgnosticRoute, Module } from '../types.js';
|
|
|
8
8
|
*
|
|
9
9
|
* @returns A framework-agnostic route object.
|
|
10
10
|
*/
|
|
11
|
-
export declare function createRoute(path: string,
|
|
12
|
-
export declare function createRoute(path: string,
|
|
13
|
-
export declare function createRoute(path: string, flowLayout: boolean, module: Module, children?: readonly AgnosticRoute[]): AgnosticRoute;
|
|
11
|
+
export declare function createRoute(path: string, children?: readonly AgnosticRoute[]): AgnosticRoute;
|
|
12
|
+
export declare function createRoute(path: string, module: Module, children?: readonly AgnosticRoute[]): AgnosticRoute;
|
|
14
13
|
//# sourceMappingURL=createRoute.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createRoute.d.ts","sourceRoot":"","sources":["../src/runtime/createRoute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"createRoute.d.ts","sourceRoot":"","sources":["../src/runtime/createRoute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CAAC;AAC9F,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CAAC"}
|
package/runtime/createRoute.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function createRoute(path,
|
|
1
|
+
function createRoute(path, moduleOrChildren, children) {
|
|
2
2
|
let module;
|
|
3
3
|
if (Array.isArray(moduleOrChildren)) {
|
|
4
4
|
children = moduleOrChildren;
|
|
@@ -8,8 +8,7 @@ function createRoute(path, flowLayout, moduleOrChildren, children) {
|
|
|
8
8
|
return {
|
|
9
9
|
path,
|
|
10
10
|
module,
|
|
11
|
-
children
|
|
12
|
-
flowLayout
|
|
11
|
+
children
|
|
13
12
|
};
|
|
14
13
|
}
|
|
15
14
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/runtime/createRoute.ts"],
|
|
4
|
-
"sourcesContent": ["import type { AgnosticRoute, Module } from '../types.js';\n\n/**\n * Create a single framework-agnostic route object. Later, it can be transformed into a framework-specific route object,\n * e.g., the one used by React Router.\n *\n * @param path - A route path segment.\n * @param children - An array of child routes.\n *\n * @returns A framework-agnostic route object.\n */\nexport function createRoute(path: string,
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type { AgnosticRoute, Module } from '../types.js';\n\n/**\n * Create a single framework-agnostic route object. Later, it can be transformed into a framework-specific route object,\n * e.g., the one used by React Router.\n *\n * @param path - A route path segment.\n * @param children - An array of child routes.\n *\n * @returns A framework-agnostic route object.\n */\nexport function createRoute(path: string, children?: readonly AgnosticRoute[]): AgnosticRoute;\nexport function createRoute(path: string, module: Module, children?: readonly AgnosticRoute[]): AgnosticRoute;\nexport function createRoute(\n path: string,\n moduleOrChildren?: Module | readonly AgnosticRoute[],\n children?: readonly AgnosticRoute[],\n): AgnosticRoute {\n let module: Module | undefined;\n if (Array.isArray(moduleOrChildren)) {\n // eslint-disable-next-line no-param-reassign\n children = moduleOrChildren;\n } else {\n module = moduleOrChildren as Module | undefined;\n }\n\n return {\n path,\n module,\n children,\n };\n}\n"],
|
|
5
|
+
"mappings": "AAaO,SAAS,YACd,MACA,kBACA,UACe;AACf,MAAI;AACJ,MAAI,MAAM,QAAQ,gBAAgB,GAAG;AAEnC,eAAW;AAAA,EACb,OAAO;AACL,aAAS;AAAA,EACX;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createRoutesFromMeta.d.ts","sourceRoot":"","sources":["../src/vite-plugin/createRoutesFromMeta.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"createRoutesFromMeta.d.ts","sourceRoot":"","sources":["../src/vite-plugin/createRoutesFromMeta.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAqDjE;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,eAAe,GAAG,MAAM,CA0ErH"}
|
|
@@ -19,10 +19,9 @@ function createImport(mod, file) {
|
|
|
19
19
|
return template(`import * as ${mod} from '${path}';
|
|
20
20
|
`, ([statement]) => statement);
|
|
21
21
|
}
|
|
22
|
-
function createRouteData(path,
|
|
23
|
-
const serverLayout = flowLayout ?? false;
|
|
22
|
+
function createRouteData(path, mod, children) {
|
|
24
23
|
return template(
|
|
25
|
-
`const route = createRoute("${path}"
|
|
24
|
+
`const route = createRoute("${path}", ${mod ? `, ${mod}` : ""}${children ? `, CHILDREN` : ""})`,
|
|
26
25
|
([statement]) => statement.declarationList.declarations[0].initializer,
|
|
27
26
|
[
|
|
28
27
|
transformer(
|
|
@@ -55,7 +54,7 @@ function createRoutesFromMeta(views, { code: codeFile }) {
|
|
|
55
54
|
mod = `Layout${currentId}`;
|
|
56
55
|
imports.push(createImport(mod, relativize(layout, codeDir)));
|
|
57
56
|
}
|
|
58
|
-
return createRouteData(convertFSRouteSegmentToURLPatternFormat(path),
|
|
57
|
+
return createRouteData(convertFSRouteSegmentToURLPatternFormat(path), mod, _children);
|
|
59
58
|
});
|
|
60
59
|
});
|
|
61
60
|
if (imports.length > 0) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/vite-plugin/createRoutesFromMeta.ts"],
|
|
4
|
-
"sourcesContent": ["import { relative, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { template, transform as transformer } from '@vaadin/hilla-generator-utils/ast.js';\nimport createSourceFile from '@vaadin/hilla-generator-utils/createSourceFile.js';\nimport ts, {\n type CallExpression,\n type ImportDeclaration,\n type StringLiteral,\n type VariableStatement,\n} from 'typescript';\n\nimport { transformTree } from '../shared/transformTree.js';\nimport type { RouteMeta } from './collectRoutesFromFS.js';\nimport type { RuntimeFileUrls } from './generateRuntimeFiles.js';\nimport { convertFSRouteSegmentToURLPatternFormat } from './utils.js';\n\nconst printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });\n\n/**\n * Convert a file URL to a relative path from the generated directory.\n *\n * @param url - The file URL to convert.\n * @param generatedDir - The directory where the generated view file will be stored.\n */\nfunction relativize(url: URL, generatedDir: URL): string {\n const result = relative(fileURLToPath(generatedDir), fileURLToPath(url)).replaceAll(sep, '/');\n\n if (!result.startsWith('.')) {\n return `./${result}`;\n }\n\n return result;\n}\n\n/**\n * Create an import declaration for a `views` module.\n *\n * @param mod - The name of the route module to import.\n * @param file - The file path of the module.\n */\nfunction createImport(mod: string, file: string): ImportDeclaration {\n const path = `${file.substring(0, file.lastIndexOf('.'))}.js`;\n return template(`import * as ${mod} from '${path}';\\n`, ([statement]) => statement as ts.ImportDeclaration);\n}\n\n/**\n * Create an abstract route creation function call. The nested function calls create a route tree.\n *\n * @param path - The path of the route.\n * @param mod - The name of the route module imported as a namespace.\n * @param children - The list of child route call expressions.\n */\nfunction createRouteData(
|
|
5
|
-
"mappings": "AAAA,SAAS,UAAU,WAAW;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,UAAU,aAAa,mBAAmB;AACnD,OAAO,sBAAsB;AAC7B,OAAO;AAAA,OAKA;AAEP,SAAS,qBAAqB;AAG9B,SAAS,+CAA+C;AAExD,MAAM,UAAU,GAAG,cAAc,EAAE,SAAS,GAAG,YAAY,SAAS,CAAC;AAQrE,SAAS,WAAW,KAAU,cAA2B;AACvD,QAAM,SAAS,SAAS,cAAc,YAAY,GAAG,cAAc,GAAG,CAAC,EAAE,WAAW,KAAK,GAAG;AAE5F,MAAI,CAAC,OAAO,WAAW,GAAG,GAAG;AAC3B,WAAO,KAAK,MAAM;AAAA,EACpB;AAEA,SAAO;AACT;AAQA,SAAS,aAAa,KAAa,MAAiC;AAClE,QAAM,OAAO,GAAG,KAAK,UAAU,GAAG,KAAK,YAAY,GAAG,CAAC,CAAC;AACxD,SAAO,SAAS,eAAe,GAAG,UAAU,IAAI;AAAA,GAAQ,CAAC,CAAC,SAAS,MAAM,SAAiC;AAC5G;AASA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { relative, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { template, transform as transformer } from '@vaadin/hilla-generator-utils/ast.js';\nimport createSourceFile from '@vaadin/hilla-generator-utils/createSourceFile.js';\nimport ts, {\n type CallExpression,\n type ImportDeclaration,\n type StringLiteral,\n type VariableStatement,\n} from 'typescript';\n\nimport { transformTree } from '../shared/transformTree.js';\nimport type { RouteMeta } from './collectRoutesFromFS.js';\nimport type { RuntimeFileUrls } from './generateRuntimeFiles.js';\nimport { convertFSRouteSegmentToURLPatternFormat } from './utils.js';\n\nconst printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });\n\n/**\n * Convert a file URL to a relative path from the generated directory.\n *\n * @param url - The file URL to convert.\n * @param generatedDir - The directory where the generated view file will be stored.\n */\nfunction relativize(url: URL, generatedDir: URL): string {\n const result = relative(fileURLToPath(generatedDir), fileURLToPath(url)).replaceAll(sep, '/');\n\n if (!result.startsWith('.')) {\n return `./${result}`;\n }\n\n return result;\n}\n\n/**\n * Create an import declaration for a `views` module.\n *\n * @param mod - The name of the route module to import.\n * @param file - The file path of the module.\n */\nfunction createImport(mod: string, file: string): ImportDeclaration {\n const path = `${file.substring(0, file.lastIndexOf('.'))}.js`;\n return template(`import * as ${mod} from '${path}';\\n`, ([statement]) => statement as ts.ImportDeclaration);\n}\n\n/**\n * Create an abstract route creation function call. The nested function calls create a route tree.\n *\n * @param path - The path of the route.\n * @param mod - The name of the route module imported as a namespace.\n * @param children - The list of child route call expressions.\n */\nfunction createRouteData(path: string, mod: string | undefined, children?: readonly CallExpression[]): CallExpression {\n return template(\n `const route = createRoute(\"${path}\", ${mod ? `, ${mod}` : ''}${children ? `, CHILDREN` : ''})`,\n ([statement]) => (statement as VariableStatement).declarationList.declarations[0].initializer as CallExpression,\n [\n transformer((node) =>\n ts.isIdentifier(node) && node.text === 'CHILDREN'\n ? ts.factory.createArrayLiteralExpression(children, true)\n : node,\n ),\n ],\n );\n}\n\n/**\n * Loads all the files from the received metadata and creates a framework-agnostic route tree.\n *\n * @param views - The abstract route tree.\n * @param generatedDir - The directory where the generated view file will be stored.\n */\nexport default function createRoutesFromMeta(views: readonly RouteMeta[], { code: codeFile }: RuntimeFileUrls): string {\n const codeDir = new URL('./', codeFile);\n const imports: ImportDeclaration[] = [];\n const errors: string[] = [];\n let id = 0;\n\n const routes = transformTree<readonly RouteMeta[], readonly CallExpression[]>(views, (metas, next) => {\n errors.push(\n ...metas\n .map((route) => route.path)\n .filter((item, index, arr) => arr.indexOf(item) !== index)\n .map((dup) => `console.error(\"Two views share the same path: ${dup}\");`),\n );\n\n return metas.map(({ file, layout, path, children, flowLayout }) => {\n let _children: readonly CallExpression[] | undefined;\n\n if (children) {\n _children = next(...children);\n }\n\n const currentId = id;\n id += 1;\n\n let mod: string | undefined;\n if (file) {\n mod = `Page${currentId}`;\n imports.push(createImport(mod, relativize(file, codeDir)));\n } else if (layout) {\n mod = `Layout${currentId}`;\n imports.push(createImport(mod, relativize(layout, codeDir)));\n }\n\n return createRouteData(convertFSRouteSegmentToURLPatternFormat(path), mod, _children);\n });\n });\n\n // Prepend the import for `createRoute` if it was used\n if (imports.length > 0) {\n const createRouteImport = template(\n 'import { createRoute } from \"@vaadin/hilla-file-router/runtime.js\";',\n ([statement]) => statement as ts.ImportDeclaration,\n );\n imports.unshift(createRouteImport);\n }\n\n imports.unshift(\n template(\n 'import type { AgnosticRoute } from \"@vaadin/hilla-file-router/types.js\";',\n ([statement]) => statement as ts.ImportDeclaration,\n ),\n );\n\n const routeDeclaration = template(\n `import a from 'IMPORTS';\n\n${errors.join('\\n')}\n\nconst routes: readonly AgnosticRoute[] = ROUTE;\n\nexport default routes;\n`,\n [\n transformer((node) =>\n ts.isImportDeclaration(node) && (node.moduleSpecifier as StringLiteral).text === 'IMPORTS' ? imports : node,\n ),\n transformer((node) =>\n ts.isIdentifier(node) && node.text === 'ROUTE' ? ts.factory.createArrayLiteralExpression(routes, true) : node,\n ),\n ],\n );\n\n const file = createSourceFile(routeDeclaration, 'file-routes.ts');\n return printer.printFile(file);\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,UAAU,WAAW;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,UAAU,aAAa,mBAAmB;AACnD,OAAO,sBAAsB;AAC7B,OAAO;AAAA,OAKA;AAEP,SAAS,qBAAqB;AAG9B,SAAS,+CAA+C;AAExD,MAAM,UAAU,GAAG,cAAc,EAAE,SAAS,GAAG,YAAY,SAAS,CAAC;AAQrE,SAAS,WAAW,KAAU,cAA2B;AACvD,QAAM,SAAS,SAAS,cAAc,YAAY,GAAG,cAAc,GAAG,CAAC,EAAE,WAAW,KAAK,GAAG;AAE5F,MAAI,CAAC,OAAO,WAAW,GAAG,GAAG;AAC3B,WAAO,KAAK,MAAM;AAAA,EACpB;AAEA,SAAO;AACT;AAQA,SAAS,aAAa,KAAa,MAAiC;AAClE,QAAM,OAAO,GAAG,KAAK,UAAU,GAAG,KAAK,YAAY,GAAG,CAAC,CAAC;AACxD,SAAO,SAAS,eAAe,GAAG,UAAU,IAAI;AAAA,GAAQ,CAAC,CAAC,SAAS,MAAM,SAAiC;AAC5G;AASA,SAAS,gBAAgB,MAAc,KAAyB,UAAsD;AACpH,SAAO;AAAA,IACL,8BAA8B,IAAI,MAAM,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,WAAW,eAAe,EAAE;AAAA,IAC5F,CAAC,CAAC,SAAS,MAAO,UAAgC,gBAAgB,aAAa,CAAC,EAAE;AAAA,IAClF;AAAA,MACE;AAAA,QAAY,CAAC,SACX,GAAG,aAAa,IAAI,KAAK,KAAK,SAAS,aACnC,GAAG,QAAQ,6BAA6B,UAAU,IAAI,IACtD;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF;AAQe,SAAR,qBAAsC,OAA6B,EAAE,MAAM,SAAS,GAA4B;AACrH,QAAM,UAAU,IAAI,IAAI,MAAM,QAAQ;AACtC,QAAM,UAA+B,CAAC;AACtC,QAAM,SAAmB,CAAC;AAC1B,MAAI,KAAK;AAET,QAAM,SAAS,cAA+D,OAAO,CAAC,OAAO,SAAS;AACpG,WAAO;AAAA,MACL,GAAG,MACA,IAAI,CAAC,UAAU,MAAM,IAAI,EACzB,OAAO,CAAC,MAAM,OAAO,QAAQ,IAAI,QAAQ,IAAI,MAAM,KAAK,EACxD,IAAI,CAAC,QAAQ,iDAAiD,GAAG,KAAK;AAAA,IAC3E;AAEA,WAAO,MAAM,IAAI,CAAC,EAAE,MAAAA,OAAM,QAAQ,MAAM,UAAU,WAAW,MAAM;AACjE,UAAI;AAEJ,UAAI,UAAU;AACZ,oBAAY,KAAK,GAAG,QAAQ;AAAA,MAC9B;AAEA,YAAM,YAAY;AAClB,YAAM;AAEN,UAAI;AACJ,UAAIA,OAAM;AACR,cAAM,OAAO,SAAS;AACtB,gBAAQ,KAAK,aAAa,KAAK,WAAWA,OAAM,OAAO,CAAC,CAAC;AAAA,MAC3D,WAAW,QAAQ;AACjB,cAAM,SAAS,SAAS;AACxB,gBAAQ,KAAK,aAAa,KAAK,WAAW,QAAQ,OAAO,CAAC,CAAC;AAAA,MAC7D;AAEA,aAAO,gBAAgB,wCAAwC,IAAI,GAAG,KAAK,SAAS;AAAA,IACtF,CAAC;AAAA,EACH,CAAC;AAGD,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA,CAAC,CAAC,SAAS,MAAM;AAAA,IACnB;AACA,YAAQ,QAAQ,iBAAiB;AAAA,EACnC;AAEA,UAAQ;AAAA,IACN;AAAA,MACE;AAAA,MACA,CAAC,CAAC,SAAS,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,mBAAmB;AAAA,IACvB;AAAA;AAAA,EAEF,OAAO,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMf;AAAA,MACE;AAAA,QAAY,CAAC,SACX,GAAG,oBAAoB,IAAI,KAAM,KAAK,gBAAkC,SAAS,YAAY,UAAU;AAAA,MACzG;AAAA,MACA;AAAA,QAAY,CAAC,SACX,GAAG,aAAa,IAAI,KAAK,KAAK,SAAS,UAAU,GAAG,QAAQ,6BAA6B,QAAQ,IAAI,IAAI;AAAA,MAC3G;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO,iBAAiB,kBAAkB,gBAAgB;AAChE,SAAO,QAAQ,UAAU,IAAI;AAC/B;",
|
|
6
6
|
"names": ["file"]
|
|
7
7
|
}
|