use crate::types::{BranchEntry, FileCoverage, FnEntry, Location, Position};
pub fn remap_coverage(coverage: &FileCoverage) -> Option<FileCoverage> {
let input_sm_value = coverage.input_source_map.as_ref()?;
let input_sm_json = serde_json::to_string(input_sm_value).ok()?;
let sm = srcmap_sourcemap::SourceMap::from_json(&input_sm_json).ok()?;
let primary_source = resolve_primary_source(&sm)?;
let mut out = coverage.clone();
out.path = primary_source;
out.input_source_map = None;
for loc in out.statement_map.values_mut() {
remap_location(loc, &sm);
}
for fn_entry in out.fn_map.values_mut() {
remap_fn_entry(fn_entry, &sm);
}
for branch_entry in out.branch_map.values_mut() {
remap_branch_entry(branch_entry, &sm);
}
Some(out)
}
pub fn remap_coverage_map(
coverage_map: &std::collections::BTreeMap<String, FileCoverage>,
) -> std::collections::BTreeMap<String, FileCoverage> {
let mut out = std::collections::BTreeMap::new();
for (path, fc) in coverage_map {
match remap_coverage(fc) {
Some(remapped) => {
out.insert(remapped.path.clone(), remapped);
}
None => {
out.insert(path.clone(), fc.clone());
}
}
}
out
}
fn resolve_primary_source(sm: &srcmap_sourcemap::SourceMap) -> Option<String> {
let first = sm.sources.first()?;
if first.is_empty() {
return None;
}
let root = sm.source_root.as_deref().unwrap_or("");
if root.is_empty() {
return Some(first.clone());
}
let bare = first.strip_prefix(root).unwrap_or(first.as_str());
if root.ends_with('/') || bare.starts_with('/') {
Some(format!("{root}{bare}"))
} else {
Some(format!("{root}/{bare}"))
}
}
fn remap_position(pos: &mut Position, sm: &srcmap_sourcemap::SourceMap) {
if pos.line == 0 {
return;
}
let gen_line = pos.line - 1;
if let Some(orig) = sm.original_position_for(gen_line, pos.column) {
pos.line = orig.line + 1;
pos.column = orig.column;
}
}
fn remap_location(loc: &mut Location, sm: &srcmap_sourcemap::SourceMap) {
remap_position(&mut loc.start, sm);
remap_position(&mut loc.end, sm);
}
fn remap_fn_entry(fn_entry: &mut FnEntry, sm: &srcmap_sourcemap::SourceMap) {
remap_location(&mut fn_entry.decl, sm);
remap_location(&mut fn_entry.loc, sm);
fn_entry.line = fn_entry.loc.start.line;
}
fn remap_branch_entry(branch_entry: &mut BranchEntry, sm: &srcmap_sourcemap::SourceMap) {
remap_location(&mut branch_entry.loc, sm);
for loc in &mut branch_entry.locations {
remap_location(loc, sm);
}
branch_entry.line = branch_entry.loc.start.line;
}