Skip to content

Commit 3f32cae

Browse files
feat: Add debug_id field to SourceMapIndex (#117)
Also, add support for encoding and decoding the new `debug_id` field, and add tests. In order to be able to more thoroughly test encoding/decoding, this code adds `PartialEq` and `Debug` implementations to some structs which were lacking it previously. Closes #113
1 parent 811d878 commit 3f32cae

File tree

6 files changed

+203
-14
lines changed

6 files changed

+203
-14
lines changed

src/decoder.rs

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ fn decode_index(rsm: RawSourceMap) -> Result<SourceMapIndex> {
292292
sections,
293293
rsm.x_facebook_offsets,
294294
rsm.x_metro_module_paths,
295-
))
295+
)
296+
.with_debug_id(rsm._debug_id_new.or(rsm.debug_id)))
296297
}
297298

298299
fn decode_common(rsm: RawSourceMap) -> Result<DecodedMap> {
@@ -387,4 +388,95 @@ mod tests {
387388
assert_eq!(decode("g"), vec![5]);
388389
assert_eq!(decode("Bg"), vec![0, 11]);
389390
}
391+
392+
#[test]
393+
fn test_decode_sourcemap_index_no_debug_id() {
394+
let raw = RawSourceMap {
395+
version: Some(3),
396+
file: Some("test.js".into()),
397+
sources: None,
398+
source_root: None,
399+
sources_content: None,
400+
sections: Some(vec![]),
401+
names: None,
402+
range_mappings: None,
403+
mappings: None,
404+
ignore_list: None,
405+
x_facebook_offsets: None,
406+
x_metro_module_paths: None,
407+
x_facebook_sources: None,
408+
debug_id: None,
409+
_debug_id_new: None,
410+
};
411+
412+
let decoded = decode_common(raw).expect("should decoded");
413+
assert_eq!(
414+
decoded,
415+
DecodedMap::Index(SourceMapIndex::new(Some("test.js".into()), vec![]))
416+
);
417+
}
418+
419+
#[test]
420+
fn test_decode_sourcemap_index_debug_id() {
421+
const DEBUG_ID: &str = "0123456789abcdef0123456789abcdef";
422+
423+
let raw = RawSourceMap {
424+
version: Some(3),
425+
file: Some("test.js".into()),
426+
sources: None,
427+
source_root: None,
428+
sources_content: None,
429+
sections: Some(vec![]),
430+
names: None,
431+
range_mappings: None,
432+
mappings: None,
433+
ignore_list: None,
434+
x_facebook_offsets: None,
435+
x_metro_module_paths: None,
436+
x_facebook_sources: None,
437+
debug_id: None,
438+
_debug_id_new: Some(DEBUG_ID.parse().expect("valid debug id")),
439+
};
440+
441+
let decoded = decode_common(raw).expect("should decode");
442+
assert_eq!(
443+
decoded,
444+
DecodedMap::Index(
445+
SourceMapIndex::new(Some("test.js".into()), vec![])
446+
.with_debug_id(Some(DEBUG_ID.parse().expect("valid debug id")))
447+
)
448+
);
449+
}
450+
451+
#[test]
452+
fn test_decode_sourcemap_index_debug_id_from_legacy_key() {
453+
const DEBUG_ID: &str = "0123456789abcdef0123456789abcdef";
454+
455+
let raw = RawSourceMap {
456+
version: Some(3),
457+
file: Some("test.js".into()),
458+
sources: None,
459+
source_root: None,
460+
sources_content: None,
461+
sections: Some(vec![]),
462+
names: None,
463+
range_mappings: None,
464+
mappings: None,
465+
ignore_list: None,
466+
x_facebook_offsets: None,
467+
x_metro_module_paths: None,
468+
x_facebook_sources: None,
469+
debug_id: Some(DEBUG_ID.parse().expect("valid debug id")),
470+
_debug_id_new: None,
471+
};
472+
473+
let decoded = decode_common(raw).expect("should decode");
474+
assert_eq!(
475+
decoded,
476+
DecodedMap::Index(
477+
SourceMapIndex::new(Some("test.js".into()), vec![])
478+
.with_debug_id(Some(DEBUG_ID.parse().expect("valid debug id")))
479+
)
480+
);
481+
}
390482
}

src/encoder.rs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ impl Encodable for SourceMapIndex {
214214
x_metro_module_paths: None,
215215
x_facebook_sources: None,
216216
debug_id: None,
217-
_debug_id_new: None,
217+
// Put the debug ID on _debug_id_new to serialize it to the debugId field.
218+
_debug_id_new: self.debug_id(),
218219
}
219220
}
220221
}
@@ -255,4 +256,61 @@ mod tests {
255256
assert_eq!(encode(&[5]), "g");
256257
assert_eq!(encode(&[0, 11]), "Bg");
257258
}
259+
260+
#[test]
261+
fn test_encode_sourcemap_index_no_debug_id() {
262+
let smi = SourceMapIndex::new(Some("test.js".into()), vec![]);
263+
let raw = smi.as_raw_sourcemap();
264+
265+
assert_eq!(
266+
raw,
267+
RawSourceMap {
268+
version: Some(3),
269+
file: Some("test.js".into()),
270+
sources: None,
271+
source_root: None,
272+
sources_content: None,
273+
sections: Some(vec![]),
274+
names: None,
275+
range_mappings: None,
276+
mappings: None,
277+
ignore_list: None,
278+
x_facebook_offsets: None,
279+
x_metro_module_paths: None,
280+
x_facebook_sources: None,
281+
debug_id: None,
282+
_debug_id_new: None,
283+
}
284+
);
285+
}
286+
287+
#[test]
288+
fn test_encode_sourcemap_index_debug_id() {
289+
const DEBUG_ID: &str = "0123456789abcdef0123456789abcdef";
290+
291+
let smi = SourceMapIndex::new(Some("test.js".into()), vec![])
292+
.with_debug_id(Some(DEBUG_ID.parse().expect("valid debug id")));
293+
294+
let raw = smi.as_raw_sourcemap();
295+
assert_eq!(
296+
raw,
297+
RawSourceMap {
298+
version: Some(3),
299+
file: Some("test.js".into()),
300+
sources: None,
301+
source_root: None,
302+
sources_content: None,
303+
sections: Some(vec![]),
304+
names: None,
305+
range_mappings: None,
306+
mappings: None,
307+
ignore_list: None,
308+
x_facebook_offsets: None,
309+
x_metro_module_paths: None,
310+
x_facebook_sources: None,
311+
debug_id: None,
312+
_debug_id_new: Some(DEBUG_ID.parse().expect("valid debug id")),
313+
}
314+
);
315+
}
258316
}

src/hermes.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@ use std::ops::{Deref, DerefMut};
1212
/// These are starting locations of scopes.
1313
/// The `name_index` represents the index into the `HermesFunctionMap.names` vec,
1414
/// which represents the function names/scopes.
15-
#[derive(Debug, Clone)]
15+
#[derive(Debug, Clone, PartialEq)]
1616
pub struct HermesScopeOffset {
1717
line: u32,
1818
column: u32,
1919
name_index: u32,
2020
}
2121

22-
#[derive(Debug, Clone)]
22+
#[derive(Debug, Clone, PartialEq)]
2323
pub struct HermesFunctionMap {
2424
names: Vec<String>,
2525
mappings: Vec<HermesScopeOffset>,
2626
}
2727

2828
/// Represents a `react-native`-style SourceMap, which has additional scope
2929
/// information embedded.
30-
#[derive(Debug, Clone)]
30+
#[derive(Debug, Clone, PartialEq)]
3131
pub struct SourceMapHermes {
3232
pub(crate) sm: SourceMap,
3333
// There should be one `HermesFunctionMap` per each `sources` entry in the main SourceMap.

src/jsontypes.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@ use serde::de::IgnoredAny;
33
use serde::{Deserialize, Serialize};
44
use serde_json::Value;
55

6-
#[derive(Serialize, Deserialize)]
6+
#[derive(Serialize, Deserialize, PartialEq, Debug)]
77
pub struct RawSectionOffset {
88
pub line: u32,
99
pub column: u32,
1010
}
1111

12-
#[derive(Serialize, Deserialize)]
12+
#[derive(Serialize, Deserialize, PartialEq, Debug)]
1313
pub struct RawSection {
1414
pub offset: RawSectionOffset,
1515
pub url: Option<String>,
1616
pub map: Option<Box<RawSourceMap>>,
1717
}
1818

19-
#[derive(Serialize, Deserialize, Clone, Debug)]
19+
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
2020
pub struct FacebookScopeMapping {
2121
pub names: Vec<String>,
2222
pub mappings: String,
@@ -28,7 +28,7 @@ pub struct FacebookScopeMapping {
2828
// See the decoder in `hermes.rs` for details.
2929
pub type FacebookSources = Option<Vec<Option<Vec<FacebookScopeMapping>>>>;
3030

31-
#[derive(Serialize, Deserialize)]
31+
#[derive(Serialize, Deserialize, PartialEq, Debug)]
3232
pub struct RawSourceMap {
3333
pub version: Option<u32>,
3434
#[serde(skip_serializing_if = "Option::is_none")]

src/sourceview.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ impl fmt::Debug for SourceView {
151151
}
152152
}
153153

154+
impl PartialEq for SourceView {
155+
fn eq(&self, other: &Self) -> bool {
156+
self.source == other.source
157+
}
158+
}
159+
154160
impl SourceView {
155161
/// Creates an optimized view of a given source.
156162
pub fn new(source: Arc<str>) -> SourceView {

src/types.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl<'a> Default for RewriteOptions<'a> {
6161
/// Usually the two things are too distinct to provide a common
6262
/// interface however for token lookup and writing back into a writer
6363
/// general methods are provided.
64-
#[derive(Debug, Clone)]
64+
#[derive(Debug, Clone, PartialEq)]
6565
pub enum DecodedMap {
6666
/// Indicates a regular sourcemap
6767
Regular(SourceMap),
@@ -419,7 +419,7 @@ impl fmt::Display for Token<'_> {
419419
}
420420

421421
/// Represents a section in a sourcemap index
422-
#[derive(Debug, Clone)]
422+
#[derive(Debug, Clone, PartialEq)]
423423
pub struct SourceMapSection {
424424
offset: (u32, u32),
425425
url: Option<String>,
@@ -443,20 +443,21 @@ impl<'a> Iterator for SourceMapSectionIter<'a> {
443443
}
444444

445445
/// Represents a sourcemap index in memory
446-
#[derive(Debug, Clone)]
446+
#[derive(Debug, Clone, PartialEq)]
447447
pub struct SourceMapIndex {
448448
file: Option<String>,
449449
sections: Vec<SourceMapSection>,
450450
x_facebook_offsets: Option<Vec<Option<u32>>>,
451451
x_metro_module_paths: Option<Vec<String>>,
452+
debug_id: Option<DebugId>,
452453
}
453454

454455
/// Represents a sourcemap in memory
455456
///
456457
/// This is always represents a regular "non-indexed" sourcemap. Particularly
457458
/// in case the `from_reader` method is used an index sourcemap will be
458459
/// rejected with an error on reading.
459-
#[derive(Clone, Debug)]
460+
#[derive(Clone, Debug, PartialEq)]
460461
pub struct SourceMap {
461462
pub(crate) file: Option<Arc<str>>,
462463
pub(crate) tokens: Vec<RawToken>,
@@ -1078,6 +1079,7 @@ impl SourceMapIndex {
10781079
sections,
10791080
x_facebook_offsets: None,
10801081
x_metro_module_paths: None,
1082+
debug_id: None,
10811083
}
10821084
}
10831085

@@ -1099,9 +1101,21 @@ impl SourceMapIndex {
10991101
sections,
11001102
x_facebook_offsets,
11011103
x_metro_module_paths,
1104+
debug_id: None,
11021105
}
11031106
}
11041107

1108+
/// Returns the debug ID.
1109+
pub(crate) fn debug_id(&self) -> Option<DebugId> {
1110+
self.debug_id
1111+
}
1112+
1113+
/// Adds the given debug id to the sourcemap index.
1114+
pub(crate) fn with_debug_id(mut self, debug_id: Option<DebugId>) -> Self {
1115+
self.debug_id = debug_id;
1116+
self
1117+
}
1118+
11051119
/// Returns the embedded filename in case there is one.
11061120
pub fn get_file(&self) -> Option<&str> {
11071121
self.file.as_ref().map(|x| &x[..])
@@ -1306,7 +1320,7 @@ impl SourceMapSection {
13061320

13071321
#[cfg(test)]
13081322
mod tests {
1309-
use super::{RewriteOptions, SourceMap};
1323+
use super::{RewriteOptions, SourceMap, SourceMapIndex};
13101324
use debugid::DebugId;
13111325

13121326
#[test]
@@ -1416,6 +1430,25 @@ mod tests {
14161430
assert_eq!(sm_new.sources, sm.sources);
14171431
}
14181432

1433+
#[test]
1434+
fn test_sourcemap_index_default_debug_id() {
1435+
let sm = SourceMapIndex::new(None, vec![]);
1436+
assert!(sm.debug_id().is_none());
1437+
}
1438+
1439+
#[test]
1440+
fn test_sourcemap_index_debug_id() {
1441+
const DEBUG_ID: &str = "0123456789abcdef0123456789abcdef";
1442+
1443+
let sm = SourceMapIndex::new(None, vec![])
1444+
.with_debug_id(Some(DEBUG_ID.parse().expect("valid debug id")));
1445+
1446+
assert_eq!(
1447+
sm.debug_id(),
1448+
Some(DEBUG_ID.parse().expect("valid debug id"))
1449+
);
1450+
}
1451+
14191452
mod prop {
14201453
//! This module exists to test the following property:
14211454
//!

0 commit comments

Comments
 (0)