Skip to main content

parcel_sourcemap/
mapping_line.rs

1use crate::mapping::OriginalLocation;
2use crate::sourcemap_error::{SourceMapError, SourceMapErrorType};
3use rkyv::{Archive, Deserialize, Serialize};
4
5#[derive(Archive, Serialize, Deserialize, Debug, Clone, Copy, Default)]
6pub struct LineMapping {
7    pub generated_column: u32,
8    pub original: Option<OriginalLocation>,
9}
10
11#[derive(Archive, Serialize, Deserialize, Debug, Default, Clone)]
12pub struct MappingLine {
13    pub mappings: Vec<LineMapping>,
14    pub last_column: u32,
15    pub is_sorted: bool,
16}
17
18impl MappingLine {
19    pub fn new() -> Self {
20        Self {
21            mappings: Vec::new(),
22            last_column: 0,
23            is_sorted: true,
24        }
25    }
26
27    pub fn add_mapping(&mut self, generated_column: u32, original: Option<OriginalLocation>) {
28        if self.is_sorted && self.last_column > generated_column {
29            self.is_sorted = false;
30        }
31
32        self.mappings.push(LineMapping {
33            generated_column,
34            original,
35        });
36
37        self.last_column = generated_column;
38    }
39
40    pub fn ensure_sorted(&mut self) {
41        if !self.is_sorted {
42            self.mappings
43                .sort_by(|a, b| a.generated_column.cmp(&b.generated_column));
44            self.is_sorted = true
45        }
46    }
47
48    pub fn find_closest_mapping(&mut self, generated_column: u32) -> Option<LineMapping> {
49        if self.mappings.is_empty() {
50            return None;
51        }
52
53        self.ensure_sorted();
54        let index = match self
55            .mappings
56            .binary_search_by(|m| m.generated_column.cmp(&generated_column))
57        {
58            Ok(index) => index,
59            Err(index) => {
60                if index == 0 || index == self.mappings.len() {
61                    return Some(LineMapping {
62                        generated_column: 0,
63                        original: self.mappings[0].original,
64                    });
65                }
66
67                index - 1
68            }
69        };
70
71        Some(self.mappings[index])
72    }
73
74    pub fn offset_columns(
75        &mut self,
76        generated_column: u32,
77        generated_column_offset: i64,
78    ) -> Result<(), SourceMapError> {
79        let (start_column, overflowed) =
80            (generated_column as i64).overflowing_add(generated_column_offset);
81        if overflowed || start_column > (u32::MAX as i64) {
82            return Err(SourceMapError::new_with_reason(
83                SourceMapErrorType::UnexpectedNegativeNumber,
84                "column + column_offset cannot be negative",
85            ));
86        }
87
88        self.ensure_sorted();
89        let mut index = match self
90            .mappings
91            .binary_search_by(|m| m.generated_column.cmp(&generated_column))
92        {
93            Ok(index) => index,
94            Err(index) => index,
95        };
96
97        if generated_column_offset < 0 {
98            let u_start_column = start_column as u32;
99            let start_index = match self
100                .mappings
101                .binary_search_by(|m| m.generated_column.cmp(&u_start_column))
102            {
103                Ok(index) => index,
104                Err(index) => index,
105            };
106
107            self.mappings.drain(start_index..index);
108            index = start_index;
109        }
110
111        let abs_offset = generated_column_offset.unsigned_abs() as u32;
112        for i in index..self.mappings.len() {
113            let mapping = &mut self.mappings[i];
114            mapping.generated_column = if generated_column_offset < 0 {
115                mapping.generated_column - abs_offset
116            } else {
117                mapping.generated_column + abs_offset
118            };
119        }
120
121        Ok(())
122    }
123}