@vitarx/plugin-vite 1.0.4 → 1.0.5
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/passes/directives/processDirectives.d.ts +1 -1
- package/dist/passes/directives/processDirectives.js +15 -10
- package/dist/passes/hmr/inject-state.d.ts +1 -1
- package/dist/passes/hmr/inject-state.js +38 -57
- package/dist/passes/imports/collectRefVariables.d.ts +1 -0
- package/dist/passes/imports/collectRefVariables.js +52 -19
- package/dist/passes/jsx/processJSXFragment.js +18 -1
- package/dist/passes/props/attribute.d.ts +3 -0
- package/dist/passes/props/attribute.js +13 -3
- package/dist/transform.js +5 -1
- package/dist/types.d.ts +1 -1
- package/dist/utils/branch-factory.js +26 -6
- package/dist/utils/component-collect.d.ts +7 -0
- package/dist/utils/component-collect.js +12 -236
- package/dist/utils/default-export.d.ts +38 -0
- package/dist/utils/default-export.js +119 -0
- package/dist/utils/function-extract.d.ts +45 -0
- package/dist/utils/function-extract.js +98 -0
- package/dist/utils/generate.d.ts +7 -0
- package/dist/utils/generate.js +20 -0
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +2 -2
- package/dist/utils/jsx-helpers.d.ts +1 -4
- package/dist/utils/jsx-helpers.js +2 -15
- package/dist/utils/vif-helpers.js +6 -3
- package/package.json +2 -2
|
@@ -1,48 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 组件收集模块
|
|
3
|
-
* 负责从 AST 中收集组件函数信息
|
|
4
|
-
* @module utils/component-collect
|
|
5
|
-
*/
|
|
6
|
-
import * as t from '@babel/types';
|
|
7
|
-
import { DEFAULT_EXPORT_BASE_NAME } from '../constants/index.js';
|
|
8
1
|
// 导入名称收集相关工具函数
|
|
9
|
-
import { collectAllBindingNames, collectBuilderWrappedNames, collectExportedNames
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
* 生成唯一的默认导出组件名称
|
|
13
|
-
* 避免与已存在的名称冲突
|
|
14
|
-
*/
|
|
15
|
-
function generateUniqueDefaultName(exportedNames) {
|
|
16
|
-
// 如果默认名称未被占用,直接返回
|
|
17
|
-
if (!exportedNames.has(DEFAULT_EXPORT_BASE_NAME)) {
|
|
18
|
-
return DEFAULT_EXPORT_BASE_NAME;
|
|
19
|
-
}
|
|
20
|
-
// 否则生成唯一别名
|
|
21
|
-
return generateUniqueAlias(DEFAULT_EXPORT_BASE_NAME, exportedNames);
|
|
22
|
-
}
|
|
2
|
+
import { collectAllBindingNames, collectBuilderWrappedNames, collectExportedNames } from './collect-names.js';
|
|
3
|
+
import { extractFunctionFromVariableInit } from './function-extract.js';
|
|
4
|
+
import { processAnonymousDefaultExport, processIdentifierDefaultExport } from './default-export.js';
|
|
23
5
|
/**
|
|
24
6
|
* 检查名称是否为有效的组件名称
|
|
25
7
|
* 必须以大写字母开头(符合 React/Vue 组件命名规范)
|
|
8
|
+
* @param name - 待检查的名称
|
|
9
|
+
* @returns 是否为有效组件名称
|
|
26
10
|
*/
|
|
27
|
-
function isValidComponentName(name) {
|
|
28
|
-
// 使用正则表达式检查首字母是否为大写
|
|
11
|
+
export function isValidComponentName(name) {
|
|
29
12
|
return /^[A-Z]/.test(name);
|
|
30
13
|
}
|
|
31
14
|
/**
|
|
32
15
|
* 尝试添加组件信息到组件列表中
|
|
33
|
-
*
|
|
34
|
-
* @param
|
|
35
|
-
* @param
|
|
36
|
-
* @param
|
|
37
|
-
* @param
|
|
38
|
-
* @param builderWrappedNames 已被包装器包装的函数名称集合,默认为空集合
|
|
16
|
+
* @param name - 组件名称
|
|
17
|
+
* @param node - 函数声明节点
|
|
18
|
+
* @param exportedNames - 已导出的名称集合
|
|
19
|
+
* @param components - 组件信息数组
|
|
20
|
+
* @param builderWrappedNames - 已被包装器包装的函数名称集合
|
|
39
21
|
*/
|
|
40
22
|
function tryAddComponent(name, node, exportedNames, components, builderWrappedNames = new Set()) {
|
|
41
23
|
// 检查组件名称是否有效(大写开头)且是否已导出
|
|
42
24
|
if (isValidComponentName(name) && exportedNames.has(name)) {
|
|
43
|
-
// 判断组件是否已被 builder/defineComponent 等包装器包装
|
|
44
25
|
const isWrapped = builderWrappedNames.has(name);
|
|
45
|
-
// 将组件信息添加到组件数组中
|
|
46
26
|
components.push({ name, node, isWrapped });
|
|
47
27
|
}
|
|
48
28
|
}
|
|
@@ -58,14 +38,12 @@ function tryAddComponent(name, node, exportedNames, components, builderWrappedNa
|
|
|
58
38
|
* @param allBindingNames - 所有绑定名称集合(用于生成唯一名称时避免冲突)
|
|
59
39
|
*/
|
|
60
40
|
function processVariableDeclaration(declaration, exportedNames, components, builderWrappedNames = new Set(), program, builderAlias, allBindingNames) {
|
|
61
|
-
// 遍历变量声明中的每个声明
|
|
62
41
|
for (const decl of declaration.declarations) {
|
|
63
42
|
// 跳过非标识符的变量名(如解构赋值)
|
|
64
43
|
if (decl.id.type !== 'Identifier')
|
|
65
44
|
continue;
|
|
66
45
|
const init = decl.init;
|
|
67
46
|
if (init?.type === 'ArrowFunctionExpression' || init?.type === 'FunctionExpression') {
|
|
68
|
-
// 检查初始值是否为箭头函数或函数表达式
|
|
69
47
|
tryAddComponent(decl.id.name, init, exportedNames, components, builderWrappedNames);
|
|
70
48
|
}
|
|
71
49
|
else if (init?.type === 'CallExpression' &&
|
|
@@ -73,7 +51,6 @@ function processVariableDeclaration(declaration, exportedNames, components, buil
|
|
|
73
51
|
builderAlias != null &&
|
|
74
52
|
allBindingNames) {
|
|
75
53
|
// 处理 builder 包装的变量声明:const App = builder(() => <div/>)
|
|
76
|
-
// 仅处理已导出且名称合法的变量
|
|
77
54
|
if (!isValidComponentName(decl.id.name) || !exportedNames.has(decl.id.name))
|
|
78
55
|
continue;
|
|
79
56
|
const result = extractFunctionFromVariableInit(init, decl.id.name, allBindingNames, builderAlias);
|
|
@@ -82,14 +59,11 @@ function processVariableDeclaration(declaration, exportedNames, components, buil
|
|
|
82
59
|
const stmtIndex = program.body.findIndex(stmt => {
|
|
83
60
|
if (stmt === declaration)
|
|
84
61
|
return true;
|
|
85
|
-
// 变量声明可能在 ExportNamedDeclaration 内部
|
|
86
62
|
return stmt.type === 'ExportNamedDeclaration' && stmt.declaration === declaration;
|
|
87
63
|
});
|
|
88
|
-
// 将提取的函数声明插入到变量声明之前
|
|
89
64
|
if (stmtIndex !== -1) {
|
|
90
65
|
program.body.splice(stmtIndex, 0, result.funcNode);
|
|
91
66
|
}
|
|
92
|
-
// 直接添加为包装组件(不经过 tryAddComponent,因为内部函数名不在 exportedNames 中)
|
|
93
67
|
components.push({
|
|
94
68
|
name: result.name,
|
|
95
69
|
node: result.funcNode,
|
|
@@ -99,173 +73,6 @@ function processVariableDeclaration(declaration, exportedNames, components, buil
|
|
|
99
73
|
}
|
|
100
74
|
}
|
|
101
75
|
}
|
|
102
|
-
/**
|
|
103
|
-
* 将函数表达式或箭头函数转换为命名函数声明
|
|
104
|
-
* 用于将匿名函数转换为可追踪的命名函数
|
|
105
|
-
*/
|
|
106
|
-
function convertToNamedFunctionDeclaration(func, name) {
|
|
107
|
-
let body;
|
|
108
|
-
// 处理箭头函数的隐式返回:将表达式体包装为显式 return 语句
|
|
109
|
-
if (func.type === 'ArrowFunctionExpression' && func.body.type !== 'BlockStatement') {
|
|
110
|
-
body = t.blockStatement([t.returnStatement(func.body)]);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
body = func.body;
|
|
114
|
-
}
|
|
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
|
-
// 保留原始位置信息用于源码映射
|
|
123
|
-
funcDecl.loc = func.loc;
|
|
124
|
-
return funcDecl;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* 从调用表达式中提取函数参数
|
|
128
|
-
* 将 export default builder(()=><div/>) 转换为:
|
|
129
|
-
* const _defaultExport = ()=><div/>
|
|
130
|
-
* export default builder(_defaultExport)
|
|
131
|
-
* @param callExpr - 调用表达式
|
|
132
|
-
* @param exportedNames - 已存在的名称集合
|
|
133
|
-
* @param builderAlias - builder 的本地别名
|
|
134
|
-
* @returns 提取结果,包含名称、函数声明节点和是否是 builder 包装
|
|
135
|
-
*/
|
|
136
|
-
function extractFunctionFromCallExpression(callExpr, exportedNames, builderAlias) {
|
|
137
|
-
// 判断是否为 builder 函数调用
|
|
138
|
-
const isBuilder = isBuilderCall(callExpr, builderAlias);
|
|
139
|
-
// 遍历调用表达式的所有参数
|
|
140
|
-
for (let i = 0; i < callExpr.arguments.length; i++) {
|
|
141
|
-
const arg = callExpr.arguments[i];
|
|
142
|
-
// 找到作为参数传入的匿名函数
|
|
143
|
-
if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
|
|
144
|
-
// 生成唯一名称
|
|
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
|
-
// 转换为命名函数声明
|
|
180
|
-
const funcNode = convertToNamedFunctionDeclaration(arg, name);
|
|
181
|
-
// 将原参数替换为标识符引用
|
|
182
|
-
callExpr.arguments[i] = t.identifier(name);
|
|
183
|
-
return { name, funcNode, isBuilderWrapped: isBuilder };
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// 未找到可提取的函数参数
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* 处理默认导出的匿名函数
|
|
191
|
-
* 为匿名函数生成唯一名称并转换为命名函数声明
|
|
192
|
-
* @param node - 默认导出节点
|
|
193
|
-
* @param program - AST Program 节点,用于插入提取的函数声明
|
|
194
|
-
* @param exportedNames - 已存在的名称集合
|
|
195
|
-
* @param components - 组件信息数组
|
|
196
|
-
* @param builderAlias - builder 的本地别名
|
|
197
|
-
*/
|
|
198
|
-
function processAnonymousDefaultExport(node, program, exportedNames, components, builderAlias) {
|
|
199
|
-
const decl = node.declaration;
|
|
200
|
-
let funcNode = null;
|
|
201
|
-
let name;
|
|
202
|
-
let isWrapped = false;
|
|
203
|
-
// 处理无名称的函数声明 export default function() {}
|
|
204
|
-
if (decl.type === 'FunctionDeclaration' && !decl.id) {
|
|
205
|
-
name = generateUniqueDefaultName(exportedNames);
|
|
206
|
-
decl.id = t.identifier(name);
|
|
207
|
-
funcNode = decl;
|
|
208
|
-
}
|
|
209
|
-
else if (decl.type === 'FunctionExpression') {
|
|
210
|
-
// 处理函数表达式 export default function() {}
|
|
211
|
-
name = generateUniqueDefaultName(exportedNames);
|
|
212
|
-
funcNode = convertToNamedFunctionDeclaration(decl, name);
|
|
213
|
-
node.declaration = funcNode;
|
|
214
|
-
}
|
|
215
|
-
else if (decl.type === 'ArrowFunctionExpression') {
|
|
216
|
-
// 处理箭头函数 export default () => {}
|
|
217
|
-
name = generateUniqueDefaultName(exportedNames);
|
|
218
|
-
funcNode = convertToNamedFunctionDeclaration(decl, name);
|
|
219
|
-
node.declaration = funcNode;
|
|
220
|
-
}
|
|
221
|
-
else if (decl.type === 'CallExpression') {
|
|
222
|
-
// 处理包装调用 export default builder(() => {})
|
|
223
|
-
const result = extractFunctionFromCallExpression(decl, exportedNames, builderAlias);
|
|
224
|
-
if (result) {
|
|
225
|
-
name = result.name;
|
|
226
|
-
funcNode = result.funcNode;
|
|
227
|
-
isWrapped = result.isBuilderWrapped;
|
|
228
|
-
// 将提取的函数声明插入到导出语句之前
|
|
229
|
-
const exportIndex = program.body.indexOf(node);
|
|
230
|
-
if (exportIndex !== -1) {
|
|
231
|
-
program.body.splice(exportIndex, 0, funcNode);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
// 如果成功提取到函数节点,添加到组件列表
|
|
236
|
-
if (funcNode) {
|
|
237
|
-
components.push({ name: name, node: funcNode, isWrapped });
|
|
238
|
-
}
|
|
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
|
-
}
|
|
269
76
|
/**
|
|
270
77
|
* 收集模块中的组件函数
|
|
271
78
|
* 遍历 AST 程序节点,提取所有导出的组件函数
|
|
@@ -274,65 +81,34 @@ function findVariableDeclaration(program, name) {
|
|
|
274
81
|
* @returns 组件信息数组
|
|
275
82
|
*/
|
|
276
83
|
export function collectComponentFunctions(program, builderAlias = null) {
|
|
277
|
-
// 收集所有已导出的名称
|
|
278
84
|
const exportedNames = collectExportedNames(program);
|
|
279
|
-
// 收集所有绑定名称(用于生成唯一名称时避免冲突)
|
|
280
85
|
const allBindingNames = collectAllBindingNames(program);
|
|
281
|
-
// 收集被 builder 包装的函数名称
|
|
282
86
|
const builderWrappedNames = collectBuilderWrappedNames(program, builderAlias);
|
|
283
|
-
// 存储收集到的组件信息
|
|
284
87
|
const components = [];
|
|
285
|
-
// 遍历程序体中的所有节点
|
|
286
88
|
for (const node of program.body) {
|
|
287
|
-
// 处理普通函数声明 function Component() {}
|
|
288
89
|
if (node.type === 'FunctionDeclaration' && node.id) {
|
|
289
90
|
tryAddComponent(node.id.name, node, exportedNames, components, builderWrappedNames);
|
|
290
91
|
}
|
|
291
92
|
else if (node.type === 'VariableDeclaration') {
|
|
292
|
-
// 处理变量声明 const Component = () => {} 或 const App = builder(() => {})
|
|
293
93
|
processVariableDeclaration(node, exportedNames, components, builderWrappedNames, program, builderAlias, allBindingNames);
|
|
294
94
|
}
|
|
295
95
|
else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
|
|
296
|
-
// 处理命名导出 export function Component() {} 或 export const Component = () => {}
|
|
297
96
|
if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
|
|
298
97
|
tryAddComponent(node.declaration.id.name, node.declaration, exportedNames, components, builderWrappedNames);
|
|
299
98
|
}
|
|
300
99
|
else if (node.declaration.type === 'VariableDeclaration') {
|
|
301
|
-
// 处理变量声明 const Component = () => {} 或 const App = builder(() => {})
|
|
302
100
|
processVariableDeclaration(node.declaration, exportedNames, components, builderWrappedNames, program, builderAlias, allBindingNames);
|
|
303
101
|
}
|
|
304
102
|
}
|
|
305
103
|
else if (node.type === 'ExportDefaultDeclaration') {
|
|
306
|
-
// 处理默认导出 export default Component 或 export default () => {}
|
|
307
104
|
const decl = node.declaration;
|
|
308
105
|
if (decl.type === 'FunctionDeclaration' && decl.id) {
|
|
309
|
-
// 处理具名函数默认导出 export default function Component() {}
|
|
310
106
|
tryAddComponent(decl.id.name, decl, exportedNames, components, builderWrappedNames);
|
|
311
107
|
}
|
|
312
108
|
else if (decl.type === 'Identifier') {
|
|
313
|
-
|
|
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
|
-
}
|
|
109
|
+
processIdentifierDefaultExport(decl, program, allBindingNames, components, builderAlias);
|
|
333
110
|
}
|
|
334
111
|
else {
|
|
335
|
-
// 处理匿名默认导出
|
|
336
112
|
processAnonymousDefaultExport(node, program, allBindingNames, components, builderAlias);
|
|
337
113
|
}
|
|
338
114
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 默认导出处理模块
|
|
3
|
+
* 处理 export default 的各种形式,提取组件函数
|
|
4
|
+
* @module utils/default-export
|
|
5
|
+
*/
|
|
6
|
+
import * as t from '@babel/types';
|
|
7
|
+
import type { ComponentInfo } from './component-collect.js';
|
|
8
|
+
/**
|
|
9
|
+
* 在 program.body 中查找指定名称的变量声明
|
|
10
|
+
* 用于处理 export default X 场景,追溯标识符对应的变量声明
|
|
11
|
+
* @param program - AST Program 节点
|
|
12
|
+
* @param name - 要查找的变量名
|
|
13
|
+
* @returns 包含变量声明和所在语句的对象,未找到返回 null
|
|
14
|
+
*/
|
|
15
|
+
export declare function findVariableDeclaration(program: t.Program, name: string): {
|
|
16
|
+
decl: t.VariableDeclarator;
|
|
17
|
+
statement: t.Statement;
|
|
18
|
+
} | null;
|
|
19
|
+
/**
|
|
20
|
+
* 处理默认导出的匿名函数
|
|
21
|
+
* 为匿名函数生成唯一名称并转换为命名函数声明
|
|
22
|
+
* @param node - 默认导出节点
|
|
23
|
+
* @param program - AST Program 节点,用于插入提取的函数声明
|
|
24
|
+
* @param allBindingNames - 所有绑定名称集合(用于生成唯一名称时避免冲突)
|
|
25
|
+
* @param components - 组件信息数组
|
|
26
|
+
* @param builderAlias - builder 的本地别名
|
|
27
|
+
*/
|
|
28
|
+
export declare function processAnonymousDefaultExport(node: t.ExportDefaultDeclaration, program: t.Program, allBindingNames: Set<string>, components: ComponentInfo[], builderAlias: string | null): void;
|
|
29
|
+
/**
|
|
30
|
+
* 处理标识符默认导出的 builder 包装追溯
|
|
31
|
+
* 处理 export default X 场景,追溯 X 是否为 builder 包装的组件
|
|
32
|
+
* @param decl - 标识符声明节点
|
|
33
|
+
* @param program - AST Program 节点
|
|
34
|
+
* @param allBindingNames - 所有绑定名称集合
|
|
35
|
+
* @param components - 组件信息数组
|
|
36
|
+
* @param builderAlias - builder 的本地别名
|
|
37
|
+
*/
|
|
38
|
+
export declare function processIdentifierDefaultExport(decl: t.Identifier, program: t.Program, allBindingNames: Set<string>, components: ComponentInfo[], builderAlias: string | null): void;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 默认导出处理模块
|
|
3
|
+
* 处理 export default 的各种形式,提取组件函数
|
|
4
|
+
* @module utils/default-export
|
|
5
|
+
*/
|
|
6
|
+
import * as t from '@babel/types';
|
|
7
|
+
import { generateUniqueDefaultName } from './generate.js';
|
|
8
|
+
import { convertToNamedFunctionDeclaration, extractFunctionFromCallExpression, extractFunctionFromVariableInit } from './function-extract.js';
|
|
9
|
+
import { isValidComponentName } from './component-collect.js';
|
|
10
|
+
/**
|
|
11
|
+
* 在 program.body 中查找指定名称的变量声明
|
|
12
|
+
* 用于处理 export default X 场景,追溯标识符对应的变量声明
|
|
13
|
+
* @param program - AST Program 节点
|
|
14
|
+
* @param name - 要查找的变量名
|
|
15
|
+
* @returns 包含变量声明和所在语句的对象,未找到返回 null
|
|
16
|
+
*/
|
|
17
|
+
export function findVariableDeclaration(program, name) {
|
|
18
|
+
for (const stmt of program.body) {
|
|
19
|
+
// 查找普通变量声明
|
|
20
|
+
if (stmt.type === 'VariableDeclaration') {
|
|
21
|
+
for (const decl of stmt.declarations) {
|
|
22
|
+
if (decl.id.type === 'Identifier' && decl.id.name === name) {
|
|
23
|
+
return { decl, statement: stmt };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// 查找命名导出中的变量声明
|
|
28
|
+
if (stmt.type === 'ExportNamedDeclaration' &&
|
|
29
|
+
stmt.declaration?.type === 'VariableDeclaration') {
|
|
30
|
+
for (const decl of stmt.declaration.declarations) {
|
|
31
|
+
if (decl.id.type === 'Identifier' && decl.id.name === name) {
|
|
32
|
+
return { decl, statement: stmt };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 处理默认导出的匿名函数
|
|
41
|
+
* 为匿名函数生成唯一名称并转换为命名函数声明
|
|
42
|
+
* @param node - 默认导出节点
|
|
43
|
+
* @param program - AST Program 节点,用于插入提取的函数声明
|
|
44
|
+
* @param allBindingNames - 所有绑定名称集合(用于生成唯一名称时避免冲突)
|
|
45
|
+
* @param components - 组件信息数组
|
|
46
|
+
* @param builderAlias - builder 的本地别名
|
|
47
|
+
*/
|
|
48
|
+
export function processAnonymousDefaultExport(node, program, allBindingNames, components, builderAlias) {
|
|
49
|
+
const decl = node.declaration;
|
|
50
|
+
let funcNode = null;
|
|
51
|
+
let name;
|
|
52
|
+
let isWrapped = false;
|
|
53
|
+
// 处理无名称的函数声明 export default function() {}
|
|
54
|
+
if (decl.type === 'FunctionDeclaration' && !decl.id) {
|
|
55
|
+
name = generateUniqueDefaultName(allBindingNames);
|
|
56
|
+
decl.id = t.identifier(name);
|
|
57
|
+
funcNode = decl;
|
|
58
|
+
}
|
|
59
|
+
else if (decl.type === 'FunctionExpression') {
|
|
60
|
+
// 处理函数表达式 export default function() {}
|
|
61
|
+
name = generateUniqueDefaultName(allBindingNames);
|
|
62
|
+
funcNode = convertToNamedFunctionDeclaration(decl, name);
|
|
63
|
+
node.declaration = funcNode;
|
|
64
|
+
}
|
|
65
|
+
else if (decl.type === 'ArrowFunctionExpression') {
|
|
66
|
+
// 处理箭头函数 export default () => {}
|
|
67
|
+
name = generateUniqueDefaultName(allBindingNames);
|
|
68
|
+
funcNode = convertToNamedFunctionDeclaration(decl, name);
|
|
69
|
+
node.declaration = funcNode;
|
|
70
|
+
}
|
|
71
|
+
else if (decl.type === 'CallExpression') {
|
|
72
|
+
// 处理包装调用 export default builder(() => {})
|
|
73
|
+
const result = extractFunctionFromCallExpression(decl, allBindingNames, builderAlias);
|
|
74
|
+
if (result) {
|
|
75
|
+
name = result.name;
|
|
76
|
+
funcNode = result.funcNode;
|
|
77
|
+
isWrapped = result.isBuilderWrapped;
|
|
78
|
+
// 将提取的函数声明插入到导出语句之前
|
|
79
|
+
const exportIndex = program.body.indexOf(node);
|
|
80
|
+
if (exportIndex !== -1) {
|
|
81
|
+
program.body.splice(exportIndex, 0, funcNode);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// 如果成功提取到函数节点,添加到组件列表
|
|
86
|
+
if (funcNode) {
|
|
87
|
+
components.push({ name: name, node: funcNode, isWrapped });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* 处理标识符默认导出的 builder 包装追溯
|
|
92
|
+
* 处理 export default X 场景,追溯 X 是否为 builder 包装的组件
|
|
93
|
+
* @param decl - 标识符声明节点
|
|
94
|
+
* @param program - AST Program 节点
|
|
95
|
+
* @param allBindingNames - 所有绑定名称集合
|
|
96
|
+
* @param components - 组件信息数组
|
|
97
|
+
* @param builderAlias - builder 的本地别名
|
|
98
|
+
*/
|
|
99
|
+
export function processIdentifierDefaultExport(decl, program, allBindingNames, components, builderAlias) {
|
|
100
|
+
// 追溯标识符对应的变量声明,判断是否为 builder 包装组件
|
|
101
|
+
if (!isValidComponentName(decl.name))
|
|
102
|
+
return;
|
|
103
|
+
const varDecl = findVariableDeclaration(program, decl.name);
|
|
104
|
+
if (varDecl?.decl.init?.type !== 'CallExpression')
|
|
105
|
+
return;
|
|
106
|
+
const result = extractFunctionFromVariableInit(varDecl.decl.init, decl.name, allBindingNames, builderAlias);
|
|
107
|
+
if (!result)
|
|
108
|
+
return;
|
|
109
|
+
// 将提取的函数声明插入到变量声明所在语句之前
|
|
110
|
+
const stmtIndex = program.body.indexOf(varDecl.statement);
|
|
111
|
+
if (stmtIndex !== -1) {
|
|
112
|
+
program.body.splice(stmtIndex, 0, result.funcNode);
|
|
113
|
+
}
|
|
114
|
+
components.push({
|
|
115
|
+
name: result.name,
|
|
116
|
+
node: result.funcNode,
|
|
117
|
+
isWrapped: result.isBuilderWrapped
|
|
118
|
+
});
|
|
119
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 函数提取模块
|
|
3
|
+
* 从调用表达式中提取匿名函数,转换为命名函数声明
|
|
4
|
+
* @module utils/function-extract
|
|
5
|
+
*/
|
|
6
|
+
import * as t from '@babel/types';
|
|
7
|
+
/**
|
|
8
|
+
* 将函数表达式或箭头函数转换为命名函数声明
|
|
9
|
+
* 用于将匿名函数转换为可追踪的命名函数
|
|
10
|
+
* @param func - 函数表达式或箭头函数节点
|
|
11
|
+
* @param name - 生成的函数名称
|
|
12
|
+
* @returns 命名函数声明节点
|
|
13
|
+
*/
|
|
14
|
+
export declare function convertToNamedFunctionDeclaration(func: t.FunctionExpression | t.ArrowFunctionExpression, name: string): t.FunctionDeclaration;
|
|
15
|
+
/**
|
|
16
|
+
* 从调用表达式中提取函数参数
|
|
17
|
+
* 将 export default builder(()=><div/>) 转换为:
|
|
18
|
+
* const _defaultExport = ()=><div/>
|
|
19
|
+
* export default builder(_defaultExport)
|
|
20
|
+
* @param callExpr - 调用表达式
|
|
21
|
+
* @param exportedNames - 已存在的名称集合
|
|
22
|
+
* @param builderAlias - builder 的本地别名
|
|
23
|
+
* @returns 提取结果,包含名称、函数声明节点和是否是 builder 包装
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractFunctionFromCallExpression(callExpr: t.CallExpression, exportedNames: Set<string>, builderAlias: string | null): {
|
|
26
|
+
name: string;
|
|
27
|
+
funcNode: t.FunctionDeclaration;
|
|
28
|
+
isBuilderWrapped: boolean;
|
|
29
|
+
} | null;
|
|
30
|
+
/**
|
|
31
|
+
* 从变量声明的调用表达式中提取函数
|
|
32
|
+
* 将 const App = builder(() => <div/>) 转换为:
|
|
33
|
+
* function App$1() { return <div/> }
|
|
34
|
+
* const App = builder(App$1)
|
|
35
|
+
* @param callExpr - 调用表达式
|
|
36
|
+
* @param variableName - 变量名(作为内部函数名的基础)
|
|
37
|
+
* @param allBindingNames - 所有绑定名称集合(用于避免命名冲突)
|
|
38
|
+
* @param builderAlias - builder 的本地别名
|
|
39
|
+
* @returns 提取结果,包含名称、函数声明节点和是否是 builder 包装
|
|
40
|
+
*/
|
|
41
|
+
export declare function extractFunctionFromVariableInit(callExpr: t.CallExpression, variableName: string, allBindingNames: Set<string>, builderAlias: string | null): {
|
|
42
|
+
name: string;
|
|
43
|
+
funcNode: t.FunctionDeclaration;
|
|
44
|
+
isBuilderWrapped: boolean;
|
|
45
|
+
} | null;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 函数提取模块
|
|
3
|
+
* 从调用表达式中提取匿名函数,转换为命名函数声明
|
|
4
|
+
* @module utils/function-extract
|
|
5
|
+
*/
|
|
6
|
+
import * as t from '@babel/types';
|
|
7
|
+
import { isBuilderCall } from './collect-names.js';
|
|
8
|
+
import { generateUniqueAlias, generateUniqueDefaultName } from './generate.js';
|
|
9
|
+
/**
|
|
10
|
+
* 将函数表达式或箭头函数转换为命名函数声明
|
|
11
|
+
* 用于将匿名函数转换为可追踪的命名函数
|
|
12
|
+
* @param func - 函数表达式或箭头函数节点
|
|
13
|
+
* @param name - 生成的函数名称
|
|
14
|
+
* @returns 命名函数声明节点
|
|
15
|
+
*/
|
|
16
|
+
export function convertToNamedFunctionDeclaration(func, name) {
|
|
17
|
+
let body;
|
|
18
|
+
// 处理箭头函数的隐式返回:将表达式体包装为显式 return 语句
|
|
19
|
+
if (func.type === 'ArrowFunctionExpression' && func.body.type !== 'BlockStatement') {
|
|
20
|
+
body = t.blockStatement([t.returnStatement(func.body)]);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
body = func.body;
|
|
24
|
+
}
|
|
25
|
+
// 创建函数声明节点
|
|
26
|
+
const funcDecl = t.functionDeclaration(t.identifier(name), // 函数名称
|
|
27
|
+
func.params, // 参数列表
|
|
28
|
+
body, // 函数体
|
|
29
|
+
func.type === 'FunctionExpression' ? func.generator : false, // 是否为生成器
|
|
30
|
+
func.async // 是否为异步函数
|
|
31
|
+
);
|
|
32
|
+
// 保留原始位置信息用于源码映射
|
|
33
|
+
funcDecl.loc = func.loc;
|
|
34
|
+
return funcDecl;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 从调用表达式中提取函数参数
|
|
38
|
+
* 将 export default builder(()=><div/>) 转换为:
|
|
39
|
+
* const _defaultExport = ()=><div/>
|
|
40
|
+
* export default builder(_defaultExport)
|
|
41
|
+
* @param callExpr - 调用表达式
|
|
42
|
+
* @param exportedNames - 已存在的名称集合
|
|
43
|
+
* @param builderAlias - builder 的本地别名
|
|
44
|
+
* @returns 提取结果,包含名称、函数声明节点和是否是 builder 包装
|
|
45
|
+
*/
|
|
46
|
+
export function extractFunctionFromCallExpression(callExpr, exportedNames, builderAlias) {
|
|
47
|
+
// 判断是否为 builder 函数调用
|
|
48
|
+
const isBuilder = isBuilderCall(callExpr, builderAlias);
|
|
49
|
+
// 遍历调用表达式的所有参数
|
|
50
|
+
for (let i = 0; i < callExpr.arguments.length; i++) {
|
|
51
|
+
const arg = callExpr.arguments[i];
|
|
52
|
+
// 找到作为参数传入的匿名函数
|
|
53
|
+
if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
|
|
54
|
+
// 生成唯一名称
|
|
55
|
+
const name = generateUniqueDefaultName(exportedNames);
|
|
56
|
+
// 转换为命名函数声明
|
|
57
|
+
const funcNode = convertToNamedFunctionDeclaration(arg, name);
|
|
58
|
+
// 将原参数替换为标识符引用
|
|
59
|
+
callExpr.arguments[i] = t.identifier(name);
|
|
60
|
+
return { name, funcNode, isBuilderWrapped: isBuilder };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// 未找到可提取的函数参数
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 从变量声明的调用表达式中提取函数
|
|
68
|
+
* 将 const App = builder(() => <div/>) 转换为:
|
|
69
|
+
* function App$1() { return <div/> }
|
|
70
|
+
* const App = builder(App$1)
|
|
71
|
+
* @param callExpr - 调用表达式
|
|
72
|
+
* @param variableName - 变量名(作为内部函数名的基础)
|
|
73
|
+
* @param allBindingNames - 所有绑定名称集合(用于避免命名冲突)
|
|
74
|
+
* @param builderAlias - builder 的本地别名
|
|
75
|
+
* @returns 提取结果,包含名称、函数声明节点和是否是 builder 包装
|
|
76
|
+
*/
|
|
77
|
+
export function extractFunctionFromVariableInit(callExpr, variableName, allBindingNames, builderAlias) {
|
|
78
|
+
// 判断是否为 builder 函数调用
|
|
79
|
+
const isBuilder = isBuilderCall(callExpr, builderAlias);
|
|
80
|
+
// 遍历调用表达式的所有参数
|
|
81
|
+
for (let i = 0; i < callExpr.arguments.length; i++) {
|
|
82
|
+
const arg = callExpr.arguments[i];
|
|
83
|
+
// 找到作为参数传入的匿名函数
|
|
84
|
+
if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
|
|
85
|
+
// 以变量名为基础生成唯一别名,避免与已有名称冲突
|
|
86
|
+
const name = generateUniqueAlias(variableName, allBindingNames);
|
|
87
|
+
// 将新名称加入集合,防止后续生成重复名称
|
|
88
|
+
allBindingNames.add(name);
|
|
89
|
+
// 转换为命名函数声明
|
|
90
|
+
const funcNode = convertToNamedFunctionDeclaration(arg, name);
|
|
91
|
+
// 将原参数替换为标识符引用
|
|
92
|
+
callExpr.arguments[i] = t.identifier(name);
|
|
93
|
+
return { name, funcNode, isBuilderWrapped: isBuilder };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// 未找到可提取的函数参数
|
|
97
|
+
return null;
|
|
98
|
+
}
|
package/dist/utils/generate.d.ts
CHANGED
|
@@ -6,3 +6,10 @@
|
|
|
6
6
|
* @returns 唯一的别名
|
|
7
7
|
*/
|
|
8
8
|
export declare function generateUniqueAlias(baseName: string, existingNames: Set<string>): string;
|
|
9
|
+
/**
|
|
10
|
+
* 生成唯一的默认导出组件名称
|
|
11
|
+
* 优先使用基础名称,若冲突则生成唯一别名
|
|
12
|
+
* @param existingNames - 已存在的名称集合
|
|
13
|
+
* @returns 唯一的默认导出名称
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateUniqueDefaultName(existingNames: Set<string>): string;
|