@asterflow/fs 1.0.8 → 2.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/README.md +38 -88
- package/dist/cjs/index.cjs +85 -73
- package/dist/mjs/index.js +69 -55
- package/dist/types/index.d.ts +30 -72
- package/dist/types/types/asterflow.d.ts +48 -0
- package/dist/types/utils/codegen.d.ts +15 -0
- package/dist/types/utils/format.d.ts +4 -0
- package/dist/types/utils/glob.d.ts +6 -0
- package/dist/types/utils/log.d.ts +1 -0
- package/package.json +16 -9
- package/tsconfig.json +2 -16
package/README.md
CHANGED
|
@@ -2,120 +2,70 @@
|
|
|
2
2
|
|
|
3
3
|
# @asterflow/fs
|
|
4
4
|
|
|
5
|
-

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
7
9
|

|
|
8
10
|
|
|
9
11
|
</div>
|
|
10
12
|
|
|
11
|
-
>
|
|
13
|
+
> Generates a static route manifest from a file-based `routes/` directory and registers it on an AsterFlow app as a plugin.
|
|
12
14
|
|
|
13
15
|
## 📦 Installation
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
|
|
17
|
-
npm install @asterflow/fs
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## 💡 About
|
|
21
|
-
|
|
22
|
-
`@asterflow/fs` brings the convenience of file system-based routing to your AsterFlow projects. Inspired by modern web frameworks, this plugin automatically discovers and registers your routes based on the file and directory structure, allowing you to focus on writing your API logic instead of manual route configuration.
|
|
23
|
-
|
|
24
|
-
## ✨ Features
|
|
25
|
-
|
|
26
|
-
- **Convention over Configuration:** Automatically generates API routes from your file structure.
|
|
27
|
-
- **Dynamic Parameters:** Support for dynamic segments in filenames (e.g., `$id.ts`).
|
|
28
|
-
- **Index Routes:** `index.ts` files are treated as the base route of a directory.
|
|
29
|
-
- **Type-Safe:** Fully integrated with AsterFlow's type system.
|
|
30
|
-
- **Seamless Integration:** Automatically registers all discovered routes before the server starts.
|
|
31
|
-
|
|
32
|
-
## 🚀 Usage
|
|
33
|
-
|
|
34
|
-
### 1\. Project Structure
|
|
35
|
-
|
|
36
|
-
Create a directory to store your route files. By convention, this directory is usually `routes/` or `src/routes/`.
|
|
37
|
-
|
|
18
|
+
bun install @asterflow/fs
|
|
38
19
|
```
|
|
39
|
-
.
|
|
40
|
-
├── routes/
|
|
41
|
-
│ ├── index.ts # Handles GET /
|
|
42
|
-
│ ├── users/
|
|
43
|
-
│ │ ├── index.ts # Handles GET /users
|
|
44
|
-
│ │ └── $id.ts # Handles GET /users/:id
|
|
45
|
-
├── src
|
|
46
|
-
│ └── index.ts # Your main application file
|
|
47
|
-
└── package.json
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### 2\. Define Your Routes
|
|
51
20
|
|
|
52
|
-
|
|
21
|
+
Register the plugin with a generated route manifest:
|
|
53
22
|
|
|
54
|
-
|
|
23
|
+
```ts
|
|
24
|
+
import { AsterFlow } from 'asterflow'
|
|
25
|
+
import { fsRoutingPlugin } from '@asterflow/fs'
|
|
26
|
+
import routes from './routes.gen'
|
|
55
27
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
export default new Method({
|
|
60
|
-
// The 'path' property will be overwritten by the plugin,
|
|
61
|
-
// but can be useful for isolated testing.
|
|
62
|
-
path: '/',
|
|
63
|
-
method: 'get',
|
|
64
|
-
handler({ response, url }) {
|
|
65
|
-
// 'id' will be available at runtime
|
|
66
|
-
const params = url.getParams();
|
|
67
|
-
return response.success({ user: { id: params.id } });
|
|
68
|
-
}
|
|
69
|
-
});
|
|
28
|
+
const app = new AsterFlow()
|
|
29
|
+
.use(fsRoutingPlugin, { routes })
|
|
70
30
|
```
|
|
71
31
|
|
|
72
|
-
###
|
|
32
|
+
### ✨ Features
|
|
73
33
|
|
|
74
|
-
|
|
34
|
+
- **Static manifest, not runtime scanning**: `generateRouteManifest` walks a routes directory once and writes a file with one literal `import` per route plus a default-exported array - a bundler can follow these imports, unlike the old `await import(dynamicPath)` approach.
|
|
35
|
+
- **File-to-URL conventions**: `index.ts` becomes `/`, `users/index.ts` becomes `/users`, and a `$`-prefixed segment like `$id.ts` becomes a `:id` param.
|
|
36
|
+
- **Auto path assignment**: in the generated manifest, any route whose `default export` has no explicit `path` gets one assigned from its file location.
|
|
37
|
+
- **Safe registration**: `fsRoutingPlugin` registers every entry in `routes` with `instance.controller(route)` on `beforeInitialize`, and skips (with a warning) any entry that isn't a `Method`/`Router` instance instead of throwing.
|
|
75
38
|
|
|
76
|
-
|
|
39
|
+
## ❓ How to Use
|
|
77
40
|
|
|
78
|
-
|
|
79
|
-
import { AsterFlow } from 'asterflow';
|
|
80
|
-
import { fsRouting } from '@asterflow/fs';
|
|
81
|
-
import { join } from 'path';
|
|
41
|
+
Generate the manifest ahead of time, usually via the `asterflow generate` CLI command, or by calling the generator directly from a build script:
|
|
82
42
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
.use(fsRouting, {
|
|
86
|
-
path: join(process.cwd(), 'src', 'routes')
|
|
87
|
-
});
|
|
43
|
+
```ts
|
|
44
|
+
import { generateRouteManifest } from '@asterflow/fs'
|
|
88
45
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
})
|
|
46
|
+
await generateRouteManifest({
|
|
47
|
+
routesDir: './src/routes',
|
|
48
|
+
outFile: './src/routes.gen.ts'
|
|
49
|
+
})
|
|
93
50
|
```
|
|
94
51
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
## 🗺️ Routing Conventions
|
|
52
|
+
Route files just export a `Method` or `Router` - the `path` is filled in by the generator from the file's location, so `src/routes/users/$id.ts` becomes `/users/:id`:
|
|
98
53
|
|
|
99
|
-
|
|
54
|
+
```ts
|
|
55
|
+
// src/routes/users/$id.ts
|
|
56
|
+
import { Method } from '@asterflow/router'
|
|
100
57
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
| `users/index.ts` | `/users` |
|
|
106
|
-
| `$id.ts` | `/:id` |
|
|
107
|
-
| `products/$id.ts` | `/products/:id` |
|
|
108
|
-
| `categories/$categoryId/products/$productId.ts` | `/categories/:categoryId/products/:productId` |
|
|
109
|
-
|
|
110
|
-
- Files named `index` become the root of their directory.
|
|
111
|
-
- Filenames prefixed with `$` (e.g., `$id.ts`) are converted to dynamic URL parameters (e.g., `/:id`).
|
|
58
|
+
export default new Method(Method.GET, {
|
|
59
|
+
handler: ({ url, response }) => response.success({ id: url.getParams().id })
|
|
60
|
+
})
|
|
61
|
+
```
|
|
112
62
|
|
|
113
63
|
## 🔗 Related Packages
|
|
114
64
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
65
|
+
- [@asterflow/plugin](https://www.npmjs.com/package/@asterflow/plugin) - builds `fsRoutingPlugin` via `Plugin.create()`.
|
|
66
|
+
- [@asterflow/router](https://www.npmjs.com/package/@asterflow/router) - provides the `Method`/`Router` classes that route files export and that the plugin registers.
|
|
67
|
+
- Depended on by `@asterflow/cli` - its `generate` command calls this package's `generateRouteManifest` to produce the route manifest.
|
|
118
68
|
|
|
119
69
|
## 📄 License
|
|
120
70
|
|
|
121
|
-
|
|
71
|
+
This project is licensed under the [MIT License](../../LICENSE).
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,52 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
for (var
|
|
8
|
-
|
|
9
|
-
},
|
|
10
|
-
if (
|
|
11
|
-
for (let
|
|
12
|
-
!
|
|
13
|
-
return
|
|
2
|
+
var f = Object.defineProperty;
|
|
3
|
+
var T = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var P = Object.getOwnPropertyNames;
|
|
5
|
+
var S = Object.prototype.hasOwnProperty;
|
|
6
|
+
var O = (e, r) => {
|
|
7
|
+
for (var s in r)
|
|
8
|
+
f(e, s, { get: r[s], enumerable: !0 });
|
|
9
|
+
}, I = (e, r, s, t) => {
|
|
10
|
+
if (r && typeof r == "object" || typeof r == "function")
|
|
11
|
+
for (let o of P(r))
|
|
12
|
+
!S.call(e, o) && o !== s && f(e, o, { get: () => r[o], enumerable: !(t = T(r, o)) || t.enumerable });
|
|
13
|
+
return e;
|
|
14
14
|
};
|
|
15
|
-
var
|
|
16
|
-
|
|
15
|
+
var M = (e) => I(f({}, "__esModule", { value: !0 }), e);
|
|
17
16
|
// plugins/fs/src/index.ts
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
default: () =>
|
|
21
|
-
fsRoutingPlugin: () =>
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
var _ = {};
|
|
18
|
+
O(_, {
|
|
19
|
+
default: () => D,
|
|
20
|
+
fsRoutingPlugin: () => F,
|
|
21
|
+
generateRouteManifest: () => U,
|
|
22
|
+
getFilesRecursively: () => c,
|
|
23
|
+
transformPathToUrl: () => m
|
|
24
24
|
});
|
|
25
|
-
module.exports =
|
|
26
|
-
var
|
|
27
|
-
|
|
25
|
+
module.exports = M(_);
|
|
26
|
+
var $ = require("@asterflow/plugin"), u = require("@asterflow/router");
|
|
28
27
|
// plugins/fs/package.json
|
|
29
|
-
var
|
|
30
|
-
|
|
31
|
-
// plugins/fs/src/utils/format.ts
|
|
32
|
-
var d = require("path");
|
|
33
|
-
function u(t, o) {
|
|
34
|
-
let e = (0, d.relative)(o, t).replace(/\.(ts|js)$/, "");
|
|
35
|
-
return e.endsWith("/index") ? e = e.slice(0, -6) : e === "index" && (e = ""), e = e.replace(/\$/g, ":"), `/${e}`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// plugins/fs/src/utils/glob.ts
|
|
39
|
-
var g = require("fs/promises"), m = require("path");
|
|
40
|
-
async function n(t) {
|
|
41
|
-
let o = await (0, g.readdir)(t, { withFileTypes: !0 });
|
|
42
|
-
return (await Promise.all(
|
|
43
|
-
o.map(async (e) => {
|
|
44
|
-
let s = (0, m.join)(t, e.name);
|
|
45
|
-
return e.isDirectory() ? n(s) : s;
|
|
46
|
-
})
|
|
47
|
-
)).flat();
|
|
48
|
-
}
|
|
49
|
-
|
|
28
|
+
var y = "2.0.0";
|
|
50
29
|
// plugins/fs/src/utils/log.ts
|
|
51
30
|
var l = {
|
|
52
31
|
reset: "\x1B[0m",
|
|
@@ -54,42 +33,75 @@ var l = {
|
|
|
54
33
|
yellow: "\x1B[33m",
|
|
55
34
|
cyan: "\x1B[36m"
|
|
56
35
|
};
|
|
57
|
-
function
|
|
58
|
-
console.warn(`${l.yellow}%s %s${l.reset}`, "[AsterFlow]",
|
|
59
|
-
for (let [
|
|
60
|
-
console.log(`${l.cyan}%s:${l.reset} %s`,
|
|
36
|
+
function w(e, r) {
|
|
37
|
+
console.warn(`${l.yellow}%s %s${l.reset}`, "[AsterFlow]", e), console.group();
|
|
38
|
+
for (let [s, t] of Object.entries(r))
|
|
39
|
+
console.log(`${l.cyan}%s:${l.reset} %s`, s, t);
|
|
61
40
|
console.groupEnd(), console.log();
|
|
62
41
|
}
|
|
63
|
-
|
|
42
|
+
// plugins/fs/src/utils/codegen.ts
|
|
43
|
+
var p = require("fs/promises"), i = require("path");
|
|
44
|
+
// plugins/fs/src/utils/format.ts
|
|
45
|
+
var h = require("path");
|
|
46
|
+
function m(e, r) {
|
|
47
|
+
let t = (0, h.relative)(r, e).replace(/\.(ts|js)$/, "");
|
|
48
|
+
return t.endsWith("/index") ? t = t.slice(0, -6) : t === "index" && (t = ""), t = t.replace(/\$/g, ":"), `/${t}`;
|
|
49
|
+
}
|
|
50
|
+
// plugins/fs/src/utils/glob.ts
|
|
51
|
+
var R = require("fs/promises"), j = require("path");
|
|
52
|
+
async function c(e) {
|
|
53
|
+
let r = await (0, R.readdir)(e, { withFileTypes: !0 });
|
|
54
|
+
return (await Promise.all(
|
|
55
|
+
r.map(async (t) => {
|
|
56
|
+
let o = (0, j.join)(e, t.name);
|
|
57
|
+
return t.isDirectory() ? c(o) : o;
|
|
58
|
+
})
|
|
59
|
+
)).flat();
|
|
60
|
+
}
|
|
61
|
+
// plugins/fs/src/utils/codegen.ts
|
|
62
|
+
var N = new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
63
|
+
async function U({ routesDir: e, outFile: r }) {
|
|
64
|
+
let t = (await c(e)).filter((n) => N.has((0, i.extname)(n)) && !n.endsWith(".d.ts")).sort(), o = (0, i.dirname)(r), g = [], d = [], x = [];
|
|
65
|
+
t.forEach((n, v) => {
|
|
66
|
+
let a = `Route${v}`, E = A((0, i.relative)(o, n)), k = m(n, e);
|
|
67
|
+
g.push(`import ${a} from '${E}'`), d.push(`if (!${a}.path) ${a}.path = ${JSON.stringify(k)}`), x.push(a);
|
|
68
|
+
});
|
|
69
|
+
let b = [
|
|
70
|
+
"
|
|
71
|
+
`
|
|
72
|
+
...g,
|
|
73
|
+
"",
|
|
74
|
+
...d,
|
|
75
|
+
"",
|
|
76
|
+
`export default [${x.join(", ")}]`,
|
|
77
|
+
""
|
|
78
|
+
].join(`
|
|
79
|
+
`);
|
|
80
|
+
await (0, p.mkdir)(o, { recursive: !0 }), await (0, p.writeFile)(r, b);
|
|
81
|
+
}
|
|
82
|
+
function A(e) {
|
|
83
|
+
let s = e.replace(/\.(ts|tsx|js|jsx)$/, "").split(i.sep).join("/");
|
|
84
|
+
return s.startsWith(".") ? s : `./${s}`;
|
|
85
|
+
}
|
|
64
86
|
// plugins/fs/src/index.ts
|
|
65
|
-
var
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (!(i instanceof a.Method || i instanceof a.Router)) {
|
|
79
|
-
c("File Skipped: Invalid Export Type", {
|
|
80
|
-
File: e,
|
|
81
|
-
"Exported Type": typeof i,
|
|
82
|
-
Reason: "The file does not export a known class instance (e.g., Router, Method)."
|
|
83
|
-
});
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
i.path || (i.path = u(e, r.path)), t.controller(i);
|
|
87
|
+
var F = $.Plugin.create({ name: "fs-routing" }).decorate("creator", "Ashu11-A").decorate("version", y).config({ routes: [] }).extends((e, r) => ({
|
|
88
|
+
registerRoutes(s) {
|
|
89
|
+
for (let t of s.routes) {
|
|
90
|
+
if (!(t instanceof u.Method || t instanceof u.Router)) {
|
|
91
|
+
w("Route Skipped: Invalid Entry", {
|
|
92
|
+
"Exported Type": typeof t,
|
|
93
|
+
Reason: "An entry in the generated route manifest is not a Router/Method instance.",
|
|
94
|
+
Solution: "Re-run `asterflow generate` - if the problem persists, check the route file's default export."
|
|
95
|
+
});
|
|
96
|
+
continue;
|
|
87
97
|
}
|
|
98
|
+
e.controller(t);
|
|
99
|
+
}
|
|
88
100
|
}
|
|
89
|
-
})).on("beforeInitialize",
|
|
90
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
101
|
+
})).on("beforeInitialize", (e, r) => e.registerRoutes(r)), D = F;
|
|
91
102
|
0 && (module.exports = {
|
|
92
103
|
fsRoutingPlugin,
|
|
104
|
+
generateRouteManifest,
|
|
93
105
|
getFilesRecursively,
|
|
94
106
|
transformPathToUrl
|
|
95
107
|
});
|
package/dist/mjs/index.js
CHANGED
|
@@ -1,73 +1,87 @@
|
|
|
1
1
|
// plugins/fs/src/index.ts
|
|
2
|
-
import { Plugin as
|
|
3
|
-
import { Method as
|
|
4
|
-
|
|
2
|
+
import { Plugin as O } from "@asterflow/plugin";
|
|
3
|
+
import { Method as I, Router as M } from "@asterflow/router";
|
|
5
4
|
// plugins/fs/package.json
|
|
6
|
-
var
|
|
7
|
-
|
|
5
|
+
var f = "2.0.0";
|
|
6
|
+
// plugins/fs/src/utils/log.ts
|
|
7
|
+
var a = {
|
|
8
|
+
reset: "\x1B[0m",
|
|
9
|
+
red: "\x1B[31m",
|
|
10
|
+
yellow: "\x1B[33m",
|
|
11
|
+
cyan: "\x1B[36m"
|
|
12
|
+
};
|
|
13
|
+
function m(t, r) {
|
|
14
|
+
console.warn(`${a.yellow}%s %s${a.reset}`, "[AsterFlow]", t), console.group();
|
|
15
|
+
for (let [s, e] of Object.entries(r))
|
|
16
|
+
console.log(`${a.cyan}%s:${a.reset} %s`, s, e);
|
|
17
|
+
console.groupEnd(), console.log();
|
|
18
|
+
}
|
|
19
|
+
// plugins/fs/src/utils/codegen.ts
|
|
20
|
+
import { mkdir as v, writeFile as E } from "fs/promises";
|
|
21
|
+
import { dirname as k, extname as T, relative as d, sep as P } from "path";
|
|
8
22
|
// plugins/fs/src/utils/format.ts
|
|
9
|
-
import { relative as
|
|
10
|
-
function
|
|
11
|
-
let e =
|
|
23
|
+
import { relative as $ } from "path";
|
|
24
|
+
function g(t, r) {
|
|
25
|
+
let e = $(r, t).replace(/\.(ts|js)$/, "");
|
|
12
26
|
return e.endsWith("/index") ? e = e.slice(0, -6) : e === "index" && (e = ""), e = e.replace(/\$/g, ":"), `/${e}`;
|
|
13
27
|
}
|
|
14
|
-
|
|
15
28
|
// plugins/fs/src/utils/glob.ts
|
|
16
|
-
import { readdir as
|
|
17
|
-
import { join as
|
|
29
|
+
import { readdir as F } from "fs/promises";
|
|
30
|
+
import { join as b } from "path";
|
|
18
31
|
async function l(t) {
|
|
19
|
-
let
|
|
32
|
+
let r = await F(t, { withFileTypes: !0 });
|
|
20
33
|
return (await Promise.all(
|
|
21
|
-
|
|
22
|
-
let
|
|
23
|
-
return e.isDirectory() ? l(
|
|
34
|
+
r.map(async (e) => {
|
|
35
|
+
let o = b(t, e.name);
|
|
36
|
+
return e.isDirectory() ? l(o) : o;
|
|
24
37
|
})
|
|
25
38
|
)).flat();
|
|
26
39
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
// plugins/fs/src/utils/codegen.ts
|
|
41
|
+
var S = new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
42
|
+
async function B({ routesDir: t, outFile: r }) {
|
|
43
|
+
let e = (await l(t)).filter((i) => S.has(T(i)) && !i.endsWith(".d.ts")).sort(), o = k(r), c = [], p = [], u = [];
|
|
44
|
+
e.forEach((i, w) => {
|
|
45
|
+
let n = `Route${w}`, h = x(d(o, i)), R = g(i, t);
|
|
46
|
+
c.push(`import ${n} from '${h}'`), p.push(`if (!${n}.path) ${n}.path = ${JSON.stringify(R)}`), u.push(n);
|
|
47
|
+
});
|
|
48
|
+
let y = [
|
|
49
|
+
"
|
|
50
|
+
`
|
|
51
|
+
...c,
|
|
52
|
+
"",
|
|
53
|
+
...p,
|
|
54
|
+
"",
|
|
55
|
+
`export default [${u.join(", ")}]`,
|
|
56
|
+
""
|
|
57
|
+
].join(`
|
|
58
|
+
`);
|
|
59
|
+
await v(o, { recursive: !0 }), await E(r, y);
|
|
60
|
+
}
|
|
61
|
+
function x(t) {
|
|
62
|
+
let s = t.replace(/\.(ts|tsx|js|jsx)$/, "").split(P).join("/");
|
|
63
|
+
return s.startsWith(".") ? s : `./${s}`;
|
|
40
64
|
}
|
|
41
|
-
|
|
42
65
|
// plugins/fs/src/index.ts
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
});
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (!(s instanceof y || s instanceof h)) {
|
|
57
|
-
a("File Skipped: Invalid Export Type", {
|
|
58
|
-
File: e,
|
|
59
|
-
"Exported Type": typeof s,
|
|
60
|
-
Reason: "The file does not export a known class instance (e.g., Router, Method)."
|
|
61
|
-
});
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
s.path || (s.path = u(e, r.path)), t.controller(s);
|
|
66
|
+
var W = O.create({ name: "fs-routing" }).decorate("creator", "Ashu11-A").decorate("version", f).config({ routes: [] }).extends((t, r) => ({
|
|
67
|
+
registerRoutes(s) {
|
|
68
|
+
for (let e of s.routes) {
|
|
69
|
+
if (!(e instanceof I || e instanceof M)) {
|
|
70
|
+
m("Route Skipped: Invalid Entry", {
|
|
71
|
+
"Exported Type": typeof e,
|
|
72
|
+
Reason: "An entry in the generated route manifest is not a Router/Method instance.",
|
|
73
|
+
Solution: "Re-run `asterflow generate` - if the problem persists, check the route file's default export."
|
|
74
|
+
});
|
|
75
|
+
continue;
|
|
65
76
|
}
|
|
77
|
+
t.controller(e);
|
|
78
|
+
}
|
|
66
79
|
}
|
|
67
|
-
})).on("beforeInitialize",
|
|
80
|
+
})).on("beforeInitialize", (t, r) => t.registerRoutes(r)), V = W;
|
|
68
81
|
export {
|
|
69
|
-
|
|
70
|
-
|
|
82
|
+
V as default,
|
|
83
|
+
W as fsRoutingPlugin,
|
|
84
|
+
B as generateRouteManifest,
|
|
71
85
|
l as getFilesRecursively,
|
|
72
|
-
|
|
86
|
+
g as transformPathToUrl
|
|
73
87
|
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,74 +1,32 @@
|
|
|
1
|
-
// Generated by dts-bundle-generator v9.5.1
|
|
2
|
-
|
|
3
1
|
import { Plugin } from '@asterflow/plugin';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
path: string;
|
|
34
|
-
defaultConfig: {
|
|
35
|
-
path: string;
|
|
36
|
-
};
|
|
37
|
-
}, {
|
|
38
|
-
creator: string;
|
|
39
|
-
version: string;
|
|
40
|
-
}, {
|
|
41
|
-
files: string[];
|
|
42
|
-
}, {
|
|
43
|
-
registerRoutes: (context: {
|
|
44
|
-
creator: string;
|
|
45
|
-
version: string;
|
|
46
|
-
path: string;
|
|
47
|
-
defaultConfig: {
|
|
48
|
-
path: string;
|
|
49
|
-
};
|
|
50
|
-
files: string[];
|
|
51
|
-
}) => Promise<void>;
|
|
2
|
+
import { type AnyRouter } from '@asterflow/router';
|
|
3
|
+
export * from './utils/codegen';
|
|
4
|
+
export * from './utils/format';
|
|
5
|
+
export * from './utils/glob';
|
|
6
|
+
export * from './types/asterflow.d';
|
|
7
|
+
export declare const fsRoutingPlugin: Plugin<{
|
|
8
|
+
decorate: {
|
|
9
|
+
creator: string;
|
|
10
|
+
version: string;
|
|
11
|
+
};
|
|
12
|
+
config: {
|
|
13
|
+
routes: AnyRouter[];
|
|
14
|
+
defaultConfig: {
|
|
15
|
+
routes: AnyRouter[];
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
path: "fs-routing";
|
|
19
|
+
instance: import("asterflow").AnyAsterflow;
|
|
20
|
+
derive: {};
|
|
21
|
+
extension: {
|
|
22
|
+
registerRoutes: (context: {
|
|
23
|
+
routes: AnyRouter[];
|
|
24
|
+
defaultConfig: {
|
|
25
|
+
routes: AnyRouter[];
|
|
26
|
+
};
|
|
27
|
+
creator: string;
|
|
28
|
+
version: string;
|
|
29
|
+
}) => void;
|
|
30
|
+
};
|
|
52
31
|
}>;
|
|
53
|
-
|
|
54
|
-
* Recursively lists files from a starting directory.
|
|
55
|
-
* @param dirPath The path to the starting directory.
|
|
56
|
-
* @returns A promise that resolves to an array of file paths.
|
|
57
|
-
*/
|
|
58
|
-
export declare function getFilesRecursively(dirPath: string): Promise<string[]>;
|
|
59
|
-
/**
|
|
60
|
-
* Transforms a file path into a robustly formatted URL route.
|
|
61
|
-
*/
|
|
62
|
-
export declare function transformPathToUrl(filePath: string, rootDir: string): string;
|
|
63
|
-
export type FSRoutingContext = {
|
|
64
|
-
path: string;
|
|
65
|
-
files: string[];
|
|
66
|
-
creator: string;
|
|
67
|
-
version: string;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export {
|
|
71
|
-
fsRoutingPlugin as default,
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export {};
|
|
32
|
+
export default fsRoutingPlugin;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Runtime } from '@asterflow/adapter'
|
|
2
|
+
import type { AnyAsterflow } from 'asterflow'
|
|
3
|
+
import type { Responders } from '@asterflow/response'
|
|
4
|
+
import type {
|
|
5
|
+
AnySchema,
|
|
6
|
+
MethodHandler, MethodKeys,
|
|
7
|
+
Middleware,
|
|
8
|
+
MiddlewareOutput,
|
|
9
|
+
MethodOptions,
|
|
10
|
+
RouterOptions,
|
|
11
|
+
RouteHandler,
|
|
12
|
+
SchemaDynamic
|
|
13
|
+
} from '@asterflow/router'
|
|
14
|
+
|
|
15
|
+
// FS plugin augmentation: core router now supports optional path/param directly,
|
|
16
|
+
// this module augmentation is kept for backward compatibility and type helpers.
|
|
17
|
+
declare module '@asterflow/router' {
|
|
18
|
+
type MethodOptionsFS<
|
|
19
|
+
Responder extends Responders,
|
|
20
|
+
Path extends string = string,
|
|
21
|
+
Drive extends Runtime = Runtime,
|
|
22
|
+
Method extends MethodKeys = MethodKeys,
|
|
23
|
+
Schema extends AnySchema = AnySchema,
|
|
24
|
+
Middlewares extends readonly Middleware<Responder, Schema, string, Record<string, unknown>>[] = [],
|
|
25
|
+
Context extends MiddlewareOutput<Middlewares> = MiddlewareOutput<Middlewares>,
|
|
26
|
+
Instance extends AnyAsterflow = AnyAsterflow,
|
|
27
|
+
Handler extends MethodHandler<Path, Drive, Responder, Schema, Middlewares, Context, Instance> = MethodHandler<Path, Drive, Responder, Schema, Middlewares, Context, Instance>,
|
|
28
|
+
> = Omit<MethodOptions<Responder, Path, Drive, Method, Schema, Middlewares, Context, Instance, Handler>, 'path'>
|
|
29
|
+
& {
|
|
30
|
+
path?: Path
|
|
31
|
+
param?: Path
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type RouterOptionsFS<
|
|
35
|
+
Path extends string,
|
|
36
|
+
Schema extends SchemaDynamic<MethodKeys>,
|
|
37
|
+
Responder extends Responders,
|
|
38
|
+
Middlewares extends readonly Middleware<Responder, AnySchema, string, Record<string, unknown>>[],
|
|
39
|
+
Context extends MiddlewareOutput<Middlewares>,
|
|
40
|
+
Routers extends {
|
|
41
|
+
[Method in MethodKeys]?: RouteHandler<Path, Responder, Method, Schema, Middlewares, Context>;
|
|
42
|
+
}
|
|
43
|
+
> = Omit<RouterOptions<Path, Schema, Responder, Middlewares, Context, Routers>, 'path'>
|
|
44
|
+
& {
|
|
45
|
+
path?: Path
|
|
46
|
+
param?: Path
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface GenerateRouteManifestOptions {
|
|
2
|
+
/** Directory scanned for route files (e.g. `src/routes`). */
|
|
3
|
+
routesDir: string;
|
|
4
|
+
/** Path of the manifest file to write (e.g. `src/routes.gen.ts`). */
|
|
5
|
+
outFile: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Scans `routesDir` once and writes a manifest file at `outFile` containing a
|
|
9
|
+
* static `import` per route file plus a default-exported `AnyRouter[]`. Meant
|
|
10
|
+
* to run at build/dev time (the `asterflow generate` CLI command), not at
|
|
11
|
+
* request time - the resulting imports are literal specifiers a bundler can
|
|
12
|
+
* follow, unlike `fsRoutingPlugin`'s old `await import(file)` with a
|
|
13
|
+
* fully-dynamic path, which bundlers can't statically resolve at all.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateRouteManifest({ routesDir, outFile }: GenerateRouteManifestOptions): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function logWarning(title: string, details: Record<string, string>): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asterflow/fs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Generates a static route manifest from a file-based routes/ directory and registers it on an AsterFlow app as a plugin.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"asterflow",
|
|
7
|
+
"plugin",
|
|
8
|
+
"file-based-routing",
|
|
9
|
+
"fs-routing"
|
|
10
|
+
],
|
|
4
11
|
"main": "dist/cjs/index.cjs",
|
|
5
12
|
"module": "dist/mjs/index.js",
|
|
6
13
|
"types": "dist/types/index.d.ts",
|
|
@@ -10,12 +17,12 @@
|
|
|
10
17
|
"author": "Ashu11-A",
|
|
11
18
|
"repository": {
|
|
12
19
|
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/AsterFlow/
|
|
20
|
+
"url": "git+https://github.com/AsterFlow/AsterFlow.git"
|
|
14
21
|
},
|
|
15
22
|
"bugs": {
|
|
16
|
-
"url": "https://github.com/AsterFlow/
|
|
23
|
+
"url": "https://github.com/AsterFlow/AsterFlow/issues"
|
|
17
24
|
},
|
|
18
|
-
"homepage": "https://github.com/AsterFlow/
|
|
25
|
+
"homepage": "https://github.com/AsterFlow/AsterFlow",
|
|
19
26
|
"exports": {
|
|
20
27
|
".": {
|
|
21
28
|
"types": "./dist/types/index.d.ts",
|
|
@@ -27,11 +34,11 @@
|
|
|
27
34
|
"node": ">=20"
|
|
28
35
|
},
|
|
29
36
|
"dependencies": {
|
|
30
|
-
"@asterflow/
|
|
31
|
-
"@asterflow/
|
|
32
|
-
"@asterflow/url-parser": "^2.0.3"
|
|
37
|
+
"@asterflow/router": "^2.0.0",
|
|
38
|
+
"@asterflow/url-parser": "^4.1.1"
|
|
33
39
|
},
|
|
34
40
|
"devDependencies": {
|
|
35
|
-
"asterflow": "^
|
|
41
|
+
"@asterflow/plugin": "^1.0.9",
|
|
42
|
+
"asterflow": "^1.0.0"
|
|
36
43
|
}
|
|
37
|
-
}
|
|
44
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -18,23 +18,9 @@
|
|
|
18
18
|
"noUncheckedIndexedAccess": true,
|
|
19
19
|
"noUnusedLocals": false,
|
|
20
20
|
"noUnusedParameters": false,
|
|
21
|
-
"noPropertyAccessFromIndexSignature": false
|
|
22
|
-
"paths": {
|
|
23
|
-
"@asterflow/fs": [
|
|
24
|
-
"./types"
|
|
25
|
-
],
|
|
26
|
-
"@asterflow/fs/*": [
|
|
27
|
-
"./types/*"
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
"declaration": true,
|
|
31
|
-
"declarationMap": true
|
|
21
|
+
"noPropertyAccessFromIndexSignature": false
|
|
32
22
|
},
|
|
33
23
|
"include": [
|
|
34
|
-
"
|
|
35
|
-
],
|
|
36
|
-
"exclude": [
|
|
37
|
-
"node_modules",
|
|
38
|
-
"**/*.spec.ts"
|
|
24
|
+
"dist"
|
|
39
25
|
]
|
|
40
26
|
}
|