/** * View-model projection for the Code Graph "Visualization" view. * * Projects the raw graph `GraphCatalog` (consumed by JSON shape from * `@opensip-tools/contracts` — never from `@opensip-tools/graph`) into * the slim, embed-ready `GraphViewModel` the Cytoscape renderer consumes. * * PACKAGE-LEVEL projection (item 10): the visualization renders a * node-link graph at *package* granularity, NOT function granularity. * Function-level catalogs on real repos contain thousands of function * nodes — unusable in a node-link layout. This projector aggregates the * function call graph up to packages: * * - Node = one package (id = label = package name via the same * attribution the Coupling view uses — see `packageOf` below, which * mirrors `pkgOf` in `path-utils.ts`). * - Edge = caller-package → callee-package, with `weight` = the number * of underlying function→function call edges between those packages. * * This is intentionally the same package→package data the Coupling grid * shows — a node-link rendering of it rather than a matrix. Every OTHER * consumer (Coupling drilldown, Functions table, rules, …) still reads * the function-level catalog directly; only THIS view aggregates up. * * This module is the bundle-size budget enforcement point: the report * ships what this projector emits, not the catalog's storage shape. * * Architecture decisions: * - Projection runs at report-generation time (server-side, in * `generator.ts`) and the result is embedded as a JSON blob, mirroring * the existing `graph-catalog` blob. * - Cross-package cycles are detected with Tarjan's SCC over the package * graph (cheap at package granularity — tens of nodes, not thousands). * The engine's SCC implementation is off-limits to this package (the * catalog-decoupling rule §2.4); the local replica lives in the sibling * `graph-scc.ts` module. */ import type { GraphCatalog, GraphFunctionOccurrence } from '@opensip-tools/contracts'; /** * Slim, embed-ready projection of a graph catalog for the dashboard's * Visualization view. Produced by {@link projectCatalogToGraphViewModel} * and consumed by `view-graph.ts`. * * Aggregated to PACKAGE granularity — one node per package, one edge per * directed package→package coupling. */ export interface GraphViewModel { /** * Catalog-level language (e.g. `'typescript'`). Copied here so the view * doesn't need a separate handle on `graphCatalog`. The catalog is * single-language; this is NOT a per-node filter. */ readonly language: string; readonly nodes: readonly GraphViewModelNode[]; readonly edges: readonly GraphViewModelEdge[]; } export interface GraphViewModelNode { /** Stable handle AND display label — the package name. */ readonly id: string; /** Display label — the package name (same as {@link id}). */ readonly label: string; /** * Total coupling degree = fan-in + fan-out call count (sum of incident * edge weights). Drives node *size* — hub packages render larger. * Pre-computed here so the renderer can size without re-iterating edges. */ readonly totalCoupling: number; /** * SCC membership over the PACKAGE graph. `null` = not in a non-trivial * package-level cycle. Non-null = string id shared by every package in * the same cyclic cluster. Drives cross-package-cycle highlighting. */ readonly sccId: string | null; } export interface GraphViewModelEdge { /** Source package name (caller). */ readonly source: string; /** Target package name (callee). */ readonly target: string; /** * Number of underlying function→function call edges from the source * package into the target package. Drives edge *thickness*. */ readonly weight: number; /** * `true` iff this edge participates in a package-level cycle (both * endpoints in the same non-null `sccId`). Highlights cross-package * cycle backbones in concert with the node `sccId` grouping. */ readonly isCycleEdge: boolean; } /** Thrown when the catalog is structurally unusable for projection. */ export declare class GraphViewModelError extends Error { constructor(message: string); } /** * Project a graph catalog into the slim, PACKAGE-LEVEL {@link GraphViewModel}. * * Pure function — no I/O, no side effects. Four passes: * - Pass A: map every function `bodyHash` to its package (so call targets, * which are bodyHashes, can be resolved to a package). * - Pass B: walk function call edges, aggregate to package→package edges * keyed by `caller→callee`, accumulating a call-count `weight`. * - Pass C: derive package nodes (one per package seen) and accumulate * `totalCoupling` (fan-in + fan-out weight) on each. * - Pass D: Tarjan SCC over the package graph — stamp `sccId` on cyclic * packages and `isCycleEdge` on edges whose endpoints share an `sccId`. * * @throws {GraphViewModelError} when `catalog` or `catalog.functions` is missing. */ export declare function projectCatalogToGraphViewModel(catalog: GraphCatalog): GraphViewModel; /** * The package a function occurrence belongs to. Mirrors `pkgOf` in * `path-utils.ts` (the browser-side helper the Coupling view uses) so the * server-side projection and the client-side coupling matrix attribute * functions to packages identically: prefer the build-time-stamped * `occurrence.package` (scope-stripped), else the path heuristic. */ export declare function packageOf(occ: GraphFunctionOccurrence): string; //# sourceMappingURL=graph-view-model.d.ts.map