runtime/entrypoints/report.entrypoint.ts
runtime/entrypoints/report.entrypoint.ts is a file in GovLab Patterns. 139 lines of code and 33 definitions.
import {
FAILURE_EXIT,
LIST_SEPARATOR,
NO_CACHE_ENV,
NO_CACHE_ON,
REPORT_FLAG_NAMES,
} from "#configuration/constants/invocation.constants";
import { HEAL_ATTEMPTS, HTML_SUFFIX, SLUG_JOIN } from "#configuration/constants/report.constants";
import { HEAL_NOTES, healNote, moduleDrift, moduleWritten, writeSummary } from "#configuration/strings/report.strings";
import type { ModuleArtifacts, ModuleSvgs, ModuleTitle } from "#types/report.types";
import type { ModuleScope, RepoContext } from "#types/package.types";
import { ROOT, absolutePath, relativePath } from "@ssot/paths";
import { basename, resolve } from "node:path";
import { buildContext, emptyContext } from "#core/factories/context.factory";
import { discoverModules, sourceFiles, testFilesOf } from "#core/loaders/package.loader";
import { flagValue, hasFlag, resolveArgv } from "@govlab/argv";
import { healModule, runHexCheck } from "#core/coordinators/report.coordinator";
import { hexArtifactsExist, moduleFingerprint, openReportCache } from "#core/caches/report.cache";
import { loadGovlabConfig, masterExcludeMarkers, pathExclusion } from "@govlab/quality/config";
import { persistArtifacts, writeHexMaster, writeSvgCollection } from "#core/persistence/report.persistence";
import { REPORT_ARGV } from "#configuration/configs/invocation.config";
import { buildModuleReport } from "#core/coordinators/package.coordinator";
import { checkHexMaster } from "#core/validators/report.validator";
import { defineCheck } from "@govlab/context/check";
import process from "node:process";
import { settleParses } from "#core/loaders/source.loader";
import { titleFor } from "#core/resolvers/package.resolver";
defineCheck({ detects: [], enforces: ["architecture:reproducibility"] });
const argv = resolveArgv(REPORT_ARGV);
const ignored = (flagValue(argv, REPORT_FLAG_NAMES.ignore) ?? "")
.split(LIST_SEPARATOR)
.filter((entry) => entry.length > 0);
const markers = masterExcludeMarkers(await loadGovlabConfig(process.cwd()));
const pruned = pathExclusion(process.cwd(), [...markers, ...ignored]);
const masterPath = absolutePath("projectInfo.findings");
const cache = openReportCache(process.env[NO_CACHE_ENV] === NO_CACHE_ON);
const scope: ModuleScope = { pruned, root: ROOT };
const titleOf = function titleOf(moduleDir: string): string {
return titleFor(ROOT, moduleDir);
};
const pool = async function pool(items: readonly string[], worker: (item: string) => Promise<void>): Promise<void> {
await items.reduce(async (queued, item) => {
await queued;
await worker(item);
}, Promise.resolve());
};
const artifactsFor = async function artifactsFor(moduleDir: string, ctx: RepoContext): Promise<ModuleArtifacts> {
const { built, title } = await buildModuleReport(moduleDir, ctx, scope);
const artifacts = new Map<string, string>([
...[...built.pages].map(([base, html]): [string, string] => [`${base}.generated${HTML_SUFFIX}`, html]),
[basename(relativePath("moduleInfo.analysis")), built.analysis],
[basename(relativePath("moduleInfo.findings")), built.findings],
[basename(relativePath("moduleInfo.report")), JSON.stringify(built.report)],
]);
return { artifacts, findings: { findings: built.findingsData, module: title }, svgs: built.svgs };
};
const svgUnits = function svgUnits(byModule: ReadonlyMap<string, ReadonlyMap<string, string>>): ModuleSvgs[] {
return [...byModule].map(([moduleDir, svgs]) => ({ slug: titleOf(moduleDir).split("/").join(SLUG_JOIN), svgs }));
};
const knownSlugs = function knownSlugs(modules: readonly string[]): Set<string> {
return new Set(modules.map((dir) => titleOf(dir).split("/").join(SLUG_JOIN)));
};
const titles = function titles(modules: readonly string[]): ModuleTitle[] {
return modules.map((dir) => ({ dir, title: titleOf(dir) }));
};
const writeModule = async function writeModule(moduleDir: string, ctx: RepoContext): Promise<Map<string, string>> {
const { artifacts, svgs } = await artifactsFor(moduleDir, ctx);
persistArtifacts(moduleDir, artifacts);
process.stdout.write(moduleWritten(titleOf(moduleDir), artifacts.size));
return svgs;
};
const writeAll = async function writeAll(modules: readonly string[], ctx: RepoContext): Promise<void> {
const svgs = new Map<string, Map<string, string>>();
await pool(modules, async (moduleDir) => {
const fanIn = [...ctx.fanIn].filter(([key]) => key.startsWith(`${moduleDir}::`));
const files = [...sourceFiles(moduleDir, pruned), ...testFilesOf(moduleDir, pruned)];
const key = moduleFingerprint(files, fanIn, ctx.importCycles.get(moduleDir) ?? []);
if (!cache.unchanged(moduleDir, key) || !hexArtifactsExist(moduleDir)) {
svgs.set(moduleDir, await writeModule(moduleDir, ctx));
cache.update(moduleDir, key);
}
});
writeSvgCollection(ROOT, svgUnits(svgs), knownSlugs(modules));
writeHexMaster(masterPath, titles(modules));
cache.flush();
process.stdout.write(writeSummary(svgs.size, modules.length));
};
const runAll = async function runAll(check: boolean): Promise<void> {
const modules = discoverModules(ROOT, pruned);
const ctx = await buildContext(modules, scope);
if (!check) {
await writeAll(modules, ctx);
return;
}
await runHexCheck({
attempts: HEAL_ATTEMPTS,
async generate(moduleDir) {
return artifactsFor(moduleDir, ctx);
},
masterOk(collected) {
return checkHexMaster(masterPath, collected);
},
modules,
pool,
reparse: settleParses,
title: titleOf,
writeMaster() {
writeHexMaster(masterPath, titles(modules));
},
writeSvgs(byModule) {
writeSvgCollection(ROOT, svgUnits(byModule), knownSlugs(modules));
},
});
};
const runOne = async function runOne(moduleDir: string, check: boolean, fast: boolean): Promise<void> {
const ctx = fast ? emptyContext() : await buildContext(discoverModules(ROOT, pruned), scope);
if (!check) {
await writeModule(moduleDir, ctx);
return;
}
const result = await healModule(moduleDir, {
attempts: HEAL_ATTEMPTS,
async generate(dir) {
return artifactsFor(dir, ctx);
},
reparse: settleParses,
});
if (result.state === "drift") {
process.stderr.write(moduleDrift(moduleDir));
process.exitCode = FAILURE_EXIT;
return;
}
process.stdout.write(healNote(HEAL_NOTES[result.state]));
};
const check = hasFlag(argv, REPORT_FLAG_NAMES.check);
const target = resolve(argv.positionals[0] ?? ".");
await (hasFlag(argv, REPORT_FLAG_NAMES.all)
? runAll(check)
: runOne(target, check, hasFlag(argv, REPORT_FLAG_NAMES.fast)));