@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/hilla-file-router",
3
- "version": "24.6.0-alpha5",
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-alpha5",
83
- "@vaadin/hilla-react-auth": "24.6.0-alpha5",
84
- "@vaadin/hilla-react-signals": "24.6.0-alpha5",
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 RouteTransformer<T> = (original: RouteObject | undefined, overriding: T | undefined, children?: readonly RouteObject[]) => RouteObject | undefined;
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: readonly RouteObject[]): this;
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;AAG1B,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;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,GAAG,SAAS,CAAC;AAkB7B;;;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;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;IA4EhD;;;;;;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;CASzD"}
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 === void 0) {
148
+ if (!originalRoutes) {
116
149
  return originalRoutes;
117
150
  }
118
- const [serverRoutesTree, clientRoutesTree] = transformTree(
151
+ const { match: serverList, default: clientList } = split(
119
152
  originalRoutes,
120
- (routes, next) => (
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
- // The server subtree is wrapped with the server layout component,
154
- // which applies the top-level server layout to all matches.
155
- ...serverRoutesTree ? [
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: serverRoutesTree,
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
- ...clientRoutesTree ?? []
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(Boolean);
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(Boolean);
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": "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",
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": "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",
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-alpha5"
5
+ version: "24.6.0-beta2"
6
6
  });
7
7
  }
8
8
  import { signal } from "@vaadin/hilla-react-signals";
@@ -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, flowLayout: boolean, children?: readonly AgnosticRoute[]): AgnosticRoute;
12
- export declare function createRoute(path: string, flowLayout: boolean, module: Module, children?: readonly AgnosticRoute[]): AgnosticRoute;
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,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,CAAC;AACnH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,GAClC,aAAa,CAAC;AACjB,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,GAClC,aAAa,CAAC"}
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"}
@@ -1,4 +1,4 @@
1
- function createRoute(path, flowLayout, moduleOrChildren, children) {
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, flowLayout: boolean, children?: readonly AgnosticRoute[]): AgnosticRoute;\nexport function createRoute(\n path: string,\n flowLayout: boolean,\n module: Module,\n children?: readonly AgnosticRoute[],\n): AgnosticRoute;\nexport function createRoute(\n path: string,\n flowLayout: boolean,\n module: Module,\n children?: readonly AgnosticRoute[],\n): AgnosticRoute;\nexport function createRoute(\n path: string,\n flowLayout: boolean,\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 flowLayout,\n };\n}\n"],
5
- "mappings": "AAwBO,SAAS,YACd,MACA,YACA,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,IACA;AAAA,EACF;AACF;",
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;AA2DjE;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,eAAe,GAAG,MAAM,CA0ErH"}
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, flowLayout, mod, children) {
23
- const serverLayout = flowLayout ?? false;
22
+ function createRouteData(path, mod, children) {
24
23
  return template(
25
- `const route = createRoute("${path}",${serverLayout}${mod ? `, ${mod}` : ""}${children ? `, CHILDREN` : ""})`,
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), flowLayout, mod, _children);
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(\n path: string,\n flowLayout: boolean | undefined,\n mod: string | undefined,\n children?: readonly CallExpression[],\n): CallExpression {\n const serverLayout = flowLayout ?? false;\n return template(\n `const route = createRoute(\"${path}\",${serverLayout}${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), flowLayout, 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": "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",
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": "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",
6
6
  "names": ["file"]
7
7
  }