code-auditor-mcp 5.0.2 → 5.2.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 (336) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +184 -3
  3. package/README.md +24 -2
  4. package/configs/hhra-compat.json +12 -118
  5. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  6. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +11 -1
  7. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  8. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
  9. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +57 -52
  10. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
  11. package/dist/analyzers/provenance.d.ts +9 -4
  12. package/dist/analyzers/provenance.d.ts.map +1 -1
  13. package/dist/analyzers/provenance.js +8 -25
  14. package/dist/analyzers/provenance.js.map +1 -1
  15. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  16. package/dist/analyzers/reactAnalyzer.js +0 -5
  17. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  18. package/dist/analyzers/ruleRegistry.js +4 -4
  19. package/dist/analyzers/ruleRegistry.js.map +1 -1
  20. package/dist/analyzers/ruleTiming.d.ts +1 -1
  21. package/dist/analyzers/ruleTiming.js +2 -2
  22. package/dist/analyzers/ruleTiming.js.map +1 -1
  23. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
  24. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +22 -26
  25. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
  26. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +32 -15
  27. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  28. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +189 -115
  29. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  30. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +0 -2
  31. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  32. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +0 -5
  33. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  34. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -10
  35. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
  36. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +7 -49
  37. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
  38. package/dist/analyzers/universal/schema/config.d.ts.map +1 -1
  39. package/dist/analyzers/universal/schema/config.js +0 -2
  40. package/dist/analyzers/universal/schema/config.js.map +1 -1
  41. package/dist/analyzers/universal/schema/types.d.ts +0 -2
  42. package/dist/analyzers/universal/schema/types.d.ts.map +1 -1
  43. package/dist/analyzers/vendorSurfaces.d.ts +126 -0
  44. package/dist/analyzers/vendorSurfaces.d.ts.map +1 -0
  45. package/dist/analyzers/vendorSurfaces.js +580 -0
  46. package/dist/analyzers/vendorSurfaces.js.map +1 -0
  47. package/dist/auditRunner.d.ts.map +1 -1
  48. package/dist/auditRunner.js +136 -142
  49. package/dist/auditRunner.js.map +1 -1
  50. package/dist/churn/churnExtractor.d.ts +0 -1
  51. package/dist/churn/churnExtractor.d.ts.map +1 -1
  52. package/dist/churn/churnExtractor.js +2 -4
  53. package/dist/churn/churnExtractor.js.map +1 -1
  54. package/dist/cli.d.ts +1 -1
  55. package/dist/cli.d.ts.map +1 -1
  56. package/dist/cli.js +195 -26
  57. package/dist/cli.js.map +1 -1
  58. package/dist/codeIndex/migrations.d.ts.map +1 -1
  59. package/dist/codeIndex/migrations.js +4 -3
  60. package/dist/codeIndex/migrations.js.map +1 -1
  61. package/dist/codeIndexDB.d.ts +11 -2
  62. package/dist/codeIndexDB.d.ts.map +1 -1
  63. package/dist/codeIndexDB.js +27 -2
  64. package/dist/codeIndexDB.js.map +1 -1
  65. package/dist/config/configLoader.d.ts +60 -7
  66. package/dist/config/configLoader.d.ts.map +1 -1
  67. package/dist/config/configLoader.js +252 -60
  68. package/dist/config/configLoader.js.map +1 -1
  69. package/dist/config/defaults.d.ts +77 -18
  70. package/dist/config/defaults.d.ts.map +1 -1
  71. package/dist/config/defaults.js +105 -43
  72. package/dist/config/defaults.js.map +1 -1
  73. package/dist/constants.d.ts +2 -1
  74. package/dist/constants.d.ts.map +1 -1
  75. package/dist/constants.js +4 -0
  76. package/dist/constants.js.map +1 -1
  77. package/dist/daemon/main.d.ts +0 -1
  78. package/dist/daemon/main.d.ts.map +1 -1
  79. package/dist/daemon/main.js +11 -4
  80. package/dist/daemon/main.js.map +1 -1
  81. package/dist/dataPaths.d.ts +17 -11
  82. package/dist/dataPaths.d.ts.map +1 -1
  83. package/dist/dataPaths.js +51 -16
  84. package/dist/dataPaths.js.map +1 -1
  85. package/dist/hookLog.d.ts +54 -0
  86. package/dist/hookLog.d.ts.map +1 -0
  87. package/dist/hookLog.js +105 -0
  88. package/dist/hookLog.js.map +1 -0
  89. package/dist/hookLogPath.generated.d.ts +3 -0
  90. package/dist/hookLogPath.generated.d.ts.map +1 -0
  91. package/dist/hookLogPath.generated.js +8 -0
  92. package/dist/hookLogPath.generated.js.map +1 -0
  93. package/dist/index.d.ts +0 -5
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +0 -7
  96. package/dist/index.js.map +1 -1
  97. package/dist/installConfig.d.ts +15 -2
  98. package/dist/installConfig.d.ts.map +1 -1
  99. package/dist/installConfig.js +17 -2
  100. package/dist/installConfig.js.map +1 -1
  101. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  102. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +18 -3
  103. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  104. package/dist/mcp-tools/workflowGuide.js +8 -8
  105. package/dist/mcp-tools/workflowGuide.js.map +1 -1
  106. package/dist/mcp-tools-shared.d.ts.map +1 -1
  107. package/dist/mcp-tools-shared.js +5 -2
  108. package/dist/mcp-tools-shared.js.map +1 -1
  109. package/dist/mcp-ui-simple.d.ts +5 -0
  110. package/dist/mcp-ui-simple.d.ts.map +1 -1
  111. package/dist/mcp-ui-simple.js +9 -2
  112. package/dist/mcp-ui-simple.js.map +1 -1
  113. package/dist/mcp.d.ts +0 -1
  114. package/dist/mcp.d.ts.map +1 -1
  115. package/dist/mcp.js +36 -33
  116. package/dist/mcp.js.map +1 -1
  117. package/dist/mcpAuditJobs.d.ts +10 -0
  118. package/dist/mcpAuditJobs.d.ts.map +1 -1
  119. package/dist/mcpAuditJobs.js +10 -1
  120. package/dist/mcpAuditJobs.js.map +1 -1
  121. package/dist/mcpAutoIndex.d.ts.map +1 -1
  122. package/dist/mcpAutoIndex.js +2 -1
  123. package/dist/mcpAutoIndex.js.map +1 -1
  124. package/dist/phase/colorMath.d.ts +18 -5
  125. package/dist/phase/colorMath.d.ts.map +1 -1
  126. package/dist/phase/colorMath.js +88 -5
  127. package/dist/phase/colorMath.js.map +1 -1
  128. package/dist/phase/dataAccessCallsCandidates.js +1 -1
  129. package/dist/phase/dataAccessCallsCandidates.js.map +1 -1
  130. package/dist/phase/goFunctionAnalysis.d.ts +2 -2
  131. package/dist/phase/goFunctionAnalysis.js +2 -2
  132. package/dist/phase/goFunctions.d.ts +2 -2
  133. package/dist/phase/goFunctions.js +2 -2
  134. package/dist/phase/goImports.d.ts +2 -2
  135. package/dist/phase/goImports.js +2 -2
  136. package/dist/phase/goSwitches.d.ts +2 -2
  137. package/dist/phase/goSwitches.js +2 -2
  138. package/dist/phase/loopQueryCandidates.js +1 -1
  139. package/dist/phase/loopQueryCandidates.js.map +1 -1
  140. package/dist/phase/phaseModel.d.ts +37 -8
  141. package/dist/phase/phaseModel.d.ts.map +1 -1
  142. package/dist/phase/phaseModel.js +33 -8
  143. package/dist/phase/phaseModel.js.map +1 -1
  144. package/dist/phase/producers.d.ts.map +1 -1
  145. package/dist/phase/producers.js +24 -17
  146. package/dist/phase/producers.js.map +1 -1
  147. package/dist/phase/reachability.d.ts +44 -1
  148. package/dist/phase/reachability.d.ts.map +1 -1
  149. package/dist/phase/reachability.js +79 -0
  150. package/dist/phase/reachability.js.map +1 -1
  151. package/dist/phase/rules/crossDomain.d.ts.map +1 -1
  152. package/dist/phase/rules/crossDomain.js +16 -6
  153. package/dist/phase/rules/crossDomain.js.map +1 -1
  154. package/dist/phase/rules/dry.d.ts.map +1 -1
  155. package/dist/phase/rules/dry.js +0 -1
  156. package/dist/phase/rules/dry.js.map +1 -1
  157. package/dist/phase/rules/goRules.d.ts +2 -2
  158. package/dist/phase/rules/goRules.js +2 -2
  159. package/dist/phase/rules/secrets.d.ts +22 -8
  160. package/dist/phase/rules/secrets.d.ts.map +1 -1
  161. package/dist/phase/rules/secrets.js +48 -67
  162. package/dist/phase/rules/secrets.js.map +1 -1
  163. package/dist/phase/rules/styles.d.ts +23 -9
  164. package/dist/phase/rules/styles.d.ts.map +1 -1
  165. package/dist/phase/rules/styles.js +47 -15
  166. package/dist/phase/rules/styles.js.map +1 -1
  167. package/dist/phase/rules/unreferencedModule.d.ts.map +1 -1
  168. package/dist/phase/rules/unreferencedModule.js +16 -5
  169. package/dist/phase/rules/unreferencedModule.js.map +1 -1
  170. package/dist/phase/runner.d.ts +16 -7
  171. package/dist/phase/runner.d.ts.map +1 -1
  172. package/dist/phase/runner.js +32 -20
  173. package/dist/phase/runner.js.map +1 -1
  174. package/dist/phase/stylesCss.d.ts.map +1 -1
  175. package/dist/phase/stylesCss.js +4 -0
  176. package/dist/phase/stylesCss.js.map +1 -1
  177. package/dist/phase/stylesMarkup.d.ts.map +1 -1
  178. package/dist/phase/stylesMarkup.js +4 -0
  179. package/dist/phase/stylesMarkup.js.map +1 -1
  180. package/dist/phase/stylesSource.d.ts.map +1 -1
  181. package/dist/phase/stylesSource.js +6 -0
  182. package/dist/phase/stylesSource.js.map +1 -1
  183. package/dist/phase/testProgram.d.ts +57 -0
  184. package/dist/phase/testProgram.d.ts.map +1 -0
  185. package/dist/phase/testProgram.js +244 -0
  186. package/dist/phase/testProgram.js.map +1 -0
  187. package/dist/phase/typeDeclarations.d.ts +2 -2
  188. package/dist/phase/typeDeclarations.js +2 -2
  189. package/dist/phase/types.d.ts +46 -0
  190. package/dist/phase/types.d.ts.map +1 -1
  191. package/dist/pipelineAdapters.d.ts +1 -171
  192. package/dist/pipelineAdapters.d.ts.map +1 -1
  193. package/dist/pipelineAdapters.js +47 -1281
  194. package/dist/pipelineAdapters.js.map +1 -1
  195. package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
  196. package/dist/reporting/csvReportGenerator.js +0 -6
  197. package/dist/reporting/csvReportGenerator.js.map +1 -1
  198. package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
  199. package/dist/reporting/htmlReportGenerator.js +0 -4
  200. package/dist/reporting/htmlReportGenerator.js.map +1 -1
  201. package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
  202. package/dist/reporting/jsonReportGenerator.js +0 -1
  203. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  204. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
  205. package/dist/reporting/sarifReportGenerator.js +0 -7
  206. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  207. package/dist/sqlite/driver.d.ts +17 -1
  208. package/dist/sqlite/driver.d.ts.map +1 -1
  209. package/dist/sqlite/driver.js +28 -5
  210. package/dist/sqlite/driver.js.map +1 -1
  211. package/dist/styles/cssInJsHarvest.d.ts +36 -0
  212. package/dist/styles/cssInJsHarvest.d.ts.map +1 -0
  213. package/dist/styles/cssInJsHarvest.js +78 -0
  214. package/dist/styles/cssInJsHarvest.js.map +1 -0
  215. package/dist/styles/definedClasses.d.ts +95 -0
  216. package/dist/styles/definedClasses.d.ts.map +1 -0
  217. package/dist/styles/definedClasses.js +129 -0
  218. package/dist/styles/definedClasses.js.map +1 -0
  219. package/dist/styles/markupStyleHarvest.d.ts +33 -0
  220. package/dist/styles/markupStyleHarvest.d.ts.map +1 -0
  221. package/dist/styles/markupStyleHarvest.js +73 -0
  222. package/dist/styles/markupStyleHarvest.js.map +1 -0
  223. package/dist/styles/styleExtractor.d.ts +37 -0
  224. package/dist/styles/styleExtractor.d.ts.map +1 -1
  225. package/dist/styles/styleExtractor.js +89 -33
  226. package/dist/styles/styleExtractor.js.map +1 -1
  227. package/dist/styles/styleIndexer.d.ts.map +1 -1
  228. package/dist/styles/styleIndexer.js +11 -10
  229. package/dist/styles/styleIndexer.js.map +1 -1
  230. package/dist/styles/tailwindExpander.d.ts.map +1 -1
  231. package/dist/styles/tailwindExpander.js +31 -10
  232. package/dist/styles/tailwindExpander.js.map +1 -1
  233. package/dist/telemetry.d.ts +67 -1
  234. package/dist/telemetry.d.ts.map +1 -1
  235. package/dist/telemetry.js +100 -20
  236. package/dist/telemetry.js.map +1 -1
  237. package/dist/types/crossLanguage.d.ts +1 -0
  238. package/dist/types/crossLanguage.d.ts.map +1 -1
  239. package/dist/types.d.ts +23 -56
  240. package/dist/types.d.ts.map +1 -1
  241. package/dist/types.js +4 -4
  242. package/dist/types.js.map +1 -1
  243. package/dist/version.generated.d.ts +1 -1
  244. package/dist/version.generated.js +1 -1
  245. package/examples/.auditrc.example.json +7 -22
  246. package/examples/.auditrc.json +12 -155
  247. package/examples/.code-auditor.json +8 -51
  248. package/examples/nextjs.auditrc.json +7 -34
  249. package/examples/node-api.auditrc.json +6 -46
  250. package/examples/react.auditrc.json +8 -25
  251. package/examples/tolerant-solid.auditrc.json +12 -44
  252. package/package.json +6 -5
  253. package/plugin/.claude-plugin/manifest.json +10 -9
  254. package/plugin/.claude-plugin/plugin.json +1 -1
  255. package/plugin/hooks/hooks.json +4 -4
  256. package/plugin/scripts/hook-audit.sh +9 -0
  257. package/plugin/scripts/hook-common.sh +8 -2
  258. package/plugin/scripts/hook-drift-check.sh +10 -1
  259. package/plugin/scripts/hook-log-path.sh +7 -0
  260. package/plugin/scripts/hook-self-audit.sh +9 -0
  261. package/plugin/scripts/hook-warm.sh +17 -11
  262. package/plugin/skills/code-auditor/SKILL.md +26 -3
  263. package/dist/__tests__/fixtures/spec-20/scripts/tool.d.ts +0 -6
  264. package/dist/__tests__/fixtures/spec-20/scripts/tool.d.ts.map +0 -1
  265. package/dist/__tests__/fixtures/spec-20/scripts/tool.js +0 -12
  266. package/dist/__tests__/fixtures/spec-20/scripts/tool.js.map +0 -1
  267. package/dist/__tests__/fixtures/spec-20/src/demo-module.d.ts +0 -7
  268. package/dist/__tests__/fixtures/spec-20/src/demo-module.d.ts.map +0 -1
  269. package/dist/__tests__/fixtures/spec-20/src/demo-module.js +0 -13
  270. package/dist/__tests__/fixtures/spec-20/src/demo-module.js.map +0 -1
  271. package/dist/__tests__/fixtures/spec-52/item-01-prepare-in-loop.d.ts +0 -14
  272. package/dist/__tests__/fixtures/spec-52/item-01-prepare-in-loop.d.ts.map +0 -1
  273. package/dist/__tests__/fixtures/spec-52/item-01-prepare-in-loop.js +0 -16
  274. package/dist/__tests__/fixtures/spec-52/item-01-prepare-in-loop.js.map +0 -1
  275. package/dist/__tests__/fixtures/spec-52/item-02-prepare-bind-accumulate-batch.d.ts +0 -15
  276. package/dist/__tests__/fixtures/spec-52/item-02-prepare-bind-accumulate-batch.d.ts.map +0 -1
  277. package/dist/__tests__/fixtures/spec-52/item-02-prepare-bind-accumulate-batch.js +0 -17
  278. package/dist/__tests__/fixtures/spec-52/item-02-prepare-bind-accumulate-batch.js.map +0 -1
  279. package/dist/__tests__/fixtures/spec-52/item-03-exec-in-loop.d.ts +0 -14
  280. package/dist/__tests__/fixtures/spec-52/item-03-exec-in-loop.d.ts.map +0 -1
  281. package/dist/__tests__/fixtures/spec-52/item-03-exec-in-loop.js +0 -19
  282. package/dist/__tests__/fixtures/spec-52/item-03-exec-in-loop.js.map +0 -1
  283. package/dist/__tests__/fixtures/spec-52/item-04-storage-sql-exec-in-loop.d.ts +0 -18
  284. package/dist/__tests__/fixtures/spec-52/item-04-storage-sql-exec-in-loop.d.ts.map +0 -1
  285. package/dist/__tests__/fixtures/spec-52/item-04-storage-sql-exec-in-loop.js +0 -19
  286. package/dist/__tests__/fixtures/spec-52/item-04-storage-sql-exec-in-loop.js.map +0 -1
  287. package/dist/__tests__/fixtures/spec-52/item-05-upsert-forms.d.ts +0 -19
  288. package/dist/__tests__/fixtures/spec-52/item-05-upsert-forms.d.ts.map +0 -1
  289. package/dist/__tests__/fixtures/spec-52/item-05-upsert-forms.js +0 -19
  290. package/dist/__tests__/fixtures/spec-52/item-05-upsert-forms.js.map +0 -1
  291. package/dist/__tests__/fixtures/spec-52/item-06-chained-prepare-run-in-loop.d.ts +0 -17
  292. package/dist/__tests__/fixtures/spec-52/item-06-chained-prepare-run-in-loop.d.ts.map +0 -1
  293. package/dist/__tests__/fixtures/spec-52/item-06-chained-prepare-run-in-loop.js +0 -19
  294. package/dist/__tests__/fixtures/spec-52/item-06-chained-prepare-run-in-loop.js.map +0 -1
  295. package/dist/__tests__/fixtures/spec-52/item-07-chained-prepare-bind-first-in-loop.d.ts +0 -25
  296. package/dist/__tests__/fixtures/spec-52/item-07-chained-prepare-bind-first-in-loop.d.ts.map +0 -1
  297. package/dist/__tests__/fixtures/spec-52/item-07-chained-prepare-bind-first-in-loop.js +0 -21
  298. package/dist/__tests__/fixtures/spec-52/item-07-chained-prepare-bind-first-in-loop.js.map +0 -1
  299. package/dist/__tests__/fixtures/spec-52/item-08-promise-all-of-statements-in-loop.d.ts +0 -15
  300. package/dist/__tests__/fixtures/spec-52/item-08-promise-all-of-statements-in-loop.d.ts.map +0 -1
  301. package/dist/__tests__/fixtures/spec-52/item-08-promise-all-of-statements-in-loop.js +0 -19
  302. package/dist/__tests__/fixtures/spec-52/item-08-promise-all-of-statements-in-loop.js.map +0 -1
  303. package/dist/__tests__/fixtures/spec-52/item-09-promise-all-map-of-statements-in-loop.d.ts +0 -14
  304. package/dist/__tests__/fixtures/spec-52/item-09-promise-all-map-of-statements-in-loop.d.ts.map +0 -1
  305. package/dist/__tests__/fixtures/spec-52/item-09-promise-all-map-of-statements-in-loop.js +0 -14
  306. package/dist/__tests__/fixtures/spec-52/item-09-promise-all-map-of-statements-in-loop.js.map +0 -1
  307. package/dist/__tests__/fixtures/spec-52/item-10-promise-all-map-of-eager-all-in-loop.d.ts +0 -15
  308. package/dist/__tests__/fixtures/spec-52/item-10-promise-all-map-of-eager-all-in-loop.d.ts.map +0 -1
  309. package/dist/__tests__/fixtures/spec-52/item-10-promise-all-map-of-eager-all-in-loop.js +0 -16
  310. package/dist/__tests__/fixtures/spec-52/item-10-promise-all-map-of-eager-all-in-loop.js.map +0 -1
  311. package/dist/languages/go/analyzer-darwin-amd64 +0 -0
  312. package/dist/languages/go/analyzer-darwin-arm64 +0 -0
  313. package/dist/languages/go/analyzer-linux-amd64 +0 -0
  314. package/dist/languages/go/analyzer-linux-arm64 +0 -0
  315. package/dist/languages/go/analyzer-src/analyzer.go +0 -643
  316. package/dist/languages/go/analyzer-src/dataaccess.go +0 -388
  317. package/dist/languages/go/analyzer-src/go.mod +0 -3
  318. package/dist/languages/go/analyzer-src/indexer.go +0 -268
  319. package/dist/languages/go/analyzer-src/parser.go +0 -461
  320. package/dist/languages/go/analyzer-src/solid.go +0 -311
  321. package/dist/languages/go/analyzer-src/testconventions.go +0 -25
  322. package/dist/languages/go/analyzer-src/types.go +0 -156
  323. package/dist/languages/go/analyzer-windows-amd64.exe +0 -0
  324. package/dist/languages/go/go.mod +0 -7
  325. package/dist/languages/go/main.go +0 -203
  326. package/dist/native/ast-grep-napi.darwin-arm64.node +0 -0
  327. package/dist/native/ast-grep-napi.darwin-x64.node +0 -0
  328. package/dist/native/ast-grep-napi.linux-arm64-gnu.node +0 -0
  329. package/dist/native/ast-grep-napi.linux-arm64-musl.node +0 -0
  330. package/dist/native/ast-grep-napi.linux-x64-gnu.node +0 -0
  331. package/dist/native/ast-grep-napi.linux-x64-musl.node +0 -0
  332. package/dist/native/ast-grep-napi.win32-x64-msvc.node +0 -0
  333. package/dist/native-bootstrap.d.ts +0 -15
  334. package/dist/native-bootstrap.d.ts.map +0 -1
  335. package/dist/native-bootstrap.js +0 -75
  336. package/dist/native-bootstrap.js.map +0 -1
@@ -1,643 +0,0 @@
1
- package analyzer
2
-
3
- import (
4
- "go/ast"
5
- "go/token"
6
- "sort"
7
- "strconv"
8
- "strings"
9
- "time"
10
- )
11
-
12
- // Analyzer is the main Go code analyzer
13
- type Analyzer struct {
14
- options AnalysisOptions
15
- parser *Parser
16
- }
17
-
18
- // NewAnalyzer creates a new Go analyzer
19
- func NewAnalyzer(options AnalysisOptions) *Analyzer {
20
- parser := NewParser(options)
21
- return &Analyzer{
22
- options: options,
23
- parser: parser,
24
- }
25
- }
26
-
27
- // Analyze performs comprehensive analysis of Go files
28
- func (a *Analyzer) Analyze(files []string) (*AnalysisResult, error) {
29
- startTime := time.Now()
30
-
31
- // Exclude *_test.go files before parsing: test code is not production API.
32
- // Mirrors languages/testConventions.ts go.filePatterns.
33
- files = excludeTestFiles(files)
34
-
35
- // Parse all files
36
- if err := a.parser.ParseFiles(files); err != nil {
37
- return nil, err
38
- }
39
-
40
- result := &AnalysisResult{
41
- Violations: []Violation{},
42
- IndexEntries: []IndexEntry{},
43
- Metrics: Metrics{
44
- FilesAnalyzed: int64(len(files)),
45
- ExecutionTime: 0, // Will be set at the end
46
- },
47
- Errors: []Error{},
48
- }
49
-
50
- // Run enabled analyzers
51
- a.runEnabledAnalyzers(result)
52
-
53
- // Generate index entries
54
- indexer := NewIndexer(a.parser)
55
- result.IndexEntries = indexer.GenerateIndexEntries()
56
-
57
- // Filter violations by severity
58
- result.Violations = a.filterViolationsBySeverity(result.Violations)
59
-
60
- // Calculate execution time
61
- result.Metrics.ExecutionTime = time.Since(startTime).Milliseconds()
62
-
63
- return result, nil
64
- }
65
-
66
- // runEnabledAnalyzers runs each enabled analyzer and appends its violations to
67
- // the result. Shared by Analyze and AnalyzeContent to avoid duplicated dispatch.
68
- func (a *Analyzer) runEnabledAnalyzers(result *AnalysisResult) {
69
- for _, analyzerName := range a.options.Analyzers {
70
- switch analyzerName {
71
- case "solid":
72
- result.Violations = append(result.Violations, a.runSOLIDAnalysis()...)
73
- case "imports":
74
- result.Violations = append(result.Violations, a.runImportAnalysis()...)
75
- case "errors":
76
- result.Violations = append(result.Violations, a.runErrorAnalysis()...)
77
- case "goroutines":
78
- result.Violations = append(result.Violations, a.runGoroutineAnalysis()...)
79
- case "channels":
80
- result.Violations = append(result.Violations, a.runChannelAnalysis()...)
81
- case "data-access":
82
- result.Violations = append(result.Violations, a.runDataAccessAnalysis()...)
83
- }
84
- }
85
- }
86
-
87
- // AnalyzeContent performs analysis of Go content from a string
88
- func (a *Analyzer) AnalyzeContent(filePath, content string) (*AnalysisResult, error) {
89
- startTime := time.Now()
90
-
91
- // A *_test.go file is test code, not production API — exempt it the same
92
- // way the multi-file path does (languages/testConventions.ts go.filePatterns).
93
- if isTestFile(filePath) {
94
- return &AnalysisResult{
95
- Violations: []Violation{},
96
- IndexEntries: []IndexEntry{},
97
- Metrics: Metrics{
98
- FilesAnalyzed: 0,
99
- ExecutionTime: 0,
100
- },
101
- Errors: []Error{},
102
- }, nil
103
- }
104
-
105
- // Parse content instead of file
106
- if err := a.parser.ParseContent(filePath, content); err != nil {
107
- return nil, err
108
- }
109
-
110
- result := &AnalysisResult{
111
- Violations: []Violation{},
112
- IndexEntries: []IndexEntry{},
113
- Metrics: Metrics{
114
- FilesAnalyzed: 1,
115
- ExecutionTime: 0, // Will be set at the end
116
- },
117
- Errors: []Error{},
118
- }
119
-
120
- // Run enabled analyzers
121
- a.runEnabledAnalyzers(result)
122
-
123
- // Generate index entries
124
- indexer := NewIndexer(a.parser)
125
- result.IndexEntries = indexer.GenerateIndexEntries()
126
-
127
- // Filter violations by severity
128
- result.Violations = a.filterViolationsBySeverity(result.Violations)
129
-
130
- // Calculate execution time
131
- result.Metrics.ExecutionTime = time.Since(startTime).Milliseconds()
132
-
133
- return result, nil
134
- }
135
-
136
- // runSOLIDAnalysis runs SOLID principle analysis
137
- func (a *Analyzer) runSOLIDAnalysis() []Violation {
138
- solidAnalyzer := NewSOLIDAnalyzer(a.parser)
139
- return solidAnalyzer.Analyze()
140
- }
141
-
142
- // runImportAnalysis analyzes import usage and organization.
143
- //
144
- // The old `import-organization` predicate was a raw import count
145
- // (`len(file.Imports) > 10`). Count is not "organization" — a file with twelve
146
- // well-grouped imports is fine, and a file with two mis-grouped imports is not.
147
- // The honest reading is grouping: Go convention (goimports/gofmt) requires
148
- // standard-library imports first, then third-party, then local, each block
149
- // sorted. A stdlib import appearing after a third-party import is the
150
- // "mixed-up imports" case a reviewer actually flags. "Unnecessary deps" is out
151
- // of scope — the Go compiler already rejects unused imports at build time, so a
152
- // static analyzer adds no signal there.
153
- func (a *Analyzer) runImportAnalysis() []Violation {
154
- var violations []Violation
155
-
156
- for filePath, file := range a.parser.files {
157
- // Detect import grouping violations (stdlib vs third-party vs local).
158
- if pos, grouped := firstImportGroupViolation(file.Imports); grouped > 0 {
159
- line := a.parser.fileSet.Position(pos).Line
160
- violations = append(violations, Violation{
161
- File: filePath,
162
- Line: line,
163
- Severity: "high",
164
- Message: "Import block mixes standard library and third-party imports without grouping",
165
- Details: map[string]interface{}{
166
- "importCount": len(file.Imports),
167
- "groupingViolations": grouped,
168
- },
169
- Suggestion: "Group standard library imports first, then third-party imports, each block separated by a blank line",
170
- Analyzer: "go",
171
- Rule: "import-organization",
172
- })
173
- }
174
-
175
- // Check for dot imports (considered bad practice)
176
- for _, importSpec := range file.Imports {
177
- if importSpec.Name != nil && importSpec.Name.Name == "." {
178
- pos := a.parser.fileSet.Position(importSpec.Pos())
179
- violations = append(violations, Violation{
180
- File: filePath,
181
- Line: pos.Line,
182
- Severity: "high",
183
- Message: "Dot import detected - can lead to namespace pollution",
184
- Details: map[string]interface{}{
185
- "import": importSpec.Path.Value,
186
- },
187
- Suggestion: "Use explicit import names instead of dot imports",
188
- Analyzer: "go",
189
- Rule: "import-style",
190
- })
191
- }
192
- }
193
- }
194
-
195
- return violations
196
- }
197
-
198
- // runErrorAnalysis analyzes error handling patterns.
199
- //
200
- // It performs an errcheck-style walk: an error identifier assigned from a call
201
- // result that is never compared, returned, passed to another call, or
202
- // explicitly ignored is a dropped error — a likely bug regardless of what the
203
- // enclosing function is named. This replaces the old name-substring proxy
204
- // ("handle"/"check"/"validate"/"verify") that fired on any function whose name
205
- // merely contained one of those words.
206
- func (a *Analyzer) runErrorAnalysis() []Violation {
207
- var violations []Violation
208
-
209
- for filePath, file := range a.parser.files {
210
- ast.Inspect(file, func(n ast.Node) bool {
211
- funcDecl, ok := n.(*ast.FuncDecl)
212
- if !ok || funcDecl.Body == nil || isTestFunction(funcDecl.Name.Name) {
213
- return true
214
- }
215
- if !a.functionDropsError(funcDecl) {
216
- return true
217
- }
218
- pos := a.parser.fileSet.Position(funcDecl.Pos())
219
- violations = append(violations, Violation{
220
- File: filePath,
221
- Line: pos.Line,
222
- Severity: "severe",
223
- Message: "Function assigns an error that is never checked, returned, or propagated",
224
- Details: map[string]interface{}{
225
- "function": funcDecl.Name.Name,
226
- },
227
- Suggestion: "Check the error, return it, or explicitly ignore it with '_ = err'",
228
- Analyzer: "go",
229
- Rule: "error-handling",
230
- })
231
- return true
232
- })
233
- }
234
-
235
- return violations
236
- }
237
-
238
- // runGoroutineAnalysis analyzes goroutine usage for potential issues.
239
- //
240
- // It walks the AST for a `go` statement and reports the function when a
241
- // goroutine is launched with no synchronization mechanism — sync primitives
242
- // (Add/Done/Wait/Lock/Unlock/RLock/RUnlock) or a channel send/receive —
243
- // anywhere in the same function. This replaces the old name-substring proxy
244
- // ("go"/"async"/"concurrent") that fired on any function whose name merely
245
- // contained those substrings.
246
- func (a *Analyzer) runGoroutineAnalysis() []Violation {
247
- var violations []Violation
248
-
249
- for filePath, file := range a.parser.files {
250
- ast.Inspect(file, func(n ast.Node) bool {
251
- funcDecl, ok := n.(*ast.FuncDecl)
252
- if !ok || funcDecl.Body == nil || isTestFunction(funcDecl.Name.Name) {
253
- return true
254
- }
255
- hasGo, hasSync := a.analyzeConcurrency(funcDecl)
256
- if !hasGo || hasSync {
257
- return true
258
- }
259
- pos := a.parser.fileSet.Position(funcDecl.Pos())
260
- violations = append(violations, Violation{
261
- File: filePath,
262
- Line: pos.Line,
263
- Severity: "severe",
264
- Message: "Function launches a goroutine without synchronization",
265
- Details: map[string]interface{}{
266
- "function": funcDecl.Name.Name,
267
- },
268
- Suggestion: "Use sync.WaitGroup or a channel to synchronize the goroutine",
269
- Analyzer: "go",
270
- Rule: "concurrency",
271
- })
272
- return true
273
- })
274
- }
275
-
276
- return violations
277
- }
278
-
279
- // runChannelAnalysis analyzes channels for the provable same-goroutine deadlock.
280
- //
281
- // The old predicate was `containsChannel(function.Signature) && function.Complexity
282
- // > 3` — a signature substring ("chan") plus a cyclomatic-complexity count standing
283
- // in for "potential deadlock". Neither is a deadlock: a channel in the signature is
284
- // not a deadlock, and a 3-statement function can deadlock. The honest, provable
285
- // signal is a *same-goroutine* deadlock: a channel created unbuffered
286
- // (`make(chan T)`, no buffer) that is both sent to and received from (or operated
287
- // on twice) in the same function with no `go` statement in the body. An unbuffered
288
- // send blocks until a receiver is ready; if the counterpart lives in the same
289
- // goroutine, the first operation blocks before the second can run — guaranteed,
290
- // independent of external code. Cross-goroutine deadlock detection is out of scope:
291
- // it needs inter-procedural escape/dataflow analysis the syntax-only subprocess
292
- // lacks.
293
- func (a *Analyzer) runChannelAnalysis() []Violation {
294
- var violations []Violation
295
-
296
- for filePath, file := range a.parser.files {
297
- ast.Inspect(file, func(n ast.Node) bool {
298
- funcDecl, ok := n.(*ast.FuncDecl)
299
- if !ok || funcDecl.Body == nil || isTestFunction(funcDecl.Name.Name) {
300
- return true
301
- }
302
- channel := a.deadlockChannel(funcDecl)
303
- if channel == "" {
304
- return true
305
- }
306
- pos := a.parser.fileSet.Position(funcDecl.Pos())
307
- violations = append(violations, Violation{
308
- File: filePath,
309
- Line: pos.Line,
310
- Severity: "critical",
311
- Message: "Guaranteed deadlock: unbuffered channel is both sent to and received from in the same goroutine",
312
- Details: map[string]interface{}{
313
- "function": funcDecl.Name.Name,
314
- "channel": channel,
315
- },
316
- Suggestion: "Buffer the channel, or run one side (send or receive) in its own goroutine",
317
- Analyzer: "go",
318
- Rule: "channel-deadlock",
319
- })
320
- return true
321
- })
322
- }
323
-
324
- return violations
325
- }
326
-
327
- // filterViolationsBySeverity filters violations based on minimum severity
328
- func (a *Analyzer) filterViolationsBySeverity(violations []Violation) []Violation {
329
- if a.options.MinSeverity == "" {
330
- return violations
331
- }
332
-
333
- severityOrder := map[string]int{
334
- "high": 1,
335
- "severe": 2,
336
- "critical": 3,
337
- }
338
-
339
- minLevel := severityOrder[a.options.MinSeverity]
340
- if minLevel == 0 {
341
- return violations
342
- }
343
-
344
- // A non-nil empty slice so "no violations" serializes to [] not null — a
345
- // nil slice marshals to JSON null, which the TypeScript caller reads as a
346
- // crash rather than an empty result (the same silent-empty class this whole
347
- // subprocess boundary is built to remove).
348
- filtered := make([]Violation, 0, len(violations))
349
- for _, violation := range violations {
350
- if severityOrder[violation.Severity] >= minLevel {
351
- filtered = append(filtered, violation)
352
- }
353
- }
354
-
355
- return filtered
356
- }
357
-
358
- // Helper functions for analysis
359
-
360
- // syncMethodNames are the selector names on sync primitives that signal a
361
- // function is synchronizing its goroutines (sync.WaitGroup and sync.Mutex /
362
- // sync.RWMutex method sets).
363
- var syncMethodNames = map[string]bool{
364
- "Add": true,
365
- "Done": true,
366
- "Wait": true,
367
- "Lock": true,
368
- "Unlock": true,
369
- "RLock": true,
370
- "RUnlock": true,
371
- }
372
-
373
- // functionDropsError reports whether a function body assigns an error from a
374
- // call result and never checks, returns, passes, or explicitly ignores that
375
- // same error on the same path. It collects the source positions of every `err`
376
- // binding-from-call and every "checking" use, then flags an assignment whose
377
- // next use of `err` is a reassignment (or the end of the function) rather than
378
- // a check. Position ordering (not identifier pointer identity) is what links a
379
- // use to its binding, since each `err` occurrence is a distinct AST node.
380
- func (a *Analyzer) functionDropsError(funcDecl *ast.FuncDecl) bool {
381
- var assignPositions []token.Pos
382
- var checkPositions []token.Pos
383
-
384
- // A function with a named `err` result propagates that error on a bare
385
- // `return` — Go returns the current value of the named result. Treating
386
- // bare returns as a check is what keeps `func (w *W) Write(...) (n int,
387
- // err error) { n, err = io.Write(...); return }` from being flagged as a
388
- // dropped error (the dominant named-return idiom).
389
- hasNamedErr := funcDeclHasNamedErr(funcDecl)
390
-
391
- ast.Inspect(funcDecl.Body, func(n ast.Node) bool {
392
- switch node := n.(type) {
393
- case *ast.AssignStmt:
394
- if assignHasCallRHS(node) {
395
- for _, lhs := range node.Lhs {
396
- if ident, ok := lhs.(*ast.Ident); ok && ident.Name == "err" {
397
- assignPositions = append(assignPositions, ident.Pos())
398
- }
399
- }
400
- }
401
- // Explicit ignore: `_ = err`
402
- if len(node.Lhs) == 1 && len(node.Rhs) == 1 && isBlankIdent(node.Lhs[0]) {
403
- if ident, ok := node.Rhs[0].(*ast.Ident); ok && ident.Name == "err" {
404
- checkPositions = append(checkPositions, ident.Pos())
405
- }
406
- }
407
- case *ast.BinaryExpr:
408
- // `err != nil` / `err == nil`
409
- if node.Op == token.NEQ || node.Op == token.EQL {
410
- for _, side := range []ast.Expr{node.X, node.Y} {
411
- if ident, ok := side.(*ast.Ident); ok && ident.Name == "err" {
412
- checkPositions = append(checkPositions, ident.Pos())
413
- }
414
- }
415
- }
416
- case *ast.ReturnStmt:
417
- if len(node.Results) == 0 && hasNamedErr {
418
- checkPositions = append(checkPositions, node.Pos())
419
- }
420
- for _, res := range node.Results {
421
- if ident, ok := res.(*ast.Ident); ok && ident.Name == "err" {
422
- checkPositions = append(checkPositions, ident.Pos())
423
- }
424
- }
425
- case *ast.CallExpr:
426
- for _, arg := range node.Args {
427
- if ident, ok := arg.(*ast.Ident); ok && ident.Name == "err" {
428
- checkPositions = append(checkPositions, ident.Pos())
429
- }
430
- }
431
- }
432
- return true
433
- })
434
-
435
- sort.Slice(assignPositions, func(i, j int) bool { return assignPositions[i] < assignPositions[j] })
436
- sort.Slice(checkPositions, func(i, j int) bool { return checkPositions[i] < checkPositions[j] })
437
-
438
- // An assigned `err` is handled iff a check falls strictly after it and
439
- // before the next assignment (or the end of the function).
440
- for i, assign := range assignPositions {
441
- var upper token.Pos
442
- if i+1 < len(assignPositions) {
443
- upper = assignPositions[i+1]
444
- } else {
445
- upper = token.Pos(1<<62 - 1) // function end (effectively +inf)
446
- }
447
- handled := false
448
- for _, check := range checkPositions {
449
- if check > assign && check < upper {
450
- handled = true
451
- break
452
- }
453
- }
454
- if !handled {
455
- return true
456
- }
457
- }
458
- return false
459
- }
460
-
461
- // funcDeclHasNamedErr reports whether the function's result list names an
462
- // error result `err` (the `(err error)` named-return shape).
463
- func funcDeclHasNamedErr(funcDecl *ast.FuncDecl) bool {
464
- if funcDecl.Type == nil || funcDecl.Type.Results == nil {
465
- return false
466
- }
467
- for _, field := range funcDecl.Type.Results.List {
468
- for _, name := range field.Names {
469
- if name.Name == "err" {
470
- return true
471
- }
472
- }
473
- }
474
- return false
475
- }
476
-
477
- // assignHasCallRHS reports whether any right-hand side of an assignment is a
478
- // call expression (the `x, err := f()` shape that produces an error).
479
- func assignHasCallRHS(stmt *ast.AssignStmt) bool {
480
- for _, rhs := range stmt.Rhs {
481
- if _, ok := rhs.(*ast.CallExpr); ok {
482
- return true
483
- }
484
- }
485
- return false
486
- }
487
-
488
- // isBlankIdent reports whether an expression is the blank identifier `_`.
489
- func isBlankIdent(expr ast.Expr) bool {
490
- ident, ok := expr.(*ast.Ident)
491
- return ok && ident.Name == "_"
492
- }
493
-
494
- // analyzeConcurrency reports whether a function body launches a goroutine
495
- // (hasGo) and whether it contains any synchronization signal (hasSync): a
496
- // sync.Add/Done/Wait/Lock/Unlock/RLock/RUnlock call or a channel send/receive.
497
- func (a *Analyzer) analyzeConcurrency(funcDecl *ast.FuncDecl) (hasGo, hasSync bool) {
498
- ast.Inspect(funcDecl.Body, func(n ast.Node) bool {
499
- switch node := n.(type) {
500
- case *ast.GoStmt:
501
- hasGo = true
502
- case *ast.SendStmt:
503
- hasSync = true
504
- case *ast.UnaryExpr:
505
- if node.Op == token.ARROW {
506
- hasSync = true
507
- }
508
- case *ast.SelectorExpr:
509
- if syncMethodNames[node.Sel.Name] {
510
- hasSync = true
511
- }
512
- }
513
- return true
514
- })
515
- return hasGo, hasSync
516
- }
517
-
518
- // deadlockChannel reports the name of an unbuffered channel that is operated on
519
- // twice (sent to or received from) at the top level of a function body with no
520
- // `go` statement — a guaranteed same-goroutine deadlock. Returns "" when no such
521
- // channel exists. A buffered channel (`make(chan T, N)`) never qualifies because
522
- // its send does not block; and any `go` statement makes the deadlock unprovable
523
- // (the counterpart could live in the spawned goroutine), so the function is
524
- // cleared.
525
- func (a *Analyzer) deadlockChannel(funcDecl *ast.FuncDecl) string {
526
- unbuffered := make(map[string]bool)
527
- ops := make(map[string]int)
528
- hasGo := false
529
-
530
- for _, stmt := range funcDecl.Body.List {
531
- ast.Inspect(stmt, func(n ast.Node) bool {
532
- switch node := n.(type) {
533
- case *ast.GoStmt:
534
- hasGo = true
535
- case *ast.AssignStmt:
536
- // `ch := make(chan T)` / `ch = make(chan T)` — unbuffered creation.
537
- for i, rhs := range node.Rhs {
538
- if isUnbufferedMakeChan(rhs) && i < len(node.Lhs) {
539
- if ident, ok := node.Lhs[i].(*ast.Ident); ok {
540
- unbuffered[ident.Name] = true
541
- }
542
- }
543
- }
544
- case *ast.SendStmt:
545
- if ident, ok := node.Chan.(*ast.Ident); ok {
546
- ops[ident.Name]++
547
- }
548
- case *ast.UnaryExpr:
549
- if node.Op == token.ARROW {
550
- if ident, ok := node.X.(*ast.Ident); ok {
551
- ops[ident.Name]++
552
- }
553
- }
554
- }
555
- return true
556
- })
557
- }
558
-
559
- if hasGo {
560
- return ""
561
- }
562
- for name := range unbuffered {
563
- if ops[name] >= 2 {
564
- return name
565
- }
566
- }
567
- return ""
568
- }
569
-
570
- // isUnbufferedMakeChan reports whether expr is `make(chan T)` — a single-argument
571
- // make of a channel type, i.e. an unbuffered channel. `make(chan T, N)` has two
572
- // arguments (a buffer), so its send does not block.
573
- func isUnbufferedMakeChan(expr ast.Expr) bool {
574
- call, ok := expr.(*ast.CallExpr)
575
- if !ok || len(call.Args) != 1 {
576
- return false
577
- }
578
- ident, ok := call.Fun.(*ast.Ident)
579
- if !ok || ident.Name != "make" {
580
- return false
581
- }
582
- _, ok = call.Args[0].(*ast.ChanType)
583
- return ok
584
- }
585
-
586
- // importGroup classifies an unquoted import path into a grouping tier:
587
- // 0 = standard library (first path segment has no '.'), 1 = third-party (first
588
- // segment has a '.'), 2 = local (relative './' or '../'). This is the
589
- // stdlib-before-third-party-before-local convention goimports/gofmt enforce.
590
- func importGroup(path string) int {
591
- if strings.HasPrefix(path, ".") {
592
- return 2
593
- }
594
- first := path
595
- if idx := strings.IndexByte(path, '/'); idx >= 0 {
596
- first = path[:idx]
597
- }
598
- if strings.Contains(first, ".") {
599
- return 1
600
- }
601
- return 0
602
- }
603
-
604
- // firstImportGroupViolation reports the position of the first import that breaks
605
- // the stdlib-before-third-party-before-local grouping, and how many imports in
606
- // total are out of group order. It returns (token.NoPos, 0) when the import
607
- // block is grouped (the group sequence is non-decreasing).
608
- func firstImportGroupViolation(imports []*ast.ImportSpec) (token.Pos, int) {
609
- maxGroup := -1
610
- grouped := 0
611
- firstPos := token.NoPos
612
- for _, spec := range imports {
613
- path, err := strconv.Unquote(spec.Path.Value)
614
- if err != nil {
615
- path = spec.Path.Value
616
- }
617
- g := importGroup(path)
618
- switch {
619
- case g > maxGroup:
620
- maxGroup = g
621
- case g < maxGroup:
622
- grouped++
623
- if firstPos == token.NoPos {
624
- firstPos = spec.Pos()
625
- }
626
- }
627
- }
628
- return firstPos, grouped
629
- }
630
-
631
- // excludeTestFiles removes *_test.go files from a file list. Test files are
632
- // compiled only by `go test`, never as production API — they are exempt from
633
- // analysis and indexing the same way the TypeScript pipeline excludes test
634
- // files at discovery (see testconventions.go).
635
- func excludeTestFiles(files []string) []string {
636
- out := make([]string, 0, len(files))
637
- for _, f := range files {
638
- if !isTestFile(f) {
639
- out = append(out, f)
640
- }
641
- }
642
- return out
643
- }