vitarx-router 4.0.0-beta.2 → 4.0.0-beta.21

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 (93) hide show
  1. package/README.md +42 -17
  2. package/dist/{plugin-vite/auto-routes → auto-routes}/handleHotUpdate.d.ts +1 -1
  3. package/dist/components/RouterView.js +5 -4
  4. package/dist/core/common/constant.d.ts +5 -6
  5. package/dist/core/common/constant.js +5 -6
  6. package/dist/core/common/utils.js +2 -1
  7. package/dist/core/router/checkOptions.d.ts +11 -0
  8. package/dist/core/router/checkOptions.js +119 -0
  9. package/dist/core/router/manager.js +27 -23
  10. package/dist/core/router/router.d.ts +154 -1
  11. package/dist/core/router/router.js +303 -230
  12. package/dist/core/router/web.d.ts +13 -0
  13. package/dist/core/router/web.js +35 -4
  14. package/dist/core/shared/link.d.ts +7 -0
  15. package/dist/core/shared/link.js +11 -8
  16. package/dist/core/shared/route.js +1 -2
  17. package/dist/core/shared/router.d.ts +3 -3
  18. package/dist/core/shared/router.js +7 -4
  19. package/dist/core/types/options.d.ts +2 -0
  20. package/dist/file-router/config/index.d.ts +2 -1
  21. package/dist/file-router/config/index.js +2 -1
  22. package/dist/file-router/config/resolve.d.ts +43 -0
  23. package/dist/file-router/config/resolve.js +69 -0
  24. package/dist/file-router/{utils/validateOptions.d.ts → config/validate.d.ts} +11 -10
  25. package/dist/file-router/config/validate.js +280 -0
  26. package/dist/file-router/constants.d.ts +12 -2
  27. package/dist/file-router/constants.js +13 -3
  28. package/dist/file-router/generator/generateRoutes.d.ts +44 -13
  29. package/dist/file-router/generator/generateRoutes.js +159 -80
  30. package/dist/file-router/generator/generateTypes.d.ts +3 -29
  31. package/dist/file-router/generator/generateTypes.js +36 -41
  32. package/dist/file-router/global.d.ts +1 -1
  33. package/dist/file-router/index.d.ts +224 -90
  34. package/dist/file-router/index.js +571 -135
  35. package/dist/file-router/macros/astValueExtractor.d.ts +1 -1
  36. package/dist/file-router/macros/astValueExtractor.js +27 -7
  37. package/dist/file-router/macros/definePage.d.ts +20 -3
  38. package/dist/file-router/macros/definePage.js +120 -40
  39. package/dist/file-router/parser/exportChecker.d.ts +4 -23
  40. package/dist/file-router/parser/exportChecker.js +38 -79
  41. package/dist/file-router/parser/filterUtils.d.ts +25 -0
  42. package/dist/file-router/parser/filterUtils.js +43 -0
  43. package/dist/file-router/parser/index.d.ts +2 -1
  44. package/dist/file-router/parser/index.js +2 -1
  45. package/dist/file-router/parser/parsePage.d.ts +56 -9
  46. package/dist/file-router/parser/parsePage.js +194 -172
  47. package/dist/file-router/parser/routePath.d.ts +22 -0
  48. package/dist/file-router/parser/routePath.js +74 -0
  49. package/dist/file-router/types/hooks.d.ts +52 -0
  50. package/dist/file-router/types/index.d.ts +3 -0
  51. package/dist/file-router/types/index.js +1 -0
  52. package/dist/file-router/types/options.d.ts +279 -0
  53. package/dist/file-router/types/options.js +1 -0
  54. package/dist/file-router/types/route.d.ts +114 -0
  55. package/dist/file-router/types/route.js +1 -0
  56. package/dist/file-router/utils/fileReader.d.ts +11 -0
  57. package/dist/file-router/utils/fileReader.js +22 -0
  58. package/dist/file-router/utils/findRoute.d.ts +8 -0
  59. package/dist/file-router/utils/findRoute.js +22 -0
  60. package/dist/file-router/utils/index.d.ts +4 -2
  61. package/dist/file-router/utils/index.js +4 -2
  62. package/dist/file-router/utils/logger.d.ts +6 -6
  63. package/dist/file-router/utils/logger.js +44 -4
  64. package/dist/file-router/utils/pathStrategy.d.ts +28 -0
  65. package/dist/file-router/utils/{namingStrategy.js → pathStrategy.js} +18 -28
  66. package/dist/file-router/utils/pathUtils.d.ts +31 -0
  67. package/dist/file-router/utils/pathUtils.js +53 -1
  68. package/dist/plugin-vite/constant.d.ts +9 -0
  69. package/dist/plugin-vite/constant.js +9 -0
  70. package/dist/plugin-vite/index.d.ts +4 -24
  71. package/dist/plugin-vite/index.js +4 -94
  72. package/dist/plugin-vite/plugin.d.ts +86 -0
  73. package/dist/plugin-vite/plugin.js +181 -0
  74. package/dist/plugin-vite/watcher.d.ts +15 -0
  75. package/dist/plugin-vite/watcher.js +65 -0
  76. package/package.json +9 -7
  77. package/dist/file-router/config/configUtils.d.ts +0 -54
  78. package/dist/file-router/config/configUtils.js +0 -88
  79. package/dist/file-router/scanner/filterUtils.d.ts +0 -35
  80. package/dist/file-router/scanner/filterUtils.js +0 -188
  81. package/dist/file-router/scanner/index.d.ts +0 -8
  82. package/dist/file-router/scanner/index.js +0 -8
  83. package/dist/file-router/scanner/routeTreeBuilder.d.ts +0 -21
  84. package/dist/file-router/scanner/routeTreeBuilder.js +0 -312
  85. package/dist/file-router/scanner/scanPages.d.ts +0 -48
  86. package/dist/file-router/scanner/scanPages.js +0 -174
  87. package/dist/file-router/types.d.ts +0 -344
  88. package/dist/file-router/utils/namingStrategy.d.ts +0 -57
  89. package/dist/file-router/utils/validateOptions.js +0 -233
  90. /package/dist/{plugin-vite/auto-routes → auto-routes}/handleHotUpdate.js +0 -0
  91. /package/dist/{plugin-vite/auto-routes → auto-routes}/index.d.ts +0 -0
  92. /package/dist/{plugin-vite/auto-routes → auto-routes}/index.js +0 -0
  93. /package/dist/file-router/{types.js → types/hooks.js} +0 -0
@@ -1,312 +0,0 @@
1
- /**
2
- * 分组布局文件和普通页面
3
- *
4
- * @param pages - 页面列表
5
- * @returns 分组结果
6
- */
7
- function groupPagesByType(pages) {
8
- const layoutFiles = new Map();
9
- const normalPages = [];
10
- // 遍历所有页面,根据 isLayoutFile 标记进行分组
11
- for (const page of pages) {
12
- if (page.isLayoutFile) {
13
- layoutFiles.set(page.path, { ...page, children: [] });
14
- }
15
- else {
16
- normalPages.push({ ...page, children: [] });
17
- }
18
- }
19
- return { layoutFiles, normalPages };
20
- }
21
- /**
22
- * 按目录分组页面
23
- *
24
- * @param normalPages - 普通页面列表
25
- * @param layoutFiles - 布局文件映射
26
- * @returns 按目录分组的结果
27
- */
28
- function groupPagesByDirectory(normalPages, layoutFiles) {
29
- const pagesByDir = new Map();
30
- // 为每个页面确定其所属的目录路径
31
- for (const page of normalPages) {
32
- const dirPath = determineDirectoryPath(page);
33
- if (!pagesByDir.has(dirPath)) {
34
- pagesByDir.set(dirPath, []);
35
- }
36
- pagesByDir.get(dirPath).push(page);
37
- }
38
- // 确定需要创建的目录路由
39
- const routesToCreate = determineDirectoryRoutes(pagesByDir, layoutFiles);
40
- return { map: pagesByDir, routesToCreate };
41
- }
42
- /**
43
- * 确定页面所属的目录路径
44
- *
45
- * @param page - 页面信息
46
- * @returns 目录路径
47
- */
48
- function determineDirectoryPath(page) {
49
- const pathParts = page.path.split('/').filter(Boolean);
50
- // 索引页面的目录路径就是其自身路径
51
- if (page.isIndex) {
52
- return page.path;
53
- }
54
- // 根目录下的页面,目录路径为 /
55
- if (page.parentPath === '' || page.parentPath === '/') {
56
- return '/';
57
- }
58
- // 只有一级路径的页面,目录路径为 /
59
- if (pathParts.length <= 1) {
60
- return '/';
61
- }
62
- // 多级路径的页面,目录路径为去掉最后一级的路径
63
- return '/' + pathParts.slice(0, -1).join('/');
64
- }
65
- /**
66
- * 确定需要创建的目录路由
67
- *
68
- * @param pagesByDir - 按目录分组的页面
69
- * @param layoutFiles - 布局文件映射
70
- * @returns 需要创建的目录路由路径集合
71
- */
72
- function determineDirectoryRoutes(pagesByDir, layoutFiles) {
73
- const routesToCreate = new Set();
74
- for (const [dirPath, dirPages] of pagesByDir) {
75
- // 跳过根目录
76
- if (dirPath === '/')
77
- continue;
78
- // 目录下有多个页面,需要创建目录路由
79
- if (dirPages.length > 1) {
80
- routesToCreate.add(dirPath);
81
- }
82
- // 目录下只有一个页面但存在布局文件,也需要创建目录路由
83
- else if (dirPages.length === 1 && layoutFiles.has(dirPath)) {
84
- routesToCreate.add(dirPath);
85
- }
86
- }
87
- return routesToCreate;
88
- }
89
- /**
90
- * 收集所有需要处理的目录路径
91
- *
92
- * @param routesToCreate - 需要创建的目录路由
93
- * @returns 所有目录路径集合
94
- */
95
- function collectAllDirectoryPaths(routesToCreate) {
96
- const allDirPaths = new Set();
97
- for (const dirPath of routesToCreate) {
98
- allDirPaths.add(dirPath);
99
- const pathParts = dirPath.split('/').filter(Boolean);
100
- // 收集所有父级目录路径
101
- for (let i = 1; i < pathParts.length; i++) {
102
- const parentPath = '/' + pathParts.slice(0, i).join('/');
103
- if (routesToCreate.has(parentPath)) {
104
- allDirPaths.add(parentPath);
105
- }
106
- }
107
- }
108
- return allDirPaths;
109
- }
110
- /**
111
- * 构建目录路由
112
- *
113
- * @param allDirPaths - 所有目录路径
114
- * @param pagesByDir - 按目录分组的页面
115
- * @param layoutFiles - 布局文件映射
116
- * @returns 目录路由映射
117
- */
118
- function buildDirectoryRoutes(allDirPaths, pagesByDir, layoutFiles) {
119
- const dirRoutes = new Map();
120
- for (const dirPath of allDirPaths) {
121
- const pathParts = dirPath.split('/').filter(Boolean);
122
- const dirName = pathParts[pathParts.length - 1] || '';
123
- // 检查是否存在对应的布局文件
124
- const layoutFile = layoutFiles.get(dirPath);
125
- const dirPages = pagesByDir.get(dirPath) || [];
126
- // 创建目录路由配置
127
- const dirRoute = layoutFile
128
- ? { ...layoutFile, children: [] }
129
- : {
130
- path: dirPath,
131
- name: dirName,
132
- filePath: '',
133
- params: [],
134
- isIndex: false,
135
- isDynamic: false,
136
- children: [],
137
- parentPath: pathParts.length > 1 ? '/' + pathParts.slice(0, -1).join('/') : ''
138
- };
139
- // 添加子路由
140
- for (const page of dirPages) {
141
- dirRoute.children.push(createChildRoute(page));
142
- }
143
- dirRoutes.set(dirPath, dirRoute);
144
- }
145
- return dirRoutes;
146
- }
147
- /**
148
- * 创建子路由
149
- *
150
- * @param page - 页面信息
151
- * @returns 子路由配置
152
- */
153
- function createChildRoute(page) {
154
- const pathParts = page.path.split('/').filter(Boolean);
155
- const relativePath = pathParts[pathParts.length - 1] || '';
156
- // 创建子路由配置,使用相对路径
157
- const childRoute = {
158
- ...page,
159
- path: page.isIndex ? '' : relativePath,
160
- children: []
161
- };
162
- // 为索引路由添加特殊的名称后缀
163
- if (page.isIndex && page.name) {
164
- childRoute.name = `${page.name}-index`;
165
- }
166
- return childRoute;
167
- }
168
- /**
169
- * 组装最终路由树
170
- *
171
- * @param pagesByDir - 按目录分组的页面
172
- * @param dirRoutes - 目录路由映射
173
- * @param routesToCreate - 需要创建的目录路由
174
- * @param layoutFiles - 布局文件映射
175
- * @returns 路由树根节点列表
176
- */
177
- function assembleRouteTree(pagesByDir, dirRoutes, routesToCreate, layoutFiles) {
178
- const root = [];
179
- // 添加根目录下的页面
180
- const rootPages = pagesByDir.get('/') || [];
181
- for (const page of rootPages) {
182
- root.push({ ...page, children: [] });
183
- }
184
- // 添加不需要创建目录路由的页面
185
- for (const [dirPath, dirPages] of pagesByDir) {
186
- if (dirPath === '/')
187
- continue;
188
- if (routesToCreate.has(dirPath))
189
- continue;
190
- if (dirPages.length === 1) {
191
- const page = dirPages[0];
192
- root.push({ ...page, children: [] });
193
- }
194
- }
195
- // 组装目录路由
196
- for (const [dirPath, dirRoute] of dirRoutes) {
197
- const pathParts = dirPath.split('/').filter(Boolean);
198
- // 一级目录路由直接添加到根
199
- if (pathParts.length === 1) {
200
- root.push(dirRoute);
201
- }
202
- else {
203
- // 多级目录路由添加到父级路由
204
- const parentDirPath = '/' + pathParts.slice(0, -1).join('/');
205
- const parentRoute = dirRoutes.get(parentDirPath);
206
- if (parentRoute) {
207
- const relativePath = pathParts[pathParts.length - 1];
208
- parentRoute.children.push({
209
- ...dirRoute,
210
- path: relativePath
211
- });
212
- }
213
- else {
214
- // 如果父级路由不存在,直接添加到根
215
- root.push(dirRoute);
216
- }
217
- }
218
- }
219
- // 添加未被处理的布局文件
220
- for (const layoutFile of layoutFiles.values()) {
221
- if (!dirRoutes.has(layoutFile.path)) {
222
- root.push(layoutFile);
223
- }
224
- }
225
- return root;
226
- }
227
- /**
228
- * 处理路由的子路由
229
- *
230
- * @param routes - 路由列表
231
- * @returns 处理后的路由列表
232
- */
233
- function processRouteChildren(routes) {
234
- // 先排序路由,然后处理子路由
235
- return sortRoutes(routes).map(route => {
236
- const processed = { ...route, children: [] };
237
- if (route.children.length > 0) {
238
- processed.children = route.children.map(child => {
239
- const newChild = {
240
- ...child,
241
- children: []
242
- };
243
- // 递归处理子路由
244
- if (child.children.length > 0) {
245
- newChild.children = processRouteChildren(child.children);
246
- }
247
- return newChild;
248
- });
249
- }
250
- return processed;
251
- });
252
- }
253
- /**
254
- * 排序路由
255
- *
256
- * 排序规则:
257
- * 1. 索引路由优先
258
- * 2. 静态路由优先于动态路由
259
- * 3. 按路径字母顺序排序
260
- *
261
- * @param routes - 路由列表
262
- * @returns 排序后的路由列表
263
- */
264
- function sortRoutes(routes) {
265
- return routes
266
- .sort((a, b) => {
267
- // 索引路由优先
268
- if (a.isIndex && !b.isIndex)
269
- return -1;
270
- if (!a.isIndex && b.isIndex)
271
- return 1;
272
- // 静态路由优先于动态路由
273
- if (a.isDynamic && !b.isDynamic)
274
- return 1;
275
- if (!a.isDynamic && b.isDynamic)
276
- return -1;
277
- // 按路径字母顺序排序
278
- return a.path.localeCompare(b.path);
279
- })
280
- .map(route => ({
281
- ...route,
282
- // 递归排序子路由
283
- children: sortRoutes(route.children)
284
- }));
285
- }
286
- /**
287
- * 构建路由树
288
- *
289
- * 核心规则:
290
- * 1. 同名文件+目录组合:文件作为布局组件,目录内文件作为子路由
291
- * 2. 目录下的所有文件(包括 index)都作为子路由
292
- * 3. 子路由使用相对路径
293
- * 4. 有 index 子路由时自动添加 redirect
294
- * 5. 只有 index 文件的目录不创建目录路由
295
- *
296
- * @param pages - 解析后的页面列表
297
- * @returns 路由树根节点列表
298
- */
299
- export function buildRouteTree(pages) {
300
- // 1. 分组布局文件和普通页面
301
- const { layoutFiles, normalPages } = groupPagesByType(pages);
302
- // 2. 按目录分组页面并确定需要创建的目录路由
303
- const { map: pagesByDir, routesToCreate } = groupPagesByDirectory(normalPages, layoutFiles);
304
- // 3. 收集所有需要处理的目录路径
305
- const allDirPaths = collectAllDirectoryPaths(routesToCreate);
306
- // 4. 构建目录路由
307
- const dirRoutes = buildDirectoryRoutes(allDirPaths, pagesByDir, layoutFiles);
308
- // 5. 组装最终路由树
309
- const root = assembleRouteTree(pagesByDir, dirRoutes, routesToCreate, layoutFiles);
310
- // 6. 处理子路由并排序
311
- return processRouteChildren(root);
312
- }
@@ -1,48 +0,0 @@
1
- import type { ResolvedPageConfig } from '../config/index.js';
2
- import type { NamingStrategy, ParsedPage } from '../types.js';
3
- /**
4
- * 页面扫描选项
5
- *
6
- * 配置 scanPages 函数的扫描行为。
7
- */
8
- export interface ScanOptions {
9
- /**
10
- * 页面配置
11
- */
12
- page: ResolvedPageConfig;
13
- /** 要处理的文件扩展名列表 */
14
- extensions: string[];
15
- /**
16
- * 路由命名策略
17
- * - `kebab`: 将驼峰命名转换为 kebab-case(默认)
18
- * - `lowercase`: 简单转换为小写
19
- * - `none`: 保持原始命名
20
- * @default 'kebab'
21
- */
22
- namingStrategy: NamingStrategy;
23
- }
24
- /**
25
- * 多目录扫描选项
26
- *
27
- * 用于扫描多个页面目录,每个目录可以有独立的包含/排除规则。
28
- */
29
- export interface MultiScanOptions {
30
- /** 页面目录配置列表 */
31
- pages: ResolvedPageConfig[];
32
- /** 要处理的文件扩展名列表 */
33
- extensions: string[];
34
- /**
35
- * 路由命名策略
36
- * - `kebab`: 将驼峰命名转换为 kebab-case(默认)
37
- * - `lowercase`: 简单转换为小写
38
- * - `none`: 保持原始命名
39
- */
40
- namingStrategy: NamingStrategy;
41
- }
42
- /**
43
- * 扫描多个页面目录
44
- *
45
- * @param options - 多目录扫描选项
46
- * @returns 合并后的页面列表
47
- */
48
- export declare function scanMultiplePages(options: MultiScanOptions): ParsedPage[];
@@ -1,174 +0,0 @@
1
- /**
2
- * @fileoverview 页面扫描模块
3
- *
4
- * 负责扫描指定目录下的页面文件,并构建路由树结构。
5
- * 支持同名文件+目录组合(布局路由)、嵌套路由、glob 包含/排除规则。
6
- * 与构建工具无关,可在任何 Node.js 环境中使用。
7
- */
8
- import fs from 'node:fs';
9
- import path from 'node:path';
10
- import { parsePageFile } from '../parser/index.js';
11
- import { warn } from '../utils/logger.js';
12
- import { shouldProcessFile } from './filterUtils.js';
13
- /**
14
- * 聚合命名视图
15
- *
16
- * 将同一路径下的命名视图文件合并到主页面配置中。
17
- *
18
- * @param pages - 页面列表
19
- * @returns 聚合后的页面列表
20
- */
21
- function aggregateNamedViews(pages) {
22
- // 按路径分组页面
23
- const pagesByPath = new Map();
24
- for (const page of pages) {
25
- if (!pagesByPath.has(page.path)) {
26
- pagesByPath.set(page.path, []);
27
- }
28
- pagesByPath.get(page.path).push(page);
29
- }
30
- const aggregatedPages = [];
31
- for (const [path, pathPages] of pagesByPath) {
32
- // 分离默认视图和命名视图
33
- const defaultPages = pathPages.filter(p => p.viewName === null || p.viewName === 'default');
34
- const namedViews = pathPages.filter(p => p.viewName !== null && p.viewName !== 'default');
35
- // 检查是否只有命名视图而没有默认视图
36
- if (defaultPages.length === 0 && namedViews.length > 0) {
37
- const namedViewFiles = namedViews.map(p => p.filePath).join(', ');
38
- const firstNamedView = namedViews[0];
39
- const baseName = firstNamedView.filePath.split('/').pop()?.split('@')[0].split('.')[0] || 'index';
40
- throw new Error(`[file-router] 命名视图错误: 路径 "${path}" 只有命名视图文件 (${namedViewFiles}),` +
41
- `缺少默认视图文件 (${baseName}.tsx 或 ${baseName}@default.tsx)。\n` +
42
- `修复方案: 添加 ${baseName}.tsx 或 ${baseName}@default.tsx 文件。`);
43
- }
44
- // 如果没有命名视图,直接添加所有页面
45
- if (namedViews.length === 0) {
46
- aggregatedPages.push(...pathPages);
47
- continue;
48
- }
49
- // 以第一个默认视图为基础,添加命名视图
50
- const basePage = { ...defaultPages[0], children: defaultPages[0].children || [] };
51
- basePage.namedViews = {};
52
- namedViews.forEach(page => {
53
- basePage.namedViews[page.viewName] = page.filePath;
54
- });
55
- aggregatedPages.push(basePage);
56
- }
57
- return aggregatedPages;
58
- }
59
- /**
60
- * 扫描单个目录
61
- *
62
- * @param dir - 目录路径
63
- * @param pageDir - 页面根目录
64
- * @param parentPath - 父级路径
65
- * @param extensions - 文件扩展名
66
- * @param include - 包含模式
67
- * @param exclude - 排除模式
68
- * @param namingStrategy - 命名策略
69
- * @param pathPrefix - 路径前缀
70
- * @param pages - 页面收集器
71
- */
72
- function scanDirectory(dir, pageDir, parentPath, extensions, include, exclude, namingStrategy, pathPrefix, pages) {
73
- // 读取目录内容
74
- const entries = fs.readdirSync(dir, { withFileTypes: true });
75
- const directories = [];
76
- const files = [];
77
- // 分类目录和文件
78
- for (const entry of entries) {
79
- const fullPath = path.join(dir, entry.name);
80
- const isDir = entry.isDirectory();
81
- // 检查是否应该处理该文件/目录
82
- if (!shouldProcessFile(fullPath, pageDir, include, exclude, isDir)) {
83
- continue;
84
- }
85
- if (isDir) {
86
- directories.push(entry);
87
- }
88
- else if (entry.isFile()) {
89
- files.push(entry);
90
- }
91
- }
92
- // 收集目录名和文件名(用于检测布局路由)
93
- const dirNames = new Set(directories.map(d => d.name));
94
- const fileBaseNames = new Map();
95
- // 处理文件,检查扩展名和同名冲突
96
- for (const file of files) {
97
- const ext = path.extname(file.name);
98
- if (!extensions.includes(ext))
99
- continue;
100
- const baseName = path.basename(file.name, ext);
101
- const existing = fileBaseNames.get(baseName);
102
- // 处理同名文件冲突(不同扩展名)
103
- if (existing) {
104
- warn(`同名文件冲突: "${baseName}"`, `存在多个扩展名版本 (${existing.ext} 和 ${ext}),将忽略 "${file.name}"`);
105
- continue;
106
- }
107
- fileBaseNames.set(baseName, { entry: file, ext });
108
- }
109
- // 解析文件并检查布局路由
110
- for (const [baseName, { entry }] of fileBaseNames) {
111
- const filePath = path.join(dir, entry.name);
112
- // 检查是否存在同名目录(布局路由)
113
- const hasSameNameDir = dirNames.has(baseName);
114
- // 解析页面文件
115
- const parsed = parsePageFile(filePath, pageDir, parentPath, namingStrategy, pathPrefix);
116
- if (parsed) {
117
- // 如果存在同名目录,标记为布局文件
118
- if (hasSameNameDir) {
119
- parsed.isLayoutFile = true;
120
- }
121
- pages.push(parsed);
122
- }
123
- }
124
- // 递归扫描子目录
125
- for (const directory of directories) {
126
- const dirPath = path.join(dir, directory.name);
127
- const newParentPath = parentPath ? `${parentPath}/${directory.name}` : directory.name;
128
- scanDirectory(dirPath, pageDir, newParentPath, extensions, include, exclude, namingStrategy, pathPrefix, pages);
129
- }
130
- }
131
- /**
132
- * 扫描页面目录
133
- *
134
- * 核心流程:
135
- * 1. 递归扫描目录,收集文件和子目录
136
- * 2. 检测同名文件+目录组合(布局路由)
137
- * 3. 解析每个文件为 ParsedPage
138
- * 4. 聚合命名视图
139
- *
140
- * @param options - 扫描选项
141
- * @returns - 解析后的页面列表
142
- */
143
- function scanPages(options) {
144
- // 检查目录是否存在
145
- if (!fs.existsSync(options.page.dir))
146
- return [];
147
- const { extensions, namingStrategy, page } = options;
148
- const { include, exclude, prefix, dir } = page;
149
- const pages = [];
150
- // 扫描目录并收集页面
151
- scanDirectory(dir, dir, '', extensions, include, exclude || [], namingStrategy, prefix, pages);
152
- // 聚合命名视图
153
- return aggregateNamedViews(pages);
154
- }
155
- /**
156
- * 扫描多个页面目录
157
- *
158
- * @param options - 多目录扫描选项
159
- * @returns 合并后的页面列表
160
- */
161
- export function scanMultiplePages(options) {
162
- const { pages, extensions, namingStrategy = 'kebab' } = options;
163
- const allPages = [];
164
- // 扫描每个页面目录
165
- for (const dirConfig of pages) {
166
- const pages = scanPages({
167
- page: dirConfig,
168
- extensions,
169
- namingStrategy
170
- });
171
- allPages.push(...pages);
172
- }
173
- return allPages;
174
- }