|
|
@ -1,6 +1,6 @@ |
|
|
|
const { readFileSync, existsSync } = require('fs') |
|
|
|
const { readFileSync, existsSync } = require('fs') |
|
|
|
const { resolve } = require('path') |
|
|
|
const { resolve } = require('path') |
|
|
|
const { parse } = require('@vue/compiler-dom') |
|
|
|
const { parse } = require('@vue/compiler-sfc') |
|
|
|
const parser = require('@babel/parser') |
|
|
|
const parser = require('@babel/parser') |
|
|
|
const traverse = require('@babel/traverse').default |
|
|
|
const traverse = require('@babel/traverse').default |
|
|
|
|
|
|
|
|
|
|
@ -10,6 +10,23 @@ const traverse = require('@babel/traverse').default |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
class CallChainTracer { |
|
|
|
class CallChainTracer { |
|
|
|
constructor() { |
|
|
|
constructor() { |
|
|
|
|
|
|
|
this.debugMode = process.env.ROUTE_MAPPING_DEBUG === 'true' || process.argv.includes('--debug') |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 调试日志输出 |
|
|
|
|
|
|
|
* @param {string} message - 日志消息 |
|
|
|
|
|
|
|
* @param {any} data - 附加数据 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
debugLog(message, data = null) { |
|
|
|
|
|
|
|
if (this.debugMode) { |
|
|
|
|
|
|
|
const timestamp = new Date().toISOString() |
|
|
|
|
|
|
|
if (data) { |
|
|
|
|
|
|
|
console.log(`[${timestamp}] [CallChainTracer] ${message}`, data) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
console.log(`[${timestamp}] [CallChainTracer] ${message}`) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -18,21 +35,32 @@ class CallChainTracer { |
|
|
|
* @returns {Array} 增强的API映射数组 |
|
|
|
* @returns {Array} 增强的API映射数组 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
traceMethodTriggersToVisualComponents(apiMappings) { |
|
|
|
traceMethodTriggersToVisualComponents(apiMappings) { |
|
|
|
|
|
|
|
this.debugLog('开始追溯method类型的触发源到可视控件') |
|
|
|
|
|
|
|
this.debugLog('API映射数量', apiMappings.length) |
|
|
|
|
|
|
|
|
|
|
|
const enhancedApiMappings = apiMappings.map(module => { |
|
|
|
const enhancedApiMappings = apiMappings.map(module => { |
|
|
|
|
|
|
|
this.debugLog(`处理模块: ${module.module}`) |
|
|
|
|
|
|
|
|
|
|
|
const enhancedApiMappings = module.apiMappings.map(api => { |
|
|
|
const enhancedApiMappings = module.apiMappings.map(api => { |
|
|
|
if (!api.triggerSources || api.triggerSources.length === 0) { |
|
|
|
if (!api.triggerSources || api.triggerSources.length === 0) { |
|
|
|
|
|
|
|
this.debugLog(`API ${api.apiMethodName} 没有触发源,跳过`) |
|
|
|
return api |
|
|
|
return api |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog(`处理API: ${api.apiMethodName},触发源数量: ${api.triggerSources.length}`) |
|
|
|
|
|
|
|
|
|
|
|
// 只处理triggerType为method的触发源
|
|
|
|
// 只处理triggerType为method的触发源
|
|
|
|
const enhancedTriggerSources = api.triggerSources.map(trigger => { |
|
|
|
const enhancedTriggerSources = api.triggerSources.map(trigger => { |
|
|
|
if (trigger.triggerType === 'method') { |
|
|
|
if (trigger.triggerType === 'method') { |
|
|
|
return this.traceMethodToVisualComponent( |
|
|
|
this.debugLog(`追溯method类型触发源: ${trigger.triggerName} in ${trigger.component}`) |
|
|
|
|
|
|
|
const result = this.traceMethodToVisualComponent( |
|
|
|
trigger, |
|
|
|
trigger, |
|
|
|
module.module, |
|
|
|
module.module, |
|
|
|
module.serviceName, |
|
|
|
module.serviceName, |
|
|
|
api.apiMethodName |
|
|
|
api.apiMethodName |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
this.debugLog(`追溯结果:`, result) |
|
|
|
|
|
|
|
return result |
|
|
|
} |
|
|
|
} |
|
|
|
return trigger |
|
|
|
return trigger |
|
|
|
}) |
|
|
|
}) |
|
|
@ -49,6 +77,7 @@ class CallChainTracer { |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog('追溯完成') |
|
|
|
return enhancedApiMappings |
|
|
|
return enhancedApiMappings |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -61,21 +90,33 @@ class CallChainTracer { |
|
|
|
* @returns {Object} 增强的触发源对象 |
|
|
|
* @returns {Object} 增强的触发源对象 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
traceMethodToVisualComponent(trigger, moduleName, serviceName, apiMethodName) { |
|
|
|
traceMethodToVisualComponent(trigger, moduleName, serviceName, apiMethodName) { |
|
|
|
|
|
|
|
this.debugLog(`开始追溯method: ${trigger.triggerName} in ${trigger.component}`) |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
// 查找组件文件
|
|
|
|
// 查找组件文件
|
|
|
|
const componentPath = this.findComponentFile(trigger.component, moduleName) |
|
|
|
const componentPath = this.findComponentFile(trigger.component, moduleName) |
|
|
|
|
|
|
|
this.debugLog(`查找组件文件: ${trigger.component} in ${moduleName}`, componentPath) |
|
|
|
|
|
|
|
|
|
|
|
if (!componentPath) { |
|
|
|
if (!componentPath) { |
|
|
|
|
|
|
|
this.debugLog(`未找到组件文件: ${trigger.component}`) |
|
|
|
return trigger |
|
|
|
return trigger |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const content = readFileSync(componentPath, 'utf-8') |
|
|
|
const content = readFileSync(componentPath, 'utf-8') |
|
|
|
|
|
|
|
this.debugLog(`读取组件文件成功,内容长度: ${content.length}`) |
|
|
|
|
|
|
|
|
|
|
|
// 解析Vue组件
|
|
|
|
// 解析Vue组件
|
|
|
|
const ast = this.parseVueComponent(content) |
|
|
|
const ast = this.parseVueComponent(content) |
|
|
|
if (!ast) return trigger |
|
|
|
this.debugLog(`解析Vue组件结果:`, ast ? '成功' : '失败') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!ast) { |
|
|
|
|
|
|
|
this.debugLog(`Vue组件解析失败`) |
|
|
|
|
|
|
|
return trigger |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 建立函数调用关系映射
|
|
|
|
// 建立函数调用关系映射
|
|
|
|
const functionCallMap = this.buildFunctionCallMap(ast) |
|
|
|
const functionCallMap = this.buildFunctionCallMap(ast) |
|
|
|
|
|
|
|
this.debugLog(`建立函数调用关系映射,映射数量: ${functionCallMap.size}`) |
|
|
|
|
|
|
|
|
|
|
|
// 追溯method到可视控件
|
|
|
|
// 追溯method到可视控件
|
|
|
|
const visualContext = this.traceToVisualComponent( |
|
|
|
const visualContext = this.traceToVisualComponent( |
|
|
@ -85,16 +126,22 @@ class CallChainTracer { |
|
|
|
trigger.component |
|
|
|
trigger.component |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog(`追溯可视控件结果:`, visualContext) |
|
|
|
|
|
|
|
|
|
|
|
if (visualContext) { |
|
|
|
if (visualContext) { |
|
|
|
return { |
|
|
|
const result = { |
|
|
|
...trigger, |
|
|
|
...trigger, |
|
|
|
triggerName: visualContext.triggerName, |
|
|
|
triggerName: visualContext.triggerName, |
|
|
|
triggerType: visualContext.triggerType |
|
|
|
triggerType: visualContext.triggerType |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this.debugLog(`追溯成功,返回结果:`, result) |
|
|
|
|
|
|
|
return result |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog(`追溯失败,返回原始trigger`) |
|
|
|
return trigger |
|
|
|
return trigger |
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
this.debugLog(`追溯过程中发生错误:`, error.message) |
|
|
|
return trigger |
|
|
|
return trigger |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -106,21 +153,28 @@ class CallChainTracer { |
|
|
|
* @returns {string|null} 组件文件路径 |
|
|
|
* @returns {string|null} 组件文件路径 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
findComponentFile(componentName, moduleName) { |
|
|
|
findComponentFile(componentName, moduleName) { |
|
|
|
|
|
|
|
this.debugLog(`查找组件文件: ${componentName} in ${moduleName}`) |
|
|
|
|
|
|
|
|
|
|
|
// 优先在指定模块中查找
|
|
|
|
// 优先在指定模块中查找
|
|
|
|
if (moduleName) { |
|
|
|
if (moduleName) { |
|
|
|
// 检查views目录
|
|
|
|
// 检查views目录
|
|
|
|
const viewPath = resolve(__dirname, `../../src/renderer/modules/${moduleName}/views/${componentName}.vue`) |
|
|
|
const viewPath = resolve(__dirname, `../../src/renderer/modules/${moduleName}/views/${componentName}.vue`) |
|
|
|
|
|
|
|
this.debugLog(`检查views路径: ${viewPath}`, existsSync(viewPath)) |
|
|
|
if (existsSync(viewPath)) { |
|
|
|
if (existsSync(viewPath)) { |
|
|
|
|
|
|
|
this.debugLog(`找到组件文件: ${viewPath}`) |
|
|
|
return viewPath |
|
|
|
return viewPath |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 检查components目录
|
|
|
|
// 检查components目录
|
|
|
|
const componentPath = resolve(__dirname, `../../src/renderer/modules/${moduleName}/components/${componentName}.vue`) |
|
|
|
const componentPath = resolve(__dirname, `../../src/renderer/modules/${moduleName}/components/${componentName}.vue`) |
|
|
|
|
|
|
|
this.debugLog(`检查components路径: ${componentPath}`, existsSync(componentPath)) |
|
|
|
if (existsSync(componentPath)) { |
|
|
|
if (existsSync(componentPath)) { |
|
|
|
|
|
|
|
this.debugLog(`找到组件文件: ${componentPath}`) |
|
|
|
return componentPath |
|
|
|
return componentPath |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog(`未找到组件文件: ${componentName}`) |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -133,11 +187,15 @@ class CallChainTracer { |
|
|
|
try { |
|
|
|
try { |
|
|
|
// 提取script部分
|
|
|
|
// 提取script部分
|
|
|
|
const scriptMatch = content.match(/<script[^>]*>([\s\S]*?)<\/script>/) |
|
|
|
const scriptMatch = content.match(/<script[^>]*>([\s\S]*?)<\/script>/) |
|
|
|
|
|
|
|
this.debugLog(`提取script部分:`, scriptMatch ? '成功' : '失败') |
|
|
|
|
|
|
|
|
|
|
|
if (!scriptMatch) { |
|
|
|
if (!scriptMatch) { |
|
|
|
|
|
|
|
this.debugLog(`未找到script标签`) |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const scriptContent = scriptMatch[1] |
|
|
|
const scriptContent = scriptMatch[1] |
|
|
|
|
|
|
|
this.debugLog(`script内容长度: ${scriptContent.length}`) |
|
|
|
|
|
|
|
|
|
|
|
// 使用Babel解析JavaScript
|
|
|
|
// 使用Babel解析JavaScript
|
|
|
|
const ast = parser.parse(scriptContent, { |
|
|
|
const ast = parser.parse(scriptContent, { |
|
|
@ -145,8 +203,10 @@ class CallChainTracer { |
|
|
|
plugins: ['jsx', 'typescript'] |
|
|
|
plugins: ['jsx', 'typescript'] |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog(`Babel解析结果:`, ast ? '成功' : '失败') |
|
|
|
return ast |
|
|
|
return ast |
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
this.debugLog(`解析Vue组件时发生错误:`, error.message) |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -220,21 +280,31 @@ class CallChainTracer { |
|
|
|
* @returns {Object|null} 可视控件上下文 |
|
|
|
* @returns {Object|null} 可视控件上下文 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
traceToVisualComponent(methodName, functionCallMap, filePath, componentName) { |
|
|
|
traceToVisualComponent(methodName, functionCallMap, filePath, componentName) { |
|
|
|
|
|
|
|
this.debugLog(`追溯method到可视控件: ${methodName}`) |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
// 读取组件文件内容
|
|
|
|
// 读取组件文件内容
|
|
|
|
const content = readFileSync(filePath, 'utf-8') |
|
|
|
const content = readFileSync(filePath, 'utf-8') |
|
|
|
|
|
|
|
|
|
|
|
// 分析模板中的事件绑定
|
|
|
|
// 分析模板中的事件绑定
|
|
|
|
|
|
|
|
this.debugLog(`分析模板中的事件绑定: ${methodName}`) |
|
|
|
const visualContext = this.analyzeTemplateForMethod(content, methodName, componentName, filePath) |
|
|
|
const visualContext = this.analyzeTemplateForMethod(content, methodName, componentName, filePath) |
|
|
|
|
|
|
|
this.debugLog(`模板分析结果:`, visualContext) |
|
|
|
|
|
|
|
|
|
|
|
if (visualContext) { |
|
|
|
if (visualContext) { |
|
|
|
|
|
|
|
this.debugLog(`在模板中找到事件绑定`) |
|
|
|
return visualContext |
|
|
|
return visualContext |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果模板中没有找到,检查是否有其他方法调用了这个方法
|
|
|
|
// 如果模板中没有找到,检查是否有其他方法调用了这个方法
|
|
|
|
|
|
|
|
this.debugLog(`模板中未找到,检查方法调用关系`) |
|
|
|
const callerContext = this.findMethodCaller(methodName, functionCallMap) |
|
|
|
const callerContext = this.findMethodCaller(methodName, functionCallMap) |
|
|
|
|
|
|
|
this.debugLog(`找到调用者:`, callerContext) |
|
|
|
|
|
|
|
|
|
|
|
if (callerContext) { |
|
|
|
if (callerContext) { |
|
|
|
// 检查调用者是否是生命周期钩子
|
|
|
|
// 检查调用者是否是生命周期钩子
|
|
|
|
if (this.isLifecycleHook(callerContext)) { |
|
|
|
if (this.isLifecycleHook(callerContext)) { |
|
|
|
|
|
|
|
this.debugLog(`调用者是生命周期钩子: ${callerContext}`) |
|
|
|
return { |
|
|
|
return { |
|
|
|
triggerName: '', |
|
|
|
triggerName: '', |
|
|
|
triggerType: 'page' |
|
|
|
triggerType: 'page' |
|
|
@ -242,11 +312,13 @@ class CallChainTracer { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 继续递归追溯
|
|
|
|
// 继续递归追溯
|
|
|
|
|
|
|
|
this.debugLog(`递归追溯调用者: ${callerContext}`) |
|
|
|
return this.traceToVisualComponent(callerContext, functionCallMap, filePath, componentName) |
|
|
|
return this.traceToVisualComponent(callerContext, functionCallMap, filePath, componentName) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog(`未找到调用者,追溯失败`) |
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
// 静默处理错误
|
|
|
|
this.debugLog(`追溯可视控件时发生错误:`, error.message) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return null |
|
|
|
return null |
|
|
@ -261,24 +333,36 @@ class CallChainTracer { |
|
|
|
* @returns {Object|null} 可视控件上下文 |
|
|
|
* @returns {Object|null} 可视控件上下文 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
analyzeTemplateForMethod(content, methodName, componentName, filePath) { |
|
|
|
analyzeTemplateForMethod(content, methodName, componentName, filePath) { |
|
|
|
|
|
|
|
this.debugLog(`分析模板中的方法调用: ${methodName}`) |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
// 使用Vue编译器解析单文件组件
|
|
|
|
// 使用Vue编译器解析单文件组件
|
|
|
|
const { descriptor } = parse(content) |
|
|
|
const { descriptor } = parse(content) |
|
|
|
|
|
|
|
this.debugLog(`Vue编译器解析结果:`, descriptor ? '成功' : '失败') |
|
|
|
|
|
|
|
|
|
|
|
if (!descriptor.template) { |
|
|
|
if (!descriptor.template) { |
|
|
|
|
|
|
|
this.debugLog(`未找到template部分`) |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 解析模板AST
|
|
|
|
// 解析模板AST
|
|
|
|
const templateAst = descriptor.template.ast |
|
|
|
const templateAst = descriptor.template.ast |
|
|
|
|
|
|
|
this.debugLog(`模板AST解析结果:`, templateAst ? '成功' : '失败') |
|
|
|
|
|
|
|
|
|
|
|
if (!templateAst) { |
|
|
|
if (!templateAst) { |
|
|
|
|
|
|
|
this.debugLog(`模板AST解析失败`) |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 遍历模板AST,查找事件绑定
|
|
|
|
// 遍历模板AST,查找事件绑定
|
|
|
|
return this.findEventBindingInTemplate(templateAst, methodName, componentName, filePath) |
|
|
|
this.debugLog(`开始遍历模板AST查找事件绑定`) |
|
|
|
|
|
|
|
const result = this.findEventBindingInTemplate(templateAst, methodName, componentName, filePath) |
|
|
|
|
|
|
|
this.debugLog(`模板AST遍历结果:`, result) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result |
|
|
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
this.debugLog(`分析模板时发生错误:`, error.message) |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -292,29 +376,49 @@ class CallChainTracer { |
|
|
|
* @returns {Object|null} 可视组件上下文 |
|
|
|
* @returns {Object|null} 可视组件上下文 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
findEventBindingInTemplate(node, methodName, componentName, filePath) { |
|
|
|
findEventBindingInTemplate(node, methodName, componentName, filePath) { |
|
|
|
if (!node) return null |
|
|
|
this.debugLog(`查找事件绑定: ${methodName} in ${node.tag || 'root'}`) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!node) { |
|
|
|
|
|
|
|
this.debugLog(`节点为空`) |
|
|
|
|
|
|
|
return null |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 检查当前节点是否有事件绑定
|
|
|
|
// 检查当前节点是否有事件绑定
|
|
|
|
if (node.props) { |
|
|
|
if (node.props) { |
|
|
|
|
|
|
|
this.debugLog(`检查节点属性,属性数量: ${node.props.length}`) |
|
|
|
|
|
|
|
|
|
|
|
for (const prop of node.props) { |
|
|
|
for (const prop of node.props) { |
|
|
|
if (prop.type === 7) { // DIRECTIVE类型
|
|
|
|
if (prop.type === 7) { // DIRECTIVE类型
|
|
|
|
const eventName = prop.name |
|
|
|
const eventName = prop.name |
|
|
|
|
|
|
|
this.debugLog(`检查指令: ${eventName}`) |
|
|
|
|
|
|
|
|
|
|
|
if (eventName === 'on' && prop.arg) { |
|
|
|
if (eventName === 'on' && prop.arg) { |
|
|
|
const eventType = prop.arg.content |
|
|
|
const eventType = prop.arg.content |
|
|
|
|
|
|
|
this.debugLog(`检查事件类型: ${eventType}`) |
|
|
|
|
|
|
|
|
|
|
|
if (['click', 'submit', 'change', 'input'].includes(eventType)) { |
|
|
|
if (['click', 'submit', 'change', 'input'].includes(eventType)) { |
|
|
|
|
|
|
|
this.debugLog(`匹配事件类型: ${eventType}`) |
|
|
|
|
|
|
|
|
|
|
|
// 检查事件处理函数
|
|
|
|
// 检查事件处理函数
|
|
|
|
if (prop.exp && this.isMethodCall(prop.exp, methodName)) { |
|
|
|
if (prop.exp && this.isMethodCall(prop.exp, methodName)) { |
|
|
|
|
|
|
|
this.debugLog(`找到匹配的方法调用: ${methodName}`) |
|
|
|
|
|
|
|
|
|
|
|
const context = this.createVisualContext(node, eventType, componentName, methodName, filePath) |
|
|
|
const context = this.createVisualContext(node, eventType, componentName, methodName, filePath) |
|
|
|
|
|
|
|
this.debugLog(`创建可视上下文:`, context) |
|
|
|
|
|
|
|
|
|
|
|
// 如果找到的是form,需要查找其中的submit按钮
|
|
|
|
// 如果找到的是form,需要查找其中的submit按钮
|
|
|
|
if (context.triggerType === 'form') { |
|
|
|
if (context.triggerType === 'form') { |
|
|
|
|
|
|
|
this.debugLog(`找到form,查找submit按钮`) |
|
|
|
const submitButton = this.findSubmitButtonInForm(node, componentName, methodName, filePath) |
|
|
|
const submitButton = this.findSubmitButtonInForm(node, componentName, methodName, filePath) |
|
|
|
if (submitButton) { |
|
|
|
if (submitButton) { |
|
|
|
|
|
|
|
this.debugLog(`找到submit按钮:`, submitButton) |
|
|
|
return submitButton |
|
|
|
return submitButton |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return context |
|
|
|
return context |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
this.debugLog(`事件处理函数不匹配: ${methodName}`) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -324,14 +428,20 @@ class CallChainTracer { |
|
|
|
|
|
|
|
|
|
|
|
// 递归检查子节点
|
|
|
|
// 递归检查子节点
|
|
|
|
if (node.children) { |
|
|
|
if (node.children) { |
|
|
|
|
|
|
|
this.debugLog(`递归检查子节点,子节点数量: ${node.children.length}`) |
|
|
|
|
|
|
|
|
|
|
|
for (const child of node.children) { |
|
|
|
for (const child of node.children) { |
|
|
|
if (child.type === 1) { // ELEMENT类型
|
|
|
|
if (child.type === 1) { // ELEMENT类型
|
|
|
|
const result = this.findEventBindingInTemplate(child, methodName, componentName, filePath) |
|
|
|
const result = this.findEventBindingInTemplate(child, methodName, componentName, filePath) |
|
|
|
if (result) return result |
|
|
|
if (result) { |
|
|
|
|
|
|
|
this.debugLog(`在子节点中找到结果:`, result) |
|
|
|
|
|
|
|
return result |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog(`未找到事件绑定`) |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -388,24 +498,35 @@ class CallChainTracer { |
|
|
|
* @returns {boolean} 是否是方法调用 |
|
|
|
* @returns {boolean} 是否是方法调用 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
isMethodCall(exp, methodName) { |
|
|
|
isMethodCall(exp, methodName) { |
|
|
|
if (!exp) return false |
|
|
|
this.debugLog(`检查表达式是否是方法调用: ${methodName}`) |
|
|
|
|
|
|
|
this.debugLog(`表达式类型: ${exp.type}`, exp) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!exp) { |
|
|
|
|
|
|
|
this.debugLog(`表达式为空`) |
|
|
|
|
|
|
|
return false |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 简单的方法调用:methodName
|
|
|
|
// 简单的方法调用:methodName
|
|
|
|
if (exp.type === 4 && exp.content === methodName) { // SIMPLE_EXPRESSION
|
|
|
|
if (exp.type === 4 && exp.content === methodName) { // SIMPLE_EXPRESSION
|
|
|
|
|
|
|
|
this.debugLog(`匹配简单方法调用: ${methodName}`) |
|
|
|
return true |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 带参数的方法调用:methodName(...) - 检查content是否以methodName开头
|
|
|
|
// 带参数的方法调用:methodName(...) - 检查content是否以methodName开头
|
|
|
|
if (exp.type === 4 && exp.content && exp.content.startsWith(methodName + '(')) { |
|
|
|
if (exp.type === 4 && exp.content && exp.content.startsWith(methodName + '(')) { |
|
|
|
|
|
|
|
this.debugLog(`匹配带参数的方法调用: ${methodName}`) |
|
|
|
return true |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 带参数的方法调用:methodName(...)
|
|
|
|
// 带参数的方法调用:methodName(...)
|
|
|
|
if (exp.type === 8) { // COMPOUND_EXPRESSION
|
|
|
|
if (exp.type === 8) { // COMPOUND_EXPRESSION
|
|
|
|
|
|
|
|
this.debugLog(`检查复合表达式`) |
|
|
|
const children = exp.children |
|
|
|
const children = exp.children |
|
|
|
if (children && children.length >= 1) { |
|
|
|
if (children && children.length >= 1) { |
|
|
|
const firstChild = children[0] |
|
|
|
const firstChild = children[0] |
|
|
|
|
|
|
|
this.debugLog(`第一个子节点:`, firstChild) |
|
|
|
if (firstChild.type === 4 && firstChild.content === methodName) { |
|
|
|
if (firstChild.type === 4 && firstChild.content === methodName) { |
|
|
|
|
|
|
|
this.debugLog(`匹配复合表达式中的方法调用: ${methodName}`) |
|
|
|
return true |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -413,9 +534,13 @@ class CallChainTracer { |
|
|
|
|
|
|
|
|
|
|
|
// 检查AST中的方法调用
|
|
|
|
// 检查AST中的方法调用
|
|
|
|
if (exp.ast) { |
|
|
|
if (exp.ast) { |
|
|
|
return this.checkAstMethodCall(exp.ast, methodName) |
|
|
|
this.debugLog(`检查AST中的方法调用`) |
|
|
|
|
|
|
|
const result = this.checkAstMethodCall(exp.ast, methodName) |
|
|
|
|
|
|
|
this.debugLog(`AST检查结果:`, result) |
|
|
|
|
|
|
|
return result |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.debugLog(`未匹配任何方法调用模式`) |
|
|
|
return false |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|