code-auditor-mcp 2.6.1 → 3.0.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 (347) hide show
  1. package/README.md +319 -147
  2. package/dist/analyzers/analyzerUtils.d.ts +13 -11
  3. package/dist/analyzers/analyzerUtils.d.ts.map +1 -1
  4. package/dist/analyzers/analyzerUtils.js +22 -56
  5. package/dist/analyzers/analyzerUtils.js.map +1 -1
  6. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
  7. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.d.ts.map +1 -1
  8. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.js.map +1 -1
  9. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  10. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  11. package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
  12. package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
  13. package/dist/analyzers/dataAccessAnalyzer.d.ts.map +1 -1
  14. package/dist/analyzers/dataAccessAnalyzer.js +50 -24
  15. package/dist/analyzers/dataAccessAnalyzer.js.map +1 -1
  16. package/dist/analyzers/documentationAnalyzer.d.ts +4 -1
  17. package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
  18. package/dist/analyzers/documentationAnalyzer.js +210 -111
  19. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  20. package/dist/analyzers/dryAnalyzer.d.ts.map +1 -1
  21. package/dist/analyzers/dryAnalyzer.js +190 -58
  22. package/dist/analyzers/dryAnalyzer.js.map +1 -1
  23. package/dist/analyzers/invariantsAnalyzer.d.ts +20 -0
  24. package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -0
  25. package/dist/analyzers/invariantsAnalyzer.js +148 -0
  26. package/dist/analyzers/invariantsAnalyzer.js.map +1 -0
  27. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  28. package/dist/analyzers/reactAnalyzer.js +2 -2
  29. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  30. package/dist/analyzers/schemaAnalyzer.d.ts +2 -0
  31. package/dist/analyzers/schemaAnalyzer.d.ts.map +1 -1
  32. package/dist/analyzers/schemaAnalyzer.js +306 -147
  33. package/dist/analyzers/schemaAnalyzer.js.map +1 -1
  34. package/dist/analyzers/solidAnalyzer.d.ts.map +1 -1
  35. package/dist/analyzers/solidAnalyzer.js +145 -119
  36. package/dist/analyzers/solidAnalyzer.js.map +1 -1
  37. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +3 -1
  38. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
  39. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +41 -1
  40. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  41. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  42. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +8 -8
  43. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  44. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  45. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +6 -6
  46. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  47. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  48. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  49. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +1 -1
  50. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  51. package/dist/api/index.js +1 -0
  52. package/dist/api/index.js.map +1 -1
  53. package/dist/auditRunner.d.ts.map +1 -1
  54. package/dist/auditRunner.js +367 -24
  55. package/dist/auditRunner.js.map +1 -1
  56. package/dist/cli.d.ts +1 -1
  57. package/dist/cli.d.ts.map +1 -1
  58. package/dist/cli.js +740 -18
  59. package/dist/cli.js.map +1 -1
  60. package/dist/codeIndexDB-enhanced.d.ts +35 -13
  61. package/dist/codeIndexDB-enhanced.d.ts.map +1 -1
  62. package/dist/codeIndexDB-enhanced.js +311 -214
  63. package/dist/codeIndexDB-enhanced.js.map +1 -1
  64. package/dist/codeIndexDB.d.ts +222 -0
  65. package/dist/codeIndexDB.d.ts.map +1 -0
  66. package/dist/codeIndexDB.js +2042 -0
  67. package/dist/codeIndexDB.js.map +1 -0
  68. package/dist/codeIndexService.d.ts.map +1 -1
  69. package/dist/codeIndexService.js.map +1 -1
  70. package/dist/componentScanner.d.ts +14 -8
  71. package/dist/componentScanner.d.ts.map +1 -1
  72. package/dist/componentScanner.js +136 -113
  73. package/dist/componentScanner.js.map +1 -1
  74. package/dist/config/configLoader.d.ts.map +1 -1
  75. package/dist/config/configLoader.js +10 -7
  76. package/dist/config/configLoader.js.map +1 -1
  77. package/dist/config/defaults.d.ts.map +1 -1
  78. package/dist/constants.js.map +1 -1
  79. package/dist/fingerprint.d.ts +15 -0
  80. package/dist/fingerprint.d.ts.map +1 -0
  81. package/dist/fingerprint.js +32 -0
  82. package/dist/fingerprint.js.map +1 -0
  83. package/dist/functionScanner.d.ts +5 -0
  84. package/dist/functionScanner.d.ts.map +1 -1
  85. package/dist/functionScanner.js +417 -341
  86. package/dist/functionScanner.js.map +1 -1
  87. package/dist/generators/AWSQConfigGenerator.d.ts.map +1 -1
  88. package/dist/generators/AiderConfigGenerator.d.ts.map +1 -1
  89. package/dist/generators/BaseConfigGenerator.d.ts.map +1 -1
  90. package/dist/generators/BaseConfigGenerator.js.map +1 -1
  91. package/dist/generators/ClaudeConfigGenerator.d.ts.map +1 -1
  92. package/dist/generators/ClineConfigGenerator.d.ts.map +1 -1
  93. package/dist/generators/CodeiumConfigGenerator.d.ts.map +1 -1
  94. package/dist/generators/ConfigGeneratorFactory.d.ts.map +1 -1
  95. package/dist/generators/ConfigGeneratorFactory.js.map +1 -1
  96. package/dist/generators/ContinueConfigGenerator.d.ts.map +1 -1
  97. package/dist/generators/CopilotConfigGenerator.d.ts.map +1 -1
  98. package/dist/generators/CursorConfigGenerator.d.ts.map +1 -1
  99. package/dist/generators/JetBrainsConfigGenerator.d.ts.map +1 -1
  100. package/dist/generators/VSCodeConfigGenerator.d.ts.map +1 -1
  101. package/dist/grammars/tree-sitter-go.wasm +0 -0
  102. package/dist/grammars/tree-sitter-javascript.wasm +0 -0
  103. package/dist/grammars/tree-sitter-tsx.wasm +0 -0
  104. package/dist/grammars/tree-sitter-typescript.wasm +0 -0
  105. package/dist/index.d.ts +1 -0
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +2 -1
  108. package/dist/index.js.map +1 -1
  109. package/dist/invariants/index.d.ts +9 -0
  110. package/dist/invariants/index.d.ts.map +1 -0
  111. package/dist/invariants/index.js +4 -0
  112. package/dist/invariants/index.js.map +1 -0
  113. package/dist/invariants/invariant-rules.schema.json +137 -0
  114. package/dist/invariants/ruleEngine.d.ts +32 -0
  115. package/dist/invariants/ruleEngine.d.ts.map +1 -0
  116. package/dist/invariants/ruleEngine.js +536 -0
  117. package/dist/invariants/ruleEngine.js.map +1 -0
  118. package/dist/invariants/ruleValidator.d.ts +17 -0
  119. package/dist/invariants/ruleValidator.d.ts.map +1 -0
  120. package/dist/invariants/ruleValidator.js +264 -0
  121. package/dist/invariants/ruleValidator.js.map +1 -0
  122. package/dist/invariants/types.d.ts +78 -0
  123. package/dist/invariants/types.d.ts.map +1 -0
  124. package/dist/invariants/types.js +5 -0
  125. package/dist/invariants/types.js.map +1 -0
  126. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
  127. package/dist/languages/LanguageOrchestrator.js.map +1 -1
  128. package/dist/languages/LanguageRegistry.d.ts.map +1 -1
  129. package/dist/languages/RuntimeManager.d.ts.map +1 -1
  130. package/dist/languages/RuntimeManager.js +1 -1
  131. package/dist/languages/RuntimeManager.js.map +1 -1
  132. package/dist/languages/UniversalAnalyzer.d.ts.map +1 -1
  133. package/dist/languages/UniversalAnalyzer.js.map +1 -1
  134. package/dist/languages/adapterBridge.d.ts +102 -0
  135. package/dist/languages/adapterBridge.d.ts.map +1 -0
  136. package/dist/languages/adapterBridge.js +382 -0
  137. package/dist/languages/adapterBridge.js.map +1 -0
  138. package/dist/languages/go/GoAdapter.d.ts +37 -26
  139. package/dist/languages/go/GoAdapter.d.ts.map +1 -1
  140. package/dist/languages/go/GoAdapter.js +560 -281
  141. package/dist/languages/go/GoAdapter.js.map +1 -1
  142. package/dist/languages/index.d.ts +5 -2
  143. package/dist/languages/index.d.ts.map +1 -1
  144. package/dist/languages/index.js +11 -9
  145. package/dist/languages/index.js.map +1 -1
  146. package/dist/languages/tree-sitter/converter.d.ts +43 -0
  147. package/dist/languages/tree-sitter/converter.d.ts.map +1 -0
  148. package/dist/languages/tree-sitter/converter.js +150 -0
  149. package/dist/languages/tree-sitter/converter.js.map +1 -0
  150. package/dist/languages/tree-sitter/parser.d.ts +36 -0
  151. package/dist/languages/tree-sitter/parser.d.ts.map +1 -0
  152. package/dist/languages/tree-sitter/parser.js +114 -0
  153. package/dist/languages/tree-sitter/parser.js.map +1 -0
  154. package/dist/languages/types.d.ts +11 -0
  155. package/dist/languages/types.d.ts.map +1 -1
  156. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +92 -0
  157. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -0
  158. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +951 -0
  159. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -0
  160. package/dist/mcp-tools/projectTasks.d.ts +80 -11
  161. package/dist/mcp-tools/projectTasks.d.ts.map +1 -1
  162. package/dist/mcp-tools/projectTasks.js +279 -13
  163. package/dist/mcp-tools/projectTasks.js.map +1 -1
  164. package/dist/mcp-tools/whitelistTools.d.ts +21 -21
  165. package/dist/mcp-tools/whitelistTools.d.ts.map +1 -1
  166. package/dist/mcp-tools/workflowGuide.d.ts.map +1 -1
  167. package/dist/mcp-tools/workflowGuide.js +130 -126
  168. package/dist/mcp-tools/workflowGuide.js.map +1 -1
  169. package/dist/mcp-tools-shared.d.ts.map +1 -1
  170. package/dist/mcp-tools-shared.js.map +1 -1
  171. package/dist/mcp-ui-simple.js +1 -1
  172. package/dist/mcp-ui-simple.js.map +1 -1
  173. package/dist/mcp.d.ts +1 -1
  174. package/dist/mcp.d.ts.map +1 -1
  175. package/dist/mcp.js +1455 -1132
  176. package/dist/mcp.js.map +1 -1
  177. package/dist/mcpAuditJobs.d.ts +4 -0
  178. package/dist/mcpAuditJobs.d.ts.map +1 -1
  179. package/dist/mcpAuditJobs.js +49 -2
  180. package/dist/mcpAuditJobs.js.map +1 -1
  181. package/dist/mcpDiagnostics.d.ts.map +1 -1
  182. package/dist/mcpDiagnostics.js +8 -5
  183. package/dist/mcpDiagnostics.js.map +1 -1
  184. package/dist/mcpToolErrors.d.ts.map +1 -1
  185. package/dist/mcpToolErrors.js.map +1 -1
  186. package/dist/native/ast-grep-napi.darwin-arm64.node +0 -0
  187. package/dist/native/ast-grep-napi.darwin-x64.node +0 -0
  188. package/dist/native/ast-grep-napi.linux-arm64-gnu.node +0 -0
  189. package/dist/native/ast-grep-napi.linux-arm64-musl.node +0 -0
  190. package/dist/native/ast-grep-napi.linux-x64-gnu.node +0 -0
  191. package/dist/native/ast-grep-napi.linux-x64-musl.node +0 -0
  192. package/dist/native/ast-grep-napi.win32-x64-msvc.node +0 -0
  193. package/dist/native-bootstrap.d.ts +15 -0
  194. package/dist/native-bootstrap.d.ts.map +1 -0
  195. package/dist/native-bootstrap.js +75 -0
  196. package/dist/native-bootstrap.js.map +1 -0
  197. package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
  198. package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
  199. package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
  200. package/dist/reporting/reportGenerator.d.ts.map +1 -1
  201. package/dist/reporting/reportGenerator.js +4 -0
  202. package/dist/reporting/reportGenerator.js.map +1 -1
  203. package/dist/reporting/sarifReportGenerator.d.ts +39 -0
  204. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -0
  205. package/dist/reporting/sarifReportGenerator.js +229 -0
  206. package/dist/reporting/sarifReportGenerator.js.map +1 -0
  207. package/dist/search/QueryParser.d.ts +41 -0
  208. package/dist/search/QueryParser.d.ts.map +1 -1
  209. package/dist/search/QueryParser.js +200 -19
  210. package/dist/search/QueryParser.js.map +1 -1
  211. package/dist/services/CodeMapGenerator.d.ts.map +1 -1
  212. package/dist/services/CodeMapGenerator.js +4 -4
  213. package/dist/services/CodeMapGenerator.js.map +1 -1
  214. package/dist/services/ProjectTaskRepository.d.ts +34 -9
  215. package/dist/services/ProjectTaskRepository.d.ts.map +1 -1
  216. package/dist/services/ProjectTaskRepository.js +385 -10
  217. package/dist/services/ProjectTaskRepository.js.map +1 -1
  218. package/dist/services/SchemaParser.d.ts.map +1 -1
  219. package/dist/services/SchemaParser.js +5 -8
  220. package/dist/services/SchemaParser.js.map +1 -1
  221. package/dist/services/auditJobService.d.ts +1 -1
  222. package/dist/services/projectTaskHelpers.js.map +1 -1
  223. package/dist/services/whitelistService.d.ts.map +1 -1
  224. package/dist/services/whitelistService.js +1 -1
  225. package/dist/services/whitelistService.js.map +1 -1
  226. package/dist/tool-registry.d.ts +79 -0
  227. package/dist/tool-registry.d.ts.map +1 -0
  228. package/dist/tool-registry.js +139 -0
  229. package/dist/tool-registry.js.map +1 -0
  230. package/dist/types/projectTask.d.ts +31 -0
  231. package/dist/types/projectTask.d.ts.map +1 -1
  232. package/dist/types.d.ts +26 -2
  233. package/dist/types.d.ts.map +1 -1
  234. package/dist/types.js.map +1 -1
  235. package/dist/ui/InteractivePrompts.d.ts.map +1 -1
  236. package/dist/ui/InteractivePrompts.js.map +1 -1
  237. package/dist/utils/astParser.d.ts +31 -38
  238. package/dist/utils/astParser.d.ts.map +1 -1
  239. package/dist/utils/astParser.js +138 -196
  240. package/dist/utils/astParser.js.map +1 -1
  241. package/dist/utils/astUtils.d.ts +87 -58
  242. package/dist/utils/astUtils.d.ts.map +1 -1
  243. package/dist/utils/astUtils.js +852 -581
  244. package/dist/utils/astUtils.js.map +1 -1
  245. package/dist/utils/componentPatterns.js.map +1 -1
  246. package/dist/utils/componentResponsibility.d.ts +13 -9
  247. package/dist/utils/componentResponsibility.d.ts.map +1 -1
  248. package/dist/utils/componentResponsibility.js +236 -206
  249. package/dist/utils/componentResponsibility.js.map +1 -1
  250. package/dist/utils/dependencyExtractor.d.ts +11 -6
  251. package/dist/utils/dependencyExtractor.d.ts.map +1 -1
  252. package/dist/utils/dependencyExtractor.js +200 -119
  253. package/dist/utils/dependencyExtractor.js.map +1 -1
  254. package/dist/utils/fileDiscovery.d.ts +1 -1
  255. package/dist/utils/fileDiscovery.d.ts.map +1 -1
  256. package/dist/utils/fileDiscovery.js.map +1 -1
  257. package/dist/utils/jsDocParser.d.ts +27 -30
  258. package/dist/utils/jsDocParser.d.ts.map +1 -1
  259. package/dist/utils/jsDocParser.js +271 -207
  260. package/dist/utils/jsDocParser.js.map +1 -1
  261. package/dist/utils/reactDetection.d.ts +27 -12
  262. package/dist/utils/reactDetection.d.ts.map +1 -1
  263. package/dist/utils/reactDetection.js +331 -219
  264. package/dist/utils/reactDetection.js.map +1 -1
  265. package/dist/workers/auditWorker.js +17 -3
  266. package/dist/workers/auditWorker.js.map +1 -1
  267. package/package.json +54 -51
  268. package/dist/adapters/GoAdapter.d.ts +0 -53
  269. package/dist/adapters/GoAdapter.d.ts.map +0 -1
  270. package/dist/adapters/GoAdapter.js +0 -611
  271. package/dist/adapters/GoAdapter.js.map +0 -1
  272. package/dist/adapters/GoConfig.d.ts +0 -35
  273. package/dist/adapters/GoConfig.d.ts.map +0 -1
  274. package/dist/adapters/GoConfig.js +0 -155
  275. package/dist/adapters/GoConfig.js.map +0 -1
  276. package/dist/adapters/LanguageAdapter.d.ts +0 -135
  277. package/dist/adapters/LanguageAdapter.d.ts.map +0 -1
  278. package/dist/adapters/LanguageAdapter.js +0 -47
  279. package/dist/adapters/LanguageAdapter.js.map +0 -1
  280. package/dist/adapters/TypeScriptAdapter.d.ts +0 -43
  281. package/dist/adapters/TypeScriptAdapter.d.ts.map +0 -1
  282. package/dist/adapters/TypeScriptAdapter.js +0 -386
  283. package/dist/adapters/TypeScriptAdapter.js.map +0 -1
  284. package/dist/adapters/UniversalAnalyzer.d.ts +0 -42
  285. package/dist/adapters/UniversalAnalyzer.d.ts.map +0 -1
  286. package/dist/adapters/UniversalAnalyzer.js +0 -103
  287. package/dist/adapters/UniversalAnalyzer.js.map +0 -1
  288. package/dist/adapters/UniversalSOLIDAnalyzer.d.ts +0 -48
  289. package/dist/adapters/UniversalSOLIDAnalyzer.d.ts.map +0 -1
  290. package/dist/adapters/UniversalSOLIDAnalyzer.js +0 -178
  291. package/dist/adapters/UniversalSOLIDAnalyzer.js.map +0 -1
  292. package/dist/adapters/solidAnalyzerCompat.d.ts +0 -21
  293. package/dist/adapters/solidAnalyzerCompat.d.ts.map +0 -1
  294. package/dist/adapters/solidAnalyzerCompat.js +0 -78
  295. package/dist/adapters/solidAnalyzerCompat.js.map +0 -1
  296. package/dist/analyzers/dataAccessAnalyzerCompat.d.ts +0 -20
  297. package/dist/analyzers/dataAccessAnalyzerCompat.d.ts.map +0 -1
  298. package/dist/analyzers/dataAccessAnalyzerCompat.js +0 -59
  299. package/dist/analyzers/dataAccessAnalyzerCompat.js.map +0 -1
  300. package/dist/analyzers/documentationAnalyzerCompat.d.ts +0 -20
  301. package/dist/analyzers/documentationAnalyzerCompat.d.ts.map +0 -1
  302. package/dist/analyzers/documentationAnalyzerCompat.js +0 -52
  303. package/dist/analyzers/documentationAnalyzerCompat.js.map +0 -1
  304. package/dist/analyzers/dryAnalyzerCompat.d.ts +0 -20
  305. package/dist/analyzers/dryAnalyzerCompat.d.ts.map +0 -1
  306. package/dist/analyzers/dryAnalyzerCompat.js +0 -44
  307. package/dist/analyzers/dryAnalyzerCompat.js.map +0 -1
  308. package/dist/analyzers/schemaAnalyzerCompat.d.ts +0 -20
  309. package/dist/analyzers/schemaAnalyzerCompat.d.ts.map +0 -1
  310. package/dist/analyzers/schemaAnalyzerCompat.js +0 -69
  311. package/dist/analyzers/schemaAnalyzerCompat.js.map +0 -1
  312. package/dist/analyzers/solidAnalyzerCompat.d.ts +0 -20
  313. package/dist/analyzers/solidAnalyzerCompat.d.ts.map +0 -1
  314. package/dist/analyzers/solidAnalyzerCompat.js +0 -78
  315. package/dist/analyzers/solidAnalyzerCompat.js.map +0 -1
  316. package/dist/codeIndexDb.d.ts +0 -394
  317. package/dist/codeIndexDb.d.ts.map +0 -1
  318. package/dist/codeIndexDb.js +0 -2077
  319. package/dist/codeIndexDb.js.map +0 -1
  320. package/dist/languages/typescript/TypeScriptAdapter.d.ts +0 -108
  321. package/dist/languages/typescript/TypeScriptAdapter.d.ts.map +0 -1
  322. package/dist/languages/typescript/TypeScriptAdapter.js +0 -567
  323. package/dist/languages/typescript/TypeScriptAdapter.js.map +0 -1
  324. package/dist/languages/typescript/test-extraction.d.ts +0 -2
  325. package/dist/languages/typescript/test-extraction.d.ts.map +0 -1
  326. package/dist/languages/typescript/test-extraction.js +0 -36
  327. package/dist/languages/typescript/test-extraction.js.map +0 -1
  328. package/dist/mcp-hybrid.d.ts +0 -10
  329. package/dist/mcp-hybrid.d.ts.map +0 -1
  330. package/dist/mcp-hybrid.js +0 -41
  331. package/dist/mcp-hybrid.js.map +0 -1
  332. package/dist/mcp-index.d.ts +0 -13
  333. package/dist/mcp-index.d.ts.map +0 -1
  334. package/dist/mcp-index.js +0 -123
  335. package/dist/mcp-index.js.map +0 -1
  336. package/dist/mcp-standalone.d.ts +0 -3
  337. package/dist/mcp-standalone.d.ts.map +0 -1
  338. package/dist/mcp-standalone.js +0 -1201
  339. package/dist/mcp-standalone.js.map +0 -1
  340. package/dist/mcp-ui-server.d.ts +0 -27
  341. package/dist/mcp-ui-server.d.ts.map +0 -1
  342. package/dist/mcp-ui-server.js +0 -484
  343. package/dist/mcp-ui-server.js.map +0 -1
  344. package/dist/test-multi-strategy-search.d.ts +0 -3
  345. package/dist/test-multi-strategy-search.d.ts.map +0 -1
  346. package/dist/test-multi-strategy-search.js +0 -170
  347. package/dist/test-multi-strategy-search.js.map +0 -1
@@ -1,15 +1,34 @@
1
1
  /**
2
2
  * Function Scanner
3
3
  * Scans directories for functions using AST parsing
4
+ *
5
+ * ## Migration: TypeScript Compiler API → tree-sitter
6
+ *
7
+ * All `ts.Node`/`ts.SourceFile`/`ts.SyntaxKind` usage replaced with tree-sitter `ASTNode`
8
+ * and adapterBridge utilities. The old `import * as ts from 'typescript'` is removed.
4
9
  */
5
10
  import { discoverFiles } from './utils/fileDiscovery.js';
6
- import { parseTypeScriptFile } from './utils/astParser.js';
7
- import { findNodesByKind, getLineAndColumn } from './utils/astUtils.js';
8
- import { getImports, getImportsDetailed, extractIdentifierUsage, getReExports } from './utils/astUtils.js';
11
+ import { findNodesByKind, getLineAndColumn, getImports, getImportsDetailed, extractIdentifierUsage, getReExports } from './utils/astUtils.js';
12
+ import { parseFile, walkAST, hasModifier, isExported } from './languages/adapterBridge.js';
9
13
  import { isReactComponent, detectComponentType, getComponentName, extractHooks, extractPropTypes } from './utils/reactDetection.js';
10
14
  import { buildImportMap, extractFunctionCalls, getLocalFunctionNames, normalizeCallTarget } from './utils/dependencyExtractor.js';
11
- import * as ts from 'typescript';
15
+ import { readFile } from 'fs/promises';
12
16
  import path from 'path';
17
+ // ---------------------------------------------------------------------------
18
+ // Helpers
19
+ // ---------------------------------------------------------------------------
20
+ /** Get raw text from a tree-sitter node (stored on ASTNode.raw). */
21
+ function rawText(node) {
22
+ return node.raw?.text ?? '';
23
+ }
24
+ /** Find the first child of a given type. */
25
+ function findChildOfType(node, type) {
26
+ return node.children?.find(c => c.type === type);
27
+ }
28
+ /** Check if a node type is a variable/lexical declaration. */
29
+ function isVariableDecl(type) {
30
+ return type === 'lexical_declaration' || type === 'variable_declaration';
31
+ }
13
32
  /**
14
33
  * Scan directory for functions
15
34
  */
@@ -47,27 +66,27 @@ export async function scanDirectoryForFunctions(dirPath, options) {
47
66
  */
48
67
  export async function extractFunctionsFromFile(filePath, options) {
49
68
  const functions = [];
50
- // Parse file
51
- const parseResult = await parseTypeScriptFile(filePath);
52
- if (!parseResult.sourceFile) {
69
+ // Read content and parse
70
+ const content = await readFile(filePath, 'utf-8');
71
+ const ast = parseFile(filePath, content);
72
+ if (!ast)
53
73
  return functions;
54
- }
55
- const sourceFile = parseResult.sourceFile;
74
+ const root = ast.root;
56
75
  // Get file dependencies
57
- const imports = getImports(sourceFile);
76
+ const imports = getImports(root);
58
77
  const dependencies = imports
59
78
  .map(imp => imp.moduleSpecifier)
60
79
  .filter(spec => !spec.startsWith('.') && !spec.startsWith('/'))
61
80
  .filter((v, i, a) => a.indexOf(v) === i); // Unique only
62
81
  // Build import map for dependency tracking
63
- const importMap = buildImportMap(sourceFile);
64
- const detailedImports = getImportsDetailed(sourceFile);
65
- const localFunctions = getLocalFunctionNames(sourceFile);
82
+ const importMap = buildImportMap(root);
83
+ const detailedImports = getImportsDetailed(root);
84
+ const localFunctions = getLocalFunctionNames(root);
66
85
  // Track import usage across the file
67
86
  const importNames = new Set(detailedImports.map(imp => imp.localName));
68
- const fileUsageMap = extractIdentifierUsage(sourceFile, sourceFile, importNames);
87
+ const fileUsageMap = extractIdentifierUsage(root, content, importNames);
69
88
  // Track re-exports - these imports are used even if not referenced in code
70
- const reExports = getReExports(sourceFile);
89
+ const reExports = getReExports(root);
71
90
  for (const reExport of reExports) {
72
91
  // Find imports that match re-exported names
73
92
  for (const imp of detailedImports) {
@@ -91,260 +110,263 @@ export async function extractFunctionsFromFile(filePath, options) {
91
110
  }
92
111
  }
93
112
  // Find all function declarations
94
- const functionDeclarations = findNodesByKind(sourceFile, ts.SyntaxKind.FunctionDeclaration);
113
+ const functionDeclarations = findNodesByKind(root, 'function_declaration');
95
114
  for (const func of functionDeclarations) {
96
- const funcDecl = func;
97
- if (funcDecl.name) {
98
- const { line } = getLineAndColumn(sourceFile, func.getStart());
115
+ const nameNode = findChildOfType(func, 'identifier');
116
+ if (!nameNode)
117
+ continue;
118
+ const { line } = getLineAndColumn(func);
119
+ // Extract function calls
120
+ const body = findChildOfType(func, 'statement_block');
121
+ const functionCalls = body ? extractFunctionCalls(body, content, importMap) : [];
122
+ const normalizedCalls = functionCalls.map(call => normalizeCallTarget(call.callee, filePath, localFunctions));
123
+ // Track which imports this function uses
124
+ const functionUsageMap = extractIdentifierUsage(func, content, importNames);
125
+ const usedImports = Array.from(functionUsageMap.keys());
126
+ // Apply unused imports configuration
127
+ const config = options?.unusedImportsConfig;
128
+ let unusedImports = detailedImports
129
+ .filter(imp => {
130
+ // Skip side-effect imports - they're never "unused"
131
+ if (imp.importType === 'side-effect')
132
+ return false;
133
+ // Check if import is used in this function OR at module level
134
+ if (functionUsageMap.has(imp.localName) || fileUsageMap.has(imp.localName))
135
+ return false;
136
+ // Apply type-only configuration
137
+ if (!config?.includeTypeOnlyImports && imp.isTypeOnly)
138
+ return false;
139
+ // Apply ignore patterns
140
+ if (config?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
141
+ return false;
142
+ return true;
143
+ })
144
+ .map(imp => imp.localName);
145
+ // Get parameter count from formal_parameters
146
+ const params = findChildOfType(func, 'formal_parameters');
147
+ const paramCount = params?.children?.filter(c => c.type === 'required_parameter' || c.type === 'optional_parameter' || c.type === 'rest_parameter').length ?? 0;
148
+ functions.push({
149
+ name: rawText(nameNode),
150
+ filePath,
151
+ lineNumber: line,
152
+ language: getLanguageFromPath(filePath),
153
+ dependencies,
154
+ purpose: `Function ${rawText(nameNode)} implementation`,
155
+ context: `Located in ${path.basename(filePath)}`,
156
+ metadata: {
157
+ kind: 'function',
158
+ isAsync: hasModifier(func, 'async'),
159
+ isExported: isExported(func),
160
+ parameterCount: paramCount,
161
+ functionCalls: normalizedCalls,
162
+ usedImports,
163
+ unusedImports: unusedImports.length > 0 ? unusedImports : undefined,
164
+ body: body ? rawText(body) : undefined
165
+ }
166
+ });
167
+ }
168
+ // Find arrow functions assigned to variables
169
+ const varStmts = [
170
+ ...findNodesByKind(root, 'lexical_declaration'),
171
+ ...findNodesByKind(root, 'variable_declaration')
172
+ ];
173
+ for (const varStmt of varStmts) {
174
+ for (const varDecl of varStmt.children ?? []) {
175
+ if (varDecl.type !== 'variable_declarator')
176
+ continue;
177
+ const nameNode = findChildOfType(varDecl, 'identifier');
178
+ const arrowFunc = varDecl.children?.find(c => c.type === 'arrow_function');
179
+ if (!nameNode || !arrowFunc)
180
+ continue;
181
+ const { line } = getLineAndColumn(varDecl);
99
182
  // Extract function calls
100
- const functionCalls = funcDecl.body ? extractFunctionCalls(funcDecl.body, sourceFile, importMap) : [];
183
+ const body = findChildOfType(arrowFunc, 'statement_block');
184
+ const functionCalls = body ? extractFunctionCalls(body, content, importMap) : [];
101
185
  const normalizedCalls = functionCalls.map(call => normalizeCallTarget(call.callee, filePath, localFunctions));
102
186
  // Track which imports this function uses
103
- const functionUsageMap = funcDecl ?
104
- extractIdentifierUsage(funcDecl, sourceFile, importNames) : new Map();
187
+ const functionUsageMap = extractIdentifierUsage(arrowFunc, content, importNames);
105
188
  const usedImports = Array.from(functionUsageMap.keys());
106
189
  // Apply unused imports configuration
107
- const config = options?.unusedImportsConfig;
190
+ const fConfig = options?.unusedImportsConfig;
108
191
  let unusedImports = detailedImports
109
192
  .filter(imp => {
110
- // Skip side-effect imports - they're never "unused"
111
193
  if (imp.importType === 'side-effect')
112
194
  return false;
113
- // Check if import is used in this function OR at module level
114
195
  if (functionUsageMap.has(imp.localName) || fileUsageMap.has(imp.localName))
115
196
  return false;
116
- // Apply type-only configuration
117
- if (!config?.includeTypeOnlyImports && imp.isTypeOnly)
197
+ if (!fConfig?.includeTypeOnlyImports && imp.isTypeOnly)
118
198
  return false;
119
- // Apply ignore patterns
120
- if (config?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
199
+ if (fConfig?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
121
200
  return false;
122
201
  return true;
123
202
  })
124
203
  .map(imp => imp.localName);
204
+ const arrowParams = findChildOfType(arrowFunc, 'formal_parameters');
205
+ const arrowParamCount = arrowParams?.children?.filter(c => c.type === 'required_parameter' || c.type === 'optional_parameter' || c.type === 'rest_parameter').length ?? 0;
125
206
  functions.push({
126
- name: funcDecl.name.text,
207
+ name: rawText(nameNode),
127
208
  filePath,
128
209
  lineNumber: line,
129
210
  language: getLanguageFromPath(filePath),
130
211
  dependencies,
131
- purpose: `Function ${funcDecl.name.text} implementation`,
132
- context: `Located in ${path.basename(filePath)}`,
212
+ purpose: `Arrow function ${rawText(nameNode)}`,
213
+ context: `Defined in ${path.basename(filePath)}`,
133
214
  metadata: {
134
- kind: 'function',
135
- isAsync: !!funcDecl.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword),
136
- isExported: !!funcDecl.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword),
137
- parameterCount: funcDecl.parameters.length,
215
+ kind: 'arrow',
216
+ isAsync: hasModifier(arrowFunc, 'async'),
217
+ isExported: isExported(varStmt),
218
+ parameterCount: arrowParamCount,
138
219
  functionCalls: normalizedCalls,
139
220
  usedImports,
140
221
  unusedImports: unusedImports.length > 0 ? unusedImports : undefined,
141
- body: funcDecl.body ? funcDecl.body.getText(sourceFile) : undefined
222
+ body: body ? rawText(body) : undefined
142
223
  }
143
224
  });
144
225
  }
145
226
  }
146
- // Find arrow functions assigned to variables
147
- const variableStatements = findNodesByKind(sourceFile, ts.SyntaxKind.VariableStatement);
148
- for (const varStmt of variableStatements) {
149
- const varDeclarations = varStmt.declarationList.declarations;
150
- for (const varDecl of varDeclarations) {
151
- if (varDecl.initializer &&
152
- varDecl.initializer.kind === ts.SyntaxKind.ArrowFunction &&
153
- ts.isIdentifier(varDecl.name)) {
154
- const { line } = getLineAndColumn(sourceFile, varDecl.getStart());
155
- const arrowFunc = varDecl.initializer;
156
- const varStmtNode = varStmt;
157
- // Extract function calls
158
- const functionCalls = arrowFunc.body ? extractFunctionCalls(arrowFunc.body, sourceFile, importMap) : [];
159
- const normalizedCalls = functionCalls.map(call => normalizeCallTarget(call.callee, filePath, localFunctions));
160
- // Track which imports this function uses
161
- const functionUsageMap = arrowFunc ?
162
- extractIdentifierUsage(arrowFunc, sourceFile, importNames) : new Map();
163
- const usedImports = Array.from(functionUsageMap.keys());
164
- // Apply unused imports configuration
165
- const config = options?.unusedImportsConfig;
166
- let unusedImports = detailedImports
167
- .filter(imp => {
168
- // Skip side-effect imports - they're never "unused"
169
- if (imp.importType === 'side-effect')
170
- return false;
171
- // Check if import is used in this function OR at module level
172
- if (functionUsageMap.has(imp.localName) || fileUsageMap.has(imp.localName))
173
- return false;
174
- // Apply type-only configuration
175
- if (!config?.includeTypeOnlyImports && imp.isTypeOnly)
176
- return false;
177
- // Apply ignore patterns
178
- if (config?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
179
- return false;
180
- return true;
181
- })
182
- .map(imp => imp.localName);
183
- functions.push({
184
- name: varDecl.name.text,
185
- filePath,
186
- lineNumber: line,
187
- language: getLanguageFromPath(filePath),
188
- dependencies,
189
- purpose: `Arrow function ${varDecl.name.text}`,
190
- context: `Defined in ${path.basename(filePath)}`,
191
- metadata: {
192
- kind: 'arrow',
193
- isAsync: arrowFunc.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) || false,
194
- isExported: varStmtNode.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword) || false,
195
- parameterCount: arrowFunc.parameters.length,
196
- functionCalls: normalizedCalls,
197
- usedImports,
198
- unusedImports: unusedImports.length > 0 ? unusedImports : undefined,
199
- body: arrowFunc.body ? arrowFunc.body.getText(sourceFile) : undefined
200
- }
201
- });
202
- }
203
- }
204
- }
205
227
  // Find class methods
206
- const classDeclarations = findNodesByKind(sourceFile, ts.SyntaxKind.ClassDeclaration);
228
+ const classDeclarations = findNodesByKind(root, 'class_declaration');
207
229
  for (const classDecl of classDeclarations) {
208
- const className = classDecl.name?.text || 'AnonymousClass';
209
- const methods = classDecl.members.filter(member => member.kind === ts.SyntaxKind.MethodDeclaration);
230
+ const classNameNode = findChildOfType(classDecl, 'identifier');
231
+ const className = classNameNode ? rawText(classNameNode) : 'AnonymousClass';
232
+ const classBody = findChildOfType(classDecl, 'class_body');
233
+ const methods = classBody?.children?.filter(m => m.type === 'method_definition') ?? [];
210
234
  for (const method of methods) {
211
- if (ts.isIdentifier(method.name)) {
212
- const { line } = getLineAndColumn(sourceFile, method.getStart());
213
- // Extract function calls
214
- const functionCalls = method.body ? extractFunctionCalls(method.body, sourceFile, importMap) : [];
215
- const normalizedCalls = functionCalls.map(call => normalizeCallTarget(call.callee, filePath, localFunctions));
216
- // Track which imports this method uses
217
- const functionUsageMap = method ?
218
- extractIdentifierUsage(method, sourceFile, importNames) : new Map();
219
- const usedImports = Array.from(functionUsageMap.keys());
220
- // Apply unused imports configuration
221
- const config = options?.unusedImportsConfig;
222
- let unusedImports = detailedImports
223
- .filter(imp => {
224
- // Skip side-effect imports - they're never "unused"
225
- if (imp.importType === 'side-effect')
226
- return false;
227
- // Check if import is used in this method OR at module level
228
- if (functionUsageMap.has(imp.localName) || fileUsageMap.has(imp.localName))
229
- return false;
230
- // Apply type-only configuration
231
- if (!config?.includeTypeOnlyImports && imp.isTypeOnly)
232
- return false;
233
- // Apply ignore patterns
234
- if (config?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
235
- return false;
236
- return true;
237
- })
238
- .map(imp => imp.localName);
235
+ const methodNameNode = findChildOfType(method, 'identifier');
236
+ if (!methodNameNode)
237
+ continue;
238
+ const { line } = getLineAndColumn(method);
239
+ // Extract function calls
240
+ const body = findChildOfType(method, 'statement_block');
241
+ const functionCalls = body ? extractFunctionCalls(body, content, importMap) : [];
242
+ const normalizedCalls = functionCalls.map(call => normalizeCallTarget(call.callee, filePath, localFunctions));
243
+ // Track which imports this method uses
244
+ const functionUsageMap = extractIdentifierUsage(method, content, importNames);
245
+ const usedImports = Array.from(functionUsageMap.keys());
246
+ // Apply unused imports configuration
247
+ const mConfig = options?.unusedImportsConfig;
248
+ let unusedImports = detailedImports
249
+ .filter(imp => {
250
+ if (imp.importType === 'side-effect')
251
+ return false;
252
+ if (functionUsageMap.has(imp.localName) || fileUsageMap.has(imp.localName))
253
+ return false;
254
+ if (!mConfig?.includeTypeOnlyImports && imp.isTypeOnly)
255
+ return false;
256
+ if (mConfig?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
257
+ return false;
258
+ return true;
259
+ })
260
+ .map(imp => imp.localName);
261
+ const methodParams = findChildOfType(method, 'formal_parameters');
262
+ const methodParamCount = methodParams?.children?.filter(c => c.type === 'required_parameter' || c.type === 'optional_parameter' || c.type === 'rest_parameter').length ?? 0;
263
+ functions.push({
264
+ name: `${className}.${rawText(methodNameNode)}`,
265
+ filePath,
266
+ lineNumber: line,
267
+ language: getLanguageFromPath(filePath),
268
+ dependencies,
269
+ purpose: `Method ${rawText(methodNameNode)} of class ${className}`,
270
+ context: `Class method in ${path.basename(filePath)}`,
271
+ metadata: {
272
+ kind: 'method',
273
+ className,
274
+ isAsync: hasModifier(method, 'async'),
275
+ isStatic: hasModifier(method, 'static'),
276
+ isPrivate: hasModifier(method, 'private'),
277
+ parameterCount: methodParamCount,
278
+ functionCalls: normalizedCalls,
279
+ usedImports,
280
+ unusedImports: unusedImports.length > 0 ? unusedImports : undefined,
281
+ body: body ? rawText(body) : undefined
282
+ }
283
+ });
284
+ }
285
+ }
286
+ // Check if this is a React file and scan for components
287
+ if (filePath.endsWith('.tsx') || filePath.endsWith('.jsx') ||
288
+ (filePath.endsWith('.js') && dependencies.includes('react'))) {
289
+ // Walk all nodes for React components
290
+ walkAST(root, (node) => {
291
+ if (!isReactComponent(node))
292
+ return;
293
+ const componentType = detectComponentType(node);
294
+ if (!componentType)
295
+ return;
296
+ const componentName = getComponentName(node);
297
+ const { line } = getLineAndColumn(node);
298
+ const endLine = node.location?.end?.line ?? line;
299
+ // Determine which node to use for prop extraction
300
+ // For arrow functions, use the parent variable declarator
301
+ let nodeForProps = node;
302
+ if (node.type === 'arrow_function' &&
303
+ node.parent && (node.parent.type === 'variable_declarator' ||
304
+ isVariableDecl(node.parent.type))) {
305
+ nodeForProps = node.parent;
306
+ }
307
+ // Track which imports this component uses
308
+ const componentUsageMap = extractIdentifierUsage(node, content, importNames);
309
+ const usedImports = Array.from(componentUsageMap.keys());
310
+ // Apply unused imports configuration
311
+ const cConfig = options?.unusedImportsConfig;
312
+ let unusedImports = detailedImports
313
+ .filter(imp => {
314
+ if (imp.importType === 'side-effect')
315
+ return false;
316
+ if (componentUsageMap.has(imp.localName) || fileUsageMap.has(imp.localName))
317
+ return false;
318
+ if (!cConfig?.includeTypeOnlyImports && imp.isTypeOnly)
319
+ return false;
320
+ if (cConfig?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
321
+ return false;
322
+ return true;
323
+ })
324
+ .map(imp => imp.localName);
325
+ // Check if we already indexed this as a regular function
326
+ const existingFunc = functions.find(f => f.name === componentName && f.lineNumber === line);
327
+ if (existingFunc) {
328
+ // Update the existing function with component metadata
329
+ existingFunc.purpose = `React ${componentType} component`;
330
+ existingFunc.metadata = {
331
+ ...existingFunc.metadata,
332
+ entityType: 'component',
333
+ componentType,
334
+ props: extractPropTypes(nodeForProps),
335
+ hooks: extractHooks(node),
336
+ jsxElements: extractJSXElements(node),
337
+ isExported: isComponentExported(node),
338
+ complexity: calculateComponentComplexity(node),
339
+ body: getComponentBody(node)
340
+ };
341
+ }
342
+ else {
343
+ // Add new component
239
344
  functions.push({
240
- name: `${className}.${method.name.text}`,
345
+ name: componentName,
241
346
  filePath,
242
347
  lineNumber: line,
348
+ startLine: line,
349
+ endLine,
243
350
  language: getLanguageFromPath(filePath),
244
351
  dependencies,
245
- purpose: `Method ${method.name.text} of class ${className}`,
246
- context: `Class method in ${path.basename(filePath)}`,
352
+ purpose: `React ${componentType} component`,
353
+ context: `Located in ${path.basename(filePath)}`,
247
354
  metadata: {
248
- kind: 'method',
249
- className,
250
- isAsync: !!method.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword),
251
- isStatic: !!method.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword),
252
- isPrivate: !!method.modifiers?.some(m => m.kind === ts.SyntaxKind.PrivateKeyword),
253
- parameterCount: method.parameters.length,
254
- functionCalls: normalizedCalls,
255
- usedImports,
256
- unusedImports: unusedImports.length > 0 ? unusedImports : undefined,
257
- body: method.body ? method.body.getText(sourceFile) : undefined
258
- }
259
- });
260
- }
261
- }
262
- }
263
- // Check if this is a React file and scan for components
264
- if (filePath.endsWith('.tsx') || filePath.endsWith('.jsx') ||
265
- (filePath.endsWith('.js') && dependencies.includes('react'))) {
266
- // Check all nodes for React components
267
- const checkNode = (node) => {
268
- if (isReactComponent(node)) {
269
- const componentType = detectComponentType(node);
270
- const componentName = getComponentName(node);
271
- const { line } = getLineAndColumn(sourceFile, node.getStart());
272
- const endLine = getLineAndColumn(sourceFile, node.getEnd()).line;
273
- // Skip if we already indexed this as a regular function
274
- if (functions.some(f => f.name === componentName && f.lineNumber === line)) {
275
- // Update the existing function with component metadata
276
- const existingFunc = functions.find(f => f.name === componentName && f.lineNumber === line);
277
- existingFunc.purpose = `React ${componentType} component`;
278
- // For arrow functions, we need to check the parent variable declaration for types
279
- let nodeForProps = node;
280
- if (ts.isArrowFunction(node) && ts.isVariableDeclaration(node.parent)) {
281
- nodeForProps = node.parent;
282
- }
283
- existingFunc.metadata = {
284
- ...existingFunc.metadata,
285
355
  entityType: 'component',
286
356
  componentType,
287
- props: extractPropTypes(nodeForProps, sourceFile),
288
- hooks: extractHooks(node, sourceFile),
357
+ props: extractPropTypes(nodeForProps),
358
+ hooks: extractHooks(node),
289
359
  jsxElements: extractJSXElements(node),
290
360
  isExported: isComponentExported(node),
291
361
  complexity: calculateComponentComplexity(node),
292
- body: getComponentBody(node, sourceFile)
293
- };
294
- }
295
- else {
296
- // Track which imports this component uses
297
- const componentUsageMap = extractIdentifierUsage(node, sourceFile, importNames);
298
- const usedImports = Array.from(componentUsageMap.keys());
299
- // Apply unused imports configuration
300
- const config = options?.unusedImportsConfig;
301
- let unusedImports = detailedImports
302
- .filter(imp => {
303
- // Skip side-effect imports - they're never "unused"
304
- if (imp.importType === 'side-effect')
305
- return false;
306
- // Check if import is used in this component OR at module level
307
- if (componentUsageMap.has(imp.localName) || fileUsageMap.has(imp.localName))
308
- return false;
309
- // Apply type-only configuration
310
- if (!config?.includeTypeOnlyImports && imp.isTypeOnly)
311
- return false;
312
- // Apply ignore patterns
313
- if (config?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
314
- return false;
315
- return true;
316
- })
317
- .map(imp => imp.localName);
318
- // Add new component
319
- functions.push({
320
- name: componentName,
321
- filePath,
322
- lineNumber: line,
323
- startLine: line,
324
- endLine: endLine,
325
- language: getLanguageFromPath(filePath),
326
- dependencies,
327
- purpose: `React ${componentType} component`,
328
- context: `Located in ${path.basename(filePath)}`,
329
- metadata: {
330
- entityType: 'component',
331
- componentType,
332
- props: extractPropTypes(node, sourceFile),
333
- hooks: extractHooks(node, sourceFile),
334
- jsxElements: extractJSXElements(node),
335
- isExported: isComponentExported(node),
336
- complexity: calculateComponentComplexity(node),
337
- body: getComponentBody(node, sourceFile),
338
- usedImports,
339
- unusedImports: unusedImports.length > 0 ? unusedImports : undefined,
340
- calledBy: []
341
- }
342
- });
343
- }
362
+ body: getComponentBody(node),
363
+ usedImports,
364
+ unusedImports: unusedImports.length > 0 ? unusedImports : undefined,
365
+ calledBy: []
366
+ }
367
+ });
344
368
  }
345
- ts.forEachChild(node, checkNode);
346
- };
347
- checkNode(sourceFile);
369
+ });
348
370
  }
349
371
  // Add file-level unused import analysis if configured
350
372
  if (options?.unusedImportsConfig?.checkLevel === 'file' && functions.length > 0) {
@@ -358,17 +380,14 @@ export async function extractFunctionsFromFile(filePath, options) {
358
380
  }
359
381
  }
360
382
  // Calculate file-level unused imports
361
- const config = options.unusedImportsConfig;
383
+ const flConfig = options.unusedImportsConfig;
362
384
  const fileUnusedImports = detailedImports
363
385
  .filter(imp => {
364
- // Check if import is used anywhere in the file
365
386
  if (allUsedImports.has(imp.localName))
366
387
  return false;
367
- // Apply type-only configuration
368
- if (!config?.includeTypeOnlyImports && imp.isTypeOnly)
388
+ if (!flConfig?.includeTypeOnlyImports && imp.isTypeOnly)
369
389
  return false;
370
- // Apply ignore patterns
371
- if (config?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
390
+ if (flConfig?.ignorePatterns?.some(pattern => imp.localName.match(new RegExp(pattern))))
372
391
  return false;
373
392
  return true;
374
393
  })
@@ -394,38 +413,49 @@ export async function extractFunctionsFromFile(filePath, options) {
394
413
  }
395
414
  return functions;
396
415
  }
416
+ // ---------------------------------------------------------------------------
397
417
  // Helper functions for React component extraction
418
+ // ---------------------------------------------------------------------------
398
419
  function extractJSXElements(node) {
399
420
  const elements = new Set();
400
- function visit(child) {
401
- if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child)) {
402
- const tagName = ts.isJsxElement(child)
403
- ? child.openingElement.tagName
404
- : child.tagName;
405
- if (ts.isIdentifier(tagName)) {
406
- elements.add(tagName.text);
421
+ walkAST(node, (child) => {
422
+ if (child.type === 'jsx_element') {
423
+ const openTag = findChildOfType(child, 'open_tag');
424
+ if (openTag) {
425
+ const tagNameNode = openTag.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
426
+ if (tagNameNode) {
427
+ if (tagNameNode.type === 'identifier') {
428
+ elements.add(rawText(tagNameNode));
429
+ }
430
+ else if (tagNameNode.type === 'member_expression') {
431
+ elements.add(rawText(tagNameNode));
432
+ }
433
+ }
407
434
  }
408
- else if (ts.isPropertyAccessExpression(tagName)) {
409
- elements.add(tagName.getText());
435
+ }
436
+ else if (child.type === 'jsx_self_closing_element') {
437
+ const tagNameNode = child.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
438
+ if (tagNameNode) {
439
+ if (tagNameNode.type === 'identifier') {
440
+ elements.add(rawText(tagNameNode));
441
+ }
442
+ else if (tagNameNode.type === 'member_expression') {
443
+ elements.add(rawText(tagNameNode));
444
+ }
410
445
  }
411
446
  }
412
- ts.forEachChild(child, visit);
413
- }
414
- ts.forEachChild(node, visit);
447
+ });
415
448
  return Array.from(elements);
416
449
  }
417
450
  function isComponentExported(node) {
418
- // Check for export modifier
419
- if (ts.canHaveModifiers(node)) {
420
- const modifiers = ts.getModifiers(node);
421
- if (modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) {
422
- return true;
423
- }
451
+ // Check for export modifier on the node itself
452
+ if (isExported(node)) {
453
+ return true;
424
454
  }
425
455
  // Check if parent is an export statement
426
456
  let parent = node.parent;
427
457
  while (parent) {
428
- if (ts.isExportAssignment(parent) || ts.isExportDeclaration(parent)) {
458
+ if (parent.type === 'export_statement' || parent.type === 'export_declaration') {
429
459
  return true;
430
460
  }
431
461
  parent = parent.parent;
@@ -434,29 +464,34 @@ function isComponentExported(node) {
434
464
  }
435
465
  function calculateComponentComplexity(node) {
436
466
  let complexity = 1; // Base complexity
437
- function visit(child) {
467
+ walkAST(node, (child) => {
438
468
  // Control flow statements
439
- if (ts.isIfStatement(child) || ts.isConditionalExpression(child)) {
469
+ if (child.type === 'if_statement' || child.type === 'ternary_expression') {
440
470
  complexity++;
441
471
  }
442
- else if (ts.isForStatement(child) || ts.isForInStatement(child) ||
443
- ts.isForOfStatement(child) || ts.isWhileStatement(child)) {
472
+ else if (child.type === 'for_statement' || child.type === 'for_in_statement' ||
473
+ child.type === 'while_statement') {
444
474
  complexity += 2;
445
475
  }
446
- else if (ts.isSwitchStatement(child)) {
447
- complexity += child.caseBlock.clauses.length;
476
+ else if (child.type === 'switch_statement') {
477
+ // Count switch_case children in switch body
478
+ const body = findChildOfType(child, 'switch_body');
479
+ if (body) {
480
+ const cases = body.children?.filter(c => c.type === 'switch_case' || c.type === 'switch_default') ?? [];
481
+ complexity += cases.length;
482
+ }
448
483
  }
449
484
  // Callbacks and event handlers
450
- if (ts.isCallExpression(child)) {
451
- const expression = child.expression;
452
- if (ts.isPropertyAccessExpression(expression) &&
453
- expression.name.text === 'map') {
454
- complexity++;
485
+ if (child.type === 'call_expression') {
486
+ const expr = child.children?.[0];
487
+ if (expr?.type === 'member_expression') {
488
+ const propNode = expr.children?.[expr.children.length - 1];
489
+ if (propNode && rawText(propNode) === 'map') {
490
+ complexity++;
491
+ }
455
492
  }
456
493
  }
457
- ts.forEachChild(child, visit);
458
- }
459
- ts.forEachChild(node, visit);
494
+ });
460
495
  return complexity;
461
496
  }
462
497
  /**
@@ -488,115 +523,156 @@ export async function scanFunctionsInDirectory(dirPath, options) {
488
523
  */
489
524
  export class FunctionScanner {
490
525
  async scanFunctions(content, filePath, language) {
491
- // Parse the content directly
492
526
  const functions = [];
493
- // Create a TypeScript source file from content
494
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
527
+ // Parse content directly via tree-sitter
528
+ const ast = parseFile(filePath, content);
529
+ if (!ast)
530
+ return functions;
531
+ const root = ast.root;
495
532
  // Get file dependencies
496
- const imports = getImports(sourceFile);
533
+ const imports = getImports(root);
497
534
  const dependencies = imports
498
535
  .map(imp => imp.moduleSpecifier)
499
536
  .filter(spec => !spec.startsWith('.') && !spec.startsWith('/'))
500
537
  .filter((v, i, a) => a.indexOf(v) === i); // Unique only
538
+ // Build import map for dependency tracking
539
+ const importMap = buildImportMap(root);
501
540
  // Find all function declarations
502
- const functionDeclarations = findNodesByKind(sourceFile, ts.SyntaxKind.FunctionDeclaration);
503
- for (const func of functionDeclarations) {
504
- const funcNode = func;
505
- if (!funcNode.name)
541
+ for (const func of findNodesByKind(root, 'function_declaration')) {
542
+ const nameNode = findChildOfType(func, 'identifier');
543
+ if (!nameNode)
506
544
  continue;
507
- const { line } = getLineAndColumn(sourceFile, funcNode.getStart());
545
+ const { line } = getLineAndColumn(func);
546
+ const params = findChildOfType(func, 'formal_parameters');
547
+ const paramCount = params?.children?.filter(c => c.type === 'required_parameter' || c.type === 'optional_parameter' || c.type === 'rest_parameter').length ?? 0;
548
+ // Build signature: text up to the statement block (before first '{' of body)
549
+ const bodyNode = findChildOfType(func, 'statement_block');
550
+ const fullText = rawText(func);
551
+ const signature = fullText.split('{')[0]?.trim() ?? undefined;
508
552
  functions.push({
509
- name: funcNode.name.text,
510
- filePath: filePath,
553
+ name: rawText(nameNode),
554
+ filePath,
511
555
  lineNumber: line,
512
- language: language,
556
+ language,
513
557
  dependencies,
514
- purpose: `Function ${funcNode.name.text} implementation`,
558
+ purpose: `Function ${rawText(nameNode)} implementation`,
515
559
  context: `Located in ${path.basename(filePath)}`,
516
560
  metadata: {
517
561
  kind: 'function',
518
- isAsync: !!funcNode.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword),
519
- isExported: !!funcNode.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword),
520
- parameterCount: funcNode.parameters.length
562
+ isAsync: hasModifier(func, 'async'),
563
+ isExported: isExported(func),
564
+ parameterCount: paramCount,
565
+ signature,
566
+ body: bodyNode ? rawText(bodyNode) : undefined,
521
567
  }
522
568
  });
523
569
  }
524
570
  // Find arrow functions and variable declarations
525
- const varDeclarations = findNodesByKind(sourceFile, ts.SyntaxKind.VariableStatement);
526
- for (const varStmt of varDeclarations) {
527
- const varStmtNode = varStmt;
528
- for (const declaration of varStmtNode.declarationList.declarations) {
529
- if (declaration.initializer &&
530
- declaration.initializer.kind === ts.SyntaxKind.ArrowFunction &&
531
- ts.isIdentifier(declaration.name)) {
532
- const arrowFunc = declaration.initializer;
533
- const { line } = getLineAndColumn(sourceFile, declaration.getStart());
534
- functions.push({
535
- name: declaration.name.text,
536
- filePath: filePath,
537
- lineNumber: line,
538
- language: language,
539
- dependencies,
540
- purpose: `Arrow function ${declaration.name.text}`,
541
- context: `Defined in ${path.basename(filePath)}`,
542
- metadata: {
543
- kind: 'arrow',
544
- isAsync: !!arrowFunc.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword),
545
- isExported: !!varStmtNode.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword),
546
- parameterCount: arrowFunc.parameters.length
547
- }
548
- });
549
- }
571
+ for (const varStmt of [
572
+ ...findNodesByKind(root, 'lexical_declaration'),
573
+ ...findNodesByKind(root, 'variable_declaration')
574
+ ]) {
575
+ for (const declaration of varStmt.children ?? []) {
576
+ if (declaration.type !== 'variable_declarator')
577
+ continue;
578
+ const nameNode = findChildOfType(declaration, 'identifier');
579
+ const init = declaration.children?.find(c => c.type === 'arrow_function');
580
+ if (!nameNode || !init)
581
+ continue;
582
+ const { line } = getLineAndColumn(declaration);
583
+ const arrowParams = findChildOfType(init, 'formal_parameters');
584
+ const arrowParamCount = arrowParams?.children?.filter(c => c.type === 'required_parameter' || c.type === 'optional_parameter' || c.type === 'rest_parameter').length ?? 0;
585
+ const fullText = rawText(init);
586
+ const signature = fullText.split('{')[0]?.trim() ?? undefined;
587
+ const bodyNode = findChildOfType(init, 'statement_block');
588
+ functions.push({
589
+ name: rawText(nameNode),
590
+ filePath,
591
+ lineNumber: line,
592
+ language,
593
+ dependencies,
594
+ purpose: `Arrow function ${rawText(nameNode)}`,
595
+ context: `Defined in ${path.basename(filePath)}`,
596
+ metadata: {
597
+ kind: 'arrow',
598
+ isAsync: hasModifier(init, 'async'),
599
+ isExported: isExported(varStmt),
600
+ parameterCount: arrowParamCount,
601
+ signature,
602
+ body: bodyNode ? rawText(bodyNode) : undefined,
603
+ }
604
+ });
550
605
  }
551
606
  }
552
607
  // Find class methods
553
- const classDeclarations = findNodesByKind(sourceFile, ts.SyntaxKind.ClassDeclaration);
554
- for (const classDecl of classDeclarations) {
555
- const classNode = classDecl;
556
- if (!classNode.name)
608
+ for (const classDecl of findNodesByKind(root, 'class_declaration')) {
609
+ const nameNode = findChildOfType(classDecl, 'identifier');
610
+ if (!nameNode)
557
611
  continue;
558
- const className = classNode.name.text;
559
- for (const member of classNode.members) {
560
- if (ts.isMethodDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
561
- const method = member;
562
- const { line } = getLineAndColumn(sourceFile, method.getStart());
563
- functions.push({
564
- name: `${className}.${method.name.text}`,
565
- filePath: filePath,
566
- lineNumber: line,
567
- language: language,
568
- dependencies,
569
- purpose: `Method ${method.name.text} of class ${className}`,
570
- context: `Class method in ${path.basename(filePath)}`,
571
- metadata: {
572
- kind: 'method',
573
- className,
574
- isAsync: !!method.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword),
575
- isStatic: !!method.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword),
576
- isPrivate: !!method.modifiers?.some(m => m.kind === ts.SyntaxKind.PrivateKeyword),
577
- parameterCount: method.parameters.length
578
- }
579
- });
580
- }
612
+ const className = rawText(nameNode);
613
+ const classBody = findChildOfType(classDecl, 'class_body');
614
+ for (const member of classBody?.children ?? []) {
615
+ if (member.type !== 'method_definition')
616
+ continue;
617
+ const mNameNode = findChildOfType(member, 'identifier');
618
+ if (!mNameNode)
619
+ continue;
620
+ const { line } = getLineAndColumn(member);
621
+ const methodParams = findChildOfType(member, 'formal_parameters');
622
+ const methodParamCount = methodParams?.children?.filter(c => c.type === 'required_parameter' || c.type === 'optional_parameter' || c.type === 'rest_parameter').length ?? 0;
623
+ const fullText = rawText(member);
624
+ const signature = fullText.split('{')[0]?.trim() ?? undefined;
625
+ const bodyNode = findChildOfType(member, 'statement_block');
626
+ functions.push({
627
+ name: `${className}.${rawText(mNameNode)}`,
628
+ filePath,
629
+ lineNumber: line,
630
+ language,
631
+ dependencies,
632
+ purpose: `Method ${rawText(mNameNode)} of class ${className}`,
633
+ context: `Class method in ${path.basename(filePath)}`,
634
+ metadata: {
635
+ kind: 'method',
636
+ className,
637
+ isAsync: hasModifier(member, 'async'),
638
+ isStatic: hasModifier(member, 'static'),
639
+ isPrivate: hasModifier(member, 'private'),
640
+ parameterCount: methodParamCount,
641
+ signature,
642
+ body: bodyNode ? rawText(bodyNode) : undefined,
643
+ }
644
+ });
581
645
  }
582
646
  }
583
647
  return functions;
584
648
  }
585
649
  }
650
+ // ---------------------------------------------------------------------------
586
651
  // Helper function to get component body
587
- function getComponentBody(node, sourceFile) {
588
- if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
589
- return node.body ? node.body.getText(sourceFile) : undefined;
652
+ // ---------------------------------------------------------------------------
653
+ function getComponentBody(node) {
654
+ if (node.type === 'function_declaration' || node.type === 'function_expression') {
655
+ const body = findChildOfType(node, 'statement_block');
656
+ return body ? rawText(body) : undefined;
590
657
  }
591
- else if (ts.isArrowFunction(node)) {
592
- return node.body ? node.body.getText(sourceFile) : undefined;
658
+ else if (node.type === 'arrow_function') {
659
+ const body = findChildOfType(node, 'statement_block');
660
+ return body ? rawText(body) : undefined;
593
661
  }
594
- else if (ts.isClassDeclaration(node)) {
662
+ else if (node.type === 'class_declaration') {
595
663
  // For class components, get the render method body
596
- const renderMethod = node.members.find(member => ts.isMethodDeclaration(member) &&
597
- member.name && ts.isIdentifier(member.name) &&
598
- member.name.text === 'render');
599
- return renderMethod?.body ? renderMethod.body.getText(sourceFile) : undefined;
664
+ const classBody = findChildOfType(node, 'class_body');
665
+ if (!classBody)
666
+ return undefined;
667
+ for (const member of classBody.children ?? []) {
668
+ if (member.type !== 'method_definition')
669
+ continue;
670
+ const mNameNode = findChildOfType(member, 'identifier');
671
+ if (mNameNode && rawText(mNameNode) === 'render') {
672
+ const body = findChildOfType(member, 'statement_block');
673
+ return body ? rawText(body) : undefined;
674
+ }
675
+ }
600
676
  }
601
677
  return undefined;
602
678
  }