monocart-coverage-reports 2.2.1 → 2.3.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/README.md +142 -26
- package/lib/cli.js +0 -6
- package/lib/converter/ast.js +26 -5
- package/lib/converter/collect-source-maps.js +15 -3
- package/lib/converter/converter.js +318 -119
- package/lib/converter/find-original-range.js +5 -0
- package/lib/converter/info-branch.js +13 -5
- package/lib/default/options.js +3 -0
- package/lib/generate.js +151 -89
- package/lib/index.d.ts +15 -2
- package/lib/index.js +45 -15
- package/lib/istanbul/istanbul.js +9 -9
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/platform/share.js +13 -0
- package/lib/utils/dedupe.js +21 -8
- package/lib/utils/source-path.js +5 -0
- package/lib/utils/util.js +30 -1
- package/lib/v8/v8.js +149 -75
- package/package.json +6 -4
- package/lib/utils/decode-mappings-worker.js +0 -9
- package/lib/utils/decode-mappings.js +0 -35
|
@@ -1,27 +1,12 @@
|
|
|
1
|
-
// https://github.com/demurgos/v8-coverage
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
* @
|
|
5
|
-
*
|
|
6
|
-
* @true means that the ranges form a tree of blocks representing how many times each statement or expression inside was executed.
|
|
7
|
-
* It detects skipped or repeated statements. The root range counts the number of function calls.
|
|
8
|
-
* @functionName can be an empty string. This is common for the FunctionCov representing the whole module.
|
|
2
|
+
* V8 Coverage Data Converter
|
|
3
|
+
* @copyright https://github.com/cenfun/monocart-coverage-reports
|
|
4
|
+
* @author cenfun@gmail.com
|
|
9
5
|
*/
|
|
10
|
-
// https://github.com/bcoe/v8-coverage
|
|
11
|
-
/**
|
|
12
|
-
* @ranges is always non-empty. The first range is called the "root range".
|
|
13
|
-
* @isBlockCoverage indicates if the function has block coverage information.
|
|
14
|
-
If this is false, it usually means that the functions was never called.
|
|
15
|
-
It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
|
|
16
|
-
* @functionName can be an empty string. This is common for the FunctionCov representing the whole module.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
// if you have a line of code that says `var x= 10; console.log(x);` that's one line and 2 statements.
|
|
20
6
|
|
|
21
7
|
const path = require('path');
|
|
22
8
|
|
|
23
9
|
const Util = require('../utils/util.js');
|
|
24
|
-
const decodeMappings = require('../utils/decode-mappings.js');
|
|
25
10
|
|
|
26
11
|
// position mapping for conversion between offset and line/column
|
|
27
12
|
const { Locator } = require('monocart-formatter');
|
|
@@ -29,8 +14,11 @@ const findOriginalRange = require('./find-original-range.js');
|
|
|
29
14
|
const { getJsAstInfo, getCssAstInfo } = require('./ast.js');
|
|
30
15
|
const { getIgnoredRanges } = require('./ignore.js');
|
|
31
16
|
|
|
32
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
sortRanges, dedupeCountRanges, mergeRangesWith
|
|
19
|
+
} = require('../utils/dedupe.js');
|
|
33
20
|
const { getSourceType, initSourceMapSourcePath } = require('../utils/source-path.js');
|
|
21
|
+
const { decode } = require('../packages/monocart-coverage-vendor.js');
|
|
34
22
|
|
|
35
23
|
const InfoLine = require('./info-line.js');
|
|
36
24
|
const InfoBranch = require('./info-branch.js');
|
|
@@ -226,13 +214,14 @@ const calculateV8Lines = (lines, blankCount, commentCount) => {
|
|
|
226
214
|
* * `f` - hit count for functions
|
|
227
215
|
* * `b` - hit count for branches
|
|
228
216
|
*/
|
|
229
|
-
const collectFileCoverage = (
|
|
217
|
+
const collectFileCoverage = (v8Data, state, options) => {
|
|
230
218
|
|
|
231
|
-
const { sourcePath } = item;
|
|
232
219
|
const {
|
|
233
220
|
bytes,
|
|
234
221
|
functions,
|
|
235
222
|
branches,
|
|
223
|
+
|
|
224
|
+
sourcePath,
|
|
236
225
|
locator
|
|
237
226
|
} = state;
|
|
238
227
|
|
|
@@ -277,11 +266,13 @@ const collectFileCoverage = (item, state, coverageData, options) => {
|
|
|
277
266
|
data.functions = functions.map((info) => {
|
|
278
267
|
return info.getRange();
|
|
279
268
|
});
|
|
269
|
+
sortRanges(data.functions);
|
|
280
270
|
|
|
281
271
|
// branch group with locations to flat branches
|
|
282
272
|
data.branches = branches.map((info) => {
|
|
283
273
|
return info.getRanges();
|
|
284
274
|
}).flat();
|
|
275
|
+
sortRanges(data.branches);
|
|
285
276
|
|
|
286
277
|
// ==========================================
|
|
287
278
|
// lines
|
|
@@ -292,8 +283,8 @@ const collectFileCoverage = (item, state, coverageData, options) => {
|
|
|
292
283
|
|
|
293
284
|
// ==========================================
|
|
294
285
|
// v8 data and summary
|
|
295
|
-
|
|
296
|
-
|
|
286
|
+
v8Data.data = data;
|
|
287
|
+
v8Data.summary = {
|
|
297
288
|
functions: calculateV8Functions(data.functions),
|
|
298
289
|
branches: calculateV8Branches(data.branches),
|
|
299
290
|
lines: calculateV8Lines(lines, blankCount, commentCount)
|
|
@@ -301,7 +292,7 @@ const collectFileCoverage = (item, state, coverageData, options) => {
|
|
|
301
292
|
|
|
302
293
|
// ==========================================
|
|
303
294
|
// istanbul
|
|
304
|
-
const
|
|
295
|
+
const istanbulData = {
|
|
305
296
|
path: sourcePath,
|
|
306
297
|
|
|
307
298
|
statementMap: {},
|
|
@@ -313,24 +304,36 @@ const collectFileCoverage = (item, state, coverageData, options) => {
|
|
|
313
304
|
b: {}
|
|
314
305
|
};
|
|
315
306
|
|
|
307
|
+
// for codecov https://docs.codecov.com/docs/codecov-custom-coverage-format
|
|
308
|
+
data.lines = {};
|
|
309
|
+
|
|
316
310
|
lines.filter((it) => !it.ignored).forEach((line, index) => {
|
|
317
|
-
|
|
318
|
-
|
|
311
|
+
istanbulData.statementMap[`${index}`] = line.generate();
|
|
312
|
+
istanbulData.s[`${index}`] = line.count;
|
|
313
|
+
|
|
314
|
+
let count = 0;
|
|
315
|
+
if (line.covered) {
|
|
316
|
+
count = line.count;
|
|
317
|
+
} else if (!line.covered && line.count > 0) {
|
|
318
|
+
count = '1/2';
|
|
319
|
+
}
|
|
320
|
+
// 1-base
|
|
321
|
+
data.lines[`${line.line}`] = count;
|
|
319
322
|
});
|
|
320
323
|
|
|
321
324
|
functions.filter((it) => !it.ignored).forEach((fn, index) => {
|
|
322
|
-
|
|
323
|
-
|
|
325
|
+
istanbulData.fnMap[`${index}`] = fn.generate(locator);
|
|
326
|
+
istanbulData.f[`${index}`] = fn.count;
|
|
324
327
|
});
|
|
325
328
|
|
|
326
329
|
branches.filter((it) => !it.ignored).forEach((branch, index) => {
|
|
327
330
|
const { map, counts } = branch.generate(locator);
|
|
328
|
-
|
|
329
|
-
|
|
331
|
+
istanbulData.branchMap[`${index}`] = map;
|
|
332
|
+
istanbulData.b[`${index}`] = counts;
|
|
330
333
|
});
|
|
331
334
|
|
|
332
|
-
//
|
|
333
|
-
|
|
335
|
+
// istanbul data
|
|
336
|
+
return istanbulData;
|
|
334
337
|
|
|
335
338
|
};
|
|
336
339
|
|
|
@@ -600,13 +603,13 @@ const handleOriginalBytesCoverage = (state, originalMap) => {
|
|
|
600
603
|
|
|
601
604
|
// ========================================================================================================
|
|
602
605
|
|
|
603
|
-
const decodeSourceMappings =
|
|
606
|
+
const decodeSourceMappings = (state, originalDecodedMap) => {
|
|
604
607
|
|
|
605
608
|
const generatedLocator = state.locator;
|
|
606
609
|
|
|
607
610
|
const { sources, mappings } = state.sourceMap;
|
|
608
611
|
|
|
609
|
-
const decodedList =
|
|
612
|
+
const decodedList = decode(mappings);
|
|
610
613
|
|
|
611
614
|
sources.forEach((source, i) => {
|
|
612
615
|
originalDecodedMap.set(i, []);
|
|
@@ -667,7 +670,7 @@ const getOriginalDecodedMappings = (originalDecodedMap, sourceIndex, locator) =>
|
|
|
667
670
|
// all mappings for the original file sorted
|
|
668
671
|
const decodedMappings = originalDecodedMap.get(sourceIndex);
|
|
669
672
|
|
|
670
|
-
if (!
|
|
673
|
+
if (!decodedMappings) {
|
|
671
674
|
return [];
|
|
672
675
|
}
|
|
673
676
|
|
|
@@ -701,8 +704,6 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
701
704
|
sourceFilter = () => true;
|
|
702
705
|
}
|
|
703
706
|
|
|
704
|
-
const fileSources = state.fileSources;
|
|
705
|
-
|
|
706
707
|
// create original content mappings
|
|
707
708
|
const originalMap = new Map();
|
|
708
709
|
|
|
@@ -722,9 +723,6 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
722
723
|
return;
|
|
723
724
|
}
|
|
724
725
|
|
|
725
|
-
// keep original formatted content
|
|
726
|
-
fileSources[sourcePath] = sourceContent;
|
|
727
|
-
|
|
728
726
|
const locator = new Locator(sourceContent);
|
|
729
727
|
|
|
730
728
|
const decodedMappings = getOriginalDecodedMappings(originalDecodedMap, sourceIndex, locator);
|
|
@@ -735,11 +733,11 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
735
733
|
|
|
736
734
|
const originalState = {
|
|
737
735
|
original: true,
|
|
738
|
-
//
|
|
736
|
+
// original file is js
|
|
739
737
|
js: true,
|
|
740
738
|
type,
|
|
741
|
-
sourcePath,
|
|
742
739
|
source: sourceContent,
|
|
740
|
+
sourcePath,
|
|
743
741
|
locator,
|
|
744
742
|
decodedMappings,
|
|
745
743
|
// coverage info
|
|
@@ -749,7 +747,9 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
749
747
|
astInfo: {
|
|
750
748
|
functions: [],
|
|
751
749
|
branches: []
|
|
752
|
-
}
|
|
750
|
+
},
|
|
751
|
+
// coverage data
|
|
752
|
+
v8Data: {}
|
|
753
753
|
};
|
|
754
754
|
|
|
755
755
|
originalMap.set(sourceIndex, originalState);
|
|
@@ -758,14 +758,12 @@ const initOriginalList = (state, originalDecodedMap, options) => {
|
|
|
758
758
|
return originalMap;
|
|
759
759
|
};
|
|
760
760
|
|
|
761
|
-
const collectOriginalList = (
|
|
761
|
+
const collectOriginalList = (state, originalMap) => {
|
|
762
762
|
|
|
763
763
|
const { fileUrls, sourceMap } = state;
|
|
764
|
-
const distFile = sourceMap.file || path.basename(
|
|
764
|
+
const distFile = sourceMap.file || path.basename(state.sourcePath);
|
|
765
765
|
|
|
766
766
|
// collect original files
|
|
767
|
-
const sourceList = [];
|
|
768
|
-
|
|
769
767
|
originalMap.forEach((originalState) => {
|
|
770
768
|
|
|
771
769
|
const {
|
|
@@ -776,7 +774,7 @@ const collectOriginalList = (item, state, originalMap, options) => {
|
|
|
776
774
|
const url = fileUrls[sourcePath] || sourcePath;
|
|
777
775
|
|
|
778
776
|
// add dist for id
|
|
779
|
-
const id = Util.calculateSha1(
|
|
777
|
+
const id = Util.calculateSha1(sourcePath + source);
|
|
780
778
|
|
|
781
779
|
const sourceItem = {
|
|
782
780
|
url,
|
|
@@ -788,31 +786,26 @@ const collectOriginalList = (item, state, originalMap, options) => {
|
|
|
788
786
|
source
|
|
789
787
|
};
|
|
790
788
|
|
|
791
|
-
//
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
sourceList.push(sourceItem);
|
|
789
|
+
// save v8 data and add to originalList
|
|
790
|
+
originalState.v8Data = sourceItem;
|
|
791
|
+
state.originalList.push(originalState);
|
|
795
792
|
});
|
|
796
793
|
|
|
797
|
-
return sourceList;
|
|
798
794
|
};
|
|
799
795
|
|
|
800
796
|
// ========================================================================================================
|
|
801
797
|
|
|
802
|
-
const generateCoverageForDist = (
|
|
798
|
+
const generateCoverageForDist = (state) => {
|
|
803
799
|
|
|
804
800
|
handleFunctionsCoverage(state);
|
|
805
801
|
handleBranchesCoverage(state);
|
|
806
802
|
handleBytesCoverage(state);
|
|
807
803
|
|
|
808
|
-
collectFileCoverage(item, state, state.coverageData, options);
|
|
809
|
-
|
|
810
804
|
};
|
|
811
805
|
|
|
812
|
-
const unpackSourceMap =
|
|
806
|
+
const unpackSourceMap = (state, options) => {
|
|
813
807
|
|
|
814
|
-
const {
|
|
815
|
-
const sourceMap = state.sourceMap;
|
|
808
|
+
const { sourceMap } = state;
|
|
816
809
|
|
|
817
810
|
// keep original urls
|
|
818
811
|
const fileUrls = {};
|
|
@@ -822,12 +815,10 @@ const unpackSourceMap = async (item, state, options) => {
|
|
|
822
815
|
|
|
823
816
|
// ===============================================
|
|
824
817
|
// decode mappings for each original file
|
|
825
|
-
|
|
818
|
+
|
|
826
819
|
const originalDecodedMap = new Map();
|
|
827
820
|
// for find-original-range
|
|
828
|
-
state.decodedMappings =
|
|
829
|
-
// only debug level
|
|
830
|
-
Util.logTime(`decode source mappings: ${sourcePath}`, time_start_decode);
|
|
821
|
+
state.decodedMappings = decodeSourceMappings(state, originalDecodedMap);
|
|
831
822
|
|
|
832
823
|
// filter original list and init list
|
|
833
824
|
const originalMap = initOriginalList(state, originalDecodedMap, options);
|
|
@@ -856,28 +847,28 @@ const unpackSourceMap = async (item, state, options) => {
|
|
|
856
847
|
handleOriginalBytesCoverage(state, originalMap);
|
|
857
848
|
|
|
858
849
|
// collect coverage for original list
|
|
859
|
-
|
|
850
|
+
collectOriginalList(state, originalMap);
|
|
860
851
|
|
|
861
852
|
};
|
|
862
853
|
|
|
863
|
-
const unpackDistFile =
|
|
854
|
+
const unpackDistFile = (item, state, options) => {
|
|
864
855
|
|
|
865
856
|
if (state.sourceMap) {
|
|
866
857
|
if (Util.loggingType === 'debug') {
|
|
867
858
|
// js self
|
|
868
859
|
item.debug = true;
|
|
869
|
-
generateCoverageForDist(
|
|
860
|
+
generateCoverageForDist(state);
|
|
870
861
|
} else {
|
|
871
862
|
item.dedupe = true;
|
|
872
863
|
}
|
|
873
864
|
|
|
874
865
|
// unpack source map
|
|
875
|
-
|
|
866
|
+
unpackSourceMap(state, options);
|
|
876
867
|
|
|
877
868
|
} else {
|
|
878
869
|
|
|
879
870
|
// css/js self
|
|
880
|
-
generateCoverageForDist(
|
|
871
|
+
generateCoverageForDist(state);
|
|
881
872
|
|
|
882
873
|
}
|
|
883
874
|
|
|
@@ -885,27 +876,260 @@ const unpackDistFile = async (item, state, options) => {
|
|
|
885
876
|
|
|
886
877
|
// ========================================================================================================
|
|
887
878
|
|
|
888
|
-
const
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
879
|
+
const filterCoverageList = (item) => {
|
|
880
|
+
const {
|
|
881
|
+
functions, scriptOffset, source
|
|
882
|
+
} = item;
|
|
883
|
+
|
|
884
|
+
// no script offset
|
|
885
|
+
if (!scriptOffset) {
|
|
886
|
+
return functions;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
// vm script offset
|
|
890
|
+
const minOffset = scriptOffset;
|
|
891
|
+
// the inline sourcemap could be removed
|
|
892
|
+
const maxOffset = source.length;
|
|
893
|
+
|
|
894
|
+
const rootFunctionInfo = {
|
|
895
|
+
root: true,
|
|
896
|
+
ranges: [{
|
|
897
|
+
startOffset: minOffset,
|
|
898
|
+
endOffset: maxOffset,
|
|
899
|
+
count: 1
|
|
900
|
+
}]
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
const coverageList = functions.filter((block) => {
|
|
904
|
+
const { ranges } = block;
|
|
905
|
+
|
|
906
|
+
// first one is function coverage info
|
|
907
|
+
const functionRange = ranges[0];
|
|
908
|
+
const { startOffset, endOffset } = functionRange;
|
|
909
|
+
if (startOffset >= minOffset && endOffset <= maxOffset) {
|
|
910
|
+
return true;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// blocks
|
|
914
|
+
const len = ranges.length;
|
|
915
|
+
if (len > 1) {
|
|
916
|
+
for (let i = 1; i < len; i++) {
|
|
917
|
+
const range = ranges[i];
|
|
918
|
+
if (range.startOffset >= minOffset && range.endOffset <= maxOffset) {
|
|
919
|
+
rootFunctionInfo.ranges.push(range);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
893
922
|
}
|
|
923
|
+
|
|
924
|
+
return false;
|
|
894
925
|
});
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
});
|
|
926
|
+
|
|
927
|
+
// first one for root function
|
|
928
|
+
if (rootFunctionInfo.ranges.length > 1) {
|
|
929
|
+
coverageList.unshift(rootFunctionInfo);
|
|
900
930
|
}
|
|
931
|
+
|
|
932
|
+
return coverageList;
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
// ========================================================================================================
|
|
936
|
+
|
|
937
|
+
const isCoveredInRanges = (range, uncoveredBytes) => {
|
|
938
|
+
if (!uncoveredBytes.length) {
|
|
939
|
+
return true;
|
|
940
|
+
}
|
|
941
|
+
for (const item of uncoveredBytes) {
|
|
942
|
+
if (range.start >= item.start && range.end <= item.end) {
|
|
943
|
+
return false;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
return true;
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
const mergeV8Data = (state, stateList) => {
|
|
950
|
+
// console.log(stateList);
|
|
951
|
+
|
|
952
|
+
// const sourcePath = state.sourcePath;
|
|
953
|
+
// console.log(sourcePath);
|
|
954
|
+
// if (sourcePath.endsWith('scroll_zoom.ts')) {
|
|
955
|
+
// console.log('merge v8 data ===================================', sourcePath);
|
|
956
|
+
// console.log(stateList.map((it) => it.bytes));
|
|
957
|
+
// console.log(stateList.map((it) => it.functions));
|
|
958
|
+
// console.log(stateList.map((it) => it.branches.map((b) => [`${b.start}-${b.end}`, JSON.stringify(b.locations.map((l) => l.count))])));
|
|
959
|
+
// }
|
|
960
|
+
|
|
961
|
+
// ===========================================================
|
|
962
|
+
// bytes
|
|
963
|
+
const mergedBytes = [];
|
|
964
|
+
const uncoveredList = [];
|
|
965
|
+
stateList.forEach((st) => {
|
|
966
|
+
const bytes = dedupeCountRanges(st.bytes);
|
|
967
|
+
const uncoveredBytes = [];
|
|
968
|
+
bytes.forEach((range) => {
|
|
969
|
+
if (range.count) {
|
|
970
|
+
mergedBytes.push(range);
|
|
971
|
+
} else {
|
|
972
|
+
uncoveredBytes.push(range);
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
uncoveredList.push(uncoveredBytes);
|
|
976
|
+
});
|
|
977
|
+
// just remove uncovered range
|
|
978
|
+
uncoveredList.forEach((currentBytes) => {
|
|
979
|
+
currentBytes.forEach((range) => {
|
|
980
|
+
for (const targetBytes of uncoveredList) {
|
|
981
|
+
if (targetBytes === currentBytes) {
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
if (isCoveredInRanges(range, targetBytes)) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
mergedBytes.push(range);
|
|
989
|
+
});
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
// will be dedupeCountRanges in collectFileCoverage
|
|
993
|
+
state.bytes = mergedBytes;
|
|
994
|
+
|
|
995
|
+
// ===========================================================
|
|
996
|
+
// functions
|
|
997
|
+
const allFunctions = stateList.map((it) => it.functions).flat();
|
|
998
|
+
const functionComparer = (lastRange, range) => {
|
|
999
|
+
// if (lastRange.start === range.start && lastRange.end === range.end) {
|
|
1000
|
+
// return true;
|
|
1001
|
+
// }
|
|
1002
|
+
|
|
1003
|
+
// function range could be from sourcemap, not exact matched
|
|
1004
|
+
|
|
1005
|
+
// end is same
|
|
1006
|
+
// {start: 2017, end: 2315, count: 481}
|
|
1007
|
+
// {start: 2018, end: 2315, count: 14}
|
|
1008
|
+
|
|
1009
|
+
// start is same
|
|
1010
|
+
// {start: 10204, end: 10379, count: 0}
|
|
1011
|
+
// {start: 10204, end: 10393, count: 5}
|
|
1012
|
+
|
|
1013
|
+
// only one position matched could be same
|
|
1014
|
+
if (lastRange.start === range.start || lastRange.end === range.end) {
|
|
1015
|
+
// console.log(lastRange.start, range.start, lastRange.end, range.end);
|
|
1016
|
+
|
|
1017
|
+
// if (lastRange.start === range.start) {
|
|
1018
|
+
// console.log(range.end - lastRange.end, lastRange.start, lastRange.end, 'end', range.end, state.sourcePath);
|
|
1019
|
+
// } else {
|
|
1020
|
+
// console.log(range.start - lastRange.start, lastRange.start, lastRange.end, 'start', range.start, state.sourcePath);
|
|
1021
|
+
// }
|
|
1022
|
+
|
|
1023
|
+
return true;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
return false;
|
|
1027
|
+
};
|
|
1028
|
+
const functionHandler = (lastRange, range) => {
|
|
1029
|
+
lastRange.count += range.count;
|
|
1030
|
+
};
|
|
1031
|
+
const mergedFunctions = mergeRangesWith(allFunctions, functionComparer, functionHandler);
|
|
1032
|
+
state.functions = mergedFunctions;
|
|
1033
|
+
|
|
1034
|
+
// ===========================================================
|
|
1035
|
+
// branches
|
|
1036
|
+
const allBranches = stateList.map((it) => it.branches).flat();
|
|
1037
|
+
const branchComparer = (lastRange, range) => {
|
|
1038
|
+
// exact matched because the branch range is generated from ast
|
|
1039
|
+
return lastRange.start === range.start && lastRange.end === range.end;
|
|
1040
|
+
};
|
|
1041
|
+
const branchHandler = (lastRange, range) => {
|
|
1042
|
+
// merge locations count
|
|
1043
|
+
lastRange.locations.forEach((item, i) => {
|
|
1044
|
+
const loc = range.locations[i];
|
|
1045
|
+
if (loc) {
|
|
1046
|
+
item.count += loc.count;
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
};
|
|
1050
|
+
const mergedBranches = mergeRangesWith(allBranches, branchComparer, branchHandler);
|
|
1051
|
+
state.branches = mergedBranches;
|
|
1052
|
+
|
|
1053
|
+
// if (sourcePath.endsWith('scroll_zoom.ts')) {
|
|
1054
|
+
// console.log(mergedBytes);
|
|
1055
|
+
// console.log(mergedFunctions);
|
|
1056
|
+
// console.log(mergedBranches.map((b) => [`${b.start}-${b.end}`, JSON.stringify(b.locations.map((l) => l.count))]));
|
|
1057
|
+
// }
|
|
1058
|
+
|
|
1059
|
+
|
|
901
1060
|
};
|
|
902
1061
|
|
|
903
|
-
const
|
|
1062
|
+
const generateV8DataList = (stateList, options) => {
|
|
1063
|
+
|
|
1064
|
+
const stateMap = new Map();
|
|
1065
|
+
|
|
1066
|
+
// all original files from dist
|
|
1067
|
+
const allOriginalList = [];
|
|
1068
|
+
stateList.forEach((state) => {
|
|
1069
|
+
const { v8Data, originalList } = state;
|
|
1070
|
+
// dedupe dist file if not debug
|
|
1071
|
+
if (!v8Data.dedupe) {
|
|
1072
|
+
stateMap.set(v8Data.id, state);
|
|
1073
|
+
}
|
|
1074
|
+
allOriginalList.push(originalList);
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
// merge istanbul and v8(converted)
|
|
1078
|
+
const mergeMap = new Map();
|
|
1079
|
+
allOriginalList.flat().forEach((originalState) => {
|
|
1080
|
+
const { v8Data } = originalState;
|
|
1081
|
+
const id = v8Data.id;
|
|
1082
|
+
// exists item
|
|
1083
|
+
const prevState = stateMap.get(id);
|
|
1084
|
+
if (prevState) {
|
|
1085
|
+
// ignore empty item, just override it
|
|
1086
|
+
if (!prevState.v8Data.empty) {
|
|
1087
|
+
if (mergeMap.has(id)) {
|
|
1088
|
+
mergeMap.get(id).push(originalState);
|
|
1089
|
+
} else {
|
|
1090
|
+
mergeMap.set(id, [prevState, originalState]);
|
|
1091
|
+
}
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
stateMap.set(id, originalState);
|
|
1096
|
+
});
|
|
904
1097
|
|
|
905
|
-
|
|
1098
|
+
const mergeIds = mergeMap.keys();
|
|
1099
|
+
for (const id of mergeIds) {
|
|
1100
|
+
const state = stateMap.get(id);
|
|
1101
|
+
// for source the type could be ts, so just use js (boolean)
|
|
1102
|
+
if (state.js) {
|
|
1103
|
+
mergeV8Data(state, mergeMap.get(id));
|
|
1104
|
+
} else {
|
|
1105
|
+
// should no css here, css can not be in sources
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
// new v8 data list (includes sources)
|
|
1110
|
+
const v8DataList = [];
|
|
1111
|
+
// global file sources and istanbul coverage data
|
|
906
1112
|
const fileSources = {};
|
|
907
1113
|
const coverageData = {};
|
|
908
|
-
|
|
1114
|
+
stateMap.forEach((state) => {
|
|
1115
|
+
const { v8Data } = state;
|
|
1116
|
+
const istanbulData = collectFileCoverage(v8Data, state, options);
|
|
1117
|
+
const { sourcePath, source } = v8Data;
|
|
1118
|
+
v8DataList.push(v8Data);
|
|
1119
|
+
fileSources[sourcePath] = source;
|
|
1120
|
+
coverageData[sourcePath] = istanbulData;
|
|
1121
|
+
});
|
|
1122
|
+
|
|
1123
|
+
return {
|
|
1124
|
+
v8DataList,
|
|
1125
|
+
fileSources,
|
|
1126
|
+
coverageData
|
|
1127
|
+
};
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
const convertV8List = (v8list, options) => {
|
|
1131
|
+
|
|
1132
|
+
const stateList = [];
|
|
909
1133
|
|
|
910
1134
|
for (const item of v8list) {
|
|
911
1135
|
// console.log([item.id]);
|
|
@@ -918,14 +1142,11 @@ const convertV8List = async (v8list, options) => {
|
|
|
918
1142
|
const js = type === 'js';
|
|
919
1143
|
item.js = js;
|
|
920
1144
|
|
|
921
|
-
// append file source
|
|
922
|
-
fileSources[sourcePath] = source;
|
|
923
|
-
|
|
924
1145
|
// source mapping
|
|
925
1146
|
const locator = new Locator(source);
|
|
926
1147
|
|
|
927
1148
|
// ============================
|
|
928
|
-
// move
|
|
1149
|
+
// move sourceMap
|
|
929
1150
|
const sourceMap = item.sourceMap;
|
|
930
1151
|
if (sourceMap) {
|
|
931
1152
|
delete item.sourceMap;
|
|
@@ -936,7 +1157,7 @@ const convertV8List = async (v8list, options) => {
|
|
|
936
1157
|
let coverageList = [];
|
|
937
1158
|
let astInfo;
|
|
938
1159
|
if (js) {
|
|
939
|
-
coverageList = item
|
|
1160
|
+
coverageList = filterCoverageList(item);
|
|
940
1161
|
// remove original functions
|
|
941
1162
|
if (Util.loggingType !== 'debug') {
|
|
942
1163
|
delete item.functions;
|
|
@@ -954,56 +1175,34 @@ const convertV8List = async (v8list, options) => {
|
|
|
954
1175
|
// ============================
|
|
955
1176
|
|
|
956
1177
|
// current file and it's sources from sourceMap
|
|
1178
|
+
// see const originalState
|
|
957
1179
|
const state = {
|
|
958
1180
|
js,
|
|
959
1181
|
type,
|
|
1182
|
+
source,
|
|
960
1183
|
sourcePath,
|
|
961
1184
|
sourceMap,
|
|
962
|
-
coverageList,
|
|
963
1185
|
locator,
|
|
1186
|
+
decodedMappings: [],
|
|
964
1187
|
// coverage info
|
|
965
1188
|
bytes: [],
|
|
966
1189
|
functions: [],
|
|
967
1190
|
branches: [],
|
|
968
1191
|
astInfo,
|
|
969
|
-
// for
|
|
970
|
-
|
|
971
|
-
|
|
1192
|
+
// for sub source files
|
|
1193
|
+
coverageList,
|
|
1194
|
+
originalList: [],
|
|
1195
|
+
// coverage data
|
|
1196
|
+
v8Data: item
|
|
972
1197
|
};
|
|
973
1198
|
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
// merge state
|
|
977
|
-
Object.assign(fileSources, state.fileSources);
|
|
978
|
-
Object.assign(coverageData, state.coverageData);
|
|
979
|
-
|
|
980
|
-
if (Util.isList(state.sourceList)) {
|
|
981
|
-
sourceList = sourceList.concat(state.sourceList);
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
// add all sources
|
|
987
|
-
if (sourceList.length) {
|
|
988
|
-
sourceList.forEach((item) => {
|
|
1199
|
+
unpackDistFile(item, state, options);
|
|
989
1200
|
|
|
990
|
-
|
|
991
|
-
const prevItem = v8list.find((it) => it.id === item.id);
|
|
992
|
-
if (prevItem) {
|
|
993
|
-
prevItem.dedupe = true;
|
|
994
|
-
}
|
|
1201
|
+
stateList.push(state);
|
|
995
1202
|
|
|
996
|
-
v8list.push(item);
|
|
997
|
-
});
|
|
998
1203
|
}
|
|
999
1204
|
|
|
1000
|
-
|
|
1001
|
-
dedupeV8List(v8list);
|
|
1002
|
-
|
|
1003
|
-
return {
|
|
1004
|
-
fileSources,
|
|
1005
|
-
coverageData
|
|
1006
|
-
};
|
|
1205
|
+
return generateV8DataList(stateList, options);
|
|
1007
1206
|
|
|
1008
1207
|
};
|
|
1009
1208
|
|
|
@@ -545,6 +545,11 @@ const findEndMapping = (range, state, startMapping) => {
|
|
|
545
545
|
|
|
546
546
|
const findOriginalRange = (range, state, originalMap) => {
|
|
547
547
|
|
|
548
|
+
// if (typeof range.startOffset !== 'number') {
|
|
549
|
+
// console.log('=========================================================================', state.sourcePath);
|
|
550
|
+
// console.log(range);
|
|
551
|
+
// }
|
|
552
|
+
|
|
548
553
|
// startOffset: inclusive
|
|
549
554
|
// endOffset: exclusive
|
|
550
555
|
const startResult = findStartMapping(range, state, originalMap);
|