core/loaders/grammar.loader.ts

core/loaders/grammar.loader.ts is a file in GovLab Context. 89 lines of code and 17 definitions.

import { CHECK_KEY, RECORDS_KEY } from "#configuration/constants/ontology.constants";
import {
    DOCUMENT_TYPES_FILE,
    KEYWORDS_FILE,
    PRODUCTIONS_FILE,
    TEMPLATES_SOURCE,
    TEMPLATE_FILE_PREFIX,
    TERMINALS_KEY,
} from "#configuration/constants/grammar.constants";
import type { GrammarFile, PagData } from "#types/grammar.types";
import {
    normalizeDocumentType,
    normalizeKeyword,
    normalizeProduction,
    normalizeTemplate,
    refused,
} from "#core/normalizers/grammar.normalizer";
import { readJsonDir, readJsonFile } from "#core/loaders/ontology.loader";
import type { CheckTable } from "#core/stores/check.store";
import { PAG_KINDS } from "#configuration/schemas/grammar.schema";
import type { ReadAudit } from "#core/observers/record.observer";
import { absolutePath } from "@ssot/paths";
import { asString } from "#core/normalizers/field.normalizer";
import { isObject } from "#core/predicates/record.predicate";
import { join } from "node:path";
import { keywordIdOf } from "#core/selectors/grammar.selector";

interface GrammarLoad {
    audit: ReadAudit;
    checks: CheckTable;
    dir: string;
}

const fileOf = function fileOf(load: GrammarLoad, source: string, kind: string): GrammarFile {
    const parsed = readJsonFile(join(load.dir, source));
    if (!isObject(parsed)) {
        load.audit.reject(parsed, source);
        return { kind, object: {}, source };
    }
    const tracked = load.audit.track(parsed, source);
    load.audit.attribution(tracked);
    return { kind, object: tracked, source };
};

const declaredRecords = function declaredRecords<T>(
    load: GrammarLoad,
    file: GrammarFile,
    normalize: (raw: Record<string, unknown>) => T,
    idOf: (record: T) => string,
): T[] {
    load.checks.forKind(file.kind, file.object[CHECK_KEY]);
    return load.audit.records(file.object[RECORDS_KEY], file.source).map((raw) => {
        const record = normalize(raw);
        load.checks.forRecord(file.kind, idOf(record), raw[CHECK_KEY]);
        return record;
    });
};

const terminalsOf = function terminalsOf(file: GrammarFile): string[] {
    const terminals = file.object[TERMINALS_KEY];
    return Array.isArray(terminals) ? terminals.map(asString) : [];
};

export const loadBundledData = function loadBundledData(audit: ReadAudit, checks: CheckTable): PagData {
    const load: GrammarLoad = { audit, checks, dir: absolutePath("govlab.context.grammar") };
    const productionsFile = fileOf(load, PRODUCTIONS_FILE, PAG_KINDS.production);
    const keywords = declaredRecords(
        load,
        fileOf(load, KEYWORDS_FILE, PAG_KINDS.keyword),
        refused(PAG_KINDS.keyword, normalizeKeyword),
        keywordIdOf,
    );
    const documentTypes = declaredRecords(
        load,
        fileOf(load, DOCUMENT_TYPES_FILE, PAG_KINDS.documentType),
        refused(PAG_KINDS.documentType, normalizeDocumentType),
        (record) => record.type,
    );
    const productions = declaredRecords(
        load,
        productionsFile,
        refused(PAG_KINDS.production, normalizeProduction),
        (record) => record.lhs,
    );
    const template = refused(PAG_KINDS.template, normalizeTemplate);
    const raws = readJsonDir(load.dir, { only: (name) => name.startsWith(TEMPLATE_FILE_PREFIX) });
    const templates = audit.records(raws, TEMPLATES_SOURCE).map((raw) => {
        audit.attribution(raw);
        const record = template(raw);
        checks.forRecord(PAG_KINDS.template, record.type, raw[CHECK_KEY]);
        return record;
    });
    return { documentTypes, keywords, productions, templates, terminals: terminalsOf(productionsFile) };
};