monocart-coverage-reports 2.2.2 → 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.
@@ -33,17 +33,25 @@ module.exports = class InfoBranch {
33
33
  const line = groupLoc.start.line;
34
34
 
35
35
  // remove ignored
36
- const locations = this.locations.filter((it) => !it.ignored);
36
+ // do NOT change previous number type to object, need used for sourcemap
37
+ const newLocations = this.locations.filter((it) => !it.ignored).map((it) => {
38
+ const item = {
39
+ start: it.start,
40
+ end: it.end,
41
+ none: it.none,
42
+ count: it.count
43
+ };
37
44
 
38
- // [ { start:{line,column}, end:{line,column}, count }, ...]
39
- locations.forEach((item) => {
45
+ // [ { start:{line,column}, end:{line,column}, count }, ...]
40
46
  Util.updateOffsetToLocation(locator, item);
47
+
48
+ return item;
41
49
  });
42
50
 
43
51
  const map = {
44
52
  loc: groupLoc,
45
53
  type: this.type,
46
- locations: locations.map((item) => {
54
+ locations: newLocations.map((item) => {
47
55
  const {
48
56
  start, end, none
49
57
  } = item;
@@ -63,7 +71,7 @@ module.exports = class InfoBranch {
63
71
  line: line
64
72
  };
65
73
 
66
- const counts = locations.map((item) => item.count);
74
+ const counts = newLocations.map((item) => item.count);
67
75
 
68
76
  return {
69
77
  map,
@@ -6,6 +6,9 @@ module.exports = {
6
6
  // {string} output dir
7
7
  outputDir: './coverage-reports',
8
8
 
9
+ // {string|string[]} input raw dir(s)
10
+ inputDir: null,
11
+
9
12
  // {string} v8 or html for istanbul by default
10
13
  // {array} multiple reports with options
11
14
  // v8 report or istanbul supported reports
package/lib/generate.js CHANGED
@@ -44,39 +44,35 @@ const getReportGroup = (reports, lcov, dataType) => {
44
44
  reportMap.lcovonly = {};
45
45
  }
46
46
 
47
- const defaultReport = dataType === 'v8' ? 'v8' : 'html';
48
-
49
- if (Util.isList(reports)) {
50
- reports.forEach((it) => {
51
- if (Util.isList(it)) {
52
- // ["v8"]
53
- reportMap[it[0]] = {
47
+ const reportList = Util.toList(reports, ',');
48
+ reportList.forEach((it) => {
49
+ if (Util.isList(it)) {
50
+ // ["v8"], ["v8", {}]
51
+ const id = it[0];
52
+ if (typeof id === 'string' && id) {
53
+ reportMap[id] = {
54
54
  ... it[1]
55
55
  };
56
- return;
57
- }
58
- if (typeof it === 'string') {
59
- reportMap[it] = {};
60
- return;
61
56
  }
62
- reportMap[defaultReport] = {};
63
- });
64
- } else if (typeof reports === 'string' && reports) {
65
- reportMap[reports] = {};
66
- } else {
57
+ return;
58
+ }
59
+ if (typeof it === 'string' && it) {
60
+ reportMap[it] = {};
61
+ }
62
+ });
63
+
64
+ // using default report if no reports
65
+ if (!Object.keys(reportMap).length) {
66
+ const defaultReport = dataType === 'v8' ? 'v8' : 'html';
67
67
  reportMap[defaultReport] = {};
68
68
  }
69
69
 
70
- const allSupportedReports = {
71
-
70
+ const allBuildInReports = {
72
71
  // v8
73
72
  'v8': 'v8',
74
73
  'v8-json': 'v8',
75
74
  'codecov': 'v8',
76
75
 
77
- // both
78
- 'console-summary': 'both',
79
-
80
76
  // istanbul
81
77
  'clover': 'istanbul',
82
78
  'cobertura': 'istanbul',
@@ -90,29 +86,41 @@ const getReportGroup = (reports, lcov, dataType) => {
90
86
  'teamcity': 'istanbul',
91
87
  'text': 'istanbul',
92
88
  'text-lcov': 'istanbul',
93
- 'text-summary': 'istanbul'
89
+ 'text-summary': 'istanbul',
90
+
91
+ // both
92
+ 'console-summary': 'both',
93
+ 'raw': 'both'
94
94
  };
95
95
 
96
96
  // group v8 and istanbul
97
97
  const reportGroup = {};
98
98
  Object.keys(reportMap).forEach((k) => {
99
+ const options = reportMap[k];
99
100
 
100
- const groupName = allSupportedReports[k];
101
- if (!groupName) {
102
- Util.logError(`Unsupported report: ${k}`);
103
- return;
101
+ let type = allBuildInReports[k];
102
+ if (!type) {
103
+ // for custom reporter
104
+ type = options.type || 'v8';
104
105
  }
105
106
 
106
- let group = reportGroup[groupName];
107
+ let group = reportGroup[type];
107
108
  if (!group) {
108
109
  group = {};
109
- reportGroup[groupName] = group;
110
+ reportGroup[type] = group;
110
111
  }
111
112
 
112
- group[k] = reportMap[k];
113
+ group[k] = options;
113
114
 
114
115
  });
115
116
 
117
+ // requires a default istanbul report if data is istanbul
118
+ if (dataType === 'istanbul' && !reportGroup.istanbul) {
119
+ reportGroup.istanbul = {
120
+ html: {}
121
+ };
122
+ }
123
+
116
124
  return reportGroup;
117
125
  };
118
126
 
@@ -145,23 +153,14 @@ const nFormatter = (v) => {
145
153
  return v;
146
154
  };
147
155
 
148
- const showConsoleSummary = (coverageResults, options) => {
156
+ const showConsoleSummary = (reportData, reportOptions, options) => {
149
157
 
150
- const bothGroup = options.reportGroup.both;
151
- if (!bothGroup) {
152
- return;
153
- }
154
-
155
- const consoleOptions = bothGroup['console-summary'];
156
- if (!consoleOptions) {
157
- return;
158
- }
159
-
160
- const { metrics } = consoleOptions;
158
+ const { metrics } = reportOptions;
161
159
 
162
160
  const {
163
161
  summary, name, type
164
- } = coverageResults;
162
+ } = reportData;
163
+
165
164
  if (name) {
166
165
  EC.logCyan(name);
167
166
  }
@@ -217,10 +216,36 @@ const showConsoleSummary = (coverageResults, options) => {
217
216
  });
218
217
  };
219
218
 
219
+ const saveRawReport = (reportData, reportOptions, options) => {
220
+ const rawOptions = {
221
+ outputDir: 'raw',
222
+ ... reportOptions
223
+ };
224
+
225
+ const cacheDir = options.cacheDir;
226
+ const rawDir = path.resolve(options.outputDir, rawOptions.outputDir);
227
+ // console.log(rawDir, cacheDir);
228
+ if (fs.existsSync(rawDir)) {
229
+ Util.logError(`Failed to save raw report because the dir already exists: ${Util.relativePath(rawDir)}`);
230
+ return;
231
+ }
232
+
233
+ const rawParent = path.dirname(rawDir);
234
+ if (!fs.existsSync(rawParent)) {
235
+ fs.mkdirSync(rawParent, {
236
+ recursive: true
237
+ });
238
+ }
239
+
240
+ // just rename the cache folder name
241
+ fs.renameSync(cacheDir, rawDir);
242
+
243
+ };
244
+
220
245
 
221
246
  // ========================================================================================================
222
247
 
223
- const getCoverageResults = async (dataList, options) => {
248
+ const getCoverageResults = async (dataList, sourceCache, options) => {
224
249
  // get first and check v8list or istanbul data
225
250
  const firstData = dataList[0];
226
251
  const dataType = firstData.type;
@@ -233,27 +258,50 @@ const getCoverageResults = async (dataList, options) => {
233
258
  // v8list
234
259
  if (dataType === 'v8') {
235
260
  // merge v8list first
236
- const v8list = await mergeV8Coverage(dataList, options);
261
+ const v8list = await mergeV8Coverage(dataList, sourceCache, options);
237
262
  // console.log('after merge', v8list.map((it) => it.url));
238
263
 
239
- const { coverageData, fileSources } = await convertV8List(v8list, options);
240
- return generateV8ListReports(v8list, coverageData, fileSources, options);
264
+ // only debug level
265
+ const time_start = Date.now();
266
+ const results = convertV8List(v8list, options);
267
+ const {
268
+ v8DataList, coverageData, fileSources
269
+ } = results;
270
+ Util.logTime(`converted v8 data: ${v8DataList.length}`, time_start);
241
271
 
272
+ return generateV8ListReports(v8DataList, coverageData, fileSources, options);
242
273
  }
243
274
 
244
275
  // istanbul data
245
- const istanbulData = mergeIstanbulCoverage(dataList, options);
276
+ const istanbulData = mergeIstanbulCoverage(dataList);
246
277
  const { coverageData, fileSources } = initIstanbulData(istanbulData, options);
247
278
  return saveIstanbulReports(coverageData, fileSources, options);
248
279
  };
249
280
 
250
- const generateCoverageReports = async (dataList, options) => {
251
- const coverageResults = await getCoverageResults(dataList, options);
281
+ const generateCoverageReports = async (dataList, sourceCache, options) => {
282
+ const coverageResults = await getCoverageResults(dataList, sourceCache, options);
252
283
 
253
284
  // [ 'type', 'reportPath', 'name', 'watermarks', 'summary', 'files' ]
254
285
  // console.log(Object.keys(coverageResults));
255
286
 
256
- showConsoleSummary(coverageResults, options);
287
+ const buildInBothReports = {
288
+ 'console-summary': showConsoleSummary,
289
+ 'raw': saveRawReport
290
+ };
291
+
292
+ const bothGroup = options.reportGroup.both;
293
+ if (bothGroup) {
294
+ const bothReports = Object.keys(bothGroup);
295
+ for (const reportName of bothReports) {
296
+ const reportOptions = bothGroup[reportName];
297
+ const buildInHandler = buildInBothReports[reportName];
298
+ if (buildInHandler) {
299
+ await buildInHandler(coverageResults, reportOptions, options);
300
+ } else {
301
+ await Util.runCustomReporter(reportName, coverageResults, reportOptions, options);
302
+ }
303
+ }
304
+ }
257
305
 
258
306
  return coverageResults;
259
307
  };
@@ -261,26 +309,45 @@ const generateCoverageReports = async (dataList, options) => {
261
309
  // ========================================================================================================
262
310
 
263
311
 
264
- const getCoverageDataList = async (cacheDir) => {
265
- const files = fs.readdirSync(cacheDir).filter((f) => f.startsWith('coverage-'));
266
- if (!files.length) {
267
- return;
268
- }
269
-
312
+ const getInputData = async (inputList) => {
270
313
  const dataList = [];
271
- for (const item of files) {
272
- const content = await Util.readFile(path.resolve(cacheDir, item));
273
- if (content) {
274
- dataList.push(JSON.parse(content));
314
+ const sourceCache = new Map();
315
+
316
+ const addJsonData = async (dir, filename) => {
317
+ const isCoverage = filename.startsWith('coverage-');
318
+ const isSource = filename.startsWith('source-');
319
+ if (isCoverage || isSource) {
320
+ const content = await Util.readFile(path.resolve(dir, filename));
321
+ if (content) {
322
+ const json = JSON.parse(content);
323
+ if (isCoverage) {
324
+ dataList.push(json);
325
+ } else {
326
+ sourceCache.set(json.id, json);
327
+ }
328
+ }
275
329
  }
276
- }
330
+ };
277
331
 
278
- if (dataList.length) {
279
- return dataList;
332
+ for (const dir of inputList) {
333
+ const allFiles = fs.readdirSync(dir);
334
+ if (!allFiles.length) {
335
+ continue;
336
+ }
337
+ for (const filename of allFiles) {
338
+ // only json file
339
+ if (filename.endsWith('.json')) {
340
+ await addJsonData(dir, filename);
341
+ }
342
+ }
280
343
  }
344
+ return {
345
+ dataList,
346
+ sourceCache
347
+ };
281
348
  };
282
349
 
283
350
  module.exports = {
284
- getCoverageDataList,
351
+ getInputData,
285
352
  generateCoverageReports
286
353
  };
package/lib/index.d.ts CHANGED
@@ -37,9 +37,6 @@ declare namespace MCR {
37
37
  ['codecov'] | ["codecov", {
38
38
  outputFile?: string;
39
39
  }] |
40
- ['console-summary'] | ['console-summary', {
41
- metrics?: Array<"bytes" | "functions" | "branches" | "lines" | "statements">;
42
- }] |
43
40
  ['clover'] | ['clover', {
44
41
  file?: string;
45
42
  }] |
@@ -91,6 +88,16 @@ declare namespace MCR {
91
88
  }] |
92
89
  ['text-summary'] | ['text-summary', {
93
90
  file?: string;
91
+ }] |
92
+ ['console-summary'] | ['console-summary', {
93
+ metrics?: Array<"bytes" | "functions" | "branches" | "lines" | "statements">;
94
+ }] |
95
+ ['raw'] | ['raw', {
96
+ outputDir?: string;
97
+ }] |
98
+ [string] | [string, {
99
+ type?: "v8" | "istanbul" | "both";
100
+ [key: string]: any;
94
101
  }];
95
102
 
96
103
  export type AddedResults = {
@@ -172,6 +179,9 @@ declare namespace MCR {
172
179
  /** {string} output dir */
173
180
  outputDir?: string;
174
181
 
182
+ /** {string|string[]} input raw dir(s) */
183
+ inputDir?: string | string[];
184
+
175
185
  /** {string} v8 or html for istanbul by default
176
186
  * {array} multiple reports with options
177
187
  * v8 report or istanbul supported reports */
package/lib/index.js CHANGED
@@ -4,7 +4,7 @@ const defaultOptions = require('./default/options.js');
4
4
  const Util = require('./utils/util.js');
5
5
 
6
6
  const { initV8ListAndSourcemap } = require('./v8/v8.js');
7
- const { getCoverageDataList, generateCoverageReports } = require('./generate.js');
7
+ const { getInputData, generateCoverageReports } = require('./generate.js');
8
8
 
9
9
  class CoverageReport {
10
10
 
@@ -41,10 +41,12 @@ class CoverageReport {
41
41
  // add coverage data: {array} V8 format, {object} Istanbul format
42
42
  async add(data) {
43
43
 
44
+ const time_start = Date.now();
45
+
44
46
  this.initOptions();
45
47
 
46
48
  if (!Util.checkCoverageData(data)) {
47
- Util.logError(`The coverage data must be Array(V8) or Object(Istanbul): ${this.options.name}`);
49
+ Util.logError(`${this.options.name}: The added coverage data must be Array(V8) or Object(Istanbul)`);
48
50
  return;
49
51
  }
50
52
 
@@ -69,40 +71,68 @@ class CoverageReport {
69
71
  const dataContent = JSON.stringify(results);
70
72
  await Util.writeFile(dataPath, dataContent);
71
73
 
74
+ Util.logTime(`added coverage data: ${results.type}`, time_start);
75
+
72
76
  return results;
73
77
  }
74
78
 
75
79
  // generate report
76
80
  async generate() {
77
81
 
78
- if (!this.hasCache()) {
79
- Util.logError(`Not found coverage cache: ${this.options.cacheDir}`);
82
+ const time_start = Date.now();
83
+
84
+ this.initOptions();
85
+
86
+ const { inputDir, cacheDir } = this.options;
87
+ const inputDirs = Util.toList(inputDir, ',');
88
+ if (this.hasCache()) {
89
+ inputDirs.push(cacheDir);
90
+ }
91
+
92
+ const inputList = inputDirs.filter((dir) => {
93
+ const hasDir = fs.existsSync(dir);
94
+ if (!hasDir) {
95
+ Util.logError(`Not found coverage data dir: ${Util.relativePath(dir)}`);
96
+ }
97
+ return hasDir;
98
+ });
99
+
100
+ if (!inputList.length) {
80
101
  return;
81
102
  }
82
103
 
83
- const cacheDir = this.options.cacheDir;
84
- const dataList = await getCoverageDataList(cacheDir);
85
- if (!dataList) {
86
- Util.logError(`Not found coverage data in cache dir: ${cacheDir}`);
104
+ const { dataList, sourceCache } = await getInputData(inputList);
105
+ if (!dataList.length) {
106
+ const dirs = inputList.map((dir) => Util.relativePath(dir));
107
+ Util.logError(`Not found coverage data in dir(s): ${dirs.join(', ')}`);
87
108
  return;
88
109
  }
89
110
 
90
111
  // empty output dir except cache dir before generate reports
91
112
  const outputDir = this.options.outputDir;
113
+
114
+ if (fs.existsSync(outputDir)) {
92
115
  // if assets dir is out of output dir will be ignore
93
- fs.readdirSync(outputDir).forEach((itemName) => {
94
- if (itemName === this.cacheDirName) {
95
- return;
96
- }
97
- Util.rmSync(path.resolve(outputDir, itemName));
98
- });
116
+ fs.readdirSync(outputDir).forEach((itemName) => {
117
+ if (itemName === this.cacheDirName) {
118
+ return;
119
+ }
120
+ Util.rmSync(path.resolve(outputDir, itemName));
121
+ });
122
+ } else {
123
+ fs.mkdirSync(outputDir, {
124
+ recursive: true
125
+ });
126
+ }
99
127
 
100
- const coverageResults = await generateCoverageReports(dataList, this.options);
128
+ const coverageResults = await generateCoverageReports(dataList, sourceCache, this.options);
101
129
 
102
130
  if (this.logging !== 'debug') {
103
131
  Util.rmSync(cacheDir);
104
132
  }
105
133
 
134
+ Util.logTime(`generated coverage reports: ${coverageResults.reportPath}`, time_start);
135
+
106
136
  const onEnd = this.options.onEnd;
107
137
  if (typeof onEnd === 'function') {
108
138
  await onEnd(coverageResults);
@@ -52,7 +52,7 @@ const saveIstanbulReports = (coverageData, fileSources, options) => {
52
52
  coverageMap,
53
53
  // The summarizer to default to (may be overridden by some reports)
54
54
  // values can be nested/flat/pkg. Defaults to 'pkg'
55
- defaultSummarizer: options.defaultSummarizer || 'nested',
55
+ defaultSummarizer: options.defaultSummarizer || 'pkg',
56
56
 
57
57
  dir: options.outputDir,
58
58
  watermarks,
@@ -89,7 +89,8 @@ const saveIstanbulReports = (coverageData, fileSources, options) => {
89
89
 
90
90
  const istanbulGroup = options.reportGroup.istanbul;
91
91
  Object.keys(istanbulGroup).forEach((reportName) => {
92
- const report = istanbulReports.create(reportName, istanbulGroup[reportName]);
92
+ const reportOptions = istanbulGroup[reportName];
93
+ const report = istanbulReports.create(reportName, reportOptions);
93
94
  report.execute(context);
94
95
  });
95
96
 
@@ -115,14 +116,13 @@ const saveIstanbulReports = (coverageData, fileSources, options) => {
115
116
  return coverageResults;
116
117
  };
117
118
 
118
- const mergeIstanbulCoverage = (dataList, options) => {
119
+ const mergeIstanbulCoverage = (dataList) => {
120
+ const istanbulCoverageList = dataList.map((it) => it.data);
119
121
  const coverageMap = istanbulLibCoverage.createCoverageMap();
120
- dataList.forEach((d) => {
121
- coverageMap.merge(d.data);
122
+ istanbulCoverageList.forEach((coverage) => {
123
+ coverageMap.merge(coverage);
122
124
  });
123
-
124
125
  const istanbulData = coverageMap.toJSON();
125
-
126
126
  return istanbulData;
127
127
  };
128
128