monocart-coverage-reports 2.8.4 → 2.8.6

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/lib/generate.js CHANGED
@@ -21,7 +21,6 @@ const { getGroupedRows } = require('./utils/snapshot.js');
21
21
 
22
22
  // maybe v8 or to istanbul reports
23
23
  const generateV8ListReports = async (v8list, coverageData, fileSources, options) => {
24
- const time_start = Date.now();
25
24
  let istanbulReportPath;
26
25
  // v8 to istanbul reports
27
26
  if (options.reportGroup.istanbul) {
@@ -32,7 +31,6 @@ const generateV8ListReports = async (v8list, coverageData, fileSources, options)
32
31
  // v8 reports and v8 coverage results
33
32
  // could be no v8 or v8-json, but requires v8 coverage results
34
33
  const v8CoverageResults = await saveV8Report(v8list, options, istanbulReportPath);
35
- Util.logTime('- saved coverage reports', time_start);
36
34
  return v8CoverageResults;
37
35
  };
38
36
 
@@ -434,9 +432,15 @@ const getCoverageResults = async (dataList, sourceCache, options) => {
434
432
  // v8list
435
433
  if (dataType === 'v8') {
436
434
  // merge v8list first
435
+ const t1 = Date.now();
437
436
  const v8list = await mergeV8Coverage(dataList, sourceCache, options);
437
+ Util.logTime('┌ [generate] merged v8 coverage data', t1);
438
438
  // console.log('after merge', v8list.map((it) => it.url));
439
+
440
+ const t2 = Date.now();
439
441
  const results = convertV8List(v8list, options);
442
+ Util.logTime('┌ [generate] converted coverage data', t2);
443
+
440
444
  const {
441
445
  v8DataList, coverageData, fileSources
442
446
  } = results;
@@ -444,9 +448,12 @@ const getCoverageResults = async (dataList, sourceCache, options) => {
444
448
  }
445
449
 
446
450
  // istanbul data
451
+ const t3 = Date.now();
447
452
  const istanbulData = mergeIstanbulCoverage(dataList);
448
453
  const { coverageData, fileSources } = initIstanbulData(istanbulData, options);
449
- return saveIstanbulReports(coverageData, fileSources, options);
454
+ Util.logTime('┌ [generate] prepared istanbul coverage data', t3);
455
+ const results = await saveIstanbulReports(coverageData, fileSources, options);
456
+ return results;
450
457
  };
451
458
 
452
459
  const generateCoverageReports = async (dataList, sourceCache, options) => {
@@ -468,11 +475,13 @@ const generateCoverageReports = async (dataList, sourceCache, options) => {
468
475
  for (const reportName of bothReports) {
469
476
  const reportOptions = bothGroup[reportName];
470
477
  const buildInHandler = buildInBothReports[reportName];
478
+ const t1 = Date.now();
471
479
  if (buildInHandler) {
472
480
  await buildInHandler(coverageResults, reportOptions, options);
473
481
  } else {
474
482
  await Util.runCustomReporter(reportName, coverageResults, reportOptions, options);
475
483
  }
484
+ Util.logTime(`┌ [generate] saved report: ${reportName}`, t1);
476
485
  }
477
486
  }
478
487
 
@@ -663,28 +672,111 @@ const getEmptyData = (all, dataList) => {
663
672
 
664
673
  // ========================================================================================================
665
674
 
675
+ const getInputList = (mcr) => {
676
+ // get input dirs
677
+ const { inputDir, cacheDir } = mcr.options;
666
678
 
667
- const getInputData = async (inputList, all, cacheDir, addHandler) => {
668
- const dataList = [];
669
- const sourceCache = new Map();
679
+ const inputDirs = Util.toList(inputDir, ',');
680
+
681
+ const inputList = inputDirs.filter((dir) => {
682
+ const hasDir = fs.existsSync(dir);
683
+ if (!hasDir) {
684
+ // could be empty
685
+ Util.logInfo(`Not found coverage data dir: ${Util.relativePath(dir)}`);
686
+ }
687
+ return hasDir;
688
+ });
670
689
 
671
- const addJsonData = async (dir, filename) => {
672
- const isCoverage = filename.startsWith('coverage-');
673
- const isSource = filename.startsWith('source-');
674
- if (isCoverage || isSource) {
690
+ if (mcr.hasCache()) {
691
+ inputList.push(cacheDir);
692
+ }
693
+
694
+ return inputList;
695
+ };
696
+
697
+ const addJsonData = async (mcr, dataList, sourceCache, dir, filename) => {
698
+ const isCoverage = filename.startsWith('coverage-');
699
+ const isSource = filename.startsWith('source-');
700
+ if (isCoverage || isSource) {
701
+ let json;
702
+ if (mcr.fileCache.has(filename)) {
703
+ json = mcr.fileCache.get(filename);
704
+ } else {
675
705
  const content = await Util.readFile(path.resolve(dir, filename));
676
706
  if (content) {
677
- const json = JSON.parse(content);
678
- if (isCoverage) {
679
- dataList.push(json);
680
- } else {
707
+ json = JSON.parse(content);
708
+ }
709
+ }
710
+ if (json) {
711
+ if (isCoverage) {
712
+ dataList.push(json);
713
+ } else {
714
+ sourceCache.set(json.id, json);
715
+ }
716
+ }
717
+ }
718
+ };
719
+
720
+ const addEmptyData = async (mcr, dataList, sourceCache) => {
721
+
722
+ const { all, cacheDir } = mcr.options;
723
+ // add empty coverage for all files
724
+ // dataList for data type, before `add` we don't which one is tested, because using hash id
725
+ const emptyData = getEmptyData(all, dataList);
726
+ if (!emptyData) {
727
+ return;
728
+ }
729
+
730
+ let files = 0;
731
+ if (Util.isList(emptyData)) {
732
+ files = emptyData.length;
733
+ } else {
734
+ files = Object.keys(emptyData).length;
735
+ }
736
+
737
+ Util.logDebug(`added all files with empty coverage: ${EC.yellow(files)}`);
738
+ const coverageResults = await mcr.add(emptyData);
739
+ // after `add`
740
+ if (!coverageResults) {
741
+ return;
742
+ }
743
+
744
+ dataList.push(coverageResults);
745
+
746
+ if (coverageResults.type === 'v8') {
747
+ // sourceCache
748
+ coverageResults.data.forEach((entry) => {
749
+ const { id } = entry;
750
+ if (sourceCache.has(id)) {
751
+ // console.log('+', entry.sourcePath);
752
+ return;
753
+ }
754
+ // console.log('-', entry.sourcePath);
755
+ const { cacheName, cachePath } = Util.getCacheFileInfo('source', id, cacheDir);
756
+ if (mcr.fileCache.has(cacheName)) {
757
+ const json = mcr.fileCache.get(cacheName);
758
+ sourceCache.set(json.id, json);
759
+ } else {
760
+ const content = Util.readFileSync(cachePath);
761
+ if (content) {
762
+ const json = JSON.parse(content);
681
763
  sourceCache.set(json.id, json);
682
764
  }
683
765
  }
684
- }
685
- };
766
+ });
767
+ }
768
+ };
769
+
770
+ const getInputData = async (mcr) => {
771
+
772
+ const inputList = getInputList(mcr);
773
+ // console.log('input list', inputList);
774
+
775
+ const dataList = [];
776
+ const sourceCache = new Map();
686
777
 
687
778
  for (const dir of inputList) {
779
+
688
780
  const allFiles = fs.readdirSync(dir);
689
781
  if (!allFiles.length) {
690
782
  continue;
@@ -692,38 +784,17 @@ const getInputData = async (inputList, all, cacheDir, addHandler) => {
692
784
  for (const filename of allFiles) {
693
785
  // only json file
694
786
  if (filename.endsWith('.json')) {
695
- await addJsonData(dir, filename);
787
+ await addJsonData(mcr, dataList, sourceCache, dir, filename);
696
788
  }
697
789
  }
698
790
  }
699
791
 
700
- // add empty coverage for all files
701
- // dataList for data type, before `add` we don't which one is tested, because using hash id
702
- const emptyData = getEmptyData(all, dataList);
703
- if (emptyData) {
704
- Util.logDebug(`added empty files for all: ${EC.yellow(emptyData.length)}`);
705
- const coverageResults = await addHandler(emptyData);
706
- // after `add`
707
- if (coverageResults) {
708
- dataList.push(coverageResults);
709
- if (coverageResults.type === 'v8') {
710
- // sourceCache
711
- coverageResults.data.forEach((entry) => {
712
- const { id } = entry;
713
- if (sourceCache.has(id)) {
714
- // console.log('+', entry.sourcePath);
715
- return;
716
- }
717
- // console.log('-', entry.sourcePath);
718
- const sourcePath = Util.resolveCacheSourcePath(cacheDir, id);
719
- const content = Util.readFileSync(sourcePath);
720
- if (content) {
721
- const json = JSON.parse(content);
722
- sourceCache.set(json.id, json);
723
- }
724
- });
725
- }
726
- }
792
+ await addEmptyData(mcr, dataList, sourceCache);
793
+
794
+ if (!dataList.length) {
795
+ const dirs = inputList.map((dir) => Util.relativePath(dir));
796
+ Util.logError(`Not found coverage data in dir(s): ${dirs.join(', ')}`);
797
+ return;
727
798
  }
728
799
 
729
800
  return {
@@ -783,14 +854,11 @@ const resolveEntrySourceMap = (entry, sourceMapCache) => {
783
854
  }
784
855
  };
785
856
 
786
- const readCoverageData = (filePath, entryFilter, sourceCache) => {
857
+ const readCoverageData = (item, entryFilter, sourceCache) => {
787
858
 
788
- const content = fs.readFileSync(filePath).toString('utf-8');
789
- if (!content) {
790
- return;
791
- }
859
+ const json = item.json;
792
860
 
793
- const json = JSON.parse(content);
861
+ // raw v8 json
794
862
  let coverageData = json.result;
795
863
  if (!Util.isList(coverageData)) {
796
864
  return;
@@ -818,7 +886,7 @@ const readCoverageData = (filePath, entryFilter, sourceCache) => {
818
886
  return coverageData;
819
887
  };
820
888
 
821
- const readFromDir = async (dir, entryFilter, addHandler) => {
889
+ const readFromDir = async (mcr, dir) => {
822
890
 
823
891
  if (!dir || !fs.existsSync(dir)) {
824
892
  Util.logInfo(`Not found V8 coverage dir: ${dir}`);
@@ -826,41 +894,63 @@ const readFromDir = async (dir, entryFilter, addHandler) => {
826
894
  }
827
895
 
828
896
  const files = fs.readdirSync(dir);
829
- if (!files.length) {
897
+ const list = [];
898
+ files.forEach((filename) => {
899
+ if (filename.startsWith('coverage-')) {
900
+ list.push({
901
+ type: 'coverage',
902
+ filename
903
+ });
904
+ return;
905
+ }
906
+ if (filename.startsWith('source-')) {
907
+ list.push({
908
+ type: 'source',
909
+ filename
910
+ });
911
+ }
912
+ });
913
+
914
+ if (!list.length) {
830
915
  Util.logInfo(`No coverage files in the dir: ${dir}`);
831
916
  return;
832
917
  }
833
918
 
834
- const coverageFiles = [];
919
+ const contentList = await Promise.all(list.map((it) => Util.readFile(path.resolve(dir, it.filename))));
835
920
  const sourceCache = {};
836
- files.forEach((filename) => {
837
- const isCoverage = filename.startsWith('coverage-');
838
- if (isCoverage) {
839
- coverageFiles.push(filename);
921
+ const coverageFiles = [];
922
+
923
+ contentList.forEach((content, i) => {
924
+ if (!content) {
840
925
  return;
841
926
  }
842
- const isSource = filename.startsWith('source-');
843
- if (isSource) {
844
- const filePath = path.resolve(dir, filename);
845
- const content = fs.readFileSync(filePath).toString('utf-8');
846
- if (content) {
847
- const json = JSON.parse(content);
848
- if (json.url) {
849
- sourceCache[json.url] = json;
850
- }
927
+ const json = JSON.parse(content);
928
+ if (!json) {
929
+ return;
930
+ }
931
+ const item = list[i];
932
+ if (item.type === 'source') {
933
+ if (json.url) {
934
+ sourceCache[json.url] = json;
851
935
  }
936
+ } else {
937
+ item.json = json;
938
+ coverageFiles.push(item);
852
939
  }
853
940
  });
854
941
 
855
- // filter before adding
856
- for (const filename of coverageFiles) {
857
- const filePath = path.resolve(dir, filename);
858
- const coverageData = readCoverageData(filePath, entryFilter, sourceCache);
942
+ const entryFilter = mcr.getEntryFilter();
943
+
944
+ const results = [];
945
+ for (const item of coverageFiles) {
946
+ const coverageData = readCoverageData(item, entryFilter, sourceCache);
859
947
  if (coverageData) {
860
- await addHandler(coverageData);
948
+ const res = await mcr.add(coverageData);
949
+ results.push(res);
861
950
  }
862
951
  }
863
952
 
953
+ return results;
864
954
  };
865
955
 
866
956
  module.exports = {
package/lib/index.d.ts CHANGED
@@ -128,7 +128,7 @@ declare namespace MCR {
128
128
  path: string;
129
129
  type: "v8" | "istanbul";
130
130
  data: any;
131
- } | undefined;
131
+ };
132
132
 
133
133
 
134
134
  export interface MetricsSummary {
@@ -204,7 +204,7 @@ declare namespace MCR {
204
204
  watermarks: Watermarks;
205
205
  summary: CoverageSummary;
206
206
  files: CoverageFile[];
207
- } | undefined;
207
+ };
208
208
 
209
209
  export type LoggingType = "off" | "error" | "info" | "debug";
210
210
  export interface CoverageReportOptions {
@@ -329,7 +329,7 @@ declare namespace MCR {
329
329
  onEntry?: (entry: V8CoverageEntry) => Promise<void>;
330
330
 
331
331
  /** {function} onEnd hook */
332
- onEnd?: (coverageResults: CoverageResults) => Promise<void>;
332
+ onEnd?: (coverageResults: CoverageResults | undefined) => Promise<void>;
333
333
 
334
334
  [key: string]: any;
335
335
  }
@@ -357,7 +357,7 @@ declare namespace MCR {
357
357
  /** add coverage data
358
358
  *
359
359
  * @param coverageData {array} V8 format, {object} Istanbul format */
360
- add: (coverageData: any[] | any) => Promise<AddedResults>;
360
+ add: (coverageData: any[] | any) => Promise<AddedResults | undefined>;
361
361
 
362
362
  /**
363
363
  * add V8 coverage from a dir
@@ -366,7 +366,7 @@ declare namespace MCR {
366
366
  addFromDir: (dir: string) => Promise<void>;
367
367
 
368
368
  /** generate report */
369
- generate: () => Promise<CoverageResults>;
369
+ generate: () => Promise<CoverageResults | undefined>;
370
370
 
371
371
  /** check if cache exists */
372
372
  hasCache: () => boolean;
package/lib/index.js CHANGED
@@ -53,6 +53,7 @@ class CoverageReport {
53
53
  ... options
54
54
  };
55
55
  this.initOptions();
56
+ this.fileCache = new Map();
56
57
  }
57
58
 
58
59
  initOptions(force) {
@@ -97,9 +98,6 @@ class CoverageReport {
97
98
  }
98
99
 
99
100
  const dataId = Util.uid();
100
- const dataName = `coverage-${dataId}.json`;
101
- const dataPath = path.resolve(this.options.cacheDir, dataName);
102
-
103
101
  const results = {
104
102
  id: dataId
105
103
  };
@@ -107,15 +105,16 @@ class CoverageReport {
107
105
  if (Array.isArray(data)) {
108
106
  results.type = 'v8';
109
107
  // could be empty list after entryFilter
110
- results.data = await initV8ListAndSourcemap(data, this.options);
108
+ results.data = await initV8ListAndSourcemap(this, data);
111
109
  } else {
112
110
  results.type = 'istanbul';
113
111
  results.data = data;
114
112
  }
115
113
 
116
- // save data to cache dir
117
- const dataContent = JSON.stringify(results);
118
- await Util.writeFile(dataPath, dataContent);
114
+ // save data to cache
115
+ const { cacheName, cachePath } = Util.getCacheFileInfo('coverage', dataId, this.options.cacheDir);
116
+ this.fileCache.set(cacheName, results);
117
+ await Util.writeFile(cachePath, JSON.stringify(results));
119
118
 
120
119
  Util.logTime(`added coverage data: ${results.type}`, time_start);
121
120
 
@@ -123,11 +122,11 @@ class CoverageReport {
123
122
  }
124
123
 
125
124
  // add coverage from dir
126
- addFromDir(dir) {
127
- const entryFilter = this.getEntryFilter();
128
- return readFromDir(dir, entryFilter, (coverageData) => {
129
- return this.add(coverageData);
130
- });
125
+ async addFromDir(dir) {
126
+ const time_start = Date.now();
127
+ const results = await readFromDir(this, dir);
128
+ Util.logTime(`added from dir: ${dir}`, time_start);
129
+ return results;
131
130
  }
132
131
 
133
132
  // generate report
@@ -137,34 +136,13 @@ class CoverageReport {
137
136
 
138
137
  this.initOptions();
139
138
 
140
- const {
141
- all, inputDir, cacheDir
142
- } = this.options;
143
-
144
- const inputDirs = Util.toList(inputDir, ',');
145
- if (this.hasCache()) {
146
- inputDirs.push(cacheDir);
147
- }
148
-
149
- const inputList = inputDirs.filter((dir) => {
150
- const hasDir = fs.existsSync(dir);
151
- if (!hasDir) {
152
- // could be empty
153
- Util.logInfo(`Not found coverage data dir: ${Util.relativePath(dir)}`);
154
- }
155
- return hasDir;
156
- });
157
-
158
- const { dataList, sourceCache } = await getInputData(inputList, all, cacheDir, (emptyData) => {
159
- return this.add(emptyData);
160
- });
161
-
162
- if (!dataList.length) {
163
- const dirs = inputList.map((dir) => Util.relativePath(dir));
164
- Util.logError(`Not found coverage data in dir(s): ${dirs.join(', ')}`);
139
+ const inputData = await getInputData(this);
140
+ if (!inputData) {
165
141
  return;
166
142
  }
167
143
 
144
+ const { dataList, sourceCache } = inputData;
145
+
168
146
  // empty output dir except cache dir before generate reports
169
147
  const outputDir = this.options.outputDir;
170
148
 
@@ -179,19 +157,21 @@ class CoverageReport {
179
157
  });
180
158
  }
181
159
 
160
+ Util.logTime('┌ [generate] prepared coverage data', time_start);
161
+
182
162
  const coverageResults = await generateCoverageReports(dataList, sourceCache, this.options);
183
163
 
184
164
  if (this.logging !== 'debug') {
185
- Util.rmSync(cacheDir);
165
+ Util.rmSync(this.options.cacheDir);
186
166
  }
187
167
 
188
- Util.logTime(`generated coverage reports: ${EC.cyan(coverageResults.reportPath)}`, time_start);
189
-
190
168
  const onEnd = this.options.onEnd;
191
169
  if (typeof onEnd === 'function') {
192
170
  await onEnd.call(this, coverageResults);
193
171
  }
194
172
 
173
+ Util.logTime(`generated coverage reports: ${EC.cyan(coverageResults.reportPath)}`, time_start);
174
+
195
175
  return coverageResults;
196
176
  }
197
177
 
@@ -89,9 +89,11 @@ const saveIstanbulReports = (coverageData, fileSources, options) => {
89
89
 
90
90
  const istanbulGroup = options.reportGroup.istanbul;
91
91
  Object.keys(istanbulGroup).forEach((reportName) => {
92
+ const t1 = Date.now();
92
93
  const reportOptions = istanbulGroup[reportName];
93
94
  const report = istanbulReports.create(reportName, reportOptions);
94
95
  report.execute(context);
96
+ Util.logTime(`┌ [generate] saved report: ${reportName}`, t1);
95
97
  });
96
98
 
97
99
  // add watermarks and color