# core/analyzers/invocation.analyzer.ts

> 62 lines of code and 16 definitions.

Tree: GovLab Docs
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/docs#file-docs-core-analyzers-invocation-analyzer-ts
Source text: https://banes-lab.com/source/docs/core/analyzers/invocation.analyzer.ts.txt

Listed in [core/analyzers](https://banes-lab.com/api/source/docs/core/analyzers.md), after [core/analyzers/graph.analyzer.ts](https://banes-lab.com/source/docs/core/analyzers/graph.analyzer.ts.md) and before [core/analyzers/location.analyzer.ts](https://banes-lab.com/source/docs/core/analyzers/location.analyzer.ts.md).

## Definitions

- `adjacencyOf` (lexical_declaration, line 7, exported)
- `byId` (lexical_declaration, line 3)
- `adjacency` (lexical_declaration, line 8, exported)
- `reachableFrom` (lexical_declaration, line 15, exported)
- `order` (lexical_declaration, line 16, exported)
- `visited` (lexical_declaration, line 17, exported)
- `stack` (lexical_declaration, line 18, exported)
- `id` (lexical_declaration, line 19, exported)
- `incidentKeptEdges` (lexical_declaration, line 31)
- `selectWithinEdgeBudget` (lexical_declaration, line 40, exported)
- `kept` (lexical_declaration, line 45, exported)
- `edgeCount` (lexical_declaration, line 46, exported)
- `added` (lexical_declaration, line 48, exported)
- `rootIds` (lexical_declaration, line 58, exported)
- `roots` (lexical_declaration, line 59, exported)
- `[first]` (lexical_declaration, line 66, exported)

## Contained in

- [core/analyzers](https://banes-lab.com/anatomy/docs/folder-docs-core-analyzers.md)

## Used by

- [core/plugins/diagram.invocation.plugin.ts](https://banes-lab.com/source/docs/core/plugins/diagram.invocation.plugin.ts.md)

## Linked from

- [core/plugins](https://banes-lab.com/anatomy/docs/folder-docs-core-plugins.md)

## Source

```typescript
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] : [];
};
```
