code-auditor-mcp 3.1.1 → 3.4.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 (357) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +665 -1
  3. package/README.md +85 -11
  4. package/dist/__test_tmp__/spec18_test.d.ts +2 -0
  5. package/dist/__test_tmp__/spec18_test.d.ts.map +1 -0
  6. package/dist/__test_tmp__/spec18_test.js +5 -0
  7. package/dist/__test_tmp__/spec18_test.js.map +1 -0
  8. package/dist/__tests__/fixtures/spec-20/scripts/tool.d.ts +6 -0
  9. package/dist/__tests__/fixtures/spec-20/scripts/tool.d.ts.map +1 -0
  10. package/dist/__tests__/fixtures/spec-20/scripts/tool.js +12 -0
  11. package/dist/__tests__/fixtures/spec-20/scripts/tool.js.map +1 -0
  12. package/dist/__tests__/fixtures/spec-20/src/demo-module.d.ts +7 -0
  13. package/dist/__tests__/fixtures/spec-20/src/demo-module.d.ts.map +1 -0
  14. package/dist/__tests__/fixtures/spec-20/src/demo-module.js +13 -0
  15. package/dist/__tests__/fixtures/spec-20/src/demo-module.js.map +1 -0
  16. package/dist/analyzers/analyzerUtils.js +2 -2
  17. package/dist/analyzers/analyzerUtils.js.map +1 -1
  18. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts +1 -1
  19. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
  20. package/dist/analyzers/cross-language/APIContractAnalyzer.js +2 -2
  21. package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -1
  22. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.d.ts +3 -0
  23. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.d.ts.map +1 -1
  24. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.js +3 -3
  25. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.js.map +1 -1
  26. package/dist/analyzers/cross-language/SchemaValidator.d.ts +1 -1
  27. package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
  28. package/dist/analyzers/cross-language/SchemaValidator.js +2 -2
  29. package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
  30. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +83 -0
  31. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -0
  32. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +611 -0
  33. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -0
  34. package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
  35. package/dist/analyzers/documentationAnalyzer.js +8 -4
  36. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  37. package/dist/analyzers/orm/adapterRegistry.d.ts +41 -0
  38. package/dist/analyzers/orm/adapterRegistry.d.ts.map +1 -0
  39. package/dist/analyzers/orm/adapterRegistry.js +73 -0
  40. package/dist/analyzers/orm/adapterRegistry.js.map +1 -0
  41. package/dist/analyzers/orm/drizzleAdapter.d.ts +42 -0
  42. package/dist/analyzers/orm/drizzleAdapter.d.ts.map +1 -0
  43. package/dist/analyzers/orm/drizzleAdapter.js +166 -0
  44. package/dist/analyzers/orm/drizzleAdapter.js.map +1 -0
  45. package/dist/analyzers/orm/index.d.ts +14 -0
  46. package/dist/analyzers/orm/index.d.ts.map +1 -0
  47. package/dist/analyzers/orm/index.js +24 -0
  48. package/dist/analyzers/orm/index.js.map +1 -0
  49. package/dist/analyzers/orm/prismaAdapter.d.ts +45 -0
  50. package/dist/analyzers/orm/prismaAdapter.d.ts.map +1 -0
  51. package/dist/analyzers/orm/prismaAdapter.js +170 -0
  52. package/dist/analyzers/orm/prismaAdapter.js.map +1 -0
  53. package/dist/analyzers/orm/types.d.ts +63 -0
  54. package/dist/analyzers/orm/types.d.ts.map +1 -0
  55. package/dist/analyzers/orm/types.js +10 -0
  56. package/dist/analyzers/orm/types.js.map +1 -0
  57. package/dist/analyzers/provenance.d.ts +133 -0
  58. package/dist/analyzers/provenance.d.ts.map +1 -0
  59. package/dist/analyzers/provenance.js +1041 -0
  60. package/dist/analyzers/provenance.js.map +1 -0
  61. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  62. package/dist/analyzers/reactAnalyzer.js +117 -1
  63. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  64. package/dist/analyzers/ruleRegistry.d.ts +38 -0
  65. package/dist/analyzers/ruleRegistry.d.ts.map +1 -0
  66. package/dist/analyzers/ruleRegistry.js +123 -0
  67. package/dist/analyzers/ruleRegistry.js.map +1 -0
  68. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +58 -0
  69. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -0
  70. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +445 -0
  71. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -0
  72. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +52 -0
  73. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
  74. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +108 -26
  75. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  76. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +64 -0
  77. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  78. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +259 -53
  79. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  80. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  81. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +5 -15
  82. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  83. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  84. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +10 -10
  85. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  86. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +25 -0
  87. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  88. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +250 -59
  89. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  90. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +103 -0
  91. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -0
  92. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +750 -0
  93. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -0
  94. package/dist/auditRunner.d.ts.map +1 -1
  95. package/dist/auditRunner.js +483 -3
  96. package/dist/auditRunner.js.map +1 -1
  97. package/dist/baseline.d.ts +98 -0
  98. package/dist/baseline.d.ts.map +1 -0
  99. package/dist/baseline.js +184 -0
  100. package/dist/baseline.js.map +1 -0
  101. package/dist/churn/churnExtractor.d.ts +32 -0
  102. package/dist/churn/churnExtractor.d.ts.map +1 -0
  103. package/dist/churn/churnExtractor.js +261 -0
  104. package/dist/churn/churnExtractor.js.map +1 -0
  105. package/dist/cli.js +1215 -11
  106. package/dist/cli.js.map +1 -1
  107. package/dist/codeIndexDB-enhanced.js +1 -1
  108. package/dist/codeIndexDB-enhanced.js.map +1 -1
  109. package/dist/codeIndexDB.d.ts +101 -0
  110. package/dist/codeIndexDB.d.ts.map +1 -1
  111. package/dist/codeIndexDB.js +661 -5
  112. package/dist/codeIndexDB.js.map +1 -1
  113. package/dist/config/configLoader.d.ts.map +1 -1
  114. package/dist/config/configLoader.js +95 -1
  115. package/dist/config/configLoader.js.map +1 -1
  116. package/dist/config/defaults.d.ts +72 -1
  117. package/dist/config/defaults.d.ts.map +1 -1
  118. package/dist/config/defaults.js +146 -15
  119. package/dist/config/defaults.js.map +1 -1
  120. package/dist/config/pathProfiles.d.ts +38 -0
  121. package/dist/config/pathProfiles.d.ts.map +1 -0
  122. package/dist/config/pathProfiles.js +47 -0
  123. package/dist/config/pathProfiles.js.map +1 -0
  124. package/dist/conventions/conventionMiner.d.ts +63 -0
  125. package/dist/conventions/conventionMiner.d.ts.map +1 -0
  126. package/dist/conventions/conventionMiner.js +696 -0
  127. package/dist/conventions/conventionMiner.js.map +1 -0
  128. package/dist/coverage/coverageService.d.ts +49 -0
  129. package/dist/coverage/coverageService.d.ts.map +1 -0
  130. package/dist/coverage/coverageService.js +117 -0
  131. package/dist/coverage/coverageService.js.map +1 -0
  132. package/dist/coverage/istanbulParser.d.ts +84 -0
  133. package/dist/coverage/istanbulParser.d.ts.map +1 -0
  134. package/dist/coverage/istanbulParser.js +120 -0
  135. package/dist/coverage/istanbulParser.js.map +1 -0
  136. package/dist/coverage/lcovParser.d.ts +40 -0
  137. package/dist/coverage/lcovParser.d.ts.map +1 -0
  138. package/dist/coverage/lcovParser.js +168 -0
  139. package/dist/coverage/lcovParser.js.map +1 -0
  140. package/dist/fingerprint.d.ts +17 -0
  141. package/dist/fingerprint.d.ts.map +1 -1
  142. package/dist/fingerprint.js +42 -0
  143. package/dist/fingerprint.js.map +1 -1
  144. package/dist/grammars/tree-sitter-css.wasm +0 -0
  145. package/dist/graph/blastRadius.d.ts +27 -0
  146. package/dist/graph/blastRadius.d.ts.map +1 -0
  147. package/dist/graph/blastRadius.js +150 -0
  148. package/dist/graph/blastRadius.js.map +1 -0
  149. package/dist/graph/callGraph.d.ts +78 -0
  150. package/dist/graph/callGraph.d.ts.map +1 -0
  151. package/dist/graph/callGraph.js +484 -0
  152. package/dist/graph/callGraph.js.map +1 -0
  153. package/dist/graph/importGraph.d.ts +91 -0
  154. package/dist/graph/importGraph.d.ts.map +1 -0
  155. package/dist/graph/importGraph.js +602 -0
  156. package/dist/graph/importGraph.js.map +1 -0
  157. package/dist/graph/outputFormatter.d.ts +55 -0
  158. package/dist/graph/outputFormatter.d.ts.map +1 -0
  159. package/dist/graph/outputFormatter.js +283 -0
  160. package/dist/graph/outputFormatter.js.map +1 -0
  161. package/dist/hooks/codex.d.ts +36 -1
  162. package/dist/hooks/codex.d.ts.map +1 -1
  163. package/dist/hooks/codex.js +88 -54
  164. package/dist/hooks/codex.js.map +1 -1
  165. package/dist/hotspots/hotspotScorer.d.ts +20 -0
  166. package/dist/hotspots/hotspotScorer.d.ts.map +1 -0
  167. package/dist/hotspots/hotspotScorer.js +202 -0
  168. package/dist/hotspots/hotspotScorer.js.map +1 -0
  169. package/dist/invariants/invariant-rules.schema.json +42 -1
  170. package/dist/invariants/ruleEngine.d.ts +4 -1
  171. package/dist/invariants/ruleEngine.d.ts.map +1 -1
  172. package/dist/invariants/ruleEngine.js +141 -5
  173. package/dist/invariants/ruleEngine.js.map +1 -1
  174. package/dist/invariants/ruleValidator.d.ts.map +1 -1
  175. package/dist/invariants/ruleValidator.js +62 -1
  176. package/dist/invariants/ruleValidator.js.map +1 -1
  177. package/dist/invariants/types.d.ts +23 -2
  178. package/dist/invariants/types.d.ts.map +1 -1
  179. package/dist/languages/UniversalAnalyzer.d.ts +1 -1
  180. package/dist/languages/UniversalAnalyzer.d.ts.map +1 -1
  181. package/dist/languages/UniversalAnalyzer.js +61 -4
  182. package/dist/languages/UniversalAnalyzer.js.map +1 -1
  183. package/dist/languages/index.d.ts +1 -0
  184. package/dist/languages/index.d.ts.map +1 -1
  185. package/dist/languages/index.js +3 -0
  186. package/dist/languages/index.js.map +1 -1
  187. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts +59 -0
  188. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -0
  189. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js +236 -0
  190. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -0
  191. package/dist/languages/tree-sitter/parser.d.ts.map +1 -1
  192. package/dist/languages/tree-sitter/parser.js +2 -0
  193. package/dist/languages/tree-sitter/parser.js.map +1 -1
  194. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  195. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +61 -10
  196. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  197. package/dist/ledger.d.ts +128 -0
  198. package/dist/ledger.d.ts.map +1 -0
  199. package/dist/ledger.js +345 -0
  200. package/dist/ledger.js.map +1 -0
  201. package/dist/mcp-tools/projectTasks.d.ts.map +1 -1
  202. package/dist/mcp-tools/projectTasks.js +9 -14
  203. package/dist/mcp-tools/projectTasks.js.map +1 -1
  204. package/dist/mcp.js +0 -0
  205. package/dist/mcpAuditJobs.d.ts.map +1 -1
  206. package/dist/mcpAuditJobs.js +3 -0
  207. package/dist/mcpAuditJobs.js.map +1 -1
  208. package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
  209. package/dist/reporting/csvReportGenerator.js +7 -1
  210. package/dist/reporting/csvReportGenerator.js.map +1 -1
  211. package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
  212. package/dist/reporting/htmlReportGenerator.js +5 -1
  213. package/dist/reporting/htmlReportGenerator.js.map +1 -1
  214. package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
  215. package/dist/reporting/jsonReportGenerator.js +10 -2
  216. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  217. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
  218. package/dist/reporting/sarifReportGenerator.js +17 -17
  219. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  220. package/dist/scripts/runBench.d.ts +94 -0
  221. package/dist/scripts/runBench.d.ts.map +1 -0
  222. package/dist/scripts/runBench.js +1559 -0
  223. package/dist/scripts/runBench.js.map +1 -0
  224. package/dist/search/QueryParser.d.ts.map +1 -1
  225. package/dist/search/QueryParser.js +51 -4
  226. package/dist/search/QueryParser.js.map +1 -1
  227. package/dist/services/CodeMapGenerator.d.ts +33 -0
  228. package/dist/services/CodeMapGenerator.d.ts.map +1 -1
  229. package/dist/services/CodeMapGenerator.js +404 -0
  230. package/dist/services/CodeMapGenerator.js.map +1 -1
  231. package/dist/styles/normalizer.d.ts +37 -0
  232. package/dist/styles/normalizer.d.ts.map +1 -0
  233. package/dist/styles/normalizer.js +301 -0
  234. package/dist/styles/normalizer.js.map +1 -0
  235. package/dist/styles/styleExtractor.d.ts +38 -0
  236. package/dist/styles/styleExtractor.d.ts.map +1 -0
  237. package/dist/styles/styleExtractor.js +630 -0
  238. package/dist/styles/styleExtractor.js.map +1 -0
  239. package/dist/styles/styleIndexer.d.ts +35 -0
  240. package/dist/styles/styleIndexer.d.ts.map +1 -0
  241. package/dist/styles/styleIndexer.js +266 -0
  242. package/dist/styles/styleIndexer.js.map +1 -0
  243. package/dist/styles/tailwindConfigLoader.d.ts +38 -0
  244. package/dist/styles/tailwindConfigLoader.d.ts.map +1 -0
  245. package/dist/styles/tailwindConfigLoader.js +374 -0
  246. package/dist/styles/tailwindConfigLoader.js.map +1 -0
  247. package/dist/styles/tailwindExpander.d.ts +38 -0
  248. package/dist/styles/tailwindExpander.d.ts.map +1 -0
  249. package/dist/styles/tailwindExpander.js +637 -0
  250. package/dist/styles/tailwindExpander.js.map +1 -0
  251. package/dist/styles/types.d.ts +92 -0
  252. package/dist/styles/types.d.ts.map +1 -0
  253. package/dist/styles/types.js +10 -0
  254. package/dist/styles/types.js.map +1 -0
  255. package/dist/symbols.d.ts +21 -0
  256. package/dist/symbols.d.ts.map +1 -0
  257. package/dist/symbols.js +31 -0
  258. package/dist/symbols.js.map +1 -0
  259. package/dist/types.d.ts +326 -3
  260. package/dist/types.d.ts.map +1 -1
  261. package/dist/types.js.map +1 -1
  262. package/package.json +9 -5
  263. package/plugin/.claude-plugin/plugin.json +1 -1
  264. package/plugin/scripts/hook-audit.sh +5 -1
  265. package/plugin/skills/code-auditor/SKILL.md +51 -0
  266. package/dist/analyzers/__tests__/fixtures/spec-17/anonymous-callback-map.d.ts +0 -21
  267. package/dist/analyzers/__tests__/fixtures/spec-17/anonymous-callback-map.d.ts.map +0 -1
  268. package/dist/analyzers/__tests__/fixtures/spec-17/anonymous-callback-map.js +0 -21
  269. package/dist/analyzers/__tests__/fixtures/spec-17/anonymous-callback-map.js.map +0 -1
  270. package/dist/analyzers/__tests__/fixtures/spec-17/barrel-test-migration.d.ts +0 -13
  271. package/dist/analyzers/__tests__/fixtures/spec-17/barrel-test-migration.d.ts.map +0 -1
  272. package/dist/analyzers/__tests__/fixtures/spec-17/barrel-test-migration.js +0 -12
  273. package/dist/analyzers/__tests__/fixtures/spec-17/barrel-test-migration.js.map +0 -1
  274. package/dist/analyzers/__tests__/fixtures/spec-17/direct-access-allow-config.d.ts +0 -11
  275. package/dist/analyzers/__tests__/fixtures/spec-17/direct-access-allow-config.d.ts.map +0 -1
  276. package/dist/analyzers/__tests__/fixtures/spec-17/direct-access-allow-config.js +0 -22
  277. package/dist/analyzers/__tests__/fixtures/spec-17/direct-access-allow-config.js.map +0 -1
  278. package/dist/analyzers/__tests__/fixtures/spec-17/exported-undocumented.d.ts +0 -9
  279. package/dist/analyzers/__tests__/fixtures/spec-17/exported-undocumented.d.ts.map +0 -1
  280. package/dist/analyzers/__tests__/fixtures/spec-17/exported-undocumented.js +0 -13
  281. package/dist/analyzers/__tests__/fixtures/spec-17/exported-undocumented.js.map +0 -1
  282. package/dist/analyzers/__tests__/fixtures/spec-17/for-loop-query.d.ts +0 -13
  283. package/dist/analyzers/__tests__/fixtures/spec-17/for-loop-query.d.ts.map +0 -1
  284. package/dist/analyzers/__tests__/fixtures/spec-17/for-loop-query.js +0 -18
  285. package/dist/analyzers/__tests__/fixtures/spec-17/for-loop-query.js.map +0 -1
  286. package/dist/analyzers/__tests__/fixtures/spec-17/import-node-builtin.d.ts +0 -10
  287. package/dist/analyzers/__tests__/fixtures/spec-17/import-node-builtin.d.ts.map +0 -1
  288. package/dist/analyzers/__tests__/fixtures/spec-17/import-node-builtin.js +0 -16
  289. package/dist/analyzers/__tests__/fixtures/spec-17/import-node-builtin.js.map +0 -1
  290. package/dist/analyzers/__tests__/fixtures/spec-17/jsx-event-handler.d.ts +0 -14
  291. package/dist/analyzers/__tests__/fixtures/spec-17/jsx-event-handler.d.ts.map +0 -1
  292. package/dist/analyzers/__tests__/fixtures/spec-17/jsx-event-handler.js +0 -18
  293. package/dist/analyzers/__tests__/fixtures/spec-17/jsx-event-handler.js.map +0 -1
  294. package/dist/analyzers/__tests__/fixtures/spec-17/nested-loops-query.d.ts +0 -13
  295. package/dist/analyzers/__tests__/fixtures/spec-17/nested-loops-query.d.ts.map +0 -1
  296. package/dist/analyzers/__tests__/fixtures/spec-17/nested-loops-query.js +0 -22
  297. package/dist/analyzers/__tests__/fixtures/spec-17/nested-loops-query.js.map +0 -1
  298. package/dist/analyzers/__tests__/fixtures/spec-17/nine-line-repeated.d.ts +0 -10
  299. package/dist/analyzers/__tests__/fixtures/spec-17/nine-line-repeated.d.ts.map +0 -1
  300. package/dist/analyzers/__tests__/fixtures/spec-17/nine-line-repeated.js +0 -20
  301. package/dist/analyzers/__tests__/fixtures/spec-17/nine-line-repeated.js.map +0 -1
  302. package/dist/analyzers/__tests__/fixtures/spec-17/private-methods.d.ts +0 -18
  303. package/dist/analyzers/__tests__/fixtures/spec-17/private-methods.d.ts.map +0 -1
  304. package/dist/analyzers/__tests__/fixtures/spec-17/private-methods.js +0 -28
  305. package/dist/analyzers/__tests__/fixtures/spec-17/private-methods.js.map +0 -1
  306. package/dist/analyzers/__tests__/fixtures/spec-17/scope-all-config.d.ts +0 -11
  307. package/dist/analyzers/__tests__/fixtures/spec-17/scope-all-config.d.ts.map +0 -1
  308. package/dist/analyzers/__tests__/fixtures/spec-17/scope-all-config.js +0 -31
  309. package/dist/analyzers/__tests__/fixtures/spec-17/scope-all-config.js.map +0 -1
  310. package/dist/analyzers/__tests__/fixtures/spec-17/sql-tagged-template.d.ts +0 -11
  311. package/dist/analyzers/__tests__/fixtures/spec-17/sql-tagged-template.d.ts.map +0 -1
  312. package/dist/analyzers/__tests__/fixtures/spec-17/sql-tagged-template.js +0 -18
  313. package/dist/analyzers/__tests__/fixtures/spec-17/sql-tagged-template.js.map +0 -1
  314. package/dist/analyzers/__tests__/fixtures/spec-17/structural-similar-methods.d.ts +0 -13
  315. package/dist/analyzers/__tests__/fixtures/spec-17/structural-similar-methods.d.ts.map +0 -1
  316. package/dist/analyzers/__tests__/fixtures/spec-17/structural-similar-methods.js +0 -61
  317. package/dist/analyzers/__tests__/fixtures/spec-17/structural-similar-methods.js.map +0 -1
  318. package/dist/analyzers/__tests__/fixtures/spec-17/template-prefix-table.d.ts +0 -10
  319. package/dist/analyzers/__tests__/fixtures/spec-17/template-prefix-table.d.ts.map +0 -1
  320. package/dist/analyzers/__tests__/fixtures/spec-17/template-prefix-table.js +0 -15
  321. package/dist/analyzers/__tests__/fixtures/spec-17/template-prefix-table.js.map +0 -1
  322. package/dist/analyzers/__tests__/fixtures/spec-17/token-identical-20-lines.d.ts +0 -11
  323. package/dist/analyzers/__tests__/fixtures/spec-17/token-identical-20-lines.d.ts.map +0 -1
  324. package/dist/analyzers/__tests__/fixtures/spec-17/token-identical-20-lines.js +0 -49
  325. package/dist/analyzers/__tests__/fixtures/spec-17/token-identical-20-lines.js.map +0 -1
  326. package/dist/analyzers/__tests__/fixtures/spec-17/tsx-no-db-usage.d.ts +0 -10
  327. package/dist/analyzers/__tests__/fixtures/spec-17/tsx-no-db-usage.d.ts.map +0 -1
  328. package/dist/analyzers/__tests__/fixtures/spec-17/tsx-no-db-usage.js +0 -19
  329. package/dist/analyzers/__tests__/fixtures/spec-17/tsx-no-db-usage.js.map +0 -1
  330. package/dist/analyzers/__tests__/fixtures/spec-17/twenty-methods-vs-complex.d.ts +0 -37
  331. package/dist/analyzers/__tests__/fixtures/spec-17/twenty-methods-vs-complex.d.ts.map +0 -1
  332. package/dist/analyzers/__tests__/fixtures/spec-17/twenty-methods-vs-complex.js +0 -73
  333. package/dist/analyzers/__tests__/fixtures/spec-17/twenty-methods-vs-complex.js.map +0 -1
  334. package/dist/analyzers/__tests__/fixtures/spec-17/unique-method-74-lines.d.ts +0 -12
  335. package/dist/analyzers/__tests__/fixtures/spec-17/unique-method-74-lines.d.ts.map +0 -1
  336. package/dist/analyzers/__tests__/fixtures/spec-17/unique-method-74-lines.js +0 -82
  337. package/dist/analyzers/__tests__/fixtures/spec-17/unique-method-74-lines.js.map +0 -1
  338. package/dist/analyzers/__tests__/fixtures/spec-17/word-the-in-comment.d.ts +0 -10
  339. package/dist/analyzers/__tests__/fixtures/spec-17/word-the-in-comment.d.ts.map +0 -1
  340. package/dist/analyzers/__tests__/fixtures/spec-17/word-the-in-comment.js +0 -15
  341. package/dist/analyzers/__tests__/fixtures/spec-17/word-the-in-comment.js.map +0 -1
  342. package/dist/analyzers/dataAccessAnalyzer.d.ts +0 -46
  343. package/dist/analyzers/dataAccessAnalyzer.d.ts.map +0 -1
  344. package/dist/analyzers/dataAccessAnalyzer.js +0 -474
  345. package/dist/analyzers/dataAccessAnalyzer.js.map +0 -1
  346. package/dist/analyzers/dryAnalyzer.d.ts +0 -31
  347. package/dist/analyzers/dryAnalyzer.d.ts.map +0 -1
  348. package/dist/analyzers/dryAnalyzer.js +0 -734
  349. package/dist/analyzers/dryAnalyzer.js.map +0 -1
  350. package/dist/analyzers/schemaAnalyzer.d.ts +0 -23
  351. package/dist/analyzers/schemaAnalyzer.d.ts.map +0 -1
  352. package/dist/analyzers/schemaAnalyzer.js +0 -564
  353. package/dist/analyzers/schemaAnalyzer.js.map +0 -1
  354. package/dist/analyzers/solidAnalyzer.d.ts +0 -33
  355. package/dist/analyzers/solidAnalyzer.d.ts.map +0 -1
  356. package/dist/analyzers/solidAnalyzer.js +0 -847
  357. package/dist/analyzers/solidAnalyzer.js.map +0 -1
@@ -0,0 +1,1041 @@
1
+ /**
2
+ * Provenance Resolver — Spec 21
3
+ *
4
+ * Language-neutral DB and validator receiver detection through
5
+ * provenance tracking instead of English name matching.
6
+ *
7
+ * "Where did this variable's value come from?" rather than
8
+ * "Is this variable named 'db'?"
9
+ *
10
+ * ─── Architecture ───
11
+ * 1. extractDBProvenancedImports → seed identifiers from known package imports
12
+ * 2. propagateProvenance → follow assignments, destructuring, params
13
+ * 3. buildProvenanceContext → combine seeds + propagation + fallbacks (R3)
14
+ * 4. isDBProvenanced → answer: is this call-expression DB-bound?
15
+ *
16
+ * ─── Modes (R3) ───
17
+ * hybrid (default) — provenance-primary + conjunctive name-fallback
18
+ * provenance — strict provenance only, never consults name lists
19
+ * names — legacy English-only name matching (opt-in escape hatch)
20
+ */
21
+ // ═══════════════════════════════════════════════════════════════════════════
22
+ // Constants — the universal vocabulary (package names are language-invariant)
23
+ // ═══════════════════════════════════════════════════════════════════════════
24
+ /** Database packages — spec R1.1 */
25
+ export const DB_PACKAGES = new Set([
26
+ 'better-sqlite3',
27
+ 'drizzle-orm',
28
+ '@prisma/client',
29
+ 'pg',
30
+ 'mysql2',
31
+ 'postgres',
32
+ 'kysely',
33
+ 'knex',
34
+ 'mongodb',
35
+ 'mongoose',
36
+ '@libsql/client',
37
+ '@planetscale/database',
38
+ '@neondatabase/serverless',
39
+ '@vercel/postgres',
40
+ 'bun:sqlite',
41
+ 'node:sqlite',
42
+ ]);
43
+ /** Validator packages — spec R4.1 */
44
+ export const VALIDATOR_PACKAGES = new Set([
45
+ 'zod',
46
+ 'joi',
47
+ 'ajv',
48
+ 'valibot',
49
+ 'yup',
50
+ 'superstruct',
51
+ 'arktype',
52
+ '@sinclair/typebox',
53
+ 'class-validator',
54
+ ]);
55
+ /** Known DB type names — spec R1.1 (propagation rule 8) */
56
+ export const DB_TYPES = new Set([
57
+ 'D1Database',
58
+ 'D1PreparedStatement',
59
+ 'D1Result',
60
+ 'Database',
61
+ 'Pool',
62
+ 'PrismaClient',
63
+ 'Kysely',
64
+ 'Connection',
65
+ 'SqliteDatabase',
66
+ 'BetterSQLite3Database',
67
+ ]);
68
+ /** DB call methods — the fixed API surface (language-invariant) */
69
+ export const DB_CALL_METHODS = new Set([
70
+ 'exec',
71
+ 'prepare',
72
+ 'batch',
73
+ 'run',
74
+ 'all',
75
+ 'first',
76
+ 'query',
77
+ 'get',
78
+ 'each',
79
+ 'raw',
80
+ 'values',
81
+ ]);
82
+ /** ORM method patterns — fixed API surface for ORM recognition (Spec 21 R1) */
83
+ export const ORM_METHODS = new Set([
84
+ 'find',
85
+ 'findOne',
86
+ 'findMany',
87
+ 'findFirst',
88
+ 'findUnique',
89
+ 'select',
90
+ 'insert',
91
+ 'insertMany',
92
+ 'update',
93
+ 'updateOne',
94
+ 'updateMany',
95
+ 'delete',
96
+ 'deleteOne',
97
+ 'deleteMany',
98
+ 'from',
99
+ 'where',
100
+ 'join',
101
+ 'leftJoin',
102
+ 'rightJoin',
103
+ 'innerJoin',
104
+ 'create',
105
+ 'createMany',
106
+ 'aggregate',
107
+ 'count',
108
+ 'distinct',
109
+ 'execute',
110
+ 'query',
111
+ ]);
112
+ // ═══════════════════════════════════════════════════════════════════════════
113
+ // Package matching
114
+ // ═══════════════════════════════════════════════════════════════════════════
115
+ /** Check if a module specifier matches a DB package (exact or subpath). */
116
+ function matchesDBPackage(specifier) {
117
+ return [...DB_PACKAGES].some((pkg) => specifier === pkg || specifier.startsWith(pkg + '/'));
118
+ }
119
+ /** Check if a module specifier matches a validator package. */
120
+ function matchesValidatorPackage(specifier) {
121
+ return [...VALIDATOR_PACKAGES].some((pkg) => specifier === pkg || specifier.startsWith(pkg + '/'));
122
+ }
123
+ // ═══════════════════════════════════════════════════════════════════════════
124
+ // Import extraction (R1 seed phase)
125
+ // ═══════════════════════════════════════════════════════════════════════════
126
+ /**
127
+ * Extract all DB-provenanced identifiers from a file's import statements.
128
+ *
129
+ * An import like `import Database from 'better-sqlite3'` produces
130
+ * `Database` as DB-provenanced with reason "package".
131
+ */
132
+ export function extractDBProvenancedImports(ast, adapter) {
133
+ const seedMap = new Map();
134
+ const imports = adapter.extractImports(ast);
135
+ for (const imp of imports) {
136
+ const specifier = imp.source;
137
+ if (!matchesDBPackage(specifier))
138
+ continue;
139
+ for (const spec of imp.specifiers) {
140
+ const localName = spec.alias ?? spec.name;
141
+ const label = spec.isDefault
142
+ ? `default import from ${specifier}`
143
+ : spec.isNamespace
144
+ ? `namespace import from ${specifier}`
145
+ : `named import from ${specifier}`;
146
+ // Don't overwrite existing evidence (first import wins for dedup)
147
+ if (!seedMap.has(localName)) {
148
+ seedMap.set(localName, {
149
+ identifier: localName,
150
+ reason: 'package',
151
+ source: label,
152
+ chain: [],
153
+ });
154
+ }
155
+ }
156
+ }
157
+ return seedMap;
158
+ }
159
+ /**
160
+ * Extract all validator-provenanced identifiers from a file's imports.
161
+ * Same pattern as extractDBProvenancedImports but for validator packages.
162
+ */
163
+ export function extractValidatorProvenancedImports(ast, adapter) {
164
+ const seedMap = new Map();
165
+ const imports = adapter.extractImports(ast);
166
+ for (const imp of imports) {
167
+ const specifier = imp.source;
168
+ if (!matchesValidatorPackage(specifier))
169
+ continue;
170
+ for (const spec of imp.specifiers) {
171
+ const localName = spec.alias ?? spec.name;
172
+ const label = spec.isDefault
173
+ ? `default import from ${specifier}`
174
+ : spec.isNamespace
175
+ ? `namespace import from ${specifier}`
176
+ : `named import from ${specifier}`;
177
+ if (!seedMap.has(localName)) {
178
+ seedMap.set(localName, {
179
+ identifier: localName,
180
+ reason: 'package',
181
+ source: label,
182
+ chain: [],
183
+ });
184
+ }
185
+ }
186
+ }
187
+ return seedMap;
188
+ }
189
+ // ═══════════════════════════════════════════════════════════════════════════
190
+ // Provenance propagation (R1 core)
191
+ // ═══════════════════════════════════════════════════════════════════════════
192
+ /**
193
+ * Propagate provenance through assignments, destructuring, parameters,
194
+ * class fields, and type annotations within a single file.
195
+ *
196
+ * The 8 single-file propagation rules (spec R1):
197
+ * 1. new Expression → variable
198
+ * 2. DB-provenanced call return → variable
199
+ * 3. member expression on DB receiver → variable
200
+ * 4. object destructuring from DB source
201
+ * 5. array destructuring from DB source
202
+ * 6. default parameter with DB value
203
+ * 7. class field initialized with DB value
204
+ * 8. type annotation with known DB type
205
+ */
206
+ export function propagateProvenance(ast, adapter, sourceCode, seedMap) {
207
+ // Work on a copy so we can add newly-provenanced identifiers during the walk
208
+ const provenanceMap = new Map(seedMap);
209
+ // Keep iterating until no new identifiers are discovered (handles chains)
210
+ let changed = true;
211
+ let iterations = 0;
212
+ const MAX_ITERATIONS = 10; // safety valve for circular references
213
+ while (changed && iterations < MAX_ITERATIONS) {
214
+ changed = false;
215
+ iterations++;
216
+ walkAST(ast.root, (node, parent) => {
217
+ // ── Rule 1 & 2 & 3 & 8: variable declarations ──
218
+ if (node.type === 'variable_declarator') {
219
+ const { nameNode, valueNode, typeAnnotationNode } = splitVariableDeclarator(node, adapter);
220
+ if (!nameNode)
221
+ return;
222
+ // Rule 8: type annotation — let x: D1Database
223
+ if (typeAnnotationNode && nameNode.type === 'identifier') {
224
+ const typeText = adapter.getNodeText(typeAnnotationNode, sourceCode).trim();
225
+ if (DB_TYPES.has(typeText)) {
226
+ const name = adapter.getNodeText(nameNode, sourceCode);
227
+ if (!provenanceMap.has(name)) {
228
+ provenanceMap.set(name, {
229
+ identifier: name,
230
+ reason: 'type',
231
+ source: `type annotation ${typeText}`,
232
+ chain: [],
233
+ });
234
+ changed = true;
235
+ }
236
+ // Type-provenanced names count as DB-provenanced for further propagation
237
+ }
238
+ }
239
+ if (valueNode) {
240
+ const propagated = tryPropagateFromExpression(valueNode, adapter, sourceCode, provenanceMap);
241
+ if (propagated) {
242
+ // Extract the variable name(s) from the name node
243
+ const varNames = extractPatternNames(nameNode, adapter, sourceCode);
244
+ for (const varName of varNames) {
245
+ if (!provenanceMap.has(varName)) {
246
+ provenanceMap.set(varName, {
247
+ identifier: varName,
248
+ reason: 'propagation',
249
+ source: propagated.source,
250
+ chain: [...propagated.chain, propagated.identifier],
251
+ });
252
+ changed = true;
253
+ }
254
+ }
255
+ }
256
+ }
257
+ return;
258
+ }
259
+ // ── Rule 6: default parameters ──
260
+ if (node.type === 'assignment_pattern' &&
261
+ parent?.type === 'formal_parameters') {
262
+ const children = adapter.getChildren(node);
263
+ // assignment_pattern has [left, right]
264
+ if (children.length >= 2) {
265
+ const leftNode = children[0];
266
+ const rightNode = children[1];
267
+ if (leftNode.type === 'identifier') {
268
+ const paramName = adapter.getNodeText(leftNode, sourceCode);
269
+ const propagated = tryPropagateFromExpression(rightNode, adapter, sourceCode, provenanceMap);
270
+ if (propagated && !provenanceMap.has(paramName)) {
271
+ provenanceMap.set(paramName, {
272
+ identifier: paramName,
273
+ reason: 'propagation',
274
+ source: `default parameter = ${propagated.source}`,
275
+ chain: [...propagated.chain, propagated.identifier],
276
+ });
277
+ changed = true;
278
+ }
279
+ }
280
+ }
281
+ return;
282
+ }
283
+ // ── Rule 7: class field initialization ──
284
+ if (node.type === 'public_field_definition' ||
285
+ node.type === 'field_definition') {
286
+ const children = adapter.getChildren(node);
287
+ // Typically [name, value] or [decorators..., name, value]
288
+ const nameChild = children.find((c) => c.type === 'property_identifier');
289
+ const valueChild = children.find((c) => c.type !== 'property_identifier' &&
290
+ c.type !== 'decorator' &&
291
+ c.type !== 'private' &&
292
+ c.type !== 'public' &&
293
+ c.type !== 'protected' &&
294
+ c.type !== 'static' &&
295
+ c.type !== 'readonly' &&
296
+ c.type !== 'abstract');
297
+ if (nameChild && valueChild) {
298
+ const fieldName = adapter.getNodeText(nameChild, sourceCode);
299
+ const propagated = tryPropagateFromExpression(valueChild, adapter, sourceCode, provenanceMap);
300
+ if (propagated && !provenanceMap.has(fieldName)) {
301
+ provenanceMap.set(fieldName, {
302
+ identifier: fieldName,
303
+ reason: 'propagation',
304
+ source: `class field initialized from ${propagated.source}`,
305
+ chain: [...propagated.chain, propagated.identifier],
306
+ });
307
+ changed = true;
308
+ }
309
+ }
310
+ return;
311
+ }
312
+ });
313
+ }
314
+ return provenanceMap;
315
+ }
316
+ // ═══════════════════════════════════════════════════════════════════════════
317
+ // Propagation helpers
318
+ // ═══════════════════════════════════════════════════════════════════════════
319
+ /**
320
+ * Given a value expression node, check if it indicates DB provenance
321
+ * and return the evidence of the provenanced source if so.
322
+ */
323
+ function tryPropagateFromExpression(node, adapter, sourceCode, provenanceMap) {
324
+ // ── Rule 1: new Database(...) ──
325
+ if (node.type === 'new_expression') {
326
+ const constructorNode = findChildOfType(node, [
327
+ 'identifier',
328
+ 'member_expression',
329
+ ]);
330
+ if (constructorNode) {
331
+ const name = extractIdentifierName(constructorNode, adapter, sourceCode);
332
+ if (name && provenanceMap.has(name)) {
333
+ return provenanceMap.get(name);
334
+ }
335
+ }
336
+ }
337
+ // ── Rule 2: drizzle(env.DB) — call where callee is DB-provenanced ──
338
+ // ── Rule 3: db.prepare(sql) — member expression call on DB receiver ──
339
+ if (node.type === 'call_expression') {
340
+ // Walk children before arguments to get the callee
341
+ const calleeNode = getCallExpressionCallee(node, adapter);
342
+ if (calleeNode) {
343
+ // Case: simple identifier call — drizzle(...)
344
+ if (calleeNode.type === 'identifier') {
345
+ const name = adapter.getNodeText(calleeNode, sourceCode);
346
+ if (name && provenanceMap.has(name)) {
347
+ return provenanceMap.get(name);
348
+ }
349
+ }
350
+ // Case: member expression — db.prepare(...)
351
+ if (calleeNode.type === 'member_expression') {
352
+ const receiver = getMemberExpressionReceiver(calleeNode, adapter, sourceCode);
353
+ if (receiver && provenanceMap.has(receiver)) {
354
+ return provenanceMap.get(receiver);
355
+ }
356
+ }
357
+ }
358
+ }
359
+ // ── Simple identifier reference (for destructuring sources) ──
360
+ if (node.type === 'identifier') {
361
+ const name = adapter.getNodeText(node, sourceCode);
362
+ if (name && provenanceMap.has(name)) {
363
+ return provenanceMap.get(name);
364
+ }
365
+ }
366
+ // ── Member expression on DB-provenanced source (for non-call uses) ──
367
+ if (node.type === 'member_expression') {
368
+ const receiver = getMemberExpressionReceiver(node, adapter, sourceCode);
369
+ if (receiver && provenanceMap.has(receiver)) {
370
+ return provenanceMap.get(receiver);
371
+ }
372
+ }
373
+ return null;
374
+ }
375
+ /**
376
+ * Split a variable_declarator into its name, value, and type annotation
377
+ * child nodes.
378
+ */
379
+ function splitVariableDeclarator(node, adapter) {
380
+ const children = adapter.getChildren(node);
381
+ let nameNode = null;
382
+ let valueNode = null;
383
+ let typeAnnotationNode = null;
384
+ let pastEquals = false;
385
+ for (const child of children) {
386
+ if (child.type === '=' || child.type === 'equals') {
387
+ pastEquals = true;
388
+ continue;
389
+ }
390
+ if (child.type === ':')
391
+ continue;
392
+ if (child.type === 'type_annotation') {
393
+ typeAnnotationNode = child;
394
+ continue;
395
+ }
396
+ if (!pastEquals && !nameNode) {
397
+ // First non-syntax child is the name/pattern
398
+ if (child.type === 'identifier' ||
399
+ child.type === 'object_pattern' ||
400
+ child.type === 'array_pattern') {
401
+ nameNode = child;
402
+ }
403
+ }
404
+ else if (pastEquals && !valueNode) {
405
+ // First non-syntax child after equals is the value
406
+ if (child.type !== 'type_annotation') {
407
+ valueNode = child;
408
+ }
409
+ }
410
+ else if (!pastEquals && nameNode && !valueNode) {
411
+ // No '=' child in this grammar (e.g., TypeScript tree-sitter);
412
+ // the expression AFTER the name is the value.
413
+ if (child.type !== 'type_annotation') {
414
+ valueNode = child;
415
+ }
416
+ }
417
+ }
418
+ return { nameNode, valueNode, typeAnnotationNode };
419
+ }
420
+ /**
421
+ * Extract all variable names from a destructuring or identifier pattern.
422
+ * - identifier → [name]
423
+ * - object_pattern → [prop1, prop2, ...] rule 4
424
+ * - array_pattern → [elem1, elem2, ...] rule 5
425
+ */
426
+ function extractPatternNames(node, adapter, sourceCode) {
427
+ const names = [];
428
+ function collect(node) {
429
+ if (node.type === 'identifier') {
430
+ const name = adapter.getNodeText(node, sourceCode);
431
+ if (name)
432
+ names.push(name);
433
+ }
434
+ else if (node.type === 'object_pattern') {
435
+ // Each child is a shorthand_property_identifier, pair_pattern, or rest_pattern
436
+ for (const child of adapter.getChildren(node)) {
437
+ if (child.type === '{' ||
438
+ child.type === '}' ||
439
+ child.type === ',') {
440
+ continue;
441
+ }
442
+ if (child.type === 'shorthand_property_identifier') {
443
+ const name = adapter.getNodeText(child, sourceCode);
444
+ if (name)
445
+ names.push(name);
446
+ }
447
+ else if (child.type === 'pair_pattern') {
448
+ // pair_pattern children: [property, value]
449
+ // Extract from the value side (which might be an identifier or nested pattern)
450
+ const pairChildren = adapter.getChildren(child);
451
+ if (pairChildren.length >= 2) {
452
+ collect(pairChildren[1]);
453
+ }
454
+ }
455
+ else if (child.type === 'rest_pattern') {
456
+ collectChildren(child, adapter, sourceCode, names);
457
+ }
458
+ else {
459
+ collect(child);
460
+ }
461
+ }
462
+ }
463
+ else if (node.type === 'array_pattern') {
464
+ for (const child of adapter.getChildren(node)) {
465
+ if (child.type === '[' || child.type === ']' || child.type === ',') {
466
+ continue;
467
+ }
468
+ collect(child);
469
+ }
470
+ }
471
+ else if (node.type === 'assignment_pattern') {
472
+ // Default value in destructuring — collect from the left side
473
+ const children = adapter.getChildren(node);
474
+ if (children.length >= 1) {
475
+ collect(children[0]);
476
+ }
477
+ }
478
+ }
479
+ collect(node);
480
+ return names;
481
+ }
482
+ function collectChildren(node, adapter, sourceCode, names) {
483
+ for (const child of adapter.getChildren(node)) {
484
+ if (child.type === 'identifier') {
485
+ const name = adapter.getNodeText(child, sourceCode);
486
+ if (name)
487
+ names.push(name);
488
+ }
489
+ else {
490
+ collectChildren(child, adapter, sourceCode, names);
491
+ }
492
+ }
493
+ }
494
+ /**
495
+ * Extract the "receiver" identifier from a member expression chain.
496
+ * For `db.prepare` → "db"
497
+ * For `this.db.prepare` → "db" (walk to the deepest non-member identifier)
498
+ */
499
+ function getMemberExpressionReceiver(node, adapter, sourceCode) {
500
+ // Walk down the member expression chain to find the root object
501
+ let current = node;
502
+ while (current.type === 'member_expression') {
503
+ const children = adapter.getChildren(current);
504
+ const object = children.find((c) => c.type !== '.' && c.type !== 'property_identifier');
505
+ // The object of this member expression should be the first child
506
+ const firstChild = children[0];
507
+ if (firstChild &&
508
+ firstChild.type !== '.' &&
509
+ firstChild.type !== 'property_identifier') {
510
+ if (firstChild.type === 'member_expression') {
511
+ current = firstChild;
512
+ continue;
513
+ }
514
+ if (firstChild.type === 'identifier') {
515
+ return adapter.getNodeText(firstChild, sourceCode);
516
+ }
517
+ // e.g., this.db → member_expression(this, db)
518
+ if (firstChild.type === 'this' || firstChild.type === 'super') {
519
+ // This is a member expression on `this` — check the property side
520
+ // We need to check if `this.X` is provenanced... but `this` itself isn't.
521
+ // For propagation, this means looking at the full chain.
522
+ // For now, return null — this is handled by the caller
523
+ return null;
524
+ }
525
+ }
526
+ break;
527
+ }
528
+ return null;
529
+ }
530
+ /**
531
+ * Get the callee of a call expression (everything before arguments).
532
+ */
533
+ function getCallExpressionCallee(node, adapter) {
534
+ for (const child of adapter.getChildren(node)) {
535
+ if (child.type === 'arguments')
536
+ break;
537
+ // await_expression wraps the actual callee — recurse into it
538
+ if (child.type === 'await_expression') {
539
+ const inner = getCallExpressionCallee(child, adapter);
540
+ if (inner)
541
+ return inner;
542
+ continue;
543
+ }
544
+ if (child.type === 'identifier' ||
545
+ child.type === 'member_expression' ||
546
+ child.type === 'call_expression') {
547
+ return child;
548
+ }
549
+ }
550
+ return null;
551
+ }
552
+ /** Find first child (recursively excluding punctuation) matching one of the types. */
553
+ function findChildOfType(node, types) {
554
+ for (const child of node.children ?? []) {
555
+ if (types.includes(child.type))
556
+ return child;
557
+ const found = findChildOfType(child, types);
558
+ if (found)
559
+ return found;
560
+ }
561
+ return null;
562
+ }
563
+ /** Extract the identifier name from a node (handles member_expression chains). */
564
+ function extractIdentifierName(node, adapter, sourceCode) {
565
+ if (node.type === 'identifier') {
566
+ return adapter.getNodeText(node, sourceCode);
567
+ }
568
+ if (node.type === 'member_expression') {
569
+ // Get the deepest identifier in the chain
570
+ const firstChild = node.children?.[0];
571
+ if (firstChild) {
572
+ return extractIdentifierName(firstChild, adapter, sourceCode);
573
+ }
574
+ }
575
+ return null;
576
+ }
577
+ /** Depth-first walk of the AST, calling the visitor for each node. */
578
+ function walkAST(root, visitor) {
579
+ function walk(node, parent) {
580
+ visitor(node, parent);
581
+ for (const child of node.children ?? []) {
582
+ walk(child, node);
583
+ }
584
+ }
585
+ walk(root, null);
586
+ }
587
+ /**
588
+ * Build a ProvenanceContext for a file.
589
+ *
590
+ * This is the main entry point — call once per file before analysis.
591
+ * Combines import extraction, propagation, and mode-based fallback.
592
+ */
593
+ export function buildProvenanceContext(ast, adapter, sourceCode, options) {
594
+ const mode = options.mode;
595
+ // 1. Extract seed identifiers from imports
596
+ const dbSeeds = extractDBProvenancedImports(ast, adapter);
597
+ const validatorSeeds = options.mode !== 'names'
598
+ ? extractValidatorProvenancedImports(ast, adapter)
599
+ : new Map();
600
+ // 2. Propagate provenance through assignments
601
+ let dbProvenanced = propagateProvenance(ast, adapter, sourceCode, dbSeeds);
602
+ let validatorProvenanced = mode !== 'names'
603
+ ? propagateProvenance(ast, adapter, sourceCode, validatorSeeds)
604
+ : new Map();
605
+ // 3. Fallback: in hybrid mode, add identifiers that match name lists
606
+ // but weren't caught by provenance (R3)
607
+ if (mode === 'hybrid') {
608
+ dbProvenanced = addNameListFallbacks(dbProvenanced, sourceCode, options.dbReceiverNames ?? [], options.dbBindingNames ?? []);
609
+ }
610
+ // 4. In names mode, use ONLY name lists
611
+ if (mode === 'names') {
612
+ dbProvenanced = buildNamesOnlyProvenance(sourceCode, options.dbReceiverNames ?? [], options.dbBindingNames ?? []);
613
+ }
614
+ return {
615
+ dbProvenanced,
616
+ validatorProvenanced,
617
+ mode,
618
+ };
619
+ }
620
+ /**
621
+ * Add fallback provenance entries for identifiers that match name lists
622
+ * but weren't caught by the provenance chain (R3 hybrid mode).
623
+ *
624
+ * These entries carry `reason: 'fallback'` — visible in config detection
625
+ * so users can audit and tighten their chains.
626
+ */
627
+ function addNameListFallbacks(provenanceMap, sourceCode, dbReceiverNames, dbBindingNames) {
628
+ const result = new Map(provenanceMap);
629
+ // Scan for DB receiver names used as identifiers
630
+ for (const name of dbReceiverNames) {
631
+ if (result.has(name))
632
+ continue; // already provenanced — provenance wins
633
+ // Check if this name appears as an identifier in the source
634
+ if (identifierAppearsInSource(sourceCode, name)) {
635
+ result.set(name, {
636
+ identifier: name,
637
+ reason: 'fallback',
638
+ source: `name list match: dbReceiverNames contains "${name}"`,
639
+ chain: [],
640
+ });
641
+ }
642
+ }
643
+ // Scan for binding names like env.DB
644
+ for (const binding of dbBindingNames) {
645
+ if (sourceCode.includes(binding)) {
646
+ // Extract the property after the dot, e.g. "DB" from "env.DB"
647
+ const dotIdx = binding.lastIndexOf('.');
648
+ const shortName = dotIdx >= 0 ? binding.substring(dotIdx + 1) : binding;
649
+ // Also add the full binding path
650
+ if (!result.has(binding)) {
651
+ result.set(binding, {
652
+ identifier: binding,
653
+ reason: 'fallback',
654
+ source: `name list match: dbBindingNames contains "${binding}"`,
655
+ chain: [],
656
+ });
657
+ }
658
+ if (shortName !== binding && !result.has(shortName)) {
659
+ result.set(shortName, {
660
+ identifier: shortName,
661
+ reason: 'fallback',
662
+ source: `from binding ${binding}`,
663
+ chain: [],
664
+ });
665
+ }
666
+ }
667
+ }
668
+ return result;
669
+ }
670
+ /**
671
+ * Build a provenance map using ONLY name lists (for names mode).
672
+ */
673
+ function buildNamesOnlyProvenance(sourceCode, dbReceiverNames, dbBindingNames) {
674
+ return addNameListFallbacks(new Map(), sourceCode, dbReceiverNames, dbBindingNames);
675
+ }
676
+ /** Check if an identifier name appears as a standalone identifier in source. */
677
+ function identifierAppearsInSource(sourceCode, name) {
678
+ // Use word boundary matching to avoid partial matches
679
+ const pattern = new RegExp(`\\b${escapeRegex(name)}\\b`);
680
+ return pattern.test(sourceCode);
681
+ }
682
+ function escapeRegex(s) {
683
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
684
+ }
685
+ // ═══════════════════════════════════════════════════════════════════════════
686
+ // Core detection — is this call DB-provenanced?
687
+ // ═══════════════════════════════════════════════════════════════════════════
688
+ /**
689
+ * Determine if a call-expression node's callee is DB-provenanced.
690
+ *
691
+ * This replaces the old `isDBCallee()` / `isDbCallNode()` name-based
692
+ * pattern matching in UniversalDataAccessAnalyzer.
693
+ *
694
+ * Checks:
695
+ * 1. Simple identifier call → is the identifier DB-provenanced?
696
+ * 2. Member expression call → is the receiver DB-provenanced AND is the
697
+ * method in the DB call method set?
698
+ * 3. ORM patterns → receiver is DB-provenanced and method matches ORM API
699
+ */
700
+ export function isDBProvenanced(node, adapter, sourceCode, context, dbCallMethods) {
701
+ if (node.type !== 'call_expression')
702
+ return false;
703
+ const methods = dbCallMethods ?? DB_CALL_METHODS;
704
+ const calleeNode = getCallExpressionCallee(node, adapter);
705
+ if (!calleeNode)
706
+ return false;
707
+ // Case 1: Simple identifier call — e.g. query(...)
708
+ if (calleeNode.type === 'identifier') {
709
+ const name = adapter.getNodeText(calleeNode, sourceCode);
710
+ if (name !== null && context.dbProvenanced.has(name)) {
711
+ return true;
712
+ }
713
+ // Hybrid fallback: standalone calls to dbCallMethods (query, execute, etc.)
714
+ // qualify as likely DB calls when provenance couldn't resolve the import.
715
+ // This catches patterns like `import { query } from './db'` where './db' is
716
+ // a local re-export of a known package — provenance can't see through it,
717
+ // but the method name is strong evidence.
718
+ if (context.mode === 'hybrid' && name !== null && methods.has(name)) {
719
+ return true;
720
+ }
721
+ return false;
722
+ }
723
+ // Case 2: Member expression — e.g. db.prepare(...)
724
+ if (calleeNode.type === 'member_expression') {
725
+ return isMemberExpressionDBProvenanced(calleeNode, adapter, sourceCode, context, methods);
726
+ }
727
+ return false;
728
+ }
729
+ /**
730
+ * Check if a member_expression call is DB-provenanced.
731
+ *
732
+ * Traverses the member chain to find the root receiver,
733
+ * checks if it's in the provenance context, and verifies
734
+ * the method matches the DB call/ORM API.
735
+ */
736
+ function isMemberExpressionDBProvenanced(node, adapter, sourceCode, context, methods) {
737
+ // Walk the member expression chain to find the root
738
+ let rootReceiver = null;
739
+ let current = node;
740
+ while (current.type === 'member_expression') {
741
+ const children = adapter.getChildren(current);
742
+ const firstChild = children[0];
743
+ if (!firstChild)
744
+ break;
745
+ if (firstChild.type === 'identifier') {
746
+ rootReceiver = adapter.getNodeText(firstChild, sourceCode);
747
+ break;
748
+ }
749
+ if (firstChild.type === 'member_expression') {
750
+ current = firstChild;
751
+ continue;
752
+ }
753
+ // this.db.prepare → root is a chain on `this`, check `this.xxx`
754
+ if (firstChild.type === 'this' || firstChild.type === 'super') {
755
+ rootReceiver = 'this';
756
+ break;
757
+ }
758
+ break;
759
+ }
760
+ if (!rootReceiver)
761
+ return false;
762
+ // In names mode, check the method name directly
763
+ if (context.mode === 'names') {
764
+ return isDBMethodCall(node, adapter, sourceCode, context, methods);
765
+ }
766
+ // Check if the root receiver is DB-provenanced
767
+ if (!context.dbProvenanced.has(rootReceiver)) {
768
+ if (rootReceiver !== 'this')
769
+ return false;
770
+ // For `this.xxx`, check if the method chain itself suggests DB usage
771
+ return isDBMethodOnThis(node, adapter, sourceCode, context, methods);
772
+ }
773
+ // Check that the method is in the DB call/ORM API
774
+ return isDBMethodCall(node, adapter, sourceCode, context, methods);
775
+ }
776
+ /**
777
+ * Check if a call through a member expression uses a DB method
778
+ * (exec, prepare, all, etc.) or an ORM method (find, insert, etc.).
779
+ */
780
+ function isDBMethodCall(node, _adapter, _sourceCode, _context, methods) {
781
+ // Walk the member expression chain and check each property
782
+ let current = node;
783
+ while (current.type === 'member_expression') {
784
+ const children = current.children ?? [];
785
+ // The property is typically the second or third child
786
+ for (const child of children) {
787
+ if (child.type === 'property_identifier') {
788
+ const propName = child.type === 'property_identifier'
789
+ ? _adapter.getNodeText(child, _sourceCode)
790
+ : null;
791
+ if (propName && (methods.has(propName) || ORM_METHODS.has(propName))) {
792
+ return true;
793
+ }
794
+ }
795
+ }
796
+ // Go deeper if there's a nested member expression
797
+ const firstChild = children[0];
798
+ if (firstChild?.type === 'member_expression') {
799
+ current = firstChild;
800
+ }
801
+ else {
802
+ break;
803
+ }
804
+ }
805
+ return false;
806
+ }
807
+ /**
808
+ * For `this.xxx.method()` calls — check if the method chain suggests
809
+ * DB access. Used when the receiver is `this` (not directly DB-provenanced).
810
+ */
811
+ function isDBMethodOnThis(node, adapter, sourceCode, _context, methods) {
812
+ // Walk the chain: this.db.prepare → check if any property matches DB methods
813
+ let current = node;
814
+ while (current.type === 'member_expression') {
815
+ const children = adapter.getChildren(current);
816
+ for (const child of children) {
817
+ if (child.type === 'property_identifier') {
818
+ const propName = adapter.getNodeText(child, sourceCode);
819
+ if (propName && (methods.has(propName) || ORM_METHODS.has(propName))) {
820
+ return true;
821
+ }
822
+ }
823
+ }
824
+ const firstChild = children[0];
825
+ if (firstChild?.type === 'member_expression') {
826
+ current = firstChild;
827
+ }
828
+ else {
829
+ break;
830
+ }
831
+ }
832
+ return false;
833
+ }
834
+ /**
835
+ * Check if an identifier is validator-provenanced (R4 infrastructure).
836
+ *
837
+ * This will be consumed by Spec 15's validator-bypass detection.
838
+ */
839
+ export function isValidatorProvenanced(identifier, context) {
840
+ return context.validatorProvenanced.has(identifier);
841
+ }
842
+ // ═══════════════════════════════════════════════════════════════════════════
843
+ // Inference (R2 — to be wired during R2 implementation)
844
+ // ═══════════════════════════════════════════════════════════════════════════
845
+ /**
846
+ * Infer additional DB receivers by tracing identifiers that call DB methods
847
+ * back through assignment chains to provenanced sources.
848
+ *
849
+ * This is the conjunctive inference guard in action: an identifier is only
850
+ * inferred if it (a) appears as a receiver of a known DB call method AND
851
+ * (b) can be traced back to a provenanced source through assignments.
852
+ *
853
+ * Deferred: full implementation in R2 step.
854
+ */
855
+ export function inferReceivers(provenancedSet, fileAst, adapter, sourceCode) {
856
+ const inferred = { identifiers: [], evidence: [] };
857
+ const seen = new Set();
858
+ // Step 1: Build an assignment graph — name → source text of initializer
859
+ const assignmentGraph = buildAssignmentGraph(fileAst, adapter, sourceCode);
860
+ // Step 2: Walk all call expressions whose callee is a member expression
861
+ walkAST(fileAst.root, (node) => {
862
+ if (node.type !== 'call_expression')
863
+ return;
864
+ const callee = getCallExpressionCallee(node, adapter);
865
+ if (!callee || callee.type !== 'member_expression')
866
+ return;
867
+ // Extract method name (the property being called)
868
+ const methodName = extractMemberExpressionProperty(callee, adapter, sourceCode);
869
+ if (!methodName || !DB_CALL_METHODS.has(methodName))
870
+ return;
871
+ // Get the receiver identifier
872
+ const receiver = getMemberExpressionReceiver(callee, adapter, sourceCode);
873
+ if (!receiver)
874
+ return;
875
+ // Already in the provenanced set → skip (already first-class, not inferred)
876
+ if (provenancedSet.has(receiver))
877
+ return;
878
+ // Already added to inferred
879
+ if (seen.has(receiver))
880
+ return;
881
+ // Step 3: Trace receiver through assignment chain to see if it reaches
882
+ // a provenanced source
883
+ const traced = traceAssignmentChain(receiver, assignmentGraph, provenancedSet);
884
+ if (traced.found) {
885
+ seen.add(receiver);
886
+ inferred.identifiers.push(receiver);
887
+ inferred.evidence.push({
888
+ identifier: receiver,
889
+ reason: `calls .${methodName}() traced to ${traced.chains[0]} — ${traced.reason}`,
890
+ });
891
+ }
892
+ });
893
+ return inferred;
894
+ }
895
+ /**
896
+ * Build a reverse assignment graph from the AST.
897
+ * Maps variable name → the text of its initializer expression.
898
+ * Handles: const/let/var declarations, parameter defaults, class fields.
899
+ */
900
+ function buildAssignmentGraph(ast, adapter, sourceCode) {
901
+ const graph = new Map();
902
+ walkAST(ast.root, (node, parent) => {
903
+ // const/let/var x = <expr>
904
+ if (node.type === 'variable_declarator') {
905
+ const { nameNode, valueNode } = splitVariableDeclarator(node, adapter);
906
+ if (nameNode && valueNode) {
907
+ const names = extractPatternNames(nameNode, adapter, sourceCode);
908
+ const valueText = adapter.getNodeText(valueNode, sourceCode);
909
+ for (const name of names) {
910
+ if (!graph.has(name))
911
+ graph.set(name, valueText);
912
+ }
913
+ }
914
+ return;
915
+ }
916
+ // Parameter defaults: function foo(x = <expr>)
917
+ if (node.type === 'assignment_pattern' &&
918
+ parent?.type === 'formal_parameters') {
919
+ const children = adapter.getChildren(node);
920
+ if (children.length >= 2) {
921
+ const leftNode = children[0];
922
+ const rightNode = children[1];
923
+ if (leftNode.type === 'identifier') {
924
+ const paramName = adapter.getNodeText(leftNode, sourceCode);
925
+ const valueText = adapter.getNodeText(rightNode, sourceCode);
926
+ if (!graph.has(paramName))
927
+ graph.set(paramName, valueText);
928
+ }
929
+ }
930
+ return;
931
+ }
932
+ // Class field: fieldName = <expr>
933
+ if (node.type === 'public_field_definition' ||
934
+ node.type === 'field_definition') {
935
+ const children = adapter.getChildren(node);
936
+ const nameChild = children.find((c) => c.type === 'property_identifier');
937
+ const valueChild = children.find((c) => c.type !== 'property_identifier' &&
938
+ c.type !== 'decorator' &&
939
+ c.type !== 'private' &&
940
+ c.type !== 'public' &&
941
+ c.type !== 'protected' &&
942
+ c.type !== 'static' &&
943
+ c.type !== 'readonly' &&
944
+ c.type !== 'abstract' &&
945
+ c.type !== '=');
946
+ if (nameChild && valueChild) {
947
+ const fieldName = adapter.getNodeText(nameChild, sourceCode);
948
+ const valueText = adapter.getNodeText(valueChild, sourceCode);
949
+ if (!graph.has(fieldName))
950
+ graph.set(fieldName, valueText);
951
+ }
952
+ return;
953
+ }
954
+ });
955
+ return graph;
956
+ }
957
+ /**
958
+ * Trace a receiver identifier through the assignment graph to see if it
959
+ * ultimately resolves to a provenanced source.
960
+ */
961
+ function traceAssignmentChain(receiver, assignmentGraph, provenancedSet) {
962
+ const visited = new Set();
963
+ const chain = [receiver];
964
+ let current = receiver;
965
+ let depth = 0;
966
+ const MAX_DEPTH = 10;
967
+ while (depth < MAX_DEPTH) {
968
+ // Check if current is directly provenanced
969
+ if (provenancedSet.has(current)) {
970
+ return {
971
+ found: true,
972
+ chains: chain,
973
+ reason: provenancedSet.get(current).source,
974
+ };
975
+ }
976
+ // Also check if any identifier in the initializer text matches a provenanced source
977
+ const initText = assignmentGraph.get(current);
978
+ if (initText) {
979
+ // Extract identifiers from the initializer text and check against provenanced set
980
+ const idents = extractTopLevelIdentifiers(initText);
981
+ for (const ident of idents) {
982
+ if (provenancedSet.has(ident)) {
983
+ chain.push(current);
984
+ return {
985
+ found: true,
986
+ chains: chain,
987
+ reason: provenancedSet.get(ident).source,
988
+ };
989
+ }
990
+ }
991
+ }
992
+ // Move to the next link in the chain
993
+ if (!initText || visited.has(initText))
994
+ break;
995
+ visited.add(initText);
996
+ // Try to find a next identifier to trace
997
+ const idents = extractTopLevelIdentifiers(initText);
998
+ let foundNext = false;
999
+ for (const ident of idents) {
1000
+ if (assignmentGraph.has(ident) && !visited.has(ident)) {
1001
+ chain.push(ident);
1002
+ current = ident;
1003
+ foundNext = true;
1004
+ break;
1005
+ }
1006
+ }
1007
+ if (!foundNext)
1008
+ break;
1009
+ depth++;
1010
+ }
1011
+ return { found: false, chains: [], reason: '' };
1012
+ }
1013
+ /**
1014
+ * Extract top-level identifier names from an expression text.
1015
+ * E.g., "db.prepare(sql)" → ["db"], "getConnection()" → ["getConnection"]
1016
+ */
1017
+ function extractTopLevelIdentifiers(text) {
1018
+ // Strip member access and arguments to get the root identifier
1019
+ // Match the first identifier before any '.' or '('
1020
+ const match = text.match(/^[\p{L}_$][\p{L}\p{N}_$]*/u);
1021
+ if (match && match[0]) {
1022
+ return [match[0]];
1023
+ }
1024
+ return [];
1025
+ }
1026
+ /**
1027
+ * Extract the property name from a member expression node.
1028
+ * For `db.prepare` → "prepare", for `db.sql.prepare` → "prepare"
1029
+ */
1030
+ function extractMemberExpressionProperty(node, adapter, sourceCode) {
1031
+ const children = adapter.getChildren(node);
1032
+ // The property is the last non-dot child
1033
+ for (let i = children.length - 1; i >= 0; i--) {
1034
+ const child = children[i];
1035
+ if (child.type === 'property_identifier') {
1036
+ return adapter.getNodeText(child, sourceCode);
1037
+ }
1038
+ }
1039
+ return null;
1040
+ }
1041
+ //# sourceMappingURL=provenance.js.map