261 lines
7.5 KiB
Python
Executable File
261 lines
7.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
# CodeDetect API文档生成器
|
||
|
||
import os
|
||
import sys
|
||
import re
|
||
import inspect
|
||
import json
|
||
from pathlib import Path
|
||
from typing import Dict, List, Any, Optional
|
||
from dataclasses import dataclass, asdict
|
||
|
||
@dataclass
|
||
class APIEndpoint:
|
||
"""API端点信息"""
|
||
method: str
|
||
path: str
|
||
description: str
|
||
parameters: List[Dict[str, Any]]
|
||
responses: Dict[str, Any]
|
||
auth_required: bool = False
|
||
|
||
@dataclass
|
||
class WebSocketEvent:
|
||
"""WebSocket事件信息"""
|
||
event_name: str
|
||
direction: str # 'send' or 'receive'
|
||
description: str
|
||
data_structure: Dict[str, Any]
|
||
|
||
class APIDocGenerator:
|
||
"""API文档生成器"""
|
||
|
||
def __init__(self, source_dir: str = "src"):
|
||
self.source_dir = Path(source_dir)
|
||
self.output_dir = Path("docs/api")
|
||
self.endpoints: List[APIEndpoint] = []
|
||
self.websocket_events: List[WebSocketEvent] = []
|
||
|
||
def generate_all_docs(self):
|
||
"""生成所有API文档"""
|
||
print("🚀 开始生成API文档...")
|
||
|
||
# 创建输出目录
|
||
self.output_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
# 扫描源代码
|
||
self._scan_api_endpoints()
|
||
self._scan_websocket_events()
|
||
|
||
# 生成文档
|
||
self._generate_rest_api_docs()
|
||
self._generate_websocket_docs()
|
||
self._generate_openapi_spec()
|
||
|
||
print("✅ API文档生成完成")
|
||
|
||
def _scan_api_endpoints(self):
|
||
"""扫描API端点"""
|
||
api_file = self.source_dir / "ui" / "api.py"
|
||
if not api_file.exists():
|
||
print(f"⚠️ API文件不存在: {api_file}")
|
||
return
|
||
|
||
print("📡 扫描REST API端点...")
|
||
|
||
# 简单的端点检测逻辑
|
||
content = api_file.read_text()
|
||
|
||
# 查找路由定义
|
||
route_pattern = r'@(\w+)\.route\([\'"]([^\'"]+)[\'"](?:,\s*methods=\[([^\]]+)\])?\)'
|
||
matches = re.findall(route_pattern, content)
|
||
|
||
for decorator, path, methods in matches:
|
||
if methods:
|
||
method_list = [m.strip().strip('\'"') for m in methods.split(',')]
|
||
else:
|
||
method_list = ['GET']
|
||
|
||
for method in method_list:
|
||
endpoint = APIEndpoint(
|
||
method=method,
|
||
path=path,
|
||
description=f"{method} {path}",
|
||
parameters=[],
|
||
responses={"200": {"description": "Success"}}
|
||
)
|
||
self.endpoints.append(endpoint)
|
||
|
||
print(f" 发现 {len(self.endpoints)} 个API端点")
|
||
|
||
def _scan_websocket_events(self):
|
||
"""扫描WebSocket事件"""
|
||
socketio_file = self.source_dir / "ui" / "socketio_handlers.py"
|
||
if not socketio_file.exists():
|
||
print(f"⚠️ WebSocket文件不存在: {socketio_file}")
|
||
return
|
||
|
||
print("🔌 扫描WebSocket事件...")
|
||
|
||
content = socketio_file.read_text()
|
||
|
||
# 查找事件处理器
|
||
event_pattern = r'@socketio\.on\([\'"]([^\'"]+)[\'"]\)'
|
||
matches = re.findall(event_pattern, content)
|
||
|
||
for event_name in matches:
|
||
event = WebSocketEvent(
|
||
event_name=event_name,
|
||
direction="receive",
|
||
description=f"WebSocket事件: {event_name}",
|
||
data_structure={}
|
||
)
|
||
self.websocket_events.append(event)
|
||
|
||
print(f" 发现 {len(self.websocket_events)} 个WebSocket事件")
|
||
|
||
def _generate_rest_api_docs(self):
|
||
"""生成REST API文档"""
|
||
doc_content = """# CodeDetect REST API 参考
|
||
|
||
## 概述
|
||
|
||
CodeDetect提供RESTful API用于代码验证和突变生成。
|
||
|
||
## 认证
|
||
|
||
大多数API端点需要认证。使用Bearer Token格式:
|
||
|
||
```
|
||
Authorization: Bearer <your-api-key>
|
||
```
|
||
|
||
## 基础URL
|
||
|
||
```
|
||
http://localhost:5000/api/v1
|
||
```
|
||
|
||
"""
|
||
|
||
# 按路径分组端点
|
||
endpoints_by_path = {}
|
||
for endpoint in self.endpoints:
|
||
if endpoint.path not in endpoints_by_path:
|
||
endpoints_by_path[endpoint.path] = []
|
||
endpoints_by_path[endpoint.path].append(endpoint)
|
||
|
||
# 生成端点文档
|
||
for path, path_endpoints in endpoints_by_path.items():
|
||
doc_content += f"\n## {path}\n\n"
|
||
|
||
for endpoint in path_endpoints:
|
||
doc_content += f"### {endpoint.method} {path}\n\n"
|
||
doc_content += f"{endpoint.description}\n\n"
|
||
|
||
if endpoint.parameters:
|
||
doc_content += "#### 请求参数\n\n"
|
||
for param in endpoint.parameters:
|
||
doc_content += f"- **{param['name']}** ({param['type']}): {param['description']}\n"
|
||
doc_content += "\n"
|
||
|
||
doc_content += "#### 响应\n\n"
|
||
for status, response in endpoint.responses.items():
|
||
doc_content += f"**{status}**: {response['description']}\n\n"
|
||
|
||
doc_content += "---\n\n"
|
||
|
||
# 写入文件
|
||
(self.output_dir / "rest-api.md").write_text(doc_content)
|
||
|
||
def _generate_websocket_docs(self):
|
||
"""生成WebSocket文档"""
|
||
doc_content = """# CodeDetect WebSocket API 参考
|
||
|
||
## 概述
|
||
|
||
CodeDetect使用WebSocket提供实时更新和进度通知。
|
||
|
||
## 连接
|
||
|
||
```javascript
|
||
const socket = io('http://localhost:5000');
|
||
```
|
||
|
||
## 事件
|
||
|
||
"""
|
||
|
||
# 生成事件文档
|
||
for event in self.websocket_events:
|
||
doc_content += f"### {event.event_name}\n\n"
|
||
doc_content += f"**方向**: {event.direction}\n\n"
|
||
doc_content += f"{event.description}\n\n"
|
||
|
||
if event.data_structure:
|
||
doc_content += "#### 数据结构\n\n"
|
||
doc_content += "```json\n"
|
||
doc_content += json.dumps(event.data_structure, indent=2, ensure_ascii=False)
|
||
doc_content += "\n```\n\n"
|
||
|
||
doc_content += "---\n\n"
|
||
|
||
# 写入文件
|
||
(self.output_dir / "websocket-api.md").write_text(doc_content)
|
||
|
||
def _generate_openapi_spec(self):
|
||
"""生成OpenAPI规范"""
|
||
spec = {
|
||
"openapi": "3.0.0",
|
||
"info": {
|
||
"title": "CodeDetect API",
|
||
"version": "1.0.0",
|
||
"description": "CodeDetect代码验证和突变生成API"
|
||
},
|
||
"servers": [
|
||
{
|
||
"url": "http://localhost:5000/api/v1",
|
||
"description": "开发服务器"
|
||
}
|
||
],
|
||
"paths": {},
|
||
"components": {
|
||
"securitySchemes": {
|
||
"BearerAuth": {
|
||
"type": "http",
|
||
"scheme": "bearer",
|
||
"bearerFormat": "JWT"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
# 添加路径
|
||
for endpoint in self.endpoints:
|
||
path = endpoint.path
|
||
method = endpoint.method.lower()
|
||
|
||
if path not in spec["paths"]:
|
||
spec["paths"][path] = {}
|
||
|
||
spec["paths"][path][method] = {
|
||
"summary": endpoint.description,
|
||
"responses": endpoint.responses
|
||
}
|
||
|
||
if endpoint.auth_required:
|
||
spec["paths"][path][method]["security"] = [{"BearerAuth": []}]
|
||
|
||
# 写入文件
|
||
(self.output_dir / "openapi.json").write_text(
|
||
json.dumps(spec, indent=2, ensure_ascii=False)
|
||
)
|
||
|
||
def main():
|
||
"""主函数"""
|
||
generator = APIDocGenerator()
|
||
generator.generate_all_docs()
|
||
|
||
if __name__ == "__main__":
|
||
main() |