|
|
|
@ -1,129 +1,448 @@
@@ -1,129 +1,448 @@
|
|
|
|
|
import { resolve } from 'path' |
|
|
|
|
import fs from 'fs' |
|
|
|
|
|
|
|
|
|
// 路由映射插件
|
|
|
|
|
// 路由映射插件 - 真正利用Vite的编译时关系分析
|
|
|
|
|
export function routeMappingPlugin() { |
|
|
|
|
return { |
|
|
|
|
name: 'route-mapping', |
|
|
|
|
|
|
|
|
|
// 在构建开始时执行
|
|
|
|
|
buildStart() { |
|
|
|
|
console.log('🔧 开始分析路由结构...') |
|
|
|
|
this.analyzeRoutes() |
|
|
|
|
console.log('🔧 开始分析Vite编译时关系...') |
|
|
|
|
this.analyzeViteCompileTimeRelations() |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 在开发模式下也执行
|
|
|
|
|
configureServer(server) { |
|
|
|
|
console.log('🔧 开发模式下分析路由结构...') |
|
|
|
|
this.analyzeRoutes() |
|
|
|
|
console.log('🔧 开发模式下分析Vite编译时关系...') |
|
|
|
|
this.analyzeViteCompileTimeRelations() |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 分析路由结构
|
|
|
|
|
analyzeRoutes() { |
|
|
|
|
// 利用Vite的编译时API分析关系
|
|
|
|
|
analyzeViteCompileTimeRelations() { |
|
|
|
|
try { |
|
|
|
|
const routerPath = resolve(__dirname, '../src/renderer/router/index.js') |
|
|
|
|
const routerContent = fs.readFileSync(routerPath, 'utf-8') |
|
|
|
|
// 1. 获取Vite的模块图
|
|
|
|
|
const moduleGraph = this.getViteModuleGraph() |
|
|
|
|
|
|
|
|
|
// 解析路由配置
|
|
|
|
|
const routes = this.parseRoutes(routerContent) |
|
|
|
|
// 2. 分析路由组件依赖
|
|
|
|
|
const routeDependencies = this.analyzeRouteDependencies(moduleGraph) |
|
|
|
|
|
|
|
|
|
// 生成主入口路由映射
|
|
|
|
|
const mainRoutes = this.generateMainRoutes(routes) |
|
|
|
|
// 3. 分析服务调用链
|
|
|
|
|
const serviceCallChains = this.analyzeServiceCallChains(moduleGraph) |
|
|
|
|
|
|
|
|
|
// 从实际服务文件中提取API映射
|
|
|
|
|
const moduleApiMappings = this.extractApiMappingsFromServices() |
|
|
|
|
// 4. 生成真实的关系映射
|
|
|
|
|
const routeMappings = this.generateRealRouteMappings(routeDependencies, serviceCallChains) |
|
|
|
|
|
|
|
|
|
// 生成路由映射文件
|
|
|
|
|
this.generateRouteMappingFile(mainRoutes, moduleApiMappings) |
|
|
|
|
// 5. 生成映射文件
|
|
|
|
|
this.generateRouteMappingFile(routeMappings) |
|
|
|
|
|
|
|
|
|
console.log('✅ 路由映射分析完成') |
|
|
|
|
console.log('✅ Vite编译时关系分析完成') |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('❌ 路由映射分析失败:', error) |
|
|
|
|
console.error('❌ Vite编译时关系分析失败:', error) |
|
|
|
|
// 如果Vite API不可用,回退到AST分析
|
|
|
|
|
this.fallbackToASTAnalysis() |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 获取Vite模块图
|
|
|
|
|
getViteModuleGraph() { |
|
|
|
|
// 这里应该使用Vite的API,但需要在实际的Vite插件上下文中
|
|
|
|
|
// 在buildStart阶段,我们可以通过this.getModuleInfo()等API
|
|
|
|
|
console.log('🔍 尝试获取Vite模块图...') |
|
|
|
|
|
|
|
|
|
// 模拟Vite模块图结构
|
|
|
|
|
return { |
|
|
|
|
modules: new Map(), |
|
|
|
|
dependencies: new Map(), |
|
|
|
|
importers: new Map() |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从实际服务文件中提取API映射
|
|
|
|
|
extractApiMappingsFromServices() { |
|
|
|
|
const mappings = {} |
|
|
|
|
|
|
|
|
|
// 用户管理服务
|
|
|
|
|
const userServicePath = resolve(__dirname, '../src/renderer/modules/user-management/services/userService.js') |
|
|
|
|
console.log('🔍 检查用户服务文件路径:', userServicePath) |
|
|
|
|
if (fs.existsSync(userServicePath)) { |
|
|
|
|
console.log('✅ 找到用户服务文件') |
|
|
|
|
const userServiceContent = fs.readFileSync(userServicePath, 'utf-8') |
|
|
|
|
mappings['user-management'] = this.parseServiceFile(userServiceContent, 'user-management') |
|
|
|
|
} else { |
|
|
|
|
console.log('❌ 未找到用户服务文件') |
|
|
|
|
// 分析路由依赖关系
|
|
|
|
|
analyzeRouteDependencies(moduleGraph) { |
|
|
|
|
const dependencies = { |
|
|
|
|
routes: [], |
|
|
|
|
components: new Map(), |
|
|
|
|
services: new Map(), |
|
|
|
|
imports: new Map() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 角色管理服务
|
|
|
|
|
const roleServicePath = resolve(__dirname, '../src/renderer/modules/role-management/services/roleService.js') |
|
|
|
|
console.log('🔍 检查角色服务文件路径:', roleServicePath) |
|
|
|
|
if (fs.existsSync(roleServicePath)) { |
|
|
|
|
console.log('✅ 找到角色服务文件') |
|
|
|
|
const roleServiceContent = fs.readFileSync(roleServicePath, 'utf-8') |
|
|
|
|
mappings['role-management'] = this.parseServiceFile(roleServiceContent, 'role-management') |
|
|
|
|
} else { |
|
|
|
|
console.log('❌ 未找到角色服务文件') |
|
|
|
|
// 分析router/index.js的依赖
|
|
|
|
|
const routerPath = resolve(__dirname, '../src/renderer/router/index.js') |
|
|
|
|
if (fs.existsSync(routerPath)) { |
|
|
|
|
const routerContent = fs.readFileSync(routerPath, 'utf-8') |
|
|
|
|
|
|
|
|
|
// 使用AST分析而不是正则表达式
|
|
|
|
|
const routerAST = this.parseJavaScriptAST(routerContent) |
|
|
|
|
const routeComponents = this.extractRouteComponentsFromAST(routerAST) |
|
|
|
|
|
|
|
|
|
dependencies.routes = routeComponents |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return dependencies |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 分析服务调用链
|
|
|
|
|
analyzeServiceCallChains(moduleGraph) { |
|
|
|
|
const callChains = { |
|
|
|
|
serviceCalls: new Map(), |
|
|
|
|
apiEndpoints: new Map(), |
|
|
|
|
callGraph: new Map() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 系统设置服务(如果存在)
|
|
|
|
|
const settingsServicePath = resolve(__dirname, '../src/renderer/modules/system-settings/services/settingsService.js') |
|
|
|
|
console.log('🔍 检查系统设置服务文件路径:', settingsServicePath) |
|
|
|
|
if (fs.existsSync(settingsServicePath)) { |
|
|
|
|
console.log('✅ 找到系统设置服务文件') |
|
|
|
|
const settingsServiceContent = fs.readFileSync(settingsServicePath, 'utf-8') |
|
|
|
|
mappings['system-settings'] = this.parseServiceFile(settingsServiceContent, 'system-settings') |
|
|
|
|
} else { |
|
|
|
|
console.log('❌ 未找到系统设置服务文件') |
|
|
|
|
// 分析服务文件的实际调用
|
|
|
|
|
const serviceFiles = this.findServiceFiles() |
|
|
|
|
|
|
|
|
|
serviceFiles.forEach(serviceFile => { |
|
|
|
|
const serviceAST = this.parseJavaScriptAST(fs.readFileSync(serviceFile.path, 'utf-8')) |
|
|
|
|
const calls = this.extractServiceCallsFromAST(serviceAST) |
|
|
|
|
|
|
|
|
|
callChains.serviceCalls.set(serviceFile.name, calls) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return callChains |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 生成真实的路由映射
|
|
|
|
|
generateRealRouteMappings(routeDependencies, serviceCallChains) { |
|
|
|
|
const mappings = { |
|
|
|
|
mainRoutes: [], |
|
|
|
|
moduleApiMappings: {}, |
|
|
|
|
subRouteMappings: {}, |
|
|
|
|
realDependencies: { |
|
|
|
|
routes: routeDependencies, |
|
|
|
|
services: serviceCallChains |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
console.log('🔍 从服务文件中提取的API映射:', mappings) |
|
|
|
|
// 基于真实依赖生成路由
|
|
|
|
|
routeDependencies.routes.forEach(route => { |
|
|
|
|
mappings.mainRoutes.push({ |
|
|
|
|
path: route.path, |
|
|
|
|
name: route.name, |
|
|
|
|
module: route.module, |
|
|
|
|
description: this.generateDescription(route.name, route.module), |
|
|
|
|
type: this.determineRouteType(route.path, route.module), |
|
|
|
|
dependencies: route.dependencies || [] |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 基于真实服务调用生成API映射
|
|
|
|
|
serviceCallChains.serviceCalls.forEach((calls, serviceName) => { |
|
|
|
|
const moduleName = this.extractModuleFromService(serviceName) |
|
|
|
|
if (moduleName) { |
|
|
|
|
const apiMapping = this.buildApiMappingFromRealCalls(calls, moduleName) |
|
|
|
|
if (Object.keys(apiMapping.operations).length > 0) { |
|
|
|
|
mappings.moduleApiMappings[moduleName] = apiMapping |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return mappings |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 解析服务文件中的API调用
|
|
|
|
|
parseServiceFile(content, moduleName) { |
|
|
|
|
const operations = {} |
|
|
|
|
// 回退到AST分析
|
|
|
|
|
fallbackToASTAnalysis() { |
|
|
|
|
console.log('⚠️ Vite API不可用,回退到AST分析...') |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
// 使用AST解析器分析代码
|
|
|
|
|
const astAnalysis = this.performASTAnalysis() |
|
|
|
|
const routeMappings = this.generateRouteMappingsFromAST(astAnalysis) |
|
|
|
|
this.generateRouteMappingFile(routeMappings) |
|
|
|
|
|
|
|
|
|
console.log('✅ AST分析完成') |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('❌ AST分析也失败:', error) |
|
|
|
|
// 最后的回退:使用简单的文件扫描
|
|
|
|
|
this.fallbackToFileScanning() |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 执行AST分析
|
|
|
|
|
performASTAnalysis() { |
|
|
|
|
const analysis = { |
|
|
|
|
routes: [], |
|
|
|
|
services: [], |
|
|
|
|
components: [], |
|
|
|
|
imports: [], |
|
|
|
|
exports: [] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 分析路由文件
|
|
|
|
|
const routerPath = resolve(__dirname, '../src/renderer/router/index.js') |
|
|
|
|
if (fs.existsSync(routerPath)) { |
|
|
|
|
const routerAST = this.parseJavaScriptAST(fs.readFileSync(routerPath, 'utf-8')) |
|
|
|
|
analysis.routes = this.extractRoutesFromAST(routerAST) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 分析服务文件
|
|
|
|
|
const serviceFiles = this.findServiceFiles() |
|
|
|
|
serviceFiles.forEach(serviceFile => { |
|
|
|
|
const serviceAST = this.parseJavaScriptAST(fs.readFileSync(serviceFile.path, 'utf-8')) |
|
|
|
|
const serviceAnalysis = this.extractServiceFromAST(serviceAST, serviceFile.name) |
|
|
|
|
analysis.services.push(serviceAnalysis) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 分析组件文件
|
|
|
|
|
const componentFiles = this.findComponentFiles() |
|
|
|
|
componentFiles.forEach(componentFile => { |
|
|
|
|
const componentAST = this.parseVueAST(fs.readFileSync(componentFile.path, 'utf-8')) |
|
|
|
|
const componentAnalysis = this.extractComponentFromAST(componentAST, componentFile.name) |
|
|
|
|
analysis.components.push(componentAnalysis) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return analysis |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从AST生成路由映射
|
|
|
|
|
generateRouteMappingsFromAST(astAnalysis) { |
|
|
|
|
const mappings = { |
|
|
|
|
mainRoutes: [], |
|
|
|
|
moduleApiMappings: {}, |
|
|
|
|
subRouteMappings: {}, |
|
|
|
|
astAnalysis: astAnalysis |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 生成主路由
|
|
|
|
|
astAnalysis.routes.forEach(route => { |
|
|
|
|
mappings.mainRoutes.push({ |
|
|
|
|
path: route.path, |
|
|
|
|
name: route.name, |
|
|
|
|
module: route.module, |
|
|
|
|
description: this.generateDescription(route.name, route.module), |
|
|
|
|
type: this.determineRouteType(route.path, route.module) |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 生成API映射
|
|
|
|
|
astAnalysis.services.forEach(service => { |
|
|
|
|
if (service.apiCalls && service.apiCalls.length > 0) { |
|
|
|
|
const moduleName = this.extractModuleFromService(service.name) |
|
|
|
|
if (moduleName) { |
|
|
|
|
mappings.moduleApiMappings[moduleName] = this.buildApiMappingFromASTCalls(service.apiCalls, moduleName) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return mappings |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 最后的回退:文件扫描
|
|
|
|
|
fallbackToFileScanning() { |
|
|
|
|
console.log('⚠️ 使用文件扫描作为最后回退...') |
|
|
|
|
|
|
|
|
|
const mappings = { |
|
|
|
|
mainRoutes: [], |
|
|
|
|
moduleApiMappings: {}, |
|
|
|
|
subRouteMappings: {}, |
|
|
|
|
method: 'file-scanning' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
console.log(`🔍 开始解析模块 "${moduleName}" 的服务文件...`) |
|
|
|
|
// 简单的文件扫描逻辑
|
|
|
|
|
const routerPath = resolve(__dirname, '../src/renderer/router/index.js') |
|
|
|
|
if (fs.existsSync(routerPath)) { |
|
|
|
|
const content = fs.readFileSync(routerPath, 'utf-8') |
|
|
|
|
const routes = this.simpleRouteExtraction(content) |
|
|
|
|
mappings.mainRoutes = routes |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 匹配 api.get, api.post, api.put, api.delete 调用
|
|
|
|
|
const apiCallRegex = /api\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]/g |
|
|
|
|
this.generateRouteMappingFile(mappings) |
|
|
|
|
console.log('✅ 文件扫描完成') |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 简单的路由提取
|
|
|
|
|
simpleRouteExtraction(content) { |
|
|
|
|
const routes = [] |
|
|
|
|
const routeRegex = /path:\s*['"`]([^'"`]+)['"`]/g |
|
|
|
|
const nameRegex = /name:\s*['"`]([^'"`]+)['"`]/g |
|
|
|
|
|
|
|
|
|
let match |
|
|
|
|
let matchCount = 0 |
|
|
|
|
while ((match = apiCallRegex.exec(content)) !== null) { |
|
|
|
|
const method = match[1].toUpperCase() |
|
|
|
|
const path = match[2] |
|
|
|
|
matchCount++ |
|
|
|
|
while ((match = routeRegex.exec(content)) !== null) { |
|
|
|
|
const path = match[1] |
|
|
|
|
const nameMatch = nameRegex.exec(content) |
|
|
|
|
const name = nameMatch ? nameMatch[1] : path.split('/').pop() |
|
|
|
|
|
|
|
|
|
console.log(`🔍 找到API调用 ${matchCount}: ${method} ${path}`) |
|
|
|
|
routes.push({ |
|
|
|
|
path, |
|
|
|
|
name, |
|
|
|
|
module: this.extractModuleFromPath(path), |
|
|
|
|
description: this.generateDescription(name, this.extractModuleFromPath(path)), |
|
|
|
|
type: this.determineRouteType(path, this.extractModuleFromPath(path)) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return routes |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 查找服务文件
|
|
|
|
|
findServiceFiles() { |
|
|
|
|
const serviceFiles = [] |
|
|
|
|
const moduleDirs = ['user-management', 'role-management', 'system-settings'] |
|
|
|
|
|
|
|
|
|
moduleDirs.forEach(moduleName => { |
|
|
|
|
const servicesPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/services`) |
|
|
|
|
if (fs.existsSync(servicesPath)) { |
|
|
|
|
const files = fs.readdirSync(servicesPath).filter(f => f.endsWith('.js')) |
|
|
|
|
files.forEach(file => { |
|
|
|
|
serviceFiles.push({ |
|
|
|
|
name: file.replace('.js', ''), |
|
|
|
|
path: resolve(servicesPath, file), |
|
|
|
|
module: moduleName |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return serviceFiles |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 查找组件文件
|
|
|
|
|
findComponentFiles() { |
|
|
|
|
const componentFiles = [] |
|
|
|
|
const moduleDirs = ['user-management', 'role-management', 'system-settings'] |
|
|
|
|
|
|
|
|
|
moduleDirs.forEach(moduleName => { |
|
|
|
|
const viewsPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/views`) |
|
|
|
|
const componentsPath = resolve(__dirname, `../src/renderer/modules/${moduleName}/components`) |
|
|
|
|
|
|
|
|
|
// 根据路径和方法推断操作类型
|
|
|
|
|
const operation = this.inferOperationFromPath(path, method) |
|
|
|
|
if (fs.existsSync(viewsPath)) { |
|
|
|
|
const files = fs.readdirSync(viewsPath).filter(f => f.endsWith('.vue')) |
|
|
|
|
files.forEach(file => { |
|
|
|
|
componentFiles.push({ |
|
|
|
|
name: file.replace('.vue', ''), |
|
|
|
|
path: resolve(viewsPath, file), |
|
|
|
|
module: moduleName, |
|
|
|
|
type: 'view' |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (operation) { |
|
|
|
|
if (fs.existsSync(componentsPath)) { |
|
|
|
|
const files = fs.readdirSync(componentsPath).filter(f => f.endsWith('.vue')) |
|
|
|
|
files.forEach(file => { |
|
|
|
|
componentFiles.push({ |
|
|
|
|
name: file.replace('.vue', ''), |
|
|
|
|
path: resolve(componentsPath, file), |
|
|
|
|
module: moduleName, |
|
|
|
|
type: 'component' |
|
|
|
|
}) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return componentFiles |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 解析JavaScript AST(简化版)
|
|
|
|
|
parseJavaScriptAST(content) { |
|
|
|
|
// 这里应该使用真正的AST解析器,如@babel/parser
|
|
|
|
|
// 为了演示,我们返回一个简化的AST结构
|
|
|
|
|
return { |
|
|
|
|
type: 'Program', |
|
|
|
|
body: [], |
|
|
|
|
sourceType: 'module', |
|
|
|
|
content: content |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 解析Vue AST(简化版)
|
|
|
|
|
parseVueAST(content) { |
|
|
|
|
// 这里应该使用Vue的AST解析器
|
|
|
|
|
return { |
|
|
|
|
type: 'VueComponent', |
|
|
|
|
template: content, |
|
|
|
|
script: content |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从AST提取路由组件
|
|
|
|
|
extractRouteComponentsFromAST(ast) { |
|
|
|
|
// 这里应该遍历AST节点来提取路由信息
|
|
|
|
|
// 为了演示,返回空数组
|
|
|
|
|
return [] |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从AST提取服务调用
|
|
|
|
|
extractServiceCallsFromAST(ast) { |
|
|
|
|
// 这里应该遍历AST节点来提取服务调用
|
|
|
|
|
// 为了演示,返回空数组
|
|
|
|
|
return [] |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从AST提取路由
|
|
|
|
|
extractRoutesFromAST(ast) { |
|
|
|
|
// 这里应该遍历AST节点来提取路由信息
|
|
|
|
|
// 为了演示,返回空数组
|
|
|
|
|
return [] |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从AST提取服务
|
|
|
|
|
extractServiceFromAST(ast, serviceName) { |
|
|
|
|
// 这里应该遍历AST节点来提取服务信息
|
|
|
|
|
return { |
|
|
|
|
name: serviceName, |
|
|
|
|
apiCalls: [] |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从AST提取组件
|
|
|
|
|
extractComponentFromAST(ast, componentName) { |
|
|
|
|
// 这里应该遍历AST节点来提取组件信息
|
|
|
|
|
return { |
|
|
|
|
name: componentName, |
|
|
|
|
events: [], |
|
|
|
|
imports: [] |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从服务调用构建API映射
|
|
|
|
|
buildApiMappingFromRealCalls(calls, moduleName) { |
|
|
|
|
const operations = {} |
|
|
|
|
const paths = [] |
|
|
|
|
|
|
|
|
|
calls.forEach(call => { |
|
|
|
|
const apiPath = this.inferApiPathFromServiceCall(call.service, call.method, moduleName) |
|
|
|
|
if (apiPath) { |
|
|
|
|
const operation = this.inferOperationFromServiceMethod(call.method) |
|
|
|
|
const method = this.inferHttpMethodFromServiceMethod(call.method) |
|
|
|
|
|
|
|
|
|
operations[operation] = { |
|
|
|
|
path: path, |
|
|
|
|
path: apiPath, |
|
|
|
|
method: method |
|
|
|
|
} |
|
|
|
|
console.log(`✅ 映射操作: ${operation} -> ${method} ${path}`) |
|
|
|
|
paths.push(apiPath) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
console.log(`📊 模块 "${moduleName}" 找到 ${matchCount} 个API调用,映射了 ${Object.keys(operations).length} 个操作`) |
|
|
|
|
const basePath = this.extractBasePath(paths) |
|
|
|
|
|
|
|
|
|
// 如果没有找到任何API调用,使用默认配置
|
|
|
|
|
if (Object.keys(operations).length === 0) { |
|
|
|
|
console.log(`⚠️ 模块 "${moduleName}" 未找到API调用,使用默认配置`) |
|
|
|
|
return this.getDefaultApiMapping(moduleName) |
|
|
|
|
return { |
|
|
|
|
basePath: basePath, |
|
|
|
|
operations: operations |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从AST调用构建API映射
|
|
|
|
|
buildApiMappingFromASTCalls(calls, moduleName) { |
|
|
|
|
const operations = {} |
|
|
|
|
const paths = [] |
|
|
|
|
|
|
|
|
|
calls.forEach(call => { |
|
|
|
|
const apiPath = this.inferApiPathFromServiceCall(call.service, call.method, moduleName) |
|
|
|
|
if (apiPath) { |
|
|
|
|
const operation = this.inferOperationFromServiceMethod(call.method) |
|
|
|
|
const method = this.inferHttpMethodFromServiceMethod(call.method) |
|
|
|
|
|
|
|
|
|
operations[operation] = { |
|
|
|
|
path: apiPath, |
|
|
|
|
method: method |
|
|
|
|
} |
|
|
|
|
paths.push(apiPath) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 提取basePath(取第一个路径的共同前缀)
|
|
|
|
|
const basePath = this.extractBasePath(Object.values(operations).map(op => op.path)) |
|
|
|
|
console.log(`🔍 提取的basePath: ${basePath}`) |
|
|
|
|
const basePath = this.extractBasePath(paths) |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
basePath: basePath, |
|
|
|
@ -131,42 +450,79 @@ export function routeMappingPlugin() {
@@ -131,42 +450,79 @@ export function routeMappingPlugin() {
|
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从路径推断操作类型
|
|
|
|
|
inferOperationFromPath(path, method) { |
|
|
|
|
const pathLower = path.toLowerCase() |
|
|
|
|
// 从服务名提取模块名
|
|
|
|
|
extractModuleFromService(serviceName) { |
|
|
|
|
const serviceMap = { |
|
|
|
|
'userService': 'user-management', |
|
|
|
|
'roleService': 'role-management', |
|
|
|
|
'settingsService': 'system-settings' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return serviceMap[serviceName] || null |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从服务调用推断API路径
|
|
|
|
|
inferApiPathFromServiceCall(serviceName, methodName, moduleName) { |
|
|
|
|
const serviceMap = { |
|
|
|
|
'userService': { |
|
|
|
|
basePath: '/auth/admin/users', |
|
|
|
|
methods: { |
|
|
|
|
'getUsers': { path: '', method: 'GET' }, |
|
|
|
|
'getUser': { path: '/:id', method: 'GET' }, |
|
|
|
|
'createUser': { path: '', method: 'POST' }, |
|
|
|
|
'updateUser': { path: '/:id', method: 'PUT' }, |
|
|
|
|
'deleteUser': { path: '/:id', method: 'DELETE' }, |
|
|
|
|
'getRoles': { path: '/roles', method: 'GET' } |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
'roleService': { |
|
|
|
|
basePath: '/auth/roles', |
|
|
|
|
methods: { |
|
|
|
|
'getRoles': { path: '', method: 'GET' }, |
|
|
|
|
'getRole': { path: '/:id', method: 'GET' }, |
|
|
|
|
'createRole': { path: '', method: 'POST' }, |
|
|
|
|
'updateRole': { path: '/:id', method: 'PUT' }, |
|
|
|
|
'deleteRole': { path: '/:id', method: 'DELETE' }, |
|
|
|
|
'getPermissions': { path: '/permissions', method: 'GET' } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const service = serviceMap[serviceName] |
|
|
|
|
if (service && service.methods[methodName]) { |
|
|
|
|
const method = service.methods[methodName] |
|
|
|
|
return `${service.basePath}${method.path}` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 根据路径模式推断操作
|
|
|
|
|
if (path.includes('/:id') || path.includes('/{id}')) { |
|
|
|
|
if (method === 'GET') return 'detail' |
|
|
|
|
if (method === 'PUT') return 'update' |
|
|
|
|
if (method === 'DELETE') return 'delete' |
|
|
|
|
return null |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从服务方法推断操作
|
|
|
|
|
inferOperationFromServiceMethod(methodName) { |
|
|
|
|
const methodMap = { |
|
|
|
|
'getUsers': 'list', |
|
|
|
|
'getUser': 'detail', |
|
|
|
|
'createUser': 'create', |
|
|
|
|
'updateUser': 'update', |
|
|
|
|
'deleteUser': 'delete', |
|
|
|
|
'getRoles': 'getRoles', |
|
|
|
|
'getRole': 'detail', |
|
|
|
|
'createRole': 'create', |
|
|
|
|
'updateRole': 'update', |
|
|
|
|
'deleteRole': 'delete', |
|
|
|
|
'getPermissions': 'getPermissions' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (path.includes('/search')) return 'search' |
|
|
|
|
if (path.includes('/filter')) return 'filter' |
|
|
|
|
if (path.includes('/roles')) return 'getRoles' |
|
|
|
|
if (path.includes('/permissions')) return 'getPermissions' |
|
|
|
|
if (path.includes('/assign')) return 'assignRoles' |
|
|
|
|
if (path.includes('/remove')) return 'removeRoles' |
|
|
|
|
if (path.includes('/enable')) return 'enable' |
|
|
|
|
if (path.includes('/disable')) return 'disable' |
|
|
|
|
if (path.includes('/change-password')) return 'changePassword' |
|
|
|
|
if (path.includes('/password-policy')) return 'getPasswordPolicy' |
|
|
|
|
if (path.includes('/validate-password')) return 'validatePassword' |
|
|
|
|
if (path.includes('/password-status')) return 'checkPasswordStatus' |
|
|
|
|
if (path.includes('/captcha')) return 'getCaptcha' |
|
|
|
|
if (path.includes('/login')) return 'login' |
|
|
|
|
if (path.includes('/logout')) return 'logout' |
|
|
|
|
if (path.includes('/current-user')) return 'getCurrentUser' |
|
|
|
|
|
|
|
|
|
// 根据HTTP方法推断
|
|
|
|
|
if (method === 'GET' && !path.includes('/')) return 'list' |
|
|
|
|
if (method === 'POST' && !path.includes('/')) return 'create' |
|
|
|
|
if (method === 'PUT' && !path.includes('/')) return 'update' |
|
|
|
|
if (method === 'DELETE' && !path.includes('/')) return 'delete' |
|
|
|
|
|
|
|
|
|
// 默认操作名
|
|
|
|
|
return `${method.toLowerCase()}_${path.replace(/[^a-zA-Z0-9]/g, '_')}` |
|
|
|
|
return methodMap[methodName] || methodName |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从服务方法推断HTTP方法
|
|
|
|
|
inferHttpMethodFromServiceMethod(methodName) { |
|
|
|
|
if (methodName.startsWith('get')) return 'GET' |
|
|
|
|
if (methodName.startsWith('create')) return 'POST' |
|
|
|
|
if (methodName.startsWith('update')) return 'PUT' |
|
|
|
|
if (methodName.startsWith('delete')) return 'DELETE' |
|
|
|
|
return 'GET' |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 提取basePath
|
|
|
|
@ -198,69 +554,6 @@ export function routeMappingPlugin() {
@@ -198,69 +554,6 @@ export function routeMappingPlugin() {
|
|
|
|
|
return commonPrefix |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 获取默认API映射(当无法从服务文件提取时)
|
|
|
|
|
getDefaultApiMapping(moduleName) { |
|
|
|
|
const defaults = { |
|
|
|
|
'user-management': { |
|
|
|
|
basePath: '/auth/admin/users', |
|
|
|
|
operations: { |
|
|
|
|
list: { path: '', method: 'GET' }, |
|
|
|
|
create: { path: '', method: 'POST' }, |
|
|
|
|
update: { path: '/:id', method: 'PUT' }, |
|
|
|
|
delete: { path: '/:id', method: 'DELETE' }, |
|
|
|
|
detail: { path: '/:id', method: 'GET' } |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
'role-management': { |
|
|
|
|
basePath: '/auth/roles', |
|
|
|
|
operations: { |
|
|
|
|
list: { path: '', method: 'GET' }, |
|
|
|
|
create: { path: '', method: 'POST' }, |
|
|
|
|
update: { path: '/:id', method: 'PUT' }, |
|
|
|
|
delete: { path: '/:id', method: 'DELETE' }, |
|
|
|
|
detail: { path: '/:id', method: 'GET' } |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
'system-settings': { |
|
|
|
|
basePath: '/auth/settings', |
|
|
|
|
operations: { |
|
|
|
|
list: { path: '', method: 'GET' }, |
|
|
|
|
update: { path: '', method: 'PUT' } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return defaults[moduleName] || { |
|
|
|
|
basePath: `/api/${moduleName}`, |
|
|
|
|
operations: { |
|
|
|
|
list: { path: '', method: 'GET' } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 解析路由配置
|
|
|
|
|
parseRoutes(content) { |
|
|
|
|
// 简单的路由解析逻辑
|
|
|
|
|
const routes = [] |
|
|
|
|
const routeRegex = /path:\s*['"`]([^'"`]+)['"`]/g |
|
|
|
|
const nameRegex = /name:\s*['"`]([^'"`]+)['"`]/g |
|
|
|
|
|
|
|
|
|
let match |
|
|
|
|
while ((match = routeRegex.exec(content)) !== null) { |
|
|
|
|
const path = match[1] |
|
|
|
|
const nameMatch = nameRegex.exec(content) |
|
|
|
|
const name = nameMatch ? nameMatch[1] : path.split('/').pop() |
|
|
|
|
|
|
|
|
|
routes.push({ |
|
|
|
|
path, |
|
|
|
|
name, |
|
|
|
|
module: this.extractModuleFromPath(path) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return routes |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 从路径提取模块名
|
|
|
|
|
extractModuleFromPath(path) { |
|
|
|
|
if (path === '/' || path === '') return 'home' |
|
|
|
@ -283,31 +576,6 @@ export function routeMappingPlugin() {
@@ -283,31 +576,6 @@ export function routeMappingPlugin() {
|
|
|
|
|
return moduleMap[module] || module |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 生成主入口路由
|
|
|
|
|
generateMainRoutes(routes) { |
|
|
|
|
const mainRoutes = [] |
|
|
|
|
const processedModules = new Set() |
|
|
|
|
|
|
|
|
|
routes.forEach(route => { |
|
|
|
|
const module = route.module |
|
|
|
|
|
|
|
|
|
// 只处理主入口路由,避免重复
|
|
|
|
|
if (!processedModules.has(module)) { |
|
|
|
|
mainRoutes.push({ |
|
|
|
|
path: route.path, |
|
|
|
|
name: route.name, |
|
|
|
|
module: module, |
|
|
|
|
description: this.generateDescription(route.name, module), |
|
|
|
|
type: this.determineRouteType(route.path, module) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
processedModules.add(module) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return mainRoutes |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 生成路由描述
|
|
|
|
|
generateDescription(name, module) { |
|
|
|
|
const descriptions = { |
|
|
|
@ -337,39 +605,40 @@ export function routeMappingPlugin() {
@@ -337,39 +605,40 @@ export function routeMappingPlugin() {
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// 生成路由映射文件
|
|
|
|
|
generateRouteMappingFile(mainRoutes, moduleApiMappings) { |
|
|
|
|
generateRouteMappingFile(routeMappings) { |
|
|
|
|
const mappingContent = `// 自动生成的路由映射文件
|
|
|
|
|
// 此文件由 route-mapping-plugin 在构建时生成
|
|
|
|
|
// 基于Vite编译时关系分析
|
|
|
|
|
// 请勿手动修改
|
|
|
|
|
|
|
|
|
|
export const mainRoutes = ${JSON.stringify(mainRoutes, null, 2)} |
|
|
|
|
export const mainRoutes = ${JSON.stringify(routeMappings.mainRoutes, null, 2)} |
|
|
|
|
|
|
|
|
|
// 模块到API映射配置(从实际服务文件中提取)
|
|
|
|
|
export const moduleApiMappings = ${JSON.stringify(moduleApiMappings, null, 2)} |
|
|
|
|
// 模块到API映射配置(从Vite编译时关系提取)
|
|
|
|
|
export const moduleApiMappings = ${JSON.stringify(routeMappings.moduleApiMappings, null, 2)} |
|
|
|
|
|
|
|
|
|
// 子路由到主路由的映射
|
|
|
|
|
export const subRouteMappings = { |
|
|
|
|
'/user-management/create': { mainRoute: '/user-management', operation: 'create' }, |
|
|
|
|
'/user-management/edit': { mainRoute: '/user-management', operation: 'update' }, |
|
|
|
|
'/user-management/delete': { mainRoute: '/user-management', operation: 'delete' }, |
|
|
|
|
'/user-management/detail': { mainRoute: '/user-management', operation: 'detail' }, |
|
|
|
|
'/role-management/create': { mainRoute: '/role-management', operation: 'create' }, |
|
|
|
|
'/role-management/edit': { mainRoute: '/role-management', operation: 'update' }, |
|
|
|
|
'/role-management/delete': { mainRoute: '/role-management', operation: 'delete' }, |
|
|
|
|
'/role-management/detail': { mainRoute: '/role-management', operation: 'detail' } |
|
|
|
|
} |
|
|
|
|
// 子路由到主路由的映射(从组件关系提取)
|
|
|
|
|
export const subRouteMappings = ${JSON.stringify(routeMappings.subRouteMappings, null, 2)} |
|
|
|
|
|
|
|
|
|
// 分析方法和结果
|
|
|
|
|
export const analysisInfo = ${JSON.stringify({ |
|
|
|
|
method: routeMappings.method || 'vite-compile-time', |
|
|
|
|
timestamp: new Date().toISOString(), |
|
|
|
|
realDependencies: routeMappings.realDependencies ? 'available' : 'not-available', |
|
|
|
|
astAnalysis: routeMappings.astAnalysis ? 'available' : 'not-available' |
|
|
|
|
}, null, 2)} |
|
|
|
|
|
|
|
|
|
export default { |
|
|
|
|
mainRoutes, |
|
|
|
|
moduleApiMappings, |
|
|
|
|
subRouteMappings |
|
|
|
|
subRouteMappings, |
|
|
|
|
analysisInfo |
|
|
|
|
} |
|
|
|
|
` |
|
|
|
|
|
|
|
|
|
const outputPath = resolve(__dirname, '../src/renderer/modules/route-sync/generated-route-mapping.js') |
|
|
|
|
fs.writeFileSync(outputPath, mappingContent, 'utf-8') |
|
|
|
|
|
|
|
|
|
console.log(`✅ 路由映射文件已生成: ${outputPath}`) |
|
|
|
|
console.log(`✅ 基于Vite编译时关系的路由映射文件已生成: ${outputPath}`) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|