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,17 +1,31 @@
1
- import * as ts from 'typescript';
1
+ /**
2
+ * Component Responsibility Detection Utilities
3
+ * Detects and categorizes responsibilities within React components
4
+ */
5
+ import { walkAST, getLineAndColumn } from '../languages/adapterBridge.js';
2
6
  import { ResponsibilityType } from '../types.js';
3
7
  import { extractHooks } from './reactDetection.js';
8
+ // ---------------------------------------------------------------------------
9
+ // Helpers
10
+ // ---------------------------------------------------------------------------
11
+ /** Get raw text from a tree-sitter node (stored on ASTNode.raw). */
12
+ function rawText(node) {
13
+ return node.raw?.text ?? '';
14
+ }
15
+ // ---------------------------------------------------------------------------
16
+ // Main detection entry point
17
+ // ---------------------------------------------------------------------------
4
18
  /**
5
19
  * Detects and categorizes responsibilities within a React component
6
20
  */
7
- export function detectComponentResponsibilities(sourceFile, component, metadata) {
21
+ export function detectComponentResponsibilities(component, metadata) {
8
22
  const responsibilities = [];
9
23
  const seenTypes = new Set();
10
24
  // Analyze different aspects of the component
11
- const hookResponsibilities = analyzeHookUsage(sourceFile, component, metadata);
12
- const eventResponsibilities = analyzeEventHandlers(sourceFile, component);
13
- const effectResponsibilities = analyzeEffects(sourceFile, component);
14
- const renderingResponsibilities = analyzeRenderingLogic(sourceFile, component);
25
+ const hookResponsibilities = analyzeHookUsage(component, metadata);
26
+ const eventResponsibilities = analyzeEventHandlers(component);
27
+ const effectResponsibilities = analyzeEffects(component);
28
+ const renderingResponsibilities = analyzeRenderingLogic(component);
15
29
  // Combine and deduplicate responsibilities
16
30
  [...hookResponsibilities, ...eventResponsibilities, ...effectResponsibilities, ...renderingResponsibilities]
17
31
  .forEach(resp => {
@@ -34,58 +48,63 @@ export function detectComponentResponsibilities(sourceFile, component, metadata)
34
48
  });
35
49
  return responsibilities;
36
50
  }
51
+ // ---------------------------------------------------------------------------
52
+ // Pattern detection helpers
53
+ // ---------------------------------------------------------------------------
37
54
  /**
38
55
  * Identifies data fetching patterns in code
39
56
  */
40
57
  export function containsDataFetching(node) {
41
58
  let hasDataFetching = false;
42
- const checkNode = (n) => {
59
+ walkAST(node, (n) => {
43
60
  // Check for fetch, axios, API calls
44
- if (ts.isCallExpression(n)) {
45
- const callText = n.expression.getText();
46
- if (callText.includes('fetch') ||
47
- callText.includes('axios') ||
48
- callText.includes('api') ||
49
- callText.includes('http') ||
50
- callText.includes('request')) {
51
- hasDataFetching = true;
61
+ if (n.type === 'call_expression') {
62
+ const exprNode = n.children?.[0]; // identifier or member_expression
63
+ if (exprNode) {
64
+ const callText = rawText(exprNode);
65
+ if (callText.includes('fetch') ||
66
+ callText.includes('axios') ||
67
+ callText.includes('api') ||
68
+ callText.includes('http') ||
69
+ callText.includes('request')) {
70
+ hasDataFetching = true;
71
+ }
52
72
  }
53
73
  }
54
74
  // Check for async/await patterns
55
- if (ts.isAwaitExpression(n)) {
75
+ if (n.type === 'await_expression') {
56
76
  hasDataFetching = true;
57
77
  }
58
- ts.forEachChild(n, checkNode);
59
- };
60
- checkNode(node);
78
+ });
61
79
  return hasDataFetching;
62
80
  }
63
81
  /**
64
82
  * Identifies form handling patterns
65
83
  */
66
- export function containsFormHandling(node, sourceFile) {
84
+ export function containsFormHandling(node) {
67
85
  let hasFormHandling = false;
68
- const checkNode = (n) => {
86
+ walkAST(node, (n) => {
69
87
  // Check for form-related method calls
70
- if (ts.isCallExpression(n)) {
71
- const callText = n.expression.getText();
72
- if (callText.includes('preventDefault') ||
73
- callText.includes('handleSubmit') ||
74
- callText.includes('validate') ||
75
- callText.includes('setFieldValue')) {
76
- hasFormHandling = true;
88
+ if (n.type === 'call_expression') {
89
+ const exprNode = n.children?.[0];
90
+ if (exprNode) {
91
+ const callText = rawText(exprNode);
92
+ if (callText.includes('preventDefault') ||
93
+ callText.includes('handleSubmit') ||
94
+ callText.includes('validate') ||
95
+ callText.includes('setFieldValue')) {
96
+ hasFormHandling = true;
97
+ }
77
98
  }
78
99
  }
79
- // Check for form state patterns
80
- if (ts.isIdentifier(n)) {
81
- const text = n.getText();
100
+ // Check for form state patterns in identifiers
101
+ if (n.type === 'identifier') {
102
+ const text = rawText(n);
82
103
  if (text.includes('form') || text.includes('Field') || text.includes('input')) {
83
104
  hasFormHandling = true;
84
105
  }
85
106
  }
86
- ts.forEachChild(n, checkNode);
87
- };
88
- checkNode(node);
107
+ });
89
108
  return hasFormHandling;
90
109
  }
91
110
  /**
@@ -95,38 +114,42 @@ export function containsBusinessLogic(node) {
95
114
  let hasBusinessLogic = false;
96
115
  let statementCount = 0;
97
116
  let hasComplexConditions = false;
98
- const checkNode = (n) => {
99
- // Count statements in functions
100
- if (ts.isBlock(n)) {
101
- statementCount += n.statements.length;
117
+ walkAST(node, (n) => {
118
+ // Count statements in blocks
119
+ if (n.type === 'statement_block') {
120
+ statementCount += (n.children ?? []).length;
102
121
  }
103
122
  // Check for complex conditions
104
- if (ts.isIfStatement(n) || ts.isConditionalExpression(n)) {
105
- // Check if condition is complex
106
- const conditionText = n.getFullText();
123
+ if (n.type === 'if_statement' || n.type === 'ternary_expression') {
124
+ const conditionText = rawText(n);
107
125
  if (conditionText.includes('&&') && conditionText.includes('||')) {
108
126
  hasComplexConditions = true;
109
127
  }
110
128
  }
111
- // Check for calculations or transformations
112
- if (ts.isBinaryExpression(n)) {
113
- const operator = n.operatorToken.kind;
114
- if (operator === ts.SyntaxKind.AsteriskToken ||
115
- operator === ts.SyntaxKind.SlashToken ||
116
- operator === ts.SyntaxKind.PercentToken) {
129
+ // Check for calculations or transformations (binary expressions)
130
+ if (n.type === 'binary_expression') {
131
+ // Check operator token in raw tree-sitter children
132
+ const raw = n.raw;
133
+ const opChild = raw?.children?.find(c => !c.isNamed);
134
+ if (opChild && (opChild.type === '*' || opChild.type === '/' || opChild.type === '%')) {
117
135
  hasBusinessLogic = true;
118
136
  }
119
137
  }
120
138
  // Check for array operations suggesting data transformation
121
- if (ts.isCallExpression(n) && ts.isPropertyAccessExpression(n.expression)) {
122
- const methodName = n.expression.name.getText();
123
- if (['map', 'filter', 'reduce', 'sort', 'groupBy'].includes(methodName)) {
124
- hasBusinessLogic = true;
139
+ if (n.type === 'call_expression') {
140
+ const exprNode = n.children?.[0];
141
+ if (exprNode && exprNode.type === 'member_expression') {
142
+ // Property of member expression is the last child
143
+ const propNode = exprNode.children?.[exprNode.children.length - 1];
144
+ if (propNode) {
145
+ const methodName = rawText(propNode);
146
+ if (['map', 'filter', 'reduce', 'sort', 'groupBy'].includes(methodName)) {
147
+ hasBusinessLogic = true;
148
+ }
149
+ }
125
150
  }
126
151
  }
127
- ts.forEachChild(n, checkNode);
128
- };
129
- checkNode(node);
152
+ });
130
153
  // Consider it business logic if there are complex conditions or many statements
131
154
  return hasBusinessLogic || (statementCount > 10 && hasComplexConditions);
132
155
  }
@@ -153,12 +176,15 @@ export function areResponsibilitiesRelated(resp1, resp2) {
153
176
  ];
154
177
  return relatedGroups.some(group => group.includes(resp1) && group.includes(resp2));
155
178
  }
179
+ // ---------------------------------------------------------------------------
180
+ // Sub-analyzers
181
+ // ---------------------------------------------------------------------------
156
182
  /**
157
183
  * Analyzes hook usage to identify responsibilities
158
184
  */
159
- export function analyzeHookUsage(sourceFile, component, metadata) {
185
+ export function analyzeHookUsage(component, metadata) {
160
186
  const responsibilities = [];
161
- const hooks = metadata?.hooks || extractHooks(component, sourceFile);
187
+ const hooks = metadata?.hooks || extractHooks(component);
162
188
  // Define hook groups that represent cohesive responsibilities
163
189
  const hookGroups = {
164
190
  state: {
@@ -208,21 +234,7 @@ export function analyzeHookUsage(sourceFile, component, metadata) {
208
234
  });
209
235
  }
210
236
  }
211
- // Group hooks by type for backward compatibility
212
- const stateHooks = hooks.filter(h => h.name === 'useState' || h.name === 'useReducer');
213
- const effectHooks = hooks.filter(h => h.name === 'useEffect' || h.name === 'useLayoutEffect');
214
- const contextHooks = hooks.filter(h => h.name === 'useContext');
215
- const routerHooks = hooks.filter(h => h.name === 'useRouter' || h.name === 'useNavigate' || h.name === 'useParams' || h.name === 'useSearchParams');
216
237
  const customHooks = hooks.filter(h => h.customHook);
217
- // Additional analysis for custom hooks only (standard hooks already handled by groups)
218
- const uncategorizedHooks = hooks.filter(hook => {
219
- // Skip if already in a group
220
- for (const [_, hookNames] of usedGroups.entries()) {
221
- if (hookNames.includes(hook.name))
222
- return false;
223
- }
224
- return true;
225
- });
226
238
  // Analyze custom hooks for mixed responsibilities
227
239
  if (customHooks.length > 0) {
228
240
  customHooks.forEach(hook => {
@@ -250,116 +262,110 @@ export function analyzeHookUsage(sourceFile, component, metadata) {
250
262
  /**
251
263
  * Analyzes useEffect hooks for side effects and data fetching
252
264
  */
253
- export function analyzeEffects(sourceFile, component) {
265
+ export function analyzeEffects(component) {
254
266
  const responsibilities = [];
255
- ts.forEachChild(component, function visit(node) {
256
- if (ts.isCallExpression(node) &&
257
- ts.isIdentifier(node.expression) &&
258
- (node.expression.text === 'useEffect' || node.expression.text === 'useLayoutEffect')) {
259
- const effectBody = node.arguments[0];
260
- if (effectBody) {
261
- // Check for data fetching
262
- if (containsDataFetching(effectBody)) {
263
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
264
- responsibilities.push({
265
- type: ResponsibilityType.DataFetching,
266
- indicators: ['fetch in useEffect', 'async data loading'],
267
- severity: 'mixed',
268
- line: line + 1,
269
- details: 'Data fetching in effect hook'
270
- });
271
- }
272
- // Check for subscriptions
273
- if (effectBody.getText().match(/addEventListener|subscribe|on\(/)) {
274
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
275
- responsibilities.push({
276
- type: ResponsibilityType.Subscriptions,
277
- indicators: ['event subscription', 'listener setup'],
278
- severity: 'mixed',
279
- line: line + 1
280
- });
281
- }
282
- // Check for side effects (analytics, logging)
283
- if (effectBody.getText().match(/track|analytics|log|console|gtag|ga\(/i)) {
284
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
285
- responsibilities.push({
286
- type: ResponsibilityType.SideEffects,
287
- indicators: ['analytics', 'tracking', 'logging'],
288
- severity: 'unrelated',
289
- line: line + 1,
290
- details: 'Analytics/logging side effects'
291
- });
267
+ // Walk children only, not the component node itself (matches old ts.forEachChild behavior)
268
+ for (const child of component.children ?? []) {
269
+ walkAST(child, (node) => {
270
+ if (node.type === 'call_expression') {
271
+ const callee = node.children?.[0];
272
+ if (callee && callee.type === 'identifier') {
273
+ const calleeText = rawText(callee);
274
+ if (calleeText === 'useEffect' || calleeText === 'useLayoutEffect') {
275
+ const argsNode = node.children?.find(c => c.type === 'arguments');
276
+ const argList = argsNode?.children ?? [];
277
+ // First argument is the effect callback
278
+ const effectBody = argList.find(c => c.type !== '(' && c.type !== ')');
279
+ if (effectBody) {
280
+ const effectText = rawText(effectBody);
281
+ const { line } = getLineAndColumn(node);
282
+ // Check for data fetching
283
+ if (containsDataFetching(effectBody)) {
284
+ responsibilities.push({
285
+ type: ResponsibilityType.DataFetching,
286
+ indicators: ['fetch in useEffect', 'async data loading'],
287
+ severity: 'mixed',
288
+ line,
289
+ details: 'Data fetching in effect hook'
290
+ });
291
+ }
292
+ // Check for subscriptions
293
+ if (effectText.match(/addEventListener|subscribe|on\(/)) {
294
+ responsibilities.push({
295
+ type: ResponsibilityType.Subscriptions,
296
+ indicators: ['event subscription', 'listener setup'],
297
+ severity: 'mixed',
298
+ line
299
+ });
300
+ }
301
+ // Check for side effects (analytics, logging)
302
+ if (effectText.match(/track|analytics|log|console|gtag|ga\(/i)) {
303
+ responsibilities.push({
304
+ type: ResponsibilityType.SideEffects,
305
+ indicators: ['analytics', 'tracking', 'logging'],
306
+ severity: 'unrelated',
307
+ line,
308
+ details: 'Analytics/logging side effects'
309
+ });
310
+ }
311
+ }
312
+ }
292
313
  }
293
314
  }
294
- }
295
- ts.forEachChild(node, visit);
296
- });
297
- return responsibilities;
298
- }
299
- /**
300
- * Helper to find a node at a specific line number
301
- */
302
- function findNodeAtLine(root, targetLine) {
303
- let result = null;
304
- function visit(node) {
305
- if (result)
306
- return;
307
- const sourceFile = node.getSourceFile();
308
- if (sourceFile) {
309
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
310
- if (line + 1 === targetLine) {
311
- result = node;
312
- return;
313
- }
314
- }
315
- ts.forEachChild(node, visit);
315
+ });
316
316
  }
317
- visit(root);
318
- return result;
317
+ return responsibilities;
319
318
  }
320
319
  /**
321
320
  * Analyzes event handlers in a component
322
321
  */
323
- export function analyzeEventHandlers(sourceFile, component) {
322
+ export function analyzeEventHandlers(component) {
324
323
  const responsibilities = [];
325
324
  const eventHandlers = [];
326
- ts.forEachChild(component, function visit(node) {
327
- // Check JSX attributes for event handlers
328
- if (ts.isJsxAttribute(node) && ts.isIdentifier(node.name)) {
329
- const attrName = node.name.text;
330
- if (attrName.startsWith('on')) {
331
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
332
- // Calculate complexity of the handler
333
- let complexity = 0;
334
- if (node.initializer && ts.isJsxExpression(node.initializer)) {
335
- const expr = node.initializer.expression;
336
- if (expr) {
337
- // Inline function or arrow function
338
- if (ts.isFunctionExpression(expr) || ts.isArrowFunction(expr)) {
339
- complexity = calculateHandlerComplexity(expr);
325
+ // Walk children only, not the component node itself
326
+ for (const child of component.children ?? []) {
327
+ walkAST(child, (node) => {
328
+ // Check JSX attributes for event handlers
329
+ if (node.type === 'jsx_attribute') {
330
+ const nameNode = node.children?.find(c => c.type === 'property_identifier');
331
+ if (nameNode) {
332
+ const attrName = rawText(nameNode);
333
+ if (attrName.startsWith('on')) {
334
+ const { line } = getLineAndColumn(node);
335
+ // Calculate complexity of the handler
336
+ let complexity = 0;
337
+ const initializer = node.children?.find(c => c.type === 'jsx_expression');
338
+ if (initializer) {
339
+ // The expression inside jsx_expression (skip `{` and `}`)
340
+ const expr = initializer.children?.find(c => c.type !== '{' && c.type !== '}');
341
+ if (expr && (expr.type === 'arrow_function' || expr.type === 'function_expression')) {
342
+ complexity = calculateHandlerComplexity(expr);
343
+ }
340
344
  }
345
+ eventHandlers.push({
346
+ name: attrName,
347
+ complexity,
348
+ line
349
+ });
341
350
  }
342
351
  }
343
- eventHandlers.push({
344
- name: attrName,
345
- complexity,
346
- line: line + 1
347
- });
348
352
  }
349
- }
350
- // Check for method definitions that look like event handlers
351
- if ((ts.isMethodDeclaration(node) || ts.isPropertyDeclaration(node)) && node.name) {
352
- const name = node.name.getText();
353
- if (name.match(/^(handle|on)[A-Z]/)) {
354
- const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
355
- const complexity = ts.isMethodDeclaration(node) && node.body
356
- ? calculateHandlerComplexity(node)
357
- : 0;
358
- eventHandlers.push({ name, complexity, line: line + 1 });
353
+ // Check for method definitions that look like event handlers
354
+ if (node.type === 'method_definition' || node.type === 'public_field_definition') {
355
+ const nameNode = node.children?.find(c => c.type === 'identifier' || c.type === 'property_identifier');
356
+ if (nameNode) {
357
+ const name = rawText(nameNode);
358
+ if (name.match(/^(handle|on)[A-Z]/)) {
359
+ const { line } = getLineAndColumn(node);
360
+ const complexity = node.type === 'method_definition'
361
+ ? calculateHandlerComplexity(node)
362
+ : 0;
363
+ eventHandlers.push({ name, complexity, line });
364
+ }
365
+ }
359
366
  }
360
- }
361
- ts.forEachChild(node, visit);
362
- });
367
+ });
368
+ }
363
369
  // Analyze the collected event handlers
364
370
  if (eventHandlers.length > 0) {
365
371
  // Check for complex business logic in handlers
@@ -401,64 +407,88 @@ export function analyzeEventHandlers(sourceFile, component) {
401
407
  */
402
408
  function calculateHandlerComplexity(node) {
403
409
  let lineCount = 0;
404
- const sourceFile = node.getSourceFile();
405
- if (sourceFile && node.getStart() && node.getEnd()) {
406
- const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
407
- const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
408
- lineCount = end.line - start.line + 1;
410
+ // Use location for line span calculation
411
+ if (node.location?.start && node.location?.end) {
412
+ lineCount = node.location.end.line - node.location.start.line + 1;
409
413
  }
410
414
  // Also check for complexity indicators
411
- let hasBusinessLogic = containsBusinessLogic(node);
415
+ const hasBusinessLogic = containsBusinessLogic(node);
412
416
  return hasBusinessLogic ? lineCount * 1.5 : lineCount;
413
417
  }
414
418
  /**
415
419
  * Analyzes rendering logic and JSX complexity
416
420
  */
417
- export function analyzeRenderingLogic(sourceFile, component) {
421
+ export function analyzeRenderingLogic(component) {
418
422
  const responsibilities = [];
419
423
  let jsxElementCount = 0;
420
424
  let conditionalRenderCount = 0;
421
425
  let hasComplexStyling = false;
422
426
  let hasLayoutLogic = false;
423
- ts.forEachChild(component, function visit(node) {
424
- // Count JSX elements
425
- if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
426
- jsxElementCount++;
427
- // Check for layout components
428
- const tagName = ts.isJsxElement(node)
429
- ? node.openingElement.tagName.getText()
430
- : node.tagName.getText();
431
- if (tagName.match(/Grid|Flex|Layout|Container|Row|Col/i)) {
432
- hasLayoutLogic = true;
427
+ // Walk children only, not the component node itself
428
+ for (const child of component.children ?? []) {
429
+ walkAST(child, (node) => {
430
+ // Count JSX elements
431
+ if (node.type === 'jsx_element') {
432
+ jsxElementCount++;
433
+ // Check for layout components — find tag name from open_tag child
434
+ const openTag = node.children?.find(c => c.type === 'open_tag');
435
+ if (openTag) {
436
+ const tagNode = openTag.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
437
+ if (tagNode) {
438
+ const tagName = rawText(tagNode);
439
+ if (tagName.match(/Grid|Flex|Layout|Container|Row|Col/i)) {
440
+ hasLayoutLogic = true;
441
+ }
442
+ }
443
+ }
433
444
  }
434
- }
435
- // Check for conditional rendering
436
- if (ts.isConditionalExpression(node) && node.parent &&
437
- (ts.isJsxExpression(node.parent) || ts.isReturnStatement(node.parent))) {
438
- conditionalRenderCount++;
439
- }
440
- // Check for complex styling logic
441
- if (ts.isJsxAttribute(node) && node.name && node.name.getText() === 'style') {
442
- if (node.initializer && ts.isJsxExpression(node.initializer)) {
443
- const styleExpr = node.initializer.expression;
444
- if (styleExpr && !ts.isObjectLiteralExpression(styleExpr)) {
445
- // Dynamic style calculation
446
- hasComplexStyling = true;
445
+ if (node.type === 'jsx_self_closing_element') {
446
+ jsxElementCount++;
447
+ // Check tag name (first named child that's not `<`)
448
+ const tagNode = node.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
449
+ if (tagNode) {
450
+ const tagName = rawText(tagNode);
451
+ if (tagName.match(/Grid|Flex|Layout|Container|Row|Col/i)) {
452
+ hasLayoutLogic = true;
453
+ }
447
454
  }
448
455
  }
449
- }
450
- // Check for className with complex logic
451
- if (ts.isJsxAttribute(node) && node.name && node.name.getText() === 'className') {
452
- if (node.initializer && ts.isJsxExpression(node.initializer)) {
453
- const classExpr = node.initializer.expression;
454
- if (classExpr && !ts.isStringLiteral(classExpr)) {
455
- // Dynamic className
456
- hasComplexStyling = true;
456
+ // Check for conditional rendering (ternary in JSX expression or return statement)
457
+ if (node.type === 'ternary_expression' && node.parent) {
458
+ const parentType = node.parent.type;
459
+ if (parentType === 'jsx_expression' || parentType === 'return_statement') {
460
+ conditionalRenderCount++;
457
461
  }
458
462
  }
459
- }
460
- ts.forEachChild(node, visit);
461
- });
463
+ // Check for complex styling logic
464
+ if (node.type === 'jsx_attribute') {
465
+ const nameNode = node.children?.find(c => c.type === 'property_identifier');
466
+ if (nameNode) {
467
+ const attrName = rawText(nameNode);
468
+ if (attrName === 'style') {
469
+ const jsxExpr = node.children?.find(c => c.type === 'jsx_expression');
470
+ if (jsxExpr) {
471
+ const styleExpr = jsxExpr.children?.find(c => c.type !== '{' && c.type !== '}');
472
+ if (styleExpr && styleExpr.type !== 'object') {
473
+ // Dynamic style calculation
474
+ hasComplexStyling = true;
475
+ }
476
+ }
477
+ }
478
+ if (attrName === 'className') {
479
+ const jsxExpr = node.children?.find(c => c.type === 'jsx_expression');
480
+ if (jsxExpr) {
481
+ const classExpr = jsxExpr.children?.find(c => c.type !== '{' && c.type !== '}');
482
+ if (classExpr && classExpr.type !== 'string') {
483
+ // Dynamic className
484
+ hasComplexStyling = true;
485
+ }
486
+ }
487
+ }
488
+ }
489
+ }
490
+ });
491
+ }
462
492
  // Add layout responsibility only if it's significant
463
493
  // Don't flag basic styling in forms or simple components
464
494
  if ((hasLayoutLogic && jsxElementCount > 20) || (hasComplexStyling && !hasLayoutLogic)) {