Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct SourceMapBuilder {
source_root: Option<String>,
sources: Vec<String>,
source_contents: Vec<Option<String>>,
sources_mapping: Vec<u32>,
}

#[cfg(any(unix, windows, target_os = "redox"))]
Expand Down Expand Up @@ -57,6 +58,7 @@ impl SourceMapBuilder {
source_root: None,
sources: vec![],
source_contents: vec![],
sources_mapping: vec![],
}
}

Expand All @@ -82,10 +84,15 @@ impl SourceMapBuilder {

/// Registers a new source with the builder and returns the source ID.
pub fn add_source(&mut self, src: &str) -> u32 {
self.add_source_with_id(src, !0)
}

fn add_source_with_id(&mut self, src: &str, old_id: u32) -> u32 {
let count = self.sources.len() as u32;
let id = *self.source_map.entry(src.into()).or_insert(count);
if id == count {
self.sources.push(src.into());
self.sources_mapping.push(old_id);
}
id
}
Expand Down Expand Up @@ -144,7 +151,7 @@ impl SourceMapBuilder {

let rv = to_read.len();
for (src_id, path) in to_read {
if let Ok(mut f) = fs::File::open(&path) {
if let Ok(mut f) = fs::File::open(path) {
let mut contents = String::new();
if f.read_to_string(&mut contents).is_ok() {
self.set_source_contents(src_id, Some(&contents));
Expand Down Expand Up @@ -174,9 +181,23 @@ impl SourceMapBuilder {
src_col: u32,
source: Option<&str>,
name: Option<&str>,
) -> RawToken {
self.add_with_id(dst_line, dst_col, src_line, src_col, source, !0, name)
}

#[allow(clippy::too_many_arguments)]
fn add_with_id(
&mut self,
dst_line: u32,
dst_col: u32,
src_line: u32,
src_col: u32,
source: Option<&str>,
source_id: u32,
name: Option<&str>,
) -> RawToken {
let src_id = match source {
Some(source) => self.add_source(source),
Some(source) => self.add_source_with_id(source, source_id),
None => !0,
};
let name_id = match name {
Expand Down Expand Up @@ -223,12 +244,13 @@ impl SourceMapBuilder {
/// optionally removing the name.
pub fn add_token(&mut self, token: &Token<'_>, with_name: bool) -> RawToken {
let name = if with_name { token.get_name() } else { None };
self.add(
self.add_with_id(
token.get_dst_line(),
token.get_dst_col(),
token.get_src_line(),
token.get_src_col(),
token.get_source(),
token.get_src_id(),
name,
)
}
Expand All @@ -249,6 +271,10 @@ impl SourceMapBuilder {
}
}

pub(crate) fn take_mapping(&mut self) -> Vec<u32> {
std::mem::take(&mut self.sources_mapping)
}

/// Converts the builder into a sourcemap.
pub fn into_sourcemap(self) -> SourceMap {
let contents = if !self.source_contents.is_empty() {
Expand Down
2 changes: 1 addition & 1 deletion src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ pub fn decode_regular(rsm: RawSourceMap) -> Result<SourceMap> {
if name_id >= names.len() as u32 {
fail!(Error::BadNameReference(name_id));
}
name = name_id as u32;
name = name_id;
}
}

Expand Down
26 changes: 22 additions & 4 deletions src/hermes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ impl SourceMapHermes {

/// Resolves the name of the enclosing function for the given [`Token`].
pub fn get_scope_for_token(&self, token: Token) -> Option<&str> {
let function_map = (self.function_maps.get(token.get_src_id() as usize))?.as_ref()?;
let function_map = self
.function_maps
.get(token.get_src_id() as usize)?
.as_ref()?;

// Find the closest mapping, just like here:
// https://github.com/facebook/metro/blob/63b523eb20e7bdf62018aeaf195bb5a3a1a67f36/packages/metro-symbolicate/src/SourceMetadataMapConsumer.js#L204-L231
Expand All @@ -120,10 +123,25 @@ impl SourceMapHermes {
pub fn rewrite(self, options: &RewriteOptions<'_>) -> Result<Self> {
let Self {
sm,
function_maps,
raw_facebook_sources,
mut function_maps,
mut raw_facebook_sources,
} = self;
let sm = sm.rewrite(options)?;

let (sm, mapping) = sm.rewrite_with_mapping(options)?;

if function_maps.len() >= mapping.len() {
function_maps = mapping
.iter()
.map(|idx| function_maps[*idx as usize].take())
.collect();
raw_facebook_sources = raw_facebook_sources.map(|mut sources| {
mapping
.into_iter()
.map(|idx| sources[idx as usize].take())
.collect()
});
}

Ok(Self {
sm,
function_maps,
Expand Down
14 changes: 13 additions & 1 deletion src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,14 @@ impl SourceMap {
/// });
/// ```
pub fn rewrite(self, options: &RewriteOptions<'_>) -> Result<SourceMap> {
Ok(self.rewrite_with_mapping(options)?.0)
}

/// Same as `rewrite`, except also returns a remapping index for deduplicated `sources`.
pub(crate) fn rewrite_with_mapping(
self,
options: &RewriteOptions<'_>,
) -> Result<(SourceMap, Vec<u32>)> {
let mut builder = SourceMapBuilder::new(self.get_file());

for token in self.tokens() {
Expand Down Expand Up @@ -795,7 +803,11 @@ impl SourceMap {
builder.strip_prefixes(&prefixes);
}

Ok(builder.into_sourcemap())
let mapping = builder.take_mapping();

let sm = builder.into_sourcemap();

Ok((sm, mapping))
}
}

Expand Down
5 changes: 5 additions & 0 deletions tests/test_hermes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use sourcemap::SourceMapHermes;
fn test_react_native_hermes() {
let input = include_bytes!("./fixtures/react-native-hermes/output.map");
let sm = SourceMapHermes::from_reader(&input[..]).unwrap();
let sm = sm.rewrite(&Default::default()).unwrap();

// at foo (address at unknown:1:11939)
assert_eq!(
Expand All @@ -24,6 +25,10 @@ fn test_react_native_hermes() {
fn test_react_native_metro() {
let input = include_bytes!("./fixtures/react-native-metro/output.js.map");
let sm = SourceMapHermes::from_reader(&input[..]).unwrap();
// The given map has a bogus `__prelude__` first source, which is being
// dropped (as its not referenced) by rewriting the sourcemap, and thus
// the internal hermes mappings also need to be rewritten accordingly
let sm = sm.rewrite(&Default::default()).unwrap();

// at foo (output.js:1289:11)
let token = sm.lookup_token(1288, 10).unwrap();
Expand Down