@@ -16,6 +16,7 @@ const {
1616 StringPrototypeIncludes,
1717 StringPrototypeLocaleCompare,
1818 StringPrototypeStartsWith,
19+ StringPrototypeTrim,
1920} = primordials ;
2021const {
2122 copyFileSync,
@@ -45,6 +46,20 @@ const kIgnoreRegex = /\/\* node:coverage ignore next (?<count>\d+ )?\*\//;
4546const kLineEndingRegex = / \r ? \n $ / u;
4647const kLineSplitRegex = / (?< = \r ? \n ) / u;
4748const 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 ) \* \/ / ;
49+ const kTypeOnlyImportRegex = / ^ \s * i m p o r t \s + t y p e \b / u;
50+ const kTypeScriptSourceRegex = / \. (?: c t s | m t s | t s ) $ / u;
51+
52+ let stripTypeScriptTypesForCoverage ;
53+
54+ function getStripTypeScriptTypesForCoverage ( ) {
55+ if ( ! process . config . variables . node_use_amaro ) {
56+ return ;
57+ }
58+
59+ stripTypeScriptTypesForCoverage ??=
60+ require ( 'internal/modules/typescript' ) . stripTypeScriptTypesForCoverage ;
61+ return stripTypeScriptTypesForCoverage ;
62+ }
4863
4964class CoverageLine {
5065 constructor ( line , startOffset , src , length = src ?. length ) {
@@ -70,6 +85,7 @@ class TestCoverage {
7085 }
7186
7287 #sourceLines = new SafeMap ( ) ;
88+ #typeScriptLines = new SafeSet ( ) ;
7389
7490 getLines ( fileUrl , source ) {
7591 // Split the file source into lines. Make sure the lines maintain their
@@ -134,6 +150,57 @@ class TestCoverage {
134150 return lines ;
135151 }
136152
153+ markTypeScriptOnlyLines ( fileUrl , source ) {
154+ if ( this . #typeScriptLines. has ( fileUrl ) ) {
155+ return ;
156+ }
157+ this . #typeScriptLines. add ( fileUrl ) ;
158+
159+ if ( RegExpPrototypeExec ( kTypeScriptSourceRegex , fileUrl ) === null ) {
160+ return ;
161+ }
162+
163+ const lines = this . getLines ( fileUrl , source ) ;
164+ if ( ! lines ) {
165+ return ;
166+ }
167+
168+ let strippedLines ;
169+ const stripSource = getStripTypeScriptTypesForCoverage ( ) ;
170+
171+ if ( stripSource ) {
172+ source ??= readFileSync ( fileURLToPath ( fileUrl ) , 'utf8' ) ;
173+
174+ try {
175+ strippedLines = RegExpPrototypeSymbolSplit (
176+ kLineSplitRegex ,
177+ stripSource ( source ) ,
178+ ) ;
179+ } catch {
180+ strippedLines = undefined ;
181+ }
182+ }
183+
184+ for ( let i = 0 ; i < lines . length ; ++ i ) {
185+ const originalLine = lines [ i ] . src ;
186+
187+ if ( StringPrototypeTrim ( originalLine ) . length === 0 ) {
188+ continue ;
189+ }
190+
191+ if ( strippedLines ?. [ i ] !== undefined ) {
192+ if ( StringPrototypeTrim ( strippedLines [ i ] ) . length === 0 ) {
193+ lines [ i ] . ignore = true ;
194+ }
195+ continue ;
196+ }
197+
198+ if ( RegExpPrototypeExec ( kTypeOnlyImportRegex , originalLine ) !== null ) {
199+ lines [ i ] . ignore = true ;
200+ }
201+ }
202+ }
203+
137204 summary ( ) {
138205 internalBinding ( 'profiler' ) . takeCoverage ( ) ;
139206 const coverage = this . getCoverageFromDirectory ( ) ;
@@ -369,10 +436,12 @@ class TestCoverage {
369436 offset += length + 1 ;
370437 return coverageLine ;
371438 } ) ;
372- if ( data . sourcesContent != null ) {
373- for ( let j = 0 ; j < data . sources . length ; ++ j ) {
374- this . getLines ( data . sources [ j ] , data . sourcesContent [ j ] ) ;
439+ for ( let j = 0 ; j < data . sources . length ; ++ j ) {
440+ const source = data . sourcesContent ?. [ j ] ;
441+ if ( source != null ) {
442+ this . getLines ( data . sources [ j ] , source ) ;
375443 }
444+ this . markTypeScriptOnlyLines ( data . sources [ j ] , source ) ;
376445 }
377446 const sourceMap = new SourceMap ( data , { __proto__ : null , lineLengths } ) ;
378447
0 commit comments