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,769 +1,1040 @@
1
1
  /**
2
2
  * AST Utility Functions
3
- * Provides helper functions for working with TypeScript AST nodes
3
+ * Provides helper functions for working with tree-sitter AST nodes
4
+ *
5
+ * ## Migration: TypeScript Compiler API → tree-sitter
6
+ *
7
+ * All functions now use tree-sitter `ASTNode` via the `adapterBridge` facade.
8
+ * The `ts.SourceFile` parameter has been replaced with `ASTNode` (root node).
9
+ * For source-code-dependent operations, `sourceCode: string` is passed separately.
4
10
  */
5
- import * as ts from 'typescript';
11
+ import { walkAST, findNodes, getNodeText as bridgeGetNodeText, getLineAndColumn as bridgeGetLineAndColumn, isExported as bridgeIsExported, calculateComplexity as bridgeCalculateComplexity, hasModifier, } from '../languages/adapterBridge.js';
12
+ // ---------------------------------------------------------------------------
13
+ // Helpers
14
+ // ---------------------------------------------------------------------------
15
+ /** Get raw text from a tree-sitter node (stored on ASTNode.raw). */
16
+ function rawText(node) {
17
+ return node.raw?.text ?? '';
18
+ }
19
+ /** Find the first child of a given type. */
20
+ function findChildOfType(node, type) {
21
+ return node.children?.find(c => c.type === type);
22
+ }
23
+ // ---------------------------------------------------------------------------
24
+ // Node finding (re-exports from adapterBridge)
25
+ // ---------------------------------------------------------------------------
6
26
  /**
7
- * Find all nodes of a specific kind in the AST
27
+ * Find all nodes matching a predicate in the AST subtree.
28
+ * Replacement for the old `findNodesByKind<T>(node, SyntaxKind)`.
8
29
  */
9
- export function findNodesByKind(node, kind) {
10
- const results = [];
11
- function visit(node) {
12
- if (node.kind === kind) {
13
- results.push(node);
14
- }
15
- ts.forEachChild(node, visit);
16
- }
17
- visit(node);
18
- return results;
30
+ export function findNodesByType(root, predicate) {
31
+ return findNodes(root, predicate);
19
32
  }
33
+ // ---------------------------------------------------------------------------
34
+ // Text extraction (re-exports from adapterBridge)
35
+ // ---------------------------------------------------------------------------
20
36
  /**
21
- * Get the text content of a node
37
+ * Get the text content of a node.
38
+ * Uses sourceCode if provided; falls back to raw tree-sitter text.
22
39
  */
23
- export function getNodeText(node, sourceFile) {
24
- return node.getText(sourceFile);
25
- }
40
+ export { bridgeGetNodeText as getNodeText };
41
+ // ---------------------------------------------------------------------------
42
+ // Position helpers (re-exports from adapterBridge)
43
+ // ---------------------------------------------------------------------------
26
44
  /**
27
- * Get line and column number for a position
45
+ * Get line and column number for a tree-sitter ASTNode.
28
46
  */
29
- export function getLineAndColumn(sourceFile, position) {
30
- const { line, character } = sourceFile.getLineAndCharacterOfPosition(position);
31
- return { line: line + 1, column: character + 1 };
32
- }
47
+ export { bridgeGetLineAndColumn as getLineAndColumn };
48
+ // ---------------------------------------------------------------------------
49
+ // Export checks (re-exports from adapterBridge)
50
+ // ---------------------------------------------------------------------------
51
+ export { bridgeIsExported as isExported };
52
+ // ---------------------------------------------------------------------------
53
+ // Complexity (re-exports from adapterBridge)
54
+ // ---------------------------------------------------------------------------
55
+ export { bridgeCalculateComplexity as calculateComplexity };
56
+ // ---------------------------------------------------------------------------
57
+ // Import extraction
58
+ // ---------------------------------------------------------------------------
33
59
  /**
34
- * Extract import statements from a source file
60
+ * Extract import statements from an AST root node.
61
+ * Uses tree-sitter import_statement structure:
62
+ * import_statement → import_clause? → (identifier | named_imports) → string
35
63
  */
36
- export function getImports(sourceFile) {
64
+ export function getImports(root) {
37
65
  const imports = [];
38
- ts.forEachChild(sourceFile, node => {
39
- if (ts.isImportDeclaration(node)) {
40
- const moduleSpecifier = node.moduleSpecifier.text;
41
- const importedNames = [];
42
- const isTypeOnly = node.importClause?.isTypeOnly || false;
43
- if (node.importClause) {
44
- // Default import
45
- if (node.importClause.name) {
46
- importedNames.push(node.importClause.name.text);
47
- }
48
- // Named imports
49
- if (node.importClause.namedBindings) {
50
- if (ts.isNamespaceImport(node.importClause.namedBindings)) {
51
- importedNames.push(`* as ${node.importClause.namedBindings.name.text}`);
52
- }
53
- else if (ts.isNamedImports(node.importClause.namedBindings)) {
54
- node.importClause.namedBindings.elements.forEach(element => {
55
- importedNames.push(element.name.text);
56
- });
66
+ const importNodes = findNodes(root, n => n.type === 'import_statement');
67
+ for (const node of importNodes) {
68
+ // Module specifier (the string literal at the end)
69
+ const moduleNode = findChildOfType(node, 'string');
70
+ if (!moduleNode)
71
+ continue;
72
+ const moduleSpecifier = rawText(moduleNode).replace(/^["']|["']$/g, '');
73
+ const importedNames = [];
74
+ const importClause = findChildOfType(node, 'import_clause');
75
+ let isTypeOnly = false;
76
+ if (importClause) {
77
+ // Check for `type` keyword in import clause
78
+ const raw = importClause.raw;
79
+ isTypeOnly = raw?.children?.some(c => !c.isNamed && c.type === 'type') ?? false;
80
+ // Default import (identifier child of import_clause that's not 'type' modifier)
81
+ const defaultId = importClause.children?.find(c => c.type === 'identifier');
82
+ if (defaultId) {
83
+ importedNames.push(rawText(defaultId));
84
+ }
85
+ // Named imports
86
+ const namedImports = findChildOfType(importClause, 'named_imports');
87
+ if (namedImports) {
88
+ for (const child of namedImports.children ?? []) {
89
+ if (child.type !== 'import_specifier')
90
+ continue;
91
+ // The identifier children — last one is the local name
92
+ const ids = child.children?.filter(c => c.type === 'identifier') ?? [];
93
+ if (ids.length > 0) {
94
+ importedNames.push(rawText(ids[ids.length - 1]));
57
95
  }
58
96
  }
59
97
  }
60
- const { line } = getLineAndColumn(sourceFile, node.getStart());
61
- imports.push({
62
- moduleSpecifier,
63
- importedNames,
64
- isTypeOnly,
65
- line
66
- });
98
+ // Namespace import
99
+ const namespaceImport = findChildOfType(importClause, 'namespace_import');
100
+ if (namespaceImport) {
101
+ const nsId = findChildOfType(namespaceImport, 'identifier');
102
+ if (nsId) {
103
+ importedNames.push(`* as ${rawText(nsId)}`);
104
+ }
105
+ }
67
106
  }
68
- });
107
+ const { line } = bridgeGetLineAndColumn(node);
108
+ imports.push({ moduleSpecifier, importedNames, isTypeOnly, line });
109
+ }
69
110
  return imports;
70
111
  }
112
+ // ---------------------------------------------------------------------------
113
+ // Export extraction
114
+ // ---------------------------------------------------------------------------
71
115
  /**
72
- * Extract export statements from a source file
116
+ * Extract export statements from an AST root node.
117
+ * Uses tree-sitter export_statement structure.
73
118
  */
74
- export function getExports(sourceFile) {
119
+ export function getExports(root) {
75
120
  const exports = [];
76
- ts.forEachChild(sourceFile, node => {
77
- if (ts.isExportDeclaration(node)) {
78
- const isTypeOnly = node.isTypeOnly || false;
79
- const { line } = getLineAndColumn(sourceFile, node.getStart());
80
- if (node.exportClause && ts.isNamedExports(node.exportClause)) {
81
- node.exportClause.elements.forEach(element => {
82
- exports.push({
83
- name: element.name.text,
84
- isDefault: false,
85
- isTypeOnly,
86
- line
87
- });
88
- });
121
+ // export declarations: export { name1, name2 }
122
+ const exportNodes = findNodes(root, n => n.type === 'export_statement' || n.type === 'export_declaration');
123
+ for (const node of exportNodes) {
124
+ const { line } = bridgeGetLineAndColumn(node);
125
+ // Check for type-only exports
126
+ const raw = node.raw;
127
+ const isTypeOnly = raw?.children?.some(c => !c.isNamed && c.type === 'type') ?? false;
128
+ // export clause with named exports
129
+ const exportClause = findChildOfType(node, 'export_clause');
130
+ if (exportClause) {
131
+ const namedExports = findChildOfType(exportClause, 'named_exports');
132
+ if (namedExports) {
133
+ for (const child of namedExports.children ?? []) {
134
+ if (child.type !== 'export_specifier')
135
+ continue;
136
+ const ids = child.children?.filter(c => c.type === 'identifier') ?? [];
137
+ if (ids.length > 0) {
138
+ exports.push({
139
+ name: rawText(ids[ids.length - 1]),
140
+ isDefault: false,
141
+ isTypeOnly,
142
+ line
143
+ });
144
+ }
145
+ }
89
146
  }
90
147
  }
91
- else if (ts.isExportAssignment(node)) {
92
- const { line } = getLineAndColumn(sourceFile, node.getStart());
93
- exports.push({
94
- name: 'default',
95
- isDefault: true,
96
- isTypeOnly: false,
97
- line
98
- });
148
+ // Check for `default` keyword — export default X
149
+ const isDefault = raw?.children?.some(c => !c.isNamed && c.type === 'default') ?? false;
150
+ if (isDefault) {
151
+ const exported = node.children?.find(c => c.type === 'identifier' || c.type === 'function_declaration' ||
152
+ c.type === 'class_declaration' || c.type === 'call_expression');
153
+ if (exported) {
154
+ const nameNode = findChildOfType(exported, 'identifier');
155
+ exports.push({
156
+ name: nameNode ? rawText(nameNode) : 'default',
157
+ isDefault: true,
158
+ isTypeOnly,
159
+ line
160
+ });
161
+ }
99
162
  }
100
- });
163
+ }
101
164
  return exports;
102
165
  }
166
+ // ---------------------------------------------------------------------------
167
+ // Function finding
168
+ // ---------------------------------------------------------------------------
103
169
  /**
104
- * Check if a node is exported
170
+ * Find all function declarations in the AST.
105
171
  */
106
- export function isExported(node) {
107
- return ((ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0);
172
+ export function findFunctions(root) {
173
+ return findNodes(root, n => n.type === 'function_declaration');
108
174
  }
175
+ // ---------------------------------------------------------------------------
176
+ // Class finding
177
+ // ---------------------------------------------------------------------------
109
178
  /**
110
- * Find all function declarations
179
+ * Find all class declarations in the AST.
111
180
  */
112
- export function findFunctions(sourceFile) {
113
- return findNodesByKind(sourceFile, ts.SyntaxKind.FunctionDeclaration);
181
+ export function findClasses(root) {
182
+ return findNodes(root, n => n.type === 'class_declaration');
114
183
  }
184
+ // ---------------------------------------------------------------------------
185
+ // AST node inspection
186
+ // ---------------------------------------------------------------------------
115
187
  /**
116
- * Find all class declarations
117
- */
118
- export function findClasses(sourceFile) {
119
- return findNodesByKind(sourceFile, ts.SyntaxKind.ClassDeclaration);
120
- }
121
- /**
122
- * Get AST node for inspection
188
+ * Get AST node for inspection/debugging.
123
189
  */
124
190
  export function getASTNode(node) {
125
191
  return {
126
- kind: ts.SyntaxKind[node.kind],
127
- text: node.getText?.() || '',
128
- children: node.getChildren?.().map(child => getASTNode(child)) || []
192
+ type: node.type,
193
+ text: rawText(node),
194
+ children: (node.children ?? []).map(child => getASTNode(child))
129
195
  };
130
196
  }
197
+ // ---------------------------------------------------------------------------
198
+ // Decorator checks
199
+ // ---------------------------------------------------------------------------
131
200
  /**
132
- * Calculate cyclomatic complexity of a function/method
133
- */
134
- export function calculateComplexity(node) {
135
- let complexity = 1; // Base complexity
136
- function visit(node) {
137
- switch (node.kind) {
138
- case ts.SyntaxKind.IfStatement:
139
- case ts.SyntaxKind.WhileStatement:
140
- case ts.SyntaxKind.ForStatement:
141
- case ts.SyntaxKind.ForInStatement:
142
- case ts.SyntaxKind.ForOfStatement:
143
- case ts.SyntaxKind.ConditionalExpression:
144
- case ts.SyntaxKind.CatchClause:
145
- case ts.SyntaxKind.CaseClause:
146
- complexity++;
147
- break;
148
- case ts.SyntaxKind.BinaryExpression:
149
- const binary = node;
150
- if (binary.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||
151
- binary.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
152
- complexity++;
153
- }
154
- break;
155
- }
156
- ts.forEachChild(node, visit);
157
- }
158
- if (node.body) {
159
- visit(node.body);
160
- }
161
- return complexity;
162
- }
163
- /**
164
- * Check if a node has a specific decorator
201
+ * Check if a node has a specific decorator.
202
+ * Tree-sitter parses decorators as `decorator` nodes.
165
203
  */
166
204
  export function hasDecorator(node, decoratorName) {
167
- if (!ts.canHaveDecorators(node)) {
168
- return false;
169
- }
170
- const decorators = ts.getDecorators(node);
171
- if (!decorators) {
172
- return false;
173
- }
205
+ const decorators = findNodes(node, n => n.type === 'decorator');
174
206
  return decorators.some(decorator => {
175
- if (ts.isCallExpression(decorator.expression)) {
176
- const expression = decorator.expression.expression;
177
- return ts.isIdentifier(expression) && expression.text === decoratorName;
207
+ // decorator → call_expression → identifier (e.g., @Component())
208
+ const callExpr = findChildOfType(decorator, 'call_expression');
209
+ if (callExpr) {
210
+ const callee = callExpr.children?.[0];
211
+ if (callee?.type === 'identifier' && rawText(callee) === decoratorName) {
212
+ return true;
213
+ }
214
+ }
215
+ // decorator → identifier (e.g., @deprecated)
216
+ const id = findChildOfType(decorator, 'identifier');
217
+ if (id && rawText(id) === decoratorName) {
218
+ return true;
178
219
  }
179
- return ts.isIdentifier(decorator.expression) &&
180
- decorator.expression.text === decoratorName;
220
+ return false;
181
221
  });
182
222
  }
223
+ // ---------------------------------------------------------------------------
224
+ // Class method extraction
225
+ // ---------------------------------------------------------------------------
183
226
  /**
184
- * Get method names from a class
227
+ * Get method names from a class declaration node.
228
+ * Tree-sitter: class_declaration → class_body → method_definition / public_field_definition
185
229
  */
186
230
  export function getClassMethods(classNode) {
187
231
  const methods = [];
188
- classNode.members.forEach(member => {
189
- if (ts.isMethodDeclaration(member) && member.name && ts.isIdentifier(member.name)) {
190
- methods.push(member.name.text);
232
+ const classBody = findChildOfType(classNode, 'class_body');
233
+ if (!classBody)
234
+ return methods;
235
+ for (const member of classBody.children ?? []) {
236
+ if (member.type === 'method_definition' || member.type === 'public_field_definition') {
237
+ const nameNode = member.children?.find(c => c.type === 'identifier' || c.type === 'property_identifier');
238
+ if (nameNode) {
239
+ methods.push(rawText(nameNode));
240
+ }
191
241
  }
192
- });
242
+ }
193
243
  return methods;
194
244
  }
245
+ // ---------------------------------------------------------------------------
246
+ // Line counting
247
+ // ---------------------------------------------------------------------------
195
248
  /**
196
- * Count lines of code (excluding comments and empty lines)
249
+ * Count lines of code (excluding comments and empty lines).
250
+ * Takes source text directly instead of ts.SourceFile.
197
251
  */
198
- export function countLinesOfCode(sourceFile) {
199
- const text = sourceFile.getFullText();
200
- const lines = text.split('\n');
252
+ export function countLinesOfCode(sourceCode) {
253
+ const lines = sourceCode.split('\n');
201
254
  let count = 0;
202
255
  for (const line of lines) {
203
256
  const trimmed = line.trim();
204
- if (trimmed && !trimmed.startsWith('//') && !trimmed.startsWith('/*')) {
257
+ if (trimmed && !trimmed.startsWith('//') && !trimmed.startsWith('/*') && !trimmed.startsWith('*')) {
205
258
  count++;
206
259
  }
207
260
  }
208
261
  return count;
209
262
  }
263
+ // ---------------------------------------------------------------------------
264
+ // Variable declaration finding
265
+ // ---------------------------------------------------------------------------
210
266
  /**
211
- * Find all variable declarations
267
+ * Find all variable declarations in the AST.
268
+ * Tree-sitter: variable_declarator nodes.
212
269
  */
213
- export function findVariableDeclarations(sourceFile) {
214
- const declarations = [];
215
- function visit(node) {
216
- if (ts.isVariableDeclaration(node)) {
217
- declarations.push(node);
218
- }
219
- ts.forEachChild(node, visit);
220
- }
221
- visit(sourceFile);
222
- return declarations;
270
+ export function findVariableDeclarations(root) {
271
+ return findNodes(root, n => n.type === 'variable_declarator');
223
272
  }
273
+ // ---------------------------------------------------------------------------
274
+ // Async function check
275
+ // ---------------------------------------------------------------------------
224
276
  /**
225
- * Check if a function is async
277
+ * Check if a function node is async.
226
278
  */
227
279
  export function isAsyncFunction(node) {
228
- return !!(node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.AsyncKeyword));
280
+ return hasModifier(node, 'async');
229
281
  }
282
+ // ---------------------------------------------------------------------------
283
+ // Parameter count
284
+ // ---------------------------------------------------------------------------
230
285
  /**
231
- * Get parameter count for a function
286
+ * Get parameter count for a function/method node.
287
+ * Tree-sitter: formal_parameters → required_parameter / optional_parameter.
232
288
  */
233
289
  export function getParameterCount(node) {
234
- return node.parameters.length;
290
+ const params = findChildOfType(node, 'formal_parameters');
291
+ if (!params)
292
+ return 0;
293
+ let count = 0;
294
+ for (const child of params.children ?? []) {
295
+ if (child.type === 'required_parameter' || child.type === 'optional_parameter' ||
296
+ child.type === 'rest_parameter') {
297
+ count++;
298
+ }
299
+ }
300
+ return count;
235
301
  }
302
+ // ---------------------------------------------------------------------------
303
+ // Type alias finding
304
+ // ---------------------------------------------------------------------------
236
305
  /**
237
- * Find all type aliases
306
+ * Find all type aliases in the AST.
307
+ * Tree-sitter: type_alias_declaration nodes.
238
308
  */
239
- export function findTypeAliases(sourceFile) {
240
- return findNodesByKind(sourceFile, ts.SyntaxKind.TypeAliasDeclaration);
309
+ export function findTypeAliases(root) {
310
+ return findNodes(root, n => n.type === 'type_alias_declaration');
241
311
  }
312
+ // ---------------------------------------------------------------------------
313
+ // Interface finding
314
+ // ---------------------------------------------------------------------------
242
315
  /**
243
- * Find all interfaces
316
+ * Find all interface declarations in the AST.
317
+ * Tree-sitter: interface_declaration nodes.
244
318
  */
245
- export function findInterfaces(sourceFile) {
246
- return findNodesByKind(sourceFile, ts.SyntaxKind.InterfaceDeclaration);
319
+ export function findInterfaces(root) {
320
+ return findNodes(root, n => n.type === 'interface_declaration');
247
321
  }
322
+ // ---------------------------------------------------------------------------
323
+ // File parsing
324
+ // ---------------------------------------------------------------------------
248
325
  /**
249
- * Parse a TypeScript file
326
+ * Parse a TypeScript file and return an AST.
327
+ * Uses the adapterBridge parseFile function.
250
328
  */
251
329
  export async function parseTypeScriptFile(filePath) {
330
+ // Dynamic import to avoid circular dependency
331
+ const { parseFile } = await import('../languages/adapterBridge.js');
252
332
  const fs = await import('fs').then(m => m.promises);
253
333
  const content = await fs.readFile(filePath, 'utf-8');
254
- const compilerOptions = {
255
- target: ts.ScriptTarget.Latest,
256
- module: ts.ModuleKind.ESNext,
257
- jsx: ts.JsxEmit.React,
258
- lib: ['es2020', 'dom'],
259
- skipLibCheck: true,
260
- skipDefaultLibCheck: true,
261
- allowJs: true,
262
- checkJs: false,
263
- strict: false,
264
- noResolve: true,
265
- noLib: false,
266
- moduleResolution: ts.ModuleResolutionKind.NodeJs
267
- };
268
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
269
- // For now, just return the source file without full type checking
270
- // This avoids the need for a full TypeScript compiler host setup
271
- const errors = [];
272
- // Check for basic syntax errors by walking the AST
273
- function checkSyntax(node) {
274
- if (node.kind === ts.SyntaxKind.Unknown) {
275
- errors.push({
276
- file: sourceFile,
277
- start: node.getStart(),
278
- length: node.getWidth(),
279
- messageText: 'Syntax error',
280
- category: ts.DiagnosticCategory.Error,
281
- code: 1000
282
- });
283
- }
284
- ts.forEachChild(node, checkSyntax);
334
+ const ast = parseFile(filePath, content);
335
+ if (!ast) {
336
+ const failLocation = { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } };
337
+ const failAst = { root: { type: 'source_file', range: [0, 0], location: failLocation, raw: null }, language: 'unknown', filePath, errors: [{ message: 'Failed to parse file', location: failLocation, severity: 'error' }] };
338
+ return { ast: failAst, errors: [{ message: 'Failed to parse file', line: 0, column: 0 }] };
285
339
  }
286
- checkSyntax(sourceFile);
287
- return { sourceFile, errors };
340
+ return { ast, errors: ast.errors ?? [] };
288
341
  }
342
+ // ---------------------------------------------------------------------------
343
+ // Detailed imports
344
+ // ---------------------------------------------------------------------------
289
345
  /**
290
- * Enhanced version of getImports that returns detailed ImportMapping[]
346
+ * Enhanced version of getImports that returns detailed ImportMapping[].
347
+ * Uses tree-sitter import_statement traversal.
291
348
  */
292
- export function getImportsDetailed(sourceFile) {
349
+ export function getImportsDetailed(root) {
293
350
  const imports = [];
294
- ts.forEachChild(sourceFile, node => {
295
- if (ts.isImportDeclaration(node)) {
296
- const moduleSpecifier = node.moduleSpecifier.text;
297
- const importClause = node.importClause;
298
- if (importClause) {
299
- // Default import
300
- if (importClause.name) {
301
- imports.push({
302
- localName: importClause.name.text,
303
- importedName: 'default',
304
- modulePath: moduleSpecifier,
305
- importType: 'default',
306
- isTypeOnly: importClause.isTypeOnly || false
307
- });
308
- }
309
- // Named imports
310
- if (importClause.namedBindings) {
311
- if (ts.isNamespaceImport(importClause.namedBindings)) {
312
- imports.push({
313
- localName: importClause.namedBindings.name.text,
314
- importedName: '*',
315
- modulePath: moduleSpecifier,
316
- importType: 'namespace',
317
- isTypeOnly: importClause.isTypeOnly || false
318
- });
319
- }
320
- else if (ts.isNamedImports(importClause.namedBindings)) {
321
- importClause.namedBindings.elements.forEach(element => {
322
- imports.push({
323
- localName: element.name.text,
324
- importedName: element.propertyName?.text || element.name.text,
325
- modulePath: moduleSpecifier,
326
- importType: 'named',
327
- isTypeOnly: importClause.isTypeOnly || element.isTypeOnly || false
328
- });
329
- });
330
- }
331
- }
351
+ const importNodes = findNodes(root, n => n.type === 'import_statement');
352
+ for (const node of importNodes) {
353
+ const moduleNode = findChildOfType(node, 'string');
354
+ if (!moduleNode)
355
+ continue;
356
+ const moduleSpecifier = rawText(moduleNode).replace(/^["']|["']$/g, '');
357
+ const importClause = findChildOfType(node, 'import_clause');
358
+ if (!importClause) {
359
+ // Side-effect import (no import clause)
360
+ imports.push({
361
+ localName: `[side-effect]::${moduleSpecifier}`,
362
+ importedName: '[side-effect]',
363
+ modulePath: moduleSpecifier,
364
+ importType: 'namespace', // side-effect imports treated as namespace
365
+ isTypeOnly: false
366
+ });
367
+ continue;
368
+ }
369
+ const raw = importClause.raw;
370
+ const isTypeOnly = raw?.children?.some(c => !c.isNamed && c.type === 'type') ?? false;
371
+ // Default import
372
+ const defaultId = importClause.children?.find(c => c.type === 'identifier');
373
+ if (defaultId) {
374
+ imports.push({
375
+ localName: rawText(defaultId),
376
+ importedName: 'default',
377
+ modulePath: moduleSpecifier,
378
+ importType: 'default',
379
+ isTypeOnly: isTypeOnly || false
380
+ });
381
+ }
382
+ // Named imports
383
+ const namedImports = findChildOfType(importClause, 'named_imports');
384
+ if (namedImports) {
385
+ for (const child of namedImports.children ?? []) {
386
+ if (child.type !== 'import_specifier')
387
+ continue;
388
+ const identifiers = child.children?.filter(c => c.type === 'identifier') ?? [];
389
+ if (identifiers.length === 0)
390
+ continue;
391
+ const localName = rawText(identifiers[identifiers.length - 1]);
392
+ const importedName = identifiers.length > 1 ? rawText(identifiers[0]) : localName;
393
+ imports.push({
394
+ localName,
395
+ importedName,
396
+ modulePath: moduleSpecifier,
397
+ importType: 'named',
398
+ isTypeOnly: isTypeOnly || false
399
+ });
332
400
  }
333
- else {
334
- // Side-effect import (no import clause) - e.g., import './polyfills'
401
+ }
402
+ // Namespace import
403
+ const nsImport = findChildOfType(importClause, 'namespace_import');
404
+ if (nsImport) {
405
+ const nsId = findChildOfType(nsImport, 'identifier');
406
+ if (nsId) {
335
407
  imports.push({
336
- localName: `[side-effect]::${moduleSpecifier}`,
337
- importedName: '[side-effect]',
408
+ localName: rawText(nsId),
409
+ importedName: '*',
338
410
  modulePath: moduleSpecifier,
339
- importType: 'side-effect',
340
- isTypeOnly: false
411
+ importType: 'namespace',
412
+ isTypeOnly: isTypeOnly || false
341
413
  });
342
414
  }
343
415
  }
344
- });
416
+ }
345
417
  return imports;
346
418
  }
419
+ // ---------------------------------------------------------------------------
420
+ // Re-exports
421
+ // ---------------------------------------------------------------------------
347
422
  /**
348
- * Get re-exports from a source file
423
+ * Get re-exports from a source file.
424
+ * Tree-sitter: export_statement → string (module specifier).
349
425
  */
350
- export function getReExports(sourceFile) {
426
+ export function getReExports(root) {
351
427
  const reExports = [];
352
- ts.forEachChild(sourceFile, node => {
353
- // Handle export declarations with module specifier - e.g., export { x } from './y'
354
- if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
355
- const moduleSpecifier = node.moduleSpecifier.text;
356
- if (node.exportClause && ts.isNamedExports(node.exportClause)) {
357
- node.exportClause.elements.forEach(element => {
358
- reExports.push({
359
- name: element.propertyName?.text || element.name.text,
360
- module: moduleSpecifier
361
- });
362
- });
363
- }
364
- else if (!node.exportClause) {
365
- // export * from './module'
366
- reExports.push({
367
- name: '*',
368
- module: moduleSpecifier
369
- });
428
+ const exportNodes = findNodes(root, n => n.type === 'export_statement' || n.type === 'export_declaration');
429
+ for (const node of exportNodes) {
430
+ // Check if there's a module specifier (export { x } from './y')
431
+ const moduleNode = findChildOfType(node, 'string');
432
+ if (!moduleNode)
433
+ continue;
434
+ const moduleSpecifier = rawText(moduleNode).replace(/^["']|["']$/g, '');
435
+ const exportClause = findChildOfType(node, 'export_clause');
436
+ if (exportClause) {
437
+ const namedExports = findChildOfType(exportClause, 'named_exports');
438
+ if (namedExports) {
439
+ for (const child of namedExports.children ?? []) {
440
+ if (child.type !== 'export_specifier')
441
+ continue;
442
+ const identifiers = child.children?.filter(c => c.type === 'identifier') ?? [];
443
+ if (identifiers.length > 0) {
444
+ const name = identifiers.length > 1
445
+ ? rawText(identifiers[0])
446
+ : rawText(identifiers[identifiers.length - 1]);
447
+ reExports.push({ name, module: moduleSpecifier });
448
+ }
449
+ }
370
450
  }
371
451
  }
372
- });
452
+ else if (!exportClause) {
453
+ // export * from './module' — no export clause
454
+ reExports.push({ name: '*', module: moduleSpecifier });
455
+ }
456
+ }
373
457
  return reExports;
374
458
  }
459
+ // ---------------------------------------------------------------------------
460
+ // Identifier usage extraction
461
+ // ---------------------------------------------------------------------------
462
+ /**
463
+ * Check whether an identifier node is used in a type-only position.
464
+ *
465
+ * Tree-sitter equivalence mapping for the original TS API checks:
466
+ *
467
+ * | TS API check | Tree-sitter equivalent |
468
+ * |------------------------------------|----------------------------------------|
469
+ * | ts.isTypeNode(p) | p.type === 'type_annotation' |
470
+ * | ts.isTypeReferenceNode(p) | p.type === 'type_reference' |
471
+ * | ts.isTypeQueryNode(p) | p.type === 'typeof_expression' |
472
+ * | ts.isQualifiedName(p) | p.type === 'qualified_name' |
473
+ * | ts.isExpressionWithTypeArguments(p)| p.type === 'generic_type' |
474
+ * | ts.isPropertyAccessExpression(p) | p.type === 'member_expression' |
475
+ * | ts.isHeritageClause(p) | p.type === 'heritage_clause' |
476
+ * | ts.isInterfaceDeclaration(p) | p.type === 'interface_declaration' |
477
+ * | ts.isTypeAliasDeclaration(p) | p.type === 'type_alias_declaration' |
478
+ * | ts.isClassDeclaration(p) | p.type === 'class_declaration' |
479
+ * | ts.isTypeParameterDeclaration(p) | p.type === 'type_parameter' |
480
+ * | ts.isVariableDeclaration(p) | p.type === 'variable_declarator' |
481
+ * | ts.isAsExpression(p) | p.type === 'as_expression' |
482
+ * | ts.isTypeAssertionExpression(p) | p.type === 'type_assertion' |
483
+ * | ts.isSatisfiesExpression(p) | (not directly; check parent) |
484
+ * | ts.isTypeReferenceNode(p) | p.type === 'type_identifier' |
485
+ * | ts.isUnionTypeNode(p) | p.type === 'union_type' |
486
+ * | ts.isIntersectionTypeNode(p) | p.type === 'intersection_type' |
487
+ * | ts.isConditionalTypeNode(p) | p.type === 'conditional_type' |
488
+ * | ts.isMappedTypeNode(p) | p.type === 'mapped_type_clause' |
489
+ * | ts.isIndexSignatureDeclaration(p) | p.type === 'index_signature' |
490
+ * | ts.isTypePredicateNode(p) | p.type === 'type_predicate' |
491
+ * | ts.isMethodDeclaration(p) | p.type === 'method_definition' |
492
+ * | ts.isMethodSignature(p) | p.type === 'method_signature' |
493
+ * | ts.isPropertyDeclaration(p) | p.type === 'class_property' |
494
+ * | ts.isPropertySignature(p) | p.type === 'property_signature' |
495
+ * | ts.isGetAccessorDeclaration(p) | p.type === 'get_accessor' |
496
+ * | ts.isFunctionDeclaration(p) | p.type === 'function_declaration' |
497
+ * | ts.isArrowFunction(p) | p.type === 'arrow_function' |
498
+ * | ts.isFunctionExpression(p) | p.type === 'function_expression' |
499
+ * | ts.isParameter(p) | p.type === 'required_parameter' |
500
+ * | ts.isCallExpression(p) | p.type === 'call_expression' |
501
+ * | ts.isNewExpression(p) | p.type === 'new_expression' |
502
+ * | ts.isTaggedTemplateExpression(p) | p.type === 'tagged_template_literal' |
503
+ * | ts.isImportDeclaration(p) | p.type === 'import_statement' |
504
+ * | ts.isImportSpecifier(p) | p.type === 'import_specifier' |
505
+ * | ts.isImportClause(p) | p.type === 'import_clause' |
506
+ * | ts.isNamedImports(p) | p.type === 'named_imports' |
507
+ * | ts.isExportSpecifier(p) | p.type === 'export_specifier' |
508
+ * | ts.isJsxElement(p) | p.type === 'jsx_element' |
509
+ * | ts.isJsxSelfClosingElement(p) | p.type === 'jsx_self_closing_element' |
510
+ * | ts.isDecorator(p) | p.type === 'decorator' |
511
+ * | ts.isSpreadElement(p) | p.type === 'spread_element' |
512
+ * | ts.isSpreadAssignment(p) | p.type === 'spread_element' |
513
+ * | ts.isShorthandPropertyAssignment(p)| p.type === 'shorthand_property_identifier' |
514
+ * | ts.isPropertyAssignment(p) | p.type === 'pair' with 'property_identifier' child |
515
+ * | ts.isIdentifier(p) | p.type === 'identifier' |
516
+ * | ts.isElementAccessExpression(p) | p.type === 'subscript_expression' |
517
+ */
518
+ /** Set of tree-sitter node types that represent type positions */
519
+ const TYPE_NODE_TYPES = new Set([
520
+ 'type_annotation',
521
+ 'type_identifier',
522
+ 'generic_type',
523
+ 'qualified_name',
524
+ 'union_type',
525
+ 'intersection_type',
526
+ 'conditional_type',
527
+ 'mapped_type_clause',
528
+ 'index_signature',
529
+ 'type_predicate',
530
+ 'predefined_type',
531
+ 'string_type',
532
+ 'number_type',
533
+ 'boolean_type',
534
+ 'object_type',
535
+ 'array_type',
536
+ 'tuple_type',
537
+ 'function_type',
538
+ 'constructor_type',
539
+ 'typeof_expression',
540
+ 'template_type',
541
+ 'literal_type',
542
+ 'lookup_type',
543
+ 'this_type',
544
+ 'optional_type',
545
+ 'rest_type',
546
+ ]);
547
+ /** Set of declaration node types that can have heritage clauses or type params */
548
+ const DECLARATION_TYPES = new Set([
549
+ 'function_declaration',
550
+ 'method_definition',
551
+ 'method_signature',
552
+ 'arrow_function',
553
+ 'function_expression',
554
+ 'variable_declarator',
555
+ 'class_declaration',
556
+ 'interface_declaration',
557
+ 'type_alias_declaration',
558
+ ]);
559
+ /** Set of node types that represent spreads */
560
+ const SPREAD_TYPES = new Set(['spread_element', 'rest_parameter']);
561
+ /**
562
+ * Recursively check if the identifier node is contained within the given type node.
563
+ */
564
+ function isNodeInTypePosition(identifier, typeNode) {
565
+ let found = false;
566
+ function checkNode(node) {
567
+ if (found)
568
+ return;
569
+ if (node === identifier) {
570
+ found = true;
571
+ return;
572
+ }
573
+ for (const child of node.children ?? []) {
574
+ checkNode(child);
575
+ }
576
+ }
577
+ checkNode(typeNode);
578
+ return found;
579
+ }
580
+ /**
581
+ * Check if an identifier node is used only as a type.
582
+ * Uses tree-sitter node type checks instead of TS API's `isTypeNode` etc.
583
+ */
584
+ function isTypeOnlyUsage(identifier) {
585
+ const parent = identifier.parent;
586
+ if (!parent)
587
+ return false;
588
+ // Direct type position — parent is a type_annotation, type_reference, etc.
589
+ if (TYPE_NODE_TYPES.has(parent.type)) {
590
+ return true;
591
+ }
592
+ // Type query: `typeof X`
593
+ if (parent.type === 'typeof_expression') {
594
+ return true;
595
+ }
596
+ // Qualified name in type position
597
+ if (parent.type === 'qualified_name' && parent.children?.[0] === identifier) {
598
+ return isTypeOnlyUsage(parent);
599
+ }
600
+ // Generic type arguments: `SomeType<X>` where X is the identifier
601
+ if (parent.type === 'generic_type' && parent.children?.[0] === identifier) {
602
+ const heritageClause = parent.parent;
603
+ if (heritageClause?.type === 'heritage_clause') {
604
+ const raw = heritageClause.raw;
605
+ const isExtends = raw?.children?.some(c => !c.isNamed && c.type === 'extends');
606
+ if (isExtends) {
607
+ const interfaceNode = heritageClause.parent;
608
+ if (interfaceNode?.type === 'interface_declaration') {
609
+ return true;
610
+ }
611
+ }
612
+ }
613
+ }
614
+ // `namespace.Type` in type position — check if left side is identifier
615
+ if (parent.type === 'member_expression' && parent.children?.[0] === identifier) {
616
+ const grandParent = parent.parent;
617
+ if (grandParent?.type === 'generic_type') {
618
+ const heritageClause = grandParent.parent;
619
+ if (heritageClause?.type === 'heritage_clause') {
620
+ const raw = heritageClause.raw;
621
+ const isExtends = raw?.children?.some(c => !c.isNamed && c.type === 'extends');
622
+ if (isExtends) {
623
+ const interfaceNode = heritageClause.parent;
624
+ if (interfaceNode?.type === 'interface_declaration') {
625
+ return true;
626
+ }
627
+ }
628
+ }
629
+ }
630
+ }
631
+ // Type alias: `type X = SomeType`
632
+ if (parent.type === 'type_alias_declaration') {
633
+ const typeAnnotation = findChildOfType(parent, 'type_annotation');
634
+ if (typeAnnotation) {
635
+ return isNodeInTypePosition(identifier, typeAnnotation);
636
+ }
637
+ }
638
+ // Class implements: `class X implements SomeType`
639
+ if (parent.type === 'class_declaration') {
640
+ for (const child of parent.children ?? []) {
641
+ if (child.type !== 'heritage_clause')
642
+ continue;
643
+ const raw = child.raw;
644
+ const isImplements = raw?.children?.some(c => !c.isNamed && c.type === 'implements');
645
+ if (!isImplements)
646
+ continue;
647
+ for (const typeNode of child.children ?? []) {
648
+ if (typeNode === identifier)
649
+ return true;
650
+ if (typeNode.type === 'member_expression' && typeNode.children?.[0] === identifier)
651
+ return true;
652
+ if (typeNode.type === 'generic_type' && typeNode.children?.[0] === identifier)
653
+ return true;
654
+ }
655
+ }
656
+ }
657
+ // Generic constraints: `function test<T extends SomeType>()`
658
+ if (parent.type === 'type_parameter') {
659
+ const constraint = findChildOfType(parent, 'type_annotation'); // or constraint
660
+ if (constraint) {
661
+ return isNodeInTypePosition(identifier, constraint);
662
+ }
663
+ // Also check for generic_type in constraint position
664
+ for (const child of parent.children ?? []) {
665
+ if (child.type !== 'identifier' && child.type !== 'type_parameter') {
666
+ if (isNodeInTypePosition(identifier, child))
667
+ return true;
668
+ }
669
+ }
670
+ }
671
+ // Type annotations in variable declarations: `const x: SomeType = ...`
672
+ if (parent.type === 'variable_declarator') {
673
+ const typeAnnot = findChildOfType(parent, 'type_annotation');
674
+ if (typeAnnot && isNodeInTypePosition(identifier, typeAnnot))
675
+ return true;
676
+ }
677
+ // Type assertions: `value as SomeType` or `<SomeType>value`
678
+ if (parent.type === 'as_expression') {
679
+ const typeNode = parent.children?.find(c => c.type !== 'identifier' && c.type !== 'as');
680
+ if (typeNode && isNodeInTypePosition(identifier, typeNode))
681
+ return true;
682
+ }
683
+ if (parent.type === 'type_assertion') {
684
+ const typeNode = findChildOfType(parent, 'type_annotation');
685
+ if (typeNode && isNodeInTypePosition(identifier, typeNode))
686
+ return true;
687
+ }
688
+ // Type parameters/arguments: `Array<SomeType>`, `Promise<SomeType>`
689
+ if (parent.type === 'type_identifier' || parent.type === 'generic_type') {
690
+ const typeArgs = findChildOfType(parent, 'type_arguments');
691
+ if (typeArgs) {
692
+ for (const arg of typeArgs.children ?? []) {
693
+ if (isNodeInTypePosition(identifier, arg))
694
+ return true;
695
+ }
696
+ }
697
+ }
698
+ // Return type annotations: `function test(): SomeType`
699
+ if (DECLARATION_TYPES.has(parent.type)) {
700
+ const typeAnnot = findChildOfType(parent, 'type_annotation');
701
+ if (typeAnnot && isNodeInTypePosition(identifier, typeAnnot))
702
+ return true;
703
+ }
704
+ // Parameter type annotations: `function test(x: SomeType)`
705
+ if (parent.type === 'required_parameter' || parent.type === 'optional_parameter') {
706
+ const typeAnnot = findChildOfType(parent, 'type_annotation');
707
+ if (typeAnnot && isNodeInTypePosition(identifier, typeAnnot))
708
+ return true;
709
+ }
710
+ // Property type annotations: `{ prop: SomeType }` or `class { prop: SomeType }`
711
+ if (parent.type === 'property_signature' || parent.type === 'class_property') {
712
+ const typeAnnot = findChildOfType(parent, 'type_annotation');
713
+ if (typeAnnot && isNodeInTypePosition(identifier, typeAnnot))
714
+ return true;
715
+ }
716
+ // Index signature: `{ [key: string]: SomeType }`
717
+ if (parent.type === 'index_signature') {
718
+ const typeAnnot = findChildOfType(parent, 'type_annotation');
719
+ if (typeAnnot && isNodeInTypePosition(identifier, typeAnnot))
720
+ return true;
721
+ }
722
+ // Mapped type constraint or type
723
+ if (parent.type === 'mapped_type_clause') {
724
+ const typeParam = findChildOfType(parent, 'type_parameter');
725
+ if (typeParam) {
726
+ const constraint = findChildOfType(typeParam, 'type_annotation');
727
+ if (constraint && isNodeInTypePosition(identifier, constraint))
728
+ return true;
729
+ }
730
+ const typeAnnot = findChildOfType(parent, 'type_annotation');
731
+ if (typeAnnot && isNodeInTypePosition(identifier, typeAnnot))
732
+ return true;
733
+ }
734
+ // Conditional types: `T extends SomeType ? X : Y`
735
+ if (parent.type === 'conditional_type') {
736
+ for (const child of parent.children ?? []) {
737
+ if (isNodeInTypePosition(identifier, child))
738
+ return true;
739
+ }
740
+ }
741
+ // Union and intersection types
742
+ if (parent.type === 'union_type' || parent.type === 'intersection_type') {
743
+ for (const child of parent.children ?? []) {
744
+ if (isNodeInTypePosition(identifier, child))
745
+ return true;
746
+ }
747
+ }
748
+ // Type predicate: `function isX(value: any): value is SomeType`
749
+ if (parent.type === 'type_predicate') {
750
+ const annot = findChildOfType(parent, 'type_annotation');
751
+ if (annot && isNodeInTypePosition(identifier, annot))
752
+ return true;
753
+ }
754
+ // Walk up: if parent is itself in a type position, check further up
755
+ if (parent.parent) {
756
+ // Heritage clauses
757
+ if (parent.type === 'generic_type' && parent.parent.type === 'heritage_clause') {
758
+ return true;
759
+ }
760
+ // Type arguments in call expressions: `func<SomeType>()`
761
+ if (parent.parent.type === 'call_expression') {
762
+ const typeArgs = findChildOfType(parent.parent, 'type_arguments');
763
+ if (typeArgs) {
764
+ for (const arg of typeArgs.children ?? []) {
765
+ if (isNodeInTypePosition(identifier, arg))
766
+ return true;
767
+ }
768
+ }
769
+ }
770
+ // Type arguments in new expressions: `new Class<SomeType>()`
771
+ if (parent.parent.type === 'new_expression') {
772
+ const typeArgs = findChildOfType(parent.parent, 'type_arguments');
773
+ if (typeArgs) {
774
+ for (const arg of typeArgs.children ?? []) {
775
+ if (isNodeInTypePosition(identifier, arg))
776
+ return true;
777
+ }
778
+ }
779
+ }
780
+ // Type arguments in tagged template expressions
781
+ if (parent.parent.type === 'tagged_template_literal') {
782
+ const typeArgs = findChildOfType(parent.parent, 'type_arguments');
783
+ if (typeArgs) {
784
+ for (const arg of typeArgs.children ?? []) {
785
+ if (isNodeInTypePosition(identifier, arg))
786
+ return true;
787
+ }
788
+ }
789
+ }
790
+ }
791
+ return false;
792
+ }
375
793
  /**
376
- * Extract identifier usage to track which imports are used
794
+ * Extract identifier usage to track which imports are used.
795
+ * Uses tree-sitter AST traversal with walkAST.
377
796
  */
378
- export function extractIdentifierUsage(node, sourceFile, importNames) {
797
+ export function extractIdentifierUsage(root, sourceCode, importNames) {
379
798
  const usageMap = new Map();
380
- function visit(node) {
381
- // Handle identifiers (most common case)
382
- if (ts.isIdentifier(node)) {
383
- const name = node.text;
799
+ walkAST(root, (node) => {
800
+ // --- identifiers ---
801
+ if (node.type === 'identifier') {
802
+ const name = rawText(node);
384
803
  if (importNames.has(name)) {
385
- // Check if this identifier should be counted as usage
386
804
  let shouldCount = true;
387
- // Skip if this is part of an import declaration
388
- let parent = node.parent;
389
- while (parent) {
390
- if (ts.isImportDeclaration(parent) || ts.isImportSpecifier(parent) ||
391
- ts.isImportClause(parent) || ts.isNamedImports(parent)) {
805
+ // Skip if part of an import declaration
806
+ let p = node.parent;
807
+ while (p) {
808
+ if (p.type === 'import_statement' || p.type === 'import_specifier' ||
809
+ p.type === 'import_clause' || p.type === 'named_imports') {
392
810
  shouldCount = false;
393
811
  break;
394
812
  }
395
- parent = parent.parent;
813
+ p = p.parent;
396
814
  }
397
- // For property access expressions, only count the leftmost identifier
398
- if (shouldCount && ts.isPropertyAccessExpression(node.parent)) {
399
- // Only count if this identifier is the expression (left side), not the name (right side)
400
- shouldCount = node.parent.expression === node;
815
+ // For member expressions, only count the leftmost (object) identifier
816
+ if (shouldCount && node.parent?.type === 'member_expression') {
817
+ shouldCount = node.parent.children?.[0] === node;
401
818
  }
402
- // Handle element access (dynamic property access) - e.g., config[key]
403
- if (shouldCount && ts.isElementAccessExpression(node.parent)) {
404
- shouldCount = node.parent.expression === node;
819
+ // For subscript expressions (element access), only count expression side
820
+ if (shouldCount && node.parent?.type === 'subscript_expression') {
821
+ shouldCount = node.parent.children?.[0] === node;
405
822
  }
406
823
  if (shouldCount) {
407
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
824
+ const { line } = bridgeGetLineAndColumn(node);
408
825
  const existing = usageMap.get(name) || {
409
826
  usageType: 'direct',
410
827
  usageCount: 0,
411
- lineNumbers: []
828
+ lineNumbers: [],
412
829
  };
413
830
  existing.usageCount++;
414
- existing.lineNumbers.push(line + 1);
415
- // Determine usage type - comprehensive type usage detection
831
+ existing.lineNumbers.push(line);
416
832
  if (isTypeOnlyUsage(node)) {
417
833
  existing.usageType = 'type';
418
834
  }
419
- else if (ts.isExportSpecifier(node.parent)) {
835
+ else if (node.parent?.type === 'export_specifier') {
420
836
  existing.usageType = 'reexport';
421
837
  }
422
838
  usageMap.set(name, existing);
423
839
  }
424
840
  }
425
841
  }
426
- // Handle spread operators - e.g., {...defaults}
427
- else if (ts.isSpreadElement(node) || ts.isSpreadAssignment(node)) {
428
- const expr = node.expression;
429
- if (ts.isIdentifier(expr) && importNames.has(expr.text)) {
430
- const { line } = sourceFile.getLineAndCharacterOfPosition(expr.getStart());
431
- const existing = usageMap.get(expr.text) || {
842
+ // --- spread elements ---
843
+ else if (SPREAD_TYPES.has(node.type)) {
844
+ const expr = node.children?.find(c => c.type !== '...');
845
+ if (expr?.type === 'identifier' && importNames.has(rawText(expr))) {
846
+ const { line } = bridgeGetLineAndColumn(expr);
847
+ const existing = usageMap.get(rawText(expr)) || {
432
848
  usageType: 'direct',
433
849
  usageCount: 0,
434
- lineNumbers: []
850
+ lineNumbers: [],
435
851
  };
436
852
  existing.usageCount++;
437
- existing.lineNumbers.push(line + 1);
438
- usageMap.set(expr.text, existing);
853
+ existing.lineNumbers.push(line);
854
+ usageMap.set(rawText(expr), existing);
439
855
  }
440
856
  }
441
- // Handle JSX elements - e.g., <Button /> or <Button.Primary />
442
- else if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
443
- const tagName = ts.isJsxElement(node) ? node.openingElement.tagName : node.tagName;
444
- if (ts.isIdentifier(tagName) && importNames.has(tagName.text)) {
445
- const { line } = sourceFile.getLineAndCharacterOfPosition(tagName.getStart());
446
- const existing = usageMap.get(tagName.text) || {
447
- usageType: 'direct',
448
- usageCount: 0,
449
- lineNumbers: []
450
- };
451
- existing.usageCount++;
452
- existing.lineNumbers.push(line + 1);
453
- usageMap.set(tagName.text, existing);
857
+ // --- JSX elements: <Button /> or <Button.Primary /> ---
858
+ else if (node.type === 'jsx_element' || node.type === 'jsx_self_closing_element') {
859
+ let tagNameNode;
860
+ if (node.type === 'jsx_element') {
861
+ const openTag = findChildOfType(node, 'open_tag');
862
+ if (openTag) {
863
+ tagNameNode = openTag.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
864
+ }
865
+ }
866
+ else {
867
+ tagNameNode = node.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
454
868
  }
455
- else if (ts.isPropertyAccessExpression(tagName)) {
456
- // Handle compound components like <Button.Primary />
457
- if (ts.isIdentifier(tagName.expression) && importNames.has(tagName.expression.text)) {
458
- const { line } = sourceFile.getLineAndCharacterOfPosition(tagName.expression.getStart());
459
- const existing = usageMap.get(tagName.expression.text) || {
869
+ if (tagNameNode) {
870
+ if (tagNameNode.type === 'identifier' && importNames.has(rawText(tagNameNode))) {
871
+ const { line } = bridgeGetLineAndColumn(tagNameNode);
872
+ const existing = usageMap.get(rawText(tagNameNode)) || {
460
873
  usageType: 'direct',
461
874
  usageCount: 0,
462
- lineNumbers: []
875
+ lineNumbers: [],
463
876
  };
464
877
  existing.usageCount++;
465
- existing.lineNumbers.push(line + 1);
466
- usageMap.set(tagName.expression.text, existing);
878
+ existing.lineNumbers.push(line);
879
+ usageMap.set(rawText(tagNameNode), existing);
880
+ }
881
+ else if (tagNameNode.type === 'member_expression') {
882
+ const leftmost = tagNameNode.children?.[0];
883
+ if (leftmost?.type === 'identifier' && importNames.has(rawText(leftmost))) {
884
+ const { line } = bridgeGetLineAndColumn(leftmost);
885
+ const existing = usageMap.get(rawText(leftmost)) || {
886
+ usageType: 'direct',
887
+ usageCount: 0,
888
+ lineNumbers: [],
889
+ };
890
+ existing.usageCount++;
891
+ existing.lineNumbers.push(line);
892
+ usageMap.set(rawText(leftmost), existing);
893
+ }
467
894
  }
468
895
  }
469
896
  }
470
- // Handle decorators - e.g., @withAuth
471
- else if (ts.isDecorator(node)) {
472
- const expr = node.expression;
473
- if (ts.isIdentifier(expr) && importNames.has(expr.text)) {
474
- const { line } = sourceFile.getLineAndCharacterOfPosition(expr.getStart());
475
- const existing = usageMap.get(expr.text) || {
897
+ // --- decorators: @withAuth ---
898
+ else if (node.type === 'decorator') {
899
+ // decorator identifier (e.g., @deprecated)
900
+ const id = findChildOfType(node, 'identifier');
901
+ if (id && importNames.has(rawText(id))) {
902
+ const { line } = bridgeGetLineAndColumn(id);
903
+ const existing = usageMap.get(rawText(id)) || {
476
904
  usageType: 'direct',
477
905
  usageCount: 0,
478
- lineNumbers: []
906
+ lineNumbers: [],
479
907
  };
480
908
  existing.usageCount++;
481
- existing.lineNumbers.push(line + 1);
482
- usageMap.set(expr.text, existing);
909
+ existing.lineNumbers.push(line);
910
+ usageMap.set(rawText(id), existing);
483
911
  }
484
- else if (ts.isCallExpression(expr) && ts.isIdentifier(expr.expression) &&
485
- importNames.has(expr.expression.text)) {
486
- const { line } = sourceFile.getLineAndCharacterOfPosition(expr.expression.getStart());
487
- const existing = usageMap.get(expr.expression.text) || {
912
+ // decorator → call_expression → identifier (e.g., @Component())
913
+ const callExpr = findChildOfType(node, 'call_expression');
914
+ if (callExpr) {
915
+ const callee = callExpr.children?.[0];
916
+ if (callee?.type === 'identifier' && importNames.has(rawText(callee))) {
917
+ const { line } = bridgeGetLineAndColumn(callee);
918
+ const existing = usageMap.get(rawText(callee)) || {
919
+ usageType: 'direct',
920
+ usageCount: 0,
921
+ lineNumbers: [],
922
+ };
923
+ existing.usageCount++;
924
+ existing.lineNumbers.push(line);
925
+ usageMap.set(rawText(callee), existing);
926
+ }
927
+ }
928
+ }
929
+ // --- Object literal property assignments: { key: ImportedValue } ---
930
+ else if (node.type === 'pair') {
931
+ const key = node.children?.find(c => c.type === 'property_identifier');
932
+ const value = node.children?.find(c => c.type === 'identifier' && c !== key);
933
+ if (value && importNames.has(rawText(value))) {
934
+ const { line } = bridgeGetLineAndColumn(value);
935
+ const existing = usageMap.get(rawText(value)) || {
488
936
  usageType: 'direct',
489
937
  usageCount: 0,
490
- lineNumbers: []
938
+ lineNumbers: [],
491
939
  };
492
940
  existing.usageCount++;
493
- existing.lineNumbers.push(line + 1);
494
- usageMap.set(expr.expression.text, existing);
941
+ existing.lineNumbers.push(line);
942
+ usageMap.set(rawText(value), existing);
495
943
  }
496
944
  }
497
- // Handle object literal property assignments for factory patterns
498
- else if (ts.isPropertyAssignment(node)) {
499
- // Check if the initializer is an imported identifier
500
- if (ts.isIdentifier(node.initializer) && importNames.has(node.initializer.text)) {
501
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.initializer.getStart());
502
- const existing = usageMap.get(node.initializer.text) || {
945
+ // --- Shorthand property assignments: { ComponentA, ComponentB } ---
946
+ else if (node.type === 'shorthand_property_identifier') {
947
+ // The value node is a reference to an imported name
948
+ const ref = node.children?.find(c => c.type === 'identifier');
949
+ if (ref && importNames.has(rawText(ref))) {
950
+ const { line } = bridgeGetLineAndColumn(ref);
951
+ const existing = usageMap.get(rawText(ref)) || {
503
952
  usageType: 'direct',
504
953
  usageCount: 0,
505
- lineNumbers: []
954
+ lineNumbers: [],
506
955
  };
507
956
  existing.usageCount++;
508
- existing.lineNumbers.push(line + 1);
509
- usageMap.set(node.initializer.text, existing);
957
+ existing.lineNumbers.push(line);
958
+ usageMap.set(rawText(ref), existing);
510
959
  }
511
- }
512
- // Handle shorthand property assignments - e.g., { ComponentA, ComponentB }
513
- else if (ts.isShorthandPropertyAssignment(node)) {
514
- if (importNames.has(node.name.text)) {
515
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.name.getStart());
516
- const existing = usageMap.get(node.name.text) || {
960
+ else if (ref && importNames.has(rawText(ref))) {
961
+ // shorthand_property_identifier might itself be just text
962
+ const { line } = bridgeGetLineAndColumn(node);
963
+ const existing = usageMap.get(rawText(node)) || {
517
964
  usageType: 'direct',
518
965
  usageCount: 0,
519
- lineNumbers: []
966
+ lineNumbers: [],
520
967
  };
521
968
  existing.usageCount++;
522
- existing.lineNumbers.push(line + 1);
523
- usageMap.set(node.name.text, existing);
524
- }
525
- }
526
- ts.forEachChild(node, visit);
527
- }
528
- /**
529
- * Comprehensive check for type-only usage patterns
530
- */
531
- function isTypeOnlyUsage(node) {
532
- let parent = node.parent;
533
- // Direct type node checks
534
- if (ts.isTypeNode(parent) || ts.isTypeReferenceNode(parent)) {
535
- return true;
536
- }
537
- // Type query (typeof X)
538
- if (ts.isTypeQueryNode(parent)) {
539
- return true;
540
- }
541
- // Qualified name in type position
542
- if (ts.isQualifiedName(parent) && parent.left === node) {
543
- return isTypeOnlyUsage(parent);
544
- }
545
- // Interface extension: interface X extends BaseType
546
- // Check if this identifier is used in an interface extends clause
547
- if (ts.isExpressionWithTypeArguments(parent) && parent.expression === node) {
548
- const heritageClause = parent.parent;
549
- if (ts.isHeritageClause(heritageClause) && heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {
550
- const interfaceDecl = heritageClause.parent;
551
- if (ts.isInterfaceDeclaration(interfaceDecl)) {
552
- return true;
553
- }
969
+ existing.lineNumbers.push(line);
970
+ usageMap.set(rawText(node), existing);
554
971
  }
555
972
  }
556
- // Also handle property access in interface extension: interface X extends Namespace.BaseType
557
- if (ts.isPropertyAccessExpression(parent) && parent.expression === node) {
558
- const grandParent = parent.parent;
559
- if (ts.isExpressionWithTypeArguments(grandParent) && grandParent.expression === parent) {
560
- const heritageClause = grandParent.parent;
561
- if (ts.isHeritageClause(heritageClause) && heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {
562
- const interfaceDecl = heritageClause.parent;
563
- if (ts.isInterfaceDeclaration(interfaceDecl)) {
564
- return true;
565
- }
566
- }
567
- }
568
- }
569
- // Type alias: type X = BaseType | BaseType & Other
570
- if (ts.isTypeAliasDeclaration(parent) && parent.type) {
571
- return isNodeInTypePosition(node, parent.type);
572
- }
573
- // Class implements: class X implements BaseType
574
- if (ts.isClassDeclaration(parent) && parent.heritageClauses) {
575
- for (const clause of parent.heritageClauses) {
576
- if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
577
- for (const type of clause.types) {
578
- if (type.expression === node ||
579
- (ts.isPropertyAccessExpression(type.expression) && type.expression.expression === node)) {
580
- return true;
581
- }
582
- }
583
- }
584
- }
585
- }
586
- // Generic constraints: function test<T extends BaseType>()
587
- if (ts.isTypeParameterDeclaration(parent) && parent.constraint) {
588
- return isNodeInTypePosition(node, parent.constraint);
589
- }
590
- // Type annotations in variable declarations: const x: BaseType = ...
591
- if (ts.isVariableDeclaration(parent) && parent.type) {
592
- return isNodeInTypePosition(node, parent.type);
593
- }
594
- // Type assertions: value as BaseType or <BaseType>value
595
- if (ts.isAsExpression(parent) && parent.type) {
596
- return isNodeInTypePosition(node, parent.type);
597
- }
598
- if (ts.isTypeAssertionExpression(parent) && parent.type) {
599
- return isNodeInTypePosition(node, parent.type);
600
- }
601
- // Satisfies expressions: expression satisfies Type
602
- if (ts.isSatisfiesExpression && ts.isSatisfiesExpression(parent) && parent.type) {
603
- return isNodeInTypePosition(node, parent.type);
604
- }
605
- // Type parameters/arguments: Array<BaseType>, Promise<BaseType>
606
- if (ts.isTypeReferenceNode(parent) && parent.typeArguments) {
607
- for (const arg of parent.typeArguments) {
608
- if (isNodeInTypePosition(node, arg)) {
609
- return true;
610
- }
611
- }
612
- }
613
- // Return type annotations: function test(): BaseType
614
- if ((ts.isFunctionDeclaration(parent) ||
615
- ts.isMethodDeclaration(parent) ||
616
- ts.isArrowFunction(parent) ||
617
- ts.isFunctionExpression(parent) ||
618
- ts.isGetAccessorDeclaration(parent) ||
619
- ts.isMethodSignature(parent)) &&
620
- parent.type) {
621
- return isNodeInTypePosition(node, parent.type);
622
- }
623
- // Parameter type annotations: function test(x: BaseType)
624
- if (ts.isParameter(parent) && parent.type) {
625
- return isNodeInTypePosition(node, parent.type);
626
- }
627
- // Property type annotations: { prop: BaseType } or class { prop: BaseType }
628
- if ((ts.isPropertyDeclaration(parent) ||
629
- ts.isPropertySignature(parent)) &&
630
- parent.type) {
631
- return isNodeInTypePosition(node, parent.type);
632
- }
633
- // Index signature types: { [key: string]: BaseType }
634
- if (ts.isIndexSignatureDeclaration(parent) && parent.type) {
635
- return isNodeInTypePosition(node, parent.type);
636
- }
637
- // Mapped type constraint or type: { [K in keyof BaseType]: ... }
638
- if (ts.isMappedTypeNode(parent)) {
639
- if (parent.typeParameter && parent.typeParameter.constraint) {
640
- return isNodeInTypePosition(node, parent.typeParameter.constraint);
641
- }
642
- if (parent.type) {
643
- return isNodeInTypePosition(node, parent.type);
644
- }
645
- }
646
- // Conditional types: T extends BaseType ? X : Y
647
- if (ts.isConditionalTypeNode(parent)) {
648
- return isNodeInTypePosition(node, parent.checkType) ||
649
- isNodeInTypePosition(node, parent.extendsType) ||
650
- isNodeInTypePosition(node, parent.trueType) ||
651
- isNodeInTypePosition(node, parent.falseType);
652
- }
653
- // Union and intersection types: BaseType | Other, BaseType & Other
654
- if (ts.isUnionTypeNode(parent) || ts.isIntersectionTypeNode(parent)) {
655
- for (const type of parent.types) {
656
- if (isNodeInTypePosition(node, type)) {
657
- return true;
658
- }
659
- }
660
- }
661
- // Type predicate: function isX(value: any): value is BaseType
662
- if (ts.isTypePredicateNode(parent) && parent.type) {
663
- return isNodeInTypePosition(node, parent.type);
664
- }
665
- // Check if we need to traverse up the tree
666
- if (parent.parent) {
667
- // For nested type structures, check if parent is in type position
668
- if (ts.isTypeNode(parent)) {
669
- return true;
670
- }
671
- // Check grandparent for certain patterns
672
- const grandparent = parent.parent;
673
- // Heritage clauses (extends/implements) with property access
674
- if (ts.isExpressionWithTypeArguments(parent) &&
675
- ts.isHeritageClause(grandparent)) {
676
- return true;
677
- }
678
- // Type arguments in call expressions: func<BaseType>()
679
- if (ts.isCallExpression(grandparent) &&
680
- grandparent.typeArguments) {
681
- for (const arg of grandparent.typeArguments) {
682
- if (isNodeInTypePosition(node, arg)) {
683
- return true;
684
- }
685
- }
686
- }
687
- // Type arguments in new expressions: new Class<BaseType>()
688
- if (ts.isNewExpression(grandparent) &&
689
- grandparent.typeArguments) {
690
- for (const arg of grandparent.typeArguments) {
691
- if (isNodeInTypePosition(node, arg)) {
692
- return true;
693
- }
694
- }
695
- }
696
- // Tagged template type arguments: tag<BaseType>`...`
697
- if (ts.isTaggedTemplateExpression(grandparent) &&
698
- grandparent.typeArguments) {
699
- for (const arg of grandparent.typeArguments) {
700
- if (isNodeInTypePosition(node, arg)) {
701
- return true;
702
- }
703
- }
704
- }
705
- }
706
- return false;
707
- }
708
- /**
709
- * Helper to check if a node is within a type node
710
- */
711
- function isNodeInTypePosition(identifier, typeNode) {
712
- let found = false;
713
- function checkNode(node) {
714
- if (found)
715
- return;
716
- if (node === identifier) {
717
- found = true;
718
- return;
719
- }
720
- ts.forEachChild(node, checkNode);
721
- }
722
- checkNode(typeNode);
723
- return found;
724
- }
725
- visit(node);
973
+ });
726
974
  return usageMap;
727
975
  }
976
+ // ---------------------------------------------------------------------------
977
+ // Local function check
978
+ // ---------------------------------------------------------------------------
728
979
  /**
729
- * Check if a function name is defined locally in the file
980
+ * Check if a function name is defined locally in the file.
981
+ * Uses tree-sitter instead of TS API.
730
982
  */
731
- export function isLocalFunction(name, sourceFile) {
983
+ export function isLocalFunction(name, root) {
732
984
  let found = false;
733
- function visit(node) {
985
+ walkAST(root, (node) => {
734
986
  if (found)
735
987
  return;
736
- if (ts.isFunctionDeclaration(node) && node.name && node.name.text === name) {
737
- found = true;
738
- }
739
- else if (ts.isVariableStatement(node)) {
740
- node.declarationList.declarations.forEach(decl => {
741
- if (ts.isVariableDeclaration(decl) && ts.isIdentifier(decl.name) &&
742
- decl.name.text === name && decl.initializer &&
743
- (ts.isFunctionExpression(decl.initializer) || ts.isArrowFunction(decl.initializer))) {
744
- found = true;
745
- }
746
- });
988
+ // function declarations
989
+ if (node.type === 'function_declaration') {
990
+ const nameNode = findChildOfType(node, 'identifier');
991
+ if (nameNode && rawText(nameNode) === name) {
992
+ found = true;
993
+ }
747
994
  }
748
- else if (ts.isClassDeclaration(node) && node.name && node.name.text === name) {
749
- found = true;
995
+ // variable declarations with arrow functions or function expressions
996
+ if (node.type === 'variable_declarator') {
997
+ const nameNode = findChildOfType(node, 'identifier');
998
+ const initializer = node.children?.find(c => c.type === 'arrow_function' || c.type === 'function_expression');
999
+ if (nameNode && initializer && rawText(nameNode) === name) {
1000
+ found = true;
1001
+ }
750
1002
  }
751
- if (!found) {
752
- ts.forEachChild(node, visit);
1003
+ // class declarations
1004
+ if (node.type === 'class_declaration') {
1005
+ const nameNode = findChildOfType(node, 'identifier');
1006
+ if (nameNode && rawText(nameNode) === name) {
1007
+ found = true;
1008
+ }
753
1009
  }
754
- }
755
- visit(sourceFile);
1010
+ });
756
1011
  return found;
757
1012
  }
1013
+ // ---------------------------------------------------------------------------
1014
+ // Call target normalization
1015
+ // ---------------------------------------------------------------------------
758
1016
  /**
759
- * Normalize a function call target for consistent naming
1017
+ * Normalize a function call target for consistent naming.
1018
+ * No TypeScript dependency — pure string manipulation.
760
1019
  */
761
1020
  export function normalizeCallTarget(callee, filePath) {
762
- // If it already has a module path separator, return as-is
763
1021
  if (callee.includes('#') || callee.includes('.')) {
764
1022
  return callee;
765
1023
  }
766
- // Otherwise, prefix with file path
767
1024
  return `${filePath}#${callee}`;
768
1025
  }
1026
+ // ---------------------------------------------------------------------------
1027
+ // findNodesByKind — backwards compatible alias
1028
+ // ---------------------------------------------------------------------------
1029
+ /**
1030
+ * Backward-compatible findNodesByKind.
1031
+ * For code that used `findNodesByKind<ts.CallExpression>(sourceFile, ts.SyntaxKind.CallExpression)`,
1032
+ * the equivalent is `findNodesByKind(root, 'call_expression')`.
1033
+ *
1034
+ * Note: the type parameter is retained only for backward compatibility with
1035
+ * the generic-based call pattern; tree-sitter uses string types, not SyntaxKind enums.
1036
+ */
1037
+ export function findNodesByKind(root, nodeType) {
1038
+ return findNodes(root, n => n.type === nodeType);
1039
+ }
769
1040
  //# sourceMappingURL=astUtils.js.map