1#![deny(clippy::all)]
2
3pub mod mapping;
4pub mod mapping_line;
5pub mod sourcemap_error;
6pub mod utils;
7mod vlq_utils;
8
9use crate::utils::make_relative_path;
10pub use mapping::{Mapping, OriginalLocation};
11use mapping_line::MappingLine;
12pub use sourcemap_error::{SourceMapError, SourceMapErrorType};
13use std::io;
14
15use rkyv::{
16 archived_root,
17 de::deserializers::AllocDeserializer,
18 ser::{serializers::AlignedSerializer, Serializer},
19 AlignedVec, Archive, Deserialize, Serialize,
20};
21
22use vlq_utils::{is_mapping_separator, read_relative_vlq};
23
24#[derive(Archive, Serialize, Deserialize, Debug, Default, Clone)]
25pub struct SourceMapInner {
26 pub sources: Vec<String>,
27 pub sources_content: Vec<String>,
28 pub names: Vec<String>,
29 pub mapping_lines: Vec<MappingLine>,
30}
31
32#[derive(Debug, Clone)]
33pub struct SourceMap {
34 pub project_root: String,
35 inner: SourceMapInner,
36}
37
38impl SourceMap {
39 pub fn new(project_root: &str) -> Self {
40 Self {
41 project_root: String::from(project_root),
42 inner: SourceMapInner::default(),
43 }
44 }
45
46 fn ensure_lines(&mut self, generated_line: usize) {
47 let mut line = self.inner.mapping_lines.len();
48 if line <= generated_line {
49 self.inner
50 .mapping_lines
51 .reserve(generated_line - self.inner.mapping_lines.len() + 1);
52 while line <= generated_line {
53 self.inner.mapping_lines.push(MappingLine::new());
54 line += 1;
55 }
56 }
57 }
58
59 pub fn add_mapping(
60 &mut self,
61 generated_line: u32,
62 generated_column: u32,
63 original: Option<OriginalLocation>,
64 ) {
65 self.ensure_lines(generated_line as usize);
67 self.inner.mapping_lines[generated_line as usize].add_mapping(generated_column, original);
68 }
69
70 pub fn add_mapping_with_offset(
71 &mut self,
72 mapping: Mapping,
73 line_offset: i64,
74 column_offset: i64,
75 ) -> Result<(), SourceMapError> {
76 let (generated_line, generated_line_overflowed) =
77 (mapping.generated_line as i64).overflowing_add(line_offset);
78 if generated_line_overflowed || generated_line > (u32::MAX as i64) {
79 return Err(SourceMapError::new_with_reason(
80 SourceMapErrorType::UnexpectedlyBigNumber,
81 "mapping.generated_line + line_offset",
82 ));
83 }
84
85 if generated_line < 0 {
86 return Err(SourceMapError::new_with_reason(
87 SourceMapErrorType::UnexpectedNegativeNumber,
88 "mapping.generated_line + line_offset",
89 ));
90 }
91
92 let (generated_column, generated_column_overflowed) =
93 (mapping.generated_column as i64).overflowing_add(column_offset);
94 if generated_column_overflowed || generated_column > (u32::MAX as i64) {
95 return Err(SourceMapError::new_with_reason(
96 SourceMapErrorType::UnexpectedlyBigNumber,
97 "mapping.generated_column + column_offset",
98 ));
99 }
100
101 if generated_column < 0 {
102 return Err(SourceMapError::new_with_reason(
103 SourceMapErrorType::UnexpectedNegativeNumber,
104 "mapping.generated_column + column_offset",
105 ));
106 }
107
108 self.add_mapping(
109 generated_line as u32,
110 generated_column as u32,
111 mapping.original,
112 );
113 Ok(())
114 }
115
116 pub fn find_closest_mapping(
117 &mut self,
118 generated_line: u32,
119 generated_column: u32,
120 ) -> Option<Mapping> {
121 if let Some(line) = self.inner.mapping_lines.get_mut(generated_line as usize) {
122 if let Some(line_mapping) = line.find_closest_mapping(generated_column) {
123 return Some(Mapping {
124 generated_line,
125 generated_column: line_mapping.generated_column,
126 original: line_mapping.original,
127 });
128 }
129 }
130
131 None
132 }
133
134 pub fn get_mappings(&self) -> Vec<Mapping> {
135 let mut mappings = Vec::new();
136 for (generated_line, mapping_line) in self.inner.mapping_lines.iter().enumerate() {
137 for mapping in mapping_line.mappings.iter() {
138 mappings.push(Mapping {
139 generated_line: generated_line as u32,
140 generated_column: mapping.generated_column,
141 original: mapping.original,
142 });
143 }
144 }
145 mappings
146 }
147
148 pub fn write_vlq<W>(&mut self, output: &mut W) -> Result<(), SourceMapError>
149 where
150 W: io::Write,
151 {
152 let mut last_generated_line: u32 = 0;
153 let mut previous_source: i64 = 0;
154 let mut previous_original_line: i64 = 0;
155 let mut previous_original_column: i64 = 0;
156 let mut previous_name: i64 = 0;
157
158 for (generated_line, line_content) in self.inner.mapping_lines.iter_mut().enumerate() {
159 let mut previous_generated_column: u32 = 0;
160 let cloned_generated_line = generated_line as u32;
161 if cloned_generated_line > 0 {
162 output.write_all(
164 &b";".repeat((cloned_generated_line - last_generated_line) as usize),
165 )?;
166 }
167
168 line_content.ensure_sorted();
169
170 let mut is_first_mapping: bool = true;
171 for mapping in &line_content.mappings {
172 let generated_column = mapping.generated_column;
173 let original_location_option = &mapping.original;
174 if !is_first_mapping {
175 output.write_all(b",")?;
176 }
177
178 vlq::encode(
179 (generated_column - previous_generated_column) as i64,
180 output,
181 )?;
182 previous_generated_column = generated_column;
183
184 if let Some(original) = &original_location_option {
186 let original_source = original.source as i64;
187 vlq::encode(original_source - previous_source, output)?;
188 previous_source = original_source;
189
190 let original_line = original.original_line as i64;
191 vlq::encode((original_line - previous_original_line) as i64, output)?;
192 previous_original_line = original_line;
193
194 let original_column = original.original_column as i64;
195 vlq::encode(original_column - previous_original_column, output)?;
196 previous_original_column = original_column;
197
198 if let Some(name) = original.name {
199 let original_name = name as i64;
200 vlq::encode(original_name - previous_name, output)?;
201 previous_name = original_name;
202 }
203 }
204
205 is_first_mapping = false;
206 }
207
208 last_generated_line = cloned_generated_line;
209 }
210
211 Ok(())
212 }
213
214 pub fn add_source(&mut self, source: &str) -> u32 {
215 let relative_source = make_relative_path(self.project_root.as_str(), source);
216 match self
217 .inner
218 .sources
219 .iter()
220 .position(|s| relative_source.eq(s))
221 {
222 Some(i) => i as u32,
223 None => {
224 self.inner.sources.push(relative_source);
225 (self.inner.sources.len() - 1) as u32
226 }
227 }
228 }
229
230 pub fn add_sources(&mut self, sources: Vec<&str>) -> Vec<u32> {
231 self.inner.sources.reserve(sources.len());
232 let mut result_vec = Vec::with_capacity(sources.len());
233 for s in sources.iter() {
234 result_vec.push(self.add_source(s));
235 }
236 result_vec
237 }
238
239 pub fn get_source_index(&self, source: &str) -> Result<Option<u32>, SourceMapError> {
240 let normalized_source = make_relative_path(self.project_root.as_str(), source);
241 Ok(self
242 .inner
243 .sources
244 .iter()
245 .position(|s| normalized_source.eq(s))
246 .map(|v| v as u32))
247 }
248
249 pub fn get_source(&self, index: u32) -> Result<&str, SourceMapError> {
250 self.inner
251 .sources
252 .get(index as usize)
253 .map(|v| v.as_str())
254 .ok_or_else(|| SourceMapError::new(SourceMapErrorType::SourceOutOfRange))
255 }
256
257 pub fn get_sources(&self) -> &Vec<String> {
258 &self.inner.sources
259 }
260
261 pub fn add_name(&mut self, name: &str) -> u32 {
262 return match self.inner.names.iter().position(|s| name.eq(s)) {
263 Some(i) => i as u32,
264 None => {
265 self.inner.names.push(String::from(name));
266 (self.inner.names.len() - 1) as u32
267 }
268 };
269 }
270
271 pub fn add_names(&mut self, names: Vec<&str>) -> Vec<u32> {
272 self.inner.names.reserve(names.len());
273 return names.iter().map(|n| self.add_name(n)).collect();
274 }
275
276 pub fn get_name_index(&self, name: &str) -> Option<u32> {
277 self.inner
278 .names
279 .iter()
280 .position(|n| name.eq(n))
281 .map(|v| v as u32)
282 }
283
284 pub fn get_name(&self, index: u32) -> Result<&str, SourceMapError> {
285 self.inner
286 .names
287 .get(index as usize)
288 .map(|v| v.as_str())
289 .ok_or_else(|| SourceMapError::new(SourceMapErrorType::NameOutOfRange))
290 }
291
292 pub fn get_names(&self) -> &Vec<String> {
293 &self.inner.names
294 }
295
296 pub fn set_source_content(
297 &mut self,
298 source_index: usize,
299 source_content: &str,
300 ) -> Result<(), SourceMapError> {
301 if self.inner.sources.is_empty() || source_index > self.inner.sources.len() - 1 {
302 return Err(SourceMapError::new(SourceMapErrorType::SourceOutOfRange));
303 }
304
305 let sources_content_len = self.inner.sources_content.len();
306 if sources_content_len > source_index {
307 self.inner.sources_content[source_index] = String::from(source_content);
308 } else {
309 self.inner
310 .sources_content
311 .reserve((source_index + 1) - sources_content_len);
312 let items_to_add = source_index - sources_content_len;
313 for _n in 0..items_to_add {
314 self.inner.sources_content.push(String::from(""));
315 }
316 self.inner
317 .sources_content
318 .push(String::from(source_content));
319 }
320
321 Ok(())
322 }
323
324 pub fn get_source_content(&self, index: u32) -> Result<&str, SourceMapError> {
325 self.inner
326 .sources_content
327 .get(index as usize)
328 .map(|v| v.as_str())
329 .ok_or_else(|| SourceMapError::new(SourceMapErrorType::SourceOutOfRange))
330 }
331
332 pub fn get_sources_content(&self) -> &Vec<String> {
333 &self.inner.sources_content
334 }
335
336 pub fn to_buffer(&self, output: &mut AlignedVec) -> Result<(), SourceMapError> {
338 output.clear();
339 let mut serializer = AlignedSerializer::new(output);
340 serializer.serialize_value(&self.inner)?;
341 Ok(())
342 }
343
344 pub fn from_buffer(project_root: &str, buf: &[u8]) -> Result<SourceMap, SourceMapError> {
346 let archived = unsafe { archived_root::<SourceMapInner>(buf) };
347 let mut deserializer = AllocDeserializer;
349 let inner = archived.deserialize(&mut deserializer)?;
350 Ok(SourceMap {
351 project_root: String::from(project_root),
352 inner,
353 })
354 }
355
356 pub fn add_sourcemap(
357 &mut self,
358 sourcemap: &mut SourceMap,
359 line_offset: i64,
360 ) -> Result<(), SourceMapError> {
361 self.inner.sources.reserve(sourcemap.inner.sources.len());
362 let mut source_indexes = Vec::with_capacity(sourcemap.inner.sources.len());
363 let sources = std::mem::take(&mut sourcemap.inner.sources);
364 for s in sources.iter() {
365 source_indexes.push(self.add_source(s));
366 }
367
368 self.inner.names.reserve(sourcemap.inner.names.len());
369 let mut names_indexes = Vec::with_capacity(sourcemap.inner.names.len());
370 let names = std::mem::take(&mut sourcemap.inner.names);
371 for n in names.iter() {
372 names_indexes.push(self.add_name(n));
373 }
374
375 self.inner
376 .sources_content
377 .reserve(sourcemap.inner.sources_content.len());
378 let sources_content = std::mem::take(&mut sourcemap.inner.sources_content);
379 for (i, source_content_str) in sources_content.iter().enumerate() {
380 if let Some(source_index) = source_indexes.get(i) {
381 self.set_source_content(*source_index as usize, source_content_str)?;
382 }
383 }
384
385 let mapping_lines = std::mem::take(&mut sourcemap.inner.mapping_lines);
386 for (line, mapping_line) in mapping_lines.into_iter().enumerate() {
387 let generated_line = (line as i64) + line_offset;
388 if generated_line >= 0 {
389 let mut line = mapping_line;
390 for mapping in line.mappings.iter_mut() {
391 match &mut mapping.original {
392 Some(original_mapping_location) => {
393 original_mapping_location.source = match source_indexes
394 .get(original_mapping_location.source as usize)
395 {
396 Some(new_source_index) => *new_source_index,
397 None => {
398 return Err(SourceMapError::new(
399 SourceMapErrorType::SourceOutOfRange,
400 ));
401 }
402 };
403
404 original_mapping_location.name = match original_mapping_location.name {
405 Some(name_index) => match names_indexes.get(name_index as usize) {
406 Some(new_name_index) => Some(*new_name_index),
407 None => {
408 return Err(SourceMapError::new(
409 SourceMapErrorType::NameOutOfRange,
410 ));
411 }
412 },
413 None => None,
414 };
415 }
416 None => {}
417 }
418 }
419
420 self.ensure_lines(generated_line as usize);
421 self.inner.mapping_lines[generated_line as usize] = line;
422 }
423 }
424
425 Ok(())
426 }
427
428 pub fn extends(&mut self, original_sourcemap: &mut SourceMap) -> Result<(), SourceMapError> {
429 self.inner
430 .sources
431 .reserve(original_sourcemap.inner.sources.len());
432 let mut source_indexes = Vec::with_capacity(original_sourcemap.inner.sources.len());
433 for s in original_sourcemap.inner.sources.iter() {
434 source_indexes.push(self.add_source(s));
435 }
436
437 self.inner
438 .names
439 .reserve(original_sourcemap.inner.names.len());
440 let mut names_indexes = Vec::with_capacity(original_sourcemap.inner.names.len());
441 for n in original_sourcemap.inner.names.iter() {
442 names_indexes.push(self.add_name(n));
443 }
444
445 self.inner
446 .sources_content
447 .reserve(original_sourcemap.inner.sources_content.len());
448 for (i, source_content_str) in original_sourcemap.inner.sources_content.iter().enumerate() {
449 if let Some(source_index) = source_indexes.get(i) {
450 self.set_source_content(*source_index as usize, source_content_str)?;
451 }
452 }
453
454 for (_generated_line, line_content) in self.inner.mapping_lines.iter_mut().enumerate() {
455 for mapping in line_content.mappings.iter_mut() {
456 let original_location_option = &mut mapping.original;
457 if let Some(original_location) = original_location_option {
458 let found_mapping = original_sourcemap.find_closest_mapping(
459 original_location.original_line,
460 original_location.original_column,
461 );
462 match found_mapping {
463 Some(original_mapping) => match original_mapping.original {
464 Some(original_mapping_location) => {
465 *original_location_option = Some(OriginalLocation::new(
466 original_mapping_location.original_line,
467 original_mapping_location.original_column,
468 match source_indexes
469 .get(original_mapping_location.source as usize)
470 {
471 Some(new_source_index) => *new_source_index,
472 None => {
473 return Err(SourceMapError::new(
474 SourceMapErrorType::SourceOutOfRange,
475 ));
476 }
477 },
478 match original_mapping_location.name {
479 Some(name_index) => {
480 match names_indexes.get(name_index as usize) {
481 Some(new_name_index) => Some(*new_name_index),
482 None => {
483 return Err(SourceMapError::new(
484 SourceMapErrorType::NameOutOfRange,
485 ));
486 }
487 }
488 }
489 None => None,
490 },
491 ));
492 }
493 None => {
494 *original_location_option = None;
495 }
496 },
497 None => {
498 *original_location_option = None;
499 }
500 }
501 }
502 }
503 }
504
505 Ok(())
506 }
507
508 pub fn add_vlq_map(
509 &mut self,
510 input: &[u8],
511 sources: Vec<&str>,
512 sources_content: Vec<&str>,
513 names: Vec<&str>,
514 line_offset: i64,
515 column_offset: i64,
516 ) -> Result<(), SourceMapError> {
517 let mut generated_line: i64 = line_offset;
518 let mut generated_column: i64 = column_offset;
519 let mut original_line = 0;
520 let mut original_column = 0;
521 let mut source = 0;
522 let mut name = 0;
523
524 let source_indexes: Vec<u32> = self.add_sources(sources);
525 let name_indexes: Vec<u32> = self.add_names(names);
526
527 self.inner.sources_content.reserve(sources_content.len());
528 for (i, source_content) in sources_content.iter().enumerate() {
529 if let Some(source_index) = source_indexes.get(i) {
530 self.set_source_content(*source_index as usize, source_content)?;
531 }
532 }
533
534 let mut input = input.iter().cloned().peekable();
535 while let Some(byte) = input.peek().cloned() {
536 match byte {
537 b';' => {
538 generated_line += 1;
539 generated_column = column_offset;
540 input.next().unwrap();
541 }
542 b',' => {
543 input.next().unwrap();
544 }
545 _ => {
546 read_relative_vlq(&mut generated_column, &mut input)?;
548
549 let original = if input.peek().cloned().map_or(true, is_mapping_separator) {
552 None
553 } else {
554 read_relative_vlq(&mut source, &mut input)?;
555 read_relative_vlq(&mut original_line, &mut input)?;
556 read_relative_vlq(&mut original_column, &mut input)?;
557 Some(OriginalLocation::new(
558 original_line as u32,
559 original_column as u32,
560 match source_indexes.get(source as usize) {
561 Some(v) => *v,
562 None => {
563 return Err(SourceMapError::new(
564 SourceMapErrorType::SourceOutOfRange,
565 ));
566 }
567 },
568 if input.peek().cloned().map_or(true, is_mapping_separator) {
569 None
570 } else {
571 read_relative_vlq(&mut name, &mut input)?;
572 Some(match name_indexes.get(name as usize) {
573 Some(v) => *v,
574 None => {
575 return Err(SourceMapError::new(
576 SourceMapErrorType::NameOutOfRange,
577 ));
578 }
579 })
580 },
581 ))
582 };
583
584 if generated_line >= 0 {
585 self.add_mapping(generated_line as u32, generated_column as u32, original);
586 }
587 }
588 }
589 }
590
591 Ok(())
592 }
593
594 pub fn offset_columns(
595 &mut self,
596 generated_line: u32,
597 generated_column: u32,
598 generated_column_offset: i64,
599 ) -> Result<(), SourceMapError> {
600 match self.inner.mapping_lines.get_mut(generated_line as usize) {
601 Some(line) => line.offset_columns(generated_column, generated_column_offset),
602 None => Ok(()),
603 }
604 }
605
606 pub fn offset_lines(
607 &mut self,
608 generated_line: u32,
609 generated_line_offset: i64,
610 ) -> Result<(), SourceMapError> {
611 if generated_line_offset == 0 || self.inner.mapping_lines.is_empty() {
612 return Ok(());
613 }
614
615 let (start_line, overflowed) =
616 (generated_line as i64).overflowing_add(generated_line_offset);
617 if overflowed || start_line > (u32::MAX as i64) {
618 return Err(SourceMapError::new_with_reason(
619 SourceMapErrorType::UnexpectedNegativeNumber,
620 "column + column_offset cannot be negative",
621 ));
622 }
623
624 let line = generated_line as usize;
625 let abs_offset = generated_line_offset.abs() as usize;
626 if generated_line_offset > 0 {
627 if line > self.inner.mapping_lines.len() {
628 self.ensure_lines(line + abs_offset);
629 } else {
630 self.inner
631 .mapping_lines
632 .splice(line..line, (0..abs_offset).map(|_| MappingLine::new()));
633 }
634 } else {
635 self.inner.mapping_lines.drain(line - abs_offset..line);
636 }
637
638 Ok(())
639 }
640
641 pub fn add_empty_map(
642 &mut self,
643 source: &str,
644 source_content: &str,
645 line_offset: i64,
646 ) -> Result<(), SourceMapError> {
647 let source_index = self.add_source(source);
648 self.set_source_content(source_index as usize, source_content)?;
649
650 for (line_count, _line) in source_content.lines().enumerate() {
651 let generated_line = (line_count as i64) + line_offset;
652 if generated_line >= 0 {
653 self.add_mapping(
654 generated_line as u32,
655 0,
656 Some(OriginalLocation::new(
657 line_count as u32,
658 0,
659 source_index,
660 None,
661 )),
662 )
663 }
664 }
665
666 Ok(())
667 }
668}
669
670#[allow(non_fmt_panics)]
671#[test]
672fn test_buffers() {
673 let map = SourceMap::new("/");
674 let mut output = AlignedVec::new();
675 match map.to_buffer(&mut output) {
676 Ok(_) => {}
677 Err(err) => panic!("{:?}", err),
678 }
679 match SourceMap::from_buffer("/", &output) {
680 Ok(map) => {
681 println!("{:?}", map)
682 }
683 Err(err) => panic!("{:?}", err),
684 }
685}