@mycodemap/mycodemap 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.
Files changed (329) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +21 -0
  3. package/README.md +559 -0
  4. package/dist/ai/claude.d.ts +38 -0
  5. package/dist/ai/claude.d.ts.map +1 -0
  6. package/dist/ai/claude.js +169 -0
  7. package/dist/ai/claude.js.map +1 -0
  8. package/dist/ai/codex.d.ts +38 -0
  9. package/dist/ai/codex.d.ts.map +1 -0
  10. package/dist/ai/codex.js +169 -0
  11. package/dist/ai/codex.js.map +1 -0
  12. package/dist/ai/factory.d.ts +48 -0
  13. package/dist/ai/factory.d.ts.map +1 -0
  14. package/dist/ai/factory.js +95 -0
  15. package/dist/ai/factory.js.map +1 -0
  16. package/dist/ai/index.d.ts +12 -0
  17. package/dist/ai/index.d.ts.map +1 -0
  18. package/dist/ai/index.js +29 -0
  19. package/dist/ai/index.js.map +1 -0
  20. package/dist/ai/provider.d.ts +70 -0
  21. package/dist/ai/provider.d.ts.map +1 -0
  22. package/dist/ai/provider.js +31 -0
  23. package/dist/ai/provider.js.map +1 -0
  24. package/dist/ai/subagent-caller.d.ts +90 -0
  25. package/dist/ai/subagent-caller.d.ts.map +1 -0
  26. package/dist/ai/subagent-caller.js +280 -0
  27. package/dist/ai/subagent-caller.js.map +1 -0
  28. package/dist/ai/types.d.ts +70 -0
  29. package/dist/ai/types.d.ts.map +1 -0
  30. package/dist/ai/types.js +5 -0
  31. package/dist/ai/types.js.map +1 -0
  32. package/dist/cache/file-hash-cache.d.ts +76 -0
  33. package/dist/cache/file-hash-cache.d.ts.map +1 -0
  34. package/dist/cache/file-hash-cache.js +159 -0
  35. package/dist/cache/file-hash-cache.js.map +1 -0
  36. package/dist/cache/index.d.ts +151 -0
  37. package/dist/cache/index.d.ts.map +1 -0
  38. package/dist/cache/index.js +303 -0
  39. package/dist/cache/index.js.map +1 -0
  40. package/dist/cache/lru-cache.d.ts +93 -0
  41. package/dist/cache/lru-cache.d.ts.map +1 -0
  42. package/dist/cache/lru-cache.js +194 -0
  43. package/dist/cache/lru-cache.js.map +1 -0
  44. package/dist/cache/parse-cache.d.ts +68 -0
  45. package/dist/cache/parse-cache.d.ts.map +1 -0
  46. package/dist/cache/parse-cache.js +173 -0
  47. package/dist/cache/parse-cache.js.map +1 -0
  48. package/dist/cli/commands/analyze.d.ts +96 -0
  49. package/dist/cli/commands/analyze.d.ts.map +1 -0
  50. package/dist/cli/commands/analyze.js +567 -0
  51. package/dist/cli/commands/analyze.js.map +1 -0
  52. package/dist/cli/commands/ci.d.ts +25 -0
  53. package/dist/cli/commands/ci.d.ts.map +1 -0
  54. package/dist/cli/commands/ci.js +481 -0
  55. package/dist/cli/commands/ci.js.map +1 -0
  56. package/dist/cli/commands/complexity.d.ts +70 -0
  57. package/dist/cli/commands/complexity.d.ts.map +1 -0
  58. package/dist/cli/commands/complexity.js +479 -0
  59. package/dist/cli/commands/complexity.js.map +1 -0
  60. package/dist/cli/commands/cycles.d.ts +10 -0
  61. package/dist/cli/commands/cycles.d.ts.map +1 -0
  62. package/dist/cli/commands/cycles.js +202 -0
  63. package/dist/cli/commands/cycles.js.map +1 -0
  64. package/dist/cli/commands/deps.d.ts +61 -0
  65. package/dist/cli/commands/deps.d.ts.map +1 -0
  66. package/dist/cli/commands/deps.js +340 -0
  67. package/dist/cli/commands/deps.js.map +1 -0
  68. package/dist/cli/commands/generate.d.ts +8 -0
  69. package/dist/cli/commands/generate.d.ts.map +1 -0
  70. package/dist/cli/commands/generate.js +61 -0
  71. package/dist/cli/commands/generate.js.map +1 -0
  72. package/dist/cli/commands/impact.d.ts +55 -0
  73. package/dist/cli/commands/impact.d.ts.map +1 -0
  74. package/dist/cli/commands/impact.js +455 -0
  75. package/dist/cli/commands/impact.js.map +1 -0
  76. package/dist/cli/commands/init.d.ts +4 -0
  77. package/dist/cli/commands/init.d.ts.map +1 -0
  78. package/dist/cli/commands/init.js +50 -0
  79. package/dist/cli/commands/init.js.map +1 -0
  80. package/dist/cli/commands/query.d.ts +22 -0
  81. package/dist/cli/commands/query.d.ts.map +1 -0
  82. package/dist/cli/commands/query.js +718 -0
  83. package/dist/cli/commands/query.js.map +1 -0
  84. package/dist/cli/commands/watch-foreground.d.ts +9 -0
  85. package/dist/cli/commands/watch-foreground.d.ts.map +1 -0
  86. package/dist/cli/commands/watch-foreground.js +67 -0
  87. package/dist/cli/commands/watch-foreground.js.map +1 -0
  88. package/dist/cli/commands/watch.d.ts +12 -0
  89. package/dist/cli/commands/watch.d.ts.map +1 -0
  90. package/dist/cli/commands/watch.js +114 -0
  91. package/dist/cli/commands/watch.js.map +1 -0
  92. package/dist/cli/commands/workflow.d.ts +25 -0
  93. package/dist/cli/commands/workflow.d.ts.map +1 -0
  94. package/dist/cli/commands/workflow.js +488 -0
  95. package/dist/cli/commands/workflow.js.map +1 -0
  96. package/dist/cli/index.d.ts +3 -0
  97. package/dist/cli/index.d.ts.map +1 -0
  98. package/dist/cli/index.js +115 -0
  99. package/dist/cli/index.js.map +1 -0
  100. package/dist/cli/paths.d.ts +90 -0
  101. package/dist/cli/paths.d.ts.map +1 -0
  102. package/dist/cli/paths.js +136 -0
  103. package/dist/cli/paths.js.map +1 -0
  104. package/dist/cli/runtime-logger.d.ts +13 -0
  105. package/dist/cli/runtime-logger.d.ts.map +1 -0
  106. package/dist/cli/runtime-logger.js +213 -0
  107. package/dist/cli/runtime-logger.js.map +1 -0
  108. package/dist/core/analyzer.d.ts +3 -0
  109. package/dist/core/analyzer.d.ts.map +1 -0
  110. package/dist/core/analyzer.js +359 -0
  111. package/dist/core/analyzer.js.map +1 -0
  112. package/dist/core/ast-complexity-analyzer.d.ts +40 -0
  113. package/dist/core/ast-complexity-analyzer.d.ts.map +1 -0
  114. package/dist/core/ast-complexity-analyzer.js +279 -0
  115. package/dist/core/ast-complexity-analyzer.js.map +1 -0
  116. package/dist/core/global-index.d.ts +69 -0
  117. package/dist/core/global-index.d.ts.map +1 -0
  118. package/dist/core/global-index.js +388 -0
  119. package/dist/core/global-index.js.map +1 -0
  120. package/dist/generator/ai-overview.d.ts +51 -0
  121. package/dist/generator/ai-overview.d.ts.map +1 -0
  122. package/dist/generator/ai-overview.js +160 -0
  123. package/dist/generator/ai-overview.js.map +1 -0
  124. package/dist/generator/context.d.ts +5 -0
  125. package/dist/generator/context.d.ts.map +1 -0
  126. package/dist/generator/context.js +514 -0
  127. package/dist/generator/context.js.map +1 -0
  128. package/dist/generator/file-describer.d.ts +93 -0
  129. package/dist/generator/file-describer.d.ts.map +1 -0
  130. package/dist/generator/file-describer.js +375 -0
  131. package/dist/generator/file-describer.js.map +1 -0
  132. package/dist/generator/index.d.ts +8 -0
  133. package/dist/generator/index.d.ts.map +1 -0
  134. package/dist/generator/index.js +259 -0
  135. package/dist/generator/index.js.map +1 -0
  136. package/dist/index.d.ts +5 -0
  137. package/dist/index.d.ts.map +1 -0
  138. package/dist/index.js +6 -0
  139. package/dist/index.js.map +1 -0
  140. package/dist/orchestrator/adapters/ast-grep-adapter.d.ts +75 -0
  141. package/dist/orchestrator/adapters/ast-grep-adapter.d.ts.map +1 -0
  142. package/dist/orchestrator/adapters/ast-grep-adapter.js +242 -0
  143. package/dist/orchestrator/adapters/ast-grep-adapter.js.map +1 -0
  144. package/dist/orchestrator/adapters/base-adapter.d.ts +24 -0
  145. package/dist/orchestrator/adapters/base-adapter.d.ts.map +1 -0
  146. package/dist/orchestrator/adapters/base-adapter.js +2 -0
  147. package/dist/orchestrator/adapters/base-adapter.js.map +1 -0
  148. package/dist/orchestrator/adapters/codemap-adapter.d.ts +56 -0
  149. package/dist/orchestrator/adapters/codemap-adapter.d.ts.map +1 -0
  150. package/dist/orchestrator/adapters/codemap-adapter.js +163 -0
  151. package/dist/orchestrator/adapters/codemap-adapter.js.map +1 -0
  152. package/dist/orchestrator/adapters/index.d.ts +10 -0
  153. package/dist/orchestrator/adapters/index.d.ts.map +1 -0
  154. package/dist/orchestrator/adapters/index.js +3 -0
  155. package/dist/orchestrator/adapters/index.js.map +1 -0
  156. package/dist/orchestrator/ai-feed-generator.d.ts +210 -0
  157. package/dist/orchestrator/ai-feed-generator.d.ts.map +1 -0
  158. package/dist/orchestrator/ai-feed-generator.js +377 -0
  159. package/dist/orchestrator/ai-feed-generator.js.map +1 -0
  160. package/dist/orchestrator/commit-validator.d.ts +30 -0
  161. package/dist/orchestrator/commit-validator.d.ts.map +1 -0
  162. package/dist/orchestrator/commit-validator.js +87 -0
  163. package/dist/orchestrator/commit-validator.js.map +1 -0
  164. package/dist/orchestrator/confidence.d.ts +25 -0
  165. package/dist/orchestrator/confidence.d.ts.map +1 -0
  166. package/dist/orchestrator/confidence.js +138 -0
  167. package/dist/orchestrator/confidence.js.map +1 -0
  168. package/dist/orchestrator/file-header-scanner.d.ts +48 -0
  169. package/dist/orchestrator/file-header-scanner.d.ts.map +1 -0
  170. package/dist/orchestrator/file-header-scanner.js +158 -0
  171. package/dist/orchestrator/file-header-scanner.js.map +1 -0
  172. package/dist/orchestrator/git-analyzer.d.ts +192 -0
  173. package/dist/orchestrator/git-analyzer.d.ts.map +1 -0
  174. package/dist/orchestrator/git-analyzer.js +539 -0
  175. package/dist/orchestrator/git-analyzer.js.map +1 -0
  176. package/dist/orchestrator/index.d.ts +20 -0
  177. package/dist/orchestrator/index.d.ts.map +1 -0
  178. package/dist/orchestrator/index.js +16 -0
  179. package/dist/orchestrator/index.js.map +1 -0
  180. package/dist/orchestrator/intent-router.d.ts +41 -0
  181. package/dist/orchestrator/intent-router.d.ts.map +1 -0
  182. package/dist/orchestrator/intent-router.js +98 -0
  183. package/dist/orchestrator/intent-router.js.map +1 -0
  184. package/dist/orchestrator/result-fusion.d.ts +114 -0
  185. package/dist/orchestrator/result-fusion.d.ts.map +1 -0
  186. package/dist/orchestrator/result-fusion.js +332 -0
  187. package/dist/orchestrator/result-fusion.js.map +1 -0
  188. package/dist/orchestrator/test-linker.d.ts +166 -0
  189. package/dist/orchestrator/test-linker.d.ts.map +1 -0
  190. package/dist/orchestrator/test-linker.js +570 -0
  191. package/dist/orchestrator/test-linker.js.map +1 -0
  192. package/dist/orchestrator/tool-orchestrator.d.ts +108 -0
  193. package/dist/orchestrator/tool-orchestrator.d.ts.map +1 -0
  194. package/dist/orchestrator/tool-orchestrator.js +247 -0
  195. package/dist/orchestrator/tool-orchestrator.js.map +1 -0
  196. package/dist/orchestrator/types.d.ts +162 -0
  197. package/dist/orchestrator/types.d.ts.map +1 -0
  198. package/dist/orchestrator/types.js +39 -0
  199. package/dist/orchestrator/types.js.map +1 -0
  200. package/dist/orchestrator/workflow/ci-executor.d.ts +157 -0
  201. package/dist/orchestrator/workflow/ci-executor.d.ts.map +1 -0
  202. package/dist/orchestrator/workflow/ci-executor.js +423 -0
  203. package/dist/orchestrator/workflow/ci-executor.js.map +1 -0
  204. package/dist/orchestrator/workflow/config.d.ts +97 -0
  205. package/dist/orchestrator/workflow/config.d.ts.map +1 -0
  206. package/dist/orchestrator/workflow/config.js +115 -0
  207. package/dist/orchestrator/workflow/config.js.map +1 -0
  208. package/dist/orchestrator/workflow/git-analyzer.d.ts +173 -0
  209. package/dist/orchestrator/workflow/git-analyzer.d.ts.map +1 -0
  210. package/dist/orchestrator/workflow/git-analyzer.js +473 -0
  211. package/dist/orchestrator/workflow/git-analyzer.js.map +1 -0
  212. package/dist/orchestrator/workflow/index.d.ts +21 -0
  213. package/dist/orchestrator/workflow/index.d.ts.map +1 -0
  214. package/dist/orchestrator/workflow/index.js +21 -0
  215. package/dist/orchestrator/workflow/index.js.map +1 -0
  216. package/dist/orchestrator/workflow/phase-checkpoint.d.ts +38 -0
  217. package/dist/orchestrator/workflow/phase-checkpoint.d.ts.map +1 -0
  218. package/dist/orchestrator/workflow/phase-checkpoint.js +75 -0
  219. package/dist/orchestrator/workflow/phase-checkpoint.js.map +1 -0
  220. package/dist/orchestrator/workflow/phase-inheritance.d.ts +128 -0
  221. package/dist/orchestrator/workflow/phase-inheritance.d.ts.map +1 -0
  222. package/dist/orchestrator/workflow/phase-inheritance.js +266 -0
  223. package/dist/orchestrator/workflow/phase-inheritance.js.map +1 -0
  224. package/dist/orchestrator/workflow/result-fusion.d.ts +117 -0
  225. package/dist/orchestrator/workflow/result-fusion.d.ts.map +1 -0
  226. package/dist/orchestrator/workflow/result-fusion.js +246 -0
  227. package/dist/orchestrator/workflow/result-fusion.js.map +1 -0
  228. package/dist/orchestrator/workflow/templates.d.ts +116 -0
  229. package/dist/orchestrator/workflow/templates.d.ts.map +1 -0
  230. package/dist/orchestrator/workflow/templates.js +546 -0
  231. package/dist/orchestrator/workflow/templates.js.map +1 -0
  232. package/dist/orchestrator/workflow/test-linker.d.ts +152 -0
  233. package/dist/orchestrator/workflow/test-linker.d.ts.map +1 -0
  234. package/dist/orchestrator/workflow/test-linker.js +342 -0
  235. package/dist/orchestrator/workflow/test-linker.js.map +1 -0
  236. package/dist/orchestrator/workflow/types.d.ts +202 -0
  237. package/dist/orchestrator/workflow/types.d.ts.map +1 -0
  238. package/dist/orchestrator/workflow/types.js +4 -0
  239. package/dist/orchestrator/workflow/types.js.map +1 -0
  240. package/dist/orchestrator/workflow/visualizer.d.ts +56 -0
  241. package/dist/orchestrator/workflow/visualizer.d.ts.map +1 -0
  242. package/dist/orchestrator/workflow/visualizer.js +300 -0
  243. package/dist/orchestrator/workflow/visualizer.js.map +1 -0
  244. package/dist/orchestrator/workflow/workflow-context.d.ts +50 -0
  245. package/dist/orchestrator/workflow/workflow-context.d.ts.map +1 -0
  246. package/dist/orchestrator/workflow/workflow-context.js +105 -0
  247. package/dist/orchestrator/workflow/workflow-context.js.map +1 -0
  248. package/dist/orchestrator/workflow/workflow-orchestrator.d.ts +126 -0
  249. package/dist/orchestrator/workflow/workflow-orchestrator.d.ts.map +1 -0
  250. package/dist/orchestrator/workflow/workflow-orchestrator.js +489 -0
  251. package/dist/orchestrator/workflow/workflow-orchestrator.js.map +1 -0
  252. package/dist/orchestrator/workflow/workflow-persistence.d.ts +38 -0
  253. package/dist/orchestrator/workflow/workflow-persistence.d.ts.map +1 -0
  254. package/dist/orchestrator/workflow/workflow-persistence.js +166 -0
  255. package/dist/orchestrator/workflow/workflow-persistence.js.map +1 -0
  256. package/dist/parser/implementations/fast-parser.d.ts +65 -0
  257. package/dist/parser/implementations/fast-parser.d.ts.map +1 -0
  258. package/dist/parser/implementations/fast-parser.js +299 -0
  259. package/dist/parser/implementations/fast-parser.js.map +1 -0
  260. package/dist/parser/implementations/smart-parser.d.ts +220 -0
  261. package/dist/parser/implementations/smart-parser.d.ts.map +1 -0
  262. package/dist/parser/implementations/smart-parser.js +1536 -0
  263. package/dist/parser/implementations/smart-parser.js.map +1 -0
  264. package/dist/parser/implementations/tree-sitter-parser.d.ts +57 -0
  265. package/dist/parser/implementations/tree-sitter-parser.d.ts.map +1 -0
  266. package/dist/parser/implementations/tree-sitter-parser.js +375 -0
  267. package/dist/parser/implementations/tree-sitter-parser.js.map +1 -0
  268. package/dist/parser/index.d.ts +19 -0
  269. package/dist/parser/index.d.ts.map +1 -0
  270. package/dist/parser/index.js +449 -0
  271. package/dist/parser/index.js.map +1 -0
  272. package/dist/parser/interfaces/IParser.d.ts +218 -0
  273. package/dist/parser/interfaces/IParser.d.ts.map +1 -0
  274. package/dist/parser/interfaces/IParser.js +22 -0
  275. package/dist/parser/interfaces/IParser.js.map +1 -0
  276. package/dist/plugins/built-in/call-graph.d.ts +38 -0
  277. package/dist/plugins/built-in/call-graph.d.ts.map +1 -0
  278. package/dist/plugins/built-in/call-graph.js +135 -0
  279. package/dist/plugins/built-in/call-graph.js.map +1 -0
  280. package/dist/plugins/built-in/complexity-analyzer.d.ts +45 -0
  281. package/dist/plugins/built-in/complexity-analyzer.d.ts.map +1 -0
  282. package/dist/plugins/built-in/complexity-analyzer.js +155 -0
  283. package/dist/plugins/built-in/complexity-analyzer.js.map +1 -0
  284. package/dist/plugins/index.d.ts +34 -0
  285. package/dist/plugins/index.d.ts.map +1 -0
  286. package/dist/plugins/index.js +103 -0
  287. package/dist/plugins/index.js.map +1 -0
  288. package/dist/plugins/plugin-loader.d.ts +22 -0
  289. package/dist/plugins/plugin-loader.d.ts.map +1 -0
  290. package/dist/plugins/plugin-loader.js +200 -0
  291. package/dist/plugins/plugin-loader.js.map +1 -0
  292. package/dist/plugins/plugin-registry.d.ts +20 -0
  293. package/dist/plugins/plugin-registry.d.ts.map +1 -0
  294. package/dist/plugins/plugin-registry.js +143 -0
  295. package/dist/plugins/plugin-registry.js.map +1 -0
  296. package/dist/plugins/types.d.ts +72 -0
  297. package/dist/plugins/types.d.ts.map +1 -0
  298. package/dist/plugins/types.js +5 -0
  299. package/dist/plugins/types.js.map +1 -0
  300. package/dist/types/index.d.ts +373 -0
  301. package/dist/types/index.d.ts.map +1 -0
  302. package/dist/types/index.js +7 -0
  303. package/dist/types/index.js.map +1 -0
  304. package/dist/watcher/daemon.d.ts +64 -0
  305. package/dist/watcher/daemon.d.ts.map +1 -0
  306. package/dist/watcher/daemon.js +189 -0
  307. package/dist/watcher/daemon.js.map +1 -0
  308. package/dist/watcher/file-watcher.d.ts +70 -0
  309. package/dist/watcher/file-watcher.d.ts.map +1 -0
  310. package/dist/watcher/file-watcher.js +127 -0
  311. package/dist/watcher/file-watcher.js.map +1 -0
  312. package/dist/watcher/index.d.ts +5 -0
  313. package/dist/watcher/index.d.ts.map +1 -0
  314. package/dist/watcher/index.js +6 -0
  315. package/dist/watcher/index.js.map +1 -0
  316. package/dist/watcher/watch-worker.d.ts +2 -0
  317. package/dist/watcher/watch-worker.d.ts.map +1 -0
  318. package/dist/watcher/watch-worker.js +57 -0
  319. package/dist/watcher/watch-worker.js.map +1 -0
  320. package/dist/worker/index.d.ts +76 -0
  321. package/dist/worker/index.d.ts.map +1 -0
  322. package/dist/worker/index.js +155 -0
  323. package/dist/worker/index.js.map +1 -0
  324. package/dist/worker/parse-worker.d.ts +2 -0
  325. package/dist/worker/parse-worker.d.ts.map +1 -0
  326. package/dist/worker/parse-worker.js +202 -0
  327. package/dist/worker/parse-worker.js.map +1 -0
  328. package/mycodemap.config.schema.json +42 -0
  329. package/package.json +69 -0
@@ -0,0 +1,1536 @@
1
+ // ============================================
2
+ // Smart Parser - 基于 TS Compiler API 的深度解析器
3
+ // ============================================
4
+ // [META] since:2024-06 | owner:parser-team | stable:true
5
+ // [WHY] 基于 TS Compiler API 的深度解析器,提供完整的类型信息和调用图分析
6
+ import * as ts from 'typescript';
7
+ import * as path from 'path';
8
+ import * as fs from 'fs';
9
+ /**
10
+ * 将构建路径转换为源代码路径
11
+ * 例如: ../types/index.js -> ../types/index.ts
12
+ */
13
+ function normalizeSourcePath(depPath) {
14
+ // 已经是 .ts 或 .tsx 的不需要转换
15
+ if (depPath.endsWith('.ts') || depPath.endsWith('.tsx')) {
16
+ return depPath;
17
+ }
18
+ // 替换 .js/.jsx 后缀为 .ts/.tsx
19
+ return depPath.replace(/\.js$/i, '.ts').replace(/\.jsx$/i, '.tsx');
20
+ }
21
+ /**
22
+ * Smart Parser - 使用 TypeScript Compiler API 进行深度分析
23
+ */
24
+ export class SmartParser {
25
+ name = 'smart-parser';
26
+ mode = 'smart';
27
+ constructor(_options) {
28
+ }
29
+ /**
30
+ * 解析单个文件
31
+ */
32
+ async parseFile(filePath) {
33
+ const content = fs.readFileSync(filePath, 'utf-8');
34
+ const sourceFile = ts.createSourceFile(path.basename(filePath), content, ts.ScriptTarget.Latest, true);
35
+ const exports = this.extractExports(sourceFile);
36
+ const imports = this.extractImports(sourceFile);
37
+ const symbols = this.extractSymbols(sourceFile);
38
+ const dependencies = this.extractDependencies(imports, exports);
39
+ const typeInfo = this.extractTypeInfo(sourceFile);
40
+ const callGraph = this.extractCallGraph(sourceFile);
41
+ const complexity = this.calculateComplexity(sourceFile, content);
42
+ return {
43
+ path: filePath,
44
+ exports,
45
+ imports,
46
+ symbols,
47
+ dependencies,
48
+ type: this.getModuleType(filePath),
49
+ stats: this.getFileStats(content),
50
+ typeInfo,
51
+ callGraph,
52
+ complexity
53
+ };
54
+ }
55
+ /**
56
+ * 批量解析文件
57
+ */
58
+ async parseFiles(filePaths) {
59
+ const results = [];
60
+ for (const filePath of filePaths) {
61
+ try {
62
+ const result = await this.parseFile(filePath);
63
+ results.push(result);
64
+ }
65
+ catch (error) {
66
+ console.error(`解析失败: ${filePath}`, error);
67
+ }
68
+ }
69
+ return results;
70
+ }
71
+ /**
72
+ * 释放资源
73
+ */
74
+ dispose() {
75
+ // 清理资源
76
+ }
77
+ /**
78
+ * 提取导出信息
79
+ */
80
+ extractExports(sourceFile) {
81
+ const exports = [];
82
+ ts.forEachChild(sourceFile, (node) => {
83
+ if (ts.isExportDeclaration(node)) {
84
+ if (node.moduleSpecifier) {
85
+ const source = this.getStringLiteral(node.moduleSpecifier, sourceFile);
86
+ if (source && node.exportClause && ts.isNamedExports(node.exportClause)) {
87
+ for (const spec of node.exportClause.elements) {
88
+ exports.push({
89
+ name: spec.name.text,
90
+ kind: 'variable',
91
+ isDefault: false,
92
+ isTypeOnly: false,
93
+ origin: normalizeSourcePath(source)
94
+ });
95
+ }
96
+ }
97
+ }
98
+ }
99
+ else if (this.isExportable(node)) {
100
+ const name = this.getNodeName(node);
101
+ if (name) {
102
+ exports.push({
103
+ name,
104
+ kind: this.getSymbolKind(node),
105
+ isDefault: false,
106
+ isTypeOnly: false
107
+ });
108
+ }
109
+ }
110
+ });
111
+ return exports;
112
+ }
113
+ /**
114
+ * 检查节点是否可导出
115
+ */
116
+ isExportable(node) {
117
+ return ts.isClassDeclaration(node) ||
118
+ ts.isFunctionDeclaration(node) ||
119
+ ts.isInterfaceDeclaration(node) ||
120
+ ts.isTypeAliasDeclaration(node) ||
121
+ ts.isEnumDeclaration(node) ||
122
+ ts.isModuleDeclaration(node);
123
+ }
124
+ /**
125
+ * 获取节点名称
126
+ */
127
+ getNodeName(node) {
128
+ const nameNode = node.name;
129
+ if (nameNode && ts.isIdentifier(nameNode)) {
130
+ return nameNode.text;
131
+ }
132
+ return null;
133
+ }
134
+ /**
135
+ * 获取符号类型
136
+ */
137
+ getSymbolKind(node) {
138
+ if (ts.isClassDeclaration(node))
139
+ return 'class';
140
+ if (ts.isFunctionDeclaration(node))
141
+ return 'function';
142
+ if (ts.isInterfaceDeclaration(node))
143
+ return 'interface';
144
+ if (ts.isTypeAliasDeclaration(node))
145
+ return 'type';
146
+ if (ts.isEnumDeclaration(node))
147
+ return 'enum';
148
+ if (ts.isMethodDeclaration(node))
149
+ return 'method';
150
+ if (ts.isPropertyDeclaration(node))
151
+ return 'property';
152
+ return 'variable';
153
+ }
154
+ /**
155
+ * 获取字符串字面量
156
+ */
157
+ getStringLiteral(node, _sourceFile) {
158
+ if (ts.isStringLiteral(node)) {
159
+ return node.text;
160
+ }
161
+ return null;
162
+ }
163
+ /**
164
+ * 提取导入信息
165
+ */
166
+ extractImports(sourceFile) {
167
+ const imports = [];
168
+ ts.forEachChild(sourceFile, (node) => {
169
+ if (ts.isImportDeclaration(node)) {
170
+ const source = this.getStringLiteral(node.moduleSpecifier, sourceFile) || '';
171
+ const specifiers = [];
172
+ if (node.importClause) {
173
+ if (node.importClause.namedBindings) {
174
+ if (ts.isNamedImports(node.importClause.namedBindings)) {
175
+ for (const spec of node.importClause.namedBindings.elements) {
176
+ specifiers.push({
177
+ name: spec.name.text,
178
+ alias: spec.propertyName?.text,
179
+ isTypeOnly: false
180
+ });
181
+ }
182
+ }
183
+ }
184
+ if (node.importClause.name) {
185
+ specifiers.unshift({
186
+ name: node.importClause.name.text,
187
+ isTypeOnly: false
188
+ });
189
+ }
190
+ }
191
+ imports.push({
192
+ source: normalizeSourcePath(source),
193
+ sourceType: source.startsWith('.') ? 'relative' : 'alias',
194
+ specifiers,
195
+ isTypeOnly: false
196
+ });
197
+ }
198
+ });
199
+ return imports;
200
+ }
201
+ /**
202
+ * 提取符号信息 - 增强版,包含详细签名
203
+ */
204
+ extractSymbols(sourceFile) {
205
+ const symbols = [];
206
+ const visit = (node) => {
207
+ let symbol = null;
208
+ if (ts.isFunctionDeclaration(node) && node.name) {
209
+ symbol = this.createFunctionSymbol(node.name.text, node, sourceFile);
210
+ }
211
+ else if (ts.isClassDeclaration(node) && node.name) {
212
+ symbol = this.createClassSymbol(node.name.text, node, sourceFile);
213
+ }
214
+ else if (ts.isInterfaceDeclaration(node) && node.name) {
215
+ symbol = this.createInterfaceSymbol(node.name.text, node, sourceFile);
216
+ }
217
+ else if (ts.isTypeAliasDeclaration(node) && node.name) {
218
+ symbol = this.createTypeAliasSymbol(node.name.text, node, sourceFile);
219
+ }
220
+ else if (ts.isEnumDeclaration(node) && node.name) {
221
+ symbol = this.createEnumSymbol(node.name.text, node, sourceFile);
222
+ }
223
+ else if (ts.isVariableStatement(node)) {
224
+ // 处理变量声明
225
+ for (const decl of node.declarationList.declarations) {
226
+ if (ts.isIdentifier(decl.name)) {
227
+ const varSymbol = this.createVariableSymbol(decl.name.text, decl, sourceFile);
228
+ if (varSymbol)
229
+ symbols.push(varSymbol);
230
+ }
231
+ }
232
+ }
233
+ if (symbol) {
234
+ symbols.push(symbol);
235
+ }
236
+ ts.forEachChild(node, visit);
237
+ };
238
+ visit(sourceFile);
239
+ return symbols;
240
+ }
241
+ /**
242
+ * 创建函数符号 - 包含签名信息
243
+ */
244
+ createFunctionSymbol(name, node, sourceFile) {
245
+ const baseSymbol = this.createBaseSymbol(name, 'function', node, sourceFile);
246
+ const signature = this.extractFunctionSignature(node, sourceFile);
247
+ const visibility = this.getVisibility(node);
248
+ return {
249
+ ...baseSymbol,
250
+ visibility,
251
+ signature
252
+ };
253
+ }
254
+ /**
255
+ * 创建类符号 - 包含成员信息
256
+ */
257
+ createClassSymbol(name, node, sourceFile) {
258
+ const baseSymbol = this.createBaseSymbol(name, 'class', node, sourceFile);
259
+ const visibility = this.getVisibility(node);
260
+ const members = this.extractClassMembers(node, sourceFile);
261
+ const extendsClause = node.heritageClauses?.find(hc => hc.token === ts.SyntaxKind.ExtendsKeyword);
262
+ const implementsClause = node.heritageClauses?.find(hc => hc.token === ts.SyntaxKind.ImplementsKeyword);
263
+ const extends_ = extendsClause?.types.map(t => t.expression.getText(sourceFile));
264
+ const implements_ = implementsClause?.types.map(t => t.getText(sourceFile));
265
+ return {
266
+ ...baseSymbol,
267
+ visibility,
268
+ members: members.length > 0 ? members : undefined,
269
+ extends: extends_,
270
+ implements: implements_
271
+ };
272
+ }
273
+ /**
274
+ * 创建接口符号 - 包含成员信息
275
+ */
276
+ createInterfaceSymbol(name, node, sourceFile) {
277
+ const baseSymbol = this.createBaseSymbol(name, 'interface', node, sourceFile);
278
+ const members = this.extractInterfaceMembers(node, sourceFile);
279
+ const extendsClause = node.heritageClauses?.find(hc => hc.token === ts.SyntaxKind.ExtendsKeyword);
280
+ const extends_ = extendsClause?.types.map(t => t.getText(sourceFile));
281
+ return {
282
+ ...baseSymbol,
283
+ visibility: 'public',
284
+ members: members.length > 0 ? members : undefined,
285
+ extends: extends_
286
+ };
287
+ }
288
+ /**
289
+ * 创建类型别名符号
290
+ */
291
+ createTypeAliasSymbol(name, node, sourceFile) {
292
+ const baseSymbol = this.createBaseSymbol(name, 'type', node, sourceFile);
293
+ const typeText = node.type.getText(sourceFile);
294
+ return {
295
+ ...baseSymbol,
296
+ visibility: 'public',
297
+ type: typeText
298
+ };
299
+ }
300
+ /**
301
+ * 创建枚举符号
302
+ */
303
+ createEnumSymbol(name, node, sourceFile) {
304
+ const baseSymbol = this.createBaseSymbol(name, 'enum', node, sourceFile);
305
+ const members = node.members.map(m => ({
306
+ name: m.name.getText(sourceFile),
307
+ kind: 'property',
308
+ type: 'enum_member',
309
+ visibility: 'public',
310
+ optional: false
311
+ }));
312
+ return {
313
+ ...baseSymbol,
314
+ visibility: 'public',
315
+ members
316
+ };
317
+ }
318
+ /**
319
+ * 创建变量符号
320
+ */
321
+ createVariableSymbol(name, node, sourceFile) {
322
+ const baseSymbol = this.createBaseSymbol(name, 'variable', node, sourceFile);
323
+ const type = node.type?.getText(sourceFile) || 'any';
324
+ return {
325
+ ...baseSymbol,
326
+ visibility: 'public',
327
+ type
328
+ };
329
+ }
330
+ /**
331
+ * 创建基础符号
332
+ */
333
+ createBaseSymbol(name, kind, node, sourceFile) {
334
+ const start = node.getStart();
335
+ const pos = sourceFile.getLineAndCharacterOfPosition(start);
336
+ const decorators = this.extractDecorators(node, kind);
337
+ const jsdoc = this.extractJSDoc(node, sourceFile);
338
+ const result = {
339
+ id: this.generateId(name + sourceFile.fileName + pos.line),
340
+ name,
341
+ kind,
342
+ location: {
343
+ file: sourceFile.fileName,
344
+ line: pos.line + 1,
345
+ column: pos.character + 1
346
+ },
347
+ relatedSymbols: [],
348
+ decorators: decorators.length > 0 ? decorators : undefined
349
+ };
350
+ if (jsdoc) {
351
+ result.jsdoc = jsdoc;
352
+ // 同时保留简单的 documentation 字段用于兼容
353
+ result.documentation = jsdoc.description;
354
+ }
355
+ return result;
356
+ }
357
+ /**
358
+ * 提取 JSDoc 注释
359
+ */
360
+ extractJSDoc(node, sourceFile) {
361
+ const jsDocTags = ts.getJSDocTags(node);
362
+ const fullText = sourceFile.getFullText();
363
+ // 获取节点前的注释范围
364
+ const commentRanges = ts.getLeadingCommentRanges(fullText, node.getFullStart());
365
+ if (!commentRanges || commentRanges.length === 0) {
366
+ return undefined;
367
+ }
368
+ // 获取最后一个注释(通常是 JSDoc)
369
+ const lastComment = commentRanges[commentRanges.length - 1];
370
+ const commentText = fullText.slice(lastComment.pos, lastComment.end);
371
+ // 检查是否是 JSDoc 注释 (/** ... */)
372
+ if (!commentText.startsWith('/**')) {
373
+ return undefined;
374
+ }
375
+ // 解析 JSDoc
376
+ return this.parseJSDocText(commentText);
377
+ }
378
+ /**
379
+ * 解析 JSDoc 文本
380
+ */
381
+ parseJSDocText(commentText) {
382
+ const lines = commentText
383
+ .split('\n')
384
+ .map(line => line.trim())
385
+ .map(line => line.replace(/^\/\*\*/, '')) // 移除开头 /**
386
+ .map(line => line.replace(/\*\/$/, '')) // 移除结尾 */
387
+ .map(line => line.replace(/^\*\s?/, '')) // 移除行首 *
388
+ .filter(line => line.length > 0);
389
+ const result = {
390
+ description: '',
391
+ tags: [],
392
+ params: [],
393
+ examples: [],
394
+ see: []
395
+ };
396
+ let currentTag = null;
397
+ let currentTagText = [];
398
+ let inDescription = true;
399
+ for (const line of lines) {
400
+ const tagMatch = line.match(/^@(\w+)(?:\s+(.*))?$/);
401
+ if (tagMatch) {
402
+ // 保存之前的 tag
403
+ if (currentTag) {
404
+ this.processJSDocTag(result, currentTag, currentTagText.join(' '));
405
+ }
406
+ currentTag = tagMatch[1];
407
+ currentTagText = tagMatch[2] ? [tagMatch[2]] : [];
408
+ inDescription = false;
409
+ }
410
+ else if (currentTag) {
411
+ currentTagText.push(line);
412
+ }
413
+ else if (inDescription) {
414
+ result.description += (result.description ? ' ' : '') + line;
415
+ }
416
+ }
417
+ // 处理最后一个 tag
418
+ if (currentTag) {
419
+ this.processJSDocTag(result, currentTag, currentTagText.join(' '));
420
+ }
421
+ return result;
422
+ }
423
+ /**
424
+ * 处理单个 JSDoc tag
425
+ */
426
+ processJSDocTag(result, tagName, tagText) {
427
+ switch (tagName) {
428
+ case 'param': {
429
+ const paramMatch = tagText.match(/^\{([^}]+)\}\s+(\w+)(?:\s+-\s*(.*))?$/);
430
+ if (paramMatch) {
431
+ result.params.push({
432
+ type: paramMatch[1],
433
+ name: paramMatch[2],
434
+ description: paramMatch[3]
435
+ });
436
+ }
437
+ else {
438
+ const simpleMatch = tagText.match(/^(\w+)(?:\s+-\s*(.*))?$/);
439
+ if (simpleMatch) {
440
+ result.params.push({
441
+ name: simpleMatch[1],
442
+ description: simpleMatch[2]
443
+ });
444
+ }
445
+ }
446
+ break;
447
+ }
448
+ case 'returns':
449
+ case 'return': {
450
+ const returnMatch = tagText.match(/^\{([^}]+)\}(?:\s+-\s*(.*))?$/);
451
+ if (returnMatch) {
452
+ result.returns = {
453
+ type: returnMatch[1],
454
+ description: returnMatch[2]
455
+ };
456
+ }
457
+ else {
458
+ result.returns = { description: tagText };
459
+ }
460
+ break;
461
+ }
462
+ case 'example':
463
+ result.examples.push(tagText);
464
+ break;
465
+ case 'deprecated':
466
+ result.deprecated = tagText;
467
+ break;
468
+ case 'since':
469
+ result.since = tagText;
470
+ break;
471
+ case 'see':
472
+ result.see.push(tagText);
473
+ break;
474
+ default:
475
+ result.tags.push({ name: tagName, text: tagText });
476
+ }
477
+ }
478
+ /**
479
+ * 提取函数签名 - 增强版,包含调用关系
480
+ */
481
+ extractFunctionSignature(node, sourceFile) {
482
+ const parameters = [];
483
+ for (const param of node.parameters) {
484
+ if (ts.isIdentifier(param.name)) {
485
+ parameters.push({
486
+ name: param.name.text,
487
+ type: param.type?.getText() || 'any',
488
+ optional: !!param.questionToken || !!param.initializer,
489
+ defaultValue: param.initializer?.getText()
490
+ });
491
+ }
492
+ }
493
+ const returnType = node.type?.getText() || 'void';
494
+ const async = !!(node.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword));
495
+ // 提取泛型参数
496
+ const genericParams = node.typeParameters?.map((tp) => {
497
+ let text = tp.name.text;
498
+ if (tp.constraint) {
499
+ text += ` extends ${tp.constraint.getText()}`;
500
+ }
501
+ if (tp.default) {
502
+ text += ` = ${tp.default.getText()}`;
503
+ }
504
+ return text;
505
+ });
506
+ // 提取函数体内的调用
507
+ const calls = this.extractCallsFromFunction(node, sourceFile);
508
+ // 提取关键代码片段
509
+ const bodySnippets = this.extractBodySnippets(node, sourceFile);
510
+ return {
511
+ parameters,
512
+ returnType,
513
+ async,
514
+ genericParams: genericParams?.length > 0 ? genericParams : undefined,
515
+ calls: calls.length > 0 ? calls : undefined,
516
+ bodySnippets: bodySnippets.length > 0 ? bodySnippets : undefined
517
+ };
518
+ }
519
+ /**
520
+ * 从函数体内提取调用
521
+ */
522
+ extractCallsFromFunction(node, sourceFile) {
523
+ const calls = [];
524
+ const body = node.body;
525
+ if (!body)
526
+ return calls;
527
+ const visit = (n) => {
528
+ if (ts.isCallExpression(n)) {
529
+ const callee = this.extractCalleeName(n, sourceFile);
530
+ if (callee) {
531
+ const pos = sourceFile.getLineAndCharacterOfPosition(n.getStart());
532
+ calls.push({
533
+ callee,
534
+ line: pos.line + 1,
535
+ column: pos.character + 1
536
+ });
537
+ }
538
+ }
539
+ ts.forEachChild(n, visit);
540
+ };
541
+ visit(body);
542
+ return calls;
543
+ }
544
+ /**
545
+ * 提取函数体关键代码片段
546
+ *
547
+ * 参考 Repomix 的 --compress 模式:
548
+ * - 保留控制流结构(if/loop/try/switch)
549
+ * - 省略实现细节,用 // ⋮ 标记
550
+ * - 提取 guard clauses 和早期返回
551
+ */
552
+ extractBodySnippets(node, sourceFile) {
553
+ const snippets = [];
554
+ const body = node.body;
555
+ if (!body)
556
+ return snippets;
557
+ const addSnippet = (type, node, description) => {
558
+ const start = node.getStart();
559
+ const end = node.getEnd();
560
+ const startPos = sourceFile.getLineAndCharacterOfPosition(start);
561
+ const endPos = sourceFile.getLineAndCharacterOfPosition(end);
562
+ // 提取代码并压缩
563
+ const originalCode = node.getText(sourceFile);
564
+ const compressedCode = this.compressCode(originalCode, type);
565
+ snippets.push({
566
+ type,
567
+ lines: compressedCode,
568
+ lineStart: startPos.line + 1,
569
+ lineEnd: endPos.line + 1,
570
+ description
571
+ });
572
+ };
573
+ const visit = (n) => {
574
+ // 检查是否为顶层语句(函数体直接子节点)
575
+ const isTopLevel = n.parent === body ||
576
+ (ts.isBlock(n.parent) && n.parent.parent === body);
577
+ if (ts.isIfStatement(n)) {
578
+ // 检查是否是 guard clause(早期返回)
579
+ if (this.isGuardClause(n)) {
580
+ addSnippet('guard', n, 'Guard clause');
581
+ }
582
+ else {
583
+ addSnippet('if', n);
584
+ }
585
+ }
586
+ else if (ts.isForStatement(n) || ts.isForInStatement(n) ||
587
+ ts.isForOfStatement(n) || ts.isWhileStatement(n) ||
588
+ ts.isDoStatement(n)) {
589
+ addSnippet('loop', n);
590
+ }
591
+ else if (ts.isTryStatement(n)) {
592
+ addSnippet('try', n);
593
+ }
594
+ else if (ts.isSwitchStatement(n)) {
595
+ addSnippet('switch', n);
596
+ }
597
+ else if (isTopLevel && ts.isReturnStatement(n)) {
598
+ // 顶层返回语句(非 guard clause 的返回)
599
+ addSnippet('early-return', n, 'Return statement');
600
+ }
601
+ // 递归访问子节点,但不进入嵌套函数
602
+ if (!ts.isFunctionDeclaration(n) &&
603
+ !ts.isArrowFunction(n) &&
604
+ !ts.isMethodDeclaration(n)) {
605
+ ts.forEachChild(n, visit);
606
+ }
607
+ };
608
+ visit(body);
609
+ return snippets;
610
+ }
611
+ /**
612
+ * 检查是否是 guard clause(早期返回)
613
+ */
614
+ isGuardClause(node) {
615
+ // Guard clause 特征:
616
+ // 1. if 条件在函数开始位置
617
+ // 2. 只有 then 分支,没有 else
618
+ // 3. then 分支包含 return 或 throw
619
+ if (node.elseStatement)
620
+ return false;
621
+ const thenStatement = node.thenStatement;
622
+ if (ts.isBlock(thenStatement)) {
623
+ // 检查块中的第一个语句是否是 return/throw
624
+ const firstStatement = thenStatement.statements[0];
625
+ if (firstStatement && (ts.isReturnStatement(firstStatement) || ts.isThrowStatement(firstStatement))) {
626
+ return true;
627
+ }
628
+ }
629
+ else if (ts.isReturnStatement(thenStatement) || ts.isThrowStatement(thenStatement)) {
630
+ return true;
631
+ }
632
+ return false;
633
+ }
634
+ /**
635
+ * 压缩代码(保留结构,省略实现)
636
+ *
637
+ * 参考 Repomix 风格:
638
+ * if (condition) {
639
+ * // ⋮ implementation
640
+ * }
641
+ */
642
+ compressCode(code, type) {
643
+ const lines = code.split('\n');
644
+ if (lines.length <= 3) {
645
+ // 短代码不压缩
646
+ return code.trim();
647
+ }
648
+ switch (type) {
649
+ case 'if':
650
+ case 'guard': {
651
+ // 提取 if 条件
652
+ const conditionMatch = code.match(/if\s*\(([^)]+)\)/);
653
+ if (conditionMatch) {
654
+ const condition = conditionMatch[1].trim();
655
+ // 检查是否有 return/throw
656
+ const hasReturn = code.includes('return');
657
+ const hasThrow = code.includes('throw');
658
+ const action = hasReturn ? 'return' : (hasThrow ? 'throw' : '{ ... }');
659
+ return `if (${condition}) { // ⋮ ${action} }`;
660
+ }
661
+ return `if (...) { // ⋮ }`;
662
+ }
663
+ case 'loop': {
664
+ // 提取循环类型和条件
665
+ if (code.includes('for')) {
666
+ const forMatch = code.match(/for\s*\(([^)]+)\)/);
667
+ if (forMatch) {
668
+ return `for (${forMatch[1].trim()}) { // ⋮ }`;
669
+ }
670
+ return `for (...) { // ⋮ }`;
671
+ }
672
+ else if (code.includes('while')) {
673
+ const whileMatch = code.match(/while\s*\(([^)]+)\)/);
674
+ if (whileMatch) {
675
+ return `while (${whileMatch[1].trim()}) { // ⋮ }`;
676
+ }
677
+ return `while (...) { // ⋮ }`;
678
+ }
679
+ return `loop { // ⋮ }`;
680
+ }
681
+ case 'try': {
682
+ return `try { // ⋮ } catch (...) { // ⋮ }`;
683
+ }
684
+ case 'switch': {
685
+ // 提取 case 名称
686
+ const caseMatches = code.match(/case\s+([^:]+):/g);
687
+ if (caseMatches && caseMatches.length > 0) {
688
+ const cases = caseMatches.map(c => c.replace(/case\s+/, '').replace(':', '')).slice(0, 3);
689
+ return `switch (...) { case ${cases.join(', ')}${caseMatches.length > 3 ? '...' : ''} // ⋮ }`;
690
+ }
691
+ return `switch (...) { // ⋮ }`;
692
+ }
693
+ case 'early-return': {
694
+ // 返回语句不压缩
695
+ return code.trim();
696
+ }
697
+ default:
698
+ return code.substring(0, 100) + (code.length > 100 ? '...' : '');
699
+ }
700
+ }
701
+ /**
702
+ * 提取类成员
703
+ */
704
+ extractClassMembers(node, sourceFile) {
705
+ const members = [];
706
+ for (const member of node.members) {
707
+ if (ts.isMethodDeclaration(member) && member.name) {
708
+ const name = this.getMemberName(member.name);
709
+ if (name) {
710
+ const signature = this.extractFunctionSignature(member, sourceFile);
711
+ members.push({
712
+ name,
713
+ kind: 'method',
714
+ type: signature?.returnType || 'void',
715
+ visibility: this.getVisibility(member),
716
+ optional: !!member.questionToken,
717
+ static: this.isStatic(member),
718
+ abstract: this.isAbstract(member),
719
+ signature
720
+ });
721
+ }
722
+ }
723
+ else if (ts.isPropertyDeclaration(member) && member.name) {
724
+ const name = this.getMemberName(member.name);
725
+ if (name) {
726
+ members.push({
727
+ name,
728
+ kind: 'property',
729
+ type: member.type?.getText(sourceFile) || 'any',
730
+ visibility: this.getVisibility(member),
731
+ optional: !!member.questionToken,
732
+ static: this.isStatic(member),
733
+ abstract: this.isAbstract(member),
734
+ readonly: this.isReadonly(member)
735
+ });
736
+ }
737
+ }
738
+ else if (ts.isGetAccessorDeclaration(member) && member.name) {
739
+ const name = this.getMemberName(member.name);
740
+ if (name) {
741
+ members.push({
742
+ name,
743
+ kind: 'getter',
744
+ type: member.type?.getText(sourceFile) || 'any',
745
+ visibility: this.getVisibility(member),
746
+ optional: false,
747
+ static: this.isStatic(member)
748
+ });
749
+ }
750
+ }
751
+ else if (ts.isSetAccessorDeclaration(member) && member.name) {
752
+ const name = this.getMemberName(member.name);
753
+ if (name) {
754
+ members.push({
755
+ name,
756
+ kind: 'setter',
757
+ type: member.parameters[0]?.type?.getText(sourceFile) || 'any',
758
+ visibility: this.getVisibility(member),
759
+ optional: false,
760
+ static: this.isStatic(member)
761
+ });
762
+ }
763
+ }
764
+ }
765
+ return members;
766
+ }
767
+ /**
768
+ * 提取接口成员
769
+ */
770
+ extractInterfaceMembers(node, sourceFile) {
771
+ const members = [];
772
+ for (const member of node.members) {
773
+ if (ts.isPropertySignature(member) && member.name) {
774
+ const name = this.getMemberName(member.name);
775
+ if (name) {
776
+ members.push({
777
+ name,
778
+ kind: 'property',
779
+ type: member.type?.getText(sourceFile) || 'any',
780
+ visibility: 'public',
781
+ optional: !!member.questionToken
782
+ });
783
+ }
784
+ }
785
+ else if (ts.isMethodSignature(member) && member.name) {
786
+ const name = this.getMemberName(member.name);
787
+ if (name) {
788
+ const parameters = [];
789
+ for (const param of member.parameters) {
790
+ if (ts.isIdentifier(param.name)) {
791
+ parameters.push({
792
+ name: param.name.text,
793
+ type: param.type?.getText(sourceFile) || 'any',
794
+ optional: !!param.questionToken
795
+ });
796
+ }
797
+ }
798
+ members.push({
799
+ name,
800
+ kind: 'method',
801
+ type: member.type?.getText(sourceFile) || 'void',
802
+ visibility: 'public',
803
+ optional: !!member.questionToken,
804
+ signature: {
805
+ parameters,
806
+ returnType: member.type?.getText(sourceFile) || 'void',
807
+ async: false
808
+ }
809
+ });
810
+ }
811
+ }
812
+ }
813
+ return members;
814
+ }
815
+ /**
816
+ * 获取成员名称
817
+ */
818
+ getMemberName(name) {
819
+ if (ts.isIdentifier(name))
820
+ return name.text;
821
+ if (ts.isStringLiteral(name))
822
+ return name.text;
823
+ if (ts.isNumericLiteral(name))
824
+ return name.text;
825
+ return null;
826
+ }
827
+ /**
828
+ * 获取可见性
829
+ */
830
+ getVisibility(node) {
831
+ const modifiers = node.modifiers;
832
+ if (!modifiers)
833
+ return 'public';
834
+ for (const modifier of modifiers) {
835
+ if (modifier.kind === ts.SyntaxKind.PrivateKeyword)
836
+ return 'private';
837
+ if (modifier.kind === ts.SyntaxKind.ProtectedKeyword)
838
+ return 'protected';
839
+ if (modifier.kind === ts.SyntaxKind.PublicKeyword)
840
+ return 'public';
841
+ }
842
+ return 'public';
843
+ }
844
+ /**
845
+ * 检查是否为 static
846
+ */
847
+ isStatic(node) {
848
+ const modifiers = node.modifiers;
849
+ return modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword) || false;
850
+ }
851
+ /**
852
+ * 检查是否为 abstract
853
+ */
854
+ isAbstract(node) {
855
+ const modifiers = node.modifiers;
856
+ return modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) || false;
857
+ }
858
+ /**
859
+ * 检查是否为 readonly
860
+ */
861
+ isReadonly(node) {
862
+ const modifiers = node.modifiers;
863
+ return modifiers?.some((m) => m.kind === ts.SyntaxKind.ReadonlyKeyword) || false;
864
+ }
865
+ /**
866
+ * 提取装饰器信息
867
+ */
868
+ extractDecorators(node, kind) {
869
+ const decorators = [];
870
+ // 直接检查节点的 modifiers 属性
871
+ const modifiers = node.modifiers;
872
+ if (!modifiers || !Array.isArray(modifiers))
873
+ return decorators;
874
+ for (const modifier of modifiers) {
875
+ if (modifier.kind === ts.SyntaxKind.Decorator) {
876
+ const decorator = modifier;
877
+ const decoratorInfo = this.parseDecorator(decorator, kind);
878
+ if (decoratorInfo) {
879
+ decorators.push(decoratorInfo);
880
+ }
881
+ }
882
+ }
883
+ return decorators;
884
+ }
885
+ /**
886
+ * 解析装饰器,获取名称和参数
887
+ */
888
+ parseDecorator(decorator, targetKind) {
889
+ let decoratorName = '';
890
+ let params = undefined;
891
+ // 获取装饰器表达式
892
+ const expr = decorator.expression;
893
+ if (ts.isCallExpression(expr)) {
894
+ // 处理带参数的装饰器,如 @Component({...})
895
+ const callee = expr.expression;
896
+ if (ts.isIdentifier(callee)) {
897
+ decoratorName = callee.text;
898
+ }
899
+ // 解析参数
900
+ if (expr.arguments.length > 0) {
901
+ const firstArg = expr.arguments[0];
902
+ params = this.parseDecoratorArg(firstArg);
903
+ }
904
+ }
905
+ else if (ts.isIdentifier(expr)) {
906
+ // 处理不带参数的装饰器,如 @Injectable
907
+ decoratorName = expr.text;
908
+ }
909
+ // 确定装饰器目标类型
910
+ let target = 'class';
911
+ if (targetKind === 'method') {
912
+ target = 'method';
913
+ }
914
+ else if (targetKind === 'property') {
915
+ target = 'property';
916
+ }
917
+ else if (targetKind === 'parameter') {
918
+ target = 'parameter';
919
+ }
920
+ return {
921
+ name: decoratorName,
922
+ params,
923
+ target
924
+ };
925
+ }
926
+ /**
927
+ * 解析装饰器参数
928
+ */
929
+ parseDecoratorArg(arg) {
930
+ // 处理对象字面量
931
+ if (ts.isObjectLiteralExpression(arg)) {
932
+ const result = {};
933
+ for (const prop of arg.properties) {
934
+ if (ts.isPropertyAssignment(prop)) {
935
+ const key = prop.name.getText();
936
+ const value = this.parseExpression(prop.initializer);
937
+ result[key] = value;
938
+ }
939
+ }
940
+ return result;
941
+ }
942
+ // 处理字符串字面量
943
+ if (ts.isStringLiteral(arg)) {
944
+ return arg.text;
945
+ }
946
+ // 处理数字字面量
947
+ if (ts.isNumericLiteral(arg)) {
948
+ return Number(arg.text);
949
+ }
950
+ // 处理布尔字面量
951
+ if (arg.kind === ts.SyntaxKind.TrueKeyword || arg.kind === ts.SyntaxKind.FalseKeyword) {
952
+ return arg.kind === ts.SyntaxKind.TrueKeyword;
953
+ }
954
+ // 处理 null 字面量
955
+ if (arg.kind === ts.SyntaxKind.NullKeyword) {
956
+ return null;
957
+ }
958
+ // 处理标识符(如 true, false, null, undefined)
959
+ if (ts.isIdentifier(arg)) {
960
+ const text = arg.text;
961
+ if (text === 'true')
962
+ return true;
963
+ if (text === 'false')
964
+ return false;
965
+ if (text === 'null')
966
+ return null;
967
+ if (text === 'undefined')
968
+ return undefined;
969
+ return text;
970
+ }
971
+ // 处理数组字面量
972
+ if (ts.isArrayLiteralExpression(arg)) {
973
+ return arg.elements.map(elem => this.parseDecoratorArg(elem));
974
+ }
975
+ return undefined;
976
+ }
977
+ /**
978
+ * 解析表达式为 JavaScript 值
979
+ */
980
+ parseExpression(expr) {
981
+ if (ts.isStringLiteral(expr))
982
+ return expr.text;
983
+ if (ts.isNumericLiteral(expr))
984
+ return Number(expr.text);
985
+ if (expr.kind === ts.SyntaxKind.TrueKeyword || expr.kind === ts.SyntaxKind.FalseKeyword) {
986
+ return expr.kind === ts.SyntaxKind.TrueKeyword;
987
+ }
988
+ if (expr.kind === ts.SyntaxKind.NullKeyword)
989
+ return null;
990
+ if (ts.isIdentifier(expr))
991
+ return expr.text;
992
+ if (ts.isArrayLiteralExpression(expr))
993
+ return expr.elements.map(elem => this.parseExpression(elem));
994
+ if (ts.isObjectLiteralExpression(expr)) {
995
+ const result = {};
996
+ for (const prop of expr.properties) {
997
+ if (ts.isPropertyAssignment(prop)) {
998
+ const key = prop.name.getText();
999
+ result[key] = this.parseExpression(prop.initializer);
1000
+ }
1001
+ }
1002
+ return result;
1003
+ }
1004
+ return expr.getText();
1005
+ }
1006
+ /**
1007
+ * 提取依赖列表
1008
+ */
1009
+ extractDependencies(imports, exports) {
1010
+ const deps = new Set();
1011
+ // 收集所有 import 依赖
1012
+ for (const imp of imports) {
1013
+ deps.add(imp.source);
1014
+ }
1015
+ // 处理 re-export 依赖 (export { foo } from './module')
1016
+ if (exports) {
1017
+ for (const exp of exports) {
1018
+ if (exp.origin) {
1019
+ deps.add(exp.origin);
1020
+ }
1021
+ }
1022
+ }
1023
+ return Array.from(deps);
1024
+ }
1025
+ /**
1026
+ * 提取类型信息 - 增强版
1027
+ */
1028
+ extractTypeInfo(sourceFile) {
1029
+ const typeDefinitions = [];
1030
+ const genericParams = [];
1031
+ const crossFileRefs = [];
1032
+ const unionTypes = [];
1033
+ const intersectionTypes = [];
1034
+ const typeAliases = [];
1035
+ // 复杂类型信息
1036
+ const conditionalTypes = [];
1037
+ const mappedTypes = [];
1038
+ const templateLiteralTypes = [];
1039
+ const indexedAccessTypes = [];
1040
+ const inferredTypes = [];
1041
+ const visit = (node) => {
1042
+ // 提取接口
1043
+ if (ts.isInterfaceDeclaration(node) && node.name) {
1044
+ const members = node.members.map(m => ({
1045
+ name: m.name?.getText(sourceFile) || 'unknown',
1046
+ type: this.getTypeFromMember(m, sourceFile),
1047
+ optional: m.questionToken ? true : false,
1048
+ visibility: 'public',
1049
+ isReadonly: m.modifiers?.some((mod) => mod.kind === ts.SyntaxKind.ReadonlyKeyword) || false
1050
+ }));
1051
+ const extendsList = node.heritageClauses
1052
+ ?.flatMap(clause => clause.types.map(t => t.getText(sourceFile))) || [];
1053
+ const genericParamsList = node.typeParameters
1054
+ ?.map(tp => ({
1055
+ name: tp.name.text,
1056
+ extends: tp.constraint?.getText(sourceFile),
1057
+ default: tp.default?.getText(sourceFile)
1058
+ })) || [];
1059
+ typeDefinitions.push({
1060
+ name: node.name.text,
1061
+ kind: 'interface',
1062
+ members,
1063
+ extends: extendsList,
1064
+ genericParams: genericParamsList
1065
+ });
1066
+ // 添加泛型参数
1067
+ genericParams.push(...genericParamsList);
1068
+ }
1069
+ // 提取类型别名
1070
+ if (ts.isTypeAliasDeclaration(node) && node.name) {
1071
+ const genericParamsList = node.typeParameters
1072
+ ?.map(tp => ({
1073
+ name: tp.name.text,
1074
+ extends: tp.constraint?.getText(sourceFile),
1075
+ default: tp.default?.getText(sourceFile)
1076
+ })) || [];
1077
+ typeAliases.push({
1078
+ name: node.name.text,
1079
+ type: node.type.getText(sourceFile),
1080
+ genericParams: genericParamsList
1081
+ });
1082
+ typeDefinitions.push({
1083
+ name: node.name.text,
1084
+ kind: 'alias',
1085
+ members: [],
1086
+ genericParams: genericParamsList
1087
+ });
1088
+ }
1089
+ // 提取类
1090
+ if (ts.isClassDeclaration(node) && node.name) {
1091
+ const members = node.members
1092
+ .filter(m => ts.isPropertyDeclaration(m) || ts.isMethodDeclaration(m))
1093
+ .map(m => ({
1094
+ name: m.name ? m.name.getText(sourceFile) : 'unknown',
1095
+ type: m.kind === ts.SyntaxKind.MethodDeclaration
1096
+ ? 'method'
1097
+ : this.getTypeFromMember(m, sourceFile),
1098
+ optional: m.questionToken ? true : false,
1099
+ visibility: this.getVisibility(m),
1100
+ isReadonly: m.modifiers?.some((mod) => mod.kind === ts.SyntaxKind.ReadonlyKeyword) || false
1101
+ }));
1102
+ const extendsList = node.heritageClauses
1103
+ ?.filter(c => c.token === ts.SyntaxKind.ExtendsKeyword)
1104
+ .flatMap(clause => clause.types.map(t => t.getText(sourceFile))) || [];
1105
+ const implementsList = node.heritageClauses
1106
+ ?.filter(c => c.token === ts.SyntaxKind.ImplementsKeyword)
1107
+ .flatMap(clause => clause.types.map(t => t.getText(sourceFile))) || [];
1108
+ const genericParamsList = node.typeParameters
1109
+ ?.map(tp => ({
1110
+ name: tp.name.text,
1111
+ extends: tp.constraint?.getText(sourceFile),
1112
+ default: tp.default?.getText(sourceFile)
1113
+ })) || [];
1114
+ typeDefinitions.push({
1115
+ name: node.name.text,
1116
+ kind: 'class',
1117
+ members,
1118
+ extends: extendsList,
1119
+ implements: implementsList,
1120
+ genericParams: genericParamsList
1121
+ });
1122
+ }
1123
+ // 提取枚举
1124
+ if (ts.isEnumDeclaration(node) && node.name) {
1125
+ const members = node.members.map((m, idx) => ({
1126
+ name: m.name.getText(sourceFile),
1127
+ type: m.initializer ? m.initializer.getText(sourceFile) : String(idx),
1128
+ optional: false,
1129
+ visibility: 'public'
1130
+ }));
1131
+ typeDefinitions.push({
1132
+ name: node.name.text,
1133
+ kind: 'enum',
1134
+ members
1135
+ });
1136
+ }
1137
+ // 提取联合类型
1138
+ if (ts.isUnionTypeNode(node)) {
1139
+ unionTypes.push(node.getText(sourceFile));
1140
+ }
1141
+ // 提取交叉类型
1142
+ if (ts.isIntersectionTypeNode(node)) {
1143
+ intersectionTypes.push(node.getText(sourceFile));
1144
+ }
1145
+ // 提取跨文件引用(从类型引用中)
1146
+ if (ts.isTypeReferenceNode(node) && node.typeName) {
1147
+ const typeName = node.typeName.getText(sourceFile);
1148
+ if (!typeName.startsWith('_') && typeName[0] === typeName[0].toUpperCase()) {
1149
+ const pos = sourceFile.getLineAndCharacterOfPosition(node.getStart());
1150
+ crossFileRefs.push({
1151
+ symbol: typeName,
1152
+ file: sourceFile.fileName,
1153
+ line: pos.line + 1,
1154
+ column: pos.character + 1
1155
+ });
1156
+ }
1157
+ }
1158
+ // 提取条件类型 T extends U ? X : Y
1159
+ if (ts.isConditionalTypeNode(node)) {
1160
+ conditionalTypes.push({
1161
+ checkType: node.checkType.getText(sourceFile),
1162
+ extendsType: node.extendsType.getText(sourceFile),
1163
+ trueType: node.trueType.getText(sourceFile),
1164
+ falseType: node.falseType.getText(sourceFile)
1165
+ });
1166
+ }
1167
+ // 提取映射类型 [K in keyof T]: T[K]
1168
+ if (ts.isMappedTypeNode(node)) {
1169
+ const typeParam = node.typeParameter;
1170
+ const nameType = node.nameType;
1171
+ mappedTypes.push({
1172
+ typeParameter: typeParam.name.text,
1173
+ constraint: typeParam.constraint?.getText(sourceFile) || '',
1174
+ valueType: node.type?.getText(sourceFile) || 'unknown',
1175
+ asType: nameType?.getText(sourceFile),
1176
+ readonly: node.readonlyToken ?
1177
+ (node.readonlyToken.kind === ts.SyntaxKind.ReadonlyKeyword ? 'add' : 'remove') : undefined,
1178
+ optional: node.questionToken ?
1179
+ (node.questionToken.kind === ts.SyntaxKind.QuestionToken ? 'add' : 'remove') : undefined
1180
+ });
1181
+ }
1182
+ // 提取模板字面量类型
1183
+ if (ts.isTemplateLiteralTypeNode(node)) {
1184
+ const spans = node.templateSpans.map(span => ({
1185
+ type: span.type.getText(sourceFile),
1186
+ literal: span.literal.text
1187
+ }));
1188
+ templateLiteralTypes.push({
1189
+ head: node.head.text,
1190
+ spans
1191
+ });
1192
+ }
1193
+ // 提取索引访问类型 T[K]
1194
+ if (ts.isIndexedAccessTypeNode(node)) {
1195
+ indexedAccessTypes.push(node.getText(sourceFile));
1196
+ }
1197
+ // 提取 infer 类型
1198
+ if (ts.isInferTypeNode(node)) {
1199
+ inferredTypes.push(node.typeParameter.name.text);
1200
+ }
1201
+ ts.forEachChild(node, visit);
1202
+ };
1203
+ visit(sourceFile);
1204
+ return {
1205
+ typeDefinitions,
1206
+ genericParams,
1207
+ crossFileRefs,
1208
+ unionTypes,
1209
+ intersectionTypes,
1210
+ typeAliases,
1211
+ conditionalTypes,
1212
+ mappedTypes,
1213
+ templateLiteralTypes,
1214
+ indexedAccessTypes,
1215
+ inferredTypes
1216
+ };
1217
+ }
1218
+ /**
1219
+ * 从成员获取类型
1220
+ */
1221
+ getTypeFromMember(member, sourceFile) {
1222
+ if (ts.isPropertySignature(member) && member.type) {
1223
+ return member.type.getText(sourceFile);
1224
+ }
1225
+ if (ts.isMethodSignature(member)) {
1226
+ return 'method';
1227
+ }
1228
+ return 'any';
1229
+ }
1230
+ /**
1231
+ * 提取调用图 - 增强版
1232
+ */
1233
+ extractCallGraph(sourceFile) {
1234
+ const calls = [];
1235
+ const recursive = [];
1236
+ const callCounts = {};
1237
+ // 收集所有函数/方法名
1238
+ const functionNames = new Set();
1239
+ const collectNames = (node) => {
1240
+ if (ts.isFunctionDeclaration(node) && node.name) {
1241
+ functionNames.add(node.name.text);
1242
+ }
1243
+ else if (ts.isClassDeclaration(node) && node.name) {
1244
+ // 收集类方法名
1245
+ for (const member of node.members) {
1246
+ if (ts.isMethodDeclaration(member) && member.name) {
1247
+ const methodName = this.getMemberName(member.name);
1248
+ if (methodName) {
1249
+ functionNames.add(`${node.name.text}.${methodName}`);
1250
+ }
1251
+ }
1252
+ }
1253
+ }
1254
+ ts.forEachChild(node, collectNames);
1255
+ };
1256
+ collectNames(sourceFile);
1257
+ // 提取调用关系
1258
+ const extractCalls = (node, funcName) => {
1259
+ callCounts[funcName] = 0;
1260
+ const visit = (n) => {
1261
+ if (ts.isCallExpression(n)) {
1262
+ const callee = this.extractCalleeName(n, sourceFile);
1263
+ if (callee) {
1264
+ calls.push({
1265
+ caller: funcName,
1266
+ callee,
1267
+ line: n.getStart()
1268
+ });
1269
+ callCounts[funcName] = (callCounts[funcName] || 0) + 1;
1270
+ // 检查是否递归调用
1271
+ if (callee === funcName || callee.endsWith(`.${funcName}`)) {
1272
+ if (!recursive.includes(funcName)) {
1273
+ recursive.push(funcName);
1274
+ }
1275
+ }
1276
+ }
1277
+ }
1278
+ ts.forEachChild(n, visit);
1279
+ };
1280
+ // 根据节点类型获取函数体
1281
+ let body;
1282
+ if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node) || ts.isArrowFunction(node)) {
1283
+ body = node.body;
1284
+ }
1285
+ else if (ts.isFunctionExpression(node)) {
1286
+ body = node.body;
1287
+ }
1288
+ if (body) {
1289
+ visit(body);
1290
+ }
1291
+ };
1292
+ // 处理函数声明
1293
+ const processFunction = (node) => {
1294
+ if (ts.isFunctionDeclaration(node) && node.name) {
1295
+ extractCalls(node, node.name.text);
1296
+ }
1297
+ else if (ts.isClassDeclaration(node)) {
1298
+ // 处理类方法
1299
+ for (const member of node.members) {
1300
+ if (ts.isMethodDeclaration(member) && member.name && node.name) {
1301
+ const methodName = this.getMemberName(member.name);
1302
+ if (methodName) {
1303
+ extractCalls(member, `${node.name.text}.${methodName}`);
1304
+ }
1305
+ }
1306
+ }
1307
+ }
1308
+ };
1309
+ ts.forEachChild(sourceFile, processFunction);
1310
+ return { calls, recursive, callCounts };
1311
+ }
1312
+ /**
1313
+ * 提取被调用函数的名称
1314
+ */
1315
+ extractCalleeName(callExpr, sourceFile) {
1316
+ const expr = callExpr.expression;
1317
+ if (ts.isIdentifier(expr)) {
1318
+ // 简单函数调用:funcName()
1319
+ return expr.text;
1320
+ }
1321
+ else if (ts.isPropertyAccessExpression(expr)) {
1322
+ // 方法调用:obj.method() 或 Class.staticMethod()
1323
+ return expr.getText(sourceFile);
1324
+ }
1325
+ else if (ts.isElementAccessExpression(expr)) {
1326
+ // 数组/索引调用:arr[0]()
1327
+ return expr.getText(sourceFile);
1328
+ }
1329
+ return null;
1330
+ }
1331
+ /**
1332
+ * 计算复杂度
1333
+ */
1334
+ calculateComplexity(sourceFile, content) {
1335
+ let cyclomatic = 1;
1336
+ let cognitive = 0;
1337
+ const details = [];
1338
+ const visit = (node, depth) => {
1339
+ let funcName;
1340
+ let funcNode;
1341
+ if (ts.isFunctionDeclaration(node) && node.name) {
1342
+ funcName = node.name.text;
1343
+ funcNode = node;
1344
+ }
1345
+ else if (ts.isMethodDeclaration(node) && node.name) {
1346
+ // 获取方法名
1347
+ const methodName = node.name;
1348
+ if (ts.isIdentifier(methodName)) {
1349
+ funcName = methodName.text;
1350
+ }
1351
+ else if (ts.isStringLiteral(methodName)) {
1352
+ funcName = methodName.text;
1353
+ }
1354
+ funcNode = node;
1355
+ }
1356
+ else if (ts.isArrowFunction(node)) {
1357
+ // 箭头函数通常没有名字,跳过详细信息但仍计算复杂度
1358
+ funcName = '(arrow)';
1359
+ funcNode = node;
1360
+ }
1361
+ if (funcNode && funcName) {
1362
+ const funcCyclomatic = this.calculateFunctionCyclomatic(funcNode);
1363
+ const funcCognitive = this.calculateFunctionCognitive(funcNode);
1364
+ cyclomatic += funcCyclomatic;
1365
+ cognitive += funcCognitive;
1366
+ // 只为有名字的函数添加详情
1367
+ if (funcName !== '(arrow)') {
1368
+ details.push({
1369
+ name: funcName,
1370
+ cyclomatic: funcCyclomatic,
1371
+ cognitive: funcCognitive,
1372
+ lines: funcNode.getEnd() - funcNode.getStart()
1373
+ });
1374
+ }
1375
+ }
1376
+ ts.forEachChild(node, n => visit(n, depth + 1));
1377
+ };
1378
+ visit(sourceFile, 0);
1379
+ // 计算代码行数和注释比例
1380
+ const lines = content.split('\n');
1381
+ let codeLines = 0;
1382
+ let commentLines = 0;
1383
+ for (const line of lines) {
1384
+ const trimmed = line.trim();
1385
+ if (trimmed === '')
1386
+ continue;
1387
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*')) {
1388
+ commentLines++;
1389
+ }
1390
+ else {
1391
+ codeLines++;
1392
+ }
1393
+ }
1394
+ const commentRatio = codeLines > 0 ? commentLines / (codeLines + commentLines) : 0;
1395
+ // 计算可维护性指数
1396
+ const maintainability = this.calculateMaintainabilityIndex(codeLines, cyclomatic, commentRatio);
1397
+ return {
1398
+ cyclomatic,
1399
+ cognitive,
1400
+ maintainability,
1401
+ details: { functions: details.slice(0, 10) }
1402
+ };
1403
+ }
1404
+ /**
1405
+ * 计算函数圈复杂度
1406
+ */
1407
+ calculateFunctionCyclomatic(node) {
1408
+ let complexity = 1;
1409
+ const countNodes = (n) => {
1410
+ if (ts.isIfStatement(n) || ts.isWhileStatement(n) ||
1411
+ ts.isForStatement(n) || ts.isForInStatement(n) ||
1412
+ ts.isForOfStatement(n) || ts.isCaseClause(n) ||
1413
+ ts.isCatchClause(n) || ts.isConditionalExpression(n)) {
1414
+ complexity++;
1415
+ }
1416
+ ts.forEachChild(n, countNodes);
1417
+ };
1418
+ // 获取函数体
1419
+ let body;
1420
+ if ('body' in node) {
1421
+ body = node.body;
1422
+ }
1423
+ if (body) {
1424
+ countNodes(body);
1425
+ }
1426
+ return complexity;
1427
+ }
1428
+ /**
1429
+ * 计算函数认知复杂度
1430
+ */
1431
+ calculateFunctionCognitive(node) {
1432
+ let cognitive = 0;
1433
+ const countNodes = (n, depth) => {
1434
+ cognitive += depth;
1435
+ if (ts.isIfStatement(n) || ts.isSwitchStatement(n)) {
1436
+ cognitive += 1;
1437
+ }
1438
+ if (ts.isTryStatement(n) || ts.isWithStatement(n)) {
1439
+ cognitive += 2;
1440
+ }
1441
+ ts.forEachChild(n, child => countNodes(child, depth + 1));
1442
+ };
1443
+ // 获取函数体
1444
+ let body;
1445
+ if ('body' in node) {
1446
+ body = node.body;
1447
+ }
1448
+ if (body) {
1449
+ countNodes(body, 0);
1450
+ }
1451
+ return cognitive;
1452
+ }
1453
+ /**
1454
+ * 计算可维护性指数 (Microsoft Maintainability Index)
1455
+ *
1456
+ * 基于微软的可维护性指数公式进行适应性调整:
1457
+ * MI = MAX(0, (171 - 5.2 * ln(Halstead Volume) - 0.23 * Cyclomatic - 16.2 * ln(LOC)) * 100 / 171)
1458
+ *
1459
+ * 简化版本(无需 Halstead Volume):
1460
+ * - 基于圈复杂度和代码行数计算
1461
+ * - 结果范围 0-100
1462
+ * - 考虑了文件大小和复杂度的平衡
1463
+ */
1464
+ calculateMaintainabilityIndex(loc, cyclomatic, commentRatio) {
1465
+ // 规范化输入
1466
+ const normalizedLOC = Math.max(1, loc);
1467
+ const normalizedCC = Math.max(1, cyclomatic);
1468
+ // 基础分 100
1469
+ let mi = 100;
1470
+ // 圈复杂度惩罚(每点复杂度减少2分)
1471
+ mi -= (normalizedCC - 1) * 2;
1472
+ // 代码行数惩罚(对数缩放,避免大文件过度惩罚)
1473
+ // 100行: -5分, 500行: -15分, 1000行: -20分
1474
+ mi -= Math.log(normalizedLOC / 10 + 1) * 5;
1475
+ // 注释奖励(最多+15分)
1476
+ mi += commentRatio * 15;
1477
+ // 确保结果在 0-100 范围内
1478
+ return Math.max(0, Math.min(100, Math.round(mi)));
1479
+ }
1480
+ /**
1481
+ * 获取模块类型
1482
+ */
1483
+ getModuleType(filePath) {
1484
+ const basename = path.basename(filePath);
1485
+ if (basename.includes('.test.') || basename.includes('.spec.')) {
1486
+ return 'test';
1487
+ }
1488
+ if (basename === 'tsconfig.json' || basename === 'jest.config.js') {
1489
+ return 'config';
1490
+ }
1491
+ if (basename.endsWith('.d.ts')) {
1492
+ return 'type';
1493
+ }
1494
+ return 'source';
1495
+ }
1496
+ /**
1497
+ * 获取文件统计
1498
+ */
1499
+ getFileStats(content) {
1500
+ const lines = content.split('\n');
1501
+ let codeLines = 0;
1502
+ let commentLines = 0;
1503
+ let blankLines = 0;
1504
+ for (const line of lines) {
1505
+ const trimmed = line.trim();
1506
+ if (trimmed === '') {
1507
+ blankLines++;
1508
+ }
1509
+ else if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*')) {
1510
+ commentLines++;
1511
+ }
1512
+ else {
1513
+ codeLines++;
1514
+ }
1515
+ }
1516
+ return {
1517
+ lines: lines.length,
1518
+ codeLines,
1519
+ commentLines,
1520
+ blankLines
1521
+ };
1522
+ }
1523
+ /**
1524
+ * 生成 ID
1525
+ */
1526
+ generateId(name) {
1527
+ let hash = 0;
1528
+ for (let i = 0; i < name.length; i++) {
1529
+ const char = name.charCodeAt(i);
1530
+ hash = ((hash << 5) - hash) + char;
1531
+ hash = hash & hash;
1532
+ }
1533
+ return Math.abs(hash).toString(36);
1534
+ }
1535
+ }
1536
+ //# sourceMappingURL=smart-parser.js.map