monocart-coverage-reports 2.7.4 → 2.7.6

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/cli.js CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const fs = require('fs');
4
3
  const path = require('path');
5
4
  const EC = require('eight-colors');
6
5
 
@@ -133,11 +132,6 @@ const executeCommand = async (command, cliOptions) => {
133
132
  }
134
133
  // =========================================
135
134
 
136
- if (!fs.existsSync(nodeV8CoverageDir)) {
137
- EC.logRed(`Invalid V8 coverage dir: ${Util.relativePath(nodeV8CoverageDir)}`);
138
- return 1;
139
- }
140
-
141
135
  await coverageReport.addFromDir(nodeV8CoverageDir);
142
136
  await coverageReport.generate();
143
137
 
@@ -155,14 +149,29 @@ process.on('uncaughtException', function(err) {
155
149
  Util.logError(`Process uncaughtException: ${err.message || err}`);
156
150
  });
157
151
 
152
+ // the -- separator
153
+ const argv = [];
154
+ const subArgv = [];
155
+ let separator = false;
156
+ process.argv.forEach((it) => {
157
+ if (!separator && it === '--') {
158
+ separator = true;
159
+ }
160
+ if (separator) {
161
+ subArgv.push(it);
162
+ } else {
163
+ argv.push(it);
164
+ }
165
+ });
166
+
158
167
  program
159
168
  .name('mcr')
160
169
  .description('CLI to generate coverage reports')
161
170
  .version(version)
162
- .argument('<command>', 'command to execute')
171
+ .argument('[command]', 'command to execute')
163
172
  .allowUnknownOption()
164
173
  .option('-c, --config <path>', 'custom config file path')
165
- .option('--logging <logging>', 'off, error, info, debug')
174
+ .option('-l, --logging <logging>', 'off, error, info, debug')
166
175
 
167
176
  .option('-n, --name <name>', 'report name for title')
168
177
  .option('-r, --reports <name[,name]>', 'coverage reports to use')
@@ -183,8 +192,17 @@ program
183
192
  .option('--require <module>', 'preload module at startup')
184
193
 
185
194
  .action((_command, cliOptions) => {
186
- const command = program.args.join(' ');
195
+ const args = [].concat(program.args).concat(subArgv);
196
+ if (args[0] === '--') {
197
+ args.shift();
198
+ }
199
+ const command = args.join(' ').trim();
200
+ if (!command) {
201
+ program.outputHelp();
202
+ return;
203
+ }
204
+
187
205
  executeCommand(command, cliOptions);
188
206
  });
189
207
 
190
- program.parse();
208
+ program.parse(argv);
@@ -4,7 +4,7 @@ const EC = require('eight-colors');
4
4
  const { WebSocket } = require('../packages/monocart-coverage-vendor.js');
5
5
  const Util = require('../utils/util.js');
6
6
 
7
- const CDPSession = require('./cdp-session.js');
7
+ const WSSession = require('./ws-session.js');
8
8
  const CoverageClient = require('./coverage-client.js');
9
9
 
10
10
  const getDebuggerUrl = async (options) => {
@@ -85,7 +85,7 @@ const getCDPSession = async (options) => {
85
85
  ws.once('open', () => {
86
86
  clearTimeout(timeoutId);
87
87
  Util.logDebug(`${EC.green('Connected')} ${url}`);
88
- const session = new CDPSession(ws);
88
+ const session = new WSSession(ws);
89
89
  resolve([null, session]);
90
90
  });
91
91
 
@@ -1,6 +1,6 @@
1
1
  const { EventEmitter } = require('events');
2
2
 
3
- class CDPSession extends EventEmitter {
3
+ class WSSession extends EventEmitter {
4
4
  constructor(ws) {
5
5
  super();
6
6
  this.ws = ws;
@@ -60,4 +60,4 @@ class CDPSession extends EventEmitter {
60
60
  }
61
61
  }
62
62
 
63
- module.exports = CDPSession;
63
+ module.exports = WSSession;
@@ -8,6 +8,12 @@ const BranchTypes = {
8
8
  AssignmentPattern: 'AssignmentPattern'
9
9
  };
10
10
 
11
+ const setGeneratedOnly = (block, generatedOnly) => {
12
+ if (block && generatedOnly) {
13
+ block.generatedOnly = true;
14
+ }
15
+ };
16
+
11
17
  const getParentFunctionState = (reverseParents) => {
12
18
  const parentFunction = reverseParents.find((it) => it._state && it._state.isFunction);
13
19
  if (!parentFunction) {
@@ -266,6 +272,7 @@ const updateBranchCount = (group) => {
266
272
  const groupBlock = getFunctionBlock(group.start, group.end, functionState);
267
273
  if (groupBlock) {
268
274
  parentCount = groupBlock.count;
275
+ setGeneratedOnly(groupBlock, group.generatedOnly);
269
276
  }
270
277
 
271
278
  // calculate branches count
@@ -277,6 +284,7 @@ const updateBranchCount = (group) => {
277
284
  return;
278
285
  }
279
286
  item.block = getFunctionBlock(start, end, functionState);
287
+ setGeneratedOnly(item.block, group.generatedOnly);
280
288
  });
281
289
 
282
290
 
@@ -314,12 +322,16 @@ const generateBranches = (branchMap) => {
314
322
  }
315
323
  });
316
324
 
317
- branches.push({
325
+ const branch = {
318
326
  type: group.type,
319
327
  start: group.start,
320
328
  end: group.end,
321
329
  locations: group.locations
322
- });
330
+ };
331
+
332
+ setGeneratedOnly(branch, group.generatedOnly);
333
+
334
+ branches.push(branch);
323
335
  });
324
336
 
325
337
  // sort branches
@@ -395,6 +407,34 @@ const generateStatements = (statementNodes) => {
395
407
  return statements;
396
408
  };
397
409
 
410
+ // =======================================================================================
411
+ // handle special generated codes for original coverage
412
+
413
+ const webpackWrapHandler = (node) => {
414
+ // ignore webpack wrap for original function
415
+ // id: { type: 'Identifier', name: '__webpack_modules__' },
416
+ const name = node.id && node.id.name;
417
+ if (name === '__webpack_modules__' && node.init && node.init.properties) {
418
+ // mark all as wrap function
419
+ node.init.properties.forEach((it) => {
420
+ it.value._webpackWrapKey = it.key && it.key.value;
421
+ });
422
+ // console.log('==========================', node.type);
423
+ // console.log(name, parents.length);
424
+ }
425
+ };
426
+
427
+ const viteImportDefaultHandler = (node, group) => {
428
+ // ignore vite conditional expression for __esModule default
429
+ const testObj = node.test.object;
430
+ const testName = testObj && testObj.name;
431
+ if (testName && testName.startsWith('__vite__cjsImport')) {
432
+ setGeneratedOnly(group, true);
433
+ }
434
+
435
+ };
436
+
437
+
398
438
  // =======================================================================================
399
439
 
400
440
  const collectNodes = (ast) => {
@@ -409,18 +449,7 @@ const collectNodes = (ast) => {
409
449
 
410
450
  VariableDeclarator(node, parents) {
411
451
 
412
- // =============================================================
413
- // id: { type: 'Identifier', name: '__webpack_modules__' },
414
- const name = node.id && node.id.name;
415
- if (name === '__webpack_modules__' && node.init && node.init.properties) {
416
- // mark all as wrap function
417
- node.init.properties.forEach((it) => {
418
- it.value._wrapKey = it.key && it.key.value;
419
- });
420
- // console.log('==========================', node.type);
421
- // console.log(name, parents.length);
422
- }
423
- // =============================================================
452
+ webpackWrapHandler(node);
424
453
 
425
454
  },
426
455
 
@@ -473,10 +502,14 @@ const collectNodes = (ast) => {
473
502
  // Ternary
474
503
  // var b = a ? 'consequent' : 'alternate';
475
504
  ConditionalExpression: (node, parents) => {
505
+
476
506
  const { consequent, alternate } = node;
477
507
  const group = createBranchGroup(BranchTypes.ConditionalExpression, node, parents, branchMap);
478
508
  addBranch(group, consequent, locationMap);
479
509
  addBranch(group, alternate, locationMap);
510
+
511
+ viteImportDefaultHandler(node, group);
512
+
480
513
  },
481
514
 
482
515
  // if an if statement; can also be else if.
@@ -619,7 +652,7 @@ const collectAstInfo = (ast, coverageInfo) => {
619
652
  const bodyStart = node.body.start;
620
653
  const bodyEnd = node.body.end;
621
654
  const functionName = id && id.name;
622
- const isWrap = Boolean(node._wrapKey);
655
+ const _webpackWrapKey = node._webpackWrapKey;
623
656
 
624
657
  const functionItem = {
625
658
  start,
@@ -629,9 +662,9 @@ const collectAstInfo = (ast, coverageInfo) => {
629
662
  functionName,
630
663
  count: rootState.count
631
664
  };
632
- if (isWrap) {
633
- functionItem.wrap = true;
634
- }
665
+
666
+ setGeneratedOnly(functionItem, _webpackWrapKey);
667
+
635
668
  functions.push(functionItem);
636
669
 
637
670
  const functionState = {
@@ -641,9 +674,9 @@ const collectAstInfo = (ast, coverageInfo) => {
641
674
 
642
675
  const functionRange = findFunctionRange(item, coverageInfo);
643
676
  if (functionRange) {
644
- if (isWrap) {
645
- functionRange.wrap = true;
646
- }
677
+
678
+ setGeneratedOnly(functionRange, _webpackWrapKey);
679
+
647
680
  functionState.range = functionRange;
648
681
  functionState.count = functionRange.count;
649
682
  functionItem.count = functionRange.count;
@@ -28,7 +28,14 @@ const loadSourceMap = async (url = '') => {
28
28
  return;
29
29
  }
30
30
 
31
- return res.data;
31
+ const content = res.data;
32
+
33
+ // could be string not json, if Content-Type is application/octet-stream
34
+ if (typeof content === 'string') {
35
+ return JSON.parse(content);
36
+ }
37
+
38
+ return content;
32
39
  };
33
40
 
34
41
  const getSourceMapUrl = (content, url) => {
@@ -3,10 +3,12 @@
3
3
  * @copyright https://github.com/cenfun/monocart-coverage-reports
4
4
  * @author cenfun@gmail.com
5
5
  */
6
- const Util = require('../utils/util.js');
7
6
 
8
- // position mapping for conversion between offset and line/column
7
+ const EC = require('eight-colors');
9
8
  const { Locator } = require('monocart-formatter');
9
+
10
+ const Util = require('../utils/util.js');
11
+
10
12
  const findOriginalRange = require('./find-original-range.js');
11
13
  const { getJsAstInfo, getCssAstInfo } = require('./ast.js');
12
14
  const { getIgnoredRanges } = require('./ignore.js');
@@ -510,6 +512,11 @@ const handleOriginalBytesCoverage = (state) => {
510
512
 
511
513
  const handleGeneratedBytesCoverage = (state) => {
512
514
 
515
+ // it could be a dist file, do not handle twice
516
+ if (state.addedGeneratedBytes) {
517
+ return;
518
+ }
519
+
513
520
  const { js, coverageList } = state;
514
521
 
515
522
  if (js) {
@@ -524,6 +531,8 @@ const handleGeneratedBytesCoverage = (state) => {
524
531
  });
525
532
  }
526
533
 
534
+ state.addedGeneratedBytes = true;
535
+
527
536
  };
528
537
 
529
538
  // ========================================================================================================
@@ -551,15 +560,16 @@ const handleOriginalFunctionsCoverage = (state, originalStateMap) => {
551
560
 
552
561
  // function count
553
562
  state.astInfo.functions.forEach((it) => {
554
- const {
555
- start, end, bodyStart, bodyEnd, wrap
556
- } = it;
557
563
 
558
564
  // remove webpack wrap functions for functions count, not for ranges here
559
- if (wrap) {
565
+ if (it.generatedOnly) {
560
566
  return;
561
567
  }
562
568
 
569
+ const {
570
+ start, end, bodyStart, bodyEnd
571
+ } = it;
572
+
563
573
  const result = findOriginalRange(start, end, state, originalStateMap);
564
574
  if (result.error) {
565
575
  logMappingErrors('function', result);
@@ -598,6 +608,10 @@ const handleOriginalBranchesCoverage = (state, originalStateMap) => {
598
608
  // function count
599
609
  state.astInfo.branches.forEach((group) => {
600
610
 
611
+ if (group.generatedOnly) {
612
+ return;
613
+ }
614
+
601
615
  const { type, locations } = group;
602
616
 
603
617
  // start
@@ -668,6 +682,11 @@ const handleOriginalStatementsCoverage = (state, originalStateMap) => {
668
682
 
669
683
  // statement count
670
684
  state.astInfo.statements.forEach((it) => {
685
+
686
+ if (it.generatedOnly) {
687
+ return;
688
+ }
689
+
671
690
  const { start, end } = it;
672
691
 
673
692
  const result = findOriginalRange(start, end, state, originalStateMap);
@@ -799,11 +818,10 @@ const handleAllOriginalBytesCoverage = (state, originalStateMap) => {
799
818
 
800
819
  // v8 coverage
801
820
  coverageList.forEach((block) => {
802
- block.ranges.forEach((range, index) => {
821
+ block.ranges.forEach((range) => {
803
822
 
804
823
  // remove wrap functions for original files
805
- if (range.wrap) {
806
- // console.log(range);
824
+ if (range.generatedOnly) {
807
825
  return;
808
826
  }
809
827
 
@@ -1443,7 +1461,7 @@ const convertV8List = (v8list, options) => {
1443
1461
  delete item.ranges;
1444
1462
  }
1445
1463
  }
1446
- Util.logTime(`- parsed ast: ${sourcePath}`, time_start_ast);
1464
+ Util.logTime(`- parsed ast: ${sourcePath} (${EC.cyan(Util.BSF(maxContentLength))})`, time_start_ast);
1447
1465
 
1448
1466
  // console.log(sourcePath, astInfo.statements.length);
1449
1467
  // ============================
@@ -1460,6 +1478,7 @@ const convertV8List = (v8list, options) => {
1460
1478
  locator,
1461
1479
  maxContentLength,
1462
1480
  decodedMappings: [],
1481
+ cacheMap: new Map(),
1463
1482
  // coverage info
1464
1483
  bytes: [],
1465
1484
  functions: [],
@@ -1475,7 +1494,8 @@ const convertV8List = (v8list, options) => {
1475
1494
 
1476
1495
  const time_start_unpack = Date.now();
1477
1496
  unpackDistFile(item, state, options);
1478
- Util.logTime(`- unpacked dist: ${sourcePath}`, time_start_unpack);
1497
+ const unpackedFiles = EC.cyan(`${state.originalList.length} files`);
1498
+ Util.logTime(`- unpacked dist: ${sourcePath} (${unpackedFiles})`, time_start_unpack);
1479
1499
 
1480
1500
  stateList.push(state);
1481
1501
 
@@ -1483,7 +1503,8 @@ const convertV8List = (v8list, options) => {
1483
1503
 
1484
1504
  const time_start_convert = Date.now();
1485
1505
  const dataList = generateV8DataList(stateList, options);
1486
- Util.logTime('- generated v8 data list', time_start_convert);
1506
+ const dataFiles = EC.cyan(`${dataList.v8DataList.length} files`);
1507
+ Util.logTime(`- generated data list (${dataFiles})`, time_start_convert);
1487
1508
 
1488
1509
  return dataList;
1489
1510
  };
@@ -119,8 +119,32 @@ const alignText = (gt, ot) => {
119
119
  return gl;
120
120
  };
121
121
 
122
+ const getWordEndPosition = (list, gp, direction) => {
123
+ // for end only
124
+ if (direction !== 'end') {
125
+ return;
126
+ }
127
+
128
+ const prev = list[gp - 1];
129
+ if (prev && prev.original && prev.wordEnd) {
130
+ const op = prev.original.index + 1;
131
+ // console.log(gp, JSON.stringify(gt));
132
+ // console.log(op, JSON.stringify(ot));
133
+ return {
134
+ pos: op
135
+ };
136
+ }
137
+ };
138
+
122
139
  const getAlignPosition = (gt, gp, ot, direction) => {
123
140
 
141
+ // there is no need to align for long text
142
+ const maxLength = 500;
143
+ if (gt.length > maxLength || ot.length > maxLength) {
144
+ // console.log(gt.length, ot.length, gp);
145
+ return;
146
+ }
147
+
124
148
  // generatedText: '"false";\n',
125
149
  // originalText: "'false';\r\n ",
126
150
  // generatedPos: 7
@@ -147,20 +171,7 @@ const getAlignPosition = (gt, gp, ot, direction) => {
147
171
  }
148
172
 
149
173
  // inclusive, for end only
150
- if (gp && direction === 'end') {
151
- const prev = list[gp - 1];
152
- if (prev && prev.original && prev.wordEnd) {
153
- // console.log(direction, '=====================================================================');
154
- const op = prev.original.index + 1;
155
- // console.log(gp, JSON.stringify(gt));
156
- // console.log(op, JSON.stringify(ot));
157
-
158
- return {
159
- pos: op
160
- };
161
-
162
- }
163
- }
174
+ return getWordEndPosition(list, gp, direction);
164
175
 
165
176
  };
166
177
 
@@ -252,13 +263,19 @@ const getComparedPosition = (info, direction) => {
252
263
  const gt = info.generatedText;
253
264
  const gp = info.generatedPos;
254
265
  const ot = info.originalText;
266
+ const olt = info.originalLineText;
267
+
268
+ // seems direction is start only
269
+ if (gp === 0) {
270
+ return;
271
+ }
255
272
 
256
273
  // whole generated text
257
274
  if (gp >= gt.length) {
258
275
  // console.log(JSON.stringify(gt), gt.length, gp);
259
276
  // console.log(JSON.stringify(ot));
260
277
  return {
261
- pos: info.originalLineText.length
278
+ pos: olt.length
262
279
  };
263
280
  }
264
281
 
@@ -803,16 +820,26 @@ const getMappingInfo = (start, end, state) => {
803
820
 
804
821
  const findOriginalRange = (start, end, state, originalMap) => {
805
822
 
806
- const { sourcePath } = state;
823
+ const { sourcePath, cacheMap } = state;
824
+
825
+ const key = `${start}_${end}`;
826
+ if (cacheMap.has(key)) {
827
+ return cacheMap.get(key);
828
+ }
807
829
 
808
830
  const createMappingError = (errors) => {
809
- return {
831
+ const res = {
810
832
  error: true,
811
833
  start,
812
834
  end,
813
835
  sourcePath,
814
836
  errors
815
837
  };
838
+
839
+ // cache error response
840
+ cacheMap.set(key, res);
841
+
842
+ return res;
816
843
  };
817
844
 
818
845
  const cache = getOriginalState(start, end, state, originalMap);
@@ -835,12 +862,23 @@ const findOriginalRange = (start, end, state, originalMap) => {
835
862
 
836
863
  const { originalState } = cache;
837
864
 
838
- return {
865
+ const inComment = originalState.locator.lineParser.commentParser.isComment(originalStart, originalEnd);
866
+ if (inComment) {
867
+ return createMappingError(['the range in a original comment']);
868
+ }
869
+
870
+
871
+ const res = {
839
872
  start: originalStart,
840
873
  end: originalEnd,
841
874
  originalState
842
875
  };
843
876
 
877
+ // cache response
878
+ cacheMap.set(key, res);
879
+
880
+ return res;
881
+
844
882
  };
845
883
 
846
884
  module.exports = findOriginalRange;
package/lib/generate.js CHANGED
@@ -21,7 +21,7 @@ const { getGroupedRows } = require('./utils/snapshot.js');
21
21
 
22
22
  // maybe v8 or to istanbul reports
23
23
  const generateV8ListReports = async (v8list, coverageData, fileSources, options) => {
24
-
24
+ const time_start = Date.now();
25
25
  let istanbulReportPath;
26
26
  // v8 to istanbul reports
27
27
  if (options.reportGroup.istanbul) {
@@ -32,7 +32,7 @@ const generateV8ListReports = async (v8list, coverageData, fileSources, options)
32
32
  // v8 reports and v8 coverage results
33
33
  // could be no v8 or v8-json, but requires v8 coverage results
34
34
  const v8CoverageResults = await saveV8Report(v8list, options, istanbulReportPath);
35
-
35
+ Util.logTime('- saved coverage reports', time_start);
36
36
  return v8CoverageResults;
37
37
  };
38
38
 
@@ -436,15 +436,10 @@ const getCoverageResults = async (dataList, sourceCache, options) => {
436
436
  // merge v8list first
437
437
  const v8list = await mergeV8Coverage(dataList, sourceCache, options);
438
438
  // console.log('after merge', v8list.map((it) => it.url));
439
-
440
- // only debug level
441
- const time_start = Date.now();
442
439
  const results = convertV8List(v8list, options);
443
440
  const {
444
441
  v8DataList, coverageData, fileSources
445
442
  } = results;
446
- Util.logTime(`converted v8 list: ${v8DataList.length}`, time_start);
447
-
448
443
  return generateV8ListReports(v8DataList, coverageData, fileSources, options);
449
444
  }
450
445
 
@@ -806,7 +801,7 @@ const readCoverageData = (filePath, entryFilter, sourceCache) => {
806
801
  const readFromDir = async (dir, entryFilter, addHandler) => {
807
802
 
808
803
  if (!dir || !fs.existsSync(dir)) {
809
- Util.logError(`Invalid V8 coverage dir: ${dir}`);
804
+ Util.logInfo(`Not found V8 coverage dir: ${dir}`);
810
805
  return;
811
806
  }
812
807
 
package/lib/index.d.ts CHANGED
@@ -452,6 +452,14 @@ declare namespace MCR {
452
452
  detach: () => Promise<void>
453
453
  }
454
454
 
455
+ /** custom websocket CDPSession */
456
+ export class WSSession implements CDPSession {
457
+ constructor(ws: any);
458
+ send: (method: string, params?: any) => Promise<any>;
459
+ on: (type: string, handler: (e: any) => void) => void;
460
+ detach: () => Promise<void>
461
+ }
462
+
455
463
  export interface CDPOptions {
456
464
  /** Adapt to the CDPSession of Playwright or Puppeteer */
457
465
  session?: CDPSession;
package/lib/index.js CHANGED
@@ -11,6 +11,8 @@ const {
11
11
  getInputData, readFromDir, generateCoverageReports
12
12
  } = require('./generate.js');
13
13
  const { getSnapshot, diffSnapshot } = require('./utils/snapshot.js');
14
+
15
+ const WSSession = require('./client/ws-session.js');
14
16
  const CDPClient = require('./client/cdp-client.js');
15
17
 
16
18
  const resolveConfigOptions = async (configPath) => {
@@ -181,7 +183,7 @@ class CoverageReport {
181
183
  Util.rmSync(cacheDir);
182
184
  }
183
185
 
184
- Util.logTime(`generated coverage reports: ${coverageResults.reportPath}`, time_start);
186
+ Util.logTime(`generated coverage reports: ${EC.cyan(coverageResults.reportPath)}`, time_start);
185
187
 
186
188
  const onEnd = this.options.onEnd;
187
189
  if (typeof onEnd === 'function') {
@@ -286,6 +288,7 @@ const MCR = function(options) {
286
288
  MCR.CoverageReport = CoverageReport;
287
289
  MCR.getSnapshot = getSnapshot;
288
290
  MCR.diffSnapshot = diffSnapshot;
291
+ MCR.WSSession = WSSession;
289
292
  MCR.CDPClient = CDPClient;
290
293
 
291
294
  module.exports = MCR;
package/lib/index.mjs CHANGED
@@ -3,4 +3,6 @@ export default MCR;
3
3
  export const CoverageReport = MCR.CoverageReport;
4
4
  export const getSnapshot = MCR.getSnapshot;
5
5
  export const diffSnapshot = MCR.diffSnapshot;
6
+
7
+ export const WSSession = MCR.WSSession;
6
8
  export const CDPClient = MCR.CDPClient;