gitnexus 1.6.8-rc.8 → 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 (439) 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 +23 -2
  135. package/dist/core/ingestion/languages/c-cpp.js +17 -5
  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 +8 -1
  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 +44 -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/clone-safety.d.ts +109 -0
  238. package/dist/core/ingestion/workers/clone-safety.js +465 -0
  239. package/dist/core/ingestion/workers/parse-worker.d.ts +23 -0
  240. package/dist/core/ingestion/workers/parse-worker.js +81 -53
  241. package/dist/core/ingestion/workers/post-result.d.ts +22 -0
  242. package/dist/core/ingestion/workers/post-result.js +87 -0
  243. package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
  244. package/dist/core/ingestion/workers/result-merge.js +43 -0
  245. package/dist/core/ingestion/workers/worker-pool.d.ts +15 -40
  246. package/dist/core/ingestion/workers/worker-pool.js +43 -16
  247. package/dist/core/lbug/csv-generator.d.ts +51 -3
  248. package/dist/core/lbug/csv-generator.js +369 -255
  249. package/dist/core/lbug/lbug-adapter.d.ts +58 -18
  250. package/dist/core/lbug/lbug-adapter.js +346 -84
  251. package/dist/core/lbug/lbug-config.d.ts +19 -0
  252. package/dist/core/lbug/lbug-config.js +29 -0
  253. package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
  254. package/dist/core/lbug/pdg-emit-sink.js +358 -0
  255. package/dist/core/lbug/pool-adapter.d.ts +35 -0
  256. package/dist/core/lbug/pool-adapter.js +90 -1
  257. package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
  258. package/dist/core/lbug/rel-pair-routing.js +140 -0
  259. package/dist/core/lbug/schema.d.ts +2 -2
  260. package/dist/core/lbug/schema.js +3 -0
  261. package/dist/core/logger.d.ts +0 -5
  262. package/dist/core/run-analyze.d.ts +96 -0
  263. package/dist/core/run-analyze.js +207 -3
  264. package/dist/core/tree-sitter/parser-loader.js +5 -4
  265. package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
  266. package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
  267. package/dist/core/tree-sitter/vendored-grammars.js +57 -0
  268. package/dist/core/wiki/generator.js +3 -1
  269. package/dist/core/wiki/graph-queries.d.ts +6 -0
  270. package/dist/core/wiki/graph-queries.js +9 -1
  271. package/dist/mcp/http-transport.d.ts +134 -0
  272. package/dist/mcp/http-transport.js +503 -0
  273. package/dist/mcp/local/local-backend.d.ts +110 -24
  274. package/dist/mcp/local/local-backend.js +1225 -19
  275. package/dist/mcp/local/pdg-impact.d.ts +384 -0
  276. package/dist/mcp/local/pdg-impact.js +1972 -0
  277. package/dist/mcp/resources.js +13 -1
  278. package/dist/mcp/tools.d.ts +12 -0
  279. package/dist/mcp/tools.js +214 -7
  280. package/dist/server/analyze-launch.d.ts +29 -0
  281. package/dist/server/analyze-launch.js +137 -0
  282. package/dist/server/analyze-upload.d.ts +33 -0
  283. package/dist/server/analyze-upload.js +123 -0
  284. package/dist/server/analyze-worker-ipc.d.ts +58 -0
  285. package/dist/server/analyze-worker-ipc.js +16 -0
  286. package/dist/server/analyze-worker.d.ts +17 -1
  287. package/dist/server/analyze-worker.js +7 -1
  288. package/dist/server/api.d.ts +17 -0
  289. package/dist/server/api.js +132 -168
  290. package/dist/server/git-clone.d.ts +43 -2
  291. package/dist/server/git-clone.js +211 -16
  292. package/dist/server/mcp-http.d.ts +5 -6
  293. package/dist/server/mcp-http.js +9 -82
  294. package/dist/server/middleware.d.ts +40 -0
  295. package/dist/server/middleware.js +92 -0
  296. package/dist/server/private-ip.d.ts +1 -0
  297. package/dist/server/private-ip.js +15 -0
  298. package/dist/server/upload-ingest.d.ts +56 -0
  299. package/dist/server/upload-ingest.js +276 -0
  300. package/dist/server/upload-paths.d.ts +37 -0
  301. package/dist/server/upload-paths.js +57 -0
  302. package/dist/server/upload-sweep.d.ts +20 -0
  303. package/dist/server/upload-sweep.js +57 -0
  304. package/dist/storage/git.js +5 -8
  305. package/dist/storage/parse-cache.d.ts +22 -1
  306. package/dist/storage/parse-cache.js +44 -10
  307. package/dist/storage/repo-manager.d.ts +121 -10
  308. package/dist/storage/repo-manager.js +43 -5
  309. package/dist/types/pipeline.d.ts +9 -0
  310. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
  311. package/hooks/claude/gitnexus-hook.cjs +110 -13
  312. package/hooks/claude/hook-db-lock-probe.cjs +513 -26
  313. package/package.json +8 -2
  314. package/scripts/assert-publish-grammar-coverage.cjs +31 -0
  315. package/scripts/build-tree-sitter-grammars.cjs +16 -10
  316. package/scripts/cross-platform-tests.ts +1 -0
  317. package/skills/gitnexus-debugging.md +16 -4
  318. package/skills/gitnexus-exploring.md +3 -3
  319. package/skills/gitnexus-guide.md +33 -0
  320. package/skills/gitnexus-pdg-query.md +89 -0
  321. package/skills/gitnexus-refactoring.md +1 -1
  322. package/skills/gitnexus-taint-analysis.md +178 -0
  323. package/vendor/tree-sitter-c/package.json +1 -1
  324. package/vendor/tree-sitter-dart/package.json +1 -1
  325. package/vendor/tree-sitter-kotlin/package.json +1 -1
  326. package/vendor/tree-sitter-proto/package.json +1 -1
  327. package/vendor/tree-sitter-swift/package.json +1 -1
  328. package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
  329. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
  330. package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
  331. package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
  332. package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
  333. package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
  334. package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
  335. package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
  336. package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
  337. package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
  338. package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
  339. package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
  340. package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
  341. package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
  342. package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
  343. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
  344. package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
  345. package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
  346. package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
  347. package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
  348. package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
  349. package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
  350. package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
  351. package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
  352. package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
  353. package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
  354. package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
  355. package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
  356. package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
  357. package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
  358. package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
  359. package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
  360. package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
  361. package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
  362. package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
  363. package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
  364. package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
  365. package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
  366. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
  367. package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
  368. package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
  369. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
  370. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
  371. package/web/assets/index-BvYev1UJ.js +635 -0
  372. package/web/assets/index-_lgn7hs5.css +2 -0
  373. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
  374. package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
  375. package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
  376. package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
  377. package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
  378. package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
  379. package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
  380. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
  381. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
  382. package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
  383. package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
  384. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
  385. package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
  386. package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
  387. package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
  388. package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
  389. package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
  390. package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
  391. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
  392. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
  393. package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
  394. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
  395. package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
  396. package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
  397. package/web/index.html +13 -15
  398. package/scripts/materialize-vendor-grammars.cjs +0 -97
  399. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
  400. package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
  401. package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
  402. package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
  403. package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
  404. package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
  405. package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
  406. package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
  407. package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
  408. package/web/assets/chunk-CilyBKbf.js +0 -1
  409. package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
  410. package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
  411. package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
  412. package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
  413. package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
  414. package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
  415. package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
  416. package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
  417. package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
  418. package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
  419. package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
  420. package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
  421. package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
  422. package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
  423. package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
  424. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
  425. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
  426. package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
  427. package/web/assets/index-BKWA-m7o.css +0 -2
  428. package/web/assets/index-CG6q8eTs.js +0 -626
  429. package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
  430. package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
  431. package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
  432. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
  433. package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
  434. package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
  435. package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
  436. package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
  437. package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
  438. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
  439. /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
@@ -0,0 +1,870 @@
1
+ import { CallSiteFactAccumulator as FactAccumulator } from './call-site-harvest.js';
2
+ /** Selector inners that are a `.name` / `?.name` member access (not a call). */
3
+ const ASSIGNABLE_SELECTOR_TYPES = new Set([
4
+ 'unconditional_assignable_selector',
5
+ 'conditional_assignable_selector',
6
+ ]);
7
+ /** Node types that own a nested CFG — their subtrees are opaque to harvesting. */
8
+ const NESTED_FUNCTION_TYPES = new Set(['function_expression', 'function_body']);
9
+ const COMMENT_TYPES = new Set(['comment', 'documentation_comment']);
10
+ const FUNCTION_VALUE_TYPES = new Set(['function_expression']);
11
+ export class DartHarvester {
12
+ fnNode;
13
+ signature;
14
+ bindings = [];
15
+ /** Single function-scope name → binding index (v1: no block scope). */
16
+ table = new Map();
17
+ synthetic = new Map();
18
+ fnId;
19
+ /** >0 while walking a conditionally-evaluated subexpression — defs become may-defs. */
20
+ conditionalDepth = 0;
21
+ /**
22
+ * Chain-head / `new_expression` node id → binding indices its single-target
23
+ * result is assigned to (`var x = f()` / `x = g()` ⇒ `[x]`). Populated just
24
+ * before the value walk reaches the call (see {@link registerResultDefs}) and
25
+ * consumed by {@link visitChainCall} / {@link visitNew}. Mirrors the Python /
26
+ * Go harvesters' `resultDefTargets`.
27
+ */
28
+ resultDefTargets = new Map();
29
+ /**
30
+ * @param fnNode The function-bearing node: a `function_body` (whose previous
31
+ * sibling is the signature carrying the params) or a `function_expression`
32
+ * (a closure, carrying its own `parameters`).
33
+ * @param signature The previous-sibling signature for a `function_body`, or
34
+ * undefined for a `function_expression` (which carries params directly).
35
+ */
36
+ constructor(fnNode, signature) {
37
+ this.fnNode = fnNode;
38
+ this.signature = signature;
39
+ this.fnId = fnNode.id;
40
+ this.declareParams();
41
+ const body = this.bodyOf(fnNode);
42
+ if (body)
43
+ this.prescan(body);
44
+ }
45
+ /** The completed binding table — pass to `CfgBuilder.finish`. */
46
+ bindingTable() {
47
+ return this.bindings;
48
+ }
49
+ /** The body subtree to pre-scan: a `function_body`'s `block`/expr, or a closure's body. */
50
+ bodyOf(fnNode) {
51
+ if (fnNode.type === 'function_expression') {
52
+ return fnNode.childForFieldName('body') ?? undefined;
53
+ }
54
+ // `function_body` — its child `block` or arrow expression.
55
+ return fnNode.namedChildren.find((c) => !COMMENT_TYPES.has(c.type));
56
+ }
57
+ // ── parameters ────────────────────────────────────────────────────────────
58
+ /** The `formal_parameter_list` owning this function's params. */
59
+ paramList() {
60
+ if (this.fnNode.type === 'function_expression') {
61
+ return this.fnNode.childForFieldName('parameters') ?? undefined;
62
+ }
63
+ if (!this.signature)
64
+ return undefined;
65
+ // A `method_signature` wraps a `function_signature` / getter / setter that
66
+ // carries the actual `formal_parameter_list`; unwrap one level first.
67
+ let sig = this.signature;
68
+ if (sig.type === 'method_signature') {
69
+ const inner = sig.namedChildren.find((c) => c.type === 'function_signature' ||
70
+ c.type === 'setter_signature' ||
71
+ c.type === 'getter_signature' ||
72
+ c.type === 'constructor_signature' ||
73
+ c.type === 'factory_constructor_signature');
74
+ if (inner)
75
+ sig = inner;
76
+ }
77
+ return sig.namedChildren.find((c) => c.type === 'formal_parameter_list');
78
+ }
79
+ /** Every `formal_parameter`'s bound name node. */
80
+ paramNames() {
81
+ const list = this.paramList();
82
+ if (!list)
83
+ return [];
84
+ const names = [];
85
+ for (const p of list.namedChildren) {
86
+ if (p.type !== 'formal_parameter')
87
+ continue;
88
+ const name = p.childForFieldName('name') ?? p.namedChildren.find((c) => c.type === 'identifier');
89
+ if (name)
90
+ names.push(name);
91
+ }
92
+ return names;
93
+ }
94
+ // ── phase 1: declaration pre-scan ────────────────────────────────────────
95
+ declare(nameNode, kind) {
96
+ const name = nameNode.text;
97
+ if (!name || name === '_' || this.table.has(name))
98
+ return;
99
+ this.table.set(name, this.bindings.length);
100
+ this.bindings.push({
101
+ name,
102
+ declLine: nameNode.startPosition.row + 1,
103
+ declColumn: nameNode.startPosition.column,
104
+ kind,
105
+ });
106
+ }
107
+ declareParams() {
108
+ for (const name of this.paramNames())
109
+ this.declare(name, 'param');
110
+ }
111
+ /**
112
+ * Pre-scan the function body once, declaring every bound name. Recurses into
113
+ * compound expressions but NOT into nested function/closure bodies (opaque).
114
+ */
115
+ prescan(node) {
116
+ const t = node.type;
117
+ if (FUNCTION_VALUE_TYPES.has(t) && node.id !== this.fnId)
118
+ return;
119
+ switch (t) {
120
+ case 'initialized_variable_definition':
121
+ this.declareInitializedVar(node, 'let');
122
+ break;
123
+ case 'for_loop_parts':
124
+ this.declareForParts(node);
125
+ break;
126
+ case 'catch_parameters':
127
+ this.declareCatchParams(node);
128
+ break;
129
+ default:
130
+ break;
131
+ }
132
+ for (let i = 0; i < node.namedChildCount; i++) {
133
+ const c = node.namedChild(i);
134
+ if (c)
135
+ this.prescan(c);
136
+ }
137
+ }
138
+ /** Declare every name of an `initialized_variable_definition` (`var a = 1, b = 2`). */
139
+ declareInitializedVar(node, kind) {
140
+ const name = node.childForFieldName('name');
141
+ if (name)
142
+ this.declare(name, kind);
143
+ // Trailing comma-separated bindings: each `initialized_identifier` (`b = 2`)
144
+ // names another local that the `name` field alone misses.
145
+ for (let i = 0; i < node.namedChildCount; i++) {
146
+ const c = node.namedChild(i);
147
+ if (c?.type !== 'initialized_identifier')
148
+ continue;
149
+ const id = c.namedChildren.find((g) => g.type === 'identifier');
150
+ if (id)
151
+ this.declare(id, kind);
152
+ }
153
+ }
154
+ /**
155
+ * Declare a `for`'s loop variable: a C-style `init:local_variable_declaration`
156
+ * is handled by its own `initialized_variable_definition` recursion; a for-in
157
+ * binds the `name:identifier` after the optional `inferred_type`/type. A for-in
158
+ * over an existing variable (`for (e in xs)`) has no declaration — its bare
159
+ * `identifier` is a use (an assignment target), not a new binding.
160
+ */
161
+ declareForParts(node) {
162
+ // for-in declares the loop var only when a binder keyword/type precedes it.
163
+ if (!this.isForIn(node))
164
+ return;
165
+ if (!this.forInDeclares(node))
166
+ return;
167
+ const name = node.childForFieldName('name');
168
+ if (name)
169
+ this.declare(name, 'let');
170
+ }
171
+ /** A `for_loop_parts` is for-in iff it has an `in` keyword child + a `value` field. */
172
+ isForIn(node) {
173
+ return node.children.some((c) => c.type === 'in');
174
+ }
175
+ /** A for-in declares a fresh loop var iff a binder keyword/type precedes the name. */
176
+ forInDeclares(node) {
177
+ return node.namedChildren.some((c) => c.type === 'inferred_type' ||
178
+ c.type === 'final_builtin' ||
179
+ c.type === 'type_identifier' ||
180
+ c.type === 'void_type');
181
+ }
182
+ /** Declare a `catch (e[, st])` error name(s). */
183
+ declareCatchParams(node) {
184
+ for (const id of node.namedChildren) {
185
+ if (id.type === 'identifier')
186
+ this.declare(id, 'catch');
187
+ }
188
+ }
189
+ // ── phase 2: per-statement fact extraction ───────────────────────────────
190
+ /** Def/use facts for one statement (or construct-header expression) node. */
191
+ facts(node) {
192
+ const acc = new FactAccumulator(node.startPosition.row + 1);
193
+ this.walkValue(node, acc);
194
+ return acc.finish();
195
+ }
196
+ /** Facts for an expression whose WHOLE evaluation is conditional (case tests). */
197
+ factsConditional(node) {
198
+ const acc = new FactAccumulator(node.startPosition.row + 1);
199
+ this.conditional(() => this.walkValue(node, acc));
200
+ return acc.finish();
201
+ }
202
+ /**
203
+ * Def-ONLY facts for a value-position binding carrier (`var x = switch (…) {…}`,
204
+ * #2207): just the declared name(s)' def, attached to the continuation block the
205
+ * switch arms rejoin. The subject + arm-value USES are already harvested onto
206
+ * the branch's own blocks, so this must NOT re-walk the value — only each
207
+ * `initialized_variable_definition`'s `name` (and trailing binders) is a def.
208
+ */
209
+ bindingDefFacts(stmt) {
210
+ const acc = new FactAccumulator(stmt.startPosition.row + 1);
211
+ for (const def of stmt.namedChildren) {
212
+ if (def.type !== 'initialized_variable_definition')
213
+ continue;
214
+ const name = def.childForFieldName('name');
215
+ if (name)
216
+ this.def(name, acc);
217
+ for (let i = 0; i < def.namedChildCount; i++) {
218
+ const c = def.namedChild(i);
219
+ if (c?.type !== 'initialized_identifier')
220
+ continue;
221
+ const id = c.namedChildren.find((g) => g.type === 'identifier');
222
+ if (id)
223
+ this.def(id, acc);
224
+ }
225
+ }
226
+ return acc.defCount() ? acc.finish() : undefined;
227
+ }
228
+ /**
229
+ * Facts for a `for` head. For-in: the loop var name is a def, the collection a
230
+ * use. C-style: the init/condition/update sub-expressions are walked for
231
+ * defs/uses (the init `local_variable_declaration` defines, the condition reads,
232
+ * the update def-and-uses).
233
+ */
234
+ forHeadFacts(parts) {
235
+ const line = (parts ?? this.fnNode).startPosition.row + 1;
236
+ const acc = new FactAccumulator(line);
237
+ if (!parts)
238
+ return undefined;
239
+ if (this.isForIn(parts)) {
240
+ const value = parts.childForFieldName('value');
241
+ if (value)
242
+ this.walkValue(value, acc);
243
+ // The loop var: a fresh `for (var e in xs)` binder is a def; a
244
+ // `for (e in xs)` over an existing var also writes it each iteration (a
245
+ // def). Either way the `name:identifier` is a def of the loop variable.
246
+ const name = parts.childForFieldName('name');
247
+ if (name)
248
+ this.def(name, acc);
249
+ }
250
+ else {
251
+ // C-style: walk init / condition / update.
252
+ const init = parts.childForFieldName('init');
253
+ const cond = parts.childForFieldName('condition');
254
+ const update = parts.childForFieldName('update');
255
+ if (init)
256
+ this.walkValue(init, acc);
257
+ if (cond)
258
+ this.walkValue(cond, acc);
259
+ if (update)
260
+ this.walkValue(update, acc);
261
+ }
262
+ return acc.finish();
263
+ }
264
+ /** ENTRY-block facts for the parameters (defs only). */
265
+ paramFacts() {
266
+ const acc = new FactAccumulator(this.fnNode.startPosition.row + 1);
267
+ for (const name of this.paramNames())
268
+ this.def(name, acc);
269
+ return acc.defCount() ? acc.finish() : undefined;
270
+ }
271
+ /** Def fact(s) for a `catch (e[, st])` — prepend to the handler entry block. */
272
+ catchParamFacts(catchParams) {
273
+ if (!catchParams)
274
+ return undefined;
275
+ const acc = new FactAccumulator(catchParams.startPosition.row + 1);
276
+ for (const id of catchParams.namedChildren) {
277
+ if (id.type === 'identifier')
278
+ this.def(id, acc);
279
+ }
280
+ return acc.defCount() ? acc.finish() : undefined;
281
+ }
282
+ resolve(nameNode) {
283
+ const name = nameNode.text;
284
+ const idx = this.table.get(name);
285
+ if (idx !== undefined)
286
+ return idx;
287
+ let syn = this.synthetic.get(name);
288
+ if (syn === undefined) {
289
+ syn = this.bindings.length;
290
+ this.synthetic.set(name, syn);
291
+ this.bindings.push({ name, declLine: 0, declColumn: 0, kind: 'module', synthetic: true });
292
+ }
293
+ return syn;
294
+ }
295
+ def(nameNode, acc) {
296
+ if (nameNode.text === '_')
297
+ return; // blank target defines nothing
298
+ if (this.conditionalDepth > 0)
299
+ acc.addMayDef(this.resolve(nameNode));
300
+ else
301
+ acc.addDef(this.resolve(nameNode));
302
+ }
303
+ use(nameNode, acc) {
304
+ if (nameNode.text === '_')
305
+ return;
306
+ acc.addUse(this.resolve(nameNode));
307
+ }
308
+ /** Run `fn` with defs demoted to may-defs (conditionally-evaluated context). */
309
+ conditional(fn) {
310
+ this.conditionalDepth++;
311
+ try {
312
+ fn();
313
+ }
314
+ finally {
315
+ this.conditionalDepth--;
316
+ }
317
+ }
318
+ /** Value-position walk: collect uses; route def positions to the pattern handler. */
319
+ walkValue(node, acc) {
320
+ const t = node.type;
321
+ if (FUNCTION_VALUE_TYPES.has(t) && node.id !== this.fnId)
322
+ return; // opaque closure
323
+ switch (t) {
324
+ case 'identifier':
325
+ this.use(node, acc);
326
+ return;
327
+ case 'initialized_variable_definition': {
328
+ const name = node.childForFieldName('name');
329
+ // The `value` field can REPEAT across a Dart postfix run (`= g` `(y)`):
330
+ // collect every `value`-tagged child as one chain and walk them together
331
+ // so a member/free call across the run is harvested as one site.
332
+ const valueRun = this.fieldRun(node, 'value');
333
+ // Register result-defs BEFORE the value walk so the call the value walk
334
+ // reaches carries them — single identifier target only (`var x = f()`);
335
+ // a trailing comma-separated `b = 2` declarator attaches nothing.
336
+ if (name && valueRun.length > 0)
337
+ this.registerRunResultDefs(valueRun, [name]);
338
+ if (valueRun.length > 0)
339
+ this.walkRun(valueRun, acc);
340
+ if (name)
341
+ this.def(name, acc);
342
+ // Trailing comma-separated bindings (`var a = 1, b = 2;`): each
343
+ // `initialized_identifier` is an `identifier` + its own value expr.
344
+ for (let i = 0; i < node.namedChildCount; i++) {
345
+ const c = node.namedChild(i);
346
+ if (c?.type !== 'initialized_identifier')
347
+ continue;
348
+ const id = c.namedChildren.find((g) => g.type === 'identifier');
349
+ const val = c.namedChildren.find((g) => g.type !== 'identifier');
350
+ if (val)
351
+ this.walkValue(val, acc);
352
+ if (id)
353
+ this.def(id, acc);
354
+ }
355
+ return;
356
+ }
357
+ case 'assignment_expression': {
358
+ const lvalue = node.childForFieldName('left');
359
+ const op = node.childForFieldName('operator');
360
+ // The `right` field can REPEAT across a postfix run (`= obj` `.m` `(y)`):
361
+ // collect every `right`-tagged child and group the run so a call across
362
+ // it is one site.
363
+ const rhs = this.fieldRun(node, 'right');
364
+ const scalar = lvalue ? this.scalarAssignTarget(lvalue) : undefined;
365
+ // A plain `x = <call>` attaches `resultDefs: [x]` (compound `+=` does not —
366
+ // the prior value flows in too).
367
+ if (scalar && op?.text === '=' && rhs.length > 0) {
368
+ this.registerRunResultDefs(rhs, [scalar]);
369
+ }
370
+ if (rhs.length > 0)
371
+ this.walkRun(rhs, acc);
372
+ if (lvalue) {
373
+ if (scalar) {
374
+ this.def(scalar, acc);
375
+ if (op && op.text !== '=')
376
+ this.use(scalar, acc); // compound assign reads too
377
+ }
378
+ else {
379
+ // `this.x = …`, `a[i] = …` — a member / subscript write is NOT a
380
+ // scalar def; walk the lvalue so its root identifier is a use.
381
+ this.walkValue(lvalue, acc);
382
+ }
383
+ }
384
+ return;
385
+ }
386
+ case 'postfix_expression':
387
+ case 'unary_expression': {
388
+ // `i++` (`postfix_expression`) / `++i` (`unary_expression` with an
389
+ // `increment_operator`) — the assignable operand is def-and-use. A
390
+ // `unary_expression` with no `increment_operator` (`!x`, `-x`, `await e`)
391
+ // is a pure read and falls through to the generic walk below.
392
+ const isUpdate = t === 'postfix_expression' ||
393
+ node.namedChildren.some((c) => c.type === 'increment_operator');
394
+ const operand = isUpdate
395
+ ? node.namedChildren.find((c) => c.type === 'assignable_expression')
396
+ : undefined;
397
+ if (operand) {
398
+ const scalar = this.scalarAssignTarget(operand);
399
+ if (scalar) {
400
+ this.use(scalar, acc);
401
+ this.def(scalar, acc);
402
+ }
403
+ else {
404
+ // `obj.x++` / `a[i]++` — member/subscript update, not a scalar def.
405
+ this.walkValue(operand, acc);
406
+ }
407
+ }
408
+ else {
409
+ for (let i = 0; i < node.namedChildCount; i++) {
410
+ const c = node.namedChild(i);
411
+ if (c)
412
+ this.walkValue(c, acc);
413
+ }
414
+ }
415
+ return;
416
+ }
417
+ case 'selector': {
418
+ // FALLBACK: a `selector` reached OUTSIDE a postfix run (normal chains are
419
+ // grouped + harvested by `walkChildren`/`walkRun`). `.name` / `(...args)`
420
+ // — a member-access suffix name is not a scalar binding; walk the argument
421
+ // part for uses but skip the bare property id. No site is emitted here.
422
+ for (const c of node.namedChildren) {
423
+ if (c.type === 'unconditional_assignable_selector' ||
424
+ c.type === 'conditional_assignable_selector') {
425
+ continue; // `.name` — property name is not a use
426
+ }
427
+ this.walkValue(c, acc);
428
+ }
429
+ return;
430
+ }
431
+ case 'logical_and_expression':
432
+ case 'logical_or_expression':
433
+ // `a && b` / `a || b` — the right operand is conditionally evaluated. The
434
+ // operand may be a flattened postfix run (`a && g(x)` ⇒ `a`, `g`,
435
+ // `selector`), so group runs and demote everything after the operator.
436
+ this.walkBinaryConditional(node, acc, new Set(['&&', '||']));
437
+ return;
438
+ case 'if_null_expression':
439
+ // `a ?? b` — the right operand only evaluates when the left is null.
440
+ this.walkBinaryConditional(node, acc, new Set(['??']));
441
+ return;
442
+ case 'conditional_expression':
443
+ // `c ? a : b` — the condition runs always; both arms are conditional.
444
+ this.walkBinaryConditional(node, acc, new Set(['?', ':']));
445
+ return;
446
+ case 'switch_expression': {
447
+ // `switch (x) { p1 => a, p2 => b }` (Dart 3): the subject runs always;
448
+ // each arm (pattern + value) is conditional, so a def inside an arm value
449
+ // (`z = 1`) is a MAY-def, not an unconditional KILL of the prior `z`
450
+ // (#2206). Mirrors conditional_expression.
451
+ const subject = node.childForFieldName('condition');
452
+ if (subject)
453
+ this.walkValue(subject, acc);
454
+ for (const c of node.namedChildren) {
455
+ if (c.type === 'switch_expression_case') {
456
+ this.conditional(() => this.walkValue(c, acc));
457
+ }
458
+ }
459
+ return;
460
+ }
461
+ case 'new_expression':
462
+ // `new Foo(args)` — the only single-node call shape Dart has. Constructor
463
+ // site (`kind: 'new'`).
464
+ this.visitNew(node, acc);
465
+ return;
466
+ case 'inferred_type':
467
+ case 'final_builtin':
468
+ case 'type_identifier':
469
+ case 'void_type':
470
+ // Binding keyword / type position — no scalar value uses.
471
+ return;
472
+ default:
473
+ // A container (`expression_statement`, `argument`, `await_expression`,
474
+ // `cascade_section`'s parent, …) whose children may form Dart postfix
475
+ // call/access RUNS (`identifier` + `selector*`). Group runs so a call is
476
+ // harvested as one site; non-run children walk normally.
477
+ this.walkChildren(node.namedChildren, acc);
478
+ }
479
+ }
480
+ // ── Dart postfix call/access chains (#2227 follow-up) ─────────────────────
481
+ /**
482
+ * Walk a container's named children, coalescing each Dart postfix RUN — a
483
+ * chain HEAD immediately followed by one or more `selector` (and/or a
484
+ * `cascade_section`) siblings — into a single {@link walkRun} so a member /
485
+ * free call across the run is harvested as ONE call site. A child that does
486
+ * not start a run walks via {@link walkValue} as before.
487
+ */
488
+ walkChildren(children, acc) {
489
+ const named = children.filter((c) => !COMMENT_TYPES.has(c.type));
490
+ let i = 0;
491
+ while (i < named.length) {
492
+ const head = named[i];
493
+ // A run continues over immediately-following `selector` / `cascade_section`
494
+ // siblings (the postfix suffixes applied to `head`).
495
+ let end = i + 1;
496
+ while (end < named.length && this.isSuffix(named[end]))
497
+ end++;
498
+ if (end > i + 1) {
499
+ this.walkRun(named.slice(i, end), acc);
500
+ }
501
+ else {
502
+ this.walkValue(head, acc);
503
+ }
504
+ i = end;
505
+ }
506
+ }
507
+ /** A postfix-run suffix node: a `.name`/`(args)` `selector` or a `..m()` cascade. */
508
+ isSuffix(node) {
509
+ return node.type === 'selector' || node.type === 'cascade_section';
510
+ }
511
+ /**
512
+ * Walk a binary / ternary expression whose operands are FLATTENED across the
513
+ * node's children (`a ?? g(x)` ⇒ children `a`, `??`, `g`, `selector`). The
514
+ * children before the FIRST boundary operator (`boundaries`) run
515
+ * unconditionally; everything after a boundary is conditionally evaluated (a
516
+ * may-def context). Each segment is grouped via {@link walkChildren} so a
517
+ * postfix call split across children (`g` + `selector`) is one site.
518
+ */
519
+ walkBinaryConditional(node, acc, boundaries) {
520
+ const segments = [[]];
521
+ for (let i = 0; i < node.childCount; i++) {
522
+ const c = node.child(i);
523
+ if (!c || COMMENT_TYPES.has(c.type))
524
+ continue;
525
+ if (!c.isNamed && boundaries.has(c.text)) {
526
+ segments.push([]);
527
+ continue;
528
+ }
529
+ if (c.isNamed)
530
+ segments[segments.length - 1].push(c);
531
+ }
532
+ // First segment unconditional; the rest are conditional arms / right operands.
533
+ if (segments[0].length > 0)
534
+ this.walkChildren(segments[0], acc);
535
+ for (let i = 1; i < segments.length; i++) {
536
+ const seg = segments[i];
537
+ if (seg.length > 0)
538
+ this.conditional(() => this.walkChildren(seg, acc));
539
+ }
540
+ }
541
+ /**
542
+ * Walk one postfix run `[head, suffix*]`. A lone node (no suffixes) is just a
543
+ * value walk. A run with suffixes is a Dart call/access chain: each `selector`
544
+ * whose inner is an `argument_part` is a call applied to the prefix; an
545
+ * assignable `.name`/`?.name` selector is a member access; a `cascade_section`
546
+ * with an `argument_part` is a free call on its method name.
547
+ */
548
+ walkRun(run, acc) {
549
+ if (run.length === 1) {
550
+ this.walkValue(run[0], acc);
551
+ return;
552
+ }
553
+ const head = run[0];
554
+ const suffixes = run.slice(1);
555
+ const hasCascade = suffixes.some((s) => s.type === 'cascade_section');
556
+ // A cascade target (`a..m()`) is read once; its cascade calls are FREE calls
557
+ // on the method name (matching the scope-extractor's cascade classification).
558
+ if (hasCascade) {
559
+ this.walkValue(head, acc);
560
+ for (const s of suffixes) {
561
+ if (s.type === 'cascade_section')
562
+ this.visitCascade(s, acc);
563
+ else
564
+ this.walkValue(s, acc);
565
+ }
566
+ return;
567
+ }
568
+ // Plain postfix chain: walk left→right, opening a call site at each
569
+ // `selector(argument_part)`. The callee path / receiver come from the prefix.
570
+ // Only the LAST call in the run receives the binding result (`var x =
571
+ // a.b().c()` ⇒ x is `.c()`'s result, not `.b()`'s).
572
+ const lastCallIdx = this.lastCallSelectorIndex(run);
573
+ let chainStartUseRecorded = false;
574
+ let rootIdx;
575
+ let rootSegment;
576
+ const accesses = []; // dotted member segments since the last call
577
+ for (let i = 0; i < run.length; i++) {
578
+ const node = run[i];
579
+ if (node === head) {
580
+ const resolvedHead = this.chainHead(head);
581
+ if (resolvedHead) {
582
+ rootIdx = this.resolve(resolvedHead);
583
+ rootSegment = resolvedHead.text;
584
+ }
585
+ else {
586
+ // A non-identifier head (parenthesized expr, literal) — walk it for
587
+ // uses; it has no static root segment.
588
+ this.walkValue(head, acc);
589
+ }
590
+ continue;
591
+ }
592
+ // node is a `selector`.
593
+ const inner = node.namedChild(0);
594
+ if (inner?.type === 'argument_part') {
595
+ // Call marker — `prefix(args)`. Record the chain root use (once). For a
596
+ // FREE call the head IS the callee NAME — a statement-level use but NOT a
597
+ // value occurrence in any enclosing argument (`exec(escape(x))` must not
598
+ // put `escape` into exec's arg 0). For a MEMBER call the head is the
599
+ // RECEIVER (a real value that launders taint) — a normal occurrence use.
600
+ if (rootIdx !== undefined && !chainStartUseRecorded) {
601
+ if (accesses.length === 0)
602
+ acc.addUseWithoutOccurrence(rootIdx);
603
+ else
604
+ acc.addUse(rootIdx);
605
+ chainStartUseRecorded = true;
606
+ }
607
+ // The accesses since the last call form the callee tail; the FINAL access
608
+ // IS the callee (carried by the path, `skipFinalRead`), but an inner
609
+ // access is a member READ — `a.b.c()` reads `a.b` then calls `.c` (mirror
610
+ // the Go / Python `walkChain` innermost member-read). A single access
611
+ // (`obj.method()`) is just the callee — no read.
612
+ if (rootIdx !== undefined && accesses.length >= 2) {
613
+ acc.addMemberRead(rootIdx, accesses[0]);
614
+ }
615
+ const anchor = this.callAnchor(run, i, head);
616
+ this.visitChainCall(node, inner, acc, {
617
+ rootIdx,
618
+ callee: this.calleePath(rootSegment, accesses),
619
+ anchor,
620
+ isMember: accesses.length > 0,
621
+ isLastCall: i === lastCallIdx,
622
+ });
623
+ // After a call the result is opaque — subsequent accesses have no static
624
+ // root (the call return value), so drop the path.
625
+ accesses.length = 0;
626
+ rootSegment = undefined;
627
+ rootIdx = undefined;
628
+ continue;
629
+ }
630
+ if (inner && ASSIGNABLE_SELECTOR_TYPES.has(inner.type)) {
631
+ // `.name` / `?.name` member access — extends the dotted path. A trailing
632
+ // access NOT followed by a call is a value-position member READ (record
633
+ // the root use + at most one member-read site at the innermost access).
634
+ const seg = this.selectorName(inner);
635
+ if (seg)
636
+ accesses.push(seg.text);
637
+ const isLastAndNotCall = i === run.length - 1;
638
+ if (isLastAndNotCall && rootIdx !== undefined) {
639
+ if (!chainStartUseRecorded) {
640
+ acc.addUse(rootIdx);
641
+ chainStartUseRecorded = true;
642
+ }
643
+ // Innermost access is a member read (`a.b` in `a.b.c` value position).
644
+ if (accesses.length >= 1)
645
+ acc.addMemberRead(rootIdx, accesses[0]);
646
+ }
647
+ continue;
648
+ }
649
+ // An index `[i]` / other selector — walk its inner for uses.
650
+ this.walkValue(node, acc);
651
+ }
652
+ // A chain that ended without any call but had a root (`a.b` as a whole value
653
+ // read) still records its root use even when the access loop didn't (e.g. a
654
+ // single non-call selector run reached here without a call).
655
+ if (rootIdx !== undefined && !chainStartUseRecorded)
656
+ acc.addUse(rootIdx);
657
+ }
658
+ /** The chain root binding node — an `identifier` head (not `this`/`super`/literal). */
659
+ chainHead(head) {
660
+ return head.type === 'identifier' && head.text !== '_' ? head : undefined;
661
+ }
662
+ /** The bound name identifier of an assignable selector inner (`.name` ⇒ `name`). */
663
+ selectorName(inner) {
664
+ for (let i = inner.namedChildCount - 1; i >= 0; i--) {
665
+ const c = inner.namedChild(i);
666
+ if (c?.type === 'identifier')
667
+ return c;
668
+ }
669
+ return undefined;
670
+ }
671
+ /** Dotted callee path `root.a.b` (or undefined when the root is not an identifier). */
672
+ calleePath(rootSegment, accesses) {
673
+ if (rootSegment === undefined)
674
+ return undefined;
675
+ return [rootSegment, ...accesses].join('.');
676
+ }
677
+ /**
678
+ * The `at` anchor for a call `selector` at `run[i]`, byte-aligned with the
679
+ * Dart CALLS `atRange` (see file header): a FREE / implicit-constructor call
680
+ * (the call selector immediately follows the chain head) anchors on the head
681
+ * identifier; a MEMBER call anchors on the method-NAME identifier of the
682
+ * preceding `.method` selector.
683
+ */
684
+ callAnchor(run, i, head) {
685
+ const prev = run[i - 1];
686
+ if (prev && prev.type === 'selector') {
687
+ const inner = prev.namedChild(0);
688
+ const nameId = inner ? this.selectorName(inner) : undefined;
689
+ if (nameId)
690
+ return [nameId.startPosition.row + 1, nameId.startPosition.column];
691
+ }
692
+ // Free / constructor call — anchor on the chain head (the callee identifier).
693
+ return [head.startPosition.row + 1, head.startPosition.column];
694
+ }
695
+ /**
696
+ * Open + populate a call site for a Dart postfix `prefix(args)` call. The
697
+ * callee NAME is a statement-level use (recorded as the chain root above, or
698
+ * here for a bare free call), NOT a value occurrence in any enclosing argument.
699
+ */
700
+ visitChainCall(selector, argPart, acc, info) {
701
+ const siteIdx = acc.openCallSite('call', info.anchor);
702
+ acc.pushFrame(siteIdx);
703
+ if (info.callee !== undefined)
704
+ acc.setSiteCallee(siteIdx, info.callee);
705
+ // A member call (`obj.m(x)`, `a.b.c(x)`) launders taint through its receiver
706
+ // root; a bare free call (`foo(x)`) has no receiver.
707
+ if (info.isMember && info.rootIdx !== undefined)
708
+ acc.setSiteReceiver(siteIdx, info.rootIdx);
709
+ // Only the run's terminal call receives the binding result (its `.parent` is
710
+ // the run's shared `initialized_variable_definition` / `assignment_expression`).
711
+ if (info.isLastCall) {
712
+ const resultDefs = this.resultDefTargets.get(selector.parent?.id ?? -1);
713
+ if (resultDefs !== undefined)
714
+ acc.setSiteResultDefs(siteIdx, resultDefs);
715
+ }
716
+ this.walkArguments(argPart, siteIdx, acc);
717
+ acc.popFrame();
718
+ }
719
+ /** Index in `run` of the LAST call-marker selector (`selector(argument_part)`). */
720
+ lastCallSelectorIndex(run) {
721
+ for (let i = run.length - 1; i >= 0; i--) {
722
+ const n = run[i];
723
+ if (n.type === 'selector' && n.namedChild(0)?.type === 'argument_part')
724
+ return i;
725
+ }
726
+ return -1;
727
+ }
728
+ /** A single `new Foo(args)` constructor site (`kind: 'new'`). */
729
+ visitNew(node, acc) {
730
+ const typeId = node.namedChildren.find((c) => c.type === 'type_identifier');
731
+ const argsNode = node.namedChildren.find((c) => c.type === 'arguments');
732
+ // `new_expression` is NOT captured for CALLS by the Dart scope-resolution, so
733
+ // this `at` finds no resolved id — anchor on the node start for consistency.
734
+ const siteIdx = acc.openCallSite('new', [
735
+ node.startPosition.row + 1,
736
+ node.startPosition.column,
737
+ ]);
738
+ acc.pushFrame(siteIdx);
739
+ if (typeId)
740
+ acc.setSiteCallee(siteIdx, typeId.text); // the type is not a scalar binding
741
+ const resultDefs = this.resultDefTargets.get(node.id);
742
+ if (resultDefs !== undefined)
743
+ acc.setSiteResultDefs(siteIdx, resultDefs);
744
+ if (argsNode)
745
+ this.walkArgumentsNode(argsNode, siteIdx, acc);
746
+ acc.popFrame();
747
+ }
748
+ /** A cascade call `a..method(args)` — a FREE call on the method name. */
749
+ visitCascade(cascade, acc) {
750
+ const cascadeSelector = cascade.namedChildren.find((c) => c.type === 'cascade_selector');
751
+ const argPart = cascade.namedChildren.find((c) => c.type === 'argument_part');
752
+ // A property cascade (`..field = x`, no argument_part) is not a call — walk
753
+ // its non-selector children for uses and stop.
754
+ if (!argPart) {
755
+ for (const c of cascade.namedChildren) {
756
+ if (c.type === 'cascade_selector')
757
+ continue;
758
+ this.walkValue(c, acc);
759
+ }
760
+ return;
761
+ }
762
+ const nameId = cascadeSelector
763
+ ? (this.selectorName(cascadeSelector) ?? cascadeSelector)
764
+ : undefined;
765
+ const anchor = nameId
766
+ ? [nameId.startPosition.row + 1, nameId.startPosition.column]
767
+ : [cascade.startPosition.row + 1, cascade.startPosition.column];
768
+ const siteIdx = acc.openCallSite('call', anchor);
769
+ acc.pushFrame(siteIdx);
770
+ if (nameId)
771
+ acc.setSiteCallee(siteIdx, nameId.text);
772
+ this.walkArguments(argPart, siteIdx, acc);
773
+ acc.popFrame();
774
+ }
775
+ /** Walk a `selector → argument_part → arguments` for per-arg occurrences. */
776
+ walkArguments(argPart, siteIdx, acc) {
777
+ const args = argPart.namedChildren.find((c) => c.type === 'arguments');
778
+ if (args)
779
+ this.walkArgumentsNode(args, siteIdx, acc);
780
+ }
781
+ /** Walk an `arguments` node, tagging each positional / named arg's occurrence position. */
782
+ walkArgumentsNode(args, siteIdx, acc) {
783
+ let pos = 0;
784
+ for (let i = 0; i < args.namedChildCount; i++) {
785
+ const arg = args.namedChild(i);
786
+ if (!arg || COMMENT_TYPES.has(arg.type))
787
+ continue;
788
+ if (arg.type === 'argument' || arg.type === 'named_argument') {
789
+ acc.setFrameArg(pos);
790
+ // The argument value may be a flattened postfix run (`escape(x)` ⇒
791
+ // `escape` + `selector(x)`) — group via `walkChildren` so a NESTED call is
792
+ // its own parent-linked site (the via-tagged sanitizer-interposition
793
+ // substrate). A `named_argument` (`k: v`) records only the VALUE
794
+ // occurrence — the `label` name (`k`) is dropped.
795
+ const valueChildren = arg.namedChildren.filter((c) => c.type !== 'label');
796
+ this.walkChildren(valueChildren, acc);
797
+ pos++;
798
+ }
799
+ else {
800
+ // A spread `...xs` argument variant, if the grammar surfaces one.
801
+ acc.setFrameArg(pos);
802
+ acc.setSiteSpread(siteIdx, pos);
803
+ this.walkValue(arg, acc);
804
+ pos++;
805
+ }
806
+ }
807
+ }
808
+ /**
809
+ * Register result-defs for a single-target binding whose value RUN's terminal
810
+ * call / `new` should carry `[x]`: `var x = f()` / `var x = obj.m()` /
811
+ * `var x = new Foo()` / `x = g(y)`. Keyed so the run's call selector (whose
812
+ * `.parent` is the run's shared parent — the `initialized_variable_definition`
813
+ * or `assignment_expression`) AND a single `new_expression` run-node both hit.
814
+ */
815
+ registerRunResultDefs(run, targets) {
816
+ const defs = [];
817
+ for (const target of targets) {
818
+ if (target.type !== 'identifier' || target.text === '_')
819
+ continue;
820
+ defs.push(this.resolve(target));
821
+ }
822
+ if (defs.length === 0)
823
+ return;
824
+ // A postfix-chain run: its call selector keys on the run's shared parent.
825
+ const parentId = run[0]?.parent?.id;
826
+ if (parentId !== undefined)
827
+ this.resultDefTargets.set(parentId, defs);
828
+ // A single `new Foo(…)` value: `visitNew` keys on the `new_expression` itself.
829
+ if (run.length === 1 && run[0].type === 'new_expression') {
830
+ this.resultDefTargets.set(run[0].id, defs);
831
+ }
832
+ }
833
+ /** The `field`-tagged children of `node` (a Dart postfix run flattens here). */
834
+ fieldRun(node, field) {
835
+ const run = [];
836
+ for (let i = 0; i < node.childCount; i++) {
837
+ const c = node.child(i);
838
+ if (!c || COMMENT_TYPES.has(c.type))
839
+ continue;
840
+ if (node.fieldNameForChild?.(i) === field)
841
+ run.push(c);
842
+ }
843
+ return run;
844
+ }
845
+ /**
846
+ * The bare `identifier` of an `assignable_expression` lvalue WHEN it is a
847
+ * scalar target (`x = …`), or undefined when it is a member / subscript write
848
+ * (`obj.x = …`, `a[i] = …`) — those carry a trailing
849
+ * `unconditional_assignable_selector` / `conditional_assignable_selector` /
850
+ * `index_selector` and are NOT scalar defs (their root identifier is a use).
851
+ */
852
+ scalarAssignTarget(node) {
853
+ // Unwrap nested `assignable_expression` wrappers (defensive).
854
+ let n = node;
855
+ let hops = 4;
856
+ while (n.type === 'assignable_expression' && hops-- > 0) {
857
+ const named = n.namedChildren.filter((c) => !COMMENT_TYPES.has(c.type));
858
+ // A single bare identifier child ⇒ scalar target; any trailing selector ⇒
859
+ // member/subscript write (not scalar).
860
+ if (named.length === 1 && named[0].type === 'identifier')
861
+ return named[0];
862
+ if (named.length === 1 && named[0].type === 'assignable_expression') {
863
+ n = named[0];
864
+ continue;
865
+ }
866
+ return undefined; // identifier + selector(s) — member/subscript write
867
+ }
868
+ return n.type === 'identifier' ? n : undefined;
869
+ }
870
+ }