aaex-file-router 1.0.2 → 1.2.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 +114 -37
- package/dist/components/FileLink.d.ts +8 -0
- package/dist/components/FileLink.d.ts.map +1 -0
- package/dist/components/FileLink.js +6 -0
- package/dist/components/FileLink.js.map +1 -0
- package/dist/core/FileScanner.js +1 -1
- package/dist/core/FileScanner.js.map +1 -1
- package/dist/core/RouteGenerator.d.ts +6 -1
- package/dist/core/RouteGenerator.d.ts.map +1 -1
- package/dist/core/RouteGenerator.js +119 -101
- package/dist/core/RouteGenerator.js.map +1 -1
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/pages/test/about.d.ts +1 -0
- package/dist/pages/test/about.d.ts.map +1 -0
- package/dist/pages/test/about.js +2 -0
- package/dist/pages/test/about.js.map +1 -0
- package/dist/pages/users/[id].d.ts +1 -0
- package/dist/pages/users/[id].d.ts.map +1 -0
- package/dist/pages/users/[id].js +2 -0
- package/dist/pages/users/[id].js.map +1 -0
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +14 -12
- package/dist/plugin.js.map +1 -1
- package/dist/test/index.js +4 -8
- package/dist/test/index.js.map +1 -1
- package/package.json +48 -40
- package/dist/test/routes.d.ts +0 -4
- package/dist/test/routes.d.ts.map +0 -1
- package/dist/test/routes.js +0 -20
- package/dist/test/routes.js.map +0 -1
- package/dist/test/routes.ts +0 -26
package/README.md
CHANGED
|
@@ -2,17 +2,20 @@
|
|
|
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.0
|
|
6
|
-
Fixed issue that required --legacy-peer-deps flag for installation
|
|
5
|
+
## V. 1.2.0
|
|
7
6
|
|
|
7
|
+
Added support for slugs in urls ex: - pages - users - [id].tsx
|
|
8
|
+
resolves to users/:id
|
|
8
9
|
|
|
9
10
|
## Features
|
|
10
11
|
|
|
11
12
|
- **Automatic Route Generation**: Routes are generated based on your file and folder structure
|
|
12
13
|
- **Layout Support**: Create `layout.tsx` files to wrap nested routes
|
|
14
|
+
- **Slug Support**: Creates dynamic routes for [slug] files
|
|
13
15
|
- **Static & Lazy Loading**: Top-level routes use static imports, nested routes use lazy loading
|
|
14
16
|
- **Hot Reload**: Vite plugin watches for file changes and regenerates routes automatically
|
|
15
17
|
- **TypeScript Support**: Full TypeScript support with generated route types
|
|
18
|
+
- **Type safe link component**: Link component that knows what routes are available
|
|
16
19
|
|
|
17
20
|
## Installation
|
|
18
21
|
|
|
@@ -31,23 +34,24 @@ src/pages/
|
|
|
31
34
|
└── test/
|
|
32
35
|
├── layout.tsx # Layout wrapper for /test/* routes
|
|
33
36
|
├── index.tsx # Route "/test"
|
|
34
|
-
|
|
37
|
+
├── hello.tsx # Route "/test/hello"
|
|
38
|
+
└── [slug].tsx # Route "/test/:slug"
|
|
35
39
|
```
|
|
36
40
|
|
|
37
41
|
### 2. Configure Vite
|
|
38
42
|
|
|
39
43
|
```typescript
|
|
40
44
|
// vite.config.ts
|
|
41
|
-
import { defineConfig } from
|
|
42
|
-
import react from
|
|
43
|
-
import { aaexFileRouter } from
|
|
45
|
+
import { defineConfig } from "vite";
|
|
46
|
+
import react from "@vitejs/plugin-react";
|
|
47
|
+
import { aaexFileRouter } from "aaex-file-router";
|
|
44
48
|
|
|
45
49
|
export default defineConfig({
|
|
46
50
|
plugins: [
|
|
47
51
|
react(),
|
|
48
52
|
aaexFileRouter({
|
|
49
|
-
pagesDir:
|
|
50
|
-
outputFile:
|
|
53
|
+
pagesDir: "./src/pages", //page files location(optional: default ./src/pages)
|
|
54
|
+
outputFile: "./src/routes.ts", //generated routes (default: ./src/routes.ts)
|
|
51
55
|
}),
|
|
52
56
|
],
|
|
53
57
|
});
|
|
@@ -57,14 +61,14 @@ export default defineConfig({
|
|
|
57
61
|
|
|
58
62
|
```typescript
|
|
59
63
|
// src/main.tsx
|
|
60
|
-
import React from
|
|
61
|
-
import ReactDOM from
|
|
62
|
-
import { RouterProvider, createBrowserRouter } from
|
|
63
|
-
import routes from
|
|
64
|
+
import React from "react";
|
|
65
|
+
import ReactDOM from "react-dom/client";
|
|
66
|
+
import { RouterProvider, createBrowserRouter } from "react-router-dom";
|
|
67
|
+
import routes from "./routes";
|
|
64
68
|
|
|
65
69
|
const router = createBrowserRouter(routes);
|
|
66
70
|
|
|
67
|
-
ReactDOM.createRoot(document.getElementById(
|
|
71
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
68
72
|
<React.StrictMode>
|
|
69
73
|
<RouterProvider router={router} />
|
|
70
74
|
</React.StrictMode>
|
|
@@ -74,17 +78,21 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
74
78
|
## File Conventions
|
|
75
79
|
|
|
76
80
|
### `index.tsx`
|
|
81
|
+
|
|
77
82
|
Renders at the parent route path.
|
|
83
|
+
|
|
78
84
|
```
|
|
79
85
|
pages/index.tsx → "/"
|
|
80
86
|
pages/about/index.tsx → "/about"
|
|
81
87
|
```
|
|
82
88
|
|
|
83
89
|
### `layout.tsx`
|
|
90
|
+
|
|
84
91
|
Wraps all sibling and nested routes. Children are rendered in an `<Outlet />`.
|
|
92
|
+
|
|
85
93
|
```typescript
|
|
86
94
|
// pages/admin/layout.tsx
|
|
87
|
-
import { Outlet } from
|
|
95
|
+
import { Outlet } from "react-router-dom";
|
|
88
96
|
|
|
89
97
|
export default function AdminLayout() {
|
|
90
98
|
return (
|
|
@@ -96,8 +104,31 @@ export default function AdminLayout() {
|
|
|
96
104
|
}
|
|
97
105
|
```
|
|
98
106
|
|
|
107
|
+
### Slug files
|
|
108
|
+
|
|
109
|
+
Filenames wrapper in hardbrackets `[filename]` will resolve to a dynamic route
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
pages/test/[<filename>].tsx → "/test/:<filename>"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
//pages/test/[slug].tsx
|
|
117
|
+
|
|
118
|
+
import { useParams } from "react-router-dom";
|
|
119
|
+
|
|
120
|
+
export default function TestWithSlug() {
|
|
121
|
+
// replace slug with what the file is called
|
|
122
|
+
const { slug } = useParams();
|
|
123
|
+
|
|
124
|
+
return <div>{slug}</div>;
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
99
128
|
### Named files
|
|
129
|
+
|
|
100
130
|
Any other `.tsx` file becomes a route based on its filename.
|
|
131
|
+
|
|
101
132
|
```
|
|
102
133
|
pages/about.tsx → "/about"
|
|
103
134
|
pages/blog/post.tsx → "/blog/post"
|
|
@@ -110,18 +141,18 @@ The plugin generates a `routes.ts` file with all your routes:
|
|
|
110
141
|
```typescript
|
|
111
142
|
// src/routes.ts
|
|
112
143
|
// AUTO GENERATED: DO NOT EDIT
|
|
113
|
-
import React from
|
|
114
|
-
import Index from
|
|
115
|
-
import AdminLayout from
|
|
116
|
-
import type { RouteObject } from
|
|
144
|
+
import React from "react";
|
|
145
|
+
import Index from "./pages/index.tsx";
|
|
146
|
+
import AdminLayout from "./pages/admin/layout.tsx";
|
|
147
|
+
import type { RouteObject } from "react-router-dom";
|
|
117
148
|
|
|
118
149
|
const routes: RouteObject[] = [
|
|
119
150
|
{
|
|
120
|
-
path:
|
|
151
|
+
path: "/",
|
|
121
152
|
element: React.createElement(Index),
|
|
122
153
|
},
|
|
123
154
|
{
|
|
124
|
-
path:
|
|
155
|
+
path: "admin",
|
|
125
156
|
element: React.createElement(AdminLayout),
|
|
126
157
|
children: [
|
|
127
158
|
// nested routes...
|
|
@@ -134,12 +165,12 @@ export default routes;
|
|
|
134
165
|
|
|
135
166
|
## Route Resolution Examples
|
|
136
167
|
|
|
137
|
-
| File Structure
|
|
138
|
-
|
|
139
|
-
| `pages/index.tsx`
|
|
140
|
-
| `pages/about.tsx`
|
|
141
|
-
| `pages/blog/index.tsx`
|
|
142
|
-
| `pages/blog/post.tsx`
|
|
168
|
+
| File Structure | Route Path |
|
|
169
|
+
| ----------------------------------- | -------------------- |
|
|
170
|
+
| `pages/index.tsx` | `/` |
|
|
171
|
+
| `pages/about.tsx` | `/about` |
|
|
172
|
+
| `pages/blog/index.tsx` | `/blog` |
|
|
173
|
+
| `pages/blog/post.tsx` | `/blog/post` |
|
|
143
174
|
| `pages/admin/layout.tsx` + children | `/admin/*` (grouped) |
|
|
144
175
|
|
|
145
176
|
## Layouts
|
|
@@ -148,7 +179,7 @@ Layouts wrap their child routes and provide shared UI:
|
|
|
148
179
|
|
|
149
180
|
```typescript
|
|
150
181
|
// pages/dashboard/layout.tsx
|
|
151
|
-
import { Outlet } from
|
|
182
|
+
import { Outlet } from "react-router-dom";
|
|
152
183
|
|
|
153
184
|
export default function DashboardLayout() {
|
|
154
185
|
return (
|
|
@@ -164,39 +195,79 @@ export default function DashboardLayout() {
|
|
|
164
195
|
|
|
165
196
|
All routes in `pages/dashboard/*` will render inside this layout.
|
|
166
197
|
|
|
198
|
+
## FileLink component
|
|
199
|
+
|
|
200
|
+
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.
|
|
201
|
+
|
|
202
|
+
## Notice!
|
|
203
|
+
|
|
204
|
+
At the moment it can only do the basic routing where the "to" prop is a string.
|
|
205
|
+
React Router's normal Link still works in cases where type safety is less important.
|
|
206
|
+
|
|
207
|
+
## Usage
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
// src/routeTypes.ts
|
|
211
|
+
// * AUTO GENERATED: DO NOT EDIT
|
|
212
|
+
|
|
213
|
+
//this file is auto generated along with the route definition file
|
|
214
|
+
export type FileRoutes = "/" | "test";
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
//src/pages/index.tsx
|
|
219
|
+
import { FileLink } from "aaex-file-router";
|
|
220
|
+
import type { FileRoutes } from "../routeTypes";
|
|
221
|
+
|
|
222
|
+
export default function Home() {
|
|
223
|
+
return (
|
|
224
|
+
<>
|
|
225
|
+
Hello Home!
|
|
226
|
+
{/* FileRoutes is optional and not required it will work fine with any string if not passed */}
|
|
227
|
+
<FileLink<FileRoutes> to="test">Test safe</FileLink>
|
|
228
|
+
//or //no type safety
|
|
229
|
+
<FileLink to="some-route">Non safe</FileLink>
|
|
230
|
+
</>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
167
235
|
## API Reference
|
|
168
236
|
|
|
169
237
|
### FileScanner
|
|
238
|
+
|
|
170
239
|
Scans the file system and converts files into a structured format.
|
|
171
240
|
|
|
172
241
|
```typescript
|
|
173
|
-
import { FileScanner } from
|
|
242
|
+
import { FileScanner } from "aaex-file-router/core";
|
|
174
243
|
|
|
175
|
-
const scanner = new FileScanner(
|
|
244
|
+
const scanner = new FileScanner("./src/pages");
|
|
176
245
|
const fileData = await scanner.get_file_data();
|
|
177
246
|
```
|
|
178
247
|
|
|
179
248
|
### RouteGenerator
|
|
249
|
+
|
|
180
250
|
Converts file structure into React Router route configuration.
|
|
181
251
|
|
|
182
252
|
```typescript
|
|
183
|
-
import { RouteGenerator } from
|
|
253
|
+
import { RouteGenerator } from "aaex-file-router/core";
|
|
184
254
|
|
|
185
255
|
const generator = new RouteGenerator();
|
|
186
256
|
const routesCode = await generator.generateComponentsMap(fileData);
|
|
187
257
|
```
|
|
188
258
|
|
|
189
259
|
### aaexFileRouter (Vite Plugin)
|
|
260
|
+
|
|
190
261
|
Automatically watches for file changes and regenerates routes.
|
|
191
262
|
|
|
192
263
|
```typescript
|
|
193
|
-
import { aaexFileRouter } from
|
|
264
|
+
import { aaexFileRouter } from "aaex-file-router/core";
|
|
194
265
|
|
|
195
266
|
export default defineConfig({
|
|
196
267
|
plugins: [
|
|
197
268
|
aaexFileRouter({
|
|
198
|
-
pagesDir:
|
|
199
|
-
outputFile:
|
|
269
|
+
pagesDir: "./src/pages",
|
|
270
|
+
outputFile: "./src/routes.ts",
|
|
200
271
|
}),
|
|
201
272
|
],
|
|
202
273
|
});
|
|
@@ -206,7 +277,7 @@ export default defineConfig({
|
|
|
206
277
|
|
|
207
278
|
1. **File Scanning**: Recursively scans your pages directory and builds a file tree
|
|
208
279
|
2. **Route Generation**: Converts the file structure into React Router `RouteObject` format
|
|
209
|
-
3. **Smart Importing**:
|
|
280
|
+
3. **Smart Importing**:
|
|
210
281
|
- Top-level files use static imports for faster initial load
|
|
211
282
|
- Nested/grouped routes use lazy loading for code splitting
|
|
212
283
|
- Layout files are statically imported as route wrappers
|
|
@@ -221,7 +292,8 @@ export default defineConfig({
|
|
|
221
292
|
## Common Patterns
|
|
222
293
|
|
|
223
294
|
### Shared Layout
|
|
224
|
-
|
|
295
|
+
|
|
296
|
+
```sh
|
|
225
297
|
pages/
|
|
226
298
|
├── layout.tsx # Wraps entire app
|
|
227
299
|
├── index.tsx
|
|
@@ -229,7 +301,8 @@ pages/
|
|
|
229
301
|
```
|
|
230
302
|
|
|
231
303
|
### Nested Layouts
|
|
232
|
-
|
|
304
|
+
|
|
305
|
+
```sh
|
|
233
306
|
pages/
|
|
234
307
|
├── layout.tsx # Root layout
|
|
235
308
|
├── admin/
|
|
@@ -239,7 +312,8 @@ pages/
|
|
|
239
312
|
```
|
|
240
313
|
|
|
241
314
|
### Route Groups Without Layout
|
|
242
|
-
|
|
315
|
+
|
|
316
|
+
```sh
|
|
243
317
|
pages/
|
|
244
318
|
├── blog/
|
|
245
319
|
│ ├── post.tsx # Routes as /blog/post (no grouping)
|
|
@@ -249,14 +323,17 @@ pages/
|
|
|
249
323
|
## Troubleshooting
|
|
250
324
|
|
|
251
325
|
### Routes not updating on file change
|
|
326
|
+
|
|
252
327
|
- Ensure Vite dev server is running (`npm run dev`)
|
|
253
328
|
- Check that `pagesDir` in vite config matches your actual pages directory
|
|
254
329
|
|
|
255
330
|
### Duplicate imports in generated file
|
|
331
|
+
|
|
256
332
|
- This shouldn't happen, but if it does, try restarting the dev server
|
|
257
333
|
- Check for files with the same name in different directories
|
|
258
334
|
|
|
259
335
|
### Unexpected route paths
|
|
336
|
+
|
|
260
337
|
- Remember: `index.tsx` files inherit their parent's path
|
|
261
338
|
- Directories without `layout.tsx` flatten their children into absolute routes
|
|
262
339
|
- File names are converted to lowercase for routes
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface FileLinkProps<RouteType extends string = string> {
|
|
3
|
+
to: RouteType;
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export declare function FileLink<RouteType extends string = string>({ to, children, }: FileLinkProps<RouteType>): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=FileLink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileLink.d.ts","sourceRoot":"","sources":["../../src/components/FileLink.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,aAAa,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM;IACvD,EAAE,EAAE,SAAS,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,QAAQ,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,EAAE,EAC1D,EAAE,EACF,QAAQ,GACT,EAAE,aAAa,CAAC,SAAS,CAAC,2CAE1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileLink.js","sourceRoot":"","sources":["../../src/components/FileLink.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAOxC,MAAM,UAAU,QAAQ,CAAoC,EAC1D,EAAE,EACF,QAAQ,GACiB;IACzB,OAAO,KAAC,IAAI,IAAC,EAAE,EAAE,EAAE,YAAG,QAAQ,GAAQ,CAAC;AACzC,CAAC"}
|
package/dist/core/FileScanner.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileScanner.js","sourceRoot":"","sources":["../../src/core/FileScanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,QAAQ,IAAI,EAAE,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"FileScanner.js","sourceRoot":"","sources":["../../src/core/FileScanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,6 @@ export declare class RouteGenerator {
|
|
|
3
3
|
private topLevelImports;
|
|
4
4
|
private importSet;
|
|
5
5
|
private processedFiles;
|
|
6
|
-
private clearImports;
|
|
7
6
|
/**
|
|
8
7
|
* Recursively converts FileData tree into React Router RouteConfig array
|
|
9
8
|
* Handles layout files, index files, and nested routes with proper pathing
|
|
@@ -18,5 +17,11 @@ export declare class RouteGenerator {
|
|
|
18
17
|
* @returns Complete routes file content ready to be written to disk
|
|
19
18
|
*/
|
|
20
19
|
generateComponentsMap(fileData: FileData[]): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Generates a TypeScript definition file exporting a union type of all route paths
|
|
22
|
+
* @param fileData - FileData tree from FileScanner
|
|
23
|
+
* @returns Type definition file content as string
|
|
24
|
+
*/
|
|
25
|
+
generateRoutesTypeDef(fileData: FileData[]): Promise<string>;
|
|
21
26
|
}
|
|
22
27
|
//# sourceMappingURL=RouteGenerator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouteGenerator.d.ts","sourceRoot":"","sources":["../../src/core/RouteGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AASzC,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,cAAc,CAA0B;IAEhD,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"RouteGenerator.d.ts","sourceRoot":"","sources":["../../src/core/RouteGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AASzC,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,cAAc,CAA0B;IAEhD;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAkLxB;;;;;OAKG;IACU,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA8BzE;;;;OAIG;IACS,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAwCzE"}
|
|
@@ -2,9 +2,6 @@ export class RouteGenerator {
|
|
|
2
2
|
topLevelImports = [];
|
|
3
3
|
importSet = new Set();
|
|
4
4
|
processedFiles = new Set();
|
|
5
|
-
clearImports() {
|
|
6
|
-
this.topLevelImports = [];
|
|
7
|
-
}
|
|
8
5
|
/**
|
|
9
6
|
* Recursively converts FileData tree into React Router RouteConfig array
|
|
10
7
|
* Handles layout files, index files, and nested routes with proper pathing
|
|
@@ -14,6 +11,8 @@ export class RouteGenerator {
|
|
|
14
11
|
fileDataToRoutes(fileData, parentPath = "", flattenPrefix = "", inGroup = false) {
|
|
15
12
|
const routes = [];
|
|
16
13
|
const processedIndexes = new Set();
|
|
14
|
+
/** Converts `[slug]` → `:slug` */
|
|
15
|
+
const normalizeDynamicSegment = (name) => name.replace(/\[([^\]]+)\]/g, ":$1");
|
|
17
16
|
/**
|
|
18
17
|
* Utility function to safely join path segments
|
|
19
18
|
* - Filters out empty/falsy parts to avoid "///" in paths
|
|
@@ -23,119 +22,103 @@ export class RouteGenerator {
|
|
|
23
22
|
* Example: posixJoin("pages\\test", "hello") -> "pages/test/hello"
|
|
24
23
|
*/
|
|
25
24
|
const posixJoin = (...parts) => parts.filter(Boolean).join("/").replace(/\\/g, "/");
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
25
|
+
/** Converts "user", "[id]" → "User", "Id" */
|
|
26
|
+
const toPascal = (str) => str
|
|
27
|
+
.replace(/\[|\]/g, "")
|
|
28
|
+
.replace(/(^\w|[-_]\w)/g, (m) => m.replace(/[-_]/, "").toUpperCase());
|
|
29
|
+
/** Build import name from parent folder + file */
|
|
30
|
+
const getImportName = (file) => {
|
|
31
|
+
const segments = file.relative_path.replace(/^src[\/\\]/, "").split("/");
|
|
32
|
+
const parentFolder = segments.length > 1 ? segments[segments.length - 2] : "";
|
|
33
|
+
const parentName = parentFolder ? toPascal(parentFolder) : "";
|
|
34
|
+
const nameWithoutExt = file.name.replace(/\.[jt]sx?$/, "");
|
|
35
|
+
const fileNamePart = nameWithoutExt.toLowerCase() === "index"
|
|
36
|
+
? ""
|
|
37
|
+
: toPascal(nameWithoutExt);
|
|
38
|
+
return `${parentName}${fileNamePart}`;
|
|
39
|
+
};
|
|
40
|
+
/** Create route object (handles lazy vs top-level import) */
|
|
41
|
+
const createRoute = (file, path, importName, lazy = false) => {
|
|
42
|
+
const filePath = file.relative_path.replace(/^src[\/\\]/, "./");
|
|
43
|
+
const element = lazy
|
|
44
|
+
? `React.createElement(React.lazy(() => import('${filePath}')))`
|
|
45
|
+
: `React.createElement(${importName})`;
|
|
46
|
+
return { path: normalizeDynamicSegment(path), element };
|
|
47
|
+
};
|
|
48
|
+
/** Recursive processing */
|
|
49
|
+
const processFile = (file, currentParentPath, currentFlatten, group) => {
|
|
50
|
+
if (!file.isDirectory && this.processedFiles.has(file.relative_path))
|
|
51
|
+
return;
|
|
52
|
+
if (file.isDirectory && file.children?.length) {
|
|
53
|
+
const layoutFile = file.children.find((c) => !c.isDirectory && /^layout\.(tsx|jsx|ts|js)$/i.test(c.name));
|
|
54
|
+
if (!layoutFile) {
|
|
55
|
+
const newFlatten = posixJoin(currentFlatten, file.name.toLowerCase());
|
|
56
|
+
routes.push(...this.fileDataToRoutes(file.children, currentParentPath, newFlatten, false));
|
|
57
|
+
return;
|
|
38
58
|
}
|
|
39
|
-
|
|
40
|
-
const layoutPath =
|
|
41
|
-
const layoutImportName = `TestLayout`;
|
|
59
|
+
const layoutImportName = "TestLayout";
|
|
60
|
+
const layoutPath = layoutFile.relative_path.replace(/^src[\/\\]/, "./");
|
|
42
61
|
this.topLevelImports.push(`import ${layoutImportName} from '${layoutPath}';`);
|
|
43
|
-
this.processedFiles.add(
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const nonLayoutChildren = file.children.filter((c) => !/^layout\.(tsx|jsx|ts|js)$/i.test(c.name));
|
|
47
|
-
for (const child of nonLayoutChildren) {
|
|
62
|
+
this.processedFiles.add(layoutFile.relative_path);
|
|
63
|
+
const childRoutes = [];
|
|
64
|
+
for (const child of file.children.filter((c) => !/^layout\.(tsx|jsx|ts|js)$/i.test(c.name))) {
|
|
48
65
|
if (child.isDirectory) {
|
|
49
|
-
|
|
50
|
-
childrenRoutes.push(...this.fileDataToRoutes([child], posixJoin(parentPath, file.name), "", true));
|
|
66
|
+
processFile(child, posixJoin(currentParentPath, file.name), "", true);
|
|
51
67
|
}
|
|
52
68
|
else {
|
|
53
69
|
const childNameWithoutExt = child.name.replace(/\.[jt]sx?$/, "");
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
path: "",
|
|
59
|
-
element: `React.createElement(React.lazy(() => import('${childPath}')))`,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
childrenRoutes.push({
|
|
64
|
-
path: childNameWithoutExt.toLowerCase(),
|
|
65
|
-
element: `React.createElement(React.lazy(() => import('${childPath}')))`,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
// Mark child as processed so it doesn't get added as top-level
|
|
70
|
+
const path = childNameWithoutExt.toLowerCase() === "index"
|
|
71
|
+
? ""
|
|
72
|
+
: normalizeDynamicSegment(childNameWithoutExt.toLowerCase());
|
|
73
|
+
childRoutes.push(createRoute(child, path, undefined, true));
|
|
69
74
|
this.processedFiles.add(child.relative_path);
|
|
70
75
|
}
|
|
71
76
|
}
|
|
72
77
|
routes.push({
|
|
73
|
-
path: file.name.toLowerCase(),
|
|
78
|
+
path: normalizeDynamicSegment(file.name.toLowerCase()),
|
|
74
79
|
element: `React.createElement(${layoutImportName})`,
|
|
75
|
-
children:
|
|
80
|
+
children: childRoutes.length ? childRoutes : undefined,
|
|
76
81
|
});
|
|
82
|
+
return;
|
|
77
83
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const siblingDirExists = fileData.some((f) => f.isDirectory &&
|
|
87
|
-
f.name.toLowerCase() === nameWithoutExt.toLowerCase());
|
|
88
|
-
if (siblingDirExists) {
|
|
89
|
-
this.processedFiles.add(file.relative_path);
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
// Skip layout files
|
|
93
|
-
if (/^layout\.(tsx|jsx|ts|js)$/i.test(file.name)) {
|
|
94
|
-
this.processedFiles.add(file.relative_path);
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
// Determine path
|
|
98
|
-
const fileSegment = isIndexFile ? "" : nameWithoutExt.toLowerCase();
|
|
99
|
-
let fullPath;
|
|
100
|
-
if (flattenPrefix) {
|
|
101
|
-
fullPath = posixJoin(flattenPrefix, fileSegment);
|
|
102
|
-
}
|
|
103
|
-
else if (inGroup) {
|
|
104
|
-
fullPath = fileSegment;
|
|
105
|
-
}
|
|
106
|
-
else if (parentPath) {
|
|
107
|
-
fullPath = posixJoin(parentPath, fileSegment);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
fullPath = isIndexFile ? "/" : fileSegment;
|
|
111
|
-
}
|
|
112
|
-
// Create import & avoid duplicates
|
|
113
|
-
const importNameBase = nameWithoutExt.replace(/[^a-zA-Z0-9]/g, "_");
|
|
114
|
-
const capitalized = importNameBase.charAt(0).toUpperCase() + importNameBase.slice(1);
|
|
115
|
-
const filePath = file.relative_path.replace(/^src[\/\\]/, "./");
|
|
116
|
-
if (inGroup) {
|
|
117
|
-
// Lazy-load child component inside group
|
|
118
|
-
routes.push({
|
|
119
|
-
path: fullPath === "/" ? "" : fullPath.replace(/^\/+/, ""),
|
|
120
|
-
element: `React.createElement(React.lazy(() => import('${filePath}')))`,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
// Top-level files use static imports
|
|
125
|
-
if (!this.importSet.has(filePath)) {
|
|
126
|
-
this.topLevelImports.push(`import ${capitalized} from '${filePath}';`);
|
|
127
|
-
this.importSet.add(filePath);
|
|
128
|
-
}
|
|
129
|
-
routes.push({
|
|
130
|
-
path: fullPath === "/" ? "/" : fullPath.replace(/^\/+/, ""),
|
|
131
|
-
element: `React.createElement(${capitalized})`,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
84
|
+
// ---------------- FILES ----------------
|
|
85
|
+
const nameWithoutExt = file.name.replace(/\.[jt]sx?$/, "");
|
|
86
|
+
const isIndex = nameWithoutExt.toLowerCase() === "index";
|
|
87
|
+
if (isIndex && processedIndexes.has(file.relative_path))
|
|
88
|
+
return;
|
|
89
|
+
if (fileData.some((f) => f.isDirectory &&
|
|
90
|
+
f.name.toLowerCase() === nameWithoutExt.toLowerCase()) ||
|
|
91
|
+
/^layout\.(tsx|jsx|ts|js)$/i.test(file.name)) {
|
|
134
92
|
this.processedFiles.add(file.relative_path);
|
|
135
|
-
|
|
136
|
-
processedIndexes.add(file.relative_path);
|
|
93
|
+
return;
|
|
137
94
|
}
|
|
138
|
-
|
|
95
|
+
const rawSegment = isIndex ? "" : nameWithoutExt.toLowerCase();
|
|
96
|
+
const fileSegment = normalizeDynamicSegment(rawSegment);
|
|
97
|
+
let fullPath;
|
|
98
|
+
if (currentFlatten)
|
|
99
|
+
fullPath = posixJoin(currentFlatten, fileSegment);
|
|
100
|
+
else if (group)
|
|
101
|
+
fullPath = fileSegment;
|
|
102
|
+
else if (currentParentPath)
|
|
103
|
+
fullPath = posixJoin(currentParentPath, fileSegment);
|
|
104
|
+
else
|
|
105
|
+
fullPath = isIndex ? "/" : fileSegment;
|
|
106
|
+
const importName = getImportName(file);
|
|
107
|
+
if (group)
|
|
108
|
+
routes.push(createRoute(file, fullPath, undefined, true));
|
|
109
|
+
else {
|
|
110
|
+
if (!this.importSet.has(file.relative_path)) {
|
|
111
|
+
this.topLevelImports.push(`import ${importName} from './${file.relative_path.replace(/^src[\/\\]/, "")}';`);
|
|
112
|
+
this.importSet.add(file.relative_path);
|
|
113
|
+
}
|
|
114
|
+
routes.push(createRoute(file, fullPath, importName));
|
|
115
|
+
}
|
|
116
|
+
this.processedFiles.add(file.relative_path);
|
|
117
|
+
if (isIndex)
|
|
118
|
+
processedIndexes.add(file.relative_path);
|
|
119
|
+
};
|
|
120
|
+
for (const file of fileData)
|
|
121
|
+
processFile(file, parentPath, flattenPrefix, inGroup);
|
|
139
122
|
return routes;
|
|
140
123
|
}
|
|
141
124
|
/**
|
|
@@ -166,5 +149,40 @@ export default routes;
|
|
|
166
149
|
`;
|
|
167
150
|
return mapString;
|
|
168
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Generates a TypeScript definition file exporting a union type of all route paths
|
|
154
|
+
* @param fileData - FileData tree from FileScanner
|
|
155
|
+
* @returns Type definition file content as string
|
|
156
|
+
*/
|
|
157
|
+
async generateRoutesTypeDef(fileData) {
|
|
158
|
+
// Reset state
|
|
159
|
+
this.topLevelImports = [];
|
|
160
|
+
this.importSet = new Set();
|
|
161
|
+
this.processedFiles = new Set();
|
|
162
|
+
const routes = this.fileDataToRoutes(fileData);
|
|
163
|
+
const routePaths = [];
|
|
164
|
+
const addRoute = (route, parentPath = "") => {
|
|
165
|
+
const fullPath = parentPath
|
|
166
|
+
? `${parentPath}/${route.path}`.replace(/\/+/g, "/")
|
|
167
|
+
: route.path;
|
|
168
|
+
// Replace ":param" with ${string} for TypeScript type
|
|
169
|
+
const tsPath = fullPath
|
|
170
|
+
.split("/")
|
|
171
|
+
.map((seg) => (seg.startsWith(":") ? "${string}" : seg))
|
|
172
|
+
.join("/");
|
|
173
|
+
routePaths.push(tsPath);
|
|
174
|
+
if (route.children?.length) {
|
|
175
|
+
route.children.forEach((child) => addRoute(child, fullPath));
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
routes.forEach((route) => addRoute(route));
|
|
179
|
+
const uniquePaths = Array.from(new Set(routePaths))
|
|
180
|
+
.map((p) => `\`${p}\``) // wrap in backticks for template literal types
|
|
181
|
+
.join(" | ");
|
|
182
|
+
return `// * AUTO GENERATED: DO NOT EDIT
|
|
183
|
+
|
|
184
|
+
export type FileRoutes = ${uniquePaths};
|
|
185
|
+
`;
|
|
186
|
+
}
|
|
169
187
|
}
|
|
170
188
|
//# sourceMappingURL=RouteGenerator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouteGenerator.js","sourceRoot":"","sources":["../../src/core/RouteGenerator.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,cAAc;IACjB,eAAe,GAAa,EAAE,CAAC;IAC/B,SAAS,GAAgB,IAAI,GAAG,EAAE,CAAC;IACnC,cAAc,GAAgB,IAAI,GAAG,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"RouteGenerator.js","sourceRoot":"","sources":["../../src/core/RouteGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,gDAAgD;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { RouteGenerator } from './core/RouteGenerator.js';
|
|
3
|
-
export { aaexFileRouter } from './plugin.js';
|
|
4
|
-
export type { VitePluginOptions } from './plugin.js';
|
|
1
|
+
export { FileLink } from "./components/FileLink.js";
|
|
5
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { RouteGenerator } from './core/RouteGenerator.js';
|
|
3
|
-
// export type { FileData } from './core/types';
|
|
4
|
-
export { aaexFileRouter } from './plugin.js';
|
|
1
|
+
export { FileLink } from "./components/FileLink.js";
|
|
5
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=about.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"about.d.ts","sourceRoot":"","sources":["../../../src/pages/test/about.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"about.js","sourceRoot":"","sources":["../../../src/pages/test/about.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=%5Bid%5D.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"[id].d.ts","sourceRoot":"","sources":["../../../src/pages/users/[id].tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"[id].js","sourceRoot":"","sources":["../../../src/pages/users/[id].tsx"],"names":[],"mappings":""}
|
package/dist/plugin.d.ts
CHANGED
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAM9B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAM9B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAmDtE"}
|
package/dist/plugin.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { promises as fs } from
|
|
2
|
-
import path from
|
|
3
|
-
import { FileScanner } from
|
|
4
|
-
import { RouteGenerator } from
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { FileScanner } from "./core/FileScanner.js";
|
|
4
|
+
import { RouteGenerator } from "./core/RouteGenerator.js";
|
|
5
5
|
/**
|
|
6
6
|
* Vite plugin that auto-generates routes when page files change
|
|
7
7
|
* Watches the pages directory and regenerates routes.ts on file create/delete
|
|
8
8
|
*/
|
|
9
9
|
export function aaexFileRouter(options = {}) {
|
|
10
|
-
const pagesDir = options.pagesDir ||
|
|
11
|
-
const outputFile = options.outputFile ||
|
|
10
|
+
const pagesDir = options.pagesDir || "./src/pages";
|
|
11
|
+
const outputFile = options.outputFile || "./src/routes.ts";
|
|
12
12
|
let scanner;
|
|
13
13
|
let generator;
|
|
14
14
|
return {
|
|
15
|
-
name:
|
|
16
|
-
apply:
|
|
15
|
+
name: "aaex-file-router",
|
|
16
|
+
apply: "serve", // Only run in dev mode
|
|
17
17
|
configResolved() {
|
|
18
18
|
scanner = new FileScanner(pagesDir);
|
|
19
19
|
generator = new RouteGenerator();
|
|
@@ -21,9 +21,9 @@ export function aaexFileRouter(options = {}) {
|
|
|
21
21
|
async configureServer(server) {
|
|
22
22
|
// Watch the pages directory for changes
|
|
23
23
|
server.watcher.add(path.resolve(process.cwd(), pagesDir));
|
|
24
|
-
server.watcher.on(
|
|
24
|
+
server.watcher.on("all", async (event, filePath) => {
|
|
25
25
|
// Only regenerate on file add/unlink events
|
|
26
|
-
if (event ===
|
|
26
|
+
if (event === "add" || event === "unlink") {
|
|
27
27
|
try {
|
|
28
28
|
console.log(`📄 [aaex-file-router] ${event}: ${filePath}`);
|
|
29
29
|
// Regenerate routes
|
|
@@ -31,12 +31,14 @@ export function aaexFileRouter(options = {}) {
|
|
|
31
31
|
generator = new RouteGenerator();
|
|
32
32
|
const fileData = await scanner.get_file_data();
|
|
33
33
|
const routesCode = await generator.generateComponentsMap(fileData);
|
|
34
|
+
const routesType = await generator.generateRoutesTypeDef(fileData);
|
|
34
35
|
// Write routes file
|
|
35
|
-
await fs.writeFile(outputFile, routesCode,
|
|
36
|
+
await fs.writeFile(outputFile, routesCode, "utf-8");
|
|
37
|
+
await fs.writeFile("src/routeTypes.ts", routesType, "utf-8");
|
|
36
38
|
console.log(`✅ [aaex-file-router] Routes regenerated at ${outputFile}`);
|
|
37
39
|
}
|
|
38
40
|
catch (error) {
|
|
39
|
-
console.error(
|
|
41
|
+
console.error("❌ [aaex-file-router] Error regenerating routes:", error);
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
});
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/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,uBAAuB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAO1D;;;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,qBAAqB,CAAC,QAAQ,CAAC,CAAC;wBACnE,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"}
|
package/dist/test/index.js
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import { fileURLToPath } from "url";
|
|
2
2
|
import { FileScanner } from "../core/FileScanner.js";
|
|
3
3
|
import { RouteGenerator } from "../core/RouteGenerator.js";
|
|
4
|
-
import { promises as fs } from "fs";
|
|
5
|
-
import path from "path";
|
|
6
4
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
8
5
|
const pagesDir = "/src/pages";
|
|
9
6
|
async function generateRoutes() {
|
|
10
7
|
try {
|
|
11
8
|
const scanner = new FileScanner(pagesDir);
|
|
12
9
|
const fileData = await scanner.get_file_data();
|
|
10
|
+
// console.log(fileData);
|
|
13
11
|
const generator = new RouteGenerator();
|
|
14
12
|
const routeMap = await generator.generateComponentsMap(fileData);
|
|
15
|
-
//
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
await fs.writeFile(filePath, routeMap, "utf-8");
|
|
19
|
-
console.log(`Routes file created at: ${filePath}`);
|
|
13
|
+
// console.log("Route map: ", routeMap)
|
|
14
|
+
const routType = await generator.generateRoutesTypeDef(fileData);
|
|
15
|
+
console.log(routType);
|
|
20
16
|
}
|
|
21
17
|
catch (error) {
|
|
22
18
|
console.error("Error generating routes:", error);
|
package/dist/test/index.js.map
CHANGED
|
@@ -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;
|
|
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;AAG3D,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;QAG/C,yBAAyB;QAGzB,MAAM,SAAS,GAAG,IAAI,cAAc,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAGjE,uCAAuC;QAEvC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAEjE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAGxB,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,40 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "aaex-file-router",
|
|
3
|
-
"version": "1.0
|
|
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
|
-
"main": "dist/index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
-
"build": "npx tsc",
|
|
9
|
-
"dev": "npx tsc --watch"
|
|
10
|
-
},
|
|
11
|
-
"keywords": [
|
|
12
|
-
"react",
|
|
13
|
-
"router",
|
|
14
|
-
"vite-plugin"
|
|
15
|
-
],
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"react": "^19.2.0",
|
|
35
|
-
"react-dom": "^19.2.0",
|
|
36
|
-
"react-router-dom": "^7.9.6",
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "aaex-file-router",
|
|
3
|
+
"version": "1.2.0",
|
|
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
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"build": "npx tsc",
|
|
9
|
+
"dev": "npx tsc --watch"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"react",
|
|
13
|
+
"router",
|
|
14
|
+
"vite-plugin"
|
|
15
|
+
],
|
|
16
|
+
|
|
17
|
+
"exports":{
|
|
18
|
+
".": "./dist/index.js",
|
|
19
|
+
"./core": "./dist/core/index.js"
|
|
20
|
+
},
|
|
21
|
+
"author": "TmRAaEx",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"type": "module",
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENCE"
|
|
28
|
+
],
|
|
29
|
+
"types": "dist/index.d.ts",
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^24.10.1",
|
|
32
|
+
"@types/react": "^19.2.7",
|
|
33
|
+
"@types/react-dom": "^19.2.3",
|
|
34
|
+
"react": "^19.2.0",
|
|
35
|
+
"react-dom": "^19.2.0",
|
|
36
|
+
"react-router-dom": "^7.9.6",
|
|
37
|
+
"typescript": "^5.9.3",
|
|
38
|
+
"vite": "^7.2.4",
|
|
39
|
+
"vite-plugin-dts": "^4.5.4"
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"react": "^19.2.0",
|
|
44
|
+
"react-dom": "^19.2.0",
|
|
45
|
+
"react-router-dom": "^7.9.6",
|
|
46
|
+
"vite": "^7.2.4"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/dist/test/routes.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/test/routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,QAAA,MAAM,MAAM,EAAE,WAAW,EAexB,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/test/routes.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import Index from './pages/index.tsx';
|
|
3
|
-
const routes = [
|
|
4
|
-
{
|
|
5
|
-
"path": "/",
|
|
6
|
-
"element": React.createElement(Index)
|
|
7
|
-
},
|
|
8
|
-
{
|
|
9
|
-
"path": "test",
|
|
10
|
-
"element": React.createElement(React.lazy(() => import('./pages/test/layout.tsx'))),
|
|
11
|
-
"children": [
|
|
12
|
-
{
|
|
13
|
-
"path": "",
|
|
14
|
-
"element": React.createElement(React.lazy(() => import('./pages/test/index.tsx')))
|
|
15
|
-
}
|
|
16
|
-
]
|
|
17
|
-
}
|
|
18
|
-
];
|
|
19
|
-
export default routes;
|
|
20
|
-
//# sourceMappingURL=routes.js.map
|
package/dist/test/routes.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/test/routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,mBAAmB,CAAC;AAGtC,MAAM,MAAM,GAAkB;IAC5B;QACE,MAAM,EAAE,GAAG;QACX,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC;KACtC;IACD;QACE,MAAM,EAAE,MAAM;QACd,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC;QACnF,UAAU,EAAE;YACV;gBACE,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC;aACnF;SACF;KACF;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/test/routes.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import Index from './/pages/index.tsx';
|
|
4
|
-
import type { RouteObject } from 'react-router-dom';
|
|
5
|
-
|
|
6
|
-
const routes: RouteObject[] = [
|
|
7
|
-
{
|
|
8
|
-
"path": "/",
|
|
9
|
-
"element": "<Index/>"
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
"path": "test",
|
|
13
|
-
"element": React.createElement(React.lazy(() => import('.//pages/test/layout.tsx'))),
|
|
14
|
-
"children": [
|
|
15
|
-
{
|
|
16
|
-
"path": "",
|
|
17
|
-
"element": React.createElement(React.lazy(() => import('.//pages/test/index.tsx')))
|
|
18
|
-
}
|
|
19
|
-
]
|
|
20
|
-
}
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
// Convert stringified lazy imports back to actual function calls
|
|
24
|
-
// Regex: "React.createElement(React.lazy(() => import('(.*)')))" - matches stringified lazy import wrappers
|
|
25
|
-
// Replaces them with actual lazy import functions (removes surrounding quotes)
|
|
26
|
-
export default routes;
|