transformer.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. Copyright 2015, Yahoo Inc.
  3. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
  4. */
  5. 'use strict';
  6. const debug = require('debug')('istanbuljs');
  7. const libCoverage = require('istanbul-lib-coverage');
  8. const { MappedCoverage } = require('./mapped');
  9. const getMapping = require('./get-mapping');
  10. const { getUniqueKey, getOutput } = require('./transform-utils');
  11. class SourceMapTransformer {
  12. constructor(finder, opts = {}) {
  13. this.finder = finder;
  14. this.baseDir = opts.baseDir || process.cwd();
  15. }
  16. processFile(fc, sourceMap, coverageMapper) {
  17. let changes = 0;
  18. Object.keys(fc.statementMap).forEach(s => {
  19. const loc = fc.statementMap[s];
  20. const hits = fc.s[s];
  21. const mapping = getMapping(sourceMap, loc, fc.path);
  22. if (mapping) {
  23. changes += 1;
  24. const mappedCoverage = coverageMapper(mapping.source);
  25. mappedCoverage.addStatement(mapping.loc, hits);
  26. }
  27. });
  28. Object.keys(fc.fnMap).forEach(f => {
  29. const fnMeta = fc.fnMap[f];
  30. const hits = fc.f[f];
  31. const mapping = getMapping(sourceMap, fnMeta.decl, fc.path);
  32. const spanMapping = getMapping(sourceMap, fnMeta.loc, fc.path);
  33. if (
  34. mapping &&
  35. spanMapping &&
  36. mapping.source === spanMapping.source
  37. ) {
  38. changes += 1;
  39. const mappedCoverage = coverageMapper(mapping.source);
  40. mappedCoverage.addFunction(
  41. fnMeta.name,
  42. mapping.loc,
  43. spanMapping.loc,
  44. hits
  45. );
  46. }
  47. });
  48. Object.keys(fc.branchMap).forEach(b => {
  49. const branchMeta = fc.branchMap[b];
  50. const hits = fc.b[b];
  51. const locs = [];
  52. const mappedHits = [];
  53. let source;
  54. let skip;
  55. branchMeta.locations.forEach((loc, i) => {
  56. const mapping = getMapping(sourceMap, loc, fc.path);
  57. if (mapping) {
  58. if (!source) {
  59. source = mapping.source;
  60. }
  61. if (mapping.source !== source) {
  62. skip = true;
  63. }
  64. locs.push(mapping.loc);
  65. mappedHits.push(hits[i]);
  66. }
  67. });
  68. if (!skip && locs.length > 0) {
  69. changes += 1;
  70. const mappedCoverage = coverageMapper(source);
  71. mappedCoverage.addBranch(
  72. branchMeta.type,
  73. locs[0] /* XXX */,
  74. locs,
  75. mappedHits
  76. );
  77. }
  78. });
  79. return changes > 0;
  80. }
  81. transform(coverageMap) {
  82. const uniqueFiles = {};
  83. const getMappedCoverage = file => {
  84. const key = getUniqueKey(file);
  85. if (!uniqueFiles[key]) {
  86. uniqueFiles[key] = {
  87. file,
  88. mappedCoverage: new MappedCoverage(file)
  89. };
  90. }
  91. return uniqueFiles[key].mappedCoverage;
  92. };
  93. coverageMap.files().forEach(file => {
  94. const fc = coverageMap.fileCoverageFor(file);
  95. const sourceMap = this.finder(file);
  96. if (!sourceMap) {
  97. uniqueFiles[getUniqueKey(file)] = {
  98. file,
  99. mappedCoverage: fc
  100. };
  101. return;
  102. }
  103. const changed = this.processFile(fc, sourceMap, getMappedCoverage);
  104. if (!changed) {
  105. debug(`File [${file}] ignored, nothing could be mapped`);
  106. }
  107. });
  108. return libCoverage.createCoverageMap(getOutput(uniqueFiles));
  109. }
  110. }
  111. module.exports = {
  112. create(finder, opts) {
  113. return new SourceMapTransformer(finder, opts);
  114. }
  115. };