code-auditor-mcp 2.6.2 → 3.0.1

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 (344) hide show
  1. package/README.md +23 -196
  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 → codeIndexDB.d.ts} +51 -224
  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 +58 -22
  161. package/dist/mcp-tools/projectTasks.d.ts.map +1 -1
  162. package/dist/mcp-tools/projectTasks.js +172 -10
  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 +1376 -1181
  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/mcpToolErrors.d.ts.map +1 -1
  182. package/dist/mcpToolErrors.js.map +1 -1
  183. package/dist/native/ast-grep-napi.darwin-arm64.node +0 -0
  184. package/dist/native/ast-grep-napi.darwin-x64.node +0 -0
  185. package/dist/native/ast-grep-napi.linux-arm64-gnu.node +0 -0
  186. package/dist/native/ast-grep-napi.linux-arm64-musl.node +0 -0
  187. package/dist/native/ast-grep-napi.linux-x64-gnu.node +0 -0
  188. package/dist/native/ast-grep-napi.linux-x64-musl.node +0 -0
  189. package/dist/native/ast-grep-napi.win32-x64-msvc.node +0 -0
  190. package/dist/native-bootstrap.d.ts +15 -0
  191. package/dist/native-bootstrap.d.ts.map +1 -0
  192. package/dist/native-bootstrap.js +75 -0
  193. package/dist/native-bootstrap.js.map +1 -0
  194. package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
  195. package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
  196. package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
  197. package/dist/reporting/reportGenerator.d.ts.map +1 -1
  198. package/dist/reporting/reportGenerator.js +4 -0
  199. package/dist/reporting/reportGenerator.js.map +1 -1
  200. package/dist/reporting/sarifReportGenerator.d.ts +39 -0
  201. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -0
  202. package/dist/reporting/sarifReportGenerator.js +229 -0
  203. package/dist/reporting/sarifReportGenerator.js.map +1 -0
  204. package/dist/search/QueryParser.d.ts +41 -0
  205. package/dist/search/QueryParser.d.ts.map +1 -1
  206. package/dist/search/QueryParser.js +200 -19
  207. package/dist/search/QueryParser.js.map +1 -1
  208. package/dist/services/CodeMapGenerator.d.ts.map +1 -1
  209. package/dist/services/CodeMapGenerator.js +4 -4
  210. package/dist/services/CodeMapGenerator.js.map +1 -1
  211. package/dist/services/ProjectTaskRepository.d.ts +15 -2
  212. package/dist/services/ProjectTaskRepository.d.ts.map +1 -1
  213. package/dist/services/ProjectTaskRepository.js +16 -1
  214. package/dist/services/ProjectTaskRepository.js.map +1 -1
  215. package/dist/services/SchemaParser.d.ts.map +1 -1
  216. package/dist/services/SchemaParser.js +5 -8
  217. package/dist/services/SchemaParser.js.map +1 -1
  218. package/dist/services/auditJobService.d.ts +1 -1
  219. package/dist/services/projectTaskHelpers.js.map +1 -1
  220. package/dist/services/whitelistService.d.ts.map +1 -1
  221. package/dist/services/whitelistService.js +1 -1
  222. package/dist/services/whitelistService.js.map +1 -1
  223. package/dist/tool-registry.d.ts +79 -0
  224. package/dist/tool-registry.d.ts.map +1 -0
  225. package/dist/tool-registry.js +139 -0
  226. package/dist/tool-registry.js.map +1 -0
  227. package/dist/types/projectTask.d.ts +4 -0
  228. package/dist/types/projectTask.d.ts.map +1 -1
  229. package/dist/types.d.ts +26 -2
  230. package/dist/types.d.ts.map +1 -1
  231. package/dist/types.js.map +1 -1
  232. package/dist/ui/InteractivePrompts.d.ts.map +1 -1
  233. package/dist/ui/InteractivePrompts.js.map +1 -1
  234. package/dist/utils/astParser.d.ts +31 -38
  235. package/dist/utils/astParser.d.ts.map +1 -1
  236. package/dist/utils/astParser.js +138 -196
  237. package/dist/utils/astParser.js.map +1 -1
  238. package/dist/utils/astUtils.d.ts +87 -58
  239. package/dist/utils/astUtils.d.ts.map +1 -1
  240. package/dist/utils/astUtils.js +852 -581
  241. package/dist/utils/astUtils.js.map +1 -1
  242. package/dist/utils/componentPatterns.js.map +1 -1
  243. package/dist/utils/componentResponsibility.d.ts +13 -9
  244. package/dist/utils/componentResponsibility.d.ts.map +1 -1
  245. package/dist/utils/componentResponsibility.js +236 -206
  246. package/dist/utils/componentResponsibility.js.map +1 -1
  247. package/dist/utils/dependencyExtractor.d.ts +11 -6
  248. package/dist/utils/dependencyExtractor.d.ts.map +1 -1
  249. package/dist/utils/dependencyExtractor.js +200 -119
  250. package/dist/utils/dependencyExtractor.js.map +1 -1
  251. package/dist/utils/fileDiscovery.d.ts +1 -1
  252. package/dist/utils/fileDiscovery.d.ts.map +1 -1
  253. package/dist/utils/fileDiscovery.js +15 -6
  254. package/dist/utils/fileDiscovery.js.map +1 -1
  255. package/dist/utils/jsDocParser.d.ts +27 -30
  256. package/dist/utils/jsDocParser.d.ts.map +1 -1
  257. package/dist/utils/jsDocParser.js +271 -207
  258. package/dist/utils/jsDocParser.js.map +1 -1
  259. package/dist/utils/reactDetection.d.ts +27 -12
  260. package/dist/utils/reactDetection.d.ts.map +1 -1
  261. package/dist/utils/reactDetection.js +331 -219
  262. package/dist/utils/reactDetection.js.map +1 -1
  263. package/dist/workers/auditWorker.js +17 -3
  264. package/dist/workers/auditWorker.js.map +1 -1
  265. package/package.json +54 -51
  266. package/dist/adapters/GoAdapter.d.ts +0 -53
  267. package/dist/adapters/GoAdapter.d.ts.map +0 -1
  268. package/dist/adapters/GoAdapter.js +0 -611
  269. package/dist/adapters/GoAdapter.js.map +0 -1
  270. package/dist/adapters/GoConfig.d.ts +0 -35
  271. package/dist/adapters/GoConfig.d.ts.map +0 -1
  272. package/dist/adapters/GoConfig.js +0 -155
  273. package/dist/adapters/GoConfig.js.map +0 -1
  274. package/dist/adapters/LanguageAdapter.d.ts +0 -135
  275. package/dist/adapters/LanguageAdapter.d.ts.map +0 -1
  276. package/dist/adapters/LanguageAdapter.js +0 -47
  277. package/dist/adapters/LanguageAdapter.js.map +0 -1
  278. package/dist/adapters/TypeScriptAdapter.d.ts +0 -43
  279. package/dist/adapters/TypeScriptAdapter.d.ts.map +0 -1
  280. package/dist/adapters/TypeScriptAdapter.js +0 -386
  281. package/dist/adapters/TypeScriptAdapter.js.map +0 -1
  282. package/dist/adapters/UniversalAnalyzer.d.ts +0 -42
  283. package/dist/adapters/UniversalAnalyzer.d.ts.map +0 -1
  284. package/dist/adapters/UniversalAnalyzer.js +0 -103
  285. package/dist/adapters/UniversalAnalyzer.js.map +0 -1
  286. package/dist/adapters/UniversalSOLIDAnalyzer.d.ts +0 -48
  287. package/dist/adapters/UniversalSOLIDAnalyzer.d.ts.map +0 -1
  288. package/dist/adapters/UniversalSOLIDAnalyzer.js +0 -178
  289. package/dist/adapters/UniversalSOLIDAnalyzer.js.map +0 -1
  290. package/dist/adapters/solidAnalyzerCompat.d.ts +0 -21
  291. package/dist/adapters/solidAnalyzerCompat.d.ts.map +0 -1
  292. package/dist/adapters/solidAnalyzerCompat.js +0 -78
  293. package/dist/adapters/solidAnalyzerCompat.js.map +0 -1
  294. package/dist/analyzers/dataAccessAnalyzerCompat.d.ts +0 -20
  295. package/dist/analyzers/dataAccessAnalyzerCompat.d.ts.map +0 -1
  296. package/dist/analyzers/dataAccessAnalyzerCompat.js +0 -59
  297. package/dist/analyzers/dataAccessAnalyzerCompat.js.map +0 -1
  298. package/dist/analyzers/documentationAnalyzerCompat.d.ts +0 -20
  299. package/dist/analyzers/documentationAnalyzerCompat.d.ts.map +0 -1
  300. package/dist/analyzers/documentationAnalyzerCompat.js +0 -52
  301. package/dist/analyzers/documentationAnalyzerCompat.js.map +0 -1
  302. package/dist/analyzers/dryAnalyzerCompat.d.ts +0 -20
  303. package/dist/analyzers/dryAnalyzerCompat.d.ts.map +0 -1
  304. package/dist/analyzers/dryAnalyzerCompat.js +0 -44
  305. package/dist/analyzers/dryAnalyzerCompat.js.map +0 -1
  306. package/dist/analyzers/schemaAnalyzerCompat.d.ts +0 -20
  307. package/dist/analyzers/schemaAnalyzerCompat.d.ts.map +0 -1
  308. package/dist/analyzers/schemaAnalyzerCompat.js +0 -69
  309. package/dist/analyzers/schemaAnalyzerCompat.js.map +0 -1
  310. package/dist/analyzers/solidAnalyzerCompat.d.ts +0 -20
  311. package/dist/analyzers/solidAnalyzerCompat.d.ts.map +0 -1
  312. package/dist/analyzers/solidAnalyzerCompat.js +0 -78
  313. package/dist/analyzers/solidAnalyzerCompat.js.map +0 -1
  314. package/dist/codeIndexDb.d.ts.map +0 -1
  315. package/dist/codeIndexDb.js +0 -2102
  316. package/dist/codeIndexDb.js.map +0 -1
  317. package/dist/languages/typescript/TypeScriptAdapter.d.ts +0 -108
  318. package/dist/languages/typescript/TypeScriptAdapter.d.ts.map +0 -1
  319. package/dist/languages/typescript/TypeScriptAdapter.js +0 -567
  320. package/dist/languages/typescript/TypeScriptAdapter.js.map +0 -1
  321. package/dist/languages/typescript/test-extraction.d.ts +0 -2
  322. package/dist/languages/typescript/test-extraction.d.ts.map +0 -1
  323. package/dist/languages/typescript/test-extraction.js +0 -36
  324. package/dist/languages/typescript/test-extraction.js.map +0 -1
  325. package/dist/mcp-hybrid.d.ts +0 -10
  326. package/dist/mcp-hybrid.d.ts.map +0 -1
  327. package/dist/mcp-hybrid.js +0 -41
  328. package/dist/mcp-hybrid.js.map +0 -1
  329. package/dist/mcp-index.d.ts +0 -13
  330. package/dist/mcp-index.d.ts.map +0 -1
  331. package/dist/mcp-index.js +0 -136
  332. package/dist/mcp-index.js.map +0 -1
  333. package/dist/mcp-standalone.d.ts +0 -3
  334. package/dist/mcp-standalone.d.ts.map +0 -1
  335. package/dist/mcp-standalone.js +0 -1324
  336. package/dist/mcp-standalone.js.map +0 -1
  337. package/dist/mcp-ui-server.d.ts +0 -27
  338. package/dist/mcp-ui-server.d.ts.map +0 -1
  339. package/dist/mcp-ui-server.js +0 -484
  340. package/dist/mcp-ui-server.js.map +0 -1
  341. package/dist/test-multi-strategy-search.d.ts +0 -3
  342. package/dist/test-multi-strategy-search.d.ts.map +0 -1
  343. package/dist/test-multi-strategy-search.js +0 -170
  344. package/dist/test-multi-strategy-search.js.map +0 -1
@@ -1,8 +1,66 @@
1
1
  /**
2
2
  * React Component Detection Utilities
3
3
  * Provides AST-based detection of React components and their properties
4
+ *
5
+ * ## Migration: TypeScript Compiler API → tree-sitter
6
+ *
7
+ * ### Capability regressions (documented per Spec 08 plan Step 2.5):
8
+ *
9
+ * | Check | TS API approach | tree-sitter approach | Honest outcome |
10
+ * |--------------------------|-------------------------------------|-----------------------------------|----------------|
11
+ * | Prop type from interface | `checker.getTypeAtLocation()` | Parse type annotation as string | Recovers for inline types; loses cross-file interface resolution |
12
+ * | `PropTypes.oneOf` | Type string from checker | Match call pattern textually | Full parity — doesn't need checker |
13
+ * | Symbol resolution | `checker.getSymbolAtLocation()` | Not possible without checker | Lost — falls through to parameter destructuring heuristics |
4
14
  */
5
- import * as ts from 'typescript';
15
+ import { findNodes, getNodeText, getLineAndColumn } from '../languages/adapterBridge.js';
16
+ // ---------------------------------------------------------------------------
17
+ // Helpers
18
+ // ---------------------------------------------------------------------------
19
+ /** Get raw text from a tree-sitter node (stored on ASTNode.raw). */
20
+ function rawText(node) {
21
+ return node.raw?.text ?? '';
22
+ }
23
+ /** Check if a tree-sitter node type is a function-like declaration. */
24
+ function isFunctionType(type) {
25
+ return type === 'function_declaration' || type === 'function_expression' || type === 'arrow_function';
26
+ }
27
+ /** Check if a tree-sitter node type is a JSX node. */
28
+ function isJsxType(type) {
29
+ return type === 'jsx_element' || type === 'jsx_fragment' || type === 'jsx_self_closing_element';
30
+ }
31
+ /**
32
+ * Check if a name follows React component naming convention (PascalCase)
33
+ */
34
+ function isComponentName(name) {
35
+ return /^[A-Z][a-zA-Z0-9]*$/.test(name);
36
+ }
37
+ /**
38
+ * Check if a hook name is a built-in React hook
39
+ */
40
+ function isBuiltInHook(hookName) {
41
+ const builtInHooks = [
42
+ 'useState', 'useEffect', 'useContext', 'useReducer', 'useCallback',
43
+ 'useMemo', 'useRef', 'useImperativeHandle', 'useLayoutEffect',
44
+ 'useDebugValue', 'useId', 'useDeferredValue', 'useTransition',
45
+ 'useSyncExternalStore', 'useInsertionEffect'
46
+ ];
47
+ return builtInHooks.includes(hookName);
48
+ }
49
+ /**
50
+ * Find the first child of a given type.
51
+ */
52
+ function findChildOfType(node, type) {
53
+ return node.children?.find(c => c.type === type);
54
+ }
55
+ /**
56
+ * Find all children of a given type.
57
+ */
58
+ function findChildrenOfType(node, type) {
59
+ return node.children?.filter(c => c.type === type) ?? [];
60
+ }
61
+ // ---------------------------------------------------------------------------
62
+ // Component detection
63
+ // ---------------------------------------------------------------------------
6
64
  /**
7
65
  * Check if a node is any type of React component
8
66
  */
@@ -13,17 +71,22 @@ export function isReactComponent(node) {
13
71
  * Check if a node is a functional React component
14
72
  */
15
73
  export function isFunctionalComponent(node) {
16
- if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
74
+ if (node.type === 'function_declaration' || node.type === 'function_expression') {
17
75
  return returnsJSX(node);
18
76
  }
19
- if (ts.isArrowFunction(node)) {
77
+ if (node.type === 'arrow_function') {
20
78
  return returnsJSX(node);
21
79
  }
22
80
  // Check for variable declarations with arrow functions
23
- if (ts.isVariableStatement(node)) {
24
- const declaration = node.declarationList.declarations[0];
25
- if (declaration && declaration.initializer && ts.isArrowFunction(declaration.initializer)) {
26
- return returnsJSX(declaration.initializer);
81
+ // tree-sitter: lexical_declaration / variable_declaration → variable_declarator
82
+ if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {
83
+ const declarator = findChildOfType(node, 'variable_declarator');
84
+ if (declarator) {
85
+ // Find the value/initializer (non-identifier child)
86
+ const initializer = declarator.children?.find(c => c.type !== 'identifier' && c.type !== 'type_annotation');
87
+ if (initializer && initializer.type === 'arrow_function') {
88
+ return returnsJSX(initializer);
89
+ }
27
90
  }
28
91
  }
29
92
  return false;
@@ -32,120 +95,157 @@ export function isFunctionalComponent(node) {
32
95
  * Check if a node returns JSX elements
33
96
  */
34
97
  export function returnsJSX(node) {
35
- let hasJSX = false;
36
- function visit(child) {
37
- if (ts.isJsxElement(child) || ts.isJsxFragment(child) ||
38
- ts.isJsxSelfClosingElement(child)) {
39
- hasJSX = true;
40
- }
41
- // Check return statements
42
- if (ts.isReturnStatement(child) && child.expression) {
43
- if (ts.isJsxElement(child.expression) ||
44
- ts.isJsxFragment(child.expression) ||
45
- ts.isJsxSelfClosingElement(child.expression)) {
46
- hasJSX = true;
47
- }
48
- }
49
- if (!hasJSX) {
50
- ts.forEachChild(child, visit);
98
+ // Check for JSX elements anywhere in the subtree
99
+ const jsxNodes = findNodes(node, n => isJsxType(n.type));
100
+ if (jsxNodes.length > 0)
101
+ return true;
102
+ // Check for return statements containing JSX
103
+ const returnNodes = findNodes(node, n => n.type === 'return_statement');
104
+ for (const ret of returnNodes) {
105
+ for (const child of ret.children ?? []) {
106
+ if (isJsxType(child.type))
107
+ return true;
51
108
  }
52
109
  }
53
- ts.forEachChild(node, visit);
54
- return hasJSX;
110
+ return false;
55
111
  }
56
112
  /**
57
113
  * Check if a node is a class component extending React.Component
58
114
  */
59
115
  export function isClassComponent(node) {
60
- if (!ts.isClassDeclaration(node)) {
116
+ if (node.type !== 'class_declaration')
61
117
  return false;
62
- }
63
- // Check if class extends React.Component or React.PureComponent
64
- if (node.heritageClauses) {
65
- for (const clause of node.heritageClauses) {
66
- if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
67
- for (const type of clause.types) {
68
- const expression = type.expression;
69
- // Check for React.Component or React.PureComponent
70
- if (ts.isPropertyAccessExpression(expression)) {
71
- const obj = expression.expression;
72
- const prop = expression.name;
73
- if (ts.isIdentifier(obj) && obj.text === 'React' &&
74
- ts.isIdentifier(prop) && (prop.text === 'Component' || prop.text === 'PureComponent')) {
75
- return true;
76
- }
77
- }
78
- // Check for Component (when imported directly)
79
- if (ts.isIdentifier(expression) &&
80
- (expression.text === 'Component' || expression.text === 'PureComponent')) {
118
+ // Check heritage clauses for extends React.Component / PureComponent
119
+ for (const child of node.children ?? []) {
120
+ if (child.type !== 'heritage_clause')
121
+ continue;
122
+ // Check if this is an 'extends' clause (not 'implements')
123
+ const raw = child.raw;
124
+ if (!raw?.children)
125
+ continue;
126
+ const isExtends = raw.children.some(c => !c.isNamed && c.type === 'extends');
127
+ if (!isExtends)
128
+ continue;
129
+ // Check each type in the extends clause
130
+ for (const typeNode of child.children ?? []) {
131
+ if (typeNode.type === 'member_expression') {
132
+ // React.Component or React.PureComponent
133
+ const parts = typeNode.children ?? [];
134
+ if (parts.length >= 2) {
135
+ const obj = parts[0];
136
+ const prop = parts[parts.length - 1];
137
+ if (obj.type === 'identifier' && rawText(obj) === 'React' &&
138
+ prop.type === 'property_identifier' &&
139
+ (rawText(prop) === 'Component' || rawText(prop) === 'PureComponent')) {
81
140
  return true;
82
141
  }
83
142
  }
84
143
  }
144
+ if (typeNode.type === 'identifier') {
145
+ const name = rawText(typeNode);
146
+ if (name === 'Component' || name === 'PureComponent') {
147
+ return true;
148
+ }
149
+ }
85
150
  }
86
151
  }
87
152
  return false;
88
153
  }
154
+ // ---------------------------------------------------------------------------
155
+ // Hook extraction
156
+ // ---------------------------------------------------------------------------
89
157
  /**
90
158
  * Extract hooks usage from a component node
91
159
  */
92
- export function extractHooks(node, sourceFile) {
160
+ export function extractHooks(node) {
93
161
  const hooks = [];
94
- function visit(child) {
95
- if (ts.isCallExpression(child)) {
96
- const expression = child.expression;
97
- // Check for hook calls (functions starting with 'use')
98
- if (ts.isIdentifier(expression) && expression.text.startsWith('use')) {
99
- const line = sourceFile.getLineAndCharacterOfPosition(expression.getStart()).line + 1;
162
+ // Find all call expressions in the component
163
+ const callExprs = findNodes(node, n => n.type === 'call_expression');
164
+ for (const call of callExprs) {
165
+ // The expression being called is the first child (identifier or member_expression)
166
+ const callee = call.children?.[0];
167
+ if (!callee)
168
+ continue;
169
+ if (callee.type === 'identifier') {
170
+ const name = rawText(callee);
171
+ if (name.startsWith('use')) {
172
+ const { line } = getLineAndColumn(callee);
100
173
  hooks.push({
101
- name: expression.text,
174
+ name,
102
175
  line,
103
- customHook: !isBuiltInHook(expression.text)
176
+ customHook: !isBuiltInHook(name)
104
177
  });
105
178
  }
106
179
  }
107
- ts.forEachChild(child, visit);
108
180
  }
109
- ts.forEachChild(node, visit);
110
181
  return hooks;
111
182
  }
183
+ // ---------------------------------------------------------------------------
184
+ // Prop type extraction
185
+ // ---------------------------------------------------------------------------
112
186
  /**
113
- * Check if a hook name is a built-in React hook
187
+ * Extract props from a TypeScript type literal / object_type node.
114
188
  */
115
- function isBuiltInHook(hookName) {
116
- const builtInHooks = [
117
- 'useState', 'useEffect', 'useContext', 'useReducer', 'useCallback',
118
- 'useMemo', 'useRef', 'useImperativeHandle', 'useLayoutEffect',
119
- 'useDebugValue', 'useId', 'useDeferredValue', 'useTransition',
120
- 'useSyncExternalStore', 'useInsertionEffect'
121
- ];
122
- return builtInHooks.includes(hookName);
189
+ function extractPropsFromTypeLiteral(typeLiteral) {
190
+ const props = [];
191
+ for (const member of typeLiteral.children ?? []) {
192
+ if (member.type !== 'property_signature')
193
+ continue;
194
+ const nameNode = member.children?.find(c => c.type === 'identifier' || c.type === 'property_identifier');
195
+ if (!nameNode)
196
+ continue;
197
+ const typeChild = member.children?.find(c => c.type === 'type_annotation');
198
+ const typeStr = typeChild ? getNodeText(typeChild, '') || rawText(typeChild) : 'any';
199
+ // Check for optional marker
200
+ const raw = member.raw;
201
+ const hasQuestion = raw?.children?.some(c => !c.isNamed && c.type === '?') ?? false;
202
+ props.push({
203
+ name: rawText(nameNode),
204
+ type: typeStr,
205
+ required: !hasQuestion,
206
+ hasDefault: false
207
+ });
208
+ }
209
+ return props;
123
210
  }
124
211
  /**
125
212
  * Extract prop types from a component (TypeScript interfaces/types)
213
+ *
214
+ * NOTE: Cross-file interface resolution via TypeChecker is NOT available
215
+ * with tree-sitter. We recover inline types and parameter destructuring,
216
+ * but type references (e.g. `React.FC<Props>`) without inline definition
217
+ * will fall through to parameter heuristics.
126
218
  */
127
- export function extractPropTypes(node, sourceFile, typeChecker) {
219
+ export function extractPropTypes(node) {
128
220
  const props = [];
129
221
  // Handle variable declarations with type annotations (e.g., const Button: React.FC<Props>)
130
- if (ts.isVariableDeclaration(node) && node.type && node.initializer) {
131
- // Check if it's a React.FC<Props> type
132
- if (ts.isTypeReferenceNode(node.type) && node.type.typeArguments?.length) {
133
- const propsType = node.type.typeArguments[0];
134
- if (ts.isTypeReferenceNode(propsType) && ts.isIdentifier(propsType.typeName)) {
135
- // This is a reference to a Props interface, but without TypeChecker we can't resolve it
136
- // Instead, check the function parameters for destructured props
137
- if (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer)) {
138
- const firstParam = node.initializer.parameters[0];
139
- if (firstParam && ts.isObjectBindingPattern(firstParam.name)) {
140
- for (const element of firstParam.name.elements) {
141
- if (ts.isBindingElement(element) && element.name && ts.isIdentifier(element.name)) {
142
- props.push({
143
- name: element.name.text,
144
- type: 'any',
145
- required: !element.dotDotDotToken && !element.initializer,
146
- hasDefault: !!element.initializer
147
- });
148
- }
222
+ if (node.type === 'variable_declarator') {
223
+ const typeAnnot = findChildOfType(node, 'type_annotation');
224
+ const initializer = node.children?.find(c => c.type !== 'identifier' && c.type !== 'type_annotation');
225
+ // If there's a type annotation, extract props from destructured parameters
226
+ if (initializer && (initializer.type === 'arrow_function' || initializer.type === 'function_expression')) {
227
+ const params = findChildOfType(initializer, 'formal_parameters');
228
+ if (params) {
229
+ const firstParam = params.children?.[0];
230
+ if (firstParam) {
231
+ // Check for destructured parameter (object pattern)
232
+ if (firstParam.type === 'object_pattern' || firstParam.type === 'object_binding_pattern') {
233
+ for (const element of firstParam.children ?? []) {
234
+ if (element.type !== 'binding_element' && element.type !== 'pair_pattern' &&
235
+ element.type !== 'shorthand_property_identifier_pattern')
236
+ continue;
237
+ const nameNode = element.children?.find(c => c.type === 'identifier' || c.type === 'property_identifier');
238
+ if (!nameNode)
239
+ continue;
240
+ const raw = element.raw;
241
+ const hasRest = raw?.children?.some(c => !c.isNamed && c.type === '...') ?? false;
242
+ const hasDefault = element.children?.some(c => c.type !== 'identifier' && c.type !== 'property_identifier') ?? false;
243
+ props.push({
244
+ name: rawText(nameNode),
245
+ type: 'any',
246
+ required: !hasRest && !hasDefault,
247
+ hasDefault
248
+ });
149
249
  }
150
250
  }
151
251
  }
@@ -153,57 +253,60 @@ export function extractPropTypes(node, sourceFile, typeChecker) {
153
253
  }
154
254
  }
155
255
  // For functional components, check the first parameter
156
- if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)) {
157
- const firstParam = node.parameters[0];
158
- if (firstParam) {
159
- // Check if parameter is destructured (common React pattern)
160
- if (ts.isObjectBindingPattern(firstParam.name)) {
161
- for (const element of firstParam.name.elements) {
162
- if (ts.isBindingElement(element) && element.name && ts.isIdentifier(element.name)) {
256
+ if (isFunctionType(node.type)) {
257
+ const params = findChildOfType(node, 'formal_parameters');
258
+ if (params) {
259
+ const firstParam = params.children?.[0];
260
+ if (firstParam) {
261
+ // Check if parameter is destructured
262
+ if (firstParam.type === 'object_pattern' || firstParam.type === 'object_binding_pattern') {
263
+ for (const element of firstParam.children ?? []) {
264
+ if (element.type !== 'binding_element' && element.type !== 'shorthand_property_identifier_pattern')
265
+ continue;
266
+ const nameNode = element.children?.find(c => c.type === 'identifier' || c.type === 'property_identifier');
267
+ if (!nameNode)
268
+ continue;
269
+ const raw = element.raw;
270
+ const hasRest = raw?.children?.some(c => !c.isNamed && c.type === '...') ?? false;
271
+ const hasDefault = element.children?.some(c => c.type !== 'identifier' && c.type !== 'property_identifier') ?? false;
163
272
  props.push({
164
- name: element.name.text,
165
- type: 'any', // Without full type resolution
166
- required: !element.dotDotDotToken && !element.initializer,
167
- hasDefault: !!element.initializer
273
+ name: rawText(nameNode),
274
+ type: 'any',
275
+ required: !hasRest && !hasDefault,
276
+ hasDefault
168
277
  });
169
278
  }
170
279
  }
171
- }
172
- // Extract props from type annotation
173
- if (firstParam.type) {
174
- if (ts.isTypeLiteralNode(firstParam.type)) {
175
- extractPropsFromTypeLiteral(firstParam.type, props);
176
- }
177
- else if (ts.isTypeReferenceNode(firstParam.type) && typeChecker) {
178
- // Handle interface references
179
- const symbol = typeChecker.getSymbolAtLocation(firstParam.type.typeName);
180
- if (symbol) {
181
- const type = typeChecker.getTypeOfSymbolAtLocation(symbol, firstParam.type);
182
- const propSymbols = type.getProperties();
183
- for (const propSymbol of propSymbols) {
184
- const propType = typeChecker.getTypeOfSymbolAtLocation(propSymbol, propSymbol.valueDeclaration);
185
- props.push({
186
- name: propSymbol.getName(),
187
- type: typeChecker.typeToString(propType),
188
- required: !(propSymbol.flags & ts.SymbolFlags.Optional),
189
- hasDefault: false // TODO: Detect default props
190
- });
191
- }
280
+ // Extract props from type annotation on parameter
281
+ const typeAnnot = findChildOfType(firstParam, 'type_annotation');
282
+ if (typeAnnot && typeAnnot.children?.[0]) {
283
+ const typeNode = typeAnnot.children[0];
284
+ if (typeNode.type === 'object_type' || typeNode.type === 'type_literal') {
285
+ props.push(...extractPropsFromTypeLiteral(typeNode));
192
286
  }
287
+ // NOTE: type_reference (interface references) can't be resolved
288
+ // without TypeChecker — this is a known tree-sitter limitation.
193
289
  }
194
290
  }
195
291
  }
196
292
  }
197
- // For class components, check Props interface/type
198
- if (ts.isClassDeclaration(node) && node.heritageClauses) {
199
- // Look for Props type in extends clause (e.g., React.Component<Props>)
200
- for (const clause of node.heritageClauses) {
201
- if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
202
- for (const type of clause.types) {
203
- if (type.typeArguments && type.typeArguments.length > 0) {
204
- const propsType = type.typeArguments[0];
205
- if (ts.isTypeLiteralNode(propsType)) {
206
- extractPropsFromTypeLiteral(propsType, props);
293
+ // For class components, check Props in extends clause
294
+ if (node.type === 'class_declaration') {
295
+ for (const child of node.children ?? []) {
296
+ if (child.type !== 'heritage_clause')
297
+ continue;
298
+ const raw = child.raw;
299
+ const isExtends = raw?.children?.some(c => !c.isNamed && c.type === 'extends') ?? false;
300
+ if (!isExtends)
301
+ continue;
302
+ for (const typeNode of child.children ?? []) {
303
+ if (typeNode.type === 'generic_type') {
304
+ // React.Component<Props> — type_arguments contain the props type
305
+ const typeArgs = findChildOfType(typeNode, 'type_arguments');
306
+ if (typeArgs?.children) {
307
+ const firstArg = typeArgs.children[0];
308
+ if (firstArg?.type === 'object_type' || firstArg?.type === 'type_literal') {
309
+ props.push(...extractPropsFromTypeLiteral(firstArg));
207
310
  }
208
311
  }
209
312
  }
@@ -212,131 +315,140 @@ export function extractPropTypes(node, sourceFile, typeChecker) {
212
315
  }
213
316
  return props;
214
317
  }
318
+ // ---------------------------------------------------------------------------
319
+ // Component import extraction
320
+ // ---------------------------------------------------------------------------
215
321
  /**
216
- * Extract props from a TypeScript type literal
322
+ * Extract component imports from an AST.
217
323
  */
218
- function extractPropsFromTypeLiteral(typeLiteral, props) {
219
- for (const member of typeLiteral.members) {
220
- if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
221
- props.push({
222
- name: member.name.text,
223
- type: member.type ? member.type.getText() : 'any',
224
- required: !member.questionToken,
225
- hasDefault: false
226
- });
227
- }
228
- }
229
- }
230
- /**
231
- * Extract component imports from a source file
232
- */
233
- export function extractComponentImports(sourceFile) {
324
+ export function extractComponentImports(astRoot) {
234
325
  const imports = [];
235
- function visit(node) {
236
- if (ts.isImportDeclaration(node)) {
237
- const moduleSpecifier = node.moduleSpecifier;
238
- if (ts.isStringLiteral(moduleSpecifier)) {
239
- const importPath = moduleSpecifier.text;
240
- // Check if it's likely a component import (local files, not node_modules)
241
- if (importPath.startsWith('.') || importPath.startsWith('/')) {
242
- const importClause = node.importClause;
243
- if (importClause) {
244
- // Default import
245
- if (importClause.name) {
246
- const name = importClause.name.text;
247
- if (isComponentName(name)) {
248
- imports.push({
249
- name,
250
- path: importPath,
251
- isDefault: true
252
- });
253
- }
254
- }
255
- // Named imports
256
- if (importClause.namedBindings && ts.isNamedImports(importClause.namedBindings)) {
257
- for (const element of importClause.namedBindings.elements) {
258
- const name = element.name.text;
259
- if (isComponentName(name)) {
260
- imports.push({
261
- name,
262
- path: importPath,
263
- isDefault: false
264
- });
265
- }
266
- }
326
+ const importNodes = findNodes(astRoot, n => n.type === 'import_statement');
327
+ for (const imp of importNodes) {
328
+ // Find module specifier (string child)
329
+ const moduleNode = findChildOfType(imp, 'string');
330
+ if (!moduleNode)
331
+ continue;
332
+ const rawSpecifier = rawText(moduleNode);
333
+ const importPath = rawSpecifier.replace(/^["']|["']$/g, '');
334
+ // Only check local imports (not node_modules)
335
+ if (!importPath.startsWith('.') && !importPath.startsWith('/'))
336
+ continue;
337
+ const importClause = findChildOfType(imp, 'import_clause');
338
+ if (!importClause)
339
+ continue;
340
+ // Default import (identifier child of import_clause)
341
+ for (const child of importClause.children ?? []) {
342
+ if (child.type === 'identifier') {
343
+ const name = rawText(child);
344
+ if (isComponentName(name)) {
345
+ imports.push({ name, path: importPath, isDefault: true });
346
+ }
347
+ }
348
+ // Named imports
349
+ if (child.type === 'named_imports') {
350
+ for (const spec of child.children ?? []) {
351
+ if (spec.type !== 'import_specifier')
352
+ continue;
353
+ // The last identifier in the specifier is the local name
354
+ const identifiers = spec.children?.filter(c => c.type === 'identifier') ?? [];
355
+ const localName = identifiers[identifiers.length - 1];
356
+ if (localName) {
357
+ const name = rawText(localName);
358
+ if (isComponentName(name)) {
359
+ imports.push({ name, path: importPath, isDefault: false });
267
360
  }
268
361
  }
269
362
  }
270
363
  }
271
364
  }
272
- ts.forEachChild(node, visit);
273
365
  }
274
- visit(sourceFile);
275
366
  return imports;
276
367
  }
277
- /**
278
- * Check if a name follows React component naming convention (PascalCase)
279
- */
280
- function isComponentName(name) {
281
- return /^[A-Z][a-zA-Z0-9]*$/.test(name);
282
- }
368
+ // ---------------------------------------------------------------------------
369
+ // Component type detection
370
+ // ---------------------------------------------------------------------------
283
371
  /**
284
372
  * Detect the specific type of component (functional, class, memo, forwardRef)
285
373
  */
286
374
  export function detectComponentType(node) {
287
- // Check for memo wrapped components
288
- if (ts.isCallExpression(node)) {
289
- const expression = node.expression;
290
- if ((ts.isIdentifier(expression) && expression.text === 'memo') ||
291
- (ts.isPropertyAccessExpression(expression) &&
292
- ts.isIdentifier(expression.expression) && expression.expression.text === 'React' &&
293
- ts.isIdentifier(expression.name) && expression.name.text === 'memo')) {
294
- return 'memo';
295
- }
296
- // Check for forwardRef
297
- if ((ts.isIdentifier(expression) && expression.text === 'forwardRef') ||
298
- (ts.isPropertyAccessExpression(expression) &&
299
- ts.isIdentifier(expression.expression) && expression.expression.text === 'React' &&
300
- ts.isIdentifier(expression.name) && expression.name.text === 'forwardRef')) {
301
- return 'forwardRef';
375
+ // Check for call expression wrapping (memo, forwardRef)
376
+ if (node.type === 'call_expression') {
377
+ const callee = node.children?.[0];
378
+ if (callee) {
379
+ if (callee.type === 'identifier') {
380
+ const name = rawText(callee);
381
+ if (name === 'memo')
382
+ return 'memo';
383
+ if (name === 'forwardRef')
384
+ return 'forwardRef';
385
+ }
386
+ if (callee.type === 'member_expression') {
387
+ const parts = callee.children ?? [];
388
+ if (parts.length >= 2) {
389
+ const obj = parts[0];
390
+ const prop = parts[parts.length - 1];
391
+ if (obj.type === 'identifier' && rawText(obj) === 'React') {
392
+ const propName = rawText(prop);
393
+ if (propName === 'memo')
394
+ return 'memo';
395
+ if (propName === 'forwardRef')
396
+ return 'forwardRef';
397
+ }
398
+ }
399
+ }
302
400
  }
303
401
  }
304
- if (isClassComponent(node)) {
402
+ if (isClassComponent(node))
305
403
  return 'class';
306
- }
307
- if (isFunctionalComponent(node)) {
404
+ if (isFunctionalComponent(node))
308
405
  return 'functional';
309
- }
310
406
  return null;
311
407
  }
408
+ // ---------------------------------------------------------------------------
409
+ // Component name extraction
410
+ // ---------------------------------------------------------------------------
312
411
  /**
313
412
  * Get component name from various declaration patterns
314
413
  */
315
414
  export function getComponentName(node) {
316
415
  // Function declaration
317
- if (ts.isFunctionDeclaration(node) && node.name) {
318
- return node.name.text;
416
+ if (node.type === 'function_declaration') {
417
+ const nameNode = findChildOfType(node, 'identifier');
418
+ if (nameNode)
419
+ return rawText(nameNode);
319
420
  }
320
421
  // Class declaration
321
- if (ts.isClassDeclaration(node) && node.name) {
322
- return node.name.text;
422
+ if (node.type === 'class_declaration') {
423
+ const nameNode = findChildOfType(node, 'identifier');
424
+ if (nameNode)
425
+ return rawText(nameNode);
323
426
  }
324
- // Variable declaration with arrow function or function expression
325
- if (ts.isVariableStatement(node)) {
326
- const declaration = node.declarationList.declarations[0];
327
- if (declaration && ts.isIdentifier(declaration.name)) {
328
- return declaration.name.text;
427
+ // Variable declaration / lexical declaration
428
+ if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {
429
+ const declarator = findChildOfType(node, 'variable_declarator');
430
+ if (declarator) {
431
+ const nameNode = declarator.children?.find(c => c.type === 'identifier');
432
+ if (nameNode)
433
+ return rawText(nameNode);
329
434
  }
330
435
  }
331
- // Variable declaration (direct)
332
- if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
333
- return node.name.text;
436
+ // Variable declarator (direct)
437
+ if (node.type === 'variable_declarator') {
438
+ const nameNode = node.children?.find(c => c.type === 'identifier');
439
+ if (nameNode)
440
+ return rawText(nameNode);
334
441
  }
335
442
  // For memo/forwardRef wrapped components, try to extract from the argument
336
- if (ts.isCallExpression(node) && node.arguments.length > 0) {
337
- const firstArg = node.arguments[0];
338
- if (ts.isFunctionExpression(firstArg) && firstArg.name) {
339
- return firstArg.name.text;
443
+ if (node.type === 'call_expression') {
444
+ const args = findChildOfType(node, 'arguments');
445
+ if (args?.children) {
446
+ const firstArg = args.children[0];
447
+ if (firstArg?.type === 'function_expression') {
448
+ const nameNode = findChildOfType(firstArg, 'identifier');
449
+ if (nameNode)
450
+ return rawText(nameNode);
451
+ }
340
452
  }
341
453
  }
342
454
  return 'AnonymousComponent';