core/coordinators/page.coordinator.ts

core/coordinators/page.coordinator.ts is a file in GovLab Patterns. 142 lines of code and 28 definitions.

import { FALLBACK_STATE, HIGH_SEVERITY, MEDIUM_SEVERITY } from "#configuration/constants/report.constants";
import type { HexPage, Nested, PageOutput, PageParts, RenderContext, TreeNode } from "#types/page.types";
import type { PageRender, ReportPage } from "#types/report.types";
import { nestedTip, pageLabel } from "#configuration/strings/report.strings";
import type { CodeFinding } from "#types/code.types";
import { FINDING_KINDS } from "#configuration/strings/code.strings";
import type { FileEntry } from "#types/package.types";
import type { WalkNode } from "#types/walk.types";
import { assertHardened } from "#core/validators/markup.validator";
import { increment } from "#core/counters/base.counter";
import { keyOf } from "#core/formatters/definition.formatter";
import { metricsOf } from "#core/counters/report.counter";
import { pageBaseName } from "#core/converters/page.converter";
import { renderHexGrid } from "#core/renderers/walk.renderer";
import { renderPage } from "#core/renderers/report.renderer";
import { stateOf } from "#core/classifiers/syntax.classifier";
import { subtreeFiles } from "#core/converters/folder.converter";
import { syntaxDistribution } from "#core/analyzers/syntax.analyzer";
import { walkCells } from "#core/converters/walk.converter";
import { walkSubtitle } from "#configuration/strings/walk.strings";

const guarded = function guarded(
    nodes: readonly WalkNode[],
    flagged: ReadonlyMap<string, string>,
    label: string,
): string {
    if (nodes.length === 0) {
        return "";
    }
    const svg = renderHexGrid(nodes, { flagged, title: label });
    assertHardened(svg, label);
    return svg;
};

const dominantState = function dominantState(files: readonly FileEntry[]): string {
    const counts = new Map<string, number>();
    for (const node of files.flatMap((entry) => entry.walk)) {
        increment(counts, node.state ?? stateOf(node.label));
    }
    return [...counts].sort((a, b) => b[1] - a[1])[0]?.[0] ?? FALLBACK_STATE;
};

const nestedFor = function nestedFor(child: TreeNode, ctx: RenderContext): Nested {
    const files = subtreeFiles(child);
    const fileSet = new Set(files.map((entry) => entry.rel));
    const defs = ctx.insight.symbols.filter((stat) => fileSet.has(stat.file)).length;
    const subFindings = ctx.findings.filter((finding) => fileSet.has(finding.file));
    const severity = subFindings.some((finding) => finding.severity === HIGH_SEVERITY)
        ? HIGH_SEVERITY
        : MEDIUM_SEVERITY;
    const node: WalkNode = {
        depth: 0,
        file: child.rel,
        label: child.kind,
        name: child.rel,
        role: "node",
        state: dominantState(files),
        tip: nestedTip(child.rel, child.count, defs, subFindings.length),
    };
    const page = child.kind === "dir" ? pageBaseName(child.rel) : "";
    return {
        child: { anomalies: subFindings.length, count: child.count, defs, label: child.name, page },
        flagged: subFindings.length > 0,
        node,
        severity,
    };
};

const flagMap = function flagMap(findings: readonly CodeFinding[]): Map<string, string> {
    const map = new Map<string, string>();
    for (const finding of findings) {
        const keys = finding.kind === FINDING_KINDS.callCycle ? finding.members : [keyOf(finding.file, finding.name)];
        for (const key of keys) {
            map.set(key, finding.severity);
        }
    }
    return map;
};

const toPageRender = function toPageRender(page: HexPage, ctx: RenderContext, parts: PageParts): PageRender {
    const walk = page.inlined.flatMap((entry) => entry.walk);
    const flagged = flagMap(parts.findings);
    const nestedNodes = parts.nested.map((item) => item.node);
    return {
        crumbs: page.crumbs,
        definitions: parts.symbols.length,
        distribution: syntaxDistribution(page.inlined.flatMap((entry) => entry.records)),
        fanIn: ctx.fanIn,
        findings: parts.findings,
        label: parts.label,
        mainCells: walkCells(walk, flagged),
        mainSvg: guarded(walk, flagged, parts.label),
        nested: parts.nested.map((item) => item.child),
        nestedCells: walkCells(nestedNodes, parts.nestedFlags),
        nestedSubtitle: walkSubtitle(nestedNodes.length),
        nestedSvg: guarded(nestedNodes, parts.nestedFlags, parts.label),
        symbols: parts.symbols,
        walkSubtitle: walkSubtitle(walk.length),
    };
};

const toReportPage = function toReportPage(
    page: HexPage,
    ctx: RenderContext,
    render: PageRender,
    files: ReadonlySet<string>,
): ReportPage {
    return {
        crumbs: render.crumbs,
        distribution: render.distribution,
        files: [...files].sort((a, b) => a.localeCompare(b)),
        findings: render.findings,
        id: page.page,
        label: render.label,
        metrics: metricsOf({
            edges: ctx.graph.edges.filter((edge) => files.has(edge.file)),
            findings: render.findings,
            symbols: render.symbols,
            unresolved: ctx.graph.external.filter((call) => files.has(call.file)).length,
        }),
        nested: render.nested,
        rel: page.rel,
        subtitle: render.walkSubtitle,
        walk: render.mainSvg === "" ? null : page.page,
    };
};

export const renderOne = function renderOne(page: HexPage, ctx: RenderContext): PageOutput {
    const label = page.rel === "" ? ctx.title : pageLabel(ctx.title, page.rel);
    const files = new Set(page.inlined.map((entry) => entry.rel));
    const symbols = ctx.insight.symbols.filter((stat) => files.has(stat.file));
    const isRoot = page.rel === "";
    const findings = ctx.findings.filter((finding) => (finding.file === "" ? isRoot : files.has(finding.file)));
    const nested = page.drilled.map((dir) => nestedFor(dir, ctx));
    const nestedFlags = new Map(
        nested
            .filter((item) => item.flagged)
            .map((item) => [keyOf(item.node.file ?? "", item.node.name ?? ""), item.severity]),
    );
    const render = toPageRender(page, ctx, { findings, label, nested, nestedFlags, symbols });
    return {
        html: renderPage(render),
        mainCells: render.mainCells,
        mainSvg: render.mainSvg,
        nestedCells: render.nestedCells,
        nestedSvg: render.nestedSvg,
        report: toReportPage(page, ctx, render, files),
    };
};