# core/converters/ontology.reference.converter.ts

> 183 lines of code and 24 definitions.

Tree: Bane's Lab Build Scripts
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/build-scripts#file-build-scripts-core-converters-ontology-reference-converter-ts
Source text: https://banes-lab.com/source/build-scripts/core/converters/ontology.reference.converter.ts.txt

Listed in [core/converters](https://banes-lab.com/api/source/build-scripts/core/converters.md), after [core/converters/ontology.index.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/ontology.index.converter.ts.md) and before [core/converters/ontology.vocabulary.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/ontology.vocabulary.converter.ts.md).

## Definitions

- `indexOf` (lexical_declaration, line 65)
- `groupReferencesOf` (lexical_declaration, line 185, exported)
- `archCategories` (lexical_declaration, line 69)
- `lexCategories` (lexical_declaration, line 86)
- `algoDomains` (lexical_declaration, line 100)
- `relations` (lexical_declaration, line 142)
- `vocabularies` (lexical_declaration, line 166)
- `groupRecord` (lexical_declaration, line 54)
- `forces` (lexical_declaration, line 114)
- `kinds` (lexical_declaration, line 133)
- `relationOfVocabulary` (lexical_declaration, line 158)
- `LIST_JOINER` (lexical_declaration, line 33)
- `FORCE_KIND` (lexical_declaration, line 34)
- `KIND_KIND` (lexical_declaration, line 35)
- `RELATION_KIND` (lexical_declaration, line 36)
- `CATEGORY_KIND` (lexical_declaration, line 37)
- `DOMAIN_KIND` (lexical_declaration, line 38)
- `TERMS_RELATION` (lexical_declaration, line 39)
- `KINDS_RELATION` (lexical_declaration, line 40)
- `REVERSE_SUFFIX` (lexical_declaration, line 41)
- `SummaryArguments` (type_alias_declaration, line 43)
- `Grouped` (interface_declaration, line 45)
- `held` (lexical_declaration, line 159)
- `relation` (lexical_declaration, line 169)

## Contained in

- [core/converters](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-converters.md)

## Uses

- [configuration/strings/ontology.strings.ts](https://banes-lab.com/source/build-scripts/configuration/strings/ontology.strings.ts.md)
- [core/converters/reference.field.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/reference.field.converter.ts.md)
- [core/resolvers/ontology.resolver.ts](https://banes-lab.com/source/build-scripts/core/resolvers/ontology.resolver.ts.md)

## Used by

- [core/converters/reference.converter.ts](https://banes-lab.com/source/build-scripts/core/converters/reference.converter.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-configuration-strings.md)
- [core/converters](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-converters.md)
- [core/resolvers](https://banes-lab.com/anatomy/build-scripts/folder-build-scripts-core-resolvers.md)

## Source

```typescript
import {
    ALGO_DOMAIN_FACE,
    ALGO_FACE,
    ARCH_CATEGORY_FACE,
    ARCH_FACE,
    CONTRACTS_RELATION,
    FORCE_FACE,
    KIND_FACE,
    LEX_CATEGORY_FACE,
    LEX_FACE,
    PRINCIPLE_RELATION,
    RELATION_FACE,
    VOCABULARY_FACE,
} from "@govlab/constants";
import {
    CONTRACT_MEMBER,
    PRINCIPLE_MEMBER,
    TERM_MEMBER,
    forceSummary,
    forceTitleOf,
    groupSummary,
    groupTitleOf,
    relationSummary,
} from "@banes-lab/web/strings/catalog.strings";
import type { ReferenceIndex, ReferenceRecord } from "@banes-lab/web/types/reference.types.js";
import { hyphenatedOf, relationsOf } from "#core/converters/reference.field.converter";
import { refOf, vocabularyAnchor } from "#core/resolvers/ontology.resolver";
import { CLOSED_VOCABULARIES } from "@govlab/context";
import type { OntologySnapshot } from "@banes-lab/web/types/ontology.types.js";
import { relationLabelOf } from "@banes-lab/web/strings/reference.strings";
import { unknownSnapshotVocabulary } from "#configuration/strings/ontology.strings";

const LIST_JOINER = ", ";
const FORCE_KIND = "force";
const KIND_KIND = "kind";
const RELATION_KIND = "relation";
const CATEGORY_KIND = "category" as const;
const DOMAIN_KIND = "domain" as const;
const TERMS_RELATION = "terms";
const KINDS_RELATION = "kinds";
const REVERSE_SUFFIX = "-of";

type SummaryArguments = Parameters<typeof groupSummary>;

interface Grouped {
    readonly edges: readonly { readonly label: string; readonly ref: string }[];
    readonly id: string;
    readonly kind: SummaryArguments[1];
    readonly member: SummaryArguments[3];
    readonly relation: string;
    readonly title: string;
}

const groupRecord = function groupRecord(group: Grouped): ReferenceRecord {
    return {
        code: null,
        kind: group.kind,
        layer: null,
        name: group.title,
        relations: [{ edges: group.edges, relation: group.relation }],
        summary: groupSummary(group.title, group.kind, group.edges.length, group.member),
    };
};

const indexOf = function indexOf(face: string, groups: readonly Grouped[]): ReferenceIndex {
    return Object.fromEntries(groups.map((group) => [refOf(face, group.id), groupRecord(group)]));
};

const archCategories = function archCategories(snapshot: OntologySnapshot): ReferenceIndex {
    return indexOf(
        ARCH_CATEGORY_FACE,
        snapshot.principles.map((group) => ({
            edges: group.principles.map((principle) => ({
                label: principle.name,
                ref: refOf(ARCH_FACE, principle.id),
            })),
            id: group.id,
            kind: CATEGORY_KIND,
            member: PRINCIPLE_MEMBER,
            relation: PRINCIPLE_RELATION,
            title: groupTitleOf(group.id, group.category),
        })),
    );
};

const lexCategories = function lexCategories(snapshot: OntologySnapshot): ReferenceIndex {
    return indexOf(
        LEX_CATEGORY_FACE,
        snapshot.terms.map((group) => ({
            edges: group.terms.map((term) => ({ label: term.name, ref: refOf(LEX_FACE, term.id) })),
            id: group.id,
            kind: CATEGORY_KIND,
            member: TERM_MEMBER,
            relation: TERMS_RELATION,
            title: groupTitleOf(group.id, group.category),
        })),
    );
};

const algoDomains = function algoDomains(snapshot: OntologySnapshot): ReferenceIndex {
    return indexOf(
        ALGO_DOMAIN_FACE,
        snapshot.contracts.map((group) => ({
            edges: group.contracts.map((contract) => ({ label: contract.title, ref: refOf(ALGO_FACE, contract.id) })),
            id: group.id,
            kind: DOMAIN_KIND,
            member: CONTRACT_MEMBER,
            relation: CONTRACTS_RELATION,
            title: groupTitleOf(group.id, group.domain),
        })),
    );
};

const forces = function forces(snapshot: OntologySnapshot): ReferenceIndex {
    return Object.fromEntries(
        snapshot.forces.map((view) => [
            refOf(FORCE_FACE, view.id),
            {
                code: null,
                kind: FORCE_KIND,
                layer: null,
                name: forceTitleOf(view.force),
                relations: [...relationsOf(view)],
                summary:
                    view.concerns.length === 0
                        ? forceSummary(view.contracts.length, view.principles.length)
                        : view.concerns.join(LIST_JOINER),
            },
        ]),
    );
};

const kinds = function kinds(snapshot: OntologySnapshot): ReferenceIndex {
    return Object.fromEntries(
        snapshot.kinds.map((view) => [
            refOf(KIND_FACE, view.kind),
            { code: null, kind: KIND_KIND, layer: null, name: view.kind, relations: [], summary: view.discriminator },
        ]),
    );
};

const relations = function relations(snapshot: OntologySnapshot): ReferenceIndex {
    return Object.fromEntries(
        snapshot.ranges.map((view) => [
            refOf(RELATION_FACE, view.relation),
            {
                code: null,
                kind: RELATION_KIND,
                layer: null,
                name: relationLabelOf(hyphenatedOf(view.relation)),
                relations: view.kinds.length === 0 ? [] : [{ edges: view.kinds, relation: KINDS_RELATION }],
                summary: relationSummary(view.kinds.map((edge) => edge.label)),
            },
        ]),
    );
};

const relationOfVocabulary = function relationOfVocabulary(id: string): string {
    const held = CLOSED_VOCABULARIES.find((vocabulary) => vocabulary.id === id);
    if (held === undefined) {
        throw new Error(unknownSnapshotVocabulary(id));
    }
    return held.relation + REVERSE_SUFFIX;
};

const vocabularies = function vocabularies(snapshot: OntologySnapshot): ReferenceIndex {
    return Object.fromEntries(
        snapshot.vocabularies.flatMap((vocabulary) => {
            const relation = relationOfVocabulary(vocabulary.id);
            return vocabulary.entries.map((entry) => [
                refOf(VOCABULARY_FACE, vocabularyAnchor(vocabulary.id, entry.value)),
                {
                    code: null,
                    kind: vocabulary.id,
                    layer: null,
                    name: entry.value,
                    relations: entry.records.length === 0 ? [] : [{ edges: entry.records, relation }],
                    summary: entry.definition,
                },
            ]);
        }),
    );
};

export const groupReferencesOf = function groupReferencesOf(
    snapshot: OntologySnapshot,
): ReadonlyMap<string, ReferenceIndex> {
    return new Map([
        [ALGO_DOMAIN_FACE, algoDomains(snapshot)],
        [ARCH_CATEGORY_FACE, archCategories(snapshot)],
        [FORCE_FACE, forces(snapshot)],
        [KIND_FACE, kinds(snapshot)],
        [LEX_CATEGORY_FACE, lexCategories(snapshot)],
        [RELATION_FACE, relations(snapshot)],
        [VOCABULARY_FACE, vocabularies(snapshot)],
    ]);
};
```
