186
node_modules/vitest/dist/coverage.js
generated
vendored
Normal file
186
node_modules/vitest/dist/coverage.js
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
import { relative } from 'pathe';
|
||||
import { m as mm } from './vendor/index.xL8XjTLv.js';
|
||||
import './vendor/_commonjsHelpers.jjO7Zipk.js';
|
||||
import 'util';
|
||||
import 'path';
|
||||
|
||||
const THRESHOLD_KEYS = ["lines", "functions", "statements", "branches"];
|
||||
const GLOBAL_THRESHOLDS_KEY = "global";
|
||||
class BaseCoverageProvider {
|
||||
/**
|
||||
* Check if current coverage is above configured thresholds and bump the thresholds if needed
|
||||
*/
|
||||
updateThresholds({ thresholds: allThresholds, perFile, configurationFile, onUpdate }) {
|
||||
let updatedThresholds = false;
|
||||
const config = resolveConfig(configurationFile);
|
||||
assertConfigurationModule(config);
|
||||
for (const { coverageMap, thresholds, name } of allThresholds) {
|
||||
const summaries = perFile ? coverageMap.files().map((file) => coverageMap.fileCoverageFor(file).toSummary()) : [coverageMap.getCoverageSummary()];
|
||||
const thresholdsToUpdate = [];
|
||||
for (const key of THRESHOLD_KEYS) {
|
||||
const threshold = thresholds[key] ?? 100;
|
||||
const actual = Math.min(...summaries.map((summary) => summary[key].pct));
|
||||
if (actual > threshold)
|
||||
thresholdsToUpdate.push([key, actual]);
|
||||
}
|
||||
if (thresholdsToUpdate.length === 0)
|
||||
continue;
|
||||
updatedThresholds = true;
|
||||
for (const [threshold, newValue] of thresholdsToUpdate) {
|
||||
if (name === GLOBAL_THRESHOLDS_KEY) {
|
||||
config.test.coverage.thresholds[threshold] = newValue;
|
||||
} else {
|
||||
const glob = config.test.coverage.thresholds[name];
|
||||
glob[threshold] = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updatedThresholds) {
|
||||
console.log("Updating thresholds to configuration file. You may want to push with updated coverage thresholds.");
|
||||
onUpdate();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check collected coverage against configured thresholds. Sets exit code to 1 when thresholds not reached.
|
||||
*/
|
||||
checkThresholds({ thresholds: allThresholds, perFile }) {
|
||||
for (const { coverageMap, thresholds, name } of allThresholds) {
|
||||
if (thresholds.branches === void 0 && thresholds.functions === void 0 && thresholds.lines === void 0 && thresholds.statements === void 0)
|
||||
continue;
|
||||
const summaries = perFile ? coverageMap.files().map((file) => ({
|
||||
file,
|
||||
summary: coverageMap.fileCoverageFor(file).toSummary()
|
||||
})) : [{
|
||||
file: null,
|
||||
summary: coverageMap.getCoverageSummary()
|
||||
}];
|
||||
for (const { summary, file } of summaries) {
|
||||
for (const thresholdKey of ["lines", "functions", "statements", "branches"]) {
|
||||
const threshold = thresholds[thresholdKey];
|
||||
if (threshold !== void 0) {
|
||||
const coverage = summary.data[thresholdKey].pct;
|
||||
if (coverage < threshold) {
|
||||
process.exitCode = 1;
|
||||
let errorMessage = `ERROR: Coverage for ${thresholdKey} (${coverage}%) does not meet ${name === GLOBAL_THRESHOLDS_KEY ? name : `"${name}"`} threshold (${threshold}%)`;
|
||||
if (perFile && file)
|
||||
errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
|
||||
console.error(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Constructs collected coverage and users' threshold options into separate sets
|
||||
* where each threshold set holds their own coverage maps. Threshold set is either
|
||||
* for specific files defined by glob pattern or global for all other files.
|
||||
*/
|
||||
resolveThresholds({ coverageMap, thresholds, createCoverageMap, root }) {
|
||||
const resolvedThresholds = [];
|
||||
const files = coverageMap.files();
|
||||
const filesMatchedByGlobs = [];
|
||||
const globalCoverageMap = createCoverageMap();
|
||||
for (const key of Object.keys(thresholds)) {
|
||||
if (key === "perFile" || key === "autoUpdate" || key === "100" || THRESHOLD_KEYS.includes(key))
|
||||
continue;
|
||||
const glob = key;
|
||||
const globThresholds = resolveGlobThresholds(thresholds[glob]);
|
||||
const globCoverageMap = createCoverageMap();
|
||||
const matchingFiles = files.filter((file) => mm.isMatch(relative(root, file), glob));
|
||||
filesMatchedByGlobs.push(...matchingFiles);
|
||||
for (const file of matchingFiles) {
|
||||
const fileCoverage = coverageMap.fileCoverageFor(file);
|
||||
globCoverageMap.addFileCoverage(fileCoverage);
|
||||
}
|
||||
resolvedThresholds.push({
|
||||
name: glob,
|
||||
coverageMap: globCoverageMap,
|
||||
thresholds: globThresholds
|
||||
});
|
||||
}
|
||||
for (const file of files.filter((file2) => !filesMatchedByGlobs.includes(file2))) {
|
||||
const fileCoverage = coverageMap.fileCoverageFor(file);
|
||||
globalCoverageMap.addFileCoverage(fileCoverage);
|
||||
}
|
||||
resolvedThresholds.unshift({
|
||||
name: GLOBAL_THRESHOLDS_KEY,
|
||||
coverageMap: globalCoverageMap,
|
||||
thresholds: {
|
||||
branches: thresholds.branches,
|
||||
functions: thresholds.functions,
|
||||
lines: thresholds.lines,
|
||||
statements: thresholds.statements
|
||||
}
|
||||
});
|
||||
return resolvedThresholds;
|
||||
}
|
||||
/**
|
||||
* Resolve reporters from various configuration options
|
||||
*/
|
||||
resolveReporters(configReporters) {
|
||||
if (!Array.isArray(configReporters))
|
||||
return [[configReporters, {}]];
|
||||
const resolvedReporters = [];
|
||||
for (const reporter of configReporters) {
|
||||
if (Array.isArray(reporter)) {
|
||||
resolvedReporters.push([reporter[0], reporter[1] || {}]);
|
||||
} else {
|
||||
resolvedReporters.push([reporter, {}]);
|
||||
}
|
||||
}
|
||||
return resolvedReporters;
|
||||
}
|
||||
hasTerminalReporter(reporters) {
|
||||
return reporters.some(([reporter]) => reporter === "text" || reporter === "text-summary" || reporter === "text-lcov" || reporter === "teamcity");
|
||||
}
|
||||
toSlices(array, size) {
|
||||
return array.reduce((chunks, item) => {
|
||||
const index = Math.max(0, chunks.length - 1);
|
||||
const lastChunk = chunks[index] || [];
|
||||
chunks[index] = lastChunk;
|
||||
if (lastChunk.length >= size)
|
||||
chunks.push([item]);
|
||||
else
|
||||
lastChunk.push(item);
|
||||
return chunks;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
function resolveGlobThresholds(thresholds) {
|
||||
if (!thresholds || typeof thresholds !== "object")
|
||||
return {};
|
||||
return {
|
||||
lines: "lines" in thresholds && typeof thresholds.lines === "number" ? thresholds.lines : void 0,
|
||||
branches: "branches" in thresholds && typeof thresholds.branches === "number" ? thresholds.branches : void 0,
|
||||
functions: "functions" in thresholds && typeof thresholds.functions === "number" ? thresholds.functions : void 0,
|
||||
statements: "statements" in thresholds && typeof thresholds.statements === "number" ? thresholds.statements : void 0
|
||||
};
|
||||
}
|
||||
function assertConfigurationModule(config) {
|
||||
try {
|
||||
if (typeof config.test.coverage.thresholds !== "object")
|
||||
throw new Error("Expected config.test.coverage.thresholds to be an object");
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(`Unable to parse thresholds from configuration file: ${message}`);
|
||||
}
|
||||
}
|
||||
function resolveConfig(configModule) {
|
||||
const mod = configModule.exports.default;
|
||||
try {
|
||||
if (mod.$type === "object")
|
||||
return mod;
|
||||
if (mod.$type === "function-call") {
|
||||
if (mod.$args[0].$type === "object")
|
||||
return mod.$args[0];
|
||||
if (mod.$args[0].$type === "arrow-function-expression" && mod.$args[0].$body.$type === "object")
|
||||
return mod.$args[0].$body;
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error(error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
throw new Error("Failed to update coverage thresholds. Configuration file is too complex.");
|
||||
}
|
||||
|
||||
export { BaseCoverageProvider };
|
||||
Reference in New Issue
Block a user