All files / istanbul-lib-report/src/reports/lcovonly index.ts

97.5% Statements 39/40
60% Branches 6/10
100% Functions 9/9
97.5% Lines 39/40

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                                              9x 9x 9x 9x 9x       9x       12x 12x 12x 12x 12x 12x 12x 12x   12x 12x 12x   12x     33x 33x   12x 12x   12x 33x 33x     12x 223x   12x 12x   12x 78x 78x 78x 78x 168x           12x 12x 12x       9x          
/*
 Copyright 2012-2015, Yahoo Inc.
 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
import path from "node:path";
 
import type { ContentWriter, Context, ReportNode } from "../../index";
import ReportBase from "../../report-base";
 
/** options accepted by {@link LcovOnlyReport} */
export interface LcovOnlyOptions {
  /** the file to write the report to, defaults to `lcov.info` */
  file?: string;
  /** the project root used to relativize file paths, defaults to `process.cwd()` */
  projectRoot?: string;
}
 
class LcovOnlyReport extends ReportBase {
  declare file: string;
  declare projectRoot: string;
  declare contentWriter: ContentWriter | null;
 
  constructor(opts?: LcovOnlyOptions) {
    super();
    opts = opts || {};
    this.file = opts.file || "lcov.info";
    this.projectRoot = opts.projectRoot || process.cwd();
    this.contentWriter = null;
  }
 
  onStart(root: ReportNode, context: Context): void {
    this.contentWriter = context.writer.writeFile(this.file);
  }
 
  onDetail(node: ReportNode): void {
    const fc = node.getFileCoverage();
    const writer = this.contentWriter!;
    const functions = fc.f;
    const functionMap = fc.fnMap;
    const lines = fc.getLineCoverage();
    const branches = fc.b;
    const branchMap = fc.branchMap;
    const summary = node.getCoverageSummary()!;
 
    writer.println("TN:");
    const fileName = path.relative(this.projectRoot, fc.path);
    writer.println("SF:" + fileName);
 
    Object.values(functionMap).forEach((meta) => {
      // Some versions of the instrumenter in the wild populate 'loc'
      // but not 'decl':
      const decl = meta.decl || meta.loc;
      writer.println("FN:" + [decl.start.line, meta.name].join(","));
    });
    writer.println("FNF:" + summary.functions.total);
    writer.println("FNH:" + summary.functions.covered);
 
    Object.entries(functionMap).forEach(([key, meta]) => {
      const stats = functions[key];
      writer.println("FNDA:" + [stats, meta.name].join(","));
    });
 
    Object.entries(lines).forEach((entry) => {
      writer.println("DA:" + entry.join(","));
    });
    writer.println("LF:" + summary.lines.total);
    writer.println("LH:" + summary.lines.covered);
 
    Object.entries(branches).forEach(([key, branchArray]) => {
      const meta = branchMap[key];
      if (meta) {
        const { line } = meta.loc.start;
        branchArray.forEach((b, i) => {
          writer.println("BRDA:" + [line, key, i, b].join(","));
        });
      } else E{
        console.warn("Missing coverage entries in", fileName, key);
      }
    });
    writer.println("BRF:" + summary.branches.total);
    writer.println("BRH:" + summary.branches.covered);
    writer.println("end_of_record");
  }
 
  onEnd(): void {
    this.contentWriter!.close();
  }
}
 
export default LcovOnlyReport;