core/analyzers/invocation.analyzer.ts
core/analyzers/invocation.analyzer.ts is a file in GovLab Docs. 62 lines of code and 16 definitions.
import type { CodeEdge, CodeGraph } from "#types/graph.types";
const byId = function byId(left: string, right: string): number {
return left.localeCompare(right);
};
export const adjacencyOf = function adjacencyOf(graph: CodeGraph): Map<string, string[]> {
const adjacency = new Map<string, string[]>();
for (const edge of graph.edges) {
adjacency.set(edge.from, [...(adjacency.get(edge.from) ?? []), edge.to]);
}
return adjacency;
};
export const reachableFrom = function reachableFrom(root: string, adjacency: ReadonlyMap<string, string[]>): string[] {
const order: string[] = [];
const visited = new Set<string>();
const stack = [root];
let id = stack.pop();
while (id !== undefined) {
if (!visited.has(id)) {
visited.add(id);
order.push(id);
stack.push(...(adjacency.get(id) ?? []).toSorted(byId).toReversed());
}
id = stack.pop();
}
return order;
};
const incidentKeptEdges = function incidentKeptEdges(
id: string,
edges: readonly CodeEdge[],
kept: ReadonlySet<string>,
): number {
return edges.filter((edge) => (edge.from === id && kept.has(edge.to)) || (edge.to === id && kept.has(edge.from)))
.length;
};
export const selectWithinEdgeBudget = function selectWithinEdgeBudget(
order: readonly string[],
edges: readonly CodeEdge[],
budget: number,
): Set<string> {
const kept = new Set<string>();
let edgeCount = 0;
for (const id of order) {
const added = incidentKeptEdges(id, edges, kept);
if (edgeCount + added > budget) {
return kept;
}
kept.add(id);
edgeCount += added;
}
return kept;
};
export const rootIds = function rootIds(graph: CodeGraph): string[] {
const roots = graph.nodes
.filter((node) => node.kind === "entry" || node.kind === "factory")
.map((node) => node.id)
.toSorted(byId);
if (roots.length > 0) {
return roots;
}
const [first] = graph.nodes.toSorted((left, right) => byId(left.id, right.id));
return first ? [first.id] : [];
};