core/formatters/coverage.formatter.ts

core/formatters/coverage.formatter.ts is a file in GovLab Docs. 50 lines of code and 13 definitions.

import {
    COVERAGE_COMPLETE,
    COVERAGE_GAPS,
    coverageGaps,
    coverageHeading,
    missingAiContext,
    missingCapabilities,
    rankedRow,
    withoutRelationships,
} from "#configuration/strings/coverage.strings";
import { arrayField, recordField } from "#core/selectors/record.selector";
import type { CoverageRow } from "#types/index.types";
import type { ManifestModule } from "#types/manifest.types";
import { RELATIONSHIP_KEYS } from "#configuration/constants/manifest.constants";

const GAP_JOIN = ", ";

const gapsOf = function gapsOf(module: ManifestModule, isPrivate: boolean): string[] {
    const { manifest } = module;
    const relationships = RELATIONSHIP_KEYS.reduce((sum, key) => sum + arrayField(manifest, key).length, 0);
    const hasAiContext = Boolean(recordField(manifest, "docs")?.["aiContext"]);
    return [
        ...(arrayField(manifest, "capabilities").length === 0 ? [COVERAGE_GAPS.capabilities] : []),
        ...(!isPrivate && !hasAiContext ? [COVERAGE_GAPS.aiContext] : []),
        ...(relationships === 0 ? [COVERAGE_GAPS.relationships] : []),
    ];
};

export const coverageRow = function coverageRow(module: ManifestModule): CoverageRow {
    const isPrivate = recordField(module.manifest, "visibility")?.["private"] === true;
    return { gaps: gapsOf(module, isPrivate), isPrivate, slug: module.label };
};

const withGap = function withGap(rows: readonly CoverageRow[], gap: string): number {
    return rows.filter((row) => row.gaps.includes(gap)).length;
};

const byGapsThenSlug = function byGapsThenSlug(left: CoverageRow, right: CoverageRow): number {
    return right.gaps.length - left.gaps.length || left.slug.localeCompare(right.slug);
};

export const blockingGaps = function blockingGaps(rows: readonly CoverageRow[]): number {
    return withGap(rows, COVERAGE_GAPS.capabilities) + withGap(rows, COVERAGE_GAPS.aiContext);
};

export const renderCoverage = function renderCoverage(rows: readonly CoverageRow[]): string[] {
    const blocking = blockingGaps(rows);
    const ranked = rows.filter((row) => row.gaps.length > 0).toSorted(byGapsThenSlug);
    return [
        coverageHeading(rows.length),
        missingCapabilities(withGap(rows, COVERAGE_GAPS.capabilities)),
        missingAiContext(withGap(rows, COVERAGE_GAPS.aiContext)),
        withoutRelationships(withGap(rows, COVERAGE_GAPS.relationships)),
        ...ranked.map((row) => rankedRow(row.slug, row.isPrivate, row.gaps.join(GAP_JOIN))),
        blocking === 0 ? COVERAGE_COMPLETE : coverageGaps(blocking),
    ];
};