monocart-coverage-reports 2.10.4 → 2.10.5
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/converter/converter.js +239 -129
- package/lib/converter/untested.js +298 -0
- package/lib/default/options.js +2 -1
- package/lib/generate.js +3 -238
- package/lib/index.d.ts +9 -2
- package/lib/istanbul/istanbul.js +27 -2
- package/lib/packages/monocart-coverage-vendor.js +2 -2
- package/lib/utils/util.js +19 -0
- package/lib/v8/v8.js +16 -36
- package/package.json +3 -3
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const Util = require('../utils/util.js');
|
|
4
|
+
|
|
5
|
+
const { pathToFileURL, fileURLToPath } = require('url');
|
|
6
|
+
|
|
7
|
+
// const EC = require('eight-colors');
|
|
8
|
+
const { minimatch, convertSourceMap } = require('../packages/monocart-coverage-vendor.js');
|
|
9
|
+
|
|
10
|
+
// ========================================================================================================
|
|
11
|
+
|
|
12
|
+
const resolveAllDirList = (input) => {
|
|
13
|
+
const dirs = Util.toList(input, ',');
|
|
14
|
+
if (!dirs.length) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const dirList = dirs.filter((it) => fs.existsSync(it));
|
|
18
|
+
if (!dirList.length) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
return dirList;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const resolveAllFilter = (input) => {
|
|
25
|
+
// for function handler
|
|
26
|
+
if (typeof input === 'function') {
|
|
27
|
+
return input;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// for single minimatch pattern
|
|
31
|
+
if (input && typeof input === 'string') {
|
|
32
|
+
// string to multiple patterns "{...}"
|
|
33
|
+
const obj = Util.strToObj(input);
|
|
34
|
+
if (obj) {
|
|
35
|
+
input = obj;
|
|
36
|
+
} else {
|
|
37
|
+
return (filePath) => {
|
|
38
|
+
return minimatch(filePath, input);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// for patterns
|
|
44
|
+
if (input && typeof input === 'object') {
|
|
45
|
+
const patterns = Object.keys(input);
|
|
46
|
+
return (filePath) => {
|
|
47
|
+
for (const pattern of patterns) {
|
|
48
|
+
if (minimatch(filePath, pattern)) {
|
|
49
|
+
return input[pattern];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// false if not matched
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// default
|
|
57
|
+
return () => true;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const resolveAllOptions = (input) => {
|
|
61
|
+
if (!input) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let dir;
|
|
66
|
+
let filter;
|
|
67
|
+
let transformer;
|
|
68
|
+
|
|
69
|
+
if (typeof input === 'string') {
|
|
70
|
+
const obj = Util.strToObj(input);
|
|
71
|
+
if (obj) {
|
|
72
|
+
dir = obj.dir;
|
|
73
|
+
filter = obj.filter;
|
|
74
|
+
transformer = obj.transformer;
|
|
75
|
+
} else {
|
|
76
|
+
dir = input;
|
|
77
|
+
}
|
|
78
|
+
} else if (Array.isArray(input)) {
|
|
79
|
+
dir = input;
|
|
80
|
+
} else {
|
|
81
|
+
dir = input.dir;
|
|
82
|
+
filter = input.filter;
|
|
83
|
+
transformer = input.transformer;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const dirList = resolveAllDirList(dir);
|
|
87
|
+
if (!dirList) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const fileFilter = resolveAllFilter(filter);
|
|
92
|
+
const fileTransformer = typeof transformer === 'function' ? transformer : () => {};
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
dirList,
|
|
96
|
+
fileFilter,
|
|
97
|
+
fileTransformer
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const resolveFileType = (fileType, filePath) => {
|
|
102
|
+
if (fileType === 'js' || fileType === 'css') {
|
|
103
|
+
return fileType;
|
|
104
|
+
}
|
|
105
|
+
const extname = path.extname(filePath);
|
|
106
|
+
if (['.css', '.scss', '.sass', '.less'].includes(extname)) {
|
|
107
|
+
return 'css';
|
|
108
|
+
}
|
|
109
|
+
return 'js';
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const saveUntestedFileSource = async (entryFile, options) => {
|
|
113
|
+
const {
|
|
114
|
+
id,
|
|
115
|
+
url,
|
|
116
|
+
source,
|
|
117
|
+
sourceMap
|
|
118
|
+
} = entryFile;
|
|
119
|
+
// console.log('-', entry.sourcePath);
|
|
120
|
+
|
|
121
|
+
const { cachePath } = Util.getCacheFileInfo('source', id, options.cacheDir);
|
|
122
|
+
if (fs.existsSync(cachePath)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// save source and sourceMap to separated json file
|
|
127
|
+
const sourceData = {
|
|
128
|
+
id,
|
|
129
|
+
url,
|
|
130
|
+
source,
|
|
131
|
+
sourceMap
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// remove comments if not debug
|
|
135
|
+
if (!Util.isDebug()) {
|
|
136
|
+
sourceData.source = convertSourceMap.removeComments(source);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// console.log('save untested file', id, url);
|
|
140
|
+
|
|
141
|
+
await Util.saveSourceCacheFile(sourceData, options);
|
|
142
|
+
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const getUntestedCoverageData = async (emptyList, options, coverageType) => {
|
|
146
|
+
|
|
147
|
+
// save all empty coverage
|
|
148
|
+
const dataId = Util.uid();
|
|
149
|
+
const results = {
|
|
150
|
+
id: dataId
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
if (coverageType === 'istanbul') {
|
|
154
|
+
results.type = 'istanbul';
|
|
155
|
+
results.data = {};
|
|
156
|
+
} else {
|
|
157
|
+
results.type = 'v8';
|
|
158
|
+
results.data = [];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const emptyCoverageList = [];
|
|
162
|
+
|
|
163
|
+
// save all empty source and sourcemap
|
|
164
|
+
for (const entryFile of emptyList) {
|
|
165
|
+
|
|
166
|
+
// for raw report: source file
|
|
167
|
+
await saveUntestedFileSource(entryFile, options);
|
|
168
|
+
|
|
169
|
+
const { type, url } = entryFile;
|
|
170
|
+
|
|
171
|
+
if (coverageType === 'istanbul') {
|
|
172
|
+
|
|
173
|
+
// ===============================================
|
|
174
|
+
const item = {
|
|
175
|
+
path: fileURLToPath(url),
|
|
176
|
+
statementMap: {},
|
|
177
|
+
fnMap: {},
|
|
178
|
+
branchMap: {},
|
|
179
|
+
s: {},
|
|
180
|
+
f: {},
|
|
181
|
+
b: {}
|
|
182
|
+
};
|
|
183
|
+
// object
|
|
184
|
+
results.data[item.path] = item;
|
|
185
|
+
emptyCoverageList.push(item);
|
|
186
|
+
|
|
187
|
+
} else {
|
|
188
|
+
|
|
189
|
+
// ===============================================
|
|
190
|
+
if (type === 'js') {
|
|
191
|
+
// empty js
|
|
192
|
+
entryFile.functions = entryFile.functions || [{
|
|
193
|
+
functionName: '',
|
|
194
|
+
ranges: [{
|
|
195
|
+
startOffset: 0,
|
|
196
|
+
endOffset: entryFile.source.length,
|
|
197
|
+
count: 0
|
|
198
|
+
}]
|
|
199
|
+
}];
|
|
200
|
+
} else {
|
|
201
|
+
// empty css
|
|
202
|
+
entryFile.ranges = entryFile.ranges || [];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const item = {
|
|
206
|
+
... entryFile
|
|
207
|
+
};
|
|
208
|
+
delete item.source;
|
|
209
|
+
delete item.sourceMap;
|
|
210
|
+
|
|
211
|
+
// array
|
|
212
|
+
results.data.push(item);
|
|
213
|
+
// will be parsed to AST and converted to V8 coverage
|
|
214
|
+
emptyCoverageList.push(entryFile);
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// for raw report: coverage file
|
|
221
|
+
const { cachePath } = Util.getCacheFileInfo('coverage', dataId, options.cacheDir);
|
|
222
|
+
await Util.writeFile(cachePath, JSON.stringify(results));
|
|
223
|
+
|
|
224
|
+
return emptyCoverageList;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const getEmptyCoverages = async (fileList, options, coverageType, fileTransformer) => {
|
|
228
|
+
|
|
229
|
+
const emptyList = [];
|
|
230
|
+
|
|
231
|
+
for (const item of fileList) {
|
|
232
|
+
const {
|
|
233
|
+
filePath, fileType, sourcePath
|
|
234
|
+
} = item;
|
|
235
|
+
const type = resolveFileType(fileType, filePath);
|
|
236
|
+
const url = pathToFileURL(filePath).toString();
|
|
237
|
+
const source = Util.readFileSync(filePath);
|
|
238
|
+
const entryFile = {
|
|
239
|
+
empty: true,
|
|
240
|
+
type,
|
|
241
|
+
url,
|
|
242
|
+
sourcePath,
|
|
243
|
+
// for empty, css supports both source and text
|
|
244
|
+
source
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
await fileTransformer(entryFile, coverageType);
|
|
248
|
+
|
|
249
|
+
// after transformer
|
|
250
|
+
entryFile.id = Util.calculateSha1(entryFile.sourcePath + entryFile.source);
|
|
251
|
+
|
|
252
|
+
emptyList.push(entryFile);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// save empty coverage for merging raw reports
|
|
256
|
+
return getUntestedCoverageData(emptyList, options, coverageType);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const getUntestedList = (testedMap, options, coverageType = 'v8') => {
|
|
260
|
+
const allOptions = resolveAllOptions(options.all);
|
|
261
|
+
// console.log('allOptions', all, allOptions);
|
|
262
|
+
if (!allOptions) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const {
|
|
266
|
+
dirList, fileFilter, fileTransformer
|
|
267
|
+
} = allOptions;
|
|
268
|
+
const fileList = [];
|
|
269
|
+
dirList.forEach((dir) => {
|
|
270
|
+
Util.forEachFile(dir, [], (fileName, fileDir) => {
|
|
271
|
+
const filePath = path.resolve(fileDir, fileName);
|
|
272
|
+
// return file extname for file type
|
|
273
|
+
const fileType = fileFilter(filePath);
|
|
274
|
+
if (fileType) {
|
|
275
|
+
const sourcePath = Util.relativePath(filePath);
|
|
276
|
+
if (!testedMap.has(sourcePath)) {
|
|
277
|
+
fileList.push({
|
|
278
|
+
filePath,
|
|
279
|
+
fileType,
|
|
280
|
+
sourcePath
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
// console.log('fileList', fileList);
|
|
287
|
+
if (!fileList.length) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return getEmptyCoverages(fileList, options, coverageType, fileTransformer);
|
|
292
|
+
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
module.exports = {
|
|
297
|
+
getUntestedList
|
|
298
|
+
};
|
package/lib/default/options.js
CHANGED
package/lib/generate.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
const EC = require('eight-colors');
|
|
6
|
-
const { minimatch } = require('./packages/monocart-coverage-vendor.js');
|
|
3
|
+
const { fileURLToPath } = require('url');
|
|
7
4
|
|
|
8
5
|
const Util = require('./utils/util.js');
|
|
9
6
|
const { convertV8List } = require('./converter/converter.js');
|
|
@@ -178,7 +175,7 @@ const getCoverageResults = async (dataList, sourceCache, options) => {
|
|
|
178
175
|
// console.log('after merge', v8list.map((it) => it.url));
|
|
179
176
|
|
|
180
177
|
const t2 = Date.now();
|
|
181
|
-
const results = convertV8List(v8list, options);
|
|
178
|
+
const results = await convertV8List(v8list, options);
|
|
182
179
|
Util.logTime('┌ [generate] converted coverage data', t2);
|
|
183
180
|
|
|
184
181
|
const {
|
|
@@ -189,7 +186,7 @@ const getCoverageResults = async (dataList, sourceCache, options) => {
|
|
|
189
186
|
|
|
190
187
|
// istanbul data
|
|
191
188
|
const t3 = Date.now();
|
|
192
|
-
const istanbulData = mergeIstanbulCoverage(dataList);
|
|
189
|
+
const istanbulData = await mergeIstanbulCoverage(dataList, options);
|
|
193
190
|
const { coverageData, fileSources } = initIstanbulData(istanbulData, options);
|
|
194
191
|
Util.logTime('┌ [generate] prepared istanbul coverage data', t3);
|
|
195
192
|
const results = await saveIstanbulReports(coverageData, fileSources, options);
|
|
@@ -219,187 +216,6 @@ const generateCoverageReports = async (dataList, sourceCache, options) => {
|
|
|
219
216
|
return coverageResults;
|
|
220
217
|
};
|
|
221
218
|
|
|
222
|
-
// ========================================================================================================
|
|
223
|
-
|
|
224
|
-
const resolveAllDirList = (input) => {
|
|
225
|
-
const dirs = Util.toList(input, ',');
|
|
226
|
-
if (!dirs.length) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
const dirList = dirs.filter((it) => fs.existsSync(it));
|
|
230
|
-
if (!dirList.length) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
return dirList;
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const resolveAllFilter = (input) => {
|
|
237
|
-
// for function handler
|
|
238
|
-
if (typeof input === 'function') {
|
|
239
|
-
return input;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// for single minimatch pattern
|
|
243
|
-
if (input && typeof input === 'string') {
|
|
244
|
-
// string to multiple patterns "{...}"
|
|
245
|
-
const obj = Util.strToObj(input);
|
|
246
|
-
if (obj) {
|
|
247
|
-
input = obj;
|
|
248
|
-
} else {
|
|
249
|
-
return (filePath) => {
|
|
250
|
-
return minimatch(filePath, input);
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// for patterns
|
|
256
|
-
if (input && typeof input === 'object') {
|
|
257
|
-
const patterns = Object.keys(input);
|
|
258
|
-
return (filePath) => {
|
|
259
|
-
for (const pattern of patterns) {
|
|
260
|
-
if (minimatch(filePath, pattern)) {
|
|
261
|
-
return input[pattern];
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
// false if not matched
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// default
|
|
269
|
-
return () => true;
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
const resolveAllDataType = (type, dataList) => {
|
|
273
|
-
if (!type && dataList.length) {
|
|
274
|
-
const firstData = dataList[0];
|
|
275
|
-
type = firstData.type;
|
|
276
|
-
}
|
|
277
|
-
const types = {
|
|
278
|
-
v8: 'v8',
|
|
279
|
-
istanbul: 'istanbul'
|
|
280
|
-
};
|
|
281
|
-
return types[type] || types.v8;
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
const resolveAllOptions = (input, dataList) => {
|
|
285
|
-
if (!input) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
let type;
|
|
290
|
-
let dir;
|
|
291
|
-
let filter;
|
|
292
|
-
|
|
293
|
-
if (typeof input === 'string') {
|
|
294
|
-
const obj = Util.strToObj(input);
|
|
295
|
-
if (obj) {
|
|
296
|
-
type = obj.type;
|
|
297
|
-
dir = obj.dir;
|
|
298
|
-
filter = obj.filter;
|
|
299
|
-
} else {
|
|
300
|
-
dir = input;
|
|
301
|
-
}
|
|
302
|
-
} else if (Array.isArray(input)) {
|
|
303
|
-
dir = input;
|
|
304
|
-
} else {
|
|
305
|
-
type = input.type;
|
|
306
|
-
dir = input.dir;
|
|
307
|
-
filter = input.filter;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const dirList = resolveAllDirList(dir);
|
|
311
|
-
if (!dirList) {
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const dataType = resolveAllDataType(type, dataList);
|
|
316
|
-
const fileFilter = resolveAllFilter(filter);
|
|
317
|
-
|
|
318
|
-
return {
|
|
319
|
-
dirList,
|
|
320
|
-
dataType,
|
|
321
|
-
fileFilter
|
|
322
|
-
};
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
const resolveFileType = (fileType, filePath) => {
|
|
326
|
-
if (fileType === 'js' || fileType === 'css') {
|
|
327
|
-
return fileType;
|
|
328
|
-
}
|
|
329
|
-
const extname = path.extname(filePath);
|
|
330
|
-
if (['.css', '.scss', '.sass', '.less'].includes(extname)) {
|
|
331
|
-
return 'css';
|
|
332
|
-
}
|
|
333
|
-
return 'js';
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
const getV8EmptyData = (fileList) => {
|
|
337
|
-
const v8DataList = [];
|
|
338
|
-
fileList.forEach((item) => {
|
|
339
|
-
const { filePath, fileType } = item;
|
|
340
|
-
const type = resolveFileType(fileType, filePath);
|
|
341
|
-
const url = pathToFileURL(filePath).toString();
|
|
342
|
-
const source = Util.readFileSync(filePath);
|
|
343
|
-
const entryFile = {
|
|
344
|
-
empty: true,
|
|
345
|
-
type,
|
|
346
|
-
url,
|
|
347
|
-
// for empty, css supports both source and text
|
|
348
|
-
source
|
|
349
|
-
};
|
|
350
|
-
v8DataList.push(entryFile);
|
|
351
|
-
});
|
|
352
|
-
return v8DataList;
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
const getIstanbulEmptyData = (fileList) => {
|
|
356
|
-
const istanbulData = {};
|
|
357
|
-
fileList.forEach((item) => {
|
|
358
|
-
const { filePath } = item;
|
|
359
|
-
istanbulData[filePath] = {
|
|
360
|
-
path: filePath,
|
|
361
|
-
statementMap: {},
|
|
362
|
-
fnMap: {},
|
|
363
|
-
branchMap: {},
|
|
364
|
-
s: {},
|
|
365
|
-
f: {},
|
|
366
|
-
b: {}
|
|
367
|
-
};
|
|
368
|
-
});
|
|
369
|
-
return istanbulData;
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const getEmptyData = (all, dataList) => {
|
|
373
|
-
const allOptions = resolveAllOptions(all, dataList);
|
|
374
|
-
// console.log('allOptions', all, allOptions);
|
|
375
|
-
if (!allOptions) {
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
const {
|
|
379
|
-
dirList, dataType, fileFilter
|
|
380
|
-
} = allOptions;
|
|
381
|
-
const fileList = [];
|
|
382
|
-
dirList.forEach((dir) => {
|
|
383
|
-
Util.forEachFile(dir, [], (fileName, fileDir) => {
|
|
384
|
-
const filePath = path.resolve(fileDir, fileName);
|
|
385
|
-
const fileType = fileFilter(filePath);
|
|
386
|
-
if (fileType) {
|
|
387
|
-
fileList.push({
|
|
388
|
-
filePath,
|
|
389
|
-
fileType
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
|
-
});
|
|
394
|
-
// console.log('fileList', fileList);
|
|
395
|
-
if (!fileList.length) {
|
|
396
|
-
return;
|
|
397
|
-
}
|
|
398
|
-
if (dataType === 'v8') {
|
|
399
|
-
return getV8EmptyData(fileList);
|
|
400
|
-
}
|
|
401
|
-
return getIstanbulEmptyData(fileList);
|
|
402
|
-
};
|
|
403
219
|
|
|
404
220
|
// ========================================================================================================
|
|
405
221
|
|
|
@@ -448,55 +264,6 @@ const addJsonData = async (mcr, dataList, sourceCache, dir, filename) => {
|
|
|
448
264
|
}
|
|
449
265
|
};
|
|
450
266
|
|
|
451
|
-
const addEmptyData = async (mcr, dataList, sourceCache) => {
|
|
452
|
-
|
|
453
|
-
const { all, cacheDir } = mcr.options;
|
|
454
|
-
// add empty coverage for all files
|
|
455
|
-
// dataList for data type, before `add` we don't which one is tested, because using hash id
|
|
456
|
-
const emptyData = getEmptyData(all, dataList);
|
|
457
|
-
if (!emptyData) {
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
let files = 0;
|
|
462
|
-
if (Util.isList(emptyData)) {
|
|
463
|
-
files = emptyData.length;
|
|
464
|
-
} else {
|
|
465
|
-
files = Object.keys(emptyData).length;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
Util.logDebug(`added all files with empty coverage: ${EC.yellow(files)}`);
|
|
469
|
-
const coverageResults = await mcr.add(emptyData);
|
|
470
|
-
// after `add`
|
|
471
|
-
if (!coverageResults) {
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
dataList.push(coverageResults);
|
|
476
|
-
|
|
477
|
-
if (coverageResults.type === 'v8') {
|
|
478
|
-
// sourceCache
|
|
479
|
-
coverageResults.data.forEach((entry) => {
|
|
480
|
-
const { id } = entry;
|
|
481
|
-
if (sourceCache.has(id)) {
|
|
482
|
-
// console.log('+', entry.sourcePath);
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
// console.log('-', entry.sourcePath);
|
|
486
|
-
const { cacheName, cachePath } = Util.getCacheFileInfo('source', id, cacheDir);
|
|
487
|
-
if (mcr.fileCache.has(cacheName)) {
|
|
488
|
-
const json = mcr.fileCache.get(cacheName);
|
|
489
|
-
sourceCache.set(json.id, json);
|
|
490
|
-
} else {
|
|
491
|
-
const content = Util.readFileSync(cachePath);
|
|
492
|
-
if (content) {
|
|
493
|
-
const json = JSON.parse(content);
|
|
494
|
-
sourceCache.set(json.id, json);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
};
|
|
500
267
|
|
|
501
268
|
const getInputData = async (mcr) => {
|
|
502
269
|
|
|
@@ -520,8 +287,6 @@ const getInputData = async (mcr) => {
|
|
|
520
287
|
}
|
|
521
288
|
}
|
|
522
289
|
|
|
523
|
-
await addEmptyData(mcr, dataList, sourceCache);
|
|
524
|
-
|
|
525
290
|
if (!dataList.length) {
|
|
526
291
|
const dirs = inputList.map((dir) => Util.relativePath(dir));
|
|
527
292
|
Util.logError(`Not found coverage data in dir(s): ${dirs.join(', ')}`);
|
package/lib/index.d.ts
CHANGED
|
@@ -359,8 +359,7 @@ declare namespace MCR {
|
|
|
359
359
|
all?: string | string[] | {
|
|
360
360
|
/** the dir(s) of all files */
|
|
361
361
|
dir: string | string[];
|
|
362
|
-
|
|
363
|
-
type?: "v8" | "istanbul";
|
|
362
|
+
|
|
364
363
|
/**
|
|
365
364
|
* the file filter, return the file type, if true, defaults to css if ".css" otherwise is js
|
|
366
365
|
*
|
|
@@ -369,6 +368,14 @@ declare namespace MCR {
|
|
|
369
368
|
filter?: string | {
|
|
370
369
|
[pattern: string]: "js" | "css" | boolean;
|
|
371
370
|
} | ((filePath: string) => "js" | "css" | boolean);
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* the file transformer for source and sourceMap
|
|
374
|
+
* some of untested files like .ts/.jsx/.vue can not be parsed to AST directly by acorn
|
|
375
|
+
* so this is the function which can transform the original source to generated source and sourceMap
|
|
376
|
+
*/
|
|
377
|
+
transformer?: (entry: any) => Promise<void>;
|
|
378
|
+
|
|
372
379
|
};
|
|
373
380
|
|
|
374
381
|
/** (V8 only) {boolean} Enable/Disable ignoring uncovered codes with the special comments: v8 ignore next/next N/start/stop */
|
package/lib/istanbul/istanbul.js
CHANGED
|
@@ -8,6 +8,7 @@ const Util = require('../utils/util.js');
|
|
|
8
8
|
const IstanbulSummary = require('./istanbul-summary.js');
|
|
9
9
|
|
|
10
10
|
const { initIstanbulSourcePath } = require('../utils/source-path.js');
|
|
11
|
+
const { getUntestedList } = require('../converter/untested.js');
|
|
11
12
|
|
|
12
13
|
const findHtmlPath = (outputDir) => {
|
|
13
14
|
const defaultHtml = path.resolve(outputDir, 'index.html');
|
|
@@ -121,18 +122,42 @@ const saveIstanbulReports = (coverageData, fileSources, options) => {
|
|
|
121
122
|
return coverageResults;
|
|
122
123
|
};
|
|
123
124
|
|
|
124
|
-
const
|
|
125
|
+
const addUntestedFiles = async (istanbulData, options) => {
|
|
126
|
+
const testedMap = new Map();
|
|
127
|
+
Object.keys(istanbulData).forEach((filePath) => {
|
|
128
|
+
const sourcePath = Util.relativePath(filePath);
|
|
129
|
+
testedMap.set(sourcePath, true);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// untested files
|
|
133
|
+
const untestedList = await getUntestedList(testedMap, options, 'istanbul');
|
|
134
|
+
if (!untestedList) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// console.log('istanbul untestedList', untestedList);
|
|
139
|
+
untestedList.forEach((item) => {
|
|
140
|
+
if (!istanbulData[item.path]) {
|
|
141
|
+
istanbulData[item.path] = item;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const mergeIstanbulCoverage = async (dataList, options) => {
|
|
125
148
|
const istanbulCoverageList = dataList.map((it) => it.data);
|
|
126
149
|
const coverageMap = istanbulLibCoverage.createCoverageMap();
|
|
127
150
|
istanbulCoverageList.forEach((coverage) => {
|
|
128
151
|
coverageMap.merge(coverage);
|
|
129
152
|
});
|
|
130
153
|
const istanbulData = coverageMap.toJSON();
|
|
154
|
+
|
|
155
|
+
await addUntestedFiles(istanbulData, options);
|
|
156
|
+
|
|
131
157
|
return istanbulData;
|
|
132
158
|
};
|
|
133
159
|
|
|
134
160
|
const initIstanbulData = (istanbulData, options) => {
|
|
135
|
-
|
|
136
161
|
const fileSources = options.fileSources || {};
|
|
137
162
|
const coverageData = initIstanbulSourcePath(istanbulData, fileSources, options);
|
|
138
163
|
|