repowiki-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analyzer/api-analyzer.d.ts +22 -0
- package/dist/analyzer/api-analyzer.d.ts.map +1 -0
- package/dist/analyzer/api-analyzer.js +272 -0
- package/dist/analyzer/api-analyzer.js.map +1 -0
- package/dist/analyzer/config-analyzer.d.ts +18 -0
- package/dist/analyzer/config-analyzer.d.ts.map +1 -0
- package/dist/analyzer/config-analyzer.js +200 -0
- package/dist/analyzer/config-analyzer.js.map +1 -0
- package/dist/analyzer/database-analyzer.d.ts +24 -0
- package/dist/analyzer/database-analyzer.d.ts.map +1 -0
- package/dist/analyzer/database-analyzer.js +391 -0
- package/dist/analyzer/database-analyzer.js.map +1 -0
- package/dist/analyzer/index.d.ts +10 -0
- package/dist/analyzer/index.d.ts.map +1 -0
- package/dist/analyzer/index.js +10 -0
- package/dist/analyzer/index.js.map +1 -0
- package/dist/analyzer/module-analyzer.d.ts +20 -0
- package/dist/analyzer/module-analyzer.d.ts.map +1 -0
- package/dist/analyzer/module-analyzer.js +252 -0
- package/dist/analyzer/module-analyzer.js.map +1 -0
- package/dist/analyzer/workflow-analyzer.d.ts +19 -0
- package/dist/analyzer/workflow-analyzer.d.ts.map +1 -0
- package/dist/analyzer/workflow-analyzer.js +165 -0
- package/dist/analyzer/workflow-analyzer.js.map +1 -0
- package/dist/detector/dependency-detector.d.ts +50 -0
- package/dist/detector/dependency-detector.d.ts.map +1 -0
- package/dist/detector/dependency-detector.js +326 -0
- package/dist/detector/dependency-detector.js.map +1 -0
- package/dist/detector/entrypoint-detector.d.ts +30 -0
- package/dist/detector/entrypoint-detector.d.ts.map +1 -0
- package/dist/detector/entrypoint-detector.js +240 -0
- package/dist/detector/entrypoint-detector.js.map +1 -0
- package/dist/detector/index.d.ts +10 -0
- package/dist/detector/index.d.ts.map +1 -0
- package/dist/detector/index.js +10 -0
- package/dist/detector/index.js.map +1 -0
- package/dist/detector/tech-stack-detector.d.ts +41 -0
- package/dist/detector/tech-stack-detector.d.ts.map +1 -0
- package/dist/detector/tech-stack-detector.js +300 -0
- package/dist/detector/tech-stack-detector.js.map +1 -0
- package/dist/generator/index.d.ts +9 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +9 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/markdown-generator.d.ts +71 -0
- package/dist/generator/markdown-generator.d.ts.map +1 -0
- package/dist/generator/markdown-generator.js +235 -0
- package/dist/generator/markdown-generator.js.map +1 -0
- package/dist/generator/mermaid-generator.d.ts +30 -0
- package/dist/generator/mermaid-generator.d.ts.map +1 -0
- package/dist/generator/mermaid-generator.js +297 -0
- package/dist/generator/mermaid-generator.js.map +1 -0
- package/dist/generator/sidebar-generator.d.ts +10 -0
- package/dist/generator/sidebar-generator.d.ts.map +1 -0
- package/dist/generator/sidebar-generator.js +120 -0
- package/dist/generator/sidebar-generator.js.map +1 -0
- package/dist/generator/wiki-generator.d.ts +45 -0
- package/dist/generator/wiki-generator.d.ts.map +1 -0
- package/dist/generator/wiki-generator.js +217 -0
- package/dist/generator/wiki-generator.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/auth-manager.d.ts +50 -0
- package/dist/llm/auth-manager.d.ts.map +1 -0
- package/dist/llm/auth-manager.js +172 -0
- package/dist/llm/auth-manager.js.map +1 -0
- package/dist/llm/index.d.ts +10 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +9 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/llm-client.d.ts +132 -0
- package/dist/llm/llm-client.d.ts.map +1 -0
- package/dist/llm/llm-client.js +308 -0
- package/dist/llm/llm-client.js.map +1 -0
- package/dist/llm/prompt-manager.d.ts +67 -0
- package/dist/llm/prompt-manager.d.ts.map +1 -0
- package/dist/llm/prompt-manager.js +283 -0
- package/dist/llm/prompt-manager.js.map +1 -0
- package/dist/models/analysis-result.d.ts +425 -0
- package/dist/models/analysis-result.d.ts.map +1 -0
- package/dist/models/analysis-result.js +34 -0
- package/dist/models/analysis-result.js.map +1 -0
- package/dist/models/analysis-types.d.ts +223 -0
- package/dist/models/analysis-types.d.ts.map +1 -0
- package/dist/models/analysis-types.js +95 -0
- package/dist/models/analysis-types.js.map +1 -0
- package/dist/models/file-reference.d.ts +62 -0
- package/dist/models/file-reference.d.ts.map +1 -0
- package/dist/models/file-reference.js +34 -0
- package/dist/models/file-reference.js.map +1 -0
- package/dist/models/index.d.ts +10 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +10 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/project-profile.d.ts +48 -0
- package/dist/models/project-profile.d.ts.map +1 -0
- package/dist/models/project-profile.js +26 -0
- package/dist/models/project-profile.js.map +1 -0
- package/dist/models/wiki-page.d.ts +57 -0
- package/dist/models/wiki-page.d.ts.map +1 -0
- package/dist/models/wiki-page.js +19 -0
- package/dist/models/wiki-page.js.map +1 -0
- package/dist/pipeline.d.ts +30 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +159 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/scanner/file-scanner.d.ts +27 -0
- package/dist/scanner/file-scanner.d.ts.map +1 -0
- package/dist/scanner/file-scanner.js +149 -0
- package/dist/scanner/file-scanner.js.map +1 -0
- package/dist/scanner/ignore-rules.d.ts +31 -0
- package/dist/scanner/ignore-rules.d.ts.map +1 -0
- package/dist/scanner/ignore-rules.js +98 -0
- package/dist/scanner/ignore-rules.js.map +1 -0
- package/dist/scanner/index.d.ts +8 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +8 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/tree-builder.d.ts +20 -0
- package/dist/scanner/tree-builder.d.ts.map +1 -0
- package/dist/scanner/tree-builder.js +118 -0
- package/dist/scanner/tree-builder.js.map +1 -0
- package/package.json +34 -0
- package/src/analyzer/api-analyzer.ts +324 -0
- package/src/analyzer/config-analyzer.ts +209 -0
- package/src/analyzer/database-analyzer.ts +468 -0
- package/src/analyzer/index.ts +26 -0
- package/src/analyzer/module-analyzer.ts +308 -0
- package/src/analyzer/workflow-analyzer.ts +190 -0
- package/src/detector/dependency-detector.ts +390 -0
- package/src/detector/entrypoint-detector.ts +270 -0
- package/src/detector/index.ts +21 -0
- package/src/detector/tech-stack-detector.ts +377 -0
- package/src/generator/index.ts +36 -0
- package/src/generator/markdown-generator.ts +277 -0
- package/src/generator/mermaid-generator.ts +340 -0
- package/src/generator/sidebar-generator.ts +134 -0
- package/src/generator/wiki-generator.ts +281 -0
- package/src/index.ts +12 -0
- package/src/llm/auth-manager.ts +207 -0
- package/src/llm/index.ts +21 -0
- package/src/llm/llm-client.ts +417 -0
- package/src/llm/prompt-manager.ts +325 -0
- package/src/models/analysis-result.ts +44 -0
- package/src/models/analysis-types.ts +121 -0
- package/src/models/file-reference.ts +41 -0
- package/src/models/index.ts +44 -0
- package/src/models/project-profile.ts +29 -0
- package/src/models/wiki-page.ts +23 -0
- package/src/pipeline.ts +225 -0
- package/src/scanner/file-scanner.ts +192 -0
- package/src/scanner/ignore-rules.ts +112 -0
- package/src/scanner/index.ts +19 -0
- package/src/scanner/tree-builder.ts +156 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API 路由分析器
|
|
3
|
+
* 通过正则表达式从源码中提取 HTTP 路由定义,支持 FastAPI、Express、NestJS 等框架。
|
|
4
|
+
*/
|
|
5
|
+
import type { FileNode, ApiRoute } from '../models/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* 分析项目中的 API 路由定义
|
|
8
|
+
*
|
|
9
|
+
* 从扫描到的文件列表中筛选可能包含路由定义的文件,
|
|
10
|
+
* 读取其内容并应用多框架正则模式提取路由信息。
|
|
11
|
+
*
|
|
12
|
+
* 支持的框架:
|
|
13
|
+
* - FastAPI / Python(装饰器 @app.get / @router.post 等)
|
|
14
|
+
* - Express / Node.js(app.get / router.post 等)
|
|
15
|
+
* - NestJS / TypeScript(@Controller + @Get/@Post 装饰器等)
|
|
16
|
+
*
|
|
17
|
+
* @param rootPath - 项目根目录的绝对路径
|
|
18
|
+
* @param files - 扫描到的 FileNode 列表
|
|
19
|
+
* @returns 排序后的 ApiRoute 数组
|
|
20
|
+
*/
|
|
21
|
+
export declare function analyzeApiRoutes(rootPath: string, files: FileNode[]): Promise<ApiRoute[]>;
|
|
22
|
+
//# sourceMappingURL=api-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzer/api-analyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AA8Q7D;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,gBAAgB,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,EAAE,GAClB,OAAO,CAAC,QAAQ,EAAE,CAAC,CA4BrB"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API 路由分析器
|
|
3
|
+
* 通过正则表达式从源码中提取 HTTP 路由定义,支持 FastAPI、Express、NestJS 等框架。
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'node:fs/promises';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// 路由文件过滤
|
|
9
|
+
// ============================================================================
|
|
10
|
+
/** 路径中包含这些关键词的文件可能定义路由 */
|
|
11
|
+
const ROUTE_PATH_KEYWORDS = [
|
|
12
|
+
'route',
|
|
13
|
+
'router',
|
|
14
|
+
'controller',
|
|
15
|
+
'api',
|
|
16
|
+
'endpoint',
|
|
17
|
+
'views',
|
|
18
|
+
'handlers',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* 判断文件是否可能包含路由定义
|
|
22
|
+
* @param relativePath - 文件相对路径
|
|
23
|
+
* @returns 是否为候选路由文件
|
|
24
|
+
*/
|
|
25
|
+
function isRouteCandidateFile(relativePath) {
|
|
26
|
+
const normalized = relativePath.replace(/\\/g, '/').toLowerCase();
|
|
27
|
+
return ROUTE_PATH_KEYWORDS.some((kw) => normalized.includes(kw));
|
|
28
|
+
}
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// 正则模式定义
|
|
31
|
+
// ============================================================================
|
|
32
|
+
/**
|
|
33
|
+
* FastAPI / Python 装饰器路由
|
|
34
|
+
* 匹配 @app.get("/path") 或 @router.post("/path") 等形式
|
|
35
|
+
*/
|
|
36
|
+
const FASTAPI_ROUTE_PATTERN = /@(app|router)\.(get|post|put|delete|patch)\(\s*['"]([^'"]+)['"]/gi;
|
|
37
|
+
/**
|
|
38
|
+
* FastAPI 处理函数名
|
|
39
|
+
* 匹配 async def function_name 或 def function_name
|
|
40
|
+
*/
|
|
41
|
+
const PYTHON_FUNC_PATTERN = /(?:async\s+)?def\s+(\w+)/;
|
|
42
|
+
/**
|
|
43
|
+
* Express / Node.js 路由
|
|
44
|
+
* 匹配 app.get("/path", ...) 或 router.post("/path", ...) 等形式
|
|
45
|
+
*/
|
|
46
|
+
const EXPRESS_ROUTE_PATTERN = /(?:app|router)\.(get|post|put|delete|patch|all)\(\s*['"]([^'"]+)['"]/gi;
|
|
47
|
+
/**
|
|
48
|
+
* Express 处理函数引用
|
|
49
|
+
* 匹配 , handlerName 或 , async (req 等形式
|
|
50
|
+
*/
|
|
51
|
+
const EXPRESS_HANDLER_PATTERN = /,\s*(\w+)/;
|
|
52
|
+
/**
|
|
53
|
+
* NestJS 方法装饰器
|
|
54
|
+
* 匹配 @Get(), @Post("/path"), @Put('path') 等形式
|
|
55
|
+
*/
|
|
56
|
+
const NESTJS_METHOD_PATTERN = /@(Get|Post|Put|Delete|Patch)\(\s*['"]?([^'")]*?)['"]?\s*\)/gi;
|
|
57
|
+
/**
|
|
58
|
+
* NestJS Controller 装饰器
|
|
59
|
+
* 匹配 @Controller("prefix") 等形式
|
|
60
|
+
*/
|
|
61
|
+
const NESTJS_CONTROLLER_PATTERN = /@Controller\(\s*['"]([^'"]+)['"]\s*\)/i;
|
|
62
|
+
/**
|
|
63
|
+
* NestJS 方法名
|
|
64
|
+
* 匹配装饰器下方的 async methodName( 或 methodName( 形式
|
|
65
|
+
*/
|
|
66
|
+
const NESTJS_METHOD_NAME_PATTERN = /(?:async\s+)?(\w+)\s*\(/;
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// 路由提取逻辑
|
|
69
|
+
// ============================================================================
|
|
70
|
+
/**
|
|
71
|
+
* 提取 FastAPI 路由
|
|
72
|
+
* @param content - 文件内容
|
|
73
|
+
* @param filePath - 文件相对路径
|
|
74
|
+
* @returns 提取到的路由数组
|
|
75
|
+
*/
|
|
76
|
+
function extractFastAPIRoutes(content, filePath) {
|
|
77
|
+
const routes = [];
|
|
78
|
+
const lines = content.split('\n');
|
|
79
|
+
for (let i = 0; i < lines.length; i++) {
|
|
80
|
+
const line = lines[i];
|
|
81
|
+
// 重置正则 lastIndex
|
|
82
|
+
FASTAPI_ROUTE_PATTERN.lastIndex = 0;
|
|
83
|
+
const match = FASTAPI_ROUTE_PATTERN.exec(line);
|
|
84
|
+
if (match) {
|
|
85
|
+
const method = match[2].toUpperCase();
|
|
86
|
+
const routePath = match[3];
|
|
87
|
+
// 在后续行中查找处理函数名
|
|
88
|
+
let handler = '';
|
|
89
|
+
for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) {
|
|
90
|
+
const funcMatch = PYTHON_FUNC_PATTERN.exec(lines[j]);
|
|
91
|
+
if (funcMatch) {
|
|
92
|
+
handler = funcMatch[1];
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
routes.push({
|
|
97
|
+
method,
|
|
98
|
+
path: routePath,
|
|
99
|
+
handler,
|
|
100
|
+
filePath,
|
|
101
|
+
lineNumber: i + 1,
|
|
102
|
+
framework: 'fastapi',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return routes;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 提取 Express 路由
|
|
110
|
+
* @param content - 文件内容
|
|
111
|
+
* @param filePath - 文件相对路径
|
|
112
|
+
* @returns 提取到的路由数组
|
|
113
|
+
*/
|
|
114
|
+
function extractExpressRoutes(content, filePath) {
|
|
115
|
+
const routes = [];
|
|
116
|
+
const lines = content.split('\n');
|
|
117
|
+
for (let i = 0; i < lines.length; i++) {
|
|
118
|
+
const line = lines[i];
|
|
119
|
+
EXPRESS_ROUTE_PATTERN.lastIndex = 0;
|
|
120
|
+
const match = EXPRESS_ROUTE_PATTERN.exec(line);
|
|
121
|
+
if (match) {
|
|
122
|
+
const method = match[1].toUpperCase();
|
|
123
|
+
const routePath = match[2];
|
|
124
|
+
// 尝试从同一行或下一行提取 handler 名
|
|
125
|
+
let handler = '';
|
|
126
|
+
const handlerMatch = EXPRESS_HANDLER_PATTERN.exec(line.slice(match.index + match[0].length));
|
|
127
|
+
if (handlerMatch && handlerMatch[1] !== 'async' && handlerMatch[1] !== 'function') {
|
|
128
|
+
handler = handlerMatch[1];
|
|
129
|
+
}
|
|
130
|
+
else if (i + 1 < lines.length) {
|
|
131
|
+
const nextLineMatch = EXPRESS_HANDLER_PATTERN.exec(lines[i + 1]);
|
|
132
|
+
if (nextLineMatch &&
|
|
133
|
+
nextLineMatch[1] !== 'async' &&
|
|
134
|
+
nextLineMatch[1] !== 'function') {
|
|
135
|
+
handler = nextLineMatch[1];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
routes.push({
|
|
139
|
+
method,
|
|
140
|
+
path: routePath,
|
|
141
|
+
handler,
|
|
142
|
+
filePath,
|
|
143
|
+
lineNumber: i + 1,
|
|
144
|
+
framework: 'express',
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return routes;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 提取 NestJS 路由
|
|
152
|
+
* @param content - 文件内容
|
|
153
|
+
* @param filePath - 文件相对路径
|
|
154
|
+
* @returns 提取到的路由数组
|
|
155
|
+
*/
|
|
156
|
+
function extractNestJSRoutes(content, filePath) {
|
|
157
|
+
const routes = [];
|
|
158
|
+
const lines = content.split('\n');
|
|
159
|
+
// 首先提取 Controller 前缀
|
|
160
|
+
let controllerPrefix = '';
|
|
161
|
+
const controllerMatch = NESTJS_CONTROLLER_PATTERN.exec(content);
|
|
162
|
+
if (controllerMatch) {
|
|
163
|
+
controllerPrefix = controllerMatch[1];
|
|
164
|
+
// 确保前缀以 / 开头
|
|
165
|
+
if (!controllerPrefix.startsWith('/')) {
|
|
166
|
+
controllerPrefix = '/' + controllerPrefix;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
for (let i = 0; i < lines.length; i++) {
|
|
170
|
+
const line = lines[i];
|
|
171
|
+
NESTJS_METHOD_PATTERN.lastIndex = 0;
|
|
172
|
+
const match = NESTJS_METHOD_PATTERN.exec(line);
|
|
173
|
+
if (match) {
|
|
174
|
+
const method = match[1].toUpperCase();
|
|
175
|
+
let methodPath = match[2] || '';
|
|
176
|
+
// 组合 controller 前缀与方法路径
|
|
177
|
+
if (methodPath && !methodPath.startsWith('/')) {
|
|
178
|
+
methodPath = '/' + methodPath;
|
|
179
|
+
}
|
|
180
|
+
const fullPath = controllerPrefix + methodPath || controllerPrefix || '/';
|
|
181
|
+
// 查找方法名
|
|
182
|
+
let handler = '';
|
|
183
|
+
for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) {
|
|
184
|
+
const methodNameMatch = NESTJS_METHOD_NAME_PATTERN.exec(lines[j]);
|
|
185
|
+
if (methodNameMatch) {
|
|
186
|
+
handler = methodNameMatch[1];
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
routes.push({
|
|
191
|
+
method,
|
|
192
|
+
path: fullPath,
|
|
193
|
+
handler,
|
|
194
|
+
filePath,
|
|
195
|
+
lineNumber: i + 1,
|
|
196
|
+
framework: 'nestjs',
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return routes;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 检测文件中使用的框架并提取路由
|
|
204
|
+
* @param content - 文件内容
|
|
205
|
+
* @param filePath - 文件相对路径
|
|
206
|
+
* @returns 提取到的路由数组
|
|
207
|
+
*/
|
|
208
|
+
function extractRoutesFromContent(content, filePath) {
|
|
209
|
+
const routes = [];
|
|
210
|
+
// 根据内容特征检测框架类型
|
|
211
|
+
const hasFastAPIDecorator = /@(app|router)\.(get|post|put|delete|patch)\(/i.test(content);
|
|
212
|
+
const hasExpressCall = /(?:app|router)\.(get|post|put|delete|patch)\(\s*['"]/i.test(content);
|
|
213
|
+
const hasNestJSDecorator = /@(Get|Post|Put|Delete|Patch)\(/i.test(content);
|
|
214
|
+
const hasControllerDecorator = /@Controller\(/i.test(content);
|
|
215
|
+
// NestJS 优先级最高(因为它同时可能含有类似 Express 的模式)
|
|
216
|
+
if (hasNestJSDecorator || hasControllerDecorator) {
|
|
217
|
+
routes.push(...extractNestJSRoutes(content, filePath));
|
|
218
|
+
}
|
|
219
|
+
// 检查 FastAPI(Python 装饰器风格)
|
|
220
|
+
if (hasFastAPIDecorator) {
|
|
221
|
+
// 确认是 Python 文件(通过 def 关键词辅助判断)
|
|
222
|
+
if (/\bdef\s+\w+/.test(content)) {
|
|
223
|
+
routes.push(...extractFastAPIRoutes(content, filePath));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// 检查 Express(排除已被 NestJS 检测的情况)
|
|
227
|
+
if (hasExpressCall && !hasNestJSDecorator && !hasControllerDecorator) {
|
|
228
|
+
routes.push(...extractExpressRoutes(content, filePath));
|
|
229
|
+
}
|
|
230
|
+
return routes;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* 分析项目中的 API 路由定义
|
|
234
|
+
*
|
|
235
|
+
* 从扫描到的文件列表中筛选可能包含路由定义的文件,
|
|
236
|
+
* 读取其内容并应用多框架正则模式提取路由信息。
|
|
237
|
+
*
|
|
238
|
+
* 支持的框架:
|
|
239
|
+
* - FastAPI / Python(装饰器 @app.get / @router.post 等)
|
|
240
|
+
* - Express / Node.js(app.get / router.post 等)
|
|
241
|
+
* - NestJS / TypeScript(@Controller + @Get/@Post 装饰器等)
|
|
242
|
+
*
|
|
243
|
+
* @param rootPath - 项目根目录的绝对路径
|
|
244
|
+
* @param files - 扫描到的 FileNode 列表
|
|
245
|
+
* @returns 排序后的 ApiRoute 数组
|
|
246
|
+
*/
|
|
247
|
+
export async function analyzeApiRoutes(rootPath, files) {
|
|
248
|
+
const allRoutes = [];
|
|
249
|
+
// 筛选候选文件
|
|
250
|
+
const candidates = files.filter((f) => f.nodeType === 'file' && isRouteCandidateFile(f.relativePath));
|
|
251
|
+
for (const candidate of candidates) {
|
|
252
|
+
try {
|
|
253
|
+
const absolutePath = path.resolve(rootPath, candidate.relativePath);
|
|
254
|
+
const content = await fs.readFile(absolutePath, 'utf-8');
|
|
255
|
+
const routes = extractRoutesFromContent(content, candidate.relativePath);
|
|
256
|
+
allRoutes.push(...routes);
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
// 无法读取的文件直接跳过
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// 按文件路径和行号排序
|
|
264
|
+
allRoutes.sort((a, b) => {
|
|
265
|
+
const fileCmp = a.filePath.localeCompare(b.filePath);
|
|
266
|
+
if (fileCmp !== 0)
|
|
267
|
+
return fileCmp;
|
|
268
|
+
return a.lineNumber - b.lineNumber;
|
|
269
|
+
});
|
|
270
|
+
return allRoutes;
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=api-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-analyzer.js","sourceRoot":"","sources":["../../src/analyzer/api-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { FileNode } from '../models/index.js';
|
|
2
|
+
export interface ConfigInfo {
|
|
3
|
+
filePath: string;
|
|
4
|
+
type: 'env' | 'yaml' | 'json' | 'toml' | 'dockerfile' | 'ci' | 'js_ts';
|
|
5
|
+
keys: string[];
|
|
6
|
+
description: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 分析项目中的配置文件和环境配置
|
|
10
|
+
*
|
|
11
|
+
* 识别 docker-compose, tsconfig, env.example, *.config.js 等文件,
|
|
12
|
+
* 提取顶层配置键、工作流阶段或环境变量,以便 Wiki 文档生成时使用。
|
|
13
|
+
*
|
|
14
|
+
* @param rootPath - 项目根目录
|
|
15
|
+
* @param files - 扫描的文件节点
|
|
16
|
+
*/
|
|
17
|
+
export declare function analyzeConfigs(rootPath: string, files: FileNode[]): Promise<ConfigInfo[]>;
|
|
18
|
+
//# sourceMappingURL=config-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzer/config-analyzer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,IAAI,GAAG,OAAO,CAAC;IACvE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACvB;AAmKD;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CA2B/F"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* 判断是否为配置文件,并归类其类型
|
|
5
|
+
*/
|
|
6
|
+
function detectConfigType(relativePath) {
|
|
7
|
+
const normalized = relativePath.replace(/\\/g, '/').toLowerCase();
|
|
8
|
+
const basename = path.basename(normalized);
|
|
9
|
+
if (normalized.startsWith('.github/workflows/')) {
|
|
10
|
+
return 'ci';
|
|
11
|
+
}
|
|
12
|
+
if (basename === 'dockerfile' || basename.startsWith('dockerfile.')) {
|
|
13
|
+
return 'dockerfile';
|
|
14
|
+
}
|
|
15
|
+
if (basename.startsWith('.env')) {
|
|
16
|
+
return 'env';
|
|
17
|
+
}
|
|
18
|
+
if (basename.endsWith('.json')) {
|
|
19
|
+
return 'json';
|
|
20
|
+
}
|
|
21
|
+
if (basename.endsWith('.toml')) {
|
|
22
|
+
return 'toml';
|
|
23
|
+
}
|
|
24
|
+
if (basename.endsWith('.yaml') || basename.endsWith('.yml')) {
|
|
25
|
+
return 'yaml';
|
|
26
|
+
}
|
|
27
|
+
if (basename.endsWith('config.js') ||
|
|
28
|
+
basename.endsWith('config.ts') ||
|
|
29
|
+
basename.endsWith('config.mjs') ||
|
|
30
|
+
basename.endsWith('config.cjs')) {
|
|
31
|
+
return 'js_ts';
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 解析各种配置文件中的配置键/节
|
|
37
|
+
*/
|
|
38
|
+
async function parseConfigFiles(absolutePath, type, content) {
|
|
39
|
+
const keys = [];
|
|
40
|
+
let description = '';
|
|
41
|
+
try {
|
|
42
|
+
switch (type) {
|
|
43
|
+
case 'env': {
|
|
44
|
+
description = '环境变量模板/配置文件';
|
|
45
|
+
const lines = content.split('\n');
|
|
46
|
+
for (const line of lines) {
|
|
47
|
+
const trimmed = line.trim();
|
|
48
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
49
|
+
continue;
|
|
50
|
+
const match = /^export\s+(\w+)=|^(\w+)=/.exec(trimmed);
|
|
51
|
+
if (match) {
|
|
52
|
+
const key = match[1] || match[2];
|
|
53
|
+
if (key)
|
|
54
|
+
keys.push(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case 'json': {
|
|
60
|
+
description = 'JSON 格式配置文件';
|
|
61
|
+
try {
|
|
62
|
+
// 去除 JSON 的注释(如果有的话,如 tsconfig.json)
|
|
63
|
+
const cleanJson = content.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1');
|
|
64
|
+
const parsed = JSON.parse(cleanJson);
|
|
65
|
+
if (parsed && typeof parsed === 'object') {
|
|
66
|
+
keys.push(...Object.keys(parsed));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// 解析失败时,回退到正则
|
|
71
|
+
const keyPattern = /"([^"]+)"\s*:/g;
|
|
72
|
+
let match;
|
|
73
|
+
while ((match = keyPattern.exec(content)) !== null) {
|
|
74
|
+
if (!keys.includes(match[1])) {
|
|
75
|
+
keys.push(match[1]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case 'yaml':
|
|
82
|
+
case 'ci': {
|
|
83
|
+
description = type === 'ci' ? 'GitHub 工作流持续集成配置' : 'YAML 格式配置文件';
|
|
84
|
+
const lines = content.split('\n');
|
|
85
|
+
for (const line of lines) {
|
|
86
|
+
const match = /^([a-zA-Z0-9_\-]+)\s*:/gm.exec(line);
|
|
87
|
+
if (match) {
|
|
88
|
+
const key = match[1];
|
|
89
|
+
if (!keys.includes(key)) {
|
|
90
|
+
keys.push(key);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case 'toml': {
|
|
97
|
+
description = 'TOML 格式配置文件';
|
|
98
|
+
const lines = content.split('\n');
|
|
99
|
+
for (const line of lines) {
|
|
100
|
+
const trimmed = line.trim();
|
|
101
|
+
if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
|
|
102
|
+
const section = trimmed.slice(1, -1).trim();
|
|
103
|
+
keys.push(section);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
const match = /^([a-zA-Z0-9_\-]+)\s*=/.exec(trimmed);
|
|
107
|
+
if (match) {
|
|
108
|
+
keys.push(match[1]);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
case 'dockerfile': {
|
|
115
|
+
description = 'Docker 容器构建文件';
|
|
116
|
+
const lines = content.split('\n');
|
|
117
|
+
const envKeys = new Set();
|
|
118
|
+
for (const line of lines) {
|
|
119
|
+
const trimmed = line.trim();
|
|
120
|
+
if (trimmed.startsWith('FROM')) {
|
|
121
|
+
const parts = trimmed.split(/\s+/);
|
|
122
|
+
if (parts[1])
|
|
123
|
+
keys.push(`BaseImage: ${parts[1]}`);
|
|
124
|
+
}
|
|
125
|
+
else if (trimmed.startsWith('ENV')) {
|
|
126
|
+
// ENV KEY=VALUE 或 ENV KEY VALUE
|
|
127
|
+
const match = /^ENV\s+(\w+)(?:=|\s+)/.exec(trimmed);
|
|
128
|
+
if (match && match[1]) {
|
|
129
|
+
envKeys.add(match[1]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if (trimmed.startsWith('EXPOSE')) {
|
|
133
|
+
const parts = trimmed.split(/\s+/);
|
|
134
|
+
if (parts[1])
|
|
135
|
+
keys.push(`ExposePort: ${parts[1]}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (envKeys.size > 0) {
|
|
139
|
+
keys.push(...Array.from(envKeys).map(k => `ENV: ${k}`));
|
|
140
|
+
}
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case 'js_ts': {
|
|
144
|
+
description = 'JavaScript/TypeScript 构建/运行时配置文件';
|
|
145
|
+
// 查找默认导出的对象键或 module.exports
|
|
146
|
+
const exportMatch = /export\s+default\s*\{([\s\S]*?)\}/.exec(content) ||
|
|
147
|
+
/module\.exports\s*=\s*\{([\s\S]*?)\}/.exec(content);
|
|
148
|
+
if (exportMatch) {
|
|
149
|
+
const block = exportMatch[1];
|
|
150
|
+
const keyPattern = /^\s*(\w+)\s*:/gm;
|
|
151
|
+
let match;
|
|
152
|
+
while ((match = keyPattern.exec(block)) !== null) {
|
|
153
|
+
keys.push(match[1]);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// 解析出错则返回空 keys
|
|
162
|
+
}
|
|
163
|
+
return { keys: Array.from(new Set(keys)), description };
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 分析项目中的配置文件和环境配置
|
|
167
|
+
*
|
|
168
|
+
* 识别 docker-compose, tsconfig, env.example, *.config.js 等文件,
|
|
169
|
+
* 提取顶层配置键、工作流阶段或环境变量,以便 Wiki 文档生成时使用。
|
|
170
|
+
*
|
|
171
|
+
* @param rootPath - 项目根目录
|
|
172
|
+
* @param files - 扫描的文件节点
|
|
173
|
+
*/
|
|
174
|
+
export async function analyzeConfigs(rootPath, files) {
|
|
175
|
+
const configInfos = [];
|
|
176
|
+
for (const file of files) {
|
|
177
|
+
if (file.nodeType !== 'file')
|
|
178
|
+
continue;
|
|
179
|
+
const type = detectConfigType(file.relativePath);
|
|
180
|
+
if (!type)
|
|
181
|
+
continue;
|
|
182
|
+
try {
|
|
183
|
+
const absolutePath = path.resolve(rootPath, file.relativePath);
|
|
184
|
+
const content = await fs.readFile(absolutePath, 'utf-8');
|
|
185
|
+
const { keys, description } = await parseConfigFiles(absolutePath, type, content);
|
|
186
|
+
configInfos.push({
|
|
187
|
+
filePath: file.relativePath,
|
|
188
|
+
type,
|
|
189
|
+
keys,
|
|
190
|
+
description,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
// 忽略读取失败的文件
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// 排序,保证生成文档的顺序一致
|
|
198
|
+
return configInfos.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=config-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-analyzer.js","sourceRoot":"","sources":["../../src/analyzer/config-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据库模型分析器
|
|
3
|
+
* 通过正则表达式从 ORM 定义文件中提取数据模型、字段和关系信息。
|
|
4
|
+
* 支持 SQLAlchemy、Prisma、TypeORM、Mongoose 四种 ORM。
|
|
5
|
+
*/
|
|
6
|
+
import type { FileNode, DatabaseModel } from '../models/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* 分析项目中的数据库模型定义
|
|
9
|
+
*
|
|
10
|
+
* 从扫描到的文件列表中筛选可能包含 ORM 模型定义的文件,
|
|
11
|
+
* 读取其内容并通过正则提取模型名、字段和关系信息。
|
|
12
|
+
*
|
|
13
|
+
* 支持的 ORM:
|
|
14
|
+
* - SQLAlchemy(Python,Column + relationship 解析)
|
|
15
|
+
* - Prisma(schema.prisma 文件解析)
|
|
16
|
+
* - TypeORM(TypeScript @Entity 装饰器解析)
|
|
17
|
+
* - Mongoose(TypeScript/JavaScript Schema 解析)
|
|
18
|
+
*
|
|
19
|
+
* @param rootPath - 项目根目录的绝对路径
|
|
20
|
+
* @param files - 扫描到的 FileNode 列表
|
|
21
|
+
* @returns 排序后的 DatabaseModel 数组
|
|
22
|
+
*/
|
|
23
|
+
export declare function analyzeDatabaseModels(rootPath: string, files: FileNode[]): Promise<DatabaseModel[]>;
|
|
24
|
+
//# sourceMappingURL=database-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-analyzer.d.ts","sourceRoot":"","sources":["../../src/analyzer/database-analyzer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAmC,MAAM,oBAAoB,CAAC;AA4ZnG;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,EAAE,GAClB,OAAO,CAAC,aAAa,EAAE,CAAC,CA4B1B"}
|