blob: 1bcfaad3e2472704df0483043ade6fd0758f6070 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import type { PluginNode } from "./types";
/** The two highlight sets for the §8 bidirectional dependency hover. */
export interface HighlightSets {
/** The hovered row's DIRECT dependencies (highlighted when hovering an item). */
readonly deps: ReadonlySet<string>;
/** The loaded/unloaded rows that DIRECTLY depend on the hovered row
* (highlighted when hovering a dependency). */
readonly dependents: ReadonlySet<string>;
}
const EMPTY: HighlightSets = { deps: new Set(), dependents: new Set() };
/**
* Bidirectional hover highlighting (§8): hover any item → its DIRECT
* dependencies highlight; hover a dependency → its dependents highlight.
* One hop in each direction (the plan's grammar is "its dependencies" /
* "its dependents" — the visual neighborhood, not the transitive closure;
* the transitive closures live in `computeCascade` / `autoCheckBackendPrereqs`).
*
* Works across BOTH manager tables (a loaded row can highlight an unloaded
* dependency row and vice versa) — the node list spans the whole catalog.
* Pure input → output; `hoveredId` null (no hover) → both sets empty.
*/
export function dependencyHighlightSets(
hoveredId: string | null,
nodes: readonly PluginNode[],
): HighlightSets {
if (hoveredId === null) return EMPTY;
const hovered = nodes.find((n) => n.id === hoveredId);
if (hovered === undefined) return EMPTY;
const deps = new Set(hovered.dependsOn);
const dependents = new Set(
nodes.filter((n) => n.id !== hoveredId && n.dependsOn.includes(hoveredId)).map((n) => n.id),
);
return { deps, dependents };
}
|