context.js
1 'use strict'; 2 /* 3 Copyright 2012-2015, Yahoo Inc. 4 Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. 5 */ 6 const fs = require('fs'); 7 const FileWriter = require('./file-writer'); 8 const XMLWriter = require('./xml-writer'); 9 const tree = require('./tree'); 10 const watermarks = require('./watermarks'); 11 const SummarizerFactory = require('./summarizer-factory'); 12 13 function defaultSourceLookup(path) { 14 try { 15 return fs.readFileSync(path, 'utf8'); 16 } catch (ex) { 17 throw new Error(`Unable to lookup source: ${path} (${ex.message})`); 18 } 19 } 20 21 function normalizeWatermarks(specified = {}) { 22 Object.entries(watermarks.getDefault()).forEach(([k, value]) => { 23 const specValue = specified[k]; 24 if (!Array.isArray(specValue) || specValue.length !== 2) { 25 specified[k] = value; 26 } 27 }); 28 29 return specified; 30 } 31 32 /** 33 * A reporting context that is passed to report implementations 34 * @param {Object} [opts=null] opts options 35 * @param {String} [opts.dir='coverage'] opts.dir the reporting directory 36 * @param {Object} [opts.watermarks=null] opts.watermarks watermarks for 37 * statements, lines, branches and functions 38 * @param {Function} [opts.sourceFinder=fsLookup] opts.sourceFinder a 39 * function that returns source code given a file path. Defaults to 40 * filesystem lookups based on path. 41 * @constructor 42 */ 43 class Context { 44 constructor(opts) { 45 this.dir = opts.dir || 'coverage'; 46 this.watermarks = normalizeWatermarks(opts.watermarks); 47 this.sourceFinder = opts.sourceFinder || defaultSourceLookup; 48 this._summarizerFactory = new SummarizerFactory( 49 opts.coverageMap, 50 opts.defaultSummarizer 51 ); 52 this.data = {}; 53 } 54 55 /** 56 * returns a FileWriter implementation for reporting use. Also available 57 * as the `writer` property on the context. 58 * @returns {Writer} 59 */ 60 getWriter() { 61 return this.writer; 62 } 63 64 /** 65 * returns the source code for the specified file path or throws if 66 * the source could not be found. 67 * @param {String} filePath the file path as found in a file coverage object 68 * @returns {String} the source code 69 */ 70 getSource(filePath) { 71 return this.sourceFinder(filePath); 72 } 73 74 /** 75 * returns the coverage class given a coverage 76 * types and a percentage value. 77 * @param {String} type - the coverage type, one of `statements`, `functions`, 78 * `branches`, or `lines` 79 * @param {Number} value - the percentage value 80 * @returns {String} one of `high`, `medium` or `low` 81 */ 82 classForPercent(type, value) { 83 const watermarks = this.watermarks[type]; 84 if (!watermarks) { 85 return 'unknown'; 86 } 87 if (value < watermarks[0]) { 88 return 'low'; 89 } 90 if (value >= watermarks[1]) { 91 return 'high'; 92 } 93 return 'medium'; 94 } 95 96 /** 97 * returns an XML writer for the supplied content writer 98 * @param {ContentWriter} contentWriter the content writer to which the returned XML writer 99 * writes data 100 * @returns {XMLWriter} 101 */ 102 getXMLWriter(contentWriter) { 103 return new XMLWriter(contentWriter); 104 } 105 106 /** 107 * returns a full visitor given a partial one. 108 * @param {Object} partialVisitor a partial visitor only having the functions of 109 * interest to the caller. These functions are called with a scope that is the 110 * supplied object. 111 * @returns {Visitor} 112 */ 113 getVisitor(partialVisitor) { 114 return new tree.Visitor(partialVisitor); 115 } 116 117 getTree(name = 'defaultSummarizer') { 118 return this._summarizerFactory[name]; 119 } 120 } 121 122 Object.defineProperty(Context.prototype, 'writer', { 123 enumerable: true, 124 get() { 125 if (!this.data.writer) { 126 this.data.writer = new FileWriter(this.dir); 127 } 128 return this.data.writer; 129 } 130 }); 131 132 module.exports = Context;