domain/converters/contract.converter.ts

domain/converters/contract.converter.ts is a file in Bane's Lab Site. 147 lines of code and 15 definitions.

import {
    AFTER_TITLE,
    AXIS_LABEL,
    BEFORE_TITLE,
    CANON_LABEL,
    COMPOSED_BY_LABEL,
    COMPOSES_LABEL,
    DERIVATION_LABEL,
    DERIVED_BY_LABEL,
    DETECTS_LABEL,
    DISTINCT_FROM_LABEL,
    DOMAIN_CAPTION,
    DOMAIN_INTRO,
    DOMAIN_LABEL,
    FLOW_ARROW,
    FLOW_TITLE,
    FORCES_LABEL,
    GROUNDED_BY_LABEL,
    GROUNDS_LABEL,
    INTENT_LABEL,
    INVARIANT_LABEL,
    LABEL_SEPARATOR,
    LAYER_LABEL,
    MATH_TYPE_LABEL,
    META_LABEL,
    PRINCIPLE_LABEL,
    PRODUCTIONS_TITLE,
    PRODUCTION_ARROW,
    STAGE_LABEL,
    TIER_LABEL,
    YIELDS_LABEL,
} from "#configuration/strings/ontology.strings";
import { ALGO_ANCHOR, ALGO_DOMAIN_ANCHOR } from "#core/ids/ontology.ids";
import { ALGO_FACE, FACE_SEPARATOR } from "@govlab/constants";
import { BNF_LANGUAGE, LINE_BREAK, TEXT_LANGUAGE } from "#configuration/constants/code.constants";
import type { ContractDomainView, ContractView, ResolutionView } from "#types/ontology.types";
import type { Section, Subsection } from "#types/document.types";
import { canonOf, checkBlocks } from "#domain/converters/check.converter";
import {
    chips,
    codeOf,
    exemplarBlocks,
    glossary,
    labeled,
    linkList,
    linkOf,
    linkRow,
    linked,
    row,
    text,
} from "#domain/converters/ontology.converter";
import { diagram, edgeLine, localId, node } from "#domain/converters/ontology.graph.converter";
import type { Block } from "#types/block.types";
import { DOMAIN_SECTION_ICON } from "#configuration/icons/ontology.icons";
import { EDGE_SOLID } from "#configuration/constants/diagram.constants";
import { groupTitleOf } from "#configuration/strings/catalog.strings";

const HEADER = "flowchart LR";

const coordinates = function coordinates(contract: ContractView): Block {
    return chips([
        linked(DOMAIN_LABEL, contract.domain),
        linked(TIER_LABEL, contract.tier),
        linked(STAGE_LABEL, contract.stage),
        linked(AXIS_LABEL, contract.axis),
        linked(MATH_TYPE_LABEL, contract.mathType),
        labeled(YIELDS_LABEL, contract.yields),
        linked(LAYER_LABEL, contract.layer),
        contract.meta ? META_LABEL : null,
    ]);
};

const joins = function joins(contract: ContractView): Block {
    return glossary([
        row(COMPOSES_LABEL, linkList(contract.composes)),
        ...linkRow(COMPOSED_BY_LABEL, contract.composedBy),
        ...linkRow(DERIVED_BY_LABEL, contract.derivedBy),
        row(FORCES_LABEL, linkList(contract.force)),
        ...linkRow(PRINCIPLE_LABEL, contract.principle === null ? [] : [contract.principle]),
        row(GROUNDS_LABEL, linkList(contract.grounds)),
        ...linkRow(GROUNDED_BY_LABEL, contract.groundedBy),
        ...linkRow(DETECTS_LABEL, contract.detects),
        ...contract.distinctFrom.map((entry) =>
            row(DISTINCT_FROM_LABEL, linkOf(entry.record) + LABEL_SEPARATOR + entry.reason),
        ),
        ...(contract.canon.length === 0 ? [] : [row(CANON_LABEL, canonOf(contract.canon))]),
    ]);
};

const derivation = function derivation(contract: ContractView): readonly Block[] {
    if (contract.derivationMap.length === 0) {
        return [];
    }
    return [
        text(DERIVATION_LABEL),
        glossary(contract.derivationMap.map((step) => row(step.stage.label, linkOf(step.record)))),
    ];
};

const productions = function productions(contract: ContractView): readonly Block[] {
    if (contract.productions.length === 0) {
        return [];
    }
    const lines = contract.productions.map((production) => production.lhs + PRODUCTION_ARROW + production.rhs);
    return [codeOf(PRODUCTIONS_TITLE, lines.join(LINE_BREAK), BNF_LANGUAGE)];
};

const flow = function flow(contract: ContractView): readonly Block[] {
    return contract.flow.length === 0 ? [] : [codeOf(FLOW_TITLE, contract.flow.join(FLOW_ARROW), TEXT_LANGUAGE)];
};

const contractSubsection = function contractSubsection(contract: ContractView, resolution: ResolutionView): Subsection {
    return {
        blocks: [
            coordinates(contract),
            glossary([row(INTENT_LABEL, contract.intent), row(INVARIANT_LABEL, contract.invariant)]),
            ...flow(contract),
            ...productions(contract),
            joins(contract),
            ...derivation(contract),
            ...exemplarBlocks(contract.exemplar, BEFORE_TITLE, AFTER_TITLE),
            ...checkBlocks(resolution, ALGO_FACE + FACE_SEPARATOR + contract.id),
        ],
        id: ALGO_ANCHOR + contract.id,
        title: contract.title,
    };
};

const domainDiagram = function domainDiagram(group: ContractDomainView): string {
    const members = new Set(group.contracts.map((contract) => contract.id));
    const nodes = group.contracts.map((contract) => node(contract.id, contract.title));
    const edges = group.contracts.flatMap((contract) =>
        [...contract.composes, ...contract.derivationMap.map((step) => step.record)].flatMap((target) => {
            const id = localId(target, ALGO_FACE, members);
            return id === null || id === contract.id ? [] : [edgeLine(contract.id, EDGE_SOLID, id)];
        }),
    );
    return diagram(HEADER, [...nodes, ...new Set(edges)]);
};

const domainSection = function domainSection(group: ContractDomainView, resolution: ResolutionView): Section {
    return {
        blocks: [{ caption: DOMAIN_CAPTION, kind: "mermaid", text: domainDiagram(group) }],
        icon: DOMAIN_SECTION_ICON,
        id: ALGO_DOMAIN_ANCHOR + group.id,
        intro: DOMAIN_INTRO,
        subsections: group.contracts.map((contract) => contractSubsection(contract, resolution)),
        title: groupTitleOf(group.id, group.domain),
    };
};

export const contractSections = function contractSections(
    groups: readonly ContractDomainView[],
    resolution: ResolutionView,
): readonly Section[] {
    return groups.map((group) => domainSection(group, resolution));
};