@vitarx/plugin-vite 1.0.0-beta.1 → 1.0.0-beta.2

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 (34) hide show
  1. package/dist/constants/index.d.ts +1 -0
  2. package/dist/constants/index.js +1 -0
  3. package/dist/hmr-client/update.js +21 -4
  4. package/dist/hmr-client/utils.js +11 -3
  5. package/dist/index.js +9 -10
  6. package/dist/passes/components/ifBlock.d.ts +3 -0
  7. package/dist/passes/components/ifBlock.js +24 -8
  8. package/dist/passes/components/switch.js +49 -21
  9. package/dist/passes/directives/processDirectives.d.ts +3 -1
  10. package/dist/passes/directives/processDirectives.js +36 -9
  11. package/dist/passes/directives/vIf.d.ts +7 -2
  12. package/dist/passes/directives/vIf.js +43 -30
  13. package/dist/passes/hmr/inject-state.js +64 -7
  14. package/dist/passes/hmr/inject.js +4 -3
  15. package/dist/passes/imports/collectImports.d.ts +1 -4
  16. package/dist/passes/imports/collectImports.js +4 -5
  17. package/dist/passes/imports/collectRefVariables.js +22 -3
  18. package/dist/passes/jsx/processChildren.js +30 -1
  19. package/dist/passes/jsx/processJSXElement.js +27 -25
  20. package/dist/passes/jsx/processJSXFragment.d.ts +1 -1
  21. package/dist/passes/jsx/processJSXFragment.js +3 -2
  22. package/dist/passes/props/attribute.d.ts +3 -1
  23. package/dist/passes/props/attribute.js +27 -5
  24. package/dist/transform.js +1 -1
  25. package/dist/utils/ast-builders.js +2 -11
  26. package/dist/utils/branch-factory.js +1 -1
  27. package/dist/utils/collect-names.js +29 -0
  28. package/dist/utils/index.d.ts +1 -1
  29. package/dist/utils/index.js +1 -1
  30. package/dist/utils/jsx-helpers.d.ts +6 -0
  31. package/dist/utils/jsx-helpers.js +28 -3
  32. package/dist/utils/vif-helpers.d.ts +1 -3
  33. package/dist/utils/vif-helpers.js +2 -2
  34. package/package.json +1 -1
@@ -32,6 +32,7 @@ export declare const PURE_COMPILE_COMPONENTS: readonly ["Switch", "Match", "IfBl
32
32
  * 指令前缀
33
33
  */
34
34
  export declare const DIRECTIVE_PREFIX = "v-";
35
+ export declare const V_IF_CHAIN_DIRECTIVES: Set<string>;
35
36
  /**
36
37
  * 纯函数注释
37
38
  */
@@ -32,6 +32,7 @@ export const PURE_COMPILE_COMPONENTS = ['Switch', 'Match', 'IfBlock'];
32
32
  * 指令前缀
33
33
  */
34
34
  export const DIRECTIVE_PREFIX = 'v-';
35
+ export const V_IF_CHAIN_DIRECTIVES = new Set(['v-if', 'v-else-if', 'v-else']);
35
36
  /**
36
37
  * 纯函数注释
37
38
  */
@@ -18,7 +18,13 @@ export function processUpdate(view, newComponent) {
18
18
  const instance = view.instance;
19
19
  // 比较新旧组件的差异,检查逻辑是否有变化
20
20
  const { logic } = diffComponentChange(view.component.toString(), newComponent.toString());
21
- view.component = newComponent;
21
+ // 更新视图中的组件引用
22
+ Object.defineProperty(view, 'component', {
23
+ value: newComponent,
24
+ writable: true,
25
+ enumerable: true,
26
+ configurable: true
27
+ });
22
28
  // 如果逻辑有变化,则完全重新挂载组件
23
29
  if (logic) {
24
30
  const ctx = view.ctx;
@@ -29,12 +35,19 @@ export function processUpdate(view, newComponent) {
29
35
  }
30
36
  // 销毁旧作用域
31
37
  instance.scope.dispose();
32
- instance.scope = new EffectScope({
38
+ // 重新创建新的作用域
39
+ const scope = new EffectScope({
33
40
  name: view.name,
34
41
  errorHandler: (error, source) => {
35
42
  instance.reportError(error, `effect:${source}`);
36
43
  }
37
44
  });
45
+ Object.defineProperty(instance, 'scope', {
46
+ value: scope,
47
+ writable: true,
48
+ enumerable: true,
49
+ configurable: true
50
+ });
38
51
  // 销毁旧的子树
39
52
  instance.subView.dispose();
40
53
  // 创建新的子树
@@ -46,8 +59,12 @@ export function processUpdate(view, newComponent) {
46
59
  instance.reportError(e, 'component:run');
47
60
  subView = createCommentView(`Component<${view.name}>:failed`);
48
61
  }
49
- ;
50
- instance.subView = instance['normalizeView'](subView);
62
+ Object.defineProperty(instance, 'subView', {
63
+ value: instance['normalizeView'](subView),
64
+ writable: true,
65
+ enumerable: true,
66
+ configurable: true
67
+ });
51
68
  // 初始化新的子树
52
69
  instance.subView.init(instance.subViewContext);
53
70
  // 挂载新的子树
@@ -69,15 +69,23 @@ function separateLogicAndRender(functionCode) {
69
69
  };
70
70
  }
71
71
  // 按位置排序,从后向前替换以保持索引正确
72
- uiNodes.sort((a, b) => b.start - a.start);
72
+ uiNodes.sort((a, b) => a.start - b.start);
73
+ const filteredNodes = [];
74
+ for (const node of uiNodes) {
75
+ const isContained = filteredNodes.some(parent => node.start >= parent.start && node.end <= parent.end);
76
+ if (!isContained) {
77
+ filteredNodes.push(node);
78
+ }
79
+ }
80
+ filteredNodes.sort((a, b) => b.start - a.start);
73
81
  // 提取 UI 代码
74
- const renderCode = uiNodes
82
+ const renderCode = filteredNodes
75
83
  .map(n => wrappedCode.slice(n.start, n.end))
76
84
  .reverse()
77
85
  .join('\n');
78
86
  // 移除 UI 代码后的逻辑代码
79
87
  let logicCode = wrappedCode;
80
- for (const node of uiNodes) {
88
+ for (const node of filteredNodes) {
81
89
  logicCode = logicCode.slice(0, node.start) + logicCode.slice(node.end);
82
90
  }
83
91
  return {
package/dist/index.js CHANGED
@@ -4,14 +4,6 @@ import { version } from 'vite';
4
4
  import { shouldTransform, transform } from './transform.js';
5
5
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
6
  const IS_V8 = version.startsWith('8');
7
- let viteTransform;
8
- if (IS_V8) {
9
- // @ts-ignore
10
- viteTransform = (await import('vite')).transformWithOxc;
11
- }
12
- else {
13
- viteTransform = (await import('vite')).transformWithEsbuild;
14
- }
15
7
  /**
16
8
  * vite-plugin-vitarx
17
9
  *
@@ -30,6 +22,7 @@ export default function vitarx(options) {
30
22
  let isDEV = false;
31
23
  let isSSR = false;
32
24
  let viteConfig;
25
+ let viteTransform;
33
26
  return {
34
27
  name: 'vite-plugin-vitarx',
35
28
  enforce: 'pre',
@@ -51,8 +44,7 @@ export default function vitarx(options) {
51
44
  }
52
45
  };
53
46
  },
54
- configResolved(config) {
55
- // 根据最终的配置结果,确定是否是 SSR 模式
47
+ async configResolved(config) {
56
48
  if (!isSSR) {
57
49
  isSSR = !!config.build?.ssr;
58
50
  config.define['__VITARX_SSR__'] = JSON.stringify(isSSR);
@@ -65,6 +57,13 @@ export default function vitarx(options) {
65
57
  sourceMap: true,
66
58
  transformClassNameToClass: options?.transformClassNameToClass ?? false
67
59
  };
60
+ viteConfig = config;
61
+ if (IS_V8) {
62
+ viteTransform = (await import('vite')).transformWithOxc;
63
+ }
64
+ else {
65
+ viteTransform = (await import('vite')).transformWithEsbuild;
66
+ }
68
67
  },
69
68
  async transform(code, id) {
70
69
  if (!shouldTransform(id))
@@ -8,5 +8,8 @@ import * as t from '@babel/types';
8
8
  import { TransformContext } from '../../context.js';
9
9
  /**
10
10
  * 处理 IfBlock 组件
11
+ * 该函数用于处理包含 v-if 指令的 JSX 元素,将其转换为条件分支调用
12
+ * @param path - JSX 元素的 AST 路径
13
+ * @param ctx - 转换上下文对象,包含转换过程中的配置和信息
11
14
  */
12
15
  export declare function processIfBlock(path: NodePath<t.JSXElement>, ctx: TransformContext): void;
@@ -1,42 +1,58 @@
1
1
  import { isJSXElement } from '@babel/types';
2
2
  import { createError } from '../../error.js';
3
- import { collectVIfChainInfo, createArrowFunction, createBranch, filterWhitespaceChildren, hasDirective, removeVIfChainDirectives, validateVIfChain } from '../../utils/index.js';
3
+ import { collectVIfChainInfo, createArrowFunction, createBranch, filterWhitespaceChildren, isVIfChain, removeVIfChainDirectives, validateVIfChain } from '../../utils/index.js';
4
4
  /**
5
5
  * 处理 IfBlock 组件
6
+ * 该函数用于处理包含 v-if 指令的 JSX 元素,将其转换为条件分支调用
7
+ * @param path - JSX 元素的 AST 路径
8
+ * @param ctx - 转换上下文对象,包含转换过程中的配置和信息
6
9
  */
7
10
  export function processIfBlock(path, ctx) {
11
+ // 过滤掉子元素中的空白文本节点
8
12
  const children = filterWhitespaceChildren(path.node.children);
13
+ // 如果过滤后没有子元素,抛出错误 E014
9
14
  if (children.length === 0) {
10
15
  throw createError('E014', path.node);
11
16
  }
17
+ // 验证子元素类型是否符合要求
12
18
  validateChildrenType(children);
19
+ // 将子元素转换为 JSXElement 类型(假设前面已经验证过)
13
20
  const jsxChildren = children;
21
+ // 验证 v-if 链的合法性
14
22
  validateVIfChain(jsxChildren);
23
+ // 收集 v-if 链的相关信息,包括条件和对应的节点
15
24
  const { nodes, conditions } = collectVIfChainInfo(jsxChildren);
25
+ // 移除所有节点上的 v-if 指令
16
26
  nodes.forEach(node => removeVIfChainDirectives(node));
27
+ // 为每个节点创建箭头函数表达式
17
28
  const branches = nodes.map(node => createArrowFunction(node));
29
+ // 创建条件分支调用表达式
18
30
  const branchCall = createBranch({ conditions, branches }, ctx);
31
+ // 保留原始位置信息
19
32
  if (path.node.loc) {
20
33
  branchCall.loc = path.node.loc;
21
34
  }
35
+ // 用创建的条件分支调用替换原始节点
22
36
  path.replaceWith(branchCall);
23
37
  }
24
38
  /**
25
39
  * 验证子元素类型
40
+ * 该函数用于验证一组子节点是否符合IfBlock的要求
41
+ * @param children - 需要验证的子节点数组
42
+ * @throws 当子节点不符合要求时抛出错误
26
43
  */
27
44
  function validateChildrenType(children) {
45
+ // 遍历所有子节点进行验证
28
46
  for (const child of children) {
47
+ // 检查子节点是否为JSX元素
29
48
  if (!isJSXElement(child)) {
49
+ // 如果不是JSX元素,抛出错误E008
30
50
  throw createError('E008', child, 'IfBlock children must be JSX elements with v-if directives');
31
51
  }
32
- if (!hasVIfChainDirective(child)) {
52
+ // 检查子节点是否包含v-if/v-else-if/v-else指令链
53
+ if (!isVIfChain(child)) {
54
+ // 如果不包含指令链,抛出错误E008
33
55
  throw createError('E008', child, 'IfBlock children must have v-if/v-else-if/v-else directives');
34
56
  }
35
57
  }
36
58
  }
37
- /**
38
- * 检查元素是否有 v-if 链指令
39
- */
40
- function hasVIfChainDirective(node) {
41
- return (hasDirective(node, 'v-if') || hasDirective(node, 'v-else-if') || hasDirective(node, 'v-else'));
42
- }
@@ -2,13 +2,14 @@ import * as t from '@babel/types';
2
2
  import { isJSXElement, isJSXText } from '@babel/types';
3
3
  import { createError } from '../../error.js';
4
4
  import { createArrowFunction, createBranch, getJSXAttributeByName, getJSXElementName } from '../../utils/index.js';
5
+ import { getAttributeValue } from '../props/attribute.js';
5
6
  /**
6
7
  * 处理 Switch 组件
7
8
  * @param path - JSX 元素路径
8
9
  * @param ctx - 转换上下文
9
10
  */
10
11
  export function processSwitch(path, ctx) {
11
- const children = path.node.children;
12
+ const children = path.node.children; // 获取 Switch 组件的子节点
12
13
  // 获取 fallback 属性
13
14
  const fallbackValue = extractFallbackValue(path.node);
14
15
  // 收集 Match 子节点
@@ -17,86 +18,113 @@ export function processSwitch(path, ctx) {
17
18
  const { conditions, branches } = buildConditionsAndBranches(matchNodes);
18
19
  // 添加 fallback 分支
19
20
  if (fallbackValue) {
20
- conditions.push(t.booleanLiteral(true));
21
- branches.push(createArrowFunction(fallbackValue));
21
+ conditions.push(t.booleanLiteral(true)); // 添加一个总是为 true 的条件作为 fallback
22
+ branches.push(createArrowFunction(fallbackValue)); // 将 fallback 值转换为箭头函数
22
23
  }
23
24
  // 生成 branch 调用
24
25
  // Switch 的 when 条件如果是标识符,需要 unref
25
26
  const branchCall = createBranch({ conditions, branches }, ctx);
26
27
  if (path.node.loc) {
27
- branchCall.loc = path.node.loc;
28
+ branchCall.loc = path.node.loc; // 保留原始代码的位置信息
28
29
  }
29
- path.replaceWith(branchCall);
30
+ path.replaceWith(branchCall); // 用生成的 branch 调用替换原始的 Switch 元素
30
31
  }
31
32
  /**
32
33
  * 提取 fallback 属性值
34
+ * 该函数用于从 JSX 元素节点中提取名为 'fallback' 的属性值
35
+ * @param node - 要检查的 JSX 元素节点
36
+ * @returns 返回找到的 fallback 属性的表达式值,如果没有找到则返回 null
33
37
  */
34
38
  function extractFallbackValue(node) {
39
+ // 通过 getJSXAttributeByName 函数获取名为 'fallback' 的属性
35
40
  const fallbackAttr = getJSXAttributeByName(node, 'fallback');
36
- if (!fallbackAttr?.value)
41
+ // 如果不存在 fallback 属性,则直接返回 null
42
+ if (!fallbackAttr)
37
43
  return null;
38
- if (fallbackAttr.value.type === 'JSXExpressionContainer') {
39
- return fallbackAttr.value.expression;
40
- }
41
- return fallbackAttr.value;
44
+ // 如果存在 fallback 属性,则通过 getAttributeValue 函数提取其属性值并返回
45
+ return getAttributeValue(fallbackAttr.value);
42
46
  }
43
47
  /**
44
48
  * 收集 Match 子节点
49
+ * 该函数用于从给定的子节点数组中收集所有名为 "Match" 的 JSX 元素
50
+ * @param children - 需要处理的子节点数组
51
+ * @returns 返回包含所有 Match JSX 元素的数组
52
+ * @throws 当子节点不是 Match 组件或没有 Match 组件时抛出错误
45
53
  */
46
54
  function collectMatchNodes(children) {
47
- const matchNodes = [];
55
+ const matchNodes = []; // 用于存储收集到的 Match JSX 元素
56
+ // 遍历所有子节点
48
57
  for (const child of children) {
58
+ // 如果是文本节点,则跳过处理
49
59
  if (isJSXText(child))
50
60
  continue;
61
+ // 检查子节点是否为 JSX 元素,如果不是则抛出错误
51
62
  if (!isJSXElement(child)) {
52
63
  throw createError('E006', child, 'Switch children must be Match components');
53
64
  }
65
+ // 获取当前子节点的名称
54
66
  const childName = getJSXElementName(child);
67
+ // 如果节点名称为 "Match",则将其添加到结果数组中
55
68
  if (childName === 'Match') {
56
69
  matchNodes.push(child);
57
70
  }
58
71
  else {
72
+ // 如果不是 Match 组件,则抛出错误
59
73
  throw createError('E006', child, `Invalid child "${childName}" in Switch`);
60
74
  }
61
75
  }
76
+ // 检查是否至少有一个 Match 组件,如果没有则抛出错误
62
77
  if (matchNodes.length === 0) {
63
78
  throw createError('E015', undefined);
64
79
  }
80
+ // 返回收集到的所有 Match 组件
65
81
  return matchNodes;
66
82
  }
67
83
  /**
68
84
  * 构建条件数组和分支数组
85
+ * 该函数接收一个 JSX 元素数组,提取每个元素的 when 属性作为条件,
86
+ * 并将子元素内容转换为对应的分支函数
87
+ * @param matchNodes - JSX 元素数组,每个元素代表一个条件分支
88
+ * @returns 返回一个对象,包含 conditions 条件数组和 branches 分支数组
69
89
  */
70
90
  function buildConditionsAndBranches(matchNodes) {
71
- const conditions = [];
72
- const branches = [];
91
+ const conditions = []; // 存储提取的条件表达式
92
+ const branches = []; // 存储转换后的分支函数
93
+ // 遍历每个 JSX 元素,提取条件和分支
73
94
  for (const matchNode of matchNodes) {
95
+ // 获取 when 属性
74
96
  const whenAttr = getJSXAttributeByName(matchNode, 'when');
97
+ // 检查 when 属性是否存在且有效
75
98
  if (!whenAttr?.value) {
76
- throw createError('E007', matchNode);
99
+ throw createError('E007', matchNode); // 如果不存在,抛出错误
77
100
  }
78
- // 提取 when 条件
101
+ // 提取 when 条件表达式
79
102
  const whenExpr = whenAttr.value.type === 'JSXExpressionContainer'
80
- ? whenAttr.value.expression
81
- : whenAttr.value;
82
- conditions.push(whenExpr);
83
- // 提取分支内容
103
+ ? whenAttr.value.expression // 如果是表达式容器,取出表达式
104
+ : whenAttr.value; // 否则直接使用值
105
+ conditions.push(whenExpr); // 将条件添加到条件数组
106
+ // 提取分支内容,过滤掉空白文本节点
84
107
  const matchChildren = matchNode.children.filter(c => !isJSXText(c) || c.value.trim());
108
+ // 检查是否有子元素
85
109
  if (matchChildren.length === 0) {
86
- throw createError('E013', matchNode);
110
+ throw createError('E013', matchNode); // 如果没有子元素,抛出错误
87
111
  }
112
+ // 根据子元素数量创建不同的分支函数
88
113
  if (matchChildren.length === 1) {
89
114
  const child = matchChildren[0];
90
115
  if (isJSXText(child)) {
116
+ // 如果是单个文本节点,创建返回字符串的函数
91
117
  branches.push(createArrowFunction(t.stringLiteral(child.value.trim())));
92
118
  }
93
119
  else {
120
+ // 如果是单个表达式节点,直接使用该表达式
94
121
  branches.push(createArrowFunction(child));
95
122
  }
96
123
  }
97
124
  else {
125
+ // 如果有多个子元素,创建返回数组表达式的函数
98
126
  branches.push(createArrowFunction(t.arrayExpression(matchChildren)));
99
127
  }
100
128
  }
101
- return { conditions, branches };
129
+ return { conditions, branches }; // 返回条件和分支数组
102
130
  }
@@ -14,4 +14,6 @@ import type { DirectiveInfo } from '../../passes/props/types.js';
14
14
  * @param ctx - 转换上下文
15
15
  * @returns 处理后的调用表达式
16
16
  */
17
- export declare function processDirectives(viewCall: t.CallExpression, directives: Map<string, DirectiveInfo>, ctx: TransformContext): t.CallExpression;
17
+ export declare function processDirectives(viewCall: t.CallExpression, // 视图调用的表达式,表示要应用指令的视图节点
18
+ directives: Map<string, DirectiveInfo>, // 指令映射表,键为指令名(如'v-if'),值为指令信息
19
+ ctx: TransformContext): t.CallExpression;
@@ -15,11 +15,18 @@ import { addPureComment, createWithDirectivesCall, getAlias } from '../../utils/
15
15
  * @param ctx - 转换上下文
16
16
  * @returns 处理后的调用表达式
17
17
  */
18
- export function processDirectives(viewCall, directives, ctx) {
18
+ export function processDirectives(viewCall, // 视图调用的表达式,表示要应用指令的视图节点
19
+ directives, // 指令映射表,键为指令名(如'v-if'),值为指令信息
20
+ ctx // 转换上下文,包含转换过程中的各种信息和工具函数
21
+ ) {
22
+ // 返回处理后的调用表达式,即应用了指令的视图节点
23
+ // 如果没有指令,直接返回原始视图调用表达式
19
24
  if (directives.size === 0) {
20
25
  return viewCall;
21
26
  }
27
+ // 创建指令数组,用于存储处理后的指令信息
22
28
  const directiveArray = [];
29
+ // 遍历指令映射表,处理每个指令
23
30
  for (const [name, info] of directives) {
24
31
  const directiveName = name.slice(2); // 移除 'v-' 前缀
25
32
  const directiveValue = buildDirectiveValue(info.value, info.arg, ctx);
@@ -31,21 +38,41 @@ export function processDirectives(viewCall, directives, ctx) {
31
38
  }
32
39
  /**
33
40
  * 构建指令值对象
41
+ * 该函数用于创建一个包含指令值和参数的对象表达式
42
+ * @param value - 指令的值表达式
43
+ * @param arg - 指令的参数,可选
44
+ * @param ctx - 转换上下文对象,包含转换过程中需要的信息
45
+ * @returns 返回一个对象表达式,包含value和可能的arg属性
34
46
  */
35
- function buildDirectiveValue(value, arg, ctx) {
36
- const properties = [];
47
+ function buildDirectiveValue(value, // 表达式类型的值,可以是标识符、字面量等
48
+ arg, // 指令参数,可选字符串
49
+ ctx // 转换上下文,包含别名、导入等信息
50
+ ) {
51
+ // 返回一个表达式类型的对象
52
+ const properties = []; // 定义对象属性数组,可以是属性或方法
37
53
  // 添加 value 属性
38
54
  if (isIdentifier(value)) {
39
- markImport(ctx, 'unref');
40
- const unrefAlias = getAlias(ctx.vitarxAliases, 'unref');
41
- properties.push(t.objectMethod('get', t.identifier('value'), [], t.blockStatement([t.returnStatement(t.callExpression(t.identifier(unrefAlias), [value]))])));
55
+ // 如果值是一个标识符
56
+ markImport(ctx, 'unref'); // 标记需要导入unref函数
57
+ const unrefAlias = getAlias(ctx.vitarxAliases, 'unref'); // 获取unref函数的别名
58
+ properties.push(
59
+ // 添加一个getter方法作为属性
60
+ t.objectMethod('get', // 方法类型为getter
61
+ t.identifier('value'), // 属性名为value
62
+ [], // 无参数
63
+ t.blockStatement([t.returnStatement(t.callExpression(t.identifier(unrefAlias), [value]))]) // 返回unref(value)
64
+ ));
42
65
  }
43
66
  else {
44
- properties.push(t.objectMethod('get', t.identifier('value'), [], t.blockStatement([t.returnStatement(value)])));
67
+ // 如果值不是标识符
68
+ properties.push(
69
+ // 直接添加一个getter方法返回值
70
+ t.objectMethod('get', t.identifier('value'), [], t.blockStatement([t.returnStatement(value)])));
45
71
  }
46
72
  // 添加 arg 属性
47
73
  if (arg) {
48
- properties.push(t.objectProperty(t.identifier('arg'), t.stringLiteral(arg)));
74
+ // 如果存在参数
75
+ properties.push(t.objectProperty(t.identifier('arg'), t.stringLiteral(arg))); // 添加arg属性,值为字符串字面量
49
76
  }
50
- return t.objectExpression(properties);
77
+ return t.objectExpression(properties); // 返回包含所有属性的对象表达式
51
78
  }
@@ -16,12 +16,17 @@ type JSXContainerPath = NodePath<t.JSXFragment | t.JSXElement>;
16
16
  * @param transformJSXElement - JSX 元素转换函数
17
17
  * @returns 处理后的子元素数组(链节点已替换为 branch 调用,nullLiteral 已移除)
18
18
  */
19
- export declare function transformChildrenVIfChains(children: t.Node[], ctx: TransformContext, transformJSXElement: TransformJSXElementFn): t.Node[];
19
+ export declare function transformChildrenVIfChains(children: t.Node[], // 子元素数组,将被原地修改
20
+ ctx: TransformContext, // 转换上下文,包含转换所需的环境信息
21
+ transformJSXElement: TransformJSXElementFn): t.Node[];
20
22
  /**
21
23
  * 处理 Fragment/Element 中的 v-if 链
22
24
  * @param path - JSX Fragment 或 Element 路径
23
25
  * @param ctx - 转换上下文
24
26
  * @param transformJSXElement - JSX 元素转换函数
25
27
  */
26
- export declare function processVIfChain(path: JSXContainerPath, ctx: TransformContext, transformJSXElement: TransformJSXElementFn): void;
28
+ export declare function processVIfChain(// 导出处理 v-if 链的函数
29
+ path: JSXContainerPath, // 参数 path:接收 JSX 容器(Fragment 或 Element)的路径
30
+ ctx: TransformContext, // 参数 ctx:提供转换过程中所需的上下文信息
31
+ transformJSXElement: TransformJSXElementFn): void;
27
32
  export {};
@@ -1,5 +1,5 @@
1
1
  import * as t from '@babel/types';
2
- import { isJSXElement, isJSXText } from '@babel/types';
2
+ import { isJSXText } from '@babel/types';
3
3
  import { collectFragmentVIfChains, createArrowFunction, createBranch, isWhitespaceJSXText, removeVIfChainDirectives } from '../../utils/index.js';
4
4
  /**
5
5
  * 处理子元素数组中的 v-if 链
@@ -9,17 +9,23 @@ import { collectFragmentVIfChains, createArrowFunction, createBranch, isWhitespa
9
9
  * @param transformJSXElement - JSX 元素转换函数
10
10
  * @returns 处理后的子元素数组(链节点已替换为 branch 调用,nullLiteral 已移除)
11
11
  */
12
- export function transformChildrenVIfChains(children, ctx, transformJSXElement) {
13
- const chains = collectFragmentVIfChains(children);
12
+ export function transformChildrenVIfChains(children, // 子元素数组,将被原地修改
13
+ ctx, // 转换上下文,包含转换所需的环境信息
14
+ transformJSXElement // JSX 元素转换函数,用于转换 JSX 元素节点
15
+ ) {
16
+ // 返回处理后的子元素数组,链节点已替换为 branch 调用,nullLiteral 已移除
17
+ const chains = collectFragmentVIfChains(children); // 收集所有 v-if 链
14
18
  if (chains.length === 0)
15
- return children;
19
+ return children; // 如果没有 v-if 链,直接返回原数组
20
+ // 从后向前处理每个 v-if 链,确保正确的顺序
16
21
  for (let c = chains.length - 1; c >= 0; c--) {
17
- processVIfChainItem(chains[c], children, ctx, transformJSXElement);
22
+ processVIfChainItem(chains[c], children, ctx, transformJSXElement); // 处理单个 v-if 链项
18
23
  }
24
+ // 过滤掉 nullLiteral 类型的节点和空白文本节点
19
25
  return children.filter(child => {
20
26
  if (t.isNullLiteral(child))
21
- return false;
22
- return !(isJSXText(child) && isWhitespaceJSXText(child));
27
+ return false; // 过滤掉 nullLiteral 节点
28
+ return !(isJSXText(child) && isWhitespaceJSXText(child)); // 过滤掉空白文本节点
23
29
  });
24
30
  }
25
31
  /**
@@ -28,39 +34,46 @@ export function transformChildrenVIfChains(children, ctx, transformJSXElement) {
28
34
  * @param ctx - 转换上下文
29
35
  * @param transformJSXElement - JSX 元素转换函数
30
36
  */
31
- export function processVIfChain(path, ctx, transformJSXElement) {
32
- const children = path.node.children;
33
- const processed = transformChildrenVIfChains(children, ctx, transformJSXElement);
37
+ export function processVIfChain(// 导出处理 v-if 链的函数
38
+ path, // 参数 path:接收 JSX 容器(Fragment 或 Element)的路径
39
+ ctx, // 参数 ctx:提供转换过程中所需的上下文信息
40
+ transformJSXElement // 参数 transformJSXElement:用于转换 JSX 元素的回调函数
41
+ ) {
42
+ // 函数无返回值
43
+ const children = path.node.children; // 获取当前路径下节点的子节点数组
44
+ const processed = transformChildrenVIfChains(children, ctx, transformJSXElement); // 调用函数处理子节点中的 v-if 链
34
45
  if (processed !== children) {
35
- path.node.children = processed;
46
+ // 检查处理后的子节点是否与原始子节点不同
47
+ path.node.children = processed; // 如果不同,则更新节点的子节点数组
36
48
  }
37
49
  }
38
50
  /**
39
51
  * 处理单个 v-if 链
52
+ * 该函数用于处理包含 v-if 指令的 JSX 元素链,将其转换为条件分支结构
53
+ * @param chain - 包含 v-if 链信息的对象,包含节点、条件和索引范围
54
+ * @param children - 子节点数组,将被修改以插入转换后的条件分支
55
+ * @param ctx - 转换上下文,包含转换过程中需要的配置和信息
56
+ * @param transformJSXElement - 用于转换 JSX 元素的函数
40
57
  */
41
- function processVIfChainItem(chain, children, ctx, transformJSXElement) {
42
- const { nodes, conditions, endIndex } = chain;
43
- let start = -1;
44
- for (let i = 0; i < children.length; i++) {
45
- const child = children[i];
46
- if (isJSXElement(child) && child === nodes[0]) {
47
- start = i;
48
- break;
49
- }
50
- }
58
+ function processVIfChainItem(chain, children, // 子节点数组,将被修改以插入转换后的条件分支
59
+ ctx, // 转换上下文对象,包含转换过程中的配置和信息
60
+ transformJSXElement // 转换 JSX 元素的函数类型
61
+ ) {
62
+ const { nodes, conditions, startIndex, endIndex } = chain; // 解构赋值获取链信息
63
+ // 创建分支数组,每个分支是一个箭头函数表达式
51
64
  const branches = [];
65
+ // 遍历所有节点,移除 v-if 指令并转换节点
52
66
  for (const node of nodes) {
53
- removeVIfChainDirectives(node);
54
- const transformedNode = transformJSXElement(node, ctx, false);
67
+ removeVIfChainDirectives(node); // 移除节点上的 v-if 相关指令
68
+ const transformedNode = transformJSXElement(node, ctx, false); // 转换 JSX 元素
55
69
  if (transformedNode) {
56
- branches.push(createArrowFunction(transformedNode));
70
+ branches.push(createArrowFunction(transformedNode)); // 将转换后的节点包装为箭头函数
57
71
  }
58
72
  }
59
- const branchCall = createBranch({ conditions, branches }, ctx);
60
- if (start >= 0) {
61
- children[start] = branchCall;
62
- for (let k = start + 1; k <= endIndex; k++) {
63
- children[k] = t.nullLiteral();
64
- }
73
+ // 在起始位置创建条件分支结构
74
+ children[startIndex] = createBranch({ conditions, branches }, ctx);
75
+ // 将后续位置填充为 null 字面量,避免重复渲染
76
+ for (let k = startIndex + 1; k <= endIndex; k++) {
77
+ children[k] = t.nullLiteral();
65
78
  }
66
79
  }