Socket
Socket
Sign inDemoInstall

@vitest/coverage-v8

Package Overview
Dependencies
Maintainers
3
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vitest/coverage-v8 - npm Package Compare versions

Comparing version 1.0.0-beta.6 to 1.0.1

1

dist/index.d.ts
import { V8CoverageProvider } from './provider.js';
import 'node:inspector';
import 'vitest/coverage';

@@ -4,0 +3,0 @@ import 'vitest';

11

dist/provider.d.ts

@@ -1,2 +0,1 @@

import { Profiler } from 'node:inspector';
import { BaseCoverageProvider } from 'vitest/coverage';

@@ -20,4 +19,4 @@ import { CoverageProvider, AfterSuiteRunMeta, ReportContext, ResolvedCoverageOptions } from 'vitest';

type Options = ResolvedCoverageOptions<'v8'>;
type RawCoverage = Profiler.TakePreciseCoverageReturnType;
type CoverageByTransformMode = Record<AfterSuiteRunMeta['transformMode'], RawCoverage[]>;
type Filename = string;
type CoverageFilesByTransformMode = Record<AfterSuiteRunMeta['transformMode'], Filename[]>;
type ProjectName = NonNullable<AfterSuiteRunMeta['projectName']> | typeof DEFAULT_PROJECT;

@@ -30,3 +29,5 @@ declare const DEFAULT_PROJECT: unique symbol;

testExclude: InstanceType<TestExclude>;
coverages: Map<ProjectName, CoverageByTransformMode>;
coverageFiles: Map<ProjectName, CoverageFilesByTransformMode>;
coverageFilesDirectory: string;
pendingPromises: Promise<void>[];
initialize(ctx: Vitest): void;

@@ -39,5 +40,5 @@ resolveOptions(): Options;

private getSources;
private mergeAndTransformCoverage;
private convertCoverage;
}
export { V8CoverageProvider };

@@ -14,2 +14,3 @@ import { existsSync, promises, writeFileSync } from 'node:fs';

import { provider } from 'std-env';
import createDebug from 'debug';
import { builtinModules } from 'node:module';

@@ -174,2 +175,4 @@ import { coverageConfigDefaults, defaultExclude, defaultInclude } from 'vitest/config';

const DEFAULT_PROJECT = Symbol.for("default-project");
const debug = createDebug("vitest:coverage");
let uniqueId = 0;
class V8CoverageProvider extends BaseCoverageProvider {

@@ -180,3 +183,5 @@ name = "v8";

testExclude;
coverages = /* @__PURE__ */ new Map();
coverageFiles = /* @__PURE__ */ new Map();
coverageFilesDirectory;
pendingPromises = [];
initialize(ctx) {

@@ -209,2 +214,3 @@ const config = ctx.config.coverage;

});
this.coverageFilesDirectory = resolve(this.options.reportsDirectory, ".tmp");
}

@@ -217,3 +223,7 @@ resolveOptions() {

await promises.rm(this.options.reportsDirectory, { recursive: true, force: true, maxRetries: 10 });
this.coverages = /* @__PURE__ */ new Map();
if (existsSync(this.coverageFilesDirectory))
await promises.rm(this.coverageFilesDirectory, { recursive: true, force: true, maxRetries: 10 });
await promises.mkdir(this.coverageFilesDirectory, { recursive: true });
this.coverageFiles = /* @__PURE__ */ new Map();
this.pendingPromises = [];
}

@@ -228,8 +238,11 @@ /*

throw new Error(`Invalid transform mode: ${transformMode}`);
let entry = this.coverages.get(projectName || DEFAULT_PROJECT);
let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
if (!entry) {
entry = { web: [], ssr: [] };
this.coverages.set(projectName || DEFAULT_PROJECT, entry);
this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
}
entry[transformMode].push(coverage);
const filename = resolve(this.coverageFilesDirectory, `coverage-${uniqueId++}.json`);
entry[transformMode].push(filename);
const promise = promises.writeFile(filename, JSON.stringify(coverage), "utf-8");
this.pendingPromises.push(promise);
}

@@ -239,15 +252,32 @@ async reportCoverage({ allTestsRun } = {}) {

this.ctx.logger.log(c.blue(" % ") + c.yellow("@vitest/coverage-v8 does not work on Stackblitz. Report will be empty."));
const coverageMaps = await Promise.all(
Array.from(this.coverages.entries()).map(([projectName, coverages]) => [
this.mergeAndTransformCoverage(coverages.ssr, projectName, "ssr"),
this.mergeAndTransformCoverage(coverages.web, projectName, "web")
]).flat()
);
const coverageMap = libCoverage.createCoverageMap({});
let index = 0;
const total = this.pendingPromises.length;
await Promise.all(this.pendingPromises);
this.pendingPromises = [];
for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) {
for (const [transformMode, filenames] of Object.entries(coveragePerProject)) {
let merged = { result: [] };
for (const chunk of toSlices(filenames, this.options.processingConcurrency)) {
if (debug.enabled) {
index += chunk.length;
debug("Covered files %d/%d", index, total);
}
await Promise.all(chunk.map(async (filename) => {
const contents = await promises.readFile(filename, "utf-8");
const coverage = JSON.parse(contents);
merged = mergeProcessCovs([merged, coverage]);
}));
}
const converted = await this.convertCoverage(merged, projectName, transformMode);
const transformedCoverage = await transformCoverage(converted);
coverageMap.merge(transformedCoverage);
}
}
if (this.options.all && allTestsRun) {
const coveredFiles = coverageMaps.map((map) => map.files()).flat();
const coveredFiles = coverageMap.files();
const untestedCoverage = await this.getUntestedFiles(coveredFiles);
const untestedCoverageResults = untestedCoverage.map((files) => ({ result: [files] }));
coverageMaps.push(await this.mergeAndTransformCoverage(untestedCoverageResults));
const converted = await this.convertCoverage(untestedCoverage);
coverageMap.merge(await transformCoverage(converted));
}
const coverageMap = mergeCoverageMaps(...coverageMaps);
const context = libReport.createContext({

@@ -291,2 +321,4 @@ dir: this.options.reportsDirectory,

}
this.coverageFiles = /* @__PURE__ */ new Map();
await promises.rm(this.coverageFilesDirectory, { recursive: true });
}

@@ -298,20 +330,31 @@ }

const uncoveredFiles = includedFiles.map((file) => pathToFileURL(resolve(this.ctx.config.root, file))).filter((file) => !testedFiles.includes(file.pathname));
return await Promise.all(uncoveredFiles.map(async (uncoveredFile) => {
const { source } = await this.getSources(uncoveredFile.href, transformResults);
return {
url: uncoveredFile.href,
scriptId: "0",
// Create a made up function to mark whole file as uncovered. Note that this does not exist in source maps.
functions: [{
ranges: [{
startOffset: 0,
endOffset: source.length,
count: 0
}],
isBlockCoverage: true,
// This is magical value that indicates an empty report: https://github.com/istanbuljs/v8-to-istanbul/blob/fca5e6a9e6ef38a9cdc3a178d5a6cf9ef82e6cab/lib/v8-to-istanbul.js#LL131C40-L131C40
functionName: "(empty-report)"
}]
};
}));
let merged = { result: [] };
let index = 0;
for (const chunk of toSlices(uncoveredFiles, this.options.processingConcurrency)) {
if (debug.enabled) {
index += chunk.length;
debug("Uncovered files %d/%d", index, uncoveredFiles.length);
}
const coverages = await Promise.all(chunk.map(async (filename) => {
const { source } = await this.getSources(filename.href, transformResults);
const coverage = {
url: filename.href,
scriptId: "0",
// Create a made up function to mark whole file as uncovered. Note that this does not exist in source maps.
functions: [{
ranges: [{
startOffset: 0,
endOffset: source.length,
count: 0
}],
isBlockCoverage: true,
// This is magical value that indicates an empty report: https://github.com/istanbuljs/v8-to-istanbul/blob/fca5e6a9e6ef38a9cdc3a178d5a6cf9ef82e6cab/lib/v8-to-istanbul.js#LL131C40-L131C40
functionName: "(empty-report)"
}]
};
return { result: [coverage] };
}));
merged = mergeProcessCovs([merged, ...coverages]);
}
return merged;
}

@@ -342,27 +385,29 @@ async getSources(url, transformResults, functions = []) {

}
async mergeAndTransformCoverage(coverages, projectName, transformMode) {
async convertCoverage(coverage, projectName, transformMode) {
const viteNode = this.ctx.projects.find((project) => project.getName() === projectName)?.vitenode || this.ctx.vitenode;
const fetchCache = transformMode ? viteNode.fetchCaches[transformMode] : viteNode.fetchCache;
const transformResults = normalizeTransformResults(fetchCache);
const merged = mergeProcessCovs(coverages);
const scriptCoverages = merged.result.filter((result) => this.testExclude.shouldInstrument(fileURLToPath(result.url)));
const converted = await Promise.all(scriptCoverages.map(async ({ url, functions }) => {
const sources = await this.getSources(url, transformResults, functions);
const wrapperLength = sources.sourceMap ? WRAPPER_LENGTH : 0;
const converter = v8ToIstanbul(url, wrapperLength, sources);
await converter.load();
converter.applyCoverage(functions);
return converter.toIstanbul();
}));
const mergedCoverage = mergeCoverageMaps(...converted);
const sourceMapStore = libSourceMaps.createSourceMapStore();
return sourceMapStore.transformCoverage(mergedCoverage);
const scriptCoverages = coverage.result.filter((result) => this.testExclude.shouldInstrument(fileURLToPath(result.url)));
const coverageMap = libCoverage.createCoverageMap({});
let index = 0;
for (const chunk of toSlices(scriptCoverages, this.options.processingConcurrency)) {
if (debug.enabled) {
index += chunk.length;
debug("Converting %d/%d", index, scriptCoverages.length);
}
await Promise.all(chunk.map(async ({ url, functions }) => {
const sources = await this.getSources(url, transformResults, functions);
const wrapperLength = sources.sourceMap ? WRAPPER_LENGTH : 0;
const converter = v8ToIstanbul(url, wrapperLength, sources);
await converter.load();
converter.applyCoverage(functions);
coverageMap.merge(converter.toIstanbul());
}));
}
return coverageMap;
}
}
function mergeCoverageMaps(...coverageMaps) {
return coverageMaps.reduce((coverage, previousCoverageMap) => {
const map = libCoverage.createCoverageMap(coverage);
map.merge(previousCoverageMap);
return map;
}, libCoverage.createCoverageMap({}));
async function transformCoverage(coverageMap) {
const sourceMapStore = libSourceMaps.createSourceMapStore();
return await sourceMapStore.transformCoverage(coverageMap);
}

@@ -401,3 +446,15 @@ function removeViteHelpersFromSourceMaps(source, map) {

}
function 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;
}, []);
}
export { V8CoverageProvider };
{
"name": "@vitest/coverage-v8",
"type": "module",
"version": "1.0.0-beta.6",
"version": "1.0.1",
"description": "V8 coverage provider for Vitest",

@@ -40,3 +40,3 @@ "author": "Anthony Fu <anthonyfu117@hotmail.com>",

"peerDependencies": {
"vitest": "^1.0.0-0"
"vitest": "^1.0.0"
},

@@ -46,2 +46,3 @@ "dependencies": {

"@bcoe/v8-coverage": "^0.2.3",
"debug": "^4.3.4",
"istanbul-lib-coverage": "^3.2.2",

@@ -59,2 +60,3 @@ "istanbul-lib-report": "^3.0.1",

"devDependencies": {
"@types/debug": "^4.1.12",
"@types/istanbul-lib-coverage": "^2.0.6",

@@ -65,4 +67,4 @@ "@types/istanbul-lib-report": "^3.0.3",

"pathe": "^1.1.1",
"vitest": "1.0.0-beta.6",
"vite-node": "1.0.0-beta.6"
"vite-node": "1.0.1",
"vitest": "1.0.1"
},

@@ -69,0 +71,0 @@ "scripts": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc