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.
@@ -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
+ };