oxc_sourcemap/
sourcemap_builder.rs1use std::sync::Arc;
2
3use rustc_hash::FxHashMap;
4
5use crate::{
6 SourceMap,
7 token::{Token, TokenChunk},
8};
9
10#[derive(Debug, Default)]
12pub struct SourceMapBuilder {
13 pub(crate) file: Option<Arc<str>>,
14 pub(crate) names_map: FxHashMap<Arc<str>, u32>,
15 pub(crate) names: Vec<Arc<str>>,
16 pub(crate) sources: Vec<Arc<str>>,
17 pub(crate) sources_map: FxHashMap<Arc<str>, u32>,
18 pub(crate) source_contents: Vec<Option<Arc<str>>>,
19 pub(crate) tokens: Vec<Token>,
20 pub(crate) token_chunks: Option<Vec<TokenChunk>>,
21}
22
23impl SourceMapBuilder {
24 pub fn add_name(&mut self, name: &str) -> u32 {
26 if let Some(&id) = self.names_map.get(name) {
27 return id;
28 }
29 let count = self.names.len() as u32;
30 let name = Arc::from(name);
31 self.names_map.insert(Arc::clone(&name), count);
32 self.names.push(name);
33 count
34 }
35
36 pub fn add_source_and_content(&mut self, source: &str, source_content: &str) -> u32 {
39 let count = self.sources.len() as u32;
40 let id = *self.sources_map.entry(source.into()).or_insert(count);
41 if id == count {
42 self.sources.push(source.into());
43 self.source_contents.push(Some(source_content.into()));
44 }
45 id
46 }
47
48 pub fn set_source_and_content(&mut self, source: &str, source_content: &str) -> u32 {
51 let count = self.sources.len() as u32;
52 self.sources.push(source.into());
53 self.source_contents.push(Some(source_content.into()));
54 count
55 }
56
57 pub fn add_token(
59 &mut self,
60 dst_line: u32,
61 dst_col: u32,
62 src_line: u32,
63 src_col: u32,
64 src_id: Option<u32>,
65 name_id: Option<u32>,
66 ) {
67 self.tokens.push(Token::new(dst_line, dst_col, src_line, src_col, src_id, name_id));
68 }
69
70 pub fn set_file(&mut self, file: &str) {
71 self.file = Some(file.into());
72 }
73
74 pub fn set_token_chunks(&mut self, token_chunks: Vec<TokenChunk>) {
76 self.token_chunks = Some(token_chunks);
77 }
78
79 pub fn into_sourcemap(mut self) -> SourceMap {
80 self.names_map.shrink_to_fit();
84 self.names.shrink_to_fit();
85 self.sources.shrink_to_fit();
86 self.sources_map.shrink_to_fit();
87 self.tokens.shrink_to_fit();
89 if let Some(c) = self.token_chunks.as_mut() {
90 c.shrink_to_fit()
91 }
92 SourceMap::new(
93 self.file,
94 self.names,
95 None,
96 self.sources,
97 self.source_contents,
98 self.tokens.into_boxed_slice(),
99 self.token_chunks,
100 )
101 }
102}
103
104#[test]
105fn test_sourcemap_builder() {
106 let mut builder = SourceMapBuilder::default();
107 builder.set_source_and_content("baz.js", "");
108 builder.add_name("x");
109 builder.set_file("file");
110
111 let sm = builder.into_sourcemap();
112 assert_eq!(sm.get_source(0).map(|s| s.as_ref()), Some("baz.js"));
113 assert_eq!(sm.get_name(0).map(|s| s.as_ref()), Some("x"));
114 assert_eq!(sm.get_file().map(|s| s.as_ref()), Some("file"));
115
116 let expected = r#"{"version":3,"file":"file","names":["x"],"sources":["baz.js"],"sourcesContent":[""],"mappings":""}"#;
117 assert_eq!(expected, sm.to_json_string());
118}