# core/plugins/diagram.structure.plugin.ts

> 60 lines of code and 15 definitions.

Tree: GovLab Docs
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/docs#file-docs-core-plugins-diagram-structure-plugin-ts
Source text: https://banes-lab.com/source/docs/core/plugins/diagram.structure.plugin.ts.txt

Listed in [core/plugins](https://banes-lab.com/api/source/docs/core/plugins.md), after [core/plugins/diagram.shell.plugin.ts](https://banes-lab.com/source/docs/core/plugins/diagram.shell.plugin.ts.md) and before [core/plugins/manifest.agent.plugin.ts](https://banes-lab.com/source/docs/core/plugins/manifest.agent.plugin.ts.md).

## Definitions

- `isStructEdge` (lexical_declaration, line 17)
- `structRelations` (lexical_declaration, line 21)
- `render` (method_definition, line 43, exported)
- `STRUCT_KINDS` (lexical_declaration, line 13)
- `STRUCT_EDGE_KINDS` (lexical_declaration, line 14)
- `MIN_STRUCT_NODES` (lexical_declaration, line 15)
- `byKey` (lexical_declaration, line 25)
- `key` (lexical_declaration, line 27)
- `diagram` (lexical_declaration, line 35, exported)
- `appliesTo` (method_definition, line 36, exported)
- `graph` (lexical_declaration, line 47, exported)
- `structNodes` (lexical_declaration, line 48, exported)
- `ids` (lexical_declaration, line 49, exported)
- `classes` (lexical_declaration, line 50, exported)
- `model` (lexical_declaration, line 51, exported)

## Contained in

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

## Uses

- [core/formatters/diagram.structure.formatter.ts](https://banes-lab.com/source/docs/core/formatters/diagram.structure.formatter.ts.md)

## Linked from

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

## Source

```typescript
import type { ClassBox, ClassModel, ClassRelation } from "#types/diagram.types";
import type { CodeEdge, CodeNodeKind } from "#types/graph.types";
import {
    DIAGRAM_DESCRIPTIONS,
    DIAGRAM_TITLES,
    KIND_LEGEND,
    structureTitle,
} from "#configuration/strings/figure.strings";
import type { DiagramKind } from "#types/figure.types";
import { collapseByLabel } from "#core/converters/graph.converter";
import { emitClassDiagram } from "#core/formatters/diagram.structure.formatter";

const STRUCT_KINDS: ReadonlySet<CodeNodeKind> = new Set<CodeNodeKind>(["entry", "factory", "collaborator", "registry"]);
const STRUCT_EDGE_KINDS: ReadonlySet<CodeEdge["kind"]> = new Set<CodeEdge["kind"]>(["call", "data-flow"]);
const MIN_STRUCT_NODES = 2;

const isStructEdge = function isStructEdge(edge: CodeEdge, ids: ReadonlySet<string>): boolean {
    return ids.has(edge.from) && ids.has(edge.to) && STRUCT_EDGE_KINDS.has(edge.kind);
};

const structRelations = function structRelations(
    edges: readonly CodeEdge[],
    ids: ReadonlySet<string>,
): ClassRelation[] {
    const byKey = new Map<string, ClassRelation>();
    for (const edge of edges) {
        const key = `${edge.from} ${edge.to}`;
        if (isStructEdge(edge, ids) && !byKey.has(key)) {
            byKey.set(key, { from: edge.from, kind: "aggregation", to: edge.to });
        }
    }
    return [...byKey.values()];
};

export const diagram: DiagramKind = {
    appliesTo(context) {
        return (
            (context.codeGraph?.nodes ?? []).filter((node) => STRUCT_KINDS.has(node.kind)).length >= MIN_STRUCT_NODES
        );
    },
    id: "structure",
    order: 1,
    render(context) {
        if (context.codeGraph === null) {
            return null;
        }
        const graph = collapseByLabel(context.codeGraph);
        const structNodes = graph.nodes.filter((node) => STRUCT_KINDS.has(node.kind));
        const ids = new Set(structNodes.map((node) => node.id));
        const classes: ClassBox[] = structNodes.map((node) => ({ id: node.id, label: node.label, members: [] }));
        const model: ClassModel = {
            accDescr: DIAGRAM_DESCRIPTIONS.structure,
            accTitle: structureTitle(context.moduleName),
            classes,
            relations: structRelations(graph.edges, ids),
        };
        return {
            legend: KIND_LEGEND,
            mermaid: emitClassDiagram(model),
            sources: structNodes.map((node) => ({ file: node.source.file, label: node.label, line: node.source.line })),
        };
    },
    title: DIAGRAM_TITLES.structure,
};
```
