import { AFTER_TITLE, ALIASES_LABEL, BEFORE_TITLE, CATEGORY_CAPTION, CATEGORY_INTRO, CONFLICTS_WITH_LABEL, CONTRACTS_LABEL, DETECTED_BY_LABEL, ENABLES_LABEL, ENFORCED_BY_LABEL, KIND_LABEL, LAYER_LABEL, MEASURED_BY_LABEL, REFACTORED_BY_LABEL, REFERENCED_BY_LABEL, REINFORCES_LABEL, REQUIRES_LABEL, SCOPE_LABEL, SEVERITY_LABEL, TENSIONS_LABEL, TENSIONS_WITH_LABEL, TERM_LABEL, VIOLATED_BY_LABEL, } from "#configuration/strings/ontology.strings"; import { ARCH_ANCHOR, ARCH_CATEGORY_ANCHOR } from "#core/ids/ontology.ids"; import type { PrincipleCategoryView, PrincipleView } from "#types/ontology.types"; import type { Section, Subsection } from "#types/document.types"; import { chips, diagram, edgeLine, exemplarBlocks, glossary, labelled, linkList, linkRow, linked, localId, node, plainList, row, } from "#domain/converters/ontology.converter"; import { ARCH_FACE } from "@govlab/constants"; import type { Block } from "#types/block.types"; import { CATEGORY_SECTION_ICON } from "#configuration/icons/ontology.icons"; import type { EdgeRef } from "#types/link.types"; const HEADER = "flowchart LR"; const SOLID = " --> "; const DOTTED = " -.-> "; const NEGATIVE = " --x "; const facts = function facts(principle: PrincipleView): Block { return chips([ linked(KIND_LABEL, principle.kind), labelled(SEVERITY_LABEL, principle.severity), principle.scope.length === 0 ? null : labelled(SCOPE_LABEL, linkList(principle.scope)), principle.aliases.length === 0 ? null : labelled(ALIASES_LABEL, plainList(principle.aliases)), linked(LAYER_LABEL, principle.layer), ]); }; const relations = function relations(principle: PrincipleView): Block { return glossary([ row(REQUIRES_LABEL, linkList(principle.edges.requires)), row(REINFORCES_LABEL, linkList(principle.edges.reinforces)), row(ENABLES_LABEL, linkList(principle.edges.enables)), row(TENSIONS_WITH_LABEL, linkList(principle.edges.tensionsWith)), row(CONFLICTS_WITH_LABEL, linkList(principle.edges.conflictsWith)), ...linkRow(REFERENCED_BY_LABEL, principle.referencedBy), ...linkRow(TERM_LABEL, principle.term === null ? [] : [principle.term]), ...linkRow(CONTRACTS_LABEL, principle.contracts), ...linkRow(TENSIONS_LABEL, principle.tensions), ]); }; const descriptors = function descriptors(principle: PrincipleView): Block { return glossary([ row(VIOLATED_BY_LABEL, linkList(principle.violatedBy)), row(DETECTED_BY_LABEL, linkList(principle.detectedBy)), row(MEASURED_BY_LABEL, linkList(principle.measuredBy)), row(REFACTORED_BY_LABEL, linkList(principle.refactoredBy)), row(ENFORCED_BY_LABEL, linkList(principle.enforcedBy)), ]); }; const principleSubsection = function principleSubsection(principle: PrincipleView): Subsection { return { blocks: [ facts(principle), relations(principle), descriptors(principle), ...exemplarBlocks(principle.exemplar, BEFORE_TITLE, AFTER_TITLE), ], id: ARCH_ANCHOR + principle.id, title: principle.name, }; }; const categoryDiagram = function categoryDiagram(group: PrincipleCategoryView): string { const members = new Set(group.principles.map((principle) => principle.id)); const nodes = group.principles.map((principle) => node(principle.id, principle.name)); const edges = group.principles.flatMap((principle) => { const arrows: [readonly EdgeRef[], string][] = [ [principle.edges.requires, SOLID], [principle.edges.reinforces, SOLID], [principle.edges.enables, SOLID], [principle.edges.tensionsWith, DOTTED], [principle.edges.conflictsWith, NEGATIVE], ]; return arrows.flatMap(([targets, arrow]) => targets.flatMap((target) => { const id = localId(target, ARCH_FACE, members); return id === null || id === principle.id ? [] : [edgeLine(principle.id, arrow, id)]; }), ); }); return diagram(HEADER, [...nodes, ...edges]); }; const categorySection = function categorySection(group: PrincipleCategoryView): Section { return { blocks: [{ caption: CATEGORY_CAPTION, kind: "mermaid", text: categoryDiagram(group) }], icon: CATEGORY_SECTION_ICON, id: ARCH_CATEGORY_ANCHOR + group.id, intro: CATEGORY_INTRO, subsections: group.principles.map(principleSubsection), title: group.category, }; }; export const principleSections = function principleSections( groups: readonly PrincipleCategoryView[], ): readonly Section[] { return groups.map(categorySection); };