read-coverage.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. const { parseSync, traverse } = require('@babel/core');
  2. const { defaults } = require('@istanbuljs/schema');
  3. const { MAGIC_KEY, MAGIC_VALUE } = require('./constants');
  4. function getAst(code) {
  5. if (typeof code === 'object' && typeof code.type === 'string') {
  6. // Assume code is already a babel ast.
  7. return code;
  8. }
  9. if (typeof code !== 'string') {
  10. throw new Error('Code must be a string');
  11. }
  12. // Parse as leniently as possible
  13. return parseSync(code, {
  14. babelrc: false,
  15. configFile: false,
  16. parserOpts: {
  17. allowAwaitOutsideFunction: true,
  18. allowImportExportEverywhere: true,
  19. allowReturnOutsideFunction: true,
  20. allowSuperOutsideMethod: true,
  21. sourceType: 'script',
  22. plugins: defaults.instrumenter.parserPlugins
  23. }
  24. });
  25. }
  26. module.exports = function readInitialCoverage(code) {
  27. const ast = getAst(code);
  28. let covScope;
  29. traverse(ast, {
  30. ObjectProperty(path) {
  31. const { node } = path;
  32. if (
  33. !node.computed &&
  34. path.get('key').isIdentifier() &&
  35. node.key.name === MAGIC_KEY
  36. ) {
  37. const magicValue = path.get('value').evaluate();
  38. if (!magicValue.confident || magicValue.value !== MAGIC_VALUE) {
  39. return;
  40. }
  41. covScope =
  42. path.scope.getFunctionParent() ||
  43. path.scope.getProgramParent();
  44. path.stop();
  45. }
  46. }
  47. });
  48. if (!covScope) {
  49. return null;
  50. }
  51. const result = {};
  52. for (const key of ['path', 'hash', 'gcv', 'coverageData']) {
  53. const binding = covScope.getOwnBinding(key);
  54. if (!binding) {
  55. return null;
  56. }
  57. const valuePath = binding.path.get('init');
  58. const value = valuePath.evaluate();
  59. if (!value.confident) {
  60. return null;
  61. }
  62. result[key] = value.value;
  63. }
  64. delete result.coverageData[MAGIC_KEY];
  65. delete result.coverageData.hash;
  66. return result;
  67. };