@fluixi/core 1.0.0-alpha.82 → 1.0.0-alpha.84
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/dist/cdn/core.global.js +2 -1
- package/dist/cli/generate.cjs +4117 -292
- package/dist/cli/generate.mjs +4122 -292
- package/dist/cli/index.cjs +4117 -292
- package/dist/cli/index.mjs +4122 -292
- package/dist/cli/run.cjs +63 -1
- package/dist/cli/run.mjs +39 -1
- package/dist/src/cdn/chunk-VNLCQBFQ.mjs +747 -0
- package/dist/src/cdn/core.cjs +1279 -1
- package/dist/src/cdn/core.d.ts +3 -3
- package/dist/src/cdn/core.js +3 -3
- package/dist/src/cdn/core.mjs +642 -1
- package/dist/src/cdn/router-WMN2AA7E.mjs +66 -0
- package/dist/src/index.cjs +1201 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -11
- package/dist/src/index.mjs +1313 -1
- package/dist/src/jsx-dev-runtime.cjs +26 -1
- package/dist/src/jsx-dev-runtime.mjs +24 -1
- package/dist/src/jsx-runtime.cjs +26 -1
- package/dist/src/jsx-runtime.js +0 -9
- package/dist/src/jsx-runtime.mjs +24 -1
- package/dist/src/lib/client/chunk-2C2KDDQV.mjs +133 -0
- package/dist/src/lib/client/index.cjs +870 -1
- package/dist/src/lib/client/index.d.ts +10 -14
- package/dist/src/lib/client/index.d.ts.map +1 -1
- package/dist/src/lib/client/index.js +36 -21
- package/dist/src/lib/client/index.mjs +222 -1
- package/dist/src/lib/client/router-X526HSWQ.mjs +548 -0
- package/dist/src/lib/context/context.cjs +118 -1
- package/dist/src/lib/context/context.d.ts +20 -38
- package/dist/src/lib/context/context.d.ts.map +1 -1
- package/dist/src/lib/context/context.js +10 -47
- package/dist/src/lib/context/context.mjs +99 -1
- package/dist/src/lib/context/index.cjs +120 -1
- package/dist/src/lib/context/index.mjs +99 -1
- package/dist/src/lib/control-flow.cjs +35 -1
- package/dist/src/lib/control-flow.mjs +25 -1
- package/dist/src/lib/core.cjs +1200 -1
- package/dist/src/lib/core.d.ts +0 -2
- package/dist/src/lib/core.d.ts.map +1 -1
- package/dist/src/lib/core.js +14 -48
- package/dist/src/lib/core.mjs +1313 -1
- package/dist/src/lib/env/index.cjs +60 -1
- package/dist/src/lib/env/index.d.ts +7 -8
- package/dist/src/lib/env/index.d.ts.map +1 -1
- package/dist/src/lib/env/index.js +14 -9
- package/dist/src/lib/env/index.mjs +39 -1
- package/dist/src/lib/i18n/index.cjs +108 -1
- package/dist/src/lib/i18n/index.d.ts +31 -10
- package/dist/src/lib/i18n/index.d.ts.map +1 -1
- package/dist/src/lib/i18n/index.js +31 -10
- package/dist/src/lib/i18n/index.mjs +88 -1
- package/dist/src/lib/index.cjs +633 -1
- package/dist/src/lib/index.d.ts +0 -2
- package/dist/src/lib/index.d.ts.map +1 -1
- package/dist/src/lib/index.js +5 -11
- package/dist/src/lib/index.mjs +721 -1
- package/dist/src/lib/isomorphic.cjs +85 -1
- package/dist/src/lib/isomorphic.d.ts +41 -8
- package/dist/src/lib/isomorphic.d.ts.map +1 -1
- package/dist/src/lib/isomorphic.js +38 -5
- package/dist/src/lib/isomorphic.mjs +64 -1
- package/dist/src/lib/jsx-runtime/index.cjs +21 -1
- package/dist/src/lib/jsx-runtime/index.d.ts +1 -1
- package/dist/src/lib/jsx-runtime/index.js +1 -11
- package/dist/src/lib/jsx-runtime/index.mjs +4 -1
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +21 -1
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +4 -1
- package/dist/src/lib/plugins/fluixi-routes-plugin.cjs +302 -8
- package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts +15 -1
- package/dist/src/lib/plugins/fluixi-routes-plugin.d.ts.map +1 -1
- package/dist/src/lib/plugins/fluixi-routes-plugin.js +19 -5
- package/dist/src/lib/plugins/fluixi-routes-plugin.mjs +271 -8
- package/dist/src/lib/plugins/index.cjs +311 -8
- package/dist/src/lib/plugins/index.mjs +279 -8
- package/dist/src/lib/plugins/route-codegen.cjs +73 -8
- package/dist/src/lib/plugins/route-codegen.d.ts +0 -1
- package/dist/src/lib/plugins/route-codegen.d.ts.map +1 -1
- package/dist/src/lib/plugins/route-codegen.js +4 -5
- package/dist/src/lib/plugins/route-codegen.mjs +52 -8
- package/dist/src/lib/plugins/route-scanner.cjs +189 -1
- package/dist/src/lib/plugins/route-scanner.d.ts +1 -2
- package/dist/src/lib/plugins/route-scanner.d.ts.map +1 -1
- package/dist/src/lib/plugins/route-scanner.js +7 -8
- package/dist/src/lib/plugins/route-scanner.mjs +158 -1
- package/dist/src/lib/plugins/vite.cjs +27 -1
- package/dist/src/lib/plugins/vite.mjs +6 -1
- package/dist/src/lib/render/await.cjs +38 -1
- package/dist/src/lib/render/await.d.ts +18 -0
- package/dist/src/lib/render/await.d.ts.map +1 -1
- package/dist/src/lib/render/await.js +20 -2
- package/dist/src/lib/render/await.mjs +17 -1
- package/dist/src/lib/render/component.cjs +221 -1
- package/dist/src/lib/render/component.d.ts +3 -44
- package/dist/src/lib/render/component.d.ts.map +1 -1
- package/dist/src/lib/render/component.js +32 -59
- package/dist/src/lib/render/component.mjs +214 -1
- package/dist/src/lib/render/deferred.cjs +175 -1
- package/dist/src/lib/render/deferred.d.ts.map +1 -1
- package/dist/src/lib/render/deferred.js +8 -8
- package/dist/src/lib/render/deferred.mjs +158 -1
- package/dist/src/lib/render/index.cjs +573 -1
- package/dist/src/lib/render/index.d.ts +3 -17
- package/dist/src/lib/render/index.d.ts.map +1 -1
- package/dist/src/lib/render/index.js +12 -26
- package/dist/src/lib/render/index.mjs +590 -1
- package/dist/src/lib/render/lazy.cjs +67 -1
- package/dist/src/lib/render/lazy.d.ts +22 -1
- package/dist/src/lib/render/lazy.d.ts.map +1 -1
- package/dist/src/lib/render/lazy.js +47 -8
- package/dist/src/lib/render/lazy.mjs +50 -1
- package/dist/src/lib/render/suspense.cjs +141 -1
- package/dist/src/lib/render/suspense.d.ts +40 -0
- package/dist/src/lib/render/suspense.d.ts.map +1 -1
- package/dist/src/lib/render/suspense.js +47 -7
- package/dist/src/lib/render/suspense.mjs +136 -1
- package/dist/src/lib/render/versions.cjs +35 -1
- package/dist/src/lib/render/versions.js +6 -6
- package/dist/src/lib/render/versions.mjs +14 -1
- package/dist/src/lib/router/data.cjs +230 -1
- package/dist/src/lib/router/data.d.ts +1 -13
- package/dist/src/lib/router/data.d.ts.map +1 -1
- package/dist/src/lib/router/data.js +1 -13
- package/dist/src/lib/router/data.mjs +214 -1
- package/dist/src/lib/router/index.cjs +627 -1
- package/dist/src/lib/router/index.d.ts +62 -10
- package/dist/src/lib/router/index.d.ts.map +1 -1
- package/dist/src/lib/router/index.js +90 -39
- package/dist/src/lib/router/index.mjs +639 -1
- package/dist/src/lib/server/hydration.cjs +169 -1
- package/dist/src/lib/server/hydration.d.ts +15 -55
- package/dist/src/lib/server/hydration.d.ts.map +1 -1
- package/dist/src/lib/server/hydration.js +23 -62
- package/dist/src/lib/server/hydration.mjs +148 -1
- package/dist/src/lib/server/index.cjs +401 -11
- package/dist/src/lib/server/index.d.ts +30 -6
- package/dist/src/lib/server/index.d.ts.map +1 -1
- package/dist/src/lib/server/index.js +34 -11
- package/dist/src/lib/server/index.mjs +379 -11
- package/dist/src/lib/server/reactive.cjs +197 -1
- package/dist/src/lib/server/reactive.d.ts +18 -77
- package/dist/src/lib/server/reactive.d.ts.map +1 -1
- package/dist/src/lib/server/reactive.js +19 -78
- package/dist/src/lib/server/reactive.mjs +176 -1
- package/dist/src/lib/theme/index.cjs +110 -1
- package/dist/src/lib/theme/index.d.ts +19 -4
- package/dist/src/lib/theme/index.d.ts.map +1 -1
- package/dist/src/lib/theme/index.js +17 -2
- package/dist/src/lib/theme/index.mjs +89 -1
- package/dist/src/lib/utils/index.cjs +209 -1
- package/dist/src/lib/utils/index.d.ts +0 -93
- package/dist/src/lib/utils/index.d.ts.map +1 -1
- package/dist/src/lib/utils/index.js +0 -93
- package/dist/src/lib/utils/index.mjs +188 -1
- package/dist/src/routes.cjs +37 -1
- package/dist/src/routes.d.ts +1 -1
- package/dist/src/routes.js +2 -2
- package/dist/src/routes.mjs +17 -1
- package/dist/src/server.cjs +400 -11
- package/dist/src/server.d.ts +0 -1
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +0 -1
- package/dist/src/server.mjs +377 -11
- package/dist/src/utils.cjs +21 -1
- package/dist/src/utils.d.ts +1 -1
- package/dist/src/utils.js +1 -1
- package/dist/src/utils.mjs +4 -1
- package/dist/src/version.generated.cjs +26 -1
- package/dist/src/version.generated.d.ts +1 -1
- package/dist/src/version.generated.js +2 -2
- package/dist/src/version.generated.mjs +5 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +17 -16
- package/src/index.ts +2 -14
- package/dist/src/cdn/chunk-RN7C7HNS.mjs +0 -1
- package/dist/src/cdn/router-QB3W43UQ.mjs +0 -1
- package/dist/src/lib/client/chunk-FT22BLCQ.mjs +0 -1
- package/dist/src/lib/client/router-IH7JYMRU.mjs +0 -1
|
@@ -1,8 +1,271 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
// src/lib/plugins/fluixi-routes-plugin.ts
|
|
2
|
+
import * as path2 from "path";
|
|
3
|
+
import { nodePolyfills } from "vite-plugin-node-polyfills";
|
|
4
|
+
|
|
5
|
+
// src/lib/plugins/route-scanner.ts
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
var DEFAULT_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
|
|
9
|
+
function scanRoutes(routesDir, options = {}) {
|
|
10
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
11
|
+
const absDir = path.resolve(routesDir);
|
|
12
|
+
if (!fs.existsSync(absDir)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
return scanDirectory(absDir, absDir, "", extensions);
|
|
16
|
+
}
|
|
17
|
+
function scanDirectory(dir, rootDir, parentUrlPath, extensions) {
|
|
18
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
19
|
+
const routes = [];
|
|
20
|
+
const layoutRoute = null;
|
|
21
|
+
const files = [];
|
|
22
|
+
const dirs = [];
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
dirs.push(entry);
|
|
26
|
+
} else if (entry.isFile() && hasValidExtension(entry.name, extensions)) {
|
|
27
|
+
files.push(entry);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
let layout;
|
|
31
|
+
const nonLayoutFiles = [];
|
|
32
|
+
for (const file of files) {
|
|
33
|
+
const baseName = stripExtension(file.name);
|
|
34
|
+
if (baseName === "layout") {
|
|
35
|
+
layout = buildFileRoute(file.name, dir, rootDir, parentUrlPath, true);
|
|
36
|
+
} else {
|
|
37
|
+
nonLayoutFiles.push(file);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const fileRoutes = [];
|
|
41
|
+
for (const file of nonLayoutFiles) {
|
|
42
|
+
fileRoutes.push(
|
|
43
|
+
buildFileRoute(file.name, dir, rootDir, parentUrlPath, false)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
const dirRoutes = [];
|
|
47
|
+
for (const d of dirs) {
|
|
48
|
+
const dirName = d.name;
|
|
49
|
+
const isGroup = isRouteGroup(dirName);
|
|
50
|
+
const segment = isGroup ? "" : dirNameToSegment(dirName);
|
|
51
|
+
const childUrlPath = segment ? joinUrlPath(parentUrlPath, segment) : parentUrlPath;
|
|
52
|
+
const children = scanDirectory(
|
|
53
|
+
path.join(dir, dirName),
|
|
54
|
+
rootDir,
|
|
55
|
+
childUrlPath,
|
|
56
|
+
extensions
|
|
57
|
+
);
|
|
58
|
+
if (isGroup) {
|
|
59
|
+
dirRoutes.push(...children);
|
|
60
|
+
} else {
|
|
61
|
+
const childLayout = children.find((c) => c.isLayout && c.urlPath === childUrlPath);
|
|
62
|
+
const childNonLayout = children.filter((c) => !c.isLayout || c.urlPath !== childUrlPath);
|
|
63
|
+
if (childLayout) {
|
|
64
|
+
childLayout.children = [...childLayout.children, ...childNonLayout];
|
|
65
|
+
dirRoutes.push(childLayout);
|
|
66
|
+
} else if (childNonLayout.length > 0) {
|
|
67
|
+
dirRoutes.push(...childNonLayout);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (layout) {
|
|
72
|
+
layout.children = [...fileRoutes, ...dirRoutes];
|
|
73
|
+
routes.push(layout);
|
|
74
|
+
} else {
|
|
75
|
+
routes.push(...fileRoutes, ...dirRoutes);
|
|
76
|
+
}
|
|
77
|
+
return sortRoutes(routes);
|
|
78
|
+
}
|
|
79
|
+
function buildFileRoute(fileName, dir, rootDir, parentUrlPath, isLayout) {
|
|
80
|
+
const baseName = stripExtension(fileName);
|
|
81
|
+
const filePath = path.relative(rootDir, path.join(dir, fileName));
|
|
82
|
+
const isIndex = baseName === "index";
|
|
83
|
+
const isCatchAll = baseName.startsWith("[...");
|
|
84
|
+
const isDynamic = !isCatchAll && baseName.startsWith("[") && baseName.endsWith("]");
|
|
85
|
+
let urlSegment;
|
|
86
|
+
if (isLayout) {
|
|
87
|
+
urlSegment = "";
|
|
88
|
+
} else if (isIndex) {
|
|
89
|
+
urlSegment = "/";
|
|
90
|
+
} else if (isCatchAll) {
|
|
91
|
+
const paramName = baseName.slice(4, -1);
|
|
92
|
+
urlSegment = `*${paramName}`;
|
|
93
|
+
} else if (isDynamic) {
|
|
94
|
+
const paramName = baseName.slice(1, -1);
|
|
95
|
+
urlSegment = `:${paramName}`;
|
|
96
|
+
} else {
|
|
97
|
+
urlSegment = baseName;
|
|
98
|
+
}
|
|
99
|
+
const urlPath = isLayout ? parentUrlPath || "/" : isIndex ? parentUrlPath || "/" : joinUrlPath(parentUrlPath, urlSegment);
|
|
100
|
+
const absoluteFilePath = path.join(dir, fileName);
|
|
101
|
+
let hasRouteData = false;
|
|
102
|
+
try {
|
|
103
|
+
const content = fs.readFileSync(absoluteFilePath, "utf-8");
|
|
104
|
+
hasRouteData = /export\s+(const|function|async\s+function)\s+routeData\b/.test(content);
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
filePath: filePath.replace(/\\/g, "/"),
|
|
109
|
+
// normalize to forward slashes
|
|
110
|
+
urlSegment,
|
|
111
|
+
urlPath,
|
|
112
|
+
isLayout,
|
|
113
|
+
isIndex,
|
|
114
|
+
isDynamic,
|
|
115
|
+
isCatchAll,
|
|
116
|
+
isGroup: false,
|
|
117
|
+
children: [],
|
|
118
|
+
parentUrlPath,
|
|
119
|
+
hasRouteData,
|
|
120
|
+
rootDir,
|
|
121
|
+
dir
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function hasValidExtension(fileName, extensions) {
|
|
125
|
+
return extensions.some((ext) => fileName.endsWith(ext));
|
|
126
|
+
}
|
|
127
|
+
function stripExtension(fileName) {
|
|
128
|
+
const lastDot = fileName.lastIndexOf(".");
|
|
129
|
+
return lastDot > 0 ? fileName.slice(0, lastDot) : fileName;
|
|
130
|
+
}
|
|
131
|
+
function isRouteGroup(dirName) {
|
|
132
|
+
return dirName.startsWith("(") && dirName.endsWith(")");
|
|
133
|
+
}
|
|
134
|
+
function dirNameToSegment(dirName) {
|
|
135
|
+
if (dirName.startsWith("[...") && dirName.endsWith("]")) {
|
|
136
|
+
return "*" + dirName.slice(4, -1);
|
|
137
|
+
}
|
|
138
|
+
if (dirName.startsWith("[") && dirName.endsWith("]")) {
|
|
139
|
+
return ":" + dirName.slice(1, -1);
|
|
140
|
+
}
|
|
141
|
+
return dirName;
|
|
142
|
+
}
|
|
143
|
+
function joinUrlPath(parent, segment) {
|
|
144
|
+
const base = parent.endsWith("/") ? parent : parent + "/";
|
|
145
|
+
return base + segment;
|
|
146
|
+
}
|
|
147
|
+
function sortRoutes(routes) {
|
|
148
|
+
return routes.sort((a, b) => {
|
|
149
|
+
if (a.isLayout && !b.isLayout) return -1;
|
|
150
|
+
if (!a.isLayout && b.isLayout) return 1;
|
|
151
|
+
if (a.isIndex && !b.isIndex) return -1;
|
|
152
|
+
if (!a.isIndex && b.isIndex) return 1;
|
|
153
|
+
if (!a.isDynamic && !a.isCatchAll && (b.isDynamic || b.isCatchAll)) return -1;
|
|
154
|
+
if ((a.isDynamic || a.isCatchAll) && !b.isDynamic && !b.isCatchAll) return 1;
|
|
155
|
+
if (a.isDynamic && b.isCatchAll) return -1;
|
|
156
|
+
if (a.isCatchAll && b.isDynamic) return 1;
|
|
157
|
+
return a.urlSegment.localeCompare(b.urlSegment);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/lib/plugins/route-codegen.ts
|
|
162
|
+
function generateRouteModule(routes, routesDir) {
|
|
163
|
+
const lines = [];
|
|
164
|
+
lines.push(`// Auto-generated by fluixi route plugin`);
|
|
165
|
+
lines.push(`// Do not edit manually`);
|
|
166
|
+
lines.push(``);
|
|
167
|
+
lines.push(`import { lazy } from '@fluixi/core/router';`);
|
|
168
|
+
lines.push(``);
|
|
169
|
+
lines.push(`export const routes = ${generateRouteArray(routes, routesDir, 0)};`);
|
|
170
|
+
lines.push(``);
|
|
171
|
+
return lines.join("\n");
|
|
172
|
+
}
|
|
173
|
+
function generateRouteArray(routes, routesDir, depth) {
|
|
174
|
+
if (routes.length === 0) return "[]";
|
|
175
|
+
const indent = " ".repeat(depth);
|
|
176
|
+
const items = routes.map((route) => generateRouteObject(route, routesDir, depth + 1));
|
|
177
|
+
return `[
|
|
178
|
+
${items.join(",\n")}
|
|
179
|
+
${indent}]`;
|
|
180
|
+
}
|
|
181
|
+
function generateRouteObject(route, routesDir, depth) {
|
|
182
|
+
const indent = " ".repeat(depth);
|
|
183
|
+
const props = [];
|
|
184
|
+
const importPath = buildImportPath(route.filePath, routesDir);
|
|
185
|
+
const routePath = computeRoutePath(route);
|
|
186
|
+
props.push(`${indent} path: ${JSON.stringify(routePath)}`);
|
|
187
|
+
props.push(`${indent} component: lazy(() => import(${JSON.stringify(importPath)}))`);
|
|
188
|
+
if (route.hasRouteData) {
|
|
189
|
+
props.push(
|
|
190
|
+
`${indent} data: (args, __owner, __isCancelled) => import(${JSON.stringify(
|
|
191
|
+
importPath
|
|
192
|
+
)}).then(m => { if (typeof __isCancelled === 'function' && __isCancelled()) return undefined; if (!m.routeData) return undefined; return __owner ? m.routeData(args) : m.routeData(args); })`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
if (route.children.length > 0) {
|
|
196
|
+
const childArray = generateRouteArray(route.children, routesDir, depth + 1);
|
|
197
|
+
props.push(`${indent} children: ${childArray}`);
|
|
198
|
+
}
|
|
199
|
+
return `${indent}{
|
|
200
|
+
${props.join(",\n")}
|
|
201
|
+
${indent}}`;
|
|
202
|
+
}
|
|
203
|
+
function computeRoutePath(route) {
|
|
204
|
+
return route.urlPath;
|
|
205
|
+
}
|
|
206
|
+
function buildImportPath(filePath, routesDir) {
|
|
207
|
+
const base = routesDir.replace(/\\/g, "/").replace(/\/$/, "");
|
|
208
|
+
return `${base}/${filePath}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/lib/plugins/fluixi-routes-plugin.ts
|
|
212
|
+
var VIRTUAL_MODULE_ID = "virtual:fluixi-routes";
|
|
213
|
+
var RESOLVED_VIRTUAL_ID = "\0" + VIRTUAL_MODULE_ID;
|
|
214
|
+
var PUBLIC_MODULE_ID = "@fluixi/core/routes";
|
|
215
|
+
function fluixiRoutesPlugin(options = {}) {
|
|
216
|
+
const routesDir = options.routesDir ?? "src/routes";
|
|
217
|
+
const extensions = options.extensions ?? [".tsx", ".ts", ".jsx", ".js"];
|
|
218
|
+
let projectRoot = "";
|
|
219
|
+
let lastGenerated = null;
|
|
220
|
+
function generateModule(root) {
|
|
221
|
+
const absRoutesDir = path2.resolve(root, routesDir);
|
|
222
|
+
const scanOpts = { extensions };
|
|
223
|
+
const routes = scanRoutes(absRoutesDir, scanOpts);
|
|
224
|
+
return generateRouteModule(routes, "./" + routesDir);
|
|
225
|
+
}
|
|
226
|
+
const usePolyfills = options.polyfills !== false;
|
|
227
|
+
const polyfillsPlugin = usePolyfills ? Object.assign({}, nodePolyfills({ include: ["fs", "path"] }), { apply: "serve" }) : null;
|
|
228
|
+
const routesPlugin = {
|
|
229
|
+
name: "fluixi-routes",
|
|
230
|
+
enforce: "pre",
|
|
231
|
+
configResolved(config) {
|
|
232
|
+
projectRoot = config.root || process.cwd();
|
|
233
|
+
},
|
|
234
|
+
resolveId(id) {
|
|
235
|
+
if (id === VIRTUAL_MODULE_ID || id === PUBLIC_MODULE_ID) {
|
|
236
|
+
return RESOLVED_VIRTUAL_ID;
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
},
|
|
240
|
+
load(id) {
|
|
241
|
+
if (id !== RESOLVED_VIRTUAL_ID) return null;
|
|
242
|
+
lastGenerated = generateModule(projectRoot || process.cwd());
|
|
243
|
+
return lastGenerated;
|
|
244
|
+
},
|
|
245
|
+
// Vite dev server: watch routes directory for changes
|
|
246
|
+
configureServer(server) {
|
|
247
|
+
const root = projectRoot || process.cwd();
|
|
248
|
+
const absRoutesDir = path2.resolve(root, routesDir);
|
|
249
|
+
server.watcher.add(absRoutesDir);
|
|
250
|
+
server.watcher.on("all", (event, filePath) => {
|
|
251
|
+
if (!filePath.startsWith(absRoutesDir)) return;
|
|
252
|
+
if (!["add", "unlink", "addDir", "unlinkDir", "change"].includes(event)) return;
|
|
253
|
+
if (event !== "addDir" && event !== "unlinkDir" && !extensions.some((ext) => filePath.endsWith(ext))) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const next = generateModule(root);
|
|
257
|
+
if (next === lastGenerated) return;
|
|
258
|
+
lastGenerated = next;
|
|
259
|
+
const mod = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ID);
|
|
260
|
+
if (mod) {
|
|
261
|
+
server.moduleGraph.invalidateModule(mod);
|
|
262
|
+
server.ws.send({ type: "full-reload" });
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
return polyfillsPlugin ? [polyfillsPlugin, routesPlugin] : [routesPlugin];
|
|
268
|
+
}
|
|
269
|
+
export {
|
|
270
|
+
fluixiRoutesPlugin
|
|
271
|
+
};
|
|
@@ -1,8 +1,311 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
/*! @fluixi/core v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/lib/plugins/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
createVitePlugin: () => import_vite_plugin.createVitePlugin,
|
|
35
|
+
fluixi: () => import_vite_plugin.fluixi,
|
|
36
|
+
fluixiRoutesPlugin: () => fluixiRoutesPlugin,
|
|
37
|
+
scanRoutes: () => scanRoutes
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(index_exports);
|
|
40
|
+
|
|
41
|
+
// src/lib/plugins/vite.ts
|
|
42
|
+
var import_vite_plugin = require("@fluixi/vite-plugin");
|
|
43
|
+
|
|
44
|
+
// src/lib/plugins/fluixi-routes-plugin.ts
|
|
45
|
+
var path2 = __toESM(require("path"), 1);
|
|
46
|
+
var import_vite_plugin_node_polyfills = require("vite-plugin-node-polyfills");
|
|
47
|
+
|
|
48
|
+
// src/lib/plugins/route-scanner.ts
|
|
49
|
+
var fs = __toESM(require("fs"), 1);
|
|
50
|
+
var path = __toESM(require("path"), 1);
|
|
51
|
+
var DEFAULT_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js"];
|
|
52
|
+
function scanRoutes(routesDir, options = {}) {
|
|
53
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
54
|
+
const absDir = path.resolve(routesDir);
|
|
55
|
+
if (!fs.existsSync(absDir)) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
return scanDirectory(absDir, absDir, "", extensions);
|
|
59
|
+
}
|
|
60
|
+
function scanDirectory(dir, rootDir, parentUrlPath, extensions) {
|
|
61
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
62
|
+
const routes = [];
|
|
63
|
+
const layoutRoute = null;
|
|
64
|
+
const files = [];
|
|
65
|
+
const dirs = [];
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
if (entry.isDirectory()) {
|
|
68
|
+
dirs.push(entry);
|
|
69
|
+
} else if (entry.isFile() && hasValidExtension(entry.name, extensions)) {
|
|
70
|
+
files.push(entry);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
let layout;
|
|
74
|
+
const nonLayoutFiles = [];
|
|
75
|
+
for (const file of files) {
|
|
76
|
+
const baseName = stripExtension(file.name);
|
|
77
|
+
if (baseName === "layout") {
|
|
78
|
+
layout = buildFileRoute(file.name, dir, rootDir, parentUrlPath, true);
|
|
79
|
+
} else {
|
|
80
|
+
nonLayoutFiles.push(file);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const fileRoutes = [];
|
|
84
|
+
for (const file of nonLayoutFiles) {
|
|
85
|
+
fileRoutes.push(
|
|
86
|
+
buildFileRoute(file.name, dir, rootDir, parentUrlPath, false)
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const dirRoutes = [];
|
|
90
|
+
for (const d of dirs) {
|
|
91
|
+
const dirName = d.name;
|
|
92
|
+
const isGroup = isRouteGroup(dirName);
|
|
93
|
+
const segment = isGroup ? "" : dirNameToSegment(dirName);
|
|
94
|
+
const childUrlPath = segment ? joinUrlPath(parentUrlPath, segment) : parentUrlPath;
|
|
95
|
+
const children = scanDirectory(
|
|
96
|
+
path.join(dir, dirName),
|
|
97
|
+
rootDir,
|
|
98
|
+
childUrlPath,
|
|
99
|
+
extensions
|
|
100
|
+
);
|
|
101
|
+
if (isGroup) {
|
|
102
|
+
dirRoutes.push(...children);
|
|
103
|
+
} else {
|
|
104
|
+
const childLayout = children.find((c) => c.isLayout && c.urlPath === childUrlPath);
|
|
105
|
+
const childNonLayout = children.filter((c) => !c.isLayout || c.urlPath !== childUrlPath);
|
|
106
|
+
if (childLayout) {
|
|
107
|
+
childLayout.children = [...childLayout.children, ...childNonLayout];
|
|
108
|
+
dirRoutes.push(childLayout);
|
|
109
|
+
} else if (childNonLayout.length > 0) {
|
|
110
|
+
dirRoutes.push(...childNonLayout);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (layout) {
|
|
115
|
+
layout.children = [...fileRoutes, ...dirRoutes];
|
|
116
|
+
routes.push(layout);
|
|
117
|
+
} else {
|
|
118
|
+
routes.push(...fileRoutes, ...dirRoutes);
|
|
119
|
+
}
|
|
120
|
+
return sortRoutes(routes);
|
|
121
|
+
}
|
|
122
|
+
function buildFileRoute(fileName, dir, rootDir, parentUrlPath, isLayout) {
|
|
123
|
+
const baseName = stripExtension(fileName);
|
|
124
|
+
const filePath = path.relative(rootDir, path.join(dir, fileName));
|
|
125
|
+
const isIndex = baseName === "index";
|
|
126
|
+
const isCatchAll = baseName.startsWith("[...");
|
|
127
|
+
const isDynamic = !isCatchAll && baseName.startsWith("[") && baseName.endsWith("]");
|
|
128
|
+
let urlSegment;
|
|
129
|
+
if (isLayout) {
|
|
130
|
+
urlSegment = "";
|
|
131
|
+
} else if (isIndex) {
|
|
132
|
+
urlSegment = "/";
|
|
133
|
+
} else if (isCatchAll) {
|
|
134
|
+
const paramName = baseName.slice(4, -1);
|
|
135
|
+
urlSegment = `*${paramName}`;
|
|
136
|
+
} else if (isDynamic) {
|
|
137
|
+
const paramName = baseName.slice(1, -1);
|
|
138
|
+
urlSegment = `:${paramName}`;
|
|
139
|
+
} else {
|
|
140
|
+
urlSegment = baseName;
|
|
141
|
+
}
|
|
142
|
+
const urlPath = isLayout ? parentUrlPath || "/" : isIndex ? parentUrlPath || "/" : joinUrlPath(parentUrlPath, urlSegment);
|
|
143
|
+
const absoluteFilePath = path.join(dir, fileName);
|
|
144
|
+
let hasRouteData = false;
|
|
145
|
+
try {
|
|
146
|
+
const content = fs.readFileSync(absoluteFilePath, "utf-8");
|
|
147
|
+
hasRouteData = /export\s+(const|function|async\s+function)\s+routeData\b/.test(content);
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
filePath: filePath.replace(/\\/g, "/"),
|
|
152
|
+
// normalize to forward slashes
|
|
153
|
+
urlSegment,
|
|
154
|
+
urlPath,
|
|
155
|
+
isLayout,
|
|
156
|
+
isIndex,
|
|
157
|
+
isDynamic,
|
|
158
|
+
isCatchAll,
|
|
159
|
+
isGroup: false,
|
|
160
|
+
children: [],
|
|
161
|
+
parentUrlPath,
|
|
162
|
+
hasRouteData,
|
|
163
|
+
rootDir,
|
|
164
|
+
dir
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function hasValidExtension(fileName, extensions) {
|
|
168
|
+
return extensions.some((ext) => fileName.endsWith(ext));
|
|
169
|
+
}
|
|
170
|
+
function stripExtension(fileName) {
|
|
171
|
+
const lastDot = fileName.lastIndexOf(".");
|
|
172
|
+
return lastDot > 0 ? fileName.slice(0, lastDot) : fileName;
|
|
173
|
+
}
|
|
174
|
+
function isRouteGroup(dirName) {
|
|
175
|
+
return dirName.startsWith("(") && dirName.endsWith(")");
|
|
176
|
+
}
|
|
177
|
+
function dirNameToSegment(dirName) {
|
|
178
|
+
if (dirName.startsWith("[...") && dirName.endsWith("]")) {
|
|
179
|
+
return "*" + dirName.slice(4, -1);
|
|
180
|
+
}
|
|
181
|
+
if (dirName.startsWith("[") && dirName.endsWith("]")) {
|
|
182
|
+
return ":" + dirName.slice(1, -1);
|
|
183
|
+
}
|
|
184
|
+
return dirName;
|
|
185
|
+
}
|
|
186
|
+
function joinUrlPath(parent, segment) {
|
|
187
|
+
const base = parent.endsWith("/") ? parent : parent + "/";
|
|
188
|
+
return base + segment;
|
|
189
|
+
}
|
|
190
|
+
function sortRoutes(routes) {
|
|
191
|
+
return routes.sort((a, b) => {
|
|
192
|
+
if (a.isLayout && !b.isLayout) return -1;
|
|
193
|
+
if (!a.isLayout && b.isLayout) return 1;
|
|
194
|
+
if (a.isIndex && !b.isIndex) return -1;
|
|
195
|
+
if (!a.isIndex && b.isIndex) return 1;
|
|
196
|
+
if (!a.isDynamic && !a.isCatchAll && (b.isDynamic || b.isCatchAll)) return -1;
|
|
197
|
+
if ((a.isDynamic || a.isCatchAll) && !b.isDynamic && !b.isCatchAll) return 1;
|
|
198
|
+
if (a.isDynamic && b.isCatchAll) return -1;
|
|
199
|
+
if (a.isCatchAll && b.isDynamic) return 1;
|
|
200
|
+
return a.urlSegment.localeCompare(b.urlSegment);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/lib/plugins/route-codegen.ts
|
|
205
|
+
function generateRouteModule(routes, routesDir) {
|
|
206
|
+
const lines = [];
|
|
207
|
+
lines.push(`// Auto-generated by fluixi route plugin`);
|
|
208
|
+
lines.push(`// Do not edit manually`);
|
|
209
|
+
lines.push(``);
|
|
210
|
+
lines.push(`import { lazy } from '@fluixi/core/router';`);
|
|
211
|
+
lines.push(``);
|
|
212
|
+
lines.push(`export const routes = ${generateRouteArray(routes, routesDir, 0)};`);
|
|
213
|
+
lines.push(``);
|
|
214
|
+
return lines.join("\n");
|
|
215
|
+
}
|
|
216
|
+
function generateRouteArray(routes, routesDir, depth) {
|
|
217
|
+
if (routes.length === 0) return "[]";
|
|
218
|
+
const indent = " ".repeat(depth);
|
|
219
|
+
const items = routes.map((route) => generateRouteObject(route, routesDir, depth + 1));
|
|
220
|
+
return `[
|
|
221
|
+
${items.join(",\n")}
|
|
222
|
+
${indent}]`;
|
|
223
|
+
}
|
|
224
|
+
function generateRouteObject(route, routesDir, depth) {
|
|
225
|
+
const indent = " ".repeat(depth);
|
|
226
|
+
const props = [];
|
|
227
|
+
const importPath = buildImportPath(route.filePath, routesDir);
|
|
228
|
+
const routePath = computeRoutePath(route);
|
|
229
|
+
props.push(`${indent} path: ${JSON.stringify(routePath)}`);
|
|
230
|
+
props.push(`${indent} component: lazy(() => import(${JSON.stringify(importPath)}))`);
|
|
231
|
+
if (route.hasRouteData) {
|
|
232
|
+
props.push(
|
|
233
|
+
`${indent} data: (args, __owner, __isCancelled) => import(${JSON.stringify(
|
|
234
|
+
importPath
|
|
235
|
+
)}).then(m => { if (typeof __isCancelled === 'function' && __isCancelled()) return undefined; if (!m.routeData) return undefined; return __owner ? m.routeData(args) : m.routeData(args); })`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
if (route.children.length > 0) {
|
|
239
|
+
const childArray = generateRouteArray(route.children, routesDir, depth + 1);
|
|
240
|
+
props.push(`${indent} children: ${childArray}`);
|
|
241
|
+
}
|
|
242
|
+
return `${indent}{
|
|
243
|
+
${props.join(",\n")}
|
|
244
|
+
${indent}}`;
|
|
245
|
+
}
|
|
246
|
+
function computeRoutePath(route) {
|
|
247
|
+
return route.urlPath;
|
|
248
|
+
}
|
|
249
|
+
function buildImportPath(filePath, routesDir) {
|
|
250
|
+
const base = routesDir.replace(/\\/g, "/").replace(/\/$/, "");
|
|
251
|
+
return `${base}/${filePath}`;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// src/lib/plugins/fluixi-routes-plugin.ts
|
|
255
|
+
var VIRTUAL_MODULE_ID = "virtual:fluixi-routes";
|
|
256
|
+
var RESOLVED_VIRTUAL_ID = "\0" + VIRTUAL_MODULE_ID;
|
|
257
|
+
var PUBLIC_MODULE_ID = "@fluixi/core/routes";
|
|
258
|
+
function fluixiRoutesPlugin(options = {}) {
|
|
259
|
+
const routesDir = options.routesDir ?? "src/routes";
|
|
260
|
+
const extensions = options.extensions ?? [".tsx", ".ts", ".jsx", ".js"];
|
|
261
|
+
let projectRoot = "";
|
|
262
|
+
let lastGenerated = null;
|
|
263
|
+
function generateModule(root) {
|
|
264
|
+
const absRoutesDir = path2.resolve(root, routesDir);
|
|
265
|
+
const scanOpts = { extensions };
|
|
266
|
+
const routes = scanRoutes(absRoutesDir, scanOpts);
|
|
267
|
+
return generateRouteModule(routes, "./" + routesDir);
|
|
268
|
+
}
|
|
269
|
+
const usePolyfills = options.polyfills !== false;
|
|
270
|
+
const polyfillsPlugin = usePolyfills ? Object.assign({}, (0, import_vite_plugin_node_polyfills.nodePolyfills)({ include: ["fs", "path"] }), { apply: "serve" }) : null;
|
|
271
|
+
const routesPlugin = {
|
|
272
|
+
name: "fluixi-routes",
|
|
273
|
+
enforce: "pre",
|
|
274
|
+
configResolved(config) {
|
|
275
|
+
projectRoot = config.root || process.cwd();
|
|
276
|
+
},
|
|
277
|
+
resolveId(id) {
|
|
278
|
+
if (id === VIRTUAL_MODULE_ID || id === PUBLIC_MODULE_ID) {
|
|
279
|
+
return RESOLVED_VIRTUAL_ID;
|
|
280
|
+
}
|
|
281
|
+
return null;
|
|
282
|
+
},
|
|
283
|
+
load(id) {
|
|
284
|
+
if (id !== RESOLVED_VIRTUAL_ID) return null;
|
|
285
|
+
lastGenerated = generateModule(projectRoot || process.cwd());
|
|
286
|
+
return lastGenerated;
|
|
287
|
+
},
|
|
288
|
+
// Vite dev server: watch routes directory for changes
|
|
289
|
+
configureServer(server) {
|
|
290
|
+
const root = projectRoot || process.cwd();
|
|
291
|
+
const absRoutesDir = path2.resolve(root, routesDir);
|
|
292
|
+
server.watcher.add(absRoutesDir);
|
|
293
|
+
server.watcher.on("all", (event, filePath) => {
|
|
294
|
+
if (!filePath.startsWith(absRoutesDir)) return;
|
|
295
|
+
if (!["add", "unlink", "addDir", "unlinkDir", "change"].includes(event)) return;
|
|
296
|
+
if (event !== "addDir" && event !== "unlinkDir" && !extensions.some((ext) => filePath.endsWith(ext))) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const next = generateModule(root);
|
|
300
|
+
if (next === lastGenerated) return;
|
|
301
|
+
lastGenerated = next;
|
|
302
|
+
const mod = server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ID);
|
|
303
|
+
if (mod) {
|
|
304
|
+
server.moduleGraph.invalidateModule(mod);
|
|
305
|
+
server.ws.send({ type: "full-reload" });
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
return polyfillsPlugin ? [polyfillsPlugin, routesPlugin] : [routesPlugin];
|
|
311
|
+
}
|