diff --git a/src/sourcemap/code_coverage/HTML.zig b/src/sourcemap/code_coverage/HTML.zig
index 7575700c2a..f784125fc7 100644
--- a/src/sourcemap/code_coverage/HTML.zig
+++ b/src/sourcemap/code_coverage/HTML.zig
@@ -3,30 +3,44 @@ pub fn writeFormat(
base_path: []const u8,
writer: anytype,
) !void {
- var filename = report.source_url.slice();
+ var filename = report.source_url.byteSlice();
if (base_path.len > 0) {
- filename = bun.path.relative(base_path, filename);
+ filename = std.fs.path.relative(std.heap.page_allocator, base_path, filename) catch filename;
}
const functions_fraction = report.functionCoverageFraction();
const lines_fraction = report.linesCoverageFraction();
- // Generate HTML filename from source filename
- var html_filename_buf: bun.PathBuffer = undefined;
- const html_filename = std.fmt.bufPrint(&html_filename_buf, "{s}.html", .{bun.path.basename(filename)}) catch filename;
+ // Generate HTML filename from source filename (replace slashes with underscores)
+ var html_filename_buf: [std.fs.max_path_bytes]u8 = undefined;
+ var safe_filename_buf: [std.fs.max_path_bytes]u8 = undefined;
+
+ // Replace slashes with underscores in the filename
+ var safe_len: usize = 0;
+ for (filename) |char| {
+ if (char == '/' or char == '\\') {
+ safe_filename_buf[safe_len] = '_';
+ } else {
+ safe_filename_buf[safe_len] = char;
+ }
+ safe_len += 1;
+ }
+ const safe_filename = safe_filename_buf[0..safe_len];
+ const html_filename = std.fmt.bufPrint(&html_filename_buf, "{s}.html", .{safe_filename}) catch filename;
// Write HTML structure for this file's coverage
try writer.print(
\\
\\ | {s} |
- \\ {d:.2}% |
- \\ {d:.2}% |
+ \\ {d:.2}% |
+ \\ {d:.2}% |
\\
- , .{ filename, html_filename, filename, functions_fraction * 100.0, lines_fraction * 100.0 });
+ , .{ filename, html_filename, filename, if (functions_fraction >= 0.8) "good" else "bad", functions_fraction * 100.0, if (lines_fraction >= 0.8) "good" else "bad", lines_fraction * 100.0 });
// Add uncovered line ranges
- var executable_lines_that_havent_been_executed = report.lines_which_have_executed.clone(bun.default_allocator) catch bun.outOfMemory();
- defer executable_lines_that_havent_been_executed.deinit(bun.default_allocator);
+ const allocator = std.heap.page_allocator;
+ var executable_lines_that_havent_been_executed = report.lines_which_have_executed.clone(allocator) catch return;
+ defer executable_lines_that_havent_been_executed.deinit(allocator);
executable_lines_that_havent_been_executed.toggleAll();
executable_lines_that_havent_been_executed.setIntersection(report.executable_lines);
@@ -61,7 +75,7 @@ pub fn writeFormat(
start_of_line_range = next_line;
}
- if (prev_line != start_of_line_range) {
+ if (prev_line != start_of_line_range or (prev_line > 0 and start_of_line_range > 0)) {
if (is_first) {
is_first = false;
} else {
@@ -84,9 +98,19 @@ pub fn writeDetailedFile(
source_path: []const u8,
writer: anytype,
) !void {
- var filename = report.source_url.slice();
+ _ = writeDetailedFileWithTree(report, base_path, source_path, null, writer) catch |err| return err;
+}
+
+pub fn writeDetailedFileWithTree(
+ report: *const Report,
+ base_path: []const u8,
+ source_path: []const u8,
+ all_reports: ?[]const Report,
+ writer: anytype,
+) !void {
+ var filename = report.source_url.byteSlice();
if (base_path.len > 0) {
- filename = bun.path.relative(base_path, filename);
+ filename = std.fs.path.relative(std.heap.page_allocator, base_path, filename) catch filename;
}
const functions_fraction = report.functionCoverageFraction();
@@ -102,11 +126,24 @@ pub fn writeDetailedFile(
\\
\\
);
- try writer.print(" Coverage: {s}\n", .{bun.path.basename(filename)});
+ try writer.print(" Coverage: {s}\n", .{std.fs.path.basename(filename)});
try writer.writeAll(
\\
\\
\\
- \\ |