@vitarx/plugin-vite 0.0.1-beta.7 → 1.0.0-beta.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/README.md +64 -4
- package/dist/constants/index.d.ts +1 -11
- package/dist/constants/index.js +1 -11
- package/dist/context.d.ts +14 -10
- package/dist/context.js +7 -5
- package/dist/hmr-client/index.d.ts +2 -1
- package/dist/hmr-client/index.js +3 -2
- package/dist/hmr-client/utils.d.ts +1 -1
- package/dist/hmr-client/utils.js +7 -4
- package/dist/index.js +10 -4
- package/dist/passes/components/ifBlock.js +2 -4
- package/dist/passes/components/switch.js +2 -4
- package/dist/passes/directives/processDirectives.js +1 -1
- package/dist/passes/directives/vIf.js +2 -5
- package/dist/passes/hmr/inject-imports.d.ts +19 -0
- package/dist/passes/hmr/inject-imports.js +26 -0
- package/dist/passes/hmr/inject-state.d.ts +29 -0
- package/dist/passes/hmr/inject-state.js +101 -0
- package/dist/passes/hmr/inject.d.ts +1 -1
- package/dist/passes/hmr/inject.js +13 -123
- package/dist/passes/imports/injectImports.js +2 -2
- package/dist/passes/jsx/processChildren.js +30 -51
- package/dist/passes/jsx/processJSXElement.js +3 -6
- package/dist/passes/jsx/processJSXFragment.js +4 -4
- package/dist/passes/props/index.js +1 -8
- package/dist/transform.d.ts +5 -8
- package/dist/transform.js +19 -20
- package/dist/types.d.ts +11 -0
- package/dist/utils/ast-builders.d.ts +18 -18
- package/dist/utils/ast-builders.js +27 -41
- package/dist/utils/branch-factory.d.ts +1 -4
- package/dist/utils/branch-factory.js +4 -7
- package/dist/utils/collect-names.d.ts +37 -0
- package/dist/utils/collect-names.js +129 -0
- package/dist/utils/component-collect.d.ts +9 -4
- package/dist/utils/component-collect.js +64 -74
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +2 -2
- package/dist/utils/jsx-helpers.d.ts +3 -2
- package/dist/utils/jsx-helpers.js +3 -2
- package/package.json +11 -4
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
import * as t from '@babel/types';
|
|
6
6
|
import { isIdentifier, isStringLiteral } from '@babel/types';
|
|
7
7
|
import { PURE_COMMENT } from '../constants/index.js';
|
|
8
|
-
/** 用于追踪已添加 PURE 注释的节点 */
|
|
9
|
-
const pureCommentedNodes = new WeakSet();
|
|
10
8
|
/**
|
|
11
9
|
* 创建 unref 调用
|
|
12
10
|
* @param argument - 参数表达式
|
|
@@ -17,13 +15,13 @@ export function createUnrefCall(argument, alias) {
|
|
|
17
15
|
return t.callExpression(t.identifier(alias || 'unref'), [argument]);
|
|
18
16
|
}
|
|
19
17
|
/**
|
|
20
|
-
* 创建
|
|
18
|
+
* 创建 accessor 调用
|
|
21
19
|
* @param object - 对象表达式
|
|
22
20
|
* @param key - 键表达式
|
|
23
|
-
* @param alias -
|
|
21
|
+
* @param alias - accessor 别名
|
|
24
22
|
* @returns CallExpression
|
|
25
23
|
*/
|
|
26
|
-
export function
|
|
24
|
+
export function createAccessorCall(object, key, alias) {
|
|
27
25
|
let keyArg;
|
|
28
26
|
if (isIdentifier(key)) {
|
|
29
27
|
keyArg = t.stringLiteral(key.name);
|
|
@@ -34,36 +32,26 @@ export function createAccessCall(object, key, alias) {
|
|
|
34
32
|
else {
|
|
35
33
|
keyArg = key;
|
|
36
34
|
}
|
|
37
|
-
return t.callExpression(t.identifier(alias || '
|
|
35
|
+
return t.callExpression(t.identifier(alias || 'accessor'), [object, keyArg]);
|
|
38
36
|
}
|
|
39
37
|
/**
|
|
40
|
-
* 创建
|
|
38
|
+
* 创建 expr 调用
|
|
41
39
|
* @param argument - 参数表达式
|
|
42
|
-
* @param alias -
|
|
43
|
-
* @param locInfo - 位置信息对象
|
|
40
|
+
* @param alias - expr 别名
|
|
44
41
|
* @returns CallExpression
|
|
45
42
|
*/
|
|
46
|
-
export function
|
|
47
|
-
|
|
48
|
-
if (locInfo) {
|
|
49
|
-
args.push(locInfo);
|
|
50
|
-
}
|
|
51
|
-
return t.callExpression(t.identifier(alias || 'dynamic'), args);
|
|
43
|
+
export function createExprCall(argument, alias) {
|
|
44
|
+
return t.callExpression(t.identifier(alias || 'expr'), [t.arrowFunctionExpression([], argument)]);
|
|
52
45
|
}
|
|
53
46
|
/**
|
|
54
47
|
* 创建 branch 调用
|
|
55
48
|
* @param condition - 条件函数
|
|
56
49
|
* @param branches - 分支函数数组
|
|
57
50
|
* @param alias - branch 别名
|
|
58
|
-
* @param locInfo - 位置信息对象
|
|
59
51
|
* @returns CallExpression
|
|
60
52
|
*/
|
|
61
|
-
export function createBranchCall(condition, branches, alias
|
|
62
|
-
|
|
63
|
-
if (locInfo) {
|
|
64
|
-
args.push(locInfo);
|
|
65
|
-
}
|
|
66
|
-
return t.callExpression(t.identifier(alias || 'branch'), args);
|
|
53
|
+
export function createBranchCall(condition, branches, alias) {
|
|
54
|
+
return t.callExpression(t.identifier(alias || 'branch'), [condition, t.arrayExpression(branches)]);
|
|
67
55
|
}
|
|
68
56
|
/**
|
|
69
57
|
* 创建 createView 调用
|
|
@@ -75,15 +63,12 @@ export function createBranchCall(condition, branches, alias, locInfo) {
|
|
|
75
63
|
*/
|
|
76
64
|
export function createCreateViewCall(type, props, locInfo, alias) {
|
|
77
65
|
const args = [type];
|
|
78
|
-
// props 参数
|
|
79
66
|
if (props) {
|
|
80
67
|
args.push(props);
|
|
81
68
|
}
|
|
82
69
|
else if (locInfo) {
|
|
83
|
-
// 如果有 locInfo 但没有 props,需要传 null
|
|
84
70
|
args.push(t.nullLiteral());
|
|
85
71
|
}
|
|
86
|
-
// locInfo 参数
|
|
87
72
|
if (locInfo) {
|
|
88
73
|
args.push(locInfo);
|
|
89
74
|
}
|
|
@@ -113,29 +98,17 @@ export function createWithDirectivesCall(view, directives, alias) {
|
|
|
113
98
|
export function createArrowFunction(body) {
|
|
114
99
|
return t.arrowFunctionExpression([], body);
|
|
115
100
|
}
|
|
116
|
-
/**
|
|
117
|
-
* 创建位置信息对象
|
|
118
|
-
* @param filename - 文件名
|
|
119
|
-
* @param loc - 源码位置
|
|
120
|
-
* @returns ObjectExpression
|
|
121
|
-
*/
|
|
122
|
-
export function createLocationObject(filename, loc) {
|
|
123
|
-
return t.objectExpression([
|
|
124
|
-
t.objectProperty(t.identifier('fileName'), t.stringLiteral(filename)),
|
|
125
|
-
t.objectProperty(t.identifier('lineNumber'), t.numericLiteral(loc.start.line)),
|
|
126
|
-
t.objectProperty(t.identifier('columnNumber'), t.numericLiteral(loc.start.column + 1))
|
|
127
|
-
]);
|
|
128
|
-
}
|
|
129
101
|
/**
|
|
130
102
|
* 为调用表达式添加 @__PURE__ 注释
|
|
131
103
|
* @param node - 调用表达式节点
|
|
104
|
+
* @param ctx - 转换上下文
|
|
132
105
|
* @returns 添加注释后的节点
|
|
133
106
|
*/
|
|
134
|
-
export function addPureComment(node) {
|
|
135
|
-
if (pureCommentedNodes.has(node)) {
|
|
107
|
+
export function addPureComment(node, ctx) {
|
|
108
|
+
if (ctx.pureCommentedNodes.has(node)) {
|
|
136
109
|
return node;
|
|
137
110
|
}
|
|
138
|
-
pureCommentedNodes.add(node);
|
|
111
|
+
ctx.pureCommentedNodes.add(node);
|
|
139
112
|
t.addComment(node, 'leading', ` ${PURE_COMMENT} `, false);
|
|
140
113
|
return node;
|
|
141
114
|
}
|
|
@@ -148,6 +121,19 @@ export function addPureComment(node) {
|
|
|
148
121
|
export function getAlias(aliases, name) {
|
|
149
122
|
return aliases[name] || name;
|
|
150
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* 创建位置信息对象
|
|
126
|
+
* @param filename - 文件名
|
|
127
|
+
* @param loc - 源码位置
|
|
128
|
+
* @returns ObjectExpression
|
|
129
|
+
*/
|
|
130
|
+
export function createLocationObject(filename, loc) {
|
|
131
|
+
return t.objectExpression([
|
|
132
|
+
t.objectProperty(t.identifier('fileName'), t.stringLiteral(filename)),
|
|
133
|
+
t.objectProperty(t.identifier('lineNumber'), t.numericLiteral(loc.start.line)),
|
|
134
|
+
t.objectProperty(t.identifier('columnNumber'), t.numericLiteral(loc.start.column + 1))
|
|
135
|
+
]);
|
|
136
|
+
}
|
|
151
137
|
/**
|
|
152
138
|
* 获取开发环境下的位置信息对象
|
|
153
139
|
* 仅在开发环境下返回位置信息,生产环境返回 null
|
|
@@ -15,8 +15,6 @@ export interface BranchConfig {
|
|
|
15
15
|
branches: t.ArrowFunctionExpression[];
|
|
16
16
|
/** 是否使用 unref 包装标识符条件 */
|
|
17
17
|
useRef?: boolean;
|
|
18
|
-
/** 位置信息对象 */
|
|
19
|
-
locInfo?: t.ObjectExpression | null;
|
|
20
18
|
}
|
|
21
19
|
/**
|
|
22
20
|
* 创建 branch 调用
|
|
@@ -36,7 +34,6 @@ export declare function buildNestedCondition(conditions: t.Expression[], ctx: Tr
|
|
|
36
34
|
* @param consequent - 真值分支
|
|
37
35
|
* @param alternate - 假值分支
|
|
38
36
|
* @param ctx - 转换上下文
|
|
39
|
-
* @param locInfo - 位置信息对象
|
|
40
37
|
* @returns branch 调用表达式
|
|
41
38
|
*/
|
|
42
|
-
export declare function createBinaryBranch(condition: t.Expression, consequent: t.Expression, alternate: t.Expression, ctx: TransformContext
|
|
39
|
+
export declare function createBinaryBranch(condition: t.Expression, consequent: t.Expression, alternate: t.Expression, ctx: TransformContext): t.CallExpression;
|
|
@@ -14,15 +14,14 @@ import { addPureComment, createArrowFunction, createBranchCall, createUnrefCall,
|
|
|
14
14
|
* @returns branch 调用表达式
|
|
15
15
|
*/
|
|
16
16
|
export function createBranch(config, ctx) {
|
|
17
|
-
const { conditions, branches, useRef = true
|
|
17
|
+
const { conditions, branches, useRef = true } = config;
|
|
18
18
|
markImport(ctx, 'branch');
|
|
19
|
-
// 只有在需要 unref 且条件中有标识符时才标记导入
|
|
20
19
|
if (useRef && conditions.some(c => isIdentifier(c))) {
|
|
21
20
|
markImport(ctx, 'unref');
|
|
22
21
|
}
|
|
23
22
|
const conditionExpr = buildNestedCondition(conditions, ctx, useRef);
|
|
24
23
|
const branchAlias = getAlias(ctx.vitarxAliases, 'branch');
|
|
25
|
-
return addPureComment(createBranchCall(createArrowFunction(conditionExpr), branches, branchAlias,
|
|
24
|
+
return addPureComment(createBranchCall(createArrowFunction(conditionExpr), branches, branchAlias), ctx);
|
|
26
25
|
}
|
|
27
26
|
/**
|
|
28
27
|
* 判断表达式是否需要括号包裹
|
|
@@ -85,13 +84,11 @@ export function buildNestedCondition(conditions, ctx, useRef = true) {
|
|
|
85
84
|
* @param consequent - 真值分支
|
|
86
85
|
* @param alternate - 假值分支
|
|
87
86
|
* @param ctx - 转换上下文
|
|
88
|
-
* @param locInfo - 位置信息对象
|
|
89
87
|
* @returns branch 调用表达式
|
|
90
88
|
*/
|
|
91
|
-
export function createBinaryBranch(condition, consequent, alternate, ctx
|
|
89
|
+
export function createBinaryBranch(condition, consequent, alternate, ctx) {
|
|
92
90
|
const conditions = [condition, t.booleanLiteral(true)];
|
|
93
91
|
const branches = [createArrowFunction(consequent), createArrowFunction(alternate)];
|
|
94
|
-
// 只有条件是 Identifier 时才需要 unref
|
|
95
92
|
const useRef = isIdentifier(condition);
|
|
96
|
-
return createBranch({ conditions, branches, useRef
|
|
93
|
+
return createBranch({ conditions, branches, useRef }, ctx);
|
|
97
94
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 名称收集模块
|
|
3
|
+
* 负责从 AST 中收集导出名称、绑定名称和 builder 包装名称
|
|
4
|
+
* @module utils/collect-names
|
|
5
|
+
*/
|
|
6
|
+
import type * as t from '@babel/types';
|
|
7
|
+
/**
|
|
8
|
+
* 从命名导出中收集名称
|
|
9
|
+
*/
|
|
10
|
+
export declare function collectFromNamedExport(node: t.ExportNamedDeclaration, names: Set<string>): void;
|
|
11
|
+
/**
|
|
12
|
+
* 从默认导出中收集名称
|
|
13
|
+
*/
|
|
14
|
+
export declare function collectFromDefaultExport(node: t.ExportDefaultDeclaration, names: Set<string>): void;
|
|
15
|
+
/**
|
|
16
|
+
* 收集所有导出的标识符名称
|
|
17
|
+
*/
|
|
18
|
+
export declare function collectExportedNames(program: t.Program): Set<string>;
|
|
19
|
+
/**
|
|
20
|
+
* 收集模块中所有绑定的名称(用于避免命名冲突)
|
|
21
|
+
*/
|
|
22
|
+
export declare function collectAllBindingNames(program: t.Program): Set<string>;
|
|
23
|
+
/**
|
|
24
|
+
* 判断调用表达式是否是 builder 调用
|
|
25
|
+
* @param callExpr - 调用表达式
|
|
26
|
+
* @param builderAlias - builder 的本地别名
|
|
27
|
+
* @returns 是否是 builder 调用
|
|
28
|
+
*/
|
|
29
|
+
export declare function isBuilderCall(callExpr: t.CallExpression, builderAlias: string | null): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 收集被 builder 调用的组件名称
|
|
32
|
+
* 检测 builder(Comp) 或 builder(Comp, options) 形式的调用
|
|
33
|
+
* @param program - AST Program 节点
|
|
34
|
+
* @param builderAlias - builder 的本地别名
|
|
35
|
+
* @returns 被 builder 调用的组件名称集合
|
|
36
|
+
*/
|
|
37
|
+
export declare function collectBuilderWrappedNames(program: t.Program, builderAlias: string | null): Set<string>;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 从命名导出中收集名称
|
|
3
|
+
*/
|
|
4
|
+
export function collectFromNamedExport(node, names) {
|
|
5
|
+
if (node.declaration) {
|
|
6
|
+
if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
|
|
7
|
+
names.add(node.declaration.id.name);
|
|
8
|
+
}
|
|
9
|
+
else if (node.declaration.type === 'VariableDeclaration') {
|
|
10
|
+
for (const decl of node.declaration.declarations) {
|
|
11
|
+
if (decl.id.type === 'Identifier') {
|
|
12
|
+
names.add(decl.id.name);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (node.specifiers) {
|
|
18
|
+
for (const spec of node.specifiers) {
|
|
19
|
+
if (spec.type === 'ExportSpecifier') {
|
|
20
|
+
names.add(spec.local.name);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 从默认导出中收集名称
|
|
27
|
+
*/
|
|
28
|
+
export function collectFromDefaultExport(node, names) {
|
|
29
|
+
const decl = node.declaration;
|
|
30
|
+
if (decl.type === 'FunctionDeclaration' && decl.id) {
|
|
31
|
+
names.add(decl.id.name);
|
|
32
|
+
}
|
|
33
|
+
else if (decl.type === 'Identifier') {
|
|
34
|
+
names.add(decl.name);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 从变量声明中收集变量名
|
|
39
|
+
*/
|
|
40
|
+
function collectFromVariableDeclaration(node, names) {
|
|
41
|
+
for (const decl of node.declarations) {
|
|
42
|
+
if (decl.id.type === 'Identifier') {
|
|
43
|
+
names.add(decl.id.name);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 从导入声明中收集绑定的名称
|
|
49
|
+
*/
|
|
50
|
+
function collectFromImportDeclaration(node, names) {
|
|
51
|
+
for (const spec of node.specifiers) {
|
|
52
|
+
names.add(spec.local.name);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 收集所有导出的标识符名称
|
|
57
|
+
*/
|
|
58
|
+
export function collectExportedNames(program) {
|
|
59
|
+
const names = new Set();
|
|
60
|
+
for (const node of program.body) {
|
|
61
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
62
|
+
collectFromNamedExport(node, names);
|
|
63
|
+
}
|
|
64
|
+
else if (node.type === 'ExportDefaultDeclaration') {
|
|
65
|
+
collectFromDefaultExport(node, names);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return names;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 收集模块中所有绑定的名称(用于避免命名冲突)
|
|
72
|
+
*/
|
|
73
|
+
export function collectAllBindingNames(program) {
|
|
74
|
+
const names = new Set();
|
|
75
|
+
for (const node of program.body) {
|
|
76
|
+
if (node.type === 'FunctionDeclaration' && node.id) {
|
|
77
|
+
names.add(node.id.name);
|
|
78
|
+
}
|
|
79
|
+
else if (node.type === 'VariableDeclaration') {
|
|
80
|
+
collectFromVariableDeclaration(node, names);
|
|
81
|
+
}
|
|
82
|
+
else if (node.type === 'ImportDeclaration') {
|
|
83
|
+
collectFromImportDeclaration(node, names);
|
|
84
|
+
}
|
|
85
|
+
else if (node.type === 'ExportNamedDeclaration') {
|
|
86
|
+
collectFromNamedExport(node, names);
|
|
87
|
+
}
|
|
88
|
+
else if (node.type === 'ExportDefaultDeclaration') {
|
|
89
|
+
collectFromDefaultExport(node, names);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return names;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 判断调用表达式是否是 builder 调用
|
|
96
|
+
* @param callExpr - 调用表达式
|
|
97
|
+
* @param builderAlias - builder 的本地别名
|
|
98
|
+
* @returns 是否是 builder 调用
|
|
99
|
+
*/
|
|
100
|
+
export function isBuilderCall(callExpr, builderAlias) {
|
|
101
|
+
if (!builderAlias)
|
|
102
|
+
return false;
|
|
103
|
+
const callee = callExpr.callee;
|
|
104
|
+
return callee.type === 'Identifier' && callee.name === builderAlias;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 收集被 builder 调用的组件名称
|
|
108
|
+
* 检测 builder(Comp) 或 builder(Comp, options) 形式的调用
|
|
109
|
+
* @param program - AST Program 节点
|
|
110
|
+
* @param builderAlias - builder 的本地别名
|
|
111
|
+
* @returns 被 builder 调用的组件名称集合
|
|
112
|
+
*/
|
|
113
|
+
export function collectBuilderWrappedNames(program, builderAlias) {
|
|
114
|
+
const wrappedNames = new Set();
|
|
115
|
+
if (!builderAlias)
|
|
116
|
+
return wrappedNames;
|
|
117
|
+
for (const node of program.body) {
|
|
118
|
+
if (node.type === 'ExpressionStatement' && node.expression.type === 'CallExpression') {
|
|
119
|
+
const callExpr = node.expression;
|
|
120
|
+
if (isBuilderCall(callExpr, builderAlias)) {
|
|
121
|
+
const arg = callExpr.arguments[0];
|
|
122
|
+
if (arg?.type === 'Identifier') {
|
|
123
|
+
wrappedNames.add(arg.name);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return wrappedNames;
|
|
129
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
2
|
+
* 组件收集模块
|
|
3
|
+
* 负责从 AST 中收集组件函数信息
|
|
4
|
+
* @module utils/component-collect
|
|
5
5
|
*/
|
|
6
6
|
import * as t from '@babel/types';
|
|
7
7
|
/**
|
|
@@ -10,8 +10,13 @@ import * as t from '@babel/types';
|
|
|
10
10
|
export interface ComponentInfo {
|
|
11
11
|
name: string;
|
|
12
12
|
node: t.FunctionDeclaration | t.ArrowFunctionExpression | t.FunctionExpression;
|
|
13
|
+
/** 是否为包装组件(传递给 builder/defineComponent 等函数) */
|
|
14
|
+
isWrapped?: boolean;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* 收集模块中的组件函数
|
|
18
|
+
* @param program - AST Program 节点
|
|
19
|
+
* @param builderAlias - builder 函数的本地别名(用于识别纯构建组件)
|
|
20
|
+
* @returns 组件信息数组
|
|
16
21
|
*/
|
|
17
|
-
export declare function collectComponentFunctions(program: t.Program): ComponentInfo[];
|
|
22
|
+
export declare function collectComponentFunctions(program: t.Program, builderAlias?: string | null): ComponentInfo[];
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
2
|
+
* 组件收集模块
|
|
3
|
+
* 负责从 AST 中收集组件函数信息
|
|
4
|
+
* @module utils/component-collect
|
|
5
5
|
*/
|
|
6
6
|
import * as t from '@babel/types';
|
|
7
7
|
import { DEFAULT_EXPORT_BASE_NAME } from '../constants/index.js';
|
|
8
8
|
import { generateUniqueAlias } from './generate.js';
|
|
9
|
+
import { collectExportedNames, collectAllBindingNames, collectBuilderWrappedNames, isBuilderCall } from './collect-names.js';
|
|
9
10
|
/**
|
|
10
11
|
* 生成唯一的默认导出组件名称
|
|
11
12
|
* 避免与已存在的名称冲突
|
|
@@ -23,58 +24,22 @@ function generateUniqueDefaultName(exportedNames) {
|
|
|
23
24
|
function isValidComponentName(name) {
|
|
24
25
|
return /^[A-Z]/.test(name);
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
* 从命名导出中收集名称
|
|
28
|
-
*/
|
|
29
|
-
function collectFromNamedExport(node, names) {
|
|
30
|
-
if (node.declaration) {
|
|
31
|
-
if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
|
|
32
|
-
names.add(node.declaration.id.name);
|
|
33
|
-
}
|
|
34
|
-
else if (node.declaration.type === 'VariableDeclaration') {
|
|
35
|
-
for (const decl of node.declaration.declarations) {
|
|
36
|
-
if (decl.id.type === 'Identifier') {
|
|
37
|
-
names.add(decl.id.name);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (node.specifiers) {
|
|
43
|
-
for (const spec of node.specifiers) {
|
|
44
|
-
if (spec.type === 'ExportSpecifier') {
|
|
45
|
-
names.add(spec.local.name);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* 从默认导出中收集名称
|
|
52
|
-
*/
|
|
53
|
-
function collectFromDefaultExport(node, names) {
|
|
54
|
-
const decl = node.declaration;
|
|
55
|
-
if (decl.type === 'FunctionDeclaration' && decl.id) {
|
|
56
|
-
names.add(decl.id.name);
|
|
57
|
-
}
|
|
58
|
-
else if (decl.type === 'Identifier') {
|
|
59
|
-
names.add(decl.name);
|
|
60
|
-
}
|
|
61
|
-
// 匿名函数不在此处预留名称,而是在处理时动态生成唯一名称
|
|
62
|
-
}
|
|
63
|
-
function tryAddComponent(name, node, exportedNames, components) {
|
|
27
|
+
function tryAddComponent(name, node, exportedNames, components, builderWrappedNames = new Set()) {
|
|
64
28
|
if (isValidComponentName(name) && exportedNames.has(name)) {
|
|
65
|
-
|
|
29
|
+
const isWrapped = builderWrappedNames.has(name);
|
|
30
|
+
components.push({ name, node, isWrapped });
|
|
66
31
|
}
|
|
67
32
|
}
|
|
68
33
|
/**
|
|
69
34
|
* 处理变量声明中的组件
|
|
70
35
|
*/
|
|
71
|
-
function processVariableDeclaration(declaration, exportedNames, components) {
|
|
36
|
+
function processVariableDeclaration(declaration, exportedNames, components, builderWrappedNames = new Set()) {
|
|
72
37
|
for (const decl of declaration.declarations) {
|
|
73
38
|
if (decl.id.type !== 'Identifier')
|
|
74
39
|
continue;
|
|
75
40
|
const init = decl.init;
|
|
76
41
|
if (init?.type === 'ArrowFunctionExpression' || init?.type === 'FunctionExpression') {
|
|
77
|
-
tryAddComponent(decl.id.name, init, exportedNames, components);
|
|
42
|
+
tryAddComponent(decl.id.name, init, exportedNames, components, builderWrappedNames);
|
|
78
43
|
}
|
|
79
44
|
}
|
|
80
45
|
}
|
|
@@ -93,14 +58,43 @@ function convertToNamedFunctionDeclaration(func, name) {
|
|
|
93
58
|
funcDecl.loc = func.loc;
|
|
94
59
|
return funcDecl;
|
|
95
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* 从调用表达式中提取函数参数
|
|
63
|
+
* 将 export default builder(()=><div/>) 转换为:
|
|
64
|
+
* const _defaultExport = ()=><div/>
|
|
65
|
+
* export default builder(_defaultExport)
|
|
66
|
+
* @param callExpr - 调用表达式
|
|
67
|
+
* @param exportedNames - 已存在的名称集合
|
|
68
|
+
* @param builderAlias - builder 的本地别名
|
|
69
|
+
* @returns 提取结果,包含名称、函数声明节点和是否是 builder 包装
|
|
70
|
+
*/
|
|
71
|
+
function extractFunctionFromCallExpression(callExpr, exportedNames, builderAlias) {
|
|
72
|
+
const isBuilder = isBuilderCall(callExpr, builderAlias);
|
|
73
|
+
for (let i = 0; i < callExpr.arguments.length; i++) {
|
|
74
|
+
const arg = callExpr.arguments[i];
|
|
75
|
+
if (arg.type === 'ArrowFunctionExpression' || arg.type === 'FunctionExpression') {
|
|
76
|
+
const name = generateUniqueDefaultName(exportedNames);
|
|
77
|
+
const funcNode = convertToNamedFunctionDeclaration(arg, name);
|
|
78
|
+
callExpr.arguments[i] = t.identifier(name);
|
|
79
|
+
return { name, funcNode, isBuilderWrapped: isBuilder };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
96
84
|
/**
|
|
97
85
|
* 处理默认导出的匿名函数
|
|
98
86
|
* 为匿名函数生成唯一名称并转换为命名函数声明
|
|
87
|
+
* @param node - 默认导出节点
|
|
88
|
+
* @param program - AST Program 节点,用于插入提取的函数声明
|
|
89
|
+
* @param exportedNames - 已存在的名称集合
|
|
90
|
+
* @param components - 组件信息数组
|
|
91
|
+
* @param builderAlias - builder 的本地别名
|
|
99
92
|
*/
|
|
100
|
-
function processAnonymousDefaultExport(node, exportedNames, components) {
|
|
93
|
+
function processAnonymousDefaultExport(node, program, exportedNames, components, builderAlias) {
|
|
101
94
|
const decl = node.declaration;
|
|
102
95
|
let funcNode = null;
|
|
103
96
|
let name;
|
|
97
|
+
let isWrapped = false;
|
|
104
98
|
if (decl.type === 'FunctionDeclaration' && !decl.id) {
|
|
105
99
|
name = generateUniqueDefaultName(exportedNames);
|
|
106
100
|
decl.id = t.identifier(name);
|
|
@@ -116,59 +110,55 @@ function processAnonymousDefaultExport(node, exportedNames, components) {
|
|
|
116
110
|
funcNode = convertToNamedFunctionDeclaration(decl, name);
|
|
117
111
|
node.declaration = funcNode;
|
|
118
112
|
}
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (node.type === 'ExportNamedDeclaration') {
|
|
130
|
-
collectFromNamedExport(node, names);
|
|
131
|
-
}
|
|
132
|
-
else if (node.type === 'ExportDefaultDeclaration') {
|
|
133
|
-
collectFromDefaultExport(node, names);
|
|
113
|
+
else if (decl.type === 'CallExpression') {
|
|
114
|
+
const result = extractFunctionFromCallExpression(decl, exportedNames, builderAlias);
|
|
115
|
+
if (result) {
|
|
116
|
+
name = result.name;
|
|
117
|
+
funcNode = result.funcNode;
|
|
118
|
+
isWrapped = result.isBuilderWrapped;
|
|
119
|
+
const exportIndex = program.body.indexOf(node);
|
|
120
|
+
if (exportIndex !== -1) {
|
|
121
|
+
program.body.splice(exportIndex, 0, funcNode);
|
|
122
|
+
}
|
|
134
123
|
}
|
|
135
124
|
}
|
|
136
|
-
|
|
125
|
+
if (funcNode) {
|
|
126
|
+
components.push({ name: name, node: funcNode, isWrapped });
|
|
127
|
+
}
|
|
137
128
|
}
|
|
138
129
|
/**
|
|
139
130
|
* 收集模块中的组件函数
|
|
131
|
+
* @param program - AST Program 节点
|
|
132
|
+
* @param builderAlias - builder 函数的本地别名(用于识别纯构建组件)
|
|
133
|
+
* @returns 组件信息数组
|
|
140
134
|
*/
|
|
141
|
-
export function collectComponentFunctions(program) {
|
|
135
|
+
export function collectComponentFunctions(program, builderAlias = null) {
|
|
142
136
|
const exportedNames = collectExportedNames(program);
|
|
137
|
+
const allBindingNames = collectAllBindingNames(program);
|
|
138
|
+
const builderWrappedNames = collectBuilderWrappedNames(program, builderAlias);
|
|
143
139
|
const components = [];
|
|
144
140
|
for (const node of program.body) {
|
|
145
|
-
// 普通函数声明
|
|
146
141
|
if (node.type === 'FunctionDeclaration' && node.id) {
|
|
147
|
-
tryAddComponent(node.id.name, node, exportedNames, components);
|
|
142
|
+
tryAddComponent(node.id.name, node, exportedNames, components, builderWrappedNames);
|
|
148
143
|
}
|
|
149
|
-
// 普通变量声明
|
|
150
144
|
else if (node.type === 'VariableDeclaration') {
|
|
151
|
-
processVariableDeclaration(node, exportedNames, components);
|
|
145
|
+
processVariableDeclaration(node, exportedNames, components, builderWrappedNames);
|
|
152
146
|
}
|
|
153
|
-
// 命名导出
|
|
154
147
|
else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
|
|
155
148
|
if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
|
|
156
|
-
tryAddComponent(node.declaration.id.name, node.declaration, exportedNames, components);
|
|
149
|
+
tryAddComponent(node.declaration.id.name, node.declaration, exportedNames, components, builderWrappedNames);
|
|
157
150
|
}
|
|
158
151
|
else if (node.declaration.type === 'VariableDeclaration') {
|
|
159
|
-
processVariableDeclaration(node.declaration, exportedNames, components);
|
|
152
|
+
processVariableDeclaration(node.declaration, exportedNames, components, builderWrappedNames);
|
|
160
153
|
}
|
|
161
154
|
}
|
|
162
|
-
// 默认导出
|
|
163
155
|
else if (node.type === 'ExportDefaultDeclaration') {
|
|
164
156
|
const decl = node.declaration;
|
|
165
|
-
// 命名函数声明
|
|
166
157
|
if (decl.type === 'FunctionDeclaration' && decl.id) {
|
|
167
|
-
tryAddComponent(decl.id.name, decl, exportedNames, components);
|
|
158
|
+
tryAddComponent(decl.id.name, decl, exportedNames, components, builderWrappedNames);
|
|
168
159
|
}
|
|
169
|
-
// 匿名函数(函数声明、函数表达式、箭头函数)
|
|
170
160
|
else {
|
|
171
|
-
processAnonymousDefaultExport(node,
|
|
161
|
+
processAnonymousDefaultExport(node, program, allBindingNames, components, builderAlias);
|
|
172
162
|
}
|
|
173
163
|
}
|
|
174
164
|
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { isWhitespaceJSXText } from './ast-guards.js';
|
|
2
|
-
export { getJSXElementName, isPureCompileComponent, isComponent, isNativeElement, getJSXAttributeByName, hasDirective, getDirectiveValue, isVIfChain, isVIf, isVElseIf, isVElse, removeVDirectives, removeVIfChainDirectives, removeAttribute, filterWhitespaceChildren, hasEffectiveChildren, filterEffectiveChildren,
|
|
3
|
-
export { createUnrefCall,
|
|
2
|
+
export { getJSXElementName, isPureCompileComponent, isComponent, isNativeElement, getJSXAttributeByName, hasDirective, getDirectiveValue, isVIfChain, isVIf, isVElseIf, isVElse, removeVDirectives, removeVIfChainDirectives, removeAttribute, filterWhitespaceChildren, hasEffectiveChildren, filterEffectiveChildren, validateNoDirectMatchChild } from './jsx-helpers.js';
|
|
3
|
+
export { createUnrefCall, createAccessorCall, createExprCall, createBranchCall, createCreateViewCall, createWithDirectivesCall, createArrowFunction, createLocationObject, addPureComment, getAlias, getDevLocInfo } from './ast-builders.js';
|
|
4
4
|
export { collectPatternBindings, collectObjectPatternBindings } from './pattern-helpers.js';
|
|
5
5
|
export { createBranch, createBinaryBranch, buildNestedCondition, type BranchConfig } from './branch-factory.js';
|
|
6
6
|
export { validateVIfChain, collectVIfChainInfo, collectFragmentVIfChains, type VIfChainInfo } from './vif-helpers.js';
|
package/dist/utils/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// 类型守卫
|
|
2
2
|
export { isWhitespaceJSXText } from './ast-guards.js';
|
|
3
3
|
// JSX 辅助函数
|
|
4
|
-
export { getJSXElementName, isPureCompileComponent, isComponent, isNativeElement, getJSXAttributeByName, hasDirective, getDirectiveValue, isVIfChain, isVIf, isVElseIf, isVElse, removeVDirectives, removeVIfChainDirectives, removeAttribute, filterWhitespaceChildren, hasEffectiveChildren, filterEffectiveChildren,
|
|
4
|
+
export { getJSXElementName, isPureCompileComponent, isComponent, isNativeElement, getJSXAttributeByName, hasDirective, getDirectiveValue, isVIfChain, isVIf, isVElseIf, isVElse, removeVDirectives, removeVIfChainDirectives, removeAttribute, filterWhitespaceChildren, hasEffectiveChildren, filterEffectiveChildren, validateNoDirectMatchChild } from './jsx-helpers.js';
|
|
5
5
|
// AST 构建函数
|
|
6
|
-
export { createUnrefCall,
|
|
6
|
+
export { createUnrefCall, createAccessorCall, createExprCall, createBranchCall, createCreateViewCall, createWithDirectivesCall, createArrowFunction, createLocationObject, addPureComment, getAlias, getDevLocInfo } from './ast-builders.js';
|
|
7
7
|
// 模式处理辅助函数
|
|
8
8
|
export { collectPatternBindings, collectObjectPatternBindings } from './pattern-helpers.js';
|
|
9
9
|
// Branch 工厂
|
|
@@ -77,7 +77,8 @@ export declare function hasEffectiveChildren(node: JSXElement): boolean;
|
|
|
77
77
|
*/
|
|
78
78
|
export declare function filterEffectiveChildren(node: JSXElement): t.Node[];
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
80
|
+
* 校验子节点中不能直接包含 Match 组件
|
|
81
|
+
* Match 必须在 Switch 内使用,非 Switch 元素的子节点中不允许出现 Match
|
|
81
82
|
* @param children - 子节点数组
|
|
82
83
|
*/
|
|
83
|
-
export declare function
|
|
84
|
+
export declare function validateNoDirectMatchChild(children: t.Node[]): void;
|
|
@@ -205,10 +205,11 @@ export function filterEffectiveChildren(node) {
|
|
|
205
205
|
});
|
|
206
206
|
}
|
|
207
207
|
/**
|
|
208
|
-
*
|
|
208
|
+
* 校验子节点中不能直接包含 Match 组件
|
|
209
|
+
* Match 必须在 Switch 内使用,非 Switch 元素的子节点中不允许出现 Match
|
|
209
210
|
* @param children - 子节点数组
|
|
210
211
|
*/
|
|
211
|
-
export function
|
|
212
|
+
export function validateNoDirectMatchChild(children) {
|
|
212
213
|
for (const child of children) {
|
|
213
214
|
if (isJSXElement(child)) {
|
|
214
215
|
const childName = getJSXElementName(child);
|