ts-knowledge-graph 0.1.2 → 0.1.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 (335) hide show
  1. package/README.md +99 -41
  2. package/contribs/webview/README.md +83 -0
  3. package/contribs/webview/web/css/style.css +310 -0
  4. package/contribs/webview/web/index.html +109 -0
  5. package/contribs/webview/web/js/app.js +1249 -0
  6. package/contribs/webview/web/js_autogenerated/.gitignore +3 -0
  7. package/contribs/webview/web/js_autogenerated/kind_descriptions.js +39 -0
  8. package/contribs/webview/web/types/app_globals.d.ts +154 -0
  9. package/dist/benchmark/benchmark_stats.d.ts +41 -0
  10. package/dist/benchmark/benchmark_stats.d.ts.map +1 -0
  11. package/dist/benchmark/benchmark_stats.js +61 -0
  12. package/dist/benchmark/benchmark_stats.js.map +1 -0
  13. package/dist/benchmark/node_benchmark.d.ts +78 -0
  14. package/dist/benchmark/node_benchmark.d.ts.map +1 -0
  15. package/dist/benchmark/node_benchmark.js +112 -0
  16. package/dist/benchmark/node_benchmark.js.map +1 -0
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +16 -4
  19. package/dist/cli.js.map +1 -1
  20. package/dist/cluster/cluster_weights.d.ts +20 -0
  21. package/dist/cluster/cluster_weights.d.ts.map +1 -0
  22. package/dist/cluster/cluster_weights.js +32 -0
  23. package/dist/cluster/cluster_weights.js.map +1 -0
  24. package/dist/cluster/community_detector.d.ts +61 -0
  25. package/dist/cluster/community_detector.d.ts.map +1 -0
  26. package/dist/cluster/community_detector.js +120 -0
  27. package/dist/cluster/community_detector.js.map +1 -0
  28. package/dist/cluster/community_labeler.d.ts +84 -0
  29. package/dist/cluster/community_labeler.d.ts.map +1 -0
  30. package/dist/cluster/community_labeler.js +194 -0
  31. package/dist/cluster/community_labeler.js.map +1 -0
  32. package/dist/cluster/graph_clusterer.d.ts +47 -0
  33. package/dist/cluster/graph_clusterer.d.ts.map +1 -0
  34. package/dist/cluster/graph_clusterer.js +126 -0
  35. package/dist/cluster/graph_clusterer.js.map +1 -0
  36. package/dist/commands/benchmark_command.d.ts +11 -0
  37. package/dist/commands/benchmark_command.d.ts.map +1 -0
  38. package/dist/commands/benchmark_command.js +94 -0
  39. package/dist/commands/benchmark_command.js.map +1 -0
  40. package/dist/commands/blast_radius_command.d.ts.map +1 -1
  41. package/dist/commands/blast_radius_command.js +7 -6
  42. package/dist/commands/blast_radius_command.js.map +1 -1
  43. package/dist/commands/cluster_command.d.ts +7 -0
  44. package/dist/commands/cluster_command.d.ts.map +1 -0
  45. package/dist/commands/cluster_command.js +55 -0
  46. package/dist/commands/cluster_command.js.map +1 -0
  47. package/dist/commands/command_helpers.d.ts +9 -4
  48. package/dist/commands/command_helpers.d.ts.map +1 -1
  49. package/dist/commands/command_helpers.js +13 -8
  50. package/dist/commands/command_helpers.js.map +1 -1
  51. package/dist/commands/cost_command.d.ts +13 -0
  52. package/dist/commands/cost_command.d.ts.map +1 -0
  53. package/dist/commands/cost_command.js +139 -0
  54. package/dist/commands/cost_command.js.map +1 -0
  55. package/dist/commands/{load.d.ts → enrich_command.d.ts} +3 -2
  56. package/dist/commands/enrich_command.d.ts.map +1 -0
  57. package/dist/commands/enrich_command.js +64 -0
  58. package/dist/commands/enrich_command.js.map +1 -0
  59. package/dist/commands/extract_command.d.ts.map +1 -1
  60. package/dist/commands/extract_command.js +12 -6
  61. package/dist/commands/extract_command.js.map +1 -1
  62. package/dist/commands/hotspots_command.d.ts +7 -0
  63. package/dist/commands/hotspots_command.d.ts.map +1 -0
  64. package/dist/commands/hotspots_command.js +68 -0
  65. package/dist/commands/hotspots_command.js.map +1 -0
  66. package/dist/commands/install_command.d.ts +15 -6
  67. package/dist/commands/install_command.d.ts.map +1 -1
  68. package/dist/commands/install_command.js +62 -25
  69. package/dist/commands/install_command.js.map +1 -1
  70. package/dist/commands/load_command.d.ts.map +1 -1
  71. package/dist/commands/load_command.js +20 -13
  72. package/dist/commands/load_command.js.map +1 -1
  73. package/dist/commands/neighbors_command.d.ts.map +1 -1
  74. package/dist/commands/neighbors_command.js +6 -5
  75. package/dist/commands/neighbors_command.js.map +1 -1
  76. package/dist/commands/references_command.d.ts.map +1 -1
  77. package/dist/commands/references_command.js +6 -5
  78. package/dist/commands/references_command.js.map +1 -1
  79. package/dist/commands/report_command.d.ts +16 -0
  80. package/dist/commands/report_command.d.ts.map +1 -0
  81. package/dist/commands/report_command.js +115 -0
  82. package/dist/commands/report_command.js.map +1 -0
  83. package/dist/commands/verify_command.d.ts +8 -0
  84. package/dist/commands/verify_command.d.ts.map +1 -0
  85. package/dist/commands/verify_command.js +57 -0
  86. package/dist/commands/verify_command.js.map +1 -0
  87. package/dist/commands/web_command.d.ts +27 -0
  88. package/dist/commands/web_command.d.ts.map +1 -1
  89. package/dist/commands/web_command.js +109 -3
  90. package/dist/commands/web_command.js.map +1 -1
  91. package/dist/commands/webview_command.d.ts +36 -0
  92. package/dist/commands/webview_command.d.ts.map +1 -0
  93. package/dist/commands/webview_command.js +186 -0
  94. package/dist/commands/webview_command.js.map +1 -0
  95. package/dist/enrich/cpu_profile.d.ts +160 -0
  96. package/dist/enrich/cpu_profile.d.ts.map +1 -0
  97. package/dist/enrich/cpu_profile.js +185 -0
  98. package/dist/enrich/cpu_profile.js.map +1 -0
  99. package/dist/enrich/runtime_enricher.d.ts +64 -0
  100. package/dist/enrich/runtime_enricher.d.ts.map +1 -0
  101. package/dist/enrich/runtime_enricher.js +98 -0
  102. package/dist/enrich/runtime_enricher.js.map +1 -0
  103. package/dist/enrich/runtime_join.d.ts +124 -0
  104. package/dist/enrich/runtime_join.d.ts.map +1 -0
  105. package/dist/enrich/runtime_join.js +270 -0
  106. package/dist/enrich/runtime_join.js.map +1 -0
  107. package/dist/extract/api_extractor.d.ts +24 -0
  108. package/dist/extract/api_extractor.d.ts.map +1 -0
  109. package/dist/extract/api_extractor.js +71 -0
  110. package/dist/extract/api_extractor.js.map +1 -0
  111. package/dist/extract/config_extractor.d.ts +22 -0
  112. package/dist/extract/config_extractor.d.ts.map +1 -0
  113. package/dist/extract/config_extractor.js +61 -0
  114. package/dist/extract/config_extractor.js.map +1 -0
  115. package/dist/extract/endpoint_extractor.d.ts +36 -0
  116. package/dist/extract/endpoint_extractor.d.ts.map +1 -0
  117. package/dist/extract/endpoint_extractor.js +117 -0
  118. package/dist/extract/endpoint_extractor.js.map +1 -0
  119. package/dist/extract/git_source.d.ts +23 -0
  120. package/dist/extract/git_source.d.ts.map +1 -0
  121. package/dist/extract/git_source.js +75 -0
  122. package/dist/extract/git_source.js.map +1 -0
  123. package/dist/extract/graph_builder.d.ts +8 -0
  124. package/dist/extract/graph_builder.d.ts.map +1 -1
  125. package/dist/extract/graph_builder.js +23 -1
  126. package/dist/extract/graph_builder.js.map +1 -1
  127. package/dist/extract/node_id.d.ts +16 -0
  128. package/dist/extract/node_id.d.ts.map +1 -1
  129. package/dist/extract/node_id.js +22 -0
  130. package/dist/extract/node_id.js.map +1 -1
  131. package/dist/extract/scope_resolver.d.ts +22 -0
  132. package/dist/extract/scope_resolver.d.ts.map +1 -0
  133. package/dist/extract/scope_resolver.js +53 -0
  134. package/dist/extract/scope_resolver.js.map +1 -0
  135. package/dist/extract/semantic_extractor.d.ts +25 -0
  136. package/dist/extract/semantic_extractor.d.ts.map +1 -1
  137. package/dist/extract/semantic_extractor.js +96 -2
  138. package/dist/extract/semantic_extractor.js.map +1 -1
  139. package/dist/extract/structural_extractor.d.ts +6 -0
  140. package/dist/extract/structural_extractor.d.ts.map +1 -1
  141. package/dist/extract/structural_extractor.js +22 -12
  142. package/dist/extract/structural_extractor.js.map +1 -1
  143. package/dist/project_root.d.ts +7 -0
  144. package/dist/project_root.d.ts.map +1 -0
  145. package/dist/project_root.js +9 -0
  146. package/dist/project_root.js.map +1 -0
  147. package/dist/query/graph_query.d.ts +269 -0
  148. package/dist/query/graph_query.d.ts.map +1 -1
  149. package/dist/query/graph_query.js +585 -11
  150. package/dist/query/graph_query.js.map +1 -1
  151. package/dist/report/graph_report.d.ts +51 -0
  152. package/dist/report/graph_report.d.ts.map +1 -0
  153. package/dist/report/graph_report.js +312 -0
  154. package/dist/report/graph_report.js.map +1 -0
  155. package/dist/report/pdf_renderer.d.ts +22 -0
  156. package/dist/report/pdf_renderer.d.ts.map +1 -0
  157. package/dist/report/pdf_renderer.js +54 -0
  158. package/dist/report/pdf_renderer.js.map +1 -0
  159. package/dist/report/report_data.d.ts +128 -0
  160. package/dist/report/report_data.d.ts.map +1 -0
  161. package/dist/report/report_data.js +191 -0
  162. package/dist/report/report_data.js.map +1 -0
  163. package/dist/schema/edge.d.ts +40 -5
  164. package/dist/schema/edge.d.ts.map +1 -1
  165. package/dist/schema/edge.js +73 -0
  166. package/dist/schema/edge.js.map +1 -1
  167. package/dist/schema/node.d.ts +20 -5
  168. package/dist/schema/node.d.ts.map +1 -1
  169. package/dist/schema/node.js +36 -0
  170. package/dist/schema/node.js.map +1 -1
  171. package/dist/schema/runtime_manifest.d.ts +36 -0
  172. package/dist/schema/runtime_manifest.d.ts.map +1 -0
  173. package/dist/schema/runtime_manifest.js +23 -0
  174. package/dist/schema/runtime_manifest.js.map +1 -0
  175. package/dist/schema/source_manifest.d.ts +30 -0
  176. package/dist/schema/source_manifest.d.ts.map +1 -0
  177. package/dist/schema/source_manifest.js +21 -0
  178. package/dist/schema/source_manifest.js.map +1 -0
  179. package/dist/store/jsonl_reader.d.ts +4 -0
  180. package/dist/store/jsonl_reader.d.ts.map +1 -1
  181. package/dist/store/jsonl_reader.js +13 -1
  182. package/dist/store/jsonl_reader.js.map +1 -1
  183. package/dist/store/jsonl_store.d.ts +2 -1
  184. package/dist/store/jsonl_store.d.ts.map +1 -1
  185. package/dist/store/jsonl_store.js +4 -1
  186. package/dist/store/jsonl_store.js.map +1 -1
  187. package/dist/store/kuzu_store.d.ts +59 -0
  188. package/dist/store/kuzu_store.d.ts.map +1 -1
  189. package/dist/store/kuzu_store.js +124 -5
  190. package/dist/store/kuzu_store.js.map +1 -1
  191. package/dist/store/output_folder.d.ts +43 -0
  192. package/dist/store/output_folder.d.ts.map +1 -0
  193. package/dist/store/output_folder.js +61 -0
  194. package/dist/store/output_folder.js.map +1 -0
  195. package/dist/verify/project_verifier.d.ts +85 -0
  196. package/dist/verify/project_verifier.d.ts.map +1 -0
  197. package/dist/verify/project_verifier.js +138 -0
  198. package/dist/verify/project_verifier.js.map +1 -0
  199. package/dotclaude_folder/commands/code-graph-interview.md +123 -0
  200. package/dotclaude_folder/commands/code-graph-optimize.md +65 -0
  201. package/{skills/ts-knowledge-graph → dotclaude_folder/skills/code-graph-query}/SKILL.md +6 -6
  202. package/package.json +99 -10
  203. package/.env-sample +0 -34
  204. package/contribs/web_visualisation/README.md +0 -55
  205. package/contribs/web_visualisation/web/css/style.css +0 -115
  206. package/contribs/web_visualisation/web/data/.gitignore +0 -2
  207. package/contribs/web_visualisation/web/index.html +0 -58
  208. package/contribs/web_visualisation/web/js/app.js +0 -364
  209. package/dist/agent/agent-tools.d.ts +0 -13
  210. package/dist/agent/agent-tools.d.ts.map +0 -1
  211. package/dist/agent/agent-tools.js +0 -153
  212. package/dist/agent/agent-tools.js.map +0 -1
  213. package/dist/agent/agent_tools.d.ts +0 -13
  214. package/dist/agent/agent_tools.d.ts.map +0 -1
  215. package/dist/agent/agent_tools.js +0 -153
  216. package/dist/agent/agent_tools.js.map +0 -1
  217. package/dist/agent/code-editor.d.ts +0 -18
  218. package/dist/agent/code-editor.d.ts.map +0 -1
  219. package/dist/agent/code-editor.js +0 -43
  220. package/dist/agent/code-editor.js.map +0 -1
  221. package/dist/agent/code_editor.d.ts +0 -18
  222. package/dist/agent/code_editor.d.ts.map +0 -1
  223. package/dist/agent/code_editor.js +0 -43
  224. package/dist/agent/code_editor.js.map +0 -1
  225. package/dist/agent/optimizer-agent.d.ts +0 -30
  226. package/dist/agent/optimizer-agent.d.ts.map +0 -1
  227. package/dist/agent/optimizer-agent.js +0 -97
  228. package/dist/agent/optimizer-agent.js.map +0 -1
  229. package/dist/agent/optimizer_agent.d.ts +0 -30
  230. package/dist/agent/optimizer_agent.d.ts.map +0 -1
  231. package/dist/agent/optimizer_agent.js +0 -97
  232. package/dist/agent/optimizer_agent.js.map +0 -1
  233. package/dist/agent/verifier.d.ts +0 -9
  234. package/dist/agent/verifier.d.ts.map +0 -1
  235. package/dist/agent/verifier.js +0 -19
  236. package/dist/agent/verifier.js.map +0 -1
  237. package/dist/commands/blast-radius.d.ts +0 -5
  238. package/dist/commands/blast-radius.d.ts.map +0 -1
  239. package/dist/commands/blast-radius.js +0 -18
  240. package/dist/commands/blast-radius.js.map +0 -1
  241. package/dist/commands/blast_radius.d.ts +0 -5
  242. package/dist/commands/blast_radius.d.ts.map +0 -1
  243. package/dist/commands/blast_radius.js +0 -18
  244. package/dist/commands/blast_radius.js.map +0 -1
  245. package/dist/commands/calls.d.ts +0 -5
  246. package/dist/commands/calls.d.ts.map +0 -1
  247. package/dist/commands/calls.js +0 -7
  248. package/dist/commands/calls.js.map +0 -1
  249. package/dist/commands/command-helpers.d.ts +0 -15
  250. package/dist/commands/command-helpers.d.ts.map +0 -1
  251. package/dist/commands/command-helpers.js +0 -61
  252. package/dist/commands/command-helpers.js.map +0 -1
  253. package/dist/commands/dead-exports.d.ts +0 -5
  254. package/dist/commands/dead-exports.d.ts.map +0 -1
  255. package/dist/commands/dead-exports.js +0 -7
  256. package/dist/commands/dead-exports.js.map +0 -1
  257. package/dist/commands/dead_exports.d.ts +0 -5
  258. package/dist/commands/dead_exports.d.ts.map +0 -1
  259. package/dist/commands/dead_exports.js +0 -7
  260. package/dist/commands/dead_exports.js.map +0 -1
  261. package/dist/commands/extract.d.ts +0 -8
  262. package/dist/commands/extract.d.ts.map +0 -1
  263. package/dist/commands/extract.js +0 -49
  264. package/dist/commands/extract.js.map +0 -1
  265. package/dist/commands/find.d.ts +0 -5
  266. package/dist/commands/find.d.ts.map +0 -1
  267. package/dist/commands/find.js +0 -7
  268. package/dist/commands/find.js.map +0 -1
  269. package/dist/commands/load.d.ts.map +0 -1
  270. package/dist/commands/load.js +0 -28
  271. package/dist/commands/load.js.map +0 -1
  272. package/dist/commands/neighbors.d.ts +0 -5
  273. package/dist/commands/neighbors.d.ts.map +0 -1
  274. package/dist/commands/neighbors.js +0 -17
  275. package/dist/commands/neighbors.js.map +0 -1
  276. package/dist/commands/optimize.d.ts +0 -6
  277. package/dist/commands/optimize.d.ts.map +0 -1
  278. package/dist/commands/optimize.js +0 -59
  279. package/dist/commands/optimize.js.map +0 -1
  280. package/dist/commands/optimize_command.d.ts +0 -6
  281. package/dist/commands/optimize_command.d.ts.map +0 -1
  282. package/dist/commands/optimize_command.js +0 -59
  283. package/dist/commands/optimize_command.js.map +0 -1
  284. package/dist/commands/references.d.ts +0 -5
  285. package/dist/commands/references.d.ts.map +0 -1
  286. package/dist/commands/references.js +0 -17
  287. package/dist/commands/references.js.map +0 -1
  288. package/dist/commands/web.d.ts +0 -19
  289. package/dist/commands/web.d.ts.map +0 -1
  290. package/dist/commands/web.js +0 -120
  291. package/dist/commands/web.js.map +0 -1
  292. package/dist/commands/who-calls.d.ts +0 -5
  293. package/dist/commands/who-calls.d.ts.map +0 -1
  294. package/dist/commands/who-calls.js +0 -7
  295. package/dist/commands/who-calls.js.map +0 -1
  296. package/dist/commands/who_calls.d.ts +0 -5
  297. package/dist/commands/who_calls.d.ts.map +0 -1
  298. package/dist/commands/who_calls.js +0 -7
  299. package/dist/commands/who_calls.js.map +0 -1
  300. package/dist/extract/graph-builder.d.ts +0 -16
  301. package/dist/extract/graph-builder.d.ts.map +0 -1
  302. package/dist/extract/graph-builder.js +0 -39
  303. package/dist/extract/graph-builder.js.map +0 -1
  304. package/dist/extract/node-id.d.ts +0 -8
  305. package/dist/extract/node-id.d.ts.map +0 -1
  306. package/dist/extract/node-id.js +0 -22
  307. package/dist/extract/node-id.js.map +0 -1
  308. package/dist/extract/project-loader.d.ts +0 -5
  309. package/dist/extract/project-loader.d.ts.map +0 -1
  310. package/dist/extract/project-loader.js +0 -19
  311. package/dist/extract/project-loader.js.map +0 -1
  312. package/dist/extract/semantic-extractor.d.ts +0 -22
  313. package/dist/extract/semantic-extractor.d.ts.map +0 -1
  314. package/dist/extract/semantic-extractor.js +0 -254
  315. package/dist/extract/semantic-extractor.js.map +0 -1
  316. package/dist/extract/structural-extractor.d.ts +0 -18
  317. package/dist/extract/structural-extractor.d.ts.map +0 -1
  318. package/dist/extract/structural-extractor.js +0 -97
  319. package/dist/extract/structural-extractor.js.map +0 -1
  320. package/dist/query/graph-query.d.ts +0 -28
  321. package/dist/query/graph-query.d.ts.map +0 -1
  322. package/dist/query/graph-query.js +0 -93
  323. package/dist/query/graph-query.js.map +0 -1
  324. package/dist/store/jsonl-reader.d.ts +0 -11
  325. package/dist/store/jsonl-reader.d.ts.map +0 -1
  326. package/dist/store/jsonl-reader.js +0 -19
  327. package/dist/store/jsonl-reader.js.map +0 -1
  328. package/dist/store/jsonl-store.d.ts +0 -7
  329. package/dist/store/jsonl-store.d.ts.map +0 -1
  330. package/dist/store/jsonl-store.js +0 -13
  331. package/dist/store/jsonl-store.js.map +0 -1
  332. package/dist/store/kuzu-store.d.ts +0 -14
  333. package/dist/store/kuzu-store.d.ts.map +0 -1
  334. package/dist/store/kuzu-store.js +0 -52
  335. package/dist/store/kuzu-store.js.map +0 -1
@@ -0,0 +1,61 @@
1
+ import { Node, SyntaxKind } from 'ts-morph';
2
+ import { NodeId } from './node_id.js';
3
+ import { ScopeResolver } from './scope_resolver.js';
4
+ /**
5
+ * Detects configuration reads — `process.env.NAME` and `process.env['NAME']` —
6
+ * and emits one `ConfigFlag` node per distinct variable plus a `READS_CONFIG`
7
+ * edge from the enclosing declaration that performs the read. A variable read in
8
+ * several places collapses to one node (keyed by name) with one counted edge per
9
+ * reading scope.
10
+ *
11
+ * The detection is purely syntactic (no symbol resolution), so it runs in the
12
+ * structural pass and is always emitted. A project that never touches
13
+ * `process.env` produces no config nodes or edges, leaving its graph unchanged.
14
+ */
15
+ export class ConfigExtractor {
16
+ static extract(sourceFile, rootPath) {
17
+ const nodes = [];
18
+ const edges = [];
19
+ const moduleId = NodeId.forModule(sourceFile.getFilePath(), rootPath);
20
+ for (const access of sourceFile.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)) {
21
+ if (ConfigExtractor.isProcessEnv(access.getExpression()) === true) {
22
+ ConfigExtractor.emit(access, access.getName(), moduleId, rootPath, nodes, edges);
23
+ }
24
+ }
25
+ for (const access of sourceFile.getDescendantsOfKind(SyntaxKind.ElementAccessExpression)) {
26
+ if (ConfigExtractor.isProcessEnv(access.getExpression()) === false) {
27
+ continue;
28
+ }
29
+ const name = ConfigExtractor.stringArgument(access);
30
+ if (name !== undefined) {
31
+ ConfigExtractor.emit(access, name, moduleId, rootPath, nodes, edges);
32
+ }
33
+ }
34
+ return { nodes, edges };
35
+ }
36
+ static emit(access, name, moduleId, rootPath, nodes, edges) {
37
+ if (name === '') {
38
+ return;
39
+ }
40
+ const flagId = NodeId.forConfigFlag(name);
41
+ nodes.push({ id: flagId, kind: 'ConfigFlag', name, filePath: 'process.env' });
42
+ const scopeId = ScopeResolver.enclosingId(access, moduleId, rootPath);
43
+ edges.push({ id: `READS_CONFIG:${scopeId}->${flagId}`, kind: 'READS_CONFIG', from: scopeId, to: flagId });
44
+ }
45
+ /** Whether a node is the `process.env` member access (`process` identifier, `env` name). */
46
+ static isProcessEnv(node) {
47
+ const access = node.asKind(SyntaxKind.PropertyAccessExpression);
48
+ if (access === undefined || access.getName() !== 'env') {
49
+ return false;
50
+ }
51
+ const target = access.getExpression();
52
+ return Node.isIdentifier(target) === true && target.getText() === 'process';
53
+ }
54
+ /** The literal key of `process.env['NAME']`, or undefined when the key is computed. */
55
+ static stringArgument(access) {
56
+ const element = access.asKind(SyntaxKind.ElementAccessExpression);
57
+ const literal = element?.getArgumentExpression()?.asKind(SyntaxKind.StringLiteral);
58
+ return literal?.getLiteralText();
59
+ }
60
+ }
61
+ //# sourceMappingURL=config_extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config_extractor.js","sourceRoot":"","sources":["../../src/extract/config_extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { SourceFile } from 'ts-morph';
2
+ import { Extraction } from './structural_extractor.js';
3
+ /**
4
+ * Detects HTTP route registrations in the Express/Fastify style —
5
+ * `app.get('/path', handler)`, `router.post('/path', mw, handler)` — and emits an
6
+ * `Endpoint` node (keyed by method + path) plus a `HANDLES` edge from the endpoint
7
+ * to the function that handles it.
8
+ *
9
+ * A route is recognised syntactically: the callee is `<obj>.<verb>` for an HTTP
10
+ * verb, the first argument is a string-literal path, and the last argument is a
11
+ * handler — an inline function, or a name/member that resolves to an in-project
12
+ * callable. Resolving the named handler is why this runs in the semantic pass; an
13
+ * inline handler yields the `Endpoint` node alone (it has no declaration to point
14
+ * at).
15
+ *
16
+ * The match is a heuristic (it does not prove `obj` is an Express app), but the
17
+ * verb + string path + resolvable-handler combination is specific, so a project
18
+ * with no such call sites is unchanged. Other routers (Nest decorators, …) are out
19
+ * of scope for now — Express/Fastify first (#31 Part 3).
20
+ */
21
+ export declare class EndpointExtractor {
22
+ static extract(sourceFile: SourceFile, rootPath: string): Extraction;
23
+ private static extractRoute;
24
+ /**
25
+ * Classifies the last argument of a route call. An inline function is a valid
26
+ * handler with no node to point at; a name/member that resolves to an in-project
27
+ * callable is a valid handler whose emitted declaration becomes the `HANDLES`
28
+ * target; anything else means this is not a route.
29
+ */
30
+ private static classifyHandler;
31
+ /** Resolves a handler name/member to the in-project function, method, or function-valued variable it refers to. */
32
+ private static resolveCallable;
33
+ private static resolve;
34
+ private static inProject;
35
+ }
36
+ //# sourceMappingURL=endpoint_extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint_extractor.d.ts","sourceRoot":"","sources":["../../src/extract/endpoint_extractor.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,UAAU,EAAc,MAAM,UAAU,CAAC;AAKxE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAQvD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,iBAAiB;IAC7B,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU;IASpE,OAAO,CAAC,MAAM,CAAC,YAAY;IAoC3B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAc9B,mHAAmH;IACnH,OAAO,CAAC,MAAM,CAAC,eAAe;IAkB9B,OAAO,CAAC,MAAM,CAAC,OAAO;IAMtB,OAAO,CAAC,MAAM,CAAC,SAAS;CAKxB"}
@@ -0,0 +1,117 @@
1
+ import { relative } from 'node:path';
2
+ import { Node, SyntaxKind } from 'ts-morph';
3
+ import { NodeId } from './node_id.js';
4
+ import { ScopeResolver } from './scope_resolver.js';
5
+ /** HTTP-verb method names that register a route on an Express/Fastify app or router. */
6
+ const HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'all']);
7
+ /**
8
+ * Detects HTTP route registrations in the Express/Fastify style —
9
+ * `app.get('/path', handler)`, `router.post('/path', mw, handler)` — and emits an
10
+ * `Endpoint` node (keyed by method + path) plus a `HANDLES` edge from the endpoint
11
+ * to the function that handles it.
12
+ *
13
+ * A route is recognised syntactically: the callee is `<obj>.<verb>` for an HTTP
14
+ * verb, the first argument is a string-literal path, and the last argument is a
15
+ * handler — an inline function, or a name/member that resolves to an in-project
16
+ * callable. Resolving the named handler is why this runs in the semantic pass; an
17
+ * inline handler yields the `Endpoint` node alone (it has no declaration to point
18
+ * at).
19
+ *
20
+ * The match is a heuristic (it does not prove `obj` is an Express app), but the
21
+ * verb + string path + resolvable-handler combination is specific, so a project
22
+ * with no such call sites is unchanged. Other routers (Nest decorators, …) are out
23
+ * of scope for now — Express/Fastify first (#31 Part 3).
24
+ */
25
+ export class EndpointExtractor {
26
+ static extract(sourceFile, rootPath) {
27
+ const nodes = [];
28
+ const edges = [];
29
+ for (const call of sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)) {
30
+ EndpointExtractor.extractRoute(call, rootPath, nodes, edges);
31
+ }
32
+ return { nodes, edges };
33
+ }
34
+ static extractRoute(call, rootPath, nodes, edges) {
35
+ const callee = call.getExpression().asKind(SyntaxKind.PropertyAccessExpression);
36
+ if (callee === undefined || HTTP_METHODS.has(callee.getName()) === false) {
37
+ return;
38
+ }
39
+ const args = call.getArguments();
40
+ if (args.length < 2) {
41
+ return;
42
+ }
43
+ const pathLiteral = args[0].asKind(SyntaxKind.StringLiteral);
44
+ if (pathLiteral === undefined) {
45
+ return;
46
+ }
47
+ const handler = EndpointExtractor.classifyHandler(args[args.length - 1], rootPath);
48
+ if (handler.valid === false) {
49
+ return;
50
+ }
51
+ const method = callee.getName().toUpperCase();
52
+ const endpointId = NodeId.forEndpoint(method, pathLiteral.getLiteralText());
53
+ nodes.push({
54
+ id: endpointId,
55
+ kind: 'Endpoint',
56
+ name: `${method} ${pathLiteral.getLiteralText()}`,
57
+ filePath: relative(rootPath, call.getSourceFile().getFilePath()),
58
+ range: {
59
+ startLine: call.getStartLineNumber(),
60
+ startColumn: 0,
61
+ endLine: call.getEndLineNumber(),
62
+ endColumn: 0,
63
+ },
64
+ });
65
+ if (handler.id !== undefined) {
66
+ edges.push({ id: `HANDLES:${endpointId}->${handler.id}`, kind: 'HANDLES', from: endpointId, to: handler.id });
67
+ }
68
+ }
69
+ /**
70
+ * Classifies the last argument of a route call. An inline function is a valid
71
+ * handler with no node to point at; a name/member that resolves to an in-project
72
+ * callable is a valid handler whose emitted declaration becomes the `HANDLES`
73
+ * target; anything else means this is not a route.
74
+ */
75
+ static classifyHandler(handler, rootPath) {
76
+ if (Node.isArrowFunction(handler) === true || Node.isFunctionExpression(handler) === true) {
77
+ return { valid: true };
78
+ }
79
+ const declaration = EndpointExtractor.resolveCallable(handler);
80
+ if (declaration === undefined) {
81
+ return { valid: false };
82
+ }
83
+ if (ScopeResolver.isEmitted(declaration) === true) {
84
+ return { valid: true, id: NodeId.forDeclaration(declaration, rootPath) };
85
+ }
86
+ return { valid: true };
87
+ }
88
+ /** Resolves a handler name/member to the in-project function, method, or function-valued variable it refers to. */
89
+ static resolveCallable(node) {
90
+ const declaration = EndpointExtractor.resolve(node);
91
+ if (declaration === undefined || EndpointExtractor.inProject(declaration) === false) {
92
+ return undefined;
93
+ }
94
+ const kind = declaration.getKind();
95
+ if (kind === SyntaxKind.FunctionDeclaration || kind === SyntaxKind.MethodDeclaration) {
96
+ return declaration;
97
+ }
98
+ if (kind === SyntaxKind.VariableDeclaration) {
99
+ const initializer = declaration.asKind(SyntaxKind.VariableDeclaration)?.getInitializer();
100
+ if (initializer !== undefined && (Node.isArrowFunction(initializer) === true || Node.isFunctionExpression(initializer) === true)) {
101
+ return declaration;
102
+ }
103
+ }
104
+ return undefined;
105
+ }
106
+ static resolve(node) {
107
+ const symbol = node.getSymbol();
108
+ const resolved = symbol?.getAliasedSymbol() ?? symbol;
109
+ return resolved?.getDeclarations()[0];
110
+ }
111
+ static inProject(node) {
112
+ const sourceFile = node.getSourceFile();
113
+ return sourceFile.getFilePath().includes('/node_modules/') === false
114
+ && sourceFile.isDeclarationFile() === false;
115
+ }
116
+ }
117
+ //# sourceMappingURL=endpoint_extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint_extractor.js","sourceRoot":"","sources":["../../src/extract/endpoint_extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { SourceManifest } from '../schema/source_manifest.js';
2
+ /**
3
+ * Resolves the Git provenance of an analysed project — its GitHub repository, the
4
+ * commit being parsed, and the project root's path within the repository — so the
5
+ * graph can later link each file to its exact source on GitHub.
6
+ */
7
+ export declare class GitSource {
8
+ /**
9
+ * Detects the GitHub repository, HEAD commit, and in-repo path prefix for `dir`.
10
+ * Returns `undefined` when `dir` is not a Git work tree, has no GitHub `origin`
11
+ * remote, or Git is unavailable.
12
+ */
13
+ static detect(dir: string): Promise<SourceManifest | undefined>;
14
+ /**
15
+ * Normalises a Git `origin` URL to its GitHub web base
16
+ * (`https://<host>/<owner>/<repo>`), or `undefined` for non-GitHub remotes.
17
+ * Handles the SCP-like (`git@host:owner/repo.git`), `https://`, `git://`, and
18
+ * `ssh://` forms, with or without a trailing `.git`. The host is kept as-is so
19
+ * GitHub Enterprise remotes resolve to their own domain.
20
+ */
21
+ static githubBaseUrl(remoteUrl: string): string | undefined;
22
+ }
23
+ //# sourceMappingURL=git_source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git_source.d.ts","sourceRoot":"","sources":["../../src/extract/git_source.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI9D;;;;GAIG;AACH,qBAAa,SAAS;IACrB;;;;OAIG;WACU,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAsBrE;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CA6B3D"}
@@ -0,0 +1,75 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ /**
5
+ * Resolves the Git provenance of an analysed project — its GitHub repository, the
6
+ * commit being parsed, and the project root's path within the repository — so the
7
+ * graph can later link each file to its exact source on GitHub.
8
+ */
9
+ export class GitSource {
10
+ /**
11
+ * Detects the GitHub repository, HEAD commit, and in-repo path prefix for `dir`.
12
+ * Returns `undefined` when `dir` is not a Git work tree, has no GitHub `origin`
13
+ * remote, or Git is unavailable.
14
+ */
15
+ static async detect(dir) {
16
+ const git = async (...args) => {
17
+ try {
18
+ const { stdout } = await execFileAsync('git', ['-C', dir, ...args]);
19
+ return stdout.trim();
20
+ }
21
+ catch {
22
+ return undefined;
23
+ }
24
+ };
25
+ if (await git('rev-parse', '--is-inside-work-tree') !== 'true') {
26
+ return undefined;
27
+ }
28
+ const remoteUrl = await git('remote', 'get-url', 'origin');
29
+ const commit = await git('rev-parse', 'HEAD');
30
+ const baseUrl = remoteUrl === undefined ? undefined : GitSource.githubBaseUrl(remoteUrl);
31
+ if (baseUrl === undefined || commit === undefined) {
32
+ return undefined;
33
+ }
34
+ return { baseUrl, commit, prefix: await git('rev-parse', '--show-prefix') ?? '' };
35
+ }
36
+ /**
37
+ * Normalises a Git `origin` URL to its GitHub web base
38
+ * (`https://<host>/<owner>/<repo>`), or `undefined` for non-GitHub remotes.
39
+ * Handles the SCP-like (`git@host:owner/repo.git`), `https://`, `git://`, and
40
+ * `ssh://` forms, with or without a trailing `.git`. The host is kept as-is so
41
+ * GitHub Enterprise remotes resolve to their own domain.
42
+ */
43
+ static githubBaseUrl(remoteUrl) {
44
+ const trimmed = remoteUrl.trim();
45
+ let host;
46
+ let path;
47
+ if (trimmed.includes('://') === true) {
48
+ try {
49
+ const parsed = new URL(trimmed);
50
+ host = parsed.host;
51
+ path = parsed.pathname;
52
+ }
53
+ catch {
54
+ return undefined;
55
+ }
56
+ }
57
+ else {
58
+ const scpMatch = trimmed.match(/^[^@]+@([^:]+):(.+)$/);
59
+ if (scpMatch === null) {
60
+ return undefined;
61
+ }
62
+ host = scpMatch[1];
63
+ path = scpMatch[2];
64
+ }
65
+ if (host.toLowerCase().includes('github') === false) {
66
+ return undefined;
67
+ }
68
+ const segments = path.replace(/\.git$/, '').split('/').filter((segment) => segment.length > 0);
69
+ if (segments.length < 2) {
70
+ return undefined;
71
+ }
72
+ return `https://${host}/${segments[0]}/${segments[1]}`;
73
+ }
74
+ }
75
+ //# sourceMappingURL=git_source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git_source.js","sourceRoot":"","sources":["../../src/extract/git_source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;;;GAIG;AACH,MAAM,OAAO,SAAS;IACrB;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAW;QAC9B,MAAM,GAAG,GAAG,KAAK,EAAE,GAAG,IAAc,EAA+B,EAAE;YACpE,IAAI,CAAC;gBACJ,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;gBACpE,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;YACtB,CAAC;YAAC,MAAM,CAAC;gBACR,OAAO,SAAS,CAAC;YAClB,CAAC;QACF,CAAC,CAAC;QAEF,IAAI,MAAM,GAAG,CAAC,WAAW,EAAE,uBAAuB,CAAC,KAAK,MAAM,EAAE,CAAC;YAChE,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;QACzF,IAAI,OAAO,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACnD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,WAAW,EAAE,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC;IACnF,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,CAAC,SAAiB;QACrC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QACjC,IAAI,IAAY,CAAC;QACjB,IAAI,IAAY,CAAC;QACjB,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC;gBACJ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;gBAChC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;gBACnB,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACR,OAAO,SAAS,CAAC;YAClB,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;YACvD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACvB,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACnB,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,KAAK,EAAE,CAAC;YACrD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/F,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,OAAO,WAAW,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,CAAC;CACD"}
@@ -11,6 +11,14 @@ export declare class GraphBuilder {
11
11
  getNodes(): GraphNode[];
12
12
  getEdges(): GraphEdge[];
13
13
  private merge;
14
+ /**
15
+ * Adds an edge, collapsing duplicates by id while counting how many times the
16
+ * relationship occurs in source. The first occurrence is stored with
17
+ * `metadata.count = 1`; each later occurrence increments that count instead of
18
+ * overwriting the edge. Any pre-existing metadata (such as the `specifier` on
19
+ * an `IMPORTS` edge) is preserved.
20
+ */
21
+ private addEdge;
14
22
  private static isProjectFile;
15
23
  }
16
24
  //# sourceMappingURL=graph_builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"graph_builder.d.ts","sourceRoot":"","sources":["../../src/extract/graph_builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAI9C,MAAM,MAAM,YAAY,GAAG;IAC1B,QAAQ,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IAEtD,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAetE,QAAQ,IAAI,SAAS,EAAE;IAIvB,QAAQ,IAAI,SAAS,EAAE;IAIvB,OAAO,CAAC,KAAK;IASb,OAAO,CAAC,MAAM,CAAC,aAAa;CAG5B"}
1
+ {"version":3,"file":"graph_builder.d.ts","sourceRoot":"","sources":["../../src/extract/graph_builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAO9C,MAAM,MAAM,YAAY,GAAG;IAC1B,QAAQ,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IAEtD,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAkBtE,QAAQ,IAAI,SAAS,EAAE;IAIvB,QAAQ,IAAI,SAAS,EAAE;IAIvB,OAAO,CAAC,KAAK;IASb;;;;;;OAMG;IACH,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,MAAM,CAAC,aAAa;CAG5B"}
@@ -1,3 +1,6 @@
1
+ import { ApiExtractor } from './api_extractor.js';
2
+ import { ConfigExtractor } from './config_extractor.js';
3
+ import { EndpointExtractor } from './endpoint_extractor.js';
1
4
  import { SemanticExtractor } from './semantic_extractor.js';
2
5
  import { StructuralExtractor } from './structural_extractor.js';
3
6
  export class GraphBuilder {
@@ -11,10 +14,13 @@ export class GraphBuilder {
11
14
  .filter((file) => GraphBuilder.isProjectFile(file.getFilePath()));
12
15
  for (const sourceFile of sourceFiles) {
13
16
  this.merge(StructuralExtractor.extract(sourceFile, rootPath));
17
+ this.merge(ConfigExtractor.extract(sourceFile, rootPath));
18
+ this.merge(ApiExtractor.extract(sourceFile, rootPath));
14
19
  }
15
20
  if (options.semantic === true) {
16
21
  for (const sourceFile of sourceFiles) {
17
22
  this.merge(SemanticExtractor.extract(sourceFile, rootPath));
23
+ this.merge(EndpointExtractor.extract(sourceFile, rootPath));
18
24
  }
19
25
  }
20
26
  }
@@ -29,9 +35,25 @@ export class GraphBuilder {
29
35
  this.nodes.set(node.id, node);
30
36
  }
31
37
  for (const edge of extraction.edges) {
32
- this.edges.set(edge.id, edge);
38
+ this.addEdge(edge);
33
39
  }
34
40
  }
41
+ /**
42
+ * Adds an edge, collapsing duplicates by id while counting how many times the
43
+ * relationship occurs in source. The first occurrence is stored with
44
+ * `metadata.count = 1`; each later occurrence increments that count instead of
45
+ * overwriting the edge. Any pre-existing metadata (such as the `specifier` on
46
+ * an `IMPORTS` edge) is preserved.
47
+ */
48
+ addEdge(edge) {
49
+ const existing = this.edges.get(edge.id);
50
+ if (existing === undefined) {
51
+ this.edges.set(edge.id, { ...edge, metadata: { ...edge.metadata, count: 1 } });
52
+ return;
53
+ }
54
+ const current = typeof existing.metadata?.count === 'number' ? existing.metadata.count : 1;
55
+ existing.metadata = { ...existing.metadata, count: current + 1 };
56
+ }
35
57
  static isProjectFile(filePath) {
36
58
  return filePath.includes('/node_modules/') === false && filePath.endsWith('.d.ts') === false;
37
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"graph_builder.js","sourceRoot":"","sources":["../../src/extract/graph_builder.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAc,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAM5E,MAAM,OAAO,YAAY;IAAzB;QACkB,UAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;QACrC,UAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;IAqCvD,CAAC;IAnCA,KAAK,CAAC,OAAgB,EAAE,QAAgB,EAAE,OAAqB;QAC9D,MAAM,WAAW,GAAG,OAAO;aACzB,cAAc,EAAE;aAChB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAEnE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACtC,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC/B,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACtC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC7D,CAAC;QACF,CAAC;IACF,CAAC;IAED,QAAQ;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,QAAQ;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACjC,CAAC;IAEO,KAAK,CAAC,UAAsB;QACnC,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC/B,CAAC;IACF,CAAC;IAEO,MAAM,CAAC,aAAa,CAAC,QAAgB;QAC5C,OAAO,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,KAAK,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,KAAK,CAAC;IAC9F,CAAC;CACD"}
1
+ {"version":3,"file":"graph_builder.js","sourceRoot":"","sources":["../../src/extract/graph_builder.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,22 @@ export declare class NodeId {
3
3
  static forModule(filePath: string, rootPath: string): string;
4
4
  static forDeclaration(node: Node, rootPath: string): string;
5
5
  static forExternalModule(specifier: string): string;
6
+ /**
7
+ * A graph-wide id for a configuration variable (e.g. `process.env.PORT`), keyed
8
+ * by name so the same variable read across many files collapses to one node.
9
+ */
10
+ static forConfigFlag(name: string): string;
11
+ /**
12
+ * A graph-wide id for an external HTTP target, keyed by host (e.g. the
13
+ * `api.example.com` of a `fetch('https://api.example.com/…')`) so every call to
14
+ * the same service collapses to one node.
15
+ */
16
+ static forExternalApi(host: string): string;
17
+ /**
18
+ * A graph-wide id for an HTTP endpoint, keyed by method and route path (e.g.
19
+ * `Endpoint:GET /users/:id`) so a route registered once is one node.
20
+ */
21
+ static forEndpoint(method: string, path: string): string;
6
22
  static nameOf(node: Node): string;
7
23
  }
8
24
  //# sourceMappingURL=node_id.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node_id.d.ts","sourceRoot":"","sources":["../../src/extract/node_id.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,qBAAa,MAAM;IAClB,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI5D,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK3D,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAInD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;CAQjC"}
1
+ {"version":3,"file":"node_id.d.ts","sourceRoot":"","sources":["../../src/extract/node_id.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,qBAAa,MAAM;IAClB,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI5D,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK3D,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAInD;;;OAGG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI1C;;;;OAIG;IACH,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI3C;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAIxD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;CAQjC"}
@@ -10,6 +10,28 @@ export class NodeId {
10
10
  static forExternalModule(specifier) {
11
11
  return `External:${specifier}`;
12
12
  }
13
+ /**
14
+ * A graph-wide id for a configuration variable (e.g. `process.env.PORT`), keyed
15
+ * by name so the same variable read across many files collapses to one node.
16
+ */
17
+ static forConfigFlag(name) {
18
+ return `Config:${name}`;
19
+ }
20
+ /**
21
+ * A graph-wide id for an external HTTP target, keyed by host (e.g. the
22
+ * `api.example.com` of a `fetch('https://api.example.com/…')`) so every call to
23
+ * the same service collapses to one node.
24
+ */
25
+ static forExternalApi(host) {
26
+ return `Api:${host}`;
27
+ }
28
+ /**
29
+ * A graph-wide id for an HTTP endpoint, keyed by method and route path (e.g.
30
+ * `Endpoint:GET /users/:id`) so a route registered once is one node.
31
+ */
32
+ static forEndpoint(method, path) {
33
+ return `Endpoint:${method} ${path}`;
34
+ }
13
35
  static nameOf(node) {
14
36
  const probe = node;
15
37
  if (typeof probe.getName !== 'function') {
@@ -1 +1 @@
1
- {"version":3,"file":"node_id.js","sourceRoot":"","sources":["../../src/extract/node_id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrC,MAAM,OAAO,MAAM;IAClB,MAAM,CAAC,SAAS,CAAC,QAAgB,EAAE,QAAgB;QAClD,OAAO,UAAU,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,IAAU,EAAE,QAAgB;QACjD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QACxE,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;IAChG,CAAC;IAED,MAAM,CAAC,iBAAiB,CAAC,SAAiB;QACzC,OAAO,YAAY,SAAS,EAAE,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,IAAU;QACvB,MAAM,KAAK,GAAG,IAA8C,CAAC;QAC7D,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;YACzC,OAAO,WAAW,CAAC;QACpB,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;QAC7B,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,CAAC;CACD"}
1
+ {"version":3,"file":"node_id.js","sourceRoot":"","sources":["../../src/extract/node_id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrC,MAAM,OAAO,MAAM;IAClB,MAAM,CAAC,SAAS,CAAC,QAAgB,EAAE,QAAgB;QAClD,OAAO,UAAU,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,IAAU,EAAE,QAAgB;QACjD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;QACxE,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;IAChG,CAAC;IAED,MAAM,CAAC,iBAAiB,CAAC,SAAiB;QACzC,OAAO,YAAY,SAAS,EAAE,CAAC;IAChC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,aAAa,CAAC,IAAY;QAChC,OAAO,UAAU,IAAI,EAAE,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,cAAc,CAAC,IAAY;QACjC,OAAO,OAAO,IAAI,EAAE,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,WAAW,CAAC,MAAc,EAAE,IAAY;QAC9C,OAAO,YAAY,MAAM,IAAI,IAAI,EAAE,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,IAAU;QACvB,MAAM,KAAK,GAAG,IAA8C,CAAC;QAC7D,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;YACzC,OAAO,WAAW,CAAC;QACpB,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;QAC7B,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,CAAC;CACD"}
@@ -0,0 +1,22 @@
1
+ import { Node } from 'ts-morph';
2
+ /**
3
+ * Resolves the graph node a free-standing expression (a `process.env` read, a
4
+ * `fetch` call) should be attributed to: the id of the nearest enclosing
5
+ * declaration the structural extractor actually emits, falling back to the module.
6
+ *
7
+ * Because a node nested inside a function (a local, a nested function, an arrow) is
8
+ * not itself a graph node, the walk skips past it to the enclosing top-level
9
+ * function/variable/class or class member — so the returned id always exists in the
10
+ * graph and the edge built from it is never dropped at load.
11
+ */
12
+ export declare class ScopeResolver {
13
+ static enclosingId(node: Node, moduleId: string, rootPath: string): string;
14
+ /**
15
+ * Whether the structural extractor emits this declaration as a graph node — a
16
+ * class/interface member, or a top-level function/variable/class/etc. Used both
17
+ * to find an enclosing scope and to check that a resolved handler is a real node
18
+ * before pointing an edge at it.
19
+ */
20
+ static isEmitted(node: Node): boolean;
21
+ }
22
+ //# sourceMappingURL=scope_resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope_resolver.d.ts","sourceRoot":"","sources":["../../src/extract/scope_resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAc,MAAM,UAAU,CAAC;AAkB5C;;;;;;;;;GASG;AACH,qBAAa,aAAa;IACzB,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK1E;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO;CAcrC"}
@@ -0,0 +1,53 @@
1
+ import { SyntaxKind } from 'ts-morph';
2
+ import { NodeId } from './node_id.js';
3
+ /**
4
+ * Top-level declaration kinds the structural extractor emits as nodes. Used to
5
+ * attribute a free-standing expression to an *emitted* scope: a node nested inside
6
+ * a function (a local, a nested function) is not a graph node, so the walk skips
7
+ * past it to the nearest enclosing emitted declaration.
8
+ */
9
+ const TOP_LEVEL_SCOPE_KINDS = new Set([
10
+ SyntaxKind.FunctionDeclaration,
11
+ SyntaxKind.VariableDeclaration,
12
+ SyntaxKind.ClassDeclaration,
13
+ SyntaxKind.InterfaceDeclaration,
14
+ SyntaxKind.EnumDeclaration,
15
+ SyntaxKind.TypeAliasDeclaration,
16
+ ]);
17
+ /**
18
+ * Resolves the graph node a free-standing expression (a `process.env` read, a
19
+ * `fetch` call) should be attributed to: the id of the nearest enclosing
20
+ * declaration the structural extractor actually emits, falling back to the module.
21
+ *
22
+ * Because a node nested inside a function (a local, a nested function, an arrow) is
23
+ * not itself a graph node, the walk skips past it to the enclosing top-level
24
+ * function/variable/class or class member — so the returned id always exists in the
25
+ * graph and the edge built from it is never dropped at load.
26
+ */
27
+ export class ScopeResolver {
28
+ static enclosingId(node, moduleId, rootPath) {
29
+ const scope = node.getFirstAncestor((ancestor) => ScopeResolver.isEmitted(ancestor));
30
+ return scope === undefined ? moduleId : NodeId.forDeclaration(scope, rootPath);
31
+ }
32
+ /**
33
+ * Whether the structural extractor emits this declaration as a graph node — a
34
+ * class/interface member, or a top-level function/variable/class/etc. Used both
35
+ * to find an enclosing scope and to check that a resolved handler is a real node
36
+ * before pointing an edge at it.
37
+ */
38
+ static isEmitted(node) {
39
+ const kind = node.getKind();
40
+ if (kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.PropertyDeclaration) {
41
+ return true;
42
+ }
43
+ if (TOP_LEVEL_SCOPE_KINDS.has(kind) === false) {
44
+ return false;
45
+ }
46
+ if (kind === SyntaxKind.VariableDeclaration) {
47
+ const statement = node.asKind(SyntaxKind.VariableDeclaration)?.getVariableStatement();
48
+ return statement?.getParent()?.getKind() === SyntaxKind.SourceFile;
49
+ }
50
+ return node.getParent()?.getKind() === SyntaxKind.SourceFile;
51
+ }
52
+ }
53
+ //# sourceMappingURL=scope_resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope_resolver.js","sourceRoot":"","sources":["../../src/extract/scope_resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAa;IACjD,UAAU,CAAC,mBAAmB;IAC9B,UAAU,CAAC,mBAAmB;IAC9B,UAAU,CAAC,gBAAgB;IAC3B,UAAU,CAAC,oBAAoB;IAC/B,UAAU,CAAC,eAAe;IAC1B,UAAU,CAAC,oBAAoB;CAC/B,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,OAAO,aAAa;IACzB,MAAM,CAAC,WAAW,CAAC,IAAU,EAAE,QAAgB,EAAE,QAAgB;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrF,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChF,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,IAAU;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,IAAI,IAAI,KAAK,UAAU,CAAC,iBAAiB,IAAI,IAAI,KAAK,UAAU,CAAC,mBAAmB,EAAE,CAAC;YACtF,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC;YAC/C,OAAO,KAAK,CAAC;QACd,CAAC;QACD,IAAI,IAAI,KAAK,UAAU,CAAC,mBAAmB,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,EAAE,CAAC;YACtF,OAAO,SAAS,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,UAAU,CAAC,UAAU,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,UAAU,CAAC,UAAU,CAAC;IAC9D,CAAC;CACD"}
@@ -3,6 +3,14 @@ import { Extraction } from './structural_extractor.js';
3
3
  export declare class SemanticExtractor {
4
4
  static extract(sourceFile: SourceFile, rootPath: string): Extraction;
5
5
  private static extractClass;
6
+ /**
7
+ * Emit an `OVERRIDES` edge from a class method to the member it overrides:
8
+ * the nearest base-class method of the same name, and any implemented
9
+ * interface method of the same name. The target id is computed with
10
+ * {@link NodeId.forDeclaration} on the resolved declaration, so it matches
11
+ * the node the structural extractor already emitted for that member.
12
+ */
13
+ private static extractOverrides;
6
14
  private static extractInterface;
7
15
  private static extractSignature;
8
16
  private static addTypeEdges;
@@ -10,7 +18,24 @@ export declare class SemanticExtractor {
10
18
  private static extractCalls;
11
19
  private static extractInstantiations;
12
20
  private static extractReads;
21
+ private static extractWrites;
22
+ /**
23
+ * Emits a value-access edge from the enclosing scope to each in-project,
24
+ * module-level value declaration an identifier touches. `accesses` selects the
25
+ * identifiers (a read or a write) and `kind` is the edge emitted; the rest — the
26
+ * target must be an emitted top-level value declaration, a declaration's own name
27
+ * is skipped, self-edges are dropped — is shared by both. Repeated accesses
28
+ * collapse into one counted edge in {@link GraphBuilder}.
29
+ */
30
+ private static extractValueAccess;
13
31
  private static isValueRead;
32
+ /**
33
+ * Whether an identifier is written: the left-hand side of an assignment
34
+ * (`x = …`, `x += …`) or the operand of a `++`/`--`. A compound assignment and an
35
+ * increment also read the old value, so {@link isValueRead} reports those
36
+ * identifiers too; a plain `x = …` is a write only.
37
+ */
38
+ private static isValueWrite;
14
39
  private static isDeclarationName;
15
40
  private static isEmittedTarget;
16
41
  private static readerScope;
@@ -1 +1 @@
1
- {"version":3,"file":"semantic_extractor.d.ts","sourceRoot":"","sources":["../../src/extract/semantic_extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAON,UAAU,EAGV,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAqCvD,qBAAa,iBAAiB;IAC7B,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU;IAuBpE,OAAO,CAAC,MAAM,CAAC,YAAY;IAoB3B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAe/B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAQ/B,OAAO,CAAC,MAAM,CAAC,YAAY;IAkB3B,OAAO,CAAC,MAAM,CAAC,eAAe;IAkB9B,OAAO,CAAC,MAAM,CAAC,YAAY;IAqB3B,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAqBpC,OAAO,CAAC,MAAM,CAAC,YAAY;IA2B3B,OAAO,CAAC,MAAM,CAAC,WAAW;IA6B1B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAKhC,OAAO,CAAC,MAAM,CAAC,eAAe;IAQ9B,OAAO,CAAC,MAAM,CAAC,WAAW;IAW1B,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAOnC,OAAO,CAAC,MAAM,CAAC,OAAO;IAUtB,OAAO,CAAC,MAAM,CAAC,SAAS;IAMxB,OAAO,CAAC,MAAM,CAAC,IAAI;CAGnB"}
1
+ {"version":3,"file":"semantic_extractor.d.ts","sourceRoot":"","sources":["../../src/extract/semantic_extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAON,UAAU,EAGV,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAyDvD,qBAAa,iBAAiB;IAC7B,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU;IAwBpE,OAAO,CAAC,MAAM,CAAC,YAAY;IAqB3B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAkC/B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAe/B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAQ/B,OAAO,CAAC,MAAM,CAAC,YAAY;IAkB3B,OAAO,CAAC,MAAM,CAAC,eAAe;IAkB9B,OAAO,CAAC,MAAM,CAAC,YAAY;IAqB3B,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAqBpC,OAAO,CAAC,MAAM,CAAC,YAAY;IAI3B,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAiCjC,OAAO,CAAC,MAAM,CAAC,WAAW;IAiC1B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAiB3B,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAKhC,OAAO,CAAC,MAAM,CAAC,eAAe;IAQ9B,OAAO,CAAC,MAAM,CAAC,WAAW;IAW1B,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAOnC,OAAO,CAAC,MAAM,CAAC,OAAO;IAUtB,OAAO,CAAC,MAAM,CAAC,SAAS;IAMxB,OAAO,CAAC,MAAM,CAAC,IAAI;CAGnB"}