Skip to content

fix: sources_content should be Vec<Option<Arc<str>>> #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
24 changes: 10 additions & 14 deletions src/concat_sourcemap_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{SourceMap, Token, token::TokenChunk};
pub struct ConcatSourceMapBuilder {
pub(crate) names: Vec<Arc<str>>,
pub(crate) sources: Vec<Arc<str>>,
pub(crate) source_contents: Vec<Arc<str>>,
pub(crate) source_contents: Vec<Option<Arc<str>>>,
pub(crate) tokens: Vec<Token>,
/// The `token_chunks` is used for encode tokens to vlq mappings at parallel.
pub(crate) token_chunks: Vec<TokenChunk>,
Expand Down Expand Up @@ -109,14 +109,10 @@ impl ConcatSourceMapBuilder {
// Extend `sources` and `source_contents`.
self.sources.extend(sourcemap.get_sources().map(Into::into));

if let Some(source_contents) = &sourcemap.source_contents {
// Clone `Arc` instead of generating a new `Arc` and copying string data because
// source texts are generally long strings. Cost of copying a large string is higher
// than cloning an `Arc`.
self.source_contents.extend(source_contents.iter().map(Arc::clone));
} else {
self.source_contents.extend((0..sourcemap.sources.len()).map(|_| "".into()));
}
// Clone `Arc` instead of generating a new `Arc` and copying string data because
// source texts are generally long strings. Cost of copying a large string is higher
// than cloning an `Arc`.
self.source_contents.extend(sourcemap.source_contents.iter().cloned());

// Extend `names`.
self.names.reserve(sourcemap.names.len());
Expand Down Expand Up @@ -149,7 +145,7 @@ impl ConcatSourceMapBuilder {
self.names,
None,
self.sources,
Some(self.source_contents),
self.source_contents,
self.tokens,
Some(self.token_chunks),
)
Expand Down Expand Up @@ -182,7 +178,7 @@ where
vec!["foo".into(), "foo2".into()],
None,
vec!["foo.js".into()],
None,
vec![],
vec![Token::new(1, 1, 1, 1, Some(0), Some(0))],
None,
);
Expand All @@ -191,7 +187,7 @@ where
vec!["bar".into()],
None,
vec!["bar.js".into()],
None,
vec![],
vec![Token::new(1, 1, 1, 1, Some(0), Some(0))],
None,
);
Expand All @@ -200,7 +196,7 @@ where
vec!["abc".into()],
None,
vec!["abc.js".into()],
None,
vec![],
vec![Token::new(1, 2, 2, 2, Some(0), Some(0))],
None,
);
Expand All @@ -212,7 +208,7 @@ where
vec!["foo".into(), "foo2".into(), "bar".into(), "abc".into()],
None,
vec!["foo.js".into(), "bar.js".into(), "abc.js".into()],
None,
vec![],
vec![
Token::new(1, 1, 1, 1, Some(0), Some(0)),
Token::new(3, 1, 1, 1, Some(1), Some(2)),
Expand Down
7 changes: 4 additions & 3 deletions src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ pub fn decode(json: JSONSourceMap) -> Result<SourceMap> {
names: json.names.into_iter().map(Arc::from).collect(),
source_root: json.source_root,
sources: json.sources.into_iter().map(Arc::from).collect(),
source_contents: json.sources_content.map(|content| {
content.into_iter().map(|c| c.map(Arc::from).unwrap_or_default()).collect()
}),
source_contents: json
.sources_content
.map(|content| content.into_iter().map(|c| c.map(Arc::from)).collect())
.unwrap_or_default(),
tokens,
token_chunks: None,
x_google_ignore_list: json.x_google_ignore_list,
Expand Down
46 changes: 26 additions & 20 deletions src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,30 @@ pub fn encode(sourcemap: &SourceMap) -> JSONSourceMap {
mappings: serialize_sourcemap_mappings(sourcemap),
source_root: sourcemap.get_source_root().map(ToString::to_string),
sources: sourcemap.sources.iter().map(ToString::to_string).collect(),
sources_content: sourcemap
.source_contents
.as_ref()
.map(|x| x.iter().map(ToString::to_string).map(Some).collect()),
sources_content: Some(
sourcemap
.source_contents
.iter()
.map(|v| v.as_ref().map(|item| item.to_string()))
.collect(),
),
names: sourcemap.names.iter().map(ToString::to_string).collect(),
debug_id: sourcemap.get_debug_id().map(ToString::to_string),
x_google_ignore_list: sourcemap.get_x_google_ignore_list().map(|x| x.to_vec()),
}
}
fn escape_optional_json_string<S: AsRef<str>>(s: &Option<S>) -> String {
s.as_ref().map(escape_json_string).unwrap_or_else(|| String::from("null"))
}

// Here using `serde_json` to serialize `names` / `source_contents` / `sources`.
// It will escape the string to avoid invalid JSON string.
pub fn encode_to_string(sourcemap: &SourceMap) -> String {
let max_segments = 12
+ sourcemap.names.len() * 2
+ sourcemap.sources.len() * 2
+ sourcemap.source_contents.as_ref().map_or(0, |sources| sources.len() * 2 + 1)
+ sourcemap.source_contents.len() * 2
+ 1
+ sourcemap.x_google_ignore_list.as_ref().map_or(0, |x| x.len() * 2 + 1);
let mut contents = PreAllocatedString::new(max_segments);

Expand All @@ -56,20 +63,19 @@ pub fn encode_to_string(sourcemap: &SourceMap) -> String {
contents.push_list(sourcemap.sources.iter().map(escape_json_string));

// Quote `source_content` in parallel
if let Some(source_contents) = &sourcemap.source_contents {
contents.push("],\"sourcesContent\":[".into());
cfg_if::cfg_if! {
if #[cfg(feature = "rayon")] {
let quoted_source_contents: Vec<_> = source_contents
.par_iter()
.map(escape_json_string)
.collect();
contents.push_list(quoted_source_contents.into_iter());
} else {
contents.push_list(source_contents.iter().map(escape_json_string));
}
};
}
let source_contents = &sourcemap.source_contents;
contents.push("],\"sourcesContent\":[".into());
cfg_if::cfg_if! {
if #[cfg(feature = "rayon")] {
let quoted_source_contents: Vec<_> = source_contents
.par_iter()
.map(escape_optional_json_string)
.collect();
contents.push_list(quoted_source_contents.into_iter());
} else {
contents.push_list(source_contents.iter().map(escape_optional_json_string));
}
};

if let Some(x_google_ignore_list) = &sourcemap.x_google_ignore_list {
contents.push("],\"x_google_ignoreList\":[".into());
Expand Down Expand Up @@ -407,7 +413,7 @@ fn test_encode_escape_string() {
vec!["name_length_greater_than_16_\0".into()],
None,
vec!["\0".into()],
Some(vec!["emoji-👀-\0".into()]),
vec![Some("emoji-👀-\0".into())],
vec![],
None,
);
Expand Down
19 changes: 10 additions & 9 deletions src/sourcemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub struct SourceMap {
pub(crate) names: Vec<Arc<str>>,
pub(crate) source_root: Option<String>,
pub(crate) sources: Vec<Arc<str>>,
pub(crate) source_contents: Option<Vec<Arc<str>>>,
pub(crate) source_contents: Vec<Option<Arc<str>>>,
pub(crate) tokens: Vec<Token>,
pub(crate) token_chunks: Option<Vec<TokenChunk>>,
/// Identifies third-party sources (such as framework code or bundler-generated code), allowing developers to avoid code that they don't want to see or step through, without having to configure this beforehand.
Expand All @@ -30,7 +30,7 @@ impl SourceMap {
names: Vec<Arc<str>>,
source_root: Option<String>,
sources: Vec<Arc<str>>,
source_contents: Option<Vec<Arc<str>>>,
source_contents: Vec<Option<Arc<str>>>,
tokens: Vec<Token>,
token_chunks: Option<Vec<TokenChunk>>,
) -> Self {
Expand Down Expand Up @@ -122,12 +122,13 @@ impl SourceMap {
}

/// Adjust `source_content`.
pub fn set_source_contents(&mut self, source_contents: Vec<&str>) {
self.source_contents = Some(source_contents.into_iter().map(Into::into).collect());
pub fn set_source_contents(&mut self, source_contents: Vec<Option<&str>>) {
self.source_contents =
source_contents.into_iter().map(|v| v.map(Arc::from)).collect::<Vec<_>>();
}

pub fn get_source_contents(&self) -> Option<impl Iterator<Item = &str>> {
self.source_contents.as_ref().map(|v| v.iter().map(AsRef::as_ref))
pub fn get_source_contents(&self) -> impl Iterator<Item = Option<&str>> {
self.source_contents.iter().map(|item| item.as_ref().map(AsRef::as_ref))
}

pub fn get_token(&self, index: u32) -> Option<&Token> {
Expand Down Expand Up @@ -157,7 +158,7 @@ impl SourceMap {
}

pub fn get_source_content(&self, id: u32) -> Option<&str> {
self.source_contents.as_ref().and_then(|x| x.get(id as usize).map(AsRef::as_ref))
self.source_contents.get(id as usize).and_then(|item| item.as_ref().map(AsRef::as_ref))
}

pub fn get_source_and_content(&self, id: u32) -> Option<(&str, &str)> {
Expand Down Expand Up @@ -278,7 +279,7 @@ fn test_sourcemap_source_view_token() {
vec!["foo".into()],
None,
vec!["foo.js".into()],
None,
vec![],
vec![Token::new(1, 1, 1, 1, Some(0), Some(0))],
None,
);
Expand All @@ -291,7 +292,7 @@ fn test_mut_sourcemap() {
let mut sm = SourceMap::default();
sm.set_file("index.js");
sm.set_sources(vec!["foo.js"]);
sm.set_source_contents(vec!["foo"]);
sm.set_source_contents(vec![Some("foo")]);

assert_eq!(sm.get_file(), Some("index.js"));
assert_eq!(sm.get_source(0), Some("foo.js"));
Expand Down
8 changes: 4 additions & 4 deletions src/sourcemap_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub struct SourceMapBuilder {
pub(crate) names: Vec<Arc<str>>,
pub(crate) sources: Vec<Arc<str>>,
pub(crate) sources_map: FxHashMap<Arc<str>, u32>,
pub(crate) source_contents: Vec<Arc<str>>,
pub(crate) source_contents: Vec<Option<Arc<str>>>,
pub(crate) tokens: Vec<Token>,
pub(crate) token_chunks: Option<Vec<TokenChunk>>,
}
Expand All @@ -38,7 +38,7 @@ impl SourceMapBuilder {
let id = *self.sources_map.entry(source.into()).or_insert(count);
if id == count {
self.sources.push(source.into());
self.source_contents.push(source_content.into());
self.source_contents.push(Some(source_content.into()));
}
id
}
Expand All @@ -48,7 +48,7 @@ impl SourceMapBuilder {
pub fn set_source_and_content(&mut self, source: &str, source_content: &str) -> u32 {
let count = self.sources.len() as u32;
self.sources.push(source.into());
self.source_contents.push(source_content.into());
self.source_contents.push(Some(source_content.into()));
count
}

Expand Down Expand Up @@ -80,7 +80,7 @@ impl SourceMapBuilder {
self.names,
None,
self.sources,
Some(self.source_contents),
self.source_contents,
self.tokens,
self.token_chunks,
)
Expand Down
11 changes: 7 additions & 4 deletions src/sourcemap_visualizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@ impl<'a> SourcemapVisualizer<'a> {

pub fn into_visualizer_text(self) -> String {
let mut s = String::new();

let Some(source_contents) = &self.sourcemap.source_contents else {
let source_contents = &self.sourcemap.source_contents;
if self.sourcemap.source_contents.is_empty() {
s.push_str("[no source contents]\n");
return s;
};
}

let source_contents_lines_map: Vec<Vec<Vec<u16>>> = source_contents
.iter()
.map(|content| Self::generate_line_utf16_tables(content))
.filter_map(|content| {
let content = content.as_ref()?;
Some(Self::generate_line_utf16_tables(content))
})
.collect();

let output_lines = Self::generate_line_utf16_tables(self.output);
Expand Down
2 changes: 1 addition & 1 deletion tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn invalid_token_position() {
vec![],
None,
vec!["src.js".into()],
Some(vec!["abc\ndef".into()]),
vec![Some("abc\ndef".into())],
vec![
Token::new(0, 0, 0, 0, Some(0), None),
Token::new(0, 10, 0, 0, Some(0), None),
Expand Down