@@ -36,6 +36,46 @@ const textEncoder = new TextEncoder();
3636 */
3737const LINKER_DECLARATION_PREFIX = 'ɵɵngDeclare' ;
3838
39+ async function instrumentCoverage (
40+ filename : string ,
41+ data : string ,
42+ useInputSourcemap : boolean ,
43+ ) : Promise < string > {
44+ try {
45+ let resolvedPath = 'istanbul-lib-instrument' ;
46+ try {
47+ const requireFn = createRequire ( filename ) ;
48+ resolvedPath = requireFn . resolve ( 'istanbul-lib-instrument' ) ;
49+ } catch {
50+ // Fallback to pool worker import traversal
51+ }
52+
53+ const { createInstrumenter } = ( await import (
54+ resolvedPath
55+ ) ) as typeof import ( 'istanbul-lib-instrument' ) ;
56+ const instrumenter = createInstrumenter ( {
57+ produceSourceMap : useInputSourcemap ,
58+ esModules : true ,
59+ } ) ;
60+
61+ const instrumentedCode = instrumenter . instrumentSync ( data , filename ) ;
62+ const lastMap = instrumenter . lastSourceMap ( ) ;
63+
64+ if ( useInputSourcemap && lastMap ) {
65+ const inlineMap = Buffer . from ( JSON . stringify ( lastMap ) ) . toString ( 'base64' ) ;
66+
67+ return instrumentedCode + `\n//# sourceMappingURL=data:application/json;base64,${ inlineMap } ` ;
68+ }
69+
70+ return removeSourceMappingURL ( instrumentedCode ) ;
71+ } catch ( error ) {
72+ throw new Error (
73+ `The 'istanbul-lib-instrument' package is required for code coverage but was not found. Please install the package.` ,
74+ { cause : error } ,
75+ ) ;
76+ }
77+ }
78+
3979export default async function transformJavaScript (
4080 request : JavaScriptTransformRequest ,
4181) : Promise < unknown > {
@@ -59,41 +99,18 @@ async function transformWithBabel(
5999 data : string ,
60100 options : Omit < JavaScriptTransformRequest , 'filename' | 'data' > ,
61101) : Promise < string > {
62- const shouldLink = ! options . skipLinker && ( await requiresLinking ( filename , data ) ) ;
63102 const useInputSourcemap =
64103 options . sourcemap &&
65104 ( ! ! options . thirdPartySourcemaps || ! / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] / . test ( filename ) ) ;
66105
67- const plugins : PluginItem [ ] = [ ] ;
68-
106+ let code = data ;
69107 if ( options . instrumentForCoverage ) {
70- try {
71- let resolvedPath = 'istanbul-lib-instrument' ;
72- try {
73- const requireFn = createRequire ( filename ) ;
74- resolvedPath = requireFn . resolve ( 'istanbul-lib-instrument' ) ;
75- } catch {
76- // Fallback to pool worker import traversal
77- }
78-
79- const istanbul = await import ( resolvedPath ) ;
80- const programVisitor = istanbul . programVisitor ?? istanbul . default ?. programVisitor ;
81-
82- if ( ! programVisitor ) {
83- throw new Error ( 'programVisitor is not available in istanbul-lib-instrument.' ) ;
84- }
85-
86- const { default : coveragePluginFactory } =
87- await import ( '../babel/plugins/add-code-coverage.js' ) ;
88- plugins . push ( coveragePluginFactory ( programVisitor ) as unknown as PluginItem ) ;
89- } catch ( error ) {
90- throw new Error (
91- `The 'istanbul-lib-instrument' package is required for code coverage but was not found. Please install the package.` ,
92- { cause : error } ,
93- ) ;
94- }
108+ code = await instrumentCoverage ( filename , code , useInputSourcemap ) ;
95109 }
96110
111+ const shouldLink = ! options . skipLinker && ( await requiresLinking ( filename , code ) ) ;
112+ const plugins : PluginItem [ ] = [ ] ;
113+
97114 if ( shouldLink ) {
98115 // Lazy load the linker plugin only when linking is required
99116 const linkerPlugin = await createLinkerPlugin ( options ) ;
@@ -116,13 +133,13 @@ async function transformWithBabel(
116133 ) ;
117134 }
118135
119- // If no additional transformations are needed, return the data directly
136+ // If no additional transformations are needed, return the code directly
120137 if ( plugins . length === 0 ) {
121138 // Strip sourcemaps if they should not be used
122- return useInputSourcemap ? data : removeSourceMappingURL ( data ) ;
139+ return useInputSourcemap ? code : removeSourceMappingURL ( code ) ;
123140 }
124141
125- const result = await transformAsync ( data , {
142+ const result = await transformAsync ( code , {
126143 filename,
127144 inputSourceMap : ( useInputSourcemap ? undefined : false ) as undefined ,
128145 sourceMaps : useInputSourcemap ? 'inline' : false ,
@@ -133,7 +150,7 @@ async function transformWithBabel(
133150 plugins,
134151 } ) ;
135152
136- const outputCode = result ?. code ?? data ;
153+ const outputCode = result ?. code ?? code ;
137154
138155 // Strip sourcemaps if they should not be used.
139156 // Babel will keep the original comments even if sourcemaps are disabled.
0 commit comments