///|
/// Incremental Source Map builder. Mappings must be added in generated order.
pub struct SourceMapBuilder {
sources : Array[String]
sources_content : Array[String?]
names : Array[String]
mappings : Array[Mapping]
mut last_line : Int
mut last_column : Int
}
///|
pub fn SourceMapBuilder::new() -> SourceMapBuilder {
{
sources: Array::new(),
sources_content: Array::new(),
names: Array::new(),
mappings: Array::new(),
last_line: 0,
last_column: -1,
}
}
///|
fn SourceMapBuilder::intern_source(
self : SourceMapBuilder,
source : String,
content : String?,
) -> Int raise SourceMapError {
for i in 0..
raise SourceMapError::At(
self.mappings.length(),
"source content conflicts with an earlier mapping",
)
(None, Some(value)) => self.sources_content[i] = Some(value)
_ => ()
}
return i
}
}
self.sources.push(source)
self.sources_content.push(content)
self.sources.length() - 1
}
///|
fn intern(values : Array[String], value : String) -> Int {
for i in 0.. Unit raise SourceMapError {
self.check_order(generated_line, generated_column)
self.mappings.push(Mapping::make(generated_line, generated_column))
self.last_line = generated_line
self.last_column = generated_column
}
///|
/// Add a segment linked to an original source position and optional symbol.
pub fn SourceMapBuilder::add_mapping(
self : SourceMapBuilder,
generated_line : Int,
generated_column : Int,
source : String,
original_line : Int,
original_column : Int,
name? : String? = None,
source_content? : String? = None,
) -> Unit raise SourceMapError {
self.check_order(generated_line, generated_column)
if original_line < 0 || original_column < 0 {
raise SourceMapError::At(
self.mappings.length(),
"original positions must be non-negative",
)
}
let source_index = self.intern_source(source, source_content)
let name_index = match name {
Some(value) => Some(intern(self.names, value))
None => None
}
self.mappings.push(
Mapping::make(
generated_line,
generated_column,
source_index=Some(source_index),
original_line=Some(original_line),
original_column=Some(original_column),
name_index~,
),
)
self.last_line = generated_line
self.last_column = generated_column
}
///|
fn SourceMapBuilder::check_order(
self : SourceMapBuilder,
line : Int,
column : Int,
) -> Unit raise SourceMapError {
if line < 0 || column < 0 {
raise SourceMapError::At(
self.mappings.length(),
"generated positions must be non-negative",
)
}
if line < self.last_line ||
(line == self.last_line && column < self.last_column) {
raise SourceMapError::At(
self.mappings.length(),
"mappings must be added in generated order",
)
}
}
///|
/// Finish the map. The builder remains readable but should not be reused.
pub fn SourceMapBuilder::build(
self : SourceMapBuilder,
file? : String? = None,
source_root? : String? = None,
) -> SourceMap raise SourceMapError {
let has_source_content = self.sources_content.any(content => {
content is Some(_)
})
let sources_content = if has_source_content {
self.sources_content
} else {
[]
}
SourceMap::make(
self.sources,
self.names,
self.mappings,
file~,
source_root~,
sources_content~,
)
}