Browse Source

没有完成关系解析

master
hejl 4 days ago
parent
commit
c5e01b96fd
  1. 180
      gofaster/app/package-lock.json
  2. 3
      gofaster/app/package.json
  3. 699
      gofaster/app/plugins/route-mapping-plugin.js

180
gofaster/app/package-lock.json generated

@ -16,9 +16,12 @@ @@ -16,9 +16,12 @@
"vuex": "^4.0.2"
},
"devDependencies": {
"@babel/parser": "^7.28.3",
"@babel/traverse": "^7.28.3",
"@electron/remote": "^2.1.3",
"@types/node": "^24.2.1",
"@vue/cli-service": "^5.0.8",
"@vue/compiler-sfc": "^3.5.21",
"concurrently": "^9.2.0",
"cross-env": "^7.0.3",
"electron-builder": "^26.0.12",
@ -65,6 +68,22 @@ @@ -65,6 +68,22 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/generator": {
"version": "7.28.3",
"resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.28.3.tgz",
"integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.28.3",
"@babel/types": "^7.28.2",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
@ -81,6 +100,15 @@ @@ -81,6 +100,15 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
@ -107,11 +135,11 @@ @@ -107,11 +135,11 @@
}
},
"node_modules/@babel/parser": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
"integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
"version": "7.28.3",
"resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.3.tgz",
"integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==",
"dependencies": {
"@babel/types": "^7.28.0"
"@babel/types": "^7.28.2"
},
"bin": {
"parser": "bin/babel-parser.js"
@ -120,6 +148,38 @@ @@ -120,6 +148,38 @@
"node": ">=6.0.0"
}
},
"node_modules/@babel/template": {
"version": "7.27.2",
"resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.27.2.tgz",
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/parser": "^7.27.2",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.28.3",
"resolved": "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.28.3.tgz",
"integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.28.3",
"@babel/template": "^7.27.2",
"@babel/types": "^7.28.2",
"debug": "^4.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": {
"version": "7.28.2",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz",
@ -814,9 +874,9 @@ @@ -814,9 +874,9 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
"integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw=="
"version": "1.5.5",
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.29",
@ -1668,21 +1728,73 @@ @@ -1668,21 +1728,73 @@
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.5.18",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz",
"integrity": "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==",
"version": "3.5.21",
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz",
"integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.28.0",
"@vue/compiler-core": "3.5.18",
"@vue/compiler-dom": "3.5.18",
"@vue/compiler-ssr": "3.5.18",
"@vue/shared": "3.5.18",
"@babel/parser": "^7.28.3",
"@vue/compiler-core": "3.5.21",
"@vue/compiler-dom": "3.5.21",
"@vue/compiler-ssr": "3.5.21",
"@vue/shared": "3.5.21",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.17",
"magic-string": "^0.30.18",
"postcss": "^8.5.6",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-core": {
"version": "3.5.21",
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.21.tgz",
"integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.28.3",
"@vue/shared": "3.5.21",
"entities": "^4.5.0",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-dom": {
"version": "3.5.21",
"resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz",
"integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==",
"dev": true,
"dependencies": {
"@vue/compiler-core": "3.5.21",
"@vue/shared": "3.5.21"
}
},
"node_modules/@vue/compiler-sfc/node_modules/@vue/compiler-ssr": {
"version": "3.5.21",
"resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz",
"integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==",
"dev": true,
"dependencies": {
"@vue/compiler-dom": "3.5.21",
"@vue/shared": "3.5.21"
}
},
"node_modules/@vue/compiler-sfc/node_modules/@vue/shared": {
"version": "3.5.21",
"resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.21.tgz",
"integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==",
"dev": true
},
"node_modules/@vue/compiler-sfc/node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.5.18",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz",
@ -6922,6 +7034,18 @@ @@ -6922,6 +7034,18 @@
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
"dev": true
},
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"dev": true,
"bin": {
"jsesc": "bin/jsesc"
},
"engines": {
"node": ">=6"
}
},
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@ -7300,11 +7424,11 @@ @@ -7300,11 +7424,11 @@
}
},
"node_modules/magic-string": {
"version": "0.30.17",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
"integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
"version": "0.30.18",
"resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.18.tgz",
"integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0"
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/make-fetch-happen": {
@ -11223,6 +11347,22 @@ @@ -11223,6 +11347,22 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true
},
"node_modules/vue/node_modules/@vue/compiler-sfc": {
"version": "3.5.18",
"resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz",
"integrity": "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==",
"dependencies": {
"@babel/parser": "^7.28.0",
"@vue/compiler-core": "3.5.18",
"@vue/compiler-dom": "3.5.18",
"@vue/compiler-ssr": "3.5.18",
"@vue/shared": "3.5.18",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.17",
"postcss": "^8.5.6",
"source-map-js": "^1.2.1"
}
},
"node_modules/vuex": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",

3
gofaster/app/package.json

@ -29,9 +29,12 @@ @@ -29,9 +29,12 @@
"license": "ISC",
"description": "",
"devDependencies": {
"@babel/parser": "^7.28.3",
"@babel/traverse": "^7.28.3",
"@electron/remote": "^2.1.3",
"@types/node": "^24.2.1",
"@vue/cli-service": "^5.0.8",
"@vue/compiler-sfc": "^3.5.21",
"concurrently": "^9.2.0",
"cross-env": "^7.0.3",
"electron-builder": "^26.0.12",

699
gofaster/app/plugins/route-mapping-plugin.js

@ -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}`)
}
}
}

Loading…
Cancel
Save