1+ import assert from 'node:assert'
12import * as fs from 'node:fs/promises'
23import * as path from 'node:path'
34import {
@@ -40,16 +41,17 @@ export function createCliLogger(verbose: boolean): Logger {
4041 */
4142export type ProcessCoverageInputs = {
4243 /** Coverage file patterns (newline or comma separated) */
43- files : string
44+ filePatterns : string [ ]
4445 /** Source directory for resolving file paths from coverage files */
4546 sourceDir : string
46- /** Glob pattern to filter which files to show */
47- globPattern : string
47+ /** Glob patterns for files to exclude. If empty, no files are excluded. */
48+ excludePatterns : string [ ]
4849 /** Explicit base commit SHA for comparison */
4950 baseSha ?: string | undefined
5051 /** Explicit head commit SHA for comparison */
5152 headSha ?: string | undefined
5253}
54+
5355/**
5456 * Result of coverage processing.
5557 */
@@ -74,16 +76,10 @@ export async function processCoverage(
7476 inputs : ProcessCoverageInputs ,
7577 logger : Logger ,
7678) : Promise < ProcessCoverageResult | null > {
77- // Find all matching coverage files
78- const filePatterns = inputs . files
79- . split ( / [ \n , ] / )
80- . map ( ( line ) => line . trim ( ) )
81- . filter ( ( line ) => line . length > 0 )
82-
83- logger . info ( `Looking for coverage files matching: [${ filePatterns . join ( ', ' ) } ]` )
79+ logger . info ( `Looking for coverage files matching: [${ inputs . filePatterns . join ( ', ' ) } ]` )
8480
8581 // Sort and de-duplicate matched files for deterministic CI output
86- const globResults = await Array . fromAsync ( fs . glob ( filePatterns ) )
82+ const globResults = await Array . fromAsync ( fs . glob ( inputs . filePatterns ) )
8783 const matchedFiles = [ ...new Set ( globResults . map ( ( f ) => path . resolve ( f ) ) . sort ( ) ) ]
8884
8985 if ( matchedFiles . length === 0 ) {
@@ -135,8 +131,10 @@ export async function processCoverage(
135131 }
136132
137133 // Apply filters to the coverage report
138- const globFilteredPackages : PackageCoverage [ ] = filterByGlob ( mergedPackages , inputs . globPattern , logger )
139- const fileFilteredPackages = changedLinesPerFileMap ?filterByChangedLines ( globFilteredPackages , changedLinesPerFileMap , logger ) : globFilteredPackages
134+ const globFilteredPackages : PackageCoverage [ ] = filterByGlob ( mergedPackages , inputs . excludePatterns , logger )
135+ const fileFilteredPackages = changedLinesPerFileMap
136+ ? filterByChangedLines ( globFilteredPackages , changedLinesPerFileMap , logger )
137+ : globFilteredPackages
140138
141139 // Read file contents from disk using resolved paths
142140 const fileContents = await readFileContents ( fileFilteredPackages )
@@ -217,21 +215,23 @@ async function mergeReportAndResolveSources(
217215 const existing = fileMap . get ( resolvedPath )
218216 if ( existing ) {
219217 const merged = CoberturaCoverageParser . merge ( existing , file . lines )
218+ assert ( existing . resolvedPath )
220219 fileMap . set ( resolvedPath , merged )
221220 logger . debug ?.( `Merged duplicate file: ${ file . filename } ` )
222221 } else {
223- fileMap . set ( resolvedPath , { resolvedPath, ...file } )
222+ file . resolvedPath = resolvedPath
223+ fileMap . set ( resolvedPath , file )
224224 }
225225 }
226226 }
227227 }
228228
229229 // Convert file maps back to arrays for the final report
230- const packages : PackageCoverage [ ] = Array . from ( packageMap . values ( ) ) . map ( ( { name, fileMap } ) => {
230+ const packages : PackageCoverage [ ] = Array . from ( packageMap . values ( ) ) . map ( ( { name, fileMap } ) : PackageCoverage => {
231231 const files = Array . from ( fileMap . values ( ) )
232232 return {
233233 name,
234- files,
234+ files : files ,
235235 coverage : CoberturaCoverageParser . calculateFileCoverage ( files ) ,
236236 }
237237 } )
0 commit comments