monocart-coverage-reports 2.5.9 → 2.6.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/LICENSE +21 -21
- package/README.md +791 -778
- package/lib/cli.js +250 -215
- package/lib/converter/ast-visitor.js +675 -666
- package/lib/converter/ast.js +353 -353
- package/lib/converter/collect-source-maps.js +201 -201
- package/lib/converter/converter.js +1487 -1429
- package/lib/converter/find-original-range.js +737 -737
- package/lib/converter/ignore.js +163 -163
- package/lib/converter/info-branch.js +93 -93
- package/lib/converter/info-function.js +63 -63
- package/lib/converter/info-statement.js +43 -43
- package/lib/default/options.js +84 -84
- package/lib/default/template.html +47 -47
- package/lib/generate.js +720 -532
- package/lib/index.d.ts +360 -324
- package/lib/index.js +187 -180
- package/lib/index.mjs +5 -3
- package/lib/istanbul/istanbul-summary.js +70 -63
- package/lib/istanbul/istanbul.js +146 -146
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/platform/concurrency.js +74 -74
- package/lib/platform/share.js +484 -484
- package/lib/utils/dedupe.js +118 -118
- package/lib/utils/request.js +62 -62
- package/lib/utils/snapshot.js +381 -0
- package/lib/utils/source-path.js +179 -179
- package/lib/utils/util.js +526 -526
- package/lib/v8/v8-summary.js +138 -138
- package/lib/v8/v8.js +400 -630
- package/package.json +81 -80
package/lib/generate.js
CHANGED
|
@@ -1,532 +1,720 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const CG = require('console-grid');
|
|
4
|
-
const EC = require('eight-colors');
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
const {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
'
|
|
78
|
-
'
|
|
79
|
-
|
|
80
|
-
// istanbul
|
|
81
|
-
'clover': 'istanbul',
|
|
82
|
-
'cobertura': 'istanbul',
|
|
83
|
-
'html': 'istanbul',
|
|
84
|
-
'html-spa': 'istanbul',
|
|
85
|
-
'json': 'istanbul',
|
|
86
|
-
'json-summary': 'istanbul',
|
|
87
|
-
'lcov': 'istanbul',
|
|
88
|
-
'lcovonly': 'istanbul',
|
|
89
|
-
'none': 'istanbul',
|
|
90
|
-
'teamcity': 'istanbul',
|
|
91
|
-
'text': 'istanbul',
|
|
92
|
-
'text-lcov': 'istanbul',
|
|
93
|
-
'text-summary': 'istanbul',
|
|
94
|
-
|
|
95
|
-
// both
|
|
96
|
-
'
|
|
97
|
-
'
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
//
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
if
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
//
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
};
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const CG = require('console-grid');
|
|
4
|
+
const EC = require('eight-colors');
|
|
5
|
+
const { pathToFileURL } = require('url');
|
|
6
|
+
|
|
7
|
+
const Util = require('./utils/util.js');
|
|
8
|
+
const {
|
|
9
|
+
initIstanbulData, mergeIstanbulCoverage, saveIstanbulReports
|
|
10
|
+
} = require('./istanbul/istanbul.js');
|
|
11
|
+
|
|
12
|
+
const { mergeV8Coverage, saveV8Report } = require('./v8/v8.js');
|
|
13
|
+
|
|
14
|
+
const { convertV8List } = require('./converter/converter.js');
|
|
15
|
+
|
|
16
|
+
const { minimatch } = require('./packages/monocart-coverage-vendor.js');
|
|
17
|
+
const { getGroupedRows } = require('./utils/snapshot.js');
|
|
18
|
+
|
|
19
|
+
// ========================================================================================================
|
|
20
|
+
|
|
21
|
+
// maybe v8 or to istanbul reports
|
|
22
|
+
const generateV8ListReports = async (v8list, coverageData, fileSources, options) => {
|
|
23
|
+
|
|
24
|
+
let report;
|
|
25
|
+
|
|
26
|
+
const { v8, istanbul } = options.reportGroup;
|
|
27
|
+
|
|
28
|
+
// generate istanbul reports first
|
|
29
|
+
if (istanbul) {
|
|
30
|
+
report = await saveIstanbulReports(coverageData, fileSources, options);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// generate v8 report
|
|
34
|
+
if (v8) {
|
|
35
|
+
report = await saveV8Report(v8list, options);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return report;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ========================================================================================================
|
|
42
|
+
|
|
43
|
+
const getReportGroup = (reports, lcov, dataType) => {
|
|
44
|
+
|
|
45
|
+
const reportMap = {};
|
|
46
|
+
|
|
47
|
+
const reportList = Util.toList(reports, ',');
|
|
48
|
+
reportList.forEach((it) => {
|
|
49
|
+
if (Util.isList(it)) {
|
|
50
|
+
// ["v8"], ["v8", {}]
|
|
51
|
+
const id = it[0];
|
|
52
|
+
if (typeof id === 'string' && id) {
|
|
53
|
+
reportMap[id] = {
|
|
54
|
+
... it[1]
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (typeof it === 'string' && it) {
|
|
60
|
+
reportMap[it] = {};
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// using default report if no reports
|
|
65
|
+
if (!Object.keys(reportMap).length) {
|
|
66
|
+
const defaultReport = dataType === 'v8' ? 'v8' : 'html';
|
|
67
|
+
reportMap[defaultReport] = {};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// add lcovonly report after default report
|
|
71
|
+
if (lcov && !reportMap.lcovonly) {
|
|
72
|
+
reportMap.lcovonly = {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const allBuildInReports = {
|
|
76
|
+
// v8
|
|
77
|
+
'v8': 'v8',
|
|
78
|
+
'v8-json': 'v8',
|
|
79
|
+
|
|
80
|
+
// istanbul
|
|
81
|
+
'clover': 'istanbul',
|
|
82
|
+
'cobertura': 'istanbul',
|
|
83
|
+
'html': 'istanbul',
|
|
84
|
+
'html-spa': 'istanbul',
|
|
85
|
+
'json': 'istanbul',
|
|
86
|
+
'json-summary': 'istanbul',
|
|
87
|
+
'lcov': 'istanbul',
|
|
88
|
+
'lcovonly': 'istanbul',
|
|
89
|
+
'none': 'istanbul',
|
|
90
|
+
'teamcity': 'istanbul',
|
|
91
|
+
'text': 'istanbul',
|
|
92
|
+
'text-lcov': 'istanbul',
|
|
93
|
+
'text-summary': 'istanbul',
|
|
94
|
+
|
|
95
|
+
// both
|
|
96
|
+
'codecov': 'both',
|
|
97
|
+
'console-details': 'both',
|
|
98
|
+
'console-summary': 'both',
|
|
99
|
+
'raw': 'both'
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// group v8 and istanbul
|
|
103
|
+
const reportGroup = {};
|
|
104
|
+
Object.keys(reportMap).forEach((k) => {
|
|
105
|
+
const options = reportMap[k];
|
|
106
|
+
|
|
107
|
+
let type = allBuildInReports[k];
|
|
108
|
+
if (!type) {
|
|
109
|
+
// for custom reporter
|
|
110
|
+
type = options.type || 'v8';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let group = reportGroup[type];
|
|
114
|
+
if (!group) {
|
|
115
|
+
group = {};
|
|
116
|
+
reportGroup[type] = group;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
group[k] = options;
|
|
120
|
+
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// requires a default istanbul report if data is istanbul
|
|
124
|
+
if (dataType === 'istanbul' && !reportGroup.istanbul) {
|
|
125
|
+
reportGroup.istanbul = {
|
|
126
|
+
html: {}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return reportGroup;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// ========================================================================================================
|
|
134
|
+
|
|
135
|
+
const pFormatter = (v, row, column) => {
|
|
136
|
+
if (typeof v === 'number') {
|
|
137
|
+
return Util.getColorStrByStatus(Util.PSF(v, 100, 2), row.status);
|
|
138
|
+
}
|
|
139
|
+
return v;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const nFormatter = (v) => {
|
|
143
|
+
if (typeof v === 'number') {
|
|
144
|
+
return Util.NF(v);
|
|
145
|
+
}
|
|
146
|
+
return v;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const getRowData = (rowName, summary, metrics) => {
|
|
150
|
+
const summaryRow = {};
|
|
151
|
+
let lowest = {
|
|
152
|
+
pct: 100,
|
|
153
|
+
status: 'high'
|
|
154
|
+
};
|
|
155
|
+
metrics.map((k) => {
|
|
156
|
+
const s = summary[k];
|
|
157
|
+
if (!s) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const percent = s.pct;
|
|
161
|
+
if (typeof percent !== 'number') {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
summaryRow[k] = Util.getColorStrByStatus(Util.PSF(percent, 100, 2), s.status);
|
|
165
|
+
if (percent < lowest.pct) {
|
|
166
|
+
lowest = s;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
summaryRow.nameStatus = lowest.status;
|
|
170
|
+
summaryRow.name = rowName;
|
|
171
|
+
return summaryRow;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const getUncoveredLines = (file) => {
|
|
175
|
+
const lines = [];
|
|
176
|
+
|
|
177
|
+
const dataLines = file.data.lines;
|
|
178
|
+
|
|
179
|
+
let startLine;
|
|
180
|
+
let endLine;
|
|
181
|
+
|
|
182
|
+
const addLines = () => {
|
|
183
|
+
if (!startLine) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (endLine) {
|
|
187
|
+
// range
|
|
188
|
+
const link = startLine.color === 'yellow' && endLine.color === 'yellow' ? EC.yellow('-') : EC.red('-');
|
|
189
|
+
lines.push(EC[startLine.color](startLine.line) + link + EC[endLine.color](endLine.line));
|
|
190
|
+
startLine = null;
|
|
191
|
+
endLine = null;
|
|
192
|
+
} else {
|
|
193
|
+
// only start
|
|
194
|
+
lines.push(EC[startLine.color](startLine.line));
|
|
195
|
+
startLine = null;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const setLines = (line, color) => {
|
|
200
|
+
if (startLine) {
|
|
201
|
+
endLine = {
|
|
202
|
+
line,
|
|
203
|
+
color
|
|
204
|
+
};
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
startLine = {
|
|
208
|
+
line,
|
|
209
|
+
color
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
Object.keys(dataLines).forEach((line) => {
|
|
214
|
+
const count = dataLines[line];
|
|
215
|
+
if (count === 0) {
|
|
216
|
+
setLines(line, 'red');
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// 0 < count < 1
|
|
220
|
+
if (typeof count === 'string') {
|
|
221
|
+
setLines(line, 'yellow');
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// count >= 1
|
|
225
|
+
addLines();
|
|
226
|
+
});
|
|
227
|
+
addLines();
|
|
228
|
+
|
|
229
|
+
return lines.join(',');
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const getDetailsRows = (files, metrics, cdOptions) => {
|
|
233
|
+
|
|
234
|
+
const skipPercent = cdOptions.skipPercent;
|
|
235
|
+
if (typeof skipPercent === 'number' && skipPercent > 0) {
|
|
236
|
+
files = files.filter((file) => {
|
|
237
|
+
const { summary } = file;
|
|
238
|
+
for (const k of metrics) {
|
|
239
|
+
const percent = summary[k].pct;
|
|
240
|
+
if (typeof percent === 'number' && percent < skipPercent) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const flatRows = [];
|
|
249
|
+
files.forEach((file) => {
|
|
250
|
+
const { sourcePath, summary } = file;
|
|
251
|
+
const fileRow = getRowData(sourcePath, summary, metrics);
|
|
252
|
+
fileRow.uncoveredLines = getUncoveredLines(file);
|
|
253
|
+
flatRows.push(fileRow);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
return getGroupedRows(flatRows);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const handleCodecovReport = async (reportData, reportOptions, options) => {
|
|
260
|
+
const codecovOptions = {
|
|
261
|
+
outputFile: 'codecov.json',
|
|
262
|
+
... reportOptions
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const jsonPath = path.resolve(options.outputDir, codecovOptions.outputFile);
|
|
266
|
+
|
|
267
|
+
// https://docs.codecov.com/docs/codecov-custom-coverage-format
|
|
268
|
+
const coverage = {};
|
|
269
|
+
reportData.files.forEach((item) => {
|
|
270
|
+
const { sourcePath, data } = item;
|
|
271
|
+
coverage[sourcePath] = data.lines;
|
|
272
|
+
});
|
|
273
|
+
const codecovData = {
|
|
274
|
+
coverage
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
await Util.writeFile(jsonPath, JSON.stringify(codecovData));
|
|
278
|
+
return Util.relativePath(jsonPath);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const handleConsoleDetailsReport = (reportData, reportOptions, options) => {
|
|
282
|
+
const cdOptions = {
|
|
283
|
+
maxCols: 50,
|
|
284
|
+
skipPercent: 0,
|
|
285
|
+
metrics: [],
|
|
286
|
+
... reportOptions
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const {
|
|
290
|
+
type, name, summary, files
|
|
291
|
+
} = reportData;
|
|
292
|
+
|
|
293
|
+
if (name) {
|
|
294
|
+
EC.logCyan(name);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const metrics = Util.getMetrics(cdOptions.metrics, type);
|
|
298
|
+
const rows = getDetailsRows(files, metrics, cdOptions);
|
|
299
|
+
const summaryRow = getRowData('Summary', summary, metrics);
|
|
300
|
+
// no rows if skipped all by skipPercent
|
|
301
|
+
if (rows.length) {
|
|
302
|
+
rows.push({
|
|
303
|
+
innerBorder: true
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
rows.push(summaryRow);
|
|
307
|
+
|
|
308
|
+
const columns = [{
|
|
309
|
+
id: 'name',
|
|
310
|
+
name: 'Name'
|
|
311
|
+
}, ... metrics.map((m) => {
|
|
312
|
+
return {
|
|
313
|
+
id: m,
|
|
314
|
+
name: Util.capitalizeFirstLetter(m),
|
|
315
|
+
align: 'right'
|
|
316
|
+
};
|
|
317
|
+
}), {
|
|
318
|
+
id: 'uncoveredLines',
|
|
319
|
+
name: 'Uncovered Lines'
|
|
320
|
+
}];
|
|
321
|
+
|
|
322
|
+
return CG({
|
|
323
|
+
options: {
|
|
324
|
+
silent: cdOptions.silent,
|
|
325
|
+
nullPlaceholder: '',
|
|
326
|
+
defaultMaxWidth: cdOptions.maxCols
|
|
327
|
+
},
|
|
328
|
+
columns,
|
|
329
|
+
rows
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const handleConsoleSummaryReport = (reportData, reportOptions, options) => {
|
|
334
|
+
|
|
335
|
+
const csOptions = {
|
|
336
|
+
metrics: [],
|
|
337
|
+
... reportOptions
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
const {
|
|
341
|
+
summary, name, type
|
|
342
|
+
} = reportData;
|
|
343
|
+
|
|
344
|
+
if (name) {
|
|
345
|
+
EC.logCyan(name);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const metrics = Util.getMetrics(csOptions.metrics, type);
|
|
349
|
+
|
|
350
|
+
const rows = metrics.map((k) => {
|
|
351
|
+
return {
|
|
352
|
+
... summary[k],
|
|
353
|
+
name: Util.capitalizeFirstLetter(k)
|
|
354
|
+
};
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
const columns = [{
|
|
358
|
+
id: 'name',
|
|
359
|
+
name: 'Name'
|
|
360
|
+
}, {
|
|
361
|
+
id: 'pct',
|
|
362
|
+
name: 'Coverage %',
|
|
363
|
+
align: 'right',
|
|
364
|
+
formatter: pFormatter
|
|
365
|
+
}, {
|
|
366
|
+
id: 'covered',
|
|
367
|
+
name: 'Covered',
|
|
368
|
+
align: 'right',
|
|
369
|
+
formatter: nFormatter
|
|
370
|
+
}, {
|
|
371
|
+
id: 'uncovered',
|
|
372
|
+
name: 'Uncovered',
|
|
373
|
+
align: 'right',
|
|
374
|
+
formatter: nFormatter
|
|
375
|
+
}, {
|
|
376
|
+
id: 'total',
|
|
377
|
+
name: 'Total',
|
|
378
|
+
align: 'right',
|
|
379
|
+
formatter: nFormatter
|
|
380
|
+
}];
|
|
381
|
+
|
|
382
|
+
CG({
|
|
383
|
+
columns,
|
|
384
|
+
rows
|
|
385
|
+
});
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
const handleRawReport = (reportData, reportOptions, options) => {
|
|
389
|
+
const rawOptions = {
|
|
390
|
+
outputDir: 'raw',
|
|
391
|
+
... reportOptions
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const cacheDir = options.cacheDir;
|
|
395
|
+
const rawDir = path.resolve(options.outputDir, rawOptions.outputDir);
|
|
396
|
+
// console.log(rawDir, cacheDir);
|
|
397
|
+
if (fs.existsSync(rawDir)) {
|
|
398
|
+
Util.logError(`Failed to save raw report because the dir already exists: ${Util.relativePath(rawDir)}`);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const rawParent = path.dirname(rawDir);
|
|
403
|
+
if (!fs.existsSync(rawParent)) {
|
|
404
|
+
fs.mkdirSync(rawParent, {
|
|
405
|
+
recursive: true
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// just rename the cache folder name
|
|
410
|
+
fs.renameSync(cacheDir, rawDir);
|
|
411
|
+
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
// ========================================================================================================
|
|
416
|
+
|
|
417
|
+
const getCoverageResults = async (dataList, sourceCache, options) => {
|
|
418
|
+
// get first and check v8list or istanbul data
|
|
419
|
+
const firstData = dataList[0];
|
|
420
|
+
const dataType = firstData.type;
|
|
421
|
+
// console.log('data type', dataType);
|
|
422
|
+
|
|
423
|
+
// init reports
|
|
424
|
+
options.reportGroup = getReportGroup(options.reports, options.lcov, dataType);
|
|
425
|
+
// console.log('reportGroup', options.reportGroup);
|
|
426
|
+
|
|
427
|
+
// v8list
|
|
428
|
+
if (dataType === 'v8') {
|
|
429
|
+
// merge v8list first
|
|
430
|
+
const v8list = await mergeV8Coverage(dataList, sourceCache, options);
|
|
431
|
+
// console.log('after merge', v8list.map((it) => it.url));
|
|
432
|
+
|
|
433
|
+
// only debug level
|
|
434
|
+
const time_start = Date.now();
|
|
435
|
+
const results = convertV8List(v8list, options);
|
|
436
|
+
const {
|
|
437
|
+
v8DataList, coverageData, fileSources
|
|
438
|
+
} = results;
|
|
439
|
+
Util.logTime(`converted v8 list: ${v8DataList.length}`, time_start);
|
|
440
|
+
|
|
441
|
+
return generateV8ListReports(v8DataList, coverageData, fileSources, options);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// istanbul data
|
|
445
|
+
const istanbulData = mergeIstanbulCoverage(dataList);
|
|
446
|
+
const { coverageData, fileSources } = initIstanbulData(istanbulData, options);
|
|
447
|
+
return saveIstanbulReports(coverageData, fileSources, options);
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
const generateCoverageReports = async (dataList, sourceCache, options) => {
|
|
451
|
+
const coverageResults = await getCoverageResults(dataList, sourceCache, options);
|
|
452
|
+
|
|
453
|
+
// [ 'type', 'reportPath', 'name', 'watermarks', 'summary', 'files' ]
|
|
454
|
+
// console.log(Object.keys(coverageResults));
|
|
455
|
+
|
|
456
|
+
const buildInBothReports = {
|
|
457
|
+
'codecov': handleCodecovReport,
|
|
458
|
+
'console-details': handleConsoleDetailsReport,
|
|
459
|
+
'console-summary': handleConsoleSummaryReport,
|
|
460
|
+
'raw': handleRawReport
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const bothGroup = options.reportGroup.both;
|
|
464
|
+
if (bothGroup) {
|
|
465
|
+
const bothReports = Object.keys(bothGroup);
|
|
466
|
+
for (const reportName of bothReports) {
|
|
467
|
+
const reportOptions = bothGroup[reportName];
|
|
468
|
+
const buildInHandler = buildInBothReports[reportName];
|
|
469
|
+
if (buildInHandler) {
|
|
470
|
+
await buildInHandler(coverageResults, reportOptions, options);
|
|
471
|
+
} else {
|
|
472
|
+
await Util.runCustomReporter(reportName, coverageResults, reportOptions, options);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return coverageResults;
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
// ========================================================================================================
|
|
481
|
+
|
|
482
|
+
const resolveAllDirList = (input) => {
|
|
483
|
+
const dirs = Util.toList(input, ',');
|
|
484
|
+
if (!dirs.length) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const dirList = dirs.filter((it) => fs.existsSync(it));
|
|
488
|
+
if (!dirList.length) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
return dirList;
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
const resolveAllFilter = (input) => {
|
|
495
|
+
// for function handler
|
|
496
|
+
if (typeof input === 'function') {
|
|
497
|
+
return input;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// for single minimatch pattern
|
|
501
|
+
if (input && typeof input === 'string') {
|
|
502
|
+
return (filePath) => {
|
|
503
|
+
return minimatch(filePath, input);
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// for patterns
|
|
508
|
+
if (input && typeof input === 'object') {
|
|
509
|
+
const patterns = Object.keys(input);
|
|
510
|
+
return (filePath) => {
|
|
511
|
+
for (const pattern of patterns) {
|
|
512
|
+
if (minimatch(filePath, pattern)) {
|
|
513
|
+
return input[pattern];
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
// false if not matched
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// default
|
|
521
|
+
return () => true;
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
const resolveAllDataType = (type, dataList) => {
|
|
525
|
+
if (!type && dataList.length) {
|
|
526
|
+
const firstData = dataList[0];
|
|
527
|
+
type = firstData.type;
|
|
528
|
+
}
|
|
529
|
+
const types = {
|
|
530
|
+
v8: 'v8',
|
|
531
|
+
istanbul: 'istanbul'
|
|
532
|
+
};
|
|
533
|
+
return types[type] || types.v8;
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
const resolveAllOptions = (input, dataList) => {
|
|
537
|
+
if (!input) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
let type;
|
|
542
|
+
let dir;
|
|
543
|
+
let filter;
|
|
544
|
+
if (typeof input === 'string' || Array.isArray(input)) {
|
|
545
|
+
dir = input;
|
|
546
|
+
filter = () => true;
|
|
547
|
+
} else {
|
|
548
|
+
type = input.type;
|
|
549
|
+
dir = input.dir;
|
|
550
|
+
filter = input.filter;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const dirList = resolveAllDirList(dir);
|
|
554
|
+
if (!dirList) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const dataType = resolveAllDataType(type, dataList);
|
|
559
|
+
const fileFilter = resolveAllFilter(filter);
|
|
560
|
+
|
|
561
|
+
return {
|
|
562
|
+
dirList,
|
|
563
|
+
dataType,
|
|
564
|
+
fileFilter
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const resolveFileType = (fileType, filePath) => {
|
|
569
|
+
if (fileType === 'js' || fileType === 'css') {
|
|
570
|
+
return fileType;
|
|
571
|
+
}
|
|
572
|
+
const extname = path.extname(filePath);
|
|
573
|
+
if (['.css', '.scss', '.sass', '.less'].includes(extname)) {
|
|
574
|
+
return 'css';
|
|
575
|
+
}
|
|
576
|
+
return 'js';
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
const getV8EmptyData = (fileList) => {
|
|
580
|
+
const v8DataList = [];
|
|
581
|
+
fileList.forEach((item) => {
|
|
582
|
+
const { filePath, fileType } = item;
|
|
583
|
+
const type = resolveFileType(fileType, filePath);
|
|
584
|
+
const url = pathToFileURL(filePath).toString();
|
|
585
|
+
const source = Util.readFileSync(filePath);
|
|
586
|
+
const entryFile = {
|
|
587
|
+
empty: true,
|
|
588
|
+
type,
|
|
589
|
+
url,
|
|
590
|
+
// for empty, css supports both source and text
|
|
591
|
+
source
|
|
592
|
+
};
|
|
593
|
+
v8DataList.push(entryFile);
|
|
594
|
+
});
|
|
595
|
+
return v8DataList;
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
const getIstanbulEmptyData = (fileList) => {
|
|
599
|
+
const istanbulData = {};
|
|
600
|
+
fileList.forEach((item) => {
|
|
601
|
+
const { filePath } = item;
|
|
602
|
+
istanbulData[filePath] = {
|
|
603
|
+
path: filePath,
|
|
604
|
+
statementMap: {},
|
|
605
|
+
fnMap: {},
|
|
606
|
+
branchMap: {},
|
|
607
|
+
s: {},
|
|
608
|
+
f: {},
|
|
609
|
+
b: {}
|
|
610
|
+
};
|
|
611
|
+
});
|
|
612
|
+
return istanbulData;
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
const getEmptyData = (all, dataList) => {
|
|
616
|
+
const allOptions = resolveAllOptions(all, dataList);
|
|
617
|
+
// console.log('allOptions', all, allOptions);
|
|
618
|
+
if (!allOptions) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
const {
|
|
622
|
+
dirList, dataType, fileFilter
|
|
623
|
+
} = allOptions;
|
|
624
|
+
const fileList = [];
|
|
625
|
+
dirList.forEach((dir) => {
|
|
626
|
+
Util.forEachFile(dir, [], (fileName, fileDir) => {
|
|
627
|
+
const filePath = path.resolve(fileDir, fileName);
|
|
628
|
+
const fileType = fileFilter(filePath);
|
|
629
|
+
if (fileType) {
|
|
630
|
+
fileList.push({
|
|
631
|
+
filePath,
|
|
632
|
+
fileType
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
// console.log('fileList', fileList);
|
|
638
|
+
if (!fileList.length) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
if (dataType === 'v8') {
|
|
642
|
+
return getV8EmptyData(fileList);
|
|
643
|
+
}
|
|
644
|
+
return getIstanbulEmptyData(fileList);
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
// ========================================================================================================
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
const getInputData = async (inputList, all, cacheDir, addHandler) => {
|
|
651
|
+
const dataList = [];
|
|
652
|
+
const sourceCache = new Map();
|
|
653
|
+
|
|
654
|
+
const addJsonData = async (dir, filename) => {
|
|
655
|
+
const isCoverage = filename.startsWith('coverage-');
|
|
656
|
+
const isSource = filename.startsWith('source-');
|
|
657
|
+
if (isCoverage || isSource) {
|
|
658
|
+
const content = await Util.readFile(path.resolve(dir, filename));
|
|
659
|
+
if (content) {
|
|
660
|
+
const json = JSON.parse(content);
|
|
661
|
+
if (isCoverage) {
|
|
662
|
+
dataList.push(json);
|
|
663
|
+
} else {
|
|
664
|
+
sourceCache.set(json.id, json);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
for (const dir of inputList) {
|
|
671
|
+
const allFiles = fs.readdirSync(dir);
|
|
672
|
+
if (!allFiles.length) {
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
for (const filename of allFiles) {
|
|
676
|
+
// only json file
|
|
677
|
+
if (filename.endsWith('.json')) {
|
|
678
|
+
await addJsonData(dir, filename);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// add empty coverage for all files
|
|
684
|
+
// dataList for data type, before `add` we don't which one is tested, because using hash id
|
|
685
|
+
const emptyData = getEmptyData(all, dataList);
|
|
686
|
+
if (emptyData) {
|
|
687
|
+
const coverageResults = await addHandler(emptyData);
|
|
688
|
+
// after `add`
|
|
689
|
+
if (coverageResults) {
|
|
690
|
+
dataList.push(coverageResults);
|
|
691
|
+
if (coverageResults.type === 'v8') {
|
|
692
|
+
// sourceCache
|
|
693
|
+
coverageResults.data.forEach((entry) => {
|
|
694
|
+
const { id } = entry;
|
|
695
|
+
if (sourceCache.has(id)) {
|
|
696
|
+
// console.log('+', entry.sourcePath);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
// console.log('-', entry.sourcePath);
|
|
700
|
+
const sourcePath = Util.resolveCacheSourcePath(cacheDir, id);
|
|
701
|
+
const content = Util.readFileSync(sourcePath);
|
|
702
|
+
if (content) {
|
|
703
|
+
const json = JSON.parse(content);
|
|
704
|
+
sourceCache.set(json.id, json);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return {
|
|
712
|
+
dataList,
|
|
713
|
+
sourceCache
|
|
714
|
+
};
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
module.exports = {
|
|
718
|
+
getInputData,
|
|
719
|
+
generateCoverageReports
|
|
720
|
+
};
|