monocart-coverage-reports 1.1.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -29
- package/lib/converter/ast.js +297 -0
- package/lib/converter/branches.js +408 -0
- package/lib/converter/converter.js +720 -237
- package/lib/converter/find-original-range.js +106 -60
- package/lib/converter/info-branch.js +21 -22
- package/lib/converter/info-function.js +6 -18
- package/lib/converter/info-line.js +3 -0
- package/lib/generate.js +4 -0
- package/lib/istanbul/istanbul.js +1 -1
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/packages/monocart-coverage-vendor.js +21 -14
- package/lib/platform/share.js +104 -3
- package/lib/{converter → utils}/source-path.js +2 -2
- package/lib/utils/util.js +27 -0
- package/lib/v8/v8-summary.js +19 -24
- package/lib/v8/v8.js +66 -28
- package/package.json +24 -29
- package/lib/converter/position-mapping.js +0 -183
- /package/lib/{converter → utils}/dedupe.js +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
const Util = require('../utils/util.js');
|
|
2
|
+
|
|
3
|
+
const quickFindRange = (position, ranges) => {
|
|
4
|
+
let start = 0;
|
|
5
|
+
let end = ranges.length - 1;
|
|
6
|
+
while (end - start > 1) {
|
|
7
|
+
const i = Math.floor((start + end) * 0.5);
|
|
8
|
+
const item = ranges[i];
|
|
9
|
+
if (position < item.startOffset) {
|
|
10
|
+
end = i;
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (position > item.endOffset) {
|
|
14
|
+
start = i;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
return ranges[i];
|
|
18
|
+
}
|
|
19
|
+
// last two items, less is start
|
|
20
|
+
const endItem = ranges[end];
|
|
21
|
+
if (position < endItem.startOffset) {
|
|
22
|
+
return ranges[start];
|
|
23
|
+
}
|
|
24
|
+
return ranges[end];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const findInRanges = (start, end, ranges) => {
|
|
29
|
+
if (!Util.isList(ranges)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const range = quickFindRange(start, ranges);
|
|
33
|
+
if (start >= range.startOffset && end <= range.endOffset) {
|
|
34
|
+
return range;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
const findBranchBlock = (start, end, functionInfo) => {
|
|
40
|
+
const { range } = functionInfo;
|
|
41
|
+
if (range) {
|
|
42
|
+
const { blockMap, blockRanges } = range;
|
|
43
|
+
if (blockMap) {
|
|
44
|
+
// exact matched a block
|
|
45
|
+
const block = blockMap.get(start);
|
|
46
|
+
if (block) {
|
|
47
|
+
return block;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// support for tf2 || a || 1;
|
|
51
|
+
// "a" is in "|| a"
|
|
52
|
+
const blockItem = findInRanges(start, end, blockRanges);
|
|
53
|
+
if (blockItem) {
|
|
54
|
+
return blockItem;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// =======================================================================================
|
|
62
|
+
|
|
63
|
+
const createBranchGroup = (type, branchStart, parents, branchMap, functionInfo) => {
|
|
64
|
+
// clone and reverse parents
|
|
65
|
+
const reverseParents = [].concat(parents).reverse();
|
|
66
|
+
const group = {
|
|
67
|
+
type,
|
|
68
|
+
loc: {
|
|
69
|
+
start: branchStart,
|
|
70
|
+
// could be updated if multiple locations
|
|
71
|
+
end: branchStart
|
|
72
|
+
},
|
|
73
|
+
locations: [],
|
|
74
|
+
reverseParents,
|
|
75
|
+
functionInfo
|
|
76
|
+
};
|
|
77
|
+
branchMap.set(branchStart, group);
|
|
78
|
+
return group;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const addBranch = (group, node, locationMap, functionInfo) => {
|
|
82
|
+
const { start, end } = node;
|
|
83
|
+
|
|
84
|
+
const branchStart = group.loc.start;
|
|
85
|
+
|
|
86
|
+
// the block is not exact correct, if there is a block wrapped
|
|
87
|
+
// [x8]{ var a = b || [x4]c }, b is no block, but it can be found in x8 block
|
|
88
|
+
const block = findBranchBlock(start, end, functionInfo);
|
|
89
|
+
|
|
90
|
+
const branchInfo = {
|
|
91
|
+
// for get previous group for LogicalExpression
|
|
92
|
+
branchStart,
|
|
93
|
+
start,
|
|
94
|
+
end,
|
|
95
|
+
// cache block
|
|
96
|
+
block,
|
|
97
|
+
// branch count default to 0
|
|
98
|
+
count: 0
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
group.locations.push(branchInfo);
|
|
102
|
+
|
|
103
|
+
// update group end
|
|
104
|
+
group.loc.end = end;
|
|
105
|
+
|
|
106
|
+
locationMap.set(start, branchInfo);
|
|
107
|
+
|
|
108
|
+
return branchInfo;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// =======================================================================================
|
|
112
|
+
|
|
113
|
+
const addNodeCount = (node, parents, functionInfo) => {
|
|
114
|
+
|
|
115
|
+
const { start, end } = node;
|
|
116
|
+
const { count, range } = functionInfo;
|
|
117
|
+
|
|
118
|
+
if (range) {
|
|
119
|
+
const { blockMap, blockRanges } = range;
|
|
120
|
+
if (blockMap) {
|
|
121
|
+
const block = blockMap.get(start);
|
|
122
|
+
if (block) {
|
|
123
|
+
node._state = {
|
|
124
|
+
count: block.count
|
|
125
|
+
};
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const blockItem = findInRanges(start, end, blockRanges);
|
|
130
|
+
if (blockItem) {
|
|
131
|
+
node._state = {
|
|
132
|
+
count: blockItem.count
|
|
133
|
+
};
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const reverseParents = [].concat(parents).reverse();
|
|
141
|
+
for (const parent of reverseParents) {
|
|
142
|
+
if (parent._state) {
|
|
143
|
+
node._state = {
|
|
144
|
+
count: parent._state.count
|
|
145
|
+
};
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// function count
|
|
151
|
+
node._state = {
|
|
152
|
+
count: count
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// =======================================================================================
|
|
158
|
+
|
|
159
|
+
const createBranches = (ast, functionInfo, branchMap) => {
|
|
160
|
+
|
|
161
|
+
// locationMap for chain LogicalExpression locations
|
|
162
|
+
const locationMap = new Map();
|
|
163
|
+
|
|
164
|
+
Util.visitAst(ast, {
|
|
165
|
+
|
|
166
|
+
Function() {
|
|
167
|
+
return 'break';
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
Statement: (node, parents) => {
|
|
171
|
+
addNodeCount(node, parents, functionInfo);
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// cond-expr Ternary
|
|
175
|
+
// var b = a ? 'consequent' : 'alternate';
|
|
176
|
+
ConditionalExpression: (node, parents) => {
|
|
177
|
+
addNodeCount(node, parents, functionInfo);
|
|
178
|
+
const { consequent, alternate } = node;
|
|
179
|
+
const start = consequent.start;
|
|
180
|
+
const group = createBranchGroup('ConditionalExpression', start, parents, branchMap, functionInfo);
|
|
181
|
+
addBranch(group, consequent, locationMap, functionInfo);
|
|
182
|
+
addBranch(group, alternate, locationMap, functionInfo);
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
// if
|
|
186
|
+
// An IF statement always has exactly two branches:
|
|
187
|
+
// one where the condition is FALSE and one where the condition is TRUE
|
|
188
|
+
IfStatement: (node, parents) => {
|
|
189
|
+
addNodeCount(node, parents, functionInfo);
|
|
190
|
+
const { consequent, alternate } = node;
|
|
191
|
+
const start = consequent.start;
|
|
192
|
+
const group = createBranchGroup('IfStatement', start, parents, branchMap, functionInfo);
|
|
193
|
+
addBranch(group, consequent, locationMap, functionInfo);
|
|
194
|
+
|
|
195
|
+
// console.log('if type', consequent.type);
|
|
196
|
+
|
|
197
|
+
if (alternate) {
|
|
198
|
+
addBranch(group, alternate, locationMap, functionInfo);
|
|
199
|
+
} else {
|
|
200
|
+
// add none branch
|
|
201
|
+
group.locations.push({
|
|
202
|
+
none: true,
|
|
203
|
+
count: 0
|
|
204
|
+
});
|
|
205
|
+
// no need update group end, there is no end
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
// binary-expr
|
|
210
|
+
// var b = a || b || c;
|
|
211
|
+
// do not using BinaryExpression
|
|
212
|
+
LogicalExpression: (node, parents) => {
|
|
213
|
+
addNodeCount(node, parents, functionInfo);
|
|
214
|
+
|
|
215
|
+
const { left, right } = node;
|
|
216
|
+
const start = left.start;
|
|
217
|
+
|
|
218
|
+
// console.log(left.start, right.start);
|
|
219
|
+
|
|
220
|
+
let group;
|
|
221
|
+
// link to same branch start if LogicalExpression
|
|
222
|
+
const prevLocation = locationMap.get(start);
|
|
223
|
+
if (prevLocation) {
|
|
224
|
+
// console.log('link branch ==================', type);
|
|
225
|
+
group = branchMap.get(prevLocation.branchStart);
|
|
226
|
+
} else {
|
|
227
|
+
group = createBranchGroup('LogicalExpression', start, parents, branchMap, functionInfo);
|
|
228
|
+
addBranch(group, left, locationMap, functionInfo);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
addBranch(group, right, locationMap, functionInfo);
|
|
232
|
+
|
|
233
|
+
// console.log(group.locations.map((it) => it.start));
|
|
234
|
+
|
|
235
|
+
// sort branch locations
|
|
236
|
+
// a || b || c
|
|
237
|
+
// first, left a and right c
|
|
238
|
+
// then, left a and right b
|
|
239
|
+
if (prevLocation) {
|
|
240
|
+
const { loc, locations } = group;
|
|
241
|
+
locations.sort((a, b) => {
|
|
242
|
+
return a.start - b.start;
|
|
243
|
+
});
|
|
244
|
+
// update group end after sorted
|
|
245
|
+
loc.end = locations[locations.length - 1].end;
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
// switch
|
|
250
|
+
SwitchStatement: (node, parents) => {
|
|
251
|
+
addNodeCount(node, parents, functionInfo);
|
|
252
|
+
const start = node.start;
|
|
253
|
+
const group = createBranchGroup('SwitchStatement', start, parents, branchMap, functionInfo);
|
|
254
|
+
const cases = node.cases;
|
|
255
|
+
cases.forEach((switchCase) => {
|
|
256
|
+
// console.log('switchCase', switchCase.start);
|
|
257
|
+
addBranch(group, switchCase, locationMap, functionInfo);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// default-arg - seems that V8 coverage do NOT supported
|
|
262
|
+
// (a = 0) => {}
|
|
263
|
+
// AssignmentPattern: (node) => {}
|
|
264
|
+
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
// =======================================================================================
|
|
271
|
+
|
|
272
|
+
// const a = tf1 ? 'true' : 'false';
|
|
273
|
+
const ConditionalExpression = (group, parentCount, noBlockList, blockCount) => {
|
|
274
|
+
if (!noBlockList.length) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
let count = parentCount - blockCount;
|
|
278
|
+
noBlockList.forEach((item) => {
|
|
279
|
+
item.count = count;
|
|
280
|
+
count = 0;
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const IfStatement = (group, parentCount, noBlockList, blockCount) => {
|
|
285
|
+
if (!noBlockList.length) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
// console.log(parentCount, 'uncovered list', noBlockList.length, group.loc.start);
|
|
289
|
+
let count = parentCount - blockCount;
|
|
290
|
+
noBlockList.forEach((item) => {
|
|
291
|
+
item.count = count;
|
|
292
|
+
count = 0;
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// const b = tf2 || tf1 || a;
|
|
298
|
+
const LogicalExpression = (group, parentCount, noBlockList, blockCount) => {
|
|
299
|
+
if (!noBlockList.length) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const count = parentCount - blockCount;
|
|
303
|
+
noBlockList.forEach((item) => {
|
|
304
|
+
item.count = count;
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// const start = group.loc.start;
|
|
308
|
+
// if (start > 7874 && start < 7922) {
|
|
309
|
+
// console.log(group.type, parentCount, 'locations', group.locations, group.functionInfo.range);
|
|
310
|
+
// }
|
|
311
|
+
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const SwitchStatement = (group, parentCount, noBlockList, blockCount) => {
|
|
315
|
+
if (!noBlockList.length) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const count = parentCount - blockCount;
|
|
319
|
+
noBlockList.forEach((item) => {
|
|
320
|
+
item.count = count;
|
|
321
|
+
});
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// =======================================================================================
|
|
325
|
+
|
|
326
|
+
const getBranchParentCount = (reverseParents, functionCount) => {
|
|
327
|
+
// parent count
|
|
328
|
+
for (const parent of reverseParents) {
|
|
329
|
+
if (parent._state) {
|
|
330
|
+
return parent._state.count;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// root function count
|
|
335
|
+
return functionCount;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const updateBranchCount = (group) => {
|
|
339
|
+
|
|
340
|
+
const {
|
|
341
|
+
type, locations, reverseParents, functionInfo
|
|
342
|
+
} = group;
|
|
343
|
+
|
|
344
|
+
const functionCount = functionInfo.count;
|
|
345
|
+
|
|
346
|
+
// default is 0, no need continue
|
|
347
|
+
if (functionCount === 0) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const parentCount = getBranchParentCount(reverseParents, functionCount);
|
|
352
|
+
// console.log(functionInfo.start, 'function count', functionCount, 'parent count', parentCount);
|
|
353
|
+
|
|
354
|
+
// calculate branches count
|
|
355
|
+
// > 1
|
|
356
|
+
|
|
357
|
+
const noBlockList = [];
|
|
358
|
+
let blockCount = 0;
|
|
359
|
+
locations.forEach((item) => {
|
|
360
|
+
if (item.block) {
|
|
361
|
+
item.count = item.block.count;
|
|
362
|
+
blockCount += item.count;
|
|
363
|
+
} else {
|
|
364
|
+
noBlockList.push(item);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const handlers = {
|
|
369
|
+
ConditionalExpression,
|
|
370
|
+
IfStatement,
|
|
371
|
+
LogicalExpression,
|
|
372
|
+
SwitchStatement
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
handlers[type](group, parentCount, noBlockList, blockCount);
|
|
376
|
+
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const collectBranches = (branchMap) => {
|
|
380
|
+
|
|
381
|
+
// calculate count for all branches
|
|
382
|
+
branchMap.forEach((group) => {
|
|
383
|
+
updateBranchCount(group);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// init branches
|
|
387
|
+
const branches = [];
|
|
388
|
+
branchMap.forEach((group) => {
|
|
389
|
+
branches.push({
|
|
390
|
+
type: group.type,
|
|
391
|
+
loc: group.loc,
|
|
392
|
+
locations: group.locations
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// sort branches
|
|
397
|
+
branches.sort((a, b) => {
|
|
398
|
+
return a.loc.start - b.loc.start;
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
return branches;
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
module.exports = {
|
|
405
|
+
findInRanges,
|
|
406
|
+
createBranches,
|
|
407
|
+
collectBranches
|
|
408
|
+
};
|