UNPKG

3.64 kBJavaScriptView Raw
1const { classes } = require('istanbul-lib-coverage');
2
3function 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 */
25class 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
135module.exports = { SourceCoverage };