aaex-file-router 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,11 +2,9 @@
2
2
 
3
3
  A file-based routing system for React projects that automatically generates routes from your file structure. Similar to Next.js App Router or Remix file conventions.
4
4
 
5
- ## V. 1.3.1
5
+ ## V. 1.4.0
6
6
 
7
- Routes are now able to be infinitely nested
8
-
9
- **Notice** Only tested 3 levels deep but there is no reason i shouldnt work further
7
+ Added support for loading components
10
8
 
11
9
  ## Table of Contents
12
10
 
@@ -19,11 +17,12 @@ Routes are now able to be infinitely nested
19
17
  - [Using createBrowserRouter](#1-using-createbrowserrouter-recommended-for-most-users)
20
18
  - [Using nested Route elements](#2-using-nested-route-elements)
21
19
  - [File Conventions](#file-conventions)
22
- - [Generated Routes File](#generated-routes-file)
23
20
  - [Route Resolution Examples](#route-resolution-examples)
21
+ - [Import strategy](#import-strategy)
24
22
  - [Layouts](#layouts)
25
23
  - [FileLink component](#filelink-component)
26
24
  - [Usage](#usage)
25
+ - [Generated files](#generated-files)
27
26
  - [API Reference](#api-reference)
28
27
  - [How It Works](#how-it-works)
29
28
  - [Performance Considerations](#performance-considerations)
@@ -53,13 +52,15 @@ npm install aaex-file-router
53
52
 
54
53
  ```
55
54
  src/pages/
56
- ├── index.tsx # Root page "/"
57
- ├── about.tsx # Route "/about"
58
- └── test/
59
- ├── layout.tsx # Layout wrapper for /test/* routes
60
- ├── index.tsx # Route "/test"
61
- ├── hello.tsx # Route "/test/hello"
62
- └── [slug].tsx # Route "/test/:slug"
55
+ └── dashboard/
56
+ ├── loading.tsx Used as fallback for ALL lazy imports below
57
+ ├── index.tsx
58
+ ├── stats/
59
+ ├── loading.tsx Overrides parent
60
+ │ └── weekly.tsx
61
+ └── users/
62
+ └── [id].tsx ← used for dynamic routes ex :users/123
63
+
63
64
  ```
64
65
 
65
66
  ### 2. Configure Vite
@@ -83,6 +84,8 @@ export default defineConfig({
83
84
 
84
85
  ### 3. Use in your app
85
86
 
87
+ ### Note: Since v1.4.0 every lazy-loaded route is automatically wrapped in a Suspense boundary, using the nearest loading.tsx file as the fallback.
88
+
86
89
  #### 1. Using createBrowserRouter (recommended for most users)
87
90
 
88
91
  ```typescript
@@ -105,9 +108,7 @@ function App() {
105
108
  export default App;
106
109
  ```
107
110
 
108
- ## **OR**
109
-
110
- ### 2. using nested Route elements
111
+ ### 2. Using nested Route elements
111
112
 
112
113
  **Note** I will probably create a custom route provider using this version later since this is the only solution that works with VITE-SSR if you wrap client in `<BrowserRouter/>` and server in `<StaticRouter/>`
113
114
 
@@ -160,7 +161,7 @@ pages/about/index.tsx → "/about"
160
161
 
161
162
  Wraps all sibling and nested routes. Children are rendered in an `<Outlet />`.
162
163
 
163
- ```typescript
164
+ ```tsx
164
165
  // pages/admin/layout.tsx
165
166
  import { Outlet } from "react-router-dom";
166
167
 
@@ -174,6 +175,18 @@ export default function AdminLayout() {
174
175
  }
175
176
  ```
176
177
 
178
+ ### `loading.tsx`
179
+
180
+ Folder level loading component <br>
181
+ Autmatically gets rendered instead of files waiting on lazy import
182
+
183
+ ```tsx
184
+ // src/pages/test/loading.tsx
185
+ export default function Test() {
186
+ return <div>Loading...</div>;
187
+ }
188
+ ```
189
+
177
190
  ### Slug files
178
191
 
179
192
  Filenames wrapper in square brackets `[filename]` will resolve to a dynamic route
@@ -204,7 +217,7 @@ pages/about.tsx → "/about"
204
217
  pages/blog/post.tsx → "/blog/post"
205
218
  ```
206
219
 
207
- ## Generated Routes File
220
+ <!-- ## Generated Routes File
208
221
 
209
222
  The plugin generates a `routes.ts` file with all your routes:
210
223
 
@@ -231,7 +244,7 @@ const routes: RouteObject[] = [
231
244
  ];
232
245
 
233
246
  export default routes;
234
- ```
247
+ ``` -->
235
248
 
236
249
  ## Route Resolution Examples
237
250
 
@@ -265,6 +278,19 @@ export default function DashboardLayout() {
265
278
 
266
279
  All routes in `src/pages/dashboard/*` will render inside this layout.
267
280
 
281
+ ## Import Strategy
282
+
283
+ | File type | | | Import style | |
284
+ | ------------------------------------- | --- | --- | ------------- | --- |
285
+ | pages/\*.tsx (top level) | | | static import | |
286
+ | Files inside a folder with layout.tsx | | | Lazy loaded | |
287
+ | Files inside a folder without layout | | | Lazy loaded | |
288
+ | layout.tsx | | | Static import |
289
+ | loading.tsx | | | Static import |
290
+ ---
291
+ Top-level pages are always statically imported for faster initial navigation.
292
+ All nested pages are lazy-loaded and wrapped in a Suspense boundary.
293
+
268
294
  ## FileLink component
269
295
 
270
296
  The FileLink component is a type safe wrapper for the Link component in react router that uses an autogenerated type to check which routes are available.
@@ -276,18 +302,21 @@ React Router's normal Link still works in cases where type safety is less import
276
302
 
277
303
  ## Usage
278
304
 
305
+ If reades the type file that is automatically generated
306
+
307
+ `users/{string}` is what users/:slug gets translated to this means users/ allows any string after even if the route dosnt exist. Will look into better solution
308
+
279
309
  ```ts
280
310
  // src/routeTypes.ts
281
311
  // * AUTO GENERATED: DO NOT EDIT
282
-
283
- //this file is auto generated along with the route definition file
284
- export type FileRoutes = "/" | "test";
312
+ /
313
+ export type FileRoutes = "/" | "test" | "users/{string}";
285
314
  ```
286
315
 
287
316
  ```tsx
288
317
  // src/pages/index.tsx
289
318
  import { FileLink } from "aaex-file-router";
290
- import type { FileRoutes } from "../routeTypes";
319
+ import type { FileRoutes } from "../routeTypes"; //import type
291
320
 
292
321
  export default function Home() {
293
322
  return (
@@ -302,6 +331,47 @@ export default function Home() {
302
331
  }
303
332
  ```
304
333
 
334
+ ## Generated files
335
+
336
+ ### routes.ts
337
+
338
+ Generated route definition file
339
+
340
+ ```ts
341
+ // src/routes.ts
342
+ ...imports
343
+ export default routes = [
344
+ {
345
+ path: "/",
346
+ element: React.createElement(Index)},
347
+ {
348
+ path: "test",
349
+ element: React.createElement(TestLayout),
350
+ children:
351
+ [
352
+ {
353
+ path: "",
354
+ element: React.createElement(
355
+ React.Suspense,
356
+ { fallback: React.createElement(TestLoading) },
357
+ React.createElement(React.lazy(() => import("./pages/test/index.tsx")))
358
+ )
359
+ },
360
+ ...
361
+ ]
362
+ }
363
+ ]
364
+
365
+ ```
366
+
367
+ ### routeTypes.ts
368
+
369
+ Exports TypeScript union type of existing routes
370
+
371
+ ```ts
372
+ export type FileRoutes = `/` | `test`;
373
+ ```
374
+
305
375
  ## API Reference
306
376
 
307
377
  ### FileScanner
@@ -323,7 +393,7 @@ Converts file structure into React Router route configuration.
323
393
  import { RouteGenerator } from "aaex-file-router/core";
324
394
 
325
395
  const generator = new RouteGenerator();
326
- const routesCode = await generator.generateComponentsMap(fileData);
396
+ const routesCode = await generator.generateRoutesFile(fileData);
327
397
  ```
328
398
 
329
399
  ### aaexFileRouter (Vite Plugin)
@@ -10,10 +10,20 @@ export declare class FileScanner {
10
10
  constructor(pages_dir: string);
11
11
  /**
12
12
  * Recursively scan directory and return nested FileData
13
+ * - Scans files of a given folder
14
+ * - converts and returns as usable data
15
+ * - Format:
16
+ * {name: string,
17
+ * relative_path: string,
18
+ * parent_path: string,
19
+ * isDirectory: string
20
+ * }
21
+ * @param dir string
22
+ * @returns FileData[]
13
23
  */
14
24
  private scan_files;
15
25
  /**
16
- * Public entry point: returns nested FileData structure
26
+ * Public file point: returns nested FileData structure
17
27
  */
18
28
  get_file_data(): Promise<FileData[]>;
19
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FileScanner.d.ts","sourceRoot":"","sources":["../../src/core/FileScanner.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,qBAAa,WAAW;IACtB,QAAQ,EAAE,MAAM,CAAC;gBAEL,SAAS,EAAE,MAAM;IAI7B;;OAEG;YACW,UAAU;IA0BxB;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;CAKlD"}
1
+ {"version":3,"file":"FileScanner.d.ts","sourceRoot":"","sources":["../../src/core/FileScanner.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,qBAAa,WAAW;IACtB,QAAQ,EAAE,MAAM,CAAC;gBAEL,SAAS,EAAE,MAAM;IAI7B;;;;;;;;;;;;OAYG;YACW,UAAU;IA+BxB;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;CAKlD"}
@@ -7,21 +7,36 @@ export class FileScanner {
7
7
  }
8
8
  /**
9
9
  * Recursively scan directory and return nested FileData
10
+ * - Scans files of a given folder
11
+ * - converts and returns as usable data
12
+ * - Format:
13
+ * {name: string,
14
+ * relative_path: string,
15
+ * parent_path: string,
16
+ * isDirectory: string
17
+ * }
18
+ * @param dir string
19
+ * @returns FileData[]
10
20
  */
11
21
  async scan_files(dir) {
12
- const entries = await fs.readdir(dir, { withFileTypes: true });
22
+ //scans the parent folder and outputs an array of files
23
+ const files = await fs.readdir(dir, { withFileTypes: true });
13
24
  const result = [];
14
- for (const entry of entries) {
15
- const fullPath = path.join(dir, entry.name);
16
- const relativePath = path.relative(process.cwd(), fullPath).replace(/\\/g, "/");
25
+ for (const file of files) {
26
+ const fullPath = path.join(dir, file.name);
27
+ const relativePath = path
28
+ .relative(process.cwd(), fullPath)
29
+ .replace(/\\/g, "/");
17
30
  const parentPath = path.relative(process.cwd(), dir).replace(/\\/g, "/") + "/";
31
+ // convert to usable data
18
32
  const fileData = {
19
- name: entry.name,
33
+ name: file.name,
20
34
  relative_path: relativePath,
21
35
  parent_path: parentPath,
22
- isDirectory: entry.isDirectory(),
36
+ isDirectory: file.isDirectory(),
23
37
  };
24
- if (entry.isDirectory()) {
38
+ //recurivly scan directories for more files
39
+ if (file.isDirectory()) {
25
40
  fileData.children = await this.scan_files(fullPath);
26
41
  }
27
42
  result.push(fileData);
@@ -29,7 +44,7 @@ export class FileScanner {
29
44
  return result;
30
45
  }
31
46
  /**
32
- * Public entry point: returns nested FileData structure
47
+ * Public file point: returns nested FileData structure
33
48
  */
34
49
  async get_file_data() {
35
50
  const fullDir = path.join(process.cwd(), this.page_dir);
@@ -1 +1 @@
1
- {"version":3,"file":"FileScanner.js","sourceRoot":"","sources":["../../src/core/FileScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,IAAI,MAAM,MAAM,CAAC;AAUxB,MAAM,OAAO,WAAW;IACtB,QAAQ,CAAS;IAEjB,YAAY,SAAiB;QAC3B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;IAC5B,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU,CAAC,GAAW;QAClC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAe,EAAE,CAAC;QAE9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAChF,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;YAE/E,MAAM,QAAQ,GAAa;gBACzB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,aAAa,EAAE,YAAY;gBAC3B,WAAW,EAAE,UAAU;gBACvB,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;aACjC,CAAC;YAEF,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,QAAQ,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YACtD,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,aAAa;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
1
+ {"version":3,"file":"FileScanner.js","sourceRoot":"","sources":["../../src/core/FileScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AAUxB,MAAM,OAAO,WAAW;IACtB,QAAQ,CAAS;IAEjB,YAAY,SAAiB;QAC3B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;;;OAYG;IACK,KAAK,CAAC,UAAU,CAAC,GAAW;QAClC,uDAAuD;QACvD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAe,EAAE,CAAC;QAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,YAAY,GAAG,IAAI;iBACtB,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC;iBACjC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACvB,MAAM,UAAU,GACd,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;YAE9D,yBAAyB;YACzB,MAAM,QAAQ,GAAa;gBACzB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,aAAa,EAAE,YAAY;gBAC3B,WAAW,EAAE,UAAU;gBACvB,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;aAChC,CAAC;YACF,2CAA2C;YAC3C,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;gBACvB,QAAQ,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YACtD,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,aAAa;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -8,22 +8,18 @@ interface FileNode {
8
8
  export declare class RouteGenerator {
9
9
  private topLevelImports;
10
10
  private importSet;
11
- /**
12
- * Converts a FileData-like tree into React Router routes
13
- * @param files - Array of file/folder objects passed externally
14
- * @param parentPath - Current path for recursion
15
- */
11
+ private normalizeSegment;
12
+ private normalizeTypeSegment;
13
+ private toPascal;
14
+ private addImport;
15
+ private getImportName;
16
+ private createDirectoryRoute;
17
+ private createFileRoute;
16
18
  private fileDataToRoutes;
17
- /**
18
- * Generates a React Router routes file as a string
19
- * @param fileData - FileData-like tree
20
- */
21
- generateRoutesFile(fileData: FileNode[]): Promise<string>;
22
- /**
23
- * Generates TypeScript type definition for all route paths
24
- * @param fileData - FileData-like tree
25
- */
26
- generateRoutesTypeDef(fileData: FileNode[]): Promise<string>;
19
+ private collectPaths;
20
+ private buildTypeUnion;
21
+ generateRoutesFile(fileData: FileNode[]): string;
22
+ generateTypesFile(fileData: FileNode[]): string;
27
23
  }
28
24
  export {};
29
25
  //# sourceMappingURL=RouteGenerator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RouteGenerator.d.ts","sourceRoot":"","sources":["../../src/core/RouteGenerator.ts"],"names":[],"mappings":"AAMA,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,SAAS,CAA0B;IAE3C;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAgGxB;;;OAGG;IACU,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAsBtE;;;OAGG;IACU,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CA8B1E"}
1
+ {"version":3,"file":"RouteGenerator.d.ts","sourceRoot":"","sources":["../../src/core/RouteGenerator.ts"],"names":[],"mappings":"AAMA,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,SAAS,CAA0B;IAG3C,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,oBAAoB;IA0C5B,OAAO,CAAC,eAAe;IA4BvB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,YAAY;IA2BpB,OAAO,CAAC,cAAc;IAUf,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM;IAqBhD,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM;CASvD"}
@@ -1,126 +1,129 @@
1
1
  export class RouteGenerator {
2
2
  topLevelImports = [];
3
3
  importSet = new Set();
4
- /**
5
- * Converts a FileData-like tree into React Router routes
6
- * @param files - Array of file/folder objects passed externally
7
- * @param parentPath - Current path for recursion
8
- */
9
- fileDataToRoutes(files, parentPath = "", isChild = false) {
10
- const routes = [];
11
- const normalizeSegment = (name) => name.replace(/\[([^\]]+)\]/g, ":$1").toLowerCase();
12
- const toPascal = (str) => str
4
+ // ---------------- Helpers ----------------
5
+ normalizeSegment(name) {
6
+ return name.replace(/\[([^\]]+)\]/g, ":$1").toLowerCase();
7
+ }
8
+ normalizeTypeSegment(name) {
9
+ return name.replace(/\[([^\]]+)\]/g, "{string}");
10
+ }
11
+ toPascal(str) {
12
+ return str
13
13
  .replace(/\[|\]/g, "")
14
14
  .replace(/(^\w|[-_]\w)/g, (m) => m.replace(/[-_]/, "").toUpperCase());
15
- const getImportName = (file, parentPath) => {
16
- const nameWithoutExt = file.name.replace(/\.[jt]sx?$/, "");
17
- if (nameWithoutExt.toLowerCase() === "index" && parentPath) {
18
- // Use parent folder prefix for nested index
19
- const segments = parentPath.split("/").filter(Boolean);
20
- return toPascal(segments.join("")) + "Index";
21
- }
22
- return toPascal(nameWithoutExt);
23
- };
15
+ }
16
+ addImport(file, importName) {
17
+ if (!this.importSet.has(file.relative_path)) {
18
+ const importPath = `./${file.relative_path.replace(/^src[\/\\]/, "")}`;
19
+ this.topLevelImports.push(`import ${importName} from '${importPath}';`);
20
+ this.importSet.add(file.relative_path);
21
+ }
22
+ }
23
+ getImportName(file, parentPath) {
24
+ const nameWithoutExt = file.name.replace(/\.[jt]sx?$/, "");
25
+ if (nameWithoutExt.toLowerCase() === "index" && parentPath) {
26
+ const segments = parentPath.split("/").filter(Boolean);
27
+ return this.toPascal(segments.join("")) + "Index";
28
+ }
29
+ return this.toPascal(nameWithoutExt);
30
+ }
31
+ // ---------------- Route Creation ----------------
32
+ createDirectoryRoute(file) {
33
+ const route = { path: this.normalizeSegment(file.name) };
34
+ const layout = file.children?.find((f) => /^layout\.(tsx|jsx|ts|js)$/i.test(f.name));
35
+ if (layout) {
36
+ const importName = `${this.toPascal(file.name)}Layout`;
37
+ this.addImport(layout, importName);
38
+ route.element = `React.createElement(${importName})`;
39
+ }
40
+ const loadingFile = file.children?.find((f) => /^loading\.(tsx|jsx|ts|js)$/i.test(f.name));
41
+ let loadingName = null;
42
+ if (loadingFile) {
43
+ loadingName = this.getImportName(loadingFile, file.relative_path);
44
+ this.addImport(loadingFile, loadingName);
45
+ }
46
+ const children = file.children?.filter((f) => !/^layout\.(tsx|jsx|ts|js)$/i.test(f.name) &&
47
+ !/^loading\.(tsx|jsx|ts|js)$/i.test(f.name));
48
+ if (children?.length) {
49
+ route.children = this.fileDataToRoutes(children, route.path, true, loadingName);
50
+ }
51
+ return route;
52
+ }
53
+ createFileRoute(file, parentPath, isChild, folderLoadingName) {
54
+ const nameWithoutExt = file.name.replace(/\.[jt]sx?$/, "");
55
+ const isIndex = nameWithoutExt.toLowerCase() === "index";
56
+ let pathSegment = isIndex ? "" : this.normalizeSegment(nameWithoutExt);
57
+ if (!isChild && parentPath)
58
+ pathSegment = `${parentPath}/${pathSegment}`;
59
+ const importName = this.getImportName(file, parentPath);
60
+ this.addImport(file, importName);
61
+ const fallback = folderLoadingName
62
+ ? `React.createElement(${folderLoadingName})`
63
+ : `<div>Loading...</div>`;
64
+ const elementString = `React.createElement(React.Suspense, { fallback: ${fallback} }, React.createElement(React.lazy(() => import('./${file.relative_path.replace(/^src[\/\\]/, "")}'))))`;
65
+ return { path: pathSegment, element: elementString };
66
+ }
67
+ // ---------------- Route Recursion ----------------
68
+ fileDataToRoutes(files, parentPath = "", isChild = false, folderLoadingName = null) {
69
+ return files.map((file) => file.isDirectory
70
+ ? this.createDirectoryRoute(file)
71
+ : this.createFileRoute(file, parentPath, isChild, folderLoadingName));
72
+ }
73
+ // ---------------- Type Helpers ----------------
74
+ collectPaths(files, prefix = "") {
75
+ let result = [];
24
76
  for (const file of files) {
25
77
  if (file.isDirectory) {
26
- const layout = file.children?.find((f) => !f.isDirectory && /^layout\.(tsx|jsx|ts|js)$/i.test(f.name));
27
- const route = {
28
- path: normalizeSegment(file.name),
29
- };
30
- if (layout) {
31
- const importName = `${toPascal(file.name)}Layout`;
32
- const importPath = `./${layout.relative_path.replace(/^src[\/\\]/, "")}`;
33
- if (!this.importSet.has(layout.relative_path)) {
34
- this.topLevelImports.push(`import ${importName} from '${importPath}';`);
35
- this.importSet.add(layout.relative_path);
36
- }
37
- route.element = `React.createElement(${importName})`;
38
- }
78
+ const newPrefix = `${prefix}/${this.normalizeTypeSegment(file.name)}`;
79
+ result.push(newPrefix);
39
80
  if (file.children?.length) {
40
- const children = file.children.filter((f) => !/^layout\.(tsx|jsx|ts|js)$/i.test(f.name));
41
- if (children.length) {
42
- // Pass true for isChild to make children paths relative
43
- route.children = this.fileDataToRoutes(children, route.path, true);
44
- }
81
+ result.push(...this.collectPaths(file.children, newPrefix));
45
82
  }
46
- routes.push(route);
47
83
  }
48
84
  else {
49
- const nameWithoutExt = file.name.replace(/\.[jt]sx?$/, "");
50
- const isIndex = nameWithoutExt.toLowerCase() === "index";
51
- // If child, path is relative; otherwise, top-level gets full path
52
- let pathSegment = isIndex ? "" : normalizeSegment(nameWithoutExt);
53
- if (isChild) {
54
- // Children always use relative paths
55
- pathSegment = pathSegment;
85
+ const clean = file.name.replace(/\.[jt]sx?$/, "");
86
+ if (clean === "layout" || clean === "loading")
87
+ continue;
88
+ if (clean === "index") {
89
+ result.push(prefix || "/");
56
90
  }
57
91
  else {
58
- pathSegment = parentPath
59
- ? `${parentPath}/${pathSegment}`
60
- : pathSegment;
61
- }
62
- const importName = getImportName(file, parentPath);
63
- ;
64
- const importPath = `./${file.relative_path.replace(/^src[\/\\]/, "")}`;
65
- if (!this.importSet.has(file.relative_path)) {
66
- this.topLevelImports.push(`import ${importName} from '${importPath}';`);
67
- this.importSet.add(file.relative_path);
92
+ result.push(`${prefix}/${this.normalizeTypeSegment(clean)}`);
68
93
  }
69
- routes.push({
70
- path: pathSegment,
71
- element: `React.createElement(${importName})`,
72
- });
73
94
  }
74
95
  }
75
- return routes;
96
+ return result;
76
97
  }
77
- /**
78
- * Generates a React Router routes file as a string
79
- * @param fileData - FileData-like tree
80
- */
81
- async generateRoutesFile(fileData) {
98
+ buildTypeUnion(paths) {
99
+ const normalized = [...new Set(paths)]
100
+ .map((p) => p.replace(/\/+/g, "/"))
101
+ .map((p) => (p === "" ? "/" : p))
102
+ .sort();
103
+ return normalized.map((p) => ` | "${p}"`).join("\n");
104
+ }
105
+ // ---------------- PUBLIC METHODS ----------------
106
+ generateRoutesFile(fileData) {
82
107
  this.topLevelImports = [];
83
- this.importSet = new Set();
108
+ this.importSet.clear();
84
109
  const routes = this.fileDataToRoutes(fileData);
85
- const routesString = JSON.stringify(routes, null, 2).replace(/"React\.createElement\((\w+)\)"/g, "React.createElement($1)");
86
110
  return `//* AUTO GENERATED: DO NOT EDIT
87
111
  import React from 'react';
88
112
  ${this.topLevelImports.join("\n")}
89
113
  import type { RouteObject } from 'react-router-dom';
90
114
 
91
- const routes: RouteObject[] = ${routesString};
115
+ const routes: RouteObject[] = ${JSON.stringify(routes, null, 2).replace(/"React\.createElement\(([\s\S]*?)\)"/g, (_, inner) => `React.createElement(${inner})`)}
116
+
92
117
 
93
118
  export default routes;
94
119
  `;
95
120
  }
96
- /**
97
- * Generates TypeScript type definition for all route paths
98
- * @param fileData - FileData-like tree
99
- */
100
- async generateRoutesTypeDef(fileData) {
101
- const routes = this.fileDataToRoutes(fileData);
102
- const paths = [];
103
- const collectPaths = (routes, parentPath = "") => {
104
- for (const route of routes) {
105
- const fullPath = parentPath
106
- ? `${parentPath}/${route.path}`.replace(/\/+/g, "/")
107
- : route.path;
108
- const tsPath = fullPath
109
- .split("/")
110
- .map((seg) => (seg.startsWith(":") ? "${string}" : seg))
111
- .join("/");
112
- paths.push(tsPath);
113
- if (route.children)
114
- collectPaths(route.children, fullPath);
115
- }
116
- };
117
- collectPaths(routes);
118
- const uniquePaths = Array.from(new Set(paths))
119
- .map((p) => `\`${p}\``)
120
- .join(" | ");
121
- return `// * AUTO GENERATED: DO NOT EDIT
122
-
123
- export type FileRoutes = ${uniquePaths};
121
+ generateTypesFile(fileData) {
122
+ const paths = this.collectPaths(fileData, "");
123
+ const union = this.buildTypeUnion(paths);
124
+ return `// AUTO-GENERATED: DO NOT EDIT
125
+ export type FileRoutes =
126
+ ${union};
124
127
  `;
125
128
  }
126
129
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RouteGenerator.js","sourceRoot":"","sources":["../../src/core/RouteGenerator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RouteGenerator.js","sourceRoot":"","sources":["../../src/core/RouteGenerator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export default function Loading(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=loading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loading.d.ts","sourceRoot":"","sources":["../../../src/pages/test/loading.tsx"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,UAAU,OAAO,4CAE9B"}
@@ -0,0 +1,5 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ export default function Loading() {
3
+ return _jsx(_Fragment, { children: "Loading test..." });
4
+ }
5
+ //# sourceMappingURL=loading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loading.js","sourceRoot":"","sources":["../../../src/pages/test/loading.tsx"],"names":[],"mappings":";AAAA,MAAM,CAAC,OAAO,UAAU,OAAO;IAC3B,OAAO,gDAAoB,CAAA;AAC/B,CAAC"}
@@ -30,8 +30,8 @@ export function aaexFileRouter(options = {}) {
30
30
  scanner = new FileScanner(pagesDir);
31
31
  generator = new RouteGenerator();
32
32
  const fileData = await scanner.get_file_data();
33
- const routesCode = await generator.generateRoutesFile(fileData);
34
- const routesType = await generator.generateRoutesTypeDef(fileData);
33
+ const routesCode = generator.generateRoutesFile(fileData);
34
+ const routesType = generator.generateTypesFile(fileData);
35
35
  // Write routes file
36
36
  await fs.writeFile(outputFile, routesCode, "utf-8");
37
37
  await fs.writeFile("src/routeTypes.ts", routesType, "utf-8");
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAO3D;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,UAA6B,EAAE;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,aAAa,CAAC;IACnD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC;IAE3D,IAAI,OAAoB,CAAC;IACzB,IAAI,SAAyB,CAAC;IAE9B,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,OAAO,EAAE,uBAAuB;QAEvC,cAAc;YACZ,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;YACpC,SAAS,GAAG,IAAI,cAAc,EAAE,CAAC;QACnC,CAAC;QAED,KAAK,CAAC,eAAe,CAAC,MAAM;YAC1B,wCAAwC;YACxC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;YAE1D,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACjD,4CAA4C;gBAC5C,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC1C,IAAI,CAAC;wBACH,OAAO,CAAC,GAAG,CAAC,yBAAyB,KAAK,KAAK,QAAQ,EAAE,CAAC,CAAC;wBAE3D,oBAAoB;wBACpB,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;wBACpC,SAAS,GAAG,IAAI,cAAc,EAAE,CAAC;wBAEjC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;wBAC/C,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;wBAChE,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;wBAEnE,oBAAoB;wBACpB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;wBACpD,MAAM,EAAE,CAAC,SAAS,CAAC,mBAAmB,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;wBAE7D,OAAO,CAAC,GAAG,CACT,8CAA8C,UAAU,EAAE,CAC3D,CAAC;oBACJ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,KAAK,CACX,iDAAiD,EACjD,KAAK,CACN,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAO3D;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,UAA6B,EAAE;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,aAAa,CAAC;IACnD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC;IAE3D,IAAI,OAAoB,CAAC;IACzB,IAAI,SAAyB,CAAC;IAE9B,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,OAAO,EAAE,uBAAuB;QAEvC,cAAc;YACZ,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;YACpC,SAAS,GAAG,IAAI,cAAc,EAAE,CAAC;QACnC,CAAC;QAED,KAAK,CAAC,eAAe,CAAC,MAAM;YAC1B,wCAAwC;YACxC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;YAE1D,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;gBACjD,4CAA4C;gBAC5C,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC1C,IAAI,CAAC;wBACH,OAAO,CAAC,GAAG,CAAC,yBAAyB,KAAK,KAAK,QAAQ,EAAE,CAAC,CAAC;wBAE3D,oBAAoB;wBACpB,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;wBACpC,SAAS,GAAG,IAAI,cAAc,EAAE,CAAC;wBAEjC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;wBAC/C,MAAM,UAAU,GAAG,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;wBAC1D,MAAM,UAAU,GAAG,SAAS,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;wBAEzD,oBAAoB;wBACpB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;wBACpD,MAAM,EAAE,CAAC,SAAS,CAAC,mBAAmB,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;wBAE7D,OAAO,CAAC,GAAG,CACT,8CAA8C,UAAU,EAAE,CAC3D,CAAC;oBACJ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,KAAK,CACX,iDAAiD,EACjD,KAAK,CACN,CAAC;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -11,9 +11,10 @@ async function generateRoutes() {
11
11
  // console.log(fileData);
12
12
  console.dir(fileData, { depth: null });
13
13
  const generator = new RouteGenerator();
14
- const routeMap = await generator.generateRoutesFile(fileData);
14
+ const routeMap = generator.generateRoutesFile(fileData);
15
15
  // console.log("Route map: ", routeMap)
16
- // const routType = await generator.generateRoutesTypeDef(fileData);
16
+ const routType = generator.generateTypesFile(fileData);
17
+ console.log(routType);
17
18
  // console.log(routeMap);
18
19
  fs.writeFile("./src/test/output.ts", routeMap, "utf-8", (err) => {
19
20
  if (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,QAAQ,GAAG,YAAY,CAAC;AAE9B,KAAK,UAAU,cAAc;IAC3B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;QAE/C,yBAAyB;QAEzB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAC,EAAC,KAAK,EAAC,IAAI,EAAC,CAAC,CAAC;QAEnC,MAAM,SAAS,GAAG,IAAI,cAAc,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAE9D,uCAAuC;QAEvC,oEAAoE;QAEpE,yBAAyB;QAEzB,EAAE,CAAC,SAAS,CAAC,sBAAsB,EAAC,QAAQ,EAAC,OAAO,EAAC,CAAC,GAAG,EAAC,EAAE;YAC1D,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEnB,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,QAAQ,GAAG,YAAY,CAAC;AAE9B,KAAK,UAAU,cAAc;IAC3B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;QAE/C,yBAAyB;QAEzB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAC,EAAC,KAAK,EAAC,IAAI,EAAC,CAAC,CAAC;QAEnC,MAAM,SAAS,GAAG,IAAI,cAAc,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAI,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAEzD,uCAAuC;QAEvC,MAAM,QAAQ,GAAI,SAAS,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAGtB,yBAAyB;QAEzB,EAAE,CAAC,SAAS,CAAC,sBAAsB,EAAC,QAAQ,EAAC,OAAO,EAAC,CAAC,GAAG,EAAC,EAAE;YAC1D,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEnB,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,cAAc,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aaex-file-router",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "A file-based routing system for React projects that automatically generates routes from your file structure. Similar to Next.js App Router or Remix file conventions.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {