@vitarx/plugin-vite 0.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +298 -0
  3. package/dist/components.js +1 -0
  4. package/dist/constants/index.js +59 -0
  5. package/dist/context.js +78 -0
  6. package/dist/error.js +156 -0
  7. package/dist/hmr-client/index.js +143 -0
  8. package/dist/hmr-client/update.js +53 -0
  9. package/dist/hmr-client/utils.js +125 -0
  10. package/dist/index.js +65 -0
  11. package/dist/passes/components/ifBlock.js +42 -0
  12. package/dist/passes/components/index.js +24 -0
  13. package/dist/passes/components/switch.js +102 -0
  14. package/dist/passes/directives/index.js +6 -0
  15. package/dist/passes/directives/processDirectives.js +46 -0
  16. package/dist/passes/directives/vIf.js +64 -0
  17. package/dist/passes/hmr/index.js +5 -0
  18. package/dist/passes/hmr/inject.js +189 -0
  19. package/dist/passes/imports/collectImports.js +56 -0
  20. package/dist/passes/imports/collectRefVariables.js +95 -0
  21. package/dist/passes/imports/index.js +7 -0
  22. package/dist/passes/imports/injectImports.js +96 -0
  23. package/dist/passes/index.js +16 -0
  24. package/dist/passes/jsx/index.js +7 -0
  25. package/dist/passes/jsx/processChildren.js +114 -0
  26. package/dist/passes/jsx/processJSXElement.js +173 -0
  27. package/dist/passes/jsx/processJSXFragment.js +37 -0
  28. package/dist/passes/props/attribute.js +165 -0
  29. package/dist/passes/props/index.js +94 -0
  30. package/dist/passes/props/types.js +1 -0
  31. package/dist/passes/props/vmodel.js +115 -0
  32. package/dist/transform.js +144 -0
  33. package/dist/utils/ast-builders.js +142 -0
  34. package/dist/utils/ast-guards.js +16 -0
  35. package/dist/utils/branch-factory.js +107 -0
  36. package/dist/utils/component-collect.js +233 -0
  37. package/dist/utils/generate.js +11 -0
  38. package/dist/utils/index.js +16 -0
  39. package/dist/utils/jsx-helpers.js +168 -0
  40. package/dist/utils/pattern-helpers.js +47 -0
  41. package/dist/utils/vif-helpers.js +127 -0
  42. package/package.json +63 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * 主转换模块
3
+ * 负责解析 JSX/TSX 代码并转换为 createView 调用
4
+ * @module transform
5
+ */
6
+ import generate from '@babel/generator';
7
+ import { parse } from '@babel/parser';
8
+ import traverse from '@babel/traverse';
9
+ import { createContext } from './context.js';
10
+ import { collectExistingImports, collectLocalBindings, collectRefApiAliases, collectRefVariables, injectHMRSupport, injectImports, processJSXElement, processJSXFragment, processPureCompileComponent, processVIfChain, transformJSXElement } from './passes/index.js';
11
+ import { collectComponentFunctions, generateUniqueAlias, getJSXElementName, isPureCompileComponent } from './utils/index.js';
12
+ /** 用于追踪已处理的节点 */
13
+ const processedNodes = new WeakSet();
14
+ /**
15
+ * 检查文件是否需要转换
16
+ */
17
+ function shouldTransform(id) {
18
+ if (id.includes('node_modules'))
19
+ return false;
20
+ const ext = id.split('?')[0].split('.').pop()?.toLowerCase();
21
+ return ext === 'jsx' || ext === 'tsx';
22
+ }
23
+ /**
24
+ * 创建解析器选项
25
+ */
26
+ function createParserOptions() {
27
+ return {
28
+ sourceType: 'module',
29
+ plugins: [
30
+ 'jsx',
31
+ 'typescript',
32
+ 'decorators',
33
+ 'classProperties',
34
+ 'objectRestSpread',
35
+ 'optionalChaining',
36
+ 'nullishCoalescingOperator'
37
+ ],
38
+ // 确保保留位置信息
39
+ ranges: true,
40
+ tokens: false
41
+ };
42
+ }
43
+ /**
44
+ * 设置 API 别名
45
+ */
46
+ function setupAliases(ctx, program) {
47
+ const { vitarxImports } = collectExistingImports(program);
48
+ const localBindings = collectLocalBindings(program);
49
+ const allNames = new Set([...localBindings]);
50
+ const apiNames = [
51
+ 'createView',
52
+ 'Fragment',
53
+ 'branch',
54
+ 'dynamic',
55
+ 'access',
56
+ 'withDirectives',
57
+ 'unref',
58
+ 'isRef'
59
+ ];
60
+ for (const apiName of apiNames) {
61
+ if (vitarxImports.has(apiName)) {
62
+ ctx.vitarxAliases[apiName] = vitarxImports.get(apiName);
63
+ }
64
+ else if (allNames.has(apiName)) {
65
+ ctx.vitarxAliases[apiName] = generateUniqueAlias(apiName, allNames);
66
+ }
67
+ }
68
+ if (ctx.options.hmr) {
69
+ ctx.vitarxAliases.createView = generateUniqueAlias('jsxDEV', allNames);
70
+ }
71
+ }
72
+ /**
73
+ * 收集 ref 相关信息
74
+ */
75
+ function collectRefInfo(ctx, program) {
76
+ const refApiAliases = collectRefApiAliases(program);
77
+ ctx.refApiAliases = refApiAliases;
78
+ ctx.refVariables = collectRefVariables(program, refApiAliases);
79
+ }
80
+ /**
81
+ * 转换 AST
82
+ */
83
+ function transformAST(ast, ctx) {
84
+ const babelTraverse = typeof traverse === 'object' ? traverse.default : traverse;
85
+ babelTraverse(ast, {
86
+ JSXElement: {
87
+ enter(path) {
88
+ if (processedNodes.has(path.node))
89
+ return;
90
+ const name = getJSXElementName(path.node);
91
+ if (name && isPureCompileComponent(name)) {
92
+ processedNodes.add(path.node);
93
+ processPureCompileComponent(path, ctx);
94
+ }
95
+ },
96
+ exit(path) {
97
+ if (processedNodes.has(path.node))
98
+ return;
99
+ const name = getJSXElementName(path.node);
100
+ if (name && isPureCompileComponent(name))
101
+ return;
102
+ processedNodes.add(path.node);
103
+ processJSXElement(path, ctx);
104
+ }
105
+ },
106
+ JSXFragment: {
107
+ enter(path) {
108
+ processVIfChain(path, ctx, transformJSXElement);
109
+ },
110
+ exit(path) {
111
+ if (processedNodes.has(path.node))
112
+ return;
113
+ processedNodes.add(path.node);
114
+ processJSXFragment(path, ctx);
115
+ }
116
+ }
117
+ });
118
+ }
119
+ /**
120
+ * 生成代码
121
+ */
122
+ function generateCode(ast, code, id, sourceMap) {
123
+ const babelGenerate = typeof generate === 'object' ? generate.default : generate;
124
+ const output = babelGenerate(ast, { sourceMaps: !!sourceMap, filename: id }, code);
125
+ return { code: output.code, map: output.map || undefined };
126
+ }
127
+ /**
128
+ * 转换 JSX/TSX 代码
129
+ */
130
+ export async function transform(code, id, options) {
131
+ if (!shouldTransform(id))
132
+ return null;
133
+ const ast = parse(code, createParserOptions());
134
+ const ctx = createContext(code, id, options, ast);
135
+ setupAliases(ctx, ast.program);
136
+ collectRefInfo(ctx, ast.program);
137
+ const components = collectComponentFunctions(ast.program);
138
+ transformAST(ast, ctx);
139
+ injectImports(ast.program, ctx);
140
+ if (options.hmr && components.length > 0) {
141
+ injectHMRSupport(ast.program, components, id);
142
+ }
143
+ return generateCode(ast, code, id, options.sourceMap);
144
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * AST 节点构建函数
3
+ * @module utils/ast-builders
4
+ */
5
+ import * as t from '@babel/types';
6
+ import { isIdentifier, isStringLiteral } from '@babel/types';
7
+ import { PURE_COMMENT } from '../constants/index.js';
8
+ /** 用于追踪已添加 PURE 注释的节点 */
9
+ const pureCommentedNodes = new WeakSet();
10
+ /**
11
+ * 创建 unref 调用
12
+ * @param argument - 参数表达式
13
+ * @param alias - unref 别名
14
+ * @returns CallExpression
15
+ */
16
+ export function createUnrefCall(argument, alias) {
17
+ return t.callExpression(t.identifier(alias || 'unref'), [argument]);
18
+ }
19
+ /**
20
+ * 创建 access 调用
21
+ * @param object - 对象表达式
22
+ * @param key - 键表达式
23
+ * @param alias - access 别名
24
+ * @returns CallExpression
25
+ */
26
+ export function createAccessCall(object, key, alias) {
27
+ let keyArg;
28
+ if (isIdentifier(key)) {
29
+ keyArg = t.stringLiteral(key.name);
30
+ }
31
+ else if (isStringLiteral(key)) {
32
+ keyArg = key;
33
+ }
34
+ else {
35
+ keyArg = key;
36
+ }
37
+ return t.callExpression(t.identifier(alias || 'access'), [object, keyArg]);
38
+ }
39
+ /**
40
+ * 创建 dynamic 调用
41
+ * @param argument - 参数表达式
42
+ * @param alias - dynamic 别名
43
+ * @returns CallExpression
44
+ */
45
+ export function createDynamicCall(argument, alias) {
46
+ return t.callExpression(t.identifier(alias || 'dynamic'), [
47
+ t.arrowFunctionExpression([], argument)
48
+ ]);
49
+ }
50
+ /**
51
+ * 创建 branch 调用
52
+ * @param condition - 条件函数
53
+ * @param branches - 分支函数数组
54
+ * @param alias - branch 别名
55
+ * @returns CallExpression
56
+ */
57
+ export function createBranchCall(condition, branches, alias) {
58
+ return t.callExpression(t.identifier(alias || 'branch'), [condition, t.arrayExpression(branches)]);
59
+ }
60
+ /**
61
+ * 创建 createView 调用
62
+ * @param type - 元素类型
63
+ * @param props - props 对象
64
+ * @param locInfo - 位置信息对象
65
+ * @param alias - createView 别名
66
+ * @returns CallExpression
67
+ */
68
+ export function createCreateViewCall(type, props, locInfo, alias) {
69
+ const args = [type];
70
+ // props 参数
71
+ if (props) {
72
+ args.push(props);
73
+ }
74
+ else if (locInfo) {
75
+ // 如果有 locInfo 但没有 props,需要传 null
76
+ args.push(t.nullLiteral());
77
+ }
78
+ // locInfo 参数
79
+ if (locInfo) {
80
+ args.push(locInfo);
81
+ }
82
+ return t.callExpression(t.identifier(alias || 'createView'), args);
83
+ }
84
+ /**
85
+ * 创建 withDirectives 调用
86
+ * @param view - 视图节点
87
+ * @param directives - 指令数组,每项为 [指令名, 指令值]
88
+ * @param alias - withDirectives 别名
89
+ * @returns CallExpression
90
+ */
91
+ export function createWithDirectivesCall(view, directives, alias) {
92
+ const directiveArray = directives.map(([name, value]) => {
93
+ return t.arrayExpression([t.stringLiteral(name), value]);
94
+ });
95
+ return t.callExpression(t.identifier(alias || 'withDirectives'), [
96
+ view,
97
+ t.arrayExpression(directiveArray)
98
+ ]);
99
+ }
100
+ /**
101
+ * 创建箭头函数
102
+ * @param body - 函数体表达式
103
+ * @returns ArrowFunctionExpression
104
+ */
105
+ export function createArrowFunction(body) {
106
+ return t.arrowFunctionExpression([], body);
107
+ }
108
+ /**
109
+ * 创建位置信息对象
110
+ * @param filename - 文件名
111
+ * @param loc - 源码位置
112
+ * @returns ObjectExpression
113
+ */
114
+ export function createLocationObject(filename, loc) {
115
+ return t.objectExpression([
116
+ t.objectProperty(t.identifier('fileName'), t.stringLiteral(filename)),
117
+ t.objectProperty(t.identifier('lineNumber'), t.numericLiteral(loc.start.line)),
118
+ t.objectProperty(t.identifier('columnNumber'), t.numericLiteral(loc.start.column + 1))
119
+ ]);
120
+ }
121
+ /**
122
+ * 为调用表达式添加 @__PURE__ 注释
123
+ * @param node - 调用表达式节点
124
+ * @returns 添加注释后的节点
125
+ */
126
+ export function addPureComment(node) {
127
+ if (pureCommentedNodes.has(node)) {
128
+ return node;
129
+ }
130
+ pureCommentedNodes.add(node);
131
+ t.addComment(node, 'leading', ` ${PURE_COMMENT} `, false);
132
+ return node;
133
+ }
134
+ /**
135
+ * 获取 API 别名
136
+ * @param aliases - 别名映射
137
+ * @param name - API 名称
138
+ * @returns 别名或原名
139
+ */
140
+ export function getAlias(aliases, name) {
141
+ return aliases[name] || name;
142
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * AST 类型守卫函数
3
+ * 用于判断节点类型
4
+ * @module utils/ast-guards
5
+ */
6
+ import { isJSXText } from '@babel/types';
7
+ /**
8
+ * 判断 JSXText 是否为纯空白文本
9
+ * @param node - AST 节点
10
+ * @returns 是否为纯空白文本
11
+ */
12
+ export function isWhitespaceJSXText(node) {
13
+ if (!isJSXText(node))
14
+ return false;
15
+ return /^\s*$/.test(node.value);
16
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Branch 调用工厂模块
3
+ * 统一处理条件分支的生成
4
+ * @module utils/branch-factory
5
+ */
6
+ import * as t from '@babel/types';
7
+ import { isBooleanLiteral, isIdentifier } from '@babel/types';
8
+ import { markImport } from '../context.js';
9
+ import { addPureComment, createArrowFunction, createBranchCall, createUnrefCall, getAlias } from './ast-builders.js';
10
+ /**
11
+ * 创建 branch 调用
12
+ * @param config - 分支配置
13
+ * @param ctx - 转换上下文
14
+ * @returns branch 调用表达式
15
+ */
16
+ export function createBranch(config, ctx) {
17
+ const { conditions, branches, useRef = true } = config;
18
+ markImport(ctx, 'branch');
19
+ // 只有在需要 unref 且条件中有标识符时才标记导入
20
+ if (useRef && conditions.some(c => isIdentifier(c))) {
21
+ markImport(ctx, 'unref');
22
+ }
23
+ const conditionExpr = buildNestedCondition(conditions, ctx, useRef);
24
+ const branchAlias = getAlias(ctx.vitarxAliases, 'branch');
25
+ return addPureComment(createBranchCall(createArrowFunction(conditionExpr), branches, branchAlias));
26
+ }
27
+ /**
28
+ * 判断表达式是否需要括号包裹
29
+ * 复杂表达式(逻辑运算、三元运算等)在三元条件中需要括号
30
+ */
31
+ function needsParentheses(expr) {
32
+ const type = expr.type;
33
+ // 逻辑表达式、三元表达式、赋值表达式需要括号
34
+ return (type === 'LogicalExpression' ||
35
+ type === 'ConditionalExpression' ||
36
+ type === 'AssignmentExpression' ||
37
+ type === 'SequenceExpression' ||
38
+ type === 'ArrowFunctionExpression');
39
+ }
40
+ /**
41
+ * 包装表达式(如需要则添加括号)
42
+ */
43
+ function wrapExpression(expr) {
44
+ if (needsParentheses(expr)) {
45
+ return t.parenthesizedExpression(expr);
46
+ }
47
+ return expr;
48
+ }
49
+ /**
50
+ * 构建嵌套条件表达式
51
+ * 从后向前构建三元表达式链
52
+ */
53
+ export function buildNestedCondition(conditions, ctx, useRef = true) {
54
+ if (conditions.length === 0) {
55
+ return t.nullLiteral();
56
+ }
57
+ const unrefAlias = useRef ? getAlias(ctx.vitarxAliases, 'unref') : '';
58
+ let result = null;
59
+ const lastIndex = conditions.length - 1;
60
+ for (let i = lastIndex; i >= 0; i--) {
61
+ const condition = conditions[i];
62
+ // v-else 的情况(布尔 true)
63
+ if (isBooleanLiteral(condition) && condition.value) {
64
+ result = t.numericLiteral(i);
65
+ continue;
66
+ }
67
+ // 构建条件表达式
68
+ const conditionExpr = useRef && isIdentifier(condition) ? createUnrefCall(condition, unrefAlias) : condition;
69
+ // 对复杂条件表达式添加括号
70
+ const wrappedCondition = wrapExpression(conditionExpr);
71
+ if (result === null) {
72
+ result = t.conditionalExpression(wrappedCondition, t.numericLiteral(i), t.nullLiteral());
73
+ }
74
+ else {
75
+ // 嵌套的三元表达式也需要括号
76
+ const wrappedResult = wrapExpression(result);
77
+ result = t.conditionalExpression(wrappedCondition, t.numericLiteral(i), wrappedResult);
78
+ }
79
+ }
80
+ return result || t.nullLiteral();
81
+ }
82
+ /**
83
+ * 从条件数组和分支节点创建完整的 branch 调用
84
+ * @param conditions - 条件表达式数组
85
+ * @param branchNodes - 分支节点数组(会被包装为箭头函数)
86
+ * @param ctx - 转换上下文
87
+ * @returns branch 调用表达式
88
+ */
89
+ export function createBranchFromNodes(conditions, branchNodes, ctx) {
90
+ const branches = branchNodes.map(node => createArrowFunction(node));
91
+ return createBranch({ conditions, branches, useRef: true }, ctx);
92
+ }
93
+ /**
94
+ * 创建简单的二元条件 branch(用于三元表达式)
95
+ * @param condition - 条件表达式
96
+ * @param consequent - 真值分支
97
+ * @param alternate - 假值分支
98
+ * @param ctx - 转换上下文
99
+ * @returns branch 调用表达式
100
+ */
101
+ export function createBinaryBranch(condition, consequent, alternate, ctx) {
102
+ const conditions = [condition, t.booleanLiteral(true)];
103
+ const branches = [createArrowFunction(consequent), createArrowFunction(alternate)];
104
+ // 只有条件是 Identifier 时才需要 unref
105
+ const useRef = isIdentifier(condition);
106
+ return createBranch({ conditions, branches, useRef }, ctx);
107
+ }
@@ -0,0 +1,233 @@
1
+ /**
2
+ * AST 收集模块
3
+ * 负责收集导入、导出、组件等信息的收集
4
+ * @module passes/transform/collect
5
+ */
6
+ import * as t from '@babel/types';
7
+ import { DEFAULT_EXPORT_BASE_NAME, PURE_COMPILE_COMPONENTS } from '../constants/index.js';
8
+ import { generateUniqueAlias } from './generate.js';
9
+ /** 纯编译组件名称集合 */
10
+ const PURE_COMPILE_COMPONENT_SET = new Set(PURE_COMPILE_COMPONENTS);
11
+ /**
12
+ * 生成唯一的默认导出组件名称
13
+ * 避免与已存在的名称冲突
14
+ */
15
+ function generateUniqueDefaultName(exportedNames) {
16
+ if (!exportedNames.has(DEFAULT_EXPORT_BASE_NAME)) {
17
+ return DEFAULT_EXPORT_BASE_NAME;
18
+ }
19
+ return generateUniqueAlias(DEFAULT_EXPORT_BASE_NAME, exportedNames);
20
+ }
21
+ /**
22
+ * 检查名称是否为有效的组件名称
23
+ * 必须以大写字母开头
24
+ */
25
+ function isValidComponentName(name) {
26
+ return /^[A-Z]/.test(name);
27
+ }
28
+ /**
29
+ * 从命名导出中收集名称
30
+ */
31
+ function collectFromNamedExport(node, names) {
32
+ if (node.declaration) {
33
+ if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
34
+ names.add(node.declaration.id.name);
35
+ }
36
+ else if (node.declaration.type === 'VariableDeclaration') {
37
+ for (const decl of node.declaration.declarations) {
38
+ if (decl.id.type === 'Identifier') {
39
+ names.add(decl.id.name);
40
+ }
41
+ }
42
+ }
43
+ }
44
+ if (node.specifiers) {
45
+ for (const spec of node.specifiers) {
46
+ if (spec.type === 'ExportSpecifier') {
47
+ names.add(spec.local.name);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * 从默认导出中收集名称
54
+ */
55
+ function collectFromDefaultExport(node, names) {
56
+ const decl = node.declaration;
57
+ if (decl.type === 'FunctionDeclaration' && decl.id) {
58
+ names.add(decl.id.name);
59
+ }
60
+ else if (decl.type === 'Identifier') {
61
+ names.add(decl.name);
62
+ }
63
+ // 匿名函数不在此处预留名称,而是在处理时动态生成唯一名称
64
+ }
65
+ /**
66
+ * 检查函数是否为组件函数
67
+ * 通过遍历 AST 检查是否包含 JSX 元素
68
+ */
69
+ function isComponentFunction(node) {
70
+ let result = false;
71
+ const check = (n) => {
72
+ if (result)
73
+ return;
74
+ // 直接包含 JSX 元素
75
+ if (n.type === 'JSXElement' || n.type === 'JSXFragment') {
76
+ result = true;
77
+ return;
78
+ }
79
+ // 检查 return 语句中的纯编译组件
80
+ if (n.type === 'ReturnStatement' && n.argument?.type === 'JSXElement') {
81
+ const opening = n.argument.openingElement;
82
+ if (opening.name.type === 'JSXIdentifier' &&
83
+ PURE_COMPILE_COMPONENT_SET.has(opening.name.name)) {
84
+ result = true;
85
+ return;
86
+ }
87
+ }
88
+ // 递归遍历子节点
89
+ for (const key of Object.keys(n)) {
90
+ const child = n[key];
91
+ if (child && typeof child === 'object') {
92
+ if (Array.isArray(child)) {
93
+ for (const c of child) {
94
+ if (c && typeof child === 'object')
95
+ check(c);
96
+ }
97
+ }
98
+ else {
99
+ check(child);
100
+ }
101
+ }
102
+ }
103
+ };
104
+ check(node);
105
+ return result;
106
+ }
107
+ /**
108
+ * 尝试添加组件到列表
109
+ * 检查名称有效性、是否导出、是否为组件函数
110
+ */
111
+ function tryAddComponent(name, node, exportedNames, components) {
112
+ if (isValidComponentName(name) && exportedNames.has(name) && isComponentFunction(node)) {
113
+ components.push({ name, node });
114
+ }
115
+ }
116
+ /**
117
+ * 处理变量声明中的组件
118
+ */
119
+ function processVariableDeclaration(declaration, exportedNames, components) {
120
+ for (const decl of declaration.declarations) {
121
+ if (decl.id.type !== 'Identifier')
122
+ continue;
123
+ const init = decl.init;
124
+ if (init?.type === 'ArrowFunctionExpression' || init?.type === 'FunctionExpression') {
125
+ tryAddComponent(decl.id.name, init, exportedNames, components);
126
+ }
127
+ }
128
+ }
129
+ /**
130
+ * 将函数表达式或箭头函数转换为命名函数声明
131
+ */
132
+ function convertToNamedFunctionDeclaration(func, name) {
133
+ let body;
134
+ if (func.type === 'ArrowFunctionExpression' && func.body.type !== 'BlockStatement') {
135
+ body = t.blockStatement([t.returnStatement(func.body)]);
136
+ }
137
+ else {
138
+ body = func.body;
139
+ }
140
+ const funcDecl = t.functionDeclaration(t.identifier(name), func.params, body, func.type === 'FunctionExpression' ? func.generator : false, func.async);
141
+ funcDecl.loc = func.loc;
142
+ return funcDecl;
143
+ }
144
+ /**
145
+ * 处理默认导出的匿名函数
146
+ * 为匿名函数生成唯一名称并转换为命名函数声明
147
+ */
148
+ function processAnonymousDefaultExport(node, exportedNames, components) {
149
+ const decl = node.declaration;
150
+ let funcNode = null;
151
+ let name;
152
+ // 匿名函数声明
153
+ if (decl.type === 'FunctionDeclaration' && !decl.id) {
154
+ if (!isComponentFunction(decl))
155
+ return;
156
+ name = generateUniqueDefaultName(exportedNames);
157
+ decl.id = t.identifier(name);
158
+ funcNode = decl;
159
+ }
160
+ // 函数表达式
161
+ else if (decl.type === 'FunctionExpression') {
162
+ if (!isComponentFunction(decl))
163
+ return;
164
+ name = generateUniqueDefaultName(exportedNames);
165
+ funcNode = convertToNamedFunctionDeclaration(decl, name);
166
+ node.declaration = funcNode;
167
+ }
168
+ // 箭头函数
169
+ else if (decl.type === 'ArrowFunctionExpression') {
170
+ if (!isComponentFunction(decl))
171
+ return;
172
+ name = generateUniqueDefaultName(exportedNames);
173
+ funcNode = convertToNamedFunctionDeclaration(decl, name);
174
+ node.declaration = funcNode;
175
+ }
176
+ if (funcNode) {
177
+ components.push({ name: name, node: funcNode });
178
+ }
179
+ }
180
+ /**
181
+ * 收集所有导出的标识符名称
182
+ */
183
+ function collectExportedNames(program) {
184
+ const names = new Set();
185
+ for (const node of program.body) {
186
+ if (node.type === 'ExportNamedDeclaration') {
187
+ collectFromNamedExport(node, names);
188
+ }
189
+ else if (node.type === 'ExportDefaultDeclaration') {
190
+ collectFromDefaultExport(node, names);
191
+ }
192
+ }
193
+ return names;
194
+ }
195
+ /**
196
+ * 收集模块中的组件函数
197
+ */
198
+ export function collectComponentFunctions(program) {
199
+ const exportedNames = collectExportedNames(program);
200
+ const components = [];
201
+ for (const node of program.body) {
202
+ // 普通函数声明
203
+ if (node.type === 'FunctionDeclaration' && node.id) {
204
+ tryAddComponent(node.id.name, node, exportedNames, components);
205
+ }
206
+ // 普通变量声明
207
+ else if (node.type === 'VariableDeclaration') {
208
+ processVariableDeclaration(node, exportedNames, components);
209
+ }
210
+ // 命名导出
211
+ else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
212
+ if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
213
+ tryAddComponent(node.declaration.id.name, node.declaration, exportedNames, components);
214
+ }
215
+ else if (node.declaration.type === 'VariableDeclaration') {
216
+ processVariableDeclaration(node.declaration, exportedNames, components);
217
+ }
218
+ }
219
+ // 默认导出
220
+ else if (node.type === 'ExportDefaultDeclaration') {
221
+ const decl = node.declaration;
222
+ // 命名函数声明
223
+ if (decl.type === 'FunctionDeclaration' && decl.id) {
224
+ tryAddComponent(decl.id.name, decl, exportedNames, components);
225
+ }
226
+ // 匿名函数(函数声明、函数表达式、箭头函数)
227
+ else {
228
+ processAnonymousDefaultExport(node, exportedNames, components);
229
+ }
230
+ }
231
+ }
232
+ return components;
233
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 生成唯一的别名
3
+ * 从 $1 开始递增,直到找到不冲突的名称
4
+ */
5
+ export function generateUniqueAlias(baseName, existingNames) {
6
+ let index = 1;
7
+ while (existingNames.has(`${baseName}$${index}`)) {
8
+ index++;
9
+ }
10
+ return `${baseName}$${index}`;
11
+ }
@@ -0,0 +1,16 @@
1
+ // 类型守卫
2
+ export { isWhitespaceJSXText } from './ast-guards.js';
3
+ // JSX 辅助函数
4
+ export { getJSXElementName, isPureCompileComponent, isComponent, isNativeElement, getJSXAttributeByName, hasDirective, getDirectiveValue, isVIfChain, isVIf, isVElseIf, isVElse, removeVDirectives, removeAttribute, filterWhitespaceChildren, validateMatchInSwitch } from './jsx-helpers.js';
5
+ // AST 构建函数
6
+ export { createUnrefCall, createAccessCall, createDynamicCall, createBranchCall, createCreateViewCall, createWithDirectivesCall, createArrowFunction, createLocationObject, addPureComment, getAlias } from './ast-builders.js';
7
+ // 模式处理辅助函数
8
+ export { collectPatternBindings, collectObjectPatternBindings } from './pattern-helpers.js';
9
+ // Branch 工厂
10
+ export { createBranch, createBinaryBranch, buildNestedCondition } from './branch-factory.js';
11
+ // v-if 链处理工具
12
+ export { validateVIfChain, collectVIfChainInfo, collectFragmentVIfChains } from './vif-helpers.js';
13
+ // 组件收集
14
+ export { collectComponentFunctions } from './component-collect.js';
15
+ // 生成器
16
+ export { generateUniqueAlias } from './generate.js';