core/coordinators/package.coordinator.ts
core/coordinators/package.coordinator.ts is a file in GovLab Patterns. 111 lines of code and 19 definitions.
import type {
BuiltModule,
FileEntry,
ModuleBuild,
ModuleReportBuild,
ModuleScope,
RepoContext,
} from "#types/package.types";
import { buildAnalysis, buildFindings } from "#core/formatters/report.formatter";
import { codeGraph, codeInsight } from "#core/analyzers/code.analyzer";
import { entriesFor, testUsesOf } from "#core/loaders/source.loader";
import { sortedEdges, unresolvedNames } from "#core/selectors/code.selector";
import { NESTED_SUFFIX } from "#configuration/constants/report.constants";
import type { PageOutput } from "#types/page.types";
import type { WalkCell } from "#types/walk.types";
import { basename } from "node:path";
import { buildGroup } from "#core/converters/folder.converter";
import { definitionRecords } from "#core/converters/definition.converter";
import { diagnose } from "#core/coordinators/code.coordinator";
import { keyOf } from "#core/formatters/definition.formatter";
import { metricsOf } from "#core/counters/report.counter";
import { planNode } from "#core/converters/page.converter";
import { renderOne } from "#core/coordinators/page.coordinator";
import { titleFor } from "#core/resolvers/package.resolver";
type Rendered = readonly [string, PageOutput];
const walkArtifacts = function walkArtifacts<T>(
rendered: readonly Rendered[],
main: (output: PageOutput) => T,
nested: (output: PageOutput) => T,
): Map<string, T> {
const out = new Map<string, T>();
for (const [base, output] of rendered) {
if (output.mainSvg.length > 0) {
out.set(base, main(output));
}
if (output.nestedSvg.length > 0) {
out.set(`${base}${NESTED_SUFFIX}`, nested(output));
}
}
return out;
};
export const buildModule = function buildModule(entries: readonly FileEntry[], build: ModuleBuild): BuiltModule {
const symbols = entries.flatMap((entry) => entry.symbols);
const records = entries.flatMap((entry) => entry.records);
const insight = codeInsight(symbols, records);
const graph = codeGraph(symbols);
const diagnosed = diagnose(symbols, { graph, records, testUses: build.testUses ?? new Set() });
const findings = [...(build.extraFindings ?? []), ...diagnosed].sort(
(left, right) => right.relevance - left.relevance || JSON.stringify(left).localeCompare(JSON.stringify(right)),
);
const context = { fanIn: build.fanIn ?? new Map<string, number>(), findings, graph, insight, title: build.title };
const rendered = planNode(buildGroup(entries, "", build.moduleName), []).map((page): Rendered => [
page.page,
renderOne(page, context),
]);
return {
analysis: buildAnalysis({ findingsCount: findings.length, graph, insight, title: build.title }),
cells: walkArtifacts<WalkCell[]>(
rendered,
(output) => output.mainCells,
(output) => output.nestedCells,
),
findings: buildFindings(build.title, findings),
findingsData: findings,
pages: new Map(rendered.map(([base, output]): [string, string] => [base, output.html])),
report: {
definitions: definitionRecords(insight, graph),
edges: sortedEdges(graph),
findings,
metrics: metricsOf({
edges: graph.edges,
findings,
symbols: insight.symbols,
unresolved: graph.external.length,
}),
module: build.title,
pages: rendered.map(([, output]) => output.report),
unresolvedCalls: unresolvedNames(graph),
},
svgs: walkArtifacts<string>(
rendered,
(output) => output.mainSvg,
(output) => output.nestedSvg,
),
};
};
export const buildModuleReport = async function buildModuleReport(
moduleDir: string,
ctx: RepoContext,
scope: ModuleScope,
): Promise<ModuleReportBuild> {
const entries = await entriesFor(moduleDir, scope.pruned);
const fanIn = new Map(
entries.flatMap((entry) =>
entry.symbols.flatMap((symbol): [string, number][] => {
const count = ctx.fanIn.get(keyOf(moduleDir, symbol.name));
return count === undefined ? [] : [[symbol.name, count]];
}),
),
);
const testUses = await testUsesOf(moduleDir, scope.pruned);
const title = titleFor(scope.root, moduleDir);
const built = buildModule(entries, {
extraFindings: ctx.importCycles.get(moduleDir) ?? [],
fanIn,
moduleName: basename(moduleDir),
testUses,
title,
});
return { built, entries, title };
};