///|
/// Mutable builder for producing Source Map v3 values without manually
/// maintaining source and name indexes.
pub struct SourceMapBuilder {
mut file : String?
mut source_root : String?
sources : Array[String]
sources_content : Array[String?]
names : Array[String]
mappings : Array[MappingSegment]
ignore_list : Array[Int]
} derive(Debug)
///|
pub fn SourceMapBuilder::SourceMapBuilder(
file? : String,
source_root? : String,
) -> SourceMapBuilder {
{
file,
source_root,
sources: [],
sources_content: [],
names: [],
mappings: [],
ignore_list: [],
}
}
///|
pub fn SourceMapBuilder::source_count(self : SourceMapBuilder) -> Int {
self.sources.length()
}
///|
pub fn SourceMapBuilder::name_count(self : SourceMapBuilder) -> Int {
self.names.length()
}
///|
pub fn SourceMapBuilder::mapping_count(self : SourceMapBuilder) -> Int {
self.mappings.length()
}
///|
pub fn SourceMapBuilder::set_file(
self : SourceMapBuilder,
file : StringView,
) -> Unit {
self.file = Some(file.to_owned())
}
///|
pub fn SourceMapBuilder::clear_file(self : SourceMapBuilder) -> Unit {
self.file = None
}
///|
pub fn SourceMapBuilder::set_source_root(
self : SourceMapBuilder,
source_root : StringView,
) -> Unit {
self.source_root = Some(source_root.to_owned())
}
///|
pub fn SourceMapBuilder::clear_source_root(self : SourceMapBuilder) -> Unit {
self.source_root = None
}
///|
fn find_string(items : ArrayView[String], needle : StringView) -> Int? {
let needle = needle.to_owned()
for i, item in items {
if item == needle {
return Some(i)
}
}
None
}
///|
pub fn SourceMapBuilder::add_source(
self : SourceMapBuilder,
source : StringView,
) -> Int {
match find_string(self.sources, source) {
Some(index) => index
None => {
let index = self.sources.length()
self.sources.push(source.to_owned())
self.sources_content.push(None)
index
}
}
}
///|
pub fn SourceMapBuilder::add_name(
self : SourceMapBuilder,
name : StringView,
) -> Int {
match find_string(self.names, name) {
Some(index) => index
None => {
let index = self.names.length()
self.names.push(name.to_owned())
index
}
}
}
///|
pub fn SourceMapBuilder::set_source_content(
self : SourceMapBuilder,
source : StringView,
content : StringView,
) -> Int {
let index = self.add_source(source)
self.sources_content[index] = Some(content.to_owned())
index
}
///|
pub fn SourceMapBuilder::clear_source_content(
self : SourceMapBuilder,
source : StringView,
) -> Bool {
match find_string(self.sources, source) {
Some(index) => {
self.sources_content[index] = None
true
}
None => false
}
}
///|
pub fn SourceMapBuilder::mark_ignored(
self : SourceMapBuilder,
source : StringView,
) -> Int {
let index = self.add_source(source)
if !self.ignore_list.contains(index) {
self.ignore_list.push(index)
}
index
}
///|
pub fn SourceMapBuilder::unmark_ignored(
self : SourceMapBuilder,
source : StringView,
) -> Bool {
match find_string(self.sources, source) {
Some(index) => {
let before = self.ignore_list.length()
self.ignore_list.retain(item => item != index)
before != self.ignore_list.length()
}
None => false
}
}
///|
pub fn SourceMapBuilder::add_unmapped(
self : SourceMapBuilder,
generated_line : Int,
generated_column : Int,
) -> Unit {
self.mappings.push(MappingSegment::unmapped(generated_line, generated_column))
}
///|
pub fn SourceMapBuilder::add_mapping(
self : SourceMapBuilder,
generated_line : Int,
generated_column : Int,
source : StringView,
original_line : Int,
original_column : Int,
name? : StringView,
) -> Unit {
let source_index = self.add_source(source)
let name_index = match name {
Some(value) => Some(self.add_name(value))
None => None
}
match name_index {
Some(index) =>
self.mappings.push(
MappingSegment::mapped(
generated_line,
generated_column,
source_index,
original_line,
original_column,
name_index=index,
),
)
None =>
self.mappings.push(
MappingSegment::mapped(
generated_line, generated_column, source_index, original_line, original_column,
),
)
}
}
///|
pub fn SourceMapBuilder::add_line_start(
self : SourceMapBuilder,
generated_line : Int,
source : StringView,
original_line : Int,
) -> Unit {
self.add_mapping(generated_line, 0, source, original_line, 0)
}
///|
pub fn SourceMapBuilder::append_segments(
self : SourceMapBuilder,
segments : ArrayView[MappingSegment],
) -> Unit {
self.mappings.append(segments)
}
///|
pub fn SourceMapBuilder::sort_mappings(self : SourceMapBuilder) -> Unit {
self.mappings.sort_by((a, b) => {
let line_cmp = a.generated_line.compare(b.generated_line)
if line_cmp != 0 {
line_cmp
} else {
a.generated_column.compare(b.generated_column)
}
})
}
///|
pub fn SourceMapBuilder::build(self : SourceMapBuilder) -> SourceMap {
self.sort_mappings()
{
version: 3,
file: self.file,
source_root: self.source_root,
sources: self.sources.copy(),
sources_content: self.sources_content.copy(),
names: self.names.copy(),
mappings: self.mappings.copy(),
ignore_list: self.ignore_list.copy(),
}
}
///|
pub fn SourceMapBuilder::reset_mappings(self : SourceMapBuilder) -> Unit {
self.mappings.clear()
}
///|
pub fn SourceMapBuilder::reset_all(self : SourceMapBuilder) -> Unit {
self.file = None
self.source_root = None
self.sources.clear()
self.sources_content.clear()
self.names.clear()
self.mappings.clear()
self.ignore_list.clear()
}
///|
pub fn SourceMap::to_builder(self : SourceMap) -> SourceMapBuilder {
{
file: self.file,
source_root: self.source_root,
sources: self.sources.copy(),
sources_content: self.sources_content.copy(),
names: self.names.copy(),
mappings: self.mappings.copy(),
ignore_list: self.ignore_list.copy(),
}
}
///|
pub fn SourceMapBuilder::merge_from(
self : SourceMapBuilder,
other : SourceMap,
generated_line_offset? : Int = 0,
generated_column_offset? : Int = 0,
) -> Unit {
let source_remap : Array[Int] = []
for source in other.sources {
source_remap.push(self.add_source(source))
}
let name_remap : Array[Int] = []
for name in other.names {
name_remap.push(self.add_name(name))
}
for i, content in other.sources_content {
if i < other.sources.length() {
match content {
Some(text) => ignore(self.set_source_content(other.sources[i], text))
None => ()
}
}
}
for index in other.ignore_list {
if index >= 0 && index < other.sources.length() {
ignore(self.mark_ignored(other.sources[index]))
}
}
for segment in other.mappings {
let remapped_source = match segment.source_index {
Some(index) =>
if index >= 0 && index < source_remap.length() {
Some(source_remap[index])
} else {
None
}
None => None
}
let remapped_name = match segment.name_index {
Some(index) =>
if index >= 0 && index < name_remap.length() {
Some(name_remap[index])
} else {
None
}
None => None
}
self.mappings.push({
..segment,
generated_line: segment.generated_line + generated_line_offset,
generated_column: segment.generated_column + generated_column_offset,
source_index: remapped_source,
name_index: remapped_name,
})
}
}