# domain/converters/grammar.section.converter.ts

> 175 lines of code and 10 definitions.

Tree: Site tree
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/tree#file-domain-converters-grammar-section-converter-ts
Source text: https://banes-lab.com/source/tree/domain/converters/grammar.section.converter.ts.txt

Listed in [domain/converters](https://banes-lab.com/api/source/tree/domain/converters.md), after [domain/converters/failure.converter.ts](https://banes-lab.com/source/tree/domain/converters/failure.converter.ts.md) and before [domain/converters/graph.converter.ts](https://banes-lab.com/source/tree/domain/converters/graph.converter.ts.md).

## Definitions

- `pagRecord` (lexical_declaration, line 59)
- `section` (lexical_declaration, line 72)
- `templateRecord` (lexical_declaration, line 148)
- `keywordSection` (lexical_declaration, line 81)
- `productionSection` (lexical_declaration, line 103)
- `documentTypeRecord` (lexical_declaration, line 119)
- `grammarSections` (lexical_declaration, line 163, exported)
- `slotRow` (lexical_declaration, line 142)
- `kind` (lexical_declaration, line 143)
- `need` (lexical_declaration, line 144)

## Uses

- [domain/converters/check.converter.ts](https://banes-lab.com/source/tree/domain/converters/check.converter.ts.md)
- [domain/converters/ontology.converter.ts](https://banes-lab.com/source/tree/domain/converters/ontology.converter.ts.md)

## Source

```typescript
import {
    AXIS_LABEL,
    CONSTRAINTS_LABEL,
    DEFAULT_VERB_LABEL,
    DOCUMENT_TYPES_TITLE,
    DOCUMENT_TYPE_INTRO,
    EXAMPLE_LABEL,
    GROUNDS_LABEL,
    KEYWORD_INTRO,
    LABEL_SEPARATOR,
    LIST_SEPARATOR,
    MEANING_LABEL,
    MODEL_LABEL,
    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,
    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,
    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[],
): Section {
    return { icon: GRAMMAR_SECTION_ICON, id, intro, subsections, title };
};

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([
                        row(MEANING_LABEL, keyword.meaning),
                        row(EXAMPLE_LABEL, keyword.example),
                        ...linkRow(GROUNDS_LABEL, keyword.grounds),
                    ]),
                ],
                resolution,
            ),
        ),
    );
};

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,
            ),
        ),
    );
};

const documentTypeRecord = function documentTypeRecord(
    documentType: DocumentTypeView,
    resolution: ResolutionView,
): Subsection {
    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),
                row(VERBS_LABEL, plainList(documentType.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 {
    return pagRecord(
        template.anchor,
        template.title,
        [
            glossary([row(CONSTRAINTS_LABEL, plainList(template.constraints))]),
            ...(template.slots.length === 0
                ? [glossary([row(SLOTS_LABEL, plainList([]))])]
                : [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)),
        ),
    ];
};
```
