vitarx-router 4.0.1 → 4.0.3
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/LICENSE
CHANGED
|
@@ -1,27 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
上述版权声明和本许可声明须包含在本软件的所有副本或实质性部分中。
|
|
23
|
-
|
|
24
|
-
## 免责声明
|
|
25
|
-
|
|
26
|
-
本软件按“原样”提供,不提供任何形式的明示或暗示担保,包括但不限于对适销性、特定用途适用性和非侵权性的担保。
|
|
27
|
-
在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论是在合同、侵权或其他行为中产生的,还是与本软件或使用本软件有关的。
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 - present, ZhuChongLin <8210856@qq.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -6,10 +6,22 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type * as BabelTypes from '@babel/types';
|
|
8
8
|
import type { PageOptions } from '../types/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* 不支持节点的警告信息
|
|
11
|
+
*/
|
|
12
|
+
export interface UnsupportedNodeWarning {
|
|
13
|
+
/** 不支持的 AST 节点类型 */
|
|
14
|
+
nodeType: string;
|
|
15
|
+
/** 属性访问路径,如 "meta.nav.items[0].label" */
|
|
16
|
+
path: string;
|
|
17
|
+
/** 修复建议 */
|
|
18
|
+
suggestion: string;
|
|
19
|
+
}
|
|
9
20
|
/**
|
|
10
21
|
* 从对象表达式提取页面配置
|
|
11
22
|
*
|
|
12
23
|
* @param node - 对象表达式节点
|
|
13
|
-
* @
|
|
24
|
+
* @param warnings - 警告收集器(可选,不传则不收集警告)
|
|
25
|
+
* @returns 页面配置和警告列表
|
|
14
26
|
*/
|
|
15
|
-
export declare function extractPageOptions(node: BabelTypes.ObjectExpression): PageOptions;
|
|
27
|
+
export declare function extractPageOptions(node: BabelTypes.ObjectExpression, warnings?: UnsupportedNodeWarning[]): PageOptions;
|
|
@@ -1,12 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 不支持节点类型到修复建议的映射
|
|
3
|
+
*/
|
|
4
|
+
const UNSUPPORTED_NODE_SUGGESTIONS = {
|
|
5
|
+
Identifier: '不支持变量引用,请使用字面量值。例如将 { name: myVar } 改为 { name: "value" }',
|
|
6
|
+
MemberExpression: '不支持属性访问表达式,请使用字面量值。例如将 { api: config.url } 改为 { api: "https://example.com" }',
|
|
7
|
+
CallExpression: '不支持函数调用,请使用字面量值。例如将 { id: genId() } 改为 { id: "static-id" }',
|
|
8
|
+
ArrowFunctionExpression: '不支持箭头函数,请使用字面量值。例如将 { handler: () => {} } 改为 { handler: "handlerName" }',
|
|
9
|
+
FunctionExpression: '不支持函数表达式,请使用字面量值。例如将 { handler: function() {} } 改为 { handler: "handlerName" }',
|
|
10
|
+
NewExpression: '不支持 new 表达式(除 new RegExp 外),请使用字面量值',
|
|
11
|
+
SpreadElement: '不支持展开运算符,请显式列出所有属性',
|
|
12
|
+
ConditionalExpression: '不支持三元表达式,请使用字面量值。例如将 { val: cond ? "a" : "b" } 改为 { val: "a" }',
|
|
13
|
+
BinaryExpression: '不支持二元运算表达式,请使用字面量值。例如将 { val: 1 + 2 } 改为 { val: 3 }',
|
|
14
|
+
LogicalExpression: '不支持逻辑运算表达式,请使用字面量值。例如将 { val: a || "default" } 改为 { val: "default" }',
|
|
15
|
+
SequenceExpression: '不支持逗号表达式,请使用字面量值',
|
|
16
|
+
AssignmentExpression: '不支持赋值表达式,请使用字面量值',
|
|
17
|
+
UpdateExpression: '不支持更新表达式,请使用字面量值。例如将 { val: i++ } 改为 { val: 1 }',
|
|
18
|
+
TaggedTemplateExpression: '不支持标签模板字符串,请使用普通字符串字面量',
|
|
19
|
+
ClassExpression: '不支持类表达式,请使用字面量值',
|
|
20
|
+
ObjectMethod: '不支持对象方法定义,请使用字面量值。例如将 { fn() {} } 改为 { fn: "methodName" }'
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* 获取不支持节点的修复建议
|
|
24
|
+
*
|
|
25
|
+
* @param nodeType - AST 节点类型
|
|
26
|
+
* @returns 修复建议
|
|
27
|
+
*/
|
|
28
|
+
function getSuggestion(nodeType) {
|
|
29
|
+
return (UNSUPPORTED_NODE_SUGGESTIONS[nodeType] ??
|
|
30
|
+
`不支持 ${nodeType} 类型的表达式,definePage 配置仅支持静态字面量值(字符串、数字、布尔、null、对象、数组、正则、一元表达式、简单模板字符串)`);
|
|
31
|
+
}
|
|
1
32
|
/**
|
|
2
33
|
* 提取字面量值
|
|
3
34
|
*
|
|
4
35
|
* 从 AST 节点提取 JavaScript 字面量值。
|
|
36
|
+
* 遇到不支持的节点类型时,将警告信息收集到 warnings 数组中。
|
|
5
37
|
*
|
|
6
38
|
* @param node - AST 节点
|
|
39
|
+
* @param currentPath - 当前属性访问路径
|
|
40
|
+
* @param warnings - 警告收集器
|
|
7
41
|
* @returns 提取的值
|
|
8
42
|
*/
|
|
9
|
-
function extractAstLiteralValue(node) {
|
|
43
|
+
function extractAstLiteralValue(node, currentPath, warnings) {
|
|
10
44
|
switch (node.type) {
|
|
11
45
|
case 'StringLiteral':
|
|
12
46
|
return node.value;
|
|
@@ -16,11 +50,57 @@ function extractAstLiteralValue(node) {
|
|
|
16
50
|
return node.value;
|
|
17
51
|
case 'NullLiteral':
|
|
18
52
|
return null;
|
|
53
|
+
case 'RegExpLiteral':
|
|
54
|
+
return new RegExp(node.pattern, node.flags || '');
|
|
55
|
+
case 'TemplateLiteral': {
|
|
56
|
+
// 仅支持无表达式的简单模板字符串,如 `hello`
|
|
57
|
+
if (node.quasis.length === 1 && node.expressions.length === 0) {
|
|
58
|
+
return node.quasis[0].value.cooked;
|
|
59
|
+
}
|
|
60
|
+
warnings.push({
|
|
61
|
+
nodeType: node.type,
|
|
62
|
+
path: currentPath,
|
|
63
|
+
suggestion: '不支持带插值表达式的模板字符串,请使用纯字符串字面量。例如将 `Hello ${name}` 改为 "Hello World"'
|
|
64
|
+
});
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
case 'UnaryExpression': {
|
|
68
|
+
const arg = extractAstLiteralValue(node.argument, currentPath, warnings);
|
|
69
|
+
if (arg === undefined || arg === null)
|
|
70
|
+
return undefined;
|
|
71
|
+
switch (node.operator) {
|
|
72
|
+
case '-':
|
|
73
|
+
return -arg;
|
|
74
|
+
case '+':
|
|
75
|
+
return +arg;
|
|
76
|
+
case '!':
|
|
77
|
+
return !arg;
|
|
78
|
+
case '~':
|
|
79
|
+
return ~arg;
|
|
80
|
+
case 'void':
|
|
81
|
+
return undefined;
|
|
82
|
+
default:
|
|
83
|
+
warnings.push({
|
|
84
|
+
nodeType: node.type,
|
|
85
|
+
path: currentPath,
|
|
86
|
+
suggestion: `不支持 "${node.operator}" 一元运算符,仅支持 -, +, !, ~, void`
|
|
87
|
+
});
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
19
91
|
case 'ArrayExpression':
|
|
20
|
-
return node.elements.map(elem =>
|
|
92
|
+
return node.elements.map((elem, index) => elem ? extractAstLiteralValue(elem, `${currentPath}[${index}]`, warnings) : null);
|
|
21
93
|
case 'ObjectExpression': {
|
|
22
94
|
const obj = {};
|
|
23
95
|
for (const prop of node.properties) {
|
|
96
|
+
if (prop.type === 'ObjectMethod') {
|
|
97
|
+
warnings.push({
|
|
98
|
+
nodeType: 'ObjectMethod',
|
|
99
|
+
path: currentPath,
|
|
100
|
+
suggestion: getSuggestion('ObjectMethod')
|
|
101
|
+
});
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
24
104
|
if (prop.type !== 'ObjectProperty')
|
|
25
105
|
continue;
|
|
26
106
|
const key = prop.key.type === 'Identifier'
|
|
@@ -29,13 +109,19 @@ function extractAstLiteralValue(node) {
|
|
|
29
109
|
? prop.key.value
|
|
30
110
|
: null;
|
|
31
111
|
if (key) {
|
|
32
|
-
obj[key] = extractAstLiteralValue(prop.value);
|
|
112
|
+
obj[key] = extractAstLiteralValue(prop.value, `${currentPath}.${key}`, warnings);
|
|
33
113
|
}
|
|
34
114
|
}
|
|
35
115
|
return obj;
|
|
36
116
|
}
|
|
37
|
-
default:
|
|
117
|
+
default: {
|
|
118
|
+
warnings.push({
|
|
119
|
+
nodeType: node.type,
|
|
120
|
+
path: currentPath,
|
|
121
|
+
suggestion: getSuggestion(node.type)
|
|
122
|
+
});
|
|
38
123
|
return undefined;
|
|
124
|
+
}
|
|
39
125
|
}
|
|
40
126
|
}
|
|
41
127
|
/**
|
|
@@ -68,9 +154,11 @@ function extractStringRecord(node) {
|
|
|
68
154
|
* 提取 meta 值
|
|
69
155
|
*
|
|
70
156
|
* @param node - AST 节点
|
|
157
|
+
* @param currentPath - 当前属性访问路径
|
|
158
|
+
* @param warnings - 警告收集器
|
|
71
159
|
* @returns meta 对象
|
|
72
160
|
*/
|
|
73
|
-
function extractMetaValue(node) {
|
|
161
|
+
function extractMetaValue(node, currentPath, warnings) {
|
|
74
162
|
if (node.type !== 'ObjectExpression')
|
|
75
163
|
return undefined;
|
|
76
164
|
const meta = {};
|
|
@@ -84,7 +172,7 @@ function extractMetaValue(node) {
|
|
|
84
172
|
: null;
|
|
85
173
|
if (!key)
|
|
86
174
|
continue;
|
|
87
|
-
meta[key] = extractAstLiteralValue(prop.value);
|
|
175
|
+
meta[key] = extractAstLiteralValue(prop.value, `${currentPath}.${key}`, warnings);
|
|
88
176
|
}
|
|
89
177
|
return meta;
|
|
90
178
|
}
|
|
@@ -222,10 +310,12 @@ function extractAliasValue(node) {
|
|
|
222
310
|
* 从对象表达式提取页面配置
|
|
223
311
|
*
|
|
224
312
|
* @param node - 对象表达式节点
|
|
225
|
-
* @
|
|
313
|
+
* @param warnings - 警告收集器(可选,不传则不收集警告)
|
|
314
|
+
* @returns 页面配置和警告列表
|
|
226
315
|
*/
|
|
227
|
-
export function extractPageOptions(node) {
|
|
316
|
+
export function extractPageOptions(node, warnings) {
|
|
228
317
|
const options = {};
|
|
318
|
+
const warnList = warnings ?? [];
|
|
229
319
|
for (const prop of node.properties) {
|
|
230
320
|
if (prop.type !== 'ObjectProperty')
|
|
231
321
|
continue;
|
|
@@ -243,7 +333,7 @@ export function extractPageOptions(node) {
|
|
|
243
333
|
}
|
|
244
334
|
break;
|
|
245
335
|
case 'meta':
|
|
246
|
-
options.meta = extractMetaValue(prop.value);
|
|
336
|
+
options.meta = extractMetaValue(prop.value, 'meta', warnList);
|
|
247
337
|
break;
|
|
248
338
|
case 'pattern':
|
|
249
339
|
options.pattern = extractPatternValue(prop.value);
|
|
@@ -56,6 +56,7 @@ export function parseDefinePage(content, filePath) {
|
|
|
56
56
|
try {
|
|
57
57
|
const ast = parseCode(content);
|
|
58
58
|
const routeOptionsList = [];
|
|
59
|
+
const warnings = [];
|
|
59
60
|
babelTraverse(ast, {
|
|
60
61
|
CallExpression(nodePath) {
|
|
61
62
|
const { node } = nodePath;
|
|
@@ -66,7 +67,7 @@ export function parseDefinePage(content, filePath) {
|
|
|
66
67
|
if (!arg || arg.type !== 'ObjectExpression') {
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
69
|
-
const options = extractPageOptions(arg);
|
|
70
|
+
const options = extractPageOptions(arg, warnings);
|
|
70
71
|
routeOptionsList.push(options);
|
|
71
72
|
}
|
|
72
73
|
});
|
|
@@ -76,6 +77,10 @@ export function parseDefinePage(content, filePath) {
|
|
|
76
77
|
if (routeOptionsList.length > 1) {
|
|
77
78
|
warn('检测到多个 definePage 调用,将合并所有配置,建议每个文件只调用一次 definePage', `in ${filePath}`);
|
|
78
79
|
}
|
|
80
|
+
// 输出不支持节点的警告
|
|
81
|
+
for (const w of warnings) {
|
|
82
|
+
warn(`definePage 配置解析警告: 路径 "${w.path}" 处遇到不支持的 ${w.nodeType} 节点,该属性值将被忽略。${w.suggestion}`, `in ${filePath}`);
|
|
83
|
+
}
|
|
79
84
|
return mergePageOptions(...routeOptionsList);
|
|
80
85
|
}
|
|
81
86
|
catch (e) {
|
|
@@ -6,16 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export function findRoute(routes, path) {
|
|
8
8
|
for (const route of routes) {
|
|
9
|
-
if (!route.isGroup
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
}
|
|
9
|
+
if (!route.isGroup) {
|
|
10
|
+
if (route.fullPath === path)
|
|
11
|
+
return route;
|
|
12
|
+
}
|
|
13
|
+
else if (route.children) {
|
|
14
|
+
const result = findRoute(route.children, path);
|
|
15
|
+
if (result)
|
|
16
|
+
return result;
|
|
19
17
|
}
|
|
20
18
|
}
|
|
21
19
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitarx-router",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "Official routing solution for Vitarx framework with declarative routing, navigation guards, dynamic routes, file-based routing with HMR, and full TypeScript support.",
|
|
5
5
|
"author": "ZhuChonglin <8210856@qq.com>",
|
|
6
6
|
"license": "MIT",
|