monocart-reporter 1.7.0 → 1.7.2

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.
Files changed (38) hide show
  1. package/README.md +8 -12
  2. package/lib/cli.js +1 -1
  3. package/lib/common.js +2 -3
  4. package/lib/default/options.js +4 -3
  5. package/lib/generate-data.js +2 -7
  6. package/lib/generate-report.js +10 -11
  7. package/lib/index.d.ts +2 -9
  8. package/lib/index.js +6 -0
  9. package/lib/merge-data.js +7 -6
  10. package/lib/plugins/audit/audit.js +4 -2
  11. package/lib/plugins/comments.js +2 -3
  12. package/lib/plugins/coverage/converter/collect-source-maps.js +194 -0
  13. package/lib/plugins/coverage/converter/converter.js +547 -0
  14. package/lib/plugins/coverage/converter/decode-mappings.js +49 -0
  15. package/lib/plugins/coverage/{v8 → converter}/dedupe.js +8 -1
  16. package/lib/plugins/coverage/converter/find-original-range.js +576 -0
  17. package/lib/plugins/coverage/converter/info-branch.js +30 -0
  18. package/lib/plugins/coverage/converter/info-function.js +29 -0
  19. package/lib/plugins/coverage/converter/info-line.js +20 -0
  20. package/lib/plugins/coverage/converter/position-mapping.js +183 -0
  21. package/lib/plugins/coverage/{coverage-utils.js → converter/source-path.js} +26 -42
  22. package/lib/plugins/coverage/coverage.js +61 -57
  23. package/lib/plugins/coverage/istanbul/istanbul.js +21 -174
  24. package/lib/plugins/coverage/v8/v8.js +22 -30
  25. package/lib/plugins/network/network.js +4 -13
  26. package/lib/plugins/state/client.js +3 -4
  27. package/lib/plugins/state/state.js +6 -3
  28. package/lib/runtime/monocart-code-viewer.js +1 -1
  29. package/lib/runtime/monocart-coverage.js +13 -14
  30. package/lib/runtime/monocart-formatter.js +1 -1
  31. package/lib/runtime/monocart-network.js +1 -1
  32. package/lib/runtime/monocart-reporter.js +1 -1
  33. package/lib/runtime/monocart-v8.js +1 -1
  34. package/lib/runtime/monocart-vendor.js +13 -13
  35. package/lib/utils/util.js +97 -3
  36. package/package.json +5 -6
  37. package/lib/plugins/coverage/v8/position-mapping.js +0 -92
  38. package/lib/plugins/coverage/v8/source-map.js +0 -464
@@ -0,0 +1,576 @@
1
+
2
+ const findMapping = (list, offset) => {
3
+ let start = 0;
4
+ let end = list.length - 1;
5
+ while (end - start > 1) {
6
+ const i = Math.floor((start + end) * 0.5);
7
+ const item = list[i];
8
+ if (offset < item.generatedOffset) {
9
+ end = i;
10
+ continue;
11
+ }
12
+ if (offset > item.generatedOffset) {
13
+ start = i;
14
+ continue;
15
+ }
16
+ return list[i];
17
+ }
18
+ // last two items, less is start
19
+ const endItem = list[end];
20
+ if (offset < endItem.generatedOffset) {
21
+ return list[start];
22
+ }
23
+ return list[end];
24
+
25
+ };
26
+
27
+ const findOffsetMapping = (generatedState, offset) => {
28
+
29
+ const decodedMappings = generatedState.decodedMappings;
30
+
31
+ const mapping = findMapping(decodedMappings, offset);
32
+
33
+ const generatedOffset = mapping.generatedOffset;
34
+
35
+ // not found, allow > last, not allow < first
36
+ if (offset < generatedOffset) {
37
+ return;
38
+ }
39
+
40
+ // exact matched no need fix
41
+ const exact = generatedOffset === offset;
42
+
43
+ return {
44
+ ... mapping,
45
+ // could be fixed if not exact matched
46
+ column: mapping.originalColumn,
47
+ exact
48
+ };
49
+ };
50
+
51
+ const findNextOriginalDiffMapping = (originalState, mapping) => {
52
+ const decodedMappings = originalState.decodedMappings;
53
+ const { originalIndex, originalOffset } = mapping;
54
+
55
+ let i = originalIndex + 1;
56
+ const l = decodedMappings.length;
57
+ while (i < l) {
58
+ const item = decodedMappings[i];
59
+ // sometimes next is same line/column
60
+ if (item.originalOffset > originalOffset) {
61
+ return item;
62
+ }
63
+ i += 1;
64
+ }
65
+ };
66
+
67
+ const findNextGeneratedDiffMapping = (generatedState, mapping) => {
68
+ const decodedMappings = generatedState.decodedMappings;
69
+ const i = mapping.generatedIndex + 1;
70
+ const l = decodedMappings.length;
71
+ if (i < l) {
72
+ return decodedMappings[i];
73
+ }
74
+ };
75
+
76
+ const getGeneratedText = (mapping, generatedState) => {
77
+
78
+ const generatedText = mapping.generatedText;
79
+ if (typeof generatedText === 'string') {
80
+ return generatedText;
81
+ }
82
+
83
+ let text = '';
84
+
85
+ const { positionMapping } = generatedState;
86
+ const nextMapping = findNextGeneratedDiffMapping(generatedState, mapping);
87
+ if (nextMapping) {
88
+ text = positionMapping.getSlice(mapping.generatedOffset, nextMapping.generatedOffset);
89
+ } else {
90
+ // to the end
91
+ text = positionMapping.getSlice(mapping.generatedOffset);
92
+ }
93
+
94
+ // never cross line
95
+ if (mapping.generatedEndOffset) {
96
+ const len = mapping.generatedEndOffset - mapping.generatedOffset;
97
+ text = text.slice(0, len);
98
+ }
99
+
100
+ // keep cache
101
+ mapping.generatedText = text;
102
+
103
+ return text;
104
+
105
+ };
106
+
107
+ const getOriginalText = (mapping, originalState) => {
108
+
109
+ const originalText = mapping.originalText;
110
+ if (typeof originalText === 'string') {
111
+ return originalText;
112
+ }
113
+
114
+ let text = '';
115
+
116
+ const { positionMapping } = originalState;
117
+ const nextMapping = findNextOriginalDiffMapping(originalState, mapping);
118
+ if (nextMapping) {
119
+ text = positionMapping.getSlice(mapping.originalOffset, nextMapping.originalOffset);
120
+ } else {
121
+ // to the end
122
+ text = positionMapping.getSlice(mapping.originalOffset);
123
+ }
124
+
125
+ // the last two items could have same line and column
126
+ // so can NOT pre-calculate original end offset, just search new line with regex
127
+
128
+ // never cross line
129
+ const newLineIndex = text.search(/\r?\n/);
130
+ if (newLineIndex !== -1) {
131
+ text = text.slice(0, newLineIndex);
132
+ }
133
+
134
+ // keep cache
135
+ mapping.originalText = text;
136
+
137
+ return text;
138
+ };
139
+
140
+ // ========================================================================================================
141
+
142
+ const getBlockStartPosition = (originalText) => {
143
+ // start block characters
144
+
145
+ // originalText: 'argument) {',
146
+ // generatedLeft: 'o',
147
+ // generatedRight: '&&'
148
+
149
+ // function/block could be started with {(
150
+ const startBlockIndex = originalText.search(/[<{(]/);
151
+ if (startBlockIndex !== -1) {
152
+ return startBlockIndex;
153
+ }
154
+
155
+ // end a block
156
+ const list = ['>', '}', ')'];
157
+ for (const s of list) {
158
+ const endBlockIndex = originalText.lastIndexOf(s);
159
+ if (endBlockIndex !== -1) {
160
+ return endBlockIndex + 1;
161
+ }
162
+ }
163
+
164
+ return -1;
165
+ };
166
+
167
+ const getBlockEndPosition = (originalText) => {
168
+ // generatedText: 'e),',
169
+ // generatedPos: 2,
170
+ // originalText: 'prop))'
171
+
172
+ // generatedText: ' = false)',
173
+ // generatedPos: 8,
174
+ // originalText: '=false"'
175
+
176
+ // generatedText: '), 1 /* TEXT */)])])) : (0,vue__...)("v-if", true)], 6 /* CLASS, STYLE */);',
177
+ // generatedPos: 17,
178
+ // originalText: ' }}</slot>'
179
+
180
+ const list = ['>', '}', ')'];
181
+ for (const s of list) {
182
+ const endBlockIndex = originalText.lastIndexOf(s);
183
+ if (endBlockIndex !== -1) {
184
+ return endBlockIndex + 1;
185
+ }
186
+ }
187
+
188
+ const startBlockIndex = originalText.search(/[<{(]/);
189
+ if (startBlockIndex !== -1) {
190
+ return startBlockIndex;
191
+ }
192
+
193
+ return -1;
194
+ };
195
+
196
+ const getOriginalStartPosition = (originalText, generatedText, generatedPos) => {
197
+
198
+ if (!originalText.length) {
199
+ return 0;
200
+ }
201
+
202
+ if (originalText === generatedText) {
203
+ return generatedPos;
204
+ }
205
+
206
+ // ============================
207
+ // left matched
208
+
209
+ // originalText: '1;',
210
+ // generatedText: '1;else',
211
+ // generatedLeft: '1;'
212
+
213
+ const generatedLeft = generatedText.slice(0, generatedPos);
214
+ if (originalText.startsWith(generatedLeft)) {
215
+ return generatedLeft.length;
216
+ }
217
+
218
+ // ============================
219
+ // no case for right
220
+ // const generatedRight = generatedText.slice(generatedPos);
221
+ // if (originalText.endsWith(generatedRight)) {
222
+ // return originalText.length - generatedRight.length;
223
+ // }
224
+
225
+ // ============================
226
+ // starts with original text (few case possible useless)
227
+
228
+ // generatedText "(void 0, void 0, void 0, function* () {"
229
+ // originalText " {"
230
+
231
+ // generatedLen: 1629,
232
+ // generatedText: '__exports__);\r\n\r\n/***/ }),\r\n\r\n/***/ "./packages/v8',
233
+ // generatedPos: 489,
234
+ // originalText: '__exports__',
235
+
236
+ // original less, generated more
237
+ // const includeIndex = generatedText.indexOf(originalText);
238
+ // if (includeIndex !== -1) {
239
+
240
+ // console.log('=================== includeIndex', includeIndex, generatedPos);
241
+ // console.log(JSON.stringify(generatedText.slice(0, originalText.length + includeIndex + 10)));
242
+ // console.log(JSON.stringify(originalText));
243
+
244
+ // if (includeIndex >= generatedPos) {
245
+ // return 0;
246
+ // }
247
+
248
+ // return originalText.length;
249
+ // }
250
+
251
+ // ============================
252
+ // {} () <>
253
+ const blockIndex = getBlockStartPosition(originalText);
254
+ if (blockIndex !== -1) {
255
+ return blockIndex;
256
+ }
257
+
258
+ // ============================
259
+ // end characters
260
+
261
+ // ends with ">" in vue
262
+ // <span v-if="data.distFile">
263
+
264
+ // originalText: '">',
265
+ // generatedText: ' ? ((0,vue__.openBlock)(), '
266
+
267
+ // originalMethod?.apply
268
+ // originalText: '?.' no ?
269
+
270
+ const indexEndBlock = originalText.search(/(?<=[;,:"'\s])/);
271
+ if (indexEndBlock !== -1) {
272
+ return indexEndBlock;
273
+ }
274
+
275
+ // console.log('====================================================================');
276
+ // console.log('start position can NOT be fixed');
277
+ // console.log({
278
+ // generatedText,
279
+ // generatedPos,
280
+ // originalText
281
+ // // originalPos
282
+ // });
283
+
284
+ // ============================
285
+ // can NOT be fixed
286
+ // using original column
287
+ return 0;
288
+ };
289
+
290
+ const getOriginalEndPosition = (originalText, generatedText, generatedPos) => {
291
+
292
+ if (!originalText.length) {
293
+ return 0;
294
+ }
295
+
296
+ if (originalText === generatedText) {
297
+ return generatedPos;
298
+ }
299
+
300
+ // ============================
301
+ // {} () <>
302
+ const blockIndex = getBlockEndPosition(originalText);
303
+ if (blockIndex !== -1) {
304
+ return blockIndex;
305
+ }
306
+
307
+ // console.log('====================================================================');
308
+ // console.log('end position can NOT be fixed');
309
+ // console.log({
310
+ // generatedText,
311
+ // generatedPos,
312
+ // originalText
313
+ // // originalPos
314
+ // });
315
+
316
+ // ============================
317
+ // can NOT be fixed
318
+ // to the line end
319
+ return originalText.length;
320
+ };
321
+
322
+ // ========================================================================================================
323
+
324
+ const fixStartColumn = (startMapping, range, generatedState, originalState) => {
325
+ // exact matched no need fix
326
+ if (startMapping.exact) {
327
+ // originalColumn is the column
328
+ return;
329
+ }
330
+
331
+ // fix column
332
+ const originalColumn = startMapping.originalColumn;
333
+
334
+ const originalText = getOriginalText(startMapping, originalState);
335
+ const generatedText = getGeneratedText(startMapping, generatedState);
336
+
337
+ // actual generatedOffset < range startOffset
338
+ const generatedPos = range.startOffset - startMapping.generatedOffset;
339
+
340
+ const originalPos = getOriginalStartPosition(originalText, generatedText, generatedPos);
341
+
342
+ // if (originalState.sourcePath.endsWith('src/components/report.vue') && range.count === 0) {
343
+ // console.log('====================================================================');
344
+ // console.log('fix startMapping', originalState.sourcePath);
345
+ // console.log(startMapping);
346
+ // console.log({
347
+ // generatedPos,
348
+ // originalPos
349
+ // });
350
+ // }
351
+
352
+ // failed if originalPos = 0
353
+ startMapping.column = originalColumn + originalPos;
354
+
355
+ };
356
+
357
+ // ========================================================================================================
358
+
359
+ const fixEndColumn = (endMapping, range, startMapping, generatedState, originalState) => {
360
+
361
+ const originalColumn = endMapping.originalColumn;
362
+
363
+ // exact matched, but already -1 so need +1
364
+ if (endMapping.exact) {
365
+ endMapping.column = originalColumn + 1;
366
+ return;
367
+ }
368
+
369
+ // ================================
370
+ // diff line, to the line end
371
+ if (endMapping.originalLine !== startMapping.originalLine) {
372
+ endMapping.column = Infinity;
373
+ return;
374
+ }
375
+
376
+ // ================================
377
+ // in the same line
378
+
379
+ const originalText = getOriginalText(endMapping, originalState);
380
+
381
+ // exclusive, need exclude some end strings
382
+ if (!endMapping.exclusive) {
383
+ endMapping.column = originalColumn + originalText.length;
384
+ return;
385
+ }
386
+
387
+
388
+ const generatedText = getGeneratedText(endMapping, generatedState);
389
+
390
+ // actual generatedOffset < range endOffset
391
+ const generatedPos = range.endOffset - endMapping.generatedOffset;
392
+
393
+ const originalPos = getOriginalEndPosition(originalText, generatedText, generatedPos);
394
+
395
+ // if (originalState.sourcePath.endsWith('v8/src/app.vue') && range.count === 0) {
396
+ // console.log('====================================================================');
397
+ // console.log('fix endMapping', originalState.sourcePath);
398
+ // console.log(startMapping, endMapping);
399
+ // const generatedLen = generatedText.length;
400
+ // const gt = generatedLen > 50 ? generatedText.slice(0, 50) : generatedText;
401
+ // console.log({
402
+ // generatedLen,
403
+ // generatedText: gt,
404
+ // generatedPos,
405
+ // originalText,
406
+ // originalPos
407
+ // });
408
+ // }
409
+
410
+ // failed if originalPos = 0
411
+ endMapping.column = originalColumn + originalPos;
412
+
413
+ };
414
+
415
+ // ========================================================================================================
416
+
417
+ const isOffsetCrossLine = (startMapping, offset) => {
418
+ const { exact, generatedEndOffset } = startMapping;
419
+ if (!exact && generatedEndOffset) {
420
+ if (offset >= generatedEndOffset) {
421
+ return true;
422
+ }
423
+ }
424
+ return false;
425
+ };
426
+
427
+ const findStartMapping = (range, generatedState, originalMap) => {
428
+
429
+ // startOffset: inclusive
430
+ const startOffset = range.startOffset;
431
+
432
+ const startMapping = findOffsetMapping(generatedState, startOffset);
433
+ if (!startMapping) {
434
+ return;
435
+ }
436
+
437
+ // check end offset for start mapping only
438
+ // start mapping is inclusive, do not allow cross line
439
+ // but end mapping is exclusive and offset do -1, possible no mapping found, do not check it
440
+ if (isOffsetCrossLine(startMapping, startOffset)) {
441
+ // try next mapping if its offset in the range
442
+ const nextMapping = findNextGeneratedDiffMapping(generatedState, startMapping);
443
+ if (!nextMapping) {
444
+ return;
445
+ }
446
+
447
+ // ignore out of range
448
+ if (nextMapping.generatedOffset >= range.endOffset) {
449
+ return;
450
+ }
451
+
452
+ // if (startMapping.sourceIndex === 1 && range.count === 0) {
453
+ // console.log('=========================================================');
454
+ // console.log('find next start');
455
+ // console.log(startMapping, nextMapping, range);
456
+ // }
457
+
458
+ // exact and column
459
+ Object.assign(startMapping, nextMapping, {
460
+ exact: true,
461
+ column: nextMapping.originalColumn
462
+ });
463
+
464
+ }
465
+
466
+
467
+ // check source first, sourceIndex could be undefined
468
+ const sourceIndex = startMapping.sourceIndex;
469
+
470
+ const originalState = originalMap.get(sourceIndex);
471
+ if (!originalState) {
472
+ return;
473
+ }
474
+
475
+ return {
476
+ startMapping,
477
+ originalState
478
+ };
479
+ };
480
+
481
+
482
+ const findEndMapping = (range, generatedState, startMapping) => {
483
+
484
+ // endOffset: exclusive
485
+ const endOffset = range.endOffset;
486
+
487
+ // there could be some comments before end mapping even exact matched
488
+ const endMapping = findOffsetMapping(generatedState, endOffset - 1);
489
+ if (!endMapping) {
490
+ return;
491
+ }
492
+
493
+ // cross file ignore
494
+ if (endMapping.sourceIndex !== startMapping.sourceIndex) {
495
+ return;
496
+ }
497
+
498
+ // still exclusive
499
+ const exclusiveMapping = findOffsetMapping(generatedState, endOffset);
500
+ if (exclusiveMapping && exclusiveMapping.originalOffset === endMapping.originalOffset) {
501
+ endMapping.exclusive = true;
502
+ }
503
+
504
+ return endMapping;
505
+ };
506
+
507
+ const findOriginalRange = (range, generatedState, originalMap) => {
508
+
509
+ // startOffset: inclusive
510
+ // endOffset: exclusive
511
+
512
+ const startResult = findStartMapping(range, generatedState, originalMap);
513
+ if (!startResult) {
514
+ return;
515
+ }
516
+ const { startMapping, originalState } = startResult;
517
+
518
+ // ==================================================================================
519
+ // if (originalState.sourcePath.endsWith('app/app.module.ts')) {
520
+ // originalState.showLog = true;
521
+ // console.log('============================================================');
522
+ // console.log(originalState.sourcePath);
523
+ // console.log(range);
524
+ // } else {
525
+ // originalState.showLog = false;
526
+ // }
527
+ // ==================================================================================
528
+
529
+ const endMapping = findEndMapping(range, generatedState, startMapping);
530
+ if (!endMapping) {
531
+ return;
532
+ }
533
+
534
+ // fix start
535
+ fixStartColumn(startMapping, range, generatedState, originalState);
536
+
537
+ // fix end
538
+ fixEndColumn(endMapping, range, startMapping, generatedState, originalState);
539
+
540
+ const positionMapping = originalState.positionMapping;
541
+ const originalStart = positionMapping.locationToOffset({
542
+ line: startMapping.originalLine + 1,
543
+ column: startMapping.column
544
+ });
545
+ const originalEnd = positionMapping.locationToOffset({
546
+ line: endMapping.originalLine + 1,
547
+ column: endMapping.column
548
+ });
549
+
550
+ // range start greater than end
551
+ if (originalStart >= originalEnd) {
552
+ // console.log(`start >= end: ${originalState.sourcePath}`);
553
+ // console.log(range, originalRange);
554
+ return;
555
+ }
556
+
557
+ const originalRange = {
558
+ startOffset: originalStart,
559
+ endOffset: originalEnd,
560
+ count: range.count
561
+ };
562
+
563
+ // if (originalState.showLog) {
564
+ // console.log('startMapping and endMapping:');
565
+ // console.log(startMapping, endMapping);
566
+ // console.log(originalStart, originalEnd);
567
+ // }
568
+
569
+ return {
570
+ originalRange,
571
+ originalState
572
+ };
573
+
574
+ };
575
+
576
+ module.exports = findOriginalRange;
@@ -0,0 +1,30 @@
1
+ module.exports = class InfoBranch {
2
+ constructor(sLoc, eLoc, count) {
3
+ this.startLine = sLoc.line;
4
+ this.startColumn = sLoc.column;
5
+ this.endLine = eLoc.line;
6
+ this.endColumn = eLoc.column;
7
+ this.count = count;
8
+ }
9
+
10
+ generate() {
11
+ const location = {
12
+ start: {
13
+ line: this.startLine,
14
+ column: this.startColumn
15
+ },
16
+ end: {
17
+ line: this.endLine,
18
+ column: this.endColumn
19
+ }
20
+ };
21
+ return {
22
+ type: 'branch',
23
+ line: this.startLine,
24
+ loc: location,
25
+ locations: [{
26
+ ... location
27
+ }]
28
+ };
29
+ }
30
+ };
@@ -0,0 +1,29 @@
1
+ module.exports = class InfoFunction {
2
+ constructor(sLoc, eLoc, count, name) {
3
+ this.startLine = sLoc.line;
4
+ this.startColumn = sLoc.column;
5
+ this.endLine = eLoc.line;
6
+ this.endColumn = eLoc.column;
7
+ this.count = count;
8
+ this.name = name || '(anonymous)';
9
+ }
10
+
11
+ generate() {
12
+ const loc = {
13
+ start: {
14
+ line: this.startLine,
15
+ column: this.startColumn
16
+ },
17
+ end: {
18
+ line: this.endLine,
19
+ column: this.endColumn
20
+ }
21
+ };
22
+ return {
23
+ name: this.name,
24
+ decl: loc,
25
+ loc: loc,
26
+ line: this.startLine
27
+ };
28
+ }
29
+ };
@@ -0,0 +1,20 @@
1
+ module.exports = class InfoLine {
2
+ constructor(line, column) {
3
+ this.line = line;
4
+ this.column = column;
5
+ this.count = 1;
6
+ }
7
+
8
+ generate() {
9
+ return {
10
+ start: {
11
+ line: this.line,
12
+ column: 0
13
+ },
14
+ end: {
15
+ line: this.line,
16
+ column: this.column
17
+ }
18
+ };
19
+ }
20
+ };