domain/converters/grammar.section.converter.ts

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

import {
    AXIS_LABEL,
    CATEGORY_LABEL,
    CONSTRAINTS_LABEL,
    DEFAULT_VERB_LABEL,
    DISTINCT_FROM_LABEL,
    DOCUMENT_TYPES_TITLE,
    DOCUMENT_TYPE_INTRO,
    EXAMPLE_LABEL,
    GROUNDS_LABEL,
    KEYWORDS_KIND,
    KEYWORD_INTRO,
    LABEL_SEPARATOR,
    LIST_SEPARATOR,
    MEANING_LABEL,
    MODEL_LABEL,
    PRODUCTIONS_KIND,
    PRODUCTION_INTRO,
    PURPOSE_LABEL,
    RULE_LABEL,
    SLOTS_LABEL,
    TEMPLATES_TITLE,
    TEMPLATE_BODY_TITLE,
    TEMPLATE_INTRO,
    VERBS_LABEL,
} from "#configuration/strings/ontology.strings";
import {
    DOCUMENT_TYPE_SECTION_ID,
    KEYWORD_SECTION_PREFIX,
    PAG_ANCHOR,
    PRODUCTION_SECTION_PREFIX,
    TEMPLATE_SECTION_ID,
} from "#core/ids/ontology.ids";
import type {
    DocumentTypeView,
    GrammarView,
    KeywordCategoryView,
    KeywordView,
    ProductionGroupView,
    TemplateSlotView,
    TemplateView,
} from "#types/grammar.types";
import { FACE_SEPARATOR, PAG_FACE } from "@govlab/constants";
import { OPTIONAL_LABEL, REQUIRED_LABEL } from "#configuration/strings/reason.strings";
import type { Section, Subsection } from "#types/document.types";
import {
    chips,
    codeOf,
    glossary,
    labeled,
    linkOf,
    linkRow,
    linked,
    plainList,
    row,
    slugOf,
    text,
} from "#domain/converters/ontology.converter";
import type { Block } from "#types/block.types";
import { GRAMMAR_SECTION_ICON } from "#configuration/icons/ontology.icons";
import { PAG_LANGUAGE } from "#configuration/constants/code.constants";
import type { ResolutionView } from "#types/ontology.types";
import { checkBlocks } from "#domain/converters/check.converter";

const pagRecord = function pagRecord(
    anchor: string,
    title: string,
    blocks: readonly Block[],
    resolution: ResolutionView,
): Subsection {
    return {
        blocks: [...blocks, ...checkBlocks(resolution, PAG_FACE + FACE_SEPARATOR + anchor)],
        id: PAG_ANCHOR + anchor,
        title,
    };
};

const section = function section(
    id: string,
    title: string,
    intro: string,
    subsections: readonly Subsection[],
    kind?: string,
): Section {
    return { icon: GRAMMAR_SECTION_ICON, id, intro, subsections, title, ...(kind === undefined ? {} : { kind }) };
};

const roleRows = function roleRows(keyword: KeywordView): readonly ReturnType<typeof row>[] {
    const several = keyword.roles.length > 1;
    return keyword.roles.flatMap((role) => [
        ...(several ? [row(CATEGORY_LABEL, role.category)] : []),
        row(MEANING_LABEL, role.meaning),
        row(EXAMPLE_LABEL, role.example),
        ...linkRow(GROUNDS_LABEL, role.grounds),
    ]);
};

const keywordSection = function keywordSection(group: KeywordCategoryView, resolution: ResolutionView): Section {
    return section(
        KEYWORD_SECTION_PREFIX + slugOf(group.category),
        group.category,
        KEYWORD_INTRO,
        group.keywords.map((keyword) =>
            pagRecord(
                keyword.anchor,
                keyword.name,
                [
                    glossary([
                        ...roleRows(keyword),
                        ...keyword.distinctFrom.map((entry) =>
                            row(DISTINCT_FROM_LABEL, linkOf(entry.record) + LABEL_SEPARATOR + entry.reason),
                        ),
                    ]),
                ],
                resolution,
            ),
        ),
        KEYWORDS_KIND,
    );
};

const productionSection = function productionSection(group: ProductionGroupView, resolution: ResolutionView): Section {
    return section(
        PRODUCTION_SECTION_PREFIX + slugOf(group.group),
        group.group,
        PRODUCTION_INTRO,
        group.productions.map((production) =>
            pagRecord(
                production.anchor,
                production.lhs,
                [glossary([row(RULE_LABEL, production.rhs), ...linkRow(GROUNDS_LABEL, production.grounds)])],
                resolution,
            ),
        ),
        PRODUCTIONS_KIND,
    );
};

const documentTypeRecord = function documentTypeRecord(
    documentType: DocumentTypeView,
    resolution: ResolutionView,
): Subsection {
    const verbs = row(VERBS_LABEL, plainList(documentType.verbs));
    return pagRecord(
        documentType.anchor,
        documentType.type,
        [
            chips([
                labeled(DEFAULT_VERB_LABEL, documentType.defaultVerb),
                linked(MODEL_LABEL, documentType.model),
                linked(AXIS_LABEL, documentType.axis),
            ]),
            glossary([
                row(PURPOSE_LABEL, documentType.purpose),
                verbs,
                ...linkRow(GROUNDS_LABEL, documentType.grounds),
            ]),
        ],
        resolution,
    );
};

const slotRow = function slotRow(slot: TemplateSlotView): ReturnType<typeof row> {
    const kind = slot.values.length === 0 ? slot.kind : slot.kind + LABEL_SEPARATOR + slot.values.join(LIST_SEPARATOR);
    const need = slot.required ? REQUIRED_LABEL : OPTIONAL_LABEL;
    return row(slot.name, `${slot.description} (${kind}${LIST_SEPARATOR}${need})`);
};

const templateRecord = function templateRecord(template: TemplateView, resolution: ResolutionView): Subsection {
    const constraints = row(CONSTRAINTS_LABEL, plainList(template.constraints));
    const noSlots = row(SLOTS_LABEL, plainList([]));
    return pagRecord(
        template.anchor,
        template.title,
        [
            glossary([constraints]),
            ...(template.slots.length === 0
                ? [glossary([noSlots])]
                : [text(SLOTS_LABEL), glossary(template.slots.map(slotRow))]),
            codeOf(TEMPLATE_BODY_TITLE, template.body, PAG_LANGUAGE),
        ],
        resolution,
    );
};

export const grammarSections = function grammarSections(
    grammar: GrammarView,
    resolution: ResolutionView,
): readonly Section[] {
    return [
        ...grammar.categories.map((group) => keywordSection(group, resolution)),
        ...grammar.groups.map((group) => productionSection(group, resolution)),
        section(
            DOCUMENT_TYPE_SECTION_ID,
            DOCUMENT_TYPES_TITLE,
            DOCUMENT_TYPE_INTRO,
            grammar.documentTypes.map((documentType) => documentTypeRecord(documentType, resolution)),
        ),
        section(
            TEMPLATE_SECTION_ID,
            TEMPLATES_TITLE,
            TEMPLATE_INTRO,
            grammar.templates.map((template) => templateRecord(template, resolution)),
        ),
    ];
};