use srcmap_sourcemap::{Bias, SourceMap};
const SOURCE_MAP_JSON: &str = r#"{
"version": 3,
"file": "bundle.js",
"sources": ["src/app.ts", "src/utils.ts"],
"sourcesContent": [
"\"use strict\";\nfunction greet(name) {\n const msg = formatName(name);\n console.log(msg);\n}\n",
"// Utility functions\n\nexport function formatName(n: string): string {\n return \"Hello, \" + n;\n}\n"
],
"names": ["greet", "formatName", "console", "log"],
"mappings": "AAAA;AACAA,SAASA,MAAM;EACX,UCFJC,WAAW;EDGPC,QAAQC,IAAI;AAChB;;ACFAF,SAAgBA;EACZ,oBAAoB;AACxB",
"ignoreList": [],
"debugId": "12345678-1234-1234-1234-123456789abc"
}"#;
fn main() {
let sm = SourceMap::from_json(SOURCE_MAP_JSON).expect("valid source map");
println!(
"Parsed source map for {:?}",
sm.file.as_deref().unwrap_or("<unknown>")
);
println!(" Sources: {:?}", sm.sources);
println!(" Names: {:?}", sm.names);
println!(" Lines: {}", sm.line_count());
println!(" Mappings: {}", sm.mapping_count());
println!(" Debug ID: {:?}", sm.debug_id);
println!();
assert_eq!(sm.sources.len(), 2);
assert_eq!(sm.names.len(), 4);
assert!(sm.line_count() >= 9);
assert!(sm.mapping_count() > 0);
println!("Forward lookup: generated(1, 9) → original");
let loc = sm
.original_position_for(1, 9)
.expect("mapping should exist");
println!(
" → {}:{}:{} (name: {:?})",
sm.source(loc.source),
loc.line,
loc.column,
loc.name.map(|n| sm.name(n))
);
assert_eq!(sm.source(loc.source), "src/app.ts");
assert_eq!(loc.line, 1);
assert_eq!(loc.column, 9);
assert_eq!(loc.name.map(|n| sm.name(n)), Some("greet"));
println!();
println!("Forward lookup: generated(3, 2) → original");
let loc = sm
.original_position_for(3, 2)
.expect("mapping should exist");
println!(
" → {}:{}:{} (name: {:?})",
sm.source(loc.source),
loc.line,
loc.column,
loc.name.map(|n| sm.name(n))
);
assert_eq!(sm.source(loc.source), "src/app.ts");
assert_eq!(loc.line, 3);
assert_eq!(loc.column, 4);
assert_eq!(loc.name.map(|n| sm.name(n)), Some("console"));
println!();
println!("Reverse lookup: src/app.ts:3:4 → generated");
let gen_loc = sm
.generated_position_for("src/app.ts", 3, 4)
.expect("reverse mapping should exist");
println!(" → bundle.js:{}:{}", gen_loc.line, gen_loc.column);
assert_eq!(gen_loc.line, 3);
assert_eq!(gen_loc.column, 2);
println!();
println!("Bias lookup: generated(1, 12) with GreatestLowerBound");
let glb = sm
.original_position_for_with_bias(1, 12, Bias::GreatestLowerBound)
.expect("GLB should find mapping");
println!(" → original col {} (snapped left to col 9)", glb.column);
assert_eq!(glb.column, 9);
println!("Bias lookup: generated(1, 12) with LeastUpperBound");
let lub = sm
.original_position_for_with_bias(1, 12, Bias::LeastUpperBound)
.expect("LUB should find mapping");
println!(" → original col {} (snapped right to col 15)", lub.column);
assert_eq!(lub.column, 15);
println!();
println!("All generated positions for src/app.ts:1:0");
let all_positions = sm.all_generated_positions_for("src/app.ts", 1, 0);
for pos in &all_positions {
println!(" → generated({}:{})", pos.line, pos.column);
}
assert!(!all_positions.is_empty());
assert_eq!(all_positions[0].line, 1);
assert_eq!(all_positions[0].column, 0);
println!();
println!("Range mapping: generated(3:2 → 3:14)");
if let Some(range) = sm.map_range(3, 2, 3, 14) {
println!(
" → {}:{}:{} → {}:{}",
sm.source(range.source),
range.original_start_line,
range.original_start_column,
range.original_end_line,
range.original_end_column,
);
assert_eq!(sm.source(range.source), "src/app.ts");
} else {
println!(" (endpoints mapped to different sources — not a valid range)");
}
println!();
println!("Mappings on generated line 2:");
let line_mappings = sm.mappings_for_line(2);
for m in line_mappings {
if m.source != u32::MAX {
let name_str = if m.name != u32::MAX {
sm.name(m.name)
} else {
"(none)"
};
println!(
" gen_col={} → {}:{}:{} name={}",
m.generated_column,
sm.source(m.source),
m.original_line,
m.original_column,
name_str,
);
}
}
assert!(!sm.mappings_for_line(2).is_empty());
println!();
assert_eq!(sm.source(0), "src/app.ts");
assert_eq!(sm.source(1), "src/utils.ts");
assert_eq!(sm.name(0), "greet");
assert_eq!(sm.name(3), "log");
assert_eq!(sm.source_index("src/app.ts"), Some(0));
assert_eq!(sm.source_index("src/utils.ts"), Some(1));
assert_eq!(sm.source_index("nonexistent.js"), None);
assert!(sm.sources_content[0].is_some());
assert!(sm.sources_content[1].is_some());
println!("Source content for src/app.ts (first 40 chars):");
println!(
" {:?}...",
&sm.sources_content[0].as_deref().unwrap_or("")[..40]
);
println!();
println!("Total mappings: {}", sm.all_mappings().len());
assert_eq!(sm.all_mappings().len(), sm.mapping_count());
println!();
let output_json = sm.to_json();
println!("Serialized JSON length: {} bytes", output_json.len());
let sm2 = SourceMap::from_json(&output_json).expect("round-trip should parse");
let loc2 = sm2
.original_position_for(1, 9)
.expect("round-trip lookup should work");
assert_eq!(loc2.line, 1);
assert_eq!(loc2.column, 9);
assert_eq!(sm2.source(loc2.source), "src/app.ts");
println!("Round-trip verification passed.");
println!();
println!("All assertions passed.");
}