@@ -38,9 +38,11 @@ export interface V8CoverageRange {
3838}
3939
4040export interface V8FunctionCoverage {
41- functionName ?: string ;
41+ // V8 always emits these per Node's Profiler.FunctionCoverage contract; matching that
42+ // shape lets us pass V8FunctionCoverage[] to ast-v8-to-istanbul.convert without a cast.
43+ functionName : string ;
4244 ranges : V8CoverageRange [ ] ;
43- isBlockCoverage ? : boolean ;
45+ isBlockCoverage : boolean ;
4446}
4547
4648export interface V8ScriptCoverage {
@@ -258,10 +260,13 @@ export async function processV8CoverageFile(
258260 includeAll : boolean = false ,
259261 preParsedData ?: V8CoverageData ,
260262) : Promise < CoverageResult > {
261- // Lazy-loaded: these are only needed when coverage is enabled, which is opt-in.
262- // Using require() avoids loading them on every SDK startup (adds ~50ms + memory).
263- // eslint-disable-next-line @typescript-eslint/no-var-requires
264- const { convert } = require ( "ast-v8-to-istanbul" ) ;
263+ // Lazy-loaded: only needed when coverage is enabled (opt-in), saves ~50ms + memory at SDK startup.
264+ // Using dynamic import (not require) because ast-v8-to-istanbul is ESM-only and pulls in
265+ // estree-walker, whose package.json `exports` field has no `require` condition. Under tsx's
266+ // ESM loader, `require("ast-v8-to-istanbul")` resolves transitive imports with the require
267+ // condition and dies on estree-walker with ERR_PACKAGE_PATH_NOT_EXPORTED. Dynamic import
268+ // resolves with the import condition throughout and works under both plain Node and tsx.
269+ const { convert } = await import ( "ast-v8-to-istanbul" ) ;
265270 const data : V8CoverageData = preParsedData ?? JSON . parse ( fs . readFileSync ( v8FilePath , "utf-8" ) ) ;
266271 const coverage : CoverageResult = { } ;
267272
@@ -328,7 +333,10 @@ export async function processV8CoverageFile(
328333 code : codeForConvert ,
329334 ast,
330335 coverage : { functions : script . functions , url : script . url } ,
331- ...( sourceMap ? { sourceMap } : { } ) ,
336+ // sourceMap is parsed JSON — loadSourceMap returns Record<string, unknown> rather
337+ // than committing to a specific source-map type from a transitive dep. Cast to the
338+ // shape convert expects.
339+ ...( sourceMap ? { sourceMap : sourceMap as Parameters < typeof convert > [ 0 ] [ "sourceMap" ] } : { } ) ,
332340 ...( cjsWrapperLength ? { wrapperLength : cjsWrapperLength } : { } ) ,
333341 } ) ;
334342
0 commit comments