diff --git a/src/builder.rs b/src/builder.rs index 8bb0cc66..32d0bdcc 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(any(unix, windows, target_os = "redox")), allow(unused_imports))] +use std::collections::BTreeSet; use std::env; use std::fs; use std::io::Read; @@ -28,6 +29,7 @@ pub struct SourceMapBuilder { sources: Vec>, source_contents: Vec>>, sources_mapping: Vec, + ignore_list: BTreeSet, debug_id: Option, } @@ -61,6 +63,7 @@ impl SourceMapBuilder { sources: vec![], source_contents: vec![], sources_mapping: vec![], + ignore_list: BTreeSet::default(), debug_id: None, } } @@ -116,6 +119,10 @@ impl SourceMapBuilder { self.sources.get(src_id as usize).map(|x| &x[..]) } + pub fn add_to_ignore_list(&mut self, src_id: u32) { + self.ignore_list.insert(src_id); + } + /// Sets the source contents for an already existing source. pub fn set_source_contents(&mut self, src_id: u32, contents: Option<&str>) { assert!(src_id != !0, "Cannot set sources for tombstone source id"); @@ -304,6 +311,9 @@ impl SourceMapBuilder { let mut sm = SourceMap::new(self.file, self.tokens, self.names, self.sources, contents); sm.set_source_root(self.source_root); sm.set_debug_id(self.debug_id); + for ignored_src_id in self.ignore_list { + sm.add_to_ignore_list(ignored_src_id); + } sm } diff --git a/src/decoder.rs b/src/decoder.rs index 0ee7c75c..464505ed 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -254,6 +254,11 @@ pub fn decode_regular(rsm: RawSourceMap) -> Result { let mut sm = SourceMap::new(file, tokens, names, sources, source_content); sm.set_source_root(rsm.source_root); sm.set_debug_id(rsm.debug_id); + if let Some(ignore_list) = rsm.ignore_list { + for idx in ignore_list { + sm.add_to_ignore_list(idx); + } + } Ok(sm) } diff --git a/src/encoder.rs b/src/encoder.rs index 8225dc08..6b62d4bc 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -170,6 +170,11 @@ impl Encodable for SourceMap { names: Some(self.names().map(|x| Value::String(x.to_string())).collect()), range_mappings: serialize_range_mappings(self), mappings: Some(serialize_mappings(self)), + ignore_list: if self.ignore_list.is_empty() { + None + } else { + Some(self.ignore_list.iter().cloned().collect()) + }, x_facebook_offsets: None, x_metro_module_paths: None, x_facebook_sources: None, @@ -203,6 +208,7 @@ impl Encodable for SourceMapIndex { names: None, range_mappings: None, mappings: None, + ignore_list: None, x_facebook_offsets: None, x_metro_module_paths: None, x_facebook_sources: None, diff --git a/src/jsontypes.rs b/src/jsontypes.rs index 59d893b9..f83c192a 100644 --- a/src/jsontypes.rs +++ b/src/jsontypes.rs @@ -46,6 +46,8 @@ pub struct RawSourceMap { pub range_mappings: Option, #[serde(skip_serializing_if = "Option::is_none")] pub mappings: Option, + #[serde(rename = "ignoreList", skip_serializing_if = "Option::is_none")] + pub ignore_list: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub x_facebook_offsets: Option>>, #[serde(skip_serializing_if = "Option::is_none")] diff --git a/src/types.rs b/src/types.rs index a2afdc36..d28ac632 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::cmp::Ordering; +use std::collections::BTreeSet; use std::fmt; use std::io::{Read, Write}; use std::path::Path; @@ -464,6 +465,7 @@ pub struct SourceMap { pub(crate) sources: Vec>, pub(crate) sources_prefixed: Option>>, pub(crate) sources_content: Vec>, + pub(crate) ignore_list: BTreeSet, pub(crate) debug_id: Option, } @@ -571,6 +573,7 @@ impl SourceMap { /// - `names`: a vector of names /// - `sources` a vector of source filenames /// - `sources_content` optional source contents + /// - `ignore_list` optional list of source indexes for devtools to ignore pub fn new( file: Option>, mut tokens: Vec, @@ -591,6 +594,7 @@ impl SourceMap { .into_iter() .map(|opt| opt.map(SourceView::new)) .collect(), + ignore_list: BTreeSet::default(), debug_id: None, } } @@ -651,6 +655,14 @@ impl SourceMap { } } + pub fn add_to_ignore_list(&mut self, src_id: u32) { + self.ignore_list.insert(src_id); + } + + pub fn ignore_list(&self) -> impl Iterator { + self.ignore_list.iter() + } + /// Looks up a token by its index. pub fn get_token(&self, idx: usize) -> Option> { self.tokens.get(idx).map(|raw| Token { @@ -1201,6 +1213,9 @@ impl SourceMapIndex { map.get_source_contents(token.get_src_id()), ); } + if map.ignore_list.contains(&token.get_src_id()) { + builder.add_to_ignore_list(raw.src_id); + } } } diff --git a/tests/test_builder.rs b/tests/test_builder.rs index 8d34a307..c3d38751 100644 --- a/tests/test_builder.rs +++ b/tests/test_builder.rs @@ -6,13 +6,14 @@ fn test_builder_into_sourcemap() { builder.set_source_root(Some("/foo/bar")); builder.add_source("baz.js"); builder.add_name("x"); + builder.add_to_ignore_list(0); let sm = builder.into_sourcemap(); assert_eq!(sm.get_source_root(), Some("/foo/bar")); assert_eq!(sm.get_source(0), Some("/foo/bar/baz.js")); assert_eq!(sm.get_name(0), Some("x")); - let expected = br#"{"version":3,"sources":["baz.js"],"sourceRoot":"/foo/bar","names":["x"],"mappings":""}"#; + let expected = br#"{"version":3,"sources":["baz.js"],"sourceRoot":"/foo/bar","names":["x"],"mappings":"","ignoreList":[0]}"#; let mut output: Vec = vec![]; sm.to_writer(&mut output).unwrap(); assert_eq!(output, expected); diff --git a/tests/test_index.rs b/tests/test_index.rs index e373b7bf..b3983576 100644 --- a/tests/test_index.rs +++ b/tests/test_index.rs @@ -158,3 +158,50 @@ fn test_indexed_sourcemap_for_react_native() { let ism = SourceMapIndex::from_reader(input).unwrap(); assert!(ism.is_for_ram_bundle()); } + +#[test] +fn test_flatten_indexed_sourcemap_with_ignore_list() { + let input: &[_] = br#"{ + "version": 3, + "file": "bla", + "sections": [ + { + "offset": { + "line": 0, + "column": 0 + }, + "map": { + "version":3, + "sources":["file1.js"], + "names":["add","a","b"], + "mappings":"AAAA,QAASA,KAAIC,EAAGC,GACf,YACA,OAAOD,GAAIC", + "file":"file1.min.js" + } + }, + { + "offset": { + "line": 1, + "column": 0 + }, + "map": { + "version":3, + "sources":["file2.js"], + "names":["multiply","a","b","divide","add","c","e","Raven","captureException"], + "mappings":"AAAA,QAASA,UAASC,EAAGC,GACpB,YACA,OAAOD,GAAIC,EAEZ,QAASC,QAAOF,EAAGC,GAClB,YACA,KACC,MAAOF,UAASI,IAAIH,EAAGC,GAAID,EAAGC,GAAKG,EAClC,MAAOC,GACRC,MAAMC,iBAAiBF", + "file":"file2.min.js", + "ignoreList": [0] + } + } + ] + }"#; + + let ism = SourceMapIndex::from_reader(input).unwrap(); + assert_eq!( + ism.flatten() + .unwrap() + .ignore_list() + .copied() + .collect::>(), + vec![1] + ); +}