const { readFileSync, existsSync, readdirSync } = require('fs') const { resolve } = require('path') const parser = require('@babel/parser') const traverse = require('@babel/traverse').default /** * 组件关系分析器 * 分析组件之间的层级关系,从子组件追溯到顶级组件 */ class ComponentRelationshipAnalyzer { constructor() { this.componentRelationships = [] this.processedComponents = new Set() } /** * 分析组件关系 * @param {Array} routes - 路由数组 * @param {Array} apiMappings - API映射数组 * @returns {Array} 组件关系列表 */ analyzeComponentRelationships(routes, apiMappings) { this.componentRelationships = [] this.processedComponents.clear() // 获取所有顶级组件(routes中的组件) const topLevelComponents = routes.map(route => ({ component: route.component, module: this.getModuleFromRoute(route), path: route.path })) // 获取所有触发源组件 const triggerSourceComponents = this.extractTriggerSourceComponents(apiMappings) // 为每个触发源组件分析其与顶级组件的关系 triggerSourceComponents.forEach(triggerComponent => { this.analyzeComponentToTopLevel(triggerComponent, topLevelComponents) }) return this.componentRelationships } /** * 从路由中获取模块信息 * @param {Object} route - 路由对象 * @returns {string} 模块名称 */ getModuleFromRoute(route) { // 根据路径推断模块 if (route.path === '/') return 'core' if (route.path.includes('user-management')) return 'user-management' if (route.path.includes('role-management')) return 'role-management' if (route.path.includes('settings')) return 'system-settings' if (route.path.includes('user-profile')) return 'user-management' return 'core' } /** * 提取所有触发源组件 * @param {Array} apiMappings - API映射数组 * @returns {Array} 触发源组件数组 */ extractTriggerSourceComponents(apiMappings) { const components = [] apiMappings.forEach(apiMapping => { if (apiMapping.triggerSources) { apiMapping.triggerSources.forEach(triggerSource => { components.push({ component: triggerSource.component, module: triggerSource.module, triggerName: triggerSource.triggerName, triggerType: triggerSource.triggerType, apiMethodName: apiMapping.apiMethodName, apiModule: apiMapping.module }) }) } }) return components } /** * 分析组件到顶级组件的关系 * @param {Object} triggerComponent - 触发源组件 * @param {Array} topLevelComponents - 顶级组件数组 */ analyzeComponentToTopLevel(triggerComponent, topLevelComponents) { const componentKey = `${triggerComponent.module}:${triggerComponent.component}` // 避免重复处理 if (this.processedComponents.has(componentKey)) { return } this.processedComponents.add(componentKey) // 如果触发源组件本身就是顶级组件,直接建立关系 const isTopLevel = topLevelComponents.find(top => top.component === triggerComponent.component && top.module === triggerComponent.module ) if (isTopLevel) { this.componentRelationships.push({ startComponent: triggerComponent.component, startModule: triggerComponent.module, endComponent: triggerComponent.component, endModule: triggerComponent.module, relationshipType: 'self', path: isTopLevel.path, triggerName: triggerComponent.triggerName, triggerType: triggerComponent.triggerType, apiMethodName: triggerComponent.apiMethodName }) return } // 查找父组件关系 const parentComponents = this.findParentComponents(triggerComponent) parentComponents.forEach(parent => { // 递归查找父组件的父组件,直到找到顶级组件 this.findTopLevelAncestors(parent, triggerComponent, topLevelComponents) }) } /** * 查找组件的父组件 * @param {Object} component - 组件信息 * @returns {Array} 父组件数组 */ findParentComponents(component) { const parents = [] try { // 查找所有模块中的组件,看哪些引用了当前组件 const modulesPath = resolve(__dirname, '../../src/renderer/modules') if (existsSync(modulesPath)) { const moduleDirs = readdirSync(modulesPath, { withFileTypes: true }) .filter(dirent => dirent.isDirectory()) .map(dirent => dirent.name) moduleDirs.forEach(moduleName => { const parentComponents = this.findComponentsInModule(moduleName, component) parents.push(...parentComponents) }) } } catch (error) { // 静默处理错误 } return parents } /** * 在指定模块中查找引用目标组件的组件 * @param {string} moduleName - 模块名称 * @param {Object} targetComponent - 目标组件 * @returns {Array} 父组件数组 */ findComponentsInModule(moduleName, targetComponent) { const parents = [] try { const modulePath = resolve(__dirname, '../../src/renderer/modules', moduleName) if (!existsSync(modulePath)) return parents // 查找views目录 const viewsPath = resolve(modulePath, 'views') if (existsSync(viewsPath)) { const viewFiles = readdirSync(viewsPath).filter(file => file.endsWith('.vue')) viewFiles.forEach(file => { const componentName = file.replace('.vue', '') if (this.componentReferencesTarget(viewsPath, file, targetComponent)) { parents.push({ component: componentName, module: moduleName, type: 'view' }) } }) } // 查找components目录 const componentsPath = resolve(modulePath, 'components') if (existsSync(componentsPath)) { const componentFiles = readdirSync(componentsPath).filter(file => file.endsWith('.vue')) componentFiles.forEach(file => { const componentName = file.replace('.vue', '') if (this.componentReferencesTarget(componentsPath, file, targetComponent)) { parents.push({ component: componentName, module: moduleName, type: 'component' }) } }) } } catch (error) { // 静默处理错误 } return parents } /** * 检查组件是否引用了目标组件 * @param {string} dirPath - 目录路径 * @param {string} fileName - 文件名 * @param {Object} targetComponent - 目标组件 * @returns {boolean} 是否引用 */ componentReferencesTarget(dirPath, fileName, targetComponent) { try { const filePath = resolve(dirPath, fileName) const content = readFileSync(filePath, 'utf-8') // 检查import语句 const importPattern = new RegExp(`import.*${targetComponent.component}.*from`, 'g') if (importPattern.test(content)) { return true } // 检查components注册 const componentPattern = new RegExp(`${targetComponent.component}\\s*:`, 'g') if (componentPattern.test(content)) { return true } // 检查模板中的使用 const templatePattern = new RegExp(`<${targetComponent.component}[\\s>]`, 'g') if (templatePattern.test(content)) { return true } return false } catch (error) { return false } } /** * 查找顶级祖先组件 * @param {Object} parentComponent - 父组件 * @param {Object} originalTrigger - 原始触发组件 * @param {Array} topLevelComponents - 顶级组件数组 */ findTopLevelAncestors(parentComponent, originalTrigger, topLevelComponents) { // 检查父组件是否是顶级组件 const isTopLevel = topLevelComponents.find(top => top.component === parentComponent.component && top.module === parentComponent.module ) if (isTopLevel) { // 找到顶级组件,建立关系 this.componentRelationships.push({ startComponent: originalTrigger.component, startModule: originalTrigger.module, endComponent: parentComponent.component, endModule: parentComponent.module, relationshipType: 'ancestor', path: isTopLevel.path, triggerName: originalTrigger.triggerName, triggerType: originalTrigger.triggerType, apiMethodName: originalTrigger.apiMethodName }) return } // 继续向上查找 const grandParents = this.findParentComponents(parentComponent) grandParents.forEach(grandParent => { this.findTopLevelAncestors(grandParent, originalTrigger, topLevelComponents) }) } } module.exports = ComponentRelationshipAnalyzer