| 1 | const { classes } = require('istanbul-lib-coverage');
|
|---|
| 2 |
|
|---|
| 3 | function cloneLocation(loc) {
|
|---|
| 4 | return {
|
|---|
| 5 | start: {
|
|---|
| 6 | line: loc && loc.start.line,
|
|---|
| 7 | column: loc && loc.start.column
|
|---|
| 8 | },
|
|---|
| 9 | end: {
|
|---|
| 10 | line: loc && loc.end.line,
|
|---|
| 11 | column: loc && loc.end.column
|
|---|
| 12 | }
|
|---|
| 13 | };
|
|---|
| 14 | }
|
|---|
| 15 | /**
|
|---|
| 16 | * SourceCoverage provides mutation methods to manipulate the structure of
|
|---|
| 17 | * a file coverage object. Used by the instrumenter to create a full coverage
|
|---|
| 18 | * object for a file incrementally.
|
|---|
| 19 | *
|
|---|
| 20 | * @private
|
|---|
| 21 | * @param pathOrObj {String|Object} - see the argument for {@link FileCoverage}
|
|---|
| 22 | * @extends FileCoverage
|
|---|
| 23 | * @constructor
|
|---|
| 24 | */
|
|---|
| 25 | class SourceCoverage extends classes.FileCoverage {
|
|---|
| 26 | constructor(pathOrObj) {
|
|---|
| 27 | super(pathOrObj);
|
|---|
| 28 | this.meta = {
|
|---|
| 29 | last: {
|
|---|
| 30 | s: 0,
|
|---|
| 31 | f: 0,
|
|---|
| 32 | b: 0
|
|---|
| 33 | }
|
|---|
| 34 | };
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | newStatement(loc) {
|
|---|
| 38 | const s = this.meta.last.s;
|
|---|
| 39 | this.data.statementMap[s] = cloneLocation(loc);
|
|---|
| 40 | this.data.s[s] = 0;
|
|---|
| 41 | this.meta.last.s += 1;
|
|---|
| 42 | return s;
|
|---|
| 43 | }
|
|---|
| 44 |
|
|---|
| 45 | newFunction(name, decl, loc) {
|
|---|
| 46 | const f = this.meta.last.f;
|
|---|
| 47 | name = name || '(anonymous_' + f + ')';
|
|---|
| 48 | this.data.fnMap[f] = {
|
|---|
| 49 | name,
|
|---|
| 50 | decl: cloneLocation(decl),
|
|---|
| 51 | loc: cloneLocation(loc),
|
|---|
| 52 | // DEPRECATED: some legacy reports require this info.
|
|---|
| 53 | line: loc && loc.start.line
|
|---|
| 54 | };
|
|---|
| 55 | this.data.f[f] = 0;
|
|---|
| 56 | this.meta.last.f += 1;
|
|---|
| 57 | return f;
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | newBranch(type, loc, isReportLogic = false) {
|
|---|
| 61 | const b = this.meta.last.b;
|
|---|
| 62 | this.data.b[b] = [];
|
|---|
| 63 | this.data.branchMap[b] = {
|
|---|
| 64 | loc: cloneLocation(loc),
|
|---|
| 65 | type,
|
|---|
| 66 | locations: [],
|
|---|
| 67 | // DEPRECATED: some legacy reports require this info.
|
|---|
| 68 | line: loc && loc.start.line
|
|---|
| 69 | };
|
|---|
| 70 | this.meta.last.b += 1;
|
|---|
| 71 | this.maybeNewBranchTrue(type, b, isReportLogic);
|
|---|
| 72 | return b;
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | maybeNewBranchTrue(type, name, isReportLogic) {
|
|---|
| 76 | if (!isReportLogic) {
|
|---|
| 77 | return;
|
|---|
| 78 | }
|
|---|
| 79 | if (type !== 'binary-expr') {
|
|---|
| 80 | return;
|
|---|
| 81 | }
|
|---|
| 82 | this.data.bT = this.data.bT || {};
|
|---|
| 83 | this.data.bT[name] = [];
|
|---|
| 84 | }
|
|---|
| 85 |
|
|---|
| 86 | addBranchPath(name, location) {
|
|---|
| 87 | const bMeta = this.data.branchMap[name];
|
|---|
| 88 | const counts = this.data.b[name];
|
|---|
| 89 |
|
|---|
| 90 | /* istanbul ignore if: paranoid check */
|
|---|
| 91 | if (!bMeta) {
|
|---|
| 92 | throw new Error('Invalid branch ' + name);
|
|---|
| 93 | }
|
|---|
| 94 | bMeta.locations.push(cloneLocation(location));
|
|---|
| 95 | counts.push(0);
|
|---|
| 96 | this.maybeAddBranchTrue(name);
|
|---|
| 97 | return counts.length - 1;
|
|---|
| 98 | }
|
|---|
| 99 |
|
|---|
| 100 | maybeAddBranchTrue(name) {
|
|---|
| 101 | if (!this.data.bT) {
|
|---|
| 102 | return;
|
|---|
| 103 | }
|
|---|
| 104 | const countsTrue = this.data.bT[name];
|
|---|
| 105 | if (!countsTrue) {
|
|---|
| 106 | return;
|
|---|
| 107 | }
|
|---|
| 108 | countsTrue.push(0);
|
|---|
| 109 | }
|
|---|
| 110 |
|
|---|
| 111 | /**
|
|---|
| 112 | * Assigns an input source map to the coverage that can be used
|
|---|
| 113 | * to remap the coverage output to the original source
|
|---|
| 114 | * @param sourceMap {object} the source map
|
|---|
| 115 | */
|
|---|
| 116 | inputSourceMap(sourceMap) {
|
|---|
| 117 | this.data.inputSourceMap = sourceMap;
|
|---|
| 118 | }
|
|---|
| 119 |
|
|---|
| 120 | freeze() {
|
|---|
| 121 | // prune empty branches
|
|---|
| 122 | const map = this.data.branchMap;
|
|---|
| 123 | const branches = this.data.b;
|
|---|
| 124 | const branchesT = this.data.bT || {};
|
|---|
| 125 | Object.keys(map).forEach(b => {
|
|---|
| 126 | if (map[b].locations.length === 0) {
|
|---|
| 127 | delete map[b];
|
|---|
| 128 | delete branches[b];
|
|---|
| 129 | delete branchesT[b];
|
|---|
| 130 | }
|
|---|
| 131 | });
|
|---|
| 132 | }
|
|---|
| 133 | }
|
|---|
| 134 |
|
|---|
| 135 | module.exports = { SourceCoverage };
|
|---|