core/coordinators/quality.coordinator.ts
core/coordinators/quality.coordinator.ts is a file in GovLab Quality. 81 lines of code and 18 definitions.
import type { DetectedEcosystem, QualityOutcome, RunQualityOptions } from "#types/quality.types";
import type { RunnerContext, ToolRunner } from "#types/tool.types";
import { buildCanonIndex, canonFor } from "#core/resolvers/canon.resolver";
import { defaultPathsFor, detectEcosystems } from "#core/resolvers/scope.resolver";
import { renderHuman, renderJson } from "#core/formatters/report.formatter";
import type { Finding } from "#types/finding.types";
import { NO_ECOSYSTEM } from "#configuration/strings/tool.strings";
import { loadTools } from "#core/loaders/tool.loader";
import { selectableTools } from "#core/loaders/dependency.loader";
const detectFor = function detectFor(options: RunQualityOptions): DetectedEcosystem[] {
return options.ecosystems && options.ecosystems.length > 0
? options.ecosystems.map((ecosystem) => ({ ecosystem, languageId: ecosystem }))
: detectEcosystems(options.root);
};
const contextFor = function contextFor(
options: RunQualityOptions,
matches: readonly DetectedEcosystem[],
election: { elected: boolean | undefined },
): RunnerContext {
const { elected } = election;
const [primary] = matches;
if (primary === undefined) {
throw new Error(NO_ECOSYSTEM);
}
return {
backup: options.backup,
dryRun: options.dryRun,
ecosystem: primary.ecosystem,
elected,
env: options.env,
fix: options.fix,
languageId: primary.languageId,
paths: options.paths ?? [...new Set(matches.flatMap((match) => defaultPathsFor(match.ecosystem)))],
root: options.root,
};
};
const matchesFor = function matchesFor(
runner: ToolRunner,
detected: readonly DetectedEcosystem[],
): DetectedEcosystem[] {
return detected.filter((entry) => runner.ecosystems.includes(entry.ecosystem));
};
const decorateCanon = function decorateCanon(findings: readonly Finding[]): void {
const canonIndex = buildCanonIndex();
for (const finding of findings) {
const canon = canonFor(finding.ruleId, canonIndex);
if (canon.length > 0) {
finding.canon = canon;
}
}
};
export const runQuality = async function runQuality(options: RunQualityOptions): Promise<QualityOutcome> {
const detected = detectFor(options);
const selectable = selectableTools();
const elected = new Set(options.selectableActive);
const active = (await loadTools()).filter(
(runner) => (!options.only || options.only.includes(runner.tool)) && matchesFor(runner, detected).length > 0,
);
const results = await Promise.all(
active.map(async (runner) =>
runner.run(
contextFor(options, matchesFor(runner, detected), {
elected: selectable.has(runner.tool) ? elected.has(runner.tool) : undefined,
}),
),
),
);
const findings = results.flatMap((result) => result.findings);
const fixedCount = results.reduce((sum, result) => sum + result.fixedCount, 0);
decorateCanon(findings);
const report =
options.reporter === "json"
? renderJson(findings, fixedCount)
: renderHuman(
results.map((result) => result.output),
findings,
fixedCount,
);
const hasErrors = findings.some((finding) => finding.severity === "error" && !finding.advisory);
return { exitCode: hasErrors ? 1 : 0, findings, report };
};