gitnexus 1.6.8-rc.9 → 1.6.8

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 (430) hide show
  1. package/README.md +3 -3
  2. package/dist/_shared/graph/types.d.ts +31 -1
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/language-detection.d.ts.map +1 -1
  5. package/dist/_shared/language-detection.js +11 -1
  6. package/dist/_shared/language-detection.js.map +1 -1
  7. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  8. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  9. package/dist/_shared/lbug/schema-constants.js +6 -0
  10. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  11. package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
  12. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  13. package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
  14. package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
  15. package/dist/cli/ai-context.d.ts +31 -1
  16. package/dist/cli/ai-context.js +18 -16
  17. package/dist/cli/analyze-config.js +11 -0
  18. package/dist/cli/analyze.d.ts +14 -0
  19. package/dist/cli/analyze.js +98 -0
  20. package/dist/cli/embedding-dims.d.ts +33 -0
  21. package/dist/cli/embedding-dims.js +39 -0
  22. package/dist/cli/eval-server.d.ts +8 -0
  23. package/dist/cli/eval-server.js +242 -2
  24. package/dist/cli/help-i18n.js +19 -0
  25. package/dist/cli/i18n/en.d.ts +15 -1
  26. package/dist/cli/i18n/en.js +15 -1
  27. package/dist/cli/i18n/resources.d.ts +29 -1
  28. package/dist/cli/i18n/zh-CN.d.ts +14 -0
  29. package/dist/cli/i18n/zh-CN.js +15 -1
  30. package/dist/cli/index.js +89 -1
  31. package/dist/cli/mcp.d.ts +6 -1
  32. package/dist/cli/mcp.js +26 -1
  33. package/dist/cli/optional-grammars.d.ts +6 -8
  34. package/dist/cli/optional-grammars.js +8 -11
  35. package/dist/cli/setup.d.ts +3 -1
  36. package/dist/cli/setup.js +67 -17
  37. package/dist/cli/skill-gen.js +2 -1
  38. package/dist/cli/tool.d.ts +19 -1
  39. package/dist/cli/tool.js +96 -3
  40. package/dist/core/embeddings/hf-env.d.ts +0 -66
  41. package/dist/core/embeddings/http-client.d.ts +7 -0
  42. package/dist/core/embeddings/http-client.js +5 -3
  43. package/dist/core/embeddings/server-mapping.d.ts +1 -1
  44. package/dist/core/embeddings/server-mapping.js +7 -3
  45. package/dist/core/graph/import-cycles.d.ts +10 -0
  46. package/dist/core/graph/import-cycles.js +103 -0
  47. package/dist/core/group/cross-impact.d.ts +2 -1
  48. package/dist/core/group/cross-impact.js +5 -1
  49. package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
  50. package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
  51. package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
  52. package/dist/core/group/extractors/http-route-extractor.js +22 -4
  53. package/dist/core/group/extractors/include-extractor.js +22 -13
  54. package/dist/core/group/sync.d.ts +27 -1
  55. package/dist/core/group/sync.js +0 -0
  56. package/dist/core/incremental/subgraph-extract.js +18 -1
  57. package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
  58. package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
  59. package/dist/core/ingestion/cfg/collect.d.ts +51 -0
  60. package/dist/core/ingestion/cfg/collect.js +77 -0
  61. package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
  62. package/dist/core/ingestion/cfg/control-dependence.js +182 -0
  63. package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
  64. package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
  65. package/dist/core/ingestion/cfg/emit.d.ts +293 -0
  66. package/dist/core/ingestion/cfg/emit.js +646 -0
  67. package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
  68. package/dist/core/ingestion/cfg/post-dominators.js +176 -0
  69. package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
  70. package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
  71. package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
  72. package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
  73. package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
  74. package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
  75. package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
  76. package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
  77. package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
  78. package/dist/core/ingestion/cfg/traversal-result.js +2 -0
  79. package/dist/core/ingestion/cfg/types.d.ts +274 -0
  80. package/dist/core/ingestion/cfg/types.js +13 -0
  81. package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
  82. package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
  83. package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
  84. package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
  85. package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
  86. package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
  87. package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
  88. package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
  89. package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
  90. package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
  91. package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
  92. package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
  93. package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
  94. package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
  95. package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
  96. package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
  97. package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
  98. package/dist/core/ingestion/cfg/visitors/go.js +638 -0
  99. package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
  100. package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
  101. package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
  102. package/dist/core/ingestion/cfg/visitors/java.js +812 -0
  103. package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
  104. package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
  105. package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
  106. package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
  107. package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
  108. package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
  109. package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
  110. package/dist/core/ingestion/cfg/visitors/php.js +721 -0
  111. package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
  112. package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
  113. package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
  114. package/dist/core/ingestion/cfg/visitors/python.js +558 -0
  115. package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
  116. package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
  117. package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
  118. package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
  119. package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
  120. package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
  121. package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
  122. package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
  123. package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
  124. package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
  125. package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
  126. package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
  127. package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
  128. package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
  129. package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
  130. package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
  131. package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
  132. package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
  133. package/dist/core/ingestion/import-resolvers/utils.js +2 -0
  134. package/dist/core/ingestion/language-provider.d.ts +11 -0
  135. package/dist/core/ingestion/languages/c-cpp.js +6 -1
  136. package/dist/core/ingestion/languages/cobol.js +4 -0
  137. package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
  138. package/dist/core/ingestion/languages/cpp/captures.js +50 -1
  139. package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
  140. package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
  141. package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
  142. package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
  143. package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
  144. package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
  145. package/dist/core/ingestion/languages/cpp/query.js +23 -0
  146. package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
  147. package/dist/core/ingestion/languages/csharp.js +2 -0
  148. package/dist/core/ingestion/languages/dart.js +2 -0
  149. package/dist/core/ingestion/languages/go.js +2 -0
  150. package/dist/core/ingestion/languages/java.js +3 -0
  151. package/dist/core/ingestion/languages/kotlin/query.js +3 -2
  152. package/dist/core/ingestion/languages/kotlin.js +3 -0
  153. package/dist/core/ingestion/languages/php.js +2 -0
  154. package/dist/core/ingestion/languages/python.js +2 -0
  155. package/dist/core/ingestion/languages/ruby.js +2 -0
  156. package/dist/core/ingestion/languages/rust.js +2 -0
  157. package/dist/core/ingestion/languages/swift.js +2 -0
  158. package/dist/core/ingestion/languages/typescript.js +5 -0
  159. package/dist/core/ingestion/languages/vue.js +6 -0
  160. package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
  161. package/dist/core/ingestion/method-extractors/generic.js +1 -0
  162. package/dist/core/ingestion/method-types.d.ts +2 -0
  163. package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
  164. package/dist/core/ingestion/model/symbol-table.js +1 -0
  165. package/dist/core/ingestion/mro-processor.js +109 -0
  166. package/dist/core/ingestion/parsing-processor.js +23 -0
  167. package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
  168. package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
  169. package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
  170. package/dist/core/ingestion/pipeline-phases/index.js +2 -0
  171. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
  172. package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
  173. package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
  174. package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
  175. package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
  176. package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
  177. package/dist/core/ingestion/pipeline.d.ts +92 -10
  178. package/dist/core/ingestion/pipeline.js +11 -2
  179. package/dist/core/ingestion/scope-extractor.js +12 -2
  180. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
  181. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
  182. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
  183. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
  184. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
  185. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
  186. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
  187. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
  188. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
  189. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
  190. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
  191. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
  192. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
  193. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
  194. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
  195. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
  196. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
  197. package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
  198. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  199. package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
  200. package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
  201. package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
  202. package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
  203. package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
  204. package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
  205. package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
  206. package/dist/core/ingestion/taint/call-summary-model.js +25 -0
  207. package/dist/core/ingestion/taint/emit.d.ts +125 -0
  208. package/dist/core/ingestion/taint/emit.js +208 -0
  209. package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
  210. package/dist/core/ingestion/taint/interproc-emit.js +88 -0
  211. package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
  212. package/dist/core/ingestion/taint/interproc-solver.js +312 -0
  213. package/dist/core/ingestion/taint/match.d.ts +153 -0
  214. package/dist/core/ingestion/taint/match.js +278 -0
  215. package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
  216. package/dist/core/ingestion/taint/path-codec.js +190 -0
  217. package/dist/core/ingestion/taint/propagate.d.ts +216 -0
  218. package/dist/core/ingestion/taint/propagate.js +659 -0
  219. package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
  220. package/dist/core/ingestion/taint/site-safety.js +98 -0
  221. package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
  222. package/dist/core/ingestion/taint/source-sink-config.js +35 -12
  223. package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
  224. package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
  225. package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
  226. package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
  227. package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
  228. package/dist/core/ingestion/taint/summary-harvest.js +537 -0
  229. package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
  230. package/dist/core/ingestion/taint/summary-model.js +86 -0
  231. package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
  232. package/dist/core/ingestion/taint/typescript-model.js +102 -0
  233. package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
  234. package/dist/core/ingestion/utils/env.d.ts +7 -0
  235. package/dist/core/ingestion/utils/env.js +12 -0
  236. package/dist/core/ingestion/utils/method-props.js +1 -0
  237. package/dist/core/ingestion/workers/parse-worker.d.ts +13 -0
  238. package/dist/core/ingestion/workers/parse-worker.js +76 -17
  239. package/dist/core/ingestion/workers/worker-pool.d.ts +9 -40
  240. package/dist/core/ingestion/workers/worker-pool.js +15 -2
  241. package/dist/core/lbug/csv-generator.d.ts +51 -3
  242. package/dist/core/lbug/csv-generator.js +369 -255
  243. package/dist/core/lbug/lbug-adapter.d.ts +58 -18
  244. package/dist/core/lbug/lbug-adapter.js +346 -84
  245. package/dist/core/lbug/lbug-config.d.ts +19 -0
  246. package/dist/core/lbug/lbug-config.js +29 -0
  247. package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
  248. package/dist/core/lbug/pdg-emit-sink.js +358 -0
  249. package/dist/core/lbug/pool-adapter.d.ts +35 -0
  250. package/dist/core/lbug/pool-adapter.js +90 -1
  251. package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
  252. package/dist/core/lbug/rel-pair-routing.js +140 -0
  253. package/dist/core/lbug/schema.d.ts +2 -2
  254. package/dist/core/lbug/schema.js +3 -0
  255. package/dist/core/logger.d.ts +0 -5
  256. package/dist/core/run-analyze.d.ts +96 -0
  257. package/dist/core/run-analyze.js +207 -3
  258. package/dist/core/tree-sitter/parser-loader.js +5 -4
  259. package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
  260. package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
  261. package/dist/core/tree-sitter/vendored-grammars.js +57 -0
  262. package/dist/core/wiki/generator.js +3 -1
  263. package/dist/core/wiki/graph-queries.d.ts +6 -0
  264. package/dist/core/wiki/graph-queries.js +9 -1
  265. package/dist/mcp/http-transport.d.ts +134 -0
  266. package/dist/mcp/http-transport.js +503 -0
  267. package/dist/mcp/local/local-backend.d.ts +110 -24
  268. package/dist/mcp/local/local-backend.js +1225 -19
  269. package/dist/mcp/local/pdg-impact.d.ts +384 -0
  270. package/dist/mcp/local/pdg-impact.js +1972 -0
  271. package/dist/mcp/resources.js +13 -1
  272. package/dist/mcp/tools.d.ts +12 -0
  273. package/dist/mcp/tools.js +214 -7
  274. package/dist/server/analyze-launch.d.ts +29 -0
  275. package/dist/server/analyze-launch.js +137 -0
  276. package/dist/server/analyze-upload.d.ts +33 -0
  277. package/dist/server/analyze-upload.js +123 -0
  278. package/dist/server/analyze-worker.d.ts +17 -1
  279. package/dist/server/api.d.ts +17 -0
  280. package/dist/server/api.js +132 -168
  281. package/dist/server/git-clone.d.ts +43 -2
  282. package/dist/server/git-clone.js +211 -16
  283. package/dist/server/mcp-http.d.ts +5 -6
  284. package/dist/server/mcp-http.js +9 -82
  285. package/dist/server/middleware.d.ts +40 -0
  286. package/dist/server/middleware.js +92 -0
  287. package/dist/server/private-ip.d.ts +1 -0
  288. package/dist/server/private-ip.js +15 -0
  289. package/dist/server/upload-ingest.d.ts +56 -0
  290. package/dist/server/upload-ingest.js +276 -0
  291. package/dist/server/upload-paths.d.ts +37 -0
  292. package/dist/server/upload-paths.js +57 -0
  293. package/dist/server/upload-sweep.d.ts +20 -0
  294. package/dist/server/upload-sweep.js +57 -0
  295. package/dist/storage/git.js +5 -8
  296. package/dist/storage/parse-cache.d.ts +22 -1
  297. package/dist/storage/parse-cache.js +41 -10
  298. package/dist/storage/repo-manager.d.ts +121 -10
  299. package/dist/storage/repo-manager.js +43 -5
  300. package/dist/types/pipeline.d.ts +9 -0
  301. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
  302. package/hooks/claude/gitnexus-hook.cjs +110 -13
  303. package/hooks/claude/hook-db-lock-probe.cjs +513 -26
  304. package/package.json +8 -2
  305. package/scripts/assert-publish-grammar-coverage.cjs +31 -0
  306. package/scripts/build-tree-sitter-grammars.cjs +16 -10
  307. package/scripts/cross-platform-tests.ts +1 -0
  308. package/skills/gitnexus-debugging.md +16 -4
  309. package/skills/gitnexus-exploring.md +3 -3
  310. package/skills/gitnexus-guide.md +33 -0
  311. package/skills/gitnexus-pdg-query.md +89 -0
  312. package/skills/gitnexus-refactoring.md +1 -1
  313. package/skills/gitnexus-taint-analysis.md +178 -0
  314. package/vendor/tree-sitter-c/package.json +1 -1
  315. package/vendor/tree-sitter-dart/package.json +1 -1
  316. package/vendor/tree-sitter-kotlin/package.json +1 -1
  317. package/vendor/tree-sitter-proto/package.json +1 -1
  318. package/vendor/tree-sitter-swift/package.json +1 -1
  319. package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
  320. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
  321. package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
  322. package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
  323. package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
  324. package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
  325. package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
  326. package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
  327. package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
  328. package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
  329. package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
  330. package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
  331. package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
  332. package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
  333. package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
  334. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
  335. package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
  336. package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
  337. package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
  338. package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
  339. package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
  340. package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
  341. package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
  342. package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
  343. package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
  344. package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
  345. package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
  346. package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
  347. package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
  348. package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
  349. package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
  350. package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
  351. package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
  352. package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
  353. package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
  354. package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
  355. package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
  356. package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
  357. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
  358. package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
  359. package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
  360. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
  361. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
  362. package/web/assets/index-BvYev1UJ.js +635 -0
  363. package/web/assets/index-_lgn7hs5.css +2 -0
  364. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
  365. package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
  366. package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
  367. package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
  368. package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
  369. package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
  370. package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
  371. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
  372. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
  373. package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
  374. package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
  375. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
  376. package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
  377. package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
  378. package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
  379. package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
  380. package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
  381. package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
  382. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
  383. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
  384. package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
  385. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
  386. package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
  387. package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
  388. package/web/index.html +13 -15
  389. package/scripts/materialize-vendor-grammars.cjs +0 -97
  390. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
  391. package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
  392. package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
  393. package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
  394. package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
  395. package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
  396. package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
  397. package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
  398. package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
  399. package/web/assets/chunk-CilyBKbf.js +0 -1
  400. package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
  401. package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
  402. package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
  403. package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
  404. package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
  405. package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
  406. package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
  407. package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
  408. package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
  409. package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
  410. package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
  411. package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
  412. package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
  413. package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
  414. package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
  415. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
  416. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
  417. package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
  418. package/web/assets/index-BKWA-m7o.css +0 -2
  419. package/web/assets/index-CG6q8eTs.js +0 -626
  420. package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
  421. package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
  422. package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
  423. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
  424. package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
  425. package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
  426. package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
  427. package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
  428. package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
  429. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
  430. /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
@@ -0,0 +1,587 @@
1
+ import { CallSiteFactAccumulator as FactAccumulator } from './call-site-harvest.js';
2
+ /** Node types that own a nested CFG — their subtrees are opaque to harvesting. */
3
+ const NESTED_FUNCTION_TYPES = new Set([
4
+ 'method',
5
+ 'singleton_method',
6
+ 'do_block',
7
+ 'block',
8
+ 'lambda',
9
+ ]);
10
+ /** Parameter container node types (method + block + lambda). */
11
+ const PARAM_CONTAINER_TYPES = new Set([
12
+ 'method_parameters',
13
+ 'block_parameters',
14
+ 'lambda_parameters',
15
+ ]);
16
+ /** Parameter leaf node types whose `name` field (or bare identifier) is the binder. */
17
+ const NAMED_PARAM_TYPES = new Set([
18
+ 'optional_parameter',
19
+ 'splat_parameter',
20
+ 'hash_splat_parameter',
21
+ 'block_parameter',
22
+ 'keyword_parameter',
23
+ ]);
24
+ export class RubyHarvester {
25
+ fnNode;
26
+ bindings = [];
27
+ /** Single function-scope name → binding index (documented over-approximation). */
28
+ table = new Map();
29
+ synthetic = new Map();
30
+ fnId;
31
+ /** >0 while walking a conditionally-evaluated subexpression — defs become may-defs. */
32
+ conditionalDepth = 0;
33
+ /**
34
+ * `call` node id → binding indices its single-target result is assigned to
35
+ * (`x = f()` ⇒ `[x]`). Populated just before the value walk reaches the call
36
+ * (see {@link registerResultDefs}) and consumed by {@link visitCall}. Mirrors
37
+ * the Python / Kotlin / Go harvesters' `resultDefTargets`.
38
+ */
39
+ resultDefTargets = new Map();
40
+ constructor(fnNode) {
41
+ this.fnNode = fnNode;
42
+ this.fnId = fnNode.id;
43
+ this.declareParams(fnNode);
44
+ const body = this.bodyOf(fnNode);
45
+ if (body)
46
+ this.prescan(body);
47
+ }
48
+ /** The completed binding table — pass to `CfgBuilder.finish`. */
49
+ bindingTable() {
50
+ return this.bindings;
51
+ }
52
+ /** The function/block/lambda body node. */
53
+ bodyOf(fnNode) {
54
+ return fnNode.childForFieldName('body') ?? undefined;
55
+ }
56
+ // ── phase 1: declaration pre-scan ────────────────────────────────────────
57
+ declare(nameNode, kind) {
58
+ const name = nameNode.text;
59
+ if (!name || name === '_' || this.table.has(name))
60
+ return;
61
+ this.table.set(name, this.bindings.length);
62
+ this.bindings.push({
63
+ name,
64
+ declLine: nameNode.startPosition.row + 1,
65
+ declColumn: nameNode.startPosition.column,
66
+ kind,
67
+ });
68
+ }
69
+ /** Declare every parameter binder (method / block / lambda). */
70
+ declareParams(fnNode) {
71
+ const params = this.paramsOf(fnNode);
72
+ if (!params)
73
+ return;
74
+ for (let i = 0; i < params.namedChildCount; i++) {
75
+ const p = params.namedChild(i);
76
+ if (p)
77
+ this.declareParam(p);
78
+ }
79
+ }
80
+ /** The `parameters` field (or first parameter-container child) of a function node. */
81
+ paramsOf(fnNode) {
82
+ const field = fnNode.childForFieldName('parameters');
83
+ if (field)
84
+ return field;
85
+ return fnNode.namedChildren.find((c) => PARAM_CONTAINER_TYPES.has(c.type));
86
+ }
87
+ /** Declare the binder identifier of one parameter node. */
88
+ declareParam(p) {
89
+ if (p.type === 'identifier') {
90
+ this.declare(p, 'param');
91
+ return;
92
+ }
93
+ if (NAMED_PARAM_TYPES.has(p.type)) {
94
+ const name = p.childForFieldName('name') ?? p.namedChildren.find((c) => c.type === 'identifier');
95
+ if (name)
96
+ this.declare(name, 'param');
97
+ return;
98
+ }
99
+ // Destructured / grouped block param — declare any identifier leaves.
100
+ for (let i = 0; i < p.namedChildCount; i++) {
101
+ const c = p.namedChild(i);
102
+ if (c?.type === 'identifier')
103
+ this.declare(c, 'param');
104
+ else if (c)
105
+ this.declareParam(c);
106
+ }
107
+ }
108
+ /**
109
+ * Pre-scan the function body once, declaring every in-function local name.
110
+ * Recurses into compound statements but NOT into nested function/block/lambda
111
+ * bodies (opaque).
112
+ */
113
+ prescan(node) {
114
+ const t = node.type;
115
+ if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
116
+ return;
117
+ switch (t) {
118
+ case 'assignment': {
119
+ const left = node.childForFieldName('left');
120
+ if (left)
121
+ this.declareTargets(left);
122
+ break;
123
+ }
124
+ case 'operator_assignment': {
125
+ const left = node.childForFieldName('left');
126
+ if (left)
127
+ this.declareTargets(left);
128
+ break;
129
+ }
130
+ case 'for': {
131
+ const pattern = node.childForFieldName('pattern');
132
+ if (pattern)
133
+ this.declareTargets(pattern);
134
+ break;
135
+ }
136
+ case 'rescue': {
137
+ this.declareRescueVar(node);
138
+ break;
139
+ }
140
+ default:
141
+ break;
142
+ }
143
+ // A nested `do_block`/`block`/`lambda` body is opaque, but its OWN block
144
+ // parameters are declared (they are not local to THIS function, yet the
145
+ // single-table model harvests them where used) — handled by declareParam in
146
+ // the visitor's per-block harvester instance, not here. We only recurse to
147
+ // collect assignment/for/rescue local targets in THIS function body.
148
+ for (let i = 0; i < node.namedChildCount; i++) {
149
+ const c = node.namedChild(i);
150
+ if (c)
151
+ this.prescan(c);
152
+ }
153
+ }
154
+ /** `rescue [Exc] => e` — declare `e` (a `catch`-kind def). */
155
+ declareRescueVar(clause) {
156
+ const variable = clause.childForFieldName('variable');
157
+ const id = variable?.namedChildren.find((c) => c.type === 'identifier') ?? variable;
158
+ if (id?.type === 'identifier')
159
+ this.declare(id, 'catch');
160
+ }
161
+ /** Declare identifier leaves of an assignment / loop target (skip non-local LHS). */
162
+ declareTargets(target) {
163
+ const t = target.type;
164
+ if (t === 'identifier') {
165
+ this.declare(target, 'let');
166
+ return;
167
+ }
168
+ if (t === 'left_assignment_list') {
169
+ for (let i = 0; i < target.namedChildCount; i++) {
170
+ const c = target.namedChild(i);
171
+ if (c)
172
+ this.declareTargets(c);
173
+ }
174
+ return;
175
+ }
176
+ if (t === 'splat_parameter' || t === 'rest_assignment') {
177
+ const id = target.namedChildren.find((c) => c.type === 'identifier');
178
+ if (id)
179
+ this.declare(id, 'let');
180
+ return;
181
+ }
182
+ // instance/class/global var, constant, element/attribute target — not a
183
+ // function-scoped scalar def (the root identifier is a use only).
184
+ }
185
+ // ── phase 2: per-statement fact extraction ───────────────────────────────
186
+ /** Def/use facts for one statement (or construct-header expression) node. */
187
+ facts(node) {
188
+ const acc = new FactAccumulator(node.startPosition.row + 1);
189
+ this.walkValue(node, acc);
190
+ return acc.finish();
191
+ }
192
+ /** Facts for an expression whose WHOLE evaluation is conditional (case tests). */
193
+ factsConditional(node) {
194
+ const acc = new FactAccumulator(node.startPosition.row + 1);
195
+ this.conditional(() => this.walkValue(node, acc));
196
+ return acc.finish();
197
+ }
198
+ /**
199
+ * Facts for a `for PATTERN in VALUE` head: the loop target(s) are defs, the
200
+ * iterated expression is a use.
201
+ */
202
+ loopHeadFacts(forNode) {
203
+ const acc = new FactAccumulator(forNode.startPosition.row + 1);
204
+ const pattern = forNode.childForFieldName('pattern');
205
+ const value = forNode.childForFieldName('value');
206
+ if (value)
207
+ this.walkValue(value, acc);
208
+ if (pattern)
209
+ this.defTargets(pattern, acc);
210
+ return acc.finish();
211
+ }
212
+ /**
213
+ * Def-ONLY facts for a value-position assignment (`x = if … / case …`, #2205):
214
+ * just the LHS target(s), attached to the continuation block the branch arms
215
+ * rejoin. The branch condition + arm-value USES are harvested onto the branch's
216
+ * own blocks (visitIf / visitCase), so this must not re-walk the RHS.
217
+ */
218
+ assignmentDefFacts(stmt) {
219
+ const acc = new FactAccumulator(stmt.startPosition.row + 1);
220
+ const left = stmt.childForFieldName('left');
221
+ if (left)
222
+ this.defTargets(left, acc);
223
+ return acc.defCount() ? acc.finish() : undefined;
224
+ }
225
+ /** Facts for a `rescue [Exc] => e` header: `e` is a def, the exception list a use. */
226
+ rescueHeadFacts(clause) {
227
+ const acc = new FactAccumulator(clause.startPosition.row + 1);
228
+ const exceptions = clause.childForFieldName('exceptions');
229
+ if (exceptions)
230
+ this.walkValue(exceptions, acc);
231
+ const variable = clause.childForFieldName('variable');
232
+ const id = variable?.namedChildren.find((c) => c.type === 'identifier');
233
+ if (id)
234
+ this.def(id, acc);
235
+ return acc.finish();
236
+ }
237
+ /** ENTRY-block facts for the parameters (defs only — incl. default-value uses). */
238
+ paramFacts() {
239
+ const params = this.paramsOf(this.fnNode);
240
+ if (!params)
241
+ return undefined;
242
+ const acc = new FactAccumulator(this.fnNode.startPosition.row + 1);
243
+ for (let i = 0; i < params.namedChildCount; i++) {
244
+ const p = params.namedChild(i);
245
+ if (p)
246
+ this.defParam(p, acc);
247
+ }
248
+ return acc.defCount() || acc.useCount() ? acc.finish() : undefined;
249
+ }
250
+ /** Def the binder of one parameter node and use any default-value expr. */
251
+ defParam(p, acc) {
252
+ if (p.type === 'identifier') {
253
+ this.def(p, acc);
254
+ return;
255
+ }
256
+ if (p.type === 'optional_parameter' || p.type === 'keyword_parameter') {
257
+ const value = p.childForFieldName('value');
258
+ if (value)
259
+ this.walkValue(value, acc);
260
+ const name = p.childForFieldName('name');
261
+ if (name)
262
+ this.def(name, acc);
263
+ return;
264
+ }
265
+ if (NAMED_PARAM_TYPES.has(p.type)) {
266
+ const name = p.childForFieldName('name') ?? p.namedChildren.find((c) => c.type === 'identifier');
267
+ if (name)
268
+ this.def(name, acc);
269
+ return;
270
+ }
271
+ for (let i = 0; i < p.namedChildCount; i++) {
272
+ const c = p.namedChild(i);
273
+ if (c?.type === 'identifier')
274
+ this.def(c, acc);
275
+ else if (c)
276
+ this.defParam(c, acc);
277
+ }
278
+ }
279
+ resolve(nameNode) {
280
+ const name = nameNode.text;
281
+ const idx = this.table.get(name);
282
+ if (idx !== undefined)
283
+ return idx;
284
+ let s = this.synthetic.get(name);
285
+ if (s === undefined) {
286
+ s = this.bindings.length;
287
+ this.synthetic.set(name, s);
288
+ this.bindings.push({ name, declLine: 0, declColumn: 0, kind: 'module', synthetic: true });
289
+ }
290
+ return s;
291
+ }
292
+ def(nameNode, acc) {
293
+ if (nameNode.text === '_')
294
+ return;
295
+ if (this.conditionalDepth > 0)
296
+ acc.addMayDef(this.resolve(nameNode));
297
+ else
298
+ acc.addDef(this.resolve(nameNode));
299
+ }
300
+ use(nameNode, acc) {
301
+ if (nameNode.text === '_')
302
+ return;
303
+ // Resolve only known LOCAL names; an unknown bare identifier is a method
304
+ // call (resolves to a `module` synthetic — never a false local).
305
+ acc.addUse(this.resolve(nameNode));
306
+ }
307
+ /** Run `fn` with defs demoted to may-defs (conditionally-evaluated context). */
308
+ conditional(fn) {
309
+ this.conditionalDepth++;
310
+ try {
311
+ fn();
312
+ }
313
+ finally {
314
+ this.conditionalDepth--;
315
+ }
316
+ }
317
+ /**
318
+ * Def each identifier leaf of an assignment / loop target; route non-local
319
+ * targets (`@x`, index/attribute writes) to the value walk (root is a use).
320
+ */
321
+ defTargets(target, acc) {
322
+ const t = target.type;
323
+ if (t === 'identifier') {
324
+ this.def(target, acc);
325
+ return;
326
+ }
327
+ if (t === 'left_assignment_list') {
328
+ for (let i = 0; i < target.namedChildCount; i++) {
329
+ const c = target.namedChild(i);
330
+ if (c)
331
+ this.defTargets(c, acc);
332
+ }
333
+ return;
334
+ }
335
+ if (t === 'splat_parameter' || t === 'rest_assignment') {
336
+ const id = target.namedChildren.find((c) => c.type === 'identifier');
337
+ if (id)
338
+ this.def(id, acc);
339
+ else
340
+ this.walkValue(target, acc);
341
+ return;
342
+ }
343
+ // instance/class/global var, constant, element/attribute target — uses only.
344
+ this.walkValue(target, acc);
345
+ }
346
+ /** Value-position walk: collect uses; route def positions to the target handler. */
347
+ walkValue(node, acc) {
348
+ const t = node.type;
349
+ if (NESTED_FUNCTION_TYPES.has(t) && node.id !== this.fnId)
350
+ return; // opaque
351
+ switch (t) {
352
+ case 'identifier':
353
+ this.use(node, acc);
354
+ return;
355
+ // Non-local variables and constants — recorded as neither a scalar def nor
356
+ // a local use (they are not function-scoped locals); nothing to add.
357
+ case 'instance_variable':
358
+ case 'class_variable':
359
+ case 'global_variable':
360
+ case 'constant':
361
+ case 'self':
362
+ return;
363
+ case 'assignment': {
364
+ const left = node.childForFieldName('left');
365
+ const right = node.childForFieldName('right');
366
+ // Register result-defs BEFORE walking the value so the nested call site
367
+ // (reached during the value walk) carries them — single plain-identifier
368
+ // target only (`x = f()`); a multi-target / `@ivar` / index LHS attaches
369
+ // nothing (the per-target mapping is ambiguous).
370
+ if (left?.type === 'identifier' && right)
371
+ this.registerResultDefs(right, [left]);
372
+ if (right)
373
+ this.walkValue(right, acc);
374
+ if (left)
375
+ this.defTargets(left, acc);
376
+ return;
377
+ }
378
+ case 'operator_assignment': {
379
+ const left = node.childForFieldName('left');
380
+ const right = node.childForFieldName('right');
381
+ if (right)
382
+ this.walkValue(right, acc);
383
+ if (left) {
384
+ if (left.type === 'identifier') {
385
+ this.use(left, acc);
386
+ this.def(left, acc);
387
+ }
388
+ else {
389
+ this.walkValue(left, acc); // non-local lvalue — use only
390
+ }
391
+ }
392
+ return;
393
+ }
394
+ case 'binary': {
395
+ // `a && b` / `a || b` / `and` / `or` — the right operand is conditionally
396
+ // evaluated, so any def inside it is a may-def; uses are still recorded.
397
+ const left = node.childForFieldName('left');
398
+ const right = node.childForFieldName('right');
399
+ const op = node.childForFieldName('operator')?.text ?? '';
400
+ if (left)
401
+ this.walkValue(left, acc);
402
+ if (right) {
403
+ if (op === '&&' || op === '||' || op === 'and' || op === 'or') {
404
+ this.conditional(() => this.walkValue(right, acc));
405
+ }
406
+ else {
407
+ this.walkValue(right, acc);
408
+ }
409
+ }
410
+ return;
411
+ }
412
+ case 'call':
413
+ // `recv.meth(args)` / `meth(args)` / `puts x` / `obj.field` — every Ruby
414
+ // call shape. Records a taint site (callee path, receiver, per-arg
415
+ // occurrences, result defs, spread) plus the SAME uses the old default
416
+ // descent recorded (receiver chain root + arguments). A nested block
417
+ // child is its OWN function CFG (opaque — the `block` field is not walked).
418
+ this.visitCall(node, acc);
419
+ return;
420
+ default:
421
+ for (let i = 0; i < node.namedChildCount; i++) {
422
+ const c = node.namedChild(i);
423
+ if (c)
424
+ this.walkValue(c, acc);
425
+ }
426
+ }
427
+ }
428
+ // ── taint-site harvest ────────────────────────────────────────────────────
429
+ /**
430
+ * When `value` is a `call`, remember that call site should carry `resultDefs`
431
+ * — the binding indices of `targets` (def-position identifiers). Consumed by
432
+ * {@link visitCall} once the value walk reaches the node. Single plain-identifier
433
+ * target only (the caller restricts to it); the blank target (`_`) binds nothing
434
+ * and is skipped.
435
+ */
436
+ registerResultDefs(value, targets) {
437
+ if (value.type !== 'call')
438
+ return;
439
+ const defs = [];
440
+ for (const target of targets) {
441
+ if (target.type !== 'identifier' || target.text === '_')
442
+ continue;
443
+ defs.push(this.resolve(target));
444
+ }
445
+ if (defs.length > 0)
446
+ this.resultDefTargets.set(value.id, defs);
447
+ }
448
+ /**
449
+ * Explicit `call` handler. Records a call site (callee path, receiver, per-arg
450
+ * occurrence entries, result defs, spread marker) while reproducing EXACTLY the
451
+ * uses the old default descent recorded (receiver chain root + arguments). Ruby
452
+ * has no `new` — every site is `kind: 'call'`. The `at` anchor is the `call`
453
+ * node's start, byte-aligned with the `@reference.call.free/.member` CALLS
454
+ * anchor (which captures the whole `call` node), so the resolved-id join lands
455
+ * by exact position (see file header ANCHOR ALIGNMENT).
456
+ */
457
+ visitCall(node, acc) {
458
+ const receiver = node.childForFieldName('receiver');
459
+ const method = node.childForFieldName('method');
460
+ const args = node.childForFieldName('arguments');
461
+ const siteIdx = acc.openCallSite('call', [
462
+ node.startPosition.row + 1,
463
+ node.startPosition.column,
464
+ ]);
465
+ acc.pushFrame(siteIdx);
466
+ if (receiver) {
467
+ // Member / chained call (`obj.method`, `a.b.c`, `obj&.m`). Walk the receiver
468
+ // chain to its root binding (the receiver use + any mid-chain member reads)
469
+ // and build the dotted callee path `root.…​.method`.
470
+ const chain = this.walkReceiverChain(receiver, acc);
471
+ if (chain.rootIdx !== undefined)
472
+ acc.setSiteReceiver(siteIdx, chain.rootIdx);
473
+ const path = this.calleePath(chain.path, method);
474
+ if (path !== undefined)
475
+ acc.setSiteCallee(siteIdx, path);
476
+ }
477
+ else if (method) {
478
+ // Free / implicit-receiver call (`foo(a)`, `puts x`, `attr_accessor :x`).
479
+ // The method NAME is a statement-level use (a known local resolves to its
480
+ // binding, an unknown method to a `module` synthetic) but NOT a value
481
+ // occurrence in any enclosing argument.
482
+ if (method.text !== '_')
483
+ acc.addUseWithoutOccurrence(this.resolve(method));
484
+ acc.setSiteCallee(siteIdx, method.text);
485
+ }
486
+ const resultDefs = this.resultDefTargets.get(node.id);
487
+ if (resultDefs !== undefined)
488
+ acc.setSiteResultDefs(siteIdx, resultDefs);
489
+ if (args)
490
+ this.walkArguments(args, siteIdx, acc);
491
+ acc.popFrame();
492
+ }
493
+ /**
494
+ * Walk a member-call receiver, returning the chain ROOT binding (recorded as a
495
+ * use) and the dotted prefix path (`a.b` in `a.b.c()`), plus a member-read site
496
+ * for each NON-final access in the chain. A receiver that is itself a `call`
497
+ * (Ruby nests `a.b.c` as `call(call(a,b),c)`) recurses; a bare identifier root
498
+ * is the receiver binding; a `self` / non-identifier root has no static path.
499
+ */
500
+ walkReceiverChain(receiver, acc) {
501
+ // Collect the access names along the receiver chain (outermost-last), and the
502
+ // chain root node, by unwinding nested `call` receivers.
503
+ const accesses = [];
504
+ let cur = receiver;
505
+ for (;;) {
506
+ if (cur.type === 'call' && cur.childForFieldName('arguments') === null) {
507
+ // A no-args member `call` in receiver position is a member ACCESS
508
+ // (`a.b` in `a.b.c`) — its method name extends the path; recurse on its
509
+ // own receiver. A receiver `call` WITH arguments is an opaque call result
510
+ // (`foo(a).bar` — handled by the `else` below as a nested call site).
511
+ const m = cur.childForFieldName('method');
512
+ const inner = cur.childForFieldName('receiver');
513
+ accesses.unshift(m?.text ?? '');
514
+ if (!inner)
515
+ break;
516
+ cur = inner;
517
+ continue;
518
+ }
519
+ break;
520
+ }
521
+ let rootIdx;
522
+ let rootSegment;
523
+ if (cur.type === 'identifier' && cur.text !== '_') {
524
+ rootIdx = this.resolve(cur);
525
+ acc.addUse(rootIdx);
526
+ rootSegment = cur.text;
527
+ }
528
+ else {
529
+ // `self` / `@ivar` / a call-rooted receiver (`foo(a).bar`) / literal — walk
530
+ // for uses + nested sites; no static root segment.
531
+ this.walkValue(cur, acc);
532
+ }
533
+ // The INNERMOST access (`a.b` in `a.b.c()`) is a value-position member read;
534
+ // the trailing access (the receiver's own method) is part of the callee path,
535
+ // not a separate read.
536
+ if (rootIdx !== undefined && accesses.length >= 1) {
537
+ acc.addMemberRead(rootIdx, accesses[0]);
538
+ }
539
+ const path = rootSegment !== undefined && accesses.every((a) => a !== '')
540
+ ? [rootSegment, ...accesses].join('.')
541
+ : undefined;
542
+ return { rootIdx, path };
543
+ }
544
+ /** Dotted callee path `prefix.method` (or undefined when the prefix is opaque). */
545
+ calleePath(prefix, method) {
546
+ const m = method?.text;
547
+ if (m === undefined || m.length === 0)
548
+ return undefined;
549
+ if (prefix === undefined)
550
+ return undefined;
551
+ return `${prefix}.${m}`;
552
+ }
553
+ /**
554
+ * Walk an `argument_list`, tagging each positional / keyword / splat argument's
555
+ * occurrence position. A `pair` (`k: v`) records only the VALUE occurrence (the
556
+ * `hash_key_symbol` key is not a use). A `splat_argument` (`*xs`) /
557
+ * `hash_splat_argument` (`**kw`) marks the first spread position so the matcher
558
+ * degrades soundly; its inner value still walks. A `block_argument` (`&blk`)
559
+ * passes a block — its inner value is a use occurrence.
560
+ */
561
+ walkArguments(args, siteIdx, acc) {
562
+ let pos = 0;
563
+ for (let i = 0; i < args.namedChildCount; i++) {
564
+ const arg = args.namedChild(i);
565
+ if (!arg || arg.type === 'comment')
566
+ continue;
567
+ acc.setFrameArg(pos);
568
+ if (arg.type === 'splat_argument' || arg.type === 'hash_splat_argument') {
569
+ acc.setSiteSpread(siteIdx, pos);
570
+ const inner = arg.namedChild(0);
571
+ if (inner)
572
+ this.walkValue(inner, acc);
573
+ }
574
+ else if (arg.type === 'pair') {
575
+ // `k: v` — only the value is an occurrence; the symbol key is not a use.
576
+ const value = arg.childForFieldName('value') ?? arg.namedChild(arg.namedChildCount - 1);
577
+ if (value)
578
+ this.walkValue(value, acc);
579
+ }
580
+ else {
581
+ // Positional arg, `block_argument` (`&blk`), or a nested expression.
582
+ this.walkValue(arg, acc);
583
+ }
584
+ pos++;
585
+ }
586
+ }
587
+ }