1use crate::array_set::ArraySet;
2use crate::generator::SourceMapGenerator;
3use crate::mapping::Mapping;
4use crate::source_map::{Position, SourceMapJson};
5use crate::{binary_search, util};
6use rayon::prelude::*;
7use source_map_mappings::Bias;
8use std::cell::RefCell;
9use std::collections::HashMap;
10use std::panic;
11use std::rc::Rc;
12use std::sync::{Arc, Mutex};
13
14pub fn create_consumer(
18 source_map_raw: &str,
19 source_map_url: Option<&str>,
20) -> Result<Consumer, serde_json::Error> {
21 let source_map = serde_json::from_str::<SourceMapJson>(source_map_raw)?;
22 if source_map.sections.is_some() {
23 Ok(Consumer::IndexedConsumer(
24 IndexedConsumer::from_source_map_json(source_map, source_map_url),
25 ))
26 } else {
27 Ok(Consumer::BasicConsumer(
28 BasicConsumer::from_source_map_json(source_map, source_map_url),
29 ))
30 }
31}
32
33pub enum Consumer {
34 BasicConsumer(BasicConsumer),
35 IndexedConsumer(IndexedConsumer),
36}
37
38impl Consumer {
39 pub fn as_basic_consumer(&self) -> &BasicConsumer {
40 if let Self::BasicConsumer(ref consumer) = self {
41 consumer
42 } else {
43 panic!("The consumer is not a basic consumer");
44 }
45 }
46
47 pub fn as_indexed_consumer(&self) -> &IndexedConsumer {
48 if let Self::IndexedConsumer(ref consumer) = self {
49 consumer
50 } else {
51 panic!("The consumer is not a basic consumer");
52 }
53 }
54
55 pub fn as_basic_consumer_mut(&mut self) -> &mut BasicConsumer {
56 if let Self::BasicConsumer(ref mut consumer) = self {
57 consumer
58 } else {
59 panic!("The consumer is not a basic consumer");
60 }
61 }
62
63 pub fn as_indexed_consumer_mut(&mut self) -> &mut IndexedConsumer {
64 if let Self::IndexedConsumer(ref mut consumer) = self {
65 consumer
66 } else {
67 panic!("The consumer is not a basic consumer");
68 }
69 }
70
71 pub fn try_as_basic_consumer(&self) -> Option<&BasicConsumer> {
72 if let Self::BasicConsumer(ref consumer) = self {
73 Some(consumer)
74 } else {
75 None
76 }
77 }
78
79 pub fn try_as_indexed_consumer(&self) -> Option<&IndexedConsumer> {
80 if let Self::IndexedConsumer(ref consumer) = self {
81 Some(consumer)
82 } else {
83 None
84 }
85 }
86
87 pub fn try_as_basic_consumer_mut(&mut self) -> Option<&mut BasicConsumer> {
88 if let Self::BasicConsumer(ref mut consumer) = self {
89 Some(consumer)
90 } else {
91 None
92 }
93 }
94
95 pub fn try_as_indexed_consumer_mut(&mut self) -> Option<&mut IndexedConsumer> {
96 if let Self::IndexedConsumer(ref mut consumer) = self {
97 Some(consumer)
98 } else {
99 None
100 }
101 }
102}
103
104#[derive(Clone)]
105pub enum IterOrd {
106 GeneratedOrd,
107 OriginalOrd,
108}
109
110pub trait ConsumerTrait: Sized {
111 fn consume(source_map_raw: String, source_map_url: String, f: impl FnOnce(Self));
112 fn each_mapping(&mut self, f: impl Fn(&source_map_mappings::Mapping), ord: IterOrd);
113}
114
115pub struct BasicConsumer {
116 pub source_map: SourceMapJson,
117 pub(crate) source_lookup_cache: HashMap<String, i32>,
118 pub(crate) absolute_sources: ArraySet,
119 pub(crate) source_map_url: Option<String>,
120 pub(crate) mappings: Option<source_map_mappings::Mappings>,
121 pub(crate) computed_column_spans: bool,
122}
123impl BasicConsumer {
124 pub fn new(source_map_raw: &str, source_map_url: Option<&str>) -> Self {
125 let source_map = serde_json::from_str::<SourceMapJson>(source_map_raw).unwrap();
126 BasicConsumer {
127 source_map: source_map.clone(),
128 source_lookup_cache: Default::default(),
129 source_map_url: source_map_url.map(|it| it.to_string()),
130 absolute_sources: ArraySet::from_array(
131 source_map
132 .sources
133 .as_ref()
134 .unwrap()
135 .iter()
136 .map(|it| {
137 util::compute_source_url(
138 source_map.source_root.as_deref(),
139 it,
140 source_map_url,
141 )
142 })
143 .collect(),
144 true,
145 ),
146 mappings: None,
147 computed_column_spans: false,
148 }
149 }
150
151 pub fn from_source_map_json(source_map: SourceMapJson, source_map_url: Option<&str>) -> Self {
152 BasicConsumer {
153 source_map: source_map.clone(),
154 source_lookup_cache: Default::default(),
155 source_map_url: None,
156 absolute_sources: ArraySet::from_array(
157 source_map
158 .sources
159 .as_ref()
160 .unwrap()
161 .iter()
162 .map(|it| {
163 util::compute_source_url(
164 source_map.source_root.as_deref(),
165 it,
166 source_map_url,
167 )
168 })
169 .collect(),
170 true,
171 ),
172 mappings: None,
173 computed_column_spans: false,
174 }
175 }
176
177 pub fn from_source_map(
178 source_map: &mut SourceMapGenerator,
179 source_map_url: Option<&str>,
180 ) -> Self {
181 BasicConsumer::new(source_map.as_string().as_str(), source_map_url)
182 }
183
184 fn find_source_index(&mut self, source: &str) -> Option<i32> {
185 let cached_index = self.source_lookup_cache.get(source);
186 if let Some(&index) = cached_index {
187 return Some(index);
188 }
189
190 let source_as_map_relative =
192 util::compute_source_url(None, source, self.source_map_url.as_deref());
193 if self.absolute_sources.has(source_as_map_relative.clone()) {
194 let index = self
195 .absolute_sources
196 .index_of(source_as_map_relative)
197 .unwrap();
198
199 self.source_lookup_cache
200 .insert(source.to_string(), index as i32);
201 return Some(index as i32);
202 }
203
204 let source_as_source_root_relative = util::compute_source_url(
206 self.source_map.source_root.as_deref(),
207 source,
208 self.source_map_url.as_deref(),
209 );
210 if self
211 .absolute_sources
212 .has(source_as_source_root_relative.clone())
213 {
214 let index = self
215 .absolute_sources
216 .index_of(source_as_source_root_relative)
217 .unwrap();
218 self.source_lookup_cache
219 .insert(source.to_string(), index as i32);
220 return Some(index as i32);
221 }
222
223 None
224 }
225
226 pub fn get_sources(&self) -> Vec<String> {
227 self.absolute_sources.to_vec()
228 }
229
230 fn parse_mappings(&self) -> Result<source_map_mappings::Mappings, source_map_mappings::Error> {
231 source_map_mappings::parse_mappings::<()>(
232 self.source_map.mappings.as_ref().unwrap().as_bytes(),
233 )
234 }
235
236 pub fn all_generated_position_for(
237 &mut self,
238 source: &str,
239 original_line: i32,
240 original_column: Option<i32>,
241 ) -> Vec<source_map_mappings::Mapping> {
242 let original_column = if let Some(r) = original_column { r } else { 0 };
243 let source = self.find_source_index(source);
244 if source.is_none() {
245 return vec![];
246 }
247
248 let source = source.unwrap();
249
250 if source < 0 {
251 return vec![];
252 }
253
254 if original_line < 1 {
255 panic!("Line numbers must be >= 1");
256 }
257
258 if original_column < 0 {
259 panic!("Column numbers must be >= 0");
260 }
261
262 if self.mappings.is_none() {
263 self.mappings = self.parse_mappings().ok();
264 }
265
266 let mappings = self.mappings.as_mut().unwrap();
267
268 mappings
269 .all_generated_locations_for(
270 source as u32,
271 original_line as u32,
272 Some(original_column as u32),
273 )
274 .cloned()
275 .collect()
276 }
277
278 pub fn compute_column_spans(&mut self) {
279 if self.computed_column_spans {
280 return;
281 }
282
283 if self.mappings.is_none() {
284 self.mappings = self.parse_mappings().ok();
285 }
286
287 let mappings = self.mappings.as_mut().unwrap();
288 mappings.compute_column_spans();
289 self.computed_column_spans = true;
290 }
291
292 pub fn original_position_for(
293 &mut self,
294 generated: Position,
295 bias: Option<source_map_mappings::Bias>,
296 ) -> Option<Mapping> {
297 let generated_line = generated.line;
298 let generated_column = generated.column;
299 if generated_line < 1 {
300 panic!("Line numbers must be >= 1");
301 }
302
303 if generated_column < 0 {
304 panic!("Column numbers must be >= 0");
305 }
306
307 let bias = bias.unwrap_or(source_map_mappings::Bias::GreatestLowerBound);
308
309 if self.mappings.is_none() {
310 self.mappings = self.parse_mappings().ok();
311 }
312
313 let mappings = self.mappings.as_mut().unwrap();
314
315 let mapping = mappings
316 .original_location_for((generated_line - 1) as u32, generated_column as u32, bias)
317 .cloned();
318
319 match mapping {
320 Some(mapping) => {
321 if mapping.generated_line as i32 == generated_line {
322 mapping.original.clone().map(|original| Mapping {
323 name: original
324 .name
325 .map(|it| self.source_map.names.as_ref().unwrap()[it as usize].clone()),
326 source: self.absolute_sources.at(original.source as i32),
327 original: Some(Position {
328 line: (original.original_line + 1) as i32,
329 column: original.original_column as i32,
330 }),
331 generated: Position {
332 line: (mapping.generated_line + 1) as i32,
333 column: mapping.generated_column as i32,
334 },
335 last_generated_column: mapping.last_generated_column.map(|it| it as i32),
336 })
337 } else {
338 None
339 }
340 }
341 None => None,
342 }
343 }
344
345 pub fn has_contents_of_all_sources(&self) -> bool {
346 match self.source_map.sources_content {
347 Some(ref s) => s.len() >= self.source_map.sources.as_ref().unwrap().len(),
348 None => false,
349 }
350 }
351
352 pub fn source_content_for(
353 &mut self,
354 source: &str,
355 panic_on_missing: Option<bool>,
356 ) -> Option<String> {
357 self.source_map.sources_content.as_ref()?;
358
359 let sources_content = self.source_map.sources_content.clone().unwrap();
360 let panic_on_missing = panic_on_missing.unwrap_or(true);
361
362 let index = self.find_source_index(source);
363 return match index {
364 Some(i) => Some(sources_content[i as usize].clone()),
365 None => {
366 if panic_on_missing {
367 panic!(r#""{}" is not in the SourceMap."#, source);
368 } else {
369 None
370 }
371 }
372 };
373 }
374
375 pub fn generated_position_for(
376 &mut self,
377 source: &str,
378 original_line: i32,
379 original_column: i32,
380 bias: Option<source_map_mappings::Bias>,
381 ) -> Option<Mapping> {
382 let source = match self.find_source_index(source) {
383 Some(s) => s,
384 None => return None,
385 };
386
387 if original_line < 1 {
388 panic!("Line numbers must be >= 1")
389 }
390
391 if original_column < 0 {
392 panic!("Column numbers must be >= 0")
393 }
394
395 let bias = bias.unwrap_or(source_map_mappings::Bias::GreatestLowerBound);
396
397 if self.mappings.is_none() {
398 self.mappings = self.parse_mappings().ok();
399 }
400
401 let mappings = self.mappings.as_mut().unwrap();
402
403 let mapping = mappings
404 .generated_location_for(
405 source as u32,
406 (original_line - 1) as u32,
407 original_column as u32,
408 bias,
409 )
410 .cloned();
411
412 match mapping {
413 Some(mapping) => {
414 if mapping.original.as_ref().unwrap().source as i32 == source {
415 let last_column = mapping.last_generated_column;
416 let last_column = if self.computed_column_spans && last_column.is_none() {
417 Some(-1)
418 } else {
419 last_column.map(|it| it as i32)
420 };
421
422 Some(Mapping {
423 generated: Position {
424 line: (mapping.generated_line + 1) as i32,
425 column: mapping.generated_column as i32,
426 },
427 original: mapping.original.as_ref().map(|it| Position {
428 line: it.original_line as i32,
429 column: it.original_column as i32,
430 }),
431 source: mapping
432 .original
433 .as_ref()
434 .map(|it| self.absolute_sources.at(it.source as i32))
435 .flatten(),
436 name: mapping.original.as_ref().map(|it| {
437 self.source_map.names.as_ref().unwrap()[it.source as usize].clone()
438 }),
439 last_generated_column: last_column,
440 })
441 } else {
442 None
443 }
444 }
445 None => None,
446 }
447 }
448}
449
450impl ConsumerTrait for BasicConsumer {
451 fn consume(source_map_raw: String, source_map_url: String, f: impl FnOnce(Self)) {
452 let consumer = BasicConsumer::new(source_map_raw.as_str(), Some(source_map_url.as_str()));
453 f(consumer);
454 }
455
456 fn each_mapping(&mut self, f: impl Fn(&source_map_mappings::Mapping), ord: IterOrd) {
457 if self.mappings.is_none() {
458 match self.parse_mappings() {
459 Ok(mappings) => self.mappings = Some(mappings),
460 Err(_) => return,
461 }
462 }
463 let mappings = self.mappings.as_mut().unwrap();
464
465 match ord {
466 IterOrd::OriginalOrd => mappings.by_original_location().for_each(f),
467 IterOrd::GeneratedOrd => mappings.by_generated_location().iter().for_each(f),
468 }
469 }
470}
471
472pub struct Section {
473 generated_offset: Position,
474 consumer: BasicConsumer,
475}
476
477pub struct IndexedConsumer {
478 pub source_map: SourceMapJson,
479 pub(crate) sections: Rc<RefCell<Vec<Section>>>,
485}
486
487const SUPPORTED_SOURCE_MAP_VERSION: i32 = 3;
488
489impl IndexedConsumer {
490 pub fn new(source_map_raw: &str, source_map_url: Option<&str>) -> Self {
491 let source_map = serde_json::from_str::<SourceMapJson>(source_map_raw).unwrap();
492 Self::from_source_map_json(source_map, source_map_url)
493 }
494
495 pub fn from_source_map_json(source_map: SourceMapJson, source_map_url: Option<&str>) -> Self {
496 let version = source_map.version;
497
498 if version != SUPPORTED_SOURCE_MAP_VERSION {
501 panic!("Unsupported version: {}", version);
502 }
503
504 let last_offset = Arc::new(Mutex::new(Position {
505 line: -1,
506 column: 0,
507 }));
508
509 IndexedConsumer {
510 source_map: source_map.clone(),
511 sections: Rc::new(RefCell::new(
532 source_map
533 .sections
534 .unwrap()
535 .par_iter()
536 .map({
537 let last_offset = last_offset;
538 move |section| {
539 if section.url.is_some() {
540 panic!("Section with url is not supported.");
541 }
542
543 let line = section.offset.line;
544 let colum = section.offset.column;
545
546 let mut last_offset = last_offset.lock().unwrap();
547
548 if line < last_offset.line
549 || (line == last_offset.line && colum < last_offset.column)
550 {
551 panic!("Section offsets must be ordered and non-overlapping.")
552 }
553
554 *last_offset = section.offset.clone();
555
556 Section {
557 generated_offset: Position {
558 line: line + 1,
561 column: colum + 1,
562 },
563 consumer: BasicConsumer::from_source_map_json(
564 *section.map.clone(),
565 source_map_url,
566 ),
567 }
568 }
569 })
570 .collect(),
571 )),
572 }
573 }
574
575 pub fn get_sources(&self) -> Vec<String> {
577 let mut sources: Vec<String> = vec![];
578
579 for i in 0..(*self.sections).borrow().len() {
580 for j in 0..(*self.sections).borrow()[i]
581 .consumer
582 .source_map
583 .sources
584 .as_ref()
585 .unwrap()
586 .len()
587 {
588 sources.push(
589 (*self.sections).borrow()[i]
590 .consumer
591 .source_map
592 .sources
593 .as_ref()
594 .unwrap()[j]
595 .clone(),
596 );
597 }
598 }
599
600 sources
601 }
602
603 pub fn original_position_for(
604 &mut self,
605 input: Position,
606 bias: Option<Bias>,
607 ) -> Option<Mapping> {
608 let needle = input;
609
610 let section_index = binary_search::search(
611 needle.clone(),
612 &(*self.sections).borrow(),
613 |a, b| {
614 if a.line - b.generated_offset.line != 0 {
615 a.line - b.generated_offset.line
616 } else {
617 a.column - b.generated_offset.column
618 }
619 },
620 |a, b| {
621 if a.generated_offset.line - b.generated_offset.line != 0 {
622 a.generated_offset.line - b.generated_offset.line
623 } else {
624 a.generated_offset.column - b.generated_offset.column
625 }
626 },
627 None,
628 );
629
630 (&*self.sections)
631 .borrow_mut()
632 .get_mut(section_index as usize)
633 .map(|it| {
634 it.consumer.original_position_for(
635 Position {
636 line: needle.line - (it.generated_offset.line - 1),
637 column: needle.column
638 - if it.generated_offset.line == needle.line {
639 it.generated_offset.column - 1
640 } else {
641 0
642 },
643 },
644 bias,
645 )
646 })
647 .flatten()
648 }
649
650 pub fn has_contents_of_all_sources(&self) -> bool {
653 (*self.sections)
654 .borrow()
655 .iter()
656 .all(|it| it.consumer.has_contents_of_all_sources())
657 }
658
659 pub fn source_content_for(
663 &mut self,
664 source: &str,
665 panic_on_missing: Option<bool>,
666 ) -> Option<String> {
667 for section in (*self.sections).borrow_mut().iter_mut() {
668 if let Some(it) = section
669 .consumer
670 .source_content_for(source, panic_on_missing)
671 {
672 return Some(it);
673 }
674 }
675
676 let panic_on_missing = panic_on_missing.unwrap_or(true);
677 if panic_on_missing {
678 panic!("\"{}\"is not in the SourceMap.", source)
679 } else {
680 None
681 }
682 }
683
684 fn find_source_index(&mut self, source: &str) -> Option<i32> {
685 for i in 0..(*self.sections).borrow().len() {
686 let consumer = &mut (*self.sections).borrow_mut()[i].consumer;
687 if let Some(index) = consumer.find_source_index(source) {
688 return Some(index);
689 }
690 }
691
692 None
693 }
694
695 pub fn generated_position_for(
701 &mut self,
702 source: &str,
703 original_line: i32,
704 original_column: i32,
705 bias: Option<Bias>,
706 ) -> Option<Position> {
707 let index = self.find_source_index(source);
708 if let Some(index) = index {
709 if let Some(section) = (*self.sections).borrow_mut().get_mut(index as usize) {
710 let mut generated_position = section.consumer.generated_position_for(
711 source,
712 original_line,
713 original_column,
714 bias,
715 );
716 if let Some(ref mut generated_position) = generated_position {
717 let line_shift = generated_position.generated.line - 1;
718 let column_shift = generated_position.generated.column - 1;
719
720 if generated_position.generated.line == 1 {
721 generated_position.generated.column += column_shift;
722 if let Some(g) = &mut generated_position.last_generated_column {
723 *g += column_shift;
724 }
725 }
726
727 if let (Some(last_column), Some(next_section)) = (
728 generated_position.last_generated_column,
729 (*self.sections).borrow().get(index as usize + 1),
730 ) {
731 if last_column == -1
732 && generated_position.generated.line
733 == next_section.generated_offset.line
734 {
735 generated_position
736 .last_generated_column
737 .replace(next_section.generated_offset.column - 2);
738 }
739 generated_position.generated.line += line_shift;
740
741 return Some(Position {
742 line: generated_position.generated.line,
743 column: generated_position.generated.column,
744 });
745 }
746 }
747 }
748 }
749
750 None
751 }
752
753 pub fn all_generated_position_for(
754 &mut self,
755 source: &str,
756 original_line: i32,
757 original_column: Option<i32>,
758 ) -> Vec<source_map_mappings::Mapping> {
759 let index = self.find_source_index(source);
760 if let Some(index) = index {
761 if let Some(section) = (*self.sections).borrow_mut().get_mut(index as usize) {
762 section
763 .consumer
764 .all_generated_position_for(source, original_line, original_column)
765 .iter()
766 .map(|mapping| {
767 let mut mapping = mapping.clone();
768 let line_shift = mapping.generated_line - 1;
769 let column_shift = mapping.generated_column - 1;
770
771 if mapping.generated_line == 1 {
772 mapping.generated_column += column_shift;
773 if let Some(g) = &mut mapping.last_generated_column {
774 *g += column_shift;
775 } else {
776 }
777 }
778
779 if mapping.last_generated_column.is_some() {
780 let sections_ref = (*self.sections).borrow();
783 let next_section = sections_ref.get(index as usize + 1);
784 if let Some(next_section) = next_section {
785 if mapping.generated_line
786 == next_section.generated_offset.line as u32
787 {
788 mapping
789 .last_generated_column
790 .replace((next_section.generated_offset.column - 2) as u32);
791 }
792 }
793 mapping.generated_line += line_shift;
794 }
795
796 mapping
797 })
798 .collect()
799 } else {
800 vec![]
801 }
802 } else {
803 vec![]
804 }
805 }
806
807 pub fn computed_column_spans(&mut self) {
808 for ele in (*self.sections).borrow_mut().iter_mut() {
809 ele.consumer.compute_column_spans()
810 }
811 }
812}
813
814impl ConsumerTrait for IndexedConsumer {
815 fn consume(source_map_raw: String, source_map_url: String, f: impl FnOnce(Self)) {
816 let consumer = IndexedConsumer::new(source_map_raw.as_str(), Some(source_map_url.as_str()));
817 f(consumer);
818 }
819
820 fn each_mapping(&mut self, f: impl Fn(&source_map_mappings::Mapping), ord: IterOrd) {
821 (*self.sections)
822 .borrow_mut()
823 .iter_mut()
824 .enumerate()
825 .for_each({
826 let sections = &self.sections;
827 let f = &f;
828
829 move |(index, section)| {
830 let generated_offset = &mut section.generated_offset;
838 let line_shift = generated_offset.line - 1;
839 let column_shift = generated_offset.column - 1;
840 section.consumer.each_mapping(
841 {
842 let sections_ref = (**sections).borrow();
843 move |mapping| {
844 let next_section = sections_ref.get(index + 1);
845
846 let mut mapping = mapping.clone();
847 if mapping.generated_line == 1 {
848 mapping.generated_column += column_shift as u32;
849 if let Some(it) = &mut mapping.last_generated_column {
850 *it += column_shift as u32;
851 }
852 }
853
854 if let Some(next_section) = next_section {
855 if mapping.generated_line
856 == next_section.generated_offset.line as u32
857 {
858 mapping.last_generated_column.replace(
859 next_section.generated_offset.column as u32 - 2,
860 );
861 }
862 }
863 mapping.generated_line += line_shift as u32;
864 f(&mapping);
865 }
866 },
867 ord.clone(),
868 )
869 }
870 })
871 }
872}