core/resolvers/ontology.resolver.ts

core/resolvers/ontology.resolver.ts is a file in Bane's Lab Build Scripts. 178 lines of code and 50 definitions.

import {
    ALGO_FACE,
    ARCH_CATEGORY_FACE,
    ARCH_FACE,
    FACE_SEPARATOR,
    FORCE_FACE,
    KIND_FACE,
    LAYER_FACE,
    LEX_CATEGORY_FACE,
    LEX_FACE,
    PAG_FACE,
    REASON_FACE,
    STAGE_FACE,
    TENSION_FACE,
    VOCABULARY_FACE,
} from "@govlab/constants";
import { CANONICAL_KINDS, CLOSED_VOCABULARIES, type GovlabContext, type Principle, slugify } from "@govlab/context";
import { LOOP_KIND, NODE_KIND } from "#configuration/constants/ontology.constants";
import { archIndexOf, categoryLabelsOf } from "#core/converters/architecture.index.converter";
import type { EdgeRef } from "@banes-lab/web/types/link.types.js";
import type { Resolver } from "#types/ontology.types";
import { reasonIndexOf } from "#core/converters/reason.index.converter";
import { unregisteredVocabulary } from "#configuration/strings/ontology.strings";

const SPACE = " ";
const HYPHEN = "-";
const PAIR_JOINER = " / ";

export const refOf = function refOf(face: string, id: string): string {
    return face + FACE_SEPARATOR + id;
};

export const faceOf = function faceOf(ref: string): string {
    return ref.slice(0, ref.indexOf(FACE_SEPARATOR));
};

export const idOf = function idOf(ref: string): string {
    return ref.slice(ref.indexOf(FACE_SEPARATOR) + 1);
};

export const reasonAnchor = function reasonAnchor(kind: string, id: string): string {
    return kind + HYPHEN + id;
};

export const vocabularyAnchor = function vocabularyAnchor(id: string, value: string): string {
    return id + HYPHEN + value;
};

const vocabulary = function vocabulary(id: string, value: string): EdgeRef {
    const held = CLOSED_VOCABULARIES.find((entry) => entry.id === id);
    if (held === undefined) {
        throw new Error(unregisteredVocabulary(id));
    }
    const known = held.entries.some((entry) => entry.value === value);
    return { label: value, ref: known ? refOf(VOCABULARY_FACE, vocabularyAnchor(id, value)) : null };
};

export const pagAnchor = function pagAnchor(kind: string, id: string): string {
    return kind + HYPHEN + slugify(id);
};

const pagAnchorsOf = function pagAnchorsOf(context: GovlabContext): ReadonlySet<string> {
    return new Set(
        context.checkedRecords().flatMap((record) => {
            if (record.collection !== PAG_FACE) {
                return [];
            }
            const at = record.id.indexOf(FACE_SEPARATOR);
            return [pagAnchor(record.id.slice(0, at), record.id.slice(at + FACE_SEPARATOR.length))];
        }),
    );
};

const titleCase = function titleCase(slug: string): string {
    return slug
        .split(HYPHEN)
        .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
        .join(SPACE);
};

export const createResolver = function createResolver(context: GovlabContext): Resolver {
    const archIndex = archIndexOf(context);
    const categoryLabels = categoryLabelsOf(context);
    const reasonIndex = reasonIndexOf(context);
    const stages = new Set(context.reason.derivationLoop().stages.map((stage) => stage.id));
    const archRef = function archRef(principle: Principle): EdgeRef {
        return { label: principle.name, ref: refOf(ARCH_FACE, principle.id) };
    };
    const lex = function lex(label: string): EdgeRef {
        const term = context.lex.resolve(label);
        return { label: term?.name ?? label, ref: term === null ? null : refOf(LEX_FACE, term.id) };
    };
    const arch = function arch(label: string): EdgeRef {
        const principle = archIndex.get(slugify(label));
        return principle === undefined ? lex(label) : archRef(principle);
    };
    const algo = function algo(label: string): EdgeRef {
        const id = slugify(label);
        const contract = context.algo.get(id);
        return { label: contract?.title ?? label, ref: contract === null ? null : refOf(ALGO_FACE, id) };
    };
    const reasonAs = function reasonAs(kind: string, id: string): EdgeRef {
        const local = reasonIndex.get(kind)?.has(id) === true ? id : slugify(id);
        const label = reasonIndex.get(kind)?.get(local);
        return { label: label ?? id, ref: label === undefined ? null : refOf(REASON_FACE, reasonAnchor(kind, local)) };
    };
    const reason = function reason(id: string): EdgeRef {
        const typed = id.indexOf(FACE_SEPARATOR);
        if (typed !== -1) {
            const kinded = reasonAs(id.slice(0, typed), id.slice(typed + FACE_SEPARATOR.length));
            return { label: id, ref: kinded.ref };
        }
        const local = context.reason.resolve(id) === null ? slugify(id) : id;
        const resolution = context.reason.resolve(local);
        return resolution === null ? { label: id, ref: null } : reasonAs(resolution.kind, local);
    };
    const stage = function stage(id: string): EdgeRef {
        return { label: id, ref: stages.has(id) ? refOf(STAGE_FACE, id) : null };
    };
    const archExact = function archExact(id: string): EdgeRef {
        const principle = context.arch.get(id);
        return principle === null ? { label: id, ref: null } : archRef(principle);
    };
    const pagAnchors = pagAnchorsOf(context);
    const pag = function pag(local: string): EdgeRef {
        const at = local.indexOf(FACE_SEPARATOR);
        const id = local.slice(at + FACE_SEPARATOR.length);
        const anchor = pagAnchor(local.slice(0, at), id);
        return { label: id, ref: at !== -1 && pagAnchors.has(anchor) ? refOf(PAG_FACE, anchor) : null };
    };
    const byFace: ReadonlyMap<string, (local: string) => EdgeRef> = new Map([
        [ALGO_FACE, algo],
        [ARCH_FACE, archExact],
        [LEX_FACE, lex],
        [PAG_FACE, pag],
        [REASON_FACE, reason],
        [STAGE_FACE, stage],
    ]);
    const edgeSource = function edgeSource(id: string): EdgeRef {
        const found = [stage(id), reasonAs(NODE_KIND, id), reasonAs(LOOP_KIND, id)].find(
            (candidate) => candidate.ref !== null,
        );
        return found ?? { label: id, ref: null };
    };
    const bare = function bare(raw: string): EdgeRef {
        const found = [reason(raw), arch(raw), algo(raw)].find((candidate) => candidate.ref !== null);
        return found ?? { label: raw, ref: null };
    };
    const target = function target(raw: string): EdgeRef {
        if (!raw.includes(FACE_SEPARATOR)) {
            return bare(raw);
        }
        const resolveIn = byFace.get(faceOf(raw));
        if (resolveIn === undefined) {
            return { label: raw, ref: null };
        }
        const resolved = resolveIn(idOf(raw));
        return resolved.ref === null ? { label: raw, ref: null } : resolved;
    };
    const labels = function labels(phrases: readonly string[]): readonly EdgeRef[] {
        return phrases.map((phrase) => ({ label: phrase, ref: bare(phrase).ref }));
    };
    const tension = function tension(a: EdgeRef, b: EdgeRef): EdgeRef {
        const pair = [slugify(a.label), slugify(b.label)].sort((left, right) => left.localeCompare(right));
        return { label: a.label + PAIR_JOINER + b.label, ref: refOf(TENSION_FACE, pair.join(HYPHEN)) };
    };
    return {
        algo,
        arch,
        archCategory: (label) => ({ label, ref: refOf(ARCH_CATEGORY_FACE, slugify(label)) }),
        archId: archExact,
        edgeSource,
        force: (force, known) => ({ label: force, ref: known.has(force) ? refOf(FORCE_FACE, slugify(force)) : null }),
        kind: (kind) => ({ label: kind, ref: CANONICAL_KINDS.has(kind) ? refOf(KIND_FACE, kind) : null }),
        labels,
        layer: (id) => ({ label: context.algo.get(id)?.title ?? id, ref: refOf(LAYER_FACE, id) }),
        lexCategory: (slug) => ({
            label: categoryLabels.get(slug) ?? titleCase(slug),
            ref: refOf(LEX_CATEGORY_FACE, slug),
        }),
        pag,
        reason,
        reasonAs,
        stage,
        target,
        tension,
        vocabulary,
    };
};