veryl_sourcemap/
sourcemap.rs1use crate::SourceMapError;
2use relative_path::PathExt;
3use sourcemap::SourceMapBuilder;
4use std::fs;
5use std::path::{Path, PathBuf};
6
7const LINK_HEADER: &str = "//# sourceMappingURL=";
8
9pub struct SourceMap {
10 pub src_path: PathBuf,
11 pub dst_path: PathBuf,
12 pub map_path: PathBuf,
13 pub src_path_from_map: String,
14 pub map_path_from_dst: String,
15 builder: SourceMapBuilder,
16 source_map: Option<sourcemap::SourceMap>,
17}
18
19impl SourceMap {
20 pub fn new(src_path: &Path, dst_path: &Path, map_path: &Path) -> Self {
21 let src_path = src_path.to_path_buf();
22 let dst_path = dst_path.to_path_buf();
23 let map_path = map_path.to_path_buf();
24 let src_path_from_map = if let Ok(x) = src_path.relative_to(map_path.parent().unwrap()) {
25 x.as_str().to_owned()
26 } else {
27 src_path.to_string_lossy().to_string()
28 };
29 let map_path_from_dst = if let Ok(x) = map_path.relative_to(dst_path.parent().unwrap()) {
30 x.as_str().to_owned()
31 } else {
32 map_path.to_string_lossy().to_string()
33 };
34 let builder = SourceMapBuilder::new(Some(&map_path.file_name().unwrap().to_string_lossy()));
35 Self {
36 src_path,
37 dst_path,
38 map_path,
39 src_path_from_map,
40 map_path_from_dst,
41 builder,
42 source_map: None,
43 }
44 }
45
46 pub fn from_src(src_path: &Path) -> Result<Self, SourceMapError> {
47 let src = fs::read_to_string(src_path).map_err(|x| SourceMapError::io(x, src_path))?;
48
49 if let Some(line) = src.lines().last()
50 && line.starts_with(LINK_HEADER)
51 {
52 let map_path = line.strip_prefix(LINK_HEADER).unwrap();
53 let map_path = src_path.parent().unwrap().join(map_path);
54 let text = fs::read(&map_path).map_err(|x| SourceMapError::io(x, &map_path))?;
55
56 let src_path = src_path.to_path_buf();
57 let dst_path = PathBuf::new();
58 let src_path_from_map = String::new();
59 let map_path_from_dst = String::new();
60 let builder =
61 SourceMapBuilder::new(Some(&map_path.file_name().unwrap().to_string_lossy()));
62 let source_map = Some(sourcemap::SourceMap::from_reader(text.as_slice())?);
63
64 return Ok(Self {
65 src_path,
66 dst_path,
67 map_path,
68 src_path_from_map,
69 map_path_from_dst,
70 builder,
71 source_map,
72 });
73 }
74
75 Err(SourceMapError::NotFound)
76 }
77
78 pub fn add(
79 &mut self,
80 dst_line: u32,
81 dst_column: u32,
82 src_line: u32,
83 src_column: u32,
84 name: &str,
85 ) {
86 let dst_line = dst_line - 1;
88 let dst_column = dst_column - 1;
89 let src_line = src_line - 1;
90 let src_column = src_column - 1;
91
92 self.builder.add(
93 dst_line,
94 dst_column,
95 src_line,
96 src_column,
97 Some(&self.src_path_from_map),
98 Some(name),
99 false,
100 );
101 }
102
103 pub fn set_source_content(&mut self, content: &str) {
104 let id = self.builder.add_source(&self.src_path_from_map);
105 self.builder.set_source_contents(id, Some(content));
106 }
107
108 pub fn build(&mut self) {
109 let mut builder =
110 SourceMapBuilder::new(Some(&self.map_path.file_name().unwrap().to_string_lossy()));
111 std::mem::swap(&mut builder, &mut self.builder);
112 self.source_map = Some(builder.into_sourcemap());
113 }
114
115 pub fn get_link(&self) -> String {
116 format!("{}{}", LINK_HEADER, self.map_path_from_dst)
117 }
118
119 pub fn to_bytes(&self) -> Result<Vec<u8>, SourceMapError> {
120 if let Some(ref x) = self.source_map {
121 let mut ret = Vec::new();
122 x.to_writer(&mut ret)?;
123 Ok(ret)
124 } else {
125 Err(SourceMapError::NotFound)
126 }
127 }
128
129 pub fn lookup(&self, line: u32, column: u32) -> Option<(PathBuf, u32, u32)> {
130 if let Some(ref x) = self.source_map {
131 if let Some(token) = x.lookup_token(line - 1, column - 1) {
132 if let Some(path) = token.get_source() {
133 let path = self.map_path.parent().unwrap().join(path);
134 if let Ok(path) = fs::canonicalize(path) {
135 let line = token.get_src_line() + 1;
136 let column = token.get_src_col() + 1;
137 Some((path, line, column))
138 } else {
139 None
140 }
141 } else {
142 None
143 }
144 } else {
145 None
146 }
147 } else {
148 None
149 }
150 }
151}