@opensip-cli/dashboard 0.1.0

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 (309) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/__tests__/catalog-provenance.test.d.ts +11 -0
  5. package/dist/__tests__/catalog-provenance.test.d.ts.map +1 -0
  6. package/dist/__tests__/catalog-provenance.test.js +130 -0
  7. package/dist/__tests__/catalog-provenance.test.js.map +1 -0
  8. package/dist/__tests__/coupling-attribution.test.d.ts +9 -0
  9. package/dist/__tests__/coupling-attribution.test.d.ts.map +1 -0
  10. package/dist/__tests__/coupling-attribution.test.js +99 -0
  11. package/dist/__tests__/coupling-attribution.test.js.map +1 -0
  12. package/dist/__tests__/dashboard-bundle-weight.test.d.ts +16 -0
  13. package/dist/__tests__/dashboard-bundle-weight.test.d.ts.map +1 -0
  14. package/dist/__tests__/dashboard-bundle-weight.test.js +73 -0
  15. package/dist/__tests__/dashboard-bundle-weight.test.js.map +1 -0
  16. package/dist/__tests__/dashboard-cell-containment.test.d.ts +2 -0
  17. package/dist/__tests__/dashboard-cell-containment.test.d.ts.map +1 -0
  18. package/dist/__tests__/dashboard-cell-containment.test.js +49 -0
  19. package/dist/__tests__/dashboard-cell-containment.test.js.map +1 -0
  20. package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts +10 -0
  21. package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts.map +1 -0
  22. package/dist/__tests__/dashboard-cytoscape-vendor.test.js +40 -0
  23. package/dist/__tests__/dashboard-cytoscape-vendor.test.js.map +1 -0
  24. package/dist/__tests__/dashboard-editor-link.test.d.ts +5 -0
  25. package/dist/__tests__/dashboard-editor-link.test.d.ts.map +1 -0
  26. package/dist/__tests__/dashboard-editor-link.test.js +36 -0
  27. package/dist/__tests__/dashboard-editor-link.test.js.map +1 -0
  28. package/dist/__tests__/dashboard-filters.test.d.ts +9 -0
  29. package/dist/__tests__/dashboard-filters.test.d.ts.map +1 -0
  30. package/dist/__tests__/dashboard-filters.test.js +95 -0
  31. package/dist/__tests__/dashboard-filters.test.js.map +1 -0
  32. package/dist/__tests__/dashboard-function-card-singleton.test.d.ts +9 -0
  33. package/dist/__tests__/dashboard-function-card-singleton.test.d.ts.map +1 -0
  34. package/dist/__tests__/dashboard-function-card-singleton.test.js +87 -0
  35. package/dist/__tests__/dashboard-function-card-singleton.test.js.map +1 -0
  36. package/dist/__tests__/dashboard-function-card.test.d.ts +10 -0
  37. package/dist/__tests__/dashboard-function-card.test.d.ts.map +1 -0
  38. package/dist/__tests__/dashboard-function-card.test.js +403 -0
  39. package/dist/__tests__/dashboard-function-card.test.js.map +1 -0
  40. package/dist/__tests__/dashboard-function-row.test.d.ts +11 -0
  41. package/dist/__tests__/dashboard-function-row.test.d.ts.map +1 -0
  42. package/dist/__tests__/dashboard-function-row.test.js +101 -0
  43. package/dist/__tests__/dashboard-function-row.test.js.map +1 -0
  44. package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts +9 -0
  45. package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts.map +1 -0
  46. package/dist/__tests__/dashboard-generator-graph-catalog.test.js +75 -0
  47. package/dist/__tests__/dashboard-generator-graph-catalog.test.js.map +1 -0
  48. package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts +13 -0
  49. package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts.map +1 -0
  50. package/dist/__tests__/dashboard-graph-offline.integration.test.js +55 -0
  51. package/dist/__tests__/dashboard-graph-offline.integration.test.js.map +1 -0
  52. package/dist/__tests__/dashboard-graph-scc.test.d.ts +17 -0
  53. package/dist/__tests__/dashboard-graph-scc.test.d.ts.map +1 -0
  54. package/dist/__tests__/dashboard-graph-scc.test.js +89 -0
  55. package/dist/__tests__/dashboard-graph-scc.test.js.map +1 -0
  56. package/dist/__tests__/dashboard-graph-view-model.test.d.ts +12 -0
  57. package/dist/__tests__/dashboard-graph-view-model.test.d.ts.map +1 -0
  58. package/dist/__tests__/dashboard-graph-view-model.test.js +331 -0
  59. package/dist/__tests__/dashboard-graph-view-model.test.js.map +1 -0
  60. package/dist/__tests__/dashboard-help-drawer.test.d.ts +9 -0
  61. package/dist/__tests__/dashboard-help-drawer.test.d.ts.map +1 -0
  62. package/dist/__tests__/dashboard-help-drawer.test.js +101 -0
  63. package/dist/__tests__/dashboard-help-drawer.test.js.map +1 -0
  64. package/dist/__tests__/dashboard-html.test.d.ts +2 -0
  65. package/dist/__tests__/dashboard-html.test.d.ts.map +1 -0
  66. package/dist/__tests__/dashboard-html.test.js +169 -0
  67. package/dist/__tests__/dashboard-html.test.js.map +1 -0
  68. package/dist/__tests__/dashboard-indexes.test.d.ts +9 -0
  69. package/dist/__tests__/dashboard-indexes.test.d.ts.map +1 -0
  70. package/dist/__tests__/dashboard-indexes.test.js +211 -0
  71. package/dist/__tests__/dashboard-indexes.test.js.map +1 -0
  72. package/dist/__tests__/dashboard-path-utils.test.d.ts +6 -0
  73. package/dist/__tests__/dashboard-path-utils.test.d.ts.map +1 -0
  74. package/dist/__tests__/dashboard-path-utils.test.js +54 -0
  75. package/dist/__tests__/dashboard-path-utils.test.js.map +1 -0
  76. package/dist/__tests__/dashboard-search.test.d.ts +5 -0
  77. package/dist/__tests__/dashboard-search.test.d.ts.map +1 -0
  78. package/dist/__tests__/dashboard-search.test.js +46 -0
  79. package/dist/__tests__/dashboard-search.test.js.map +1 -0
  80. package/dist/__tests__/dashboard-sessions.test.d.ts +14 -0
  81. package/dist/__tests__/dashboard-sessions.test.d.ts.map +1 -0
  82. package/dist/__tests__/dashboard-sessions.test.js +330 -0
  83. package/dist/__tests__/dashboard-sessions.test.js.map +1 -0
  84. package/dist/__tests__/dashboard-trace.test.d.ts +5 -0
  85. package/dist/__tests__/dashboard-trace.test.d.ts.map +1 -0
  86. package/dist/__tests__/dashboard-trace.test.js +147 -0
  87. package/dist/__tests__/dashboard-trace.test.js.map +1 -0
  88. package/dist/__tests__/dashboard-validation.integration.test.d.ts +14 -0
  89. package/dist/__tests__/dashboard-validation.integration.test.d.ts.map +1 -0
  90. package/dist/__tests__/dashboard-validation.integration.test.js +221 -0
  91. package/dist/__tests__/dashboard-validation.integration.test.js.map +1 -0
  92. package/dist/__tests__/dashboard-view-conformance.test.d.ts +12 -0
  93. package/dist/__tests__/dashboard-view-conformance.test.d.ts.map +1 -0
  94. package/dist/__tests__/dashboard-view-conformance.test.js +58 -0
  95. package/dist/__tests__/dashboard-view-conformance.test.js.map +1 -0
  96. package/dist/__tests__/dashboard-view-coupling.test.d.ts +7 -0
  97. package/dist/__tests__/dashboard-view-coupling.test.d.ts.map +1 -0
  98. package/dist/__tests__/dashboard-view-coupling.test.js +381 -0
  99. package/dist/__tests__/dashboard-view-coupling.test.js.map +1 -0
  100. package/dist/__tests__/dashboard-view-distribution.test.d.ts +10 -0
  101. package/dist/__tests__/dashboard-view-distribution.test.d.ts.map +1 -0
  102. package/dist/__tests__/dashboard-view-distribution.test.js +272 -0
  103. package/dist/__tests__/dashboard-view-distribution.test.js.map +1 -0
  104. package/dist/__tests__/dashboard-view-graph.test.d.ts +13 -0
  105. package/dist/__tests__/dashboard-view-graph.test.d.ts.map +1 -0
  106. package/dist/__tests__/dashboard-view-graph.test.js +332 -0
  107. package/dist/__tests__/dashboard-view-graph.test.js.map +1 -0
  108. package/dist/__tests__/dashboard-view-template.test.d.ts +21 -0
  109. package/dist/__tests__/dashboard-view-template.test.d.ts.map +1 -0
  110. package/dist/__tests__/dashboard-view-template.test.js +153 -0
  111. package/dist/__tests__/dashboard-view-template.test.js.map +1 -0
  112. package/dist/__tests__/dashboard.test.d.ts +2 -0
  113. package/dist/__tests__/dashboard.test.d.ts.map +1 -0
  114. package/dist/__tests__/dashboard.test.js +129 -0
  115. package/dist/__tests__/dashboard.test.js.map +1 -0
  116. package/dist/__tests__/graph-tab.test.d.ts +10 -0
  117. package/dist/__tests__/graph-tab.test.d.ts.map +1 -0
  118. package/dist/__tests__/graph-tab.test.js +76 -0
  119. package/dist/__tests__/graph-tab.test.js.map +1 -0
  120. package/dist/checks.d.ts +7 -0
  121. package/dist/checks.d.ts.map +1 -0
  122. package/dist/checks.js +283 -0
  123. package/dist/checks.js.map +1 -0
  124. package/dist/code-paths/__tests__/views-registry.test.d.ts +13 -0
  125. package/dist/code-paths/__tests__/views-registry.test.d.ts.map +1 -0
  126. package/dist/code-paths/__tests__/views-registry.test.js +39 -0
  127. package/dist/code-paths/__tests__/views-registry.test.js.map +1 -0
  128. package/dist/code-paths/catalog-provenance.d.ts +22 -0
  129. package/dist/code-paths/catalog-provenance.d.ts.map +1 -0
  130. package/dist/code-paths/catalog-provenance.js +108 -0
  131. package/dist/code-paths/catalog-provenance.js.map +1 -0
  132. package/dist/code-paths/catalog-recipes-tables.d.ts +11 -0
  133. package/dist/code-paths/catalog-recipes-tables.d.ts.map +1 -0
  134. package/dist/code-paths/catalog-recipes-tables.js +86 -0
  135. package/dist/code-paths/catalog-recipes-tables.js.map +1 -0
  136. package/dist/code-paths/cytoscape-vendor.d.ts +27 -0
  137. package/dist/code-paths/cytoscape-vendor.d.ts.map +1 -0
  138. package/dist/code-paths/cytoscape-vendor.js +68 -0
  139. package/dist/code-paths/cytoscape-vendor.js.map +1 -0
  140. package/dist/code-paths/editor-link.d.ts +10 -0
  141. package/dist/code-paths/editor-link.d.ts.map +1 -0
  142. package/dist/code-paths/editor-link.js +20 -0
  143. package/dist/code-paths/editor-link.js.map +1 -0
  144. package/dist/code-paths/filters.d.ts +19 -0
  145. package/dist/code-paths/filters.d.ts.map +1 -0
  146. package/dist/code-paths/filters.js +47 -0
  147. package/dist/code-paths/filters.js.map +1 -0
  148. package/dist/code-paths/function-card.d.ts +15 -0
  149. package/dist/code-paths/function-card.d.ts.map +1 -0
  150. package/dist/code-paths/function-card.js +169 -0
  151. package/dist/code-paths/function-card.js.map +1 -0
  152. package/dist/code-paths/function-row.d.ts +17 -0
  153. package/dist/code-paths/function-row.d.ts.map +1 -0
  154. package/dist/code-paths/function-row.js +77 -0
  155. package/dist/code-paths/function-row.js.map +1 -0
  156. package/dist/code-paths/graph-controls.d.ts +27 -0
  157. package/dist/code-paths/graph-controls.d.ts.map +1 -0
  158. package/dist/code-paths/graph-controls.js +257 -0
  159. package/dist/code-paths/graph-controls.js.map +1 -0
  160. package/dist/code-paths/graph-scc.d.ts +32 -0
  161. package/dist/code-paths/graph-scc.d.ts.map +1 -0
  162. package/dist/code-paths/graph-scc.js +136 -0
  163. package/dist/code-paths/graph-scc.js.map +1 -0
  164. package/dist/code-paths/graph-stylesheet.d.ts +22 -0
  165. package/dist/code-paths/graph-stylesheet.d.ts.map +1 -0
  166. package/dist/code-paths/graph-stylesheet.js +121 -0
  167. package/dist/code-paths/graph-stylesheet.js.map +1 -0
  168. package/dist/code-paths/graph-view-model.d.ts +120 -0
  169. package/dist/code-paths/graph-view-model.d.ts.map +1 -0
  170. package/dist/code-paths/graph-view-model.js +199 -0
  171. package/dist/code-paths/graph-view-model.js.map +1 -0
  172. package/dist/code-paths/help-drawer.d.ts +18 -0
  173. package/dist/code-paths/help-drawer.d.ts.map +1 -0
  174. package/dist/code-paths/help-drawer.js +54 -0
  175. package/dist/code-paths/help-drawer.js.map +1 -0
  176. package/dist/code-paths/indexes.d.ts +28 -0
  177. package/dist/code-paths/indexes.d.ts.map +1 -0
  178. package/dist/code-paths/indexes.js +97 -0
  179. package/dist/code-paths/indexes.js.map +1 -0
  180. package/dist/code-paths/path-utils.d.ts +15 -0
  181. package/dist/code-paths/path-utils.d.ts.map +1 -0
  182. package/dist/code-paths/path-utils.js +47 -0
  183. package/dist/code-paths/path-utils.js.map +1 -0
  184. package/dist/code-paths/search.d.ts +14 -0
  185. package/dist/code-paths/search.d.ts.map +1 -0
  186. package/dist/code-paths/search.js +54 -0
  187. package/dist/code-paths/search.js.map +1 -0
  188. package/dist/code-paths/trace.d.ts +11 -0
  189. package/dist/code-paths/trace.d.ts.map +1 -0
  190. package/dist/code-paths/trace.js +60 -0
  191. package/dist/code-paths/trace.js.map +1 -0
  192. package/dist/code-paths/view-coupling.d.ts +22 -0
  193. package/dist/code-paths/view-coupling.d.ts.map +1 -0
  194. package/dist/code-paths/view-coupling.js +218 -0
  195. package/dist/code-paths/view-coupling.js.map +1 -0
  196. package/dist/code-paths/view-distribution.d.ts +20 -0
  197. package/dist/code-paths/view-distribution.d.ts.map +1 -0
  198. package/dist/code-paths/view-distribution.js +82 -0
  199. package/dist/code-paths/view-distribution.js.map +1 -0
  200. package/dist/code-paths/view-graph.d.ts +35 -0
  201. package/dist/code-paths/view-graph.d.ts.map +1 -0
  202. package/dist/code-paths/view-graph.js +379 -0
  203. package/dist/code-paths/view-graph.js.map +1 -0
  204. package/dist/code-paths/view-template.d.ts +154 -0
  205. package/dist/code-paths/view-template.d.ts.map +1 -0
  206. package/dist/code-paths/view-template.js +218 -0
  207. package/dist/code-paths/view-template.js.map +1 -0
  208. package/dist/code-paths/views-registry.d.ts +13 -0
  209. package/dist/code-paths/views-registry.d.ts.map +1 -0
  210. package/dist/code-paths/views-registry.js +53 -0
  211. package/dist/code-paths/views-registry.js.map +1 -0
  212. package/dist/code-paths.d.ts +69 -0
  213. package/dist/code-paths.d.ts.map +1 -0
  214. package/dist/code-paths.js +356 -0
  215. package/dist/code-paths.js.map +1 -0
  216. package/dist/css/cards.d.ts +9 -0
  217. package/dist/css/cards.d.ts.map +1 -0
  218. package/dist/css/cards.js +36 -0
  219. package/dist/css/cards.js.map +1 -0
  220. package/dist/css/code-paths.d.ts +9 -0
  221. package/dist/css/code-paths.d.ts.map +1 -0
  222. package/dist/css/code-paths.js +111 -0
  223. package/dist/css/code-paths.js.map +1 -0
  224. package/dist/css/data-table.d.ts +12 -0
  225. package/dist/css/data-table.d.ts.map +1 -0
  226. package/dist/css/data-table.js +103 -0
  227. package/dist/css/data-table.js.map +1 -0
  228. package/dist/css/function-card.d.ts +6 -0
  229. package/dist/css/function-card.d.ts.map +1 -0
  230. package/dist/css/function-card.js +26 -0
  231. package/dist/css/function-card.js.map +1 -0
  232. package/dist/css/help-drawer.d.ts +6 -0
  233. package/dist/css/help-drawer.d.ts.map +1 -0
  234. package/dist/css/help-drawer.js +22 -0
  235. package/dist/css/help-drawer.js.map +1 -0
  236. package/dist/css/tabs.d.ts +9 -0
  237. package/dist/css/tabs.d.ts.map +1 -0
  238. package/dist/css/tabs.js +28 -0
  239. package/dist/css/tabs.js.map +1 -0
  240. package/dist/css/theme.d.ts +8 -0
  241. package/dist/css/theme.d.ts.map +1 -0
  242. package/dist/css/theme.js +34 -0
  243. package/dist/css/theme.js.map +1 -0
  244. package/dist/css.d.ts +13 -0
  245. package/dist/css.d.ts.map +1 -0
  246. package/dist/css.js +30 -0
  247. package/dist/css.js.map +1 -0
  248. package/dist/generator.d.ts +33 -0
  249. package/dist/generator.d.ts.map +1 -0
  250. package/dist/generator.js +161 -0
  251. package/dist/generator.js.map +1 -0
  252. package/dist/index.d.ts +21 -0
  253. package/dist/index.d.ts.map +1 -0
  254. package/dist/index.js +20 -0
  255. package/dist/index.js.map +1 -0
  256. package/dist/overview.d.ts +13 -0
  257. package/dist/overview.d.ts.map +1 -0
  258. package/dist/overview.js +91 -0
  259. package/dist/overview.js.map +1 -0
  260. package/dist/recipes.d.ts +6 -0
  261. package/dist/recipes.d.ts.map +1 -0
  262. package/dist/recipes.js +68 -0
  263. package/dist/recipes.js.map +1 -0
  264. package/dist/sessions.d.ts +6 -0
  265. package/dist/sessions.d.ts.map +1 -0
  266. package/dist/sessions.js +288 -0
  267. package/dist/sessions.js.map +1 -0
  268. package/dist/shared/el.d.ts +13 -0
  269. package/dist/shared/el.d.ts.map +1 -0
  270. package/dist/shared/el.js +27 -0
  271. package/dist/shared/el.js.map +1 -0
  272. package/dist/shared/pagination.d.ts +15 -0
  273. package/dist/shared/pagination.d.ts.map +1 -0
  274. package/dist/shared/pagination.js +113 -0
  275. package/dist/shared/pagination.js.map +1 -0
  276. package/dist/shared/sortable.d.ts +14 -0
  277. package/dist/shared/sortable.d.ts.map +1 -0
  278. package/dist/shared/sortable.js +101 -0
  279. package/dist/shared/sortable.js.map +1 -0
  280. package/dist/shared/tab-activators.d.ts +16 -0
  281. package/dist/shared/tab-activators.d.ts.map +1 -0
  282. package/dist/shared/tab-activators.js +33 -0
  283. package/dist/shared/tab-activators.js.map +1 -0
  284. package/dist/shared/tab-bar.d.ts +8 -0
  285. package/dist/shared/tab-bar.d.ts.map +1 -0
  286. package/dist/shared/tab-bar.js +20 -0
  287. package/dist/shared/tab-bar.js.map +1 -0
  288. package/dist/shared.d.ts +26 -0
  289. package/dist/shared.d.ts.map +1 -0
  290. package/dist/shared.js +39 -0
  291. package/dist/shared.js.map +1 -0
  292. package/dist/subtab-bar.d.ts +23 -0
  293. package/dist/subtab-bar.d.ts.map +1 -0
  294. package/dist/subtab-bar.js +77 -0
  295. package/dist/subtab-bar.js.map +1 -0
  296. package/dist/tool-tab-registry.d.ts +76 -0
  297. package/dist/tool-tab-registry.d.ts.map +1 -0
  298. package/dist/tool-tab-registry.js +44 -0
  299. package/dist/tool-tab-registry.js.map +1 -0
  300. package/dist/tool-tabs-registrations.d.ts +19 -0
  301. package/dist/tool-tabs-registrations.d.ts.map +1 -0
  302. package/dist/tool-tabs-registrations.js +46 -0
  303. package/dist/tool-tabs-registrations.js.map +1 -0
  304. package/dist/tool-tabs.d.ts +12 -0
  305. package/dist/tool-tabs.d.ts.map +1 -0
  306. package/dist/tool-tabs.js +80 -0
  307. package/dist/tool-tabs.js.map +1 -0
  308. package/dist/vendor/cytoscape-bundle.js +600 -0
  309. package/package.json +52 -0
@@ -0,0 +1,120 @@
1
+ /**
2
+ * View-model projection for the Code Graph "Visualization" view.
3
+ *
4
+ * Projects the raw graph `GraphCatalog` (consumed by JSON shape from
5
+ * `@opensip-cli/contracts` — never from `@opensip-cli/graph`) into
6
+ * the slim, embed-ready `GraphViewModel` the Cytoscape renderer consumes.
7
+ *
8
+ * PACKAGE-LEVEL projection (item 10): the visualization renders a
9
+ * node-link graph at *package* granularity, NOT function granularity.
10
+ * Function-level catalogs on real repos contain thousands of function
11
+ * nodes — unusable in a node-link layout. This projector aggregates the
12
+ * function call graph up to packages:
13
+ *
14
+ * - Node = one package (id = label = package name via the same
15
+ * attribution the Coupling view uses — see `packageOf` below, which
16
+ * mirrors `pkgOf` in `path-utils.ts`).
17
+ * - Edge = caller-package → callee-package, with `weight` = the number
18
+ * of underlying function→function call edges between those packages.
19
+ *
20
+ * This is intentionally the same package→package data the Coupling grid
21
+ * shows — a node-link rendering of it rather than a matrix. Every OTHER
22
+ * consumer (Coupling drilldown, Functions table, rules, …) still reads
23
+ * the function-level catalog directly; only THIS view aggregates up.
24
+ *
25
+ * This module is the bundle-size budget enforcement point: the report
26
+ * ships what this projector emits, not the catalog's storage shape.
27
+ *
28
+ * Architecture decisions:
29
+ * - Projection runs at report-generation time (server-side, in
30
+ * `generator.ts`) and the result is embedded as a JSON blob, mirroring
31
+ * the existing `graph-catalog` blob.
32
+ * - Cross-package cycles are detected with Tarjan's SCC over the package
33
+ * graph (cheap at package granularity — tens of nodes, not thousands).
34
+ * The engine's SCC implementation is off-limits to this package (the
35
+ * catalog-decoupling rule §2.4); the local replica lives in the sibling
36
+ * `graph-scc.ts` module.
37
+ */
38
+ import type { GraphCatalog, GraphFunctionOccurrence } from '@opensip-cli/contracts';
39
+ /**
40
+ * Slim, embed-ready projection of a graph catalog for the dashboard's
41
+ * Visualization view. Produced by {@link projectCatalogToGraphViewModel}
42
+ * and consumed by `view-graph.ts`.
43
+ *
44
+ * Aggregated to PACKAGE granularity — one node per package, one edge per
45
+ * directed package→package coupling.
46
+ */
47
+ export interface GraphViewModel {
48
+ /**
49
+ * Catalog-level language (e.g. `'typescript'`). Copied here so the view
50
+ * doesn't need a separate handle on `graphCatalog`. The catalog is
51
+ * single-language; this is NOT a per-node filter.
52
+ */
53
+ readonly language: string;
54
+ readonly nodes: readonly GraphViewModelNode[];
55
+ readonly edges: readonly GraphViewModelEdge[];
56
+ }
57
+ export interface GraphViewModelNode {
58
+ /** Stable handle AND display label — the package name. */
59
+ readonly id: string;
60
+ /** Display label — the package name (same as {@link id}). */
61
+ readonly label: string;
62
+ /**
63
+ * Total coupling degree = fan-in + fan-out call count (sum of incident
64
+ * edge weights). Drives node *size* — hub packages render larger.
65
+ * Pre-computed here so the renderer can size without re-iterating edges.
66
+ */
67
+ readonly totalCoupling: number;
68
+ /**
69
+ * SCC membership over the PACKAGE graph. `null` = not in a non-trivial
70
+ * package-level cycle. Non-null = string id shared by every package in
71
+ * the same cyclic cluster. Drives cross-package-cycle highlighting.
72
+ */
73
+ readonly sccId: string | null;
74
+ }
75
+ export interface GraphViewModelEdge {
76
+ /** Source package name (caller). */
77
+ readonly source: string;
78
+ /** Target package name (callee). */
79
+ readonly target: string;
80
+ /**
81
+ * Number of underlying function→function call edges from the source
82
+ * package into the target package. Drives edge *thickness*.
83
+ */
84
+ readonly weight: number;
85
+ /**
86
+ * `true` iff this edge participates in a package-level cycle (both
87
+ * endpoints in the same non-null `sccId`). Highlights cross-package
88
+ * cycle backbones in concert with the node `sccId` grouping.
89
+ */
90
+ readonly isCycleEdge: boolean;
91
+ }
92
+ /** Thrown when the catalog is structurally unusable for projection. */
93
+ export declare class GraphViewModelError extends Error {
94
+ constructor(message: string);
95
+ }
96
+ /**
97
+ * Project a graph catalog into the slim, PACKAGE-LEVEL {@link GraphViewModel}.
98
+ *
99
+ * Pure function — no I/O, no side effects. Four passes:
100
+ * - Pass A: map every function `bodyHash` to its package (so call targets,
101
+ * which are bodyHashes, can be resolved to a package).
102
+ * - Pass B: walk function call edges, aggregate to package→package edges
103
+ * keyed by `caller→callee`, accumulating a call-count `weight`.
104
+ * - Pass C: derive package nodes (one per package seen) and accumulate
105
+ * `totalCoupling` (fan-in + fan-out weight) on each.
106
+ * - Pass D: Tarjan SCC over the package graph — stamp `sccId` on cyclic
107
+ * packages and `isCycleEdge` on edges whose endpoints share an `sccId`.
108
+ *
109
+ * @throws {GraphViewModelError} when `catalog` or `catalog.functions` is missing.
110
+ */
111
+ export declare function projectCatalogToGraphViewModel(catalog: GraphCatalog): GraphViewModel;
112
+ /**
113
+ * The package a function occurrence belongs to. Mirrors `pkgOf` in
114
+ * `path-utils.ts` (the browser-side helper the Coupling view uses) so the
115
+ * server-side projection and the client-side coupling matrix attribute
116
+ * functions to packages identically: prefer the build-time-stamped
117
+ * `occurrence.package` (scope-stripped), else the path heuristic.
118
+ */
119
+ export declare function packageOf(occ: GraphFunctionOccurrence): string;
120
+ //# sourceMappingURL=graph-view-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-view-model.d.ts","sourceRoot":"","sources":["../../src/code-paths/graph-view-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEpF;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,QAAQ,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,oCAAoC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,uEAAuE;AACvE,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAcD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,YAAY,GAAG,cAAc,CA4BpF;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,CAK9D"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * View-model projection for the Code Graph "Visualization" view.
3
+ *
4
+ * Projects the raw graph `GraphCatalog` (consumed by JSON shape from
5
+ * `@opensip-cli/contracts` — never from `@opensip-cli/graph`) into
6
+ * the slim, embed-ready `GraphViewModel` the Cytoscape renderer consumes.
7
+ *
8
+ * PACKAGE-LEVEL projection (item 10): the visualization renders a
9
+ * node-link graph at *package* granularity, NOT function granularity.
10
+ * Function-level catalogs on real repos contain thousands of function
11
+ * nodes — unusable in a node-link layout. This projector aggregates the
12
+ * function call graph up to packages:
13
+ *
14
+ * - Node = one package (id = label = package name via the same
15
+ * attribution the Coupling view uses — see `packageOf` below, which
16
+ * mirrors `pkgOf` in `path-utils.ts`).
17
+ * - Edge = caller-package → callee-package, with `weight` = the number
18
+ * of underlying function→function call edges between those packages.
19
+ *
20
+ * This is intentionally the same package→package data the Coupling grid
21
+ * shows — a node-link rendering of it rather than a matrix. Every OTHER
22
+ * consumer (Coupling drilldown, Functions table, rules, …) still reads
23
+ * the function-level catalog directly; only THIS view aggregates up.
24
+ *
25
+ * This module is the bundle-size budget enforcement point: the report
26
+ * ships what this projector emits, not the catalog's storage shape.
27
+ *
28
+ * Architecture decisions:
29
+ * - Projection runs at report-generation time (server-side, in
30
+ * `generator.ts`) and the result is embedded as a JSON blob, mirroring
31
+ * the existing `graph-catalog` blob.
32
+ * - Cross-package cycles are detected with Tarjan's SCC over the package
33
+ * graph (cheap at package granularity — tens of nodes, not thousands).
34
+ * The engine's SCC implementation is off-limits to this package (the
35
+ * catalog-decoupling rule §2.4); the local replica lives in the sibling
36
+ * `graph-scc.ts` module.
37
+ */
38
+ import { buildAdjacency, tarjanSccIds } from './graph-scc.js';
39
+ /** Thrown when the catalog is structurally unusable for projection. */
40
+ export class GraphViewModelError extends Error {
41
+ constructor(message) {
42
+ super(message);
43
+ this.name = 'GraphViewModelError';
44
+ }
45
+ }
46
+ /**
47
+ * Project a graph catalog into the slim, PACKAGE-LEVEL {@link GraphViewModel}.
48
+ *
49
+ * Pure function — no I/O, no side effects. Four passes:
50
+ * - Pass A: map every function `bodyHash` to its package (so call targets,
51
+ * which are bodyHashes, can be resolved to a package).
52
+ * - Pass B: walk function call edges, aggregate to package→package edges
53
+ * keyed by `caller→callee`, accumulating a call-count `weight`.
54
+ * - Pass C: derive package nodes (one per package seen) and accumulate
55
+ * `totalCoupling` (fan-in + fan-out weight) on each.
56
+ * - Pass D: Tarjan SCC over the package graph — stamp `sccId` on cyclic
57
+ * packages and `isCycleEdge` on edges whose endpoints share an `sccId`.
58
+ *
59
+ * @throws {GraphViewModelError} when `catalog` or `catalog.functions` is missing.
60
+ */
61
+ export function projectCatalogToGraphViewModel(catalog) {
62
+ if (!catalog || typeof catalog !== 'object' || !catalog.functions) {
63
+ throw new GraphViewModelError('catalog is missing or has no functions map');
64
+ }
65
+ const packageByHash = mapHashesToPackages(catalog); // Pass A
66
+ const edgeByKey = aggregatePackageEdges(catalog, packageByHash); // Pass B
67
+ const { nodes, edges } = deriveNodesAndEdges(packageByHash, edgeByKey); // Pass C
68
+ // Pass D: Tarjan SCC over the package graph. Self-loops (intra-package
69
+ // calls — the matrix diagonal) are excluded so a single package with
70
+ // internal calls is NOT flagged as a cycle; only genuine multi-package
71
+ // cycles (A→B→A) earn an sccId.
72
+ const adjacency = buildAdjacency(nodes, edges.filter((e) => e.source !== e.target));
73
+ const sccByNode = tarjanSccIds(nodes.map((n) => n.id), adjacency);
74
+ for (const node of nodes)
75
+ node.sccId = sccByNode.get(node.id) ?? null;
76
+ return {
77
+ language: catalog.language,
78
+ nodes: nodes.map(toViewModelNode),
79
+ edges: edges.map((e) => toViewModelEdge(e, sccByNode)),
80
+ };
81
+ }
82
+ /**
83
+ * The package a function occurrence belongs to. Mirrors `pkgOf` in
84
+ * `path-utils.ts` (the browser-side helper the Coupling view uses) so the
85
+ * server-side projection and the client-side coupling matrix attribute
86
+ * functions to packages identically: prefer the build-time-stamped
87
+ * `occurrence.package` (scope-stripped), else the path heuristic.
88
+ */
89
+ export function packageOf(occ) {
90
+ if (occ && typeof occ.package === 'string' && occ.package.length > 0) {
91
+ return shortPackage(occ.package);
92
+ }
93
+ return packageOfPath(occ ? occ.filePath : '');
94
+ }
95
+ /** Strip an npm scope for display: "@opensip-cli/lang-typescript" → "lang-typescript". */
96
+ function shortPackage(name) {
97
+ if (typeof name !== 'string')
98
+ return '<unknown>';
99
+ return name.codePointAt(0) === 64 /* @ */ ? name.slice(name.indexOf('/') + 1) : name;
100
+ }
101
+ /** Path-only fallback (first segment under `packages/`). */
102
+ function packageOfPath(filePath) {
103
+ if (typeof filePath !== 'string' || filePath.length === 0)
104
+ return '<unknown>';
105
+ const m = /^packages\/([^/]+)\//.exec(filePath);
106
+ return m ? m[1] : '<unknown>';
107
+ }
108
+ /** Pass A — bodyHash → package name (last write wins, mirroring buildIndexes). */
109
+ function mapHashesToPackages(catalog) {
110
+ const packageByHash = new Map();
111
+ for (const name of Object.keys(catalog.functions)) {
112
+ const occs = catalog.functions[name] ?? [];
113
+ for (const occ of occs)
114
+ packageByHash.set(occ.bodyHash, packageOf(occ));
115
+ }
116
+ return packageByHash;
117
+ }
118
+ /**
119
+ * Pass B — aggregate function call edges to directed package→package edges
120
+ * keyed by `callercallee`, accumulating a call-count `weight`. Call
121
+ * targets whose bodyHash is not an in-project function are dropped (matching
122
+ * the function-level projector's handling of unresolved/external calls).
123
+ * Self-package edges (intra-package calls) are kept — they show up as
124
+ * self-loops, consistent with the Coupling matrix diagonal.
125
+ */
126
+ function aggregatePackageEdges(catalog, packageByHash) {
127
+ const edgeByKey = new Map();
128
+ for (const name of Object.keys(catalog.functions)) {
129
+ for (const occ of catalog.functions[name] ?? []) {
130
+ accumulateOccurrenceEdges(occ, packageByHash, edgeByKey);
131
+ }
132
+ }
133
+ return edgeByKey;
134
+ }
135
+ /** Add one weighted package edge per resolved call target of `occ`. */
136
+ function accumulateOccurrenceEdges(occ, packageByHash, edgeByKey) {
137
+ const callerPkg = packageByHash.get(occ.bodyHash);
138
+ if (callerPkg === undefined)
139
+ return;
140
+ for (const edge of occ.calls ?? []) {
141
+ for (const target of edge.to ?? []) {
142
+ const calleePkg = packageByHash.get(target);
143
+ if (calleePkg === undefined)
144
+ continue; // external / unresolved
145
+ bumpEdge(edgeByKey, callerPkg, calleePkg);
146
+ }
147
+ }
148
+ }
149
+ /** Increment (or create) the weighted edge for a caller-to-callee package pair. */
150
+ function bumpEdge(edgeByKey, source, target) {
151
+ // Newline delimiter: package names never contain one, so caller+callee keys
152
+ // can't collide (unlike empty-string concat).
153
+ const key = source + '\n' + target;
154
+ const existing = edgeByKey.get(key);
155
+ if (existing)
156
+ existing.weight += 1;
157
+ else
158
+ edgeByKey.set(key, { source, target, weight: 1 });
159
+ }
160
+ /**
161
+ * Pass C — derive one node per package (every package that appears as a
162
+ * function's package OR as an edge endpoint) and accumulate `totalCoupling`
163
+ * (sum of incident edge weights) on each.
164
+ */
165
+ function deriveNodesAndEdges(packageByHash, edgeByKey) {
166
+ const nodeById = new Map();
167
+ // @fitness-ignore-next-line toctou-race-condition -- synchronous single-pass projector; `nodeById` is a local Map with no async/concurrent access, so there is no time-of-check/time-of-use window between the get and the set.
168
+ const ensure = (id) => {
169
+ let n = nodeById.get(id);
170
+ if (!n) {
171
+ n = { id, totalCoupling: 0, sccId: null };
172
+ nodeById.set(id, n);
173
+ }
174
+ return n;
175
+ };
176
+ // Every package that hosts a function is a node, even if it has no edges.
177
+ for (const pkg of packageByHash.values())
178
+ ensure(pkg);
179
+ const edges = [...edgeByKey.values()];
180
+ for (const e of edges) {
181
+ ensure(e.source).totalCoupling += e.weight;
182
+ ensure(e.target).totalCoupling += e.weight;
183
+ }
184
+ return { nodes: [...nodeById.values()], edges };
185
+ }
186
+ function toViewModelNode(n) {
187
+ return { id: n.id, label: n.id, totalCoupling: n.totalCoupling, sccId: n.sccId };
188
+ }
189
+ function toViewModelEdge(e, sccByNode) {
190
+ const sourceScc = sccByNode.get(e.source);
191
+ const targetScc = sccByNode.get(e.target);
192
+ return {
193
+ source: e.source,
194
+ target: e.target,
195
+ weight: e.weight,
196
+ isCycleEdge: sourceScc != null && sourceScc === targetScc,
197
+ };
198
+ }
199
+ //# sourceMappingURL=graph-view-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-view-model.js","sourceRoot":"","sources":["../../src/code-paths/graph-view-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Right-side help drawer — explains a single Explore view.
3
+ *
4
+ * Each view-*.ts puts a `help` field on its View literal:
5
+ * { title: string, sections: { heading: string, body: string }[] }
6
+ * Clicking the ⓘ icon next to a tab opens this drawer with that
7
+ * view's help. Clicking the backdrop, the × button, or pressing
8
+ * Escape closes it. There is one drawer at a time.
9
+ *
10
+ * The drawer resolves help dynamically via `getView(viewId).help` — there is
11
+ * NO static per-view help map. So the Plan B Code Paths restructure
12
+ * (dropping `big`/`hot`/`wide`/`untested`/`sccs` and folding cycle guidance
13
+ * into the graph view's help) needs no edit here: the drawer simply renders
14
+ * whatever views are registered. The SCC explanation now lives on the graph
15
+ * view's `help` ("Cycles / SCCs" section, view-graph.ts).
16
+ */
17
+ export declare function dashboardHelpDrawerJs(): string;
18
+ //# sourceMappingURL=help-drawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-drawer.d.ts","sourceRoot":"","sources":["../../src/code-paths/help-drawer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,wBAAgB,qBAAqB,IAAI,MAAM,CAoC9C"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Right-side help drawer — explains a single Explore view.
3
+ *
4
+ * Each view-*.ts puts a `help` field on its View literal:
5
+ * { title: string, sections: { heading: string, body: string }[] }
6
+ * Clicking the ⓘ icon next to a tab opens this drawer with that
7
+ * view's help. Clicking the backdrop, the × button, or pressing
8
+ * Escape closes it. There is one drawer at a time.
9
+ *
10
+ * The drawer resolves help dynamically via `getView(viewId).help` — there is
11
+ * NO static per-view help map. So the Plan B Code Paths restructure
12
+ * (dropping `big`/`hot`/`wide`/`untested`/`sccs` and folding cycle guidance
13
+ * into the graph view's help) needs no edit here: the drawer simply renders
14
+ * whatever views are registered. The SCC explanation now lives on the graph
15
+ * view's `help` ("Cycles / SCCs" section, view-graph.ts).
16
+ */
17
+ export function dashboardHelpDrawerJs() {
18
+ return String.raw `
19
+ function openHelpDrawer(viewId) {
20
+ const view = (typeof getView === 'function') ? getView(viewId) : null;
21
+ if (!view || !view.help) return;
22
+ closeHelpDrawer();
23
+ const overlay = el('div', { class: 'help-drawer-overlay', id: 'help-drawer-overlay' });
24
+ overlay.addEventListener('click', e => { if (e.target === overlay) closeHelpDrawer(); });
25
+ const drawer = el('aside', { class: 'help-drawer', role: 'dialog', 'aria-label': view.help.title || view.label });
26
+ const header = el('div', { class: 'help-drawer-header' });
27
+ header.appendChild(el('h3', { text: view.help.title || view.label }));
28
+ const closeBtn = el('button', { class: 'help-drawer-close', 'aria-label': 'Close', text: '×', onclick: closeHelpDrawer });
29
+ header.appendChild(closeBtn);
30
+ drawer.appendChild(header);
31
+ const body = el('div', { class: 'help-drawer-body' });
32
+ for (const section of (view.help.sections || [])) {
33
+ body.appendChild(el('h4', { text: section.heading }));
34
+ body.appendChild(el('p', { text: section.body }));
35
+ }
36
+ drawer.appendChild(body);
37
+ overlay.appendChild(drawer);
38
+ document.body.appendChild(overlay);
39
+ // Animate in on next frame so the CSS transition takes effect.
40
+ requestAnimationFrame(() => overlay.classList.add('open'));
41
+ closeBtn.focus();
42
+ }
43
+
44
+ function closeHelpDrawer() {
45
+ const existing = document.getElementById('help-drawer-overlay');
46
+ if (existing && existing.parentNode) existing.parentNode.removeChild(existing);
47
+ }
48
+
49
+ document.addEventListener('keydown', e => {
50
+ if (e.key === 'Escape' && document.getElementById('help-drawer-overlay')) closeHelpDrawer();
51
+ });
52
+ `;
53
+ }
54
+ //# sourceMappingURL=help-drawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-drawer.js","sourceRoot":"","sources":["../../src/code-paths/help-drawer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkClB,CAAC;AACF,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Browser-side `Indexes` builder — emitted as a JS string for the
3
+ * inlined dashboard script. Mirrors v0.2's `pipeline/indexes.ts`
4
+ * but ported to vanilla JS that runs in the page.
5
+ *
6
+ * The catalog persists only `functions[name][i].calls[].to[]`. v0.2's
7
+ * O(1) `Indexes` is in-memory only; the dashboard rebuilds it on
8
+ * panel-init time. Output: { byBodyHash, occurrencesByHash,
9
+ * bySimpleName, callees, callers }.
10
+ *
11
+ * Blast radius is no longer computed here. The engine's features stage
12
+ * (`pipeline/features.ts`, Plan C) is the single canonical home for the
13
+ * bounded reverse-BFS blast score; a dashboard-bound run materializes it
14
+ * into `catalog.features.function[bodyHash].blast` and the Hot view reads
15
+ * it from there (falling back to the raw inbound-caller count when the
16
+ * catalog carries no features). This builder now only assembles the
17
+ * adjacency the views need for navigation and member resolution.
18
+ *
19
+ * Also emits `resolveCalleeOcc(target, callerOcc, indexes)` — the shared
20
+ * call-target → callee-occurrence resolver. It lives here (not in any single
21
+ * view) because more than one view needs it: the Coupling drilldown AND the
22
+ * function-level Visualization both resolve a call target's bodyHash to the
23
+ * occurrence the caller can actually reach, disambiguating body-hash
24
+ * collisions across packages. Emitting it in the prelude (ahead of every
25
+ * view) removes the load-bearing cross-view emission order it used to imply.
26
+ */
27
+ export declare function dashboardIndexesJs(): string;
28
+ //# sourceMappingURL=indexes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexes.d.ts","sourceRoot":"","sources":["../../src/code-paths/indexes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,wBAAgB,kBAAkB,IAAI,MAAM,CAqE3C"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Browser-side `Indexes` builder — emitted as a JS string for the
3
+ * inlined dashboard script. Mirrors v0.2's `pipeline/indexes.ts`
4
+ * but ported to vanilla JS that runs in the page.
5
+ *
6
+ * The catalog persists only `functions[name][i].calls[].to[]`. v0.2's
7
+ * O(1) `Indexes` is in-memory only; the dashboard rebuilds it on
8
+ * panel-init time. Output: { byBodyHash, occurrencesByHash,
9
+ * bySimpleName, callees, callers }.
10
+ *
11
+ * Blast radius is no longer computed here. The engine's features stage
12
+ * (`pipeline/features.ts`, Plan C) is the single canonical home for the
13
+ * bounded reverse-BFS blast score; a dashboard-bound run materializes it
14
+ * into `catalog.features.function[bodyHash].blast` and the Hot view reads
15
+ * it from there (falling back to the raw inbound-caller count when the
16
+ * catalog carries no features). This builder now only assembles the
17
+ * adjacency the views need for navigation and member resolution.
18
+ *
19
+ * Also emits `resolveCalleeOcc(target, callerOcc, indexes)` — the shared
20
+ * call-target → callee-occurrence resolver. It lives here (not in any single
21
+ * view) because more than one view needs it: the Coupling drilldown AND the
22
+ * function-level Visualization both resolve a call target's bodyHash to the
23
+ * occurrence the caller can actually reach, disambiguating body-hash
24
+ * collisions across packages. Emitting it in the prelude (ahead of every
25
+ * view) removes the load-bearing cross-view emission order it used to imply.
26
+ */
27
+ export function dashboardIndexesJs() {
28
+ return String.raw `
29
+ function buildIndexes(catalog) {
30
+ const byBodyHash = new Map();
31
+ // All occurrences per body. byBodyHash keeps only one (last-writer-wins),
32
+ // collapsing identical bodies across packages; occurrencesByHash preserves
33
+ // every occurrence so coupling can attribute a callee to the correct
34
+ // package instead of the collision winner.
35
+ const occurrencesByHash = new Map();
36
+ const bySimpleName = new Map();
37
+ const callees = new Map();
38
+ const callers = new Map();
39
+ if (!catalog || !catalog.functions) {
40
+ return { byBodyHash, occurrencesByHash, bySimpleName, callees, callers };
41
+ }
42
+ // Pass 1: byBodyHash + occurrencesByHash + bySimpleName.
43
+ for (const name of Object.keys(catalog.functions)) {
44
+ const occs = catalog.functions[name] || [];
45
+ for (const occ of occs) {
46
+ byBodyHash.set(occ.bodyHash, occ);
47
+ let all = occurrencesByHash.get(occ.bodyHash);
48
+ if (!all) { all = []; occurrencesByHash.set(occ.bodyHash, all); }
49
+ all.push(occ);
50
+ let bucket = bySimpleName.get(name);
51
+ if (!bucket) { bucket = []; bySimpleName.set(name, bucket); }
52
+ bucket.push(occ.bodyHash);
53
+ }
54
+ }
55
+ // Pass 2: callees (forward) + callers (reverse). Edges that resolve
56
+ // to a hash not in byBodyHash are dropped; this mirrors v0.2's
57
+ // behavior for unresolved/external targets.
58
+ for (const occ of byBodyHash.values()) {
59
+ const out = [];
60
+ for (const edge of (occ.calls || [])) {
61
+ for (const target of (edge.to || [])) {
62
+ if (!byBodyHash.has(target)) continue;
63
+ out.push(target);
64
+ let inb = callers.get(target);
65
+ if (!inb) { inb = []; callers.set(target, inb); }
66
+ inb.push(occ.bodyHash);
67
+ }
68
+ }
69
+ if (out.length > 0) callees.set(occ.bodyHash, out);
70
+ }
71
+ return { byBodyHash, occurrencesByHash, bySimpleName, callees, callers };
72
+ }
73
+
74
+ // Resolve a call target (a bodyHash) to the callee occurrence the caller can
75
+ // reach, disambiguating body-hash collisions across packages. byBodyHash
76
+ // keeps only one occurrence per hash (the collision winner), which
77
+ // mis-attributes the callee's package; occurrencesByHash preserves all, so we
78
+ // prefer the caller's own package, else fall back deterministically (lowest
79
+ // qualifiedName). The dashboard catalog carries no import set, so this mirrors
80
+ // the engine's fast-mode (same-package-only) attribution. Used by the Coupling
81
+ // drilldown and the function-level Visualization projection.
82
+ function resolveCalleeOcc(target, callerOcc, indexes) {
83
+ const candidates = (indexes.occurrencesByHash && indexes.occurrencesByHash.get(target)) || null;
84
+ if (!candidates || candidates.length === 0) return indexes.byBodyHash.get(target);
85
+ if (candidates.length === 1) return candidates[0];
86
+ const callerPkg = pkgOf(callerOcc);
87
+ let samePkg = null;
88
+ let lowest = candidates[0];
89
+ for (const c of candidates) {
90
+ if (!samePkg && pkgOf(c) === callerPkg) samePkg = c;
91
+ if (c.qualifiedName < lowest.qualifiedName) lowest = c;
92
+ }
93
+ return samePkg || lowest;
94
+ }
95
+ `;
96
+ }
97
+ //# sourceMappingURL=indexes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexes.js","sourceRoot":"","sources":["../../src/code-paths/indexes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,UAAU,kBAAkB;IAChC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmElB,CAAC;AACF,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Path / name display helpers shared across the Explore views.
3
+ *
4
+ * - pkgOf: the package an occurrence belongs to — prefers the
5
+ * build-time-stamped `occurrence.package` (nearest package.json name, shown
6
+ * scope-stripped), falling back to the path heuristic for old catalogs.
7
+ * - packageOfPath: path-only fallback (first segment under packages/).
8
+ * - displayName: collapse synthetic graph names like
9
+ * "<arrow:packages/.../foo.ts:234:45>" into a short tag the table
10
+ * can render without horizontal overflow. The underlying simpleName
11
+ * is preserved as the identity (data-body-hash); only the cell text
12
+ * is shortened.
13
+ */
14
+ export declare function dashboardPathUtilsJs(): string;
15
+ //# sourceMappingURL=path-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../src/code-paths/path-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,wBAAgB,oBAAoB,IAAI,MAAM,CAgC7C"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Path / name display helpers shared across the Explore views.
3
+ *
4
+ * - pkgOf: the package an occurrence belongs to — prefers the
5
+ * build-time-stamped `occurrence.package` (nearest package.json name, shown
6
+ * scope-stripped), falling back to the path heuristic for old catalogs.
7
+ * - packageOfPath: path-only fallback (first segment under packages/).
8
+ * - displayName: collapse synthetic graph names like
9
+ * "<arrow:packages/.../foo.ts:234:45>" into a short tag the table
10
+ * can render without horizontal overflow. The underlying simpleName
11
+ * is preserved as the identity (data-body-hash); only the cell text
12
+ * is shortened.
13
+ */
14
+ export function dashboardPathUtilsJs() {
15
+ return String.raw `
16
+ function packageOfPath(filePath) {
17
+ if (typeof filePath !== 'string' || filePath.length === 0) return '<unknown>';
18
+ const m = /^packages\/([^/]+)\//.exec(filePath);
19
+ return m ? m[1] : '<unknown>';
20
+ }
21
+
22
+ // Strip an npm scope for display: "@opensip-cli/lang-typescript" -> "lang-typescript".
23
+ function shortPkg(name) {
24
+ if (typeof name !== 'string') return '<unknown>';
25
+ return name.charCodeAt(0) === 64 /* @ */ ? name.slice(name.indexOf('/') + 1) : name;
26
+ }
27
+
28
+ // The package an occurrence belongs to. Prefers the build-time-stamped
29
+ // occurrence.package (accurate for any repo layout); falls back to the path
30
+ // heuristic for legacy catalogs. Scope-stripped for compact display.
31
+ function pkgOf(occ) {
32
+ if (occ && typeof occ.package === 'string' && occ.package.length > 0) return shortPkg(occ.package);
33
+ return packageOfPath(occ ? occ.filePath : '');
34
+ }
35
+
36
+ function displayName(simpleName) {
37
+ if (typeof simpleName !== 'string') return '';
38
+ // Synthetic names from the graph tool are angle-bracketed:
39
+ // <arrow:path:line:col>, <fn-expr:path:line:col>, <module-init:path>, <default>
40
+ // Render just the kind tag — file:line is shown in the File column.
41
+ const m = /^<([a-z-]+)(?::|>)/.exec(simpleName);
42
+ if (m) return '<' + m[1] + '>';
43
+ return simpleName;
44
+ }
45
+ `;
46
+ }
47
+ //# sourceMappingURL=path-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../src/code-paths/path-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BlB,CAAC;AACF,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Substring-with-character-skip fuzzy match for the persistent search
3
+ * input and View 7. Pure algorithm emitted as a JS string.
4
+ *
5
+ * Algorithm: each character of the query must appear in the candidate
6
+ * in order, but not necessarily contiguously. Score is built from:
7
+ * - prefix match (start at index 0): +50
8
+ * - exact-case bonus per matched char: +1
9
+ * - contiguous-run bonus (matched-after-matched): +2 per
10
+ * - shorter candidate preferred: -length * 0.01
11
+ * Returns top matches sorted by score desc, score >= 0.
12
+ */
13
+ export declare function dashboardSearchJs(): string;
14
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/code-paths/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,wBAAgB,iBAAiB,IAAI,MAAM,CAwC1C"}