vitarx-router 4.0.0-beta.2 → 4.0.0-beta.4
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 +20 -3
- package/dist/{plugin-vite/auto-routes → auto-routes}/handleHotUpdate.d.ts +1 -1
- package/dist/core/router/manager.js +2 -0
- package/dist/core/shared/route.js +1 -2
- package/dist/file-router/config/index.d.ts +2 -1
- package/dist/file-router/config/index.js +2 -1
- package/dist/file-router/config/resolve.d.ts +27 -0
- package/dist/file-router/config/resolve.js +74 -0
- package/dist/file-router/{utils/validateOptions.d.ts → config/validate.d.ts} +11 -10
- package/dist/file-router/{utils/validateOptions.js → config/validate.js} +107 -95
- package/dist/file-router/constants.d.ts +12 -2
- package/dist/file-router/constants.js +13 -3
- package/dist/file-router/generator/generateRoutes.d.ts +18 -13
- package/dist/file-router/generator/generateRoutes.js +110 -69
- package/dist/file-router/generator/generateTypes.d.ts +3 -3
- package/dist/file-router/generator/generateTypes.js +36 -41
- package/dist/file-router/global.d.ts +1 -1
- package/dist/file-router/index.d.ts +129 -90
- package/dist/file-router/index.js +441 -134
- package/dist/file-router/macros/astValueExtractor.d.ts +1 -1
- package/dist/file-router/macros/definePage.d.ts +18 -3
- package/dist/file-router/macros/definePage.js +117 -39
- package/dist/file-router/parser/exportChecker.d.ts +4 -23
- package/dist/file-router/parser/exportChecker.js +36 -78
- package/dist/file-router/parser/filterUtils.d.ts +25 -0
- package/dist/file-router/parser/filterUtils.js +44 -0
- package/dist/file-router/parser/index.d.ts +2 -1
- package/dist/file-router/parser/index.js +2 -1
- package/dist/file-router/parser/parsePage.d.ts +32 -9
- package/dist/file-router/parser/parsePage.js +182 -173
- package/dist/file-router/types/hooks.d.ts +18 -0
- package/dist/file-router/types/index.d.ts +3 -0
- package/dist/file-router/types/index.js +1 -0
- package/dist/file-router/types/options.d.ts +168 -0
- package/dist/file-router/types/options.js +1 -0
- package/dist/file-router/types/route.d.ts +102 -0
- package/dist/file-router/types/route.js +1 -0
- package/dist/file-router/utils/fileReader.d.ts +11 -0
- package/dist/file-router/utils/fileReader.js +22 -0
- package/dist/file-router/utils/index.d.ts +3 -2
- package/dist/file-router/utils/index.js +3 -2
- package/dist/file-router/utils/logger.d.ts +2 -2
- package/dist/file-router/utils/logger.js +3 -3
- package/dist/file-router/utils/pathStrategy.d.ts +28 -0
- package/dist/file-router/utils/{namingStrategy.js → pathStrategy.js} +18 -28
- package/dist/file-router/utils/pathUtils.d.ts +31 -0
- package/dist/file-router/utils/pathUtils.js +53 -1
- package/dist/plugin-vite/index.d.ts +28 -9
- package/dist/plugin-vite/index.js +28 -56
- package/package.json +4 -4
- package/dist/file-router/config/configUtils.d.ts +0 -54
- package/dist/file-router/config/configUtils.js +0 -88
- package/dist/file-router/scanner/filterUtils.d.ts +0 -35
- package/dist/file-router/scanner/filterUtils.js +0 -188
- package/dist/file-router/scanner/index.d.ts +0 -8
- package/dist/file-router/scanner/index.js +0 -8
- package/dist/file-router/scanner/routeTreeBuilder.d.ts +0 -21
- package/dist/file-router/scanner/routeTreeBuilder.js +0 -312
- package/dist/file-router/scanner/scanPages.d.ts +0 -48
- package/dist/file-router/scanner/scanPages.js +0 -174
- package/dist/file-router/types.d.ts +0 -344
- package/dist/file-router/utils/namingStrategy.d.ts +0 -57
- /package/dist/{plugin-vite/auto-routes → auto-routes}/handleHotUpdate.js +0 -0
- /package/dist/{plugin-vite/auto-routes → auto-routes}/index.d.ts +0 -0
- /package/dist/{plugin-vite/auto-routes → auto-routes}/index.js +0 -0
- /package/dist/file-router/{types.js → types/hooks.js} +0 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Vitarx 前端框架官方路由解决方案,提供声明式路由配置、导
|
|
|
10
10
|
## 特性
|
|
11
11
|
|
|
12
12
|
- 🚀 **多种路由模式** - 支持 Hash、History、Memory 三种路由模式
|
|
13
|
-
- 📁 **文件路由** - 基于 Vite
|
|
13
|
+
- 📁 **文件路由** - 基于 Vite 插件的文件系统路由自动生成,HMR 热更新支持
|
|
14
14
|
- 🔒 **导航守卫** - 完整的路由守卫机制,支持权限控制
|
|
15
15
|
- 🔄 **动态路由** - 支持动态参数、正则约束、可选参数
|
|
16
16
|
- 📦 **懒加载** - 内置组件懒加载支持
|
|
@@ -403,7 +403,10 @@ import VitarxRouter from 'vitarx-router/vite'
|
|
|
403
403
|
export default defineConfig({
|
|
404
404
|
plugins: [
|
|
405
405
|
VitarxRouter({
|
|
406
|
-
|
|
406
|
+
pages: 'src/pages',
|
|
407
|
+
pathStrategy: 'kebab',
|
|
408
|
+
importMode: 'lazy',
|
|
409
|
+
dts: 'router.d.ts'
|
|
407
410
|
})
|
|
408
411
|
]
|
|
409
412
|
})
|
|
@@ -418,7 +421,21 @@ import { createRouter } from 'vitarx-router'
|
|
|
418
421
|
export const router = createRouter({ routes })
|
|
419
422
|
```
|
|
420
423
|
|
|
421
|
-
|
|
424
|
+
### 文件路由配置选项
|
|
425
|
+
|
|
426
|
+
| 选项 | 类型 | 默认值 | 说明 |
|
|
427
|
+
|------------------|---------------------------------------|---------------|----------|
|
|
428
|
+
| `pages` | `PageSource \| readonly PageSource[]` | `'src/pages'` | 页面来源配置 |
|
|
429
|
+
| `pathStrategy` | `'kebab' \| 'lowercase' \| 'raw'` | `'kebab'` | 路径命名策略 |
|
|
430
|
+
| `importMode` | `'lazy' \| 'sync'` | `'lazy'` | 组件导入模式 |
|
|
431
|
+
| `injectImports` | `readonly string[]` | - | 自定义导入语句 |
|
|
432
|
+
| `dts` | `boolean \| string` | `false` | 类型声明文件配置 |
|
|
433
|
+
| `layoutFileName` | `string` | `'_layout'` | 布局文件名 |
|
|
434
|
+
| `configFileName` | `string` | `'_config'` | 分组配置文件名 |
|
|
435
|
+
| `transform` | `CodeTransformHook` | - | 代码转换钩子 |
|
|
436
|
+
| `extendRoute` | `ExtendRouteHook` | - | 路由扩展钩子 |
|
|
437
|
+
|
|
438
|
+
详细配置请参考 [File Router 文档](src/file-router/README.md)。
|
|
422
439
|
|
|
423
440
|
## TypeScript 支持
|
|
424
441
|
|
|
@@ -200,6 +200,7 @@ export class RouteManager {
|
|
|
200
200
|
const candidates = this.dynamicRoutes.get(length);
|
|
201
201
|
if (candidates) {
|
|
202
202
|
for (const { regex, route } of candidates) {
|
|
203
|
+
regex.lastIndex = 0;
|
|
203
204
|
// 执行正则匹配
|
|
204
205
|
const match = regex.exec(formattedPath);
|
|
205
206
|
if (match) {
|
|
@@ -248,6 +249,7 @@ export class RouteManager {
|
|
|
248
249
|
// 3. 动态路由:参数校验与序列化
|
|
249
250
|
const resolvedParams = {};
|
|
250
251
|
for (const paramDef of route.pattern) {
|
|
252
|
+
paramDef.regex.lastIndex = 0;
|
|
251
253
|
const value = params[paramDef.name];
|
|
252
254
|
const rawValue = String(value ?? ''); // 统一转字符串处理
|
|
253
255
|
// 3.1 必填参数校验
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CodeTransformHook, ExtendRouteHook, FileRouterOptions, ImportMode, PageDirOptions, PathParser, PathStrategy } from '../types/index.js';
|
|
2
|
+
export type PageDirConfig = Required<PageDirOptions>;
|
|
3
|
+
/**
|
|
4
|
+
* 规范化后的配置
|
|
5
|
+
*/
|
|
6
|
+
export interface ResolvedConfig {
|
|
7
|
+
root: string;
|
|
8
|
+
pages: readonly PageDirConfig[];
|
|
9
|
+
pathStrategy: PathStrategy;
|
|
10
|
+
importMode: ImportMode;
|
|
11
|
+
injectImports: readonly string[];
|
|
12
|
+
dts: false | string;
|
|
13
|
+
layoutFileName: string;
|
|
14
|
+
configFileName: string;
|
|
15
|
+
transform?: CodeTransformHook;
|
|
16
|
+
extendRoute?: ExtendRouteHook;
|
|
17
|
+
pathParser?: PathParser;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 规范化文件路由配置
|
|
21
|
+
*
|
|
22
|
+
* 将用户提供的配置转换为内部统一格式。
|
|
23
|
+
*
|
|
24
|
+
* @param options - 用户提供的配置选项
|
|
25
|
+
* @returns - 规范化后的配置对象
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveConfig(options: FileRouterOptions): ResolvedConfig;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview 配置处理工具模块
|
|
3
|
+
*
|
|
4
|
+
* 提供页面目录配置的处理和文件检查功能。
|
|
5
|
+
* 与构建工具无关,可在任何 Node.js 环境中使用。
|
|
6
|
+
*/
|
|
7
|
+
import { accessSync, constants } from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { DEFAULT_CONFIG_FILE, DEFAULT_DTS_FILE, DEFAULT_EXCLUDE, DEFAULT_INCLUDE, DEFAULT_LAYOUT_FILE, DEFAULT_PAGES_DIR } from '../constants.js';
|
|
10
|
+
const DEFAULT_PAGE_CONFIG = {
|
|
11
|
+
exclude: DEFAULT_EXCLUDE,
|
|
12
|
+
include: DEFAULT_INCLUDE,
|
|
13
|
+
prefix: '/',
|
|
14
|
+
group: false
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* 将 pages 配置规范化为 PageConfig 数组
|
|
18
|
+
*
|
|
19
|
+
* 支持四种输入格式:
|
|
20
|
+
* 1. 字符串:单个目录路径
|
|
21
|
+
* 2. 对象:单个目录配置
|
|
22
|
+
* 3. 字符串数组:多个目录路径
|
|
23
|
+
* 4. 对象数组:每个目录独立配置
|
|
24
|
+
*
|
|
25
|
+
* @param pages - 用户配置的 pages
|
|
26
|
+
* @param root - 项目根目录路径(用于解析相对路径)
|
|
27
|
+
* @returns - 规范化后的目录配置数组
|
|
28
|
+
*/
|
|
29
|
+
function resolvePageConfigs(pages, root) {
|
|
30
|
+
const list = Array.isArray(pages) ? pages : [pages];
|
|
31
|
+
return list.map(page => {
|
|
32
|
+
const config = typeof page === 'string' ? { dir: page } : page;
|
|
33
|
+
const resolved = {
|
|
34
|
+
...DEFAULT_PAGE_CONFIG,
|
|
35
|
+
...config,
|
|
36
|
+
dir: path.isAbsolute(config.dir) ? config.dir : path.resolve(root, config.dir)
|
|
37
|
+
};
|
|
38
|
+
if (resolved.prefix !== '/' && !resolved.prefix.startsWith('/')) {
|
|
39
|
+
resolved.prefix = '/' + resolved.prefix;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
accessSync(resolved.dir, constants.R_OK | constants.W_OK);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw new Error(`File router: Pages directory "${resolved.dir}" does not exist or is not accessible`);
|
|
46
|
+
}
|
|
47
|
+
return resolved;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 规范化文件路由配置
|
|
52
|
+
*
|
|
53
|
+
* 将用户提供的配置转换为内部统一格式。
|
|
54
|
+
*
|
|
55
|
+
* @param options - 用户提供的配置选项
|
|
56
|
+
* @returns - 规范化后的配置对象
|
|
57
|
+
*/
|
|
58
|
+
export function resolveConfig(options) {
|
|
59
|
+
const { dts = false, root = process.cwd(), pages = DEFAULT_PAGES_DIR, importMode = 'lazy', injectImports = [], pathStrategy = 'kebab', layoutFileName = DEFAULT_LAYOUT_FILE, configFileName = DEFAULT_CONFIG_FILE, transform, extendRoute, pathParser } = options;
|
|
60
|
+
const resolvedPages = resolvePageConfigs(pages, root);
|
|
61
|
+
return {
|
|
62
|
+
dts: typeof dts === 'string' ? dts : dts ? DEFAULT_DTS_FILE : false,
|
|
63
|
+
root,
|
|
64
|
+
pages: resolvedPages,
|
|
65
|
+
importMode,
|
|
66
|
+
injectImports,
|
|
67
|
+
pathStrategy,
|
|
68
|
+
layoutFileName,
|
|
69
|
+
configFileName,
|
|
70
|
+
transform,
|
|
71
|
+
extendRoute,
|
|
72
|
+
pathParser
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -4,21 +4,22 @@
|
|
|
4
4
|
* 提供文件路由配置选项的验证功能,确保用户提供的配置符合要求。
|
|
5
5
|
* 当配置无效时抛出明确的错误信息,帮助用户快速定位问题。
|
|
6
6
|
*/
|
|
7
|
-
import type { FileRouterOptions } from '../types.js';
|
|
7
|
+
import type { FileRouterOptions } from '../types/index.js';
|
|
8
8
|
/**
|
|
9
9
|
* 验证插件配置选项
|
|
10
10
|
*
|
|
11
11
|
* 验证顺序:
|
|
12
12
|
* 1. root 配置
|
|
13
|
-
* 2.
|
|
14
|
-
* 3.
|
|
15
|
-
* 4.
|
|
16
|
-
* 5.
|
|
17
|
-
* 6.
|
|
18
|
-
* 7.
|
|
19
|
-
* 8.
|
|
20
|
-
* 9.
|
|
21
|
-
* 10.
|
|
13
|
+
* 2. pages 配置
|
|
14
|
+
* 3. pathStrategy 配置
|
|
15
|
+
* 4. importMode 配置
|
|
16
|
+
* 5. injectImports 配置
|
|
17
|
+
* 6. dts 配置
|
|
18
|
+
* 7. layoutFileName 配置
|
|
19
|
+
* 8. configFileName 配置
|
|
20
|
+
* 9. transform 配置
|
|
21
|
+
* 10. extendRoute 配置
|
|
22
|
+
* 11. pathParser 配置
|
|
22
23
|
*
|
|
23
24
|
* @param opts - 用户提供的配置选项
|
|
24
25
|
* @throws {Error} 当配置无效时抛出错误
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview 配置验证工具模块
|
|
3
|
+
*
|
|
4
|
+
* 提供文件路由配置选项的验证功能,确保用户提供的配置符合要求。
|
|
5
|
+
* 当配置无效时抛出明确的错误信息,帮助用户快速定位问题。
|
|
6
|
+
*/
|
|
1
7
|
/**
|
|
2
8
|
* 验证 pages 配置
|
|
3
9
|
*
|
|
@@ -9,20 +15,20 @@ function validatePagesDir(opts) {
|
|
|
9
15
|
return;
|
|
10
16
|
if (typeof opts.pages === 'string') {
|
|
11
17
|
if (opts.pages.trim() === '') {
|
|
12
|
-
throw new Error('options.
|
|
18
|
+
throw new Error('options.pages 不能为空字符串');
|
|
13
19
|
}
|
|
14
20
|
return;
|
|
15
21
|
}
|
|
16
22
|
if (Array.isArray(opts.pages)) {
|
|
17
23
|
if (opts.pages.length === 0) {
|
|
18
|
-
throw new Error('options.
|
|
24
|
+
throw new Error('options.pages 数组不能为空');
|
|
19
25
|
}
|
|
20
26
|
opts.pages.forEach((item, i) => {
|
|
21
27
|
validatePagesDirItem(item, i);
|
|
22
28
|
});
|
|
23
29
|
return;
|
|
24
30
|
}
|
|
25
|
-
throw new Error('options.
|
|
31
|
+
throw new Error('options.pages 必须是字符串、字符串数组或对象数组');
|
|
26
32
|
}
|
|
27
33
|
/**
|
|
28
34
|
* 验证 pages 数组中的单个项目
|
|
@@ -34,171 +40,175 @@ function validatePagesDir(opts) {
|
|
|
34
40
|
function validatePagesDirItem(item, index) {
|
|
35
41
|
if (typeof item === 'string') {
|
|
36
42
|
if (item.trim() === '') {
|
|
37
|
-
throw new Error(`options.
|
|
43
|
+
throw new Error(`options.pages[${index}] 不能为空字符串`);
|
|
38
44
|
}
|
|
39
45
|
return;
|
|
40
46
|
}
|
|
41
47
|
if (typeof item === 'object' && item !== null) {
|
|
42
48
|
const config = item;
|
|
43
49
|
if (!config.dir || typeof config.dir !== 'string' || config.dir.trim() === '') {
|
|
44
|
-
throw new Error(`options.
|
|
50
|
+
throw new Error(`options.pages[${index}].dir 必须是非空字符串`);
|
|
45
51
|
}
|
|
46
52
|
if (config.include !== undefined && !Array.isArray(config.include)) {
|
|
47
|
-
throw new Error(`options.
|
|
53
|
+
throw new Error(`options.pages[${index}].include 必须是数组`);
|
|
48
54
|
}
|
|
49
55
|
if (config.exclude !== undefined && !Array.isArray(config.exclude)) {
|
|
50
|
-
throw new Error(`options.
|
|
56
|
+
throw new Error(`options.pages[${index}].exclude 必须是数组`);
|
|
51
57
|
}
|
|
52
58
|
return;
|
|
53
59
|
}
|
|
54
|
-
throw new Error(`options.
|
|
60
|
+
throw new Error(`options.pages[${index}] 必须是字符串或对象`);
|
|
55
61
|
}
|
|
56
62
|
/**
|
|
57
|
-
* 验证
|
|
63
|
+
* 验证 root 配置
|
|
58
64
|
*
|
|
59
65
|
* @param opts - 配置选项
|
|
60
66
|
* @throws {Error} 当配置无效时抛出错误
|
|
61
67
|
*/
|
|
62
|
-
function
|
|
63
|
-
if (opts.
|
|
68
|
+
function validateRoot(opts) {
|
|
69
|
+
if (opts.root === undefined)
|
|
64
70
|
return;
|
|
65
|
-
if (
|
|
66
|
-
throw new Error('options.
|
|
71
|
+
if (typeof opts.root !== 'string') {
|
|
72
|
+
throw new Error('options.root 必须是字符串');
|
|
67
73
|
}
|
|
68
|
-
if (opts.
|
|
69
|
-
throw new Error('options.
|
|
74
|
+
if (opts.root.trim() === '') {
|
|
75
|
+
throw new Error('options.root 不能为空字符串');
|
|
70
76
|
}
|
|
71
|
-
opts.extensions.forEach((ext, i) => {
|
|
72
|
-
if (typeof ext !== 'string') {
|
|
73
|
-
throw new Error(`options.extensions[${i}] 必须是字符串`);
|
|
74
|
-
}
|
|
75
|
-
if (!ext.startsWith('.')) {
|
|
76
|
-
throw new Error(`options.extensions[${i}] "${ext}" 必须以 "." 开头`);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
77
|
}
|
|
80
78
|
/**
|
|
81
|
-
* 验证
|
|
79
|
+
* 验证 importMode 配置
|
|
82
80
|
*
|
|
83
81
|
* @param opts - 配置选项
|
|
84
82
|
* @throws {Error} 当配置无效时抛出错误
|
|
85
83
|
*/
|
|
86
|
-
function
|
|
87
|
-
if (opts.
|
|
84
|
+
function validateImportMode(opts) {
|
|
85
|
+
if (opts.importMode === undefined)
|
|
88
86
|
return;
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
const validModes = ['lazy', 'sync'];
|
|
88
|
+
if (!validModes.includes(opts.importMode)) {
|
|
89
|
+
throw new Error(`options.importMode 必须是 'lazy' 或 'sync'`);
|
|
91
90
|
}
|
|
92
|
-
opts.include.forEach((item, i) => {
|
|
93
|
-
if (typeof item !== 'string') {
|
|
94
|
-
throw new Error(`options.include[${i}] 必须是字符串`);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
91
|
}
|
|
98
92
|
/**
|
|
99
|
-
* 验证
|
|
93
|
+
* 验证 injectImports 配置
|
|
100
94
|
*
|
|
101
95
|
* @param opts - 配置选项
|
|
102
96
|
* @throws {Error} 当配置无效时抛出错误
|
|
103
97
|
*/
|
|
104
|
-
function
|
|
105
|
-
if (opts.
|
|
98
|
+
function validateInjectImports(opts) {
|
|
99
|
+
if (opts.injectImports === undefined)
|
|
106
100
|
return;
|
|
107
|
-
if (!Array.isArray(opts.
|
|
108
|
-
throw new Error('options.
|
|
101
|
+
if (!Array.isArray(opts.injectImports)) {
|
|
102
|
+
throw new Error('options.injectImports 必须是数组');
|
|
109
103
|
}
|
|
110
|
-
opts.
|
|
111
|
-
if (typeof
|
|
112
|
-
throw new Error(`options.
|
|
104
|
+
opts.injectImports.forEach((imp, i) => {
|
|
105
|
+
if (typeof imp !== 'string') {
|
|
106
|
+
throw new Error(`options.injectImports[${i}] 必须是字符串`);
|
|
113
107
|
}
|
|
114
108
|
});
|
|
115
109
|
}
|
|
116
110
|
/**
|
|
117
|
-
* 验证
|
|
111
|
+
* 验证 namingStrategy 配置
|
|
118
112
|
*
|
|
119
113
|
* @param opts - 配置选项
|
|
120
114
|
* @throws {Error} 当配置无效时抛出错误
|
|
121
115
|
*/
|
|
122
|
-
function
|
|
123
|
-
if (opts.
|
|
116
|
+
function validatePathStrategy(opts) {
|
|
117
|
+
if (opts.pathStrategy === undefined)
|
|
124
118
|
return;
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
const validStrategies = ['kebab', 'lowercase', 'raw'];
|
|
120
|
+
if (!validStrategies.includes(opts.pathStrategy)) {
|
|
121
|
+
throw new Error(`options.pathStrategy 必须是 'kebab'、'lowercase' 或 'raw'`);
|
|
127
122
|
}
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 验证 dts 配置
|
|
126
|
+
*
|
|
127
|
+
* @param opts - 配置选项
|
|
128
|
+
* @throws {Error} 当配置无效时抛出错误
|
|
129
|
+
*/
|
|
130
|
+
function validateDts(opts) {
|
|
131
|
+
if (opts.dts === undefined)
|
|
132
|
+
return;
|
|
133
|
+
if (typeof opts.dts === 'boolean')
|
|
134
|
+
return;
|
|
135
|
+
if (typeof opts.dts === 'string') {
|
|
136
|
+
if (opts.dts.trim() === '') {
|
|
137
|
+
throw new Error('options.dts 为字符串时不能为空字符串');
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
130
140
|
}
|
|
141
|
+
throw new Error('options.dts 必须是 boolean 或 string');
|
|
131
142
|
}
|
|
132
143
|
/**
|
|
133
|
-
* 验证
|
|
144
|
+
* 验证 layoutFileName 配置
|
|
134
145
|
*
|
|
135
146
|
* @param opts - 配置选项
|
|
136
147
|
* @throws {Error} 当配置无效时抛出错误
|
|
137
148
|
*/
|
|
138
|
-
function
|
|
139
|
-
if (opts.
|
|
149
|
+
function validateLayoutFileName(opts) {
|
|
150
|
+
if (opts.layoutFileName === undefined)
|
|
140
151
|
return;
|
|
141
|
-
if (typeof opts.
|
|
142
|
-
throw new Error('options.
|
|
152
|
+
if (typeof opts.layoutFileName !== 'string') {
|
|
153
|
+
throw new Error('options.layoutFileName 必须是字符串');
|
|
154
|
+
}
|
|
155
|
+
if (opts.layoutFileName.trim() === '') {
|
|
156
|
+
throw new Error('options.layoutFileName 不能为空字符串');
|
|
143
157
|
}
|
|
144
158
|
}
|
|
145
159
|
/**
|
|
146
|
-
* 验证
|
|
160
|
+
* 验证 configFileName 配置
|
|
147
161
|
*
|
|
148
162
|
* @param opts - 配置选项
|
|
149
163
|
* @throws {Error} 当配置无效时抛出错误
|
|
150
164
|
*/
|
|
151
|
-
function
|
|
152
|
-
if (opts.
|
|
165
|
+
function validateConfigFileName(opts) {
|
|
166
|
+
if (opts.configFileName === undefined)
|
|
153
167
|
return;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
168
|
+
if (typeof opts.configFileName !== 'string') {
|
|
169
|
+
throw new Error('options.configFileName 必须是字符串');
|
|
170
|
+
}
|
|
171
|
+
if (opts.configFileName.trim() === '') {
|
|
172
|
+
throw new Error('options.configFileName 不能为空字符串');
|
|
157
173
|
}
|
|
158
174
|
}
|
|
159
175
|
/**
|
|
160
|
-
* 验证
|
|
176
|
+
* 验证 transform 配置
|
|
161
177
|
*
|
|
162
178
|
* @param opts - 配置选项
|
|
163
179
|
* @throws {Error} 当配置无效时抛出错误
|
|
164
180
|
*/
|
|
165
|
-
function
|
|
166
|
-
if (opts.
|
|
181
|
+
function validateTransform(opts) {
|
|
182
|
+
if (opts.transform === undefined)
|
|
167
183
|
return;
|
|
168
|
-
if (typeof opts.
|
|
169
|
-
throw new Error('options.
|
|
184
|
+
if (typeof opts.transform !== 'function') {
|
|
185
|
+
throw new Error('options.transform 必须是函数');
|
|
170
186
|
}
|
|
171
187
|
}
|
|
172
188
|
/**
|
|
173
|
-
* 验证
|
|
189
|
+
* 验证 extendRoute 配置
|
|
174
190
|
*
|
|
175
191
|
* @param opts - 配置选项
|
|
176
192
|
* @throws {Error} 当配置无效时抛出错误
|
|
177
193
|
*/
|
|
178
|
-
function
|
|
179
|
-
if (opts.
|
|
194
|
+
function validateExtendRoute(opts) {
|
|
195
|
+
if (opts.extendRoute === undefined)
|
|
180
196
|
return;
|
|
181
|
-
if (
|
|
182
|
-
throw new Error('options.
|
|
197
|
+
if (typeof opts.extendRoute !== 'function') {
|
|
198
|
+
throw new Error('options.extendRoute 必须是函数');
|
|
183
199
|
}
|
|
184
|
-
opts.injectImports.forEach((imp, i) => {
|
|
185
|
-
if (typeof imp !== 'string') {
|
|
186
|
-
throw new Error(`options.injectImports[${i}] 必须是字符串`);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
200
|
}
|
|
190
201
|
/**
|
|
191
|
-
* 验证
|
|
202
|
+
* 验证 pathParser 配置
|
|
192
203
|
*
|
|
193
204
|
* @param opts - 配置选项
|
|
194
205
|
* @throws {Error} 当配置无效时抛出错误
|
|
195
206
|
*/
|
|
196
|
-
function
|
|
197
|
-
if (opts.
|
|
207
|
+
function validatePathParser(opts) {
|
|
208
|
+
if (opts.pathParser === undefined)
|
|
198
209
|
return;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
throw new Error(`options.namingStrategy 必须是 'kebab'、'lowercase' 或 'none'`);
|
|
210
|
+
if (typeof opts.pathParser !== 'function') {
|
|
211
|
+
throw new Error('options.pathParser 必须是函数');
|
|
202
212
|
}
|
|
203
213
|
}
|
|
204
214
|
/**
|
|
@@ -206,28 +216,30 @@ function validateNamingStrategy(opts) {
|
|
|
206
216
|
*
|
|
207
217
|
* 验证顺序:
|
|
208
218
|
* 1. root 配置
|
|
209
|
-
* 2.
|
|
210
|
-
* 3.
|
|
211
|
-
* 4.
|
|
212
|
-
* 5.
|
|
213
|
-
* 6.
|
|
214
|
-
* 7.
|
|
215
|
-
* 8.
|
|
216
|
-
* 9.
|
|
217
|
-
* 10.
|
|
219
|
+
* 2. pages 配置
|
|
220
|
+
* 3. pathStrategy 配置
|
|
221
|
+
* 4. importMode 配置
|
|
222
|
+
* 5. injectImports 配置
|
|
223
|
+
* 6. dts 配置
|
|
224
|
+
* 7. layoutFileName 配置
|
|
225
|
+
* 8. configFileName 配置
|
|
226
|
+
* 9. transform 配置
|
|
227
|
+
* 10. extendRoute 配置
|
|
228
|
+
* 11. pathParser 配置
|
|
218
229
|
*
|
|
219
230
|
* @param opts - 用户提供的配置选项
|
|
220
231
|
* @throws {Error} 当配置无效时抛出错误
|
|
221
232
|
*/
|
|
222
233
|
export function validateOptions(opts) {
|
|
223
234
|
validateRoot(opts);
|
|
224
|
-
validatePrefix(opts);
|
|
225
235
|
validatePagesDir(opts);
|
|
226
|
-
|
|
227
|
-
validateInclude(opts);
|
|
228
|
-
validateExclude(opts);
|
|
236
|
+
validatePathStrategy(opts);
|
|
229
237
|
validateImportMode(opts);
|
|
230
|
-
validateExtendRoute(opts);
|
|
231
238
|
validateInjectImports(opts);
|
|
232
|
-
|
|
239
|
+
validateDts(opts);
|
|
240
|
+
validateLayoutFileName(opts);
|
|
241
|
+
validateConfigFileName(opts);
|
|
242
|
+
validateTransform(opts);
|
|
243
|
+
validateExtendRoute(opts);
|
|
244
|
+
validatePathParser(opts);
|
|
233
245
|
}
|
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 定义文件路由的默认配置常量。
|
|
5
5
|
*/
|
|
6
|
-
/** 支持的页面文件扩展名列表 */
|
|
7
|
-
export declare const DEFAULT_EXTENSIONS: string[];
|
|
8
6
|
/** 默认的页面目录路径 */
|
|
9
7
|
export declare const DEFAULT_PAGES_DIR = "src/pages";
|
|
8
|
+
/** 默认的类型定义文件路径 */
|
|
9
|
+
export declare const DEFAULT_DTS_FILE = "router.d.ts";
|
|
10
10
|
/** 默认的包含模式 */
|
|
11
11
|
export declare const DEFAULT_INCLUDE: string[];
|
|
12
|
+
/** 默认的排除模式 */
|
|
13
|
+
export declare const DEFAULT_EXCLUDE: string[];
|
|
14
|
+
/**
|
|
15
|
+
* 布局文件名前缀
|
|
16
|
+
*/
|
|
17
|
+
export declare const DEFAULT_LAYOUT_FILE = "_layout";
|
|
18
|
+
/**
|
|
19
|
+
* 配置文件名
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_CONFIG_FILE = "_config";
|
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 定义文件路由的默认配置常量。
|
|
5
5
|
*/
|
|
6
|
-
/** 支持的页面文件扩展名列表 */
|
|
7
|
-
export const DEFAULT_EXTENSIONS = ['.tsx', '.ts', '.jsx', '.js'];
|
|
8
6
|
/** 默认的页面目录路径 */
|
|
9
7
|
export const DEFAULT_PAGES_DIR = 'src/pages';
|
|
8
|
+
/** 默认的类型定义文件路径 */
|
|
9
|
+
export const DEFAULT_DTS_FILE = 'router.d.ts';
|
|
10
10
|
/** 默认的包含模式 */
|
|
11
|
-
export const DEFAULT_INCLUDE = ['
|
|
11
|
+
export const DEFAULT_INCLUDE = ['**/*.{jsx,tsx}'];
|
|
12
|
+
/** 默认的排除模式 */
|
|
13
|
+
export const DEFAULT_EXCLUDE = ['**/node_modules/**', '**/dist/**', '**/.*'];
|
|
14
|
+
/**
|
|
15
|
+
* 布局文件名前缀
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_LAYOUT_FILE = '_layout';
|
|
18
|
+
/**
|
|
19
|
+
* 配置文件名
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_CONFIG_FILE = '_config';
|
|
@@ -4,17 +4,21 @@
|
|
|
4
4
|
* 负责将解析后的页面信息转换为可执行的路由配置代码。
|
|
5
5
|
* 与构建工具无关,可在任何 Node.js 环境中使用。
|
|
6
6
|
*/
|
|
7
|
-
import type { ExtendRouteHook, ImportMode,
|
|
7
|
+
import type { ExtendRouteHook, ImportMode, ParsedNode, RouteNode } from '../types/index.js';
|
|
8
8
|
/**
|
|
9
9
|
* 路由生成选项
|
|
10
10
|
*/
|
|
11
11
|
export interface GenerateRoutesOptions {
|
|
12
|
+
/**
|
|
13
|
+
* 是否生成类型代码
|
|
14
|
+
*/
|
|
15
|
+
dts: boolean;
|
|
12
16
|
/**
|
|
13
17
|
* 组件导入模式
|
|
14
18
|
* - `lazy`: 使用 lazy(() => import(...)) 懒加载组件
|
|
15
19
|
* - `file`: 直接使用文件路径作为组件
|
|
16
20
|
*/
|
|
17
|
-
importMode
|
|
21
|
+
importMode: ImportMode;
|
|
18
22
|
/**
|
|
19
23
|
* 路由扩展钩子
|
|
20
24
|
* 在生成每个路由配置时调用,允许开发者自定义扩展路由配置
|
|
@@ -24,16 +28,17 @@ export interface GenerateRoutesOptions {
|
|
|
24
28
|
* 自定义导入语句
|
|
25
29
|
* 允许向虚拟模块注入自定义的导入语句
|
|
26
30
|
*/
|
|
27
|
-
imports?: string[];
|
|
28
|
-
/**
|
|
29
|
-
* 路由命名策略
|
|
30
|
-
* - `kebab`: 将驼峰命名转换为 kebab-case(默认)
|
|
31
|
-
* - `lowercase`: 简单转换为小写
|
|
32
|
-
* - `none`: 保持原始命名
|
|
33
|
-
* @default 'kebab'
|
|
34
|
-
*/
|
|
35
|
-
namingStrategy?: NamingStrategy;
|
|
31
|
+
imports?: readonly string[];
|
|
36
32
|
}
|
|
33
|
+
export interface GenerateResult {
|
|
34
|
+
routes: RouteNode[];
|
|
35
|
+
code: string;
|
|
36
|
+
dts: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 将绝对路径转换为百分百唯一、合法的 import 变量名
|
|
40
|
+
*/
|
|
41
|
+
export declare function pathToUniqueName(absolutePath: string): string;
|
|
37
42
|
/**
|
|
38
43
|
* 生成路由配置代码
|
|
39
44
|
*
|
|
@@ -41,6 +46,6 @@ export interface GenerateRoutesOptions {
|
|
|
41
46
|
*
|
|
42
47
|
* @param pages - 解析后的页面列表
|
|
43
48
|
* @param options - 路由生成选项
|
|
44
|
-
* @returns
|
|
49
|
+
* @returns { GenerateResult } 包含routes、code、dts的路由配置结果
|
|
45
50
|
*/
|
|
46
|
-
export declare function generateRoutes(pages:
|
|
51
|
+
export declare function generateRoutes(pages: ParsedNode[], options: GenerateRoutesOptions): GenerateResult;
|