coverify
Version:
code coverage browserify transform
121 lines (106 loc) • 4.34 kB
JavaScript
;
var split = require('split2');
var through = require('through2');
var combine = require('stream-combiner2');
var fs = require('fs');
module.exports = function (cb) {
var files = {};
var original = {};
return combine(split(), through(write, end));
function write(line, enc, next) {
var file;
var m = (/^COVERAGE\s+("[^"]+"|\S+)\s+(\S+)/).exec(line);
if (m) {
file = m[1];
var ranges = m[2];
if ((/^"/).test(file) && (/"$/).test(file)) { file = JSON.parse(file); }
files[file] = JSON.parse(ranges);
original[file] = JSON.parse(ranges).filter(Boolean);
} else if (m = (/^COVERED\s+("[^"]+"|\S+)\s+(\S+)/).exec(line)) { // eslint-disable-line no-cond-assign
file = m[1];
var index = m[2];
if ((/^"/).test(file) && (/"$/).test(file)) { file = JSON.parse(file); }
delete files[file][index];
} else { this.push(line + '\n'); }
next();
}
function end() {
var ranges = Object.keys(files).reduce(function (acc, file) {
return acc.concat(files[file].filter(Boolean));
}, []);
var missed = Object.keys(files).reduce(function (acc, file) {
var seen = {};
acc[file] = files[file].filter(Boolean).filter(function (mr) {
var key = mr.join('-');
if (Object.prototype.hasOwnProperty.call(seen, key)) {
return false;
}
seen[key] = true;
return !ranges.some(function (rr) {
return (mr[0] > rr[0] && mr[1] < rr[1]) || (mr[0] === rr[0] && mr[1] < rr[1]) || (mr[0] > rr[0] && mr[1] === rr[1]);
});
});
return acc;
}, {});
var counts = Object.keys(files).reduce(function (acc, file) {
acc[file] = {
expr: original[file].length - missed[file].length,
total: original[file].length
};
return acc;
}, {});
var sources = {};
var pending = 0;
Object.keys(missed).forEach(function (file) {
pending++;
sources[file] = {};
fs.readFile(file, 'utf8', function (err, src) {
if (err) { return cb(err); }
var lines = src.split('\n');
function findLine(r) {
var c = 0;
var mlines = [];
for (var i = 0; i < lines.length; i++) {
c += lines[i].length + 1;
if (c < r[0]) { continue; } // eslint-disable-line no-continue, no-restricted-syntax
var row = { line: lines[i] };
row.range = [ 0, lines[i].length - 1 ];
if (mlines.length === 0) {
row.range[0] = r[0] - c + lines[i].length;
}
if (c > r[1]) {
row.range[1] = r[1] - c + lines[i].length;
}
mlines.push(row);
if (c > r[1]) { break; } // eslint-disable-line no-restricted-syntax
}
var offset = c - lines[i].length;
var lr = [ r[0] - offset, r[1] - offset + 1 ];
return {
lines: mlines,
num: i, // DEPRECATE
range: lr
};
}
sources[file] = [];
missed[file].forEach(function (range) {
var match = findLine(range);
sources[file].push({
range: range,
lines: match.lines,
lineNum: match.num, // DEPRECATE
column: match.range, // DEPRECATE
line: lines[match.num], // DEPRECATE
code: src.slice(range[0], range[1])
});
});
next();
});
});
function next() {
if (--pending === 0) {
cb(null, sources, counts);
}
}
}
};