@vitarx/plugin-vite 1.0.0-beta.1 → 1.0.0-beta.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.
Files changed (41) hide show
  1. package/dist/constants/index.d.ts +1 -0
  2. package/dist/constants/index.js +1 -0
  3. package/dist/context.d.ts +2 -0
  4. package/dist/context.js +1 -0
  5. package/dist/hmr-client/update.js +21 -4
  6. package/dist/hmr-client/utils.js +11 -3
  7. package/dist/index.js +9 -10
  8. package/dist/passes/components/ifBlock.d.ts +3 -0
  9. package/dist/passes/components/ifBlock.js +24 -8
  10. package/dist/passes/components/switch.js +49 -21
  11. package/dist/passes/directives/processDirectives.d.ts +3 -1
  12. package/dist/passes/directives/processDirectives.js +36 -9
  13. package/dist/passes/directives/vIf.d.ts +7 -2
  14. package/dist/passes/directives/vIf.js +43 -30
  15. package/dist/passes/hmr/inject-state.js +64 -7
  16. package/dist/passes/hmr/inject.js +4 -3
  17. package/dist/passes/imports/collectImports.d.ts +1 -4
  18. package/dist/passes/imports/collectImports.js +4 -5
  19. package/dist/passes/imports/collectRefVariables.d.ts +7 -0
  20. package/dist/passes/imports/collectRefVariables.js +69 -3
  21. package/dist/passes/imports/index.d.ts +1 -1
  22. package/dist/passes/imports/index.js +1 -1
  23. package/dist/passes/index.d.ts +1 -1
  24. package/dist/passes/index.js +1 -1
  25. package/dist/passes/jsx/processChildren.js +30 -1
  26. package/dist/passes/jsx/processJSXElement.js +27 -25
  27. package/dist/passes/jsx/processJSXFragment.d.ts +1 -1
  28. package/dist/passes/jsx/processJSXFragment.js +3 -2
  29. package/dist/passes/props/attribute.d.ts +3 -1
  30. package/dist/passes/props/attribute.js +92 -16
  31. package/dist/transform.js +3 -2
  32. package/dist/utils/ast-builders.js +2 -11
  33. package/dist/utils/branch-factory.js +1 -1
  34. package/dist/utils/collect-names.js +29 -0
  35. package/dist/utils/index.d.ts +1 -1
  36. package/dist/utils/index.js +1 -1
  37. package/dist/utils/jsx-helpers.d.ts +6 -0
  38. package/dist/utils/jsx-helpers.js +28 -3
  39. package/dist/utils/vif-helpers.d.ts +1 -3
  40. package/dist/utils/vif-helpers.js +2 -2
  41. package/package.json +1 -1
@@ -47,16 +47,73 @@ export function createWrappedComponentHMRStatements(componentName) {
47
47
  */
48
48
  export function collectLocalVariableNames(functionBody) {
49
49
  const variableNames = new Set();
50
- for (const stmt of functionBody.body) {
51
- if (stmt.type === 'VariableDeclaration') {
52
- for (const decl of stmt.declarations) {
53
- if (decl.id.type !== 'VoidPattern') {
54
- collectPatternBindings(decl.id, variableNames);
55
- }
50
+ collectFromBlock(functionBody, variableNames);
51
+ return Array.from(variableNames);
52
+ }
53
+ function collectFromBlock(block, variableNames) {
54
+ for (const stmt of block.body) {
55
+ collectFromStatement(stmt, variableNames);
56
+ }
57
+ }
58
+ function collectFromStatement(stmt, variableNames) {
59
+ if (stmt.type === 'VariableDeclaration') {
60
+ for (const decl of stmt.declarations) {
61
+ if (decl.id.type !== 'VoidPattern') {
62
+ collectPatternBindings(decl.id, variableNames);
56
63
  }
57
64
  }
58
65
  }
59
- return Array.from(variableNames);
66
+ else if (stmt.type === 'IfStatement') {
67
+ if (stmt.consequent.type === 'BlockStatement') {
68
+ collectFromBlock(stmt.consequent, variableNames);
69
+ }
70
+ else {
71
+ collectFromStatement(stmt.consequent, variableNames);
72
+ }
73
+ if (stmt.alternate) {
74
+ if (stmt.alternate.type === 'BlockStatement') {
75
+ collectFromBlock(stmt.alternate, variableNames);
76
+ }
77
+ else {
78
+ collectFromStatement(stmt.alternate, variableNames);
79
+ }
80
+ }
81
+ }
82
+ else if (stmt.type === 'ForStatement' || stmt.type === 'WhileStatement' || stmt.type === 'DoWhileStatement') {
83
+ if (stmt.body.type === 'BlockStatement') {
84
+ collectFromBlock(stmt.body, variableNames);
85
+ }
86
+ else {
87
+ collectFromStatement(stmt.body, variableNames);
88
+ }
89
+ }
90
+ else if (stmt.type === 'ForInStatement' || stmt.type === 'ForOfStatement') {
91
+ if (stmt.body.type === 'BlockStatement') {
92
+ collectFromBlock(stmt.body, variableNames);
93
+ }
94
+ else {
95
+ collectFromStatement(stmt.body, variableNames);
96
+ }
97
+ }
98
+ else if (stmt.type === 'BlockStatement') {
99
+ collectFromBlock(stmt, variableNames);
100
+ }
101
+ else if (stmt.type === 'SwitchStatement') {
102
+ for (const c of stmt.cases) {
103
+ for (const s of c.consequent) {
104
+ collectFromStatement(s, variableNames);
105
+ }
106
+ }
107
+ }
108
+ else if (stmt.type === 'TryStatement') {
109
+ collectFromBlock(stmt.block, variableNames);
110
+ if (stmt.handler) {
111
+ collectFromBlock(stmt.handler.body, variableNames);
112
+ }
113
+ if (stmt.finalizer) {
114
+ collectFromBlock(stmt.finalizer, variableNames);
115
+ }
116
+ }
60
117
  }
61
118
  /**
62
119
  * 判断表达式是否为函数类型
@@ -50,11 +50,12 @@ function createHotAcceptStatement() {
50
50
  */
51
51
  function generateComponentId(filename, componentName) {
52
52
  const combined = `${filename}:${componentName}`;
53
- let hash = 0;
53
+ let hash = 2166136261;
54
54
  for (let i = 0; i < combined.length; i++) {
55
- hash = ((hash << 5) - hash + combined.charCodeAt(i)) | 0;
55
+ hash ^= combined.charCodeAt(i);
56
+ hash = Math.imul(hash, 16777619);
56
57
  }
57
- return Math.abs(hash).toString(16);
58
+ return (hash >>> 0).toString(16);
58
59
  }
59
60
  /**
60
61
  * 注入 HMR 支持
@@ -10,10 +10,7 @@ import * as t from '@babel/types';
10
10
  * @param program - AST Program 节点
11
11
  * @returns 本地变量名集合和 vitarx 导入映射
12
12
  */
13
- export declare function collectExistingImports(program: t.Program): {
14
- localNames: Set<string>;
15
- vitarxImports: Map<string, string>;
16
- };
13
+ export declare function collectExistingImports(program: t.Program): Map<string, string>;
17
14
  /**
18
15
  * 收集本地变量绑定
19
16
  * 包括导入绑定、变量声明、函数声明、类声明
@@ -7,18 +7,17 @@ import { collectPatternBindings } from '../../utils/index.js';
7
7
  * @returns 本地变量名集合和 vitarx 导入映射
8
8
  */
9
9
  export function collectExistingImports(program) {
10
- const localNames = new Set();
11
10
  const vitarxImports = new Map();
12
11
  for (const node of program.body) {
13
12
  if (node.type !== 'ImportDeclaration')
14
13
  continue;
15
- // 跳过 import type 和 import typeof 语句
16
14
  if (node.importKind === 'type' || node.importKind === 'typeof')
17
15
  continue;
18
16
  const source = node.source.value;
17
+ if (source !== VITARX_MODULE)
18
+ continue;
19
19
  for (const specifier of node.specifiers) {
20
- localNames.add(specifier.local.name);
21
- if (source === VITARX_MODULE && specifier.type === 'ImportSpecifier') {
20
+ if (specifier.type === 'ImportSpecifier') {
22
21
  const importedName = specifier.imported.type === 'Identifier'
23
22
  ? specifier.imported.name
24
23
  : specifier.imported.value;
@@ -26,7 +25,7 @@ export function collectExistingImports(program) {
26
25
  }
27
26
  }
28
27
  }
29
- return { localNames, vitarxImports };
28
+ return vitarxImports;
30
29
  }
31
30
  /**
32
31
  * 收集本地变量绑定
@@ -20,3 +20,10 @@ export declare function collectRefApiAliases(program: t.Program): RefApiAliases;
20
20
  * @returns ref 变量名集合
21
21
  */
22
22
  export declare function collectRefVariables(program: t.Program, refApiAliases: RefApiAliases): Set<string>;
23
+ /**
24
+ * 收集确定不是 ref 的变量
25
+ * 包括函数声明、箭头函数和函数表达式变量
26
+ * @param program - AST Program 节点
27
+ * @returns 非 ref 变量名集合
28
+ */
29
+ export declare function collectNonRefVariables(program: t.Program): Set<string>;
@@ -44,8 +44,12 @@ export function collectRefVariables(program, refApiAliases) {
44
44
  const refVariables = new Set();
45
45
  const { refApiLocalNames, toRefsLocalNames } = buildApiNameSets(refApiAliases);
46
46
  for (const node of program.body) {
47
- if (node.type !== 'VariableDeclaration')
48
- continue;
47
+ collectRefVariablesFromNode(node, refVariables, refApiLocalNames, toRefsLocalNames);
48
+ }
49
+ return refVariables;
50
+ }
51
+ function collectRefVariablesFromNode(node, refVariables, refApiLocalNames, toRefsLocalNames) {
52
+ if (node.type === 'VariableDeclaration') {
49
53
  for (const decl of node.declarations) {
50
54
  if (!decl.init)
51
55
  continue;
@@ -64,7 +68,69 @@ export function collectRefVariables(program, refApiAliases) {
64
68
  }
65
69
  }
66
70
  }
67
- return refVariables;
71
+ else if (node.type === 'FunctionDeclaration' && node.body) {
72
+ for (const stmt of node.body.body) {
73
+ collectRefVariablesFromNode(stmt, refVariables, refApiLocalNames, toRefsLocalNames);
74
+ }
75
+ }
76
+ else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
77
+ collectRefVariablesFromNode(node.declaration, refVariables, refApiLocalNames, toRefsLocalNames);
78
+ }
79
+ else if (node.type === 'ExportDefaultDeclaration') {
80
+ const decl = node.declaration;
81
+ if (decl.type === 'FunctionDeclaration' && decl.body) {
82
+ for (const stmt of decl.body.body) {
83
+ collectRefVariablesFromNode(stmt, refVariables, refApiLocalNames, toRefsLocalNames);
84
+ }
85
+ }
86
+ }
87
+ }
88
+ /**
89
+ * 收集确定不是 ref 的变量
90
+ * 包括函数声明、箭头函数和函数表达式变量
91
+ * @param program - AST Program 节点
92
+ * @returns 非 ref 变量名集合
93
+ */
94
+ export function collectNonRefVariables(program) {
95
+ const nonRefVariables = new Set();
96
+ for (const node of program.body) {
97
+ collectNonRefFromNode(node, nonRefVariables);
98
+ }
99
+ return nonRefVariables;
100
+ }
101
+ function collectNonRefFromNode(node, nonRefVariables) {
102
+ if (node.type === 'FunctionDeclaration' && node.id) {
103
+ nonRefVariables.add(node.id.name);
104
+ if (node.body) {
105
+ for (const stmt of node.body.body) {
106
+ collectNonRefFromNode(stmt, nonRefVariables);
107
+ }
108
+ }
109
+ }
110
+ else if (node.type === 'VariableDeclaration') {
111
+ for (const decl of node.declarations) {
112
+ if (!decl.init)
113
+ continue;
114
+ if (decl.id.type !== 'Identifier')
115
+ continue;
116
+ const init = decl.init;
117
+ if (init.type === 'ArrowFunctionExpression' ||
118
+ init.type === 'FunctionExpression') {
119
+ nonRefVariables.add(decl.id.name);
120
+ }
121
+ }
122
+ }
123
+ else if (node.type === 'ExportNamedDeclaration') {
124
+ if (node.declaration) {
125
+ collectNonRefFromNode(node.declaration, nonRefVariables);
126
+ }
127
+ }
128
+ else if (node.type === 'ExportDefaultDeclaration') {
129
+ const decl = node.declaration;
130
+ if (decl.type === 'FunctionDeclaration' && decl.id) {
131
+ nonRefVariables.add(decl.id.name);
132
+ }
133
+ }
68
134
  }
69
135
  /**
70
136
  * 构建 API 名称集合
@@ -3,5 +3,5 @@
3
3
  * @module passes/imports
4
4
  */
5
5
  export { collectExistingImports, collectLocalBindings } from './collectImports.js';
6
- export { collectRefApiAliases, collectRefVariables } from './collectRefVariables.js';
6
+ export { collectRefApiAliases, collectNonRefVariables, collectRefVariables } from './collectRefVariables.js';
7
7
  export { injectImports } from './injectImports.js';
@@ -3,5 +3,5 @@
3
3
  * @module passes/imports
4
4
  */
5
5
  export { collectExistingImports, collectLocalBindings } from './collectImports.js';
6
- export { collectRefApiAliases, collectRefVariables } from './collectRefVariables.js';
6
+ export { collectRefApiAliases, collectNonRefVariables, collectRefVariables } from './collectRefVariables.js';
7
7
  export { injectImports } from './injectImports.js';
@@ -2,7 +2,7 @@
2
2
  * 编译转换处理模块
3
3
  * @module passes
4
4
  */
5
- export { collectExistingImports, collectLocalBindings, collectRefApiAliases, collectRefVariables, injectImports } from './imports/index.js';
5
+ export { collectExistingImports, collectLocalBindings, collectNonRefVariables, collectRefApiAliases, collectRefVariables, injectImports } from './imports/index.js';
6
6
  export { processPureCompileComponent, processSwitch, processIfBlock } from './components/index.js';
7
7
  export { processVIfChain, processDirectives } from './directives/index.js';
8
8
  export { processChildren, processJSXElement, transformJSXElement, processJSXFragment } from './jsx/index.js';
@@ -3,7 +3,7 @@
3
3
  * @module passes
4
4
  */
5
5
  // 导入处理
6
- export { collectExistingImports, collectLocalBindings, collectRefApiAliases, collectRefVariables, injectImports } from './imports/index.js';
6
+ export { collectExistingImports, collectLocalBindings, collectNonRefVariables, collectRefApiAliases, collectRefVariables, injectImports } from './imports/index.js';
7
7
  // 编译宏组件
8
8
  export { processPureCompileComponent, processSwitch, processIfBlock } from './components/index.js';
9
9
  // 指令处理
@@ -34,13 +34,18 @@ function wrapWithExpr(expr, ctx) {
34
34
  * @returns 处理后的表达式数组
35
35
  */
36
36
  export function processChildren(children, ctx) {
37
+ // 初始化结果数组,用于存储处理后的表达式
37
38
  const result = [];
39
+ // 遍历每个子节点
38
40
  for (const child of children) {
41
+ // 处理单个子节点,将其转换为表达式
39
42
  const processed = processChildNode(child, ctx);
43
+ // 如果处理结果不为null,则添加到结果数组中
40
44
  if (processed !== null) {
41
45
  result.push(processed);
42
46
  }
43
47
  }
48
+ // 返回处理后的表达式数组
44
49
  return result;
45
50
  }
46
51
  /**
@@ -63,6 +68,7 @@ function processChildNode(node, ctx) {
63
68
  if (node.type === 'JSXSpreadChild') {
64
69
  return processChildExpression(node.expression, ctx);
65
70
  }
71
+ // JSXElement/JSXFragment 由 Babel 遍历的 exit 阶段处理,此处直接透传
66
72
  if (isJSXElement(node) || isJSXFragment(node)) {
67
73
  return node;
68
74
  }
@@ -78,27 +84,50 @@ function processChildNode(node, ctx) {
78
84
  * 根据表达式类型生成对应的运行时 API 调用
79
85
  * CallExpression 在此用 expr 包装(用户函数调用需要响应式追踪)
80
86
  */
87
+ /**
88
+ * 处理子表达式函数
89
+ * @param {t.Expression} expr - 要处理的表达式节点
90
+ * @param {TransformContext} ctx - 转换上下文,包含转换所需的环境信息
91
+ * @returns {t.Expression} 处理后的表达式节点
92
+ */
81
93
  function processChildExpression(expr, ctx) {
94
+ // 如果是简单标识符,直接返回
82
95
  if (isIdentifier(expr)) {
83
96
  return expr;
84
97
  }
98
+ // 如果是成员表达式(如 obj.property),调用专门的处理函数
85
99
  if (isMemberExpression(expr)) {
86
100
  return handleMemberExpression(expr, ctx);
87
101
  }
102
+ // 如果是条件表达式(如 ternary operator),递归处理条件表达式
88
103
  if (isConditionalExpression(expr)) {
89
104
  return processConditionalExpression(expr, ctx);
90
105
  }
106
+ // 如果是逻辑表达式、二元表达式或函数调用表达式,用 expr 包装
107
+ // 这些表达式需要响应式追踪,所以需要特殊处理
91
108
  if (isLogicalExpression(expr) || isBinaryExpression(expr) || expr.type === 'CallExpression') {
92
109
  return wrapWithExpr(expr, ctx);
93
110
  }
111
+ // 其他类型的表达式直接返回,无需特殊处理
94
112
  return expr;
95
113
  }
96
114
  /**
97
115
  * 处理条件表达式,转换为 branch 调用
116
+ * 该函数接收一个条件表达式节点和转换上下文,将其转换为二元分支调用
117
+ * @param node - 条件表达式节点,包含测试条件、 consequent 和 alternate 分支
118
+ * @param ctx - 转换上下文,包含转换过程中需要的辅助信息和工具函数
119
+ * @returns 返回一个调用表达式,表示转换后的分支逻辑
98
120
  */
99
- function processConditionalExpression(node, ctx) {
121
+ function processConditionalExpression(node, // 条件表达式节点,包含 test、consequent 和 alternate 属性
122
+ ctx // 转换上下文,提供转换过程中需要的辅助方法和状态
123
+ ) {
124
+ // 返回一个调用表达式,表示分支逻辑
125
+ // 解构条件表达式节点的三个主要部分:测试条件、真分支和假分支
100
126
  const { test, consequent, alternate } = node;
127
+ // 处理真分支,如果处理结果为空则使用 null 字面量作为默认值
101
128
  const processedConsequent = processChildNode(consequent, ctx) || t.nullLiteral();
129
+ // 处理假分支,如果处理结果为空则使用 null 字面量作为默认值
102
130
  const processedAlternate = processChildNode(alternate, ctx) || t.nullLiteral();
131
+ // 创建并返回一个二元分支调用,传入测试条件、处理后的真分支和假分支
103
132
  return createBinaryBranch(test, processedConsequent, processedAlternate, ctx);
104
133
  }
@@ -2,7 +2,7 @@ import * as t from '@babel/types';
2
2
  import { isJSXElement } from '@babel/types';
3
3
  import { addWarning, markImport } from '../../context.js';
4
4
  import { createError, createWarning } from '../../error.js';
5
- import { addPureComment, createArrowFunction, createBranch, createCreateViewCall, filterEffectiveChildren, getAlias, getDevLocInfo, getDirectiveValue, getJSXAttributeByName, getJSXElementName, hasEffectiveChildren, isNativeElement, isVElse, isVIf, isVIfChain, removeVIfChainDirectives } from '../../utils/index.js';
5
+ import { addPureComment, createArrowFunction, createBranch, createCreateViewCall, filterEffectiveChildren, getAlias, getDevLocInfo, getDirectiveValue, getJSXAttributeByName, getJSXElementName, hasEffectiveChildren, isVElse, isVIf, isVIfChain, removeVIfChainDirectives, resolveJSXElementType } from '../../utils/index.js';
6
6
  import { processDirectives, transformChildrenVIfChains } from '../directives/index.js';
7
7
  import { processProps } from '../props/index.js';
8
8
  import { processChildren } from './processChildren.js';
@@ -26,26 +26,14 @@ export function processJSXElement(path, ctx) {
26
26
  * 校验 Match 组件必须在 Switch 内使用
27
27
  */
28
28
  function validateMatchInSwitch(path) {
29
- const parent = path.parentPath;
30
- if (!parent) {
31
- throw createError('E012', path.node);
32
- }
33
- // 检查父元素是否是 Switch
34
- if (parent.node.type === 'JSXElement') {
35
- const parentName = getJSXElementName(parent.node);
36
- if (parentName === 'Switch') {
37
- return;
38
- }
39
- }
40
- // 检查是否在 Fragment 内且 Fragment 的父元素是 Switch
41
- if (parent.node.type === 'JSXFragment' || parent.node.type === 'JSXElement') {
42
- const grandParent = parent.parentPath;
43
- if (grandParent?.node.type === 'JSXElement') {
44
- const grandParentName = getJSXElementName(grandParent.node);
45
- if (grandParentName === 'Switch') {
29
+ let current = path.parentPath;
30
+ while (current) {
31
+ if (current.node.type === 'JSXElement') {
32
+ const name = getJSXElementName(current.node);
33
+ if (name === 'Switch')
46
34
  return;
47
- }
48
35
  }
36
+ current = current.parentPath;
49
37
  }
50
38
  throw createError('E012', path.node);
51
39
  }
@@ -57,9 +45,6 @@ function validateMatchInSwitch(path) {
57
45
  * @returns 转换后的表达式
58
46
  */
59
47
  export function transformJSXElement(node, ctx, handleVIf = false) {
60
- const name = getJSXElementName(node);
61
- if (!name)
62
- return null;
63
48
  // 处理 v-if 链
64
49
  if (handleVIf && isVIfChain(node)) {
65
50
  if (isVIf(node)) {
@@ -69,8 +54,10 @@ export function transformJSXElement(node, ctx, handleVIf = false) {
69
54
  throw createError(isVElse(node) ? 'E003' : 'E004', node);
70
55
  }
71
56
  }
72
- // 确定元素类型
73
- const type = isNativeElement(name) ? t.stringLiteral(name) : t.identifier(name);
57
+ // 解析 JSX 元素类型
58
+ const type = resolveJSXElementType(node);
59
+ if (!type)
60
+ return null;
74
61
  // 检测是否有有效子元素
75
62
  const hasChildren = hasEffectiveChildren(node);
76
63
  // 处理属性(有子元素时跳过 children 属性)
@@ -137,20 +124,35 @@ function processElementChildren(node, props, ctx) {
137
124
  }
138
125
  /**
139
126
  * 转换单个 v-if 元素
127
+ * 该函数处理带有 v-if 指令的 JSX 元素,将其转换为条件渲染的函数调用
128
+ * @param node - 要转换的 JSX 元素节点
129
+ * @param ctx - 转换上下文,包含转换所需的环境信息
130
+ * @returns 返回转换后的条件渲染函数调用表达式,如果转换失败则返回 null
140
131
  */
141
132
  function transformSingleVIf(node, ctx) {
133
+ // 首先检查节点是否是有效的 v-if 元素
142
134
  if (!isVIf(node))
143
135
  return null;
136
+ // 获取 v-if 指令的值(条件表达式)
144
137
  const condition = getDirectiveValue(node, 'v-if');
138
+ // 如果没有找到条件表达式,则返回 null
145
139
  if (!condition)
146
140
  return null;
141
+ // 移除节点上的 v-if 相关指令链
147
142
  removeVIfChainDirectives(node);
143
+ // 转换 JSX 元素,不保留原始属性
148
144
  const transformedNode = transformJSXElement(node, ctx, false);
145
+ // 如果转换失败,返回 null
149
146
  if (!transformedNode)
150
147
  return null;
151
- const branchCall = createBranch({ conditions: [condition], branches: [createArrowFunction(transformedNode)] }, ctx);
148
+ // 创建条件分支的函数调用
149
+ const branchCall = createBranch(
150
+ // 包含条件数组和对应的分支函数
151
+ { conditions: [condition], branches: [createArrowFunction(transformedNode)] }, ctx);
152
+ // 保留原始节点的位置信息
152
153
  if (node.loc) {
153
154
  branchCall.loc = node.loc;
154
155
  }
156
+ // 返回转换后的分支函数调用
155
157
  return branchCall;
156
158
  }
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import type { NodePath } from '@babel/traverse';
7
7
  import * as t from '@babel/types';
8
- import { TransformContext } from '../../context.js';
8
+ import { type TransformContext } from '../../context.js';
9
9
  /**
10
10
  * 处理 JSX Fragment
11
11
  * @param path - JSX Fragment 路径
@@ -1,4 +1,5 @@
1
1
  import * as t from '@babel/types';
2
+ import { markImport } from '../../context.js';
2
3
  import { addPureComment, createCreateViewCall, filterWhitespaceChildren, getAlias, getDevLocInfo, validateNoDirectMatchChild } from '../../utils/index.js';
3
4
  import { processChildren } from './processChildren.js';
4
5
  /**
@@ -13,8 +14,8 @@ export function processJSXFragment(path, ctx) {
13
14
  // 校验 Match 组件
14
15
  validateNoDirectMatchChild(children);
15
16
  // 标记需要的导入
16
- ctx.imports.Fragment = true;
17
- ctx.imports.createView = true;
17
+ markImport(ctx, 'Fragment');
18
+ markImport(ctx, 'createView');
18
19
  const fragmentAlias = getAlias(ctx.vitarxAliases, 'Fragment');
19
20
  const createViewAlias = getAlias(ctx.vitarxAliases, 'createView');
20
21
  const locInfo = getDevLocInfo(ctx, node);
@@ -39,7 +39,9 @@ export declare function getAttributeValue(value: t.JSXAttribute['value']): t.Exp
39
39
  * @param ctx - 转换上下文
40
40
  * @returns 对象属性或方法节点
41
41
  */
42
- export declare function createProperty(key: string, value: t.Expression, ctx: TransformContext): t.ObjectProperty | t.ObjectMethod;
42
+ export declare function createProperty(key: string, // 属性名称,字符串类型
43
+ value: t.Expression, // 属性值表达式,使用 t.Expression 类型表示
44
+ ctx: TransformContext): t.ObjectProperty | t.ObjectMethod;
43
45
  /**
44
46
  * 处理单个 JSX 属性
45
47
  * 根据属性名类型分发到不同的处理逻辑
@@ -4,7 +4,6 @@
4
4
  * @module passes/props/attribute
5
5
  */
6
6
  import * as t from '@babel/types';
7
- import { isBooleanLiteral, isIdentifier, isJSXExpressionContainer, isNumericLiteral, isStringLiteral } from '@babel/types';
8
7
  import { markImport } from '../../context.js';
9
8
  import { createError } from '../../error.js';
10
9
  import { getAlias } from '../../utils/index.js';
@@ -71,10 +70,10 @@ export function getAttributeValue(value) {
71
70
  if (!value) {
72
71
  return t.booleanLiteral(true);
73
72
  }
74
- if (isStringLiteral(value)) {
73
+ if (t.isStringLiteral(value)) {
75
74
  return value;
76
75
  }
77
- if (isJSXExpressionContainer(value)) {
76
+ if (t.isJSXExpressionContainer(value)) {
78
77
  if (value.expression.type === 'JSXEmptyExpression') {
79
78
  return t.booleanLiteral(true);
80
79
  }
@@ -95,23 +94,101 @@ export function getAttributeValue(value) {
95
94
  * @param ctx - 转换上下文
96
95
  * @returns 对象属性或方法节点
97
96
  */
98
- export function createProperty(key, value, ctx) {
97
+ export function createProperty(key, // 属性名称,字符串类型
98
+ value, // 属性值表达式,使用 t.Expression 类型表示
99
+ ctx // 转换上下文,包含转换过程中的相关信息
100
+ ) {
101
+ // 返回类型为对象属性或对象方法
102
+ // 创建属性名的字面量节点
99
103
  const keyNode = t.stringLiteral(key);
100
- if (isStringLiteral(value) || isNumericLiteral(value) || isBooleanLiteral(value)) {
104
+ // 如果是静态值,直接创建对象属性
105
+ if (isStaticValue(value)) {
101
106
  return t.objectProperty(keyNode, value);
102
107
  }
103
- if (isIdentifier(value)) {
104
- if (ctx.refVariables.has(value.name)) {
105
- return t.objectMethod('get', keyNode, [], t.blockStatement([t.returnStatement(t.memberExpression(value, t.identifier('value')))]));
106
- }
107
- if (key === 'children') {
108
+ // 如果是标识符(变量名)
109
+ if (t.isIdentifier(value)) {
110
+ // 特殊处理 children 属性或不在 refVariables 中的变量
111
+ if (key === 'children' || ctx.nonRefVariables.has(value.name)) {
108
112
  return t.objectProperty(keyNode, value);
109
113
  }
110
- markImport(ctx, 'unref');
111
- const unrefAlias = getAlias(ctx.vitarxAliases, 'unref');
112
- return t.objectMethod('get', keyNode, [], t.blockStatement([t.returnStatement(t.callExpression(t.identifier(unrefAlias), [value]))]));
114
+ // 如果是 ref 变量,创建 getter 方法返回 ref 的 value
115
+ if (ctx.refVariables.has(value.name)) {
116
+ return createGetter(keyNode, t.returnStatement(t.memberExpression(value, t.identifier('value'))));
117
+ }
118
+ // 其他标识符属性创建 unref getter
119
+ return createUnrefGetter(keyNode, value, ctx);
120
+ }
121
+ // 如果是成员表达式(如 obj.property)
122
+ if (t.isMemberExpression(value)) {
123
+ return createUnrefGetter(keyNode, value, ctx);
113
124
  }
114
- return t.objectMethod('get', keyNode, [], t.blockStatement([t.returnStatement(value)]));
125
+ // 如果是调用表达式(如 function())
126
+ if (t.isCallExpression(value)) {
127
+ return createUnrefGetter(keyNode, value, ctx);
128
+ }
129
+ // 默认情况,创建 getter 方法返回值
130
+ return createGetter(keyNode, t.returnStatement(value));
131
+ }
132
+ /**
133
+ * 判断给定的表达式是否为静态值
134
+ * 静态值指的是那些可以在编译时确定值,不会在运行时改变的表达式
135
+ * @param value - 要检查的AST表达式节点
136
+ * @returns 如果是静态值返回true,否则返回false
137
+ */
138
+ function isStaticValue(value) {
139
+ // 使用switch语句检查表达式的类型
140
+ switch (value.type) {
141
+ // 字符串字面量是静态值
142
+ case 'StringLiteral':
143
+ // 数字字面量是静态值
144
+ case 'NumericLiteral':
145
+ // 布尔字面量是静态值
146
+ case 'BooleanLiteral':
147
+ // null字面量是静态值
148
+ case 'NullLiteral':
149
+ // 箭头函数表达式是静态值
150
+ case 'ArrowFunctionExpression':
151
+ // 函数表达式是静态值
152
+ case 'FunctionExpression':
153
+ // 对象表达式是静态值
154
+ case 'ObjectExpression':
155
+ // 数组表达式是静态值
156
+ case 'ArrayExpression':
157
+ return true;
158
+ // 其他类型的表达式都不是静态值
159
+ default:
160
+ return false;
161
+ }
162
+ }
163
+ /**
164
+ * 创建一个getter方法
165
+ * @param keyNode - 属性键的字符串字面量节点
166
+ * @param statement - getter方法体中的语句
167
+ * @returns 返回一个ObjectMethod类型的AST节点,表示一个getter方法
168
+ */
169
+ function createGetter(keyNode, statement) {
170
+ // 使用objectMethod方法创建一个getter方法
171
+ // 参数分别为: 方法类型('get')、属性键、参数数组(空数组)、方法体(包含传入的语句)
172
+ return t.objectMethod('get', keyNode, [], t.blockStatement([statement]));
173
+ }
174
+ /**
175
+ * 创建一个getter方法,该方法会对返回值进行unref处理
176
+ * @param keyNode - 对象的键节点,是一个字符串字面量
177
+ * @param value - 需要进行unref处理的值表达式
178
+ * @param ctx - 转换上下文对象,包含转换所需的各种信息和工具函数
179
+ * @returns 返回一个ObjectMethod类型的AST节点,表示一个getter方法
180
+ */
181
+ function createUnrefGetter(keyNode, // 对象的键,使用字符串字面量表示
182
+ value, // 需要进行unref处理的值表达式
183
+ ctx // 转换上下文,包含转换所需的各种信息和工具函数
184
+ ) {
185
+ // 返回一个对象方法类型的AST节点
186
+ markImport(ctx, 'unref'); // 标记需要导入unref函数
187
+ const unrefAlias = getAlias(ctx.vitarxAliases, 'unref'); // 获取unref函数的别名
188
+ return createGetter(
189
+ // 创建并返回一个getter方法
190
+ keyNode, t.returnStatement(t.callExpression(t.identifier(unrefAlias), [value])) // 返回对value进行unref处理后的结果
191
+ );
115
192
  }
116
193
  /**
117
194
  * 处理单个 JSX 属性
@@ -152,6 +229,5 @@ export function processAttribute(attr, existingPropNames, ctx) {
152
229
  return { type: 'property', property };
153
230
  }
154
231
  // 未知属性类型,作为普通属性处理
155
- const value = getAttributeValue(attr.value);
156
- return { type: 'property', property: t.objectProperty(t.identifier('unknown'), value) };
232
+ throw createError('E002', attr, 'Unsupported attribute name type');
157
233
  }