monocart-coverage-reports 2.9.3 → 2.10.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/README.md CHANGED
@@ -107,6 +107,7 @@ For more information, see [Command Line](#command-line)
107
107
  - Features:
108
108
  - A Brand-New V8 Coverage Report User Interface
109
109
  - Support for Native Byte Statistics
110
+ - Support processing big data with high performance
110
111
  - Coverage for Any Runtime Code
111
112
  - CSS Coverage Support
112
113
  - Better Support for Sourcemap Conversion
@@ -115,7 +116,10 @@ For more information, see [Command Line](#command-line)
115
116
  ![](./assets/v8.gif)
116
117
 
117
118
  - `v8-json`
118
- - [V8 coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
119
+ - Save `CoverageResults` to a json file (defaults to [`coverage-report.json`](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)).
120
+ - Shows native V8 code coverage with VSCode extension [monocart-coverage-vscode](https://github.com/cenfun/monocart-coverage-vscode)
121
+
122
+ ![](./assets/mcv.gif)
119
123
 
120
124
  > Istanbul build-in reports (both V8 and Istanbul data):
121
125
 
@@ -158,6 +162,7 @@ cat path-to/coverage-summary.md >> $GITHUB_STEP_SUMMARY
158
162
  ![](./assets/markdown-summary.png)
159
163
 
160
164
  - `markdown-details` Save coverage details to a markdown file (defaults to `coverage-details.md`).
165
+ - Preview in [runs](https://github.com/cenfun/monocart-coverage-reports/actions/workflows/ci.yml)
161
166
 
162
167
  - `raw` only keep all original data, which can be used for other reports input with `inputDir`. see [Merge Coverage Reports](#merge-coverage-reports)
163
168
 
package/README.zh-Hans.md CHANGED
@@ -107,6 +107,7 @@ mcr node my-app.js -r v8,console-details
107
107
  - 推荐使用:
108
108
  - 全新的原生V8覆盖率报告界面,更好的用户体验
109
109
  - 支持原生的Bytes覆盖率指标
110
+ - 支持高性能处理大数据
110
111
  - 支持任何运行时代码的覆盖率(压缩后的)
111
112
  - 支持CSS代码覆盖率(用于分析CSS的冗余代码)
112
113
  - 对Sourcemap转换有更好的支持
@@ -115,7 +116,8 @@ mcr node my-app.js -r v8,console-details
115
116
  ![](./assets/v8.gif)
116
117
 
117
118
  - `v8-json`
118
- - [V8 coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
119
+ - 保存 `CoverageResults` 到一个json文件
120
+ - 预览 [coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
119
121
 
120
122
  > 内置Istanbul报告 (V8和Istanbul格式数据都支持):
121
123
 
@@ -158,6 +160,7 @@ cat path-to/coverage-summary.md >> $GITHUB_STEP_SUMMARY
158
160
  ![](./assets/markdown-summary.png)
159
161
 
160
162
  - `markdown-details` 保存覆盖率详情到markdown文件 (默认是 `coverage-details.md`)
163
+ - 预览运行结果 [runs](https://github.com/cenfun/monocart-coverage-reports/actions/workflows/ci.yml)
161
164
 
162
165
  - `raw` 只是保存原始覆盖率数据, 用于使用`inputDir`参数来导入多个原始数据进行合并报告。参见 [合并覆盖率报告](#merge-coverage-reports)
163
166
 
package/lib/assets.js ADDED
@@ -0,0 +1,98 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { deflateSync } = require('lz-utils');
4
+ const Util = require('./utils/util.js');
5
+ const assetsMap = require('./packages/monocart-coverage-assets.js');
6
+
7
+ const Assets = {
8
+
9
+ getFileContent: (id) => {
10
+ const content = assetsMap[id];
11
+ if (!content) {
12
+ Util.logError(`Not found module: ${id}`);
13
+ return '';
14
+ }
15
+ return content;
16
+ },
17
+
18
+ saveHtmlReport: async (options) => {
19
+
20
+ const {
21
+ inline,
22
+ reportData,
23
+ jsFiles,
24
+ assetsPath,
25
+ outputDir,
26
+ htmlFile,
27
+
28
+ saveReportPath,
29
+
30
+ reportDataFile
31
+ } = options;
32
+
33
+ // save path
34
+ const htmlPath = path.resolve(outputDir, htmlFile);
35
+ const reportPath = Util.relativePath(htmlPath);
36
+ if (saveReportPath) {
37
+ reportData[saveReportPath] = reportPath;
38
+ }
39
+
40
+ // report data
41
+ const reportDataCompressed = deflateSync(JSON.stringify(reportData));
42
+ const reportDataStr = `window.reportData = '${reportDataCompressed}';`;
43
+
44
+ // js libs
45
+ const jsList = [];
46
+
47
+ // deps
48
+ jsFiles.forEach((id) => {
49
+ jsList.push({
50
+ filename: `${id}.js`,
51
+ str: Assets.getFileContent(id)
52
+ });
53
+ });
54
+
55
+ // html content
56
+ let htmlStr = '';
57
+ const EOL = Util.getEOL();
58
+ if (inline) {
59
+ htmlStr = [
60
+ '<script>',
61
+ reportDataStr,
62
+ ... jsList.map((it) => it.str),
63
+ '</script>'
64
+ ].join(EOL);
65
+ } else {
66
+
67
+ await Util.writeFile(path.resolve(outputDir, reportDataFile), reportDataStr);
68
+
69
+ const assetsDir = path.resolve(outputDir, assetsPath);
70
+ const relAssetsDir = Util.relativePath(assetsDir, outputDir);
71
+
72
+ for (const item of jsList) {
73
+ const filePath = path.resolve(assetsDir, item.filename);
74
+ if (!fs.existsSync(filePath)) {
75
+ await Util.writeFile(filePath, item.str);
76
+ }
77
+ }
78
+
79
+ htmlStr = [
80
+ `<script src="${reportDataFile}"></script>`,
81
+ ... jsList.map((it) => `<script src="${relAssetsDir}/${it.filename}"></script>`)
82
+ ].join(EOL);
83
+ }
84
+
85
+ // html
86
+ const template = Assets.getFileContent('template');
87
+ const html = Util.replace(template, {
88
+ title: reportData.title,
89
+ content: htmlStr
90
+ });
91
+
92
+ await Util.writeFile(htmlPath, html);
93
+
94
+ return reportPath;
95
+ }
96
+ };
97
+
98
+ module.exports = Assets;
@@ -19,7 +19,7 @@ const {
19
19
  const { getSourceType, initSourceMapSourcesPath } = require('../utils/source-path.js');
20
20
 
21
21
  const { decode } = require('@jridgewell/sourcemap-codec');
22
- const { minimatch } = require('minimatch');
22
+ const { minimatch } = require('../packages/monocart-coverage-vendor.js');
23
23
 
24
24
  const InfoBranch = require('./info-branch.js');
25
25
  const InfoFunction = require('./info-function.js');
@@ -66,8 +66,8 @@ const applyBytesToLines = (bytes, locator, lineMap) => {
66
66
  start, end, count, ignored
67
67
  } = range;
68
68
 
69
- // no need handle ignored and uncovered byte
70
- if (count === 0 && ignored) {
69
+ // no need handle ignored byte
70
+ if (ignored) {
71
71
  return;
72
72
  }
73
73
 
@@ -141,9 +141,8 @@ const handleLinesCoverage = (bytes, locator, ignoredRanges) => {
141
141
  return;
142
142
  }
143
143
 
144
- lineItem.coveredCount = 1;
145
- lineItem.uncoveredEntire = null;
146
- lineItem.uncoveredPieces = [];
144
+ Util.initLineCoverage(lineItem);
145
+
147
146
  lineMap.set(line, lineItem);
148
147
  });
149
148
 
@@ -282,8 +281,8 @@ const collectFileCoverage = (v8Data, state, options) => {
282
281
 
283
282
  // ==========================================
284
283
 
285
- data.functions = functions.map((info) => {
286
- return info.getRange();
284
+ data.functions = functions.map((info, i) => {
285
+ return info.getRange(i);
287
286
  });
288
287
  sortRanges(data.functions);
289
288
 
@@ -507,6 +506,11 @@ const handleGeneratedBytesCoverage = (state) => {
507
506
  if (js) {
508
507
  coverageList.forEach((block) => {
509
508
  block.ranges.forEach((range) => {
509
+
510
+ const { fixedStart, fixedEnd } = Util.fixSourceRange(state.locator, range.startOffset, range.endOffset);
511
+ range.startOffset = fixedStart;
512
+ range.endOffset = fixedEnd;
513
+
510
514
  addJsBytesCoverage(state, range);
511
515
  });
512
516
  });
@@ -555,7 +559,9 @@ const handleOriginalFunctionsCoverage = (state, originalStateMap) => {
555
559
  start, end, bodyStart, bodyEnd
556
560
  } = it;
557
561
 
558
- const result = findOriginalRange(start, end, state, originalStateMap);
562
+ const result = findOriginalRange(start, end, state, originalStateMap, {
563
+ checkName: true
564
+ });
559
565
  if (result.error) {
560
566
  logMappingErrors('function', result);
561
567
  return;
@@ -571,6 +577,10 @@ const handleOriginalFunctionsCoverage = (state, originalStateMap) => {
571
577
  bodyEnd: result.end
572
578
  };
573
579
 
580
+ if (result.name) {
581
+ originalFunction.functionName = result.name;
582
+ }
583
+
574
584
  // body start and end
575
585
  updateFunctionBodyRange(start, end, bodyStart, bodyEnd, originalFunction);
576
586
 
@@ -792,6 +802,7 @@ const handleOriginalEmptyBytesCoverage = (state, originalStateMap) => {
792
802
  });
793
803
  };
794
804
 
805
+
795
806
  const handleAllOriginalBytesCoverage = (state, originalStateMap) => {
796
807
 
797
808
  const { js, coverageList } = state;
@@ -814,7 +825,9 @@ const handleAllOriginalBytesCoverage = (state, originalStateMap) => {
814
825
  startOffset, endOffset, count
815
826
  } = range;
816
827
 
817
- const result = findOriginalRange(startOffset, endOffset, state, originalStateMap);
828
+ const result = findOriginalRange(startOffset, endOffset, state, originalStateMap, {
829
+ fixOriginalRange: true
830
+ });
818
831
  if (result.error) {
819
832
  logMappingErrors('byte', result);
820
833
  return;
@@ -863,7 +876,7 @@ const decodeSourceMappings = (state, originalDecodedMap) => {
863
876
  // const SOURCE_LINE = 2;
864
877
  // const SOURCE_COLUMN = 3;
865
878
  // const NAMES_INDEX = 4;
866
- const [generatedColumn, sourceIndex, originalLine, originalColumn] = segment;
879
+ const [generatedColumn, sourceIndex, originalLine, originalColumn, nameIndex] = segment;
867
880
  // the segment length could be 1, 4 or 5
868
881
 
869
882
  if (typeof sourceIndex === 'undefined') {
@@ -883,7 +896,8 @@ const decodeSourceMappings = (state, originalDecodedMap) => {
883
896
 
884
897
  sourceIndex,
885
898
  originalLine,
886
- originalColumn
899
+ originalColumn,
900
+ nameIndex
887
901
  };
888
902
 
889
903
  allDecodedMappings.push(info);
@@ -1102,6 +1116,8 @@ const unpackSourceMap = (state, options) => {
1102
1116
  const fileUrls = {};
1103
1117
  initSourceMapSourcesPath(fileUrls, sourceMap, sourcePath, options);
1104
1118
  state.fileUrls = fileUrls;
1119
+ // for function names
1120
+ state.sourceMapNames = sourceMap.names || [];
1105
1121
 
1106
1122
  // ===============================================
1107
1123
  // decode mappings for each original file
@@ -1496,6 +1512,14 @@ const generateV8DataList = (stateList, options) => {
1496
1512
  coverageData[sourcePath] = istanbulData;
1497
1513
  });
1498
1514
 
1515
+ // sort v8DataList (files)
1516
+ v8DataList.sort((a, b) => {
1517
+ if (a.sourcePath > b.sourcePath) {
1518
+ return 1;
1519
+ }
1520
+ return -1;
1521
+ });
1522
+
1499
1523
  return {
1500
1524
  v8DataList,
1501
1525
  fileSources,
@@ -1,4 +1,4 @@
1
- const diffSequence = require('diff-sequences').default;
1
+ const { diffSequence } = require('../packages/monocart-coverage-vendor.js');
2
2
  const Util = require('../utils/util.js');
3
3
  const EC = Util.EC;
4
4
 
@@ -534,8 +534,13 @@ const getGeneratedText = (m1, m2, state, offset) => {
534
534
  };
535
535
 
536
536
  // ========================================================================================================
537
+ const getFunctionName = (mp, state, options) => {
538
+ if (options.checkName && typeof mp.nameIndex !== 'undefined') {
539
+ return state.sourceMapNames[mp.nameIndex];
540
+ }
541
+ };
537
542
 
538
- const getFixedOriginalStart = (start, mappings, state, cache) => {
543
+ const getFixedOriginalStart = (start, mappings, state, cache, options) => {
539
544
 
540
545
  const [m1, m2] = mappings;
541
546
  const { originalState, crossStart } = cache;
@@ -543,7 +548,8 @@ const getFixedOriginalStart = (start, mappings, state, cache) => {
543
548
  // cross file from start of line
544
549
  if (crossStart) {
545
550
  return {
546
- originalStart: m2.originalOffset
551
+ originalStart: m2.originalOffset,
552
+ originalName: getFunctionName(m2, state, options)
547
553
  };
548
554
  }
549
555
 
@@ -574,7 +580,8 @@ const getFixedOriginalStart = (start, mappings, state, cache) => {
574
580
  // }
575
581
 
576
582
  return {
577
- originalStart: originalOffset + originalPos
583
+ originalStart: originalOffset + originalPos,
584
+ originalName: getFunctionName(m1, state, options)
578
585
  };
579
586
  };
580
587
 
@@ -635,17 +642,18 @@ const getFixedOriginalEnd = (end, mappings, state, cache) => {
635
642
 
636
643
  // ========================================================================================================
637
644
 
638
- const getOriginalStartPosition = (cache, state) => {
645
+ const getOriginalStartPosition = (cache, state, options) => {
639
646
 
640
647
  const { start, startMappings } = cache;
641
648
 
642
649
  if (Array.isArray(startMappings)) {
643
- return getFixedOriginalStart(start, startMappings, state, cache);
650
+ return getFixedOriginalStart(start, startMappings, state, cache, options);
644
651
  }
645
652
 
646
653
  // Exact match
647
654
  return {
648
- originalStart: startMappings.originalOffset
655
+ originalStart: startMappings.originalOffset,
656
+ originalName: getFunctionName(startMappings, state, options)
649
657
  };
650
658
  };
651
659
 
@@ -872,11 +880,12 @@ const getMappingInfo = (start, end, state) => {
872
880
  };
873
881
  };
874
882
 
875
- const findOriginalRange = (start, end, state, originalMap) => {
883
+
884
+ const findOriginalRange = (start, end, state, originalMap, options = {}) => {
876
885
 
877
886
  const { sourcePath, rangeCache } = state;
878
887
 
879
- const key = `${start}_${end}`;
888
+ const key = `${start}_${end}_${Boolean(options.fixOriginalRange)}`;
880
889
  if (rangeCache.has(key)) {
881
890
  return rangeCache.get(key);
882
891
  }
@@ -901,8 +910,8 @@ const findOriginalRange = (start, end, state, originalMap) => {
901
910
  return createMappingError(cache.errors);
902
911
  }
903
912
 
904
- const originalStartResult = getOriginalStartPosition(cache, state);
905
- const { originalStart } = originalStartResult;
913
+ const originalStartResult = getOriginalStartPosition(cache, state, options);
914
+ const { originalStart, originalName } = originalStartResult;
906
915
  // could be used for end
907
916
  cache.originalStart = originalStart;
908
917
 
@@ -918,19 +927,26 @@ const findOriginalRange = (start, end, state, originalMap) => {
918
927
  }
919
928
 
920
929
  const { originalState } = cache;
930
+ const locator = originalState.locator;
921
931
 
922
- const inComment = originalState.locator.lineParser.commentParser.isComment(originalStart, originalEnd);
932
+ const inComment = locator.lineParser.commentParser.isComment(originalStart, originalEnd);
923
933
  if (inComment) {
924
934
  return createMappingError(['the range in a original comment']);
925
935
  }
926
936
 
927
-
928
937
  const res = {
929
938
  start: originalStart,
930
939
  end: originalEnd,
940
+ name: originalName,
931
941
  originalState
932
942
  };
933
943
 
944
+ if (options.fixOriginalRange) {
945
+ const { fixedStart, fixedEnd } = Util.fixSourceRange(locator, originalStart, originalEnd);
946
+ res.start = fixedStart;
947
+ res.end = fixedEnd;
948
+ }
949
+
934
950
  // cache response
935
951
  rangeCache.set(key, res);
936
952