You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.3 KiB
147 lines
4.3 KiB
/* |
|
Copyright 2015, Yahoo Inc. |
|
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. |
|
*/ |
|
'use strict'; |
|
|
|
const debug = require('debug')('istanbuljs'); |
|
const libCoverage = require('istanbul-lib-coverage'); |
|
const { MappedCoverage } = require('./mapped'); |
|
const getMapping = require('./get-mapping'); |
|
const { getUniqueKey, getOutput } = require('./transform-utils'); |
|
|
|
class SourceMapTransformer { |
|
constructor(finder, opts = {}) { |
|
this.finder = finder; |
|
this.baseDir = opts.baseDir || process.cwd(); |
|
this.resolveMapping = opts.getMapping || getMapping; |
|
} |
|
|
|
processFile(fc, sourceMap, coverageMapper) { |
|
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 = []; |
|
const mappedHits = []; |
|
let source; |
|
let skip; |
|
|
|
branchMeta.locations.forEach((loc, i) => { |
|
const mapping = this.resolveMapping(sourceMap, loc, fc.path); |
|
if (mapping) { |
|
if (!source) { |
|
source = mapping.source; |
|
} |
|
|
|
if (mapping.source !== source) { |
|
skip = true; |
|
} |
|
|
|
locs.push(mapping.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) { |
|
const uniqueFiles = {}; |
|
const getMappedCoverage = file => { |
|
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 |
|
); |
|
if (!changed) { |
|
debug(`File [${file}] ignored, nothing could be mapped`); |
|
} |
|
} else { |
|
uniqueFiles[getUniqueKey(file)] = { |
|
file, |
|
mappedCoverage: new MappedCoverage(fc) |
|
}; |
|
} |
|
} |
|
|
|
return libCoverage.createCoverageMap(getOutput(uniqueFiles)); |
|
} |
|
} |
|
|
|
module.exports = { |
|
SourceMapTransformer |
|
};
|
|
|