core/validators/grammar.reference.validator.ts

core/validators/grammar.reference.validator.ts is a file in GovLab Context. 59 lines of code and 9 definitions.

import { PAG_GROUNDING_EXEMPT, PAG_PRODUCTION_EXEMPT } from "#configuration/constants/reference.constants";
import type { PagGroundingFaces } from "#types/reference.types";
import { kindRefResolves } from "#core/resolvers/reference.resolver";
import { roleIdOf } from "#core/selectors/grammar.selector";

const byName = function byName(a: string, b: string): number {
    return a.localeCompare(b);
};

const groundedConstructs = function groundedConstructs(
    faces: PagGroundingFaces,
): { id: string; grounds: readonly string[] | undefined }[] {
    return [
        ...faces.pag
            .keywords()
            .flatMap((keyword) =>
                keyword.roles.map((role) => ({ grounds: role.grounds, id: roleIdOf(keyword, role) })),
            ),
        ...faces.pag.productions().map((production) => ({ grounds: production.grounds, id: production.lhs })),
        ...faces.pag.documentTypes().map((doctype) => ({ grounds: doctype.grounds, id: doctype.type })),
    ];
};

export const unresolvedPagGroundsOf = function unresolvedPagGroundsOf(
    faces: PagGroundingFaces,
): { from: string; target: string }[] {
    const kindMembers = faces.reason.kindMembers();
    return groundedConstructs(faces).flatMap((construct) =>
        (construct.grounds ?? [])
            .filter((target) => !kindRefResolves(kindMembers, target))
            .map((target) => ({ from: construct.id, target })),
    );
};

export const ungroundedPagConstructsOf = function ungroundedPagConstructsOf(faces: PagGroundingFaces): string[] {
    return [
        ...faces.pag
            .keywords()
            .flatMap((keyword) =>
                keyword.roles
                    .filter((role) => !PAG_GROUNDING_EXEMPT.has(role.category) && (role.grounds ?? []).length === 0)
                    .map((role) => roleIdOf(keyword, role)),
            ),
        ...faces.pag
            .productions()
            .filter(
                (production) => !PAG_PRODUCTION_EXEMPT.has(production.lhs) && (production.grounds ?? []).length === 0,
            )
            .map((production) => production.lhs),
    ].toSorted(byName);
};

const unresolvedRef = function unresolvedRef(value: string | undefined, set: Set<string>): boolean {
    return typeof value !== "string" || value === "" || !set.has(value);
};

export const doctypeModelAxisOf = function doctypeModelAxisOf(faces: PagGroundingFaces): string[] {
    const models = new Set(faces.reason.models().map((model) => model.id));
    const axes = new Set(faces.reason.axes().map((axis) => axis.id));
    return faces.pag
        .documentTypes()
        .filter((doctype) => unresolvedRef(doctype.model, models) || unresolvedRef(doctype.axis, axes))
        .map((doctype) => doctype.type)
        .toSorted(byName);
};