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 +6 -1
- package/README.zh-Hans.md +4 -1
- package/lib/assets.js +98 -0
- package/lib/converter/converter.js +36 -12
- package/lib/converter/find-original-range.js +29 -13
- package/lib/converter/flatten-source-maps.js +186 -166
- package/lib/converter/ignore.js +86 -24
- package/lib/converter/info-function.js +7 -4
- package/lib/generate.js +91 -476
- package/lib/index.d.ts +22 -1
- package/lib/istanbul/istanbul.js +11 -8
- package/lib/packages/monocart-coverage-assets.js +4 -0
- package/lib/packages/monocart-coverage-vendor.js +16 -16
- package/lib/platform/share.js +22 -0
- package/lib/reports/codacy.js +43 -0
- package/lib/reports/codecov.js +28 -0
- package/lib/reports/console-details.js +174 -0
- package/lib/reports/console-summary.js +83 -0
- package/lib/reports/custom.js +34 -0
- package/lib/reports/markdown-details.js +120 -0
- package/lib/reports/markdown-summary.js +44 -0
- package/lib/reports/raw.js +33 -0
- package/lib/reports/v8-json.js +22 -0
- package/lib/reports/v8.js +51 -0
- package/lib/utils/markdown.js +132 -132
- package/lib/utils/util.js +95 -155
- package/lib/v8/v8.js +16 -74
- package/package.json +116 -112
- package/lib/packages/monocart-coverage-app.js +0 -1
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
|

|
|
116
117
|
|
|
117
118
|
- `v8-json`
|
|
118
|
-
- [
|
|
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
|
+

|
|
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
|

|
|
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
|

|
|
116
117
|
|
|
117
118
|
- `v8-json`
|
|
118
|
-
-
|
|
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
|

|
|
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('
|
|
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
|
|
70
|
-
if (
|
|
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
|
|
145
|
-
|
|
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('
|
|
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
|
-
|
|
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 =
|
|
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
|
|