prettify_js/
source_map_generator.rs1use serde::Serialize;
2
3#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
5pub struct SourceMapLine(pub u32);
6
7#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
9pub struct SourceMapColumn(pub u32);
10
11#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
13pub struct SourceCoord {
14 pub line: SourceMapLine,
15 pub column: SourceMapColumn,
16}
17
18pub struct SourceMapping {
20 pub from: SourceCoord,
22 pub to: SourceCoord,
24}
25
26#[derive(Serialize)]
27#[serde(rename_all = "camelCase")]
28struct SourceMapJson {
29 version: i32,
30 sources: Vec<String>,
31 sources_content: Vec<String>,
32 names: Vec<String>,
33 mappings: String,
34}
35
36fn encode_digit(value: u8) -> char {
37 let b = match value {
38 0..=25 => b'A' + value,
39 26..=51 => b'a' + (value - 26),
40 52..=61 => b'0' + (value - 52),
41 62 => b'+',
42 63 => b'/',
43 _ => panic!("Invalid digit"),
44 };
45 b as char
46}
47
48fn write_vlq(value: i64, output: &mut String) {
49 let mut val = if value >= 0 {
50 (value as u64) << 1
51 } else if value == i64::MIN {
52 output.push('g');
53 1 << (63 - 4)
54 } else {
55 ((-value as u64) << 1) + 1
56 };
57 loop {
58 let mut digit = val as u8 & ((1 << 5) - 1);
59 val >>= 5;
60 if val > 0 {
61 digit |= 1 << 5;
62 }
63 output.push(encode_digit(digit));
64 if val == 0 {
65 break;
66 }
67 }
68}
69
70pub fn generate_source_map(
80 from_name: String,
81 from_content: String,
82 mappings: Vec<SourceMapping>,
83) -> String {
84 let mut map = SourceMapJson {
85 version: 3,
86 sources: vec![from_name],
87 sources_content: vec![from_content],
88 names: Vec::new(),
89 mappings: String::new(),
90 };
91 let mut last_to_line = SourceMapLine(0);
92 let mut last_to_column = SourceMapColumn(0);
93 let mut last_from_line = SourceMapLine(0);
94 let mut last_from_column = SourceMapColumn(0);
95 for m in mappings {
96 if last_to_line < m.to.line {
97 while last_to_line < m.to.line {
98 map.mappings.push(';');
99 last_to_column = SourceMapColumn(0);
100 last_to_line.0 += 1;
101 }
102 } else {
103 if !map.mappings.is_empty() {
104 map.mappings.push(',');
105 }
106 }
107 write_vlq(
108 m.to.column.0 as i64 - last_to_column.0 as i64,
109 &mut map.mappings,
110 );
111 last_to_column = m.to.column;
112 write_vlq(0, &mut map.mappings);
114 write_vlq(
115 m.from.line.0 as i64 - last_from_line.0 as i64,
116 &mut map.mappings,
117 );
118 last_from_line = m.from.line;
119 write_vlq(
120 m.from.column.0 as i64 - last_from_column.0 as i64,
121 &mut map.mappings,
122 );
123 last_from_column = m.from.column;
124 }
125 serde_json::to_string(&map).unwrap()
126}