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

> 71 lines of code and 13 definitions.

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

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

## Definitions

- `buildModel` (lexical_declaration, line 44)
- `classBoxes` (lexical_declaration, line 25)
- `classRelations` (lexical_declaration, line 31)
- `sourcesOf` (lexical_declaration, line 38)
- `render` (method_definition, line 63, exported)
- `MIN_EDGES` (lexical_declaration, line 12)
- `RELATION_KIND` (lexical_declaration, line 14)
- `connectedIds` (lexical_declaration, line 21)
- `kind` (lexical_declaration, line 33)
- `diagram` (lexical_declaration, line 57, exported)
- `appliesTo` (method_definition, line 58, exported)
- `graph` (lexical_declaration, line 64, exported)
- `keep` (lexical_declaration, line 68, exported)

## Contained in

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

## Uses

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

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/docs/folder-docs-configuration-strings.md)
- [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, ClassRelationKind } from "#types/diagram.types";
import {
    DIAGRAM_DESCRIPTIONS,
    DIAGRAM_LEGENDS,
    DIAGRAM_TITLES,
    typeRelationshipTitle,
} from "#configuration/strings/figure.strings";
import type { DiagramContext, DiagramKind, DiagramSource } from "#types/figure.types";
import type { TypeEdge, TypeGraph, TypeNode } from "#types/graph.types";
import { emitClassDiagram } from "#core/formatters/diagram.structure.formatter";

const MIN_EDGES = 1;

const RELATION_KIND: ReadonlyMap<TypeEdge["kind"], ClassRelationKind> = new Map<TypeEdge["kind"], ClassRelationKind>([
    ["extends", "realization"],
    ["implements", "realization"],
    ["has", "aggregation"],
    ["uses", "dependency"],
]);

const connectedIds = function connectedIds(graph: TypeGraph): Set<string> {
    return new Set(graph.edges.flatMap((edge) => [edge.from, edge.to]));
};

const classBoxes = function classBoxes(nodes: readonly TypeNode[], keep: ReadonlySet<string>): ClassBox[] {
    return nodes
        .filter((node) => keep.has(node.id))
        .map((node) => ({ id: node.id, label: node.label, members: node.members.map((name) => ({ name })) }));
};

const classRelations = function classRelations(edges: readonly TypeEdge[]): ClassRelation[] {
    return edges.flatMap((edge) => {
        const kind = RELATION_KIND.get(edge.kind);
        return kind === undefined ? [] : [{ from: edge.from, kind, to: edge.to }];
    });
};

const sourcesOf = function sourcesOf(nodes: readonly TypeNode[], keep: ReadonlySet<string>): DiagramSource[] {
    return nodes
        .filter((node) => keep.has(node.id))
        .map((node) => ({ file: node.source.file, label: node.label, line: node.source.line }));
};

const buildModel = function buildModel(
    context: DiagramContext,
    graph: TypeGraph,
    keep: ReadonlySet<string>,
): ClassModel {
    return {
        accDescr: DIAGRAM_DESCRIPTIONS.typeRelationship,
        accTitle: typeRelationshipTitle(context.moduleName),
        classes: classBoxes(graph.nodes, keep),
        relations: classRelations(graph.edges),
    };
};

export const diagram: DiagramKind = {
    appliesTo(context) {
        return (context.typeGraph?.edges.length ?? 0) >= MIN_EDGES;
    },
    id: "type-relationship",
    order: 5,
    render(context) {
        const graph = context.typeGraph;
        if (!graph || graph.edges.length < MIN_EDGES) {
            return null;
        }
        const keep = connectedIds(graph);
        if (keep.size === 0) {
            return null;
        }
        return {
            legend: DIAGRAM_LEGENDS.typeRelationship,
            mermaid: emitClassDiagram(buildModel(context, graph, keep)),
            sources: sourcesOf(graph.nodes, keep),
        };
    },
    title: DIAGRAM_TITLES.typeRelationship,
};
```
