@asterflow/fs 2.0.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -8
- package/dist/cjs/index.cjs +92 -69
- package/dist/mjs/index.js +80 -57
- package/dist/types/index.d.ts +6 -10
- package/dist/types/utils/codegen.d.ts +6 -4
- package/dist/types/utils/constants.d.ts +1 -0
- package/dist/types/utils/loader.d.ts +10 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
|
-
>
|
|
13
|
+
> File-based routing for AsterFlow - dynamic (scan a directory at startup) or static (a pre-generated manifest, bundler-safe) - registered as a plugin.
|
|
14
14
|
|
|
15
15
|
## 📦 Installation
|
|
16
16
|
|
|
@@ -18,7 +18,19 @@
|
|
|
18
18
|
bun install @asterflow/fs
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
`fsRoutingPlugin` supports two mutually exclusive modes, picked automatically from which config key you pass:
|
|
22
|
+
|
|
23
|
+
**Dynamic** - point it at a directory, no codegen step required. Simplest for dev/unbundled runs (`bun run src/index.ts`), but the `import()` path is fully computed at runtime, so a bundler can't trace it - don't use this for a bundled/production build.
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { AsterFlow } from 'asterflow'
|
|
27
|
+
import { fsRoutingPlugin } from '@asterflow/fs'
|
|
28
|
+
|
|
29
|
+
const app = new AsterFlow()
|
|
30
|
+
.use(fsRoutingPlugin, { path: './src/routes' })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Static** - a pre-generated manifest of literal imports, safe for bundling. Generate it once (via `asterflow generate`, `--watch`, or `generateRouteManifest` in a build script) and pass the result in:
|
|
22
34
|
|
|
23
35
|
```ts
|
|
24
36
|
import { AsterFlow } from 'asterflow'
|
|
@@ -29,16 +41,19 @@ const app = new AsterFlow()
|
|
|
29
41
|
.use(fsRoutingPlugin, { routes })
|
|
30
42
|
```
|
|
31
43
|
|
|
44
|
+
Passing both `routes` and `path` is ambiguous - the plugin logs a warning and uses `path`.
|
|
45
|
+
|
|
32
46
|
### ✨ Features
|
|
33
47
|
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
- **
|
|
48
|
+
- **Two loading modes, one plugin**: `path` scans and `import()`s the directory at `beforeInitialize` (via `loadRoutesFromDir`) - no manifest file needed. `routes` takes a pre-generated array instead, for when the app gets bundled.
|
|
49
|
+
- **Static manifest generation**: `generateRouteManifest` walks a routes directory once and writes a file with one literal `import` per route plus a default-exported array, so a bundler can follow it - unlike a fully-dynamic `import(path)`, which bundlers can't resolve at all.
|
|
50
|
+
- **File-to-URL conventions** (both modes): `index.ts` becomes `/`, `users/index.ts` becomes `/users`, and a `$`-prefixed segment like `$id.ts` becomes a `:id` param.
|
|
51
|
+
- **Auto path assignment**: any route whose `default export` has no explicit `path` gets one assigned from its file location.
|
|
52
|
+
- **Safe registration**: `fsRoutingPlugin` registers every resolved route with `instance.controller(route)` on `beforeInitialize`, and skips (with a warning) any entry that isn't a `Method`/`Router` instance instead of throwing.
|
|
38
53
|
|
|
39
54
|
## ❓ How to Use
|
|
40
55
|
|
|
41
|
-
|
|
56
|
+
For a static manifest, generate it ahead of time, usually via the `asterflow generate` CLI command, or by calling the generator directly from a build script:
|
|
42
57
|
|
|
43
58
|
```ts
|
|
44
59
|
import { generateRouteManifest } from '@asterflow/fs'
|
|
@@ -49,7 +64,7 @@ await generateRouteManifest({
|
|
|
49
64
|
})
|
|
50
65
|
```
|
|
51
66
|
|
|
52
|
-
Route files just export a `Method` or `Router` - the `path` is filled in
|
|
67
|
+
Route files just export a `Method` or `Router` - the `path` is filled in from the file's location (whichever mode you use), so `src/routes/users/$id.ts` becomes `/users/:id`:
|
|
53
68
|
|
|
54
69
|
```ts
|
|
55
70
|
// src/routes/users/$id.ts
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,107 +1,130 @@
|
|
|
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 h = Object.defineProperty;
|
|
3
|
+
var I = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var N = Object.getOwnPropertyNames;
|
|
5
|
+
var U = Object.prototype.hasOwnProperty;
|
|
6
|
+
var M = (t, e) => {
|
|
7
|
+
for (var r in e)
|
|
8
|
+
h(t, r, { get: e[r], enumerable: !0 });
|
|
9
|
+
}, W = (t, e, r, o) => {
|
|
10
|
+
if (e && typeof e == "object" || typeof e == "function")
|
|
11
|
+
for (let s of N(e))
|
|
12
|
+
!U.call(t, s) && s !== r && h(t, s, { get: () => e[s], enumerable: !(o = I(e, s)) || o.enumerable });
|
|
13
|
+
return t;
|
|
14
14
|
};
|
|
15
|
-
var
|
|
15
|
+
var _ = (t) => W(h({}, "__esModule", { value: !0 }), t);
|
|
16
16
|
// plugins/fs/src/index.ts
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
default: () =>
|
|
20
|
-
fsRoutingPlugin: () =>
|
|
21
|
-
generateRouteManifest: () =>
|
|
22
|
-
getFilesRecursively: () =>
|
|
23
|
-
|
|
17
|
+
var C = {};
|
|
18
|
+
M(C, {
|
|
19
|
+
default: () => X,
|
|
20
|
+
fsRoutingPlugin: () => T,
|
|
21
|
+
generateRouteManifest: () => L,
|
|
22
|
+
getFilesRecursively: () => a,
|
|
23
|
+
loadRoutesFromDir: () => y,
|
|
24
|
+
transformPathToUrl: () => p
|
|
24
25
|
});
|
|
25
|
-
module.exports =
|
|
26
|
-
var
|
|
26
|
+
module.exports = _(C);
|
|
27
|
+
var b = require("@asterflow/plugin"), d = require("@asterflow/router");
|
|
27
28
|
// plugins/fs/package.json
|
|
28
|
-
var
|
|
29
|
+
var R = "2.2.0";
|
|
30
|
+
// plugins/fs/src/utils/loader.ts
|
|
31
|
+
var j = require("path"), v = require("url");
|
|
32
|
+
// plugins/fs/src/utils/constants.ts
|
|
33
|
+
var f = new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
34
|
+
// plugins/fs/src/utils/format.ts
|
|
35
|
+
var F = require("path");
|
|
36
|
+
function p(t, e) {
|
|
37
|
+
let o = (0, F.relative)(e, t).replace(/\.(ts|js)$/, "");
|
|
38
|
+
return o.endsWith("/index") ? o = o.slice(0, -6) : o === "index" && (o = ""), o = o.replace(/\$/g, ":"), `/${o}`;
|
|
39
|
+
}
|
|
40
|
+
// plugins/fs/src/utils/glob.ts
|
|
41
|
+
var A = require("fs/promises"), E = require("path");
|
|
42
|
+
async function a(t) {
|
|
43
|
+
let e = await (0, A.readdir)(t, { withFileTypes: !0 });
|
|
44
|
+
return (await Promise.all(
|
|
45
|
+
e.map(async (o) => {
|
|
46
|
+
let s = (0, E.join)(t, o.name);
|
|
47
|
+
return o.isDirectory() ? a(s) : s;
|
|
48
|
+
})
|
|
49
|
+
)).flat();
|
|
50
|
+
}
|
|
51
|
+
// plugins/fs/src/utils/loader.ts
|
|
52
|
+
async function y(t) {
|
|
53
|
+
let r = (await a(t)).filter((s) => f.has((0, j.extname)(s)) && !s.endsWith(".d.ts")).sort(), o = [];
|
|
54
|
+
for (let s of r) {
|
|
55
|
+
let n = (await import((0, v.pathToFileURL)(s).href)).default;
|
|
56
|
+
n != null && (n.path || (n.path = p(s, t)), o.push(n));
|
|
57
|
+
}
|
|
58
|
+
return o;
|
|
59
|
+
}
|
|
29
60
|
// plugins/fs/src/utils/log.ts
|
|
30
|
-
var
|
|
61
|
+
var c = {
|
|
31
62
|
reset: "\x1B[0m",
|
|
32
63
|
red: "\x1B[31m",
|
|
33
64
|
yellow: "\x1B[33m",
|
|
34
65
|
cyan: "\x1B[36m"
|
|
35
66
|
};
|
|
36
|
-
function w(
|
|
37
|
-
console.warn(`${
|
|
38
|
-
for (let [
|
|
39
|
-
console.log(`${
|
|
67
|
+
function w(t, e) {
|
|
68
|
+
console.warn(`${c.yellow}%s %s${c.reset}`, "[AsterFlow]", t), console.group();
|
|
69
|
+
for (let [r, o] of Object.entries(e))
|
|
70
|
+
console.log(`${c.cyan}%s:${c.reset} %s`, r, o);
|
|
40
71
|
console.groupEnd(), console.log();
|
|
41
72
|
}
|
|
42
73
|
// plugins/fs/src/utils/codegen.ts
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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);
|
|
74
|
+
var m = require("fs/promises"), i = require("path");
|
|
75
|
+
async function L({ routesDir: t, outFile: e }) {
|
|
76
|
+
let o = (await a(t)).filter((l) => f.has((0, i.extname)(l)) && !l.endsWith(".d.ts")).sort(), s = (0, i.dirname)(e), g = [], n = [], x = [];
|
|
77
|
+
o.forEach((l, k) => {
|
|
78
|
+
let u = `Route${k}`, O = $((0, i.relative)(s, l)), P = p(l, t);
|
|
79
|
+
g.push(`import ${u} from '${O}'`), n.push(`if (!${u}.path) ${u}.path = ${JSON.stringify(P)}`), x.push(u);
|
|
68
80
|
});
|
|
69
|
-
let
|
|
81
|
+
let S = [
|
|
70
82
|
"// AUTO-GENERATED by `asterflow generate` - do not edit directly.",
|
|
71
|
-
`// Source directory: ${
|
|
83
|
+
`// Source directory: ${$((0, i.relative)(s, t))}`,
|
|
72
84
|
...g,
|
|
73
85
|
"",
|
|
74
|
-
...
|
|
86
|
+
...n,
|
|
75
87
|
"",
|
|
76
88
|
`export default [${x.join(", ")}]`,
|
|
77
89
|
""
|
|
78
90
|
].join(`
|
|
79
91
|
`);
|
|
80
|
-
await (0,
|
|
92
|
+
await (0, m.mkdir)(s, { recursive: !0 }), await (0, m.writeFile)(e, S);
|
|
81
93
|
}
|
|
82
|
-
function
|
|
83
|
-
let
|
|
84
|
-
return
|
|
94
|
+
function $(t) {
|
|
95
|
+
let r = t.replace(/\.(ts|tsx|js|jsx)$/, "").split(i.sep).join("/");
|
|
96
|
+
return r.startsWith(".") ? r : `./${r}`;
|
|
85
97
|
}
|
|
86
98
|
// plugins/fs/src/index.ts
|
|
87
|
-
var
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
var T = b.Plugin.create({ name: "fs-routing" }).decorate("creator", "Ashu11-A").decorate("version", R).config({
|
|
100
|
+
routes: void 0,
|
|
101
|
+
path: void 0
|
|
102
|
+
}).extends((t, e) => ({
|
|
103
|
+
registerRoutes(r) {
|
|
104
|
+
for (let o of r) {
|
|
105
|
+
if (!(o instanceof d.Method || o instanceof d.Router)) {
|
|
91
106
|
w("Route Skipped: Invalid Entry", {
|
|
92
|
-
"Exported Type": typeof
|
|
93
|
-
Reason: "An entry in the
|
|
94
|
-
Solution: "
|
|
107
|
+
"Exported Type": typeof o,
|
|
108
|
+
Reason: "An entry in the route list is not a Router/Method instance.",
|
|
109
|
+
Solution: "Check the route file's default export - if using a static manifest, re-run `asterflow generate`."
|
|
95
110
|
});
|
|
96
111
|
continue;
|
|
97
112
|
}
|
|
98
|
-
|
|
113
|
+
t.controller(o);
|
|
99
114
|
}
|
|
100
115
|
}
|
|
101
|
-
})).on("beforeInitialize", (
|
|
116
|
+
})).on("beforeInitialize", async (t, e) => {
|
|
117
|
+
e.path && e.routes && w("Ambiguous fs-routing Config", {
|
|
118
|
+
Reason: "Both `routes` and `path` were provided.",
|
|
119
|
+
Solution: "Pass only one: `path` for dynamic (dev) loading, or `routes` for a pre-generated static manifest. `path` will be used."
|
|
120
|
+
});
|
|
121
|
+
let r = e.path ? await y(e.path) : e.routes ?? [];
|
|
122
|
+
t.registerRoutes(r);
|
|
123
|
+
}), X = T;
|
|
102
124
|
0 && (module.exports = {
|
|
103
125
|
fsRoutingPlugin,
|
|
104
126
|
generateRouteManifest,
|
|
105
127
|
getFilesRecursively,
|
|
128
|
+
loadRoutesFromDir,
|
|
106
129
|
transformPathToUrl
|
|
107
130
|
});
|
package/dist/mjs/index.js
CHANGED
|
@@ -1,87 +1,110 @@
|
|
|
1
1
|
// plugins/fs/src/index.ts
|
|
2
|
-
import { Plugin as
|
|
3
|
-
import { Method as
|
|
2
|
+
import { Plugin as U } from "@asterflow/plugin";
|
|
3
|
+
import { Method as M, Router as W } from "@asterflow/router";
|
|
4
4
|
// plugins/fs/package.json
|
|
5
|
-
var
|
|
6
|
-
// plugins/fs/src/utils/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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";
|
|
5
|
+
var g = "2.2.0";
|
|
6
|
+
// plugins/fs/src/utils/loader.ts
|
|
7
|
+
import { extname as T } from "path";
|
|
8
|
+
import { pathToFileURL as S } from "url";
|
|
9
|
+
// plugins/fs/src/utils/constants.ts
|
|
10
|
+
var p = new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
22
11
|
// plugins/fs/src/utils/format.ts
|
|
23
|
-
import { relative as
|
|
24
|
-
function
|
|
25
|
-
let
|
|
26
|
-
return
|
|
12
|
+
import { relative as v } from "path";
|
|
13
|
+
function u(e, o) {
|
|
14
|
+
let t = v(o, e).replace(/\.(ts|js)$/, "");
|
|
15
|
+
return t.endsWith("/index") ? t = t.slice(0, -6) : t === "index" && (t = ""), t = t.replace(/\$/g, ":"), `/${t}`;
|
|
27
16
|
}
|
|
28
17
|
// plugins/fs/src/utils/glob.ts
|
|
29
|
-
import { readdir as
|
|
18
|
+
import { readdir as $ } from "fs/promises";
|
|
30
19
|
import { join as b } from "path";
|
|
31
|
-
async function
|
|
32
|
-
let
|
|
20
|
+
async function a(e) {
|
|
21
|
+
let o = await $(e, { withFileTypes: !0 });
|
|
33
22
|
return (await Promise.all(
|
|
34
|
-
|
|
35
|
-
let
|
|
36
|
-
return
|
|
23
|
+
o.map(async (t) => {
|
|
24
|
+
let s = b(e, t.name);
|
|
25
|
+
return t.isDirectory() ? a(s) : s;
|
|
37
26
|
})
|
|
38
27
|
)).flat();
|
|
39
28
|
}
|
|
29
|
+
// plugins/fs/src/utils/loader.ts
|
|
30
|
+
async function h(e) {
|
|
31
|
+
let r = (await a(e)).filter((s) => p.has(T(s)) && !s.endsWith(".d.ts")).sort(), t = [];
|
|
32
|
+
for (let s of r) {
|
|
33
|
+
let i = (await import(S(s).href)).default;
|
|
34
|
+
i != null && (i.path || (i.path = u(s, e)), t.push(i));
|
|
35
|
+
}
|
|
36
|
+
return t;
|
|
37
|
+
}
|
|
38
|
+
// plugins/fs/src/utils/log.ts
|
|
39
|
+
var f = {
|
|
40
|
+
reset: "\x1B[0m",
|
|
41
|
+
red: "\x1B[31m",
|
|
42
|
+
yellow: "\x1B[33m",
|
|
43
|
+
cyan: "\x1B[36m"
|
|
44
|
+
};
|
|
45
|
+
function m(e, o) {
|
|
46
|
+
console.warn(`${f.yellow}%s %s${f.reset}`, "[AsterFlow]", e), console.group();
|
|
47
|
+
for (let [r, t] of Object.entries(o))
|
|
48
|
+
console.log(`${f.cyan}%s:${f.reset} %s`, r, t);
|
|
49
|
+
console.groupEnd(), console.log();
|
|
50
|
+
}
|
|
40
51
|
// plugins/fs/src/utils/codegen.ts
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
e.
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
import { mkdir as k, writeFile as O } from "fs/promises";
|
|
53
|
+
import { dirname as P, extname as I, relative as y, sep as N } from "path";
|
|
54
|
+
async function rt({ routesDir: e, outFile: o }) {
|
|
55
|
+
let t = (await a(e)).filter((n) => p.has(I(n)) && !n.endsWith(".d.ts")).sort(), s = P(o), c = [], i = [], d = [];
|
|
56
|
+
t.forEach((n, R) => {
|
|
57
|
+
let l = `Route${R}`, F = w(y(s, n)), A = u(n, e);
|
|
58
|
+
c.push(`import ${l} from '${F}'`), i.push(`if (!${l}.path) ${l}.path = ${JSON.stringify(A)}`), d.push(l);
|
|
47
59
|
});
|
|
48
|
-
let
|
|
60
|
+
let x = [
|
|
49
61
|
"// AUTO-GENERATED by `asterflow generate` - do not edit directly.",
|
|
50
|
-
`// Source directory: ${
|
|
62
|
+
`// Source directory: ${w(y(s, e))}`,
|
|
51
63
|
...c,
|
|
52
64
|
"",
|
|
53
|
-
...
|
|
65
|
+
...i,
|
|
54
66
|
"",
|
|
55
|
-
`export default [${
|
|
67
|
+
`export default [${d.join(", ")}]`,
|
|
56
68
|
""
|
|
57
69
|
].join(`
|
|
58
70
|
`);
|
|
59
|
-
await
|
|
71
|
+
await k(s, { recursive: !0 }), await O(o, x);
|
|
60
72
|
}
|
|
61
|
-
function
|
|
62
|
-
let
|
|
63
|
-
return
|
|
73
|
+
function w(e) {
|
|
74
|
+
let r = e.replace(/\.(ts|tsx|js|jsx)$/, "").split(N).join("/");
|
|
75
|
+
return r.startsWith(".") ? r : `./${r}`;
|
|
64
76
|
}
|
|
65
77
|
// plugins/fs/src/index.ts
|
|
66
|
-
var
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
78
|
+
var _ = U.create({ name: "fs-routing" }).decorate("creator", "Ashu11-A").decorate("version", g).config({
|
|
79
|
+
routes: void 0,
|
|
80
|
+
path: void 0
|
|
81
|
+
}).extends((e, o) => ({
|
|
82
|
+
registerRoutes(r) {
|
|
83
|
+
for (let t of r) {
|
|
84
|
+
if (!(t instanceof M || t instanceof W)) {
|
|
70
85
|
m("Route Skipped: Invalid Entry", {
|
|
71
|
-
"Exported Type": typeof
|
|
72
|
-
Reason: "An entry in the
|
|
73
|
-
Solution: "
|
|
86
|
+
"Exported Type": typeof t,
|
|
87
|
+
Reason: "An entry in the route list is not a Router/Method instance.",
|
|
88
|
+
Solution: "Check the route file's default export - if using a static manifest, re-run `asterflow generate`."
|
|
74
89
|
});
|
|
75
90
|
continue;
|
|
76
91
|
}
|
|
77
|
-
|
|
92
|
+
e.controller(t);
|
|
78
93
|
}
|
|
79
94
|
}
|
|
80
|
-
})).on("beforeInitialize", (
|
|
95
|
+
})).on("beforeInitialize", async (e, o) => {
|
|
96
|
+
o.path && o.routes && m("Ambiguous fs-routing Config", {
|
|
97
|
+
Reason: "Both `routes` and `path` were provided.",
|
|
98
|
+
Solution: "Pass only one: `path` for dynamic (dev) loading, or `routes` for a pre-generated static manifest. `path` will be used."
|
|
99
|
+
});
|
|
100
|
+
let r = o.path ? await h(o.path) : o.routes ?? [];
|
|
101
|
+
e.registerRoutes(r);
|
|
102
|
+
}), pt = _;
|
|
81
103
|
export {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
pt as default,
|
|
105
|
+
_ as fsRoutingPlugin,
|
|
106
|
+
rt as generateRouteManifest,
|
|
107
|
+
a as getFilesRecursively,
|
|
108
|
+
h as loadRoutesFromDir,
|
|
109
|
+
u as transformPathToUrl
|
|
87
110
|
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type AnyRouter } from '@asterflow/router';
|
|
|
3
3
|
export * from './utils/codegen';
|
|
4
4
|
export * from './utils/format';
|
|
5
5
|
export * from './utils/glob';
|
|
6
|
+
export * from './utils/loader';
|
|
6
7
|
export * from './types/asterflow.d';
|
|
7
8
|
export declare const fsRoutingPlugin: Plugin<{
|
|
8
9
|
decorate: {
|
|
@@ -10,23 +11,18 @@ export declare const fsRoutingPlugin: Plugin<{
|
|
|
10
11
|
version: string;
|
|
11
12
|
};
|
|
12
13
|
config: {
|
|
13
|
-
routes: AnyRouter[];
|
|
14
|
+
routes: AnyRouter[] | undefined;
|
|
15
|
+
path: string | undefined;
|
|
14
16
|
defaultConfig: {
|
|
15
|
-
routes: AnyRouter[];
|
|
17
|
+
routes: AnyRouter[] | undefined;
|
|
18
|
+
path: string | undefined;
|
|
16
19
|
};
|
|
17
20
|
};
|
|
18
21
|
path: "fs-routing";
|
|
19
22
|
instance: import("asterflow").AnyAsterflow;
|
|
20
23
|
derive: {};
|
|
21
24
|
extension: {
|
|
22
|
-
registerRoutes: (
|
|
23
|
-
routes: AnyRouter[];
|
|
24
|
-
defaultConfig: {
|
|
25
|
-
routes: AnyRouter[];
|
|
26
|
-
};
|
|
27
|
-
creator: string;
|
|
28
|
-
version: string;
|
|
29
|
-
}) => void;
|
|
25
|
+
registerRoutes: (routes: AnyRouter[]) => void;
|
|
30
26
|
};
|
|
31
27
|
}>;
|
|
32
28
|
export default fsRoutingPlugin;
|
|
@@ -7,9 +7,11 @@ export interface GenerateRouteManifestOptions {
|
|
|
7
7
|
/**
|
|
8
8
|
* Scans `routesDir` once and writes a manifest file at `outFile` containing a
|
|
9
9
|
* static `import` per route file plus a default-exported `AnyRouter[]`. Meant
|
|
10
|
-
* to run at build
|
|
11
|
-
*
|
|
12
|
-
* follow, unlike `
|
|
13
|
-
*
|
|
10
|
+
* to run at build time (the `asterflow generate` CLI command, or a bundler
|
|
11
|
+
* plugin) - the resulting imports are literal specifiers a bundler can
|
|
12
|
+
* follow, unlike `loadRoutesFromDir`'s fully-dynamic `import(file)`, which
|
|
13
|
+
* bundlers can't statically resolve at all. Use this for bundled/production
|
|
14
|
+
* builds; `loadRoutesFromDir` (passed to `fsRoutingPlugin` as `routesDir`)
|
|
15
|
+
* covers unbundled dev runs where no codegen step is wanted.
|
|
14
16
|
*/
|
|
15
17
|
export declare function generateRouteManifest({ routesDir, outFile }: GenerateRouteManifestOptions): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ROUTE_FILE_EXTENSIONS: Set<string>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AnyRouter } from '@asterflow/router';
|
|
2
|
+
/**
|
|
3
|
+
* Scans `routesDir` and `import()`s every route file at call time, assigning
|
|
4
|
+
* `path` from the file location when a route doesn't set one explicitly.
|
|
5
|
+
* Meant for unbundled dev/runtime use (no codegen step required) - the
|
|
6
|
+
* `import()` path is fully dynamic, so a bundler can't trace it. Bundled
|
|
7
|
+
* builds should use `generateRouteManifest` + a static `routes` array
|
|
8
|
+
* instead.
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadRoutesFromDir(routesDir: string): Promise<AnyRouter[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asterflow/fs",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Generates a static route manifest from a file-based routes/ directory and registers it on an AsterFlow app as a plugin.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"asterflow",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"node": ">=20"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@asterflow/plugin": "^2.0
|
|
38
|
-
"@asterflow/router": "^2.0
|
|
37
|
+
"@asterflow/plugin": "^2.2.0",
|
|
38
|
+
"@asterflow/router": "^2.2.0",
|
|
39
39
|
"@asterflow/url-parser": "^4.1.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"asterflow": "^2.0
|
|
42
|
+
"asterflow": "^2.2.0"
|
|
43
43
|
}
|
|
44
44
|
}
|