oak_source_map/
composer.rs1use crate::{Mapping, Result, SourceMap, SourceMapBuilder, SourceMapError};
7
8#[derive(Debug, Default)]
14pub struct SourceMapComposer {
15 maps: Vec<SourceMap>,
16}
17
18impl SourceMapComposer {
19 pub fn new() -> Self {
21 Self::default()
22 }
23
24 pub fn add(mut self, map: SourceMap) -> Self {
32 self.maps.push(map);
33 self
34 }
35
36 pub fn compose(self) -> Result<SourceMap> {
38 if self.maps.is_empty() {
39 return Ok(SourceMap::new());
40 }
41
42 if self.maps.len() == 1 {
43 return Ok(self.maps.into_iter().next().unwrap());
44 }
45
46 let mut maps = self.maps.into_iter();
47 let first = maps.next().unwrap();
48
49 let result = maps.try_fold(first, |acc, map| compose_two(&acc, &map))?;
50
51 Ok(result)
52 }
53}
54
55pub fn compose_two(map1: &SourceMap, map2: &SourceMap) -> Result<SourceMap> {
61 let mut builder = SourceMapBuilder::new();
62
63 let mappings1 = map1.parse_mappings()?;
64
65 for mapping in mappings1 {
66 if let (Some(source_idx), Some(orig_line), Some(orig_col)) = (mapping.source_index, mapping.original_line, mapping.original_column) {
67 let intermediate_source = map1.get_source(source_idx as usize).ok_or_else(|| SourceMapError::InvalidSourceIndex(source_idx as usize))?;
68
69 let intermediate_idx = map2.sources.iter().position(|s| s == intermediate_source);
70
71 if let Some(idx) = intermediate_idx {
72 let decoder = crate::SourceMapDecoder::new(map2.clone())?;
73
74 if let Some(intermediate_mapping) = decoder.lookup(orig_line, orig_col) {
75 if let (Some(final_source_idx), Some(final_line), Some(final_col)) = (intermediate_mapping.source_index, intermediate_mapping.original_line, intermediate_mapping.original_column) {
76 let new_source_idx = builder.add_source(map2.get_source(final_source_idx as usize).unwrap_or(""));
77
78 builder.add_mapping(mapping.generated_line, mapping.generated_column, Some(new_source_idx), Some(final_line), Some(final_col), intermediate_mapping.name_index.or(mapping.name_index));
79 continue;
80 }
81 }
82 }
83 }
84
85 builder.add_mapping(mapping.generated_line, mapping.generated_column, None, None, None, None);
86 }
87
88 Ok(builder.build())
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn test_compose_empty() {
97 let composer = SourceMapComposer::new();
98 let result = composer.compose().unwrap();
99 assert_eq!(result.version, 3);
100 }
101
102 #[test]
103 fn test_compose_single() {
104 let mut sm = SourceMap::new();
105 sm.add_source("test.ts");
106
107 let composer = SourceMapComposer::new().add(sm.clone());
108 let result = composer.compose().unwrap();
109
110 assert_eq!(result.sources, sm.sources);
111 }
112}