@4399ywkf/core 4.0.85 → 5.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.
Files changed (81) hide show
  1. package/dist/cli/index.js +2180 -0
  2. package/dist/cli/index.js.map +1 -0
  3. package/dist/config/index.d.ts +37 -0
  4. package/dist/config/index.js +143 -0
  5. package/dist/config/index.js.map +1 -0
  6. package/dist/index.d.ts +496 -6
  7. package/dist/index.js +3671 -49
  8. package/dist/index.js.map +1 -0
  9. package/dist/plugin/index.d.ts +110 -0
  10. package/dist/plugin/index.js +277 -0
  11. package/dist/plugin/index.js.map +1 -0
  12. package/dist/router/index.d.ts +126 -0
  13. package/dist/router/index.js +390 -0
  14. package/dist/router/index.js.map +1 -0
  15. package/dist/rspack/index.d.ts +29 -0
  16. package/dist/rspack/index.js +1574 -0
  17. package/dist/rspack/index.js.map +1 -0
  18. package/dist/runtime/index.d.ts +120 -0
  19. package/dist/runtime/index.js +406 -0
  20. package/dist/runtime/index.js.map +1 -0
  21. package/dist/schema-BuqmN_ra.d.ts +390 -0
  22. package/dist/types-BZV_2QtD.d.ts +97 -0
  23. package/package.json +88 -37
  24. package/README.md +0 -3
  25. package/compiled/dotenv/LICENSE +0 -23
  26. package/compiled/dotenv/index.js +0 -1
  27. package/compiled/dotenv/lib/main.d.ts +0 -73
  28. package/compiled/dotenv/package.json +0 -1
  29. package/compiled/dotenv/types/index.d.ts +0 -59
  30. package/compiled/dotenv-expand/LICENSE +0 -24
  31. package/compiled/dotenv-expand/index.js +0 -1
  32. package/compiled/dotenv-expand/lib/main.d.ts +0 -29
  33. package/compiled/dotenv-expand/package.json +0 -1
  34. package/compiled/just-diff/LICENSE +0 -21
  35. package/compiled/just-diff/index.d.ts +0 -20
  36. package/compiled/just-diff/index.js +0 -1
  37. package/compiled/just-diff/package.json +0 -1
  38. package/dist/config/config.d.ts +0 -62
  39. package/dist/config/config.js +0 -240
  40. package/dist/config/utils.d.ts +0 -8
  41. package/dist/config/utils.js +0 -40
  42. package/dist/constants.d.ts +0 -9
  43. package/dist/constants.js +0 -45
  44. package/dist/route/defineRoutes.d.ts +0 -1
  45. package/dist/route/defineRoutes.js +0 -61
  46. package/dist/route/route.d.ts +0 -3
  47. package/dist/route/route.js +0 -27
  48. package/dist/route/routeUtils.d.ts +0 -8
  49. package/dist/route/routeUtils.js +0 -46
  50. package/dist/route/routesConfig.d.ts +0 -6
  51. package/dist/route/routesConfig.js +0 -125
  52. package/dist/route/routesConvention.d.ts +0 -5
  53. package/dist/route/routesConvention.js +0 -88
  54. package/dist/route/utils.d.ts +0 -8
  55. package/dist/route/utils.js +0 -59
  56. package/dist/service/command.d.ts +0 -30
  57. package/dist/service/command.js +0 -39
  58. package/dist/service/env.d.ts +0 -4
  59. package/dist/service/env.js +0 -47
  60. package/dist/service/generatePlugin.d.ts +0 -4
  61. package/dist/service/generatePlugin.js +0 -102
  62. package/dist/service/generator.d.ts +0 -71
  63. package/dist/service/generator.js +0 -40
  64. package/dist/service/hook.d.ts +0 -16
  65. package/dist/service/hook.js +0 -52
  66. package/dist/service/path.d.ts +0 -15
  67. package/dist/service/path.js +0 -55
  68. package/dist/service/plugin.d.ts +0 -61
  69. package/dist/service/plugin.js +0 -174
  70. package/dist/service/pluginAPI.d.ts +0 -49
  71. package/dist/service/pluginAPI.js +0 -233
  72. package/dist/service/service.d.ts +0 -147
  73. package/dist/service/service.js +0 -544
  74. package/dist/service/servicePlugin.d.ts +0 -3
  75. package/dist/service/servicePlugin.js +0 -37
  76. package/dist/service/telemetry.d.ts +0 -32
  77. package/dist/service/telemetry.js +0 -127
  78. package/dist/service/utils.d.ts +0 -2
  79. package/dist/service/utils.js +0 -36
  80. package/dist/types.d.ts +0 -116
  81. package/dist/types.js +0 -77
@@ -0,0 +1,390 @@
1
+ // src/router/generator.ts
2
+ import { existsSync, readdirSync, statSync, mkdirSync, writeFileSync } from "fs";
3
+ import { join, relative } from "path";
4
+ var EXCLUDED_DIRS = /* @__PURE__ */ new Set([
5
+ "components",
6
+ "hooks",
7
+ "utils",
8
+ "services",
9
+ "models",
10
+ "assets",
11
+ "types",
12
+ "constants",
13
+ "styles"
14
+ ]);
15
+ var CONVENTION_FILES = {
16
+ page: /^page\.(tsx?|jsx?)$/,
17
+ layout: /^layout\.(tsx?|jsx?)$/,
18
+ error: /^error\.(tsx?|jsx?)$/,
19
+ loading: /^loading\.(tsx?|jsx?)$/,
20
+ catchAll: /^\$\.(tsx?|jsx?)$/
21
+ };
22
+ var ConventionalRouteGenerator = class {
23
+ options;
24
+ constructor(options) {
25
+ this.options = options;
26
+ }
27
+ generate() {
28
+ const { pagesDir } = this.options;
29
+ if (!existsSync(pagesDir)) {
30
+ console.warn(`[ywkf] \u9875\u9762\u76EE\u5F55\u4E0D\u5B58\u5728: ${pagesDir}`);
31
+ return [];
32
+ }
33
+ return this.scanDirectory(pagesDir, "/");
34
+ }
35
+ /**
36
+ * 扫描目录,生成路由树
37
+ */
38
+ scanDirectory(dir, routePath) {
39
+ const entries = readdirSync(dir);
40
+ const layoutFile = entries.find((e) => CONVENTION_FILES.layout.test(e));
41
+ const pageFile = entries.find((e) => CONVENTION_FILES.page.test(e));
42
+ const errorFile = entries.find((e) => CONVENTION_FILES.error.test(e));
43
+ const loadingFile = entries.find((e) => CONVENTION_FILES.loading.test(e));
44
+ const catchAllFile = entries.find((e) => CONVENTION_FILES.catchAll.test(e));
45
+ const subDirs = entries.filter((e) => {
46
+ if (e.startsWith(".")) return false;
47
+ if (EXCLUDED_DIRS.has(e)) return false;
48
+ return statSync(join(dir, e)).isDirectory();
49
+ });
50
+ const childRoutes = [];
51
+ for (const subDir of subDirs) {
52
+ const subDirPath = join(dir, subDir);
53
+ if (subDir.startsWith("__")) {
54
+ const pathlessRoutes = this.scanDirectory(subDirPath, routePath);
55
+ const pathlessLayout = readdirSync(subDirPath).find(
56
+ (e) => CONVENTION_FILES.layout.test(e)
57
+ );
58
+ if (pathlessLayout) {
59
+ const pathlessChildren = this.scanDirectory(subDirPath, routePath);
60
+ childRoutes.push({
61
+ path: routePath,
62
+ name: this.generateRouteName(subDir.slice(2)),
63
+ layoutFile: relative(this.options.pagesDir, join(subDirPath, pathlessLayout)),
64
+ isLayout: true,
65
+ pathless: true,
66
+ children: pathlessChildren.filter(
67
+ (r) => r.layoutFile !== relative(this.options.pagesDir, join(subDirPath, pathlessLayout))
68
+ )
69
+ });
70
+ } else {
71
+ childRoutes.push(...pathlessRoutes);
72
+ }
73
+ continue;
74
+ }
75
+ const subRoutePath = this.resolveRoutePath(subDir, routePath);
76
+ childRoutes.push(...this.scanDirectory(subDirPath, subRoutePath));
77
+ }
78
+ const routeName = this.generateRouteName(routePath);
79
+ const relPath = (file) => relative(this.options.pagesDir, join(dir, file));
80
+ if (layoutFile) {
81
+ const layoutChildren = [];
82
+ if (pageFile) {
83
+ layoutChildren.push({
84
+ path: routePath,
85
+ file: relPath(pageFile),
86
+ name: routeName + "Index",
87
+ index: true
88
+ });
89
+ }
90
+ if (catchAllFile) {
91
+ layoutChildren.push({
92
+ path: "*",
93
+ file: relPath(catchAllFile),
94
+ name: routeName + "CatchAll"
95
+ });
96
+ }
97
+ layoutChildren.push(...childRoutes);
98
+ return [
99
+ {
100
+ path: routePath,
101
+ layoutFile: relPath(layoutFile),
102
+ errorFile: errorFile ? relPath(errorFile) : void 0,
103
+ loadingFile: loadingFile ? relPath(loadingFile) : void 0,
104
+ name: routeName,
105
+ isLayout: true,
106
+ children: layoutChildren
107
+ }
108
+ ];
109
+ }
110
+ const result = [];
111
+ if (pageFile) {
112
+ result.push({
113
+ path: routePath,
114
+ file: relPath(pageFile),
115
+ errorFile: errorFile ? relPath(errorFile) : void 0,
116
+ name: routeName
117
+ });
118
+ }
119
+ if (catchAllFile) {
120
+ result.push({
121
+ path: "*",
122
+ file: relPath(catchAllFile),
123
+ name: routeName + "CatchAll"
124
+ });
125
+ }
126
+ result.push(...childRoutes);
127
+ return result;
128
+ }
129
+ /**
130
+ * 解析目录名到路由路径
131
+ *
132
+ * - [id] → :id
133
+ * - [id$] → :id?
134
+ * - [...slug] → *
135
+ * - user.profile → user/profile
136
+ */
137
+ resolveRoutePath(dirName, parentPath) {
138
+ let segment;
139
+ if (dirName.match(/^\[\.\.\.(.+)\]$/)) {
140
+ segment = "*";
141
+ } else if (dirName.match(/^\[(.+)\$\]$/)) {
142
+ const param = dirName.slice(1, -2);
143
+ segment = `:${param}?`;
144
+ } else if (dirName.match(/^\[(.+)\]$/)) {
145
+ const param = dirName.slice(1, -1);
146
+ segment = `:${param}`;
147
+ } else if (dirName.includes(".")) {
148
+ segment = dirName.replace(/\./g, "/");
149
+ } else {
150
+ segment = dirName;
151
+ }
152
+ return parentPath === "/" ? `/${segment}` : `${parentPath}/${segment}`;
153
+ }
154
+ /**
155
+ * 生成有效的 JS 标识符名称
156
+ */
157
+ generateRouteName(path) {
158
+ const name = path.split("/").filter(Boolean).map(
159
+ (s) => s.replace(/^:/, "Param").replace(/\?$/, "Optional").replace(/^\*$/, "CatchAll")
160
+ ).map((s) => {
161
+ const cleaned = s.replace(/[^a-zA-Z0-9]/g, "");
162
+ if (!cleaned) return "";
163
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
164
+ }).join("");
165
+ if (!name || /^\d/.test(name)) {
166
+ return "Page" + (name || "Root");
167
+ }
168
+ return name;
169
+ }
170
+ // ===== 代码生成 =====
171
+ generateCode() {
172
+ const routes = this.generate();
173
+ const lazyImports = [];
174
+ const errorImports = [];
175
+ const loadingImports = [];
176
+ this.collectImports(routes, lazyImports, errorImports, loadingImports);
177
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
178
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
179
+
180
+ import React, { lazy, Suspense } from "react";
181
+ import { createBrowserRouter, type RouteObject } from "react-router";
182
+
183
+ // \u61D2\u52A0\u8F7D\u9875\u9762\u7EC4\u4EF6
184
+ ${lazyImports.join("\n")}
185
+ ${errorImports.length > 0 ? "\n// \u9519\u8BEF\u8FB9\u754C\u7EC4\u4EF6\n" + errorImports.join("\n") : ""}
186
+ ${loadingImports.length > 0 ? "\n// \u52A0\u8F7D\u72B6\u6001\u7EC4\u4EF6\n" + loadingImports.join("\n") : ""}
187
+
188
+ // \u9ED8\u8BA4\u52A0\u8F7D\u72B6\u6001
189
+ const DefaultLoading = () => <div style={{ padding: 24, textAlign: "center" }}>\u52A0\u8F7D\u4E2D...</div>;
190
+
191
+ // \u61D2\u52A0\u8F7D\u5305\u88C5
192
+ function LazyRoute({
193
+ Component,
194
+ Loading = DefaultLoading,
195
+ }: {
196
+ Component: React.LazyExoticComponent<React.ComponentType<unknown>>;
197
+ Loading?: React.ComponentType;
198
+ }) {
199
+ return (
200
+ <Suspense fallback={<Loading />}>
201
+ <Component />
202
+ </Suspense>
203
+ );
204
+ }
205
+
206
+ // \u8DEF\u7531\u914D\u7F6E
207
+ export const routes: RouteObject[] = ${this.emitRouteArray(routes)};
208
+
209
+ /**
210
+ * \u521B\u5EFA\u8DEF\u7531\u5B9E\u4F8B
211
+ */
212
+ export function createRouter(basename?: string) {
213
+ return createBrowserRouter(routes, { basename: basename || "/" });
214
+ }
215
+
216
+ export default routes;
217
+ `;
218
+ }
219
+ collectImports(routes, lazyImports, errorImports, loadingImports) {
220
+ for (const route of routes) {
221
+ const name = route.name;
222
+ const toImportPath = (f) => f.replace(/\.(tsx?|jsx?)$/, "");
223
+ if (route.isLayout && route.layoutFile) {
224
+ lazyImports.push(
225
+ `const ${name}Layout = lazy(() => import("@/pages/${toImportPath(route.layoutFile)}"));`
226
+ );
227
+ }
228
+ if (route.file) {
229
+ lazyImports.push(
230
+ `const ${name}Page = lazy(() => import("@/pages/${toImportPath(route.file)}"));`
231
+ );
232
+ }
233
+ if (route.errorFile) {
234
+ errorImports.push(
235
+ `const ${name}Error = lazy(() => import("@/pages/${toImportPath(route.errorFile)}"));`
236
+ );
237
+ }
238
+ if (route.loadingFile) {
239
+ loadingImports.push(
240
+ `const ${name}Loading = lazy(() => import("@/pages/${toImportPath(route.loadingFile)}"));`
241
+ );
242
+ }
243
+ if (route.children) {
244
+ this.collectImports(route.children, lazyImports, errorImports, loadingImports);
245
+ }
246
+ }
247
+ }
248
+ emitRouteArray(routes, parentPath) {
249
+ const items = routes.map((r) => this.emitRouteObject(r, parentPath));
250
+ return `[
251
+ ${items.join(",\n ")}
252
+ ]`;
253
+ }
254
+ emitRouteObject(route, parentPath) {
255
+ const parts = [];
256
+ const name = route.name;
257
+ if (route.index) {
258
+ parts.push("index: true");
259
+ } else if (route.pathless) {
260
+ } else if (route.path === "*") {
261
+ parts.push(`path: "*"`);
262
+ } else if (parentPath && route.path.startsWith(parentPath) && parentPath !== "/") {
263
+ const rel = route.path.slice(parentPath.length + 1);
264
+ parts.push(`path: "${rel || ""}"`);
265
+ } else {
266
+ parts.push(`path: "${route.path}"`);
267
+ }
268
+ if (route.isLayout && route.layoutFile) {
269
+ const loadingProp = route.loadingFile ? ` Loading={${name}Loading}` : "";
270
+ parts.push(`element: <LazyRoute Component={${name}Layout}${loadingProp} />`);
271
+ } else if (route.file) {
272
+ parts.push(`element: <LazyRoute Component={${name}Page} />`);
273
+ }
274
+ if (route.errorFile) {
275
+ parts.push(`errorElement: <LazyRoute Component={${name}Error} />`);
276
+ }
277
+ if (route.children && route.children.length > 0) {
278
+ const childParent = route.pathless ? parentPath : route.path;
279
+ parts.push(`children: ${this.emitRouteArray(route.children, childParent)}`);
280
+ }
281
+ return `{
282
+ ${parts.join(",\n ")}
283
+ }`;
284
+ }
285
+ /**
286
+ * 写入路由文件
287
+ */
288
+ write() {
289
+ const { outputDir } = this.options;
290
+ const code = this.generateCode();
291
+ if (!existsSync(outputDir)) {
292
+ mkdirSync(outputDir, { recursive: true });
293
+ }
294
+ writeFileSync(join(outputDir, "routes.tsx"), code, "utf-8");
295
+ console.log(`[ywkf] \u7EA6\u5B9A\u5F0F\u8DEF\u7531\u5DF2\u751F\u6210`);
296
+ }
297
+ };
298
+ function generateConventionalRoutes(options) {
299
+ new ConventionalRouteGenerator(options).write();
300
+ }
301
+
302
+ // src/router/plugin.ts
303
+ import { join as join2 } from "path";
304
+ import { watch, existsSync as existsSync2 } from "fs";
305
+ var ConventionalRoutePlugin = class {
306
+ options;
307
+ isWatching = false;
308
+ hasGenerated = false;
309
+ lastGeneratedContent = "";
310
+ constructor(options) {
311
+ this.options = options;
312
+ }
313
+ apply(compiler) {
314
+ const pluginName = "ConventionalRoutePlugin";
315
+ compiler.hooks.beforeCompile.tapAsync(pluginName, (params, callback) => {
316
+ if (!this.hasGenerated) {
317
+ this.generateRoutes();
318
+ this.hasGenerated = true;
319
+ }
320
+ callback();
321
+ });
322
+ if (this.options.watch && !this.isWatching) {
323
+ this.watchPages();
324
+ }
325
+ }
326
+ /**
327
+ * 生成路由文件(带内容比对,避免不必要的重复生成)
328
+ */
329
+ generateRoutes() {
330
+ try {
331
+ const generator = new ConventionalRouteGenerator({
332
+ pagesDir: this.options.pagesDir,
333
+ outputDir: this.options.outputDir,
334
+ basename: this.options.basename
335
+ });
336
+ const newContent = generator.generateCode();
337
+ const outputPath = join2(this.options.outputDir, "routes.tsx");
338
+ const normalizedNew = this.normalizeContent(newContent);
339
+ const normalizedOld = this.normalizeContent(this.lastGeneratedContent);
340
+ if (normalizedNew === normalizedOld) {
341
+ return;
342
+ }
343
+ generator.write();
344
+ this.lastGeneratedContent = newContent;
345
+ } catch (error) {
346
+ console.error("[ywkf] \u751F\u6210\u8DEF\u7531\u5931\u8D25:", error);
347
+ }
348
+ }
349
+ /**
350
+ * 标准化内容(去掉时间戳等动态部分)
351
+ */
352
+ normalizeContent(content) {
353
+ return content.replace(/\/\/ Generated at: .+/g, "");
354
+ }
355
+ /**
356
+ * 监听页面目录变化
357
+ */
358
+ watchPages() {
359
+ if (!existsSync2(this.options.pagesDir)) {
360
+ return;
361
+ }
362
+ this.isWatching = true;
363
+ let debounceTimer = null;
364
+ const watcher = watch(
365
+ this.options.pagesDir,
366
+ { recursive: true },
367
+ (eventType, filename) => {
368
+ if (!filename?.match(/\.(tsx?|jsx?)$/)) {
369
+ return;
370
+ }
371
+ if (debounceTimer) {
372
+ clearTimeout(debounceTimer);
373
+ }
374
+ debounceTimer = setTimeout(() => {
375
+ console.log(`[ywkf] \u68C0\u6D4B\u5230\u9875\u9762\u53D8\u5316: ${filename}`);
376
+ this.generateRoutes();
377
+ }, 500);
378
+ }
379
+ );
380
+ process.on("exit", () => {
381
+ watcher.close();
382
+ });
383
+ }
384
+ };
385
+ export {
386
+ ConventionalRouteGenerator,
387
+ ConventionalRoutePlugin,
388
+ generateConventionalRoutes
389
+ };
390
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/router/generator.ts","../../src/router/plugin.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync, mkdirSync, writeFileSync } from \"fs\";\nimport { join, relative, basename } from \"path\";\n\n/**\n * 路由节点配置\n */\nexport interface RouteConfig {\n /** 路由路径 */\n path: string;\n /** 页面文件(page.tsx)相对路径 */\n file?: string;\n /** 布局文件(layout.tsx)相对路径 */\n layoutFile?: string;\n /** 错误边界文件(error.tsx)相对路径 */\n errorFile?: string;\n /** 加载状态文件(loading.tsx)相对路径 */\n loadingFile?: string;\n /** 通配路由文件($.tsx)相对路径 */\n catchAllFile?: string;\n /** 组件名称 */\n name: string;\n /** 子路由 */\n children?: RouteConfig[];\n /** 是否为 index 路由 */\n index?: boolean;\n /** 是否为布局路由 */\n isLayout?: boolean;\n /** 是否为无路径布局(__prefix) */\n pathless?: boolean;\n}\n\nexport interface GeneratorOptions {\n /** 页面目录 */\n pagesDir: string;\n /** 输出目录 */\n outputDir: string;\n /** 路由 basename */\n basename?: string;\n}\n\n/**\n * 不参与路由扫描的目录名\n */\nconst EXCLUDED_DIRS = new Set([\n \"components\",\n \"hooks\",\n \"utils\",\n \"services\",\n \"models\",\n \"assets\",\n \"types\",\n \"constants\",\n \"styles\",\n]);\n\n/**\n * 约定文件名匹配\n */\nconst CONVENTION_FILES = {\n page: /^page\\.(tsx?|jsx?)$/,\n layout: /^layout\\.(tsx?|jsx?)$/,\n error: /^error\\.(tsx?|jsx?)$/,\n loading: /^loading\\.(tsx?|jsx?)$/,\n catchAll: /^\\$\\.(tsx?|jsx?)$/,\n};\n\n/**\n * Modern.js 风格约定式路由生成器\n *\n * 文件约定:\n * - page.tsx — 页面内容(叶子组件)\n * - layout.tsx — 布局组件(使用 <Outlet> 渲染子路由)\n * - error.tsx — 错误边界组件\n * - loading.tsx — 加载状态组件\n * - $.tsx — 通配/404 路由\n *\n * 目录约定:\n * - [id]/ — 动态路由 → /:id\n * - [id$]/ — 可选动态路由 → /:id?\n * - [...slug]/ — 全匹配路由 → /*\n * - __auth/ — 无路径布局(不生成 URL 片段)\n * - user.profile/ — 扁平路由(. 分隔 → /user/profile)\n */\nexport class ConventionalRouteGenerator {\n private options: GeneratorOptions;\n\n constructor(options: GeneratorOptions) {\n this.options = options;\n }\n\n generate(): RouteConfig[] {\n const { pagesDir } = this.options;\n if (!existsSync(pagesDir)) {\n console.warn(`[ywkf] 页面目录不存在: ${pagesDir}`);\n return [];\n }\n return this.scanDirectory(pagesDir, \"/\");\n }\n\n /**\n * 扫描目录,生成路由树\n */\n private scanDirectory(dir: string, routePath: string): RouteConfig[] {\n const entries = readdirSync(dir);\n\n // 查找约定文件\n const layoutFile = entries.find((e) => CONVENTION_FILES.layout.test(e));\n const pageFile = entries.find((e) => CONVENTION_FILES.page.test(e));\n const errorFile = entries.find((e) => CONVENTION_FILES.error.test(e));\n const loadingFile = entries.find((e) => CONVENTION_FILES.loading.test(e));\n const catchAllFile = entries.find((e) => CONVENTION_FILES.catchAll.test(e));\n\n // 收集子目录\n const subDirs = entries.filter((e) => {\n if (e.startsWith(\".\")) return false;\n if (EXCLUDED_DIRS.has(e)) return false;\n return statSync(join(dir, e)).isDirectory();\n });\n\n // 递归子目录\n const childRoutes: RouteConfig[] = [];\n for (const subDir of subDirs) {\n const subDirPath = join(dir, subDir);\n\n // __prefix:无路径布局\n if (subDir.startsWith(\"__\")) {\n const pathlessRoutes = this.scanDirectory(subDirPath, routePath);\n // 如果该无路径目录有 layout,将子路由包装在其中\n const pathlessLayout = readdirSync(subDirPath).find((e) =>\n CONVENTION_FILES.layout.test(e)\n );\n if (pathlessLayout) {\n const pathlessChildren = this.scanDirectory(subDirPath, routePath);\n childRoutes.push({\n path: routePath,\n name: this.generateRouteName(subDir.slice(2)),\n layoutFile: relative(this.options.pagesDir, join(subDirPath, pathlessLayout)),\n isLayout: true,\n pathless: true,\n children: pathlessChildren.filter(\n (r) => r.layoutFile !== relative(this.options.pagesDir, join(subDirPath, pathlessLayout))\n ),\n });\n } else {\n childRoutes.push(...pathlessRoutes);\n }\n continue;\n }\n\n // 计算路由路径\n const subRoutePath = this.resolveRoutePath(subDir, routePath);\n childRoutes.push(...this.scanDirectory(subDirPath, subRoutePath));\n }\n\n // 构建当前目录的路由节点\n const routeName = this.generateRouteName(routePath);\n const relPath = (file: string) => relative(this.options.pagesDir, join(dir, file));\n\n // 有 layout.tsx → 创建布局路由节点,children 为子路由\n if (layoutFile) {\n const layoutChildren: RouteConfig[] = [];\n\n // page.tsx 作为 index 子路由\n if (pageFile) {\n layoutChildren.push({\n path: routePath,\n file: relPath(pageFile),\n name: routeName + \"Index\",\n index: true,\n });\n }\n\n // 通配路由\n if (catchAllFile) {\n layoutChildren.push({\n path: \"*\",\n file: relPath(catchAllFile),\n name: routeName + \"CatchAll\",\n });\n }\n\n layoutChildren.push(...childRoutes);\n\n return [\n {\n path: routePath,\n layoutFile: relPath(layoutFile),\n errorFile: errorFile ? relPath(errorFile) : undefined,\n loadingFile: loadingFile ? relPath(loadingFile) : undefined,\n name: routeName,\n isLayout: true,\n children: layoutChildren,\n },\n ];\n }\n\n // 无 layout → page.tsx 是叶子页面\n const result: RouteConfig[] = [];\n\n if (pageFile) {\n result.push({\n path: routePath,\n file: relPath(pageFile),\n errorFile: errorFile ? relPath(errorFile) : undefined,\n name: routeName,\n });\n }\n\n if (catchAllFile) {\n result.push({\n path: \"*\",\n file: relPath(catchAllFile),\n name: routeName + \"CatchAll\",\n });\n }\n\n result.push(...childRoutes);\n return result;\n }\n\n /**\n * 解析目录名到路由路径\n *\n * - [id] → :id\n * - [id$] → :id?\n * - [...slug] → *\n * - user.profile → user/profile\n */\n private resolveRoutePath(dirName: string, parentPath: string): string {\n let segment: string;\n\n // [...slug] → *\n if (dirName.match(/^\\[\\.\\.\\.(.+)\\]$/)) {\n segment = \"*\";\n }\n // [id$] → :id? (可选动态)\n else if (dirName.match(/^\\[(.+)\\$\\]$/)) {\n const param = dirName.slice(1, -2);\n segment = `:${param}?`;\n }\n // [id] → :id\n else if (dirName.match(/^\\[(.+)\\]$/)) {\n const param = dirName.slice(1, -1);\n segment = `:${param}`;\n }\n // user.profile → user/profile (扁平路由)\n else if (dirName.includes(\".\")) {\n segment = dirName.replace(/\\./g, \"/\");\n } else {\n segment = dirName;\n }\n\n return parentPath === \"/\"\n ? `/${segment}`\n : `${parentPath}/${segment}`;\n }\n\n /**\n * 生成有效的 JS 标识符名称\n */\n private generateRouteName(path: string): string {\n const name = path\n .split(\"/\")\n .filter(Boolean)\n .map((s) =>\n s\n .replace(/^:/, \"Param\")\n .replace(/\\?$/, \"Optional\")\n .replace(/^\\*$/, \"CatchAll\")\n )\n .map((s) => {\n const cleaned = s.replace(/[^a-zA-Z0-9]/g, \"\");\n if (!cleaned) return \"\";\n return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);\n })\n .join(\"\");\n\n if (!name || /^\\d/.test(name)) {\n return \"Page\" + (name || \"Root\");\n }\n return name;\n }\n\n // ===== 代码生成 =====\n\n generateCode(): string {\n const routes = this.generate();\n const lazyImports: string[] = [];\n const errorImports: string[] = [];\n const loadingImports: string[] = [];\n\n this.collectImports(routes, lazyImports, errorImports, loadingImports);\n\n return `// 此文件由 @4399ywkf/core 自动生成,请勿手动修改\n// Generated at: ${new Date().toISOString()}\n\nimport React, { lazy, Suspense } from \"react\";\nimport { createBrowserRouter, type RouteObject } from \"react-router\";\n\n// 懒加载页面组件\n${lazyImports.join(\"\\n\")}\n${errorImports.length > 0 ? \"\\n// 错误边界组件\\n\" + errorImports.join(\"\\n\") : \"\"}\n${loadingImports.length > 0 ? \"\\n// 加载状态组件\\n\" + loadingImports.join(\"\\n\") : \"\"}\n\n// 默认加载状态\nconst DefaultLoading = () => <div style={{ padding: 24, textAlign: \"center\" }}>加载中...</div>;\n\n// 懒加载包装\nfunction LazyRoute({\n Component,\n Loading = DefaultLoading,\n}: {\n Component: React.LazyExoticComponent<React.ComponentType<unknown>>;\n Loading?: React.ComponentType;\n}) {\n return (\n <Suspense fallback={<Loading />}>\n <Component />\n </Suspense>\n );\n}\n\n// 路由配置\nexport const routes: RouteObject[] = ${this.emitRouteArray(routes)};\n\n/**\n * 创建路由实例\n */\nexport function createRouter(basename?: string) {\n return createBrowserRouter(routes, { basename: basename || \"/\" });\n}\n\nexport default routes;\n`;\n }\n\n private collectImports(\n routes: RouteConfig[],\n lazyImports: string[],\n errorImports: string[],\n loadingImports: string[]\n ): void {\n for (const route of routes) {\n const name = route.name;\n const toImportPath = (f: string) => f.replace(/\\.(tsx?|jsx?)$/, \"\");\n\n if (route.isLayout && route.layoutFile) {\n lazyImports.push(\n `const ${name}Layout = lazy(() => import(\"@/pages/${toImportPath(route.layoutFile)}\"));`\n );\n }\n if (route.file) {\n lazyImports.push(\n `const ${name}Page = lazy(() => import(\"@/pages/${toImportPath(route.file)}\"));`\n );\n }\n if (route.errorFile) {\n errorImports.push(\n `const ${name}Error = lazy(() => import(\"@/pages/${toImportPath(route.errorFile)}\"));`\n );\n }\n if (route.loadingFile) {\n loadingImports.push(\n `const ${name}Loading = lazy(() => import(\"@/pages/${toImportPath(route.loadingFile)}\"));`\n );\n }\n\n if (route.children) {\n this.collectImports(route.children, lazyImports, errorImports, loadingImports);\n }\n }\n }\n\n private emitRouteArray(routes: RouteConfig[], parentPath?: string): string {\n const items = routes.map((r) => this.emitRouteObject(r, parentPath));\n return `[\\n ${items.join(\",\\n \")}\\n]`;\n }\n\n private emitRouteObject(route: RouteConfig, parentPath?: string): string {\n const parts: string[] = [];\n const name = route.name;\n\n // path\n if (route.index) {\n parts.push(\"index: true\");\n } else if (route.pathless) {\n // 无路径布局不输出 path\n } else if (route.path === \"*\") {\n parts.push(`path: \"*\"`);\n } else if (parentPath && route.path.startsWith(parentPath) && parentPath !== \"/\") {\n const rel = route.path.slice(parentPath.length + 1);\n parts.push(`path: \"${rel || \"\"}\"`);\n } else {\n parts.push(`path: \"${route.path}\"`);\n }\n\n // element\n if (route.isLayout && route.layoutFile) {\n const loadingProp = route.loadingFile ? ` Loading={${name}Loading}` : \"\";\n parts.push(`element: <LazyRoute Component={${name}Layout}${loadingProp} />`);\n } else if (route.file) {\n parts.push(`element: <LazyRoute Component={${name}Page} />`);\n }\n\n // errorElement\n if (route.errorFile) {\n parts.push(`errorElement: <LazyRoute Component={${name}Error} />`);\n }\n\n // children\n if (route.children && route.children.length > 0) {\n const childParent = route.pathless ? parentPath : route.path;\n parts.push(`children: ${this.emitRouteArray(route.children, childParent)}`);\n }\n\n return `{\\n ${parts.join(\",\\n \")}\\n }`;\n }\n\n /**\n * 写入路由文件\n */\n write(): void {\n const { outputDir } = this.options;\n const code = this.generateCode();\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n writeFileSync(join(outputDir, \"routes.tsx\"), code, \"utf-8\");\n console.log(`[ywkf] 约定式路由已生成`);\n }\n}\n\n/**\n * 生成约定式路由\n */\nexport function generateConventionalRoutes(options: GeneratorOptions): void {\n new ConventionalRouteGenerator(options).write();\n}\n","import type { Compiler } from \"@rspack/core\";\nimport { ConventionalRouteGenerator } from \"./generator.js\";\nimport { join } from \"path\";\nimport { watch, existsSync, readFileSync } from \"fs\";\n\nexport interface ConventionalRoutePluginOptions {\n /** 页面目录 */\n pagesDir: string;\n /** 输出目录 */\n outputDir: string;\n /** 路由 basename */\n basename?: string;\n /** 是否监听文件变化(开发模式) */\n watch?: boolean;\n}\n\n/**\n * 约定式路由 Rspack 插件\n *\n * 在编译开始前扫描 src/pages 目录,生成 .ywkf/routes.tsx\n */\nexport class ConventionalRoutePlugin {\n private options: ConventionalRoutePluginOptions;\n private isWatching = false;\n private hasGenerated = false;\n private lastGeneratedContent = \"\";\n\n constructor(options: ConventionalRoutePluginOptions) {\n this.options = options;\n }\n\n apply(compiler: Compiler): void {\n const pluginName = \"ConventionalRoutePlugin\";\n\n // 只在首次编译时生成路由\n compiler.hooks.beforeCompile.tapAsync(pluginName, (params, callback) => {\n if (!this.hasGenerated) {\n this.generateRoutes();\n this.hasGenerated = true;\n }\n callback();\n });\n\n // 开发模式下监听文件变化\n if (this.options.watch && !this.isWatching) {\n this.watchPages();\n }\n }\n\n /**\n * 生成路由文件(带内容比对,避免不必要的重复生成)\n */\n private generateRoutes(): void {\n try {\n const generator = new ConventionalRouteGenerator({\n pagesDir: this.options.pagesDir,\n outputDir: this.options.outputDir,\n basename: this.options.basename,\n });\n\n const newContent = generator.generateCode();\n const outputPath = join(this.options.outputDir, \"routes.tsx\");\n\n // 比对内容,如果相同则跳过(去掉时间戳后比较)\n const normalizedNew = this.normalizeContent(newContent);\n const normalizedOld = this.normalizeContent(this.lastGeneratedContent);\n\n if (normalizedNew === normalizedOld) {\n return; // 内容相同,跳过生成\n }\n\n generator.write();\n this.lastGeneratedContent = newContent;\n } catch (error) {\n console.error(\"[ywkf] 生成路由失败:\", error);\n }\n }\n\n /**\n * 标准化内容(去掉时间戳等动态部分)\n */\n private normalizeContent(content: string): string {\n return content.replace(/\\/\\/ Generated at: .+/g, \"\");\n }\n\n /**\n * 监听页面目录变化\n */\n private watchPages(): void {\n if (!existsSync(this.options.pagesDir)) {\n return;\n }\n\n this.isWatching = true;\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const watcher = watch(\n this.options.pagesDir,\n { recursive: true },\n (eventType, filename) => {\n // 只处理 tsx/jsx 文件\n if (!filename?.match(/\\.(tsx?|jsx?)$/)) {\n return;\n }\n\n // 防抖处理\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n\n debounceTimer = setTimeout(() => {\n console.log(`[ywkf] 检测到页面变化: ${filename}`);\n this.generateRoutes();\n }, 500);\n }\n );\n\n // 进程退出时关闭监听\n process.on(\"exit\", () => {\n watcher.close();\n });\n }\n}\n"],"mappings":"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","names":["join","existsSync"]}
@@ -0,0 +1,29 @@
1
+ import { Configuration } from '@rspack/core';
2
+ import { Y as YwkfConfig } from '../schema-BuqmN_ra.js';
3
+ import '../types-BZV_2QtD.js';
4
+ import 'react';
5
+ import 'react-router';
6
+
7
+ /**
8
+ * 创建基础 Rspack 配置
9
+ */
10
+ declare function createBaseConfig(config: Required<YwkfConfig>, cwd: string): Configuration;
11
+
12
+ /**
13
+ * 创建开发环境 Rspack 配置
14
+ */
15
+ declare function createDevConfig(config: Required<YwkfConfig>, cwd: string): Configuration;
16
+
17
+ /**
18
+ * 创建生产环境 Rspack 配置
19
+ */
20
+ declare function createProdConfig(config: Required<YwkfConfig>, cwd: string): Configuration;
21
+
22
+ /**
23
+ * 根据环境创建 Rspack 配置
24
+ */
25
+ declare function createRspackConfig(config: Required<YwkfConfig>, cwd: string, options?: {
26
+ isDev?: boolean;
27
+ }): Configuration;
28
+
29
+ export { createBaseConfig, createDevConfig, createProdConfig, createRspackConfig };