core/factories/finding.factory.ts
core/factories/finding.factory.ts is a file in GovLab Quality. 139 lines of code and 20 definitions.
import type { AdvisoryContext, TerminationSignal, ToolExit } from "#types/tool.types";
import type { AdvisoryFindingInput, Finding, NoticeSpec, PassOutcome, RunResult } from "#types/finding.types";
import {
NO_STDERR_DETAIL,
UNKNOWN_SIGNAL,
signalDeathMessage,
spawnErrorMessage,
toolErrorMessage,
} from "#configuration/strings/tool.strings";
import { spawnDetail, tailLines } from "#core/selectors/failure.selector";
import { POSITION } from "#configuration/constants/tool.constants";
import { PROJECT_TOOL } from "#configuration/constants/validation.constants";
import { formatFindings } from "#core/formatters/report.formatter";
export const EMPTY_RESULT: RunResult = { findings: [], fixedCount: 0, output: "" };
export const reportedPass = function reportedPass(findings: Finding[]): PassOutcome {
return { findings, terminal: false };
};
export const terminatedPass = function terminatedPass(result: RunResult): PassOutcome {
return { result, terminal: true };
};
export const findingsResult = function findingsResult(findings: Finding[], fixedCount = 0): RunResult {
return { findings, fixedCount, output: formatFindings(findings) };
};
export const fixedResult = function fixedResult(reported: readonly Finding[], residual: Finding[]): RunResult {
return findingsResult(residual, Math.max(0, reported.length - residual.length));
};
export const toolFinding = function toolFinding(
input: AdvisoryFindingInput & { advisory?: boolean; fixable?: boolean },
): Finding {
return {
advisory: input.advisory ?? false,
column: input.column,
ecosystem: input.ecosystem,
file: input.file,
fixable: input.fixable ?? false,
line: input.line,
message: input.message,
ruleId: input.ruleId,
severity: "error",
tool: input.tool,
};
};
export const projectFinding = function projectFinding(input: {
file: string;
message: string;
ruleId: string;
suggestion: string;
}): Finding {
return {
advisory: false,
column: 0,
ecosystem: "",
file: input.file,
fixable: false,
line: 0,
message: input.message,
ruleId: input.ruleId,
severity: "error",
suggestion: input.suggestion,
tool: PROJECT_TOOL,
};
};
export const advisoryFinding = function advisoryFinding(input: AdvisoryFindingInput): Finding {
return toolFinding({ ...input, advisory: true });
};
const buildNotice = function buildNotice(context: AdvisoryContext, spec: NoticeSpec): RunResult {
const finding: Finding = {
advisory: spec.advisory,
column: POSITION,
ecosystem: context.ecosystem,
file: context.root,
fixable: false,
line: POSITION,
message: spec.message,
ruleId: spec.ruleId,
severity: spec.severity,
tool: context.tool,
};
return { findings: [finding], fixedCount: 0, output: spec.output ?? spec.message };
};
const failureSpec = function failureSpec(context: AdvisoryContext, ruleId: string, message: string): NoticeSpec {
return { advisory: context.gating !== true, message, ruleId, severity: context.failureSeverity ?? "notice" };
};
export const advisoryNotice = function advisoryNotice(
context: AdvisoryContext,
ruleId: string,
message: string,
): RunResult {
return buildNotice(context, { advisory: true, message, ruleId, severity: "notice" });
};
export const gatingNotice = function gatingNotice(
context: AdvisoryContext,
ruleId: string,
message: string,
): RunResult {
return buildNotice(context, failureSpec(context, ruleId, message));
};
export const toolErrorRule = function toolErrorRule(tool: string): string {
return `${tool}/tool-error`;
};
export const toolFailure = function toolFailure(context: AdvisoryContext, message: string): RunResult {
return gatingNotice(context, toolErrorRule(context.tool), message);
};
export const notInstalled = function notInstalled(context: AdvisoryContext): RunResult {
return buildNotice(context, {
advisory: true,
message: context.installHint,
output: context.notInstalledOutput ?? context.installHint,
ruleId: `${context.tool}/not-installed`,
severity: "notice",
});
};
export const spawnFailure = function spawnFailure(context: AdvisoryContext, error: Error): RunResult {
const message = spawnErrorMessage(context.tool, spawnDetail(error));
return buildNotice(context, failureSpec(context, `${context.tool}/spawn-error`, message));
};
export const toolError = function toolError(context: AdvisoryContext, exit: ToolExit): RunResult {
const message = toolErrorMessage(context.tool, exit.status, tailLines(exit.stderr, NO_STDERR_DETAIL));
return gatingNotice(context, toolErrorRule(context.tool), message);
};
export const signalDeathResult = function signalDeathResult(
source: { ecosystem: string; root: string; tool: string },
signal: TerminationSignal | null,
): RunResult {
const message = signalDeathMessage(source.tool, signal ?? UNKNOWN_SIGNAL);
const finding: Finding = {
advisory: false,
column: POSITION,
ecosystem: source.ecosystem,
file: source.root,
fixable: false,
line: POSITION,
message,
ruleId: toolErrorRule(source.tool),
severity: "error",
tool: source.tool,
};
return { findings: [finding], fixedCount: 0, output: message };
};