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),
]);
},
},
};