monocart-coverage-reports 2.5.8 → 2.6.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.
- package/LICENSE +21 -21
- package/README.md +787 -763
- package/lib/cli.js +215 -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 -1400
- 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 -81
- package/lib/default/template.html +47 -47
- package/lib/generate.js +720 -532
- package/lib/index.d.ts +360 -317
- package/lib/index.js +183 -173
- 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 -165
- package/lib/utils/util.js +526 -526
- package/lib/v8/v8-summary.js +138 -138
- package/lib/v8/v8.js +399 -630
- package/package.json +81 -79
package/lib/platform/share.js
CHANGED
|
@@ -1,484 +1,484 @@
|
|
|
1
|
-
const Util = {
|
|
2
|
-
|
|
3
|
-
// definition
|
|
4
|
-
tagPattern: /(\s*)@([^@\s]+)(\s*)/g,
|
|
5
|
-
lineBreakPattern: /\r\n|[\r\n\u2028\u2029]/gu,
|
|
6
|
-
|
|
7
|
-
hasOwn: function(obj, key) {
|
|
8
|
-
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
9
|
-
},
|
|
10
|
-
|
|
11
|
-
isNull: function(input) {
|
|
12
|
-
if (input === null || typeof input === 'undefined') {
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
return false;
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
uid: function(len = 20, prefix = '') {
|
|
19
|
-
const dict = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
20
|
-
const dictLen = dict.length;
|
|
21
|
-
let str = prefix;
|
|
22
|
-
while (len--) {
|
|
23
|
-
str += dict[Math.random() * dictLen | 0];
|
|
24
|
-
}
|
|
25
|
-
return str;
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
zero: function(s, l = 2) {
|
|
29
|
-
s = `${s}`;
|
|
30
|
-
return s.padStart(l, '0');
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
toNum: function(num, toInt) {
|
|
34
|
-
if (typeof (num) !== 'number') {
|
|
35
|
-
num = parseFloat(num);
|
|
36
|
-
}
|
|
37
|
-
if (isNaN(num)) {
|
|
38
|
-
num = 0;
|
|
39
|
-
}
|
|
40
|
-
if (toInt) {
|
|
41
|
-
num = Math.round(num);
|
|
42
|
-
}
|
|
43
|
-
return num;
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
isList: function(data) {
|
|
47
|
-
if (data && data instanceof Array && data.length > 0) {
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
toList: function(data, separator) {
|
|
54
|
-
if (data instanceof Array) {
|
|
55
|
-
return data;
|
|
56
|
-
}
|
|
57
|
-
if (typeof data === 'string' && (typeof separator === 'string' || separator instanceof RegExp)) {
|
|
58
|
-
return data.split(separator).map((str) => str.trim()).filter((str) => str);
|
|
59
|
-
}
|
|
60
|
-
if (typeof data === 'undefined' || data === null) {
|
|
61
|
-
return [];
|
|
62
|
-
}
|
|
63
|
-
return [data];
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
forEach: function(rootList, callback) {
|
|
67
|
-
const isBreak = (res) => {
|
|
68
|
-
return res === 'break' || res === false;
|
|
69
|
-
};
|
|
70
|
-
const forList = (list, parent) => {
|
|
71
|
-
if (!Util.isList(list)) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
for (const item of list) {
|
|
75
|
-
const result = callback(item, parent);
|
|
76
|
-
if (isBreak(result)) {
|
|
77
|
-
return result;
|
|
78
|
-
}
|
|
79
|
-
const subResult = forList(item.subs, item);
|
|
80
|
-
if (isBreak(subResult)) {
|
|
81
|
-
return subResult;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
forList(rootList);
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
// \ to /
|
|
89
|
-
formatPath: function(str) {
|
|
90
|
-
if (str) {
|
|
91
|
-
str = str.replace(/\\/g, '/');
|
|
92
|
-
}
|
|
93
|
-
return str;
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
getCurrentTrendInfo: (data) => {
|
|
97
|
-
|
|
98
|
-
const {
|
|
99
|
-
date, duration, summary
|
|
100
|
-
} = data;
|
|
101
|
-
|
|
102
|
-
const info = {
|
|
103
|
-
date,
|
|
104
|
-
duration
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
Object.keys(summary).forEach((k) => {
|
|
108
|
-
const item = summary[k];
|
|
109
|
-
info[k] = item.value;
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
return info;
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
isTagItem: (item) => {
|
|
116
|
-
if (item.type === 'case' || (item.type === 'suite' && item.suiteType === 'describe')) {
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
return false;
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
delay: function(ms) {
|
|
123
|
-
return new Promise((resolve) => {
|
|
124
|
-
if (ms) {
|
|
125
|
-
setTimeout(resolve, ms);
|
|
126
|
-
} else {
|
|
127
|
-
setImmediate(resolve);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
// =============================================================================
|
|
133
|
-
|
|
134
|
-
getMetrics: (
|
|
135
|
-
const istanbulMetrics = ['statements', 'branches', 'functions', 'lines'];
|
|
136
|
-
const v8Metrics = ['bytes'].concat(istanbulMetrics);
|
|
137
|
-
const allMetrics = type === '
|
|
138
|
-
let list = allMetrics;
|
|
139
|
-
if (Util.isList(metrics)) {
|
|
140
|
-
const newList = list.filter((k) => metrics.includes(k));
|
|
141
|
-
if (newList.length) {
|
|
142
|
-
list = newList;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return list;
|
|
146
|
-
},
|
|
147
|
-
|
|
148
|
-
generatePercentChart: function(percent) {
|
|
149
|
-
return `<div style="--mcr-percent:${percent}%;" class="mcr-percent-chart"></div>`;
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
getStatus: (value, watermarks) => {
|
|
153
|
-
if (!watermarks) {
|
|
154
|
-
return 'unknown';
|
|
155
|
-
}
|
|
156
|
-
if (value < watermarks[0]) {
|
|
157
|
-
return 'low';
|
|
158
|
-
}
|
|
159
|
-
if (value < watermarks[1]) {
|
|
160
|
-
return 'medium';
|
|
161
|
-
}
|
|
162
|
-
return 'high';
|
|
163
|
-
},
|
|
164
|
-
|
|
165
|
-
isJsonType: (contentType) => {
|
|
166
|
-
if (contentType) {
|
|
167
|
-
if (contentType === 'application/json' || contentType === 'json') {
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return false;
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
isMarkdownType: (contentType) => {
|
|
175
|
-
if (contentType) {
|
|
176
|
-
if (contentType === 'text/markdown' || contentType === 'markdown') {
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return false;
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
isTextType: (contentType) => {
|
|
184
|
-
if (contentType) {
|
|
185
|
-
if (contentType.startsWith('text')) {
|
|
186
|
-
return true;
|
|
187
|
-
}
|
|
188
|
-
if (Util.isMarkdownType(contentType)) {
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
if (Util.isJsonType(contentType)) {
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return false;
|
|
196
|
-
},
|
|
197
|
-
|
|
198
|
-
isBlank: (codeStr) => {
|
|
199
|
-
if (typeof codeStr === 'string') {
|
|
200
|
-
const blankBlock = /\S/;
|
|
201
|
-
return !blankBlock.test(codeStr);
|
|
202
|
-
}
|
|
203
|
-
return false;
|
|
204
|
-
},
|
|
205
|
-
|
|
206
|
-
findInRanges: (startPos, endPos, rangeList, startKey = 'start', endKey = 'end') => {
|
|
207
|
-
if (!Util.isList(rangeList)) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const quickFindRange = (position, ranges) => {
|
|
212
|
-
let start = 0;
|
|
213
|
-
let end = ranges.length - 1;
|
|
214
|
-
while (end - start > 1) {
|
|
215
|
-
const i = Math.floor((start + end) * 0.5);
|
|
216
|
-
const item = ranges[i];
|
|
217
|
-
if (position < item[startKey]) {
|
|
218
|
-
end = i;
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
if (position > item[endKey]) {
|
|
222
|
-
start = i;
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
return ranges[i];
|
|
226
|
-
}
|
|
227
|
-
// last two items, less is start
|
|
228
|
-
const endItem = ranges[end];
|
|
229
|
-
if (position < endItem[startKey]) {
|
|
230
|
-
return ranges[start];
|
|
231
|
-
}
|
|
232
|
-
return ranges[end];
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
const range = quickFindRange(startPos, rangeList);
|
|
236
|
-
if (startPos >= range[startKey] && endPos <= range[endKey]) {
|
|
237
|
-
return range;
|
|
238
|
-
}
|
|
239
|
-
},
|
|
240
|
-
|
|
241
|
-
getRangeLines: (sLoc, eLoc) => {
|
|
242
|
-
|
|
243
|
-
const lines = [];
|
|
244
|
-
|
|
245
|
-
// invalid location order
|
|
246
|
-
if (sLoc.line > eLoc.line) {
|
|
247
|
-
return lines;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// nothing middle
|
|
251
|
-
if (sLoc.line === eLoc.line && sLoc.column >= eLoc.column) {
|
|
252
|
-
return lines;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const addStart = () => {
|
|
256
|
-
|
|
257
|
-
// nothing start
|
|
258
|
-
if (sLoc.column >= sLoc.length) {
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const entire = sLoc.column <= sLoc.indent;
|
|
263
|
-
lines.push({
|
|
264
|
-
line: sLoc.line,
|
|
265
|
-
entire,
|
|
266
|
-
pieces: {
|
|
267
|
-
start: sLoc.column,
|
|
268
|
-
end: sLoc.length
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
const addMiddle = () => {
|
|
274
|
-
|
|
275
|
-
const start = sLoc.column <= sLoc.indent;
|
|
276
|
-
const end = Util.isBlank(eLoc.text.slice(eLoc.column));
|
|
277
|
-
const entire = start && end;
|
|
278
|
-
// same line
|
|
279
|
-
lines.push({
|
|
280
|
-
line: sLoc.line,
|
|
281
|
-
entire,
|
|
282
|
-
pieces: {
|
|
283
|
-
start: sLoc.column,
|
|
284
|
-
end: eLoc.column
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
const addEnd = () => {
|
|
290
|
-
|
|
291
|
-
// nothing end
|
|
292
|
-
if (eLoc.column === 0) {
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// pieces in indent, ignored
|
|
297
|
-
if (eLoc.column <= eLoc.indent) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const rightText = eLoc.text.slice(eLoc.column);
|
|
302
|
-
|
|
303
|
-
// right text is blank or only ";" (few cases)
|
|
304
|
-
const entire = Util.isBlank(rightText) || rightText.trim() === ';';
|
|
305
|
-
lines.push({
|
|
306
|
-
line: eLoc.line,
|
|
307
|
-
entire,
|
|
308
|
-
pieces: {
|
|
309
|
-
start: eLoc.indent,
|
|
310
|
-
end: eLoc.column
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
// same line, single line
|
|
316
|
-
if (sLoc.line === eLoc.line) {
|
|
317
|
-
|
|
318
|
-
addMiddle();
|
|
319
|
-
|
|
320
|
-
} else {
|
|
321
|
-
// multiple lines
|
|
322
|
-
|
|
323
|
-
addStart();
|
|
324
|
-
|
|
325
|
-
// always entire for middle lines
|
|
326
|
-
const lineStart = sLoc.line + 1;
|
|
327
|
-
const lineEnd = eLoc.line;
|
|
328
|
-
if (lineEnd > lineStart) {
|
|
329
|
-
for (let i = lineStart; i < lineEnd; i++) {
|
|
330
|
-
lines.push({
|
|
331
|
-
line: i,
|
|
332
|
-
entire: true
|
|
333
|
-
// no pieces for entire line
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// check end
|
|
339
|
-
addEnd();
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return lines;
|
|
343
|
-
},
|
|
344
|
-
|
|
345
|
-
// =============================================================================
|
|
346
|
-
// svg
|
|
347
|
-
|
|
348
|
-
dFixed: (num, fixed = 1) => {
|
|
349
|
-
if (Number.isInteger(num)) {
|
|
350
|
-
return num;
|
|
351
|
-
}
|
|
352
|
-
return Util.toNum(Util.toNum(num).toFixed(fixed));
|
|
353
|
-
},
|
|
354
|
-
|
|
355
|
-
pxFixed: (num) => {
|
|
356
|
-
const floor = Math.floor(num);
|
|
357
|
-
if (num < floor + 0.5) {
|
|
358
|
-
return floor + 0.5;
|
|
359
|
-
}
|
|
360
|
-
return floor + 1.5;
|
|
361
|
-
},
|
|
362
|
-
|
|
363
|
-
point: (px, py) => {
|
|
364
|
-
return `${Util.dFixed(px)},${Util.dFixed(py)}`;
|
|
365
|
-
},
|
|
366
|
-
|
|
367
|
-
capitalizeFirstLetter: (string) => {
|
|
368
|
-
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
369
|
-
},
|
|
370
|
-
|
|
371
|
-
// =============================================================================
|
|
372
|
-
// formatter
|
|
373
|
-
|
|
374
|
-
// number
|
|
375
|
-
NF: function(v) {
|
|
376
|
-
if (typeof v === 'number' && v) {
|
|
377
|
-
return v.toLocaleString();
|
|
378
|
-
}
|
|
379
|
-
return v;
|
|
380
|
-
},
|
|
381
|
-
|
|
382
|
-
// percent
|
|
383
|
-
PF: function(v, t = 1, digits = 1, unit = '%', space = '') {
|
|
384
|
-
v = Util.toNum(v);
|
|
385
|
-
t = Util.toNum(t);
|
|
386
|
-
let per = 0;
|
|
387
|
-
if (t) {
|
|
388
|
-
per = v / t;
|
|
389
|
-
}
|
|
390
|
-
const perStr = (per * 100).toFixed(digits);
|
|
391
|
-
if (unit) {
|
|
392
|
-
return perStr + space + unit;
|
|
393
|
-
}
|
|
394
|
-
return parseFloat(perStr);
|
|
395
|
-
},
|
|
396
|
-
|
|
397
|
-
PSF: function(v, t = 1, digits = 1) {
|
|
398
|
-
return Util.PF(v, t, digits, '%', ' ');
|
|
399
|
-
},
|
|
400
|
-
|
|
401
|
-
PNF: function(v, t = 1, digits = 1) {
|
|
402
|
-
return Util.PF(v, t, digits, '');
|
|
403
|
-
},
|
|
404
|
-
|
|
405
|
-
// byte
|
|
406
|
-
BF: function(v, places = 1, space = '') {
|
|
407
|
-
v = Util.toNum(v, true);
|
|
408
|
-
if (v === 0) {
|
|
409
|
-
return `0${space}B`;
|
|
410
|
-
}
|
|
411
|
-
let prefix = '';
|
|
412
|
-
if (v < 0) {
|
|
413
|
-
v = Math.abs(v);
|
|
414
|
-
prefix = '-';
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
const base = 1024;
|
|
418
|
-
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
419
|
-
for (let i = 0, l = units.length; i < l; i++) {
|
|
420
|
-
const min = Math.pow(base, i);
|
|
421
|
-
const max = Math.pow(base, i + 1);
|
|
422
|
-
if (v > min && v < max) {
|
|
423
|
-
const unit = units[i];
|
|
424
|
-
v = prefix + parseFloat((v / min).toFixed(places)) + space + unit;
|
|
425
|
-
break;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
return v;
|
|
429
|
-
},
|
|
430
|
-
|
|
431
|
-
BSF: function(v, places = 1) {
|
|
432
|
-
return Util.BF(v, places, ' ');
|
|
433
|
-
},
|
|
434
|
-
|
|
435
|
-
// time
|
|
436
|
-
TF: function(v, space = '') {
|
|
437
|
-
const ms = Util.toNum(v, true);
|
|
438
|
-
|
|
439
|
-
if (ms < 1000) {
|
|
440
|
-
return `${ms}${space}ms`;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (ms < 60 * 1000) {
|
|
444
|
-
const ss = Math.floor(ms / 1000);
|
|
445
|
-
const sms = Math.round((ms - ss * 1000) / 100);
|
|
446
|
-
if (sms) {
|
|
447
|
-
return `${ss}.${sms}${space}s`;
|
|
448
|
-
}
|
|
449
|
-
return `${ss}${space}s`;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
const s = Math.round(ms / 1000);
|
|
453
|
-
|
|
454
|
-
const m = 60;
|
|
455
|
-
const h = m * 60;
|
|
456
|
-
const d = h * 24;
|
|
457
|
-
|
|
458
|
-
if (s < h) {
|
|
459
|
-
const minutes = Math.floor(s / m);
|
|
460
|
-
const seconds = s - minutes * m;
|
|
461
|
-
return `${minutes}${space}m ${seconds}${space}s`;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (s < d) {
|
|
465
|
-
const hours = Math.floor(s / h);
|
|
466
|
-
const minutes = Math.floor((s - hours * h) / m);
|
|
467
|
-
const seconds = s - hours * h - minutes * m;
|
|
468
|
-
return `${hours}${space}h ${minutes}${space}m ${seconds}${space}s`;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
const days = Math.floor(s / d);
|
|
472
|
-
const hours = Math.floor((s - days * d) / h);
|
|
473
|
-
const minutes = Math.floor((s - days * d - hours * h) / m);
|
|
474
|
-
const seconds = s - days * d - hours * h - minutes * m;
|
|
475
|
-
return `${days}${space}d ${hours}${space}h ${minutes}${space}m ${seconds}${space}s`;
|
|
476
|
-
},
|
|
477
|
-
|
|
478
|
-
TSF: function(v) {
|
|
479
|
-
return Util.TF(v, ' ');
|
|
480
|
-
}
|
|
481
|
-
};
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
module.exports = Util;
|
|
1
|
+
const Util = {
|
|
2
|
+
|
|
3
|
+
// definition
|
|
4
|
+
tagPattern: /(\s*)@([^@\s]+)(\s*)/g,
|
|
5
|
+
lineBreakPattern: /\r\n|[\r\n\u2028\u2029]/gu,
|
|
6
|
+
|
|
7
|
+
hasOwn: function(obj, key) {
|
|
8
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
isNull: function(input) {
|
|
12
|
+
if (input === null || typeof input === 'undefined') {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
uid: function(len = 20, prefix = '') {
|
|
19
|
+
const dict = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
20
|
+
const dictLen = dict.length;
|
|
21
|
+
let str = prefix;
|
|
22
|
+
while (len--) {
|
|
23
|
+
str += dict[Math.random() * dictLen | 0];
|
|
24
|
+
}
|
|
25
|
+
return str;
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
zero: function(s, l = 2) {
|
|
29
|
+
s = `${s}`;
|
|
30
|
+
return s.padStart(l, '0');
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
toNum: function(num, toInt) {
|
|
34
|
+
if (typeof (num) !== 'number') {
|
|
35
|
+
num = parseFloat(num);
|
|
36
|
+
}
|
|
37
|
+
if (isNaN(num)) {
|
|
38
|
+
num = 0;
|
|
39
|
+
}
|
|
40
|
+
if (toInt) {
|
|
41
|
+
num = Math.round(num);
|
|
42
|
+
}
|
|
43
|
+
return num;
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
isList: function(data) {
|
|
47
|
+
if (data && data instanceof Array && data.length > 0) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
toList: function(data, separator) {
|
|
54
|
+
if (data instanceof Array) {
|
|
55
|
+
return data;
|
|
56
|
+
}
|
|
57
|
+
if (typeof data === 'string' && (typeof separator === 'string' || separator instanceof RegExp)) {
|
|
58
|
+
return data.split(separator).map((str) => str.trim()).filter((str) => str);
|
|
59
|
+
}
|
|
60
|
+
if (typeof data === 'undefined' || data === null) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
return [data];
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
forEach: function(rootList, callback) {
|
|
67
|
+
const isBreak = (res) => {
|
|
68
|
+
return res === 'break' || res === false;
|
|
69
|
+
};
|
|
70
|
+
const forList = (list, parent) => {
|
|
71
|
+
if (!Util.isList(list)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
for (const item of list) {
|
|
75
|
+
const result = callback(item, parent);
|
|
76
|
+
if (isBreak(result)) {
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
const subResult = forList(item.subs, item);
|
|
80
|
+
if (isBreak(subResult)) {
|
|
81
|
+
return subResult;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
forList(rootList);
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
// \ to /
|
|
89
|
+
formatPath: function(str) {
|
|
90
|
+
if (str) {
|
|
91
|
+
str = str.replace(/\\/g, '/');
|
|
92
|
+
}
|
|
93
|
+
return str;
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
getCurrentTrendInfo: (data) => {
|
|
97
|
+
|
|
98
|
+
const {
|
|
99
|
+
date, duration, summary
|
|
100
|
+
} = data;
|
|
101
|
+
|
|
102
|
+
const info = {
|
|
103
|
+
date,
|
|
104
|
+
duration
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
Object.keys(summary).forEach((k) => {
|
|
108
|
+
const item = summary[k];
|
|
109
|
+
info[k] = item.value;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return info;
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
isTagItem: (item) => {
|
|
116
|
+
if (item.type === 'case' || (item.type === 'suite' && item.suiteType === 'describe')) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
delay: function(ms) {
|
|
123
|
+
return new Promise((resolve) => {
|
|
124
|
+
if (ms) {
|
|
125
|
+
setTimeout(resolve, ms);
|
|
126
|
+
} else {
|
|
127
|
+
setImmediate(resolve);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// =============================================================================
|
|
133
|
+
|
|
134
|
+
getMetrics: (metrics, type) => {
|
|
135
|
+
const istanbulMetrics = ['statements', 'branches', 'functions', 'lines'];
|
|
136
|
+
const v8Metrics = ['bytes'].concat(istanbulMetrics);
|
|
137
|
+
const allMetrics = type === 'istanbul' ? istanbulMetrics : v8Metrics;
|
|
138
|
+
let list = allMetrics;
|
|
139
|
+
if (Util.isList(metrics)) {
|
|
140
|
+
const newList = list.filter((k) => metrics.includes(k));
|
|
141
|
+
if (newList.length) {
|
|
142
|
+
list = newList;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return list;
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
generatePercentChart: function(percent) {
|
|
149
|
+
return `<div style="--mcr-percent:${percent}%;" class="mcr-percent-chart"></div>`;
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
getStatus: (value, watermarks) => {
|
|
153
|
+
if (!watermarks) {
|
|
154
|
+
return 'unknown';
|
|
155
|
+
}
|
|
156
|
+
if (value < watermarks[0]) {
|
|
157
|
+
return 'low';
|
|
158
|
+
}
|
|
159
|
+
if (value < watermarks[1]) {
|
|
160
|
+
return 'medium';
|
|
161
|
+
}
|
|
162
|
+
return 'high';
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
isJsonType: (contentType) => {
|
|
166
|
+
if (contentType) {
|
|
167
|
+
if (contentType === 'application/json' || contentType === 'json') {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return false;
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
isMarkdownType: (contentType) => {
|
|
175
|
+
if (contentType) {
|
|
176
|
+
if (contentType === 'text/markdown' || contentType === 'markdown') {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
isTextType: (contentType) => {
|
|
184
|
+
if (contentType) {
|
|
185
|
+
if (contentType.startsWith('text')) {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
if (Util.isMarkdownType(contentType)) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
if (Util.isJsonType(contentType)) {
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return false;
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
isBlank: (codeStr) => {
|
|
199
|
+
if (typeof codeStr === 'string') {
|
|
200
|
+
const blankBlock = /\S/;
|
|
201
|
+
return !blankBlock.test(codeStr);
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
findInRanges: (startPos, endPos, rangeList, startKey = 'start', endKey = 'end') => {
|
|
207
|
+
if (!Util.isList(rangeList)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const quickFindRange = (position, ranges) => {
|
|
212
|
+
let start = 0;
|
|
213
|
+
let end = ranges.length - 1;
|
|
214
|
+
while (end - start > 1) {
|
|
215
|
+
const i = Math.floor((start + end) * 0.5);
|
|
216
|
+
const item = ranges[i];
|
|
217
|
+
if (position < item[startKey]) {
|
|
218
|
+
end = i;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (position > item[endKey]) {
|
|
222
|
+
start = i;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
return ranges[i];
|
|
226
|
+
}
|
|
227
|
+
// last two items, less is start
|
|
228
|
+
const endItem = ranges[end];
|
|
229
|
+
if (position < endItem[startKey]) {
|
|
230
|
+
return ranges[start];
|
|
231
|
+
}
|
|
232
|
+
return ranges[end];
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const range = quickFindRange(startPos, rangeList);
|
|
236
|
+
if (startPos >= range[startKey] && endPos <= range[endKey]) {
|
|
237
|
+
return range;
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
getRangeLines: (sLoc, eLoc) => {
|
|
242
|
+
|
|
243
|
+
const lines = [];
|
|
244
|
+
|
|
245
|
+
// invalid location order
|
|
246
|
+
if (sLoc.line > eLoc.line) {
|
|
247
|
+
return lines;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// nothing middle
|
|
251
|
+
if (sLoc.line === eLoc.line && sLoc.column >= eLoc.column) {
|
|
252
|
+
return lines;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const addStart = () => {
|
|
256
|
+
|
|
257
|
+
// nothing start
|
|
258
|
+
if (sLoc.column >= sLoc.length) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const entire = sLoc.column <= sLoc.indent;
|
|
263
|
+
lines.push({
|
|
264
|
+
line: sLoc.line,
|
|
265
|
+
entire,
|
|
266
|
+
pieces: {
|
|
267
|
+
start: sLoc.column,
|
|
268
|
+
end: sLoc.length
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const addMiddle = () => {
|
|
274
|
+
|
|
275
|
+
const start = sLoc.column <= sLoc.indent;
|
|
276
|
+
const end = Util.isBlank(eLoc.text.slice(eLoc.column));
|
|
277
|
+
const entire = start && end;
|
|
278
|
+
// same line
|
|
279
|
+
lines.push({
|
|
280
|
+
line: sLoc.line,
|
|
281
|
+
entire,
|
|
282
|
+
pieces: {
|
|
283
|
+
start: sLoc.column,
|
|
284
|
+
end: eLoc.column
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const addEnd = () => {
|
|
290
|
+
|
|
291
|
+
// nothing end
|
|
292
|
+
if (eLoc.column === 0) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// pieces in indent, ignored
|
|
297
|
+
if (eLoc.column <= eLoc.indent) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const rightText = eLoc.text.slice(eLoc.column);
|
|
302
|
+
|
|
303
|
+
// right text is blank or only ";" (few cases)
|
|
304
|
+
const entire = Util.isBlank(rightText) || rightText.trim() === ';';
|
|
305
|
+
lines.push({
|
|
306
|
+
line: eLoc.line,
|
|
307
|
+
entire,
|
|
308
|
+
pieces: {
|
|
309
|
+
start: eLoc.indent,
|
|
310
|
+
end: eLoc.column
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// same line, single line
|
|
316
|
+
if (sLoc.line === eLoc.line) {
|
|
317
|
+
|
|
318
|
+
addMiddle();
|
|
319
|
+
|
|
320
|
+
} else {
|
|
321
|
+
// multiple lines
|
|
322
|
+
|
|
323
|
+
addStart();
|
|
324
|
+
|
|
325
|
+
// always entire for middle lines
|
|
326
|
+
const lineStart = sLoc.line + 1;
|
|
327
|
+
const lineEnd = eLoc.line;
|
|
328
|
+
if (lineEnd > lineStart) {
|
|
329
|
+
for (let i = lineStart; i < lineEnd; i++) {
|
|
330
|
+
lines.push({
|
|
331
|
+
line: i,
|
|
332
|
+
entire: true
|
|
333
|
+
// no pieces for entire line
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// check end
|
|
339
|
+
addEnd();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return lines;
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
// =============================================================================
|
|
346
|
+
// svg
|
|
347
|
+
|
|
348
|
+
dFixed: (num, fixed = 1) => {
|
|
349
|
+
if (Number.isInteger(num)) {
|
|
350
|
+
return num;
|
|
351
|
+
}
|
|
352
|
+
return Util.toNum(Util.toNum(num).toFixed(fixed));
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
pxFixed: (num) => {
|
|
356
|
+
const floor = Math.floor(num);
|
|
357
|
+
if (num < floor + 0.5) {
|
|
358
|
+
return floor + 0.5;
|
|
359
|
+
}
|
|
360
|
+
return floor + 1.5;
|
|
361
|
+
},
|
|
362
|
+
|
|
363
|
+
point: (px, py) => {
|
|
364
|
+
return `${Util.dFixed(px)},${Util.dFixed(py)}`;
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
capitalizeFirstLetter: (string) => {
|
|
368
|
+
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
369
|
+
},
|
|
370
|
+
|
|
371
|
+
// =============================================================================
|
|
372
|
+
// formatter
|
|
373
|
+
|
|
374
|
+
// number
|
|
375
|
+
NF: function(v) {
|
|
376
|
+
if (typeof v === 'number' && v) {
|
|
377
|
+
return v.toLocaleString();
|
|
378
|
+
}
|
|
379
|
+
return v;
|
|
380
|
+
},
|
|
381
|
+
|
|
382
|
+
// percent
|
|
383
|
+
PF: function(v, t = 1, digits = 1, unit = '%', space = '') {
|
|
384
|
+
v = Util.toNum(v);
|
|
385
|
+
t = Util.toNum(t);
|
|
386
|
+
let per = 0;
|
|
387
|
+
if (t) {
|
|
388
|
+
per = v / t;
|
|
389
|
+
}
|
|
390
|
+
const perStr = (per * 100).toFixed(digits);
|
|
391
|
+
if (unit) {
|
|
392
|
+
return perStr + space + unit;
|
|
393
|
+
}
|
|
394
|
+
return parseFloat(perStr);
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
PSF: function(v, t = 1, digits = 1) {
|
|
398
|
+
return Util.PF(v, t, digits, '%', ' ');
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
PNF: function(v, t = 1, digits = 1) {
|
|
402
|
+
return Util.PF(v, t, digits, '');
|
|
403
|
+
},
|
|
404
|
+
|
|
405
|
+
// byte
|
|
406
|
+
BF: function(v, places = 1, space = '') {
|
|
407
|
+
v = Util.toNum(v, true);
|
|
408
|
+
if (v === 0) {
|
|
409
|
+
return `0${space}B`;
|
|
410
|
+
}
|
|
411
|
+
let prefix = '';
|
|
412
|
+
if (v < 0) {
|
|
413
|
+
v = Math.abs(v);
|
|
414
|
+
prefix = '-';
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const base = 1024;
|
|
418
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
419
|
+
for (let i = 0, l = units.length; i < l; i++) {
|
|
420
|
+
const min = Math.pow(base, i);
|
|
421
|
+
const max = Math.pow(base, i + 1);
|
|
422
|
+
if (v > min && v < max) {
|
|
423
|
+
const unit = units[i];
|
|
424
|
+
v = prefix + parseFloat((v / min).toFixed(places)) + space + unit;
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return v;
|
|
429
|
+
},
|
|
430
|
+
|
|
431
|
+
BSF: function(v, places = 1) {
|
|
432
|
+
return Util.BF(v, places, ' ');
|
|
433
|
+
},
|
|
434
|
+
|
|
435
|
+
// time
|
|
436
|
+
TF: function(v, space = '') {
|
|
437
|
+
const ms = Util.toNum(v, true);
|
|
438
|
+
|
|
439
|
+
if (ms < 1000) {
|
|
440
|
+
return `${ms}${space}ms`;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (ms < 60 * 1000) {
|
|
444
|
+
const ss = Math.floor(ms / 1000);
|
|
445
|
+
const sms = Math.round((ms - ss * 1000) / 100);
|
|
446
|
+
if (sms) {
|
|
447
|
+
return `${ss}.${sms}${space}s`;
|
|
448
|
+
}
|
|
449
|
+
return `${ss}${space}s`;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const s = Math.round(ms / 1000);
|
|
453
|
+
|
|
454
|
+
const m = 60;
|
|
455
|
+
const h = m * 60;
|
|
456
|
+
const d = h * 24;
|
|
457
|
+
|
|
458
|
+
if (s < h) {
|
|
459
|
+
const minutes = Math.floor(s / m);
|
|
460
|
+
const seconds = s - minutes * m;
|
|
461
|
+
return `${minutes}${space}m ${seconds}${space}s`;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (s < d) {
|
|
465
|
+
const hours = Math.floor(s / h);
|
|
466
|
+
const minutes = Math.floor((s - hours * h) / m);
|
|
467
|
+
const seconds = s - hours * h - minutes * m;
|
|
468
|
+
return `${hours}${space}h ${minutes}${space}m ${seconds}${space}s`;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const days = Math.floor(s / d);
|
|
472
|
+
const hours = Math.floor((s - days * d) / h);
|
|
473
|
+
const minutes = Math.floor((s - days * d - hours * h) / m);
|
|
474
|
+
const seconds = s - days * d - hours * h - minutes * m;
|
|
475
|
+
return `${days}${space}d ${hours}${space}h ${minutes}${space}m ${seconds}${space}s`;
|
|
476
|
+
},
|
|
477
|
+
|
|
478
|
+
TSF: function(v) {
|
|
479
|
+
return Util.TF(v, ' ');
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
module.exports = Util;
|