Files
TREK/server/scripts/coverage-thresholds.mjs
T
jubnl 77dddd5e8a v4.0.0 (#1719)
Release branch for 4.0.0.
2026-08-27 13:22:39 +02:00

56 lines
2.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Prints the per-domain `thresholds` block for vitest.config.ts from the last
* coverage run, at each domain's measured value minus one point of slack.
*
* npm run test:coverage # writes coverage/coverage-summary.json
* node scripts/coverage-thresholds.mjs
*
* The gate is a RATCHET: raise an entry when you improve a domain, never lower one
* to make a build pass. Use this when you have genuinely raised coverage and want the
* new floor written down, not to re-baseline a regression away.
*
* It reads coverage-summary.json rather than the text reporter on purpose. The text
* reporter prints one row per DIRECTORY, so a domain with subdirectories (plugins,
* memories, auth) reads several points higher there than it actually is, and a
* threshold copied off it would be wrong in the loose direction.
*/
import fs from 'node:fs';
import path from 'node:path';
const summaryPath = path.join(process.cwd(), 'coverage', 'coverage-summary.json');
if (!fs.existsSync(summaryPath)) {
console.error(`no ${summaryPath} — run "npm run test:coverage" first`);
process.exit(1);
}
const METRICS = [
['statements', 'statements'],
['branches', 'branches'],
['functions', 'functions'],
['lines', 'lines'],
];
const summary = JSON.parse(fs.readFileSync(summaryPath, 'utf8'));
const domains = new Map();
for (const [file, entry] of Object.entries(summary)) {
if (file === 'total') continue;
const match = file.split('\\').join('/').match(/\/src\/nest\/([a-z0-9-]+)\//);
if (!match) continue;
const totals = domains.get(match[1]) ?? new Map(METRICS.map(([k]) => [k, { covered: 0, total: 0 }]));
for (const [key, metric] of METRICS) {
totals.get(key).covered += entry[metric].covered;
totals.get(key).total += entry[metric].total;
}
domains.set(match[1], totals);
}
// A domain with no branches at all reads as 100%, which is the right floor for it.
const floorOf = ({ covered, total }) => (total === 0 ? 100 : Math.max(0, Math.floor((100 * covered) / total) - 1));
for (const domain of [...domains.keys()].sort()) {
const totals = domains.get(domain);
const parts = METRICS.map(([key]) => `${key}: ${floorOf(totals.get(key))}`).join(', ');
console.log(` 'src/nest/${domain}/**/*.ts': { ${parts} },`);
}