import { CoverageMapProvider } from '../CoverageMapProvider' ; import * as vscode from 'vscode' ; import { CoverageColors , CoverageStatus } from '../CoverageOverlay' ; import { FileCoverage } from 'istanbul-lib-coverage' ; export type CoverageRanges = { [ status in CoverageStatus ] ? : vscode . Range [ ] ; } ; type FunctionCoverageByLine = { [ line ] : number ; } ; export abstract class AbstractFormatter { protected coverageMapProvider : CoverageMapProvider ; protected colors ? : CoverageColors ; constructor ( coverageMapProvider , colors ? ) { this . coverageMapProvider = coverageMapProvider ; this . colors = colors ; } abstract format ( editor ) ; /** remove decoractors for the given editor */ abstract clear ( editor ) ; /** dispose decoractors for all editors */ abstract dispose ( ) ; param status param opacity getColorString ( status , opacity ) { if ( opacity > 1 || opacity < 0 ) { throw new Error ( `invalid opacity (${ opacity }): value is not between 0 - 1` ) ; } switch ( status ) { case 'covered' : return this . colors ?. [ status ] ?? `rgba(9, 156, 65, ${ opacity })` ; case 'partially-covered' : return this . colors ?. [ status ] ?? `rgba(235, 198, 52, ${ opacity })` ; case 'uncovered' : return this . colors ?. [ status ] ?? `rgba(121, 31, 10, ${ opacity })` ; default : throw new Error ( `unrecognized status: ${ status }` ) ; } } private getFunctionCoverageByLine ( fileCoverage ) { const lineCoverage = { } ; Object . entries ( fileCoverage . fnMap ) . forEach ( ( [ k , { decl } ] ) => { const hits = fileCoverage . f [ k ] ; for ( let idx = decl . start . line ; idx <= decl . end . line ; idx ++ ) { lineCoverage [ idx ] = hits ; } } ) ; return lineCoverage ; } param editor lineCoverageRanges ( editor , onNoCoverageInfo ? ) { const ranges = { } ; const fileCoverage = this . coverageMapProvider . getFileCoverage ( editor . document . fileName ) ; if ( ! fileCoverage ) { return ranges ; } const lineCoverage = fileCoverage . getLineCoverage ( ) ; const branchCoveravge = fileCoverage . getBranchCoverageByLine ( ) ; const funcCoverage = this . getFunctionCoverageByLine ( fileCoverage ) ; for ( let line = 1 ; line <= editor . document . lineCount ; line ++ ) { const zeroBasedLineNumber = line - 1 ; const lc = lineCoverage [ line ] ; const bc = branchCoveravge [ line ] ; const fc = funcCoverage [ line ] ; let status ; if ( fc != null ) { status = fc > 0 ? 'covered' : 'uncovered' ; } else if ( bc != null ) { switch ( bc . coverage ) { case 100 : status = 'covered' ; break ; case 0 : status = 'uncovered' ; break ; default : status = 'partially-covered' ; break ; } } else if ( lc != null ) { status = lc > 0 ? 'covered' : 'uncovered' ; } else if ( onNoCoverageInfo ) { status = onNoCoverageInfo ( ) ; } else { continue ; } const range = new vscode . Range ( zeroBasedLineNumber , 0 , zeroBasedLineNumber , 0 ) ; if ( ranges [ status ] != null ) { ranges [ status ] ! . push ( range ) ; } else { ranges [ status ] = [ range ] ; } } return ranges ; } }