Browse Source

api收集完成

master
hejl 1 day ago
parent
commit
a2dca55854
  1. 164
      gofaster/app/plugins/modules/api-collector.js
  2. 24
      gofaster/app/plugins/modules/file-generator.js
  3. 14
      gofaster/app/plugins/route-mapping-plugin.js
  4. 160
      gofaster/app/src/renderer/modules/route-sync/direct-route-mappings.js
  5. 11
      gofaster/app/test-optimized-collection.js

164
gofaster/app/plugins/modules/api-collector.js

@ -12,6 +12,39 @@ class ApiCollector { @@ -12,6 +12,39 @@ class ApiCollector {
this.apiMappings = []
}
/**
* 获取API基础URL
* @returns {string} API基础URL
*/
getApiBaseUrl() {
try {
// 读取配置文件
const configPath = resolve(__dirname, '../../src/config/app.config.js')
if (existsSync(configPath)) {
const configContent = readFileSync(configPath, 'utf-8')
// 解析配置文件,提取apiBaseUrl
// 匹配 development 环境中的 apiBaseUrl 配置
const developmentMatch = configContent.match(/development:\s*\{[^}]*apiBaseUrl:\s*[^:]*:\s*['"`]([^'"`]+)['"`]/s)
if (developmentMatch) {
return developmentMatch[1]
}
// 如果上面没匹配到,尝试匹配简单的字符串格式
const simpleMatch = configContent.match(/apiBaseUrl:\s*['"`]([^'"`]+)['"`]/)
if (simpleMatch) {
return simpleMatch[1]
}
}
// 如果无法从配置文件获取,返回空字符串(使用相对路径)
return ''
} catch (error) {
console.warn('⚠ 无法获取API基础URL,使用相对路径:', error.message)
return ''
}
}
/**
* 收集所有模块的API映射
* @param {Array} moduleDirs - 模块目录列表
@ -25,8 +58,7 @@ class ApiCollector { @@ -25,8 +58,7 @@ class ApiCollector {
if (moduleApiMappings.length > 0) {
this.apiMappings.push({
module: moduleName,
serviceName: moduleApiMappings[0].serviceName,
servicePath: moduleApiMappings[0].servicePath,
serviceName: moduleApiMappings.serviceName,
apiMappings: moduleApiMappings
})
}
@ -50,18 +82,31 @@ class ApiCollector { @@ -50,18 +82,31 @@ class ApiCollector {
const serviceFiles = readdirSync(servicesPath).filter(file => file.endsWith('.js'))
const moduleApiMappings = []
let firstServiceName = null
serviceFiles.forEach(serviceFile => {
const servicePath = resolve(servicesPath, serviceFile)
const serviceName = serviceFile.replace('.js', '')
// 记录第一个服务名称(第一层需要)
if (!firstServiceName) {
firstServiceName = serviceName
}
try {
const serviceApiMappings = this.analyzeServiceFile(servicePath, serviceName, moduleName)
// 不再为每个API映射添加serviceName(第二层冗余信息)
moduleApiMappings.push(...serviceApiMappings)
} catch (error) {
// 静默处理错误
}
})
// 为模块API映射添加serviceName(第一层需要)
if (firstServiceName) {
moduleApiMappings.serviceName = firstServiceName
}
return moduleApiMappings
}
@ -113,7 +158,7 @@ class ApiCollector { @@ -113,7 +158,7 @@ class ApiCollector {
}
/**
* 从AST节点中提取API映射信息
* 从AST节点中提取API映射信息 - 优化版本只使用@serverApiMethod注解
* @param {Object} methodPath - 方法路径
* @param {string} methodName - 方法名称
* @param {string} serviceName - 服务名称
@ -121,49 +166,86 @@ class ApiCollector { @@ -121,49 +166,86 @@ class ApiCollector {
* @returns {Object|null} API映射对象
*/
extractApiMapping(methodPath, methodName, serviceName, servicePath) {
let httpMethod = null
let apiPath = null
// 只从@serverApiMethod注解中提取信息(强规则)
const annotationInfo = this.extractFromAnnotation(methodPath, servicePath)
if (annotationInfo) {
// 获取API基础URL
const apiBaseUrl = this.getApiBaseUrl()
// 组合完整的API路径
const fullPath = `${apiBaseUrl}${annotationInfo.path}`
// 提取路径部分,去掉协议、服务器地址和端口
const pathOnly = this.extractPathFromUrl(fullPath)
return {
apiMethodName: methodName,
method: annotationInfo.method,
path: pathOnly
}
}
// 查找HTTP方法调用
traverse(methodPath.node, {
CallExpression(path) {
const node = path.node
if (node.callee && node.callee.type === 'MemberExpression') {
const object = node.callee.object
const property = node.callee.property
// 如果没有注解,返回null(不再回退到代码分析)
return null
}
/**
* 从完整URL中提取路径部分
* @param {string} fullUrl - 完整的URL
* @returns {string} 路径部分
*/
extractPathFromUrl(fullUrl) {
try {
// 如果URL包含协议,使用URL对象解析
if (fullUrl.includes('://')) {
const url = new URL(fullUrl)
// 解码路径,确保路径参数保持原始格式
return decodeURIComponent(url.pathname)
}
// 如果没有协议,直接返回(已经是路径格式)
return fullUrl
} catch (error) {
// 如果解析失败,返回原始字符串
return fullUrl
}
}
/**
* @serverApiMethod注解中提取API信息
* @param {Object} methodPath - 方法路径
* @param {string} servicePath - 服务文件路径
* @returns {Object|null} 注解信息
*/
extractFromAnnotation(methodPath, servicePath) {
try {
const content = readFileSync(servicePath, 'utf-8')
const lines = content.split('\n')
const methodLine = methodPath.node.loc ? methodPath.node.loc.start.line : 0
// 查找方法定义前的注释行(从方法行开始向上搜索)
for (let i = methodLine - 2; i >= 0; i--) {
const line = lines[i].trim()
// 查找@serverApiMethod注解
const annotationMatch = line.match(/\/\/\s*@serverApiMethod\s+(\w+)\s+(.+)/)
if (annotationMatch) {
const method = annotationMatch[1].toUpperCase()
const path = annotationMatch[2].trim()
if (object && property &&
object.type === 'Identifier' &&
property.type === 'Identifier') {
const method = property.name.toLowerCase()
if (['get', 'post', 'put', 'delete', 'patch'].includes(method)) {
httpMethod = method.toUpperCase()
// 提取API路径
if (node.arguments && node.arguments.length > 0) {
const firstArg = node.arguments[0]
if (firstArg.type === 'StringLiteral') {
apiPath = firstArg.value
} else if (firstArg.type === 'TemplateLiteral') {
apiPath = firstArg.quasis[0].value.raw
}
}
}
return {
method: method,
path: path
}
}
// 如果遇到非注释行且不是空行,停止搜索
if (line && !line.startsWith('//') && !line.startsWith('*') && !line.startsWith('/*')) {
break
}
}
}, methodPath.scope, methodPath)
if (httpMethod && apiPath) {
return {
apiMethodName: methodName,
method: httpMethod,
path: apiPath,
line: methodPath.node.loc ? methodPath.node.loc.start.line : 0,
serviceName: serviceName,
servicePath: servicePath
}
} catch (error) {
console.error(`❌ 解析注解失败: ${servicePath}`, error.message)
}
return null

24
gofaster/app/plugins/modules/file-generator.js

@ -72,6 +72,30 @@ export default { @@ -72,6 +72,30 @@ export default {
writeFileSync(this.outputPath, content, 'utf-8')
}
/**
* 生成路由和API映射文件 - 第三步第一小步包含API信息
* @param {Array} routes - 路由数组
* @param {Array} apiMappings - API映射数组
*/
generateRouteApiMappingFile(routes, apiMappings) {
const content = `// 路由映射数据 - 构建时生成
export default {
// 路由配置
routes: ${JSON.stringify(routes, null, 2)},
// API映射配置
apiMappings: ${JSON.stringify(apiMappings, null, 2)}
}`
// 如果文件已存在,先清空内容
if (existsSync(this.outputPath)) {
writeFileSync(this.outputPath, '', 'utf-8')
}
// 写入新内容
writeFileSync(this.outputPath, content, 'utf-8')
}
/**
* 生成文件内容
* @param {Array} routes - 路由数组

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

@ -130,12 +130,16 @@ function routeMappingPlugin() { @@ -130,12 +130,16 @@ function routeMappingPlugin() {
return
}
// 第二步:启用路由分析功能
// 第三步第一小步:启用API收集功能
// 1. 分析路由配置
const routes = this._routeAnalyzer.analyzeRoutes()
// 生成包含路由信息的文件
this._fileGenerator.generateRouteMappingFile(routes)
// 2. 收集API信息(第一层)
const moduleDirs = this._routeAnalyzer.getModuleDirs()
const apiMappings = this._apiCollector.collectApiMappings(moduleDirs)
// 生成包含路由和API信息的文件
this._fileGenerator.generateRouteApiMappingFile(routes, apiMappings)
// 重置生成中标志并更新时间戳
this._generationInProgress = false
@ -148,10 +152,6 @@ function routeMappingPlugin() { @@ -148,10 +152,6 @@ function routeMappingPlugin() {
// TODO: 后续步骤将在优化过程中逐步添加
// 2. 收集API信息(第一层)
// const moduleDirs = this._routeAnalyzer.getModuleDirs()
// const apiMappings = this._apiCollector.collectApiMappings(moduleDirs)
// 3. 关联页面与API(第三层)
// const enhancedApiMappings = this._triggerAnalyzer.findTriggerSourcesForApiMappings(apiMappings)

160
gofaster/app/src/renderer/modules/route-sync/direct-route-mappings.js

@ -31,5 +31,163 @@ export default { @@ -31,5 +31,163 @@ export default {
],
// API映射配置
apiMappings: []
apiMappings: [
{
"module": "role-management",
"serviceName": "roleService",
"apiMappings": [
{
"apiMethodName": "getRoles",
"method": "GET",
"path": "/api/auth/roles"
},
{
"apiMethodName": "getRole",
"method": "GET",
"path": "/api/auth/roles/{id}"
},
{
"apiMethodName": "createRole",
"method": "POST",
"path": "/api/auth/roles"
},
{
"apiMethodName": "updateRole",
"method": "PUT",
"path": "/api/auth/roles/{id}"
},
{
"apiMethodName": "deleteRole",
"method": "DELETE",
"path": "/api/auth/roles/{id}"
},
{
"apiMethodName": "getPermissions",
"method": "GET",
"path": "/api/auth/permissions"
},
{
"apiMethodName": "assignRolesToUser",
"method": "POST",
"path": "/api/auth/roles/users/{userId}/assign"
},
{
"apiMethodName": "getUserRoles",
"method": "GET",
"path": "/api/auth/roles/users/{userId}"
},
{
"apiMethodName": "removeRolesFromUser",
"method": "DELETE",
"path": "/api/auth/roles/users/{userId}/remove"
},
{
"apiMethodName": "getRolePermissions",
"method": "GET",
"path": "/api/auth/permissions/roles/{roleId}"
},
{
"apiMethodName": "assignPermissionsToRole",
"method": "POST",
"path": "/api/auth/permissions/roles/{roleId}/assign"
},
{
"apiMethodName": "removePermissionsFromRole",
"method": "DELETE",
"path": "/api/auth/permissions/roles/{roleId}/remove"
}
]
},
{
"module": "user-management",
"serviceName": "userService",
"apiMappings": [
{
"apiMethodName": "getUsers",
"method": "GET",
"path": "/api/auth/admin/users"
},
{
"apiMethodName": "getUser",
"method": "GET",
"path": "/api/auth/admin/users/{id}"
},
{
"apiMethodName": "createUser",
"method": "POST",
"path": "/api/auth/admin/users"
},
{
"apiMethodName": "updateUser",
"method": "PUT",
"path": "/api/auth/admin/users/{id}"
},
{
"apiMethodName": "deleteUser",
"method": "DELETE",
"path": "/api/auth/admin/users/{id}"
},
{
"apiMethodName": "getRoles",
"method": "GET",
"path": "/api/auth/admin/roles"
},
{
"apiMethodName": "changePassword",
"method": "POST",
"path": "/api/auth/change-password"
},
{
"apiMethodName": "getPasswordPolicy",
"method": "GET",
"path": "/api/auth/password-policy"
},
{
"apiMethodName": "validatePassword",
"method": "POST",
"path": "/api/auth/validate-password"
},
{
"apiMethodName": "checkPasswordStatus",
"method": "GET",
"path": "/api/auth/password-status"
},
{
"apiMethodName": "getPermissions",
"method": "GET",
"path": "/api/permissions"
},
{
"apiMethodName": "getCaptcha",
"method": "GET",
"path": "/api/auth/captcha"
},
{
"apiMethodName": "login",
"method": "POST",
"path": "/api/auth/login"
},
{
"apiMethodName": "logout",
"method": "POST",
"path": "/api/auth/logout"
},
{
"apiMethodName": "getCurrentUser",
"method": "GET",
"path": "/api/auth/me"
},
{
"apiMethodName": "changePassword",
"method": "POST",
"path": "/api/auth/change-password"
},
{
"apiMethodName": "resetPassword",
"method": "POST",
"path": "/api/auth/reset-password"
}
]
}
]
}

11
gofaster/app/test-optimized-collection.js

@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
import { RouteCollector } from './src/renderer/modules/route-sync/RouteCollector.js';
const collector = new RouteCollector();
const routes = collector.collectRoutes();
console.log('优化后的路由收集结果:');
console.log('路由数量:', routes.length);
console.log('路由详情:');
routes.forEach((route, index) => {
console.log(`${index + 1}. ${route.path} - name: ${route.name} - component: ${route.component} - description: ${route.description}`);
});
Loading…
Cancel
Save