exrout 1.0.3 → 1.1.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 +271 -64
- package/dist/cjs/index.cjs +152 -10
- package/dist/cjs/index.d.ts +47 -2
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/loadRoutes.cjs +158 -22
- package/dist/cjs/loadRoutes.d.ts +16 -1
- package/dist/cjs/loadRoutes.d.ts.map +1 -0
- package/dist/cjs/loadRoutes.js.map +1 -0
- package/dist/cjs/utils.cjs +113 -2
- package/dist/cjs/utils.d.ts +43 -1
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/index.d.ts +53 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +117 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/loadRoutes.d.ts +17 -0
- package/dist/esm/loadRoutes.d.ts.map +1 -0
- package/dist/esm/loadRoutes.js +166 -0
- package/dist/esm/loadRoutes.js.map +1 -0
- package/dist/esm/utils.d.ts +44 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +112 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +52 -11
package/README.md
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
# EXROUT
|
|
1
|
+
# EXROUT 🚀
|
|
2
2
|
|
|
3
|
-
Automatically load and register Express routes based on your folder structure.
|
|
4
|
-
|
|
3
|
+
> **Express Auto Route Loader** — Automatically load and register Express routes based on your folder structure. Stop manually importing every route file!
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/exrout)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
7
|
|
|
6
8
|
## ✨ Features
|
|
7
9
|
|
|
8
|
-
- 📂 Auto-load routes from folders & subfolders
|
|
9
|
-
- 📄 `index.js
|
|
10
|
-
- 🔁
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
10
|
+
- 📂 **Auto-load routes** from folders & subfolders
|
|
11
|
+
- 📄 **Smart index files** — `index.js/ts` maps to folder root
|
|
12
|
+
- 🔁 **Dual module support** — Works with CommonJS and ES Modules
|
|
13
|
+
- 🧠 **File-based params** — `[id].ts` becomes `:id`
|
|
14
|
+
- ⚡ **Async router support** — Dynamic route initialization
|
|
15
|
+
- 🧩 **Global middleware** — Apply middleware to all routes
|
|
16
|
+
- 🧭 **Route prefixing** — Add `/api` or any prefix
|
|
17
|
+
- 🔥 **Hot reload** — Auto-refresh routes in development
|
|
18
|
+
- 🚫 **Exclusion patterns** — Skip test files, helpers, etc.
|
|
19
|
+
- 📊 **Route logging** — See loaded routes in console
|
|
20
|
+
- 🔒 **TypeScript first** — Full type safety and exports
|
|
18
21
|
|
|
19
22
|
---
|
|
20
23
|
|
|
@@ -24,99 +27,303 @@ Stop manually importing every route file.
|
|
|
24
27
|
npm install exrout
|
|
25
28
|
```
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
For hot reload support (optional):
|
|
31
|
+
```bash
|
|
32
|
+
npm install chokidar
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 🚀 Quick Start
|
|
38
|
+
|
|
39
|
+
### ES Modules
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
30
42
|
import express from "express";
|
|
31
43
|
import autoRoutes from "exrout";
|
|
32
44
|
|
|
33
45
|
const app = express();
|
|
34
46
|
|
|
35
|
-
autoRoutes(app, "./routes", {
|
|
47
|
+
await autoRoutes(app, "./routes", {
|
|
48
|
+
prefix: "/api",
|
|
49
|
+
log: true
|
|
50
|
+
});
|
|
36
51
|
|
|
37
|
-
app.listen(3000)
|
|
52
|
+
app.listen(3000, () => {
|
|
53
|
+
console.log("Server running on http://localhost:3000");
|
|
54
|
+
});
|
|
38
55
|
```
|
|
39
|
-
|
|
40
|
-
|
|
56
|
+
|
|
57
|
+
### CommonJS
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
41
60
|
const express = require("express");
|
|
42
61
|
const autoRoutes = require("exrout");
|
|
43
62
|
|
|
44
63
|
const app = express();
|
|
45
64
|
|
|
46
|
-
autoRoutes(app, "./routes")
|
|
65
|
+
autoRoutes(app, "./routes").then(() => {
|
|
66
|
+
app.listen(3000);
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 📁 Folder Structure → Routes
|
|
73
|
+
|
|
74
|
+
Your file structure automatically becomes your API routes:
|
|
47
75
|
|
|
48
|
-
app.listen(3000);
|
|
49
76
|
```
|
|
50
|
-
# 📁 Folder Structure → Routes
|
|
51
|
-
```bash
|
|
52
77
|
routes/
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
78
|
+
├── index.ts → /
|
|
79
|
+
├── users.ts → /users
|
|
80
|
+
├── posts.ts → /posts
|
|
81
|
+
├── auth/
|
|
82
|
+
│ ├── index.ts → /auth
|
|
83
|
+
│ ├── login.ts → /auth/login
|
|
84
|
+
│ ├── register.ts → /auth/register
|
|
85
|
+
│ └── [token].ts → /auth/:token
|
|
86
|
+
└── users/
|
|
87
|
+
├── index.ts → /users
|
|
88
|
+
└── [id].ts → /users/:id
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 🧩 Writing Routes
|
|
94
|
+
|
|
95
|
+
Each route file exports an Express Router:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
62
98
|
import { Router } from "express";
|
|
63
99
|
|
|
64
100
|
const router = Router();
|
|
65
101
|
|
|
66
102
|
router.get("/", (req, res) => {
|
|
67
|
-
res.json({ message: "Hello users" });
|
|
103
|
+
res.json({ message: "Hello from users!" });
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
router.post("/", (req, res) => {
|
|
107
|
+
res.json({ message: "User created!" });
|
|
68
108
|
});
|
|
69
109
|
|
|
70
110
|
export default router;
|
|
71
111
|
```
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## ⚙️ Configuration Options
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
await autoRoutes(app, "./routes", {
|
|
119
|
+
prefix: "/api", // Prefix all routes
|
|
120
|
+
middleware: [authMiddleware, loggerMiddleware], // Global middleware
|
|
121
|
+
log: true, // Log loaded routes
|
|
122
|
+
watch: true, // Hot reload in development
|
|
123
|
+
exclude: ["*.test.ts", "_*", "helpers/*"] // Exclusion patterns
|
|
79
124
|
});
|
|
80
125
|
```
|
|
81
|
-
## Available Options
|
|
82
|
-
| Option | Type | Description |
|
|
83
|
-
| ------------ | ------------ | --------------------------------------- |
|
|
84
|
-
| `prefix` | `string` | Prefix all routes (e.g. `/api`) |
|
|
85
|
-
| `middleware` | `Function[]` | Global middleware applied to all routes |
|
|
86
|
-
| `log` | `boolean` | Log loaded routes to the console |
|
|
87
|
-
| `watch` | `boolean` | Hot reload routes in development |
|
|
88
126
|
|
|
127
|
+
### Options Reference
|
|
89
128
|
|
|
90
|
-
|
|
91
|
-
|
|
129
|
+
| Option | Type | Default | Description |
|
|
130
|
+
|--------|------|---------|-------------|
|
|
131
|
+
| `prefix` | `string` | `""` | Prefix for all routes (e.g., `/api`) |
|
|
132
|
+
| `middleware` | `RequestHandler[]` | `[]` | Global middleware applied to all routes |
|
|
133
|
+
| `log` | `boolean` | `false` | Log loaded routes to console |
|
|
134
|
+
| `watch` | `boolean` | `false` | Enable hot reload (requires chokidar) |
|
|
135
|
+
| `exclude` | `string[]` | `[]` | Glob patterns to exclude files |
|
|
136
|
+
|
|
137
|
+
### Default Exclusions
|
|
138
|
+
|
|
139
|
+
These patterns are excluded by default:
|
|
140
|
+
- `*.test.ts` / `*.test.js`
|
|
141
|
+
- `*.spec.ts` / `*.spec.js`
|
|
142
|
+
- `_*` (files starting with underscore)
|
|
143
|
+
- `*.d.ts` (TypeScript declaration files)
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 🧠 Dynamic Route Parameters
|
|
148
|
+
|
|
149
|
+
Use bracket notation for dynamic segments:
|
|
150
|
+
|
|
151
|
+
```
|
|
92
152
|
routes/
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
153
|
+
└── users/
|
|
154
|
+
└── [id].ts → /users/:id
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// routes/users/[id].ts
|
|
159
|
+
import { Router } from "express";
|
|
160
|
+
|
|
161
|
+
const router = Router();
|
|
162
|
+
|
|
97
163
|
router.get("/", (req, res) => {
|
|
98
|
-
res.json({
|
|
164
|
+
res.json({ userId: req.params.id });
|
|
99
165
|
});
|
|
166
|
+
|
|
167
|
+
export default router;
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Multiple params work too:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
routes/
|
|
174
|
+
└── [category]/
|
|
175
|
+
└── [productId].ts → /:category/:productId
|
|
100
176
|
```
|
|
101
|
-
|
|
102
|
-
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## ⚡ Async Router Factory
|
|
181
|
+
|
|
182
|
+
For routes that need async initialization:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
103
185
|
import { Router } from "express";
|
|
186
|
+
import { connectDatabase } from "./db";
|
|
104
187
|
|
|
105
188
|
export default async function createRouter() {
|
|
189
|
+
await connectDatabase();
|
|
190
|
+
|
|
106
191
|
const router = Router();
|
|
107
|
-
|
|
192
|
+
|
|
108
193
|
router.get("/", async (req, res) => {
|
|
109
|
-
|
|
194
|
+
const data = await fetchData();
|
|
195
|
+
res.json(data);
|
|
110
196
|
});
|
|
111
|
-
|
|
197
|
+
|
|
112
198
|
return router;
|
|
113
199
|
}
|
|
114
200
|
```
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 🔥 Hot Reload (Development)
|
|
205
|
+
|
|
206
|
+
Enable automatic route reloading when files change:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
await autoRoutes(app, "./routes", {
|
|
210
|
+
watch: process.env.NODE_ENV === "development"
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
> ⚠️ Requires `chokidar` to be installed.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 🔌 TypeScript Support
|
|
219
|
+
|
|
220
|
+
Full TypeScript support with exported types:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import autoRoutes, {
|
|
224
|
+
AutoRoutesOptions,
|
|
225
|
+
AutoRoutesResult,
|
|
226
|
+
RouteInfo,
|
|
227
|
+
} from "exrout";
|
|
228
|
+
|
|
229
|
+
const options: AutoRoutesOptions = {
|
|
230
|
+
prefix: "/api",
|
|
231
|
+
log: true,
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const result: AutoRoutesResult = await autoRoutes(app, "./routes", options);
|
|
235
|
+
|
|
236
|
+
result.routes.forEach((route: RouteInfo) => {
|
|
237
|
+
console.log(`Route: ${route.path} -> ${route.file}`);
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 📊 Return Value
|
|
244
|
+
|
|
245
|
+
`autoRoutes` returns a promise with information about loaded routes:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const result = await autoRoutes(app, "./routes");
|
|
249
|
+
|
|
250
|
+
console.log(result.routes);
|
|
251
|
+
// [
|
|
252
|
+
// { path: "/", file: "/abs/path/routes/index.ts" },
|
|
253
|
+
// { path: "/users", file: "/abs/path/routes/users.ts" },
|
|
254
|
+
// { path: "/users/:id", file: "/abs/path/routes/users/[id].ts" }
|
|
255
|
+
// ]
|
|
256
|
+
|
|
257
|
+
// If watch mode is enabled, you can stop watching:
|
|
258
|
+
result.close?.();
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 🚫 Excluding Files
|
|
264
|
+
|
|
265
|
+
Skip certain files from being loaded as routes:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
await autoRoutes(app, "./routes", {
|
|
269
|
+
exclude: [
|
|
270
|
+
"*.test.ts", // Skip test files
|
|
271
|
+
"_*", // Skip files starting with _
|
|
272
|
+
"helpers/*", // Skip helper directories
|
|
273
|
+
"*.backup.*" // Skip backup files
|
|
274
|
+
]
|
|
275
|
+
});
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 📝 Examples
|
|
281
|
+
|
|
282
|
+
### API with Authentication
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import express from "express";
|
|
286
|
+
import autoRoutes from "exrout";
|
|
287
|
+
import { authMiddleware } from "./middleware/auth";
|
|
288
|
+
|
|
289
|
+
const app = express();
|
|
290
|
+
app.use(express.json());
|
|
291
|
+
|
|
292
|
+
// Public routes
|
|
293
|
+
await autoRoutes(app, "./routes/public");
|
|
294
|
+
|
|
295
|
+
// Protected routes with auth middleware
|
|
296
|
+
await autoRoutes(app, "./routes/protected", {
|
|
297
|
+
prefix: "/api",
|
|
298
|
+
middleware: [authMiddleware]
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
app.listen(3000);
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Microservice with Versioning
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
import express from "express";
|
|
308
|
+
import autoRoutes from "exrout";
|
|
309
|
+
|
|
310
|
+
const app = express();
|
|
311
|
+
|
|
312
|
+
// Version 1 API
|
|
313
|
+
await autoRoutes(app, "./routes/v1", { prefix: "/api/v1" });
|
|
314
|
+
|
|
315
|
+
// Version 2 API
|
|
316
|
+
await autoRoutes(app, "./routes/v2", { prefix: "/api/v2" });
|
|
317
|
+
|
|
318
|
+
app.listen(3000);
|
|
118
319
|
```
|
|
119
|
-
Routes automatically reload when files change.
|
|
120
320
|
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 🤝 Contributing
|
|
324
|
+
|
|
325
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
121
326
|
|
|
327
|
+
## 📄 License
|
|
122
328
|
|
|
329
|
+
MIT © Marouane Akrich
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,20 +1,162 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.sortRoutes = exports.extractHttpMethod = exports.shouldExclude = exports.cleanSlashes = exports.normalizeRouteName = void 0;
|
|
6
40
|
exports.default = autoRoutes;
|
|
7
41
|
const loadRoutes_1 = __importDefault(require("./loadRoutes.cjs"));
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
42
|
+
const utils_1 = require("./utils.cjs");
|
|
43
|
+
/**
|
|
44
|
+
* Automatically load and register Express routes from a directory structure
|
|
45
|
+
*
|
|
46
|
+
* @param app - Express application instance
|
|
47
|
+
* @param routesDir - Path to the routes directory
|
|
48
|
+
* @param options - Configuration options
|
|
49
|
+
* @returns Promise resolving to AutoRoutesResult
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import express from "express";
|
|
54
|
+
* import autoRoutes from "exrout";
|
|
55
|
+
*
|
|
56
|
+
* const app = express();
|
|
57
|
+
*
|
|
58
|
+
* await autoRoutes(app, "./routes", {
|
|
59
|
+
* prefix: "/api",
|
|
60
|
+
* log: true
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* app.listen(3000);
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
async function autoRoutes(app, routesDir, options = {}) {
|
|
67
|
+
const { prefix = "", middleware = [], log = false, watch = false, exclude = [], } = options;
|
|
68
|
+
// Validate inputs
|
|
69
|
+
(0, utils_1.validatePath)(routesDir);
|
|
70
|
+
if (!app || typeof app.use !== "function") {
|
|
71
|
+
throw new Error("[exrout] Invalid Express app instance provided");
|
|
72
|
+
}
|
|
73
|
+
// Default exclusions for common non-route files
|
|
74
|
+
const defaultExclusions = [
|
|
75
|
+
"*.test.ts",
|
|
76
|
+
"*.test.js",
|
|
77
|
+
"*.spec.ts",
|
|
78
|
+
"*.spec.js",
|
|
79
|
+
"_*",
|
|
80
|
+
"*.d.ts",
|
|
81
|
+
];
|
|
82
|
+
const mergedExclusions = [...defaultExclusions, ...exclude];
|
|
83
|
+
const loadOptions = {
|
|
84
|
+
prefix,
|
|
85
|
+
middleware,
|
|
86
|
+
log,
|
|
87
|
+
exclude: mergedExclusions,
|
|
88
|
+
};
|
|
89
|
+
// Initial route loading
|
|
90
|
+
let routes = await (0, loadRoutes_1.default)(app, routesDir, loadOptions);
|
|
91
|
+
if (log) {
|
|
92
|
+
console.log(`[exrout] Loaded ${routes.length} route(s)`);
|
|
93
|
+
}
|
|
94
|
+
const result = { routes };
|
|
95
|
+
// Set up file watching if enabled
|
|
11
96
|
if (watch) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
97
|
+
try {
|
|
98
|
+
// Dynamic import of chokidar (optional dependency)
|
|
99
|
+
let chokidar;
|
|
100
|
+
try {
|
|
101
|
+
chokidar = await Promise.resolve().then(() => __importStar(require("chokidar")));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
console.warn("[exrout] Watch mode requires chokidar. Install it with: npm install chokidar");
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
const watcher = chokidar.watch(routesDir, {
|
|
108
|
+
ignored: [
|
|
109
|
+
/(^|[\/\\])\../, // Ignore dotfiles
|
|
110
|
+
/node_modules/,
|
|
111
|
+
...mergedExclusions.map((p) => `**/${p}`),
|
|
112
|
+
],
|
|
113
|
+
persistent: true,
|
|
114
|
+
ignoreInitial: true,
|
|
115
|
+
});
|
|
116
|
+
let debounceTimer = null;
|
|
117
|
+
const reloadRoutes = async () => {
|
|
118
|
+
// Debounce rapid file changes
|
|
119
|
+
if (debounceTimer) {
|
|
120
|
+
clearTimeout(debounceTimer);
|
|
121
|
+
}
|
|
122
|
+
debounceTimer = setTimeout(async () => {
|
|
123
|
+
try {
|
|
124
|
+
console.log("[exrout] Reloading routes...");
|
|
125
|
+
// Note: Express doesn't support removing routes easily
|
|
126
|
+
// In a real hot-reload scenario, you'd need to restart the server
|
|
127
|
+
// or use a more sophisticated approach
|
|
128
|
+
routes = await (0, loadRoutes_1.default)(app, routesDir, loadOptions);
|
|
129
|
+
result.routes = routes;
|
|
130
|
+
console.log(`[exrout] Reloaded ${routes.length} route(s)`);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
console.error("[exrout] Error reloading routes:", error);
|
|
134
|
+
}
|
|
135
|
+
}, 300);
|
|
136
|
+
};
|
|
137
|
+
watcher.on("add", reloadRoutes);
|
|
138
|
+
watcher.on("change", reloadRoutes);
|
|
139
|
+
watcher.on("unlink", reloadRoutes);
|
|
140
|
+
result.close = () => {
|
|
141
|
+
if (debounceTimer) {
|
|
142
|
+
clearTimeout(debounceTimer);
|
|
143
|
+
}
|
|
144
|
+
watcher.close();
|
|
145
|
+
};
|
|
146
|
+
if (log) {
|
|
147
|
+
console.log("[exrout] Watch mode enabled");
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error("[exrout] Failed to initialize watch mode:", error);
|
|
152
|
+
}
|
|
19
153
|
}
|
|
154
|
+
return result;
|
|
20
155
|
}
|
|
156
|
+
var utils_2 = require("./utils.cjs");
|
|
157
|
+
Object.defineProperty(exports, "normalizeRouteName", { enumerable: true, get: function () { return utils_2.normalizeRouteName; } });
|
|
158
|
+
Object.defineProperty(exports, "cleanSlashes", { enumerable: true, get: function () { return utils_2.cleanSlashes; } });
|
|
159
|
+
Object.defineProperty(exports, "shouldExclude", { enumerable: true, get: function () { return utils_2.shouldExclude; } });
|
|
160
|
+
Object.defineProperty(exports, "extractHttpMethod", { enumerable: true, get: function () { return utils_2.extractHttpMethod; } });
|
|
161
|
+
Object.defineProperty(exports, "sortRoutes", { enumerable: true, get: function () { return utils_2.sortRoutes; } });
|
|
162
|
+
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,8 +1,53 @@
|
|
|
1
1
|
import { Express, RequestHandler } from "express";
|
|
2
|
-
|
|
2
|
+
import { RouteInfo } from "./loadRoutes";
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for autoRoutes
|
|
5
|
+
*/
|
|
6
|
+
export interface AutoRoutesOptions {
|
|
7
|
+
/** Prefix for all routes (e.g., "/api") */
|
|
3
8
|
prefix?: string;
|
|
9
|
+
/** Global middleware to apply to all routes */
|
|
4
10
|
middleware?: RequestHandler[];
|
|
11
|
+
/** Log loaded routes to console */
|
|
5
12
|
log?: boolean;
|
|
13
|
+
/** Enable hot reload in development (requires chokidar) */
|
|
6
14
|
watch?: boolean;
|
|
15
|
+
/** File patterns to exclude (supports * and ?) */
|
|
16
|
+
exclude?: string[];
|
|
7
17
|
}
|
|
8
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Result returned by autoRoutes
|
|
20
|
+
*/
|
|
21
|
+
export interface AutoRoutesResult {
|
|
22
|
+
/** List of loaded routes */
|
|
23
|
+
routes: RouteInfo[];
|
|
24
|
+
/** Stop watching for changes (if watch mode is enabled) */
|
|
25
|
+
close?: () => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Automatically load and register Express routes from a directory structure
|
|
29
|
+
*
|
|
30
|
+
* @param app - Express application instance
|
|
31
|
+
* @param routesDir - Path to the routes directory
|
|
32
|
+
* @param options - Configuration options
|
|
33
|
+
* @returns Promise resolving to AutoRoutesResult
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import express from "express";
|
|
38
|
+
* import autoRoutes from "exrout";
|
|
39
|
+
*
|
|
40
|
+
* const app = express();
|
|
41
|
+
*
|
|
42
|
+
* await autoRoutes(app, "./routes", {
|
|
43
|
+
* prefix: "/api",
|
|
44
|
+
* log: true
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* app.listen(3000);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export default function autoRoutes(app: Express, routesDir: string, options?: AutoRoutesOptions): Promise<AutoRoutesResult>;
|
|
51
|
+
export { RouteInfo, LoadRoutesOptions } from "./loadRoutes";
|
|
52
|
+
export { normalizeRouteName, cleanSlashes, shouldExclude, extractHttpMethod, sortRoutes, } from "./utils";
|
|
53
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAClD,OAAmB,EAAE,SAAS,EAAqB,MAAM,cAAc,CAAC;AAGxE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,mCAAmC;IACnC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,2DAA2D;IAC3D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAA8B,UAAU,CACtC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAmH3B;AAGD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,UAAU,GACX,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|