@vitarx/plugin-vite 1.0.1 → 1.0.2-alpha.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.
- package/dist/hmr-client/index.d.ts +15 -5
- package/dist/hmr-client/index.js +47 -25
- package/dist/passes/hmr/inject-imports.d.ts +4 -1
- package/dist/passes/hmr/inject-imports.js +8 -1
- package/dist/passes/hmr/inject-state.d.ts +6 -1
- package/dist/passes/hmr/inject-state.js +58 -5
- package/dist/passes/hmr/inject.d.ts +1 -1
- package/dist/passes/hmr/inject.js +27 -2
- package/dist/passes/imports/collectImports.d.ts +4 -4
- package/dist/passes/imports/collectImports.js +20 -5
- package/dist/passes/imports/collectRefVariables.d.ts +2 -2
- package/dist/passes/imports/collectRefVariables.js +47 -3
- package/dist/passes/imports/injectImports.d.ts +1 -0
- package/dist/passes/imports/injectImports.js +28 -2
- package/dist/transform.js +11 -1
- package/dist/utils/ast-builders.d.ts +49 -41
- package/dist/utils/ast-builders.js +60 -41
- package/dist/utils/ast-guards.d.ts +2 -1
- package/dist/utils/ast-guards.js +4 -1
- package/dist/utils/collect-names.d.ts +13 -4
- package/dist/utils/collect-names.js +38 -4
- package/dist/utils/component-collect.d.ts +4 -2
- package/dist/utils/component-collect.js +181 -6
- package/dist/utils/generate.d.ts +3 -0
- package/dist/utils/generate.js +4 -0
- package/dist/utils/jsx-helpers.d.ts +14 -0
- package/dist/utils/jsx-helpers.js +21 -0
- package/dist/utils/pattern-helpers.d.ts +4 -4
- package/dist/utils/pattern-helpers.js +13 -4
- package/dist/utils/vif-helpers.d.ts +8 -0
- package/dist/utils/vif-helpers.js +36 -0
- package/package.json +1 -1
package/dist/utils/ast-guards.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AST 类型守卫函数
|
|
3
|
-
*
|
|
3
|
+
* 用于判断节点类型和属性
|
|
4
4
|
* @module utils/ast-guards
|
|
5
5
|
*/
|
|
6
6
|
import { isJSXText } from '@babel/types';
|
|
7
7
|
/**
|
|
8
8
|
* 判断 JSXText 是否为纯空白文本
|
|
9
|
+
* 空白文本在渲染时通常需要被过滤掉
|
|
9
10
|
* @param node - AST 节点
|
|
10
11
|
* @returns 是否为纯空白文本
|
|
11
12
|
*/
|
|
12
13
|
export function isWhitespaceJSXText(node) {
|
|
14
|
+
// 先判断是否为 JSXText 类型
|
|
13
15
|
if (!isJSXText(node))
|
|
14
16
|
return false;
|
|
17
|
+
// 使用正则表达式判断是否只包含空白字符
|
|
15
18
|
return /^\s*$/.test(node.value);
|
|
16
19
|
}
|
|
@@ -5,24 +5,33 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type * as t from '@babel/types';
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* 从命名导出声明中收集名称
|
|
9
|
+
* @param node - 命名导出声明节点
|
|
10
|
+
* @param names - 存储名称的集合
|
|
9
11
|
*/
|
|
10
12
|
export declare function collectFromNamedExport(node: t.ExportNamedDeclaration, names: Set<string>): void;
|
|
11
13
|
/**
|
|
12
|
-
*
|
|
14
|
+
* 从默认导出声明中收集名称
|
|
15
|
+
* @param node - 默认导出声明节点
|
|
16
|
+
* @param names - 存储名称的集合
|
|
13
17
|
*/
|
|
14
18
|
export declare function collectFromDefaultExport(node: t.ExportDefaultDeclaration, names: Set<string>): void;
|
|
15
19
|
/**
|
|
16
20
|
* 收集所有导出的标识符名称
|
|
21
|
+
* @param program - AST Program 节点
|
|
22
|
+
* @returns 导出名称集合
|
|
17
23
|
*/
|
|
18
24
|
export declare function collectExportedNames(program: t.Program): Set<string>;
|
|
19
25
|
/**
|
|
20
26
|
* 收集模块中所有绑定的名称(用于避免命名冲突)
|
|
27
|
+
* 包括函数声明、变量声明、导入声明和导出声明
|
|
28
|
+
* @param program - AST Program 节点
|
|
29
|
+
* @returns 所有绑定名称集合
|
|
21
30
|
*/
|
|
22
31
|
export declare function collectAllBindingNames(program: t.Program): Set<string>;
|
|
23
32
|
/**
|
|
24
33
|
* 判断调用表达式是否是 builder 调用
|
|
25
|
-
* @param callExpr -
|
|
34
|
+
* @param callExpr - 调用表达式节点
|
|
26
35
|
* @param builderAlias - builder 的本地别名
|
|
27
36
|
* @returns 是否是 builder 调用
|
|
28
37
|
*/
|
|
@@ -32,6 +41,6 @@ export declare function isBuilderCall(callExpr: t.CallExpression, builderAlias:
|
|
|
32
41
|
* 检测 builder(Comp) 或 builder(Comp, options) 形式的调用
|
|
33
42
|
* @param program - AST Program 节点
|
|
34
43
|
* @param builderAlias - builder 的本地别名
|
|
35
|
-
* @returns 被 builder
|
|
44
|
+
* @returns 被 builder 包装的组件名称集合
|
|
36
45
|
*/
|
|
37
46
|
export declare function collectBuilderWrappedNames(program: t.Program, builderAlias: string | null): Set<string>;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 从命名导出声明中收集名称
|
|
3
|
+
* @param node - 命名导出声明节点
|
|
4
|
+
* @param names - 存储名称的集合
|
|
3
5
|
*/
|
|
4
6
|
export function collectFromNamedExport(node, names) {
|
|
7
|
+
// 处理内联声明(export function/const)
|
|
5
8
|
if (node.declaration) {
|
|
6
9
|
if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
|
|
7
10
|
names.add(node.declaration.id.name);
|
|
@@ -14,6 +17,7 @@ export function collectFromNamedExport(node, names) {
|
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
19
|
}
|
|
20
|
+
// 处理导出说明符(export { a, b })
|
|
17
21
|
if (node.specifiers) {
|
|
18
22
|
for (const spec of node.specifiers) {
|
|
19
23
|
if (spec.type === 'ExportSpecifier') {
|
|
@@ -23,22 +27,29 @@ export function collectFromNamedExport(node, names) {
|
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
/**
|
|
26
|
-
*
|
|
30
|
+
* 从默认导出声明中收集名称
|
|
31
|
+
* @param node - 默认导出声明节点
|
|
32
|
+
* @param names - 存储名称的集合
|
|
27
33
|
*/
|
|
28
34
|
export function collectFromDefaultExport(node, names) {
|
|
29
35
|
const decl = node.declaration;
|
|
36
|
+
// 处理命名函数声明
|
|
30
37
|
if (decl.type === 'FunctionDeclaration' && decl.id) {
|
|
31
38
|
names.add(decl.id.name);
|
|
32
39
|
}
|
|
33
40
|
else if (decl.type === 'Identifier') {
|
|
41
|
+
// 处理标识符引用(export default Component)
|
|
34
42
|
names.add(decl.name);
|
|
35
43
|
}
|
|
36
44
|
}
|
|
37
45
|
/**
|
|
38
46
|
* 从变量声明中收集变量名
|
|
47
|
+
* @param node - 变量声明节点
|
|
48
|
+
* @param names - 存储名称的集合
|
|
39
49
|
*/
|
|
40
50
|
function collectFromVariableDeclaration(node, names) {
|
|
41
51
|
for (const decl of node.declarations) {
|
|
52
|
+
// 只处理简单标识符(不处理解构)
|
|
42
53
|
if (decl.id.type === 'Identifier') {
|
|
43
54
|
names.add(decl.id.name);
|
|
44
55
|
}
|
|
@@ -46,17 +57,23 @@ function collectFromVariableDeclaration(node, names) {
|
|
|
46
57
|
}
|
|
47
58
|
/**
|
|
48
59
|
* 从导入声明中收集绑定的名称
|
|
60
|
+
* @param node - 导入声明节点
|
|
61
|
+
* @param names - 存储名称的集合
|
|
49
62
|
*/
|
|
50
63
|
function collectFromImportDeclaration(node, names) {
|
|
51
64
|
for (const spec of node.specifiers) {
|
|
65
|
+
// 收集本地绑定名称
|
|
52
66
|
names.add(spec.local.name);
|
|
53
67
|
}
|
|
54
68
|
}
|
|
55
69
|
/**
|
|
56
70
|
* 收集所有导出的标识符名称
|
|
71
|
+
* @param program - AST Program 节点
|
|
72
|
+
* @returns 导出名称集合
|
|
57
73
|
*/
|
|
58
74
|
export function collectExportedNames(program) {
|
|
59
75
|
const names = new Set();
|
|
76
|
+
// 遍历程序体中的所有节点
|
|
60
77
|
for (const node of program.body) {
|
|
61
78
|
if (node.type === 'ExportNamedDeclaration') {
|
|
62
79
|
collectFromNamedExport(node, names);
|
|
@@ -69,23 +86,32 @@ export function collectExportedNames(program) {
|
|
|
69
86
|
}
|
|
70
87
|
/**
|
|
71
88
|
* 收集模块中所有绑定的名称(用于避免命名冲突)
|
|
89
|
+
* 包括函数声明、变量声明、导入声明和导出声明
|
|
90
|
+
* @param program - AST Program 节点
|
|
91
|
+
* @returns 所有绑定名称集合
|
|
72
92
|
*/
|
|
73
93
|
export function collectAllBindingNames(program) {
|
|
74
94
|
const names = new Set();
|
|
95
|
+
// 遍历程序体中的所有节点
|
|
75
96
|
for (const node of program.body) {
|
|
97
|
+
// 函数声明
|
|
76
98
|
if (node.type === 'FunctionDeclaration' && node.id) {
|
|
77
99
|
names.add(node.id.name);
|
|
78
100
|
}
|
|
79
101
|
else if (node.type === 'VariableDeclaration') {
|
|
102
|
+
// 变量声明
|
|
80
103
|
collectFromVariableDeclaration(node, names);
|
|
81
104
|
}
|
|
82
105
|
else if (node.type === 'ImportDeclaration') {
|
|
106
|
+
// 导入声明
|
|
83
107
|
collectFromImportDeclaration(node, names);
|
|
84
108
|
}
|
|
85
109
|
else if (node.type === 'ExportNamedDeclaration') {
|
|
110
|
+
// 命名导出
|
|
86
111
|
collectFromNamedExport(node, names);
|
|
87
112
|
}
|
|
88
113
|
else if (node.type === 'ExportDefaultDeclaration') {
|
|
114
|
+
// 默认导出
|
|
89
115
|
collectFromDefaultExport(node, names);
|
|
90
116
|
}
|
|
91
117
|
}
|
|
@@ -93,14 +119,16 @@ export function collectAllBindingNames(program) {
|
|
|
93
119
|
}
|
|
94
120
|
/**
|
|
95
121
|
* 判断调用表达式是否是 builder 调用
|
|
96
|
-
* @param callExpr -
|
|
122
|
+
* @param callExpr - 调用表达式节点
|
|
97
123
|
* @param builderAlias - builder 的本地别名
|
|
98
124
|
* @returns 是否是 builder 调用
|
|
99
125
|
*/
|
|
100
126
|
export function isBuilderCall(callExpr, builderAlias) {
|
|
127
|
+
// 如果没有配置 builder 别名,直接返回 false
|
|
101
128
|
if (!builderAlias)
|
|
102
129
|
return false;
|
|
103
130
|
const callee = callExpr.callee;
|
|
131
|
+
// 检查调用者是否为标识符且名称匹配
|
|
104
132
|
return callee.type === 'Identifier' && callee.name === builderAlias;
|
|
105
133
|
}
|
|
106
134
|
/**
|
|
@@ -108,13 +136,16 @@ export function isBuilderCall(callExpr, builderAlias) {
|
|
|
108
136
|
* 检测 builder(Comp) 或 builder(Comp, options) 形式的调用
|
|
109
137
|
* @param program - AST Program 节点
|
|
110
138
|
* @param builderAlias - builder 的本地别名
|
|
111
|
-
* @returns 被 builder
|
|
139
|
+
* @returns 被 builder 包装的组件名称集合
|
|
112
140
|
*/
|
|
113
141
|
export function collectBuilderWrappedNames(program, builderAlias) {
|
|
114
142
|
const wrappedNames = new Set();
|
|
143
|
+
// 如果没有配置 builder 别名,直接返回空集合
|
|
115
144
|
if (!builderAlias)
|
|
116
145
|
return wrappedNames;
|
|
146
|
+
// 遍历程序体中的所有节点
|
|
117
147
|
for (const node of program.body) {
|
|
148
|
+
// 处理独立调用语句:builder(Comp)
|
|
118
149
|
if (node.type === 'ExpressionStatement' && node.expression.type === 'CallExpression') {
|
|
119
150
|
const callExpr = node.expression;
|
|
120
151
|
if (isBuilderCall(callExpr, builderAlias)) {
|
|
@@ -125,6 +156,7 @@ export function collectBuilderWrappedNames(program, builderAlias) {
|
|
|
125
156
|
}
|
|
126
157
|
}
|
|
127
158
|
else if (node.type === 'ExportDefaultDeclaration' && node.declaration.type === 'CallExpression') {
|
|
159
|
+
// 处理默认导出:export default builder(Comp)
|
|
128
160
|
const callExpr = node.declaration;
|
|
129
161
|
if (isBuilderCall(callExpr, builderAlias)) {
|
|
130
162
|
const arg = callExpr.arguments[0];
|
|
@@ -134,6 +166,7 @@ export function collectBuilderWrappedNames(program, builderAlias) {
|
|
|
134
166
|
}
|
|
135
167
|
}
|
|
136
168
|
else if (node.type === 'VariableDeclaration') {
|
|
169
|
+
// 处理变量声明:const Comp = builder(CompImpl)
|
|
137
170
|
for (const decl of node.declarations) {
|
|
138
171
|
if (decl.init?.type === 'CallExpression' && isBuilderCall(decl.init, builderAlias)) {
|
|
139
172
|
const arg = decl.init.arguments[0];
|
|
@@ -144,6 +177,7 @@ export function collectBuilderWrappedNames(program, builderAlias) {
|
|
|
144
177
|
}
|
|
145
178
|
}
|
|
146
179
|
else if (node.type === 'ExportNamedDeclaration' && node.declaration?.type === 'VariableDeclaration') {
|
|
180
|
+
// 处理命名导出:export const Comp = builder(CompImpl)
|
|
147
181
|
for (const decl of node.declaration.declarations) {
|
|
148
182
|
if (decl.init?.type === 'CallExpression' && isBuilderCall(decl.init, builderAlias)) {
|
|
149
183
|
const arg = decl.init.arguments[0];
|
|
@@ -5,16 +5,18 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as t from '@babel/types';
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* 组件信息接口
|
|
9
|
+
* 描述从 AST 中提取的组件函数信息
|
|
9
10
|
*/
|
|
10
11
|
export interface ComponentInfo {
|
|
11
12
|
name: string;
|
|
12
13
|
node: t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression;
|
|
13
|
-
/** 是否为包装组件(传递给 builder
|
|
14
|
+
/** 是否为包装组件(传递给 builder 函数) */
|
|
14
15
|
isWrapped?: boolean;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* 收集模块中的组件函数
|
|
19
|
+
* 遍历 AST 程序节点,提取所有导出的组件函数
|
|
18
20
|
* @param program - AST Program 节点
|
|
19
21
|
* @param builderAlias - builder 函数的本地别名(用于识别纯构建组件)
|
|
20
22
|
* @returns 组件信息数组
|
|
@@ -5,56 +5,121 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as t from '@babel/types';
|
|
7
7
|
import { DEFAULT_EXPORT_BASE_NAME } from '../constants/index.js';
|
|
8
|
+
// 导入名称收集相关工具函数
|
|
9
|
+
import { collectAllBindingNames, collectBuilderWrappedNames, collectExportedNames, isBuilderCall } from './collect-names.js';
|
|
8
10
|
import { generateUniqueAlias } from './generate.js';
|
|
9
|
-
import { collectExportedNames, collectAllBindingNames, collectBuilderWrappedNames, isBuilderCall } from './collect-names.js';
|
|
10
11
|
/**
|
|
11
12
|
* 生成唯一的默认导出组件名称
|
|
12
13
|
* 避免与已存在的名称冲突
|
|
13
14
|
*/
|
|
14
15
|
function generateUniqueDefaultName(exportedNames) {
|
|
16
|
+
// 如果默认名称未被占用,直接返回
|
|
15
17
|
if (!exportedNames.has(DEFAULT_EXPORT_BASE_NAME)) {
|
|
16
18
|
return DEFAULT_EXPORT_BASE_NAME;
|
|
17
19
|
}
|
|
20
|
+
// 否则生成唯一别名
|
|
18
21
|
return generateUniqueAlias(DEFAULT_EXPORT_BASE_NAME, exportedNames);
|
|
19
22
|
}
|
|
20
23
|
/**
|
|
21
24
|
* 检查名称是否为有效的组件名称
|
|
22
|
-
*
|
|
25
|
+
* 必须以大写字母开头(符合 React/Vue 组件命名规范)
|
|
23
26
|
*/
|
|
24
27
|
function isValidComponentName(name) {
|
|
28
|
+
// 使用正则表达式检查首字母是否为大写
|
|
25
29
|
return /^[A-Z]/.test(name);
|
|
26
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* 尝试添加组件信息到组件列表中
|
|
33
|
+
*
|
|
34
|
+
* @param name 组件名称
|
|
35
|
+
* @param node 函数声明节点,可以是函数声明、箭头函数表达式或函数表达式
|
|
36
|
+
* @param exportedNames 已导出的名称集合
|
|
37
|
+
* @param components 组件信息数组,用于存储符合条件的组件信息
|
|
38
|
+
* @param builderWrappedNames 已被包装器包装的函数名称集合,默认为空集合
|
|
39
|
+
*/
|
|
27
40
|
function tryAddComponent(name, node, exportedNames, components, builderWrappedNames = new Set()) {
|
|
41
|
+
// 检查组件名称是否有效(大写开头)且是否已导出
|
|
28
42
|
if (isValidComponentName(name) && exportedNames.has(name)) {
|
|
43
|
+
// 判断组件是否已被 builder/defineComponent 等包装器包装
|
|
29
44
|
const isWrapped = builderWrappedNames.has(name);
|
|
45
|
+
// 将组件信息添加到组件数组中
|
|
30
46
|
components.push({ name, node, isWrapped });
|
|
31
47
|
}
|
|
32
48
|
}
|
|
33
49
|
/**
|
|
34
50
|
* 处理变量声明中的组件
|
|
51
|
+
* 提取变量赋值中的箭头函数、函数表达式或 builder 包装调用作为组件
|
|
52
|
+
* @param declaration - 变量声明节点
|
|
53
|
+
* @param exportedNames - 已导出的名称集合
|
|
54
|
+
* @param components - 组件信息数组
|
|
55
|
+
* @param builderWrappedNames - 已被包装器包装的函数名称集合
|
|
56
|
+
* @param program - AST Program 节点,用于插入提取的函数声明
|
|
57
|
+
* @param builderAlias - builder 的本地别名
|
|
58
|
+
* @param allBindingNames - 所有绑定名称集合(用于生成唯一名称时避免冲突)
|
|
35
59
|
*/
|
|
36
|
-
function processVariableDeclaration(declaration, exportedNames, components, builderWrappedNames = new Set()) {
|
|
60
|
+
function processVariableDeclaration(declaration, exportedNames, components, builderWrappedNames = new Set(), program, builderAlias, allBindingNames) {
|
|
61
|
+
// 遍历变量声明中的每个声明
|
|
37
62
|
for (const decl of declaration.declarations) {
|
|
63
|
+
// 跳过非标识符的变量名(如解构赋值)
|
|
38
64
|
if (decl.id.type !== 'Identifier')
|
|
39
65
|
continue;
|
|
40
66
|
const init = decl.init;
|
|
41
67
|
if (init?.type === 'ArrowFunctionExpression' || init?.type === 'FunctionExpression') {
|
|
68
|
+
// 检查初始值是否为箭头函数或函数表达式
|
|
42
69
|
tryAddComponent(decl.id.name, init, exportedNames, components, builderWrappedNames);
|
|
43
70
|
}
|
|
71
|
+
else if (init?.type === 'CallExpression' &&
|
|
72
|
+
program &&
|
|
73
|
+
builderAlias != null &&
|
|
74
|
+
allBindingNames) {
|
|
75
|
+
// 处理 builder 包装的变量声明:const App = builder(() => <div/>)
|
|
76
|
+
// 仅处理已导出且名称合法的变量
|
|
77
|
+
if (!isValidComponentName(decl.id.name) || !exportedNames.has(decl.id.name))
|
|
78
|
+
continue;
|
|
79
|
+
const result = extractFunctionFromVariableInit(init, decl.id.name, allBindingNames, builderAlias);
|
|
80
|
+
if (result) {
|
|
81
|
+
// 找到包含该变量声明的语句在 program.body 中的位置
|
|
82
|
+
const stmtIndex = program.body.findIndex(stmt => {
|
|
83
|
+
if (stmt === declaration)
|
|
84
|
+
return true;
|
|
85
|
+
// 变量声明可能在 ExportNamedDeclaration 内部
|
|
86
|
+
return stmt.type === 'ExportNamedDeclaration' && stmt.declaration === declaration;
|
|
87
|
+
});
|
|
88
|
+
// 将提取的函数声明插入到变量声明之前
|
|
89
|
+
if (stmtIndex !== -1) {
|
|
90
|
+
program.body.splice(stmtIndex, 0, result.funcNode);
|
|
91
|
+
}
|
|
92
|
+
// 直接添加为包装组件(不经过 tryAddComponent,因为内部函数名不在 exportedNames 中)
|
|
93
|
+
components.push({
|
|
94
|
+
name: result.name,
|
|
95
|
+
node: result.funcNode,
|
|
96
|
+
isWrapped: result.isBuilderWrapped
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
44
100
|
}
|
|
45
101
|
}
|
|
46
102
|
/**
|
|
47
103
|
* 将函数表达式或箭头函数转换为命名函数声明
|
|
104
|
+
* 用于将匿名函数转换为可追踪的命名函数
|
|
48
105
|
*/
|
|
49
106
|
function convertToNamedFunctionDeclaration(func, name) {
|
|
50
107
|
let body;
|
|
108
|
+
// 处理箭头函数的隐式返回:将表达式体包装为显式 return 语句
|
|
51
109
|
if (func.type === 'ArrowFunctionExpression' && func.body.type !== 'BlockStatement') {
|
|
52
110
|
body = t.blockStatement([t.returnStatement(func.body)]);
|
|
53
111
|
}
|
|
54
112
|
else {
|
|
55
113
|
body = func.body;
|
|
56
114
|
}
|
|
57
|
-
|
|
115
|
+
// 创建函数声明节点
|
|
116
|
+
const funcDecl = t.functionDeclaration(t.identifier(name), // 函数名称
|
|
117
|
+
func.params, // 参数列表
|
|
118
|
+
body, // 函数体
|
|
119
|
+
func.type === 'FunctionExpression' ? func.generator : false, // 是否为生成器
|
|
120
|
+
func.async // 是否为异步函数
|
|
121
|
+
);
|
|
122
|
+
// 保留原始位置信息用于源码映射
|
|
58
123
|
funcDecl.loc = func.loc;
|
|
59
124
|
return funcDecl;
|
|
60
125
|
}
|
|
@@ -69,16 +134,56 @@ function convertToNamedFunctionDeclaration(func, name) {
|
|
|
69
134
|
* @returns 提取结果,包含名称、函数声明节点和是否是 builder 包装
|
|
70
135
|
*/
|
|
71
136
|
function extractFunctionFromCallExpression(callExpr, exportedNames, builderAlias) {
|
|
137
|
+
// 判断是否为 builder 函数调用
|
|
72
138
|
const isBuilder = isBuilderCall(callExpr, builderAlias);
|
|
139
|
+
// 遍历调用表达式的所有参数
|
|
73
140
|
for (let i = 0; i < callExpr.arguments.length; i++) {
|
|
74
141
|
const arg = callExpr.arguments[i];
|
|
142
|
+
// 找到作为参数传入的匿名函数
|
|
75
143
|
if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
|
|
144
|
+
// 生成唯一名称
|
|
76
145
|
const name = generateUniqueDefaultName(exportedNames);
|
|
146
|
+
// 转换为命名函数声明
|
|
147
|
+
const funcNode = convertToNamedFunctionDeclaration(arg, name);
|
|
148
|
+
// 将原参数替换为标识符引用
|
|
149
|
+
callExpr.arguments[i] = t.identifier(name);
|
|
150
|
+
return { name, funcNode, isBuilderWrapped: isBuilder };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// 未找到可提取的函数参数
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 从变量声明的调用表达式中提取函数
|
|
158
|
+
* 将 const App = builder(() => <div/>) 转换为:
|
|
159
|
+
* function App$1() { return <div/> }
|
|
160
|
+
* const App = builder(App$1)
|
|
161
|
+
* @param callExpr - 调用表达式
|
|
162
|
+
* @param variableName - 变量名(作为内部函数名的基础)
|
|
163
|
+
* @param allBindingNames - 所有绑定名称集合(用于避免命名冲突)
|
|
164
|
+
* @param builderAlias - builder 的本地别名
|
|
165
|
+
* @returns 提取结果,包含名称、函数声明节点和是否是 builder 包装
|
|
166
|
+
*/
|
|
167
|
+
function extractFunctionFromVariableInit(callExpr, variableName, allBindingNames, builderAlias) {
|
|
168
|
+
// 判断是否为 builder 函数调用
|
|
169
|
+
const isBuilder = isBuilderCall(callExpr, builderAlias);
|
|
170
|
+
// 遍历调用表达式的所有参数
|
|
171
|
+
for (let i = 0; i < callExpr.arguments.length; i++) {
|
|
172
|
+
const arg = callExpr.arguments[i];
|
|
173
|
+
// 找到作为参数传入的匿名函数
|
|
174
|
+
if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
|
|
175
|
+
// 以变量名为基础生成唯一别名,避免与已有名称冲突
|
|
176
|
+
const name = generateUniqueAlias(variableName, allBindingNames);
|
|
177
|
+
// 将新名称加入集合,防止后续生成重复名称
|
|
178
|
+
allBindingNames.add(name);
|
|
179
|
+
// 转换为命名函数声明
|
|
77
180
|
const funcNode = convertToNamedFunctionDeclaration(arg, name);
|
|
181
|
+
// 将原参数替换为标识符引用
|
|
78
182
|
callExpr.arguments[i] = t.identifier(name);
|
|
79
183
|
return { name, funcNode, isBuilderWrapped: isBuilder };
|
|
80
184
|
}
|
|
81
185
|
}
|
|
186
|
+
// 未找到可提取的函数参数
|
|
82
187
|
return null;
|
|
83
188
|
}
|
|
84
189
|
/**
|
|
@@ -95,69 +200,139 @@ function processAnonymousDefaultExport(node, program, exportedNames, components,
|
|
|
95
200
|
let funcNode = null;
|
|
96
201
|
let name;
|
|
97
202
|
let isWrapped = false;
|
|
203
|
+
// 处理无名称的函数声明 export default function() {}
|
|
98
204
|
if (decl.type === 'FunctionDeclaration' && !decl.id) {
|
|
99
205
|
name = generateUniqueDefaultName(exportedNames);
|
|
100
206
|
decl.id = t.identifier(name);
|
|
101
207
|
funcNode = decl;
|
|
102
208
|
}
|
|
103
209
|
else if (decl.type === 'FunctionExpression') {
|
|
210
|
+
// 处理函数表达式 export default function() {}
|
|
104
211
|
name = generateUniqueDefaultName(exportedNames);
|
|
105
212
|
funcNode = convertToNamedFunctionDeclaration(decl, name);
|
|
106
213
|
node.declaration = funcNode;
|
|
107
214
|
}
|
|
108
215
|
else if (decl.type === 'ArrowFunctionExpression') {
|
|
216
|
+
// 处理箭头函数 export default () => {}
|
|
109
217
|
name = generateUniqueDefaultName(exportedNames);
|
|
110
218
|
funcNode = convertToNamedFunctionDeclaration(decl, name);
|
|
111
219
|
node.declaration = funcNode;
|
|
112
220
|
}
|
|
113
221
|
else if (decl.type === 'CallExpression') {
|
|
222
|
+
// 处理包装调用 export default builder(() => {})
|
|
114
223
|
const result = extractFunctionFromCallExpression(decl, exportedNames, builderAlias);
|
|
115
224
|
if (result) {
|
|
116
225
|
name = result.name;
|
|
117
226
|
funcNode = result.funcNode;
|
|
118
227
|
isWrapped = result.isBuilderWrapped;
|
|
228
|
+
// 将提取的函数声明插入到导出语句之前
|
|
119
229
|
const exportIndex = program.body.indexOf(node);
|
|
120
230
|
if (exportIndex !== -1) {
|
|
121
231
|
program.body.splice(exportIndex, 0, funcNode);
|
|
122
232
|
}
|
|
123
233
|
}
|
|
124
234
|
}
|
|
235
|
+
// 如果成功提取到函数节点,添加到组件列表
|
|
125
236
|
if (funcNode) {
|
|
126
237
|
components.push({ name: name, node: funcNode, isWrapped });
|
|
127
238
|
}
|
|
128
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* 在 program.body 中查找指定名称的变量声明
|
|
242
|
+
* 用于处理 export default X 场景,追溯标识符对应的变量声明
|
|
243
|
+
* @param program - AST Program 节点
|
|
244
|
+
* @param name - 要查找的变量名
|
|
245
|
+
* @returns 包含变量声明和所在语句的对象,未找到返回 null
|
|
246
|
+
*/
|
|
247
|
+
function findVariableDeclaration(program, name) {
|
|
248
|
+
for (const stmt of program.body) {
|
|
249
|
+
// 查找普通变量声明
|
|
250
|
+
if (stmt.type === 'VariableDeclaration') {
|
|
251
|
+
for (const decl of stmt.declarations) {
|
|
252
|
+
if (decl.id.type === 'Identifier' && decl.id.name === name) {
|
|
253
|
+
return { decl, statement: stmt };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// 查找命名导出中的变量声明
|
|
258
|
+
if (stmt.type === 'ExportNamedDeclaration' &&
|
|
259
|
+
stmt.declaration?.type === 'VariableDeclaration') {
|
|
260
|
+
for (const decl of stmt.declaration.declarations) {
|
|
261
|
+
if (decl.id.type === 'Identifier' && decl.id.name === name) {
|
|
262
|
+
return { decl, statement: stmt };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
129
269
|
/**
|
|
130
270
|
* 收集模块中的组件函数
|
|
271
|
+
* 遍历 AST 程序节点,提取所有导出的组件函数
|
|
131
272
|
* @param program - AST Program 节点
|
|
132
273
|
* @param builderAlias - builder 函数的本地别名(用于识别纯构建组件)
|
|
133
274
|
* @returns 组件信息数组
|
|
134
275
|
*/
|
|
135
276
|
export function collectComponentFunctions(program, builderAlias = null) {
|
|
277
|
+
// 收集所有已导出的名称
|
|
136
278
|
const exportedNames = collectExportedNames(program);
|
|
279
|
+
// 收集所有绑定名称(用于生成唯一名称时避免冲突)
|
|
137
280
|
const allBindingNames = collectAllBindingNames(program);
|
|
281
|
+
// 收集被 builder 包装的函数名称
|
|
138
282
|
const builderWrappedNames = collectBuilderWrappedNames(program, builderAlias);
|
|
283
|
+
// 存储收集到的组件信息
|
|
139
284
|
const components = [];
|
|
285
|
+
// 遍历程序体中的所有节点
|
|
140
286
|
for (const node of program.body) {
|
|
287
|
+
// 处理普通函数声明 function Component() {}
|
|
141
288
|
if (node.type === 'FunctionDeclaration' && node.id) {
|
|
142
289
|
tryAddComponent(node.id.name, node, exportedNames, components, builderWrappedNames);
|
|
143
290
|
}
|
|
144
291
|
else if (node.type === 'VariableDeclaration') {
|
|
145
|
-
|
|
292
|
+
// 处理变量声明 const Component = () => {} 或 const App = builder(() => {})
|
|
293
|
+
processVariableDeclaration(node, exportedNames, components, builderWrappedNames, program, builderAlias, allBindingNames);
|
|
146
294
|
}
|
|
147
295
|
else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
|
|
296
|
+
// 处理命名导出 export function Component() {} 或 export const Component = () => {}
|
|
148
297
|
if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
|
|
149
298
|
tryAddComponent(node.declaration.id.name, node.declaration, exportedNames, components, builderWrappedNames);
|
|
150
299
|
}
|
|
151
300
|
else if (node.declaration.type === 'VariableDeclaration') {
|
|
152
|
-
|
|
301
|
+
// 处理变量声明 const Component = () => {} 或 const App = builder(() => {})
|
|
302
|
+
processVariableDeclaration(node.declaration, exportedNames, components, builderWrappedNames, program, builderAlias, allBindingNames);
|
|
153
303
|
}
|
|
154
304
|
}
|
|
155
305
|
else if (node.type === 'ExportDefaultDeclaration') {
|
|
306
|
+
// 处理默认导出 export default Component 或 export default () => {}
|
|
156
307
|
const decl = node.declaration;
|
|
157
308
|
if (decl.type === 'FunctionDeclaration' && decl.id) {
|
|
309
|
+
// 处理具名函数默认导出 export default function Component() {}
|
|
158
310
|
tryAddComponent(decl.id.name, decl, exportedNames, components, builderWrappedNames);
|
|
159
311
|
}
|
|
312
|
+
else if (decl.type === 'Identifier') {
|
|
313
|
+
// 处理标识符默认导出 export default X
|
|
314
|
+
// 追溯标识符对应的变量声明,判断是否为 builder 包装组件
|
|
315
|
+
if (isValidComponentName(decl.name) && exportedNames.has(decl.name)) {
|
|
316
|
+
const varDecl = findVariableDeclaration(program, decl.name);
|
|
317
|
+
if (varDecl?.decl.init?.type === 'CallExpression') {
|
|
318
|
+
const result = extractFunctionFromVariableInit(varDecl.decl.init, decl.name, allBindingNames, builderAlias);
|
|
319
|
+
if (result) {
|
|
320
|
+
// 将提取的函数声明插入到变量声明所在语句之前
|
|
321
|
+
const stmtIndex = program.body.indexOf(varDecl.statement);
|
|
322
|
+
if (stmtIndex !== -1) {
|
|
323
|
+
program.body.splice(stmtIndex, 0, result.funcNode);
|
|
324
|
+
}
|
|
325
|
+
components.push({
|
|
326
|
+
name: result.name,
|
|
327
|
+
node: result.funcNode,
|
|
328
|
+
isWrapped: result.isBuilderWrapped
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
160
334
|
else {
|
|
335
|
+
// 处理匿名默认导出
|
|
161
336
|
processAnonymousDefaultExport(node, program, allBindingNames, components, builderAlias);
|
|
162
337
|
}
|
|
163
338
|
}
|
package/dist/utils/generate.d.ts
CHANGED
package/dist/utils/generate.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 生成唯一的别名
|
|
3
3
|
* 从 $1 开始递增,直到找到不冲突的名称
|
|
4
|
+
* @param baseName - 基础名称
|
|
5
|
+
* @param existingNames - 已存在的名称集合(用于冲突检测)
|
|
6
|
+
* @returns 唯一的别名
|
|
4
7
|
*/
|
|
5
8
|
export function generateUniqueAlias(baseName, existingNames) {
|
|
6
9
|
let index = 1;
|
|
10
|
+
// 循环查找不冲突的名称
|
|
7
11
|
while (existingNames.has(`${baseName}$${index}`)) {
|
|
8
12
|
index++;
|
|
9
13
|
}
|
|
@@ -1,29 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JSX 相关工具函数
|
|
3
|
+
* 提供 JSX 元素的各种操作和判断方法
|
|
3
4
|
* @module utils/jsx-helpers
|
|
4
5
|
*/
|
|
5
6
|
import * as t from '@babel/types';
|
|
6
7
|
import { type Expression, type JSXAttribute, type JSXElement } from '@babel/types';
|
|
7
8
|
/**
|
|
8
9
|
* 获取 JSX 元素的名称
|
|
10
|
+
* @param node - JSX 元素节点
|
|
11
|
+
* @returns 元素名称(Identifier)或 null(MemberExpression)
|
|
9
12
|
*/
|
|
10
13
|
export declare function getJSXElementName(node: JSXElement): string | null;
|
|
11
14
|
/**
|
|
12
15
|
* 将 JSX 元素名称节点转换为 createView 的类型表达式
|
|
13
16
|
* JSXIdentifier → Identifier(组件)或 StringLiteral(原生元素)
|
|
14
17
|
* JSXMemberExpression → MemberExpression(如 Obj.Key → Obj.Key)
|
|
18
|
+
* @param node - JSX 元素节点
|
|
19
|
+
* @returns 类型表达式或 null
|
|
15
20
|
*/
|
|
16
21
|
export declare function resolveJSXElementType(node: JSXElement): t.Expression | null;
|
|
17
22
|
/**
|
|
18
23
|
* 判断名称是否为纯编译组件
|
|
24
|
+
* 纯编译组件在编译时完全展开,不会生成运行时调用
|
|
25
|
+
* @param name - 元素名称
|
|
26
|
+
* @returns 是否为纯编译组件
|
|
19
27
|
*/
|
|
20
28
|
export declare function isPureCompileComponent(name: string): boolean;
|
|
21
29
|
/**
|
|
22
30
|
* 判断名称是否为组件(首字母大写)
|
|
31
|
+
* 遵循 React/Vue 的组件命名约定
|
|
32
|
+
* @param name - 元素名称
|
|
33
|
+
* @returns 是否为组件
|
|
23
34
|
*/
|
|
24
35
|
export declare function isComponent(name: string): boolean;
|
|
25
36
|
/**
|
|
26
37
|
* 判断名称是否为原生元素
|
|
38
|
+
* 原生元素使用小写字母开头
|
|
39
|
+
* @param name - 元素名称
|
|
40
|
+
* @returns 是否为原生元素
|
|
27
41
|
*/
|
|
28
42
|
export declare function isNativeElement(name: string): boolean;
|
|
29
43
|
/**
|