monocart-coverage-reports 2.2.2 → 2.3.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.
@@ -1,27 +1,9 @@
1
- // https://github.com/demurgos/v8-coverage
2
1
  /**
3
- * @ranges is always non-empty. The first range is called the "root range".
4
- * @isBlockCoverage indicates if the function has block coverage information
5
- * @false means that there is a single range and its count is the number of times the function was called.
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
-
21
- const path = require('path');
22
-
23
6
  const Util = require('../utils/util.js');
24
- const decodeMappings = require('../utils/decode-mappings.js');
25
7
 
26
8
  // position mapping for conversion between offset and line/column
27
9
  const { Locator } = require('monocart-formatter');
@@ -29,8 +11,11 @@ const findOriginalRange = require('./find-original-range.js');
29
11
  const { getJsAstInfo, getCssAstInfo } = require('./ast.js');
30
12
  const { getIgnoredRanges } = require('./ignore.js');
31
13
 
32
- const { dedupeCountRanges } = require('../utils/dedupe.js');
14
+ const {
15
+ sortRanges, dedupeCountRanges, mergeRangesWith
16
+ } = require('../utils/dedupe.js');
33
17
  const { getSourceType, initSourceMapSourcePath } = require('../utils/source-path.js');
18
+ const { decode } = require('../packages/monocart-coverage-vendor.js');
34
19
 
35
20
  const InfoLine = require('./info-line.js');
36
21
  const InfoBranch = require('./info-branch.js');
@@ -226,13 +211,14 @@ const calculateV8Lines = (lines, blankCount, commentCount) => {
226
211
  * * `f` - hit count for functions
227
212
  * * `b` - hit count for branches
228
213
  */
229
- const collectFileCoverage = (item, state, coverageData, options) => {
214
+ const collectFileCoverage = (v8Data, state, options) => {
230
215
 
231
- const { sourcePath } = item;
232
216
  const {
233
217
  bytes,
234
218
  functions,
235
219
  branches,
220
+
221
+ sourcePath,
236
222
  locator
237
223
  } = state;
238
224
 
@@ -277,11 +263,13 @@ const collectFileCoverage = (item, state, coverageData, options) => {
277
263
  data.functions = functions.map((info) => {
278
264
  return info.getRange();
279
265
  });
266
+ sortRanges(data.functions);
280
267
 
281
268
  // branch group with locations to flat branches
282
269
  data.branches = branches.map((info) => {
283
270
  return info.getRanges();
284
271
  }).flat();
272
+ sortRanges(data.branches);
285
273
 
286
274
  // ==========================================
287
275
  // lines
@@ -292,8 +280,8 @@ const collectFileCoverage = (item, state, coverageData, options) => {
292
280
 
293
281
  // ==========================================
294
282
  // v8 data and summary
295
- item.data = data;
296
- item.summary = {
283
+ v8Data.data = data;
284
+ v8Data.summary = {
297
285
  functions: calculateV8Functions(data.functions),
298
286
  branches: calculateV8Branches(data.branches),
299
287
  lines: calculateV8Lines(lines, blankCount, commentCount)
@@ -301,7 +289,7 @@ const collectFileCoverage = (item, state, coverageData, options) => {
301
289
 
302
290
  // ==========================================
303
291
  // istanbul
304
- const istanbulCoverage = {
292
+ const istanbulData = {
305
293
  path: sourcePath,
306
294
 
307
295
  statementMap: {},
@@ -317,8 +305,8 @@ const collectFileCoverage = (item, state, coverageData, options) => {
317
305
  data.lines = {};
318
306
 
319
307
  lines.filter((it) => !it.ignored).forEach((line, index) => {
320
- istanbulCoverage.statementMap[`${index}`] = line.generate();
321
- istanbulCoverage.s[`${index}`] = line.count;
308
+ istanbulData.statementMap[`${index}`] = line.generate();
309
+ istanbulData.s[`${index}`] = line.count;
322
310
 
323
311
  let count = 0;
324
312
  if (line.covered) {
@@ -331,18 +319,18 @@ const collectFileCoverage = (item, state, coverageData, options) => {
331
319
  });
332
320
 
333
321
  functions.filter((it) => !it.ignored).forEach((fn, index) => {
334
- istanbulCoverage.fnMap[`${index}`] = fn.generate(locator);
335
- istanbulCoverage.f[`${index}`] = fn.count;
322
+ istanbulData.fnMap[`${index}`] = fn.generate(locator);
323
+ istanbulData.f[`${index}`] = fn.count;
336
324
  });
337
325
 
338
326
  branches.filter((it) => !it.ignored).forEach((branch, index) => {
339
327
  const { map, counts } = branch.generate(locator);
340
- istanbulCoverage.branchMap[`${index}`] = map;
341
- istanbulCoverage.b[`${index}`] = counts;
328
+ istanbulData.branchMap[`${index}`] = map;
329
+ istanbulData.b[`${index}`] = counts;
342
330
  });
343
331
 
344
- // append to dist file state
345
- coverageData[sourcePath] = istanbulCoverage;
332
+ // istanbul data
333
+ return istanbulData;
346
334
 
347
335
  };
348
336
 
@@ -430,7 +418,7 @@ const handleBytesCoverage = (state) => {
430
418
 
431
419
  // ========================================================================================================
432
420
 
433
- const handleOriginalFunctionsCoverage = (state, originalMap) => {
421
+ const handleOriginalFunctionsCoverage = (state, originalStateMap) => {
434
422
 
435
423
  // functions only for js
436
424
  if (!state.js) {
@@ -456,7 +444,7 @@ const handleOriginalFunctionsCoverage = (state, originalMap) => {
456
444
  endOffset: end
457
445
  };
458
446
 
459
- const result = findOriginalRange(range, state, originalMap);
447
+ const result = findOriginalRange(range, state, originalStateMap);
460
448
  if (result.error) {
461
449
  return;
462
450
  }
@@ -480,7 +468,7 @@ const handleOriginalFunctionsCoverage = (state, originalMap) => {
480
468
 
481
469
  };
482
470
 
483
- const handleOriginalBranchesCoverage = (state, originalMap) => {
471
+ const handleOriginalBranchesCoverage = (state, originalStateMap) => {
484
472
 
485
473
  // branches only for js
486
474
  if (!state.js) {
@@ -501,7 +489,7 @@ const handleOriginalBranchesCoverage = (state, originalMap) => {
501
489
  };
502
490
 
503
491
  // start
504
- const result = findOriginalRange(bRange, state, originalMap);
492
+ const result = findOriginalRange(bRange, state, originalStateMap);
505
493
  if (result.error) {
506
494
  // not in the original files
507
495
  return;
@@ -530,7 +518,7 @@ const handleOriginalBranchesCoverage = (state, originalMap) => {
530
518
  startOffset: start,
531
519
  endOffset: end
532
520
  };
533
- const res = findOriginalRange(lRange, state, originalMap);
521
+ const res = findOriginalRange(lRange, state, originalStateMap);
534
522
  if (res.error) {
535
523
  // It should not happen unless it is minify files, the SourceMap has some order problems
536
524
 
@@ -568,7 +556,7 @@ const handleOriginalBranchesCoverage = (state, originalMap) => {
568
556
 
569
557
  };
570
558
 
571
- const handleOriginalBytesCoverage = (state, originalMap) => {
559
+ const handleOriginalBytesCoverage = (state, originalStateMap) => {
572
560
 
573
561
  const { js, coverageList } = state;
574
562
 
@@ -584,7 +572,7 @@ const handleOriginalBytesCoverage = (state, originalMap) => {
584
572
  return;
585
573
  }
586
574
 
587
- const result = findOriginalRange(range, state, originalMap);
575
+ const result = findOriginalRange(range, state, originalStateMap);
588
576
  if (result.error) {
589
577
  return;
590
578
  }
@@ -608,17 +596,58 @@ const handleOriginalBytesCoverage = (state, originalMap) => {
608
596
  // });
609
597
  }
610
598
 
599
+ // check original bytes if fully in a wrapper range
600
+ originalStateMap.forEach((originalState) => {
601
+ const bytes = originalState.bytes;
602
+ if (Util.isList(bytes)) {
603
+ return;
604
+ }
605
+
606
+ const { decodedMappings } = originalState;
607
+ const len = decodedMappings.length;
608
+ if (len < 2) {
609
+ return;
610
+ }
611
+ // sort by original line/column
612
+ const startMapping = decodedMappings[0];
613
+ const endMapping = decodedMappings[len - 1];
614
+ // console.log(startMapping, endMapping);
615
+ const startOffset = startMapping.generatedOffset;
616
+ const endOffset = endMapping.generatedEndOffset || endMapping.generatedOffset;
617
+
618
+ // console.log('===========================================================', originalState.sourcePath);
619
+ // console.log(originalState.source.length, endMapping);
620
+
621
+ // only check uncovered range
622
+ // because a uncovered range could be in a covered wrapper
623
+ // { start: 0, end: 12137, count: 1 }, could be { start: > 0, end: < 12137, count: 0 }
624
+ for (const range of state.bytes) {
625
+ if (range.count > 0) {
626
+ continue;
627
+ }
628
+ if (startOffset >= range.start && endOffset <= range.end) {
629
+ bytes.push({
630
+ start: 0,
631
+ end: originalState.source.length,
632
+ count: 0
633
+ });
634
+ break;
635
+ }
636
+ }
637
+
638
+ });
639
+
611
640
  };
612
641
 
613
642
  // ========================================================================================================
614
643
 
615
- const decodeSourceMappings = async (state, originalDecodedMap) => {
644
+ const decodeSourceMappings = (state, originalDecodedMap) => {
616
645
 
617
646
  const generatedLocator = state.locator;
618
647
 
619
648
  const { sources, mappings } = state.sourceMap;
620
649
 
621
- const decodedList = await decodeMappings(mappings);
650
+ const decodedList = decode(mappings);
622
651
 
623
652
  sources.forEach((source, i) => {
624
653
  originalDecodedMap.set(i, []);
@@ -679,7 +708,7 @@ const getOriginalDecodedMappings = (originalDecodedMap, sourceIndex, locator) =>
679
708
  // all mappings for the original file sorted
680
709
  const decodedMappings = originalDecodedMap.get(sourceIndex);
681
710
 
682
- if (!decodeMappings) {
711
+ if (!decodedMappings) {
683
712
  return [];
684
713
  }
685
714
 
@@ -713,10 +742,8 @@ const initOriginalList = (state, originalDecodedMap, options) => {
713
742
  sourceFilter = () => true;
714
743
  }
715
744
 
716
- const fileSources = state.fileSources;
717
-
718
745
  // create original content mappings
719
- const originalMap = new Map();
746
+ const originalStateMap = new Map();
720
747
 
721
748
  const { sources, sourcesContent } = state.sourceMap;
722
749
 
@@ -734,9 +761,6 @@ const initOriginalList = (state, originalDecodedMap, options) => {
734
761
  return;
735
762
  }
736
763
 
737
- // keep original formatted content
738
- fileSources[sourcePath] = sourceContent;
739
-
740
764
  const locator = new Locator(sourceContent);
741
765
 
742
766
  const decodedMappings = getOriginalDecodedMappings(originalDecodedMap, sourceIndex, locator);
@@ -747,11 +771,11 @@ const initOriginalList = (state, originalDecodedMap, options) => {
747
771
 
748
772
  const originalState = {
749
773
  original: true,
750
- // only js sourceMap for now
774
+ // original file is js
751
775
  js: true,
752
776
  type,
753
- sourcePath,
754
777
  source: sourceContent,
778
+ sourcePath,
755
779
  locator,
756
780
  decodedMappings,
757
781
  // coverage info
@@ -761,24 +785,24 @@ const initOriginalList = (state, originalDecodedMap, options) => {
761
785
  astInfo: {
762
786
  functions: [],
763
787
  branches: []
764
- }
788
+ },
789
+ // coverage data
790
+ v8Data: {}
765
791
  };
766
792
 
767
- originalMap.set(sourceIndex, originalState);
793
+ originalStateMap.set(sourceIndex, originalState);
768
794
  });
769
795
 
770
- return originalMap;
796
+ return originalStateMap;
771
797
  };
772
798
 
773
- const collectOriginalList = (item, state, originalMap, options) => {
799
+ const collectOriginalList = (state, originalStateMap) => {
774
800
 
775
- const { fileUrls, sourceMap } = state;
776
- const distFile = sourceMap.file || path.basename(item.sourcePath);
801
+ const { fileUrls } = state;
802
+ const distFile = state.sourcePath;
777
803
 
778
804
  // collect original files
779
- const sourceList = [];
780
-
781
- originalMap.forEach((originalState) => {
805
+ originalStateMap.forEach((originalState) => {
782
806
 
783
807
  const {
784
808
  js, type, sourcePath, source
@@ -788,7 +812,7 @@ const collectOriginalList = (item, state, originalMap, options) => {
788
812
  const url = fileUrls[sourcePath] || sourcePath;
789
813
 
790
814
  // add dist for id
791
- const id = Util.calculateSha1(distFile + sourcePath + source);
815
+ const id = Util.calculateSha1(sourcePath + source);
792
816
 
793
817
  const sourceItem = {
794
818
  url,
@@ -800,31 +824,26 @@ const collectOriginalList = (item, state, originalMap, options) => {
800
824
  source
801
825
  };
802
826
 
803
- // generate coverage for current file, state for dist file
804
- collectFileCoverage(sourceItem, originalState, state.coverageData, options);
805
-
806
- sourceList.push(sourceItem);
827
+ // save v8 data and add to originalList
828
+ originalState.v8Data = sourceItem;
829
+ state.originalList.push(originalState);
807
830
  });
808
831
 
809
- return sourceList;
810
832
  };
811
833
 
812
834
  // ========================================================================================================
813
835
 
814
- const generateCoverageForDist = (item, state, options) => {
836
+ const generateCoverageForDist = (state) => {
815
837
 
816
838
  handleFunctionsCoverage(state);
817
839
  handleBranchesCoverage(state);
818
840
  handleBytesCoverage(state);
819
841
 
820
- collectFileCoverage(item, state, state.coverageData, options);
821
-
822
842
  };
823
843
 
824
- const unpackSourceMap = async (item, state, options) => {
844
+ const unpackSourceMap = (state, options) => {
825
845
 
826
- const { sourcePath } = item;
827
- const sourceMap = state.sourceMap;
846
+ const { sourceMap } = state;
828
847
 
829
848
  // keep original urls
830
849
  const fileUrls = {};
@@ -834,26 +853,24 @@ const unpackSourceMap = async (item, state, options) => {
834
853
 
835
854
  // ===============================================
836
855
  // decode mappings for each original file
837
- const time_start_decode = Date.now();
856
+
838
857
  const originalDecodedMap = new Map();
839
858
  // for find-original-range
840
- state.decodedMappings = await decodeSourceMappings(state, originalDecodedMap);
841
- // only debug level
842
- Util.logTime(`decode source mappings: ${sourcePath}`, time_start_decode);
859
+ state.decodedMappings = decodeSourceMappings(state, originalDecodedMap);
843
860
 
844
861
  // filter original list and init list
845
- const originalMap = initOriginalList(state, originalDecodedMap, options);
862
+ const originalStateMap = initOriginalList(state, originalDecodedMap, options);
846
863
 
847
864
  originalDecodedMap.clear();
848
865
 
849
866
  // ===============================================
850
867
 
851
868
  // handle functions before handle original state functions
852
- handleOriginalFunctionsCoverage(state, originalMap);
853
- handleOriginalBranchesCoverage(state, originalMap);
869
+ handleOriginalFunctionsCoverage(state, originalStateMap);
870
+ handleOriginalBranchesCoverage(state, originalStateMap);
854
871
 
855
872
  // handle lines info before handle ranges to update line count
856
- originalMap.forEach((originalState) => {
873
+ originalStateMap.forEach((originalState) => {
857
874
 
858
875
  handleFunctionsCoverage(originalState);
859
876
  handleBranchesCoverage(originalState);
@@ -865,31 +882,31 @@ const unpackSourceMap = async (item, state, options) => {
865
882
  });
866
883
 
867
884
  // handle ranges after lines ready
868
- handleOriginalBytesCoverage(state, originalMap);
885
+ handleOriginalBytesCoverage(state, originalStateMap);
869
886
 
870
887
  // collect coverage for original list
871
- state.sourceList = collectOriginalList(item, state, originalMap, options);
888
+ collectOriginalList(state, originalStateMap);
872
889
 
873
890
  };
874
891
 
875
- const unpackDistFile = async (item, state, options) => {
892
+ const unpackDistFile = (item, state, options) => {
876
893
 
877
894
  if (state.sourceMap) {
878
895
  if (Util.loggingType === 'debug') {
879
896
  // js self
880
897
  item.debug = true;
881
- generateCoverageForDist(item, state, options);
898
+ generateCoverageForDist(state);
882
899
  } else {
883
900
  item.dedupe = true;
884
901
  }
885
902
 
886
903
  // unpack source map
887
- await unpackSourceMap(item, state, options);
904
+ unpackSourceMap(state, options);
888
905
 
889
906
  } else {
890
907
 
891
908
  // css/js self
892
- generateCoverageForDist(item, state, options);
909
+ generateCoverageForDist(state);
893
910
 
894
911
  }
895
912
 
@@ -897,27 +914,260 @@ const unpackDistFile = async (item, state, options) => {
897
914
 
898
915
  // ========================================================================================================
899
916
 
900
- const dedupeV8List = (v8list) => {
901
- const indexes = [];
902
- v8list.forEach((item, i) => {
903
- if (item.dedupe) {
904
- indexes.push(i);
917
+ const filterCoverageList = (item) => {
918
+ const {
919
+ functions, scriptOffset, source
920
+ } = item;
921
+
922
+ // no script offset
923
+ if (!scriptOffset) {
924
+ return functions;
925
+ }
926
+
927
+ // vm script offset
928
+ const minOffset = scriptOffset;
929
+ // the inline sourcemap could be removed
930
+ const maxOffset = source.length;
931
+
932
+ const rootFunctionInfo = {
933
+ root: true,
934
+ ranges: [{
935
+ startOffset: minOffset,
936
+ endOffset: maxOffset,
937
+ count: 1
938
+ }]
939
+ };
940
+
941
+ const coverageList = functions.filter((block) => {
942
+ const { ranges } = block;
943
+
944
+ // first one is function coverage info
945
+ const functionRange = ranges[0];
946
+ const { startOffset, endOffset } = functionRange;
947
+ if (startOffset >= minOffset && endOffset <= maxOffset) {
948
+ return true;
949
+ }
950
+
951
+ // blocks
952
+ const len = ranges.length;
953
+ if (len > 1) {
954
+ for (let i = 1; i < len; i++) {
955
+ const range = ranges[i];
956
+ if (range.startOffset >= minOffset && range.endOffset <= maxOffset) {
957
+ rootFunctionInfo.ranges.push(range);
958
+ }
959
+ }
905
960
  }
961
+
962
+ return false;
906
963
  });
907
- if (indexes.length) {
908
- indexes.reverse();
909
- indexes.forEach((i) => {
910
- v8list.splice(i, 1);
911
- });
964
+
965
+ // first one for root function
966
+ if (rootFunctionInfo.ranges.length > 1) {
967
+ coverageList.unshift(rootFunctionInfo);
968
+ }
969
+
970
+ return coverageList;
971
+ };
972
+
973
+ // ========================================================================================================
974
+
975
+ const isCoveredInRanges = (range, uncoveredBytes) => {
976
+ if (!uncoveredBytes.length) {
977
+ return true;
978
+ }
979
+ for (const item of uncoveredBytes) {
980
+ if (range.start >= item.start && range.end <= item.end) {
981
+ return false;
982
+ }
912
983
  }
984
+ return true;
985
+ };
986
+
987
+ const mergeV8Data = (state, stateList) => {
988
+ // console.log(stateList);
989
+
990
+ // const sourcePath = state.sourcePath;
991
+ // console.log(sourcePath);
992
+ // if (sourcePath.endsWith('scroll_zoom.ts')) {
993
+ // console.log('merge v8 data ===================================', sourcePath);
994
+ // console.log(stateList.map((it) => it.bytes));
995
+ // console.log(stateList.map((it) => it.functions));
996
+ // console.log(stateList.map((it) => it.branches.map((b) => [`${b.start}-${b.end}`, JSON.stringify(b.locations.map((l) => l.count))])));
997
+ // }
998
+
999
+ // ===========================================================
1000
+ // bytes
1001
+ const mergedBytes = [];
1002
+ const uncoveredList = [];
1003
+ stateList.forEach((st) => {
1004
+ const bytes = dedupeCountRanges(st.bytes);
1005
+ const uncoveredBytes = [];
1006
+ bytes.forEach((range) => {
1007
+ if (range.count) {
1008
+ mergedBytes.push(range);
1009
+ } else {
1010
+ uncoveredBytes.push(range);
1011
+ }
1012
+ });
1013
+ uncoveredList.push(uncoveredBytes);
1014
+ });
1015
+ // just remove uncovered range
1016
+ uncoveredList.forEach((currentBytes) => {
1017
+ currentBytes.forEach((range) => {
1018
+ for (const targetBytes of uncoveredList) {
1019
+ if (targetBytes === currentBytes) {
1020
+ continue;
1021
+ }
1022
+ if (isCoveredInRanges(range, targetBytes)) {
1023
+ return;
1024
+ }
1025
+ }
1026
+ mergedBytes.push(range);
1027
+ });
1028
+ });
1029
+
1030
+ // will be dedupeCountRanges in collectFileCoverage
1031
+ state.bytes = mergedBytes;
1032
+
1033
+ // ===========================================================
1034
+ // functions
1035
+ const allFunctions = stateList.map((it) => it.functions).flat();
1036
+ const functionComparer = (lastRange, range) => {
1037
+ // if (lastRange.start === range.start && lastRange.end === range.end) {
1038
+ // return true;
1039
+ // }
1040
+
1041
+ // function range could be from sourcemap, not exact matched
1042
+
1043
+ // end is same
1044
+ // {start: 2017, end: 2315, count: 481}
1045
+ // {start: 2018, end: 2315, count: 14}
1046
+
1047
+ // start is same
1048
+ // {start: 10204, end: 10379, count: 0}
1049
+ // {start: 10204, end: 10393, count: 5}
1050
+
1051
+ // only one position matched could be same
1052
+ if (lastRange.start === range.start || lastRange.end === range.end) {
1053
+ // console.log(lastRange.start, range.start, lastRange.end, range.end);
1054
+
1055
+ // if (lastRange.start === range.start) {
1056
+ // console.log(range.end - lastRange.end, lastRange.start, lastRange.end, 'end', range.end, state.sourcePath);
1057
+ // } else {
1058
+ // console.log(range.start - lastRange.start, lastRange.start, lastRange.end, 'start', range.start, state.sourcePath);
1059
+ // }
1060
+
1061
+ return true;
1062
+ }
1063
+
1064
+ return false;
1065
+ };
1066
+ const functionHandler = (lastRange, range) => {
1067
+ lastRange.count += range.count;
1068
+ };
1069
+ const mergedFunctions = mergeRangesWith(allFunctions, functionComparer, functionHandler);
1070
+ state.functions = mergedFunctions;
1071
+
1072
+ // ===========================================================
1073
+ // branches
1074
+ const allBranches = stateList.map((it) => it.branches).flat();
1075
+ const branchComparer = (lastRange, range) => {
1076
+ // exact matched because the branch range is generated from ast
1077
+ return lastRange.start === range.start && lastRange.end === range.end;
1078
+ };
1079
+ const branchHandler = (lastRange, range) => {
1080
+ // merge locations count
1081
+ lastRange.locations.forEach((item, i) => {
1082
+ const loc = range.locations[i];
1083
+ if (loc) {
1084
+ item.count += loc.count;
1085
+ }
1086
+ });
1087
+ };
1088
+ const mergedBranches = mergeRangesWith(allBranches, branchComparer, branchHandler);
1089
+ state.branches = mergedBranches;
1090
+
1091
+ // if (sourcePath.endsWith('scroll_zoom.ts')) {
1092
+ // console.log(mergedBytes);
1093
+ // console.log(mergedFunctions);
1094
+ // console.log(mergedBranches.map((b) => [`${b.start}-${b.end}`, JSON.stringify(b.locations.map((l) => l.count))]));
1095
+ // }
1096
+
1097
+
913
1098
  };
914
1099
 
915
- const convertV8List = async (v8list, options) => {
1100
+ const generateV8DataList = (stateList, options) => {
1101
+
1102
+ const stateMap = new Map();
1103
+
1104
+ // all original files from dist
1105
+ const allOriginalList = [];
1106
+ stateList.forEach((state) => {
1107
+ const { v8Data, originalList } = state;
1108
+ // dedupe dist file if not debug
1109
+ if (!v8Data.dedupe) {
1110
+ stateMap.set(v8Data.id, state);
1111
+ }
1112
+ allOriginalList.push(originalList);
1113
+ });
1114
+
1115
+ // merge istanbul and v8(converted)
1116
+ const mergeMap = new Map();
1117
+ allOriginalList.flat().forEach((originalState) => {
1118
+ const { v8Data } = originalState;
1119
+ const id = v8Data.id;
1120
+ // exists item
1121
+ const prevState = stateMap.get(id);
1122
+ if (prevState) {
1123
+ // ignore empty item, just override it
1124
+ if (!prevState.v8Data.empty) {
1125
+ if (mergeMap.has(id)) {
1126
+ mergeMap.get(id).push(originalState);
1127
+ } else {
1128
+ mergeMap.set(id, [prevState, originalState]);
1129
+ }
1130
+ return;
1131
+ }
1132
+ }
1133
+ stateMap.set(id, originalState);
1134
+ });
916
1135
 
917
- // global file sources and coverage
1136
+ const mergeIds = mergeMap.keys();
1137
+ for (const id of mergeIds) {
1138
+ const state = stateMap.get(id);
1139
+ // for source the type could be ts, so just use js (boolean)
1140
+ if (state.js) {
1141
+ mergeV8Data(state, mergeMap.get(id));
1142
+ } else {
1143
+ // should no css here, css can not be in sources
1144
+ }
1145
+ }
1146
+
1147
+ // new v8 data list (includes sources)
1148
+ const v8DataList = [];
1149
+ // global file sources and istanbul coverage data
918
1150
  const fileSources = {};
919
1151
  const coverageData = {};
920
- let sourceList = [];
1152
+ stateMap.forEach((state) => {
1153
+ const { v8Data } = state;
1154
+ const istanbulData = collectFileCoverage(v8Data, state, options);
1155
+ const { sourcePath, source } = v8Data;
1156
+ v8DataList.push(v8Data);
1157
+ fileSources[sourcePath] = source;
1158
+ coverageData[sourcePath] = istanbulData;
1159
+ });
1160
+
1161
+ return {
1162
+ v8DataList,
1163
+ fileSources,
1164
+ coverageData
1165
+ };
1166
+ };
1167
+
1168
+ const convertV8List = (v8list, options) => {
1169
+
1170
+ const stateList = [];
921
1171
 
922
1172
  for (const item of v8list) {
923
1173
  // console.log([item.id]);
@@ -930,14 +1180,11 @@ const convertV8List = async (v8list, options) => {
930
1180
  const js = type === 'js';
931
1181
  item.js = js;
932
1182
 
933
- // append file source
934
- fileSources[sourcePath] = source;
935
-
936
1183
  // source mapping
937
1184
  const locator = new Locator(source);
938
1185
 
939
1186
  // ============================
940
- // move sourceMap
1187
+ // move sourceMap
941
1188
  const sourceMap = item.sourceMap;
942
1189
  if (sourceMap) {
943
1190
  delete item.sourceMap;
@@ -948,7 +1195,7 @@ const convertV8List = async (v8list, options) => {
948
1195
  let coverageList = [];
949
1196
  let astInfo;
950
1197
  if (js) {
951
- coverageList = item.functions;
1198
+ coverageList = filterCoverageList(item);
952
1199
  // remove original functions
953
1200
  if (Util.loggingType !== 'debug') {
954
1201
  delete item.functions;
@@ -966,57 +1213,34 @@ const convertV8List = async (v8list, options) => {
966
1213
  // ============================
967
1214
 
968
1215
  // current file and it's sources from sourceMap
1216
+ // see const originalState
969
1217
  const state = {
970
1218
  js,
971
1219
  type,
1220
+ source,
972
1221
  sourcePath,
973
1222
  sourceMap,
974
- coverageList,
975
1223
  locator,
1224
+ decodedMappings: [],
976
1225
  // coverage info
977
1226
  bytes: [],
978
1227
  functions: [],
979
1228
  branches: [],
980
1229
  astInfo,
981
- // for istanbul
982
- fileSources: {},
983
- coverageData: {}
1230
+ // for sub source files
1231
+ coverageList,
1232
+ originalList: [],
1233
+ // coverage data
1234
+ v8Data: item
984
1235
  };
985
1236
 
986
- await unpackDistFile(item, state, options);
1237
+ unpackDistFile(item, state, options);
987
1238
 
988
- // merge state
989
- Object.assign(fileSources, state.fileSources);
990
- Object.assign(coverageData, state.coverageData);
991
-
992
- if (Util.isList(state.sourceList)) {
993
- sourceList = sourceList.concat(state.sourceList);
994
- }
1239
+ stateList.push(state);
995
1240
 
996
1241
  }
997
1242
 
998
- // add all sources
999
- if (sourceList.length) {
1000
- sourceList.forEach((item) => {
1001
-
1002
- // second time filter for empty source
1003
- // exists same id, mark previous item as dedupe
1004
- const prevItem = v8list.find((it) => it.id === item.id);
1005
- if (prevItem) {
1006
- prevItem.dedupe = true;
1007
- }
1008
-
1009
- v8list.push(item);
1010
- });
1011
- }
1012
-
1013
- // dedupe
1014
- dedupeV8List(v8list);
1015
-
1016
- return {
1017
- fileSources,
1018
- coverageData
1019
- };
1243
+ return generateV8DataList(stateList, options);
1020
1244
 
1021
1245
  };
1022
1246