monocart-reporter 1.6.33 → 1.6.35
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 +50 -53
- package/lib/cli.js +10 -3
- package/lib/generate-data.js +7 -4
- package/lib/plugins/audit/audit.js +3 -6
- package/lib/plugins/coverage/coverage-utils.js +33 -71
- package/lib/plugins/coverage/coverage.js +84 -61
- package/lib/plugins/coverage/istanbul/istanbul.js +25 -51
- package/lib/plugins/coverage/v8/dedupe.js +8 -17
- package/lib/plugins/coverage/v8/source-map.js +187 -21
- package/lib/plugins/coverage/v8/v8.js +132 -91
- package/lib/plugins/network/network.js +7 -7
- package/lib/runtime/monocart-common.js +1 -1
- package/lib/runtime/monocart-coverage.js +14 -11
- package/lib/runtime/monocart-network.js +1 -1
- package/lib/runtime/monocart-reporter.js +1 -1
- package/lib/runtime/monocart-v8.js +1 -1
- package/lib/utils/util.js +15 -0
- package/lib/visitor.js +17 -9
- package/package.json +5 -3
|
@@ -14,18 +14,31 @@ const {
|
|
|
14
14
|
convertSourceMap
|
|
15
15
|
} = require('../../../runtime/monocart-coverage.js');
|
|
16
16
|
|
|
17
|
+
const { initSourceMapRootAndUrl } = require('../coverage-utils.js');
|
|
18
|
+
|
|
17
19
|
// const V8toIstanbul = require('v8-to-istanbul');
|
|
18
20
|
// const istanbulLibCoverage = require('istanbul-lib-coverage');
|
|
19
21
|
// const istanbulLibReport = require('istanbul-lib-report');
|
|
20
22
|
|
|
21
|
-
const {
|
|
22
|
-
getSourcePath, mergeSourceRoot, collectSourceMaps
|
|
23
|
-
} = require('../coverage-utils.js');
|
|
23
|
+
const saveIstanbulReport = (coverageData, fileSources, options) => {
|
|
24
24
|
|
|
25
|
+
// source path handler
|
|
26
|
+
let data = coverageData;
|
|
27
|
+
if (typeof options.sourcePath === 'function') {
|
|
28
|
+
data = {};
|
|
29
|
+
Object.keys(coverageData).forEach((sourcePath) => {
|
|
30
|
+
const d = coverageData[sourcePath];
|
|
31
|
+
const newSourcePath = options.sourcePath(sourcePath, fileSources);
|
|
32
|
+
if (newSourcePath) {
|
|
33
|
+
sourcePath = newSourcePath;
|
|
34
|
+
}
|
|
35
|
+
d.path = sourcePath;
|
|
36
|
+
data[sourcePath] = d;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
25
39
|
|
|
26
|
-
const saveIstanbulReport = (coverageData, fileSources, options) => {
|
|
27
40
|
|
|
28
|
-
const coverageMap = istanbulLibCoverage.createCoverageMap(
|
|
41
|
+
const coverageMap = istanbulLibCoverage.createCoverageMap(data);
|
|
29
42
|
|
|
30
43
|
// https://github.com/istanbuljs/istanbuljs/tree/master/packages/istanbul-lib-report
|
|
31
44
|
const contextOptions = {
|
|
@@ -99,46 +112,15 @@ const saveIstanbulReport = (coverageData, fileSources, options) => {
|
|
|
99
112
|
|
|
100
113
|
// ===================================================================================================
|
|
101
114
|
|
|
102
|
-
const initIstanbulV8List = async (v8list, options) => {
|
|
103
|
-
|
|
104
|
-
// filter list
|
|
105
|
-
const entryFilter = options.entryFilter;
|
|
106
|
-
if (typeof entryFilter === 'function') {
|
|
107
|
-
v8list = v8list.filter(entryFilter);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// only js with source (without css)
|
|
111
|
-
v8list = v8list.filter((item) => {
|
|
112
|
-
if (typeof item.source === 'string' && item.functions) {
|
|
113
|
-
return true;
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// collect source maps
|
|
118
|
-
if (options.unpackSourceMap) {
|
|
119
|
-
await collectSourceMaps(v8list);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// init list properties
|
|
123
|
-
v8list.forEach((item, i) => {
|
|
124
|
-
const sourcePath = getSourcePath(item.url, i + 1, 'js');
|
|
125
|
-
const filename = path.basename(sourcePath);
|
|
126
|
-
item.filename = filename;
|
|
127
|
-
item.sourcePath = sourcePath;
|
|
128
|
-
// console.log(sourcePath);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
return v8list;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
115
|
const getConversionSources = (item, fileSources) => {
|
|
116
|
+
|
|
135
117
|
const { source, sourceMap } = item;
|
|
136
118
|
|
|
137
119
|
fileSources[item.sourcePath] = source;
|
|
138
120
|
|
|
139
121
|
const sources = {
|
|
140
122
|
// remove map file
|
|
141
|
-
source: convertSourceMap.
|
|
123
|
+
source: convertSourceMap.removeComments(source)
|
|
142
124
|
};
|
|
143
125
|
|
|
144
126
|
if (!sourceMap) {
|
|
@@ -151,17 +133,8 @@ const getConversionSources = (item, fileSources) => {
|
|
|
151
133
|
// 'webpack://monocart-v8/external umd "monocart-code-viewer"'
|
|
152
134
|
// format the url to sourcePath
|
|
153
135
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
sourceMap.sourceRoot = '';
|
|
157
|
-
|
|
158
|
-
// resolve source path and add to file sources cache for html report sourceFinder
|
|
159
|
-
sourceMap.sources = sourceMap.sources.map((sourceName, i) => {
|
|
160
|
-
const sourceUrl = mergeSourceRoot(sourceRoot, sourceName);
|
|
161
|
-
const newSourceName = getSourcePath(sourceUrl, i + 1);
|
|
162
|
-
fileSources[newSourceName] = sourceMap.sourcesContent[i];
|
|
163
|
-
return newSourceName;
|
|
164
|
-
});
|
|
136
|
+
const fileUrls = {};
|
|
137
|
+
initSourceMapRootAndUrl(sourceMap, fileUrls, fileSources);
|
|
165
138
|
|
|
166
139
|
// console.log(sourceMap.sources);
|
|
167
140
|
|
|
@@ -177,7 +150,8 @@ const convertV8ToIstanbul = async (v8list, options) => {
|
|
|
177
150
|
|
|
178
151
|
// console.log('v8list before', v8list.map((it) => it.url));
|
|
179
152
|
|
|
180
|
-
|
|
153
|
+
// only js with source (without css)
|
|
154
|
+
v8list = v8list.filter((item) => item.type === 'js');
|
|
181
155
|
|
|
182
156
|
// console.log('v8list after', v8list.map((it) => it.url));
|
|
183
157
|
// console.log('has map', v8list.filter((it) => it.sourceMap));
|
|
@@ -226,7 +200,7 @@ const convertV8ToIstanbul = async (v8list, options) => {
|
|
|
226
200
|
|
|
227
201
|
const coverageData = coverageMap.toJSON();
|
|
228
202
|
|
|
229
|
-
// console.log('
|
|
203
|
+
// console.log('coverageData', Object.keys(coverageData));
|
|
230
204
|
|
|
231
205
|
return {
|
|
232
206
|
coverageData,
|
|
@@ -71,35 +71,26 @@ const dedupeCountRanges = (ranges) => {
|
|
|
71
71
|
|
|
72
72
|
sortRanges(ranges);
|
|
73
73
|
|
|
74
|
+
let hasDedupe = false;
|
|
75
|
+
|
|
74
76
|
// merge count for same range
|
|
75
77
|
ranges.reduce((lastRange, range) => {
|
|
76
78
|
if (range.start === lastRange.start && range.end === lastRange.end) {
|
|
77
79
|
range.dedupe = true;
|
|
78
80
|
lastRange.count += range.count;
|
|
81
|
+
|
|
82
|
+
hasDedupe = true;
|
|
83
|
+
|
|
79
84
|
return lastRange;
|
|
80
85
|
}
|
|
81
86
|
return range;
|
|
82
87
|
});
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// connect uncovered ranges (count = 0)
|
|
89
|
-
const coveredRanges = [];
|
|
90
|
-
const uncoveredRanges = [];
|
|
91
|
-
for (const range of ranges) {
|
|
92
|
-
if (range.count > 0) {
|
|
93
|
-
coveredRanges.push(range);
|
|
94
|
-
} else {
|
|
95
|
-
uncoveredRanges.push(range);
|
|
96
|
-
}
|
|
89
|
+
if (hasDedupe) {
|
|
90
|
+
// console.log(ranges);
|
|
91
|
+
ranges = ranges.filter((it) => !it.dedupe);
|
|
97
92
|
}
|
|
98
93
|
|
|
99
|
-
ranges = [].concat(dedupeRanges(uncoveredRanges)).concat(coveredRanges);
|
|
100
|
-
|
|
101
|
-
sortRanges(ranges);
|
|
102
|
-
|
|
103
94
|
// console.log('ranges length after', ranges.length);
|
|
104
95
|
|
|
105
96
|
return ranges;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
1
3
|
const EC = require('eight-colors');
|
|
2
4
|
|
|
3
5
|
const { SourceMapConsumer } = require('source-map');
|
|
4
6
|
|
|
5
7
|
const PositionMapping = require('./position-mapping.js');
|
|
6
8
|
const { dedupeCountRanges } = require('./dedupe.js');
|
|
7
|
-
const {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const { initSourceMapRootAndUrl } = require('../coverage-utils.js');
|
|
10
|
+
|
|
11
|
+
const Concurrency = require('../../../platform/concurrency.js');
|
|
12
|
+
const { convertSourceMap, axios } = require('../../../runtime/monocart-coverage.js');
|
|
13
|
+
const Util = require('../../../utils/util.js');
|
|
10
14
|
|
|
11
15
|
// SourceMapConsumer.GREATEST_LOWER_BOUND = 1;
|
|
12
16
|
// SourceMapConsumer.LEAST_UPPER_BOUND = 2;
|
|
@@ -134,6 +138,7 @@ const addOriginalRange = (originalMapping, start, end, count) => {
|
|
|
134
138
|
|
|
135
139
|
// =========================================================================================================
|
|
136
140
|
|
|
141
|
+
|
|
137
142
|
const unpackJsSourceMap = async (item, v8list, options) => {
|
|
138
143
|
// console.log('------------------------------------------------------');
|
|
139
144
|
// console.log(item.type, item.url);
|
|
@@ -141,17 +146,9 @@ const unpackJsSourceMap = async (item, v8list, options) => {
|
|
|
141
146
|
|
|
142
147
|
const sourceMap = item.sourceMap;
|
|
143
148
|
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
sourceMap
|
|
147
|
-
|
|
148
|
-
const urlMap = {};
|
|
149
|
-
sourceMap.sources = sourceMap.sources.map((sourceName, i) => {
|
|
150
|
-
const sourceUrl = mergeSourceRoot(sourceRoot, sourceName);
|
|
151
|
-
const newSourceName = getSourcePath(sourceUrl, i + 1);
|
|
152
|
-
urlMap[newSourceName] = sourceUrl;
|
|
153
|
-
return newSourceName;
|
|
154
|
-
});
|
|
149
|
+
const fileUrls = {};
|
|
150
|
+
const fileSources = {};
|
|
151
|
+
initSourceMapRootAndUrl(sourceMap, fileUrls, fileSources);
|
|
155
152
|
|
|
156
153
|
const generatedMapping = new PositionMapping(item.source);
|
|
157
154
|
const consumer = await new SourceMapConsumer(sourceMap);
|
|
@@ -216,18 +213,34 @@ const unpackJsSourceMap = async (item, v8list, options) => {
|
|
|
216
213
|
// append to v8list
|
|
217
214
|
originalMappings.forEach((originalMapping, currentSource) => {
|
|
218
215
|
|
|
219
|
-
const url =
|
|
216
|
+
const url = fileUrls[currentSource] || currentSource;
|
|
220
217
|
const ranges = dedupeCountRanges(originalMapping.ranges);
|
|
221
218
|
|
|
222
219
|
// console.log('add source url', url);
|
|
223
220
|
|
|
221
|
+
// original source and id
|
|
222
|
+
const source = originalMapping.source;
|
|
223
|
+
const id = Util.calculateSha1(url + source);
|
|
224
|
+
|
|
225
|
+
let ext = path.extname(currentSource);
|
|
226
|
+
let type = '';
|
|
227
|
+
if (ext) {
|
|
228
|
+
ext = ext.slice(1);
|
|
229
|
+
const reg = /^[a-z0-9]+$/;
|
|
230
|
+
if (reg.test(ext)) {
|
|
231
|
+
type = ext;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
224
236
|
v8list.push({
|
|
225
237
|
url,
|
|
226
|
-
|
|
238
|
+
id,
|
|
239
|
+
type,
|
|
227
240
|
sourcePath: currentSource,
|
|
228
241
|
distFile: item.sourceMap.file,
|
|
229
242
|
ranges,
|
|
230
|
-
source
|
|
243
|
+
source
|
|
231
244
|
});
|
|
232
245
|
|
|
233
246
|
});
|
|
@@ -235,6 +248,160 @@ const unpackJsSourceMap = async (item, v8list, options) => {
|
|
|
235
248
|
|
|
236
249
|
// =========================================================================================================
|
|
237
250
|
|
|
251
|
+
const request = async (options) => {
|
|
252
|
+
if (typeof options === 'string') {
|
|
253
|
+
options = {
|
|
254
|
+
url: options
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
let err;
|
|
258
|
+
const res = await axios(options).catch((e) => {
|
|
259
|
+
err = e;
|
|
260
|
+
});
|
|
261
|
+
return [err, res];
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const getSourceMapUrl = (content, url) => {
|
|
265
|
+
|
|
266
|
+
const m = content.match(convertSourceMap.mapFileCommentRegex);
|
|
267
|
+
if (!m) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const comment = m.pop();
|
|
272
|
+
const r = convertSourceMap.mapFileCommentRegex.exec(comment);
|
|
273
|
+
// for some odd reason //# .. captures in 1 and /* .. */ in 2
|
|
274
|
+
const filename = r[1] || r[2];
|
|
275
|
+
|
|
276
|
+
let mapUrl;
|
|
277
|
+
|
|
278
|
+
try {
|
|
279
|
+
mapUrl = new URL(filename, url);
|
|
280
|
+
} catch (e) {
|
|
281
|
+
// console.log(e)
|
|
282
|
+
}
|
|
283
|
+
if (mapUrl) {
|
|
284
|
+
return mapUrl.toString();
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const resolveSourceMap = (data) => {
|
|
289
|
+
if (data) {
|
|
290
|
+
const { sources, sourcesContent } = data;
|
|
291
|
+
if (!sources || !sourcesContent) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
return data;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const collectInlineSourceMaps = async (v8list) => {
|
|
299
|
+
const concurrency = new Concurrency();
|
|
300
|
+
for (const item of v8list) {
|
|
301
|
+
|
|
302
|
+
const { type, source } = item;
|
|
303
|
+
|
|
304
|
+
// only for js
|
|
305
|
+
if (type === 'js') {
|
|
306
|
+
const converter = convertSourceMap.fromSource(source);
|
|
307
|
+
if (converter) {
|
|
308
|
+
item.sourceMap = resolveSourceMap(converter.sourcemap);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const sourceMapUrl = getSourceMapUrl(source, item.url);
|
|
312
|
+
if (sourceMapUrl) {
|
|
313
|
+
item.sourceMapUrl = sourceMapUrl;
|
|
314
|
+
concurrency.addItem(item);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
await concurrency.start(async (item) => {
|
|
319
|
+
const [err, res] = await request({
|
|
320
|
+
url: item.sourceMapUrl
|
|
321
|
+
});
|
|
322
|
+
if (!err && res) {
|
|
323
|
+
item.sourceMap = resolveSourceMap(res.data);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const collectFileSourceMaps = async (v8list, options) => {
|
|
329
|
+
const concurrency = new Concurrency();
|
|
330
|
+
for (const item of v8list) {
|
|
331
|
+
|
|
332
|
+
const {
|
|
333
|
+
type, url, source, id
|
|
334
|
+
} = item;
|
|
335
|
+
|
|
336
|
+
// remove source just keep functions to reduce artifacts size
|
|
337
|
+
delete item.source;
|
|
338
|
+
|
|
339
|
+
const sourcePath = Util.resolveArtifactSourcePath(options.artifactsDir, id);
|
|
340
|
+
if (fs.existsSync(sourcePath)) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const sourceData = {
|
|
345
|
+
url,
|
|
346
|
+
id,
|
|
347
|
+
source: convertSourceMap.removeComments(source)
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// only for js
|
|
351
|
+
if (type === 'js') {
|
|
352
|
+
const converter = convertSourceMap.fromSource(source);
|
|
353
|
+
if (converter) {
|
|
354
|
+
sourceData.sourceMap = resolveSourceMap(converter.sourcemap);
|
|
355
|
+
await saveSourceFile(sourcePath, sourceData);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const sourceMapUrl = getSourceMapUrl(source, item.url);
|
|
359
|
+
if (sourceMapUrl) {
|
|
360
|
+
concurrency.addItem({
|
|
361
|
+
sourceMapUrl,
|
|
362
|
+
sourcePath,
|
|
363
|
+
sourceData
|
|
364
|
+
});
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
await saveSourceFile(sourcePath, sourceData);
|
|
370
|
+
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
await concurrency.start(async (item) => {
|
|
374
|
+
const [err, res] = await request({
|
|
375
|
+
url: item.sourceMapUrl
|
|
376
|
+
});
|
|
377
|
+
const sourceData = item.sourceData;
|
|
378
|
+
if (!err && res) {
|
|
379
|
+
sourceData.sourceMap = resolveSourceMap(res.data);
|
|
380
|
+
}
|
|
381
|
+
await saveSourceFile(item.sourcePath, sourceData);
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const saveSourceFile = async (filePath, data) => {
|
|
386
|
+
await Util.writeFile(filePath, JSON.stringify(data));
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
const collectSourceMaps = async (v8list, options, inlineSourceMap) => {
|
|
390
|
+
|
|
391
|
+
if (!options.unpackSourceMap) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (inlineSourceMap) {
|
|
396
|
+
await collectInlineSourceMaps(v8list);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
await collectFileSourceMaps(v8list, options);
|
|
401
|
+
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// =========================================================================================================
|
|
238
405
|
const filterSourceMapList = (v8list, options) => {
|
|
239
406
|
const sourceMapList = [];
|
|
240
407
|
const indexes = [];
|
|
@@ -262,16 +429,14 @@ const filterSourceMapList = (v8list, options) => {
|
|
|
262
429
|
return sourceMapList;
|
|
263
430
|
};
|
|
264
431
|
|
|
432
|
+
// requires ranges before unpack
|
|
265
433
|
const unpackSourceMaps = async (v8list, options) => {
|
|
266
434
|
|
|
435
|
+
// collect source maps
|
|
267
436
|
if (!options.unpackSourceMap) {
|
|
268
437
|
return;
|
|
269
438
|
}
|
|
270
439
|
|
|
271
|
-
// console.log(v8list.map((it) => it.url).join(', '));
|
|
272
|
-
|
|
273
|
-
await collectSourceMaps(v8list);
|
|
274
|
-
|
|
275
440
|
const sourceMapList = filterSourceMapList(v8list, options);
|
|
276
441
|
if (!sourceMapList) {
|
|
277
442
|
// nothing to unpack
|
|
@@ -288,5 +453,6 @@ const unpackSourceMaps = async (v8list, options) => {
|
|
|
288
453
|
|
|
289
454
|
|
|
290
455
|
module.exports = {
|
|
456
|
+
collectSourceMaps,
|
|
291
457
|
unpackSourceMaps
|
|
292
458
|
};
|