core/formatters/readme.formatter.ts
core/formatters/readme.formatter.ts is a file in GovLab Docs. 110 lines of code and 16 definitions.
import { METRICS_LAYER, REPO_METRICS_LAYER } from "#configuration/constants/layer.constants";
import { README_HEADINGS, README_TEXT, chartsNote, defaultInstall } from "#configuration/strings/readme.strings";
import type { ReadmeLayer, RenderContext } from "#types/readme.types";
import {
renderApi,
renderConcepts,
renderDeps,
renderDomains,
renderMetrics,
renderPrinciples,
renderRepoMetrics,
} from "#core/formatters/readme.section.formatter";
import {
renderConfiguration,
renderQuickStart,
renderRenderable,
titleCase,
} from "#core/formatters/markdown.formatter";
import { relativePath } from "@ssot/paths";
import { wrapLayer } from "#core/converters/layer.converter";
export const CORE_FIELDS: ReadonlySet<string> = new Set([
"overview",
"whenToUse",
"whenNotToUse",
"quickStart",
"configuration",
"disposal",
"aiContext",
"apiNotes",
"api",
"install",
]);
const section = function section(heading: string, body: string): string {
return `## ${heading}\n\n${body}`;
};
const isRenderableSlot = function isRenderableSlot(value: unknown): boolean {
return typeof value === "string" || Array.isArray(value);
};
const installLayer = function installLayer(context: RenderContext): string {
const body = isRenderableSlot(context.docs.install)
? renderRenderable(context.docs.install)
: defaultInstall(context.scoped);
const install = body.trim() === "" ? "" : `${section(README_HEADINGS.install, body)}\n\n`;
return install + section(README_HEADINGS.quickStart, renderQuickStart(context.docs.quickStart));
};
const apiLayer = function apiLayer(context: RenderContext): string {
if (context.surface.length > 0) {
return section(README_HEADINGS.api, renderApi(context.surface, context.docs.apiNotes));
}
const body = isRenderableSlot(context.docs.api) ? renderRenderable(context.docs.api) : README_TEXT.noSurface;
return section(README_HEADINGS.api, body);
};
const useLayer = function useLayer(context: RenderContext): string {
const toUse = section(README_HEADINGS.whenToUse, renderRenderable(context.docs.whenToUse));
return `${toUse}\n\n${section(README_HEADINGS.whenNotToUse, renderRenderable(context.docs.whenNotToUse))}`;
};
const chartsLayer = function chartsLayer(context: RenderContext): string | null {
return context.hasCharts ? section(README_HEADINGS.charts, chartsNote(relativePath("moduleInfo.charts"))) : null;
};
const LAYERS: readonly ReadmeLayer[] = [
{ id: "overview", render: (context) => section(README_HEADINGS.purpose, renderRenderable(context.docs.overview)) },
{ id: "use", render: useLayer },
{ id: "charts", render: chartsLayer },
{ id: "install", render: installLayer },
{ id: "api", render: apiLayer },
{
id: "config",
render: (context) => section(README_HEADINGS.configuration, renderConfiguration(context.docs.configuration)),
},
{ id: "deps", render: (context) => section(README_HEADINGS.dependencies, renderDeps(context.pkg)) },
{
id: "ai-context",
render: (context) => section(README_HEADINGS.aiContext, renderRenderable(context.docs.aiContext)),
},
{ id: "domains", render: (context) => (context.domains.length > 0 ? renderDomains(context.domains) : null) },
{
id: "principles",
render: (context) => (context.principles.length > 0 ? renderPrinciples(context.principles) : null),
},
{
id: "quality-governance",
render: (context) => (context.concepts.length > 0 ? renderConcepts(context.concepts) : null),
},
{ id: "disposal", render: (context) => section(README_HEADINGS.disposal, renderRenderable(context.docs.disposal)) },
];
const coreLayers = function coreLayers(context: RenderContext): string[] {
return LAYERS.flatMap((layer) => {
const body = layer.render(context);
return body === null || body === "" ? [] : [wrapLayer(layer.id, body)];
});
};
const customLayers = function customLayers(context: RenderContext): string[] {
return Object.keys(context.docs)
.filter((key) => !CORE_FIELDS.has(key))
.map((key) => wrapLayer(key, section(titleCase(key), renderRenderable(context.docs[key]))));
};
const repoLayer = function repoLayer(context: RenderContext): string[] {
const body = renderRepoMetrics(context.repo);
return body === "" ? [] : [wrapLayer(REPO_METRICS_LAYER, body)];
};
export const generateModuleDoc = function generateModuleDoc(context: RenderContext): string {
const parts = [
`# ${context.scoped}`,
...coreLayers(context),
...customLayers(context),
...repoLayer(context),
wrapLayer(METRICS_LAYER, renderMetrics(context)),
];
return `${parts.join("\n\n")}\n`;
};