Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | 3x 7x 7x 7x 7x 7x 49x 49x 49x 34x 34x 34x 7x 15x 15x 15x 15x 12x 12x 12x 7x 13x 13x 13x 13x 28x 28x 11x 6x 11x 11x 11x 17x 3x 3x 13x 13x 6x 6x 6x 7x 7x 7x 52x 52x 7x 52x 7x 8x 8x 8x 7x 7x 1x 7x | /*
Copyright 2015, Yahoo Inc.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
import type { TraceMap } from "@jridgewell/trace-mapping";
import * as libCoverage from "@vitest/istanbul-lib-coverage";
import type { CoverageMap, FileCoverage, Location, Range } from "@vitest/istanbul-lib-coverage";
import { createDebug } from "obug";
import getMapping from "./get-mapping";
import type { Mapping } from "./get-mapping";
import { MappedCoverage } from "./mapped";
import { getUniqueKey, getOutput } from "./transform-utils";
import type { MappedCoverageEntry } from "./transform-utils";
const debug = createDebug("istanbuljs");
/**
* a function that resolves the source map for a file, or a falsy value when
* no source map applies to the file
*/
export type SourceMapFinder = (
filePath: string,
fileCoverage: FileCoverage,
) => TraceMap | null | undefined | Promise<TraceMap | null | undefined>;
/** a function that maps a generated range back to an original source */
export type GetMapping = (
sourceMap: TraceMap,
generatedLocation: Range,
origFile: string,
) => Mapping | null;
export interface SourceMapTransformerOptions {
baseDir?: string;
getMapping?: GetMapping;
}
/** a partial position whose members may be missing entirely */
type PartialPosition = Partial<Location> & { end?: unknown };
export class SourceMapTransformer {
finder: SourceMapFinder;
baseDir: string;
resolveMapping: GetMapping;
constructor(finder: SourceMapFinder, opts: SourceMapTransformerOptions = {}) {
this.finder = finder;
this.baseDir = opts.baseDir || process.cwd();
this.resolveMapping = opts.getMapping || getMapping;
}
processFile(
fc: FileCoverage,
sourceMap: TraceMap,
coverageMapper: (source: string) => MappedCoverage,
): boolean {
let changes = 0;
Object.entries(fc.statementMap).forEach(([s, loc]) => {
const hits = fc.s[s];
const mapping = this.resolveMapping(sourceMap, loc, fc.path);
if (mapping) {
changes += 1;
const mappedCoverage = coverageMapper(mapping.source);
mappedCoverage.addStatement(mapping.loc, hits);
}
});
Object.entries(fc.fnMap).forEach(([f, fnMeta]) => {
const hits = fc.f[f];
const mapping = this.resolveMapping(sourceMap, fnMeta.decl, fc.path);
const spanMapping = this.resolveMapping(sourceMap, fnMeta.loc, fc.path);
if (mapping && spanMapping && mapping.source === spanMapping.source) {
changes += 1;
const mappedCoverage = coverageMapper(mapping.source);
mappedCoverage.addFunction(fnMeta.name, mapping.loc, spanMapping.loc, hits);
}
});
Object.entries(fc.branchMap).forEach(([b, branchMeta]) => {
const hits = fc.b[b];
const locs: Range[] = [];
const mappedHits: number[] = [];
let source: string | undefined;
let skip: boolean | undefined;
branchMeta.locations.forEach((loc, i) => {
const mapping = this.resolveMapping(sourceMap, loc, fc.path);
if (mapping) {
if (!source) {
source = mapping.source;
}
Iif (mapping.source !== source) {
skip = true;
}
locs.push(mapping.loc);
mappedHits.push(hits[i]);
}
// Check if this is an implicit else
else if (
source &&
branchMeta.type === "if" &&
i > 0 &&
(loc.start as PartialPosition).line === undefined &&
(loc.start as PartialPosition).end === undefined &&
(loc.end as PartialPosition).line === undefined &&
(loc.end as PartialPosition).end === undefined
) {
locs.push(loc);
mappedHits.push(hits[i]);
}
});
const locMapping = branchMeta.loc
? this.resolveMapping(sourceMap, branchMeta.loc, fc.path)
: null;
if (!skip && locs.length > 0) {
changes += 1;
const mappedCoverage = coverageMapper(source!);
mappedCoverage.addBranch(
branchMeta.type,
locMapping ? locMapping.loc : locs[0],
locs,
mappedHits,
);
}
});
return changes > 0;
}
async transform(coverageMap: CoverageMap): Promise<CoverageMap> {
const uniqueFiles: Record<string, MappedCoverageEntry> = {};
const getMappedCoverage = (file: string): MappedCoverage => {
const key = getUniqueKey(file);
if (!uniqueFiles[key]) {
uniqueFiles[key] = {
file,
mappedCoverage: new MappedCoverage(file),
};
}
return uniqueFiles[key].mappedCoverage;
};
for (const file of coverageMap.files()) {
const fc = coverageMap.fileCoverageFor(file);
const sourceMap = await this.finder(file, fc);
if (sourceMap) {
const changed = this.processFile(fc, sourceMap, getMappedCoverage);
Iif (!changed) {
debug(`File [${file}] ignored, nothing could be mapped`);
}
} else {
uniqueFiles[getUniqueKey(file)] = {
file,
mappedCoverage: new MappedCoverage(fc),
};
}
}
return libCoverage.createCoverageMap(getOutput(uniqueFiles));
}
}
|