Skip to content

Commit

Permalink
fix(sourcemap): using serde_json::to_string to quote sourcemap string (
Browse files Browse the repository at this point in the history
  • Loading branch information
underfin authored Apr 3, 2024
1 parent 21a5e44 commit 28fae2e
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 17 deletions.
2 changes: 1 addition & 1 deletion crates/oxc_codegen/examples/sourcemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn main() -> std::io::Result<()> {
.build(&ret.program);

if let Some(source_map) = source_map {
let result = source_map.to_json_string();
let result = source_map.to_json_string().unwrap();
let hash = BASE64_STANDARD.encode(format!(
"{}\0{}{}\0{}",
source_text.len(),
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_sourcemap/src/concat_sourcemap_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,5 @@ fn test_concat_sourcemap_builder() {
])
);

assert_eq!(sm.to_json_string(), sm.to_json_string());
assert_eq!(sm.to_json_string().unwrap(), sm.to_json_string().unwrap());
}
51 changes: 43 additions & 8 deletions crates/oxc_sourcemap/src/encode.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use crate::error::{Error, Result};
/// Port from https://github.com/getsentry/rust-sourcemap/blob/master/src/encoder.rs
/// It is a helper for encode `SourceMap` to vlq sourcemap string, but here some different.
/// - Quote `source_content` at parallel.
/// - If you using `ConcatSourceMapBuilder`, serialize `tokens` to vlq `mappings` at parallel.
use crate::{token::TokenChunk, SourceMap, Token};
use rayon::prelude::*;

pub fn encode(sourcemap: &SourceMap) -> String {
// Here using `serde_json::to_string` to serialization `names/source_contents/sources`.
// It will escape the string to avoid invalid JSON string.
pub fn encode(sourcemap: &SourceMap) -> Result<String> {
let mut buf = String::new();
buf.push_str("{\"version\":3,");
if let Some(file) = sourcemap.get_file() {
Expand All @@ -14,20 +17,35 @@ pub fn encode(sourcemap: &SourceMap) -> String {
buf.push_str("\",");
}
buf.push_str("\"names\":[");
buf.push_str(&sourcemap.names.iter().map(|x| format!("{x:?}")).collect::<Vec<_>>().join(","));
let names = sourcemap
.names
.iter()
.map(|x| serde_json::to_string(x.as_ref()))
.collect::<std::result::Result<Vec<_>, serde_json::Error>>()
.map_err(Error::from)?;
buf.push_str(&names.join(","));
buf.push_str("],\"sources\":[");
buf.push_str(&sourcemap.sources.iter().map(|x| format!("{x:?}")).collect::<Vec<_>>().join(","));
let sources = sourcemap
.sources
.iter()
.map(|x| serde_json::to_string(x.as_ref()))
.collect::<std::result::Result<Vec<_>, serde_json::Error>>()
.map_err(Error::from)?;
buf.push_str(&sources.join(","));
// Quote `source_content` at parallel.
if let Some(source_contents) = &sourcemap.source_contents {
buf.push_str("],\"sourcesContent\":[");
buf.push_str(
&source_contents.par_iter().map(|x| format!("{x:?}")).collect::<Vec<_>>().join(","),
);
let quote_source_contents = source_contents
.par_iter()
.map(|x| serde_json::to_string(x.as_ref()))
.collect::<std::result::Result<Vec<_>, serde_json::Error>>()
.map_err(Error::from)?;
buf.push_str(&quote_source_contents.join(","));
}
buf.push_str("],\"mappings\":\"");
buf.push_str(&serialize_sourcemap_mappings(sourcemap));
buf.push_str("\"}");
buf
Ok(buf)
}

#[allow(clippy::cast_possible_truncation)]
Expand Down Expand Up @@ -130,9 +148,26 @@ fn test_encode() {
"mappings": "AAAA,GAAIA,GAAI,EACR,IAAIA,GAAK,EAAG,CACVC,MAAM"
}"#;
let sm = SourceMap::from_json_string(input).unwrap();
let sm2 = SourceMap::from_json_string(&sm.to_json_string()).unwrap();
let sm2 = SourceMap::from_json_string(&sm.to_json_string().unwrap()).unwrap();

for (tok1, tok2) in sm.get_tokens().zip(sm2.get_tokens()) {
assert_eq!(tok1, tok2);
}
}

#[test]
fn test_encode_escape_string() {
// '\0' should be escaped.
let sm = SourceMap::new(
None,
vec!["\0".into()],
vec!["\0".into()],
Some(vec!["\0".into()]),
vec![],
None,
);
assert_eq!(
sm.to_json_string().unwrap(),
r#"{"version":3,"names":["\u0000"],"sources":["\u0000"],"sourcesContent":["\u0000"],"mappings":""}"#
);
}
18 changes: 13 additions & 5 deletions crates/oxc_sourcemap/src/sourcemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,29 @@ impl SourceMap {
}

/// Convert `SourceMap` to vlq sourcemap string.
#[allow(clippy::missing_errors_doc)]
/// # Errors
///
/// The `serde_json` deserialize Error.
pub fn from_json_string(value: &str) -> Result<Self> {
decode(value)
}

/// Convert the vlq sourcemap string to `SourceMap`.
pub fn to_json_string(&self) -> String {
/// # Errors
///
/// The `serde_json` serialization Error.
pub fn to_json_string(&self) -> Result<String> {
encode(self)
}

/// Convert `SourceMap` to vlq sourcemap data url.
pub fn to_data_url(&self) -> String {
/// # Errors
///
/// The `serde_json` serialization Error.
pub fn to_data_url(&self) -> Result<String> {
let base_64_str =
base64_simd::Base64::STANDARD.encode_to_boxed_str(self.to_json_string().as_bytes());
format!("data:application/json;charset=utf-8;base64,{base_64_str}")
base64_simd::Base64::STANDARD.encode_to_boxed_str(self.to_json_string()?.as_bytes());
Ok(format!("data:application/json;charset=utf-8;base64,{base_64_str}"))
}

pub fn get_file(&self) -> Option<&str> {
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_sourcemap/src/sourcemap_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,5 @@ fn test_sourcemap_builder() {

let expected =
r#"{"version":3,"names":["x"],"sources":["baz.js"],"sourcesContent":[""],"mappings":""}"#;
assert_eq!(expected, sm.to_json_string());
assert_eq!(expected, sm.to_json_string().unwrap());
}
2 changes: 1 addition & 1 deletion tasks/benchmark/benches/sourcemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn bench_sourcemap(criterion: &mut Criterion) {
for i in 0..1 {
concat_sourcemap_builder.add_sourcemap(&sourcemap, line * i);
}
concat_sourcemap_builder.into_sourcemap().to_json_string();
concat_sourcemap_builder.into_sourcemap().to_json_string().unwrap();
}
});
});
Expand Down

0 comments on commit 28fae2e

Please sign in to comment.