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.
Files changed (38) hide show
  1. package/README.md +8 -12
  2. package/lib/cli.js +1 -1
  3. package/lib/common.js +2 -3
  4. package/lib/default/options.js +4 -3
  5. package/lib/generate-data.js +2 -7
  6. package/lib/generate-report.js +10 -11
  7. package/lib/index.d.ts +2 -9
  8. package/lib/index.js +6 -0
  9. package/lib/merge-data.js +7 -6
  10. package/lib/plugins/audit/audit.js +4 -2
  11. package/lib/plugins/comments.js +2 -3
  12. package/lib/plugins/coverage/converter/collect-source-maps.js +194 -0
  13. package/lib/plugins/coverage/converter/converter.js +547 -0
  14. package/lib/plugins/coverage/converter/decode-mappings.js +49 -0
  15. package/lib/plugins/coverage/{v8 → converter}/dedupe.js +8 -1
  16. package/lib/plugins/coverage/converter/find-original-range.js +576 -0
  17. package/lib/plugins/coverage/converter/info-branch.js +30 -0
  18. package/lib/plugins/coverage/converter/info-function.js +29 -0
  19. package/lib/plugins/coverage/converter/info-line.js +20 -0
  20. package/lib/plugins/coverage/converter/position-mapping.js +183 -0
  21. package/lib/plugins/coverage/{coverage-utils.js → converter/source-path.js} +26 -42
  22. package/lib/plugins/coverage/coverage.js +61 -57
  23. package/lib/plugins/coverage/istanbul/istanbul.js +21 -174
  24. package/lib/plugins/coverage/v8/v8.js +22 -30
  25. package/lib/plugins/network/network.js +4 -13
  26. package/lib/plugins/state/client.js +3 -4
  27. package/lib/plugins/state/state.js +6 -3
  28. package/lib/runtime/monocart-code-viewer.js +1 -1
  29. package/lib/runtime/monocart-coverage.js +13 -14
  30. package/lib/runtime/monocart-formatter.js +1 -1
  31. package/lib/runtime/monocart-network.js +1 -1
  32. package/lib/runtime/monocart-reporter.js +1 -1
  33. package/lib/runtime/monocart-v8.js +1 -1
  34. package/lib/runtime/monocart-vendor.js +13 -13
  35. package/lib/utils/util.js +97 -3
  36. package/package.json +5 -6
  37. package/lib/plugins/coverage/v8/position-mapping.js +0 -92
  38. 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
- };