@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.
- package/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/__tests__/catalog-provenance.test.d.ts +11 -0
- package/dist/__tests__/catalog-provenance.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-provenance.test.js +130 -0
- package/dist/__tests__/catalog-provenance.test.js.map +1 -0
- package/dist/__tests__/coupling-attribution.test.d.ts +9 -0
- package/dist/__tests__/coupling-attribution.test.d.ts.map +1 -0
- package/dist/__tests__/coupling-attribution.test.js +99 -0
- package/dist/__tests__/coupling-attribution.test.js.map +1 -0
- package/dist/__tests__/dashboard-bundle-weight.test.d.ts +16 -0
- package/dist/__tests__/dashboard-bundle-weight.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-bundle-weight.test.js +73 -0
- package/dist/__tests__/dashboard-bundle-weight.test.js.map +1 -0
- package/dist/__tests__/dashboard-cell-containment.test.d.ts +2 -0
- package/dist/__tests__/dashboard-cell-containment.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-cell-containment.test.js +49 -0
- package/dist/__tests__/dashboard-cell-containment.test.js.map +1 -0
- package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts +10 -0
- package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-cytoscape-vendor.test.js +40 -0
- package/dist/__tests__/dashboard-cytoscape-vendor.test.js.map +1 -0
- package/dist/__tests__/dashboard-editor-link.test.d.ts +5 -0
- package/dist/__tests__/dashboard-editor-link.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-editor-link.test.js +36 -0
- package/dist/__tests__/dashboard-editor-link.test.js.map +1 -0
- package/dist/__tests__/dashboard-filters.test.d.ts +9 -0
- package/dist/__tests__/dashboard-filters.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-filters.test.js +95 -0
- package/dist/__tests__/dashboard-filters.test.js.map +1 -0
- package/dist/__tests__/dashboard-function-card-singleton.test.d.ts +9 -0
- package/dist/__tests__/dashboard-function-card-singleton.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-function-card-singleton.test.js +87 -0
- package/dist/__tests__/dashboard-function-card-singleton.test.js.map +1 -0
- package/dist/__tests__/dashboard-function-card.test.d.ts +10 -0
- package/dist/__tests__/dashboard-function-card.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-function-card.test.js +403 -0
- package/dist/__tests__/dashboard-function-card.test.js.map +1 -0
- package/dist/__tests__/dashboard-function-row.test.d.ts +11 -0
- package/dist/__tests__/dashboard-function-row.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-function-row.test.js +101 -0
- package/dist/__tests__/dashboard-function-row.test.js.map +1 -0
- package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts +9 -0
- package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-generator-graph-catalog.test.js +75 -0
- package/dist/__tests__/dashboard-generator-graph-catalog.test.js.map +1 -0
- package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts +13 -0
- package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-graph-offline.integration.test.js +55 -0
- package/dist/__tests__/dashboard-graph-offline.integration.test.js.map +1 -0
- package/dist/__tests__/dashboard-graph-scc.test.d.ts +17 -0
- package/dist/__tests__/dashboard-graph-scc.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-graph-scc.test.js +89 -0
- package/dist/__tests__/dashboard-graph-scc.test.js.map +1 -0
- package/dist/__tests__/dashboard-graph-view-model.test.d.ts +12 -0
- package/dist/__tests__/dashboard-graph-view-model.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-graph-view-model.test.js +331 -0
- package/dist/__tests__/dashboard-graph-view-model.test.js.map +1 -0
- package/dist/__tests__/dashboard-help-drawer.test.d.ts +9 -0
- package/dist/__tests__/dashboard-help-drawer.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-help-drawer.test.js +101 -0
- package/dist/__tests__/dashboard-help-drawer.test.js.map +1 -0
- package/dist/__tests__/dashboard-html.test.d.ts +2 -0
- package/dist/__tests__/dashboard-html.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-html.test.js +169 -0
- package/dist/__tests__/dashboard-html.test.js.map +1 -0
- package/dist/__tests__/dashboard-indexes.test.d.ts +9 -0
- package/dist/__tests__/dashboard-indexes.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-indexes.test.js +211 -0
- package/dist/__tests__/dashboard-indexes.test.js.map +1 -0
- package/dist/__tests__/dashboard-path-utils.test.d.ts +6 -0
- package/dist/__tests__/dashboard-path-utils.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-path-utils.test.js +54 -0
- package/dist/__tests__/dashboard-path-utils.test.js.map +1 -0
- package/dist/__tests__/dashboard-search.test.d.ts +5 -0
- package/dist/__tests__/dashboard-search.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-search.test.js +46 -0
- package/dist/__tests__/dashboard-search.test.js.map +1 -0
- package/dist/__tests__/dashboard-sessions.test.d.ts +14 -0
- package/dist/__tests__/dashboard-sessions.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-sessions.test.js +330 -0
- package/dist/__tests__/dashboard-sessions.test.js.map +1 -0
- package/dist/__tests__/dashboard-trace.test.d.ts +5 -0
- package/dist/__tests__/dashboard-trace.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-trace.test.js +147 -0
- package/dist/__tests__/dashboard-trace.test.js.map +1 -0
- package/dist/__tests__/dashboard-validation.integration.test.d.ts +14 -0
- package/dist/__tests__/dashboard-validation.integration.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-validation.integration.test.js +221 -0
- package/dist/__tests__/dashboard-validation.integration.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-conformance.test.d.ts +12 -0
- package/dist/__tests__/dashboard-view-conformance.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-conformance.test.js +58 -0
- package/dist/__tests__/dashboard-view-conformance.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-coupling.test.d.ts +7 -0
- package/dist/__tests__/dashboard-view-coupling.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-coupling.test.js +381 -0
- package/dist/__tests__/dashboard-view-coupling.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-distribution.test.d.ts +10 -0
- package/dist/__tests__/dashboard-view-distribution.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-distribution.test.js +272 -0
- package/dist/__tests__/dashboard-view-distribution.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-graph.test.d.ts +13 -0
- package/dist/__tests__/dashboard-view-graph.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-graph.test.js +332 -0
- package/dist/__tests__/dashboard-view-graph.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-template.test.d.ts +21 -0
- package/dist/__tests__/dashboard-view-template.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-template.test.js +153 -0
- package/dist/__tests__/dashboard-view-template.test.js.map +1 -0
- package/dist/__tests__/dashboard.test.d.ts +2 -0
- package/dist/__tests__/dashboard.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard.test.js +129 -0
- package/dist/__tests__/dashboard.test.js.map +1 -0
- package/dist/__tests__/graph-tab.test.d.ts +10 -0
- package/dist/__tests__/graph-tab.test.d.ts.map +1 -0
- package/dist/__tests__/graph-tab.test.js +76 -0
- package/dist/__tests__/graph-tab.test.js.map +1 -0
- package/dist/checks.d.ts +7 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +283 -0
- package/dist/checks.js.map +1 -0
- package/dist/code-paths/__tests__/views-registry.test.d.ts +13 -0
- package/dist/code-paths/__tests__/views-registry.test.d.ts.map +1 -0
- package/dist/code-paths/__tests__/views-registry.test.js +39 -0
- package/dist/code-paths/__tests__/views-registry.test.js.map +1 -0
- package/dist/code-paths/catalog-provenance.d.ts +22 -0
- package/dist/code-paths/catalog-provenance.d.ts.map +1 -0
- package/dist/code-paths/catalog-provenance.js +108 -0
- package/dist/code-paths/catalog-provenance.js.map +1 -0
- package/dist/code-paths/catalog-recipes-tables.d.ts +11 -0
- package/dist/code-paths/catalog-recipes-tables.d.ts.map +1 -0
- package/dist/code-paths/catalog-recipes-tables.js +86 -0
- package/dist/code-paths/catalog-recipes-tables.js.map +1 -0
- package/dist/code-paths/cytoscape-vendor.d.ts +27 -0
- package/dist/code-paths/cytoscape-vendor.d.ts.map +1 -0
- package/dist/code-paths/cytoscape-vendor.js +68 -0
- package/dist/code-paths/cytoscape-vendor.js.map +1 -0
- package/dist/code-paths/editor-link.d.ts +10 -0
- package/dist/code-paths/editor-link.d.ts.map +1 -0
- package/dist/code-paths/editor-link.js +20 -0
- package/dist/code-paths/editor-link.js.map +1 -0
- package/dist/code-paths/filters.d.ts +19 -0
- package/dist/code-paths/filters.d.ts.map +1 -0
- package/dist/code-paths/filters.js +47 -0
- package/dist/code-paths/filters.js.map +1 -0
- package/dist/code-paths/function-card.d.ts +15 -0
- package/dist/code-paths/function-card.d.ts.map +1 -0
- package/dist/code-paths/function-card.js +169 -0
- package/dist/code-paths/function-card.js.map +1 -0
- package/dist/code-paths/function-row.d.ts +17 -0
- package/dist/code-paths/function-row.d.ts.map +1 -0
- package/dist/code-paths/function-row.js +77 -0
- package/dist/code-paths/function-row.js.map +1 -0
- package/dist/code-paths/graph-controls.d.ts +27 -0
- package/dist/code-paths/graph-controls.d.ts.map +1 -0
- package/dist/code-paths/graph-controls.js +257 -0
- package/dist/code-paths/graph-controls.js.map +1 -0
- package/dist/code-paths/graph-scc.d.ts +32 -0
- package/dist/code-paths/graph-scc.d.ts.map +1 -0
- package/dist/code-paths/graph-scc.js +136 -0
- package/dist/code-paths/graph-scc.js.map +1 -0
- package/dist/code-paths/graph-stylesheet.d.ts +22 -0
- package/dist/code-paths/graph-stylesheet.d.ts.map +1 -0
- package/dist/code-paths/graph-stylesheet.js +121 -0
- package/dist/code-paths/graph-stylesheet.js.map +1 -0
- package/dist/code-paths/graph-view-model.d.ts +120 -0
- package/dist/code-paths/graph-view-model.d.ts.map +1 -0
- package/dist/code-paths/graph-view-model.js +199 -0
- package/dist/code-paths/graph-view-model.js.map +1 -0
- package/dist/code-paths/help-drawer.d.ts +18 -0
- package/dist/code-paths/help-drawer.d.ts.map +1 -0
- package/dist/code-paths/help-drawer.js +54 -0
- package/dist/code-paths/help-drawer.js.map +1 -0
- package/dist/code-paths/indexes.d.ts +28 -0
- package/dist/code-paths/indexes.d.ts.map +1 -0
- package/dist/code-paths/indexes.js +97 -0
- package/dist/code-paths/indexes.js.map +1 -0
- package/dist/code-paths/path-utils.d.ts +15 -0
- package/dist/code-paths/path-utils.d.ts.map +1 -0
- package/dist/code-paths/path-utils.js +47 -0
- package/dist/code-paths/path-utils.js.map +1 -0
- package/dist/code-paths/search.d.ts +14 -0
- package/dist/code-paths/search.d.ts.map +1 -0
- package/dist/code-paths/search.js +54 -0
- package/dist/code-paths/search.js.map +1 -0
- package/dist/code-paths/trace.d.ts +11 -0
- package/dist/code-paths/trace.d.ts.map +1 -0
- package/dist/code-paths/trace.js +60 -0
- package/dist/code-paths/trace.js.map +1 -0
- package/dist/code-paths/view-coupling.d.ts +22 -0
- package/dist/code-paths/view-coupling.d.ts.map +1 -0
- package/dist/code-paths/view-coupling.js +218 -0
- package/dist/code-paths/view-coupling.js.map +1 -0
- package/dist/code-paths/view-distribution.d.ts +20 -0
- package/dist/code-paths/view-distribution.d.ts.map +1 -0
- package/dist/code-paths/view-distribution.js +82 -0
- package/dist/code-paths/view-distribution.js.map +1 -0
- package/dist/code-paths/view-graph.d.ts +35 -0
- package/dist/code-paths/view-graph.d.ts.map +1 -0
- package/dist/code-paths/view-graph.js +379 -0
- package/dist/code-paths/view-graph.js.map +1 -0
- package/dist/code-paths/view-template.d.ts +154 -0
- package/dist/code-paths/view-template.d.ts.map +1 -0
- package/dist/code-paths/view-template.js +218 -0
- package/dist/code-paths/view-template.js.map +1 -0
- package/dist/code-paths/views-registry.d.ts +13 -0
- package/dist/code-paths/views-registry.d.ts.map +1 -0
- package/dist/code-paths/views-registry.js +53 -0
- package/dist/code-paths/views-registry.js.map +1 -0
- package/dist/code-paths.d.ts +69 -0
- package/dist/code-paths.d.ts.map +1 -0
- package/dist/code-paths.js +356 -0
- package/dist/code-paths.js.map +1 -0
- package/dist/css/cards.d.ts +9 -0
- package/dist/css/cards.d.ts.map +1 -0
- package/dist/css/cards.js +36 -0
- package/dist/css/cards.js.map +1 -0
- package/dist/css/code-paths.d.ts +9 -0
- package/dist/css/code-paths.d.ts.map +1 -0
- package/dist/css/code-paths.js +111 -0
- package/dist/css/code-paths.js.map +1 -0
- package/dist/css/data-table.d.ts +12 -0
- package/dist/css/data-table.d.ts.map +1 -0
- package/dist/css/data-table.js +103 -0
- package/dist/css/data-table.js.map +1 -0
- package/dist/css/function-card.d.ts +6 -0
- package/dist/css/function-card.d.ts.map +1 -0
- package/dist/css/function-card.js +26 -0
- package/dist/css/function-card.js.map +1 -0
- package/dist/css/help-drawer.d.ts +6 -0
- package/dist/css/help-drawer.d.ts.map +1 -0
- package/dist/css/help-drawer.js +22 -0
- package/dist/css/help-drawer.js.map +1 -0
- package/dist/css/tabs.d.ts +9 -0
- package/dist/css/tabs.d.ts.map +1 -0
- package/dist/css/tabs.js +28 -0
- package/dist/css/tabs.js.map +1 -0
- package/dist/css/theme.d.ts +8 -0
- package/dist/css/theme.d.ts.map +1 -0
- package/dist/css/theme.js +34 -0
- package/dist/css/theme.js.map +1 -0
- package/dist/css.d.ts +13 -0
- package/dist/css.d.ts.map +1 -0
- package/dist/css.js +30 -0
- package/dist/css.js.map +1 -0
- package/dist/generator.d.ts +33 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +161 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/overview.d.ts +13 -0
- package/dist/overview.d.ts.map +1 -0
- package/dist/overview.js +91 -0
- package/dist/overview.js.map +1 -0
- package/dist/recipes.d.ts +6 -0
- package/dist/recipes.d.ts.map +1 -0
- package/dist/recipes.js +68 -0
- package/dist/recipes.js.map +1 -0
- package/dist/sessions.d.ts +6 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +288 -0
- package/dist/sessions.js.map +1 -0
- package/dist/shared/el.d.ts +13 -0
- package/dist/shared/el.d.ts.map +1 -0
- package/dist/shared/el.js +27 -0
- package/dist/shared/el.js.map +1 -0
- package/dist/shared/pagination.d.ts +15 -0
- package/dist/shared/pagination.d.ts.map +1 -0
- package/dist/shared/pagination.js +113 -0
- package/dist/shared/pagination.js.map +1 -0
- package/dist/shared/sortable.d.ts +14 -0
- package/dist/shared/sortable.d.ts.map +1 -0
- package/dist/shared/sortable.js +101 -0
- package/dist/shared/sortable.js.map +1 -0
- package/dist/shared/tab-activators.d.ts +16 -0
- package/dist/shared/tab-activators.d.ts.map +1 -0
- package/dist/shared/tab-activators.js +33 -0
- package/dist/shared/tab-activators.js.map +1 -0
- package/dist/shared/tab-bar.d.ts +8 -0
- package/dist/shared/tab-bar.d.ts.map +1 -0
- package/dist/shared/tab-bar.js +20 -0
- package/dist/shared/tab-bar.js.map +1 -0
- package/dist/shared.d.ts +26 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +39 -0
- package/dist/shared.js.map +1 -0
- package/dist/subtab-bar.d.ts +23 -0
- package/dist/subtab-bar.d.ts.map +1 -0
- package/dist/subtab-bar.js +77 -0
- package/dist/subtab-bar.js.map +1 -0
- package/dist/tool-tab-registry.d.ts +76 -0
- package/dist/tool-tab-registry.d.ts.map +1 -0
- package/dist/tool-tab-registry.js +44 -0
- package/dist/tool-tab-registry.js.map +1 -0
- package/dist/tool-tabs-registrations.d.ts +19 -0
- package/dist/tool-tabs-registrations.d.ts.map +1 -0
- package/dist/tool-tabs-registrations.js +46 -0
- package/dist/tool-tabs-registrations.js.map +1 -0
- package/dist/tool-tabs.d.ts +12 -0
- package/dist/tool-tabs.d.ts.map +1 -0
- package/dist/tool-tabs.js +80 -0
- package/dist/tool-tabs.js.map +1 -0
- package/dist/vendor/cytoscape-bundle.js +600 -0
- package/package.json +52 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Visualization control toolbar + function-level projector.
|
|
3
|
+
*
|
|
4
|
+
* A render helper (registers no view), extracted from `view-graph.ts` to keep
|
|
5
|
+
* that emitter under the file-length budget — and, like `graph-stylesheet.ts`,
|
|
6
|
+
* deliberately named out of the `view-*` namespace so it stays clear of the
|
|
7
|
+
* views-disjoint architecture rule. Emits two browser functions plus a tiny
|
|
8
|
+
* helper as a JS string; the main emitter interpolates it into its `<script>`
|
|
9
|
+
* body, so they share one runtime scope with the view's state vars
|
|
10
|
+
* (`gvLevel`, `gvSelectedPackage`, …) and `gvRenderGraph`.
|
|
11
|
+
*
|
|
12
|
+
* - `gvRenderControls(host, catalog, indexes)` — the self-contained Level /
|
|
13
|
+
* Scope / Package / Kind / Edges control bar. Package + Kind are disabled at
|
|
14
|
+
* package level (they only apply at function level). Every change re-renders
|
|
15
|
+
* the graph in place via `gvRenderGraph`.
|
|
16
|
+
* - `gvBuildFunctionElements(indexes, pkg, includeTests, kinds, crossPackage)`
|
|
17
|
+
* — projects ONE package's function call graph client-side from the catalog
|
|
18
|
+
* indexes (the package→package view-model blob can't express it).
|
|
19
|
+
* - `gvAddOptions(sel, pairs, current)` — small `<select>` option builder.
|
|
20
|
+
*
|
|
21
|
+
* Free identifiers (supplied by earlier prelude emitters / the host template):
|
|
22
|
+
* `el`, `pkgOf`, `displayName`, `resolveCalleeOcc`, `packagesInCatalog`,
|
|
23
|
+
* `KIND_LIST`, `gvRenderGraph`, `GV_LAYOUTS`, `gvRunLayout`, `gvSccHighlight`,
|
|
24
|
+
* `gvApplySccHighlight`, and the `gv*` control-state vars.
|
|
25
|
+
*/
|
|
26
|
+
export function dashboardGraphControlsJs() {
|
|
27
|
+
return String.raw `
|
|
28
|
+
// Append [value, label] option pairs to a select, marking 'current' selected.
|
|
29
|
+
function gvAddOptions(sel, pairs, current) {
|
|
30
|
+
for (var i = 0; i < pairs.length; i++) {
|
|
31
|
+
var opt = el('option', { value: pairs[i][0], text: pairs[i][1] });
|
|
32
|
+
if (pairs[i][0] === current) opt.selected = true;
|
|
33
|
+
sel.appendChild(opt);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The view's controls, laid out as a 2-row × 4-column CSS grid where each cell
|
|
38
|
+
// is a labeled control (label + control flex pair). Auto-flow fills 4 cells per
|
|
39
|
+
// row:
|
|
40
|
+
// Row 1: Layout · Scope · Search · Highlight cycles
|
|
41
|
+
// Row 2: Level · Package · Kind · Edges
|
|
42
|
+
// Self-contained (the shared Explore filter bar was removed). The Level
|
|
43
|
+
// dropdown decides what the graph shows; Package, Kind, AND Edges only apply at
|
|
44
|
+
// function level, so all three are DISABLED at package level (faded, not
|
|
45
|
+
// hidden) — consistent greying. Most changes re-render the graph in place via
|
|
46
|
+
// gvRenderGraph; Layout re-runs the layout on the live graph (no remount).
|
|
47
|
+
function gvRenderControls(host, catalog, indexes) {
|
|
48
|
+
function rerender() { gvRenderGraph(host, catalog, indexes); }
|
|
49
|
+
var fnLevel = (gvLevel === 'function');
|
|
50
|
+
var grid = el('div', { class: 'code-paths-graph-grid' });
|
|
51
|
+
// cell(labelText, control) — one labeled grid cell (label + control). A null
|
|
52
|
+
// labelText yields an unlabeled cell (used for the search box).
|
|
53
|
+
function cell(labelText, control) {
|
|
54
|
+
var c = el('div', { class: 'code-paths-graph-cell' });
|
|
55
|
+
if (labelText) c.appendChild(el('span', { class: 'code-paths-graph-toolbar-label', text: labelText }));
|
|
56
|
+
if (control) c.appendChild(control);
|
|
57
|
+
grid.appendChild(c);
|
|
58
|
+
return c;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---- Row 1: Layout · Scope · Search · Highlight cycles ----
|
|
62
|
+
// Layout — dropdown; re-runs the layout on the live graph (no full remount).
|
|
63
|
+
var layoutSel = el('select', { class: 'code-paths-graph-select', 'data-control': 'layout' });
|
|
64
|
+
gvAddOptions(layoutSel, GV_LAYOUTS.map(function(l) { return [l.id, l.label]; }), gvCurrentLayout);
|
|
65
|
+
layoutSel.addEventListener('change', function(e) { gvRunLayout(e.target.value); });
|
|
66
|
+
cell('Layout', layoutSel);
|
|
67
|
+
|
|
68
|
+
// Scope — always enabled. Production-only vs include-tests.
|
|
69
|
+
var scopeSel = el('select', { class: 'code-paths-graph-select', 'data-control': 'scope' });
|
|
70
|
+
gvAddOptions(scopeSel, [['prod', 'Production only'], ['tests', 'Include tests']], gvIncludeTests ? 'tests' : 'prod');
|
|
71
|
+
scopeSel.addEventListener('change', function(e) { gvIncludeTests = (e.target.value === 'tests'); rerender(); });
|
|
72
|
+
cell('Scope', scopeSel);
|
|
73
|
+
|
|
74
|
+
// Search (unlabeled cell) — the name search box.
|
|
75
|
+
var searchCell = el('div', { class: 'code-paths-graph-cell code-paths-graph-cell-search' });
|
|
76
|
+
gvRenderSearchBox(searchCell);
|
|
77
|
+
grid.appendChild(searchCell);
|
|
78
|
+
|
|
79
|
+
// Highlight cycles (unlabeled cell) — the checkbox toggle.
|
|
80
|
+
var cyclesCell = el('div', { class: 'code-paths-graph-cell' });
|
|
81
|
+
gvRenderCyclesToggle(cyclesCell);
|
|
82
|
+
grid.appendChild(cyclesCell);
|
|
83
|
+
|
|
84
|
+
// ---- Row 2: Level · Package · Kind · Edges ----
|
|
85
|
+
// Level — always enabled. Drives package vs function granularity.
|
|
86
|
+
var levelSel = el('select', { class: 'code-paths-graph-select', 'data-control': 'level' });
|
|
87
|
+
gvAddOptions(levelSel, [['package', 'Package'], ['function', 'Function']], gvLevel);
|
|
88
|
+
levelSel.addEventListener('change', function(e) { gvLevel = e.target.value; rerender(); });
|
|
89
|
+
cell('Level', levelSel);
|
|
90
|
+
|
|
91
|
+
// Package — single-select; function level only (disabled at package level).
|
|
92
|
+
var pkgs = (typeof packagesInCatalog === 'function') ? packagesInCatalog(catalog) : [];
|
|
93
|
+
var pkgSel = el('select', { class: 'code-paths-graph-select', 'data-control': 'package' });
|
|
94
|
+
pkgSel.appendChild(el('option', { value: '', text: pkgs.length ? '— select —' : '— none —' }));
|
|
95
|
+
gvAddOptions(pkgSel, pkgs.map(function(p) { return [p, p]; }), gvSelectedPackage);
|
|
96
|
+
pkgSel.disabled = !fnLevel;
|
|
97
|
+
pkgSel.addEventListener('change', function(e) { gvSelectedPackage = e.target.value || null; rerender(); });
|
|
98
|
+
cell('Package', pkgSel);
|
|
99
|
+
|
|
100
|
+
// Kind — multi-select dropdown; function level only (disabled at package
|
|
101
|
+
// level). A custom checkbox popover (gvMultiSelect) rather than a native
|
|
102
|
+
// <select multiple> listbox, which renders as an always-open box.
|
|
103
|
+
cell('Kind', gvMultiSelect({
|
|
104
|
+
id: 'kind',
|
|
105
|
+
items: (typeof KIND_LIST !== 'undefined') ? KIND_LIST : [],
|
|
106
|
+
selected: gvKinds,
|
|
107
|
+
allLabel: 'All kinds',
|
|
108
|
+
disabled: !fnLevel,
|
|
109
|
+
onClose: function(sel) { gvKinds = sel; rerender(); },
|
|
110
|
+
}));
|
|
111
|
+
|
|
112
|
+
// Edges — function level only: intra-package (default) vs + cross-package.
|
|
113
|
+
// Always present; disabled at package level (consistent with Package/Kind).
|
|
114
|
+
var edgeSel = el('select', { class: 'code-paths-graph-select', 'data-control': 'granularity' });
|
|
115
|
+
gvAddOptions(edgeSel, [['intra', 'Intra-package'], ['cross', '+ cross-package']], gvCrossPackage ? 'cross' : 'intra');
|
|
116
|
+
edgeSel.disabled = !fnLevel;
|
|
117
|
+
edgeSel.addEventListener('change', function(e) { gvCrossPackage = (e.target.value === 'cross'); rerender(); });
|
|
118
|
+
cell('Edges', edgeSel);
|
|
119
|
+
|
|
120
|
+
host.appendChild(grid);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// The "Highlight cycles" checkbox — rendered into the row-3 search row (beside
|
|
124
|
+
// the search box), not in the control grid. Package-level SCC emphasis; toggles
|
|
125
|
+
// the emphasis on the live graph in place (no re-render).
|
|
126
|
+
function gvRenderCyclesToggle(host) {
|
|
127
|
+
var sccToggle = el('label', { class: 'code-paths-graph-checkbox' });
|
|
128
|
+
var sccCb = el('input', { type: 'checkbox', 'data-scc-toggle': '1' });
|
|
129
|
+
sccCb.checked = gvSccHighlight;
|
|
130
|
+
sccCb.addEventListener('change', function() { gvSccHighlight = sccCb.checked; gvApplySccHighlight(); });
|
|
131
|
+
sccToggle.appendChild(sccCb);
|
|
132
|
+
sccToggle.appendChild(document.createTextNode(' Highlight cycles'));
|
|
133
|
+
host.appendChild(sccToggle);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// A compact multi-select dropdown: a trigger button + a checkbox popover.
|
|
137
|
+
// Native <select multiple> renders an ugly always-open listbox, so we roll a
|
|
138
|
+
// small popover instead. Checkboxes toggle the selection live and update the
|
|
139
|
+
// trigger label; the graph re-renders only when the panel CLOSES (trigger
|
|
140
|
+
// re-click or outside click) so a remount doesn't fire on every checkbox.
|
|
141
|
+
// opts: { id, items:[string], selected:[string], allLabel, disabled, onClose }
|
|
142
|
+
function gvMultiSelect(opts) {
|
|
143
|
+
var wrap = el('div', { class: 'code-paths-graph-ms' });
|
|
144
|
+
var selected = opts.selected.slice();
|
|
145
|
+
function triggerLabel() {
|
|
146
|
+
if (selected.length === 0) return opts.allLabel;
|
|
147
|
+
if (selected.length === 1) return selected[0];
|
|
148
|
+
return selected.length + ' selected';
|
|
149
|
+
}
|
|
150
|
+
var trigger = el('button', { class: 'code-paths-graph-select code-paths-graph-ms-trigger', 'data-control': opts.id, text: triggerLabel() + ' ▾' });
|
|
151
|
+
trigger.disabled = !!opts.disabled;
|
|
152
|
+
var panel = el('div', { class: 'code-paths-graph-ms-panel' });
|
|
153
|
+
panel.style.display = 'none';
|
|
154
|
+
var open = false;
|
|
155
|
+
var docHandler = null;
|
|
156
|
+
function close() {
|
|
157
|
+
if (!open) return;
|
|
158
|
+
open = false;
|
|
159
|
+
panel.style.display = 'none';
|
|
160
|
+
if (docHandler) { document.removeEventListener('mousedown', docHandler); docHandler = null; }
|
|
161
|
+
opts.onClose(selected.slice());
|
|
162
|
+
}
|
|
163
|
+
function openPanel() {
|
|
164
|
+
if (open || opts.disabled) return;
|
|
165
|
+
open = true;
|
|
166
|
+
panel.style.display = 'block';
|
|
167
|
+
docHandler = function(e) { if (!wrap.contains(e.target)) close(); };
|
|
168
|
+
document.addEventListener('mousedown', docHandler);
|
|
169
|
+
}
|
|
170
|
+
trigger.addEventListener('click', function() { if (open) close(); else openPanel(); });
|
|
171
|
+
for (var i = 0; i < opts.items.length; i++) {
|
|
172
|
+
(function(item) {
|
|
173
|
+
var row = el('label', { class: 'code-paths-graph-ms-item' });
|
|
174
|
+
var cb = el('input', { type: 'checkbox' });
|
|
175
|
+
cb.checked = selected.indexOf(item) >= 0;
|
|
176
|
+
cb.addEventListener('change', function() {
|
|
177
|
+
var ix = selected.indexOf(item);
|
|
178
|
+
if (cb.checked && ix < 0) selected.push(item);
|
|
179
|
+
else if (!cb.checked && ix >= 0) selected.splice(ix, 1);
|
|
180
|
+
trigger.textContent = triggerLabel() + ' ▾';
|
|
181
|
+
});
|
|
182
|
+
row.appendChild(cb);
|
|
183
|
+
row.appendChild(document.createTextNode(' ' + item));
|
|
184
|
+
panel.appendChild(row);
|
|
185
|
+
})(opts.items[i]);
|
|
186
|
+
}
|
|
187
|
+
wrap.appendChild(trigger);
|
|
188
|
+
wrap.appendChild(panel);
|
|
189
|
+
return wrap;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Project the function-level graph for a single package, client-side from the
|
|
193
|
+
// embedded catalog indexes (the package->package view-model blob can't express
|
|
194
|
+
// it). Nodes = the package's functions passing the Scope/Kind filters; edges =
|
|
195
|
+
// resolved function->function calls. Intra-package mode keeps only calls whose
|
|
196
|
+
// callee is in the same package; "+ cross-package" mode also keeps calls
|
|
197
|
+
// leaving the package, drawing the external callee as a faded node. Node size
|
|
198
|
+
// (totalCoupling) is the incident-edge degree. Bounded by package size.
|
|
199
|
+
function gvBuildFunctionElements(indexes, pkg, includeTests, kinds, crossPackage) {
|
|
200
|
+
var elements = [];
|
|
201
|
+
if (!indexes || !indexes.occurrencesByHash || !indexes.callees) return elements;
|
|
202
|
+
var kindSet = (kinds && kinds.length) ? kinds : null;
|
|
203
|
+
function passes(occ) {
|
|
204
|
+
if (!includeTests && occ.inTestFile) return false;
|
|
205
|
+
if (kindSet && kindSet.indexOf(occ.kind) < 0) return false;
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Seeds: one occurrence per bodyHash that lives in 'pkg' and passes filters.
|
|
210
|
+
var seeds = [];
|
|
211
|
+
var seenSeed = {};
|
|
212
|
+
indexes.occurrencesByHash.forEach(function(occs) {
|
|
213
|
+
for (var i = 0; i < occs.length; i++) {
|
|
214
|
+
if (pkgOf(occs[i]) === pkg && passes(occs[i])) {
|
|
215
|
+
if (!seenSeed[occs[i].bodyHash]) { seenSeed[occs[i].bodyHash] = true; seeds.push(occs[i]); }
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
var nodeIds = {};
|
|
222
|
+
var degree = {};
|
|
223
|
+
function addNode(occ, external) {
|
|
224
|
+
if (nodeIds[occ.bodyHash]) return;
|
|
225
|
+
nodeIds[occ.bodyHash] = true;
|
|
226
|
+
if (degree[occ.bodyHash] === undefined) degree[occ.bodyHash] = 0;
|
|
227
|
+
elements.push({ group: 'nodes', data: { id: occ.bodyHash, label: displayName(occ.simpleName), external: external ? 1 : 0, totalCoupling: 0 } });
|
|
228
|
+
}
|
|
229
|
+
for (var s = 0; s < seeds.length; s++) addNode(seeds[s], false);
|
|
230
|
+
|
|
231
|
+
var edgeSeen = {};
|
|
232
|
+
for (var s2 = 0; s2 < seeds.length; s2++) {
|
|
233
|
+
var seed = seeds[s2];
|
|
234
|
+
var targets = indexes.callees.get(seed.bodyHash) || [];
|
|
235
|
+
for (var t = 0; t < targets.length; t++) {
|
|
236
|
+
var callee = resolveCalleeOcc(targets[t], seed, indexes);
|
|
237
|
+
if (!callee) continue;
|
|
238
|
+
var external = (pkgOf(callee) !== pkg);
|
|
239
|
+
if (external && !crossPackage) continue;
|
|
240
|
+
if (!external && !passes(callee)) continue;
|
|
241
|
+
addNode(callee, external);
|
|
242
|
+
var ekey = seed.bodyHash + '\n' + callee.bodyHash;
|
|
243
|
+
if (edgeSeen[ekey]) continue;
|
|
244
|
+
edgeSeen[ekey] = true;
|
|
245
|
+
elements.push({ group: 'edges', data: { id: 'fe' + s2 + '_' + t, source: seed.bodyHash, target: callee.bodyHash, weight: 1, isCycleEdge: false } });
|
|
246
|
+
degree[seed.bodyHash] = (degree[seed.bodyHash] || 0) + 1;
|
|
247
|
+
degree[callee.bodyHash] = (degree[callee.bodyHash] || 0) + 1;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
for (var e = 0; e < elements.length; e++) {
|
|
251
|
+
if (elements[e].group === 'nodes') elements[e].data.totalCoupling = degree[elements[e].data.id] || 0;
|
|
252
|
+
}
|
|
253
|
+
return elements;
|
|
254
|
+
}
|
|
255
|
+
`;
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=graph-controls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-controls.js","sourceRoot":"","sources":["../../src/code-paths/graph-controls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoOlB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Strongly-connected-components (Tarjan) over the graph view
|
|
3
|
+
* model's node/edge set.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from `graph-view-model.ts` to keep that projector under the
|
|
6
|
+
* file-length budget. The algorithm is purely structural — it operates on
|
|
7
|
+
* string ids and an adjacency map, with no dependency on the view-model
|
|
8
|
+
* shapes — so it lives as a standalone, reusable unit.
|
|
9
|
+
*
|
|
10
|
+
* Replicated here rather than imported from the graph engine: the
|
|
11
|
+
* catalog-decoupling rule forbids `dashboard → @opensip-cli/graph`.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Build a directed adjacency map (`source id → unique target ids`) from a
|
|
15
|
+
* node set and edge set. Generic over any `{ id }` node and
|
|
16
|
+
* `{ source, target }` edge so it stays independent of the view-model types.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildAdjacency(nodes: readonly {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
}[], edges: readonly {
|
|
21
|
+
readonly source: string;
|
|
22
|
+
readonly target: string;
|
|
23
|
+
}[]): Map<string, string[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Tarjan's strongly-connected-components algorithm (iterative, no recursion
|
|
26
|
+
* so deep call graphs don't blow the stack). Returns a map from node id → SCC
|
|
27
|
+
* id, populated ONLY for nodes in a non-trivial SCC (size ≥ 2, or a singleton
|
|
28
|
+
* with a self-edge). Trivial singletons are omitted so the view treats them
|
|
29
|
+
* as `sccId: null`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function tarjanSccIds(nodeIds: readonly string[], adjacency: ReadonlyMap<string, string[]>): Map<string, string>;
|
|
32
|
+
//# sourceMappingURL=graph-scc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-scc.d.ts","sourceRoot":"","sources":["../../src/code-paths/graph-scc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EACzC,KAAK,EAAE,SAAS;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,GACrE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAQvB;AAgBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GACvC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBrB"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Strongly-connected-components (Tarjan) over the graph view
|
|
3
|
+
* model's node/edge set.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from `graph-view-model.ts` to keep that projector under the
|
|
6
|
+
* file-length budget. The algorithm is purely structural — it operates on
|
|
7
|
+
* string ids and an adjacency map, with no dependency on the view-model
|
|
8
|
+
* shapes — so it lives as a standalone, reusable unit.
|
|
9
|
+
*
|
|
10
|
+
* Replicated here rather than imported from the graph engine: the
|
|
11
|
+
* catalog-decoupling rule forbids `dashboard → @opensip-cli/graph`.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Build a directed adjacency map (`source id → unique target ids`) from a
|
|
15
|
+
* node set and edge set. Generic over any `{ id }` node and
|
|
16
|
+
* `{ source, target }` edge so it stays independent of the view-model types.
|
|
17
|
+
*/
|
|
18
|
+
export function buildAdjacency(nodes, edges) {
|
|
19
|
+
const adjacency = new Map();
|
|
20
|
+
for (const node of nodes)
|
|
21
|
+
adjacency.set(node.id, []);
|
|
22
|
+
for (const edge of edges) {
|
|
23
|
+
const out = adjacency.get(edge.source);
|
|
24
|
+
if (out && !out.includes(edge.target))
|
|
25
|
+
out.push(edge.target);
|
|
26
|
+
}
|
|
27
|
+
return adjacency;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Tarjan's strongly-connected-components algorithm (iterative, no recursion
|
|
31
|
+
* so deep call graphs don't blow the stack). Returns a map from node id → SCC
|
|
32
|
+
* id, populated ONLY for nodes in a non-trivial SCC (size ≥ 2, or a singleton
|
|
33
|
+
* with a self-edge). Trivial singletons are omitted so the view treats them
|
|
34
|
+
* as `sccId: null`.
|
|
35
|
+
*/
|
|
36
|
+
export function tarjanSccIds(nodeIds, adjacency) {
|
|
37
|
+
const state = {
|
|
38
|
+
index: new Map(),
|
|
39
|
+
lowlink: new Map(),
|
|
40
|
+
onStack: new Set(),
|
|
41
|
+
stack: [],
|
|
42
|
+
components: [],
|
|
43
|
+
nextIndex: 0,
|
|
44
|
+
};
|
|
45
|
+
for (const start of nodeIds) {
|
|
46
|
+
if (state.index.has(start))
|
|
47
|
+
continue;
|
|
48
|
+
const work = [{ v: start, ai: 0 }];
|
|
49
|
+
while (work.length > 0) {
|
|
50
|
+
stepTarjanFrame(work, state, adjacency);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return assignSccIds(state.components, adjacency);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Advance the top Tarjan work-frame by one DFS step: visit the node on
|
|
57
|
+
* first touch, descend into the next unvisited successor, or — when the
|
|
58
|
+
* frame is exhausted — close out its SCC root and propagate lowlink to the
|
|
59
|
+
* parent frame before popping.
|
|
60
|
+
*/
|
|
61
|
+
function stepTarjanFrame(work, state, adjacency) {
|
|
62
|
+
const frame = work.at(-1);
|
|
63
|
+
const v = frame.v;
|
|
64
|
+
if (frame.ai === 0) {
|
|
65
|
+
state.index.set(v, state.nextIndex);
|
|
66
|
+
state.lowlink.set(v, state.nextIndex);
|
|
67
|
+
state.nextIndex += 1;
|
|
68
|
+
state.stack.push(v);
|
|
69
|
+
state.onStack.add(v);
|
|
70
|
+
}
|
|
71
|
+
const descendInto = scanSuccessors(frame, state, adjacency);
|
|
72
|
+
if (descendInto !== null) {
|
|
73
|
+
work.push({ v: descendInto, ai: 0 });
|
|
74
|
+
return; // descend
|
|
75
|
+
}
|
|
76
|
+
if (state.lowlink.get(v) === state.index.get(v))
|
|
77
|
+
popComponent(v, state);
|
|
78
|
+
work.pop();
|
|
79
|
+
const parent = work.length > 0 ? work.at(-1).v : null;
|
|
80
|
+
if (parent !== null && state.lowlink.get(v) < state.lowlink.get(parent)) {
|
|
81
|
+
state.lowlink.set(parent, state.lowlink.get(v));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Scan the frame's remaining successors, updating lowlink for already-
|
|
86
|
+
* visited on-stack nodes. Returns the first unvisited successor to descend
|
|
87
|
+
* into (leaving `frame.ai` pointing past it), or `null` when exhausted.
|
|
88
|
+
*/
|
|
89
|
+
function scanSuccessors(frame, state, adjacency) {
|
|
90
|
+
const v = frame.v;
|
|
91
|
+
const adj = adjacency.get(v) ?? [];
|
|
92
|
+
while (frame.ai < adj.length) {
|
|
93
|
+
const w = adj[frame.ai];
|
|
94
|
+
frame.ai += 1;
|
|
95
|
+
if (!state.index.has(w))
|
|
96
|
+
return w;
|
|
97
|
+
if (state.onStack.has(w)) {
|
|
98
|
+
const iw = state.index.get(w);
|
|
99
|
+
if (iw < state.lowlink.get(v))
|
|
100
|
+
state.lowlink.set(v, iw);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
/** Pop the stack down to SCC root `v`, recording the component. */
|
|
106
|
+
function popComponent(v, state) {
|
|
107
|
+
const component = [];
|
|
108
|
+
for (;;) {
|
|
109
|
+
const w = state.stack.pop();
|
|
110
|
+
state.onStack.delete(w);
|
|
111
|
+
component.push(w);
|
|
112
|
+
if (w === v)
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
state.components.push(component);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Assign a stable sccId per non-trivial component. A singleton counts as
|
|
119
|
+
* cyclic only when it has a self-edge; trivial singletons are omitted so
|
|
120
|
+
* the view treats them as `sccId: null`.
|
|
121
|
+
*/
|
|
122
|
+
function assignSccIds(components, adjacency) {
|
|
123
|
+
const sccByNode = new Map();
|
|
124
|
+
for (const component of components) {
|
|
125
|
+
const isCyclic = component.length >= 2 ||
|
|
126
|
+
(component.length === 1 && (adjacency.get(component[0]) ?? []).includes(component[0]));
|
|
127
|
+
if (!isCyclic)
|
|
128
|
+
continue;
|
|
129
|
+
// Deterministic id: smallest member id (components are not pre-sorted).
|
|
130
|
+
const sccId = `scc:${[...component].sort()[0]}`;
|
|
131
|
+
for (const member of component)
|
|
132
|
+
sccByNode.set(member, sccId);
|
|
133
|
+
}
|
|
134
|
+
return sccByNode;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=graph-scc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-scc.js","sourceRoot":"","sources":["../../src/code-paths/graph-scc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Cytoscape stylesheet for the Code Graph "Visualization" view.
|
|
3
|
+
*
|
|
4
|
+
* A render helper (registers no view), extracted from `view-graph.ts` to keep
|
|
5
|
+
* that emitter under the file-length budget and deliberately named out of the
|
|
6
|
+
* `view-*` namespace so it stays clear of the views-disjoint architecture
|
|
7
|
+
* rule. Emits the `gvStylesheet()` browser function as a JS string; the main
|
|
8
|
+
* emitter interpolates it into its `<script>` body.
|
|
9
|
+
*
|
|
10
|
+
* PACKAGE granularity (item 10): nodes are packages, not functions. The
|
|
11
|
+
* visual encoding is therefore simpler than the function-level original —
|
|
12
|
+
* uniform round-rectangle nodes sized by total coupling degree, edges
|
|
13
|
+
* thickened by call-count weight, plus the cross-package SCC accent and the
|
|
14
|
+
* shared selection/search/impact highlight classes.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Emit the `gvStylesheet()` browser function as a JS string. No leading or
|
|
18
|
+
* trailing newline, so the main emitter can interpolate it where the inline
|
|
19
|
+
* function used to sit.
|
|
20
|
+
*/
|
|
21
|
+
export declare function dashboardViewGraphStylesheetJs(): string;
|
|
22
|
+
//# sourceMappingURL=graph-stylesheet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-stylesheet.d.ts","sourceRoot":"","sources":["../../src/code-paths/graph-stylesheet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CAmGvD"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Cytoscape stylesheet for the Code Graph "Visualization" view.
|
|
3
|
+
*
|
|
4
|
+
* A render helper (registers no view), extracted from `view-graph.ts` to keep
|
|
5
|
+
* that emitter under the file-length budget and deliberately named out of the
|
|
6
|
+
* `view-*` namespace so it stays clear of the views-disjoint architecture
|
|
7
|
+
* rule. Emits the `gvStylesheet()` browser function as a JS string; the main
|
|
8
|
+
* emitter interpolates it into its `<script>` body.
|
|
9
|
+
*
|
|
10
|
+
* PACKAGE granularity (item 10): nodes are packages, not functions. The
|
|
11
|
+
* visual encoding is therefore simpler than the function-level original —
|
|
12
|
+
* uniform round-rectangle nodes sized by total coupling degree, edges
|
|
13
|
+
* thickened by call-count weight, plus the cross-package SCC accent and the
|
|
14
|
+
* shared selection/search/impact highlight classes.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Emit the `gvStylesheet()` browser function as a JS string. No leading or
|
|
18
|
+
* trailing newline, so the main emitter can interpolate it where the inline
|
|
19
|
+
* function used to sit.
|
|
20
|
+
*/
|
|
21
|
+
export function dashboardViewGraphStylesheetJs() {
|
|
22
|
+
return String.raw `function gvStylesheet() {
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
selector: 'node',
|
|
26
|
+
style: {
|
|
27
|
+
'background-color': '#c4956a',
|
|
28
|
+
'border-color': function(ele) { return ele.data('sccColor') || '#8a8a8a'; },
|
|
29
|
+
'border-width': function(ele) { return ele.data('sccId') ? 3 : 1; },
|
|
30
|
+
'shape': 'round-rectangle',
|
|
31
|
+
// Size by total coupling degree (fan-in + fan-out call count). The
|
|
32
|
+
// log-ish clamp keeps a megabus package from dwarfing the canvas.
|
|
33
|
+
'width': function(ele) { return 22 + Math.min(56, Math.sqrt(ele.data('totalCoupling') || 0) * 6); },
|
|
34
|
+
'height': function(ele) { return 22 + Math.min(56, Math.sqrt(ele.data('totalCoupling') || 0) * 6); },
|
|
35
|
+
'label': function(ele) { return ele.data('label') || ''; },
|
|
36
|
+
'font-size': 9,
|
|
37
|
+
'color': '#ddd',
|
|
38
|
+
'text-valign': 'bottom',
|
|
39
|
+
'text-halign': 'center',
|
|
40
|
+
'text-margin-y': 2,
|
|
41
|
+
'text-wrap': 'none',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
selector: 'edge',
|
|
46
|
+
style: {
|
|
47
|
+
// Thickness by call-count weight (clamped). A solid uniform style —
|
|
48
|
+
// resolution/confidence encoding is function-level and not meaningful
|
|
49
|
+
// once edges are aggregated to packages.
|
|
50
|
+
'width': function(ele) { return 1 + Math.min(7, Math.sqrt(ele.data('weight') || 1) * 1.2); },
|
|
51
|
+
'line-color': '#5a5a5a',
|
|
52
|
+
'target-arrow-color': '#5a5a5a',
|
|
53
|
+
'target-arrow-shape': 'triangle',
|
|
54
|
+
'arrow-scale': 0.8,
|
|
55
|
+
'curve-style': 'bezier',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
selector: 'edge[?isCycleEdge]',
|
|
60
|
+
style: { 'line-color': '#d46a6a', 'target-arrow-color': '#d46a6a' },
|
|
61
|
+
},
|
|
62
|
+
// Function-level "+ cross-package" mode only: a callee that lives OUTSIDE
|
|
63
|
+
// the selected package is drawn as a faded ellipse so the boundary reads
|
|
64
|
+
// at a glance. Package-level view-models never set 'external', so this
|
|
65
|
+
// selector is inert there.
|
|
66
|
+
{
|
|
67
|
+
selector: 'node[?external]',
|
|
68
|
+
style: { 'background-color': '#3a3a3a', 'border-color': '#666', 'color': '#9a9a9a', 'shape': 'ellipse', 'opacity': 0.55 },
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
selector: 'node.gv-search-hit',
|
|
72
|
+
style: { 'background-color': '#e0a96d', 'border-color': '#fff', 'border-width': 3, 'opacity': 1 },
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
selector: 'node.gv-search-fade',
|
|
76
|
+
style: { 'opacity': 0.12 },
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
selector: 'edge.gv-search-fade',
|
|
80
|
+
style: { 'opacity': 0.05 },
|
|
81
|
+
},
|
|
82
|
+
// Impact highlight (adapted to packages): clicking a package lights its
|
|
83
|
+
// direct caller packages (upstream) and callee packages (downstream).
|
|
84
|
+
// Accent palette mirrors the dashboard theme: --accent (selected),
|
|
85
|
+
// --accent-fitness (downstream), --accent-sim (upstream). Hard-coded
|
|
86
|
+
// because the Cytoscape canvas can't read CSS custom properties.
|
|
87
|
+
{
|
|
88
|
+
selector: 'node.gv-selected',
|
|
89
|
+
style: { 'background-color': '#e0a96d', 'border-color': '#fff', 'border-width': 4, 'opacity': 1 },
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
selector: 'node.gv-upstream',
|
|
93
|
+
style: { 'background-color': '#6a9bd4', 'opacity': 1 },
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
selector: 'node.gv-downstream',
|
|
97
|
+
style: { 'background-color': '#7ec47e', 'opacity': 1 },
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
selector: '.gv-dimmed',
|
|
101
|
+
style: { 'opacity': 0.1 },
|
|
102
|
+
},
|
|
103
|
+
// Cross-package cycle highlight (folded-in "Cycles / SCCs" affordance).
|
|
104
|
+
// Cycle members get a bright accent fill; cycle edges turn red and
|
|
105
|
+
// thicken; the acyclic remainder fades so multi-package cycles stand out.
|
|
106
|
+
{
|
|
107
|
+
selector: 'node.gv-scc-member',
|
|
108
|
+
style: { 'background-color': '#d46a6a', 'border-color': '#fff', 'border-width': 3, 'opacity': 1 },
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
selector: 'edge.gv-scc-edge',
|
|
112
|
+
style: { 'line-color': '#d46a6a', 'target-arrow-color': '#d46a6a', 'width': 3, 'opacity': 1 },
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
selector: '.gv-scc-dimmed',
|
|
116
|
+
style: { 'opacity': 0.08 },
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
}`;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=graph-stylesheet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-stylesheet.js","sourceRoot":"","sources":["../../src/code-paths/graph-stylesheet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;GAIG;AACH,MAAM,UAAU,8BAA8B;IAC5C,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiGjB,CAAC;AACH,CAAC"}
|