import { readFileSync, existsSync, writeFileSync } from "node:fs"; import path from "node:path"; import { globSync } from "glob"; const base = process.argv[2] ?? "."; const outFile = process.argv[3] ?? "pr-quality-body.md"; function readJson(p) { return JSON.parse(readFileSync(p, "utf8")); } const lines = []; const covPath = path.join(base, "coverage", "coverage-summary.json"); if (existsSync(covPath)) { const c = readJson(covPath); const t = c.total; lines.push("## Couverture (packages métier Vitest)"); lines.push( `| Métrique | % |`, `|----------|---|`, `| Lignes | ${t.lines.pct.toFixed(2)} |`, `| Branches | ${t.branches.pct.toFixed(2)} |`, `| Fonctions | ${t.functions.pct.toFixed(2)} |`, "" ); } else { lines.push("## Couverture", "_Résumé indisponible (fichier coverage-summary manquant)._", "", ""); } const a11yPath = path.join(base, "e2e", "a11y-summary.json"); if (existsSync(a11yPath)) { const a = readJson(a11yPath); lines.push("## Accessibilité (Axe / Playwright)"); lines.push(`- Violations : **${a.axeViolationCount}**`); if (a.axeViolationIds?.length) lines.push(`- Ids : ${a.axeViolationIds.join(", ")}`); lines.push(""); } else { lines.push("## Accessibilité", "_Résumé Axe indisponible._", "", ""); } const perfPath = path.join(base, "e2e", "perf-summary.json"); if (existsSync(perfPath)) { const p = readJson(perfPath); lines.push("## Performance (timings navigation)"); lines.push("```json"); lines.push(JSON.stringify(p.navigationTiming ?? p, null, 2)); lines.push("```", ""); } const auditPath = path.join(base, "audit.json"); if (existsSync(auditPath)) { const audit = readJson(auditPath); const vulns = audit.vulnerabilities ?? {}; const metaV = audit.metadata?.vulnerabilities; lines.push("## Sécurité (npm audit)"); if (metaV) { lines.push( `- Agrégat : critical ${metaV.critical}, high ${metaV.high}, moderate ${metaV.moderate}, low ${metaV.low}, info ${metaV.info}, total ${metaV.total}` ); } else { let high = 0; let critical = 0; for (const v of Object.values(vulns)) { if (v.severity === "high") high++; if (v.severity === "critical") critical++; } lines.push(`- Critical : ${critical}, High : ${high}`); } lines.push(`- Détail des paquets affectés : ${Object.keys(vulns).length}`, ""); } else { lines.push("## Sécurité", "_npm audit non disponible._", "", ""); } const lhr = globSync(path.join(base, "lhci", "**", "lhr-*.json").replace(/\\/g, "/"))[0]; if (lhr && existsSync(lhr)) { const rep = readJson(lhr); const cats = rep.categories ?? {}; const score = (c) => (c?.score != null ? Math.round(c.score * 100) : "n/a"); lines.push("## Lighthouse / SEO"); lines.push( `| Catégorie | Score |`, `|-----------|-------|`, `| Performance | ${score(cats.performance)} |`, `| Accessibilité | ${score(cats.accessibility)} |`, `| Bonnes pratiques | ${score(cats["best-practices"])} |`, `| SEO | ${score(cats.seo)} |`, "" ); } else { lines.push("## Lighthouse / SEO", "_Rapport LHCI indisponible._", "", ""); } lines.push("---", "_Rapport généré par CI Ben-to._"); writeFileSync(outFile, lines.join("\n"), "utf8"); console.log(`Wrote ${outFile}`);