monocart-reporter 1.7.12 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +10 -26
  2. package/lib/generate-data.js +7 -19
  3. package/lib/generate-report.js +13 -6
  4. package/lib/index.d.ts +5 -46
  5. package/lib/index.js +1 -4
  6. package/lib/index.mjs +0 -1
  7. package/lib/packages/monocart-common.js +1 -0
  8. package/lib/packages/monocart-network.js +1 -0
  9. package/lib/packages/monocart-reporter.js +1 -0
  10. package/lib/packages/monocart-vendor.js +22 -0
  11. package/lib/platform/share.js +0 -5
  12. package/lib/plugins/audit/audit.js +2 -2
  13. package/lib/plugins/coverage/coverage.js +63 -249
  14. package/lib/plugins/network/network.js +17 -13
  15. package/lib/plugins/state/client.js +1 -1
  16. package/lib/plugins/state/state.js +1 -1
  17. package/lib/utils/parse-source.js +1 -1
  18. package/lib/utils/util.js +25 -38
  19. package/lib/visitor.js +6 -26
  20. package/package.json +10 -8
  21. package/lib/plugins/coverage/converter/collect-source-maps.js +0 -194
  22. package/lib/plugins/coverage/converter/converter.js +0 -565
  23. package/lib/plugins/coverage/converter/dedupe.js +0 -110
  24. package/lib/plugins/coverage/converter/find-original-range.js +0 -581
  25. package/lib/plugins/coverage/converter/info-branch.js +0 -30
  26. package/lib/plugins/coverage/converter/info-function.js +0 -29
  27. package/lib/plugins/coverage/converter/info-line.js +0 -20
  28. package/lib/plugins/coverage/converter/position-mapping.js +0 -183
  29. package/lib/plugins/coverage/converter/source-path.js +0 -140
  30. package/lib/plugins/coverage/istanbul/istanbul-summary.js +0 -49
  31. package/lib/plugins/coverage/istanbul/istanbul.js +0 -133
  32. package/lib/plugins/coverage/v8/v8-summary.js +0 -80
  33. package/lib/plugins/coverage/v8/v8.js +0 -260
  34. package/lib/runtime/monocart-code-viewer.js +0 -1
  35. package/lib/runtime/monocart-common.js +0 -1
  36. package/lib/runtime/monocart-coverage.js +0 -14
  37. package/lib/runtime/monocart-formatter.js +0 -1
  38. package/lib/runtime/monocart-network.js +0 -1
  39. package/lib/runtime/monocart-reporter.js +0 -1
  40. package/lib/runtime/monocart-v8.js +0 -1
  41. package/lib/runtime/monocart-vendor.js +0 -22
  42. package/lib/utils/decode-mappings.js +0 -49
@@ -1,565 +0,0 @@
1
- const path = require('path');
2
-
3
- const Util = require('../../../utils/util.js');
4
- const decodeMappings = require('../../../utils/decode-mappings.js');
5
-
6
- // position mapping for conversion between offset and line/column
7
- const PositionMapping = require('./position-mapping.js');
8
- const findOriginalRange = require('./find-original-range.js');
9
-
10
- const { dedupeCountRanges } = require('./dedupe.js');
11
- const { getSourceType, initSourceMapSourcePath } = require('./source-path.js');
12
-
13
- const InfoLine = require('./info-line.js');
14
- const InfoBranch = require('./info-branch.js');
15
- const InfoFunction = require('./info-function.js');
16
-
17
- // ========================================================================================================
18
-
19
- // istanbul coverage format
20
- /**
21
- * * `path` - the file path for which coverage is being tracked
22
- * * `statementMap` - map of statement locations keyed by statement index
23
- * * `fnMap` - map of function metadata keyed by function index
24
- * * `branchMap` - map of branch metadata keyed by branch index
25
- * * `s` - hit counts for statements
26
- * * `f` - hit count for functions
27
- * * `b` - hit count for branches
28
- */
29
- const getFileCoverage = (sourcePath, inputData) => {
30
-
31
- const {
32
- lines, functions, branches, ranges
33
- } = inputData;
34
-
35
- // v8 ranges
36
- inputData.ranges = dedupeCountRanges(ranges);
37
-
38
- // istanbul coverage
39
- const coverage = {
40
- path: sourcePath,
41
-
42
- statementMap: {},
43
- s: {},
44
-
45
- fnMap: {},
46
- f: {},
47
-
48
- branchMap: {},
49
- b: {}
50
- };
51
-
52
- lines.forEach((line, index) => {
53
- coverage.statementMap[`${index}`] = line.generate();
54
- coverage.s[`${index}`] = line.count;
55
- });
56
-
57
- functions.forEach((fn, index) => {
58
- coverage.fnMap[`${index}`] = fn.generate();
59
- coverage.f[`${index}`] = fn.count;
60
- });
61
-
62
- branches.forEach((branch, index) => {
63
- coverage.branchMap[`${index}`] = branch.generate();
64
- coverage.b[`${index}`] = [branch.count];
65
- });
66
-
67
- return coverage;
68
- };
69
-
70
- // ========================================================================================================
71
-
72
- const setLineCount = (lineMap, line, count) => {
73
- const lineInfo = lineMap[line];
74
- if (lineInfo) {
75
- lineInfo.count = count;
76
- }
77
- };
78
-
79
- const setSingleLineCount = (lineMap, sLoc, eLoc, count) => {
80
- // nothing between
81
- if (sLoc.column >= eLoc.column) {
82
- return;
83
- }
84
-
85
- // sometimes column > length
86
- if (sLoc.column <= sLoc.indent && eLoc.column >= eLoc.length) {
87
- // console.log('single', sLoc.line);
88
- setLineCount(lineMap, sLoc.line, count);
89
- }
90
-
91
- };
92
-
93
- const updateLinesCount = (lineMap, sLoc, eLoc, count) => {
94
-
95
- // single line
96
- if (sLoc.line === eLoc.line) {
97
- setSingleLineCount(lineMap, sLoc, eLoc, count);
98
- return;
99
- }
100
-
101
- const firstELoc = {
102
- ... sLoc,
103
- column: sLoc.length
104
- };
105
- setSingleLineCount(lineMap, sLoc, firstELoc, count);
106
-
107
- for (let i = sLoc.line + 1; i < eLoc.line; i++) {
108
- setLineCount(lineMap, i, count);
109
- }
110
-
111
- const lastSLoc = {
112
- ... eLoc,
113
- column: eLoc.indent
114
- };
115
- setSingleLineCount(lineMap, lastSLoc, eLoc, count);
116
-
117
- };
118
-
119
- const initFileCoverage = (positionMapping, count) => {
120
-
121
- // istanbul
122
- const lines = [];
123
- const functions = [];
124
- const branches = [];
125
- // v8
126
- const ranges = [];
127
-
128
- // add all lines
129
- const lineMap = {};
130
-
131
- const { commentedLines, blankLines } = positionMapping;
132
- positionMapping.lines.forEach((it) => {
133
- // exclude comments and blanks
134
- if (commentedLines.includes(it.line) || blankLines.includes(it.line)) {
135
- return;
136
- }
137
- // line 1-base
138
- const line = it.line + 1;
139
- const lineInfo = new InfoLine(line, it.length, count);
140
- lineMap[line] = lineInfo;
141
- lines.push(lineInfo);
142
- });
143
-
144
- return {
145
- lines, functions, branches, ranges, lineMap
146
- };
147
- };
148
-
149
-
150
- // https://github.com/demurgos/v8-coverage
151
- /**
152
- * @ranges is always non-empty. The first range is called the "root range".
153
- * @isBlockCoverage indicates if the function has block coverage information
154
- * @false means that there is a single range and its count is the number of times the function was called.
155
- * @true means that the ranges form a tree of blocks representing how many times each statement or expression inside was executed.
156
- * It detects skipped or repeated statements. The root range counts the number of function calls.
157
- *
158
- * @functionName can be an empty string. This is common for the FunctionCov representing the whole module.
159
- */
160
- const addJsCoverage = (coverage, block, range, index, positionMapping) => {
161
-
162
- const {
163
- functions, branches, ranges, lineMap
164
- } = coverage;
165
-
166
- const { isBlockCoverage, functionName } = block;
167
- const {
168
- startOffset, endOffset, count
169
- } = range;
170
-
171
- ranges.push({
172
- start: startOffset,
173
- end: endOffset,
174
- count
175
- });
176
-
177
- const sLoc = positionMapping.offsetToLocation(startOffset);
178
- const eLoc = positionMapping.offsetToLocation(endOffset);
179
-
180
- // line, column
181
- updateLinesCount(lineMap, sLoc, eLoc, count);
182
-
183
- if (isBlockCoverage) {
184
- if (index === 0) {
185
- // The root range counts the number of function calls
186
- functions.push(new InfoFunction(sLoc, eLoc, count, functionName));
187
- }
188
-
189
- // index 0 not really a branch, but for covered whole function
190
- branches.push(new InfoBranch(sLoc, eLoc, count));
191
-
192
- } else {
193
- functions.push(new InfoFunction(sLoc, eLoc, count, functionName));
194
-
195
- // possible have branches in the function but no information for it
196
-
197
- }
198
- };
199
-
200
- const addCssCoverage = (coverage, range, positionMapping) => {
201
- const { lineMap } = coverage;
202
-
203
- const { start, end } = range;
204
-
205
- const sLoc = positionMapping.offsetToLocation(start);
206
- const eLoc = positionMapping.offsetToLocation(end);
207
-
208
- // line, column
209
- updateLinesCount(lineMap, sLoc, eLoc, 1);
210
-
211
- };
212
-
213
- // ========================================================================================================
214
-
215
- const getDistCoverage = (item, state) => {
216
- const positionMapping = state.positionMapping;
217
- if (item.type === 'js') {
218
- const coverage = initFileCoverage(positionMapping, 1);
219
- item.functions.forEach((block) => {
220
- block.ranges.forEach((range, index) => {
221
- addJsCoverage(coverage, block, range, index, positionMapping);
222
- });
223
- });
224
- return coverage;
225
- }
226
-
227
- const coverage = initFileCoverage(positionMapping, 0);
228
- item.ranges.forEach((range) => {
229
- addCssCoverage(coverage, range, positionMapping);
230
- });
231
- return coverage;
232
- };
233
-
234
- const unpackDistSource = (item, state) => {
235
- const coverage = getDistCoverage(item, state);
236
- const sourcePath = item.sourcePath;
237
- state.coverageData[sourcePath] = getFileCoverage(sourcePath, coverage);
238
- // after dedupe
239
- item.ranges = coverage.ranges;
240
- };
241
-
242
- // ========================================================================================================
243
-
244
- const decodeSourceMappings = async (sourceMap, generatedPositionMapping) => {
245
-
246
- const decodedList = await decodeMappings(sourceMap.mappings);
247
-
248
- const originalIndexMap = new Map();
249
- sourceMap.sources.forEach((item, i) => {
250
- originalIndexMap.set(i, []);
251
- });
252
-
253
- const allDecodedMappings = [];
254
- let generatedIndex = 0;
255
- decodedList.forEach((segments, generatedLine) => {
256
- let item = null;
257
- segments.forEach((segment) => {
258
- const [generatedColumn, sourceIndex, originalLine, originalColumn] = segment;
259
- const generatedOffset = generatedPositionMapping.locationToOffset({
260
- // 1-base
261
- line: generatedLine + 1,
262
- column: generatedColumn
263
- });
264
-
265
- item = {
266
- generatedOffset,
267
- generatedLine,
268
- generatedColumn,
269
- generatedIndex,
270
-
271
- sourceIndex,
272
- originalLine,
273
- originalColumn
274
- };
275
-
276
- allDecodedMappings.push(item);
277
- generatedIndex += 1;
278
-
279
- if (typeof sourceIndex === 'undefined') {
280
- return;
281
- }
282
-
283
- originalIndexMap.get(sourceIndex).push(item);
284
-
285
- });
286
-
287
- // line last one
288
- if (item) {
289
- const line = generatedPositionMapping.getLine(item.generatedLine + 1);
290
- // last column
291
- item.generatedEndOffset = item.generatedOffset + (line.length - item.generatedColumn);
292
- }
293
-
294
- });
295
-
296
- // defaults to sort by generated offset, not need sort
297
- // allDecodedMappings.sort((a, b) => {
298
- // return a.generatedOffset - b.generatedOffset;
299
- // });
300
-
301
- return {
302
- allDecodedMappings,
303
- originalIndexMap
304
- };
305
-
306
- };
307
-
308
- const getOriginalDecodedMappings = (originalIndexMap, sourceIndex, positionMapping) => {
309
- // all mappings for the original file sorted
310
- const decodedMappings = originalIndexMap.get(sourceIndex);
311
-
312
- if (!decodeMappings) {
313
- return [];
314
- }
315
-
316
- // sort by original line/column
317
- decodedMappings.sort((a, b) => {
318
- if (a.originalLine === b.originalLine) {
319
- return a.originalColumn - b.originalColumn;
320
- }
321
- return a.originalLine - b.originalLine;
322
- });
323
-
324
- // add offset and index
325
- decodedMappings.forEach((item, i) => {
326
- item.originalIndex = i;
327
- item.originalOffset = positionMapping.locationToOffset({
328
- line: item.originalLine + 1,
329
- column: item.originalColumn
330
- });
331
- });
332
-
333
- return decodedMappings;
334
- };
335
-
336
- const initOriginalList = (sourceMap, originalIndexMap, fileSources, options) => {
337
-
338
- // source filter
339
- const { sources, sourcesContent } = sourceMap;
340
-
341
- let sourceFilter = options.sourceFilter;
342
- if (typeof sourceFilter !== 'function') {
343
- sourceFilter = () => true;
344
- }
345
-
346
- // create original content mappings
347
- const map = new Map();
348
-
349
- sources.forEach((sourcePath, sourceIndex) => {
350
-
351
- // filter
352
- if (!sourceFilter(sourcePath)) {
353
- return;
354
- }
355
-
356
- // console.log(`add source: ${k}`);
357
- const sourceContent = sourcesContent[sourceIndex];
358
- if (typeof sourceContent !== 'string') {
359
- Util.logError(`not found source content: ${sourcePath}`);
360
- return;
361
- }
362
-
363
- // keep original formatted content
364
- fileSources[sourcePath] = sourceContent;
365
-
366
- const positionMapping = new PositionMapping(sourceContent);
367
-
368
- const decodedMappings = getOriginalDecodedMappings(originalIndexMap, sourceIndex, positionMapping);
369
-
370
- const coverage = initFileCoverage(positionMapping, 1);
371
-
372
- const type = getSourceType(sourcePath);
373
-
374
- const originalState = {
375
- source: sourceContent,
376
- type,
377
- sourcePath,
378
- positionMapping,
379
- decodedMappings,
380
- coverage
381
- };
382
-
383
- map.set(sourceIndex, originalState);
384
- });
385
-
386
- return map;
387
- };
388
-
389
- const unpackSourceMap = async (item, state, options) => {
390
- const sourceMap = item.sourceMap;
391
- const generatedPositionMapping = state.positionMapping;
392
- const distFile = sourceMap.file || path.basename(item.sourcePath);
393
-
394
- // keep original urls
395
- const fileUrls = {};
396
- initSourceMapSourcePath(sourceMap, fileUrls, options.sourcePath);
397
-
398
- // decode mappings for each original file
399
- const time_start_decode = Date.now();
400
- const { allDecodedMappings, originalIndexMap } = await decodeSourceMappings(sourceMap, generatedPositionMapping);
401
- // only debug level
402
- Util.logTime(`decode source mappings ${distFile}`, time_start_decode);
403
-
404
- // filter original list and init list
405
- const fileSources = state.fileSources;
406
- const originalMap = initOriginalList(sourceMap, originalIndexMap, fileSources, options);
407
-
408
- originalIndexMap.clear();
409
-
410
- const generatedState = {
411
- decodedMappings: allDecodedMappings,
412
- positionMapping: generatedPositionMapping
413
- };
414
-
415
- // const time_start_mapping = Date.now();
416
- item.functions.forEach((block) => {
417
- block.ranges.forEach((range, index) => {
418
-
419
- const result = findOriginalRange(range, generatedState, originalMap);
420
- if (!result) {
421
- return;
422
- }
423
-
424
- const { originalRange, originalState } = result;
425
- const { coverage, positionMapping } = originalState;
426
- addJsCoverage(coverage, block, originalRange, index, positionMapping);
427
-
428
- });
429
- });
430
-
431
- // collect original files
432
- const sourceList = [];
433
- originalMap.forEach((originalState) => {
434
- const {
435
- source, type, sourcePath, coverage
436
- } = originalState;
437
-
438
- // generate coverage
439
- state.coverageData[sourcePath] = getFileCoverage(sourcePath, coverage);
440
- const ranges = coverage.ranges;
441
-
442
- // add file item
443
- const url = fileUrls[sourcePath] || sourcePath;
444
- const id = Util.calculateSha1(url + source);
445
-
446
- const sourceItem = {
447
- url,
448
- id,
449
- type,
450
- sourcePath,
451
- distFile,
452
- ranges,
453
- source
454
- };
455
-
456
- sourceList.push(sourceItem);
457
- });
458
-
459
- state.sourceList = sourceList;
460
-
461
- };
462
-
463
- // ========================================================================================================
464
-
465
- const unpackDistFile = async (item, state, options) => {
466
-
467
- if (item.sourceMap) {
468
- if (Util.loggingType === 'debug') {
469
- // js self
470
- unpackDistSource(item, state, options);
471
- } else {
472
- item.dedupe = true;
473
- }
474
-
475
- // unpack source map
476
- await unpackSourceMap(item, state, options);
477
-
478
- // remove sourceMap
479
- delete item.sourceMap;
480
-
481
- } else {
482
-
483
- // css/js self
484
- unpackDistSource(item, state, options);
485
-
486
- }
487
-
488
- // clean after all
489
- delete item.functions;
490
-
491
- };
492
-
493
- // ========================================================================================================
494
-
495
- const dedupeV8List = (v8list) => {
496
- const indexes = [];
497
- v8list.forEach((item, i) => {
498
- if (item.dedupe) {
499
- indexes.push(i);
500
- }
501
- });
502
- if (indexes.length) {
503
- indexes.reverse();
504
- indexes.forEach((i) => {
505
- v8list.splice(i, 1);
506
- });
507
- }
508
- };
509
-
510
-
511
- const convertV8List = async (v8list, options) => {
512
-
513
- // global file sources and coverage data
514
- const fileSources = {};
515
- const coverageData = {};
516
- let sourceList = [];
517
-
518
- for (const item of v8list) {
519
- // console.log([item.id]);
520
-
521
- const { source, sourcePath } = item;
522
-
523
- const positionMapping = new PositionMapping(source);
524
-
525
- // append file source
526
- fileSources[sourcePath] = source;
527
-
528
- // current file and it's sources from sourceMap
529
- const state = {
530
- fileSources: {},
531
- coverageData: {},
532
- positionMapping
533
- };
534
-
535
- await unpackDistFile(item, state, options);
536
-
537
- // merge state
538
- Object.assign(fileSources, state.fileSources);
539
- Object.assign(coverageData, state.coverageData);
540
- if (state.sourceList) {
541
- sourceList = sourceList.concat(state.sourceList);
542
- }
543
-
544
- }
545
-
546
- // dedupe
547
- dedupeV8List(v8list);
548
-
549
- // add all sources
550
- if (sourceList.length) {
551
- sourceList.forEach((item) => {
552
- v8list.push(item);
553
- });
554
- }
555
-
556
- return {
557
- fileSources,
558
- coverageData
559
- };
560
-
561
- };
562
-
563
- module.exports = {
564
- convertV8List
565
- };
@@ -1,110 +0,0 @@
1
-
2
- const sortRanges = (ranges) => {
3
- ranges.sort((a, b) => {
4
- if (a.start === b.start) {
5
- return a.end - b.end;
6
- }
7
- return a.start - b.start;
8
- });
9
- };
10
-
11
- const filterRanges = (ranges) => {
12
- // remove start = end
13
- return ranges.filter((range) => range.start < range.end);
14
- };
15
-
16
- // apply directly to css ranges
17
- const dedupeRanges = (ranges) => {
18
-
19
- ranges = filterRanges(ranges);
20
-
21
- if (ranges.length < 2) {
22
- return ranges;
23
- }
24
-
25
- sortRanges(ranges);
26
-
27
- ranges.reduce((prevRange, range) => {
28
-
29
- // same start
30
- if (range.start === prevRange.start) {
31
- range.dedupe = true;
32
- // equal prev
33
- if (range.end === prevRange.end) {
34
- return prevRange;
35
- }
36
- // great than the prev end, update the end
37
- prevRange.end = range.end;
38
- return prevRange;
39
- }
40
-
41
- // already in the range
42
- if (range.end <= prevRange.end) {
43
- range.dedupe = true;
44
- return prevRange;
45
- }
46
-
47
- // collected, update the end
48
- if (range.start <= prevRange.end) {
49
- range.dedupe = true;
50
- prevRange.end = range.end;
51
- return prevRange;
52
- }
53
-
54
- return range;
55
- });
56
-
57
- ranges = ranges.filter((it) => !it.dedupe);
58
-
59
- return ranges;
60
- };
61
-
62
- // apply to js count ranges
63
- const dedupeCountRanges = (ranges) => {
64
-
65
- // v8 ranges format
66
- // { startOffset: 0, endOffset: 6, count: 0 },
67
- // { startOffset: 0, endOffset: 6, count: 1 },
68
- // { startOffset: 0, endOffset: 297, count: 1 }
69
-
70
- // count ranges format
71
- // { start: 0, end: 6, count: 0 }
72
-
73
- ranges = filterRanges(ranges);
74
-
75
- if (ranges.length < 2) {
76
- return ranges;
77
- }
78
-
79
- sortRanges(ranges);
80
-
81
- let hasDedupe = false;
82
-
83
- // merge count for same range
84
- ranges.reduce((lastRange, range) => {
85
- if (range.start === lastRange.start && range.end === lastRange.end) {
86
- range.dedupe = true;
87
- lastRange.count += range.count;
88
-
89
- hasDedupe = true;
90
-
91
- return lastRange;
92
- }
93
- return range;
94
- });
95
-
96
- if (hasDedupe) {
97
- // console.log(ranges);
98
- ranges = ranges.filter((it) => !it.dedupe);
99
- }
100
-
101
- // console.log('ranges length after', ranges.length);
102
-
103
- return ranges;
104
- };
105
-
106
-
107
- module.exports = {
108
- dedupeRanges,
109
- dedupeCountRanges
110
- };