@grafema/core 0.1.0-alpha.1

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 (402) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +76 -0
  3. package/dist/Orchestrator.d.ts +142 -0
  4. package/dist/Orchestrator.d.ts.map +1 -0
  5. package/dist/Orchestrator.js +481 -0
  6. package/dist/api/GraphAPI.d.ts +87 -0
  7. package/dist/api/GraphAPI.d.ts.map +1 -0
  8. package/dist/api/GraphAPI.js +210 -0
  9. package/dist/api/GuaranteeAPI.d.ts +147 -0
  10. package/dist/api/GuaranteeAPI.d.ts.map +1 -0
  11. package/dist/api/GuaranteeAPI.js +288 -0
  12. package/dist/core/ASTWorker.d.ts +133 -0
  13. package/dist/core/ASTWorker.d.ts.map +1 -0
  14. package/dist/core/ASTWorker.js +352 -0
  15. package/dist/core/ASTWorkerPool.d.ts +85 -0
  16. package/dist/core/ASTWorkerPool.d.ts.map +1 -0
  17. package/dist/core/ASTWorkerPool.js +207 -0
  18. package/dist/core/AnalysisQueue.d.ts +104 -0
  19. package/dist/core/AnalysisQueue.d.ts.map +1 -0
  20. package/dist/core/AnalysisQueue.js +299 -0
  21. package/dist/core/AnalysisWorker.d.ts +14 -0
  22. package/dist/core/AnalysisWorker.d.ts.map +1 -0
  23. package/dist/core/AnalysisWorker.js +307 -0
  24. package/dist/core/GraphBackend.d.ts +156 -0
  25. package/dist/core/GraphBackend.d.ts.map +1 -0
  26. package/dist/core/GraphBackend.js +85 -0
  27. package/dist/core/GuaranteeManager.d.ts +230 -0
  28. package/dist/core/GuaranteeManager.d.ts.map +1 -0
  29. package/dist/core/GuaranteeManager.js +352 -0
  30. package/dist/core/ManifestStore.d.ts +71 -0
  31. package/dist/core/ManifestStore.d.ts.map +1 -0
  32. package/dist/core/ManifestStore.js +146 -0
  33. package/dist/core/NodeFactory.d.ts +160 -0
  34. package/dist/core/NodeFactory.d.ts.map +1 -0
  35. package/dist/core/NodeFactory.js +137 -0
  36. package/dist/core/NodeId.d.ts +88 -0
  37. package/dist/core/NodeId.d.ts.map +1 -0
  38. package/dist/core/NodeId.js +170 -0
  39. package/dist/core/ParallelAnalyzer.d.ts +120 -0
  40. package/dist/core/ParallelAnalyzer.d.ts.map +1 -0
  41. package/dist/core/ParallelAnalyzer.js +331 -0
  42. package/dist/core/PriorityQueue.d.ts +106 -0
  43. package/dist/core/PriorityQueue.d.ts.map +1 -0
  44. package/dist/core/PriorityQueue.js +168 -0
  45. package/dist/core/Profiler.d.ts +75 -0
  46. package/dist/core/Profiler.d.ts.map +1 -0
  47. package/dist/core/Profiler.js +149 -0
  48. package/dist/core/QueueWorker.d.ts +12 -0
  49. package/dist/core/QueueWorker.d.ts.map +1 -0
  50. package/dist/core/QueueWorker.js +567 -0
  51. package/dist/core/RFDBClient.d.ts +179 -0
  52. package/dist/core/RFDBClient.d.ts.map +1 -0
  53. package/dist/core/RFDBClient.js +429 -0
  54. package/dist/core/Task.d.ts +56 -0
  55. package/dist/core/Task.d.ts.map +1 -0
  56. package/dist/core/Task.js +85 -0
  57. package/dist/core/TaskTypes.d.ts +20 -0
  58. package/dist/core/TaskTypes.d.ts.map +1 -0
  59. package/dist/core/TaskTypes.js +10 -0
  60. package/dist/core/VersionManager.d.ts +166 -0
  61. package/dist/core/VersionManager.d.ts.map +1 -0
  62. package/dist/core/VersionManager.js +237 -0
  63. package/dist/core/WorkerPool.d.ts +82 -0
  64. package/dist/core/WorkerPool.d.ts.map +1 -0
  65. package/dist/core/WorkerPool.js +109 -0
  66. package/dist/core/nodes/CallSiteNode.d.ts +26 -0
  67. package/dist/core/nodes/CallSiteNode.d.ts.map +1 -0
  68. package/dist/core/nodes/CallSiteNode.js +44 -0
  69. package/dist/core/nodes/ClassNode.d.ts +25 -0
  70. package/dist/core/nodes/ClassNode.d.ts.map +1 -0
  71. package/dist/core/nodes/ClassNode.js +40 -0
  72. package/dist/core/nodes/ConstantNode.d.ts +24 -0
  73. package/dist/core/nodes/ConstantNode.d.ts.map +1 -0
  74. package/dist/core/nodes/ConstantNode.js +39 -0
  75. package/dist/core/nodes/DatabaseQueryNode.d.ts +22 -0
  76. package/dist/core/nodes/DatabaseQueryNode.d.ts.map +1 -0
  77. package/dist/core/nodes/DatabaseQueryNode.js +37 -0
  78. package/dist/core/nodes/EntrypointNode.d.ts +102 -0
  79. package/dist/core/nodes/EntrypointNode.d.ts.map +1 -0
  80. package/dist/core/nodes/EntrypointNode.js +119 -0
  81. package/dist/core/nodes/EventListenerNode.d.ts +25 -0
  82. package/dist/core/nodes/EventListenerNode.d.ts.map +1 -0
  83. package/dist/core/nodes/EventListenerNode.js +39 -0
  84. package/dist/core/nodes/ExportNode.d.ts +26 -0
  85. package/dist/core/nodes/ExportNode.d.ts.map +1 -0
  86. package/dist/core/nodes/ExportNode.js +40 -0
  87. package/dist/core/nodes/ExternalStdioNode.d.ts +17 -0
  88. package/dist/core/nodes/ExternalStdioNode.d.ts.map +1 -0
  89. package/dist/core/nodes/ExternalStdioNode.js +26 -0
  90. package/dist/core/nodes/FunctionNode.d.ts +27 -0
  91. package/dist/core/nodes/FunctionNode.d.ts.map +1 -0
  92. package/dist/core/nodes/FunctionNode.js +53 -0
  93. package/dist/core/nodes/GuaranteeNode.d.ts +76 -0
  94. package/dist/core/nodes/GuaranteeNode.d.ts.map +1 -0
  95. package/dist/core/nodes/GuaranteeNode.js +117 -0
  96. package/dist/core/nodes/HttpRequestNode.d.ts +24 -0
  97. package/dist/core/nodes/HttpRequestNode.d.ts.map +1 -0
  98. package/dist/core/nodes/HttpRequestNode.js +38 -0
  99. package/dist/core/nodes/ImportNode.d.ts +27 -0
  100. package/dist/core/nodes/ImportNode.d.ts.map +1 -0
  101. package/dist/core/nodes/ImportNode.js +43 -0
  102. package/dist/core/nodes/LiteralNode.d.ts +26 -0
  103. package/dist/core/nodes/LiteralNode.d.ts.map +1 -0
  104. package/dist/core/nodes/LiteralNode.js +40 -0
  105. package/dist/core/nodes/MethodCallNode.d.ts +29 -0
  106. package/dist/core/nodes/MethodCallNode.d.ts.map +1 -0
  107. package/dist/core/nodes/MethodCallNode.js +47 -0
  108. package/dist/core/nodes/MethodNode.d.ts +29 -0
  109. package/dist/core/nodes/MethodNode.d.ts.map +1 -0
  110. package/dist/core/nodes/MethodNode.js +44 -0
  111. package/dist/core/nodes/ModuleNode.d.ts +29 -0
  112. package/dist/core/nodes/ModuleNode.d.ts.map +1 -0
  113. package/dist/core/nodes/ModuleNode.js +49 -0
  114. package/dist/core/nodes/NodeKind.d.ts +91 -0
  115. package/dist/core/nodes/NodeKind.d.ts.map +1 -0
  116. package/dist/core/nodes/NodeKind.js +146 -0
  117. package/dist/core/nodes/ParameterNode.d.ts +26 -0
  118. package/dist/core/nodes/ParameterNode.d.ts.map +1 -0
  119. package/dist/core/nodes/ParameterNode.js +43 -0
  120. package/dist/core/nodes/ScopeNode.d.ts +32 -0
  121. package/dist/core/nodes/ScopeNode.d.ts.map +1 -0
  122. package/dist/core/nodes/ScopeNode.js +47 -0
  123. package/dist/core/nodes/ServiceNode.d.ts +44 -0
  124. package/dist/core/nodes/ServiceNode.d.ts.map +1 -0
  125. package/dist/core/nodes/ServiceNode.js +49 -0
  126. package/dist/core/nodes/VariableDeclarationNode.d.ts +22 -0
  127. package/dist/core/nodes/VariableDeclarationNode.d.ts.map +1 -0
  128. package/dist/core/nodes/VariableDeclarationNode.js +38 -0
  129. package/dist/core/nodes/index.d.ts +25 -0
  130. package/dist/core/nodes/index.d.ts.map +1 -0
  131. package/dist/core/nodes/index.js +30 -0
  132. package/dist/index.d.ts +57 -0
  133. package/dist/index.d.ts.map +1 -0
  134. package/dist/index.js +63 -0
  135. package/dist/plugins/Plugin.d.ts +44 -0
  136. package/dist/plugins/Plugin.d.ts.map +1 -0
  137. package/dist/plugins/Plugin.js +46 -0
  138. package/dist/plugins/analysis/DatabaseAnalyzer.d.ts +23 -0
  139. package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -0
  140. package/dist/plugins/analysis/DatabaseAnalyzer.js +260 -0
  141. package/dist/plugins/analysis/ExpressAnalyzer.d.ts +19 -0
  142. package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -0
  143. package/dist/plugins/analysis/ExpressAnalyzer.js +306 -0
  144. package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts +17 -0
  145. package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -0
  146. package/dist/plugins/analysis/ExpressRouteAnalyzer.js +308 -0
  147. package/dist/plugins/analysis/FetchAnalyzer.d.ts +38 -0
  148. package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -0
  149. package/dist/plugins/analysis/FetchAnalyzer.js +344 -0
  150. package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts +65 -0
  151. package/dist/plugins/analysis/IncrementalAnalysisPlugin.d.ts.map +1 -0
  152. package/dist/plugins/analysis/IncrementalAnalysisPlugin.js +472 -0
  153. package/dist/plugins/analysis/JSASTAnalyzer.d.ts +84 -0
  154. package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -0
  155. package/dist/plugins/analysis/JSASTAnalyzer.js +1378 -0
  156. package/dist/plugins/analysis/ReactAnalyzer.d.ts +90 -0
  157. package/dist/plugins/analysis/ReactAnalyzer.d.ts.map +1 -0
  158. package/dist/plugins/analysis/ReactAnalyzer.js +1153 -0
  159. package/dist/plugins/analysis/RustAnalyzer.d.ts +13 -0
  160. package/dist/plugins/analysis/RustAnalyzer.d.ts.map +1 -0
  161. package/dist/plugins/analysis/RustAnalyzer.js +259 -0
  162. package/dist/plugins/analysis/SQLiteAnalyzer.d.ts +21 -0
  163. package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -0
  164. package/dist/plugins/analysis/SQLiteAnalyzer.js +317 -0
  165. package/dist/plugins/analysis/ServiceLayerAnalyzer.d.ts +35 -0
  166. package/dist/plugins/analysis/ServiceLayerAnalyzer.d.ts.map +1 -0
  167. package/dist/plugins/analysis/ServiceLayerAnalyzer.js +303 -0
  168. package/dist/plugins/analysis/SocketIOAnalyzer.d.ts +33 -0
  169. package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -0
  170. package/dist/plugins/analysis/SocketIOAnalyzer.js +283 -0
  171. package/dist/plugins/analysis/SystemDbAnalyzer.d.ts +27 -0
  172. package/dist/plugins/analysis/SystemDbAnalyzer.d.ts.map +1 -0
  173. package/dist/plugins/analysis/SystemDbAnalyzer.js +211 -0
  174. package/dist/plugins/analysis/ast/ConditionParser.d.ts +85 -0
  175. package/dist/plugins/analysis/ast/ConditionParser.d.ts.map +1 -0
  176. package/dist/plugins/analysis/ast/ConditionParser.js +277 -0
  177. package/dist/plugins/analysis/ast/ExpressionEvaluator.d.ts +15 -0
  178. package/dist/plugins/analysis/ast/ExpressionEvaluator.d.ts.map +1 -0
  179. package/dist/plugins/analysis/ast/ExpressionEvaluator.js +91 -0
  180. package/dist/plugins/analysis/ast/GraphBuilder.d.ts +77 -0
  181. package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -0
  182. package/dist/plugins/analysis/ast/GraphBuilder.js +1077 -0
  183. package/dist/plugins/analysis/ast/OxcAdapter.d.ts +41 -0
  184. package/dist/plugins/analysis/ast/OxcAdapter.d.ts.map +1 -0
  185. package/dist/plugins/analysis/ast/OxcAdapter.js +40 -0
  186. package/dist/plugins/analysis/ast/types.d.ts +346 -0
  187. package/dist/plugins/analysis/ast/types.d.ts.map +1 -0
  188. package/dist/plugins/analysis/ast/types.js +4 -0
  189. package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts +93 -0
  190. package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts.map +1 -0
  191. package/dist/plugins/analysis/ast/visitors/ASTVisitor.js +24 -0
  192. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +77 -0
  193. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -0
  194. package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +377 -0
  195. package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts +27 -0
  196. package/dist/plugins/analysis/ast/visitors/ClassVisitor.d.ts.map +1 -0
  197. package/dist/plugins/analysis/ast/visitors/ClassVisitor.js +232 -0
  198. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts +25 -0
  199. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -0
  200. package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +172 -0
  201. package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts +29 -0
  202. package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts.map +1 -0
  203. package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js +180 -0
  204. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts +14 -0
  205. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.d.ts.map +1 -0
  206. package/dist/plugins/analysis/ast/visitors/TypeScriptVisitor.js +200 -0
  207. package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts +45 -0
  208. package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -0
  209. package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +150 -0
  210. package/dist/plugins/analysis/ast/visitors/index.d.ts +17 -0
  211. package/dist/plugins/analysis/ast/visitors/index.d.ts.map +1 -0
  212. package/dist/plugins/analysis/ast/visitors/index.js +13 -0
  213. package/dist/plugins/discovery/DiscoveryPlugin.d.ts +34 -0
  214. package/dist/plugins/discovery/DiscoveryPlugin.d.ts.map +1 -0
  215. package/dist/plugins/discovery/DiscoveryPlugin.js +26 -0
  216. package/dist/plugins/discovery/MonorepoServiceDiscovery.d.ts +26 -0
  217. package/dist/plugins/discovery/MonorepoServiceDiscovery.d.ts.map +1 -0
  218. package/dist/plugins/discovery/MonorepoServiceDiscovery.js +79 -0
  219. package/dist/plugins/discovery/SimpleProjectDiscovery.d.ts +14 -0
  220. package/dist/plugins/discovery/SimpleProjectDiscovery.d.ts.map +1 -0
  221. package/dist/plugins/discovery/SimpleProjectDiscovery.js +65 -0
  222. package/dist/plugins/discovery/ZonServiceDiscovery.d.ts +19 -0
  223. package/dist/plugins/discovery/ZonServiceDiscovery.d.ts.map +1 -0
  224. package/dist/plugins/discovery/ZonServiceDiscovery.js +204 -0
  225. package/dist/plugins/enrichment/AliasTracker.d.ts +40 -0
  226. package/dist/plugins/enrichment/AliasTracker.d.ts.map +1 -0
  227. package/dist/plugins/enrichment/AliasTracker.js +290 -0
  228. package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts +30 -0
  229. package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -0
  230. package/dist/plugins/enrichment/HTTPConnectionEnricher.js +135 -0
  231. package/dist/plugins/enrichment/ImportExportLinker.d.ts +30 -0
  232. package/dist/plugins/enrichment/ImportExportLinker.d.ts.map +1 -0
  233. package/dist/plugins/enrichment/ImportExportLinker.js +176 -0
  234. package/dist/plugins/enrichment/InstanceOfResolver.d.ts +21 -0
  235. package/dist/plugins/enrichment/InstanceOfResolver.d.ts.map +1 -0
  236. package/dist/plugins/enrichment/InstanceOfResolver.js +117 -0
  237. package/dist/plugins/enrichment/MethodCallResolver.d.ts +41 -0
  238. package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -0
  239. package/dist/plugins/enrichment/MethodCallResolver.js +252 -0
  240. package/dist/plugins/enrichment/MountPointResolver.d.ts +26 -0
  241. package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -0
  242. package/dist/plugins/enrichment/MountPointResolver.js +189 -0
  243. package/dist/plugins/enrichment/PrefixEvaluator.d.ts +89 -0
  244. package/dist/plugins/enrichment/PrefixEvaluator.d.ts.map +1 -0
  245. package/dist/plugins/enrichment/PrefixEvaluator.js +415 -0
  246. package/dist/plugins/enrichment/RustFFIEnricher.d.ts +25 -0
  247. package/dist/plugins/enrichment/RustFFIEnricher.d.ts.map +1 -0
  248. package/dist/plugins/enrichment/RustFFIEnricher.js +170 -0
  249. package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts +114 -0
  250. package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -0
  251. package/dist/plugins/enrichment/ValueDomainAnalyzer.js +464 -0
  252. package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts +27 -0
  253. package/dist/plugins/indexing/IncrementalModuleIndexer.d.ts.map +1 -0
  254. package/dist/plugins/indexing/IncrementalModuleIndexer.js +238 -0
  255. package/dist/plugins/indexing/JSModuleIndexer.d.ts +33 -0
  256. package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -0
  257. package/dist/plugins/indexing/JSModuleIndexer.js +299 -0
  258. package/dist/plugins/indexing/RustModuleIndexer.d.ts +28 -0
  259. package/dist/plugins/indexing/RustModuleIndexer.d.ts.map +1 -0
  260. package/dist/plugins/indexing/RustModuleIndexer.js +140 -0
  261. package/dist/plugins/indexing/ServiceDetector.d.ts +46 -0
  262. package/dist/plugins/indexing/ServiceDetector.d.ts.map +1 -0
  263. package/dist/plugins/indexing/ServiceDetector.js +164 -0
  264. package/dist/plugins/validation/CallResolverValidator.d.ts +23 -0
  265. package/dist/plugins/validation/CallResolverValidator.d.ts.map +1 -0
  266. package/dist/plugins/validation/CallResolverValidator.js +108 -0
  267. package/dist/plugins/validation/DataFlowValidator.d.ts +24 -0
  268. package/dist/plugins/validation/DataFlowValidator.d.ts.map +1 -0
  269. package/dist/plugins/validation/DataFlowValidator.js +148 -0
  270. package/dist/plugins/validation/EvalBanValidator.d.ts +25 -0
  271. package/dist/plugins/validation/EvalBanValidator.d.ts.map +1 -0
  272. package/dist/plugins/validation/EvalBanValidator.js +123 -0
  273. package/dist/plugins/validation/GraphConnectivityValidator.d.ts +11 -0
  274. package/dist/plugins/validation/GraphConnectivityValidator.d.ts.map +1 -0
  275. package/dist/plugins/validation/GraphConnectivityValidator.js +135 -0
  276. package/dist/plugins/validation/SQLInjectionValidator.d.ts +43 -0
  277. package/dist/plugins/validation/SQLInjectionValidator.d.ts.map +1 -0
  278. package/dist/plugins/validation/SQLInjectionValidator.js +251 -0
  279. package/dist/plugins/validation/ShadowingDetector.d.ts +26 -0
  280. package/dist/plugins/validation/ShadowingDetector.d.ts.map +1 -0
  281. package/dist/plugins/validation/ShadowingDetector.js +119 -0
  282. package/dist/plugins/validation/TypeScriptDeadCodeValidator.d.ts +21 -0
  283. package/dist/plugins/validation/TypeScriptDeadCodeValidator.d.ts.map +1 -0
  284. package/dist/plugins/validation/TypeScriptDeadCodeValidator.js +151 -0
  285. package/dist/plugins/vcs/GitPlugin.d.ts +84 -0
  286. package/dist/plugins/vcs/GitPlugin.d.ts.map +1 -0
  287. package/dist/plugins/vcs/GitPlugin.js +295 -0
  288. package/dist/plugins/vcs/VCSPlugin.d.ts +133 -0
  289. package/dist/plugins/vcs/VCSPlugin.d.ts.map +1 -0
  290. package/dist/plugins/vcs/VCSPlugin.js +82 -0
  291. package/dist/plugins/vcs/index.d.ts +10 -0
  292. package/dist/plugins/vcs/index.d.ts.map +1 -0
  293. package/dist/plugins/vcs/index.js +18 -0
  294. package/dist/storage/backends/RFDBServerBackend.d.ts +258 -0
  295. package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -0
  296. package/dist/storage/backends/RFDBServerBackend.js +565 -0
  297. package/dist/storage/backends/typeValidation.d.ts +47 -0
  298. package/dist/storage/backends/typeValidation.d.ts.map +1 -0
  299. package/dist/storage/backends/typeValidation.js +137 -0
  300. package/dist/validation/PathValidator.d.ts +81 -0
  301. package/dist/validation/PathValidator.d.ts.map +1 -0
  302. package/dist/validation/PathValidator.js +251 -0
  303. package/package.json +57 -0
  304. package/src/.rfguard/current-session.txt +1 -0
  305. package/src/Orchestrator.ts +673 -0
  306. package/src/api/GraphAPI.ts +305 -0
  307. package/src/api/GuaranteeAPI.ts +401 -0
  308. package/src/core/ASTWorker.ts +567 -0
  309. package/src/core/ASTWorkerPool.ts +299 -0
  310. package/src/core/AnalysisQueue.ts +447 -0
  311. package/src/core/AnalysisWorker.ts +410 -0
  312. package/src/core/GraphBackend.ts +265 -0
  313. package/src/core/GuaranteeManager.ts +581 -0
  314. package/src/core/ManifestStore.ts +196 -0
  315. package/src/core/NodeFactory.ts +274 -0
  316. package/src/core/NodeId.ts +257 -0
  317. package/src/core/ParallelAnalyzer.ts +476 -0
  318. package/src/core/PriorityQueue.ts +227 -0
  319. package/src/core/Profiler.ts +188 -0
  320. package/src/core/QueueWorker.ts +780 -0
  321. package/src/core/Task.ts +107 -0
  322. package/src/core/TaskTypes.ts +40 -0
  323. package/src/core/VersionManager.ts +404 -0
  324. package/src/core/WorkerPool.ts +180 -0
  325. package/src/core/nodes/CallSiteNode.ts +72 -0
  326. package/src/core/nodes/ClassNode.ts +69 -0
  327. package/src/core/nodes/ConstantNode.ts +63 -0
  328. package/src/core/nodes/DatabaseQueryNode.ts +60 -0
  329. package/src/core/nodes/EntrypointNode.ts +164 -0
  330. package/src/core/nodes/EventListenerNode.ts +64 -0
  331. package/src/core/nodes/ExportNode.ts +71 -0
  332. package/src/core/nodes/ExternalStdioNode.ts +36 -0
  333. package/src/core/nodes/FunctionNode.ts +78 -0
  334. package/src/core/nodes/GuaranteeNode.ts +162 -0
  335. package/src/core/nodes/HttpRequestNode.ts +63 -0
  336. package/src/core/nodes/ImportNode.ts +75 -0
  337. package/src/core/nodes/LiteralNode.ts +67 -0
  338. package/src/core/nodes/MethodCallNode.ts +79 -0
  339. package/src/core/nodes/MethodNode.ts +78 -0
  340. package/src/core/nodes/ModuleNode.ts +74 -0
  341. package/src/core/nodes/NodeKind.ts +171 -0
  342. package/src/core/nodes/ParameterNode.ts +73 -0
  343. package/src/core/nodes/ScopeNode.ts +80 -0
  344. package/src/core/nodes/ServiceNode.ts +86 -0
  345. package/src/core/nodes/VariableDeclarationNode.ts +60 -0
  346. package/src/core/nodes/index.ts +49 -0
  347. package/src/index.ts +93 -0
  348. package/src/plugins/Plugin.ts +74 -0
  349. package/src/plugins/analysis/DatabaseAnalyzer.ts +322 -0
  350. package/src/plugins/analysis/ExpressAnalyzer.ts +401 -0
  351. package/src/plugins/analysis/ExpressRouteAnalyzer.ts +414 -0
  352. package/src/plugins/analysis/FetchAnalyzer.ts +441 -0
  353. package/src/plugins/analysis/IncrementalAnalysisPlugin.ts +686 -0
  354. package/src/plugins/analysis/JSASTAnalyzer.ts +1680 -0
  355. package/src/plugins/analysis/ReactAnalyzer.ts +1368 -0
  356. package/src/plugins/analysis/RustAnalyzer.ts +438 -0
  357. package/src/plugins/analysis/SQLiteAnalyzer.ts +388 -0
  358. package/src/plugins/analysis/ServiceLayerAnalyzer.ts +429 -0
  359. package/src/plugins/analysis/SocketIOAnalyzer.ts +395 -0
  360. package/src/plugins/analysis/SystemDbAnalyzer.ts +284 -0
  361. package/src/plugins/analysis/ast/ConditionParser.ts +333 -0
  362. package/src/plugins/analysis/ast/ExpressionEvaluator.ts +117 -0
  363. package/src/plugins/analysis/ast/GraphBuilder.ts +1371 -0
  364. package/src/plugins/analysis/ast/OxcAdapter.ts +63 -0
  365. package/src/plugins/analysis/ast/types.ts +400 -0
  366. package/src/plugins/analysis/ast/visitors/ASTVisitor.ts +137 -0
  367. package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +528 -0
  368. package/src/plugins/analysis/ast/visitors/ClassVisitor.ts +339 -0
  369. package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +273 -0
  370. package/src/plugins/analysis/ast/visitors/ImportExportVisitor.ts +259 -0
  371. package/src/plugins/analysis/ast/visitors/TypeScriptVisitor.ts +235 -0
  372. package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +268 -0
  373. package/src/plugins/analysis/ast/visitors/index.ts +36 -0
  374. package/src/plugins/discovery/DiscoveryPlugin.ts +50 -0
  375. package/src/plugins/discovery/MonorepoServiceDiscovery.ts +117 -0
  376. package/src/plugins/discovery/SimpleProjectDiscovery.ts +102 -0
  377. package/src/plugins/enrichment/AliasTracker.ts +399 -0
  378. package/src/plugins/enrichment/HTTPConnectionEnricher.ts +192 -0
  379. package/src/plugins/enrichment/ImportExportLinker.ts +221 -0
  380. package/src/plugins/enrichment/InstanceOfResolver.ts +165 -0
  381. package/src/plugins/enrichment/MethodCallResolver.ts +333 -0
  382. package/src/plugins/enrichment/MountPointResolver.ts +264 -0
  383. package/src/plugins/enrichment/PrefixEvaluator.ts +527 -0
  384. package/src/plugins/enrichment/RustFFIEnricher.ts +218 -0
  385. package/src/plugins/enrichment/ValueDomainAnalyzer.ts +682 -0
  386. package/src/plugins/indexing/IncrementalModuleIndexer.ts +287 -0
  387. package/src/plugins/indexing/JSModuleIndexer.ts +374 -0
  388. package/src/plugins/indexing/RustModuleIndexer.ts +160 -0
  389. package/src/plugins/indexing/ServiceDetector.ts +230 -0
  390. package/src/plugins/validation/CallResolverValidator.ts +170 -0
  391. package/src/plugins/validation/DataFlowValidator.ts +233 -0
  392. package/src/plugins/validation/EvalBanValidator.ts +175 -0
  393. package/src/plugins/validation/GraphConnectivityValidator.ts +201 -0
  394. package/src/plugins/validation/SQLInjectionValidator.ts +363 -0
  395. package/src/plugins/validation/ShadowingDetector.ts +173 -0
  396. package/src/plugins/validation/TypeScriptDeadCodeValidator.ts +203 -0
  397. package/src/plugins/vcs/GitPlugin.ts +344 -0
  398. package/src/plugins/vcs/VCSPlugin.ts +190 -0
  399. package/src/plugins/vcs/index.ts +32 -0
  400. package/src/storage/backends/RFDBServerBackend.ts +687 -0
  401. package/src/storage/backends/typeValidation.ts +151 -0
  402. package/src/validation/PathValidator.ts +342 -0
@@ -0,0 +1,1371 @@
1
+ /**
2
+ * GraphBuilder - создание узлов и рёбер графа из собранных AST данных
3
+ * OPTIMIZED: Uses batched writes to reduce FFI overhead
4
+ */
5
+
6
+ import { dirname, resolve } from 'path';
7
+ import type { GraphBackend } from '@grafema/types';
8
+ import type {
9
+ ModuleNode,
10
+ FunctionInfo,
11
+ ParameterInfo,
12
+ ScopeInfo,
13
+ VariableDeclarationInfo,
14
+ CallSiteInfo,
15
+ MethodCallInfo,
16
+ EventListenerInfo,
17
+ ClassInstantiationInfo,
18
+ ClassDeclarationInfo,
19
+ MethodCallbackInfo,
20
+ CallArgumentInfo,
21
+ ImportInfo,
22
+ ExportInfo,
23
+ HttpRequestInfo,
24
+ LiteralInfo,
25
+ VariableAssignmentInfo,
26
+ InterfaceDeclarationInfo,
27
+ TypeAliasInfo,
28
+ EnumDeclarationInfo,
29
+ DecoratorInfo,
30
+ ASTCollections,
31
+ GraphNode,
32
+ GraphEdge,
33
+ BuildResult,
34
+ } from './types.js';
35
+
36
+ export class GraphBuilder {
37
+ // Track singleton nodes to avoid duplicates (net:stdio, net:request, etc.)
38
+ private _createdSingletons: Set<string> = new Set();
39
+
40
+ // Batching buffers for optimized writes
41
+ private _nodeBuffer: GraphNode[] = [];
42
+ private _edgeBuffer: GraphEdge[] = [];
43
+
44
+ /**
45
+ * Buffer a node for batched writing
46
+ */
47
+ private _bufferNode(node: GraphNode): void {
48
+ this._nodeBuffer.push(node);
49
+ }
50
+
51
+ /**
52
+ * Buffer an edge for batched writing
53
+ */
54
+ private _bufferEdge(edge: GraphEdge): void {
55
+ this._edgeBuffer.push(edge);
56
+ }
57
+
58
+ /**
59
+ * Flush all buffered nodes to the graph
60
+ */
61
+ private async _flushNodes(graph: GraphBackend): Promise<number> {
62
+ if (this._nodeBuffer.length > 0) {
63
+ // Cast to unknown first since GraphNode is more permissive than NodeRecord
64
+ await graph.addNodes(this._nodeBuffer as unknown as import('@grafema/types').NodeRecord[]);
65
+ const count = this._nodeBuffer.length;
66
+ this._nodeBuffer = [];
67
+ return count;
68
+ }
69
+ return 0;
70
+ }
71
+
72
+ /**
73
+ * Flush all buffered edges to the graph
74
+ * Note: skip_validation=true because nodes were just flushed
75
+ */
76
+ private async _flushEdges(graph: GraphBackend): Promise<number> {
77
+ if (this._edgeBuffer.length > 0) {
78
+ await (graph as GraphBackend & { addEdges(e: GraphEdge[], skip?: boolean): Promise<void> }).addEdges(this._edgeBuffer, true /* skip_validation */);
79
+ const count = this._edgeBuffer.length;
80
+ this._edgeBuffer = [];
81
+ return count;
82
+ }
83
+ return 0;
84
+ }
85
+
86
+ /**
87
+ * Создаёт ноды и рёбра в графе (BATCHED VERSION)
88
+ */
89
+ async build(module: ModuleNode, graph: GraphBackend, projectPath: string, data: ASTCollections): Promise<BuildResult> {
90
+ const {
91
+ functions,
92
+ parameters = [],
93
+ scopes,
94
+ variableDeclarations,
95
+ callSites,
96
+ methodCalls = [],
97
+ eventListeners = [],
98
+ classInstantiations = [],
99
+ classDeclarations = [],
100
+ methodCallbacks = [],
101
+ callArguments = [],
102
+ imports = [],
103
+ exports = [],
104
+ httpRequests = [],
105
+ literals = [],
106
+ variableAssignments = [],
107
+ // TypeScript-specific collections
108
+ interfaces = [],
109
+ typeAliases = [],
110
+ enums = [],
111
+ decorators = []
112
+ } = data;
113
+
114
+ // Reset buffers for this build
115
+ this._nodeBuffer = [];
116
+ this._edgeBuffer = [];
117
+
118
+ // 1. Buffer all functions (without edges)
119
+ for (const func of functions) {
120
+ const { parentScopeId, ...funcData } = func;
121
+ this._bufferNode(funcData as GraphNode);
122
+ }
123
+
124
+ // 2. Buffer all SCOPE (without edges)
125
+ for (const scope of scopes) {
126
+ const { parentFunctionId, parentScopeId, capturesFrom, modifies, ...scopeData } = scope;
127
+ this._bufferNode(scopeData as GraphNode);
128
+ }
129
+
130
+ // 3. Buffer variables
131
+ for (const varDecl of variableDeclarations) {
132
+ const { parentScopeId, ...varData } = varDecl;
133
+ this._bufferNode(varData as GraphNode);
134
+ }
135
+
136
+ // 3.5. Buffer PARAMETER nodes and HAS_PARAMETER edges
137
+ for (const param of parameters) {
138
+ const { functionId, ...paramData } = param;
139
+ // Keep parentFunctionId on the node for queries
140
+ this._bufferNode(paramData as GraphNode);
141
+
142
+ if (param.parentFunctionId) {
143
+ this._bufferEdge({
144
+ type: 'HAS_PARAMETER',
145
+ src: param.parentFunctionId,
146
+ dst: param.id,
147
+ index: param.index
148
+ });
149
+ }
150
+ }
151
+
152
+ // 4. Buffer CALL_SITE
153
+ for (const callSite of callSites) {
154
+ const { parentScopeId, targetFunctionName, ...callData } = callSite;
155
+ this._bufferNode(callData as GraphNode);
156
+ }
157
+
158
+ // 5. Buffer edges for functions
159
+ this.bufferFunctionEdges(module, functions);
160
+
161
+ // 6. Buffer edges for SCOPE
162
+ this.bufferScopeEdges(scopes, variableDeclarations);
163
+
164
+ // 7. Buffer edges for variables
165
+ this.bufferVariableEdges(variableDeclarations);
166
+
167
+ // 8. Buffer edges for CALL_SITE
168
+ this.bufferCallSiteEdges(callSites, functions);
169
+
170
+ // 9. Buffer METHOD_CALL nodes and CONTAINS edges
171
+ this.bufferMethodCalls(methodCalls);
172
+
173
+ // 10. Buffer net:stdio and WRITES_TO edges for console.log/error
174
+ this.bufferStdioNodes(methodCalls);
175
+
176
+ // 11. Buffer CLASS nodes for class declarations and CONTAINS edges
177
+ this.bufferClassDeclarationNodes(classDeclarations);
178
+
179
+ // 12. Buffer CLASS nodes and INSTANCE_OF edges for NewExpression
180
+ this.bufferClassNodes(module, classInstantiations, classDeclarations);
181
+
182
+ // 13. Buffer PASSES_ARGUMENT edges (METHOD_CALL -> FUNCTION)
183
+ this.bufferCallbackEdges(methodCallbacks, functions);
184
+
185
+ // 14. Buffer IMPORT nodes
186
+ this.bufferImportNodes(module, imports);
187
+
188
+ // 15. Buffer EXPORT nodes
189
+ this.bufferExportNodes(module, exports);
190
+
191
+ // 16. Buffer EVENT_LISTENER nodes and HANDLED_BY edges
192
+ this.bufferEventListeners(eventListeners, functions);
193
+
194
+ // 17. Buffer HTTP requests
195
+ this.bufferHttpRequests(httpRequests, functions);
196
+
197
+ // 18. Buffer LITERAL nodes
198
+ this.bufferLiterals(literals);
199
+
200
+ // 19. Buffer ASSIGNED_FROM edges for data flow (some need to create EXPRESSION nodes)
201
+ this.bufferAssignmentEdges(variableAssignments, variableDeclarations, callSites, methodCalls, functions, classInstantiations, parameters);
202
+
203
+ // 20. Buffer PASSES_ARGUMENT edges (CALL -> argument)
204
+ this.bufferArgumentEdges(callArguments, variableDeclarations, functions, callSites, methodCalls);
205
+
206
+ // 21. Buffer INTERFACE nodes and EXTENDS edges
207
+ this.bufferInterfaceNodes(module, interfaces);
208
+
209
+ // 22. Buffer TYPE nodes
210
+ this.bufferTypeAliasNodes(module, typeAliases);
211
+
212
+ // 23. Buffer ENUM nodes
213
+ this.bufferEnumNodes(module, enums);
214
+
215
+ // 24. Buffer DECORATOR nodes and DECORATED_BY edges
216
+ this.bufferDecoratorNodes(decorators);
217
+
218
+ // 25. Buffer IMPLEMENTS edges (CLASS -> INTERFACE)
219
+ this.bufferImplementsEdges(classDeclarations, interfaces);
220
+
221
+ // FLUSH: Write all nodes first, then edges in single batch calls
222
+ const nodesCreated = await this._flushNodes(graph);
223
+ const edgesCreated = await this._flushEdges(graph);
224
+
225
+ // Handle async operations that need graph queries (IMPORTS_FROM edges)
226
+ const importExportEdges = await this.createImportExportEdges(module, imports, exports, graph, projectPath);
227
+
228
+ // Handle async operations for ASSIGNED_FROM with CLASS lookups
229
+ const classAssignmentEdges = await this.createClassAssignmentEdges(variableAssignments, graph);
230
+
231
+ return { nodes: nodesCreated, edges: edgesCreated + importExportEdges + classAssignmentEdges };
232
+ }
233
+
234
+ // ============= BUFFERED METHODS (synchronous, no awaits) =============
235
+
236
+ private bufferFunctionEdges(module: ModuleNode, functions: FunctionInfo[]): void {
237
+ for (const func of functions) {
238
+ const { parentScopeId, ...funcData } = func;
239
+
240
+ // MODULE -> CONTAINS -> FUNCTION (для функций верхнего уровня)
241
+ // или SCOPE -> CONTAINS -> FUNCTION (для вложенных функций)
242
+ if (parentScopeId) {
243
+ this._bufferEdge({
244
+ type: 'CONTAINS',
245
+ src: parentScopeId,
246
+ dst: funcData.id
247
+ });
248
+ } else {
249
+ this._bufferEdge({
250
+ type: 'CONTAINS',
251
+ src: module.id,
252
+ dst: funcData.id
253
+ });
254
+ }
255
+ }
256
+ }
257
+
258
+ private bufferScopeEdges(scopes: ScopeInfo[], variableDeclarations: VariableDeclarationInfo[]): void {
259
+ for (const scope of scopes) {
260
+ const { parentFunctionId, parentScopeId, capturesFrom, modifies, ...scopeData } = scope;
261
+
262
+ // FUNCTION -> HAS_SCOPE -> SCOPE (для function_body)
263
+ if (parentFunctionId) {
264
+ this._bufferEdge({
265
+ type: 'HAS_SCOPE',
266
+ src: parentFunctionId,
267
+ dst: scopeData.id
268
+ });
269
+ }
270
+
271
+ // SCOPE -> CONTAINS -> SCOPE (для вложенных scope, типа if внутри function)
272
+ if (parentScopeId) {
273
+ this._bufferEdge({
274
+ type: 'CONTAINS',
275
+ src: parentScopeId,
276
+ dst: scopeData.id
277
+ });
278
+ }
279
+
280
+ // CAPTURES - замыкания захватывают переменные из родительского scope
281
+ if (capturesFrom && scopeData.scopeType === 'closure') {
282
+ const parentVars = variableDeclarations.filter(v => v.parentScopeId === capturesFrom);
283
+ for (const parentVar of parentVars) {
284
+ this._bufferEdge({
285
+ type: 'CAPTURES',
286
+ src: scopeData.id,
287
+ dst: parentVar.id
288
+ });
289
+ }
290
+ }
291
+
292
+ // MODIFIES - scope модифицирует переменные (count++)
293
+ if (modifies && modifies.length > 0) {
294
+ for (const mod of modifies) {
295
+ this._bufferEdge({
296
+ type: 'MODIFIES',
297
+ src: scopeData.id,
298
+ dst: mod.variableId
299
+ });
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ private bufferVariableEdges(variableDeclarations: VariableDeclarationInfo[]): void {
306
+ for (const varDecl of variableDeclarations) {
307
+ const { parentScopeId, ...varData } = varDecl;
308
+
309
+ // SCOPE -> DECLARES -> VARIABLE
310
+ this._bufferEdge({
311
+ type: 'DECLARES',
312
+ src: parentScopeId as string,
313
+ dst: varData.id
314
+ });
315
+ }
316
+ }
317
+
318
+ private bufferCallSiteEdges(callSites: CallSiteInfo[], functions: FunctionInfo[]): void {
319
+ for (const callSite of callSites) {
320
+ const { parentScopeId, targetFunctionName, ...callData } = callSite;
321
+
322
+ // SCOPE -> CONTAINS -> CALL_SITE
323
+ this._bufferEdge({
324
+ type: 'CONTAINS',
325
+ src: parentScopeId as string,
326
+ dst: callData.id
327
+ });
328
+
329
+ // CALL_SITE -> CALLS -> FUNCTION
330
+ const targetFunction = functions.find(f => f.name === targetFunctionName);
331
+ if (targetFunction) {
332
+ this._bufferEdge({
333
+ type: 'CALLS',
334
+ src: callData.id,
335
+ dst: targetFunction.id
336
+ });
337
+ }
338
+ }
339
+ }
340
+
341
+ private bufferMethodCalls(methodCalls: MethodCallInfo[]): void {
342
+ for (const methodCall of methodCalls) {
343
+ const { parentScopeId, ...methodData } = methodCall;
344
+
345
+ // Buffer METHOD_CALL node
346
+ this._bufferNode(methodData as GraphNode);
347
+
348
+ // SCOPE -> CONTAINS -> METHOD_CALL
349
+ this._bufferEdge({
350
+ type: 'CONTAINS',
351
+ src: parentScopeId as string,
352
+ dst: methodData.id
353
+ });
354
+ }
355
+ }
356
+
357
+ private bufferStdioNodes(methodCalls: MethodCallInfo[]): void {
358
+ const consoleIOMethods = methodCalls.filter(mc =>
359
+ (mc.object === 'console' && (mc.method === 'log' || mc.method === 'error'))
360
+ );
361
+
362
+ if (consoleIOMethods.length > 0) {
363
+ const stdioId = 'net:stdio#__stdio__';
364
+ // Buffer net:stdio node only once (singleton)
365
+ if (!this._createdSingletons.has(stdioId)) {
366
+ this._bufferNode({
367
+ id: stdioId,
368
+ type: 'net:stdio',
369
+ name: '__stdio__',
370
+ description: 'Standard input/output stream'
371
+ });
372
+ this._createdSingletons.add(stdioId);
373
+ }
374
+
375
+ // Buffer WRITES_TO edges for console.log/error
376
+ for (const methodCall of consoleIOMethods) {
377
+ this._bufferEdge({
378
+ type: 'WRITES_TO',
379
+ src: methodCall.id,
380
+ dst: stdioId
381
+ });
382
+ }
383
+ }
384
+ }
385
+
386
+ private bufferClassDeclarationNodes(classDeclarations: ClassDeclarationInfo[]): void {
387
+ for (const classDecl of classDeclarations) {
388
+ const { id, type, name, file, line, column, superClass, methods } = classDecl;
389
+
390
+ // Buffer CLASS node
391
+ this._bufferNode({
392
+ id,
393
+ type,
394
+ name,
395
+ file,
396
+ line,
397
+ column,
398
+ superClass
399
+ });
400
+
401
+ // Buffer CONTAINS edges: CLASS -> METHOD
402
+ for (const methodId of methods) {
403
+ this._bufferEdge({
404
+ type: 'CONTAINS',
405
+ src: id,
406
+ dst: methodId
407
+ });
408
+ }
409
+
410
+ // If superClass, buffer DERIVES_FROM edge
411
+ if (superClass) {
412
+ const superClassId = `CLASS#${superClass}#${file}`;
413
+ this._bufferEdge({
414
+ type: 'DERIVES_FROM',
415
+ src: id,
416
+ dst: superClassId
417
+ });
418
+ }
419
+ }
420
+ }
421
+
422
+ private bufferClassNodes(module: ModuleNode, classInstantiations: ClassInstantiationInfo[], classDeclarations: ClassDeclarationInfo[]): void {
423
+ // Create lookup map: className → declaration ID
424
+ const declarationMap = new Map<string, string>();
425
+ for (const decl of classDeclarations) {
426
+ if (decl.file === module.file) {
427
+ declarationMap.set(decl.name, decl.id);
428
+ }
429
+ }
430
+
431
+ for (const instantiation of classInstantiations) {
432
+ const { variableId, className, line } = instantiation;
433
+
434
+ let classId = declarationMap.get(className);
435
+
436
+ if (!classId) {
437
+ // External class - buffer CLASS node
438
+ classId = `${module.file}:CLASS:${className}:${line}`;
439
+ this._bufferNode({
440
+ id: classId,
441
+ type: 'CLASS',
442
+ name: className,
443
+ file: module.file,
444
+ line,
445
+ isInstantiationRef: true
446
+ });
447
+ }
448
+
449
+ // Buffer INSTANCE_OF edge
450
+ this._bufferEdge({
451
+ type: 'INSTANCE_OF',
452
+ src: variableId,
453
+ dst: classId
454
+ });
455
+ }
456
+ }
457
+
458
+ private bufferCallbackEdges(methodCallbacks: MethodCallbackInfo[], functions: FunctionInfo[]): void {
459
+ for (const callback of methodCallbacks) {
460
+ const { methodCallId, callbackLine, callbackColumn } = callback;
461
+
462
+ const callbackFunction = functions.find(f =>
463
+ f.line === callbackLine && f.column === callbackColumn
464
+ );
465
+
466
+ if (callbackFunction) {
467
+ this._bufferEdge({
468
+ type: 'HAS_CALLBACK',
469
+ src: methodCallId,
470
+ dst: callbackFunction.id
471
+ });
472
+ }
473
+ }
474
+ }
475
+
476
+ private bufferImportNodes(module: ModuleNode, imports: ImportInfo[]): void {
477
+ for (const imp of imports) {
478
+ const { source, specifiers, line } = imp;
479
+
480
+ for (const spec of specifiers) {
481
+ const importType = spec.imported === 'default' ? 'default' :
482
+ spec.imported === '*' ? 'namespace' : 'named';
483
+
484
+ const importId = `${module.file}:IMPORT:${source}:${spec.local}:${line}`;
485
+
486
+ this._bufferNode({
487
+ id: importId,
488
+ type: 'IMPORT',
489
+ source: source,
490
+ importType: importType,
491
+ imported: spec.imported,
492
+ local: spec.local,
493
+ file: module.file,
494
+ line: line
495
+ });
496
+
497
+ // MODULE -> CONTAINS -> IMPORT
498
+ this._bufferEdge({
499
+ type: 'CONTAINS',
500
+ src: module.id,
501
+ dst: importId
502
+ });
503
+
504
+ // Create EXTERNAL_MODULE node for external modules
505
+ const isRelative = source.startsWith('./') || source.startsWith('../');
506
+ if (!isRelative) {
507
+ const externalModuleId = `EXTERNAL_MODULE:${source}`;
508
+
509
+ this._bufferNode({
510
+ id: externalModuleId,
511
+ type: 'EXTERNAL_MODULE',
512
+ name: source,
513
+ file: module.file,
514
+ line: line
515
+ });
516
+
517
+ this._bufferEdge({
518
+ type: 'IMPORTS',
519
+ src: module.id,
520
+ dst: externalModuleId
521
+ });
522
+ }
523
+ }
524
+ }
525
+ }
526
+
527
+ private bufferExportNodes(module: ModuleNode, exports: ExportInfo[]): void {
528
+ for (const exp of exports) {
529
+ const { type, line, name, specifiers, source } = exp;
530
+
531
+ if (type === 'default') {
532
+ const exportId = `${module.file}:EXPORT:default:${line}`;
533
+
534
+ this._bufferNode({
535
+ id: exportId,
536
+ type: 'EXPORT',
537
+ exportType: 'default',
538
+ name: 'default',
539
+ file: module.file,
540
+ line: line
541
+ });
542
+
543
+ this._bufferEdge({
544
+ type: 'CONTAINS',
545
+ src: module.id,
546
+ dst: exportId
547
+ });
548
+ } else if (type === 'named') {
549
+ if (specifiers) {
550
+ for (const spec of specifiers) {
551
+ const exportId = `${module.file}:EXPORT:${spec.exported}:${line}`;
552
+
553
+ this._bufferNode({
554
+ id: exportId,
555
+ type: 'EXPORT',
556
+ exportType: 'named',
557
+ name: spec.exported,
558
+ local: spec.local,
559
+ file: module.file,
560
+ line: line,
561
+ source: source
562
+ });
563
+
564
+ this._bufferEdge({
565
+ type: 'CONTAINS',
566
+ src: module.id,
567
+ dst: exportId
568
+ });
569
+ }
570
+ } else if (name) {
571
+ const exportId = `${module.file}:EXPORT:${name}:${line}`;
572
+
573
+ this._bufferNode({
574
+ id: exportId,
575
+ type: 'EXPORT',
576
+ exportType: 'named',
577
+ name: name,
578
+ file: module.file,
579
+ line: line
580
+ });
581
+
582
+ this._bufferEdge({
583
+ type: 'CONTAINS',
584
+ src: module.id,
585
+ dst: exportId
586
+ });
587
+ }
588
+ } else if (type === 'all') {
589
+ const exportId = `${module.file}:EXPORT:*:${line}`;
590
+
591
+ this._bufferNode({
592
+ id: exportId,
593
+ type: 'EXPORT',
594
+ exportType: 'all',
595
+ name: '*',
596
+ file: module.file,
597
+ line: line,
598
+ source: source
599
+ });
600
+
601
+ this._bufferEdge({
602
+ type: 'CONTAINS',
603
+ src: module.id,
604
+ dst: exportId
605
+ });
606
+ }
607
+ }
608
+ }
609
+
610
+ private bufferEventListeners(eventListeners: EventListenerInfo[], functions: FunctionInfo[]): void {
611
+ for (const eventListener of eventListeners) {
612
+ const { parentScopeId, callbackArg, ...listenerData } = eventListener;
613
+
614
+ this._bufferNode(listenerData as GraphNode);
615
+
616
+ this._bufferEdge({
617
+ type: 'CONTAINS',
618
+ src: parentScopeId as string,
619
+ dst: listenerData.id
620
+ });
621
+
622
+ if (callbackArg && callbackArg.type === 'ArrowFunctionExpression') {
623
+ const callbackLine = (callbackArg.loc as { start: { line: number } }).start.line;
624
+ const callbackFunction = functions.find(f =>
625
+ f.line === callbackLine && f.arrowFunction
626
+ );
627
+
628
+ if (callbackFunction) {
629
+ this._bufferEdge({
630
+ type: 'HANDLED_BY',
631
+ src: listenerData.id,
632
+ dst: callbackFunction.id
633
+ });
634
+ }
635
+ }
636
+ }
637
+ }
638
+
639
+ private bufferHttpRequests(httpRequests: HttpRequestInfo[], functions: FunctionInfo[]): void {
640
+ if (httpRequests.length > 0) {
641
+ const networkId = 'net:request#__network__';
642
+
643
+ if (!this._createdSingletons.has(networkId)) {
644
+ this._bufferNode({
645
+ id: networkId,
646
+ type: 'net:request',
647
+ name: '__network__'
648
+ });
649
+ this._createdSingletons.add(networkId);
650
+ }
651
+
652
+ for (const request of httpRequests) {
653
+ const { parentScopeId, ...requestData } = request;
654
+
655
+ this._bufferNode(requestData as GraphNode);
656
+
657
+ this._bufferEdge({
658
+ type: 'CALLS',
659
+ src: request.id,
660
+ dst: networkId
661
+ });
662
+
663
+ if (parentScopeId) {
664
+ const scopeParts = parentScopeId.split(':');
665
+ if (scopeParts.length >= 3 && scopeParts[1] === 'SCOPE') {
666
+ const functionName = scopeParts[2];
667
+ const file = scopeParts[0];
668
+
669
+ const parentFunction = functions.find(f =>
670
+ f.file === file && f.name === functionName
671
+ );
672
+
673
+ if (parentFunction) {
674
+ this._bufferEdge({
675
+ type: 'MAKES_REQUEST',
676
+ src: parentFunction.id,
677
+ dst: request.id
678
+ });
679
+ }
680
+ }
681
+ }
682
+ }
683
+ }
684
+ }
685
+
686
+ private bufferLiterals(literals: LiteralInfo[]): void {
687
+ for (const literal of literals) {
688
+ const { parentCallId, argIndex, ...literalData } = literal;
689
+ this._bufferNode(literalData as GraphNode);
690
+ }
691
+ }
692
+
693
+ private bufferAssignmentEdges(
694
+ variableAssignments: VariableAssignmentInfo[],
695
+ variableDeclarations: VariableDeclarationInfo[],
696
+ callSites: CallSiteInfo[],
697
+ methodCalls: MethodCallInfo[],
698
+ functions: FunctionInfo[],
699
+ classInstantiations: ClassInstantiationInfo[],
700
+ parameters: ParameterInfo[]
701
+ ): void {
702
+ for (const assignment of variableAssignments) {
703
+ const {
704
+ variableId,
705
+ sourceId,
706
+ sourceType,
707
+ sourceName,
708
+ sourceLine,
709
+ sourceColumn,
710
+ sourceFile,
711
+ functionName,
712
+ line,
713
+ className
714
+ } = assignment;
715
+
716
+ // Skip CLASS sourceType - handled async in createClassAssignmentEdges
717
+ if (sourceType === 'CLASS') {
718
+ continue;
719
+ }
720
+
721
+ // Direct LITERAL assignment
722
+ if (sourceId && sourceType !== 'EXPRESSION') {
723
+ this._bufferEdge({
724
+ type: 'ASSIGNED_FROM',
725
+ src: variableId,
726
+ dst: sourceId
727
+ });
728
+ }
729
+ // METHOD_CALL by coordinates
730
+ else if (sourceType === 'METHOD_CALL' && sourceLine && sourceColumn) {
731
+ const methodCall = methodCalls.find(mc =>
732
+ mc.line === sourceLine &&
733
+ mc.column === sourceColumn &&
734
+ mc.file === sourceFile
735
+ );
736
+
737
+ if (methodCall) {
738
+ this._bufferEdge({
739
+ type: 'ASSIGNED_FROM',
740
+ src: variableId,
741
+ dst: methodCall.id
742
+ });
743
+ }
744
+ }
745
+ // CALL_SITE by coordinates
746
+ else if (sourceType === 'CALL_SITE') {
747
+ const searchLine = sourceLine || assignment.callLine;
748
+ const searchColumn = sourceColumn || assignment.callColumn;
749
+ const searchName = assignment.callName;
750
+
751
+ if (searchLine && searchColumn) {
752
+ const callSite = callSites.find(cs =>
753
+ cs.line === searchLine &&
754
+ cs.column === searchColumn &&
755
+ (searchName ? cs.name === searchName : true)
756
+ );
757
+
758
+ if (callSite) {
759
+ this._bufferEdge({
760
+ type: 'ASSIGNED_FROM',
761
+ src: variableId,
762
+ dst: callSite.id
763
+ });
764
+ }
765
+ }
766
+ }
767
+ // VARIABLE by name
768
+ else if (sourceType === 'VARIABLE' && sourceName) {
769
+ const varIdParts = variableId.split('#');
770
+ const varFile = varIdParts.length >= 3 ? varIdParts[2] : null;
771
+ const sourceVariable = variableDeclarations.find(v =>
772
+ v.name === sourceName && v.file === varFile
773
+ );
774
+
775
+ if (sourceVariable) {
776
+ this._bufferEdge({
777
+ type: 'ASSIGNED_FROM',
778
+ src: variableId,
779
+ dst: sourceVariable.id
780
+ });
781
+ } else {
782
+ const sourceParam = parameters.find(p =>
783
+ p.name === sourceName && p.file === varFile
784
+ );
785
+
786
+ if (sourceParam) {
787
+ this._bufferEdge({
788
+ type: 'DERIVES_FROM',
789
+ src: variableId,
790
+ dst: sourceParam.id
791
+ });
792
+ }
793
+ }
794
+ }
795
+ // FUNCTION (arrow function assigned to variable)
796
+ else if (sourceType === 'FUNCTION' && functionName && line) {
797
+ const sourceFunction = functions.find(f =>
798
+ f.name === functionName && f.line === line
799
+ );
800
+
801
+ if (sourceFunction) {
802
+ this._bufferEdge({
803
+ type: 'ASSIGNED_FROM',
804
+ src: variableId,
805
+ dst: sourceFunction.id
806
+ });
807
+ }
808
+ }
809
+ // EXPRESSION node creation
810
+ else if (sourceType === 'EXPRESSION' && sourceId) {
811
+ const {
812
+ expressionType,
813
+ object,
814
+ property,
815
+ computed,
816
+ computedPropertyVar,
817
+ operator,
818
+ objectSourceName,
819
+ leftSourceName,
820
+ rightSourceName,
821
+ consequentSourceName,
822
+ alternateSourceName,
823
+ file: exprFile,
824
+ line: exprLine
825
+ } = assignment;
826
+
827
+ const expressionNode: GraphNode = {
828
+ id: sourceId,
829
+ type: 'EXPRESSION',
830
+ expressionType,
831
+ file: exprFile,
832
+ line: exprLine
833
+ };
834
+
835
+ if (expressionType === 'MemberExpression') {
836
+ expressionNode.object = object;
837
+ expressionNode.property = property;
838
+ expressionNode.computed = computed;
839
+ if (computedPropertyVar) {
840
+ expressionNode.computedPropertyVar = computedPropertyVar;
841
+ }
842
+ expressionNode.name = `${object}.${property}`;
843
+ } else if (expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression') {
844
+ expressionNode.operator = operator;
845
+ expressionNode.name = `<${expressionType}>`;
846
+ } else if (expressionType === 'ConditionalExpression') {
847
+ expressionNode.name = '<ternary>';
848
+ } else if (expressionType === 'TemplateLiteral') {
849
+ expressionNode.name = '<template>';
850
+ }
851
+
852
+ this._bufferNode(expressionNode);
853
+
854
+ this._bufferEdge({
855
+ type: 'ASSIGNED_FROM',
856
+ src: variableId,
857
+ dst: sourceId
858
+ });
859
+
860
+ // Buffer DERIVES_FROM edges
861
+ const varParts = variableId.split('#');
862
+ const varFile = varParts.length >= 3 ? varParts[2] : null;
863
+
864
+ if (expressionType === 'MemberExpression' && objectSourceName) {
865
+ const objectVar = variableDeclarations.find(v =>
866
+ v.name === objectSourceName && (!varFile || v.file === varFile)
867
+ );
868
+ if (objectVar) {
869
+ this._bufferEdge({
870
+ type: 'DERIVES_FROM',
871
+ src: sourceId,
872
+ dst: objectVar.id
873
+ });
874
+ }
875
+ }
876
+
877
+ if ((expressionType === 'BinaryExpression' || expressionType === 'LogicalExpression')) {
878
+ if (leftSourceName) {
879
+ const leftVar = variableDeclarations.find(v =>
880
+ v.name === leftSourceName && (!varFile || v.file === varFile)
881
+ );
882
+ if (leftVar) {
883
+ this._bufferEdge({
884
+ type: 'DERIVES_FROM',
885
+ src: sourceId,
886
+ dst: leftVar.id
887
+ });
888
+ }
889
+ }
890
+ if (rightSourceName) {
891
+ const rightVar = variableDeclarations.find(v =>
892
+ v.name === rightSourceName && (!varFile || v.file === varFile)
893
+ );
894
+ if (rightVar) {
895
+ this._bufferEdge({
896
+ type: 'DERIVES_FROM',
897
+ src: sourceId,
898
+ dst: rightVar.id
899
+ });
900
+ }
901
+ }
902
+ }
903
+
904
+ if (expressionType === 'ConditionalExpression') {
905
+ if (consequentSourceName) {
906
+ const consequentVar = variableDeclarations.find(v =>
907
+ v.name === consequentSourceName && (!varFile || v.file === varFile)
908
+ );
909
+ if (consequentVar) {
910
+ this._bufferEdge({
911
+ type: 'DERIVES_FROM',
912
+ src: sourceId,
913
+ dst: consequentVar.id
914
+ });
915
+ }
916
+ }
917
+ if (alternateSourceName) {
918
+ const alternateVar = variableDeclarations.find(v =>
919
+ v.name === alternateSourceName && (!varFile || v.file === varFile)
920
+ );
921
+ if (alternateVar) {
922
+ this._bufferEdge({
923
+ type: 'DERIVES_FROM',
924
+ src: sourceId,
925
+ dst: alternateVar.id
926
+ });
927
+ }
928
+ }
929
+ }
930
+
931
+ if (expressionType === 'TemplateLiteral') {
932
+ const { expressionSourceNames } = assignment;
933
+ if (expressionSourceNames && expressionSourceNames.length > 0) {
934
+ for (const exprSourceName of expressionSourceNames) {
935
+ const sourceVar = variableDeclarations.find(v =>
936
+ v.name === exprSourceName && (!varFile || v.file === varFile)
937
+ );
938
+ if (sourceVar) {
939
+ this._bufferEdge({
940
+ type: 'DERIVES_FROM',
941
+ src: sourceId,
942
+ dst: sourceVar.id
943
+ });
944
+ }
945
+ }
946
+ }
947
+ }
948
+ }
949
+ // DERIVES_FROM_VARIABLE
950
+ else if (sourceType === 'DERIVES_FROM_VARIABLE' && sourceName) {
951
+ const expressionId = variableId;
952
+ const exprParts = expressionId.split('#');
953
+ const exprFile = exprParts.length >= 3 ? exprParts[2] : assignment.file;
954
+
955
+ const sourceVariable = variableDeclarations.find(v =>
956
+ v.name === sourceName && v.file === exprFile
957
+ );
958
+
959
+ if (sourceVariable) {
960
+ this._bufferEdge({
961
+ type: 'DERIVES_FROM',
962
+ src: expressionId,
963
+ dst: sourceVariable.id
964
+ });
965
+ } else {
966
+ const sourceParam = parameters.find(p =>
967
+ p.name === sourceName && p.file === exprFile
968
+ );
969
+
970
+ if (sourceParam) {
971
+ this._bufferEdge({
972
+ type: 'DERIVES_FROM',
973
+ src: expressionId,
974
+ dst: sourceParam.id
975
+ });
976
+ }
977
+ }
978
+ }
979
+ }
980
+ }
981
+
982
+ private bufferArgumentEdges(
983
+ callArguments: CallArgumentInfo[],
984
+ variableDeclarations: VariableDeclarationInfo[],
985
+ functions: FunctionInfo[],
986
+ callSites: CallSiteInfo[],
987
+ methodCalls: MethodCallInfo[]
988
+ ): void {
989
+ for (const arg of callArguments) {
990
+ const {
991
+ callId,
992
+ argIndex,
993
+ targetType,
994
+ targetId,
995
+ targetName,
996
+ file,
997
+ isSpread,
998
+ functionLine,
999
+ functionColumn,
1000
+ nestedCallLine,
1001
+ nestedCallColumn
1002
+ } = arg;
1003
+
1004
+ let targetNodeId = targetId;
1005
+
1006
+ if (targetType === 'VARIABLE' && targetName) {
1007
+ const varNode = variableDeclarations.find(v =>
1008
+ v.name === targetName && v.file === file
1009
+ );
1010
+ if (varNode) {
1011
+ targetNodeId = varNode.id;
1012
+ }
1013
+ }
1014
+ else if (targetType === 'FUNCTION' && functionLine && functionColumn) {
1015
+ const funcNode = functions.find(f =>
1016
+ f.file === file && f.line === functionLine && f.column === functionColumn
1017
+ );
1018
+ if (funcNode) {
1019
+ targetNodeId = funcNode.id;
1020
+ }
1021
+ }
1022
+ else if (targetType === 'CALL' && nestedCallLine && nestedCallColumn) {
1023
+ const nestedCall = callSites.find(c =>
1024
+ c.file === file && c.line === nestedCallLine && c.column === nestedCallColumn
1025
+ ) || methodCalls.find(c =>
1026
+ c.file === file && c.line === nestedCallLine && c.column === nestedCallColumn
1027
+ );
1028
+ if (nestedCall) {
1029
+ targetNodeId = nestedCall.id;
1030
+ }
1031
+ }
1032
+
1033
+ if (targetNodeId) {
1034
+ const edgeData: GraphEdge = {
1035
+ type: 'PASSES_ARGUMENT',
1036
+ src: callId,
1037
+ dst: targetNodeId,
1038
+ metadata: { argIndex }
1039
+ };
1040
+
1041
+ if (isSpread) {
1042
+ edgeData.metadata = { ...edgeData.metadata, isSpread: true };
1043
+ }
1044
+
1045
+ this._bufferEdge(edgeData);
1046
+ }
1047
+ }
1048
+ }
1049
+
1050
+ // ============= TypeScript-specific buffer methods =============
1051
+
1052
+ /**
1053
+ * Buffer INTERFACE nodes and EXTENDS edges
1054
+ */
1055
+ private bufferInterfaceNodes(module: ModuleNode, interfaces: InterfaceDeclarationInfo[]): void {
1056
+ for (const iface of interfaces) {
1057
+ // Buffer INTERFACE node
1058
+ this._bufferNode({
1059
+ id: iface.id,
1060
+ type: 'INTERFACE',
1061
+ name: iface.name,
1062
+ file: iface.file,
1063
+ line: iface.line,
1064
+ column: iface.column,
1065
+ properties: iface.properties,
1066
+ extends: iface.extends
1067
+ });
1068
+
1069
+ // MODULE -> CONTAINS -> INTERFACE
1070
+ this._bufferEdge({
1071
+ type: 'CONTAINS',
1072
+ src: module.id,
1073
+ dst: iface.id
1074
+ });
1075
+
1076
+ // INTERFACE -> EXTENDS -> INTERFACE (for each parent interface)
1077
+ if (iface.extends && iface.extends.length > 0) {
1078
+ for (const parentName of iface.extends) {
1079
+ // Try to find the parent interface in the same file
1080
+ const parentInterface = interfaces.find(i => i.name === parentName);
1081
+ if (parentInterface) {
1082
+ this._bufferEdge({
1083
+ type: 'EXTENDS',
1084
+ src: iface.id,
1085
+ dst: parentInterface.id
1086
+ });
1087
+ } else {
1088
+ // External interface - create a reference node
1089
+ const externalId = `INTERFACE#${parentName}#${iface.file}#external`;
1090
+ this._bufferNode({
1091
+ id: externalId,
1092
+ type: 'INTERFACE',
1093
+ name: parentName,
1094
+ file: iface.file,
1095
+ line: iface.line,
1096
+ isExternal: true
1097
+ });
1098
+ this._bufferEdge({
1099
+ type: 'EXTENDS',
1100
+ src: iface.id,
1101
+ dst: externalId
1102
+ });
1103
+ }
1104
+ }
1105
+ }
1106
+ }
1107
+ }
1108
+
1109
+ /**
1110
+ * Buffer TYPE alias nodes
1111
+ */
1112
+ private bufferTypeAliasNodes(module: ModuleNode, typeAliases: TypeAliasInfo[]): void {
1113
+ for (const typeAlias of typeAliases) {
1114
+ // Buffer TYPE node
1115
+ this._bufferNode({
1116
+ id: typeAlias.id,
1117
+ type: 'TYPE',
1118
+ name: typeAlias.name,
1119
+ file: typeAlias.file,
1120
+ line: typeAlias.line,
1121
+ column: typeAlias.column,
1122
+ aliasOf: typeAlias.aliasOf
1123
+ });
1124
+
1125
+ // MODULE -> CONTAINS -> TYPE
1126
+ this._bufferEdge({
1127
+ type: 'CONTAINS',
1128
+ src: module.id,
1129
+ dst: typeAlias.id
1130
+ });
1131
+ }
1132
+ }
1133
+
1134
+ /**
1135
+ * Buffer ENUM nodes
1136
+ */
1137
+ private bufferEnumNodes(module: ModuleNode, enums: EnumDeclarationInfo[]): void {
1138
+ for (const enumDecl of enums) {
1139
+ // Buffer ENUM node
1140
+ this._bufferNode({
1141
+ id: enumDecl.id,
1142
+ type: 'ENUM',
1143
+ name: enumDecl.name,
1144
+ file: enumDecl.file,
1145
+ line: enumDecl.line,
1146
+ column: enumDecl.column,
1147
+ isConst: enumDecl.isConst,
1148
+ members: enumDecl.members
1149
+ });
1150
+
1151
+ // MODULE -> CONTAINS -> ENUM
1152
+ this._bufferEdge({
1153
+ type: 'CONTAINS',
1154
+ src: module.id,
1155
+ dst: enumDecl.id
1156
+ });
1157
+ }
1158
+ }
1159
+
1160
+ /**
1161
+ * Buffer DECORATOR nodes and DECORATED_BY edges
1162
+ */
1163
+ private bufferDecoratorNodes(decorators: DecoratorInfo[]): void {
1164
+ for (const decorator of decorators) {
1165
+ // Buffer DECORATOR node
1166
+ this._bufferNode({
1167
+ id: decorator.id,
1168
+ type: 'DECORATOR',
1169
+ name: decorator.name,
1170
+ file: decorator.file,
1171
+ line: decorator.line,
1172
+ column: decorator.column,
1173
+ arguments: decorator.arguments,
1174
+ targetType: decorator.targetType
1175
+ });
1176
+
1177
+ // TARGET -> DECORATED_BY -> DECORATOR
1178
+ this._bufferEdge({
1179
+ type: 'DECORATED_BY',
1180
+ src: decorator.targetId,
1181
+ dst: decorator.id
1182
+ });
1183
+ }
1184
+ }
1185
+
1186
+ /**
1187
+ * Buffer IMPLEMENTS edges (CLASS -> INTERFACE)
1188
+ */
1189
+ private bufferImplementsEdges(classDeclarations: ClassDeclarationInfo[], interfaces: InterfaceDeclarationInfo[]): void {
1190
+ for (const classDecl of classDeclarations) {
1191
+ if (classDecl.implements && classDecl.implements.length > 0) {
1192
+ for (const ifaceName of classDecl.implements) {
1193
+ // Try to find the interface in the same file
1194
+ const iface = interfaces.find(i => i.name === ifaceName);
1195
+ if (iface) {
1196
+ this._bufferEdge({
1197
+ type: 'IMPLEMENTS',
1198
+ src: classDecl.id,
1199
+ dst: iface.id
1200
+ });
1201
+ } else {
1202
+ // External interface - create a reference node
1203
+ const externalId = `INTERFACE#${ifaceName}#${classDecl.file}#external`;
1204
+ this._bufferNode({
1205
+ id: externalId,
1206
+ type: 'INTERFACE',
1207
+ name: ifaceName,
1208
+ file: classDecl.file,
1209
+ line: classDecl.line,
1210
+ isExternal: true
1211
+ });
1212
+ this._bufferEdge({
1213
+ type: 'IMPLEMENTS',
1214
+ src: classDecl.id,
1215
+ dst: externalId
1216
+ });
1217
+ }
1218
+ }
1219
+ }
1220
+ }
1221
+ }
1222
+
1223
+ /**
1224
+ * Handle CLASS ASSIGNED_FROM edges asynchronously (needs graph queries)
1225
+ */
1226
+ private async createClassAssignmentEdges(variableAssignments: VariableAssignmentInfo[], graph: GraphBackend): Promise<number> {
1227
+ let edgesCreated = 0;
1228
+
1229
+ for (const assignment of variableAssignments) {
1230
+ const { variableId, sourceType, className } = assignment;
1231
+
1232
+ if (sourceType === 'CLASS' && className) {
1233
+ const parts = variableId.split('#');
1234
+ const file = parts.length >= 3 ? parts[2] : null;
1235
+
1236
+ let classNode: { id: string; name: string; file?: string } | null = null;
1237
+ for await (const node of graph.queryNodes({ type: 'CLASS' })) {
1238
+ if (node.name === className && (!file || node.file === file)) {
1239
+ classNode = node as { id: string; name: string; file?: string };
1240
+ break;
1241
+ }
1242
+ }
1243
+
1244
+ if (classNode) {
1245
+ await graph.addEdge({
1246
+ type: 'ASSIGNED_FROM',
1247
+ src: variableId,
1248
+ dst: classNode.id
1249
+ });
1250
+ edgesCreated++;
1251
+ }
1252
+ }
1253
+ }
1254
+
1255
+ return edgesCreated;
1256
+ }
1257
+
1258
+ /**
1259
+ * Create IMPORTS_FROM edges linking imports to their target exports
1260
+ */
1261
+ private async createImportExportEdges(
1262
+ module: ModuleNode,
1263
+ imports: ImportInfo[],
1264
+ _exports: ExportInfo[],
1265
+ graph: GraphBackend,
1266
+ _projectPath: string
1267
+ ): Promise<number> {
1268
+ let edgesCreated = 0;
1269
+
1270
+ for (const imp of imports) {
1271
+ const { source, specifiers, line } = imp;
1272
+
1273
+ // Только для относительных импортов
1274
+ const isRelative = source.startsWith('./') || source.startsWith('../');
1275
+ if (!isRelative) {
1276
+ continue;
1277
+ }
1278
+
1279
+ // Резолвим целевой модуль
1280
+ const currentDir = dirname(module.file);
1281
+ let targetPath = resolve(currentDir, source);
1282
+
1283
+ // Пытаемся найти файл с расширениями .js, .ts, .jsx, .tsx
1284
+ const extensions = ['', '.js', '.ts', '.jsx', '.tsx', '/index.js', '/index.ts'];
1285
+ let targetModule: { id: string; file: string } | null = null;
1286
+
1287
+ // Ищем MODULE ноду по file атрибуту (не по ID, т.к. формат ID изменился)
1288
+ for (const ext of extensions) {
1289
+ const testPath = targetPath + ext;
1290
+
1291
+ // Ищем MODULE с этим file path
1292
+ for await (const node of graph.queryNodes({ type: 'MODULE' })) {
1293
+ if (node.file === testPath) {
1294
+ targetModule = node as { id: string; file: string };
1295
+ targetPath = testPath;
1296
+ break;
1297
+ }
1298
+ }
1299
+ if (targetModule) break;
1300
+ }
1301
+
1302
+ if (!targetModule) {
1303
+ // Целевой модуль не найден в графе
1304
+ continue;
1305
+ }
1306
+
1307
+ // Создаём IMPORTS edge от MODULE к MODULE (для совместимости с тестами)
1308
+ await graph.addEdge({
1309
+ type: 'IMPORTS',
1310
+ src: module.id,
1311
+ dst: targetModule.id
1312
+ });
1313
+ edgesCreated++;
1314
+
1315
+ // Для каждого импортированного идентификатора создаём ребро к соответствующему EXPORT
1316
+ for (const spec of specifiers) {
1317
+ const importId = `${module.file}:IMPORT:${source}:${spec.local}:${line}`;
1318
+ const importType = spec.imported === 'default' ? 'default' :
1319
+ spec.imported === '*' ? 'namespace' : 'named';
1320
+
1321
+ if (importType === 'namespace') {
1322
+ // import * as foo - связываем со всем модулем
1323
+ await graph.addEdge({
1324
+ type: 'IMPORTS_FROM',
1325
+ src: importId,
1326
+ dst: targetModule.id
1327
+ });
1328
+ edgesCreated++;
1329
+ } else if (importType === 'default') {
1330
+ // Находим EXPORT default в целевом модуле
1331
+ const targetExports: { id: string }[] = [];
1332
+ for await (const node of graph.queryNodes({ type: 'EXPORT' })) {
1333
+ const exportNode = node as { id: string; file?: string; exportType?: string };
1334
+ if (exportNode.file === targetPath && exportNode.exportType === 'default') {
1335
+ targetExports.push(exportNode);
1336
+ }
1337
+ }
1338
+
1339
+ if (targetExports.length > 0) {
1340
+ await graph.addEdge({
1341
+ type: 'IMPORTS_FROM',
1342
+ src: importId,
1343
+ dst: targetExports[0].id
1344
+ });
1345
+ edgesCreated++;
1346
+ }
1347
+ } else {
1348
+ // Named import - находим соответствующий named export
1349
+ const targetExports: { id: string }[] = [];
1350
+ for await (const node of graph.queryNodes({ type: 'EXPORT' })) {
1351
+ const exportNode = node as { id: string; file?: string; exportType?: string; name?: string };
1352
+ if (exportNode.file === targetPath && exportNode.exportType === 'named' && exportNode.name === spec.imported) {
1353
+ targetExports.push(exportNode);
1354
+ }
1355
+ }
1356
+
1357
+ if (targetExports.length > 0) {
1358
+ await graph.addEdge({
1359
+ type: 'IMPORTS_FROM',
1360
+ src: importId,
1361
+ dst: targetExports[0].id
1362
+ });
1363
+ edgesCreated++;
1364
+ }
1365
+ }
1366
+ }
1367
+ }
1368
+
1369
+ return edgesCreated;
1370
+ }
1371
+ }