core/plugins/manifest.document.plugin.ts

core/plugins/manifest.document.plugin.ts is a file in GovLab Docs. 121 lines of code and 23 definitions.

import { ACTIVITY_VERBS, DOC_CONCERNS } from "#configuration/constants/concern.constants";
import {
    MANIFEST_ERRORS,
    documentBody,
    documentConcern,
    documentLead,
    documentMember,
    documentName,
    documentObject,
    documentSummary,
    documentTitle,
    documentType,
    duplicateDocument,
    sectionContent,
    sectionHeading,
} from "#configuration/strings/manifest.strings";
import { docsConfig, loadGovlabConfig } from "@govlab/quality/config";
import { isNonEmptyString, isRenderable } from "#core/predicates/readme.predicate";
import { DOC_FORMS } from "#configuration/constants/form.constants";
import { DOC_VERBS } from "#configuration/constants/verb.constants";
import type { Manifest } from "#types/readme.types";
import type { ManifestPlugin } from "#types/manifest.types";
import { ROOT } from "@ssot/paths";
import { isKebab } from "#core/predicates/character.predicate";
import { isPlainRecord } from "#core/predicates/record.predicate";
import { loadUserRegistries } from "#core/loaders/registry.loader";

const SECTION = "documents";
const KNOWN_SEPARATOR = ", ";
const REGISTRIES = await loadUserRegistries(ROOT, {
    activityVerbs: ACTIVITY_VERBS,
    concerns: DOC_CONCERNS,
    forms: DOC_FORMS,
    refVerbs: DOC_VERBS,
});
const MEMBERS = docsConfig(await loadGovlabConfig(ROOT)).members;

const memberErrors = function memberErrors(doc: Manifest, at: string, ownerAxis: string): string[] {
    const { member } = doc;
    if (MEMBERS.length === 0 || ownerAxis === "module" || (typeof member === "string" && MEMBERS.includes(member))) {
        return [];
    }
    return [documentMember(at, String(member), MEMBERS.join(KNOWN_SEPARATOR))];
};

const typeErrors = function typeErrors(doc: Manifest, at: string): string[] {
    const { type, concern } = doc;
    const form = typeof type === "string" ? REGISTRIES.forms[type] : undefined;
    if (form === undefined || form.boundary) {
        return [documentType(at, String(type))];
    }
    if (form.ownerAxis === "concern" && !(typeof concern === "string" && REGISTRIES.concerns.includes(concern))) {
        return [documentConcern(at, String(concern))];
    }
    return memberErrors(doc, at, form.ownerAxis);
};

const sectionErrors = function sectionErrors(section: unknown, at: string, index: number): string[] {
    const record = isPlainRecord(section) ? section : {};
    return [
        ...(isNonEmptyString(record["heading"]) ? [] : [sectionHeading(at, index)]),
        ...(isRenderable(record["content"]) ? [] : [sectionContent(at, index)]),
    ];
};

const bodyErrors = function bodyErrors(doc: Manifest, at: string): string[] {
    const { body } = doc;
    if (!Array.isArray(body) || body.length === 0) {
        return [documentBody(at)];
    }
    return body.flatMap((section, index) => sectionErrors(section, at, index));
};

const optionalErrors = function optionalErrors(doc: Manifest, at: string): string[] {
    return [
        ...(doc["title"] !== undefined && !isNonEmptyString(doc["title"]) ? [documentTitle(at)] : []),
        ...(doc["lead"] !== undefined && !isRenderable(doc["lead"]) ? [documentLead(at)] : []),
    ];
};

const entryErrors = function entryErrors(doc: unknown, at: string): string[] {
    if (!isPlainRecord(doc)) {
        return [documentObject(at)];
    }
    return [
        ...typeErrors(doc, at),
        ...(isKebab(doc["name"]) ? [] : [documentName(at)]),
        ...(isNonEmptyString(doc["summary"]) ? [] : [documentSummary(at)]),
        ...optionalErrors(doc, at),
        ...bodyErrors(doc, at),
    ];
};

const duplicateErrors = function duplicateErrors(documents: readonly unknown[], doc: unknown, index: number): string[] {
    const name = isPlainRecord(doc) ? doc["name"] : undefined;
    if (typeof name !== "string") {
        return [];
    }
    const first = documents.findIndex((other) => isPlainRecord(other) && other["name"] === name);
    return first < index ? [duplicateDocument(index, name)] : [];
};

export const plugin: ManifestPlugin = {
    contribute(manifest, entry) {
        const documents = manifest[SECTION];
        const names = (Array.isArray(documents) ? documents : []).flatMap((doc) =>
            isPlainRecord(doc) && typeof doc["name"] === "string" ? [doc["name"]] : [],
        );
        if (names.length > 0) {
            entry[SECTION] = names;
        }
    },
    name: "documents",
    section: {
        keys: [SECTION],
        validate(manifest) {
            const documents = manifest[SECTION];
            if (documents === undefined) {
                return [];
            }
            if (!Array.isArray(documents)) {
                return [MANIFEST_ERRORS.documentsShape];
            }
            return documents.flatMap((doc, index) => [
                ...entryErrors(doc, `${SECTION}[${index}]`),
                ...duplicateErrors(documents, doc, index),
            ]);
        },
    },
};