Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/core/coverageProcessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ test("takeAndProcessSnapshot: skips coverage files without user scripts", async
{
functionName: "",
ranges: [{ startOffset: 0, endOffset: 10, count: 1 }],
isBlockCoverage: false,
},
],
},
Expand Down
22 changes: 15 additions & 7 deletions src/core/coverageProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ export interface V8CoverageRange {
}

export interface V8FunctionCoverage {
functionName?: string;
// V8 always emits these per Node's Profiler.FunctionCoverage contract; matching that
// shape lets us pass V8FunctionCoverage[] to ast-v8-to-istanbul.convert without a cast.
functionName: string;
ranges: V8CoverageRange[];
isBlockCoverage?: boolean;
isBlockCoverage: boolean;
}

export interface V8ScriptCoverage {
Expand Down Expand Up @@ -258,10 +260,13 @@ export async function processV8CoverageFile(
includeAll: boolean = false,
preParsedData?: V8CoverageData,
): Promise<CoverageResult> {
// Lazy-loaded: these are only needed when coverage is enabled, which is opt-in.
// Using require() avoids loading them on every SDK startup (adds ~50ms + memory).
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { convert } = require("ast-v8-to-istanbul");
// Lazy-loaded: only needed when coverage is enabled (opt-in), saves ~50ms + memory at SDK startup.
// Using dynamic import (not require) because ast-v8-to-istanbul is ESM-only and pulls in
// estree-walker, whose package.json `exports` field has no `require` condition. Under tsx's
// ESM loader, `require("ast-v8-to-istanbul")` resolves transitive imports with the require
// condition and dies on estree-walker with ERR_PACKAGE_PATH_NOT_EXPORTED. Dynamic import
// resolves with the import condition throughout and works under both plain Node and tsx.
const { convert } = await import("ast-v8-to-istanbul");
const data: V8CoverageData = preParsedData ?? JSON.parse(fs.readFileSync(v8FilePath, "utf-8"));
const coverage: CoverageResult = {};

Expand Down Expand Up @@ -328,7 +333,10 @@ export async function processV8CoverageFile(
code: codeForConvert,
ast,
coverage: { functions: script.functions, url: script.url },
...(sourceMap ? { sourceMap } : {}),
// sourceMap is parsed JSON — loadSourceMap returns Record<string, unknown> rather
// than committing to a specific source-map type from a transitive dep. Cast to the
// shape convert expects.
...(sourceMap ? { sourceMap: sourceMap as Parameters<typeof convert>[0]["sourceMap"] } : {}),
...(cjsWrapperLength ? { wrapperLength: cjsWrapperLength } : {}),
});

Expand Down
Loading