cgraphx 2.0.2 → 2.0.6

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 (754) hide show
  1. package/dist/.claude-template/FLOW-MAP.md +13 -3
  2. package/dist/.claude-template/agents/task-history.md +186 -0
  3. package/dist/.claude-template/commands/end.md +1 -0
  4. package/dist/.claude-template/skills/cgraphx-guide/SKILL.md +5 -3
  5. package/dist/.claude-template/skills/cgraphx-guide/how-to-use.html +8 -8
  6. package/dist/.claude-template/skills/cgraphx-guide/how-to-use.md +8 -8
  7. package/dist/.claude-template/skills/clarify-requirements/SKILL.md +13 -9
  8. package/dist/.claude-template/skills/db-query/SKILL.md +19 -2
  9. package/dist/.claude-template/skills/iboc-check/SKILL.md +51 -23
  10. package/dist/.claude-template/skills/iboc-check/filler-prompt.md +3 -4
  11. package/dist/.claude-template/skills/run-api-test/SKILL.md +15 -15
  12. package/dist/.claude-template/skills/run-api-test/assets/{template-test-report.md → template-/346/216/245/345/217/243/346/265/213/350/257/225/346/212/245/345/221/212.md} +4 -4
  13. package/dist/.claude-template/skills/run-api-test/references/bru-run.md +1 -1
  14. package/dist/.claude-template/skills/run-api-test/references/db-verification.md +2 -2
  15. package/dist/.claude-template/skills/run-api-test/references/report-format.md +6 -6
  16. package/dist/.claude-template/skills/run-api-test/references/service-readiness.md +1 -1
  17. package/dist/.claude-template/skills/run-api-test/references/test-scope.md +6 -6
  18. package/dist/.claude-template/skills/run-ui-test/SKILL.md +186 -0
  19. package/dist/.claude-template/skills/run-ui-test/references/report-format.md +77 -0
  20. package/dist/.claude-template/skills/subagent-implement/SKILL.md +3 -2
  21. package/dist/.claude-template/skills/write-api/SKILL.md +18 -18
  22. package/dist/.claude-template/skills/write-api/assets/{template-api-spec.md → template-/346/216/245/345/217/243/346/265/213/350/257/225-spec.md} +1 -1
  23. package/dist/.claude-template/skills/write-api/references/{api-spec-format.md → /346/216/245/345/217/243/346/265/213/350/257/225-spec-format.md} +3 -3
  24. package/dist/.claude-template/skills/write-plan/SKILL.md +4 -2
  25. package/dist/.claude-template/skills/write-ui-test/SKILL.md +125 -0
  26. package/dist/.claude-template/skills/write-ui-test/references//347/224/250/344/276/213/350/247/204/346/240/274-format.md +94 -0
  27. package/dist/core/code/engine/cli/analyze-config.js +320 -0
  28. package/dist/core/code/engine/cli/analyze.js +1086 -0
  29. package/dist/core/code/engine/cli/cli-message.js +83 -0
  30. package/dist/core/code/engine/cli/detect-changes-format.js +58 -0
  31. package/dist/core/code/engine/cli/embedding-dims.js +43 -0
  32. package/dist/core/code/engine/cli/format-elapsed.js +12 -0
  33. package/dist/core/code/engine/cli/help-i18n.js +144 -0
  34. package/dist/core/code/engine/cli/i18n/en.js +110 -0
  35. package/dist/core/code/engine/cli/i18n/index.js +47 -0
  36. package/dist/core/code/engine/cli/i18n/resources.js +9 -0
  37. package/dist/core/code/engine/cli/i18n/zh-CN.js +110 -0
  38. package/dist/core/code/engine/cli/lazy-action.js +67 -0
  39. package/dist/core/code/engine/cli/optional-grammars.js +136 -0
  40. package/dist/core/code/engine/cli/resolve-invocation.js +76 -0
  41. package/dist/core/code/engine/cli/status.js +156 -0
  42. package/dist/core/code/engine/cli/tool.js +384 -0
  43. package/dist/core/code/engine/config/ignore-service.js +511 -0
  44. package/dist/core/code/engine/config/supported-languages.js +17 -0
  45. package/dist/core/code/engine/core/analysis-features.js +64 -0
  46. package/dist/core/code/engine/core/analyzer-identity.js +2171 -0
  47. package/dist/core/code/engine/core/git-staleness.js +180 -0
  48. package/dist/core/code/engine/core/graph/graph.js +180 -0
  49. package/dist/core/code/engine/core/graph/import-cycles.js +106 -0
  50. package/dist/core/code/engine/core/graph/types.js +2 -0
  51. package/dist/core/code/engine/core/index-freshness.js +12 -0
  52. package/dist/core/code/engine/core/ingestion/binding-accumulator.js +341 -0
  53. package/dist/core/code/engine/core/ingestion/call-extractors/configs/c-cpp.js +168 -0
  54. package/dist/core/code/engine/core/ingestion/call-extractors/configs/csharp.js +9 -0
  55. package/dist/core/code/engine/core/ingestion/call-extractors/configs/dart.js +8 -0
  56. package/dist/core/code/engine/core/ingestion/call-extractors/configs/go.js +8 -0
  57. package/dist/core/code/engine/core/ingestion/call-extractors/configs/jvm.js +54 -0
  58. package/dist/core/code/engine/core/ingestion/call-extractors/configs/php.js +8 -0
  59. package/dist/core/code/engine/core/ingestion/call-extractors/configs/python.js +8 -0
  60. package/dist/core/code/engine/core/ingestion/call-extractors/configs/ruby.js +8 -0
  61. package/dist/core/code/engine/core/ingestion/call-extractors/configs/rust.js +8 -0
  62. package/dist/core/code/engine/core/ingestion/call-extractors/configs/swift.js +8 -0
  63. package/dist/core/code/engine/core/ingestion/call-extractors/configs/typescript-javascript.js +11 -0
  64. package/dist/core/code/engine/core/ingestion/call-extractors/generic.js +62 -0
  65. package/dist/core/code/engine/core/ingestion/call-processor.js +503 -0
  66. package/dist/core/code/engine/core/ingestion/call-routing.js +98 -0
  67. package/dist/core/code/engine/core/ingestion/call-types.js +3 -0
  68. package/dist/core/code/engine/core/ingestion/cfg/callee-cell-format.js +45 -0
  69. package/dist/core/code/engine/core/ingestion/cfg/cfg-builder.js +202 -0
  70. package/dist/core/code/engine/core/ingestion/cfg/collect.js +81 -0
  71. package/dist/core/code/engine/core/ingestion/cfg/control-dependence.js +185 -0
  72. package/dist/core/code/engine/core/ingestion/cfg/control-flow-context.js +130 -0
  73. package/dist/core/code/engine/core/ingestion/cfg/emit.js +646 -0
  74. package/dist/core/code/engine/core/ingestion/cfg/post-dominators.js +182 -0
  75. package/dist/core/code/engine/core/ingestion/cfg/reaching-def-reason-codec.js +139 -0
  76. package/dist/core/code/engine/core/ingestion/cfg/reaching-defs-graph.js +322 -0
  77. package/dist/core/code/engine/core/ingestion/cfg/reaching-defs.js +792 -0
  78. package/dist/core/code/engine/core/ingestion/cfg/synthetic-escape.js +305 -0
  79. package/dist/core/code/engine/core/ingestion/cfg/traversal-result.js +6 -0
  80. package/dist/core/code/engine/core/ingestion/cfg/types.js +14 -0
  81. package/dist/core/code/engine/core/ingestion/cfg/visitors/c-cpp-harvest.js +545 -0
  82. package/dist/core/code/engine/core/ingestion/cfg/visitors/c-cpp.js +590 -0
  83. package/dist/core/code/engine/core/ingestion/cfg/visitors/call-site-harvest.js +356 -0
  84. package/dist/core/code/engine/core/ingestion/cfg/visitors/csharp-harvest.js +593 -0
  85. package/dist/core/code/engine/core/ingestion/cfg/visitors/csharp.js +871 -0
  86. package/dist/core/code/engine/core/ingestion/cfg/visitors/dart-harvest.js +874 -0
  87. package/dist/core/code/engine/core/ingestion/cfg/visitors/dart.js +840 -0
  88. package/dist/core/code/engine/core/ingestion/cfg/visitors/go-harvest.js +625 -0
  89. package/dist/core/code/engine/core/ingestion/cfg/visitors/go.js +642 -0
  90. package/dist/core/code/engine/core/ingestion/cfg/visitors/java-harvest.js +517 -0
  91. package/dist/core/code/engine/core/ingestion/cfg/visitors/java.js +816 -0
  92. package/dist/core/code/engine/core/ingestion/cfg/visitors/kotlin-harvest.js +723 -0
  93. package/dist/core/code/engine/core/ingestion/cfg/visitors/kotlin.js +813 -0
  94. package/dist/core/code/engine/core/ingestion/cfg/visitors/php-harvest.js +630 -0
  95. package/dist/core/code/engine/core/ingestion/cfg/visitors/php.js +725 -0
  96. package/dist/core/code/engine/core/ingestion/cfg/visitors/python-harvest.js +776 -0
  97. package/dist/core/code/engine/core/ingestion/cfg/visitors/python.js +562 -0
  98. package/dist/core/code/engine/core/ingestion/cfg/visitors/ruby-harvest.js +591 -0
  99. package/dist/core/code/engine/core/ingestion/cfg/visitors/ruby.js +760 -0
  100. package/dist/core/code/engine/core/ingestion/cfg/visitors/rust-harvest.js +877 -0
  101. package/dist/core/code/engine/core/ingestion/cfg/visitors/rust.js +562 -0
  102. package/dist/core/code/engine/core/ingestion/cfg/visitors/scope-tree-harvest.js +120 -0
  103. package/dist/core/code/engine/core/ingestion/cfg/visitors/swift-harvest.js +683 -0
  104. package/dist/core/code/engine/core/ingestion/cfg/visitors/swift.js +791 -0
  105. package/dist/core/code/engine/core/ingestion/cfg/visitors/typescript-harvest.js +1060 -0
  106. package/dist/core/code/engine/core/ingestion/cfg/visitors/typescript.js +587 -0
  107. package/dist/core/code/engine/core/ingestion/class-extractors/configs/c-cpp.js +77 -0
  108. package/dist/core/code/engine/core/ingestion/class-extractors/configs/csharp.js +24 -0
  109. package/dist/core/code/engine/core/ingestion/class-extractors/configs/dart.js +10 -0
  110. package/dist/core/code/engine/core/ingestion/class-extractors/configs/go.js +28 -0
  111. package/dist/core/code/engine/core/ingestion/class-extractors/configs/jvm.js +67 -0
  112. package/dist/core/code/engine/core/ingestion/class-extractors/configs/php.js +10 -0
  113. package/dist/core/code/engine/core/ingestion/class-extractors/configs/python.js +10 -0
  114. package/dist/core/code/engine/core/ingestion/class-extractors/configs/ruby.js +13 -0
  115. package/dist/core/code/engine/core/ingestion/class-extractors/configs/rust.js +10 -0
  116. package/dist/core/code/engine/core/ingestion/class-extractors/configs/swift.js +21 -0
  117. package/dist/core/code/engine/core/ingestion/class-extractors/configs/typescript-javascript.js +31 -0
  118. package/dist/core/code/engine/core/ingestion/class-extractors/generic.js +144 -0
  119. package/dist/core/code/engine/core/ingestion/class-types.js +2 -0
  120. package/dist/core/code/engine/core/ingestion/cluster-enricher.js +174 -0
  121. package/dist/core/code/engine/core/ingestion/community-processor.js +604 -0
  122. package/dist/core/code/engine/core/ingestion/constants.js +26 -0
  123. package/dist/core/code/engine/core/ingestion/cpp-ue-preprocessor.js +263 -0
  124. package/dist/core/code/engine/core/ingestion/csharp-namespace-gate.js +133 -0
  125. package/dist/core/code/engine/core/ingestion/di-extractors/index.js +38 -0
  126. package/dist/core/code/engine/core/ingestion/di-extractors/spring.js +310 -0
  127. package/dist/core/code/engine/core/ingestion/emit-references.js +244 -0
  128. package/dist/core/code/engine/core/ingestion/entry-point-scoring.js +201 -0
  129. package/dist/core/code/engine/core/ingestion/export-detection.js +244 -0
  130. package/dist/core/code/engine/core/ingestion/field-extractor.js +29 -0
  131. package/dist/core/code/engine/core/ingestion/field-extractors/configs/c-cpp.js +107 -0
  132. package/dist/core/code/engine/core/ingestion/field-extractors/configs/csharp.js +124 -0
  133. package/dist/core/code/engine/core/ingestion/field-extractors/configs/dart.js +99 -0
  134. package/dist/core/code/engine/core/ingestion/field-extractors/configs/go.js +102 -0
  135. package/dist/core/code/engine/core/ingestion/field-extractors/configs/helpers.js +198 -0
  136. package/dist/core/code/engine/core/ingestion/field-extractors/configs/jvm.js +172 -0
  137. package/dist/core/code/engine/core/ingestion/field-extractors/configs/php.js +67 -0
  138. package/dist/core/code/engine/core/ingestion/field-extractors/configs/python.js +94 -0
  139. package/dist/core/code/engine/core/ingestion/field-extractors/configs/ruby.js +79 -0
  140. package/dist/core/code/engine/core/ingestion/field-extractors/configs/rust.js +55 -0
  141. package/dist/core/code/engine/core/ingestion/field-extractors/configs/swift.js +93 -0
  142. package/dist/core/code/engine/core/ingestion/field-extractors/configs/typescript-javascript.js +59 -0
  143. package/dist/core/code/engine/core/ingestion/field-extractors/generic.js +147 -0
  144. package/dist/core/code/engine/core/ingestion/field-extractors/typescript.js +266 -0
  145. package/dist/core/code/engine/core/ingestion/field-types.js +3 -0
  146. package/dist/core/code/engine/core/ingestion/filesystem-walker.js +136 -0
  147. package/dist/core/code/engine/core/ingestion/finalize-orchestrator.js +159 -0
  148. package/dist/core/code/engine/core/ingestion/framework-detection.js +432 -0
  149. package/dist/core/code/engine/core/ingestion/frameworks/spring/analysis-features.js +38 -0
  150. package/dist/core/code/engine/core/ingestion/frameworks/spring/annotation-arguments.js +234 -0
  151. package/dist/core/code/engine/core/ingestion/frameworks/spring/aop-candidates.js +88 -0
  152. package/dist/core/code/engine/core/ingestion/frameworks/spring/aop.js +487 -0
  153. package/dist/core/code/engine/core/ingestion/frameworks/spring/auto-configuration.js +21 -0
  154. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-candidates.js +189 -0
  155. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-catalog.js +32 -0
  156. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-factories.js +73 -0
  157. package/dist/core/code/engine/core/ingestion/frameworks/spring/conditionals.js +323 -0
  158. package/dist/core/code/engine/core/ingestion/frameworks/spring/config-bindings.js +119 -0
  159. package/dist/core/code/engine/core/ingestion/frameworks/spring/di-metadata.js +385 -0
  160. package/dist/core/code/engine/core/ingestion/frameworks/spring/resource-injection.js +96 -0
  161. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/c-cpp.js +17 -0
  162. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/csharp.js +46 -0
  163. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/dart.js +59 -0
  164. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/go.js +30 -0
  165. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/jvm.js +73 -0
  166. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/php.js +19 -0
  167. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/python.js +45 -0
  168. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/ruby.js +20 -0
  169. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/rust.js +58 -0
  170. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/swift.js +94 -0
  171. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/typescript-javascript.js +26 -0
  172. package/dist/core/code/engine/core/ingestion/import-resolvers/csharp.js +128 -0
  173. package/dist/core/code/engine/core/ingestion/import-resolvers/go.js +50 -0
  174. package/dist/core/code/engine/core/ingestion/import-resolvers/jvm.js +112 -0
  175. package/dist/core/code/engine/core/ingestion/import-resolvers/php.js +80 -0
  176. package/dist/core/code/engine/core/ingestion/import-resolvers/python.js +75 -0
  177. package/dist/core/code/engine/core/ingestion/import-resolvers/resolver-factory.js +36 -0
  178. package/dist/core/code/engine/core/ingestion/import-resolvers/ruby.js +20 -0
  179. package/dist/core/code/engine/core/ingestion/import-resolvers/rust.js +79 -0
  180. package/dist/core/code/engine/core/ingestion/import-resolvers/standard.js +180 -0
  181. package/dist/core/code/engine/core/ingestion/import-resolvers/types.js +7 -0
  182. package/dist/core/code/engine/core/ingestion/import-resolvers/utils.js +153 -0
  183. package/dist/core/code/engine/core/ingestion/import-target-adapter.js +99 -0
  184. package/dist/core/code/engine/core/ingestion/language-config.js +391 -0
  185. package/dist/core/code/engine/core/ingestion/language-provider.js +25 -0
  186. package/dist/core/code/engine/core/ingestion/languages/c/arity-metadata.js +98 -0
  187. package/dist/core/code/engine/core/ingestion/languages/c/arity.js +21 -0
  188. package/dist/core/code/engine/core/ingestion/languages/c/capture-side-channel.js +69 -0
  189. package/dist/core/code/engine/core/ingestion/languages/c/captures.js +189 -0
  190. package/dist/core/code/engine/core/ingestion/languages/c/header-scan.js +58 -0
  191. package/dist/core/code/engine/core/ingestion/languages/c/import-decomposer.js +68 -0
  192. package/dist/core/code/engine/core/ingestion/languages/c/import-target.js +103 -0
  193. package/dist/core/code/engine/core/ingestion/languages/c/index.js +33 -0
  194. package/dist/core/code/engine/core/ingestion/languages/c/interpret.js +53 -0
  195. package/dist/core/code/engine/core/ingestion/languages/c/merge-bindings.js +26 -0
  196. package/dist/core/code/engine/core/ingestion/languages/c/query.js +210 -0
  197. package/dist/core/code/engine/core/ingestion/languages/c/scope-resolver.js +112 -0
  198. package/dist/core/code/engine/core/ingestion/languages/c/simple-hooks.js +24 -0
  199. package/dist/core/code/engine/core/ingestion/languages/c/static-linkage.js +109 -0
  200. package/dist/core/code/engine/core/ingestion/languages/c-cpp.js +506 -0
  201. package/dist/core/code/engine/core/ingestion/languages/cpp/adl.js +804 -0
  202. package/dist/core/code/engine/core/ingestion/languages/cpp/arity-metadata.js +258 -0
  203. package/dist/core/code/engine/core/ingestion/languages/cpp/arity.js +37 -0
  204. package/dist/core/code/engine/core/ingestion/languages/cpp/capture-side-channel.js +89 -0
  205. package/dist/core/code/engine/core/ingestion/languages/cpp/captures.js +1975 -0
  206. package/dist/core/code/engine/core/ingestion/languages/cpp/constraint-extractor.js +311 -0
  207. package/dist/core/code/engine/core/ingestion/languages/cpp/constraint-filter.js +210 -0
  208. package/dist/core/code/engine/core/ingestion/languages/cpp/conversion-rank.js +163 -0
  209. package/dist/core/code/engine/core/ingestion/languages/cpp/file-local-linkage.js +327 -0
  210. package/dist/core/code/engine/core/ingestion/languages/cpp/header-scan.js +53 -0
  211. package/dist/core/code/engine/core/ingestion/languages/cpp/import-decomposer.js +134 -0
  212. package/dist/core/code/engine/core/ingestion/languages/cpp/import-target.js +16 -0
  213. package/dist/core/code/engine/core/ingestion/languages/cpp/index.js +33 -0
  214. package/dist/core/code/engine/core/ingestion/languages/cpp/inline-namespaces.js +379 -0
  215. package/dist/core/code/engine/core/ingestion/languages/cpp/interpret.js +239 -0
  216. package/dist/core/code/engine/core/ingestion/languages/cpp/member-lookup.js +470 -0
  217. package/dist/core/code/engine/core/ingestion/languages/cpp/merge-bindings.js +32 -0
  218. package/dist/core/code/engine/core/ingestion/languages/cpp/query.js +763 -0
  219. package/dist/core/code/engine/core/ingestion/languages/cpp/range-bindings.js +230 -0
  220. package/dist/core/code/engine/core/ingestion/languages/cpp/scope-resolver.js +354 -0
  221. package/dist/core/code/engine/core/ingestion/languages/cpp/simple-hooks.js +67 -0
  222. package/dist/core/code/engine/core/ingestion/languages/cpp/two-phase-lookup.js +348 -0
  223. package/dist/core/code/engine/core/ingestion/languages/cpp/type-classifier.js +56 -0
  224. package/dist/core/code/engine/core/ingestion/languages/cpp/user-defined-conversions.js +128 -0
  225. package/dist/core/code/engine/core/ingestion/languages/csharp/accessor-unwrap.js +67 -0
  226. package/dist/core/code/engine/core/ingestion/languages/csharp/arity-metadata.js +49 -0
  227. package/dist/core/code/engine/core/ingestion/languages/csharp/arity.js +40 -0
  228. package/dist/core/code/engine/core/ingestion/languages/csharp/cache-stats.js +32 -0
  229. package/dist/core/code/engine/core/ingestion/languages/csharp/captures.js +557 -0
  230. package/dist/core/code/engine/core/ingestion/languages/csharp/import-decomposer.js +96 -0
  231. package/dist/core/code/engine/core/ingestion/languages/csharp/import-target.js +176 -0
  232. package/dist/core/code/engine/core/ingestion/languages/csharp/index.js +95 -0
  233. package/dist/core/code/engine/core/ingestion/languages/csharp/interpret.js +150 -0
  234. package/dist/core/code/engine/core/ingestion/languages/csharp/merge-bindings.js +58 -0
  235. package/dist/core/code/engine/core/ingestion/languages/csharp/namespace-siblings.js +708 -0
  236. package/dist/core/code/engine/core/ingestion/languages/csharp/qualified-type-names.js +62 -0
  237. package/dist/core/code/engine/core/ingestion/languages/csharp/query.js +578 -0
  238. package/dist/core/code/engine/core/ingestion/languages/csharp/receiver-binding.js +142 -0
  239. package/dist/core/code/engine/core/ingestion/languages/csharp/resolution-config.js +18 -0
  240. package/dist/core/code/engine/core/ingestion/languages/csharp/scope-resolver.js +84 -0
  241. package/dist/core/code/engine/core/ingestion/languages/csharp/simple-hooks.js +81 -0
  242. package/dist/core/code/engine/core/ingestion/languages/csharp.js +204 -0
  243. package/dist/core/code/engine/core/ingestion/languages/dart/arity-metadata.js +38 -0
  244. package/dist/core/code/engine/core/ingestion/languages/dart/arity.js +34 -0
  245. package/dist/core/code/engine/core/ingestion/languages/dart/built-ins.js +37 -0
  246. package/dist/core/code/engine/core/ingestion/languages/dart/cache-stats.js +30 -0
  247. package/dist/core/code/engine/core/ingestion/languages/dart/captures.js +1096 -0
  248. package/dist/core/code/engine/core/ingestion/languages/dart/expand-wildcards.js +34 -0
  249. package/dist/core/code/engine/core/ingestion/languages/dart/extension-type-preprocess.js +33 -0
  250. package/dist/core/code/engine/core/ingestion/languages/dart/import-target.js +68 -0
  251. package/dist/core/code/engine/core/ingestion/languages/dart/index.js +45 -0
  252. package/dist/core/code/engine/core/ingestion/languages/dart/interpret.js +101 -0
  253. package/dist/core/code/engine/core/ingestion/languages/dart/merge-bindings.js +42 -0
  254. package/dist/core/code/engine/core/ingestion/languages/dart/query.js +246 -0
  255. package/dist/core/code/engine/core/ingestion/languages/dart/receiver-binding.js +90 -0
  256. package/dist/core/code/engine/core/ingestion/languages/dart/scope-resolver.js +197 -0
  257. package/dist/core/code/engine/core/ingestion/languages/dart/signature-bindings.js +54 -0
  258. package/dist/core/code/engine/core/ingestion/languages/dart/simple-hooks.js +61 -0
  259. package/dist/core/code/engine/core/ingestion/languages/dart.js +138 -0
  260. package/dist/core/code/engine/core/ingestion/languages/go/arity-metadata.js +71 -0
  261. package/dist/core/code/engine/core/ingestion/languages/go/arity.js +17 -0
  262. package/dist/core/code/engine/core/ingestion/languages/go/cache-stats.js +21 -0
  263. package/dist/core/code/engine/core/ingestion/languages/go/captures.js +492 -0
  264. package/dist/core/code/engine/core/ingestion/languages/go/expand-wildcards.js +97 -0
  265. package/dist/core/code/engine/core/ingestion/languages/go/generic-type-parameters.js +146 -0
  266. package/dist/core/code/engine/core/ingestion/languages/go/import-decomposer.js +47 -0
  267. package/dist/core/code/engine/core/ingestion/languages/go/import-target.js +70 -0
  268. package/dist/core/code/engine/core/ingestion/languages/go/index.js +39 -0
  269. package/dist/core/code/engine/core/ingestion/languages/go/interface-impls.js +955 -0
  270. package/dist/core/code/engine/core/ingestion/languages/go/interpret.js +177 -0
  271. package/dist/core/code/engine/core/ingestion/languages/go/merge-bindings.js +21 -0
  272. package/dist/core/code/engine/core/ingestion/languages/go/method-owners.js +131 -0
  273. package/dist/core/code/engine/core/ingestion/languages/go/namespace-mirror.js +56 -0
  274. package/dist/core/code/engine/core/ingestion/languages/go/package-clause.js +79 -0
  275. package/dist/core/code/engine/core/ingestion/languages/go/package-siblings.js +83 -0
  276. package/dist/core/code/engine/core/ingestion/languages/go/query.js +298 -0
  277. package/dist/core/code/engine/core/ingestion/languages/go/range-binding.js +127 -0
  278. package/dist/core/code/engine/core/ingestion/languages/go/receiver-binding.js +24 -0
  279. package/dist/core/code/engine/core/ingestion/languages/go/scope-resolver.js +75 -0
  280. package/dist/core/code/engine/core/ingestion/languages/go/simple-hooks.js +31 -0
  281. package/dist/core/code/engine/core/ingestion/languages/go/type-binding.js +279 -0
  282. package/dist/core/code/engine/core/ingestion/languages/go.js +160 -0
  283. package/dist/core/code/engine/core/ingestion/languages/index.js +66 -0
  284. package/dist/core/code/engine/core/ingestion/languages/java/analysis-features.js +16 -0
  285. package/dist/core/code/engine/core/ingestion/languages/java/arity-metadata.js +43 -0
  286. package/dist/core/code/engine/core/ingestion/languages/java/arity.js +27 -0
  287. package/dist/core/code/engine/core/ingestion/languages/java/cache-stats.js +32 -0
  288. package/dist/core/code/engine/core/ingestion/languages/java/capture-side-channel.js +123 -0
  289. package/dist/core/code/engine/core/ingestion/languages/java/captures.js +791 -0
  290. package/dist/core/code/engine/core/ingestion/languages/java/import-decomposer.js +88 -0
  291. package/dist/core/code/engine/core/ingestion/languages/java/import-target.js +103 -0
  292. package/dist/core/code/engine/core/ingestion/languages/java/index.js +43 -0
  293. package/dist/core/code/engine/core/ingestion/languages/java/interpret.js +146 -0
  294. package/dist/core/code/engine/core/ingestion/languages/java/merge-bindings.js +43 -0
  295. package/dist/core/code/engine/core/ingestion/languages/java/package-facts.js +16 -0
  296. package/dist/core/code/engine/core/ingestion/languages/java/package-siblings.js +11 -0
  297. package/dist/core/code/engine/core/ingestion/languages/java/query.js +319 -0
  298. package/dist/core/code/engine/core/ingestion/languages/java/receiver-binding.js +98 -0
  299. package/dist/core/code/engine/core/ingestion/languages/java/scope-resolver.js +213 -0
  300. package/dist/core/code/engine/core/ingestion/languages/java/simple-hooks.js +39 -0
  301. package/dist/core/code/engine/core/ingestion/languages/java/spring-aop.js +53 -0
  302. package/dist/core/code/engine/core/ingestion/languages/java/spring-bean-metadata.js +11 -0
  303. package/dist/core/code/engine/core/ingestion/languages/java/spring-conditionals.js +52 -0
  304. package/dist/core/code/engine/core/ingestion/languages/java/spring-config-bindings.js +222 -0
  305. package/dist/core/code/engine/core/ingestion/languages/java/spring-di.js +165 -0
  306. package/dist/core/code/engine/core/ingestion/languages/java.js +192 -0
  307. package/dist/core/code/engine/core/ingestion/languages/javascript/arity.js +15 -0
  308. package/dist/core/code/engine/core/ingestion/languages/javascript/captures.js +1122 -0
  309. package/dist/core/code/engine/core/ingestion/languages/javascript/import-target.js +56 -0
  310. package/dist/core/code/engine/core/ingestion/languages/javascript/index.js +109 -0
  311. package/dist/core/code/engine/core/ingestion/languages/javascript/interpret.js +45 -0
  312. package/dist/core/code/engine/core/ingestion/languages/javascript/merge-bindings.js +21 -0
  313. package/dist/core/code/engine/core/ingestion/languages/javascript/query.js +659 -0
  314. package/dist/core/code/engine/core/ingestion/languages/javascript/scope-resolver.js +78 -0
  315. package/dist/core/code/engine/core/ingestion/languages/javascript/simple-hooks.js +44 -0
  316. package/dist/core/code/engine/core/ingestion/languages/jvm/package-facts.js +46 -0
  317. package/dist/core/code/engine/core/ingestion/languages/jvm/package-siblings.js +200 -0
  318. package/dist/core/code/engine/core/ingestion/languages/kotlin/arity-metadata.js +23 -0
  319. package/dist/core/code/engine/core/ingestion/languages/kotlin/arity.js +18 -0
  320. package/dist/core/code/engine/core/ingestion/languages/kotlin/cache-stats.js +21 -0
  321. package/dist/core/code/engine/core/ingestion/languages/kotlin/capture-side-channel.js +160 -0
  322. package/dist/core/code/engine/core/ingestion/languages/kotlin/captures.js +1262 -0
  323. package/dist/core/code/engine/core/ingestion/languages/kotlin/companion-scopes.js +72 -0
  324. package/dist/core/code/engine/core/ingestion/languages/kotlin/import-decomposer.js +40 -0
  325. package/dist/core/code/engine/core/ingestion/languages/kotlin/import-target.js +135 -0
  326. package/dist/core/code/engine/core/ingestion/languages/kotlin/index.js +26 -0
  327. package/dist/core/code/engine/core/ingestion/languages/kotlin/interpret.js +75 -0
  328. package/dist/core/code/engine/core/ingestion/languages/kotlin/merge-bindings.js +28 -0
  329. package/dist/core/code/engine/core/ingestion/languages/kotlin/owners.js +134 -0
  330. package/dist/core/code/engine/core/ingestion/languages/kotlin/package-facts.js +16 -0
  331. package/dist/core/code/engine/core/ingestion/languages/kotlin/package-siblings.js +11 -0
  332. package/dist/core/code/engine/core/ingestion/languages/kotlin/query.js +243 -0
  333. package/dist/core/code/engine/core/ingestion/languages/kotlin/receiver-binding.js +103 -0
  334. package/dist/core/code/engine/core/ingestion/languages/kotlin/scope-resolver.js +207 -0
  335. package/dist/core/code/engine/core/ingestion/languages/kotlin/simple-hooks.js +42 -0
  336. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-aop.js +68 -0
  337. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-bean-metadata.js +11 -0
  338. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-conditionals.js +53 -0
  339. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-di.js +304 -0
  340. package/dist/core/code/engine/core/ingestion/languages/kotlin.js +189 -0
  341. package/dist/core/code/engine/core/ingestion/languages/php/arity-metadata.js +66 -0
  342. package/dist/core/code/engine/core/ingestion/languages/php/arity.js +43 -0
  343. package/dist/core/code/engine/core/ingestion/languages/php/cache-stats.js +32 -0
  344. package/dist/core/code/engine/core/ingestion/languages/php/captures.js +1166 -0
  345. package/dist/core/code/engine/core/ingestion/languages/php/import-decomposer.js +238 -0
  346. package/dist/core/code/engine/core/ingestion/languages/php/import-target.js +213 -0
  347. package/dist/core/code/engine/core/ingestion/languages/php/index.js +85 -0
  348. package/dist/core/code/engine/core/ingestion/languages/php/interpret.js +256 -0
  349. package/dist/core/code/engine/core/ingestion/languages/php/merge-bindings.js +50 -0
  350. package/dist/core/code/engine/core/ingestion/languages/php/namespace-siblings.js +353 -0
  351. package/dist/core/code/engine/core/ingestion/languages/php/query.js +391 -0
  352. package/dist/core/code/engine/core/ingestion/languages/php/receiver-binding.js +135 -0
  353. package/dist/core/code/engine/core/ingestion/languages/php/scope-resolver.js +361 -0
  354. package/dist/core/code/engine/core/ingestion/languages/php/simple-hooks.js +116 -0
  355. package/dist/core/code/engine/core/ingestion/languages/php.js +302 -0
  356. package/dist/core/code/engine/core/ingestion/languages/python/arity-metadata.js +49 -0
  357. package/dist/core/code/engine/core/ingestion/languages/python/arity.js +41 -0
  358. package/dist/core/code/engine/core/ingestion/languages/python/cache-stats.js +34 -0
  359. package/dist/core/code/engine/core/ingestion/languages/python/captures.js +299 -0
  360. package/dist/core/code/engine/core/ingestion/languages/python/depends-references.js +68 -0
  361. package/dist/core/code/engine/core/ingestion/languages/python/import-decomposer.js +115 -0
  362. package/dist/core/code/engine/core/ingestion/languages/python/import-target.js +440 -0
  363. package/dist/core/code/engine/core/ingestion/languages/python/index-stats.js +30 -0
  364. package/dist/core/code/engine/core/ingestion/languages/python/index.js +96 -0
  365. package/dist/core/code/engine/core/ingestion/languages/python/interpret.js +430 -0
  366. package/dist/core/code/engine/core/ingestion/languages/python/merge-bindings.js +47 -0
  367. package/dist/core/code/engine/core/ingestion/languages/python/query.js +323 -0
  368. package/dist/core/code/engine/core/ingestion/languages/python/receiver-binding.js +310 -0
  369. package/dist/core/code/engine/core/ingestion/languages/python/scope-resolver.js +80 -0
  370. package/dist/core/code/engine/core/ingestion/languages/python/simple-hooks.js +53 -0
  371. package/dist/core/code/engine/core/ingestion/languages/python.js +140 -0
  372. package/dist/core/code/engine/core/ingestion/languages/ruby/arity.js +41 -0
  373. package/dist/core/code/engine/core/ingestion/languages/ruby/cache-stats.js +21 -0
  374. package/dist/core/code/engine/core/ingestion/languages/ruby/captures.js +864 -0
  375. package/dist/core/code/engine/core/ingestion/languages/ruby/import-target.js +88 -0
  376. package/dist/core/code/engine/core/ingestion/languages/ruby/index.js +29 -0
  377. package/dist/core/code/engine/core/ingestion/languages/ruby/interpret.js +115 -0
  378. package/dist/core/code/engine/core/ingestion/languages/ruby/merge-bindings.js +21 -0
  379. package/dist/core/code/engine/core/ingestion/languages/ruby/query.js +349 -0
  380. package/dist/core/code/engine/core/ingestion/languages/ruby/receiver-binding.js +70 -0
  381. package/dist/core/code/engine/core/ingestion/languages/ruby/scope-resolver.js +263 -0
  382. package/dist/core/code/engine/core/ingestion/languages/ruby/simple-hooks.js +68 -0
  383. package/dist/core/code/engine/core/ingestion/languages/ruby.js +215 -0
  384. package/dist/core/code/engine/core/ingestion/languages/rust/arity.js +16 -0
  385. package/dist/core/code/engine/core/ingestion/languages/rust/cache-stats.js +21 -0
  386. package/dist/core/code/engine/core/ingestion/languages/rust/captures.js +304 -0
  387. package/dist/core/code/engine/core/ingestion/languages/rust/import-decomposer.js +167 -0
  388. package/dist/core/code/engine/core/ingestion/languages/rust/import-target.js +108 -0
  389. package/dist/core/code/engine/core/ingestion/languages/rust/index.js +29 -0
  390. package/dist/core/code/engine/core/ingestion/languages/rust/interpret.js +201 -0
  391. package/dist/core/code/engine/core/ingestion/languages/rust/merge-bindings.js +21 -0
  392. package/dist/core/code/engine/core/ingestion/languages/rust/method-owners.js +76 -0
  393. package/dist/core/code/engine/core/ingestion/languages/rust/module-path.js +222 -0
  394. package/dist/core/code/engine/core/ingestion/languages/rust/qualified-call.js +482 -0
  395. package/dist/core/code/engine/core/ingestion/languages/rust/query.js +280 -0
  396. package/dist/core/code/engine/core/ingestion/languages/rust/range-binding.js +687 -0
  397. package/dist/core/code/engine/core/ingestion/languages/rust/receiver-binding.js +148 -0
  398. package/dist/core/code/engine/core/ingestion/languages/rust/scope-resolver.js +151 -0
  399. package/dist/core/code/engine/core/ingestion/languages/rust/simple-hooks.js +32 -0
  400. package/dist/core/code/engine/core/ingestion/languages/rust.js +183 -0
  401. package/dist/core/code/engine/core/ingestion/languages/swift/arity-metadata.js +44 -0
  402. package/dist/core/code/engine/core/ingestion/languages/swift/arity.js +45 -0
  403. package/dist/core/code/engine/core/ingestion/languages/swift/base-type.js +30 -0
  404. package/dist/core/code/engine/core/ingestion/languages/swift/cache-stats.js +32 -0
  405. package/dist/core/code/engine/core/ingestion/languages/swift/captures.js +594 -0
  406. package/dist/core/code/engine/core/ingestion/languages/swift/conditional-directive-preprocess.js +256 -0
  407. package/dist/core/code/engine/core/ingestion/languages/swift/implicit-imports.js +60 -0
  408. package/dist/core/code/engine/core/ingestion/languages/swift/import-decomposer.js +87 -0
  409. package/dist/core/code/engine/core/ingestion/languages/swift/import-target.js +84 -0
  410. package/dist/core/code/engine/core/ingestion/languages/swift/index.js +56 -0
  411. package/dist/core/code/engine/core/ingestion/languages/swift/interpret.js +93 -0
  412. package/dist/core/code/engine/core/ingestion/languages/swift/merge-bindings.js +51 -0
  413. package/dist/core/code/engine/core/ingestion/languages/swift/query.js +226 -0
  414. package/dist/core/code/engine/core/ingestion/languages/swift/receiver-binding.js +169 -0
  415. package/dist/core/code/engine/core/ingestion/languages/swift/scope-resolver.js +192 -0
  416. package/dist/core/code/engine/core/ingestion/languages/swift/sibling-type-bindings.js +68 -0
  417. package/dist/core/code/engine/core/ingestion/languages/swift/signature-bindings.js +69 -0
  418. package/dist/core/code/engine/core/ingestion/languages/swift/simple-hooks.js +65 -0
  419. package/dist/core/code/engine/core/ingestion/languages/swift/target-grouping.js +97 -0
  420. package/dist/core/code/engine/core/ingestion/languages/swift/target-siblings.js +74 -0
  421. package/dist/core/code/engine/core/ingestion/languages/swift.js +246 -0
  422. package/dist/core/code/engine/core/ingestion/languages/typescript/arity-metadata.js +106 -0
  423. package/dist/core/code/engine/core/ingestion/languages/typescript/arity.js +57 -0
  424. package/dist/core/code/engine/core/ingestion/languages/typescript/array-callback.js +58 -0
  425. package/dist/core/code/engine/core/ingestion/languages/typescript/cache-stats.js +34 -0
  426. package/dist/core/code/engine/core/ingestion/languages/typescript/captures.js +956 -0
  427. package/dist/core/code/engine/core/ingestion/languages/typescript/cjs-export-assignment.js +535 -0
  428. package/dist/core/code/engine/core/ingestion/languages/typescript/cjs-module-exports.js +196 -0
  429. package/dist/core/code/engine/core/ingestion/languages/typescript/import-decomposer.js +374 -0
  430. package/dist/core/code/engine/core/ingestion/languages/typescript/import-target.js +65 -0
  431. package/dist/core/code/engine/core/ingestion/languages/typescript/index.js +108 -0
  432. package/dist/core/code/engine/core/ingestion/languages/typescript/interpret.js +344 -0
  433. package/dist/core/code/engine/core/ingestion/languages/typescript/merge-bindings.js +161 -0
  434. package/dist/core/code/engine/core/ingestion/languages/typescript/nuxt-auto-imports.js +325 -0
  435. package/dist/core/code/engine/core/ingestion/languages/typescript/query.js +1328 -0
  436. package/dist/core/code/engine/core/ingestion/languages/typescript/receiver-binding.js +201 -0
  437. package/dist/core/code/engine/core/ingestion/languages/typescript/scope-resolver.js +293 -0
  438. package/dist/core/code/engine/core/ingestion/languages/typescript/simple-hooks.js +139 -0
  439. package/dist/core/code/engine/core/ingestion/languages/typescript.js +455 -0
  440. package/dist/core/code/engine/core/ingestion/languages/vue/captures.js +70 -0
  441. package/dist/core/code/engine/core/ingestion/languages/vue/import-target.js +61 -0
  442. package/dist/core/code/engine/core/ingestion/languages/vue/index.js +55 -0
  443. package/dist/core/code/engine/core/ingestion/languages/vue/scope-resolver.js +295 -0
  444. package/dist/core/code/engine/core/ingestion/languages/vue.js +96 -0
  445. package/dist/core/code/engine/core/ingestion/local-symbol-pruner.js +68 -0
  446. package/dist/core/code/engine/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
  447. package/dist/core/code/engine/core/ingestion/method-extractors/configs/csharp.js +290 -0
  448. package/dist/core/code/engine/core/ingestion/method-extractors/configs/dart.js +392 -0
  449. package/dist/core/code/engine/core/ingestion/method-extractors/configs/go.js +179 -0
  450. package/dist/core/code/engine/core/ingestion/method-extractors/configs/jvm.js +350 -0
  451. package/dist/core/code/engine/core/ingestion/method-extractors/configs/php.js +306 -0
  452. package/dist/core/code/engine/core/ingestion/method-extractors/configs/python.js +312 -0
  453. package/dist/core/code/engine/core/ingestion/method-extractors/configs/ruby.js +289 -0
  454. package/dist/core/code/engine/core/ingestion/method-extractors/configs/rust.js +198 -0
  455. package/dist/core/code/engine/core/ingestion/method-extractors/configs/swift.js +286 -0
  456. package/dist/core/code/engine/core/ingestion/method-extractors/configs/typescript-javascript.js +341 -0
  457. package/dist/core/code/engine/core/ingestion/method-extractors/generic.js +209 -0
  458. package/dist/core/code/engine/core/ingestion/method-types.js +3 -0
  459. package/dist/core/code/engine/core/ingestion/model/field-registry.js +41 -0
  460. package/dist/core/code/engine/core/ingestion/model/index.js +52 -0
  461. package/dist/core/code/engine/core/ingestion/model/method-registry.js +138 -0
  462. package/dist/core/code/engine/core/ingestion/model/owned-members-lookup.js +46 -0
  463. package/dist/core/code/engine/core/ingestion/model/registration-table.js +234 -0
  464. package/dist/core/code/engine/core/ingestion/model/resolve.js +183 -0
  465. package/dist/core/code/engine/core/ingestion/model/scope-resolution-indexes.js +43 -0
  466. package/dist/core/code/engine/core/ingestion/model/semantic-model.js +179 -0
  467. package/dist/core/code/engine/core/ingestion/model/symbol-table.js +216 -0
  468. package/dist/core/code/engine/core/ingestion/model/type-registry.js +84 -0
  469. package/dist/core/code/engine/core/ingestion/mro-processor.js +709 -0
  470. package/dist/core/code/engine/core/ingestion/parsing-processor.js +312 -0
  471. package/dist/core/code/engine/core/ingestion/pipeline-phases/communities.js +69 -0
  472. package/dist/core/code/engine/core/ingestion/pipeline-phases/cross-file.js +71 -0
  473. package/dist/core/code/engine/core/ingestion/pipeline-phases/di.js +338 -0
  474. package/dist/core/code/engine/core/ingestion/pipeline-phases/http-api-calls.js +312 -0
  475. package/dist/core/code/engine/core/ingestion/pipeline-phases/index.js +54 -0
  476. package/dist/core/code/engine/core/ingestion/pipeline-phases/mro.js +40 -0
  477. package/dist/core/code/engine/core/ingestion/pipeline-phases/orm.js +78 -0
  478. package/dist/core/code/engine/core/ingestion/pipeline-phases/parse-impl.js +1286 -0
  479. package/dist/core/code/engine/core/ingestion/pipeline-phases/parse.js +41 -0
  480. package/dist/core/code/engine/core/ingestion/pipeline-phases/processes.js +193 -0
  481. package/dist/core/code/engine/core/ingestion/pipeline-phases/prune-local-symbols.js +29 -0
  482. package/dist/core/code/engine/core/ingestion/pipeline-phases/registry.js +52 -0
  483. package/dist/core/code/engine/core/ingestion/pipeline-phases/routes.js +409 -0
  484. package/dist/core/code/engine/core/ingestion/pipeline-phases/rpc-edges.js +301 -0
  485. package/dist/core/code/engine/core/ingestion/pipeline-phases/runner.js +207 -0
  486. package/dist/core/code/engine/core/ingestion/pipeline-phases/scan.js +49 -0
  487. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-aop.js +442 -0
  488. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-auto-configuration.js +264 -0
  489. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-config.js +440 -0
  490. package/dist/core/code/engine/core/ingestion/pipeline-phases/structure.js +38 -0
  491. package/dist/core/code/engine/core/ingestion/pipeline-phases/tools.js +89 -0
  492. package/dist/core/code/engine/core/ingestion/pipeline-phases/types.js +40 -0
  493. package/dist/core/code/engine/core/ingestion/pipeline.js +152 -0
  494. package/dist/core/code/engine/core/ingestion/process-processor.js +325 -0
  495. package/dist/core/code/engine/core/ingestion/resolve-references.js +205 -0
  496. package/dist/core/code/engine/core/ingestion/route-extractors/constant-resolver.js +135 -0
  497. package/dist/core/code/engine/core/ingestion/route-extractors/django-root-discovery.js +221 -0
  498. package/dist/core/code/engine/core/ingestion/route-extractors/django.js +428 -0
  499. package/dist/core/code/engine/core/ingestion/route-extractors/expo.js +39 -0
  500. package/dist/core/code/engine/core/ingestion/route-extractors/fastapi-router-bindings.js +264 -0
  501. package/dist/core/code/engine/core/ingestion/route-extractors/laravel.js +501 -0
  502. package/dist/core/code/engine/core/ingestion/route-extractors/middleware.js +175 -0
  503. package/dist/core/code/engine/core/ingestion/route-extractors/nextjs.js +81 -0
  504. package/dist/core/code/engine/core/ingestion/route-extractors/php.js +25 -0
  505. package/dist/core/code/engine/core/ingestion/route-extractors/python-const-resolver.js +307 -0
  506. package/dist/core/code/engine/core/ingestion/route-extractors/response-shapes.js +299 -0
  507. package/dist/core/code/engine/core/ingestion/route-extractors/route-path.js +71 -0
  508. package/dist/core/code/engine/core/ingestion/route-extractors/spring-shared.js +310 -0
  509. package/dist/core/code/engine/core/ingestion/route-extractors/spring.js +441 -0
  510. package/dist/core/code/engine/core/ingestion/scope-extractor-bridge.js +60 -0
  511. package/dist/core/code/engine/core/ingestion/scope-extractor.js +1373 -0
  512. package/dist/core/code/engine/core/ingestion/scope-resolution/contract/scope-resolver.js +282 -0
  513. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +72 -0
  514. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/edges.js +194 -0
  515. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/ids.js +472 -0
  516. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.js +49 -0
  517. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +43 -0
  518. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +274 -0
  519. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +93 -0
  520. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/callable-value-flow.js +1240 -0
  521. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/compound-receiver.js +1174 -0
  522. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/free-call-fallback.js +873 -0
  523. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/imported-return-types.js +226 -0
  524. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/mro.js +107 -0
  525. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/overload-narrowing.js +441 -0
  526. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/property-dispatch.js +122 -0
  527. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +1720 -0
  528. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/phase.js +395 -0
  529. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +208 -0
  530. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/registry.js +49 -0
  531. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/run.js +632 -0
  532. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js +112 -0
  533. package/dist/core/code/engine/core/ingestion/scope-resolution/resolution-outcome.js +41 -0
  534. package/dist/core/code/engine/core/ingestion/scope-resolution/scope/namespace-targets.js +81 -0
  535. package/dist/core/code/engine/core/ingestion/scope-resolution/scope/walkers.js +1835 -0
  536. package/dist/core/code/engine/core/ingestion/scope-resolution/unresolved-receivers.js +242 -0
  537. package/dist/core/code/engine/core/ingestion/scope-resolution/utils/definition-id.js +22 -0
  538. package/dist/core/code/engine/core/ingestion/scope-resolution/workspace-index.js +151 -0
  539. package/dist/core/code/engine/core/ingestion/structure-processor.js +40 -0
  540. package/dist/core/code/engine/core/ingestion/tree-sitter-queries.js +2244 -0
  541. package/dist/core/code/engine/core/ingestion/ts-js-hoc-utils.js +115 -0
  542. package/dist/core/code/engine/core/ingestion/type-env.js +1136 -0
  543. package/dist/core/code/engine/core/ingestion/type-extractors/c-cpp.js +555 -0
  544. package/dist/core/code/engine/core/ingestion/type-extractors/csharp.js +570 -0
  545. package/dist/core/code/engine/core/ingestion/type-extractors/dart.js +372 -0
  546. package/dist/core/code/engine/core/ingestion/type-extractors/go.js +508 -0
  547. package/dist/core/code/engine/core/ingestion/type-extractors/jvm.js +875 -0
  548. package/dist/core/code/engine/core/ingestion/type-extractors/php.js +537 -0
  549. package/dist/core/code/engine/core/ingestion/type-extractors/python.js +477 -0
  550. package/dist/core/code/engine/core/ingestion/type-extractors/ruby.js +380 -0
  551. package/dist/core/code/engine/core/ingestion/type-extractors/rust.js +502 -0
  552. package/dist/core/code/engine/core/ingestion/type-extractors/shared.js +843 -0
  553. package/dist/core/code/engine/core/ingestion/type-extractors/swift.js +490 -0
  554. package/dist/core/code/engine/core/ingestion/type-extractors/types.js +2 -0
  555. package/dist/core/code/engine/core/ingestion/type-extractors/typescript.js +690 -0
  556. package/dist/core/code/engine/core/ingestion/utils/ast-helpers.js +1693 -0
  557. package/dist/core/code/engine/core/ingestion/utils/call-analysis.js +779 -0
  558. package/dist/core/code/engine/core/ingestion/utils/callable-flow-captures.js +932 -0
  559. package/dist/core/code/engine/core/ingestion/utils/callable-labels.js +49 -0
  560. package/dist/core/code/engine/core/ingestion/utils/deferred-resolution-profile.js +151 -0
  561. package/dist/core/code/engine/core/ingestion/utils/effective-ram.js +67 -0
  562. package/dist/core/code/engine/core/ingestion/utils/env.js +60 -0
  563. package/dist/core/code/engine/core/ingestion/utils/event-loop.js +9 -0
  564. package/dist/core/code/engine/core/ingestion/utils/graph-sort.js +103 -0
  565. package/dist/core/code/engine/core/ingestion/utils/heap-probe.js +45 -0
  566. package/dist/core/code/engine/core/ingestion/utils/heritage-marker.js +47 -0
  567. package/dist/core/code/engine/core/ingestion/utils/line-base.js +24 -0
  568. package/dist/core/code/engine/core/ingestion/utils/max-file-size.js +59 -0
  569. package/dist/core/code/engine/core/ingestion/utils/method-props.js +198 -0
  570. package/dist/core/code/engine/core/ingestion/utils/qualified-name.js +73 -0
  571. package/dist/core/code/engine/core/ingestion/utils/receiver-chain-captures.js +60 -0
  572. package/dist/core/code/engine/core/ingestion/utils/receiver-chain-codec.js +188 -0
  573. package/dist/core/code/engine/core/ingestion/utils/scope-tree-walk.js +36 -0
  574. package/dist/core/code/engine/core/ingestion/utils/symbol-labels.js +48 -0
  575. package/dist/core/code/engine/core/ingestion/utils/template-arguments.js +187 -0
  576. package/dist/core/code/engine/core/ingestion/utils/type-parameters.js +209 -0
  577. package/dist/core/code/engine/core/ingestion/utils/verbose.js +6 -0
  578. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/c-cpp.js +133 -0
  579. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/csharp.js +66 -0
  580. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/dart.js +111 -0
  581. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/go.js +153 -0
  582. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/jvm.js +145 -0
  583. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/php.js +61 -0
  584. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/python.js +104 -0
  585. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/ruby.js +55 -0
  586. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/rust.js +79 -0
  587. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/swift.js +91 -0
  588. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/typescript-javascript.js +86 -0
  589. package/dist/core/code/engine/core/ingestion/variable-extractors/generic.js +111 -0
  590. package/dist/core/code/engine/core/ingestion/variable-types.js +3 -0
  591. package/dist/core/code/engine/core/ingestion/vue-sfc-extractor.js +544 -0
  592. package/dist/core/code/engine/core/ingestion/workers/callable-id.js +122 -0
  593. package/dist/core/code/engine/core/ingestion/workers/clone-safety.js +470 -0
  594. package/dist/core/code/engine/core/ingestion/workers/parse-worker.js +2456 -0
  595. package/dist/core/code/engine/core/ingestion/workers/post-result.js +90 -0
  596. package/dist/core/code/engine/core/ingestion/workers/quarantine.js +41 -0
  597. package/dist/core/code/engine/core/ingestion/workers/result-merge.js +59 -0
  598. package/dist/core/code/engine/core/ingestion/workers/worker-pool.js +1725 -0
  599. package/dist/core/code/engine/core/ingestion/workspace-config.js +139 -0
  600. package/dist/core/code/engine/core/lbug/conn-lock.js +72 -0
  601. package/dist/core/code/engine/core/lbug/csv-generator.js +710 -0
  602. package/dist/core/code/engine/core/lbug/cypher-escape.js +24 -0
  603. package/dist/core/code/engine/core/lbug/extension-load-error.js +339 -0
  604. package/dist/core/code/engine/core/lbug/extension-loader.js +261 -0
  605. package/dist/core/code/engine/core/lbug/graph-emit-sink.js +584 -0
  606. package/dist/core/code/engine/core/lbug/lbug-adapter.js +2703 -0
  607. package/dist/core/code/engine/core/lbug/lbug-config.js +1029 -0
  608. package/dist/core/code/engine/core/lbug/native-check.js +435 -0
  609. package/dist/core/code/engine/core/lbug/pool-adapter.js +973 -0
  610. package/dist/core/code/engine/core/lbug/query-params.js +25 -0
  611. package/dist/core/code/engine/core/lbug/query-result-utils.js +31 -0
  612. package/dist/core/code/engine/core/lbug/rel-pair-routing.js +373 -0
  613. package/dist/core/code/engine/core/lbug/schema.js +771 -0
  614. package/dist/core/code/engine/core/lbug/shutdown-helpers.js +40 -0
  615. package/dist/core/code/engine/core/lbug/sidecar-recovery.js +716 -0
  616. package/dist/core/code/engine/core/lbug/stdio-capture.js +49 -0
  617. package/dist/core/code/engine/core/lbug/sync-csv-writer.js +115 -0
  618. package/dist/core/code/engine/core/lbug/wal-checkpoint-driver.js +215 -0
  619. package/dist/core/code/engine/core/lbug/wal-driver-state.js +28 -0
  620. package/dist/core/code/engine/core/logger.js +339 -0
  621. package/dist/core/code/engine/core/platform/capabilities.js +91 -0
  622. package/dist/core/code/engine/core/run-analyze.js +1098 -0
  623. package/dist/core/code/engine/core/tree-sitter/parser-loader.js +281 -0
  624. package/dist/core/code/engine/core/tree-sitter/safe-parse.js +258 -0
  625. package/dist/core/code/engine/core/tree-sitter/vendored-grammars.js +64 -0
  626. package/dist/core/code/engine/lib/utils.js +121 -0
  627. package/dist/core/code/engine/mcp/core/lbug-adapter.js +27 -0
  628. package/dist/core/code/engine/mcp/local/aop-metadata.js +230 -0
  629. package/dist/core/code/engine/mcp/local/bean-metadata.js +49 -0
  630. package/dist/core/code/engine/mcp/local/limits.js +15 -0
  631. package/dist/core/code/engine/mcp/local/line-display.js +6 -0
  632. package/dist/core/code/engine/mcp/local/local-backend.js +4142 -0
  633. package/dist/core/code/engine/storage/branch-index.js +72 -0
  634. package/dist/core/code/engine/storage/file-hash.js +95 -0
  635. package/dist/core/code/engine/storage/fs-atomic.js +34 -0
  636. package/dist/core/code/engine/storage/git.js +555 -0
  637. package/dist/core/code/engine/storage/index-lock.js +664 -0
  638. package/dist/core/code/engine/storage/parse-cache.js +650 -0
  639. package/dist/core/code/engine/storage/parsedfile-store.js +620 -0
  640. package/dist/core/code/engine/storage/repo-manager.js +1061 -0
  641. package/dist/core/code/engine/storage/scope-index-store.js +247 -0
  642. package/dist/core/code/engine/types/pipeline.js +2 -0
  643. package/dist/core/code/scripts/install-duckdb-extension.mjs +125 -0
  644. package/dist/core/code/scripts/resolve-analyze-cmd.cjs +346 -0
  645. package/dist/core/code/shared/graph/types.js +8 -0
  646. package/dist/core/code/shared/index.js +105 -0
  647. package/dist/core/code/shared/integrations/circuit-breaker.js +242 -0
  648. package/dist/core/code/shared/integrations/resilient-fetch.js +224 -0
  649. package/dist/core/code/shared/integrations/retry.js +70 -0
  650. package/dist/core/code/shared/integrations/understand-quickly.js +145 -0
  651. package/dist/core/code/shared/language-detection.js +162 -0
  652. package/dist/core/code/shared/languages.js +27 -0
  653. package/dist/core/code/shared/lbug/schema-constants.js +98 -0
  654. package/dist/core/code/shared/mro-strategy.js +2 -0
  655. package/dist/core/code/shared/pipeline.js +5 -0
  656. package/dist/core/code/shared/scope-resolution/callable-flow-site.js +11 -0
  657. package/dist/core/code/shared/scope-resolution/def-index.js +53 -0
  658. package/dist/core/code/shared/scope-resolution/evidence-weights.js +87 -0
  659. package/dist/core/code/shared/scope-resolution/finalize-algorithm.js +807 -0
  660. package/dist/core/code/shared/scope-resolution/language-classification.js +46 -0
  661. package/dist/core/code/shared/scope-resolution/method-dispatch-index.js +100 -0
  662. package/dist/core/code/shared/scope-resolution/module-scope-index.js +59 -0
  663. package/dist/core/code/shared/scope-resolution/origin-priority.js +23 -0
  664. package/dist/core/code/shared/scope-resolution/parsed-file.js +54 -0
  665. package/dist/core/code/shared/scope-resolution/position-index.js +136 -0
  666. package/dist/core/code/shared/scope-resolution/qualified-name-index.js +77 -0
  667. package/dist/core/code/shared/scope-resolution/reference-site.js +24 -0
  668. package/dist/core/code/shared/scope-resolution/registries/class-registry.js +32 -0
  669. package/dist/core/code/shared/scope-resolution/registries/context.js +52 -0
  670. package/dist/core/code/shared/scope-resolution/registries/evidence.js +152 -0
  671. package/dist/core/code/shared/scope-resolution/registries/field-registry.js +33 -0
  672. package/dist/core/code/shared/scope-resolution/registries/lookup-core.js +392 -0
  673. package/dist/core/code/shared/scope-resolution/registries/lookup-qualified.js +58 -0
  674. package/dist/core/code/shared/scope-resolution/registries/macro-registry.js +34 -0
  675. package/dist/core/code/shared/scope-resolution/registries/method-registry.js +34 -0
  676. package/dist/core/code/shared/scope-resolution/registries/tie-breaks.js +63 -0
  677. package/dist/core/code/shared/scope-resolution/resolve-type-ref.js +128 -0
  678. package/dist/core/code/shared/scope-resolution/scope-id.js +49 -0
  679. package/dist/core/code/shared/scope-resolution/scope-tree.js +225 -0
  680. package/dist/core/code/shared/scope-resolution/symbol-definition.js +12 -0
  681. package/dist/core/code/shared/scope-resolution/types.js +25 -0
  682. package/dist/core/code/shared/test-helpers.js +17 -0
  683. package/dist/core/code/vendor/leiden/index.cjs +355 -0
  684. package/dist/core/code/vendor/leiden/utils.cjs +419 -0
  685. package/dist/core/dbquery/cli.d.ts.map +1 -1
  686. package/dist/core/dbquery/cli.js +5 -4
  687. package/dist/core/dbquery/cli.js.map +1 -1
  688. package/dist/core/dbquery/config.d.ts.map +1 -1
  689. package/dist/core/dbquery/config.js +39 -3
  690. package/dist/core/dbquery/config.js.map +1 -1
  691. package/dist/core/dbquery/drivers/http.d.ts +23 -0
  692. package/dist/core/dbquery/drivers/http.d.ts.map +1 -0
  693. package/dist/core/dbquery/drivers/http.js +125 -0
  694. package/dist/core/dbquery/drivers/http.js.map +1 -0
  695. package/dist/core/dbquery/drivers/mysql.js +1 -1
  696. package/dist/core/dbquery/drivers/mysql.js.map +1 -1
  697. package/dist/core/dbquery/drivers/postgres.js +1 -1
  698. package/dist/core/dbquery/drivers/postgres.js.map +1 -1
  699. package/dist/core/dbquery/executor.d.ts.map +1 -1
  700. package/dist/core/dbquery/executor.js +46 -12
  701. package/dist/core/dbquery/executor.js.map +1 -1
  702. package/dist/core/dbquery/format.d.ts.map +1 -1
  703. package/dist/core/dbquery/format.js +2 -1
  704. package/dist/core/dbquery/format.js.map +1 -1
  705. package/dist/core/dbquery/init.d.ts.map +1 -1
  706. package/dist/core/dbquery/init.js +7 -0
  707. package/dist/core/dbquery/init.js.map +1 -1
  708. package/dist/core/dbquery/types.d.ts +55 -7
  709. package/dist/core/dbquery/types.d.ts.map +1 -1
  710. package/dist/core/directory.d.ts +17 -0
  711. package/dist/core/directory.d.ts.map +1 -1
  712. package/dist/core/directory.js +37 -0
  713. package/dist/core/directory.js.map +1 -1
  714. package/dist/core/features/cli.d.ts.map +1 -1
  715. package/dist/core/features/cli.js +3 -2
  716. package/dist/core/features/cli.js.map +1 -1
  717. package/dist/core/features/scanner.d.ts +1 -1
  718. package/dist/core/features/scanner.d.ts.map +1 -1
  719. package/dist/core/features/scanner.js +20 -4
  720. package/dist/core/features/scanner.js.map +1 -1
  721. package/dist/core/markdown/cli.d.ts.map +1 -1
  722. package/dist/core/markdown/cli.js +9 -8
  723. package/dist/core/markdown/cli.js.map +1 -1
  724. package/dist/core/timeline/cli.d.ts.map +1 -1
  725. package/dist/core/timeline/cli.js +13 -6
  726. package/dist/core/timeline/cli.js.map +1 -1
  727. package/dist/core/timeline/debris.d.ts +20 -0
  728. package/dist/core/timeline/debris.d.ts.map +1 -0
  729. package/dist/core/timeline/debris.js +124 -0
  730. package/dist/core/timeline/debris.js.map +1 -0
  731. package/dist/core/timeline/hook-runner.d.ts.map +1 -1
  732. package/dist/core/timeline/hook-runner.js +3 -1
  733. package/dist/core/timeline/hook-runner.js.map +1 -1
  734. package/dist/core/timeline/hooks.d.ts.map +1 -1
  735. package/dist/core/timeline/hooks.js +13 -5
  736. package/dist/core/timeline/hooks.js.map +1 -1
  737. package/dist/core/timeline/installer.d.ts +2 -0
  738. package/dist/core/timeline/installer.d.ts.map +1 -1
  739. package/dist/core/timeline/installer.js +12 -0
  740. package/dist/core/timeline/installer.js.map +1 -1
  741. package/dist/core/timeline/project-root.d.ts +21 -0
  742. package/dist/core/timeline/project-root.d.ts.map +1 -0
  743. package/dist/core/timeline/project-root.js +83 -0
  744. package/dist/core/timeline/project-root.js.map +1 -0
  745. package/dist/web/register.d.ts.map +1 -1
  746. package/dist/web/register.js +2 -1
  747. package/dist/web/register.js.map +1 -1
  748. package/package.json +1 -1
  749. package/dist/.claude-template/.cgraphx/timeline-current-turn.json +0 -1
  750. package/dist/.claude-template/skills/.cgraphx/timeline-current-turn.json +0 -1
  751. package/dist/.claude-template/skills/handdrawn-deck/.cgraphx/timeline-current-turn.json +0 -1
  752. package/dist/.claude-template/skills/handdrawn-deck/references/.cgraphx/timeline-current-turn.json +0 -1
  753. package/dist/.claude-template/skills/handdrawn-sketch-engine/.cgraphx/timeline-current-turn.json +0 -1
  754. /package/dist/.claude-template/skills/run-api-test/assets/{template-test-verify.jsonl → template-/346/216/245/345/217/243/346/265/213/350/257/225/351/252/214/350/257/201.jsonl"} +0 -0
@@ -0,0 +1,2456 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.extractORMQueries = extractORMQueries;
7
+ const node_worker_threads_1 = require("node:worker_threads");
8
+ const callable_id_js_1 = require("./callable-id.js");
9
+ const tree_sitter_1 = __importDefault(require("tree-sitter"));
10
+ const node_module_1 = require("node:module");
11
+ const tree_sitter_javascript_1 = __importDefault(require("tree-sitter-javascript"));
12
+ const tree_sitter_typescript_1 = __importDefault(require("tree-sitter-typescript"));
13
+ const tree_sitter_java_1 = __importDefault(require("tree-sitter-java"));
14
+ const vendored_grammars_js_1 = require("../../tree-sitter/vendored-grammars.js");
15
+ const index_js_1 = require("../../../../shared/index.js");
16
+ const index_js_2 = require("../languages/index.js");
17
+ const constants_js_1 = require("../constants.js");
18
+ const ts_js_hoc_utils_js_1 = require("../ts-js-hoc-utils.js");
19
+ const safe_parse_js_1 = require("../../tree-sitter/safe-parse.js");
20
+ const post_result_js_1 = require("./post-result.js");
21
+ const result_merge_js_1 = require("./result-merge.js");
22
+ // ── Worker grammar loading — enforcement boundary (#2091/#2093, #2101) ───────
23
+ // The worker maintains its own grammar table (the guarded vendored-grammar
24
+ // loads below + `languageMap`) and intentionally does NOT consult the runtime
25
+ // `CGRAPH_SKIP_OPTIONAL_GRAMMARS` opt-out. It does not need to: the MAIN
26
+ // THREAD's `parseableScanned` filter (pipeline-phases/parse-impl.ts, gated on
27
+ // `parser-loader.isLanguageAvailable`, which honors the runtime opt-out and a
28
+ // genuinely-absent binding alike) excludes files of an unavailable/opted-out
29
+ // language BEFORE any chunk is dispatched, so the worker never receives them.
30
+ // That main-thread filter is the single enforcement point. Any future change
31
+ // that dispatches files to the worker WITHOUT first passing them through
32
+ // `isLanguageAvailable` must re-introduce the gate here. (The cleaner end-state
33
+ // — routing this table through `parser-loader.getLanguageGrammar` so there is
34
+ // one loader — is the deferred Tier-1 consolidation.)
35
+ // Swift/Dart/Kotlin/C are vendored grammars loaded from `vendor/` by absolute
36
+ // path (NEVER copied into node_modules — see vendored-grammars.ts / #2111). Each
37
+ // may be absent on a platform without a prebuild or a toolchain-less /
38
+ // `--ignore-scripts` install, so every load is guarded so a missing binding
39
+ // cannot crash the worker at module-load (#2091/#2093, #2116).
40
+ let Swift = null;
41
+ try {
42
+ Swift = (0, vendored_grammars_js_1.requireVendoredGrammar)('tree-sitter-swift');
43
+ }
44
+ catch { }
45
+ let Dart = null;
46
+ try {
47
+ Dart = (0, vendored_grammars_js_1.requireVendoredGrammar)('tree-sitter-dart');
48
+ }
49
+ catch { }
50
+ let Kotlin = null;
51
+ try {
52
+ Kotlin = (0, vendored_grammars_js_1.requireVendoredGrammar)('tree-sitter-kotlin');
53
+ }
54
+ catch { }
55
+ let C = null;
56
+ try {
57
+ C = (0, vendored_grammars_js_1.requireVendoredGrammar)('tree-sitter-c');
58
+ }
59
+ catch { }
60
+ // ── 非 v1 语法包懒加载(spec §7/§13)─────────────────────────────────────────
61
+ // v1 仅 java/js/ts 三个语法包随生产依赖分发;python/csharp/cpp/go/rust/php/ruby
62
+ // 7 个包移至 devDependencies,生产 --omit=dev 不装。worker 首次用到某语言时按需
63
+ // require 并缓存:成功 → 语法对象;失败(MODULE_NOT_FOUND)→ null → 该语言降级为
64
+ // "不解析,文件按结构层收录"(spec §7 末条),不阻断 analyze。开发/测试环境 devDeps
65
+ // 装齐 10 个语法包,行为与原静态 import 完全一致。守护模式参照 parser-loader.ts
66
+ // 的 requireVendoredGrammar / _require(createRequire + 缓存 + try/catch)。
67
+ const _require = (0, node_module_1.createRequire)(__filename);
68
+ const NON_V1_GRAMMAR_LOADERS = {
69
+ [index_js_1.SupportedLanguages.Python]: () => _require('tree-sitter-python'),
70
+ [index_js_1.SupportedLanguages.CPlusPlus]: () => _require('tree-sitter-cpp'),
71
+ // 显式 subpath 导入 — 理由见 parser-loader.ts(#1013)。
72
+ [index_js_1.SupportedLanguages.CSharp]: () => _require('tree-sitter-c-sharp/bindings/node/index.js'),
73
+ [index_js_1.SupportedLanguages.Go]: () => _require('tree-sitter-go'),
74
+ [index_js_1.SupportedLanguages.Rust]: () => _require('tree-sitter-rust'),
75
+ [index_js_1.SupportedLanguages.PHP]: () => _require('tree-sitter-php').php_only,
76
+ [index_js_1.SupportedLanguages.Ruby]: () => _require('tree-sitter-ruby'),
77
+ };
78
+ const lazyGrammarCache = new Map();
79
+ const loadNonV1Grammar = (key) => {
80
+ const cached = lazyGrammarCache.get(key);
81
+ if (cached !== undefined)
82
+ return cached;
83
+ const loader = NON_V1_GRAMMAR_LOADERS[key];
84
+ let result = null;
85
+ if (loader) {
86
+ try {
87
+ result = loader();
88
+ }
89
+ catch {
90
+ // 包未装(生产 --omit=dev)或原生绑定损坏 → 降级为不解析,不抛错。
91
+ result = null;
92
+ }
93
+ }
94
+ lazyGrammarCache.set(key, result);
95
+ return result;
96
+ };
97
+ const index_js_3 = require("../../../../shared/index.js");
98
+ const ast_helpers_js_1 = require("../utils/ast-helpers.js");
99
+ const callable_labels_js_1 = require("../utils/callable-labels.js");
100
+ const call_analysis_js_1 = require("../utils/call-analysis.js");
101
+ const type_env_js_1 = require("../type-env.js");
102
+ const framework_detection_js_1 = require("../framework-detection.js");
103
+ const utils_js_1 = require("../../../lib/utils.js");
104
+ const cjs_export_assignment_js_1 = require("../languages/typescript/cjs-export-assignment.js");
105
+ const vue_sfc_extractor_js_1 = require("../vue-sfc-extractor.js");
106
+ const method_props_js_1 = require("../utils/method-props.js");
107
+ const template_arguments_js_1 = require("../utils/template-arguments.js");
108
+ const scope_extractor_bridge_js_1 = require("../scope-extractor-bridge.js");
109
+ const parsedfile_store_js_1 = require("../../../storage/parsedfile-store.js");
110
+ const laravel_js_1 = require("../route-extractors/laravel.js");
111
+ const collect_js_1 = require("../cfg/collect.js");
112
+ const logger_js_1 = require("../../logger.js");
113
+ // ── ParsedFile store (#1983 parallel serialization) ─────────────────────────
114
+ // Read ONCE at worker init from `workerData` (immutable for the run, inherited
115
+ // by respawned workers via the pool's factory closure). When set, this worker
116
+ // writes its own ParsedFile shards to disk at each job flush instead of
117
+ // returning them over the MessageChannel — parallelizing serialization off the
118
+ // main thread. `undefined` ⇒ return ParsedFiles in the result (no-store
119
+ // fallback). `shardSeq` makes each shard name unique within this worker; global
120
+ // uniqueness for the run rests on the process-monotonic `threadId` (never reused
121
+ // across respawns) plus the per-run store clear on the main thread.
122
+ const PARSED_FILE_STORE_STORAGE_PATH = node_worker_threads_1.workerData?.parsedFileStoreStoragePath;
123
+ // Durable, content-addressed ParsedFile store dir (#2038 warm-cache coverage).
124
+ // When set AND the flush carries a chunk hash, the worker ALSO writes its
125
+ // ParsedFiles to `<durableDir>/<chunkHash>/` so a future warm parse-cache hit
126
+ // restores them without re-parsing. `undefined` ⇒ no durable write.
127
+ const DURABLE_PARSED_FILE_STORAGE_PATH = node_worker_threads_1.workerData?.durableParsedFileStoragePath;
128
+ let shardSeq = 0;
129
+ // ── PDG/CFG opt-in (#2081 M1) ───────────────────────────────────────────────
130
+ // Read ONCE at worker init from `workerData` (the worker never sees
131
+ // PipelineOptions — config arrives via the pool factory's `workerData`, see
132
+ // KTD7 / U5). When `pdg` is set, the worker builds a per-function control-flow
133
+ // graph from the tree-sitter AST (where it lives) and serializes it onto
134
+ // `ParsedFile.cfgSideChannel`. Off ⇒ no CFG work and no field — the default for
135
+ // every run today. `pdgMaxFunctionLines` bounds per-function CFG cost
136
+ // (0/undefined ⇒ no cap; see collectFunctionCfgs).
137
+ const PDG_ENABLED = node_worker_threads_1.workerData?.pdg === true;
138
+ const PDG_MAX_FUNCTION_LINES = node_worker_threads_1.workerData?.pdgMaxFunctionLines ??
139
+ collect_js_1.DEFAULT_PDG_MAX_FUNCTION_LINES;
140
+ // ── Bootstrap-stage diagnostics (#1741) ────────────────────────────────────
141
+ // When CGRAPH_WORKER_BOOTSTRAP=1 (or --verbose sets CGRAPH_VERBOSE), each
142
+ // worker reports its startup stage timings to stderr — which the pool tees
143
+ // and captures (worker-pool.ts captureWorkerStderr). This makes a slow or
144
+ // crashing startup diagnosable: you can see whether a worker reached
145
+ // "grammars loaded", "ready sent", or never emitted a line at all (=> it
146
+ // crashed in a native binding load before this code ran). The pool then
147
+ // attaches whatever stderr it captured to its readiness-failure message,
148
+ // so the operator sees the real cause instead of "did not report ready".
149
+ const BOOTSTRAP_LOG = process.env.CGRAPH_WORKER_BOOTSTRAP === '1' || process.env.CGRAPH_VERBOSE === '1';
150
+ const bootstrapStart = performance.now();
151
+ const bootstrapLog = (stage) => {
152
+ if (!BOOTSTRAP_LOG)
153
+ return;
154
+ const ms = Math.round(performance.now() - bootstrapStart);
155
+ process.stderr.write(`[parse-worker bootstrap] thread=${node_worker_threads_1.threadId} ${stage} (+${ms}ms)\n`);
156
+ };
157
+ // First line we can emit: every static import above (tree-sitter native
158
+ // runtime, v1 language grammars [java/js/ts], vendored grammars, helper
159
+ // modules) has already resolved by the time this module-body statement runs.
160
+ // 非 v1 语法包(python/cpp/csharp/go/rust/php/ruby)按需懒加载(spec §7/§13),
161
+ // 不在此阶段载入。
162
+ bootstrapLog('imports + grammars loaded');
163
+ // ============================================================================
164
+ // Worker-local parser + language map
165
+ // ============================================================================
166
+ const parser = new tree_sitter_1.default();
167
+ // v1 语法(java/js/ts/vue[复用 ts])与受保护 vendored 语法(swift/dart/kotlin/c)在
168
+ // 模块加载时已就绪(或为 null),直接入静态表。非 v1 语法(python/cpp/csharp/go/rust/
169
+ // php/ruby)不在此表,由 loadNonV1Grammar 按需解析(spec §7/§13)。
170
+ const languageMap = {
171
+ [index_js_1.SupportedLanguages.JavaScript]: tree_sitter_javascript_1.default,
172
+ [index_js_1.SupportedLanguages.TypeScript]: tree_sitter_typescript_1.default.typescript,
173
+ [`${index_js_1.SupportedLanguages.TypeScript}:tsx`]: tree_sitter_typescript_1.default.tsx,
174
+ [index_js_1.SupportedLanguages.Java]: tree_sitter_java_1.default,
175
+ [index_js_1.SupportedLanguages.Vue]: tree_sitter_typescript_1.default.typescript,
176
+ ...(C ? { [index_js_1.SupportedLanguages.C]: C } : {}),
177
+ ...(Kotlin ? { [index_js_1.SupportedLanguages.Kotlin]: Kotlin } : {}),
178
+ ...(Dart ? { [index_js_1.SupportedLanguages.Dart]: Dart } : {}),
179
+ ...(Swift ? { [index_js_1.SupportedLanguages.Swift]: Swift } : {}),
180
+ };
181
+ /**
182
+ * 解析 worker 语法:先查静态表(v1 + 受保护 vendored),命中即返;否则查非 v1 懒加载
183
+ * 表(首次用到时 require + 缓存)。包未装时返回 null,由调用方降级为结构层收录。
184
+ */
185
+ const resolveWorkerGrammar = (key) => {
186
+ const staticGrammar = languageMap[key];
187
+ if (staticGrammar != null)
188
+ return staticGrammar;
189
+ return loadNonV1Grammar(key);
190
+ };
191
+ /**
192
+ * Check if a language grammar is available in this worker.
193
+ * Duplicated from parser-loader.ts because workers can't import from the main thread.
194
+ * Extra filePath parameter needed to distinguish .tsx from .ts (different grammars
195
+ * under the same SupportedLanguages.TypeScript key).
196
+ */
197
+ const isLanguageAvailable = (language, filePath) => {
198
+ const key = language === index_js_1.SupportedLanguages.TypeScript && filePath.endsWith('.tsx')
199
+ ? `${language}:tsx`
200
+ : language;
201
+ return resolveWorkerGrammar(key) != null;
202
+ };
203
+ const setLanguage = (language, filePath) => {
204
+ const key = language === index_js_1.SupportedLanguages.TypeScript && filePath.endsWith('.tsx')
205
+ ? `${language}:tsx`
206
+ : language;
207
+ const lang = resolveWorkerGrammar(key);
208
+ if (!lang)
209
+ throw new Error(`Unsupported language: ${language}`);
210
+ parser.setLanguage(lang);
211
+ };
212
+ // ============================================================================
213
+ // Per-file O(1) memoization — avoids repeated parent-chain walks per symbol.
214
+ // Three bare Maps cleared at file boundaries. Map.get() returns undefined for
215
+ // missing keys, so `cached !== undefined` distinguishes "not computed" from
216
+ // a stored null (enclosing class/function not found = top-level).
217
+ // ============================================================================
218
+ const classIdCache = new Map();
219
+ const functionIdCache = new Map();
220
+ const exportCache = new Map();
221
+ const clearCaches = () => {
222
+ classIdCache.clear();
223
+ functionIdCache.clear();
224
+ exportCache.clear();
225
+ fieldInfoCache.clear();
226
+ methodInfoCache.clear();
227
+ };
228
+ // ============================================================================
229
+ // FieldExtractor cache — extract field metadata once per class, reuse for each property.
230
+ // Keyed by class node startIndex (unique per AST node within a file).
231
+ // ============================================================================
232
+ const fieldInfoCache = new Map();
233
+ /**
234
+ * Walk up from a definition node to find the nearest enclosing class/struct/interface
235
+ * AST node. Returns the SyntaxNode itself (not an ID) for passing to FieldExtractor.
236
+ */
237
+ function findEnclosingClassNode(node) {
238
+ let current = node.parent;
239
+ while (current) {
240
+ if (ast_helpers_js_1.CLASS_CONTAINER_TYPES.has(current.type)) {
241
+ // Return singleton_class directly so the method extractor sees it as
242
+ // the owner node and correctly marks methods as static. Name resolution
243
+ // for qualified names is handled separately by findEnclosingClassInfo.
244
+ return current;
245
+ }
246
+ current = current.parent;
247
+ }
248
+ return null;
249
+ }
250
+ /**
251
+ * For C++ out-of-class method definitions (e.g. `void Foo::bar() {}`), extract the
252
+ * class name from the qualified_identifier scope and find the class declaration in the
253
+ * file's AST. Returns the class SyntaxNode or null if not found.
254
+ *
255
+ * Handles pointer/reference return types where function_declarator is nested inside
256
+ * pointer_declarator or reference_declarator.
257
+ */
258
+ function findClassNodeByQualifiedName(node) {
259
+ const declarator = node.childForFieldName('declarator');
260
+ if (!declarator)
261
+ return null;
262
+ // Find the function_declarator, recursively unwrapping pointer_declarator /
263
+ // reference_declarator chains (e.g. int** Foo::bar() has
264
+ // pointer_declarator → pointer_declarator → function_declarator).
265
+ let funcDecl = null;
266
+ if (declarator.type === 'function_declarator') {
267
+ funcDecl = declarator;
268
+ }
269
+ else {
270
+ let current = declarator;
271
+ while (current && !funcDecl) {
272
+ for (let i = 0; i < current.namedChildCount; i++) {
273
+ const child = current.namedChild(i);
274
+ if (child?.type === 'function_declarator') {
275
+ funcDecl = child;
276
+ break;
277
+ }
278
+ }
279
+ if (!funcDecl) {
280
+ const next = current.namedChildren.find((c) => c.type === 'pointer_declarator' || c.type === 'reference_declarator');
281
+ current = next ?? null;
282
+ }
283
+ }
284
+ }
285
+ if (!funcDecl)
286
+ return null;
287
+ // Check if the inner declarator is a qualified_identifier (Foo::bar)
288
+ const innerDecl = funcDecl.childForFieldName('declarator');
289
+ if (!innerDecl || innerDecl.type !== 'qualified_identifier')
290
+ return null;
291
+ const scope = innerDecl.childForFieldName('scope');
292
+ if (!scope)
293
+ return null;
294
+ const className = scope.text;
295
+ // Search the file for a matching class/struct specifier, including inside
296
+ // namespace_definition blocks (the majority of production C++ uses namespaces).
297
+ const root = node.tree.rootNode;
298
+ const classTypes = new Set(['class_specifier', 'struct_specifier']);
299
+ const searchIn = (parent) => {
300
+ for (let i = 0; i < parent.namedChildCount; i++) {
301
+ const child = parent.namedChild(i);
302
+ if (!child)
303
+ continue;
304
+ if (classTypes.has(child.type)) {
305
+ const nameNode = child.childForFieldName('name');
306
+ if (nameNode?.text === className)
307
+ return child;
308
+ }
309
+ // Recurse into namespace blocks
310
+ if (child.type === 'namespace_definition') {
311
+ const found = searchIn(child);
312
+ if (found)
313
+ return found;
314
+ }
315
+ }
316
+ return null;
317
+ };
318
+ return searchIn(root);
319
+ }
320
+ /**
321
+ * Minimal no-op SymbolTable stub for FieldExtractorContext in the worker.
322
+ * Field extraction only uses symbolTable.lookupExactAll for optional type
323
+ * resolution — returning [] causes the extractor to use the raw type
324
+ * string, which is fine for us. Every other method is a no-op so the
325
+ * stub remains safe if a future FieldExtractor consults it through the
326
+ * full {@link SymbolTableReader} surface.
327
+ */
328
+ const NOOP_SYMBOL_TABLE = {
329
+ lookupExact: () => undefined,
330
+ lookupExactFull: () => undefined,
331
+ lookupExactAll: () => [],
332
+ lookupCallableByName: () => [],
333
+ getFiles: () => [][Symbol.iterator](),
334
+ getStats: () => ({ fileCount: 0 }),
335
+ };
336
+ /**
337
+ * Get (or extract and cache) field info for a class node.
338
+ * Returns a name→FieldInfo map, or undefined if the provider has no field extractor
339
+ * or the class yielded no fields.
340
+ */
341
+ function getFieldInfo(classNode, provider, context) {
342
+ if (!provider.fieldExtractor)
343
+ return undefined;
344
+ const cacheKey = classNode.startIndex;
345
+ let cached = fieldInfoCache.get(cacheKey);
346
+ if (cached)
347
+ return cached;
348
+ const result = provider.fieldExtractor.extract(classNode, context);
349
+ if (!result?.fields?.length)
350
+ return undefined;
351
+ cached = new Map();
352
+ for (const field of result.fields) {
353
+ cached.set(field.name, field);
354
+ }
355
+ fieldInfoCache.set(cacheKey, cached);
356
+ return cached;
357
+ }
358
+ // ============================================================================
359
+ // MethodExtractor cache — extract method metadata once per class, reuse for each method.
360
+ // Keyed by class node startIndex (unique per AST node within a file).
361
+ // ============================================================================
362
+ const methodInfoCache = new Map();
363
+ /**
364
+ * Get (or extract and cache) method info for a class node.
365
+ * Returns a "name:line" → MethodInfo map, or undefined if the provider has no method extractor
366
+ * or the class yielded no methods.
367
+ * Keyed by name:line (not name alone) to support overloaded methods in Java/Kotlin.
368
+ */
369
+ function getMethodInfo(classNode, provider, context) {
370
+ if (!provider.methodExtractor)
371
+ return undefined;
372
+ const cacheKey = classNode.startIndex;
373
+ let cached = methodInfoCache.get(cacheKey);
374
+ if (cached)
375
+ return cached;
376
+ const result = provider.methodExtractor.extract(classNode, context);
377
+ if (!result?.methods?.length)
378
+ return undefined;
379
+ cached = new Map();
380
+ for (const method of result.methods) {
381
+ cached.set(`${method.name}:${method.line}`, method);
382
+ }
383
+ methodInfoCache.set(cacheKey, cached);
384
+ return cached;
385
+ }
386
+ // ============================================================================
387
+ // Enclosing function detection (for call extraction) — cached
388
+ // ============================================================================
389
+ /**
390
+ * Qualified-name prefix naming the enclosing CALLABLE chain of `node`, or
391
+ * `undefined` when nothing callable encloses it (#2699).
392
+ *
393
+ * Graph node ids are file-scoped, so before this a function-local callable and
394
+ * a file-level one with the same name collapsed onto a single node: a
395
+ * top-level `save()` and `run() { const save = … }` both keyed
396
+ * `Function:<file>:save`, and `run`'s call to its OWN local was attributed to
397
+ * the top-level function — a wrong edge, not a missing one, so `impact` on
398
+ * `save` reported a caller that never calls it. Qualifying the local as
399
+ * `run.save` separates them, mirroring how class members already qualify as
400
+ * `Class.member` (and SCIP's document-scoped `local <id>` keyspace).
401
+ *
402
+ * **This pair is the lockstep guarantee.** The definition phase and the
403
+ * caller-attribution phase (`findEnclosingFunctionId`) each build ids
404
+ * independently, and an id they compute differently is not a test failure —
405
+ * it is a caller silently attaching to a node that does not exist, and the
406
+ * edge vanishing. Both phases therefore derive the nesting prefix from THIS
407
+ * function and nothing else. Keep it that way: any per-phase variation here
408
+ * fails silently.
409
+ *
410
+ * Only a callable that is genuinely nested inside another callable gains a
411
+ * prefix. Top-level functions and ordinary class methods hit the `null` branch
412
+ * and keep their existing ids byte-for-byte, which is what bounds the id churn
413
+ * this change forces.
414
+ *
415
+ * `localIdentity` completes it, and both it and the shared
416
+ * `nestedCallableQualifiedName` rule now live in `./callable-id.ts`: this
417
+ * module posts a `ready` message to `parentPort` at import, so a unit test
418
+ * cannot value-import it, and a rule three phases must agree on has to be
419
+ * testable rather than merely commented (#2714).
420
+ */
421
+ /**
422
+ * Boundary for the enclosing-callable walk (#2699).
423
+ *
424
+ * `CLASS_CONTAINER_TYPES` lists class DECLARATIONS only. A class can also own
425
+ * members without any declaration node — Java anonymous classes
426
+ * (`object_creation_expression > class_body`), enum-constant bodies, and
427
+ * interface/annotation bodies — and those owners must still stop the walk, or a
428
+ * member of one gets re-keyed as a function-local of the surrounding method.
429
+ *
430
+ * (The dead `NO_QUALIFIED_NAME` sentinel that used to sit below this — which also
431
+ * contained a literal NUL byte — was removed; the cache is two-state: absent =
432
+ * not yet computed, any string = computed.)
433
+ */
434
+ const CALLABLE_PREFIX_BOUNDARY_TYPES = new Set([
435
+ ...ast_helpers_js_1.CLASS_CONTAINER_TYPES,
436
+ // Class bodies (Java, JS/TS, Kotlin) — the owner when the declaration is
437
+ // anonymous or the grammar nests members under a body node.
438
+ 'class_body',
439
+ 'interface_body',
440
+ 'annotation_type_body',
441
+ 'enum_body',
442
+ 'enum_body_declarations',
443
+ 'enum_constant',
444
+ // Anonymous-class construction sites.
445
+ 'object_creation_expression', // Java: new Runnable() { ... }
446
+ 'object_literal', // Kotlin: object : Runnable { ... }
447
+ 'anonymous_object_creation_expression', // C#
448
+ ]);
449
+ const enclosingCallablePrefix = (node, filePath, provider) => {
450
+ // Boundary on class-likes: a method's owner is its CLASS, not whatever
451
+ // function that class happens to sit inside. `CLASS_CONTAINER_TYPES` alone is
452
+ // NOT enough for that — it lists only DECLARATION nodes, and an anonymous or
453
+ // body-form class has none. A Java anonymous class is
454
+ // `object_creation_expression > class_body > method_declaration` with no
455
+ // `class_declaration` anywhere, so the walk sailed straight through it to the
456
+ // enclosing method and re-keyed `Worker$1.run` as `Worker.makeHandler.run@7:12`,
457
+ // destroying the javac-compatible JLS identity of #2550/#2555/#2562 (4 existing
458
+ // Java tests). Adding the body/anonymous forms restores the boundary.
459
+ //
460
+ // Over-inclusion here is the SAFE direction: an extra boundary only suppresses
461
+ // the nesting prefix, which falls back to the pre-#2699 class qualification.
462
+ const fnNode = (0, ast_helpers_js_1.findAncestorBeforeBoundary)(node, ast_helpers_js_1.LOCAL_SCOPE_BODY_NODE_TYPES, CALLABLE_PREFIX_BOUNDARY_TYPES) ??
463
+ // Signature/body-split grammars: the enclosing callable is a SIBLING of the
464
+ // body, not an ancestor, so the walk above returns null for every local
465
+ // inside it. Dart is the case in hand (`function_signature` +
466
+ // `function_body` as siblings) — without this a Dart closure gets no
467
+ // prefix, so two same-named closures in one file collapse onto ONE node and
468
+ // the graph asserts a CALLS edge that does not exist in the source (#2699).
469
+ //
470
+ // SPLIT_SIGNATURE_NODE_TYPES, NOT FUNCTION_NODE_TYPES: only a callable that
471
+ // cannot hold its own body can be an enclosing callable of a SIBLING. Using
472
+ // the wider set mis-qualified a file-level PHP `$handler = function …` as
473
+ // `target.$handler` by grabbing the preceding `function target() {…}`.
474
+ (0, ast_helpers_js_1.findSplitBodyCallableAncestor)(node, ast_helpers_js_1.SPLIT_SIGNATURE_NODE_TYPES, CALLABLE_PREFIX_BOUNDARY_TYPES);
475
+ if (fnNode === null)
476
+ return undefined;
477
+ return callableOwnQualifiedName(fnNode, filePath, provider);
478
+ };
479
+ /**
480
+ * A callable node's own qualified name, including its enclosing-callable chain.
481
+ * Mutually recursive with `enclosingCallablePrefix`; recursion depth is source
482
+ * nesting depth and every level is memoized, so a file costs O(callables).
483
+ *
484
+ * An ANONYMOUS callable still gets a name — its own source position
485
+ * (`fn@12:9`). ECMAScript creates an environment record for EVERY function
486
+ * whether or not it has a name, so the `save` in
487
+ * `outer() { (function () { const save = … })() }` is a genuinely distinct
488
+ * binding from a file-level `save`. Name-only qualification cannot express
489
+ * that; position can. It is unique by construction (two functions cannot start
490
+ * at the same offset) and deterministic across reparses of the same source.
491
+ * Same reasoning as clang's USR for a function-local (`name@offset`) and
492
+ * Kythe's C++ indexer: a local is not addressable from outside its document,
493
+ * so its identity only has to be unique within it, and source position is the
494
+ * cheapest thing that is. NOT SCIP — SCIP's `local <id>` is a per-document
495
+ * counter and the spec is explicit that locals do not encode the name, so it
496
+ * is prior art for the document-scoped keyspace but not for this key shape.
497
+ */
498
+ const callableOwnQualifiedName = (fnNode, filePath, provider) => {
499
+ const cached = callableQualifiedNameCache.get(fnNode);
500
+ if (cached !== undefined)
501
+ return cached;
502
+ const efnResult = provider.methodExtractor?.extractFunctionName?.(fnNode, filePath);
503
+ // An anonymous callable has no name of its own, so it IS its position: the
504
+ // `ownName === null` branch below carries the position INSTEAD of a name,
505
+ // never in addition to one, so the two spellings cannot stack.
506
+ const ownName = efnResult?.funcName ?? (0, ast_helpers_js_1.genericFuncName)(fnNode) ?? null;
507
+ const prefix = enclosingCallablePrefix(fnNode, filePath, provider);
508
+ const classInfo = prefix === undefined
509
+ ? cachedFindEnclosingClassInfo(fnNode, filePath, provider.resolveEnclosingOwner)
510
+ : null;
511
+ const owner = prefix ?? classInfo?.className;
512
+ const result = prefix !== undefined
513
+ ? (0, callable_id_js_1.nestedCallableQualifiedName)(prefix, fnNode, ownName ?? 'fn')
514
+ : ownName === null
515
+ ? (0, callable_id_js_1.localIdentity)(fnNode, 'fn')
516
+ : owner
517
+ ? `${owner}.${ownName}`
518
+ : ownName;
519
+ callableQualifiedNameCache.set(fnNode, result);
520
+ return result;
521
+ };
522
+ /** Sentinel distinguishing "computed, anonymous" from "not yet computed". */
523
+ const callableQualifiedNameCache = new WeakMap();
524
+ /** Walk up AST to find enclosing function, return its generateId or null for top-level.
525
+ * Applies provider.labelOverride so the label matches the definition phase (single source of truth). */
526
+ const findEnclosingFunctionId = (node, filePath, provider) => {
527
+ const cached = functionIdCache.get(node);
528
+ if (cached !== undefined)
529
+ return cached;
530
+ let current = node.parent;
531
+ while (current) {
532
+ if (ast_helpers_js_1.FUNCTION_NODE_TYPES.has(current.type)) {
533
+ const efnResult = provider.methodExtractor?.extractFunctionName?.(current, filePath);
534
+ const funcName = efnResult?.funcName ?? (0, ast_helpers_js_1.genericFuncName)(current);
535
+ const label = efnResult?.label ?? (0, ast_helpers_js_1.inferFunctionLabel)(current.type);
536
+ if (funcName) {
537
+ // Apply labelOverride so label matches definition phase (e.g., Kotlin Function→Method).
538
+ // null means "skip as definition" — keep original label for scope identification.
539
+ let finalLabel = label;
540
+ if (provider.labelOverride) {
541
+ const override = provider.labelOverride(current, label);
542
+ if (override !== null)
543
+ finalLabel = override;
544
+ }
545
+ // Qualify with enclosing class to match definition-phase node IDs
546
+ const classInfo = cachedFindEnclosingClassInfo(current, filePath, provider.resolveEnclosingOwner);
547
+ const encLang = (0, index_js_3.getLanguageFromFilename)(filePath);
548
+ const standaloneMethodInfo = (finalLabel === 'Method' || finalLabel === 'Constructor') &&
549
+ encLang === index_js_1.SupportedLanguages.Go &&
550
+ provider.methodExtractor?.extractFromNode
551
+ ? provider.methodExtractor.extractFromNode(current, {
552
+ filePath,
553
+ language: encLang,
554
+ })
555
+ : null;
556
+ // A nested callable is qualified by its enclosing callable (#2699) and
557
+ // wins over the class/receiver owner: a closure inside a method belongs
558
+ // to the METHOD, not directly to the class, and a Go receiver method can
559
+ // never itself be nested inside another callable.
560
+ const nestedPrefix = enclosingCallablePrefix(current, filePath, provider);
561
+ const ownerName = nestedPrefix ?? classInfo?.className ?? standaloneMethodInfo?.receiverType ?? undefined;
562
+ // Lockstep with the other two id-building phases — see
563
+ // `nestedCallableQualifiedName`, which is the shared rule. When a
564
+ // nested prefix exists it IS `ownerName`, so this branch and the
565
+ // owner branch below cannot disagree about which prefix applies.
566
+ const qualifiedName = nestedPrefix !== undefined
567
+ ? (0, callable_id_js_1.nestedCallableQualifiedName)(nestedPrefix, current, funcName)
568
+ : ownerName
569
+ ? `${ownerName}.${funcName}`
570
+ : funcName;
571
+ // Include #<arity> suffix to match definition-phase Method/Constructor IDs.
572
+ // Use the same MethodExtractor (getMethodInfo) as the definition phase.
573
+ // When same-arity collisions exist, also append ~type1,type2.
574
+ let arity;
575
+ let encTypeTag = '';
576
+ if (finalLabel === 'Method' || finalLabel === 'Constructor') {
577
+ if (standaloneMethodInfo) {
578
+ arity = standaloneMethodInfo.parameters.some((p) => p.isVariadic)
579
+ ? undefined
580
+ : standaloneMethodInfo.parameters.length;
581
+ }
582
+ else {
583
+ const classNode = findEnclosingClassNode(current) ?? findClassNodeByQualifiedName(current);
584
+ if (classNode && encLang) {
585
+ const methodMap = getMethodInfo(classNode, provider, {
586
+ filePath,
587
+ language: encLang,
588
+ });
589
+ const defLine = current.startPosition.row + 1;
590
+ const info = methodMap?.get(`${funcName}:${defLine}`);
591
+ if (info) {
592
+ arity = info.parameters.some((p) => p.isVariadic)
593
+ ? undefined
594
+ : info.parameters.length;
595
+ if (methodMap && arity !== undefined) {
596
+ const g = (0, method_props_js_1.buildCollisionGroups)(methodMap);
597
+ encTypeTag =
598
+ (0, method_props_js_1.typeTagForId)(methodMap, funcName, arity, info, encLang, g) +
599
+ (0, method_props_js_1.constTagForId)(methodMap, funcName, arity, info, g);
600
+ }
601
+ }
602
+ }
603
+ }
604
+ }
605
+ const arityTag = arity !== undefined ? `#${arity}${encTypeTag}` : '';
606
+ const result = (0, utils_js_1.generateId)(finalLabel, `${filePath}:${qualifiedName}${arityTag}`);
607
+ functionIdCache.set(node, result);
608
+ return result;
609
+ }
610
+ }
611
+ // Language-specific enclosing function resolution (e.g., Dart where
612
+ // function_body is a sibling of function_signature, not a child).
613
+ if (provider.enclosingFunctionFinder) {
614
+ const customResult = provider.enclosingFunctionFinder(current);
615
+ if (customResult) {
616
+ let finalLabel = customResult.label;
617
+ if (provider.labelOverride) {
618
+ const override = provider.labelOverride(current.previousSibling, finalLabel);
619
+ if (override !== null)
620
+ finalLabel = override;
621
+ }
622
+ // Qualify custom result with enclosing class
623
+ const classInfo = cachedFindEnclosingClassInfo(current.previousSibling ?? current, filePath, provider.resolveEnclosingOwner);
624
+ // Same nesting rule as the generic branch above (#2699). Anchored on
625
+ // `sigNode`-equivalent (`current.previousSibling ?? current`) so Dart,
626
+ // whose body is a SIBLING of the signature, walks from the same node
627
+ // the class lookup already uses.
628
+ const nestedPrefix2 = enclosingCallablePrefix(current.previousSibling ?? current, filePath, provider);
629
+ const customOwner = nestedPrefix2 ?? classInfo?.className;
630
+ const qualifiedName = customOwner
631
+ ? `${customOwner}.${customResult.funcName}`
632
+ : customResult.funcName;
633
+ // Include #<arity> suffix to match definition-phase Method/Constructor IDs.
634
+ // When same-arity collisions exist, also append ~type1,type2.
635
+ const sigNode = current.previousSibling ?? current;
636
+ let arity2;
637
+ let encTypeTag2 = '';
638
+ if (finalLabel === 'Method' || finalLabel === 'Constructor') {
639
+ const encLang2 = (0, index_js_3.getLanguageFromFilename)(filePath);
640
+ const classNode2 = findEnclosingClassNode(sigNode) ?? findClassNodeByQualifiedName(sigNode);
641
+ if (classNode2 && encLang2) {
642
+ const methodMap2 = getMethodInfo(classNode2, provider, {
643
+ filePath,
644
+ language: encLang2,
645
+ });
646
+ const defLine2 = sigNode.startPosition.row + 1;
647
+ const info2 = methodMap2?.get(`${customResult.funcName}:${defLine2}`);
648
+ if (info2) {
649
+ arity2 = info2.parameters.some((p) => p.isVariadic)
650
+ ? undefined
651
+ : info2.parameters.length;
652
+ if (methodMap2 && arity2 !== undefined) {
653
+ const g2 = (0, method_props_js_1.buildCollisionGroups)(methodMap2);
654
+ encTypeTag2 =
655
+ (0, method_props_js_1.typeTagForId)(methodMap2, customResult.funcName, arity2, info2, encLang2, g2) +
656
+ (0, method_props_js_1.constTagForId)(methodMap2, customResult.funcName, arity2, info2, g2);
657
+ }
658
+ }
659
+ }
660
+ }
661
+ const arityTag2 = arity2 !== undefined ? `#${arity2}${encTypeTag2}` : '';
662
+ const result = (0, utils_js_1.generateId)(finalLabel, `${filePath}:${qualifiedName}${arityTag2}`);
663
+ functionIdCache.set(node, result);
664
+ return result;
665
+ }
666
+ }
667
+ current = current.parent;
668
+ }
669
+ functionIdCache.set(node, null);
670
+ return null;
671
+ };
672
+ /** Cached wrapper for findEnclosingClassInfo — avoids repeated parent walks. */
673
+ const cachedFindEnclosingClassInfo = (node, filePath, resolveEnclosingOwner, getQualifiedOwnerName) => {
674
+ const cached = classIdCache.get(node);
675
+ if (cached !== undefined)
676
+ return cached;
677
+ const result = (0, ast_helpers_js_1.findEnclosingClassInfo)(node, filePath, resolveEnclosingOwner, getQualifiedOwnerName);
678
+ classIdCache.set(node, result);
679
+ return result;
680
+ };
681
+ /** Cached wrapper for export checking — avoids repeated parent walks per symbol. */
682
+ const cachedExportCheck = (checker, node, name) => {
683
+ const cached = exportCache.get(node);
684
+ if (cached !== undefined)
685
+ return cached;
686
+ const result = checker(node, name);
687
+ exportCache.set(node, result);
688
+ return result;
689
+ };
690
+ // Label detection moved to shared getLabelFromCaptures in utils.ts
691
+ // DEFINITION_CAPTURE_KEYS and getDefinitionNodeFromCaptures imported from ../utils.js
692
+ // ============================================================================
693
+ // Process a batch of files
694
+ // ============================================================================
695
+ const processBatch = (files, onProgress) => {
696
+ const result = {
697
+ nodes: [],
698
+ relationships: [],
699
+ symbols: [],
700
+ calls: [],
701
+ assignments: [],
702
+ routes: [],
703
+ fetchCalls: [],
704
+ fetchWrapperDefs: [],
705
+ decoratorRoutes: [],
706
+ routerIncludes: [],
707
+ routerImports: [],
708
+ routerConstructorPrefixes: [],
709
+ routerModuleAliases: [],
710
+ toolDefs: [],
711
+ ormQueries: [],
712
+ constructorBindings: [],
713
+ fileScopeBindings: [],
714
+ parsedFiles: [],
715
+ skippedLanguages: {},
716
+ cfgSkipped: {},
717
+ fileCount: 0,
718
+ };
719
+ // Group by language to minimize setLanguage calls
720
+ const byLanguage = new Map();
721
+ for (const file of files) {
722
+ const lang = (0, index_js_3.getLanguageFromFilename)(file.path);
723
+ if (!lang)
724
+ continue;
725
+ let list = byLanguage.get(lang);
726
+ if (!list) {
727
+ list = [];
728
+ byLanguage.set(lang, list);
729
+ }
730
+ list.push(file);
731
+ }
732
+ let totalProcessed = 0;
733
+ let lastReported = 0;
734
+ const PROGRESS_INTERVAL = Math.max(1, Math.min(100, Math.ceil(files.length / 10)));
735
+ const onFileProcessed = onProgress
736
+ ? () => {
737
+ totalProcessed++;
738
+ if (totalProcessed - lastReported >= PROGRESS_INTERVAL) {
739
+ lastReported = totalProcessed;
740
+ onProgress(totalProcessed);
741
+ }
742
+ }
743
+ : undefined;
744
+ for (const [language, langFiles] of byLanguage) {
745
+ const provider = (0, index_js_2.getProvider)(language);
746
+ const queryString = provider.treeSitterQueries;
747
+ if (!queryString) {
748
+ // Standalone providers (regex-based, no tree-sitter) that implement
749
+ // emitScopeCaptures resolve via the scope-resolution pipeline, which
750
+ // re-extracts from source on the main thread.
751
+ if (provider.emitScopeCaptures) {
752
+ // The worker no longer builds `ParsedFile`s for standalone providers
753
+ // either — scope-resolution re-extracts on the main thread, and for
754
+ // standalone COBOL the graph nodes come from cobolPhase, not this
755
+ // artifact (#1983). Count one unit of progress per file, as before.
756
+ for (let i = 0; i < langFiles.length; i++) {
757
+ result.fileCount++;
758
+ onFileProcessed?.();
759
+ }
760
+ }
761
+ continue;
762
+ }
763
+ const tsxFiles = [];
764
+ const regularFiles = [];
765
+ if (language === index_js_1.SupportedLanguages.TypeScript) {
766
+ for (const f of langFiles) {
767
+ if (f.path.endsWith('.tsx')) {
768
+ tsxFiles.push(f);
769
+ }
770
+ else {
771
+ regularFiles.push(f);
772
+ }
773
+ }
774
+ }
775
+ else {
776
+ // Manual loop (not spread) — `push(...arr)` blows the stack on very
777
+ // large arrays when langFiles has tens of thousands of entries.
778
+ for (const f of langFiles)
779
+ regularFiles.push(f);
780
+ }
781
+ // Process regular files for this language
782
+ if (regularFiles.length > 0) {
783
+ if (isLanguageAvailable(language, regularFiles[0].path)) {
784
+ try {
785
+ setLanguage(language, regularFiles[0].path);
786
+ processFileGroup(regularFiles, language, queryString, result, onFileProcessed);
787
+ }
788
+ catch (err) {
789
+ // A throw here drops the whole language group — surface it to the pool
790
+ // (#2264) instead of silently skipping. The old empty catch hid real
791
+ // extractor/parser failures, not just an unavailable grammar.
792
+ reportWarning(`Skipped ${regularFiles.length} ${language} file(s) after a processing error: ${err instanceof Error ? err.message : String(err)}`);
793
+ }
794
+ }
795
+ else {
796
+ result.skippedLanguages[language] =
797
+ (result.skippedLanguages[language] || 0) + regularFiles.length;
798
+ }
799
+ }
800
+ // Process tsx files separately (different grammar)
801
+ if (tsxFiles.length > 0) {
802
+ if (isLanguageAvailable(language, tsxFiles[0].path)) {
803
+ try {
804
+ setLanguage(language, tsxFiles[0].path);
805
+ processFileGroup(tsxFiles, language, queryString, result, onFileProcessed);
806
+ }
807
+ catch (err) {
808
+ // See above — surface a tsx-group processing failure rather than
809
+ // silently dropping every file in it (#2264).
810
+ reportWarning(`Skipped ${tsxFiles.length} ${language} (tsx) file(s) after a processing error: ${err instanceof Error ? err.message : String(err)}`);
811
+ }
812
+ }
813
+ else {
814
+ result.skippedLanguages[language] =
815
+ (result.skippedLanguages[language] || 0) + tsxFiles.length;
816
+ }
817
+ }
818
+ }
819
+ if (onProgress && totalProcessed !== lastReported) {
820
+ onProgress(totalProcessed);
821
+ }
822
+ return result;
823
+ };
824
+ // Express/Hono method names that register routes
825
+ const EXPRESS_ROUTE_METHODS = new Set([
826
+ 'get',
827
+ 'post',
828
+ 'put',
829
+ 'delete',
830
+ 'patch',
831
+ 'all',
832
+ 'use',
833
+ 'route',
834
+ ]);
835
+ /**
836
+ * Walk a tree-sitter AST subtree looking for a call to the global `fetch()` function.
837
+ * Returns `true` if found within `maxDepth` levels of nesting — keeps the check
838
+ * lightweight so it doesn't slow down parse-worker on large function bodies.
839
+ */
840
+ const checkForFetchCall = (node, depth = 0, maxDepth = 5) => {
841
+ if (depth > maxDepth)
842
+ return false;
843
+ if (node.type === 'call_expression') {
844
+ const fn = node.childForFieldName('function');
845
+ if (fn?.type === 'identifier' && fn.text === 'fetch')
846
+ return true;
847
+ }
848
+ for (let i = 0; i < node.childCount; i++) {
849
+ if (checkForFetchCall(node.child(i), depth + 1, maxDepth))
850
+ return true;
851
+ }
852
+ return false;
853
+ };
854
+ // HTTP client methods that are ONLY used by clients, not Express route registration.
855
+ // Methods like get/post/put/delete/patch overlap with Express — those are captured by
856
+ // the express_route handler as route definitions, not consumers. The fetch() global
857
+ // function is captured separately by the route.fetch query.
858
+ const HTTP_CLIENT_ONLY_METHODS = new Set(['head', 'options', 'request', 'ajax']);
859
+ // Known HTTP client receivers u2014 skip these, they're API consumers not routes
860
+ const HTTP_CLIENT_RECEIVERS = new Set([
861
+ 'axios',
862
+ 'request',
863
+ 'fetch',
864
+ 'http',
865
+ 'https',
866
+ 'got',
867
+ 'ky',
868
+ 'superagent',
869
+ 'needle',
870
+ 'undici',
871
+ 'apiclient',
872
+ 'client',
873
+ 'httpclient',
874
+ 'api',
875
+ '$http',
876
+ 'session',
877
+ 'httpservice',
878
+ 'conn',
879
+ ]);
880
+ // Decorator names that indicate HTTP route handlers (NestJS, Flask, FastAPI, Spring)
881
+ const ROUTE_DECORATOR_NAMES = new Set([
882
+ 'Get',
883
+ 'Post',
884
+ 'Put',
885
+ 'Delete',
886
+ 'Patch',
887
+ 'Route',
888
+ 'get',
889
+ 'post',
890
+ 'put',
891
+ 'delete',
892
+ 'patch',
893
+ 'route',
894
+ 'RequestMapping',
895
+ 'GetMapping',
896
+ 'PostMapping',
897
+ 'PutMapping',
898
+ 'DeleteMapping',
899
+ 'PatchMapping',
900
+ ]);
901
+ // ============================================================================
902
+ // ORM Query Detection (Prisma + Supabase)
903
+ // ============================================================================
904
+ const PRISMA_QUERY_RE = /\bprisma\.(\w+)\.(findMany|findFirst|findUnique|findUniqueOrThrow|findFirstOrThrow|create|createMany|update|updateMany|delete|deleteMany|upsert|count|aggregate|groupBy)\s*\(/g;
905
+ const SUPABASE_QUERY_RE = /\bsupabase\.from\s*\(\s*['"](\w+)['"]\s*\)\s*\.(select|insert|update|delete|upsert)\s*\(/g;
906
+ /**
907
+ * Extract ORM query calls from file content via regex.
908
+ * Appends results to the provided array (avoids allocation when no matches).
909
+ */
910
+ function extractORMQueries(filePath, content, out) {
911
+ const hasPrisma = content.includes('prisma.');
912
+ const hasSupabase = content.includes('supabase.from');
913
+ if (!hasPrisma && !hasSupabase)
914
+ return;
915
+ if (hasPrisma) {
916
+ PRISMA_QUERY_RE.lastIndex = 0;
917
+ let m;
918
+ while ((m = PRISMA_QUERY_RE.exec(content)) !== null) {
919
+ const model = m[1];
920
+ if (model.startsWith('$'))
921
+ continue;
922
+ out.push({
923
+ filePath,
924
+ orm: 'prisma',
925
+ model,
926
+ method: m[2],
927
+ lineNumber: content.substring(0, m.index).split('\n').length - 1,
928
+ });
929
+ }
930
+ }
931
+ if (hasSupabase) {
932
+ SUPABASE_QUERY_RE.lastIndex = 0;
933
+ let m;
934
+ while ((m = SUPABASE_QUERY_RE.exec(content)) !== null) {
935
+ out.push({
936
+ filePath,
937
+ orm: 'supabase',
938
+ model: m[1],
939
+ method: m[2],
940
+ lineNumber: content.substring(0, m.index).split('\n').length - 1,
941
+ });
942
+ }
943
+ }
944
+ }
945
+ // ============================================================================
946
+ // FastAPI router prefix detection (Python)
947
+ // ============================================================================
948
+ //
949
+ // The extraction lives in `../route-extractors/fastapi-router-bindings`
950
+ // (a pure-function module — NOT a worker, no `worker_threads`, no
951
+ // `parentPort`). It's imported here only so the worker entry can call it
952
+ // per file; this module does not re-export it. Downstream consumers
953
+ // import the function and its types directly from `route-extractors/`.
954
+ const fastapi_router_bindings_js_1 = require("../route-extractors/fastapi-router-bindings.js");
955
+ const python_const_resolver_js_1 = require("../route-extractors/python-const-resolver.js");
956
+ /**
957
+ * Report a non-fatal worker issue to the pool over IPC so a caught error is not
958
+ * invisible to the operator (#2264). The pool logs it on the main thread AND
959
+ * resets the worker idle timer (so a worker grinding through failing files isn't
960
+ * falsely idle-evicted). Falls back to the local logger when there's no parent —
961
+ * this code also runs on the main thread in tests / the non-worker path. Fatal,
962
+ * group-aborting errors go through the message handler's
963
+ * `{ type: 'error', errorStack }` channel instead.
964
+ */
965
+ function reportWarning(message) {
966
+ if (node_worker_threads_1.parentPort) {
967
+ node_worker_threads_1.parentPort.postMessage({ type: 'warning', message });
968
+ }
969
+ else {
970
+ logger_js_1.logger.warn(message);
971
+ }
972
+ }
973
+ const processFileGroup = (files, language, queryString, result, onFileProcessed) => {
974
+ let query;
975
+ try {
976
+ const lang = parser.getLanguage();
977
+ query = new tree_sitter_1.default.Query(lang, queryString);
978
+ }
979
+ catch (err) {
980
+ reportWarning(`Query compilation failed for ${language}: ${err instanceof Error ? err.message : String(err)}`);
981
+ return;
982
+ }
983
+ for (const file of files) {
984
+ // Skip files larger than the max tree-sitter buffer (32 MB)
985
+ if ((0, constants_js_1.getTreeSitterContentByteLength)(file.content) > constants_js_1.TREE_SITTER_MAX_BUFFER)
986
+ continue;
987
+ // Authoritative in-flight signal for the pool: lets `WorkerPool` exclude
988
+ // exactly this file if the worker dies during parse/extract, instead of
989
+ // guessing from `items[lastProgress]` (which the language-grouped order
990
+ // here would defeat). The pool gracefully ignores this when running an
991
+ // older worker build that doesn't emit it.
992
+ if (node_worker_threads_1.parentPort) {
993
+ node_worker_threads_1.parentPort.postMessage({ type: 'starting-file', path: file.path });
994
+ }
995
+ // Vue SFC preprocessing: extract <script> block content
996
+ let parseContent = file.content;
997
+ let scopeSourceKind = 'full-file';
998
+ let lineOffset = 0;
999
+ let isVueSetup = false;
1000
+ if (language === index_js_1.SupportedLanguages.Vue) {
1001
+ const extracted = (0, vue_sfc_extractor_js_1.extractVueScript)(file.content);
1002
+ if (!extracted)
1003
+ continue; // skip .vue files with no script block
1004
+ parseContent = extracted.scriptContent;
1005
+ scopeSourceKind = 'pre-extracted-script';
1006
+ lineOffset = extracted.lineOffset;
1007
+ isVueSetup = extracted.isSetup;
1008
+ }
1009
+ // Per-language source-text transform (e.g., UE macro stripping for C++).
1010
+ // Length-preserving — see LanguageProvider.preprocessSource contract.
1011
+ parseContent =
1012
+ (0, index_js_2.getProvider)(language).preprocessSource?.(parseContent, file.path) ?? parseContent;
1013
+ clearCaches(); // Reset memoization before each new file
1014
+ let tree;
1015
+ try {
1016
+ tree = (0, safe_parse_js_1.parseSourceSafe)(parser, parseContent, undefined, {
1017
+ bufferSize: (0, constants_js_1.getTreeSitterBufferSize)(parseContent),
1018
+ }, file.path);
1019
+ }
1020
+ catch (err) {
1021
+ reportWarning(`Failed to parse file ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
1022
+ continue;
1023
+ }
1024
+ result.fileCount++;
1025
+ onFileProcessed?.();
1026
+ let matches;
1027
+ try {
1028
+ matches = query.matches(tree.rootNode);
1029
+ }
1030
+ catch (err) {
1031
+ reportWarning(`Query execution failed for ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
1032
+ continue;
1033
+ }
1034
+ const provider = (0, index_js_2.getProvider)(language);
1035
+ // #2687: ONE pass over `matches` yields both suppression sets — the
1036
+ // definition-name claims by rank (callable > Property > value), so the dedup
1037
+ // below cannot depend on tree-sitter's match order, and the concrete-typedef
1038
+ // ranges the typedef guard consumes.
1039
+ const definitionPreScan = (0, ast_helpers_js_1.buildDefinitionPreScan)(matches, provider);
1040
+ const concreteTypedefRanges = definitionPreScan.concreteTypedefRanges;
1041
+ // Produce the `ParsedFile` for the scope-resolution pipeline HERE, reusing
1042
+ // the tree we just parsed (no second tree-sitter parse). Scope-resolution
1043
+ // consumes these via the disk-backed parsedfile-store instead of
1044
+ // re-extracting each file from source on the main thread — which
1045
+ // accumulated an unbounded native tree-sitter leak on huge repos (#1983;
1046
+ // see parsedfile-store.ts). parse-impl flushes `result.parsedFiles` to disk
1047
+ // per chunk and does NOT retain them in main-thread heap, so this no longer
1048
+ // costs ~1× the semantic model in RAM during parse.
1049
+ const parsedFile = (0, scope_extractor_bridge_js_1.extractParsedFile)(provider, parseContent, file.path, reportWarning, tree, scopeSourceKind);
1050
+ if (parsedFile !== undefined) {
1051
+ // Capture-time side-channel (#1983): `extractParsedFile` just ran the
1052
+ // provider's `emitScopeCaptures`, which (for C++ ADL/namespace marks,
1053
+ // C `static`-linkage names, and Kotlin companion scopes) populated
1054
+ // module-level maps as a SIDE EFFECT that is NOT on `parsedFile`'s
1055
+ // scopes/defs. Snapshot
1056
+ // that per-file state as plain data onto `ParsedFile.captureSideChannel`
1057
+ // so the main thread can restore it (via `ScopeResolver.applyCaptureSideChannel`)
1058
+ // WITHOUT a re-parse, after this ParsedFile crosses the worker boundary /
1059
+ // disk store. Providers without capture-time side effects leave the hook
1060
+ // undefined and this is a no-op. `undefined` return ⇒ no field added.
1061
+ //
1062
+ // `extractParsedFile` returns a frozen ParsedFile, so re-wrap (shallow
1063
+ // copy — scopes/defs are carried by reference) to attach the field rather
1064
+ // than mutate the frozen object.
1065
+ const sideChannel = provider.collectCaptureSideChannel?.(file.path);
1066
+ let withChannels = sideChannel !== undefined ? { ...parsedFile, captureSideChannel: sideChannel } : parsedFile;
1067
+ // CFG side-channel (#2081 M1): build the per-function control-flow graph
1068
+ // here, where the tree-sitter AST is still in hand, and attach it as plain
1069
+ // serializable data. Only on a --pdg run and only for languages with a
1070
+ // cfgVisitor (TS/JS in M1). The same disk-store/warm-cache machinery that
1071
+ // carries captureSideChannel carries this — its coherence rests on the
1072
+ // SCHEMA_BUMP + the pdg-folded chunk-hash key (see parse-cache.ts).
1073
+ if (PDG_ENABLED && provider.cfgVisitor) {
1074
+ // Isolate the CFG build per file: a throw here (an unexpected tree-sitter
1075
+ // node shape) must NOT propagate — it would escape processFileGroup to the
1076
+ // language-group catch, which treats any throw as "parser unavailable" and
1077
+ // silently drops EVERY remaining file in the group. Skip CFG for this one
1078
+ // file; parsing + scope resolution proceed unaffected (CFG is a
1079
+ // strictly-additive opt-in). collectFunctionCfgs ALSO isolates per
1080
+ // FUNCTION now (#2195) — a deep-nesting bail or a single malformed function
1081
+ // is counted in `skipped` and skipped, not allowed to lose the whole file.
1082
+ try {
1083
+ const { cfgs, skipped } = (0, collect_js_1.collectFunctionCfgs)(tree.rootNode, provider.cfgVisitor, file.path, PDG_MAX_FUNCTION_LINES,
1084
+ // Embedded scripts (Vue SFC <script>) parse at row 0 but live at
1085
+ // `lineOffset` in the file — shift the CFG into file coordinates so
1086
+ // it joins its graph node and BasicBlock lines map to source.
1087
+ lineOffset);
1088
+ if (cfgs.length)
1089
+ withChannels = { ...withChannels, cfgSideChannel: cfgs };
1090
+ // Surface per-function CFG skips per-language (#2195): merged + logged
1091
+ // in mergeChunkResults. Only accumulate when something was skipped so
1092
+ // the common (nothing-skipped) case stays a no-op.
1093
+ if (skipped.tooManyLines || skipped.tooDeeplyNested || skipped.buildError) {
1094
+ const agg = (result.cfgSkipped ??= {});
1095
+ const prev = agg[language] ?? { tooManyLines: 0, tooDeeplyNested: 0, buildError: 0 };
1096
+ agg[language] = {
1097
+ tooManyLines: prev.tooManyLines + skipped.tooManyLines,
1098
+ tooDeeplyNested: prev.tooDeeplyNested + skipped.tooDeeplyNested,
1099
+ buildError: prev.buildError + skipped.buildError,
1100
+ };
1101
+ }
1102
+ }
1103
+ catch (err) {
1104
+ reportWarning(`CFG build failed for ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
1105
+ }
1106
+ }
1107
+ result.parsedFiles.push(withChannels);
1108
+ }
1109
+ // Build per-file type environment + constructor bindings in a single AST walk.
1110
+ // The legacy heritage pre-pass that seeded a file-local parentMap for
1111
+ // buildTypeEnv was removed in RING4-1 (#942) along with the rest of the
1112
+ // call-resolution DAG. Inheritance is now emitted by scope-resolution
1113
+ // (preEmitInheritanceEdges + @reference.inherits), so buildTypeEnv runs with
1114
+ // an empty parentMap — cross-file inheritance was never resolved here anyway.
1115
+ const parentMap = new Map();
1116
+ const typeEnv = (0, type_env_js_1.buildTypeEnv)(tree, language, {
1117
+ filePath: file.path,
1118
+ parentMap,
1119
+ enclosingFunctionFinder: provider?.enclosingFunctionFinder,
1120
+ extractFunctionName: provider?.methodExtractor?.extractFunctionName,
1121
+ });
1122
+ const callRouter = provider.callRouter;
1123
+ if (typeEnv.constructorBindings.length > 0) {
1124
+ result.constructorBindings.push({
1125
+ filePath: file.path,
1126
+ bindings: [...typeEnv.constructorBindings],
1127
+ });
1128
+ }
1129
+ // Serialize file-scope bindings for BindingAccumulator. These feed the
1130
+ // ExportedTypeMap enrichment loop in pipeline.ts — the only current
1131
+ // consumer of worker-path binding data.
1132
+ //
1133
+ // Historical note: we previously serialized all scopes
1134
+ // (`typeEnv.allScopes()`), which pushed ~4.9 MB of function-scope
1135
+ // bindings across the IPC boundary on every worker batch with zero
1136
+ // downstream readers. Narrowing to `fileScope()` recovers that cost.
1137
+ // See the `FileScopeBindings` JSDoc above for the Phase 9 reversion
1138
+ // path when a function-scope consumer lands.
1139
+ const fileScope = typeEnv.fileScope();
1140
+ if (fileScope.size > 0) {
1141
+ const scopeBindings = [];
1142
+ for (const [varName, typeName] of fileScope) {
1143
+ scopeBindings.push([varName, typeName]);
1144
+ }
1145
+ result.fileScopeBindings.push({ filePath: file.path, bindings: scopeBindings });
1146
+ }
1147
+ // Per-file map: decorator end-line → decorator info, for associating with definitions
1148
+ const fileDecorators = new Map();
1149
+ // Track start indices of definition nodes already processed by higher-priority captures
1150
+ // (e.g. @definition.function) to avoid duplicate nodes when @definition.const/@definition.variable
1151
+ // patterns overlap with the same source range.
1152
+ const processedDefinitionNodes = new Set();
1153
+ const variableInfoCache = new Map();
1154
+ for (const match of matches) {
1155
+ const captureMap = {};
1156
+ for (const c of match.captures) {
1157
+ captureMap[c.name] = c.node;
1158
+ }
1159
+ if ((0, ast_helpers_js_1.isSuppressedConcreteTypedefDuplicate)(captureMap, concreteTypedefRanges))
1160
+ continue;
1161
+ // Import matches: IMPORTS edges are emitted by the scope-resolution
1162
+ // phase from finalized ImportEdges (RING4-1 #942 / RING4-2 #943 removed
1163
+ // the legacy per-file import-map extraction that ran here). Skip.
1164
+ if (captureMap['import'] && captureMap['import.source']) {
1165
+ continue;
1166
+ }
1167
+ // Extract assignment sites (field write access)
1168
+ if (captureMap['assignment'] &&
1169
+ captureMap['assignment.receiver'] &&
1170
+ captureMap['assignment.property']) {
1171
+ const receiverText = captureMap['assignment.receiver'].text;
1172
+ const propertyName = captureMap['assignment.property'].text;
1173
+ if (receiverText && propertyName) {
1174
+ const srcId = findEnclosingFunctionId(captureMap['assignment'], file.path, provider) ||
1175
+ (0, utils_js_1.generateId)('File', file.path);
1176
+ let receiverTypeName;
1177
+ if (typeEnv) {
1178
+ receiverTypeName = typeEnv.lookup(receiverText, captureMap['assignment']) ?? undefined;
1179
+ }
1180
+ result.assignments.push({
1181
+ filePath: file.path,
1182
+ sourceId: srcId,
1183
+ receiverText,
1184
+ propertyName,
1185
+ line: captureMap['assignment'].startPosition.row + 1,
1186
+ ...(receiverTypeName ? { receiverTypeName } : {}),
1187
+ });
1188
+ }
1189
+ if (!captureMap['call'])
1190
+ continue;
1191
+ }
1192
+ // Store decorator metadata for later association with definitions
1193
+ if (captureMap['decorator'] && captureMap['decorator.name']) {
1194
+ const decoratorName = captureMap['decorator.name'].text;
1195
+ const decoratorArg = captureMap['decorator.arg']?.text;
1196
+ // #2391: the first positional arg captured as either a string node
1197
+ // (`arg_str`, present even for the empty-string literal `""` which has no
1198
+ // `string_content`) or a non-literal expression (`arg_expr`: an
1199
+ // identifier or a `+`-concatenation).
1200
+ const decoratorArgStr = captureMap['decorator.arg_str'];
1201
+ const decoratorArgExpr = captureMap['decorator.arg_expr'];
1202
+ const decoratorReceiver = captureMap['decorator.receiver']?.text;
1203
+ const decoratorNode = captureMap['decorator'];
1204
+ // Store by the decorator's end line — the definition follows immediately after
1205
+ fileDecorators.set(decoratorNode.endPosition.row, {
1206
+ name: decoratorName,
1207
+ arg: decoratorArg,
1208
+ });
1209
+ if (ROUTE_DECORATOR_NAMES.has(decoratorName)) {
1210
+ const method = decoratorName.replace('Mapping', '').toUpperCase();
1211
+ const httpMethod = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(method)
1212
+ ? method
1213
+ : 'GET';
1214
+ const base = {
1215
+ filePath: file.path,
1216
+ httpMethod,
1217
+ decoratorName,
1218
+ lineNumber: decoratorNode.startPosition.row + lineOffset,
1219
+ ...(decoratorReceiver ? { decoratorReceiver } : {}),
1220
+ };
1221
+ if (decoratorArgStr) {
1222
+ // String-literal path (the fast path, unchanged). Empty-string
1223
+ // literal `""` has no `string_content` → `decoratorArg` undefined →
1224
+ // routePath '' (a valid path under an APIRouter prefix).
1225
+ result.decoratorRoutes.push({ ...base, routePath: decoratorArg ?? '' });
1226
+ }
1227
+ else if (decoratorArgExpr) {
1228
+ // #2391 non-literal path (imported/composed constant). Emit the raw
1229
+ // expression + its operands for cross-file resolution in parse-impl;
1230
+ // `routePath` stays empty until resolved (or the route is dropped).
1231
+ const operands = decoratorArgExpr.type === 'identifier'
1232
+ ? [{ kind: 'ref', name: decoratorArgExpr.text }]
1233
+ : (0, python_const_resolver_js_1.parseConstOperands)(decoratorArgExpr);
1234
+ result.decoratorRoutes.push({
1235
+ ...base,
1236
+ routePath: '',
1237
+ routePathExpr: decoratorArgExpr.text,
1238
+ ...(operands ? { routePathOperands: operands } : {}),
1239
+ });
1240
+ }
1241
+ // Otherwise the first arg is absent or an unsupported shape
1242
+ // (attribute access, call, …) → skip; never a phantom `POST /`.
1243
+ }
1244
+ // MCP/RPC tool detection: @mcp.tool(), @app.tool(), @server.tool()
1245
+ if (decoratorName === 'tool') {
1246
+ // Re-store with isTool flag for the definition handler
1247
+ fileDecorators.set(decoratorNode.endPosition.row, {
1248
+ name: decoratorName,
1249
+ arg: decoratorArg,
1250
+ isTool: true,
1251
+ });
1252
+ }
1253
+ continue;
1254
+ }
1255
+ // Extract HTTP consumer URLs: fetch(), axios.get(), $.get(), requests.get(), etc.
1256
+ if (captureMap['route.fetch']) {
1257
+ const urlNode = captureMap['route.url'] ?? captureMap['route.template_url'];
1258
+ if (urlNode) {
1259
+ result.fetchCalls.push({
1260
+ filePath: file.path,
1261
+ fetchURL: urlNode.text,
1262
+ lineNumber: captureMap['route.fetch'].startPosition.row + lineOffset,
1263
+ });
1264
+ }
1265
+ continue;
1266
+ }
1267
+ // HTTP client calls: axios.get('/path'), $.post('/path'), requests.get('/path')
1268
+ // Skip methods also in EXPRESS_ROUTE_METHODS to avoid double-registering Express
1269
+ // routes as both route definitions AND consumers (both queries match same AST node)
1270
+ if (captureMap['http_client'] && captureMap['http_client.url']) {
1271
+ const method = captureMap['http_client.method']?.text;
1272
+ const url = captureMap['http_client.url'].text;
1273
+ if (method && HTTP_CLIENT_ONLY_METHODS.has(method) && url.startsWith('/')) {
1274
+ result.fetchCalls.push({
1275
+ filePath: file.path,
1276
+ fetchURL: url,
1277
+ lineNumber: captureMap['http_client'].startPosition.row + lineOffset,
1278
+ });
1279
+ }
1280
+ continue;
1281
+ }
1282
+ // Express/Hono route registration: app.get('/path', handler)
1283
+ if (captureMap['express_route'] &&
1284
+ captureMap['express_route.method'] &&
1285
+ captureMap['express_route.path']) {
1286
+ const method = captureMap['express_route.method'].text;
1287
+ const routePath = captureMap['express_route.path'].text;
1288
+ if (EXPRESS_ROUTE_METHODS.has(method) && routePath.startsWith('/')) {
1289
+ // Extract the receiver (the object the method is called on) to filter out
1290
+ // HTTP client calls like axios.get('/api/users') that match the same pattern
1291
+ // as Express route registrations.
1292
+ const callNode = captureMap['express_route'];
1293
+ const funcNode = callNode.childForFieldName?.('function') ?? callNode.children?.[0];
1294
+ // Walk through nested member_expressions and call_expressions to
1295
+ // reach the innermost receiver identifier. Handles chains like:
1296
+ // this.httpService.get('/path') -> member chain -> 'httpservice'
1297
+ // getClient().get('/path') -> call_expression -> 'getclient'
1298
+ // axios.get('/path') -> bare identifier -> 'axios'
1299
+ let receiverNode = funcNode?.childForFieldName?.('object') ?? funcNode?.children?.[0];
1300
+ while (receiverNode?.type === 'member_expression' ||
1301
+ receiverNode?.type === 'call_expression') {
1302
+ if (receiverNode.type === 'member_expression') {
1303
+ // Drill into the property (rightmost part) of the member expression
1304
+ const propNode = receiverNode.childForFieldName?.('property');
1305
+ if (propNode) {
1306
+ receiverNode = propNode;
1307
+ }
1308
+ else {
1309
+ break;
1310
+ }
1311
+ }
1312
+ else {
1313
+ // call_expression: unwrap to the function being called
1314
+ const innerFunc = receiverNode.childForFieldName?.('function') ?? receiverNode.children?.[0];
1315
+ if (innerFunc && innerFunc !== receiverNode) {
1316
+ receiverNode = innerFunc;
1317
+ }
1318
+ else {
1319
+ break;
1320
+ }
1321
+ }
1322
+ }
1323
+ const receiverText = receiverNode?.text?.toLowerCase() ?? '';
1324
+ if (HTTP_CLIENT_RECEIVERS.has(receiverText)) {
1325
+ // This is an HTTP client call, not a route definition u2014 skip it
1326
+ continue;
1327
+ }
1328
+ const httpMethod = method === 'all' || method === 'use' || method === 'route'
1329
+ ? 'GET'
1330
+ : method.toUpperCase();
1331
+ result.decoratorRoutes.push({
1332
+ filePath: file.path,
1333
+ routePath,
1334
+ httpMethod,
1335
+ decoratorName: `express.${method}`,
1336
+ lineNumber: captureMap['express_route'].startPosition.row + lineOffset,
1337
+ });
1338
+ }
1339
+ continue;
1340
+ }
1341
+ // Extract call sites
1342
+ if (captureMap['call']) {
1343
+ const callNode = captureMap['call'];
1344
+ const callNameNode = captureMap['call.name'];
1345
+ const callExtractor = provider.callExtractor;
1346
+ if (callExtractor) {
1347
+ // ── Path 1: Language-specific call site (bypasses routing) ────
1348
+ // Try language-specific extraction (e.g. Java `::` method references)
1349
+ // without callNameNode. If successful, skip routing and the generic
1350
+ // path entirely.
1351
+ const langCallSite = callExtractor.extract(callNode, undefined);
1352
+ if (langCallSite) {
1353
+ if (!provider.isBuiltInName(langCallSite.calledName)) {
1354
+ const sourceId = findEnclosingFunctionId(callNode, file.path, provider) ||
1355
+ (0, utils_js_1.generateId)('File', file.path);
1356
+ const receiverName = langCallSite.callForm === 'member' ? langCallSite.receiverName : undefined;
1357
+ let receiverTypeName = receiverName
1358
+ ? typeEnv.lookup(receiverName, callNode)
1359
+ : undefined;
1360
+ // Type-as-receiver heuristic (e.g. Java `User::getName`)
1361
+ if (langCallSite.typeAsReceiverHeuristic &&
1362
+ receiverName !== undefined &&
1363
+ receiverTypeName === undefined &&
1364
+ langCallSite.callForm === 'member') {
1365
+ const c0 = receiverName.charCodeAt(0);
1366
+ if (c0 >= 65 && c0 <= 90)
1367
+ receiverTypeName = receiverName;
1368
+ }
1369
+ result.calls.push({
1370
+ filePath: file.path,
1371
+ calledName: langCallSite.calledName,
1372
+ sourceId,
1373
+ callForm: langCallSite.callForm,
1374
+ ...(receiverName !== undefined ? { receiverName } : {}),
1375
+ ...(receiverTypeName !== undefined ? { receiverTypeName } : {}),
1376
+ });
1377
+ }
1378
+ continue;
1379
+ }
1380
+ // ── Path 2: Generic extraction via @call.name ────────────────
1381
+ if (callNameNode) {
1382
+ const calledName = callNameNode.text;
1383
+ // Dispatch: route language-specific calls (properties, imports).
1384
+ // Call-based heritage (Ruby include/extend/prepend) is no longer
1385
+ // routed here — those calls return 'skip' from the router and the
1386
+ // mixin edges are emitted by scope-resolution (emitHeritageEdges).
1387
+ const routed = callRouter?.(calledName, captureMap['call']);
1388
+ if (routed) {
1389
+ if (routed.kind === 'skip')
1390
+ continue;
1391
+ if (routed.kind === 'import') {
1392
+ // Call-routed imports (e.g. Ruby `require`) are emitted as
1393
+ // IMPORTS edges by the scope-resolution phase; the legacy
1394
+ // per-file extraction that consumed these was removed in
1395
+ // RING4-2 (#943). Skip.
1396
+ continue;
1397
+ }
1398
+ if (routed.kind === 'properties') {
1399
+ // #1978: thread the qualifier so a routed property's owner edge
1400
+ // points at the *qualified* nested-class node (Outer.Inner) rather
1401
+ // than a now-nonexistent simple `Class:file:Inner` id. Gated on the
1402
+ // flag → byte-identical when off. Mirrors the main owner path.
1403
+ const propGetQualifiedOwnerName = provider.classExtractor?.qualifiedNodeId === true
1404
+ ? (node, simpleName) => provider.classExtractor.extractQualifiedName(node, simpleName)
1405
+ : undefined;
1406
+ const propEnclosingInfo = cachedFindEnclosingClassInfo(captureMap['call'], file.path, provider.resolveEnclosingOwner, propGetQualifiedOwnerName);
1407
+ const propEnclosingClassId = propEnclosingInfo?.qualifiedClassId ?? propEnclosingInfo?.classId ?? null;
1408
+ // Enrich routed properties with FieldExtractor metadata
1409
+ let routedFieldMap;
1410
+ if (provider.fieldExtractor && typeEnv) {
1411
+ const classNode = findEnclosingClassNode(captureMap['call']);
1412
+ if (classNode) {
1413
+ routedFieldMap = getFieldInfo(classNode, provider, {
1414
+ typeEnv,
1415
+ symbolTable: NOOP_SYMBOL_TABLE,
1416
+ filePath: file.path,
1417
+ language,
1418
+ });
1419
+ }
1420
+ }
1421
+ for (const item of routed.items) {
1422
+ const routedFieldInfo = routedFieldMap?.get(item.propName);
1423
+ const propQualifiedName = propEnclosingInfo
1424
+ ? `${propEnclosingInfo.className}.${item.propName}`
1425
+ : item.propName;
1426
+ const nodeId = (0, utils_js_1.generateId)('Property', `${file.path}:${propQualifiedName}`);
1427
+ result.nodes.push({
1428
+ id: nodeId,
1429
+ label: 'Property',
1430
+ properties: {
1431
+ name: item.propName,
1432
+ filePath: file.path,
1433
+ startLine: item.startLine,
1434
+ endLine: item.endLine,
1435
+ language,
1436
+ isExported: true,
1437
+ description: item.accessorType,
1438
+ ...(item.declaredType
1439
+ ? { declaredType: item.declaredType }
1440
+ : routedFieldInfo?.type
1441
+ ? { declaredType: routedFieldInfo.type }
1442
+ : {}),
1443
+ ...(routedFieldInfo?.rawDeclaredType !== undefined
1444
+ ? { rawDeclaredType: routedFieldInfo.rawDeclaredType }
1445
+ : {}),
1446
+ ...(routedFieldInfo?.annotations !== undefined &&
1447
+ routedFieldInfo.annotations.length > 0
1448
+ ? { annotations: routedFieldInfo.annotations }
1449
+ : {}),
1450
+ ...(routedFieldInfo?.visibility !== undefined
1451
+ ? { visibility: routedFieldInfo.visibility }
1452
+ : {}),
1453
+ ...(routedFieldInfo?.isStatic !== undefined
1454
+ ? { isStatic: routedFieldInfo.isStatic }
1455
+ : {}),
1456
+ ...(routedFieldInfo?.isReadonly !== undefined
1457
+ ? { isReadonly: routedFieldInfo.isReadonly }
1458
+ : {}),
1459
+ },
1460
+ });
1461
+ result.symbols.push({
1462
+ filePath: file.path,
1463
+ name: item.propName,
1464
+ nodeId,
1465
+ type: 'Property',
1466
+ ...(propEnclosingClassId ? { ownerId: propEnclosingClassId } : {}),
1467
+ ...(item.declaredType
1468
+ ? { declaredType: item.declaredType }
1469
+ : routedFieldInfo?.type
1470
+ ? { declaredType: routedFieldInfo.type }
1471
+ : {}),
1472
+ ...(routedFieldInfo?.visibility !== undefined
1473
+ ? { visibility: routedFieldInfo.visibility }
1474
+ : {}),
1475
+ ...(routedFieldInfo?.isStatic !== undefined
1476
+ ? { isStatic: routedFieldInfo.isStatic }
1477
+ : {}),
1478
+ ...(routedFieldInfo?.isReadonly !== undefined
1479
+ ? { isReadonly: routedFieldInfo.isReadonly }
1480
+ : {}),
1481
+ });
1482
+ // Only emit File -> Property DEFINES for top-level properties
1483
+ // (issue #1944); class members are reached via HAS_PROPERTY.
1484
+ if (!propEnclosingClassId) {
1485
+ const fileId = (0, utils_js_1.generateId)('File', file.path);
1486
+ const relId = (0, utils_js_1.generateId)('DEFINES', `${fileId}->${nodeId}`);
1487
+ result.relationships.push({
1488
+ id: relId,
1489
+ sourceId: fileId,
1490
+ targetId: nodeId,
1491
+ type: 'DEFINES',
1492
+ confidence: 1.0,
1493
+ reason: '',
1494
+ });
1495
+ }
1496
+ if (propEnclosingClassId) {
1497
+ result.relationships.push({
1498
+ id: (0, utils_js_1.generateId)('HAS_PROPERTY', `${propEnclosingClassId}->${nodeId}`),
1499
+ sourceId: propEnclosingClassId,
1500
+ targetId: nodeId,
1501
+ type: 'HAS_PROPERTY',
1502
+ confidence: 1.0,
1503
+ reason: '',
1504
+ });
1505
+ }
1506
+ }
1507
+ continue;
1508
+ }
1509
+ // kind === 'call' — fall through to normal call processing below
1510
+ }
1511
+ if (!provider.isBuiltInName(calledName)) {
1512
+ const callSite = callExtractor.extract(callNode, callNameNode);
1513
+ if (callSite) {
1514
+ const sourceId = findEnclosingFunctionId(callNode, file.path, provider) ||
1515
+ (0, utils_js_1.generateId)('File', file.path);
1516
+ let receiverTypeName = callSite.receiverName
1517
+ ? typeEnv.lookup(callSite.receiverName, callNode)
1518
+ : undefined;
1519
+ // Type-as-receiver heuristic
1520
+ if (callSite.typeAsReceiverHeuristic &&
1521
+ callSite.receiverName !== undefined &&
1522
+ receiverTypeName === undefined &&
1523
+ callSite.callForm === 'member') {
1524
+ const c0 = callSite.receiverName.charCodeAt(0);
1525
+ if (c0 >= 65 && c0 <= 90)
1526
+ receiverTypeName = callSite.receiverName;
1527
+ }
1528
+ const inferLiteralType = provider.typeConfig?.inferLiteralType;
1529
+ // Skip when no arg list / zero args: nothing to infer for overload typing
1530
+ const argTypes = inferLiteralType && callSite.argCount !== undefined && callSite.argCount > 0
1531
+ ? (0, call_analysis_js_1.extractCallArgTypes)(callNode, inferLiteralType, (varName, cn) => typeEnv.lookup(varName, cn))
1532
+ : undefined;
1533
+ result.calls.push({
1534
+ filePath: file.path,
1535
+ calledName: callSite.calledName,
1536
+ sourceId,
1537
+ ...(callSite.argCount !== undefined ? { argCount: callSite.argCount } : {}),
1538
+ ...(callSite.callForm !== undefined ? { callForm: callSite.callForm } : {}),
1539
+ ...(callSite.receiverName !== undefined
1540
+ ? { receiverName: callSite.receiverName }
1541
+ : {}),
1542
+ ...(receiverTypeName !== undefined ? { receiverTypeName } : {}),
1543
+ ...(callSite.receiverMixedChain !== undefined
1544
+ ? { receiverMixedChain: callSite.receiverMixedChain }
1545
+ : {}),
1546
+ ...(argTypes !== undefined ? { argTypes } : {}),
1547
+ });
1548
+ }
1549
+ }
1550
+ }
1551
+ }
1552
+ continue;
1553
+ }
1554
+ const definitionNode = (0, ast_helpers_js_1.getDefinitionNodeFromCaptures)(captureMap);
1555
+ const defaultNodeLabel = (0, ast_helpers_js_1.getLabelFromCaptures)(captureMap, provider);
1556
+ if (!defaultNodeLabel)
1557
+ continue;
1558
+ const nameNode = captureMap['name'];
1559
+ const extractedClassSymbol = definitionNode && provider.classExtractor?.isTypeDeclaration(definitionNode)
1560
+ ? provider.classExtractor.extract(definitionNode, {
1561
+ name: nameNode?.text,
1562
+ type: defaultNodeLabel,
1563
+ })
1564
+ : null;
1565
+ const nodeLabel = extractedClassSymbol?.type ?? defaultNodeLabel;
1566
+ const isClassLikeLabel = nodeLabel === 'Class' ||
1567
+ nodeLabel === 'Struct' ||
1568
+ nodeLabel === 'Interface' ||
1569
+ nodeLabel === 'Enum' ||
1570
+ nodeLabel === 'Record';
1571
+ if (isClassLikeLabel &&
1572
+ provider.classExtractor?.shouldSkipClassCapture?.({
1573
+ captureMap,
1574
+ definitionNode,
1575
+ nameNode,
1576
+ nodeLabel,
1577
+ }) === true) {
1578
+ continue;
1579
+ }
1580
+ const exportDefaultCall = nodeLabel === 'Function' && definitionNode?.type === 'export_statement'
1581
+ ? definitionNode.namedChildren.find((child) => child.type === 'call_expression')
1582
+ : undefined;
1583
+ const defaultExportHocName = (() => {
1584
+ if (exportDefaultCall === undefined)
1585
+ return null;
1586
+ const argList = exportDefaultCall.childForFieldName?.('arguments');
1587
+ const callback = argList?.namedChildren.find((child) => child.type === 'arrow_function' || child.type === 'function_expression');
1588
+ if (callback === undefined)
1589
+ return null;
1590
+ const callee = exportDefaultCall.childForFieldName?.('function');
1591
+ if (callee?.type === 'identifier' &&
1592
+ ts_js_hoc_utils_js_1.DEFAULT_EXPORT_IDENTIFIER_BLOCKLIST_SET.has(callee.text))
1593
+ return null;
1594
+ if (callee?.type === 'member_expression') {
1595
+ const property = callee.childForFieldName?.('property');
1596
+ if (property?.type === 'property_identifier' &&
1597
+ ts_js_hoc_utils_js_1.ARRAY_METHOD_HOC_BLOCKLIST_SET.has(property.text))
1598
+ return null;
1599
+ }
1600
+ return (0, ts_js_hoc_utils_js_1.deriveDefaultExportHocName)(file.path);
1601
+ })();
1602
+ // `module.exports = function () {}` (#2723): the whole module is the
1603
+ // callable. The member-assignment rule captures the LEFT property as the
1604
+ // name, which here is the literal `exports` — meaningless. Override it:
1605
+ // a named function expression supplies its own name, and the anonymous
1606
+ // forms are named after the file by the same convention anonymous
1607
+ // default exports already use. Takes precedence over `nameNode` for
1608
+ // exactly that reason.
1609
+ //
1610
+ // The derived name is dropped when it COLLIDES with a callable the module
1611
+ // already declares. `format.js` holding `function format() {}` plus an
1612
+ // anonymous `module.exports = function () { return format(v); }` merged
1613
+ // both onto one node, and the inner call to `format` then resolved to
1614
+ // that merged node — fabricating a self-recursion edge present in no
1615
+ // source (#2729 review F4). A fabricated edge is worse than a missing
1616
+ // one: it hands `impact` a caller that does not exist.
1617
+ const isCjsDefaultExport = definitionNode !== undefined && (0, ast_helpers_js_1.isCjsDefaultExportAssignment)(definitionNode);
1618
+ const cjsDefaultExportOwnName = isCjsDefaultExport
1619
+ ? definitionNode?.childForFieldName('right')?.childForFieldName('name')?.text
1620
+ : undefined;
1621
+ // A collision must SUPPRESS the definition outright, not merely decline to
1622
+ // name it — falling through would let the captured left property name the
1623
+ // node the literal `exports`, which is both meaningless and the very node
1624
+ // this feature's own test forbids.
1625
+ const suppressCjsDefaultExport = (() => {
1626
+ if (!isCjsDefaultExport || cjsDefaultExportOwnName !== undefined)
1627
+ return false;
1628
+ const root = definitionNode.tree?.rootNode;
1629
+ if (root === undefined)
1630
+ return false;
1631
+ return (0, cjs_export_assignment_js_1.defaultExportNameCollides)(definitionNode, root, (0, ts_js_hoc_utils_js_1.deriveDefaultExportHocName)(file.path));
1632
+ })();
1633
+ if (suppressCjsDefaultExport)
1634
+ continue;
1635
+ const cjsDefaultExportName = isCjsDefaultExport
1636
+ ? (cjsDefaultExportOwnName ?? (0, ts_js_hoc_utils_js_1.deriveDefaultExportHocName)(file.path))
1637
+ : null;
1638
+ // Synthesize name for constructors without explicit @name capture (e.g. Swift init)
1639
+ if (!nameNode &&
1640
+ nodeLabel !== 'Constructor' &&
1641
+ !extractedClassSymbol &&
1642
+ !defaultExportHocName &&
1643
+ !cjsDefaultExportName)
1644
+ continue;
1645
+ const nodeName = extractedClassSymbol?.name ??
1646
+ defaultExportHocName ??
1647
+ cjsDefaultExportName ??
1648
+ (nameNode ? nameNode.text : 'init');
1649
+ // Dedup: variable captures (Const/Static/Variable) may overlap with higher-priority
1650
+ // captures (e.g. `const fn = () => {}` matches both @definition.function and @definition.const).
1651
+ // Multi-name declarations share the same definition node, so include the emitted name.
1652
+ //
1653
+ // `processedDefinitionNodes` alone only suppressed the value twin when the
1654
+ // function-like match happened to be processed FIRST — and it is not.
1655
+ // tree-sitter completes `@definition.const` at `@name`, while
1656
+ // `@definition.function` must also match the trailing arrow / function
1657
+ // expression, so the const match is yielded first and its edgeless twin
1658
+ // escaped (#2687). `definitionPreScan` is the order-independent view of
1659
+ // the same claim, pre-scanned over `matches` before this loop and ranked so
1660
+ // a capture is dropped only by a STRICTLY higher-ranked claimant.
1661
+ //
1662
+ // It also replaces the old bare-`startIndex` claim, which was too coarse:
1663
+ // a callable declared FIRST in a multi-name declaration
1664
+ // (`const cb = () => 1, SIBLING = 2`) registered the shared definition
1665
+ // node and silently dropped every later sibling on it. Both keys are now
1666
+ // name-scoped, so siblings survive in either declarator order.
1667
+ //
1668
+ // The long-term collapse seam for this duplicate class is
1669
+ // `selectNodeBearingDef` (#1876, still unwired); this pre-scan is the local
1670
+ // form that keeps the hot loop single-pass. Keep them in sync if #1876 lands.
1671
+ if (definitionNode) {
1672
+ const definitionNameKey = `${definitionNode.startIndex}:${nodeName}`;
1673
+ if ((0, ast_helpers_js_1.isValueDefinitionLabel)(nodeLabel)) {
1674
+ if (processedDefinitionNodes.has(definitionNameKey) ||
1675
+ definitionPreScan.nonValue.has(definitionNameKey)) {
1676
+ continue;
1677
+ }
1678
+ processedDefinitionNodes.add(definitionNameKey);
1679
+ }
1680
+ else if (nodeLabel === 'Property' && definitionPreScan.callable.has(definitionNameKey)) {
1681
+ // Only a CALLABLE collapses a property. Consulting the wider
1682
+ // `nonValue` set here would let a property suppress itself, and would
1683
+ // let an annotated Python attribute lose to its own bare-assignment
1684
+ // twin — the property must outrank `Variable`, not tie with it.
1685
+ continue;
1686
+ }
1687
+ }
1688
+ // #2735: for a bound callable the graph-node capture sits on the OUTER
1689
+ // wrapper while scope-resolution anchors on the INNER expression. The
1690
+ // position join is line-only, so `startLine` must follow the initializer
1691
+ // (ids still use `definitionNode` via `localIdentity`).
1692
+ const startRow = definitionNode &&
1693
+ (nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor')
1694
+ ? (0, callable_id_js_1.boundCallableStartRow)(definitionNode, nodeName, nodeLabel, parsedFile?.localDefs, nameNode)
1695
+ : definitionNode?.startPosition.row;
1696
+ const startLine = startRow !== undefined
1697
+ ? startRow + lineOffset
1698
+ : nameNode
1699
+ ? nameNode.startPosition.row + lineOffset
1700
+ : lineOffset;
1701
+ // Compute enclosing class BEFORE node ID — needed to qualify method IDs
1702
+ const needsOwner = nodeLabel === 'Method' ||
1703
+ nodeLabel === 'Constructor' ||
1704
+ nodeLabel === 'Property' ||
1705
+ nodeLabel === 'Function';
1706
+ // #1978: thread the class-extractor's qualifier into the owner walk when the
1707
+ // language opts into qualified node ids, so a nested member's owner resolves
1708
+ // to the *qualified* class id (Outer.Inner). Gated on the flag → byte-identical
1709
+ // when off. Mirrors parsing-processor.ts.
1710
+ const getQualifiedOwnerName = provider.classExtractor?.qualifiedNodeId === true
1711
+ ? (node, simpleName) =>
1712
+ // #1991: LOCKSTEP — a Ruby `module` owner is not a typeDeclaration, so
1713
+ // extractQualifiedName returns null; fall back to the scope walk so a
1714
+ // method inside a nested module owns through the SAME qualified Trait
1715
+ // id its node uses on the worker path too.
1716
+ provider.classExtractor.extractQualifiedName(node, simpleName) ??
1717
+ provider.classExtractor.qualifyScopeName?.(node, simpleName) ??
1718
+ null
1719
+ : undefined;
1720
+ // A Property declared inside a function/lambda BODY is a function-LOCAL
1721
+ // binding (e.g. Kotlin `val (a,b) = pair` or a `for ((k,v) in m)` loop
1722
+ // destructuring emitted as `@definition.property` to dodge the local-symbol
1723
+ // pruner), NOT a class member. Such locals must not get a HAS_PROPERTY owner
1724
+ // edge from the enclosing class. Detect them by walking from the def node:
1725
+ // if a function-like ancestor is reached BEFORE any class container, the
1726
+ // property is enclosed by a function. Language-agnostic — genuine class
1727
+ // fields sit directly in the class body with no intervening function, so
1728
+ // they are unaffected (#1919 review CF3).
1729
+ //
1730
+ // EXCEPTION: a constructor PARAMETER property (TypeScript
1731
+ // `constructor(public name: string)`) is also enclosed by a function, but
1732
+ // it IS a class member — it is reached through the parameter list, not the
1733
+ // executable body. So only strip the owner when the property is NOT inside
1734
+ // a parameter list of that function (i.e. it's a body local).
1735
+ const propOwnerNode = nameNode || definitionNode;
1736
+ // A Property is function-local (and must NOT get a class HAS_PROPERTY owner)
1737
+ // when its nearest enclosing executable body — reached before any class
1738
+ // container — is a function/accessor/initializer body, AND it is not a
1739
+ // constructor parameter-property (rescued by the param-list carve-out).
1740
+ // Uses LOCAL_SCOPE_BODY_NODE_TYPES (not FUNCTION_NODE_TYPES): the latter
1741
+ // mis-includes Dart bare signatures (over-stripping accessors) and omits
1742
+ // Kotlin/Swift init+accessor bodies (under-stripping their locals) — see
1743
+ // the #1919 review of this guard.
1744
+ const isFunctionLocalProperty = nodeLabel === 'Property' &&
1745
+ propOwnerNode !== undefined &&
1746
+ (0, ast_helpers_js_1.findAncestorBeforeBoundary)(propOwnerNode, ast_helpers_js_1.LOCAL_SCOPE_BODY_NODE_TYPES, ast_helpers_js_1.CLASS_CONTAINER_TYPES) !== null &&
1747
+ (0, ast_helpers_js_1.findAncestorBeforeBoundary)(propOwnerNode, ast_helpers_js_1.PARAMETER_LIST_NODE_TYPES, ast_helpers_js_1.LOCAL_SCOPE_BODY_NODE_TYPES) === null;
1748
+ const enclosingClassInfo = needsOwner && !isFunctionLocalProperty
1749
+ ? cachedFindEnclosingClassInfo(nameNode || definitionNode, file.path, provider.resolveEnclosingOwner, getQualifiedOwnerName)
1750
+ : null;
1751
+ const enclosingClassId = enclosingClassInfo?.qualifiedClassId ?? enclosingClassInfo?.classId ?? null;
1752
+ // A Method with no enclosing class container is owned by a NAMED binding
1753
+ // instead: an object literal (`const service = { load() {} }`) or, since
1754
+ // the #2723 follow-up, a prototype assignment
1755
+ // (`Foo.prototype.bar = function () {}`). Both resolve the owner from the
1756
+ // syntax rather than from an ancestor walk, and both are language-shaped
1757
+ // helpers behind the provider's own label decision — shared code here
1758
+ // only asks "does this Method name an owner".
1759
+ const objectLiteralOwnerInfo = !enclosingClassId && nodeLabel === 'Method' && definitionNode
1760
+ ? ((0, ast_helpers_js_1.findMemberAssignmentOwnerInfo)(definitionNode, file.path) ??
1761
+ (0, ast_helpers_js_1.findObjectLiteralBindingInfo)(definitionNode, file.path))
1762
+ : null;
1763
+ // #1978: hoisted ABOVE qualifiedName/node-id (load-bearing order) so a
1764
+ // class-like node can key its id by its fully-qualified path. Derived from
1765
+ // the SAME extractQualifiedName the owner edge uses → owner id == node id.
1766
+ const classNodeForSymbol = definitionNode || nameNode;
1767
+ const qualifiedTypeName = extractedClassSymbol?.qualifiedName ??
1768
+ (classNodeForSymbol && provider.classExtractor?.isTypeDeclaration(classNodeForSymbol)
1769
+ ? (provider.classExtractor.extractQualifiedName(classNodeForSymbol, nodeName) ?? nodeName)
1770
+ : // #1991: LOCKSTEP with parsing-processor.ts — qualify a Ruby `module`
1771
+ // (Trait) via the scope walk so same-tail nested mixin modules get
1772
+ // distinct ids on the worker path too. Gated on qualifiedNodeId.
1773
+ (0, ast_helpers_js_1.isQualifiableScopeLabel)(nodeLabel) &&
1774
+ provider.classExtractor?.qualifiedNodeId === true &&
1775
+ classNodeForSymbol
1776
+ ? (provider.classExtractor.qualifyScopeName?.(classNodeForSymbol, nodeName) ??
1777
+ undefined)
1778
+ : undefined);
1779
+ // Qualify method/property IDs with enclosing class name to avoid collisions.
1780
+ // Class-like nodes use their own fully-qualified path as the id key when the
1781
+ // language enables qualifiedNodeId (#1978); everything else is unchanged.
1782
+ // #1982: LOCKSTEP with parsing-processor.ts — a Rust inherent-impl with an
1783
+ // UNSCOPED bare target is keyed by the enclosing `mod_item` scope so the
1784
+ // worker-path Impl node id matches the sequential path and the owner walk.
1785
+ // #2699: a callable nested inside another callable is qualified by the
1786
+ // enclosing callable, so a function-local closure stops colliding with a
1787
+ // same-named file-level function.
1788
+ // Applies to VALUES as well as callables since #2699 closed A1: a
1789
+ // top-level `const handler` and a function-local `const handler`
1790
+ // otherwise collapse onto one `Const:v.ts:handler`, which was the
1791
+ // issue's original complaint and is unreachable from a callable-only
1792
+ // gate. `isPositionQualifiedLocalLabel` is the single definition of that
1793
+ // set, shared with resolution in `ids.ts` — the two phases disagreeing
1794
+ // silently drops edges rather than failing (#2714).
1795
+ // Same helper as the caller-attribution phase — see `enclosingCallablePrefix`.
1796
+ //
1797
+ // A CLASS MEMBER must never gain a local prefix, and the plain walk is not
1798
+ // enough to guarantee that once `Property`/`Static` are in the set. A
1799
+ // TypeScript constructor PARAMETER PROPERTY —
1800
+ // `constructor(private readonly port: Port)` — reaches the constructor's
1801
+ // `method_definition` THROUGH the parameter list, and `method_definition`
1802
+ // is in LOCAL_SCOPE_BODY_NODE_TYPES, so the walk hits it BEFORE any class
1803
+ // boundary and re-keys a genuine field as `C.constructor.port@r:c`. That
1804
+ // silently empties the `C.port` slot every `impact` / `rename` / FTS
1805
+ // consumer addresses, and the class still asserts HAS_PROPERTY against it.
1806
+ //
1807
+ // `isFunctionLocalProperty` above already encodes the correct test (a
1808
+ // parameter-list ancestor reached before any local-scope body means NOT
1809
+ // function-local); reuse that exclusion here rather than spelling a second
1810
+ // rule, so the owner-edge decision and the id decision cannot disagree.
1811
+ const isParameterScopedMember = (nodeLabel === 'Property' || nodeLabel === 'Static') &&
1812
+ definitionNode !== undefined &&
1813
+ (0, ast_helpers_js_1.findAncestorBeforeBoundary)(definitionNode, ast_helpers_js_1.PARAMETER_LIST_NODE_TYPES, ast_helpers_js_1.LOCAL_SCOPE_BODY_NODE_TYPES) !== null;
1814
+ const nestedCallablePrefix = (0, callable_labels_js_1.isPositionQualifiedLocalLabel)(nodeLabel) && definitionNode && !isParameterScopedMember
1815
+ ? enclosingCallablePrefix(definitionNode, file.path, provider)
1816
+ : undefined;
1817
+ const rustImplQualifiedName = nodeLabel === 'Impl' &&
1818
+ definitionNode?.type === 'impl_item' &&
1819
+ nameNode?.type === 'type_identifier'
1820
+ ? (0, ast_helpers_js_1.qualifyRustImplTargetByModScope)(definitionNode, nodeName)
1821
+ : undefined;
1822
+ const qualifiedNameBeforeModScope = rustImplQualifiedName !== undefined
1823
+ ? rustImplQualifiedName
1824
+ : // #1991: LOCKSTEP — include Trait so a Ruby mixin module's qualified
1825
+ // scope id keys the worker-path node, matching the sequential path.
1826
+ (isClassLikeLabel || (0, ast_helpers_js_1.isQualifiableScopeLabel)(nodeLabel)) &&
1827
+ provider.classExtractor?.qualifiedNodeId === true &&
1828
+ qualifiedTypeName !== undefined
1829
+ ? qualifiedTypeName
1830
+ : nestedCallablePrefix !== undefined && definitionNode
1831
+ ? (0, callable_id_js_1.nestedCallableQualifiedName)(nestedCallablePrefix, definitionNode, nodeName)
1832
+ : enclosingClassInfo
1833
+ ? `${enclosingClassInfo.className}.${nodeName}`
1834
+ : // A member whose owner is named by the assignment rather than
1835
+ // by an enclosing container (`Foo.prototype.bar = …`) qualifies
1836
+ // by that owner, so two constructors in one file that both
1837
+ // define `bar` stay distinct nodes.
1838
+ objectLiteralOwnerInfo?.ownerName !== undefined
1839
+ ? `${objectLiteralOwnerInfo.ownerName}.${nodeName}`
1840
+ : nodeName;
1841
+ // #2742: qualify by the enclosing `mod` chain, so two same-named items at
1842
+ // different module depths in one file are DISTINCT nodes. Without this,
1843
+ // `mod inner { fn dispatch }` and a crate-root `fn dispatch` both keyed
1844
+ // `Function:<file>:dispatch`, first-wins — so a correctly resolved call
1845
+ // into the inline module still rendered as a self-loop, and `impact`
1846
+ // reported the real callee as unreached.
1847
+ //
1848
+ // Keyed purely on the `mod_item` node type, exactly as the impl-target
1849
+ // qualifier above (#1982) already is, so it is a no-op for every language
1850
+ // whose grammar has no such node. The impl branch already applied it and
1851
+ // is left alone rather than qualified twice.
1852
+ //
1853
+ // Scoped to items that sit on NEITHER side of an owner edge, because only
1854
+ // the id is re-keyed here — the anchor is minted independently by
1855
+ // `findEnclosingClassInfo` and does not move with it:
1856
+ //
1857
+ // - `!enclosingClassInfo` excludes the MEMBER side. A method already
1858
+ // carries its owner's name (`Inner.method`), and for an unscoped
1859
+ // inherent impl that owner is mod-scoped by the impl qualifier above,
1860
+ // so qualifying the member again would break the byte-for-byte
1861
+ // agreement #1975/#1982 established.
1862
+ // - `!MEMBER_OWNER_NODE_TYPES.has(...)` excludes the OWNER side. A
1863
+ // `struct` / `trait` / `enum` / `impl` declared directly in a `mod` has
1864
+ // no enclosing class, so the member-side guard alone let it through
1865
+ // while its own anchor stayed bare — `mod engine { struct Config { … } }`
1866
+ // minted `Struct:<file>:engine.Config` against a `HAS_PROPERTY` edge
1867
+ // anchored on `Struct:<file>:Config`, dangling every field. The same
1868
+ // gap put `impl a::Inner` inside a `mod` back on the #1975 rake this
1869
+ // helper's own docblock warns about: the impl branch above deliberately
1870
+ // fires only for an UNSCOPED `type_identifier`, and this gate was
1871
+ // picking up the scoped targets it had just excluded.
1872
+ // - `nestedCallablePrefix === undefined` excludes an item inside a
1873
+ // CALLABLE. `fn wrapper() { mod helper { fn dispatch } }` composed the
1874
+ // mod segment outermost — `helper.wrapper.dispatch@2:8` — inverting the
1875
+ // real nesting, because the mod prefix is prepended to a name the
1876
+ // enclosing-callable pass has already qualified. Nothing dangled (the
1877
+ // `@line:col` suffix keeps such ids unique on its own, which is also why
1878
+ // the mod segment adds no identity here), but the path read as a lie
1879
+ // about the source. Skipping is the honest answer; reordering would mean
1880
+ // interleaving two qualifier passes for a shape that only ever produces
1881
+ // already-unique ids.
1882
+ //
1883
+ // Same-named members on same-named types in sibling modules therefore
1884
+ // still collapse, as do the containers themselves — unchanged from before
1885
+ // this fix, and owned by the owner edge rather than worked around here.
1886
+ const qualifiesByEnclosingModScope = rustImplQualifiedName === undefined &&
1887
+ definitionNode !== undefined &&
1888
+ !ast_helpers_js_1.MEMBER_OWNER_NODE_TYPES.has(definitionNode.type) &&
1889
+ nestedCallablePrefix === undefined &&
1890
+ !enclosingClassInfo &&
1891
+ objectLiteralOwnerInfo?.ownerName === undefined;
1892
+ const qualifiedName = qualifiesByEnclosingModScope && definitionNode !== undefined
1893
+ ? (0, ast_helpers_js_1.qualifyByEnclosingModScope)(definitionNode, qualifiedNameBeforeModScope)
1894
+ : qualifiedNameBeforeModScope;
1895
+ // Extract method metadata BEFORE generating node ID — parameterCount is needed
1896
+ // to disambiguate overloaded methods via #<arity> suffix in the ID.
1897
+ let declaredType;
1898
+ let methodProps = {};
1899
+ let arityForId; // raw param count for ID, even for variadic
1900
+ let defMethodMap;
1901
+ let defMethodInfo;
1902
+ if (nodeLabel === 'Function' || nodeLabel === 'Method' || nodeLabel === 'Constructor') {
1903
+ // Use MethodExtractor for method metadata — provides parameterCount, parameterTypes,
1904
+ // returnType, isAbstract/isFinal/annotations, visibility, and more.
1905
+ let enrichedByMethodExtractor = false;
1906
+ if (provider.methodExtractor && definitionNode) {
1907
+ const classNode = findEnclosingClassNode(definitionNode) ?? findClassNodeByQualifiedName(definitionNode);
1908
+ if (classNode) {
1909
+ const methodMap = getMethodInfo(classNode, provider, {
1910
+ filePath: file.path,
1911
+ language,
1912
+ });
1913
+ const defLine = definitionNode.startPosition.row + 1;
1914
+ const info = methodMap?.get(`${nodeName}:${defLine}`);
1915
+ if (info) {
1916
+ enrichedByMethodExtractor = true;
1917
+ arityForId = (0, method_props_js_1.arityForIdFromInfo)(info);
1918
+ methodProps = (0, method_props_js_1.buildMethodProps)(info);
1919
+ defMethodMap = methodMap;
1920
+ defMethodInfo = info;
1921
+ }
1922
+ }
1923
+ }
1924
+ // For top-level methods (e.g. Go method_declaration), try extractFromNode
1925
+ if (!enrichedByMethodExtractor &&
1926
+ provider.methodExtractor?.extractFromNode &&
1927
+ definitionNode) {
1928
+ const info = provider.methodExtractor.extractFromNode(definitionNode, {
1929
+ filePath: file.path,
1930
+ language,
1931
+ });
1932
+ if (info) {
1933
+ enrichedByMethodExtractor = true;
1934
+ arityForId = (0, method_props_js_1.arityForIdFromInfo)(info);
1935
+ methodProps = (0, method_props_js_1.buildMethodProps)(info);
1936
+ }
1937
+ }
1938
+ }
1939
+ // Append #<paramCount> to owned callable IDs to disambiguate overloads.
1940
+ // Top-level Function IDs stay stable; functions inside an owner may overload.
1941
+ // When same-arity collisions exist, append ~type1,type2 for further disambiguation.
1942
+ const needsAritySuffix = nodeLabel === 'Method' ||
1943
+ nodeLabel === 'Constructor' ||
1944
+ (nodeLabel === 'Function' && enclosingClassId !== null);
1945
+ let arityTag = needsAritySuffix && arityForId !== undefined ? `#${arityForId}` : '';
1946
+ if (arityTag && defMethodMap && defMethodInfo) {
1947
+ const groups = (0, method_props_js_1.buildCollisionGroups)(defMethodMap);
1948
+ arityTag += (0, method_props_js_1.typeTagForId)(defMethodMap, nodeName, arityForId, defMethodInfo, language, groups);
1949
+ arityTag += (0, method_props_js_1.constTagForId)(defMethodMap, nodeName, arityForId, defMethodInfo, groups);
1950
+ }
1951
+ const parameterShapeTag = nodeLabel === 'Function' || nodeLabel === 'Method'
1952
+ ? (0, method_props_js_1.parameterShapeIdTag)(methodProps.parameterTypes, methodProps.parameterTypeClasses)
1953
+ : '';
1954
+ const classTemplateArguments = extractedClassSymbol?.templateArguments ??
1955
+ provider.classExtractor?.extractTemplateArgumentsFromCapture?.({
1956
+ captureMap,
1957
+ definitionNode,
1958
+ nameNode,
1959
+ }) ??
1960
+ (captureMap['template-arguments']
1961
+ ? (0, template_arguments_js_1.extractTemplateArguments)(captureMap['template-arguments'].text)
1962
+ : undefined) ??
1963
+ (nameNode && nameNode.text ? (0, template_arguments_js_1.extractTemplateArguments)(nameNode.text) : undefined);
1964
+ const classTemplateTag = (nodeLabel === 'Class' ||
1965
+ nodeLabel === 'Struct' ||
1966
+ nodeLabel === 'Interface' ||
1967
+ nodeLabel === 'Enum' ||
1968
+ nodeLabel === 'Record') &&
1969
+ classTemplateArguments !== undefined &&
1970
+ classTemplateArguments.length > 0
1971
+ ? (0, template_arguments_js_1.templateArgumentsIdTag)(classTemplateArguments)
1972
+ : '';
1973
+ // SFINAE / `requires`-clause aware ID disambiguation (issue #1579).
1974
+ // Function-template overloads with identical parameterTypes but
1975
+ // mutually-exclusive constraints (e.g. `enable_if_t<is_integral_v<T>>`
1976
+ // vs `enable_if_t<is_floating_point_v<T>>`) need distinct graph nodes
1977
+ // so the constraint-filter step in `narrowOverloadCandidates` has two
1978
+ // candidates to narrow between. Without this tag they collapse to a
1979
+ // single Function node and the SFINAE call resolves to only one edge
1980
+ // regardless of which overload's constraint holds. This mirrors the
1981
+ // sequential `parsing-processor` path removed in #1983 — the worker is
1982
+ // now the sole parse path, so it must stamp the constraint tag and the
1983
+ // `templateConstraints` node property the resolver looks up by re-
1984
+ // hashing the def's constraints (see graph-bridge ids.ts / node-lookup.ts).
1985
+ let parsedTemplateConstraints = undefined;
1986
+ let constraintsTag = '';
1987
+ if ((nodeLabel === 'Function' || nodeLabel === 'Method') &&
1988
+ provider.extractTemplateConstraints !== undefined &&
1989
+ definitionNode) {
1990
+ try {
1991
+ parsedTemplateConstraints = provider.extractTemplateConstraints(definitionNode);
1992
+ if (parsedTemplateConstraints !== undefined) {
1993
+ constraintsTag = (0, template_arguments_js_1.templateConstraintsIdTag)(parsedTemplateConstraints);
1994
+ }
1995
+ }
1996
+ catch (err) {
1997
+ // Optional C++ template-constraint enrichment: fall back to no tag, but
1998
+ // surface the failure (#2264) — matches the CFG-build warning above.
1999
+ reportWarning(`Template-constraint extraction failed for ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
2000
+ parsedTemplateConstraints = undefined;
2001
+ constraintsTag = '';
2002
+ }
2003
+ }
2004
+ const nodeId = (0, utils_js_1.generateId)(nodeLabel, `${file.path}:${qualifiedName}${classTemplateTag}${arityTag}${parameterShapeTag}${constraintsTag}`);
2005
+ let description;
2006
+ try {
2007
+ description = provider.descriptionExtractor?.(nodeLabel, nodeName, captureMap);
2008
+ }
2009
+ catch (err) {
2010
+ // A throw here (an unexpected tree-sitter node shape, a provider bug) must
2011
+ // NOT propagate — it would escape processFileGroup to the language-group
2012
+ // catch, which treats any throw as "parser unavailable" and silently drops
2013
+ // every remaining file in the group. Mirrors the extractTemplateConstraints
2014
+ // guard above (#2286 review).
2015
+ reportWarning(`Description extraction failed for ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
2016
+ description = undefined;
2017
+ }
2018
+ let frameworkHint = definitionNode
2019
+ ? (0, framework_detection_js_1.detectFrameworkFromAST)(language, (definitionNode.text || '').slice(0, 300))
2020
+ : null;
2021
+ // Suppress Spring framework hint for methods inside interfaces
2022
+ // (Feign clients, JAX-RS proxies are consumers, not providers)
2023
+ if (frameworkHint && definitionNode) {
2024
+ let classCheck = definitionNode.parent;
2025
+ while (classCheck) {
2026
+ if (classCheck.type === 'interface_declaration') {
2027
+ frameworkHint = null;
2028
+ break;
2029
+ }
2030
+ if (classCheck.type === 'class_declaration' || classCheck.type === 'program') {
2031
+ break;
2032
+ }
2033
+ classCheck = classCheck.parent;
2034
+ }
2035
+ }
2036
+ // Decorators appear on lines immediately before their definition; allow up to
2037
+ // MAX_DECORATOR_SCAN_LINES gap for blank lines / multi-line decorator stacks.
2038
+ const MAX_DECORATOR_SCAN_LINES = 5;
2039
+ if (definitionNode) {
2040
+ const defStartLine = definitionNode.startPosition.row;
2041
+ for (let checkLine = defStartLine - 1; checkLine >= Math.max(0, defStartLine - MAX_DECORATOR_SCAN_LINES); checkLine--) {
2042
+ const dec = fileDecorators.get(checkLine);
2043
+ if (dec) {
2044
+ // Use first (closest) decorator found for framework hint
2045
+ if (!frameworkHint) {
2046
+ frameworkHint = {
2047
+ framework: 'decorator',
2048
+ entryPointMultiplier: 1.2,
2049
+ reason: `@${dec.name}${dec.arg ? `("${dec.arg}")` : ''}`,
2050
+ };
2051
+ }
2052
+ // Emit tool definition if this is a @tool decorator
2053
+ if (dec.isTool) {
2054
+ result.toolDefs.push({
2055
+ filePath: file.path,
2056
+ toolName: nodeName,
2057
+ description: (dec.arg || description || '').slice(0, 200),
2058
+ lineNumber: definitionNode.startPosition.row + lineOffset,
2059
+ handlerNodeId: nodeId,
2060
+ });
2061
+ }
2062
+ fileDecorators.delete(checkLine);
2063
+ }
2064
+ }
2065
+ }
2066
+ // Property metadata extraction (not needed before nodeId — Properties don't overload)
2067
+ if (nodeLabel === 'Property' && definitionNode) {
2068
+ // FieldExtractor is the single source of truth when available
2069
+ if (provider.fieldExtractor && typeEnv) {
2070
+ const classNode = findEnclosingClassNode(definitionNode);
2071
+ if (classNode) {
2072
+ const fieldMap = getFieldInfo(classNode, provider, {
2073
+ typeEnv,
2074
+ symbolTable: NOOP_SYMBOL_TABLE,
2075
+ filePath: file.path,
2076
+ language,
2077
+ });
2078
+ const info = fieldMap?.get(nodeName);
2079
+ if (info) {
2080
+ declaredType = info.type ?? undefined;
2081
+ // Mutate methodProps BEFORE the `{...methodProps}` spread below —
2082
+ // rawDeclaredType is the verbatim generic type text (U1, PR #2200).
2083
+ if (info.rawDeclaredType !== undefined) {
2084
+ methodProps.rawDeclaredType = info.rawDeclaredType;
2085
+ }
2086
+ // Field annotations ('@Name' strings, U2 PR #2200) — omit when empty.
2087
+ if (info.annotations !== undefined && info.annotations.length > 0) {
2088
+ methodProps.annotations = info.annotations;
2089
+ }
2090
+ methodProps.visibility = info.visibility;
2091
+ methodProps.isStatic = info.isStatic;
2092
+ methodProps.isReadonly = info.isReadonly;
2093
+ }
2094
+ }
2095
+ }
2096
+ }
2097
+ // Variable/Const/Static metadata extraction via VariableExtractor
2098
+ if ((nodeLabel === 'Const' || nodeLabel === 'Static' || nodeLabel === 'Variable') &&
2099
+ definitionNode &&
2100
+ provider.variableExtractor) {
2101
+ let variableInfoByName = variableInfoCache.get(definitionNode.startIndex);
2102
+ if (!variableInfoByName) {
2103
+ const varCtx = {
2104
+ filePath: file.path,
2105
+ language,
2106
+ };
2107
+ variableInfoByName = new Map(provider.variableExtractor
2108
+ .extractAll(definitionNode, varCtx)
2109
+ .map((info) => [info.name, info]));
2110
+ variableInfoCache.set(definitionNode.startIndex, variableInfoByName);
2111
+ }
2112
+ const varInfo = variableInfoByName.get(nodeName);
2113
+ if (varInfo) {
2114
+ if (varInfo.type)
2115
+ declaredType = varInfo.type;
2116
+ methodProps.visibility = varInfo.visibility;
2117
+ methodProps.isStatic = varInfo.isStatic;
2118
+ methodProps.isConst = varInfo.isConst;
2119
+ methodProps.isMutable = varInfo.isMutable;
2120
+ methodProps.scope = varInfo.scope;
2121
+ }
2122
+ }
2123
+ result.nodes.push({
2124
+ id: nodeId,
2125
+ label: nodeLabel,
2126
+ properties: {
2127
+ name: nodeName,
2128
+ filePath: file.path,
2129
+ startLine,
2130
+ endLine: definitionNode ? definitionNode.endPosition.row + lineOffset : startLine,
2131
+ language: language,
2132
+ isExported: language === index_js_1.SupportedLanguages.Vue && isVueSetup
2133
+ ? (0, vue_sfc_extractor_js_1.isVueSetupTopLevel)(nameNode || definitionNode)
2134
+ : cachedExportCheck(provider.exportChecker, nameNode || definitionNode, nodeName),
2135
+ ...(qualifiedTypeName !== undefined ? { qualifiedName: qualifiedTypeName } : {}),
2136
+ ...(classTemplateArguments !== undefined && classTemplateArguments.length > 0
2137
+ ? { templateArguments: classTemplateArguments }
2138
+ : {}),
2139
+ ...(parsedTemplateConstraints !== undefined
2140
+ ? { templateConstraints: parsedTemplateConstraints }
2141
+ : {}),
2142
+ ...(frameworkHint
2143
+ ? {
2144
+ astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
2145
+ astFrameworkReason: frameworkHint.reason,
2146
+ }
2147
+ : {}),
2148
+ ...(description !== undefined ? { description } : {}),
2149
+ ...methodProps,
2150
+ ...(declaredType !== undefined ? { declaredType } : {}),
2151
+ },
2152
+ });
2153
+ // enclosingClassId already computed above (before nodeId generation)
2154
+ const ownerId = enclosingClassId ?? objectLiteralOwnerInfo?.ownerId;
2155
+ result.symbols.push({
2156
+ filePath: file.path,
2157
+ name: nodeName,
2158
+ nodeId,
2159
+ type: nodeLabel,
2160
+ ...(qualifiedTypeName !== undefined ? { qualifiedName: qualifiedTypeName } : {}),
2161
+ parameterCount: methodProps.parameterCount,
2162
+ requiredParameterCount: methodProps.requiredParameterCount,
2163
+ parameterTypes: methodProps.parameterTypes,
2164
+ parameterTypeClasses: methodProps.parameterTypeClasses,
2165
+ returnType: methodProps.returnType,
2166
+ ...(declaredType !== undefined ? { declaredType } : {}),
2167
+ ...(classTemplateArguments !== undefined && classTemplateArguments.length > 0
2168
+ ? { templateArguments: classTemplateArguments }
2169
+ : {}),
2170
+ ...(ownerId !== undefined ? { ownerId } : {}),
2171
+ visibility: methodProps.visibility,
2172
+ isStatic: methodProps.isStatic,
2173
+ isReadonly: methodProps.isReadonly,
2174
+ isAbstract: methodProps.isAbstract,
2175
+ isFinal: methodProps.isFinal,
2176
+ ...(methodProps.isDeleted !== undefined
2177
+ ? { isDeleted: methodProps.isDeleted }
2178
+ : {}),
2179
+ ...(methodProps.isVirtual !== undefined
2180
+ ? { isVirtual: methodProps.isVirtual }
2181
+ : {}),
2182
+ ...(methodProps.isOverride !== undefined
2183
+ ? { isOverride: methodProps.isOverride }
2184
+ : {}),
2185
+ ...(methodProps.isAsync !== undefined ? { isAsync: methodProps.isAsync } : {}),
2186
+ ...(methodProps.isPartial !== undefined
2187
+ ? { isPartial: methodProps.isPartial }
2188
+ : {}),
2189
+ ...(methodProps.annotations !== undefined
2190
+ ? { annotations: methodProps.annotations }
2191
+ : {}),
2192
+ });
2193
+ // Only emit File -> Symbol DEFINES for top-level symbols (issue #1944).
2194
+ if (ownerId === undefined) {
2195
+ const fileId = (0, utils_js_1.generateId)('File', file.path);
2196
+ const relId = (0, utils_js_1.generateId)('DEFINES', `${fileId}->${nodeId}`);
2197
+ result.relationships.push({
2198
+ id: relId,
2199
+ sourceId: fileId,
2200
+ targetId: nodeId,
2201
+ type: 'DEFINES',
2202
+ confidence: 1.0,
2203
+ reason: '',
2204
+ });
2205
+ }
2206
+ // ── HAS_METHOD / HAS_PROPERTY: link member to enclosing class ──
2207
+ if (ownerId !== undefined) {
2208
+ const memberEdgeType = nodeLabel === 'Property' ? 'HAS_PROPERTY' : 'HAS_METHOD';
2209
+ result.relationships.push({
2210
+ id: (0, utils_js_1.generateId)(memberEdgeType, `${ownerId}->${nodeId}`),
2211
+ sourceId: ownerId,
2212
+ targetId: nodeId,
2213
+ type: memberEdgeType,
2214
+ confidence: 1.0,
2215
+ reason: objectLiteralOwnerInfo
2216
+ ? 'object literal method belongs to exported object binding'
2217
+ : '',
2218
+ });
2219
+ }
2220
+ // ── Fetch wrapper detection: record functions that call fetch() internally ──
2221
+ if (nodeLabel === 'Function' &&
2222
+ definitionNode &&
2223
+ nameNode &&
2224
+ (language === index_js_1.SupportedLanguages.TypeScript || language === index_js_1.SupportedLanguages.JavaScript)) {
2225
+ if (checkForFetchCall(definitionNode)) {
2226
+ result.fetchWrapperDefs.push({
2227
+ filePath: file.path,
2228
+ functionName: nameNode.text,
2229
+ });
2230
+ }
2231
+ }
2232
+ }
2233
+ // Extract framework routes via provider detection (e.g., Laravel routes.php)
2234
+ if (provider.isRouteFile?.(file.path)) {
2235
+ const extractedRoutes = (0, laravel_js_1.extractLaravelRoutes)(tree, file.path);
2236
+ for (const r of extractedRoutes)
2237
+ result.routes.push(r);
2238
+ }
2239
+ // Extract ORM queries (Prisma, Supabase)
2240
+ extractORMQueries(file.path, parseContent, result.ormQueries);
2241
+ // Extract FastAPI include_router(prefix=...) and `from <mod> import router`
2242
+ // sites. parse-impl aggregates these into a per-module prefix map and
2243
+ // injects the resolved prefix onto each ExtractedDecoratorRoute that
2244
+ // came from a `@router.<verb>` decorator. Python-only.
2245
+ if (language === index_js_1.SupportedLanguages.Python) {
2246
+ (0, fastapi_router_bindings_js_1.extractFastAPIRouterBindings)(file.path, parseContent, result.routerIncludes, result.routerImports, (result.routerModuleAliases ??= []), (result.routerConstructorPrefixes ??= []));
2247
+ // #2391: harvest module-level string constants + from-imports so parse-impl
2248
+ // can resolve non-literal decorator route paths cross-file. Only emit for
2249
+ // files that carry something resolvable (a constant definition or an import
2250
+ // binding) to keep the aggregate bounded on large repos.
2251
+ const constants = (0, python_const_resolver_js_1.extractPythonModuleConstants)(tree);
2252
+ if (constants.literals.size > 0 || constants.exprs.size > 0 || constants.imports.size > 0) {
2253
+ (result.moduleConstants ??= []).push({ filePath: file.path, constants });
2254
+ }
2255
+ }
2256
+ // Language-specific decorator route extraction via provider hook.
2257
+ // The provider's extractDecoratorRoutes walks the AST for framework-specific
2258
+ // route patterns (e.g., Java Spring class-level prefix joining). Routes are
2259
+ // appended to decoratorRoutes for the routes phase to emit as Route nodes.
2260
+ if (provider.extractDecoratorRoutes) {
2261
+ const frameworkRoutes = provider.extractDecoratorRoutes(tree, file.path, lineOffset);
2262
+ for (const r of frameworkRoutes)
2263
+ result.decoratorRoutes.push(r);
2264
+ }
2265
+ // Project-wide route-inheritance type collection via provider hook (#2288).
2266
+ // The per-file SharedSpringType views are aggregated by the parse phase,
2267
+ // which then resolves interface-inherited routes cross-file.
2268
+ if (provider.extractRouteInheritanceTypes) {
2269
+ const springTypes = provider.extractRouteInheritanceTypes(tree, file.path);
2270
+ if (springTypes.length > 0)
2271
+ (result.springTypes ??= []).push(...springTypes);
2272
+ }
2273
+ // Vue: emit CALLS edges for components used in <template>
2274
+ if (language === index_js_1.SupportedLanguages.Vue) {
2275
+ const templateComponents = (0, vue_sfc_extractor_js_1.extractTemplateComponents)(file.content);
2276
+ for (const componentName of templateComponents) {
2277
+ result.calls.push({
2278
+ filePath: file.path,
2279
+ calledName: componentName,
2280
+ sourceId: (0, utils_js_1.generateId)('File', file.path),
2281
+ callForm: 'free',
2282
+ });
2283
+ }
2284
+ }
2285
+ }
2286
+ };
2287
+ // ============================================================================
2288
+ // Worker message handler — supports sub-batch streaming
2289
+ // ============================================================================
2290
+ /** Accumulated result across sub-batches */
2291
+ let accumulated = {
2292
+ nodes: [],
2293
+ relationships: [],
2294
+ symbols: [],
2295
+ calls: [],
2296
+ assignments: [],
2297
+ routes: [],
2298
+ fetchCalls: [],
2299
+ fetchWrapperDefs: [],
2300
+ decoratorRoutes: [],
2301
+ routerIncludes: [],
2302
+ routerImports: [],
2303
+ routerConstructorPrefixes: [],
2304
+ routerModuleAliases: [],
2305
+ toolDefs: [],
2306
+ ormQueries: [],
2307
+ constructorBindings: [],
2308
+ fileScopeBindings: [],
2309
+ parsedFiles: [],
2310
+ skippedLanguages: {},
2311
+ cfgSkipped: {},
2312
+ fileCount: 0,
2313
+ };
2314
+ let cumulativeProcessed = 0;
2315
+ // `mergeResult` (+ its `appendAll`) lives in ./result-merge.ts (extracted so it
2316
+ // can be unit-tested without importing this entry module).
2317
+ // Signal the pool that worker-side initialization (parser imports, language
2318
+ // grammars, type-env setup, all helper modules) is complete and the message
2319
+ // handler below is about to be attached. The pool's `waitForWorkerReady`
2320
+ // resolves on this handshake — without it, a worker that crashes during
2321
+ // top-of-script init slips past pool startup (Node's `online` event fires
2322
+ // before the script body runs) and the pool only notices via the first
2323
+ // dispatch's idle timeout (~30s). Emit once; the dispatch handler treats
2324
+ // any subsequent `ready` message as a benign no-op.
2325
+ //
2326
+ // Native postMessage carries the ready handshake — Node's structured
2327
+ // clone delivers `{type:'ready'}` to the pool's waitForWorkerReady
2328
+ // listener directly. The pool drops the slot if this isn't seen within
2329
+ // `WORKER_READY_TIMEOUT_MS` (5s), so emitting it AFTER all top-of-script
2330
+ // init (imports, native binding loads, type-env setup) completes is the
2331
+ // load-bearing signal that this worker is ready for dispatch.
2332
+ bootstrapLog('ready sent');
2333
+ node_worker_threads_1.parentPort.postMessage({ type: 'ready' });
2334
+ // Module-scope `TextDecoder` for sub-batch content. The pool sends each
2335
+ // file's content as a `Uint8Array` (zero-copy ArrayBuffer transfer); we
2336
+ // decode to string lazily here, once per file, before handing to
2337
+ // tree-sitter. Hoisted to module scope so we don't allocate a new
2338
+ // ICU-backed decoder per sub-batch — `TextDecoder.decode()` is
2339
+ // stateless across calls and safe to share.
2340
+ const sharedContentDecoder = new TextDecoder('utf-8');
2341
+ /**
2342
+ * Convert the pool's sub-batch `files` array (content as `Uint8Array`,
2343
+ * transferred zero-copy) into the `ParseWorkerInput[]` shape
2344
+ * `processBatch` expects (content as `string`). This is the one place
2345
+ * the UTF-8 decode happens — runs on the worker thread in parallel with
2346
+ * continued main-thread work.
2347
+ */
2348
+ function decodeSubBatchFiles(files) {
2349
+ return files.map((f) => ({
2350
+ path: f.path,
2351
+ // Test scaffolding (the writeReadyWorker preamble that wraps
2352
+ // parentPort.on) may already convert content to string before
2353
+ // calling here; tolerate both shapes so the same worker code
2354
+ // exercises real and synthetic dispatches.
2355
+ content: typeof f.content === 'string' ? f.content : sharedContentDecoder.decode(f.content),
2356
+ }));
2357
+ }
2358
+ let firstTaskLogged = false;
2359
+ node_worker_threads_1.parentPort.on('message', (msg) => {
2360
+ if (!firstTaskLogged) {
2361
+ firstTaskLogged = true;
2362
+ bootstrapLog('first task received');
2363
+ }
2364
+ try {
2365
+ // Sub-batch mode: { type: 'sub-batch', files: [...] }
2366
+ if (msg.type === 'sub-batch') {
2367
+ const files = decodeSubBatchFiles(msg.files);
2368
+ const result = processBatch(files, (filesProcessed) => {
2369
+ node_worker_threads_1.parentPort.postMessage({
2370
+ type: 'progress',
2371
+ filesProcessed: cumulativeProcessed + filesProcessed,
2372
+ });
2373
+ });
2374
+ cumulativeProcessed += result.fileCount;
2375
+ (0, result_merge_js_1.mergeResult)(accumulated, result);
2376
+ // Signal ready for next sub-batch
2377
+ node_worker_threads_1.parentPort.postMessage({ type: 'sub-batch-done' });
2378
+ return;
2379
+ }
2380
+ // Flush: send accumulated results
2381
+ if (msg.type === 'flush') {
2382
+ // #1983 parallel serialization: when a store path is configured, write
2383
+ // this job's ParsedFiles to our own disk shard HERE (at the flush
2384
+ // boundary, where `accumulated.parsedFiles` is complete) and drop them
2385
+ // from the result so the main thread never deserializes/re-serializes
2386
+ // them. Writing at flush — not per sub-batch — encodes the invariant
2387
+ // "a shard is written iff its result is delivered": a worker that dies
2388
+ // before flush wrote no shard, so the pool's job retry yields exactly
2389
+ // one. `undefined` store path keeps ParsedFiles in the result (no-store
2390
+ // fallback). The write is synchronous: blocking this dedicated worker
2391
+ // thread protects the main thread and avoids threading async through the
2392
+ // accumulate path; per-job write time is small vs the parse it follows.
2393
+ if ((PARSED_FILE_STORE_STORAGE_PATH || DURABLE_PARSED_FILE_STORAGE_PATH) &&
2394
+ accumulated.parsedFiles.length > 0) {
2395
+ const seq = shardSeq++;
2396
+ // #2038 warm-cache coverage: ALSO write a durable, content-addressed
2397
+ // shard keyed by chunk hash so a future warm parse-cache hit (no worker
2398
+ // runs) can restore these ParsedFiles without re-parsing. Same bytes,
2399
+ // same `seq`, so durable and run-scoped shards correlate. Only when the
2400
+ // flush carried a chunk hash (content-addressed dispatch).
2401
+ if (DURABLE_PARSED_FILE_STORAGE_PATH && typeof msg.chunkHash === 'string') {
2402
+ (0, parsedfile_store_js_1.persistDurableParsedFileShardSync)(DURABLE_PARSED_FILE_STORAGE_PATH, msg.chunkHash, node_worker_threads_1.threadId, seq, accumulated.parsedFiles);
2403
+ }
2404
+ if (PARSED_FILE_STORE_STORAGE_PATH) {
2405
+ (0, parsedfile_store_js_1.persistParsedFileShardSync)(PARSED_FILE_STORE_STORAGE_PATH, `w${node_worker_threads_1.threadId}-${seq}`, accumulated.parsedFiles);
2406
+ accumulated.parsedFiles = [];
2407
+ }
2408
+ }
2409
+ (0, post_result_js_1.postResultCloneSafe)(accumulated);
2410
+ // Reset for potential reuse
2411
+ accumulated = {
2412
+ nodes: [],
2413
+ relationships: [],
2414
+ symbols: [],
2415
+ calls: [],
2416
+ assignments: [],
2417
+ routes: [],
2418
+ fetchCalls: [],
2419
+ fetchWrapperDefs: [],
2420
+ decoratorRoutes: [],
2421
+ routerIncludes: [],
2422
+ routerImports: [],
2423
+ routerConstructorPrefixes: [],
2424
+ routerModuleAliases: [],
2425
+ toolDefs: [],
2426
+ ormQueries: [],
2427
+ constructorBindings: [],
2428
+ fileScopeBindings: [],
2429
+ parsedFiles: [],
2430
+ skippedLanguages: {},
2431
+ cfgSkipped: {},
2432
+ fileCount: 0,
2433
+ };
2434
+ cumulativeProcessed = 0;
2435
+ return;
2436
+ }
2437
+ }
2438
+ catch (err) {
2439
+ // Carry the worker-side stack across the MessageChannel, not just the
2440
+ // message. Without this, an unexpected worker throw (e.g. the minified
2441
+ // `this.#<x> is not a function` family) reaches the operator as a bare
2442
+ // one-liner with no file:line — exactly what made #2068 undebuggable. The
2443
+ // pool embeds `errorStack` into its death/circuit-breaker reason so the
2444
+ // surfaced "Phase 'parse' failed" message points at the real frame (the
2445
+ // stack's first line already carries the error's type + message). We send
2446
+ // primitive fields (not the raw Error) so a non-cloneable `cause` payload
2447
+ // can never turn the report itself into a `messageerror`. `errorStack` is
2448
+ // optional on the wire, so an older pool ignores it.
2449
+ const e = err instanceof Error ? err : new Error(String(err));
2450
+ node_worker_threads_1.parentPort.postMessage({
2451
+ type: 'error',
2452
+ error: e.message,
2453
+ errorStack: e.stack,
2454
+ });
2455
+ }
2456
+ });