monocart-reporter 1.7.0 → 1.7.2
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 +8 -12
- package/lib/cli.js +1 -1
- package/lib/common.js +2 -3
- package/lib/default/options.js +4 -3
- package/lib/generate-data.js +2 -7
- package/lib/generate-report.js +10 -11
- package/lib/index.d.ts +2 -9
- package/lib/index.js +6 -0
- package/lib/merge-data.js +7 -6
- package/lib/plugins/audit/audit.js +4 -2
- package/lib/plugins/comments.js +2 -3
- package/lib/plugins/coverage/converter/collect-source-maps.js +194 -0
- package/lib/plugins/coverage/converter/converter.js +547 -0
- package/lib/plugins/coverage/converter/decode-mappings.js +49 -0
- package/lib/plugins/coverage/{v8 → converter}/dedupe.js +8 -1
- package/lib/plugins/coverage/converter/find-original-range.js +576 -0
- package/lib/plugins/coverage/converter/info-branch.js +30 -0
- package/lib/plugins/coverage/converter/info-function.js +29 -0
- package/lib/plugins/coverage/converter/info-line.js +20 -0
- package/lib/plugins/coverage/converter/position-mapping.js +183 -0
- package/lib/plugins/coverage/{coverage-utils.js → converter/source-path.js} +26 -42
- package/lib/plugins/coverage/coverage.js +61 -57
- package/lib/plugins/coverage/istanbul/istanbul.js +21 -174
- package/lib/plugins/coverage/v8/v8.js +22 -30
- package/lib/plugins/network/network.js +4 -13
- package/lib/plugins/state/client.js +3 -4
- package/lib/plugins/state/state.js +6 -3
- package/lib/runtime/monocart-code-viewer.js +1 -1
- package/lib/runtime/monocart-coverage.js +13 -14
- package/lib/runtime/monocart-formatter.js +1 -1
- 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/runtime/monocart-vendor.js +13 -13
- package/lib/utils/util.js +97 -3
- package/package.json +5 -6
- package/lib/plugins/coverage/v8/position-mapping.js +0 -92
- package/lib/plugins/coverage/v8/source-map.js +0 -464
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const EC = require('eight-colors');
|
|
4
|
-
|
|
5
|
-
const { SourceMapConsumer } = require('source-map');
|
|
6
|
-
|
|
7
|
-
const PositionMapping = require('./position-mapping.js');
|
|
8
|
-
const { dedupeCountRanges } = require('./dedupe.js');
|
|
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');
|
|
14
|
-
|
|
15
|
-
// SourceMapConsumer.GREATEST_LOWER_BOUND = 1;
|
|
16
|
-
// SourceMapConsumer.LEAST_UPPER_BOUND = 2;
|
|
17
|
-
const BIAS = {
|
|
18
|
-
left: SourceMapConsumer.GREATEST_LOWER_BOUND,
|
|
19
|
-
right: SourceMapConsumer.LEAST_UPPER_BOUND
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// =========================================================================================================
|
|
23
|
-
|
|
24
|
-
const findOriginalPosition = (consumer, line, column, sides) => {
|
|
25
|
-
let original;
|
|
26
|
-
for (const side of sides) {
|
|
27
|
-
original = consumer.originalPositionFor({
|
|
28
|
-
line,
|
|
29
|
-
column,
|
|
30
|
-
bias: BIAS[side]
|
|
31
|
-
});
|
|
32
|
-
if (original.source !== null) {
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (original && original.source !== null) {
|
|
37
|
-
return original;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const findOriginalStartPosition = (consumer, sLoc) => {
|
|
42
|
-
const { line, column } = sLoc;
|
|
43
|
-
return findOriginalPosition(consumer, line, column, ['right', 'left']);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const findOriginalEndInRange = (consumer, generatedMapping, range) => {
|
|
47
|
-
const { start, end } = range;
|
|
48
|
-
// from -2 (already -1)
|
|
49
|
-
// > start (no need equal)
|
|
50
|
-
for (let i = end - 2; i > start; i--) {
|
|
51
|
-
const loc = generatedMapping.offsetToLocation(i);
|
|
52
|
-
const op = findOriginalPosition(consumer, loc.line, loc.column, ['left', 'right']);
|
|
53
|
-
if (op) {
|
|
54
|
-
return op;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const findOriginalEndPosition = (consumer, eLoc, generatedMapping, range) => {
|
|
60
|
-
const { line, column } = eLoc;
|
|
61
|
-
|
|
62
|
-
// before end column must be >= 0
|
|
63
|
-
const currentColumn = Math.max(column - 1, 0);
|
|
64
|
-
|
|
65
|
-
let ep = findOriginalPosition(consumer, line, currentColumn, ['left', 'right']);
|
|
66
|
-
if (!ep) {
|
|
67
|
-
ep = findOriginalEndInRange(consumer, generatedMapping, range);
|
|
68
|
-
if (!ep) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const afterEndMapping = consumer.generatedPositionFor({
|
|
74
|
-
source: ep.source,
|
|
75
|
-
line: ep.line,
|
|
76
|
-
column: ep.column + 1,
|
|
77
|
-
bias: BIAS.right
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
if (afterEndMapping.line === null) {
|
|
81
|
-
return {
|
|
82
|
-
source: ep.source,
|
|
83
|
-
line: ep.line,
|
|
84
|
-
column: Infinity
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const mapping = consumer.originalPositionFor(afterEndMapping);
|
|
89
|
-
if (mapping.line !== ep.line) {
|
|
90
|
-
return {
|
|
91
|
-
source: ep.source,
|
|
92
|
-
line: ep.line,
|
|
93
|
-
column: Infinity
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return mapping;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// =========================================================================================================
|
|
101
|
-
|
|
102
|
-
const getOriginalMappings = (consumer, options) => {
|
|
103
|
-
|
|
104
|
-
// source filter
|
|
105
|
-
let sourceList = consumer.sources;
|
|
106
|
-
if (typeof options.sourceFilter === 'function') {
|
|
107
|
-
sourceList = sourceList.filter((sourceName) => {
|
|
108
|
-
return options.sourceFilter(sourceName);
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// create original content mappings
|
|
113
|
-
const originalMappings = new Map();
|
|
114
|
-
for (const sourceName of sourceList) {
|
|
115
|
-
// console.log(`add source: ${k}`);
|
|
116
|
-
const sourceContent = consumer.sourceContentFor(sourceName);
|
|
117
|
-
if (typeof sourceContent !== 'string') {
|
|
118
|
-
EC.logRed(`[MCR] not found source content: ${sourceName}`);
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const mapping = new PositionMapping(sourceContent, sourceName);
|
|
123
|
-
originalMappings.set(sourceName, mapping);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return originalMappings;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// =========================================================================================================
|
|
130
|
-
|
|
131
|
-
const addOriginalRange = (originalMapping, start, end, count) => {
|
|
132
|
-
originalMapping.ranges.push({
|
|
133
|
-
start,
|
|
134
|
-
end,
|
|
135
|
-
count
|
|
136
|
-
});
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// =========================================================================================================
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const unpackJsSourceMap = async (item, v8list, options) => {
|
|
143
|
-
// console.log('------------------------------------------------------');
|
|
144
|
-
// console.log(item.type, item.url);
|
|
145
|
-
// console.log(Object.keys(item));
|
|
146
|
-
|
|
147
|
-
const sourceMap = item.sourceMap;
|
|
148
|
-
|
|
149
|
-
const fileUrls = {};
|
|
150
|
-
const fileSources = {};
|
|
151
|
-
initSourceMapRootAndUrl(sourceMap, fileUrls, fileSources);
|
|
152
|
-
|
|
153
|
-
const generatedMapping = new PositionMapping(item.source);
|
|
154
|
-
const consumer = await new SourceMapConsumer(sourceMap);
|
|
155
|
-
const originalMappings = getOriginalMappings(consumer, options);
|
|
156
|
-
|
|
157
|
-
// generated ranges to original ranges
|
|
158
|
-
item.ranges.forEach((range) => {
|
|
159
|
-
|
|
160
|
-
// find start location
|
|
161
|
-
const sLoc = generatedMapping.offsetToLocation(range.start);
|
|
162
|
-
const oSLoc = findOriginalStartPosition(consumer, sLoc);
|
|
163
|
-
if (!oSLoc) {
|
|
164
|
-
// not found start
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// if source excluded
|
|
169
|
-
const currentSource = oSLoc.source;
|
|
170
|
-
const originalMapping = originalMappings.get(currentSource);
|
|
171
|
-
if (!originalMapping) {
|
|
172
|
-
// possible this source has been filtered
|
|
173
|
-
// console.log(`not found source: ${currentSource}`);
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const originalStart = originalMapping.locationToOffset(oSLoc);
|
|
178
|
-
|
|
179
|
-
// find end location
|
|
180
|
-
const eLoc = generatedMapping.offsetToLocation(range.end);
|
|
181
|
-
const oELoc = findOriginalEndPosition(consumer, eLoc, generatedMapping, range);
|
|
182
|
-
if (!oELoc) {
|
|
183
|
-
|
|
184
|
-
// console.log(EC.red('not found end'));
|
|
185
|
-
// console.log(item.url);
|
|
186
|
-
// console.log(originalMapping.sourceName);
|
|
187
|
-
// console.log('generated start', sLoc.line, sLoc.column, 'original start', oSLoc.line, oSLoc.column);
|
|
188
|
-
// console.log('generated end', eLoc.line, eLoc.column);
|
|
189
|
-
|
|
190
|
-
// can NOT use file end
|
|
191
|
-
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (oSLoc.source !== oELoc.source) {
|
|
196
|
-
// console.log('ERROR: range crossed source file', range, oSLoc.source, oELoc.source);
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const originalEnd = originalMapping.locationToOffset(oELoc);
|
|
201
|
-
if (originalEnd < originalStart) {
|
|
202
|
-
// range start greater than end
|
|
203
|
-
addOriginalRange(originalMapping, originalEnd, originalStart, range.count);
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
addOriginalRange(originalMapping, originalStart, originalEnd, range.count);
|
|
208
|
-
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
consumer.destroy();
|
|
212
|
-
|
|
213
|
-
// append to v8list
|
|
214
|
-
originalMappings.forEach((originalMapping, currentSource) => {
|
|
215
|
-
|
|
216
|
-
const url = fileUrls[currentSource] || currentSource;
|
|
217
|
-
const ranges = dedupeCountRanges(originalMapping.ranges);
|
|
218
|
-
|
|
219
|
-
// console.log('add source url', url);
|
|
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
|
-
|
|
236
|
-
v8list.push({
|
|
237
|
-
url,
|
|
238
|
-
id,
|
|
239
|
-
type,
|
|
240
|
-
sourcePath: currentSource,
|
|
241
|
-
distFile: item.sourceMap.file,
|
|
242
|
-
ranges,
|
|
243
|
-
source
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
});
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
// =========================================================================================================
|
|
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
|
-
// =========================================================================================================
|
|
405
|
-
const filterSourceMapList = (v8list, options) => {
|
|
406
|
-
const sourceMapList = [];
|
|
407
|
-
const indexes = [];
|
|
408
|
-
|
|
409
|
-
v8list.forEach((item, i) => {
|
|
410
|
-
const sourceMap = item.sourceMap;
|
|
411
|
-
if (!sourceMap) {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
sourceMapList.push(item);
|
|
415
|
-
indexes.push(i);
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
if (!sourceMapList.length) {
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// do not remove in debug mode
|
|
423
|
-
if (options.debug) {
|
|
424
|
-
return sourceMapList;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// remove dist file if found sourceMap
|
|
428
|
-
if (options.excludeDistFile) {
|
|
429
|
-
indexes.reverse();
|
|
430
|
-
indexes.forEach((i) => {
|
|
431
|
-
v8list.splice(i, 1);
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
return sourceMapList;
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
// requires ranges before unpack
|
|
439
|
-
const unpackSourceMaps = async (v8list, options) => {
|
|
440
|
-
|
|
441
|
-
// collect source maps
|
|
442
|
-
if (!options.unpackSourceMap) {
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const sourceMapList = filterSourceMapList(v8list, options);
|
|
447
|
-
if (!sourceMapList) {
|
|
448
|
-
// nothing to unpack
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// console.log(sourceMapList);
|
|
453
|
-
|
|
454
|
-
// only js
|
|
455
|
-
for (const item of sourceMapList) {
|
|
456
|
-
await unpackJsSourceMap(item, v8list, options);
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
module.exports = {
|
|
462
|
-
collectSourceMaps,
|
|
463
|
-
unpackSourceMaps
|
|
464
|
-
};
|