monocart-coverage-reports 1.1.0 → 2.0.0

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