core/formatters/diagram.structure.formatter.ts
core/formatters/diagram.structure.formatter.ts is a file in GovLab Docs. 34 lines of code and 11 definitions.
import type { ClassBox, ClassMember, ClassModel, ClassRelation, ClassRelationKind } from "#types/diagram.types";
import { idSanitize, label } from "#core/normalizers/diagram.normalizer";
import { accLines } from "#core/formatters/diagram.formatter";
import { byString } from "#core/selectors/base.selector";
const INDENT = " ";
const RELATION_SYMBOLS: ReadonlyMap<ClassRelationKind, string> = new Map<ClassRelationKind, string>([
["composition", "*--"],
["aggregation", "o--"],
["realization", "<|.."],
["dependency", "..>"],
]);
const byBoxId = byString<ClassBox>((box) => box.id);
const byMemberName = byString<ClassMember>((member) => member.name);
const byRelation = byString<ClassRelation>((relation) => `${relation.from} ${relation.to} ${relation.kind}`);
const memberLines = function memberLines(box: ClassBox): string[] {
const id = idSanitize(box.id);
return [
`${INDENT}class ${id}["${label(box.label)}"]`,
...box.members.toSorted(byMemberName).map((member) => `${INDENT}${id} : +${label(member.name)}`),
];
};
const relationLine = function relationLine(relation: ClassRelation): string {
const suffix = typeof relation.label === "string" ? ` : ${label(relation.label)}` : "";
const symbol = RELATION_SYMBOLS.get(relation.kind) ?? "";
return `${INDENT}${idSanitize(relation.from)} ${symbol} ${idSanitize(relation.to)}${suffix}`;
};
export const emitClassDiagram = function emitClassDiagram(model: ClassModel): string {
return [
"classDiagram",
...accLines(model),
...model.classes.toSorted(byBoxId).flatMap(memberLines),
...model.relations.toSorted(byRelation).map(relationLine),
].join("\n");
};