116 lines
2.9 KiB
JavaScript
116 lines
2.9 KiB
JavaScript
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
|
|
const repoRoot = process.cwd();
|
|
const packageName = process.argv[2] || "userfront";
|
|
const lcovPath = path.join(repoRoot, packageName, "coverage", "lcov.info");
|
|
const reportsDir = path.join(repoRoot, "reports");
|
|
|
|
const excludedSourceFiles = new Set(["lib/main.dart", "lib/i18n_data.dart"]);
|
|
|
|
function normalizeSourcePath(sourcePath) {
|
|
const normalized = sourcePath.replace(/\\/g, "/");
|
|
const packagePrefix = `${packageName}/`;
|
|
return normalized.startsWith(packagePrefix)
|
|
? normalized.slice(packagePrefix.length)
|
|
: normalized;
|
|
}
|
|
|
|
function shouldExcludeSource(sourcePath) {
|
|
const normalized = normalizeSourcePath(sourcePath);
|
|
return (
|
|
excludedSourceFiles.has(normalized) ||
|
|
normalized.endsWith(".g.dart") ||
|
|
normalized.endsWith(".freezed.dart")
|
|
);
|
|
}
|
|
|
|
function parseLcov(raw) {
|
|
const records = [];
|
|
let current = null;
|
|
|
|
for (const line of raw.split(/\r?\n/)) {
|
|
if (line.startsWith("SF:")) {
|
|
current = { sourceFile: normalizeSourcePath(line.slice(3)), lines: [] };
|
|
continue;
|
|
}
|
|
|
|
if (!current) continue;
|
|
|
|
if (line.startsWith("DA:")) {
|
|
const [, hitsValue] = line.slice(3).split(",");
|
|
const hits = Number(hitsValue);
|
|
current.lines.push(Number.isFinite(hits) ? hits : 0);
|
|
continue;
|
|
}
|
|
|
|
if (line === "end_of_record") {
|
|
records.push(current);
|
|
current = null;
|
|
}
|
|
}
|
|
|
|
if (current) {
|
|
records.push(current);
|
|
}
|
|
|
|
return records;
|
|
}
|
|
|
|
function formatPct(value) {
|
|
return `${value.toFixed(2)}%`;
|
|
}
|
|
|
|
function renderMarkdown(row) {
|
|
return [
|
|
"# Userfront Flutter Coverage Summary",
|
|
"",
|
|
"| Package | Lines | Covered / Total | LCOV |",
|
|
"| --- | ---: | ---: | --- |",
|
|
`| ${row.package} | ${formatPct(row.lines)} | ${row.coveredLines} / ${row.totalLines} | ${row.lcovPath} |`,
|
|
"",
|
|
"Coverage excludes Flutter bootstrap/generated files: `lib/main.dart`, `lib/i18n_data.dart`, `*.g.dart`, `*.freezed.dart`.",
|
|
"",
|
|
].join("\n");
|
|
}
|
|
|
|
const lcov = await readFile(lcovPath, "utf8");
|
|
const includedRecords = parseLcov(lcov).filter(
|
|
(record) => !shouldExcludeSource(record.sourceFile),
|
|
);
|
|
|
|
const totalLines = includedRecords.reduce(
|
|
(total, record) => total + record.lines.length,
|
|
0,
|
|
);
|
|
const coveredLines = includedRecords.reduce(
|
|
(total, record) => total + record.lines.filter((hits) => hits > 0).length,
|
|
0,
|
|
);
|
|
const lineCoverage = totalLines === 0 ? 0 : (coveredLines / totalLines) * 100;
|
|
|
|
const row = {
|
|
package: packageName,
|
|
statements: lineCoverage,
|
|
branches: null,
|
|
functions: null,
|
|
lines: lineCoverage,
|
|
coveredLines,
|
|
totalLines,
|
|
summaryPath: "reports/package-coverage-summary.json",
|
|
htmlPath: null,
|
|
lcovPath: `${packageName}/coverage/lcov.info`,
|
|
};
|
|
|
|
await mkdir(reportsDir, { recursive: true });
|
|
await writeFile(
|
|
path.join(reportsDir, "package-coverage-summary.json"),
|
|
`${JSON.stringify({ packages: [row] }, null, 2)}\n`,
|
|
);
|
|
await writeFile(
|
|
path.join(reportsDir, `${packageName}-coverage-summary.md`),
|
|
renderMarkdown(row),
|
|
);
|
|
|
|
console.log(renderMarkdown(row));
|