@@ -29,16 +29,11 @@ const { tmpdir } = require('os');
2929const { join, resolve, relative, matchesGlob } = require ( 'path' ) ;
3030const { fileURLToPath } = require ( 'internal/url' ) ;
3131const { kMappings, SourceMap } = require ( 'internal/source_map/source_map' ) ;
32- const { parseCommandLine } = require ( 'internal/test_runner/utils' ) ;
3332const kCoverageFileRegex = / ^ c o v e r a g e - ( \d + ) - ( \d { 13 } ) - ( \d + ) \. j s o n $ / ;
3433const kIgnoreRegex = / \/ \* n o d e : c o v e r a g e i g n o r e n e x t (?< count > \d + ) ? \* \/ / ;
3534const kLineEndingRegex = / \r ? \n $ / u;
3635const kLineSplitRegex = / (?< = \r ? \n ) / u;
3736const kStatusRegex = / \/ \* n o d e : c o v e r a g e (?< status > e n a b l e | d i s a b l e ) \* \/ / ;
38- const {
39- coverageExcludeGlobs,
40- coverageIncludeGlobs,
41- } = parseCommandLine ( ) ;
4237
4338class CoverageLine {
4439 constructor ( line , startOffset , src , length = src ?. length ) {
@@ -55,10 +50,12 @@ class CoverageLine {
5550}
5651
5752class TestCoverage {
58- constructor ( coverageDirectory , originalCoverageDirectory , workingDirectory ) {
53+ constructor ( coverageDirectory , originalCoverageDirectory , workingDirectory , excludeGlobs , includeGlobs ) {
5954 this . coverageDirectory = coverageDirectory ;
6055 this . originalCoverageDirectory = originalCoverageDirectory ;
6156 this . workingDirectory = workingDirectory ;
57+ this . excludeGlobs = excludeGlobs ;
58+ this . includeGlobs = includeGlobs ;
6259 }
6360
6461 #sourceLines = new SafeMap ( ) ;
@@ -313,7 +310,7 @@ class TestCoverage {
313310
314311 const coverageFile = join ( this . coverageDirectory , entry . name ) ;
315312 const coverage = JSONParse ( readFileSync ( coverageFile , 'utf8' ) ) ;
316- mergeCoverage ( result , this . mapCoverageWithSourceMap ( coverage ) , this . workingDirectory ) ;
313+ this . mergeCoverage ( result , this . mapCoverageWithSourceMap ( coverage ) ) ;
317314 }
318315
319316 return ArrayFrom ( result . values ( ) ) ;
@@ -336,7 +333,7 @@ class TestCoverage {
336333 const script = result [ i ] ;
337334 const { url, functions } = script ;
338335
339- if ( shouldSkipFileCoverage ( url , this . workingDirectory ) || sourceMapCache [ url ] == null ) {
336+ if ( this . shouldSkipFileCoverage ( url ) || sourceMapCache [ url ] == null ) {
340337 newResult . set ( url , script ) ;
341338 continue ;
342339 }
@@ -412,6 +409,54 @@ class TestCoverage {
412409 return MathMin ( lines [ line ] . startOffset + entry . originalColumn , lines [ line ] . endOffset ) ;
413410 }
414411
412+ mergeCoverage ( merged , coverage ) {
413+ for ( let i = 0 ; i < coverage . length ; ++ i ) {
414+ const newScript = coverage [ i ] ;
415+ const { url } = newScript ;
416+
417+ if ( this . shouldSkipFileCoverage ( url ) ) {
418+ continue ;
419+ }
420+
421+ const oldScript = merged . get ( url ) ;
422+
423+ if ( oldScript === undefined ) {
424+ merged . set ( url , newScript ) ;
425+ } else {
426+ mergeCoverageScripts ( oldScript , newScript ) ;
427+ }
428+ }
429+ }
430+
431+ shouldSkipFileCoverage ( url ) {
432+ // This check filters out core modules, which start with 'node:' in
433+ // coverage reports, as well as any invalid coverages which have been
434+ // observed on Windows.
435+ if ( ! StringPrototypeStartsWith ( url , 'file:' ) ) return true ;
436+
437+ const absolutePath = fileURLToPath ( url ) ;
438+ const relativePath = relative ( this . workingDirectory , absolutePath ) ;
439+
440+ // This check filters out files that match the exclude globs.
441+ if ( this . excludeGlobs ?. length > 0 ) {
442+ for ( let i = 0 ; i < this . excludeGlobs . length ; ++ i ) {
443+ if ( matchesGlob ( relativePath , this . excludeGlobs [ i ] ) ||
444+ matchesGlob ( absolutePath , this . excludeGlobs [ i ] ) ) return true ;
445+ }
446+ }
447+
448+ // This check filters out files that do not match the include globs.
449+ if ( this . includeGlobs ?. length > 0 ) {
450+ for ( let i = 0 ; i < this . includeGlobs . length ; ++ i ) {
451+ if ( matchesGlob ( relativePath , this . includeGlobs [ i ] ) ||
452+ matchesGlob ( absolutePath , this . includeGlobs [ i ] ) ) return false ;
453+ }
454+ return true ;
455+ }
456+
457+ // This check filters out the node_modules/ directory, unless it is explicitly included.
458+ return StringPrototypeIncludes ( url , '/node_modules/' ) ;
459+ }
415460}
416461
417462function toPercentage ( covered , total ) {
@@ -422,7 +467,7 @@ function sortCoverageFiles(a, b) {
422467 return StringPrototypeLocaleCompare ( a . path , b . path ) ;
423468}
424469
425- function setupCoverage ( ) {
470+ function setupCoverage ( options ) {
426471 let originalCoverageDirectory = process . env . NODE_V8_COVERAGE ;
427472 const cwd = process . cwd ( ) ;
428473
@@ -446,7 +491,13 @@ function setupCoverage() {
446491 // child processes.
447492 process . env . NODE_V8_COVERAGE = coverageDirectory ;
448493
449- return new TestCoverage ( coverageDirectory , originalCoverageDirectory , cwd ) ;
494+ return new TestCoverage (
495+ coverageDirectory ,
496+ originalCoverageDirectory ,
497+ cwd ,
498+ options . coverageExcludeGlobs ,
499+ options . coverageIncludeGlobs ,
500+ ) ;
450501}
451502
452503function mapRangeToLines ( range , lines ) {
@@ -490,55 +541,6 @@ function mapRangeToLines(range, lines) {
490541 return { __proto__ : null , lines : mappedLines , ignoredLines } ;
491542}
492543
493- function shouldSkipFileCoverage ( url , workingDirectory ) {
494- // This check filters out core modules, which start with 'node:' in
495- // coverage reports, as well as any invalid coverages which have been
496- // observed on Windows.
497- if ( ! StringPrototypeStartsWith ( url , 'file:' ) ) return true ;
498-
499- const absolutePath = fileURLToPath ( url ) ;
500- const relativePath = relative ( workingDirectory , absolutePath ) ;
501-
502- // This check filters out files that match the exclude globs.
503- if ( coverageExcludeGlobs ?. length > 0 ) {
504- for ( let i = 0 ; i < coverageExcludeGlobs . length ; ++ i ) {
505- if ( matchesGlob ( relativePath , coverageExcludeGlobs [ i ] ) ||
506- matchesGlob ( absolutePath , coverageExcludeGlobs [ i ] ) ) return true ;
507- }
508- }
509-
510- // This check filters out files that do not match the include globs.
511- if ( coverageIncludeGlobs ?. length > 0 ) {
512- for ( let i = 0 ; i < coverageIncludeGlobs . length ; ++ i ) {
513- if ( matchesGlob ( relativePath , coverageIncludeGlobs [ i ] ) ||
514- matchesGlob ( absolutePath , coverageIncludeGlobs [ i ] ) ) return false ;
515- }
516- return true ;
517- }
518-
519- // This check filters out the node_modules/ directory, unless it is explicitly included.
520- return StringPrototypeIncludes ( url , '/node_modules/' ) ;
521- }
522-
523- function mergeCoverage ( merged , coverage , workingDirectory ) {
524- for ( let i = 0 ; i < coverage . length ; ++ i ) {
525- const newScript = coverage [ i ] ;
526- const { url } = newScript ;
527-
528- if ( shouldSkipFileCoverage ( url , workingDirectory ) ) {
529- continue ;
530- }
531-
532- const oldScript = merged . get ( url ) ;
533-
534- if ( oldScript === undefined ) {
535- merged . set ( url , newScript ) ;
536- } else {
537- mergeCoverageScripts ( oldScript , newScript ) ;
538- }
539- }
540- }
541-
542544function mergeCoverageScripts ( oldScript , newScript ) {
543545 // Merge the functions from the new coverage into the functions from the
544546 // existing (merged) coverage.
0 commit comments