All files / istanbul-lib-coverage/src coverage-map.ts

97.14% Statements 34/35
95.65% Branches 22/23
100% Functions 14/14
97.14% Lines 34/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150                                      22x       22x                   22x 22x 4x     18x 31x     18x                         23x 1x 22x 3x   19x                     3x 3x 6x                     1x 2x 1x                 1x               10x               8x 8x 1x   7x                   12x 12x 12x 6x   6x                 1x 1x 3x     1x          
/*
Copyright 2012-2015, Yahoo Inc.
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
 
import { CoverageSummary } from "./coverage-summary";
import { FileCoverage } from "./file-coverage";
import type { FileCoverageData } from "./file-coverage";
 
/**
 * Raw, JSON-serializable data underlying a `CoverageMap`: `FileCoverage`
 * objects or their raw data keyed by file path. This can be the raw global
 * coverage object.
 */
export interface CoverageMapData {
  [path: string]: FileCoverage | FileCoverageData;
}
 
export function isCoverageMap(obj: unknown): obj is CoverageMap {
  Iif (obj instanceof CoverageMap) {
    return true;
  }
 
  return (
    typeof obj === "object" &&
    obj !== null &&
    typeof (obj as CoverageMap).data === "object" &&
    typeof (obj as CoverageMap).fileCoverageFor === "function" &&
    typeof (obj as CoverageMap).addFileCoverage === "function"
  );
}
 
function loadMap(source?: CoverageMapData): Record<string, FileCoverage> {
  const data: Record<string, FileCoverage> = Object.create(null);
  if (!source) {
    return data;
  }
 
  Object.entries(source).forEach(([k, cov]) => {
    data[k] = cov instanceof FileCoverage ? cov : new FileCoverage(cov);
  });
 
  return data;
}
 
/** CoverageMap is a map of `FileCoverage` objects keyed by file paths. */
class CoverageMap {
  data: Record<string, FileCoverage>;
 
  /**
   * @constructor
   * @param obj A coverage map from which to initialize this
   * map's contents. This can be the raw global coverage object.
   */
  constructor(obj?: CoverageMap | CoverageMapData) {
    if (obj instanceof CoverageMap) {
      this.data = obj.data;
    } else if (isCoverageMap(obj)) {
      this.data = loadMap(obj.data);
    } else {
      this.data = loadMap(obj);
    }
  }
 
  /**
   * merges a second coverage map into this one
   * @param obj - a CoverageMap or its raw data. Coverage is merged
   *  correctly for the same files and additional file coverage keys are created
   *  as needed.
   */
  merge(obj: CoverageMap | CoverageMapData): void {
    const other = obj instanceof CoverageMap ? obj : new CoverageMap(obj);
    Object.values(other.data).forEach((fc) => {
      this.addFileCoverage(fc);
    });
  }
 
  /**
   * filter the coveragemap based on the callback provided
   * @param callback - Returns true if the path
   *  should be included in the coveragemap. False if it should be
   *  removed.
   */
  filter(callback: (path: string) => boolean): void {
    Object.keys(this.data).forEach((k) => {
      if (!callback(k)) {
        delete this.data[k];
      }
    });
  }
 
  /**
   * returns a JSON-serializable POJO for this coverage map
   */
  toJSON(): CoverageMapData {
    return this.data;
  }
 
  /**
   * returns an array for file paths for which this map has coverage
   * @returns array of files
   */
  files(): string[] {
    return Object.keys(this.data);
  }
 
  /**
   * returns the file coverage for the specified file.
   * @param file
   */
  fileCoverageFor(file: string): FileCoverage {
    const fc = this.data[file];
    if (!fc) {
      throw new Error(`No file coverage available for: ${file}`);
    }
    return fc;
  }
 
  /**
   * adds a file coverage object to this map. If the path for the object,
   * already exists in the map, it is merged with the existing coverage
   * otherwise a new key is added to the map.
   * @param fc the file coverage to add
   */
  addFileCoverage(fc: string | FileCoverage | FileCoverageData): void {
    const cov = new FileCoverage(fc);
    const { path } = cov;
    if (this.data[path]) {
      this.data[path].merge(cov);
    } else {
      this.data[path] = cov;
    }
  }
 
  /**
   * returns the coverage summary for all the file coverage objects in this map.
   * @returns {CoverageSummary}
   */
  getCoverageSummary(): CoverageSummary {
    const ret = new CoverageSummary();
    Object.values(this.data).forEach((fc) => {
      ret.merge(fc.toSummary());
    });
 
    return ret;
  }
}
 
export { CoverageMap };