aaex-file-router 1.0.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/LICENSE +21 -0
- package/README.md +270 -0
- package/dist/core/FileScanner.d.ts +28 -0
- package/dist/core/FileScanner.d.ts.map +1 -0
- package/dist/core/FileScanner.js +80 -0
- package/dist/core/FileScanner.js.map +1 -0
- package/dist/core/RouteGenerator.d.ts +22 -0
- package/dist/core/RouteGenerator.d.ts.map +1 -0
- package/dist/core/RouteGenerator.js +170 -0
- package/dist/core/RouteGenerator.js.map +1 -0
- package/dist/core/types.d.ts +8 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/pages/index.d.ts +1 -0
- package/dist/pages/index.d.ts.map +1 -0
- package/dist/pages/index.js +2 -0
- package/dist/pages/index.js.map +1 -0
- package/dist/pages/test/index.d.ts +1 -0
- package/dist/pages/test/index.d.ts.map +1 -0
- package/dist/pages/test/index.js +2 -0
- package/dist/pages/test/index.js.map +1 -0
- package/dist/pages/test/layout.d.ts +1 -0
- package/dist/pages/test/layout.d.ts.map +1 -0
- package/dist/pages/test/layout.js +2 -0
- package/dist/pages/test/layout.js.map +1 -0
- package/dist/plugin.d.ts +11 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +46 -0
- package/dist/plugin.js.map +1 -0
- package/dist/test/index.d.ts +2 -0
- package/dist/test/index.d.ts.map +1 -0
- package/dist/test/index.js +26 -0
- package/dist/test/index.js.map +1 -0
- package/dist/test/routes.d.ts +4 -0
- package/dist/test/routes.d.ts.map +1 -0
- package/dist/test/routes.js +20 -0
- package/dist/test/routes.js.map +1 -0
- package/dist/test/routes.ts +26 -0
- package/dist/vite.config.d.ts +3 -0
- package/dist/vite.config.d.ts.map +1 -0
- package/dist/vite.config.js +22 -0
- package/dist/vite.config.js.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 TmRAaEx
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# AAEX File Router
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Automatic Route Generation**: Routes are generated based on your file and folder structure
|
|
8
|
+
- **Layout Support**: Create `layout.tsx` files to wrap nested routes
|
|
9
|
+
- **Static & Lazy Loading**: Top-level routes use static imports, nested routes use lazy loading
|
|
10
|
+
- **Hot Reload**: Vite plugin watches for file changes and regenerates routes automatically
|
|
11
|
+
- **TypeScript Support**: Full TypeScript support with generated route types
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install aaex-file-router
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### 1. Create your pages structure
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
src/pages/
|
|
25
|
+
├── index.tsx # Root page "/"
|
|
26
|
+
├── about.tsx # Route "/about"
|
|
27
|
+
└── test/
|
|
28
|
+
├── layout.tsx # Layout wrapper for /test/* routes
|
|
29
|
+
├── index.tsx # Route "/test"
|
|
30
|
+
└── hello.tsx # Route "/test/hello"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Configure Vite
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// vite.config.ts
|
|
37
|
+
import { defineConfig } from 'vite';
|
|
38
|
+
import react from '@vitejs/plugin-react';
|
|
39
|
+
import { aaexFileRouter } from 'aaex-file-router';
|
|
40
|
+
|
|
41
|
+
export default defineConfig({
|
|
42
|
+
plugins: [
|
|
43
|
+
react(),
|
|
44
|
+
aaexFileRouter({
|
|
45
|
+
pagesDir: './src/pages', //page files location(optional: default ./src/pages)
|
|
46
|
+
outputFile: './src/routes.ts', //generated routes (default: ./src/routes.ts)
|
|
47
|
+
}),
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. Use in your app
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// src/main.tsx
|
|
56
|
+
import React from 'react';
|
|
57
|
+
import ReactDOM from 'react-dom/client';
|
|
58
|
+
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
|
|
59
|
+
import routes from './routes';
|
|
60
|
+
|
|
61
|
+
const router = createBrowserRouter(routes);
|
|
62
|
+
|
|
63
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
64
|
+
<React.StrictMode>
|
|
65
|
+
<RouterProvider router={router} />
|
|
66
|
+
</React.StrictMode>
|
|
67
|
+
);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## File Conventions
|
|
71
|
+
|
|
72
|
+
### `index.tsx`
|
|
73
|
+
Renders at the parent route path.
|
|
74
|
+
```
|
|
75
|
+
pages/index.tsx → "/"
|
|
76
|
+
pages/about/index.tsx → "/about"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### `layout.tsx`
|
|
80
|
+
Wraps all sibling and nested routes. Children are rendered in an `<Outlet />`.
|
|
81
|
+
```typescript
|
|
82
|
+
// pages/admin/layout.tsx
|
|
83
|
+
import { Outlet } from 'react-router-dom';
|
|
84
|
+
|
|
85
|
+
export default function AdminLayout() {
|
|
86
|
+
return (
|
|
87
|
+
<div>
|
|
88
|
+
<nav>Admin Navigation</nav>
|
|
89
|
+
<Outlet /> {/* Nested routes render here */}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Named files
|
|
96
|
+
Any other `.tsx` file becomes a route based on its filename.
|
|
97
|
+
```
|
|
98
|
+
pages/about.tsx → "/about"
|
|
99
|
+
pages/blog/post.tsx → "/blog/post"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Generated Routes File
|
|
103
|
+
|
|
104
|
+
The plugin generates a `routes.ts` file with all your routes:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// src/routes.ts
|
|
108
|
+
// AUTO GENERATED: DO NOT EDIT
|
|
109
|
+
import React from 'react';
|
|
110
|
+
import Index from './pages/index.tsx';
|
|
111
|
+
import AdminLayout from './pages/admin/layout.tsx';
|
|
112
|
+
import type { RouteObject } from 'react-router-dom';
|
|
113
|
+
|
|
114
|
+
const routes: RouteObject[] = [
|
|
115
|
+
{
|
|
116
|
+
path: '/',
|
|
117
|
+
element: React.createElement(Index),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
path: 'admin',
|
|
121
|
+
element: React.createElement(AdminLayout),
|
|
122
|
+
children: [
|
|
123
|
+
// nested routes...
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
export default routes;
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Route Resolution Examples
|
|
132
|
+
|
|
133
|
+
| File Structure | Route Path |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `pages/index.tsx` | `/` |
|
|
136
|
+
| `pages/about.tsx` | `/about` |
|
|
137
|
+
| `pages/blog/index.tsx` | `/blog` |
|
|
138
|
+
| `pages/blog/post.tsx` | `/blog/post` |
|
|
139
|
+
| `pages/admin/layout.tsx` + children | `/admin/*` (grouped) |
|
|
140
|
+
|
|
141
|
+
## Layouts
|
|
142
|
+
|
|
143
|
+
Layouts wrap their child routes and provide shared UI:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// pages/dashboard/layout.tsx
|
|
147
|
+
import { Outlet } from 'react-router-dom';
|
|
148
|
+
|
|
149
|
+
export default function DashboardLayout() {
|
|
150
|
+
return (
|
|
151
|
+
<div className="dashboard">
|
|
152
|
+
<Sidebar />
|
|
153
|
+
<main>
|
|
154
|
+
<Outlet />
|
|
155
|
+
</main>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
All routes in `pages/dashboard/*` will render inside this layout.
|
|
162
|
+
|
|
163
|
+
## API Reference
|
|
164
|
+
|
|
165
|
+
### FileScanner
|
|
166
|
+
Scans the file system and converts files into a structured format.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { FileScanner } from 'aaex-file-router';
|
|
170
|
+
|
|
171
|
+
const scanner = new FileScanner('./src/pages');
|
|
172
|
+
const fileData = await scanner.get_file_data();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### RouteGenerator
|
|
176
|
+
Converts file structure into React Router route configuration.
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { RouteGenerator } from 'aaex-file-router';
|
|
180
|
+
|
|
181
|
+
const generator = new RouteGenerator();
|
|
182
|
+
const routesCode = await generator.generateComponentsMap(fileData);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### aaexFileRouter (Vite Plugin)
|
|
186
|
+
Automatically watches for file changes and regenerates routes.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { aaexFileRouter } from 'aaex-file-router';
|
|
190
|
+
|
|
191
|
+
export default defineConfig({
|
|
192
|
+
plugins: [
|
|
193
|
+
aaexFileRouter({
|
|
194
|
+
pagesDir: './src/pages',
|
|
195
|
+
outputFile: './src/routes.ts',
|
|
196
|
+
}),
|
|
197
|
+
],
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## How It Works
|
|
202
|
+
|
|
203
|
+
1. **File Scanning**: Recursively scans your pages directory and builds a file tree
|
|
204
|
+
2. **Route Generation**: Converts the file structure into React Router `RouteObject` format
|
|
205
|
+
3. **Smart Importing**:
|
|
206
|
+
- Top-level files use static imports for faster initial load
|
|
207
|
+
- Nested/grouped routes use lazy loading for code splitting
|
|
208
|
+
- Layout files are statically imported as route wrappers
|
|
209
|
+
4. **Auto-Regeneration**: Vite plugin watches for changes and automatically regenerates `routes.ts`
|
|
210
|
+
|
|
211
|
+
## Performance Considerations
|
|
212
|
+
|
|
213
|
+
- **Static Imports**: Top-level routes are statically imported, included in the main bundle
|
|
214
|
+
- **Code Splitting**: Routes nested in layout groups are lazy-loaded, improving initial bundle size
|
|
215
|
+
- **Watch Mode**: File watching only runs in development (`vite serve`), not in production builds
|
|
216
|
+
|
|
217
|
+
## Common Patterns
|
|
218
|
+
|
|
219
|
+
### Shared Layout
|
|
220
|
+
```
|
|
221
|
+
pages/
|
|
222
|
+
├── layout.tsx # Wraps entire app
|
|
223
|
+
├── index.tsx
|
|
224
|
+
└── about.tsx
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Nested Layouts
|
|
228
|
+
```
|
|
229
|
+
pages/
|
|
230
|
+
├── layout.tsx # Root layout
|
|
231
|
+
├── admin/
|
|
232
|
+
│ ├── layout.tsx # Admin layout (inherits from root)
|
|
233
|
+
│ ├── index.tsx
|
|
234
|
+
│ └── users.tsx
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Route Groups Without Layout
|
|
238
|
+
```
|
|
239
|
+
pages/
|
|
240
|
+
├── blog/
|
|
241
|
+
│ ├── post.tsx # Routes as /blog/post (no grouping)
|
|
242
|
+
│ └── author.tsx # Routes as /blog/author
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Troubleshooting
|
|
246
|
+
|
|
247
|
+
### Routes not updating on file change
|
|
248
|
+
- Ensure Vite dev server is running (`npm run dev`)
|
|
249
|
+
- Check that `pagesDir` in vite config matches your actual pages directory
|
|
250
|
+
|
|
251
|
+
### Duplicate imports in generated file
|
|
252
|
+
- This shouldn't happen, but if it does, try restarting the dev server
|
|
253
|
+
- Check for files with the same name in different directories
|
|
254
|
+
|
|
255
|
+
### Unexpected route paths
|
|
256
|
+
- Remember: `index.tsx` files inherit their parent's path
|
|
257
|
+
- Directories without `layout.tsx` flatten their children into absolute routes
|
|
258
|
+
- File names are converted to lowercase for routes
|
|
259
|
+
|
|
260
|
+
<!-- ## Contributing
|
|
261
|
+
|
|
262
|
+
Contributions are welcome! Please feel free to submit a Pull Request. -->
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
MIT
|
|
267
|
+
|
|
268
|
+
<!-- ## Support
|
|
269
|
+
|
|
270
|
+
For issues, questions, or suggestions, please open an issue on GitHub. -->
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface FileData {
|
|
2
|
+
name: string;
|
|
3
|
+
relative_path: string;
|
|
4
|
+
parent_path: string;
|
|
5
|
+
isDirectory: boolean;
|
|
6
|
+
children?: FileData[];
|
|
7
|
+
}
|
|
8
|
+
export declare class FileScanner {
|
|
9
|
+
page_dir: string;
|
|
10
|
+
topLevelImports: string[];
|
|
11
|
+
constructor(pages_dir: string);
|
|
12
|
+
/**
|
|
13
|
+
* Recursively scan directory and flatten all files/folders
|
|
14
|
+
* Adds a parentPath property to each entry to track hierarchy
|
|
15
|
+
*/
|
|
16
|
+
private scan_files;
|
|
17
|
+
/**
|
|
18
|
+
* Convert flat Dirent array into nested FileData structure
|
|
19
|
+
* Rebuilds directory hierarchy and filters children by parent path
|
|
20
|
+
*/
|
|
21
|
+
private build_file_data;
|
|
22
|
+
/**
|
|
23
|
+
* Public entry point: scans pages directory and returns nested FileData structure
|
|
24
|
+
* Handles both flat scanning and hierarchical rebuilding
|
|
25
|
+
*/
|
|
26
|
+
get_file_data(): Promise<FileData[]>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=FileScanner.d.ts.map
|
|
@@ -0,0 +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;IACjB,eAAe,EAAE,MAAM,EAAE,CAAM;gBAEnB,SAAS,EAAE,MAAM;IAI7B;;;OAGG;YACW,UAAU;IAmBxB;;;OAGG;YACW,eAAe;IA+C7B;;;OAGG;IACU,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;CAKlD"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export class FileScanner {
|
|
4
|
+
page_dir;
|
|
5
|
+
topLevelImports = [];
|
|
6
|
+
constructor(pages_dir) {
|
|
7
|
+
this.page_dir = pages_dir;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Recursively scan directory and flatten all files/folders
|
|
11
|
+
* Adds a parentPath property to each entry to track hierarchy
|
|
12
|
+
*/
|
|
13
|
+
async scan_files(dir) {
|
|
14
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
15
|
+
let result = [];
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
// Store parent directory path for later reference
|
|
18
|
+
entry.parentPath = dir;
|
|
19
|
+
result.push(entry);
|
|
20
|
+
// Recursively scan subdirectories and flatten results
|
|
21
|
+
if (entry.isDirectory()) {
|
|
22
|
+
const subFiles = await this.scan_files(path.join(dir, entry.name));
|
|
23
|
+
result = result.concat(subFiles);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Convert flat Dirent array into nested FileData structure
|
|
30
|
+
* Rebuilds directory hierarchy and filters children by parent path
|
|
31
|
+
*/
|
|
32
|
+
async build_file_data(files) {
|
|
33
|
+
const result = [];
|
|
34
|
+
for (const file of files) {
|
|
35
|
+
const fullpath = path.join(file.parentPath, file.name);
|
|
36
|
+
// Convert backslashes to forward slashes for cross-platform path consistency
|
|
37
|
+
const relative = path
|
|
38
|
+
.relative(process.cwd(), fullpath)
|
|
39
|
+
.replace(/\\/g, "/")
|
|
40
|
+
.trim();
|
|
41
|
+
if (file.isDirectory()) {
|
|
42
|
+
// Filter files to find only direct children of this directory
|
|
43
|
+
const children = files.filter((file) => file.parentPath === fullpath);
|
|
44
|
+
result.push({
|
|
45
|
+
name: file.name,
|
|
46
|
+
parent_path:
|
|
47
|
+
// Normalize parent path with forward slashes and trailing slash
|
|
48
|
+
path
|
|
49
|
+
.relative(process.cwd(), file.parentPath)
|
|
50
|
+
.replace(/\\/g, "/") + "/",
|
|
51
|
+
relative_path: relative,
|
|
52
|
+
isDirectory: true,
|
|
53
|
+
children: await this.build_file_data(children),
|
|
54
|
+
});
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
result.push({
|
|
58
|
+
name: file.name,
|
|
59
|
+
parent_path:
|
|
60
|
+
// Normalize parent path with forward slashes and trailing slash
|
|
61
|
+
path
|
|
62
|
+
.relative(process.cwd(), file.parentPath)
|
|
63
|
+
.replace(/\\/g, "/") + "/",
|
|
64
|
+
relative_path: relative,
|
|
65
|
+
isDirectory: false,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Public entry point: scans pages directory and returns nested FileData structure
|
|
72
|
+
* Handles both flat scanning and hierarchical rebuilding
|
|
73
|
+
*/
|
|
74
|
+
async get_file_data() {
|
|
75
|
+
const raw = await this.scan_files(path.join(process.cwd(), this.page_dir));
|
|
76
|
+
const result = await this.build_file_data(raw);
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=FileScanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileScanner.js","sourceRoot":"","sources":["../../src/core/FileScanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FileData } from "./FileScanner";
|
|
2
|
+
export declare class RouteGenerator {
|
|
3
|
+
private topLevelImports;
|
|
4
|
+
private importSet;
|
|
5
|
+
private processedFiles;
|
|
6
|
+
private clearImports;
|
|
7
|
+
/**
|
|
8
|
+
* Recursively converts FileData tree into React Router RouteConfig array
|
|
9
|
+
* Handles layout files, index files, and nested routes with proper pathing
|
|
10
|
+
* @param fileData - Array of files/folders to process
|
|
11
|
+
* @param parentPath - Current path context for nested routes (empty for root)
|
|
12
|
+
*/
|
|
13
|
+
private fileDataToRoutes;
|
|
14
|
+
/**
|
|
15
|
+
* Generates a complete routes configuration file as a string
|
|
16
|
+
* Includes all imports and route definitions in valid TypeScript/React code
|
|
17
|
+
* @param fileData - FileData tree from FileScanner
|
|
18
|
+
* @returns Complete routes file content ready to be written to disk
|
|
19
|
+
*/
|
|
20
|
+
generateComponentsMap(fileData: FileData[]): Promise<string>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=RouteGenerator.d.ts.map
|
|
@@ -0,0 +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,YAAY;IAGpB;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IA6KxB;;;;;OAKG;IACU,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CA6B1E"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
export class RouteGenerator {
|
|
2
|
+
topLevelImports = [];
|
|
3
|
+
importSet = new Set();
|
|
4
|
+
processedFiles = new Set();
|
|
5
|
+
clearImports() {
|
|
6
|
+
this.topLevelImports = [];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Recursively converts FileData tree into React Router RouteConfig array
|
|
10
|
+
* Handles layout files, index files, and nested routes with proper pathing
|
|
11
|
+
* @param fileData - Array of files/folders to process
|
|
12
|
+
* @param parentPath - Current path context for nested routes (empty for root)
|
|
13
|
+
*/
|
|
14
|
+
fileDataToRoutes(fileData, parentPath = "", flattenPrefix = "", inGroup = false) {
|
|
15
|
+
const routes = [];
|
|
16
|
+
const processedIndexes = new Set();
|
|
17
|
+
/**
|
|
18
|
+
* Utility function to safely join path segments
|
|
19
|
+
* - Filters out empty/falsy parts to avoid "///" in paths
|
|
20
|
+
* - Joins with "/" separator
|
|
21
|
+
* - Replaces all backslashes with forward slashes for cross-platform consistency
|
|
22
|
+
* Example: posixJoin("test", "", "hello") -> "test/hello"
|
|
23
|
+
* Example: posixJoin("pages\\test", "hello") -> "pages/test/hello"
|
|
24
|
+
*/
|
|
25
|
+
const posixJoin = (...parts) => parts.filter(Boolean).join("/").replace(/\\/g, "/");
|
|
26
|
+
for (const file of fileData) {
|
|
27
|
+
// Skip files already emitted during this generation
|
|
28
|
+
if (!file.isDirectory && this.processedFiles.has(file.relative_path)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (file.isDirectory && file.children && file.children.length > 0) {
|
|
32
|
+
const layoutChild = file.children.find((c) => !c.isDirectory && /^layout\.(tsx|jsx|ts|js)$/i.test(c.name));
|
|
33
|
+
if (!layoutChild) {
|
|
34
|
+
// No layout -> flatten children into absolute routes
|
|
35
|
+
const newFlatten = posixJoin(flattenPrefix, file.name.toLowerCase());
|
|
36
|
+
routes.push(...this.fileDataToRoutes(file.children, parentPath, newFlatten, false));
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
// Directory has layout -> import layout statically
|
|
40
|
+
const layoutPath = layoutChild.relative_path.replace(/^src[\/\\]/, "./");
|
|
41
|
+
const layoutImportName = `TestLayout`;
|
|
42
|
+
this.topLevelImports.push(`import ${layoutImportName} from '${layoutPath}';`);
|
|
43
|
+
this.processedFiles.add(layoutChild.relative_path); // Mark layout as processed
|
|
44
|
+
const childrenRoutes = [];
|
|
45
|
+
// Process children - filter out layout files
|
|
46
|
+
const nonLayoutChildren = file.children.filter((c) => !/^layout\.(tsx|jsx|ts|js)$/i.test(c.name));
|
|
47
|
+
for (const child of nonLayoutChildren) {
|
|
48
|
+
if (child.isDirectory) {
|
|
49
|
+
// Recursively handle child directories
|
|
50
|
+
childrenRoutes.push(...this.fileDataToRoutes([child], posixJoin(parentPath, file.name), "", true));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const childNameWithoutExt = child.name.replace(/\.[jt]sx?$/, "");
|
|
54
|
+
const childPath = child.relative_path.replace(/^src[\/\\]/, "./");
|
|
55
|
+
const isIndexFile = childNameWithoutExt.toLowerCase() === "index";
|
|
56
|
+
if (isIndexFile) {
|
|
57
|
+
childrenRoutes.push({
|
|
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
|
|
69
|
+
this.processedFiles.add(child.relative_path);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
routes.push({
|
|
73
|
+
path: file.name.toLowerCase(),
|
|
74
|
+
element: `React.createElement(${layoutImportName})`,
|
|
75
|
+
children: childrenRoutes.length ? childrenRoutes : undefined,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else if (!file.isDirectory) {
|
|
79
|
+
const nameWithoutExt = file.name.replace(/\.[jt]sx?$/, "");
|
|
80
|
+
const isIndexFile = nameWithoutExt.toLowerCase() === "index";
|
|
81
|
+
// Skip if already processed
|
|
82
|
+
if (isIndexFile && processedIndexes.has(file.relative_path)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// If a sibling directory with the same name exists, skip this file
|
|
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
|
+
}
|
|
134
|
+
this.processedFiles.add(file.relative_path);
|
|
135
|
+
if (isIndexFile)
|
|
136
|
+
processedIndexes.add(file.relative_path);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return routes;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Generates a complete routes configuration file as a string
|
|
143
|
+
* Includes all imports and route definitions in valid TypeScript/React code
|
|
144
|
+
* @param fileData - FileData tree from FileScanner
|
|
145
|
+
* @returns Complete routes file content ready to be written to disk
|
|
146
|
+
*/
|
|
147
|
+
async generateComponentsMap(fileData) {
|
|
148
|
+
// reset import & processed tracking each generation to avoid duplication across regen
|
|
149
|
+
this.topLevelImports = [];
|
|
150
|
+
this.importSet = new Set();
|
|
151
|
+
this.processedFiles = new Set();
|
|
152
|
+
const routes = this.fileDataToRoutes(fileData);
|
|
153
|
+
const routesString = JSON.stringify(routes, null, 2)
|
|
154
|
+
// lazy imports were serialized as strings, restore them to function calls
|
|
155
|
+
.replace(/"React\.createElement\(React\.lazy\(\(\) => import\('(.*)'\)\)\)"/g, "React.createElement(React.lazy(() => import('$1')))")
|
|
156
|
+
// React.createElement(Component) serialized as string, unquote it
|
|
157
|
+
.replace(/"React\.createElement\((\w+)\)"/g, "React.createElement($1)");
|
|
158
|
+
const mapString = `//* AUTO GENERATED: DO NOT EDIT
|
|
159
|
+
import React from 'react';
|
|
160
|
+
${this.topLevelImports.join("\n")}
|
|
161
|
+
import type { RouteObject } from 'react-router-dom';
|
|
162
|
+
|
|
163
|
+
const routes: RouteObject[] = ${routesString};
|
|
164
|
+
|
|
165
|
+
export default routes;
|
|
166
|
+
`;
|
|
167
|
+
return mapString;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=RouteGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,QAAQ;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAA;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,gDAAgD;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pages/index.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pages/index.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/test/index.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/pages/test/index.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/pages/test/layout.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/pages/test/layout.tsx"],"names":[],"mappings":""}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
export interface VitePluginOptions {
|
|
3
|
+
pagesDir?: string;
|
|
4
|
+
outputFile?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Vite plugin that auto-generates routes when page files change
|
|
8
|
+
* Watches the pages directory and regenerates routes.ts on file create/delete
|
|
9
|
+
*/
|
|
10
|
+
export declare function aaexFileRouter(options?: VitePluginOptions): Plugin;
|
|
11
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +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,CA6CtE"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { FileScanner } from './core/FileScanner.js';
|
|
4
|
+
import { RouteGenerator } from './core/RouteGenerator.js';
|
|
5
|
+
/**
|
|
6
|
+
* Vite plugin that auto-generates routes when page files change
|
|
7
|
+
* Watches the pages directory and regenerates routes.ts on file create/delete
|
|
8
|
+
*/
|
|
9
|
+
export function aaexFileRouter(options = {}) {
|
|
10
|
+
const pagesDir = options.pagesDir || './src/pages';
|
|
11
|
+
const outputFile = options.outputFile || './src/routes.ts';
|
|
12
|
+
let scanner;
|
|
13
|
+
let generator;
|
|
14
|
+
return {
|
|
15
|
+
name: 'aaex-file-router',
|
|
16
|
+
apply: 'serve', // Only run in dev mode
|
|
17
|
+
configResolved() {
|
|
18
|
+
scanner = new FileScanner(pagesDir);
|
|
19
|
+
generator = new RouteGenerator();
|
|
20
|
+
},
|
|
21
|
+
async configureServer(server) {
|
|
22
|
+
// Watch the pages directory for changes
|
|
23
|
+
server.watcher.add(path.resolve(process.cwd(), pagesDir));
|
|
24
|
+
server.watcher.on('all', async (event, filePath) => {
|
|
25
|
+
// Only regenerate on file add/unlink events
|
|
26
|
+
if (event === 'add' || event === 'unlink') {
|
|
27
|
+
try {
|
|
28
|
+
console.log(`📄 [aaex-file-router] ${event}: ${filePath}`);
|
|
29
|
+
// Regenerate routes
|
|
30
|
+
scanner = new FileScanner(pagesDir);
|
|
31
|
+
generator = new RouteGenerator();
|
|
32
|
+
const fileData = await scanner.get_file_data();
|
|
33
|
+
const routesCode = await generator.generateComponentsMap(fileData);
|
|
34
|
+
// Write routes file
|
|
35
|
+
await fs.writeFile(outputFile, routesCode, 'utf-8');
|
|
36
|
+
console.log(`✅ [aaex-file-router] Routes regenerated at ${outputFile}`);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error('❌ [aaex-file-router] Error regenerating routes:', error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,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;wBAGnE,oBAAoB;wBACpB,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;wBAEpD,OAAO,CAAC,GAAG,CAAC,8CAA8C,UAAU,EAAE,CAAC,CAAC;oBAC1E,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,KAAK,CAAC,iDAAiD,EAAE,KAAK,CAAC,CAAC;oBAC1E,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { fileURLToPath } from "url";
|
|
2
|
+
import { FileScanner } from "../core/FileScanner.js";
|
|
3
|
+
import { RouteGenerator } from "../core/RouteGenerator.js";
|
|
4
|
+
import { promises as fs } from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
const pagesDir = "/src/pages";
|
|
9
|
+
async function generateRoutes() {
|
|
10
|
+
try {
|
|
11
|
+
const scanner = new FileScanner(pagesDir);
|
|
12
|
+
const fileData = await scanner.get_file_data();
|
|
13
|
+
const generator = new RouteGenerator();
|
|
14
|
+
const routeMap = await generator.generateComponentsMap(fileData);
|
|
15
|
+
// Go up from dist/test back to src/test
|
|
16
|
+
const srcTestDir = __dirname.replace(/dist[\\/]test/, "src/test");
|
|
17
|
+
const filePath = path.join(srcTestDir, "routes.ts");
|
|
18
|
+
await fs.writeFile(filePath, routeMap, "utf-8");
|
|
19
|
+
console.log(`Routes file created at: ${filePath}`);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error("Error generating routes:", error);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
generateRoutes();
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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;AAC3D,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAC3C,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,MAAM,SAAS,GAAG,IAAI,cAAc,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAEjE,wCAAwC;QACxC,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACpD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAEhD,OAAO,CAAC,GAAG,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
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;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.config.d.ts","sourceRoot":"","sources":["../src/vite.config.ts"],"names":[],"mappings":";AAGA,wBAkBG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import dts from 'vite-plugin-dts';
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
build: {
|
|
5
|
+
lib: {
|
|
6
|
+
entry: 'src/index.ts',
|
|
7
|
+
name: 'AaexFileRouter',
|
|
8
|
+
fileName: (format) => `aaex-file-router.${format === 'es' ? 'js' : 'cjs'}`,
|
|
9
|
+
},
|
|
10
|
+
rollupOptions: {
|
|
11
|
+
external: ['react', 'react-router-dom', 'vite'],
|
|
12
|
+
output: {
|
|
13
|
+
globals: {
|
|
14
|
+
react: 'React',
|
|
15
|
+
'react-router-dom': 'ReactRouterDOM',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
plugins: [dts()], // Generate TypeScript declarations
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=vite.config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.config.js","sourceRoot":"","sources":["../src/vite.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,GAAG,MAAM,iBAAiB,CAAC;AAElC,eAAe,YAAY,CAAC;IAC1B,KAAK,EAAE;QACL,GAAG,EAAE;YACH,KAAK,EAAE,cAAc;YACrB,IAAI,EAAE,gBAAgB;YACtB,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,oBAAoB,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE;SAC3E;QACD,aAAa,EAAE;YACb,QAAQ,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,MAAM,CAAC;YAC/C,MAAM,EAAE;gBACN,OAAO,EAAE;oBACP,KAAK,EAAE,OAAO;oBACd,kBAAkB,EAAE,gBAAgB;iBACrC;aACF;SACF;KACF;IACD,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,mCAAmC;CACtD,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aaex-file-router",
|
|
3
|
+
"version": "1.0.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
|
+
"author": "TmRAaEx",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"type": "module",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENCE"
|
|
23
|
+
],
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^24.10.1",
|
|
26
|
+
"typescript": "^5.9.3",
|
|
27
|
+
"vite": "^7.2.4",
|
|
28
|
+
"vite-plugin-dts": "^4.5.4"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"fs": "^0.0.1-security"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": "^18.0.0",
|
|
35
|
+
"react-router-dom": "^6.0.0",
|
|
36
|
+
"vite": "^4.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|