import type { Edit, Finding, Hit, Verdict } from "../types/segment.types.ts"; import { dirname, join } from "node:path"; import { mkdirSync, writeFileSync } from "node:fs"; import { GENERATED_DIR } from "../constants/path.constants.ts"; export interface Report { readonly tool: string; readonly verdict: Verdict; readonly scanned: number; readonly findings: readonly Finding[]; readonly hits: readonly HitRecord[]; readonly edits: readonly EditRecord[]; readonly rejected: readonly EditRecord[]; readonly coverage: Coverage; } export interface HitRecord { readonly pattern: string; readonly path: string; readonly line: number; readonly text: string; } export interface EditRecord { readonly path: string; readonly reason: string; readonly start: number; readonly end: number; readonly replacement: string; } export interface Coverage { readonly roots: readonly string[]; readonly filesByExtension: Readonly>; } export const toHitRecords = function toHitRecords(hits: readonly Hit[]): HitRecord[] { return hits.map((hit) => ({ line: hit.span.line, path: hit.path, pattern: hit.patternId, text: hit.segments.map((s) => s.text).join("\n"), })); }; export const toEditRecords = function toEditRecords(edits: readonly Edit[]): EditRecord[] { return edits.map((edit) => ({ end: edit.end, path: edit.path, reason: edit.reason, replacement: edit.replacement, start: edit.start, })); }; export const verdictOf = function verdictOf(findings: readonly Finding[], rejected: readonly Edit[]): Verdict { return findings.length === 0 && rejected.length === 0 ? "pass" : "fail"; }; export const writeReport = function writeReport(repoRoot: string, name: string, report: Report): string { const target = join(repoRoot, GENERATED_DIR, `${name}.generated.json`); mkdirSync(dirname(target), { recursive: true }); writeFileSync(target, `${JSON.stringify(report, null, 2)}\n`, "utf8"); return target; };