diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index a90be724cc8c51..886595cdce741c 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -71,7 +71,6 @@ jobs: - semantic - minifier - codegen - - sourcemap steps: - name: Checkout Branch diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d58bdcf630051..33bfe186f0686f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,7 @@ jobs: shell: bash run: | # cargo ck # no need to check because it's already checked in linux - cargo test --workspace --exclude oxc_sourcemap + cargo test --workspace test-wasm32-wasip1-threads: name: Test wasm32-wasip1-threads diff --git a/Cargo.lock b/Cargo.lock index 62daefb644aeba..224f379c934c11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1515,7 +1515,6 @@ dependencies = [ "oxc_parser", "oxc_prettier", "oxc_semantic", - "oxc_sourcemap", "oxc_span", "oxc_tasks_common", "oxc_transformer", @@ -1934,12 +1933,13 @@ dependencies = [ [[package]] name = "oxc_sourcemap" -version = "0.38.0" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e75cb20b3bb96af20d320f71d67c9f20b5bedb253cae36881fedef51f7688f" dependencies = [ "base64-simd", "cfg-if", "cow-utils", - "insta", "rayon", "rustc-hash", "serde", diff --git a/Cargo.toml b/Cargo.toml index 4e2b3288fea1d4..b7611448fad97a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,7 +94,6 @@ oxc_minifier = { version = "0.38.0", path = "crates/oxc_minifier" } oxc_parser = { version = "0.38.0", path = "crates/oxc_parser" } oxc_regular_expression = { version = "0.38.0", path = "crates/oxc_regular_expression" } oxc_semantic = { version = "0.38.0", path = "crates/oxc_semantic" } -oxc_sourcemap = { version = "0.38.0", path = "crates/oxc_sourcemap" } oxc_span = { version = "0.38.0", path = "crates/oxc_span" } oxc_syntax = { version = "0.38.0", path = "crates/oxc_syntax" } oxc_transform_napi = { version = "0.38.0", path = "napi/transform" } @@ -119,15 +118,18 @@ quote = "1" syn = { version = "2", default-features = false } unicode-id-start = "1" +oxc-browserslist = "1.1.0" +oxc_index = "1.0.0" +oxc_resolver = "2.0.0" +oxc_sourcemap = "1" + aho-corasick = "1.1.3" allocator-api2 = "0.2.18" assert-unchecked = "0.1.2" base64 = "0.22.1" -base64-simd = "0.8" bitflags = "2.6.0" bpaf = "0.9.15" bumpalo = "3.16.0" -cfg-if = "1.0.0" compact_str = "0.8.0" console = "0.15.8" console_error_panic_hook = "0.1.7" @@ -163,9 +165,6 @@ mime_guess = "2.0.5" nonmax = "0.5.5" num-bigint = "0.4.6" num-traits = "0.2.19" -oxc-browserslist = "1.1.0" -oxc_index = "1.0.0" -oxc_resolver = "2.0.0" petgraph = "0.6.5" phf = "0.11.2" pico-args = "0.5.0" diff --git a/crates/oxc_sourcemap/CHANGELOG.md b/crates/oxc_sourcemap/CHANGELOG.md deleted file mode 100644 index 4eddfc6014e86a..00000000000000 --- a/crates/oxc_sourcemap/CHANGELOG.md +++ /dev/null @@ -1,162 +0,0 @@ -# Changelog - -All notable changes to this package will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project does not adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) until v1.0.0. - -## [0.37.0] - 2024-11-21 - -### Bug Fixes - -- 3d66929 sourcemap: Improve source map visualizer (#7386) (Hiroshi Ogawa) - -## [0.31.0] - 2024-10-08 - -### Features - -- f6e42b6 sourcemap: Add support for sourcemap debug IDs (#6221) (Tim Fish) - -## [0.30.4] - 2024-09-28 - -### Bug Fixes - -- 6f98aad sourcemap: Align sourcemap type with Rollup (#6133) (Boshen) - -## [0.29.0] - 2024-09-13 - -### Performance - -- d18c896 rust: Use `cow_utils` instead (#5664) (dalaoshu) - -## [0.28.0] - 2024-09-11 - -### Documentation - -- fefbbc1 sourcemap: Add trailing newline to README (#5539) (overlookmotel) - -## [0.24.3] - 2024-08-18 - -### Refactor - -- 5fd1701 sourcemap: Lower the `msrv`. (#4873) (rzvxa) - -## [0.24.0] - 2024-08-08 - -### Features - -- e42ac3a sourcemap: Add `ConcatSourceMapBuilder::from_sourcemaps` (#4639) (overlookmotel) - -### Performance - -- ff43dff sourcemap: Speed up VLQ encoding (#4633) (overlookmotel) -- a330773 sourcemap: Reduce string copying in `ConcatSourceMapBuilder` (#4638) (overlookmotel) -- 372316b sourcemap: `ConcatSourceMapBuilder` extend `source_contents` in separate loop (#4634) (overlookmotel) -- c7f1d48 sourcemap: Keep local copy of previous token in VLQ encode (#4596) (overlookmotel) -- 590d795 sourcemap: Shorten main loop encoding VLQ (#4586) (overlookmotel) - -## [0.23.1] - 2024-08-06 - -### Features - -- e42ac3a sourcemap: Add `ConcatSourceMapBuilder::from_sourcemaps` (#4639) (overlookmotel) - -### Performance - -- ff43dff sourcemap: Speed up VLQ encoding (#4633) (overlookmotel) -- a330773 sourcemap: Reduce string copying in `ConcatSourceMapBuilder` (#4638) (overlookmotel) -- 372316b sourcemap: `ConcatSourceMapBuilder` extend `source_contents` in separate loop (#4634) (overlookmotel) -- c7f1d48 sourcemap: Keep local copy of previous token in VLQ encode (#4596) (overlookmotel) -- 590d795 sourcemap: Shorten main loop encoding VLQ (#4586) (overlookmotel) - -## [0.23.0] - 2024-08-01 - -- 27fd062 sourcemap: [**BREAKING**] Avoid passing `Result`s (#4541) (overlookmotel) - -### Performance - -- d00014e sourcemap: Elide bounds checks in VLQ encoding (#4583) (overlookmotel) -- 1fd9dd0 sourcemap: Use simd to escape JSON string (#4487) (Brooooooklyn) - -### Refactor - -- 7c42ffc sourcemap: Align Base64 chars lookup table to cache line (#4535) (overlookmotel) - -## [0.22.1] - 2024-07-27 - -### Bug Fixes - -- 5db7bed sourcemap: Fix pre-calculation of required segments for building JSON (#4490) (overlookmotel) - -### Performance - -- 705e19f sourcemap: Reduce memory copies encoding JSON (#4489) (overlookmotel) -- 4d10c6c sourcemap: Pre allocate String buf while encoding (#4476) (Brooooooklyn) - -### Refactor - -- c958a55 sourcemap: `push_list` method for building JSON (#4486) (overlookmotel) - -## [0.22.0] - 2024-07-23 - -### Bug Fixes - -- 4cd5df0 sourcemap: Avoid negative line if token_chunks has same prev_dst_line (#4348) (underfin) - -## [0.21.0] - 2024-07-18 - -### Features - -- 205c259 sourcemap: Support SourceMapBuilder#token_chunks (#4220) (underfin) - -## [0.16.0] - 2024-06-26 - -### Features - -- 01572f0 sourcemap: Impl `std::fmt::Display` for `Error` (#3902) (DonIsaac)- d3cd3ea Oxc transform binding (#3896) (underfin) - -## [0.13.1] - 2024-05-22 - -### Features - -- 90d2d09 sourcemap: Add Sourcemap#from_json method (#3361) (underfin) - -### Bug Fixes -- 899a52b Fix some nightly warnings (Boshen) - -## [0.13.0] - 2024-05-14 - -### Features - -- f6daf0b sourcemap: Add feature "sourcemap_concurrent" (Boshen) -- 7363e14 sourcemap: Add "rayon" feature (#3198) (Boshen) - -## [0.12.3] - 2024-04-11 - -### Features - -- 8662f4f sourcemap: Add x_google_ignoreList (#2928) (underfin) -- 5cb3991 sourcemap: Add sourceRoot (#2926) (underfin) - -## [0.12.2] - 2024-04-08 - -### Features - -- 96f02e6 sourcemap: Optional JSONSourceMap fileds (#2910) (underfin) -- d87cf17 sourcemap: Add methods to mutate SourceMap (#2909) (underfin) -- 74aca1c sourcemap: Add SourceMapBuilder file (#2908) (underfin) - -## [0.12.1] - 2024-04-03 - -### Bug Fixes - -- 28fae2e sourcemap: Using serde_json::to_string to quote sourcemap string (#2889) (underfin) - -## [0.11.0] - 2024-03-30 - -### Features -- b199cb8 Add oxc sourcemap crate (#2825) (underfin) - -### Bug Fixes - -- 6177c2f codegen: Sourcemap token name should be original name (#2843) (underfin) - diff --git a/crates/oxc_sourcemap/Cargo.toml b/crates/oxc_sourcemap/Cargo.toml deleted file mode 100644 index 30c3818305355c..00000000000000 --- a/crates/oxc_sourcemap/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "oxc_sourcemap" -version = "0.38.0" -authors.workspace = true -categories.workspace = true -edition.workspace = true -homepage.workspace = true -include = ["/src"] -keywords.workspace = true -license.workspace = true -repository.workspace = true -rust-version.workspace = true -description.workspace = true - -[lints] -workspace = true - -[lib] -doctest = false - -[dependencies] -base64-simd = { workspace = true } -cfg-if = { workspace = true } -cow-utils = { workspace = true } -rustc-hash = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } - -rayon = { workspace = true, optional = true } - -[dev-dependencies] -insta = { workspace = true, features = ["glob"] } - -[features] -default = [] -concurrent = ["dep:rayon"] diff --git a/crates/oxc_sourcemap/README.md b/crates/oxc_sourcemap/README.md deleted file mode 100644 index 0d42da9b09b10c..00000000000000 --- a/crates/oxc_sourcemap/README.md +++ /dev/null @@ -1,4 +0,0 @@ -The sourcemap implement port from [rust-sourcemap](https://github.com/getsentry/rust-sourcemap), but has some different with it. - -- Encode sourcemap at parallel, including quote `sourceContent` and encode token to `vlq` mappings. -- Avoid `Sourcemap` some methods overhead, like `SourceMap::tokens()`. diff --git a/crates/oxc_sourcemap/src/concat_sourcemap_builder.rs b/crates/oxc_sourcemap/src/concat_sourcemap_builder.rs deleted file mode 100644 index 83820776aaa1cd..00000000000000 --- a/crates/oxc_sourcemap/src/concat_sourcemap_builder.rs +++ /dev/null @@ -1,234 +0,0 @@ -use std::sync::Arc; - -use crate::{token::TokenChunk, SourceMap, Token}; - -/// The `ConcatSourceMapBuilder` is a helper to concat sourcemaps. -#[derive(Debug, Default)] -pub struct ConcatSourceMapBuilder { - pub(crate) names: Vec>, - pub(crate) sources: Vec>, - pub(crate) source_contents: Vec>, - pub(crate) tokens: Vec, - /// The `token_chunks` is used for encode tokens to vlq mappings at parallel. - pub(crate) token_chunks: Vec, - pub(crate) token_chunk_prev_name_id: u32, -} - -#[allow(clippy::cast_possible_truncation)] -impl ConcatSourceMapBuilder { - /// Create new `ConcatSourceMapBuilder` with pre-allocated capacity. - /// - /// Allocating capacity before adding sourcemaps with `add_sourcemap` avoids memory copies - /// and increases performance. - /// - /// Alternatively, use `from_sourcemaps`. - pub fn with_capacity( - names_len: usize, - sources_len: usize, - tokens_len: usize, - token_chunks_len: usize, - ) -> Self { - Self { - names: Vec::with_capacity(names_len), - sources: Vec::with_capacity(sources_len), - source_contents: Vec::with_capacity(sources_len), - tokens: Vec::with_capacity(tokens_len), - token_chunks: Vec::with_capacity(token_chunks_len), - token_chunk_prev_name_id: 0, - } - } - - /// Create new `ConcatSourceMapBuilder` from an array of `SourceMap`s and line offsets. - /// - /// This avoids memory copies versus creating builder with `ConcatSourceMapBuilder::default()` - /// and then adding sourcemaps individually with `add_sourcemap`. - /// - /// # Example - /// ``` - /// let builder = ConcatSourceMapBuilder::from_sourcemaps(&[ - /// (&sourcemap1, 0), - /// (&sourcemap2, 100), - /// ]); - /// let combined_sourcemap = builder.into_sourcemap(); - /// ``` - pub fn from_sourcemaps(sourcemap_and_line_offsets: &[(&SourceMap, u32)]) -> Self { - // Calculate length of `Vec`s required - let mut names_len = 0; - let mut sources_len = 0; - let mut tokens_len = 0; - for (sourcemap, _) in sourcemap_and_line_offsets { - names_len += sourcemap.names.len(); - sources_len += sourcemap.sources.len(); - tokens_len += sourcemap.tokens.len(); - } - - let mut builder = Self::with_capacity( - names_len, - sources_len, - tokens_len, - sourcemap_and_line_offsets.len(), - ); - - for (sourcemap, line_offset) in sourcemap_and_line_offsets.iter().copied() { - builder.add_sourcemap(sourcemap, line_offset); - } - - builder - } - - pub fn add_sourcemap(&mut self, sourcemap: &SourceMap, line_offset: u32) { - let source_offset = self.sources.len() as u32; - let name_offset = self.names.len() as u32; - - // Add `token_chunks`, See `TokenChunk`. - if let Some(last_token) = self.tokens.last() { - self.token_chunks.push(TokenChunk::new( - self.tokens.len() as u32, - self.tokens.len() as u32 + sourcemap.tokens.len() as u32, - last_token.get_dst_line(), - last_token.get_dst_col(), - last_token.get_src_line(), - last_token.get_src_col(), - self.token_chunk_prev_name_id, - source_offset - 1, - )); - } else { - self.token_chunks.push(TokenChunk::new( - 0, - sourcemap.tokens.len() as u32, - 0, - 0, - 0, - 0, - 0, - 0, - )); - } - - // 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())); - } - - // Extend `names`. - self.names.reserve(sourcemap.names.len()); - self.names.extend(sourcemap.get_names().map(Into::into)); - - // Extend `tokens`. - self.tokens.reserve(sourcemap.tokens.len()); - let tokens = sourcemap.get_tokens().map(|token| { - Token::new( - token.get_dst_line() + line_offset, - token.get_dst_col(), - token.get_src_line(), - token.get_src_col(), - token.get_source_id().map(|x| x + source_offset), - token.get_name_id().map(|x| { - self.token_chunk_prev_name_id = x + name_offset; - self.token_chunk_prev_name_id - }), - ) - }); - self.tokens.extend(tokens); - } - - pub fn into_sourcemap(self) -> SourceMap { - SourceMap::new( - None, - self.names, - None, - self.sources, - Some(self.source_contents), - self.tokens, - Some(self.token_chunks), - ) - } -} - -#[test] -fn test_concat_sourcemap_builder() { - run_test(|sourcemap_and_line_offsets| { - let mut builder = ConcatSourceMapBuilder::default(); - for (sourcemap, line_offset) in sourcemap_and_line_offsets.iter().copied() { - builder.add_sourcemap(sourcemap, line_offset); - } - builder - }); -} - -#[test] -fn test_concat_sourcemap_builder_from_sourcemaps() { - run_test(ConcatSourceMapBuilder::from_sourcemaps); -} - -#[cfg(test)] -fn run_test(create_builder: F) -where - F: Fn(&[(&SourceMap, u32)]) -> ConcatSourceMapBuilder, -{ - let sm1 = SourceMap::new( - None, - vec!["foo".into(), "foo2".into()], - None, - vec!["foo.js".into()], - None, - vec![Token::new(1, 1, 1, 1, Some(0), Some(0))], - None, - ); - let sm2 = SourceMap::new( - None, - vec!["bar".into()], - None, - vec!["bar.js".into()], - None, - vec![Token::new(1, 1, 1, 1, Some(0), Some(0))], - None, - ); - let sm3 = SourceMap::new( - None, - vec!["abc".into()], - None, - vec!["abc.js".into()], - None, - vec![Token::new(1, 2, 2, 2, Some(0), Some(0))], - None, - ); - - let builder = create_builder(&[(&sm1, 0), (&sm2, 2), (&sm3, 2)]); - - let sm = SourceMap::new( - None, - vec!["foo".into(), "foo2".into(), "bar".into(), "abc".into()], - None, - vec!["foo.js".into(), "bar.js".into(), "abc.js".into()], - None, - vec![ - Token::new(1, 1, 1, 1, Some(0), Some(0)), - Token::new(3, 1, 1, 1, Some(1), Some(2)), - Token::new(3, 2, 2, 2, Some(2), Some(3)), - ], - None, - ); - let concat_sm = builder.into_sourcemap(); - - assert_eq!(concat_sm.tokens, sm.tokens); - assert_eq!(concat_sm.sources, sm.sources); - assert_eq!(concat_sm.names, sm.names); - assert_eq!( - concat_sm.token_chunks, - Some(vec![ - TokenChunk::new(0, 1, 0, 0, 0, 0, 0, 0,), - TokenChunk::new(1, 2, 1, 1, 1, 1, 0, 0,), - TokenChunk::new(2, 3, 3, 1, 1, 1, 2, 1,) - ]) - ); - - assert_eq!(sm.to_json().mappings, concat_sm.to_json().mappings); -} diff --git a/crates/oxc_sourcemap/src/decode.rs b/crates/oxc_sourcemap/src/decode.rs deleted file mode 100644 index 95ff8fff46bb74..00000000000000 --- a/crates/oxc_sourcemap/src/decode.rs +++ /dev/null @@ -1,179 +0,0 @@ -/// Port from https://github.com/getsentry/rust-sourcemap/blob/9.1.0/src/decoder.rs -/// It is a helper for decode vlq soucemap string to `SourceMap`. -use std::sync::Arc; - -use crate::error::{Error, Result}; -use crate::{SourceMap, Token}; - -/// See . -#[derive(serde::Deserialize, Default)] -#[serde(rename_all = "camelCase")] -pub struct JSONSourceMap { - /// An optional name of the generated code that this source map is associated with. - pub file: Option, - /// A string with the encoded mapping data. - pub mappings: String, - /// An optional source root, useful for relocating source files on a server or removing repeated values in the “sources” entry. - /// This value is prepended to the individual entries in the “source” field. - pub source_root: Option, - /// A list of original sources used by the “mappings” entry. - pub sources: Vec, - /// An optional list of source content, useful when the “source” can’t be hosted. - /// The contents are listed in the same order as the sources in line 5. “null” may be used if some original sources should be retrieved by name. - pub sources_content: Option>>, - /// A list of symbol names used by the “mappings” entry. - pub names: Vec, - /// An optional field containing the debugId for this sourcemap. - pub debug_id: Option, -} - -pub fn decode(json: JSONSourceMap) -> Result { - let tokens = decode_mapping(&json.mappings, json.names.len(), json.sources.len())?; - Ok(SourceMap { - file: json.file.map(Arc::from), - 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() - }), - tokens, - token_chunks: None, - x_google_ignore_list: None, - debug_id: json.debug_id, - }) -} - -pub fn decode_from_string(value: &str) -> Result { - decode(serde_json::from_str(value)?) -} - -#[allow(clippy::cast_possible_truncation)] -fn decode_mapping(mapping: &str, names_len: usize, sources_len: usize) -> Result> { - let mut tokens = vec![]; - - let mut dst_col; - let mut src_id = 0; - let mut src_line = 0; - let mut src_col = 0; - let mut name_id = 0; - let mut nums = Vec::with_capacity(6); - - for (dst_line, line) in mapping.split(';').enumerate() { - if line.is_empty() { - continue; - } - - dst_col = 0; - - for segment in line.split(',') { - if segment.is_empty() { - continue; - } - - nums.clear(); - parse_vlq_segment_into(segment, &mut nums)?; - dst_col = (i64::from(dst_col) + nums[0]) as u32; - - let mut src = !0; - let mut name = !0; - - if nums.len() > 1 { - if nums.len() != 4 && nums.len() != 5 { - return Err(Error::BadSegmentSize(nums.len() as u32)); - } - src_id = (i64::from(src_id) + nums[1]) as u32; - if src_id >= sources_len as u32 { - return Err(Error::BadSourceReference(src_id)); - } - - src = src_id; - src_line = (i64::from(src_line) + nums[2]) as u32; - src_col = (i64::from(src_col) + nums[3]) as u32; - - if nums.len() > 4 { - name_id = (i64::from(name_id) + nums[4]) as u32; - if name_id >= names_len as u32 { - return Err(Error::BadNameReference(name_id)); - } - name = name_id; - } - } - - tokens.push(Token::new( - dst_line as u32, - dst_col, - src_line, - src_col, - if src == !0 { None } else { Some(src) }, - if name == !0 { None } else { Some(name) }, - )); - } - } - - Ok(tokens) -} - -#[rustfmt::skip] -const B64: [i8; 256] = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 - 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, ]; - -fn parse_vlq_segment_into(segment: &str, rv: &mut Vec) -> Result<()> { - let mut cur = 0; - let mut shift = 0; - - for c in segment.bytes() { - let enc = i64::from(B64[c as usize]); - let val = enc & 0b11111; - let cont = enc >> 5; - cur += val.checked_shl(shift).ok_or(Error::VlqOverflow)?; - shift += 5; - - if cont == 0 { - let sign = cur & 1; - cur >>= 1; - if sign != 0 { - cur = -cur; - } - rv.push(cur); - cur = 0; - shift = 0; - } - } - - if cur != 0 || shift != 0 { - Err(Error::VlqLeftover) - } else if rv.is_empty() { - Err(Error::VlqNoValues) - } else { - Ok(()) - } -} - -#[test] -fn test_decode_sourcemap() { - let input = r#"{ - "version": 3, - "sources": ["coolstuff.js"], - "sourceRoot": "x", - "names": ["x","alert"], - "mappings": "AAAA,GAAIA,GAAI,EACR,IAAIA,GAAK,EAAG,CACVC,MAAM" - }"#; - let sm = SourceMap::from_json_string(input).unwrap(); - assert_eq!(sm.get_source_root(), Some("x")); - let mut iter = sm.get_source_view_tokens().filter(|token| token.get_name_id().is_some()); - assert_eq!(iter.next().unwrap().to_tuple(), (Some("coolstuff.js"), 0, 4, Some("x"))); - assert_eq!(iter.next().unwrap().to_tuple(), (Some("coolstuff.js"), 1, 4, Some("x"))); - assert_eq!(iter.next().unwrap().to_tuple(), (Some("coolstuff.js"), 2, 2, Some("alert"))); - assert!(iter.next().is_none()); -} - -#[test] -fn test_decode_sourcemap_optional_filed() { - let input = r#"{ - "names": [], - "sources": [], - "sourcesContent": [null], - "mappings": "" - }"#; - SourceMap::from_json_string(input).expect("should success"); -} diff --git a/crates/oxc_sourcemap/src/encode.rs b/crates/oxc_sourcemap/src/encode.rs deleted file mode 100644 index 7bc27686a2068f..00000000000000 --- a/crates/oxc_sourcemap/src/encode.rs +++ /dev/null @@ -1,464 +0,0 @@ -use std::borrow::Cow; - -#[cfg(feature = "concurrent")] -use rayon::prelude::*; - -use crate::JSONSourceMap; -/// Port from https://github.com/getsentry/rust-sourcemap/blob/9.1.0/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}; - -pub fn encode(sourcemap: &SourceMap) -> JSONSourceMap { - JSONSourceMap { - file: sourcemap.get_file().map(ToString::to_string), - 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()), - names: sourcemap.names.iter().map(ToString::to_string).collect(), - debug_id: sourcemap.get_debug_id().map(ToString::to_string), - } -} - -// 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.x_google_ignore_list.as_ref().map_or(0, |x| x.len() * 2 + 1); - let mut contents = PreAllocatedString::new(max_segments); - - contents.push("{\"version\":3,".into()); - if let Some(file) = sourcemap.get_file() { - contents.push("\"file\":\"".into()); - contents.push(file.into()); - contents.push("\",".into()); - } - - if let Some(source_root) = sourcemap.get_source_root() { - contents.push("\"sourceRoot\":\"".into()); - contents.push(source_root.into()); - contents.push("\",".into()); - } - - contents.push("\"names\":[".into()); - contents.push_list(sourcemap.names.iter().map(escape_json_string)); - - contents.push("],\"sources\":[".into()); - 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 = "concurrent")] { - 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)); - } - }; - } - - if let Some(x_google_ignore_list) = &sourcemap.x_google_ignore_list { - contents.push("],\"x_google_ignoreList\":[".into()); - contents.push_list(x_google_ignore_list.iter().map(ToString::to_string)); - } - - contents.push("],\"mappings\":\"".into()); - contents.push(serialize_sourcemap_mappings(sourcemap).into()); - - if let Some(debug_id) = sourcemap.get_debug_id() { - contents.push("\",\"debugId\":\"".into()); - contents.push(debug_id.into()); - } - - contents.push("\"}".into()); - - // Check we calculated number of segments required correctly - debug_assert!(contents.num_segments() <= max_segments); - - contents.consume() -} - -#[allow(clippy::cast_possible_truncation)] -fn serialize_sourcemap_mappings(sm: &SourceMap) -> String { - sm.token_chunks.as_ref().map_or_else( - || { - serialize_mappings( - &sm.tokens, - &TokenChunk::new(0, sm.tokens.len() as u32, 0, 0, 0, 0, 0, 0), - ) - }, - |token_chunks| { - // Serialize `tokens` to vlq `mappings` at parallel. - cfg_if::cfg_if! { - if #[cfg(feature = "concurrent")] { - token_chunks - .par_iter() - .map(|token_chunk| serialize_mappings(&sm.tokens, token_chunk)) - .collect::() - } else { - token_chunks - .iter() - .map(|token_chunk| serialize_mappings(&sm.tokens, token_chunk)) - .collect::() - } - } - }, - ) -} - -// Max length of a single VLQ encoding -const MAX_VLQ_BYTES: usize = 7; - -fn serialize_mappings(tokens: &[Token], token_chunk: &TokenChunk) -> String { - let TokenChunk { - start, - end, - mut prev_dst_line, - mut prev_dst_col, - mut prev_src_line, - mut prev_src_col, - mut prev_name_id, - mut prev_source_id, - } = *token_chunk; - - let capacity = ((end - start) * 10) as usize; - - let mut rv = String::with_capacity(capacity); - - let mut prev_token = if start == 0 { None } else { Some(&tokens[start as usize - 1]) }; - - for token in &tokens[start as usize..end as usize] { - // Max length of a single VLQ encoding is 7 bytes. Max number of calls to `encode_vlq_diff` is 5. - // Also need 1 byte for each line number difference, or 1 byte if no line num difference. - // Reserve this amount of capacity in `rv` early, so can skip bounds checks in code below. - // As well as skipping the bounds checks, this also removes a function call to - // `alloc::raw_vec::RawVec::grow_one` for every byte that's pushed. - // https://godbolt.org/z/44G8jjss3 - const MAX_TOTAL_VLQ_BYTES: usize = 5 * MAX_VLQ_BYTES; - - let num_line_breaks = token.get_dst_line() - prev_dst_line; - if num_line_breaks != 0 { - rv.reserve(MAX_TOTAL_VLQ_BYTES + num_line_breaks as usize); - // SAFETY: We have reserved sufficient capacity for `num_line_breaks` bytes - unsafe { push_bytes_unchecked(&mut rv, b';', num_line_breaks) }; - prev_dst_col = 0; - prev_dst_line += num_line_breaks; - } else if let Some(prev_token) = prev_token { - if prev_token == token { - continue; - } - rv.reserve(MAX_TOTAL_VLQ_BYTES + 1); - // SAFETY: We have reserved sufficient capacity for 1 byte - unsafe { push_byte_unchecked(&mut rv, b',') }; - } - - // SAFETY: We have reserved enough capacity above to satisfy safety contract - // of `encode_vlq_diff` for all calls below - unsafe { - encode_vlq_diff(&mut rv, token.get_dst_col(), prev_dst_col); - prev_dst_col = token.get_dst_col(); - - if let Some(source_id) = token.get_source_id() { - encode_vlq_diff(&mut rv, source_id, prev_source_id); - prev_source_id = source_id; - encode_vlq_diff(&mut rv, token.get_src_line(), prev_src_line); - prev_src_line = token.get_src_line(); - encode_vlq_diff(&mut rv, token.get_src_col(), prev_src_col); - prev_src_col = token.get_src_col(); - if let Some(name_id) = token.get_name_id() { - encode_vlq_diff(&mut rv, name_id, prev_name_id); - prev_name_id = name_id; - } - } - } - - prev_token = Some(token); - } - - rv -} - -/// Encode diff as VLQ and push encoding into `out`. -/// Will push between 1 byte (num = 0) and 7 bytes (num = -u32::MAX). -/// -/// # SAFETY -/// Caller must ensure at least 7 bytes spare capacity in `out`, -/// as this function does not perform any bounds checks. -#[inline] -unsafe fn encode_vlq_diff(out: &mut String, a: u32, b: u32) { - encode_vlq(out, i64::from(a) - i64::from(b)); -} - -// Align chars lookup table on 64 so occupies a single cache line -#[repr(align(64))] -struct Aligned64([u8; 64]); - -static B64_CHARS: Aligned64 = Aligned64([ - b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', - b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', - b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', - b'w', b'x', b'y', b'z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'+', b'/', -]); - -/// Encode number as VLQ and push encoding into `out`. -/// Will push between 1 byte (num = 0) and 7 bytes (num = -u32::MAX). -/// -/// # SAFETY -/// Caller must ensure at least 7 bytes spare capacity in `out`, -/// as this function does not perform any bounds checks. -#[allow( - clippy::cast_possible_truncation, - clippy::cast_sign_loss, - clippy::unnecessary_safety_comment -)] -unsafe fn encode_vlq(out: &mut String, num: i64) { - let mut num = if num < 0 { ((-num) << 1) + 1 } else { num << 1 }; - - // Breaking out of loop early when have reached last char (rather than conditionally adding - // 32 for last char within the loop) removes 3 instructions from the loop. - // https://godbolt.org/z/Es4Pavh9j - // This translates to a 16% speed-up for VLQ encoding. - let mut digit; - loop { - digit = num & 0b11111; - num >>= 5; - if num == 0 { - break; - } - - let b = B64_CHARS.0[digit as usize + 32]; - // SAFETY: - // * This loop can execute a maximum of 7 times, and on last turn will exit before getting here. - // Caller promises there are at least 7 bytes spare capacity in `out` at start. We only - // push 1 byte on each turn, so guaranteed there is at least 1 byte capacity in `out` here. - // * All values in `B64_CHARS` lookup table are ASCII bytes. - push_byte_unchecked(out, b); - } - - let b = B64_CHARS.0[digit as usize]; - // SAFETY: - // * The loop above pushes max 6 bytes. Caller promises there are at least 7 bytes spare capacity - // in `out` at start. So guaranteed there is at least 1 byte capacity in `out` here. - // * All values in `B64_CHARS` lookup table are ASCII bytes. - push_byte_unchecked(out, b); -} - -/// Push a byte to `out` without bounds checking. -/// -/// # SAFETY -/// * `out` must have at least 1 byte spare capacity. -/// * `b` must be an ASCII byte (i.e. not `>= 128`). -// -// `#[inline(always)]` to ensure that `len` is stored in a register during `encode_vlq`'s loop. -#[allow(clippy::inline_always)] -#[inline(always)] -unsafe fn push_byte_unchecked(out: &mut String, b: u8) { - debug_assert!(out.len() < out.capacity()); - debug_assert!(b.is_ascii()); - - let out = out.as_mut_vec(); - let len = out.len(); - let ptr = out.as_mut_ptr().add(len); - ptr.write(b); - out.set_len(len + 1); -} - -/// Push a byte to `out` a number of times without bounds checking. -/// -/// # SAFETY -/// * `out` must have at least `repeats` bytes spare capacity. -/// * `b` must be an ASCII byte (i.e. not `>= 128`). -#[inline] -unsafe fn push_bytes_unchecked(out: &mut String, b: u8, repeats: u32) { - debug_assert!(out.capacity() - out.len() >= repeats as usize); - debug_assert!(b.is_ascii()); - - let out = out.as_mut_vec(); - let len = out.len(); - let mut ptr = out.as_mut_ptr().add(len); - for _ in 0..repeats { - ptr.write(b); - ptr = ptr.add(1); - } - out.set_len(len + repeats as usize); -} - -/// A helper for pre-allocate string buffer. -/// -/// Pre-allocate a Cow<'a, str> buffer, and push the segment into it. -/// Finally, convert it to a pre-allocated length String. -struct PreAllocatedString<'a> { - buf: Vec>, - len: usize, -} - -impl<'a> PreAllocatedString<'a> { - fn new(max_segments: usize) -> Self { - Self { buf: Vec::with_capacity(max_segments), len: 0 } - } - - #[inline] - fn push(&mut self, s: Cow<'a, str>) { - self.len += s.len(); - self.buf.push(s); - } - - #[inline] - fn push_list(&mut self, mut iter: I) - where - I: Iterator, - { - let Some(first) = iter.next() else { - return; - }; - self.push(Cow::Owned(first)); - - for other in iter { - self.push(Cow::Borrowed(",")); - self.push(Cow::Owned(other)); - } - } - - #[inline] - fn consume(self) -> String { - let mut buf = String::with_capacity(self.len); - buf.extend(self.buf); - buf - } - - fn num_segments(&self) -> usize { - self.buf.len() - } -} - -fn escape_json_string>(s: S) -> String { - let s = s.as_ref(); - let mut escaped_buf = Vec::with_capacity(s.len() * 2 + 2); - // This call is infallible as only error it can return is if the writer errors. - // Writing to a `Vec` is infallible, so that's not possible here. - serde::Serialize::serialize(s, &mut serde_json::Serializer::new(&mut escaped_buf)).unwrap(); - // Safety: `escaped_buf` is valid utf8. - unsafe { String::from_utf8_unchecked(escaped_buf) } -} - -#[test] -fn test_escape_json_string() { - const FIXTURES: &[(char, &str)] = &[ - ('n', "\"n\""), - ('"', "\"\\\"\""), - ('\\', "\"\\\\\""), - ('/', "\"/\""), - ('\x08', "\"\\b\""), - ('\x0C', "\"\\f\""), - ('\n', "\"\\n\""), - ('\r', "\"\\r\""), - ('\t', "\"\\t\""), - ('\x0B', "\"\\u000b\""), - ('虎', "\"虎\""), - ('\u{3A3}', "\"\u{3A3}\""), - ]; - - for (c, expected) in FIXTURES { - let mut input = String::new(); - input.push(*c); - assert_eq!(escape_json_string(input), *expected); - } -} - -#[test] -fn test_encode() { - let input = r#"{ - "version": 3, - "sources": ["coolstuff.js"], - "sourceRoot": "x", - "names": ["x","alert"], - "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(); - - 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 mut sm = SourceMap::new( - None, - vec!["name_length_greater_than_16_\0".into()], - None, - vec!["\0".into()], - Some(vec!["emoji-👀-\0".into()]), - vec![], - None, - ); - sm.set_x_google_ignore_list(vec![0]); - sm.set_debug_id("56431d54-c0a6-451d-8ea2-ba5de5d8ca2e"); - assert_eq!( - sm.to_json_string(), - r#"{"version":3,"names":["name_length_greater_than_16_\u0000"],"sources":["\u0000"],"sourcesContent":["emoji-👀-\u0000"],"x_google_ignoreList":[0],"mappings":"","debugId":"56431d54-c0a6-451d-8ea2-ba5de5d8ca2e"}"# - ); -} - -#[test] -fn test_vlq_encode_diff() { - // Most import tests here are that with maximum values, `encode_vlq_diff` pushes maximum of 7 bytes. - // This invariant is essential to safety of `encode_vlq_diff`. - #[rustfmt::skip] - const FIXTURES: &[(u32, u32, &str)] = &[ - (0, 0, "A"), - (1, 0, "C"), - (2, 0, "E"), - (15, 0, "e"), - (16, 0, "gB"), - (511, 0, "+f"), - (512, 0, "ggB"), - (16_383, 0, "+/f"), - (16_384, 0, "gggB"), - (524_287, 0, "+//f"), - (524_288, 0, "ggggB"), - (16_777_215, 0, "+///f"), - (16_777_216, 0, "gggggB"), - (536_870_911, 0, "+////f"), - (536_870_912, 0, "ggggggB"), - (u32::MAX, 0, "+/////H"), // 7 bytes - - (0, 1, "D"), - (0, 2, "F"), - (0, 15, "f"), - (0, 16, "hB"), - (0, 511, "/f"), - (0, 512, "hgB"), - (0, 16_383, "//f"), - (0, 16_384, "hggB"), - (0, 524_287, "///f"), - (0, 524_288, "hgggB"), - (0, 16_777_215, "////f"), - (0, 16_777_216, "hggggB"), - (0, 536_870_911, "/////f"), - (0, 536_870_912, "hgggggB"), - (0, u32::MAX, "//////H"), // 7 bytes - ]; - - for (a, b, res) in FIXTURES.iter().copied() { - let mut out = String::with_capacity(MAX_VLQ_BYTES); - // SAFETY: `out` has 7 bytes spare capacity - unsafe { encode_vlq_diff(&mut out, a, b) }; - assert_eq!(&out, res); - } -} diff --git a/crates/oxc_sourcemap/src/error.rs b/crates/oxc_sourcemap/src/error.rs deleted file mode 100644 index d2aadb96fb1336..00000000000000 --- a/crates/oxc_sourcemap/src/error.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::{error, fmt}; - -#[derive(Debug)] -pub enum Error { - /// a VLQ string was malformed and data was left over - VlqLeftover, - /// a VLQ string was empty and no values could be decoded. - VlqNoValues, - /// The input encoded a number that didn't fit into i64. - VlqOverflow, - /// `serde_json` parsing failure - BadJson(serde_json::Error), - /// a mapping segment had an unsupported size - BadSegmentSize(u32), - /// a reference to a non existing source was encountered - BadSourceReference(u32), - /// a reference to a non existing name was encountered - BadNameReference(u32), -} -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Error::VlqLeftover => write!(f, "VLQ string was malformed and data was left over"), - Error::VlqNoValues => write!(f, "VLQ string was empty and no values could be decoded"), - Error::VlqOverflow => write!(f, "The input encoded a number that didn't fit into i64"), - Error::BadJson(err) => write!(f, "JSON parsing error: {err}"), - Error::BadSegmentSize(size) => { - write!(f, "Mapping segment had an unsupported size of {size}") - } - Error::BadSourceReference(idx) => { - write!(f, "Reference to non-existing source at position {idx}") - } - Error::BadNameReference(idx) => { - write!(f, "Reference to non-existing name at position {idx}") - } - } - } -} - -impl error::Error for Error { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - if let Self::BadJson(err) = self { - Some(err) - } else { - None - } - } -} - -/// The result of decoding. -pub type Result = std::result::Result; - -impl From for Error { - fn from(err: serde_json::Error) -> Error { - Error::BadJson(err) - } -} diff --git a/crates/oxc_sourcemap/src/lib.rs b/crates/oxc_sourcemap/src/lib.rs deleted file mode 100644 index c981abbf298582..00000000000000 --- a/crates/oxc_sourcemap/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod concat_sourcemap_builder; -#[allow(clippy::cast_sign_loss)] -mod decode; -mod encode; -mod error; -mod sourcemap; -mod sourcemap_builder; -mod sourcemap_visualizer; -mod token; - -pub use concat_sourcemap_builder::ConcatSourceMapBuilder; -pub use decode::JSONSourceMap; -pub use error::Error; -pub use sourcemap::SourceMap; -pub use sourcemap_builder::SourceMapBuilder; -pub use sourcemap_visualizer::SourcemapVisualizer; -pub use token::{SourceViewToken, Token, TokenChunk}; diff --git a/crates/oxc_sourcemap/src/sourcemap.rs b/crates/oxc_sourcemap/src/sourcemap.rs deleted file mode 100644 index 4e1e532252d4b2..00000000000000 --- a/crates/oxc_sourcemap/src/sourcemap.rs +++ /dev/null @@ -1,289 +0,0 @@ -use std::sync::Arc; - -use crate::{ - decode::{decode, decode_from_string, JSONSourceMap}, - encode::{encode, encode_to_string}, - error::Result, - token::{Token, TokenChunk}, - SourceViewToken, -}; - -#[derive(Debug, Clone, Default)] -pub struct SourceMap { - pub(crate) file: Option>, - pub(crate) names: Vec>, - pub(crate) source_root: Option, - pub(crate) sources: Vec>, - pub(crate) source_contents: Option>>, - pub(crate) tokens: Vec, - pub(crate) token_chunks: Option>, - /// 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. - /// The `x_google_ignoreList` field refers to the `sources` array, and lists the indices of all the known third-party sources in that source map. - /// When parsing the source map, developer tools can use this to determine sections of the code that the browser loads and runs that could be automatically ignore-listed. - pub(crate) x_google_ignore_list: Option>, - pub(crate) debug_id: Option, -} - -#[allow(clippy::cast_possible_truncation)] -impl SourceMap { - pub fn new( - file: Option>, - names: Vec>, - source_root: Option, - sources: Vec>, - source_contents: Option>>, - tokens: Vec, - token_chunks: Option>, - ) -> Self { - Self { - file, - names, - source_root, - sources, - source_contents, - tokens, - token_chunks, - x_google_ignore_list: None, - debug_id: None, - } - } - - /// Convert the vlq sourcemap to to `SourceMap`. - /// # Errors - /// - /// The `serde_json` deserialize Error. - pub fn from_json(value: JSONSourceMap) -> Result { - decode(value) - } - - /// Convert the vlq sourcemap string to `SourceMap`. - /// # Errors - /// - /// The `serde_json` deserialize Error. - pub fn from_json_string(value: &str) -> Result { - decode_from_string(value) - } - - /// Convert `SourceMap` to vlq sourcemap. - pub fn to_json(&self) -> JSONSourceMap { - encode(self) - } - - /// Convert `SourceMap` to vlq sourcemap string. - pub fn to_json_string(&self) -> String { - encode_to_string(self) - } - - /// Convert `SourceMap` to vlq sourcemap data url. - pub fn to_data_url(&self) -> String { - let base_64_str = base64_simd::STANDARD.encode_to_string(self.to_json_string().as_bytes()); - format!("data:application/json;charset=utf-8;base64,{base_64_str}") - } - - pub fn get_file(&self) -> Option<&str> { - self.file.as_deref() - } - - pub fn set_file(&mut self, file: &str) { - self.file = Some(file.into()); - } - - pub fn get_source_root(&self) -> Option<&str> { - self.source_root.as_deref() - } - - /// Set `x_google_ignoreList`. - pub fn set_x_google_ignore_list(&mut self, x_google_ignore_list: Vec) { - self.x_google_ignore_list = Some(x_google_ignore_list); - } - - pub fn set_debug_id(&mut self, debug_id: &str) { - self.debug_id = Some(debug_id.into()); - } - - pub fn get_debug_id(&self) -> Option<&str> { - self.debug_id.as_deref() - } - - pub fn get_names(&self) -> impl Iterator { - self.names.iter().map(AsRef::as_ref) - } - - /// Adjust `sources`. - pub fn set_sources(&mut self, sources: Vec<&str>) { - self.sources = sources.into_iter().map(Into::into).collect(); - } - - pub fn get_sources(&self) -> impl Iterator { - self.sources.iter().map(AsRef::as_ref) - } - - /// 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 get_source_contents(&self) -> Option> { - self.source_contents.as_ref().map(|v| v.iter().map(AsRef::as_ref)) - } - - pub fn get_token(&self, index: u32) -> Option<&Token> { - self.tokens.get(index as usize) - } - - pub fn get_source_view_token(&self, index: u32) -> Option> { - self.tokens.get(index as usize).map(|token| SourceViewToken::new(token, self)) - } - - /// Get raw tokens. - pub fn get_tokens(&self) -> impl Iterator { - self.tokens.iter() - } - - /// Get source view tokens. See [`SourceViewToken`] for more information. - pub fn get_source_view_tokens(&self) -> impl Iterator> { - self.tokens.iter().map(|token| SourceViewToken::new(token, self)) - } - - pub fn get_name(&self, id: u32) -> Option<&str> { - self.names.get(id as usize).map(AsRef::as_ref) - } - - pub fn get_source(&self, id: u32) -> Option<&str> { - self.sources.get(id as usize).map(AsRef::as_ref) - } - - 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)) - } - - pub fn get_source_and_content(&self, id: u32) -> Option<(&str, &str)> { - let source = self.get_source(id)?; - let content = self.get_source_content(id)?; - Some((source, content)) - } - - /// Generate a lookup table, it will be used at `lookup_token` or `lookup_source_view_token`. - pub fn generate_lookup_table(&self) -> Vec<(u32, u32, u32)> { - let mut table = self - .tokens - .iter() - .enumerate() - .map(|(idx, token)| (token.dst_line, token.dst_col, idx as u32)) - .collect::>(); - table.sort_unstable(); - table - } - - /// Lookup a token by line and column, it will used at remapping. - pub fn lookup_token( - &self, - lookup_table: &[(u32, u32, u32)], - line: u32, - col: u32, - ) -> Option<&Token> { - let table = greatest_lower_bound(lookup_table, &(line, col), |table| (table.0, table.1))?; - self.get_token(table.2) - } - - /// Lookup a token by line and column, it will used at remapping. See `SourceViewToken`. - pub fn lookup_source_view_token( - &self, - lookup_table: &[(u32, u32, u32)], - line: u32, - col: u32, - ) -> Option> { - self.lookup_token(lookup_table, line, col).map(|token| SourceViewToken::new(token, self)) - } -} - -fn greatest_lower_bound<'a, T, K: Ord, F: Fn(&'a T) -> K>( - slice: &'a [T], - key: &K, - map: F, -) -> Option<&'a T> { - let mut idx = match slice.binary_search_by_key(key, &map) { - Ok(index) => index, - Err(index) => { - // If there is no match, then we know for certain that the index is where we should - // insert a new token, and that the token directly before is the greatest lower bound. - return slice.get(index.checked_sub(1)?); - } - }; - - // If we get an exact match, then we need to continue looking at previous tokens to see if - // they also match. We use a linear search because the number of exact matches is generally - // very small, and almost certainly smaller than the number of tokens before the index. - for i in (0..idx).rev() { - if map(&slice[i]) == *key { - idx = i; - } else { - break; - } - } - slice.get(idx) -} - -#[test] -fn test_sourcemap_lookup_token() { - let input = r#"{ - "version": 3, - "sources": ["coolstuff.js"], - "sourceRoot": "x", - "names": ["x","alert"], - "mappings": "AAAA,GAAIA,GAAI,EACR,IAAIA,GAAK,EAAG,CACVC,MAAM" - }"#; - let sm = SourceMap::from_json_string(input).unwrap(); - let lookup_table = sm.generate_lookup_table(); - assert_eq!( - sm.lookup_source_view_token(&lookup_table, 0, 0).unwrap().to_tuple(), - (Some("coolstuff.js"), 0, 0, None) - ); - assert_eq!( - sm.lookup_source_view_token(&lookup_table, 0, 3).unwrap().to_tuple(), - (Some("coolstuff.js"), 0, 4, Some("x")) - ); - assert_eq!( - sm.lookup_source_view_token(&lookup_table, 0, 24).unwrap().to_tuple(), - (Some("coolstuff.js"), 2, 8, None) - ); - - // Lines continue out to infinity - assert_eq!( - sm.lookup_source_view_token(&lookup_table, 0, 1000).unwrap().to_tuple(), - (Some("coolstuff.js"), 2, 8, None) - ); - - // Token can return prior lines. - assert_eq!( - sm.lookup_source_view_token(&lookup_table, 1000, 0).unwrap().to_tuple(), - (Some("coolstuff.js"), 2, 8, None) - ); -} - -#[test] -fn test_sourcemap_source_view_token() { - let sm = SourceMap::new( - None, - vec!["foo".into()], - None, - vec!["foo.js".into()], - None, - vec![Token::new(1, 1, 1, 1, Some(0), Some(0))], - None, - ); - let mut source_view_tokens = sm.get_source_view_tokens(); - assert_eq!(source_view_tokens.next().unwrap().to_tuple(), (Some("foo.js"), 1, 1, Some("foo"))); -} - -#[test] -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"]); - - assert_eq!(sm.get_file(), Some("index.js")); - assert_eq!(sm.get_source(0), Some("foo.js")); - assert_eq!(sm.get_source_content(0), Some("foo")); -} diff --git a/crates/oxc_sourcemap/src/sourcemap_builder.rs b/crates/oxc_sourcemap/src/sourcemap_builder.rs deleted file mode 100644 index 7455216b30ded4..00000000000000 --- a/crates/oxc_sourcemap/src/sourcemap_builder.rs +++ /dev/null @@ -1,105 +0,0 @@ -use std::sync::Arc; - -use rustc_hash::FxHashMap; - -use crate::{ - token::{Token, TokenChunk}, - SourceMap, -}; - -/// The `SourceMapBuilder` is a helper to generate sourcemap. -#[derive(Debug, Default)] -pub struct SourceMapBuilder { - pub(crate) file: Option>, - pub(crate) names_map: FxHashMap, u32>, - pub(crate) names: Vec>, - pub(crate) sources: Vec>, - pub(crate) sources_map: FxHashMap, u32>, - pub(crate) source_contents: Vec>, - pub(crate) tokens: Vec, - pub(crate) token_chunks: Option>, -} - -#[allow(clippy::cast_possible_truncation)] -impl SourceMapBuilder { - /// Add item to `SourceMap::name`. - pub fn add_name(&mut self, name: &str) -> u32 { - let count = self.names.len() as u32; - let id = *self.names_map.entry(name.into()).or_insert(count); - if id == count { - self.names.push(name.into()); - } - id - } - - /// Add item to `SourceMap::sources` and `SourceMap::source_contents`. - /// If `source` maybe duplicate, please use it. - pub fn add_source_and_content(&mut self, source: &str, source_content: &str) -> u32 { - let count = self.sources.len() as u32; - 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()); - } - id - } - - /// Add item to `SourceMap::sources` and `SourceMap::source_contents`. - /// If `source` hasn't duplicate,it will avoid extra hash calculation. - 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()); - count - } - - /// Add item to `SourceMap::tokens`. - pub fn add_token( - &mut self, - dst_line: u32, - dst_col: u32, - src_line: u32, - src_col: u32, - src_id: Option, - name_id: Option, - ) { - self.tokens.push(Token::new(dst_line, dst_col, src_line, src_col, src_id, name_id)); - } - - pub fn set_file(&mut self, file: &str) { - self.file = Some(file.into()); - } - - /// Set the `SourceMap::token_chunks` to make the sourcemap to vlq mapping at parallel. - pub fn set_token_chunks(&mut self, token_chunks: Vec) { - self.token_chunks = Some(token_chunks); - } - - pub fn into_sourcemap(self) -> SourceMap { - SourceMap::new( - self.file, - self.names, - None, - self.sources, - Some(self.source_contents), - self.tokens, - self.token_chunks, - ) - } -} - -#[test] -fn test_sourcemap_builder() { - let mut builder = SourceMapBuilder::default(); - builder.set_source_and_content("baz.js", ""); - builder.add_name("x"); - builder.set_file("file"); - - let sm = builder.into_sourcemap(); - assert_eq!(sm.get_source(0), Some("baz.js")); - assert_eq!(sm.get_name(0), Some("x")); - assert_eq!(sm.get_file(), Some("file")); - - let expected = r#"{"version":3,"file":"file","names":["x"],"sources":["baz.js"],"sourcesContent":[""],"mappings":""}"#; - assert_eq!(expected, sm.to_json_string()); -} diff --git a/crates/oxc_sourcemap/src/sourcemap_visualizer.rs b/crates/oxc_sourcemap/src/sourcemap_visualizer.rs deleted file mode 100644 index 8637d4755a48b5..00000000000000 --- a/crates/oxc_sourcemap/src/sourcemap_visualizer.rs +++ /dev/null @@ -1,162 +0,0 @@ -use std::borrow::Cow; - -use rustc_hash::FxHashMap; - -use crate::SourceMap; -use cow_utils::CowUtils; - -/// The `SourcemapVisualizer` is a helper for sourcemap testing. -/// It print the mapping of original content and final content tokens. -pub struct SourcemapVisualizer<'a> { - output: &'a str, - sourcemap: &'a SourceMap, -} - -impl<'a> SourcemapVisualizer<'a> { - pub fn new(output: &'a str, sourcemap: &'a SourceMap) -> Self { - Self { output, sourcemap } - } - - #[allow(clippy::cast_possible_truncation)] - pub fn into_visualizer_text(self) -> String { - let source_contents_lines_map: FxHashMap>>> = self - .sourcemap - .get_sources() - .enumerate() - .map(|(source_id, source)| { - ( - source.to_string(), - self.sourcemap - .get_source_content(source_id as u32) - .map(Self::generate_line_utf16_tables), - ) - }) - .collect(); - let output_lines = Self::generate_line_utf16_tables(self.output); - - let mut s = String::new(); - - let tokens = &self.sourcemap.tokens; - - let mut last_source: Option<&str> = None; - for i in 0..tokens.len() { - let t = &tokens[i]; - let Some(source_id) = t.source_id else { continue }; - let Some(source) = self.sourcemap.get_source(source_id) else { continue }; - let Some(source_contents_lines) = source_contents_lines_map[source].as_ref() else { - continue; - }; - - // find next dst column or EOL - let dst_end_col = { - match tokens.get(i + 1) { - Some(t2) if t2.dst_line == t.dst_line => t2.dst_col, - _ => output_lines[t.dst_line as usize].len() as u32, - } - }; - - // find next src column or EOL - let src_end_col = 'result: { - for t2 in &tokens[i + 1..] { - if t2.source_id == t.source_id && t2.src_line == t.src_line { - // skip duplicate or backward - if t2.src_col <= t.src_col { - continue; - } - break 'result t2.src_col; - } - break; - } - source_contents_lines[t.src_line as usize].len() as u32 - }; - - // Print source - if last_source != Some(source) { - s.push('-'); - s.push(' '); - s.push_str(source); - s.push('\n'); - last_source = Some(source); - } - - s.push_str(&format!( - "({}:{}) {:?}", - t.src_line, - t.src_col, - Self::str_slice_by_token( - source_contents_lines, - (t.src_line, t.src_col), - (t.src_line, src_end_col) - ) - )); - - s.push_str(" --> "); - - s.push_str(&format!( - "({}:{}) {:?}", - t.dst_line, - t.dst_col, - Self::str_slice_by_token( - &output_lines, - (t.dst_line, t.dst_col), - (t.dst_line, dst_end_col) - ) - )); - s.push('\n'); - } - - s - } - - fn generate_line_utf16_tables(content: &str) -> Vec> { - let mut tables = vec![]; - let mut line_byte_offset = 0; - for (i, ch) in content.char_indices() { - match ch { - '\r' | '\n' | '\u{2028}' | '\u{2029}' => { - // Handle Windows-specific "\r\n" newlines - if ch == '\r' && content.chars().nth(i + 1) == Some('\n') { - continue; - } - tables.push(content[line_byte_offset..=i].encode_utf16().collect::>()); - line_byte_offset = i + 1; - } - _ => {} - } - } - tables.push(content[line_byte_offset..].encode_utf16().collect::>()); - tables - } - - fn str_slice_by_token(buff: &[Vec], start: (u32, u32), end: (u32, u32)) -> Cow<'_, str> { - if start.0 == end.0 { - if start.1 <= end.1 { - return Cow::Owned( - String::from_utf16(&buff[start.0 as usize][start.1 as usize..end.1 as usize]) - .unwrap(), - ); - } - return Cow::Owned( - String::from_utf16(&buff[start.0 as usize][end.1 as usize..start.1 as usize]) - .unwrap(), - ); - } - - let mut s = String::new(); - for i in start.0..=end.0 { - let slice = &buff[i as usize]; - if i == start.0 { - s.push_str(&String::from_utf16(&slice[start.1 as usize..]).unwrap()); - } else if i == end.0 { - s.push_str(&String::from_utf16(&slice[..end.1 as usize]).unwrap()); - } else { - s.push_str(&String::from_utf16(slice).unwrap()); - } - } - - let replaced: Cow = s.cow_replace("\r", ""); - - // Windows: Replace "\r\n" and replace with "\n" - Cow::Owned(replaced.into_owned()) - } -} diff --git a/crates/oxc_sourcemap/src/token.rs b/crates/oxc_sourcemap/src/token.rs deleted file mode 100644 index c100d513c7bb1d..00000000000000 --- a/crates/oxc_sourcemap/src/token.rs +++ /dev/null @@ -1,145 +0,0 @@ -use crate::SourceMap; - -/// The `Token` is used to generate vlq `mappings`. -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Token { - pub(crate) dst_line: u32, - pub(crate) dst_col: u32, - pub(crate) src_line: u32, - pub(crate) src_col: u32, - pub(crate) source_id: Option, - pub(crate) name_id: Option, -} - -impl Token { - pub fn new( - dst_line: u32, - dst_col: u32, - src_line: u32, - src_col: u32, - source_id: Option, - name_id: Option, - ) -> Self { - Self { dst_line, dst_col, src_line, src_col, source_id, name_id } - } - - pub fn get_dst_line(&self) -> u32 { - self.dst_line - } - - pub fn get_dst_col(&self) -> u32 { - self.dst_col - } - - pub fn get_src_line(&self) -> u32 { - self.src_line - } - - pub fn get_src_col(&self) -> u32 { - self.src_col - } - - pub fn get_name_id(&self) -> Option { - self.name_id - } - - pub fn get_source_id(&self) -> Option { - self.source_id - } -} - -/// The `TokenChunk` used by encode tokens to vlq mappings at parallel. -/// It is a slice of `SourceMap::tokens`, it is a unit of parallel. -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub struct TokenChunk { - pub start: u32, - pub end: u32, - pub prev_dst_line: u32, - pub prev_dst_col: u32, - pub prev_src_line: u32, - pub prev_src_col: u32, - pub prev_name_id: u32, - pub prev_source_id: u32, -} - -impl TokenChunk { - #[allow(clippy::too_many_arguments)] - pub fn new( - start: u32, - end: u32, - prev_dst_line: u32, - prev_dst_col: u32, - prev_src_line: u32, - prev_src_col: u32, - prev_name_id: u32, - prev_source_id: u32, - ) -> Self { - Self { - start, - end, - prev_dst_line, - prev_dst_col, - prev_src_line, - prev_src_col, - prev_name_id, - prev_source_id, - } - } -} - -/// The `SourceViewToken` provider extra `source` and `source_content` value. -#[derive(Debug, Clone, Copy)] -pub struct SourceViewToken<'a> { - pub(crate) token: &'a Token, - pub(crate) sourcemap: &'a SourceMap, -} - -impl<'a> SourceViewToken<'a> { - pub fn new(token: &'a Token, sourcemap: &'a SourceMap) -> Self { - Self { token, sourcemap } - } - - pub fn get_dst_line(&self) -> u32 { - self.token.dst_line - } - - pub fn get_dst_col(&self) -> u32 { - self.token.dst_col - } - - pub fn get_src_line(&self) -> u32 { - self.token.src_line - } - - pub fn get_src_col(&self) -> u32 { - self.token.src_col - } - - pub fn get_name_id(&self) -> Option { - self.token.name_id - } - - pub fn get_source_id(&self) -> Option { - self.token.source_id - } - - pub fn get_name(&self) -> Option<&str> { - self.token.name_id.and_then(|id| self.sourcemap.get_name(id)) - } - - pub fn get_source(&self) -> Option<&str> { - self.token.source_id.and_then(|id| self.sourcemap.get_source(id)) - } - - pub fn get_source_content(&self) -> Option<&str> { - self.token.source_id.and_then(|id| self.sourcemap.get_source_content(id)) - } - - pub fn get_source_and_content(&self) -> Option<(&str, &str)> { - self.token.source_id.and_then(|id| self.sourcemap.get_source_and_content(id)) - } - - pub fn to_tuple(&self) -> (Option<&str>, u32, u32, Option<&str>) { - (self.get_source(), self.get_src_line(), self.get_src_col(), self.get_name()) - } -} diff --git a/crates/oxc_sourcemap/tests/fixtures/basic/test.js b/crates/oxc_sourcemap/tests/fixtures/basic/test.js deleted file mode 100644 index 12b22c059b1580..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/basic/test.js +++ /dev/null @@ -1,7 +0,0 @@ - -// shared.js -const a = 'shared.js'; - -// index.js -const a$1 = 'index.js'; -console.log(a$1, a); diff --git a/crates/oxc_sourcemap/tests/fixtures/basic/test.js.map b/crates/oxc_sourcemap/tests/fixtures/basic/test.js.map deleted file mode 100644 index 41759e9ffd4c3b..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/basic/test.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version":3, - "sources":["shared.js","index.js"], - "sourcesContent":["const a = 'shared.js'\n\nexport { a }","import { a as a2 } from './shared'\nconst a = 'index.js'\nconsole.log(a, a2)\n"], - "names":["a","a$1"], - "mappings":";;AAAA,MAAMA,IAAI;;;ACCV,MAAMC,MAAI;AACV,QAAQ,IAAIA,KAAGD,EAAG" -} diff --git a/crates/oxc_sourcemap/tests/fixtures/basic/visualizer.snap b/crates/oxc_sourcemap/tests/fixtures/basic/visualizer.snap deleted file mode 100644 index 4f52cfd39cf04a..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/basic/visualizer.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: crates/oxc_sourcemap/tests/main.rs -input_file: crates/oxc_sourcemap/tests/fixtures/basic/test.js -snapshot_kind: text ---- -- shared.js -(0:0) "const " --> (2:0) "const " -(0:6) "a = " --> (2:6) "a = " -(0:10) "'shared.js'\n" --> (2:10) "'shared.js';\n" -- index.js -(1:0) "const " --> (5:0) "const " -(1:6) "a = " --> (5:6) "a$1 = " -(1:10) "'index.js'\n" --> (5:12) "'index.js';\n" -(2:0) "console." --> (6:0) "console." -(2:8) "log(" --> (6:8) "log(" -(2:12) "a, " --> (6:12) "a$1, " -(2:15) "a2)" --> (6:17) "a)" -(2:18) "\n" --> (6:19) ";\n" diff --git a/crates/oxc_sourcemap/tests/fixtures/esbuild/README.md b/crates/oxc_sourcemap/tests/fixtures/esbuild/README.md deleted file mode 100644 index 437cd10c655fc1..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/esbuild/README.md +++ /dev/null @@ -1 +0,0 @@ -Example code from https://github.com/evanw/source-map-visualization/ diff --git a/crates/oxc_sourcemap/tests/fixtures/esbuild/example.js b/crates/oxc_sourcemap/tests/fixtures/esbuild/example.js deleted file mode 100644 index 86903998b466e7..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/esbuild/example.js +++ /dev/null @@ -1,45 +0,0 @@ -// index.tsx -import { h as u, Fragment as l, render as c } from "preact"; - -// counter.tsx -import { h as t, Component as i } from "preact"; -import { useState as a } from "preact/hooks"; -var n = class extends i { - constructor(e) { - super(e); - this.n = () => this.setState({ t: this.state.t + 1 }); - this.r = () => this.setState({ t: this.state.t - 1 }); - this.state.t = e.e; - } - render() { - return t("div", { - class: "counter" - }, t("h1", null, this.props.label), t("p", null, t("button", { - onClick: this.r - }, "-"), " ", this.state.t, " ", t("button", { - onClick: this.n - }, "+"))); - } -}, s = (r) => { - let [o, e] = a(r.e); - return t("div", { - class: "counter" - }, t("h1", null, r.o), t("p", null, t("button", { - onClick: () => e(o - 1) - }, "-"), " ", o, " ", t("button", { - onClick: () => e(o + 1) - }, "+"))); -}; - -// index.tsx -c( - u(l, null, u(n, { - o: "Counter 1", - e: 100 - }), u(s, { - o: "Counter 2", - e: 200 - })), - document.getElementById("root") -); -//# sourceMappingURL=example.js.map diff --git a/crates/oxc_sourcemap/tests/fixtures/esbuild/example.js.map b/crates/oxc_sourcemap/tests/fixtures/esbuild/example.js.map deleted file mode 100644 index f8f5027e47dfc7..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/esbuild/example.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["index.tsx", "counter.tsx"], - "sourcesContent": ["import { h, Fragment, render } from 'preact'\nimport { CounterClass, CounterFunction } from './counter'\n\nrender(\n <>\n \n \n ,\n document.getElementById('root')!,\n)\n", "import { h, Component } from 'preact'\nimport { useState } from 'preact/hooks'\n\ninterface CounterProps {\n label_: string\n initialValue_: number\n}\n\ninterface CounterState {\n value_: number\n}\n\nexport class CounterClass extends Component {\n state: CounterState\n\n constructor(props: CounterProps) {\n super(props)\n this.state.value_ = props.initialValue_\n }\n\n increment_ = () => this.setState({ value_: this.state.value_ + 1 })\n decrement_ = () => this.setState({ value_: this.state.value_ - 1 })\n\n render() {\n return
\n

{this.props.label}

\n

\n \n {' '}\n {this.state.value_}\n {' '}\n \n

\n
\n }\n}\n\nexport let CounterFunction = (props: CounterProps) => {\n let [value, setValue] = useState(props.initialValue_)\n return
\n

{props.label_}

\n

\n \n {' '}\n {value}\n {' '}\n \n

\n
\n}\n"], - "mappings": ";AAAA,SAAS,KAAAA,GAAG,YAAAC,GAAU,UAAAC,SAAc;;;ACApC,SAAS,KAAAC,GAAG,aAAAC,SAAiB;AAC7B,SAAS,YAAAC,SAAgB;AAWlB,IAAMC,IAAN,cAA2BF,EAAsC;AAAA,EAGtE,YAAYG,GAAqB;AAC/B,UAAMA,CAAK;AAIb,SAAAC,IAAa,MAAM,KAAK,SAAS,EAAEC,GAAQ,KAAK,MAAMA,IAAS,EAAE,CAAC;AAClE,SAAAC,IAAa,MAAM,KAAK,SAAS,EAAED,GAAQ,KAAK,MAAMA,IAAS,EAAE,CAAC;AAJhE,SAAK,MAAMA,IAASF,EAAMI;AAAA,EAC5B;AAAA,EAKA,SAAS;AACP,WAAOR,EAAC;AAAA,MAAI,OAAM;AAAA,OAChBA,EAAC,YAAI,KAAK,MAAM,KAAM,GACtBA,EAAC,WACCA,EAAC;AAAA,MAAO,SAAS,KAAKO;AAAA,OAAY,GAAC,GAClC,KACA,KAAK,MAAMD,GACX,KACDN,EAAC;AAAA,MAAO,SAAS,KAAKK;AAAA,OAAY,GAAC,CACrC,CACF;AAAA,EACF;AACF,GAEWI,IAAkB,CAACL,MAAwB;AACpD,MAAI,CAACM,GAAOC,CAAQ,IAAIT,EAASE,EAAMI,CAAa;AACpD,SAAOR,EAAC;AAAA,IAAI,OAAM;AAAA,KAChBA,EAAC,YAAII,EAAMQ,CAAO,GAClBZ,EAAC,WACCA,EAAC;AAAA,IAAO,SAAS,MAAMW,EAASD,IAAQ,CAAC;AAAA,KAAG,GAAC,GAC5C,KACAA,GACA,KACDV,EAAC;AAAA,IAAO,SAAS,MAAMW,EAASD,IAAQ,CAAC;AAAA,KAAG,GAAC,CAC/C,CACF;AACF;;;AD9CAG;AAAA,EACEC,EAAAC,GAAA,MACED,EAACE,GAAA;AAAA,IAAaC,GAAO;AAAA,IAAYC,GAAe;AAAA,GAAK,GACrDJ,EAACK,GAAA;AAAA,IAAgBF,GAAO;AAAA,IAAYC,GAAe;AAAA,GAAK,CAC1D;AAAA,EACA,SAAS,eAAe,MAAM;AAChC;", - "names": ["h", "Fragment", "render", "h", "Component", "useState", "CounterClass", "props", "increment_", "value_", "decrement_", "initialValue_", "CounterFunction", "value", "setValue", "label_", "render", "h", "Fragment", "CounterClass", "label_", "initialValue_", "CounterFunction"] -} diff --git a/crates/oxc_sourcemap/tests/fixtures/esbuild/visualizer.snap b/crates/oxc_sourcemap/tests/fixtures/esbuild/visualizer.snap deleted file mode 100644 index 65ad6a967cc122..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/esbuild/visualizer.snap +++ /dev/null @@ -1,208 +0,0 @@ ---- -source: crates/oxc_sourcemap/tests/main.rs -input_file: crates/oxc_sourcemap/tests/fixtures/esbuild/example.js -snapshot_kind: text ---- -- index.tsx -(0:0) "import { " --> (1:0) "import { " -(0:9) "h, " --> (1:9) "h as " -(0:9) "h, " --> (1:14) "u, " -(0:12) "Fragment, " --> (1:17) "Fragment as " -(0:12) "Fragment, " --> (1:29) "l, " -(0:22) "render } from " --> (1:32) "render as " -(0:22) "render } from " --> (1:42) "c } from " -(0:36) "'preact'\n" --> (1:51) "\"preact\";\n" -- counter.tsx -(0:0) "import { " --> (4:0) "import { " -(0:9) "h, " --> (4:9) "h as " -(0:9) "h, " --> (4:14) "t, " -(0:12) "Component } from " --> (4:17) "Component as " -(0:12) "Component } from " --> (4:30) "i } from " -(0:29) "'preact'\n" --> (4:39) "\"preact\";\n" -(1:0) "import { " --> (5:0) "import { " -(1:9) "useState } from " --> (5:9) "useState as " -(1:9) "useState } from " --> (5:21) "a } from " -(1:25) "'preact/hooks'\n" --> (5:30) "\"preact/hooks\";\n" -(12:7) "class " --> (6:0) "var " -(12:13) "CounterClass extends " --> (6:4) "n = " -(12:7) "class CounterClass extends " --> (6:8) "class extends " -(12:34) "Component " --> (6:22) "i " -(12:72) "{\n" --> (6:24) "{\n" -(12:72) "{\n" --> (7:0) " " -(15:2) "constructor(" --> (7:2) "constructor(" -(15:14) "props: CounterProps) " --> (7:14) "e) " -(15:35) "{\n" --> (7:17) "{\n" -(16:4) "super(" --> (8:0) " super(" -(16:10) "props" --> (8:10) "e" -(16:15) ")\n" --> (8:11) ");\n" -(20:2) "increment_ = " --> (9:0) " this." -(20:2) "increment_ = " --> (9:9) "n = " -(20:15) "() => " --> (9:13) "() => " -(20:21) "this." --> (9:19) "this." -(20:26) "setState(" --> (9:24) "setState(" -(20:35) "{ " --> (9:33) "{ " -(20:37) "value_: " --> (9:35) "t: " -(20:45) "this." --> (9:38) "this." -(20:50) "state." --> (9:43) "state." -(20:56) "value_ + " --> (9:49) "t + " -(20:65) "1 " --> (9:53) "1 " -(20:67) "}" --> (9:55) "}" -(20:68) ")\n" --> (9:56) ");\n" -(21:2) "decrement_ = " --> (10:0) " this." -(21:2) "decrement_ = " --> (10:9) "r = " -(21:15) "() => " --> (10:13) "() => " -(21:21) "this." --> (10:19) "this." -(21:26) "setState(" --> (10:24) "setState(" -(21:35) "{ " --> (10:33) "{ " -(21:37) "value_: " --> (10:35) "t: " -(21:45) "this." --> (10:38) "this." -(21:50) "state." --> (10:43) "state." -(21:56) "value_ - " --> (10:49) "t - " -(21:65) "1 " --> (10:53) "1 " -(21:67) "}" --> (10:55) "}" -(21:68) ")\n" --> (10:56) ");\n" -(17:4) "this." --> (11:0) " this." -(17:9) "state." --> (11:9) "state." -(17:15) "value_ = " --> (11:15) "t = " -(17:24) "props." --> (11:19) "e." -(17:30) "initialValue_\n" --> (11:21) "e;\n" -(17:30) "initialValue_\n" --> (12:0) " " -(18:2) "}\n" --> (12:2) "}\n" -(18:2) "}\n" --> (13:0) " " -(23:2) "render() " --> (13:2) "render() " -(23:11) "{\n" --> (13:11) "{\n" -(24:4) "return " --> (14:0) " return " -(24:11) "<" --> (14:11) "t(" -(24:12) "div " --> (14:13) "\"div\", {\n" -(24:12) "div " --> (15:0) " " -(24:16) "class=" --> (15:6) "class: " -(24:22) "\"counter\">\n" --> (15:13) "\"counter\"\n" -(24:22) "\"counter\">\n" --> (16:0) " }, " -(25:6) "<" --> (16:7) "t(" -(25:7) "h1>{" --> (16:9) "\"h1\", null, " -(25:11) "this." --> (16:21) "this." -(25:16) "props." --> (16:26) "props." -(25:22) "label}" --> (16:32) "label" -(25:28) "\n" --> (16:37) "), " -(26:6) "<" --> (16:40) "t(" -(26:7) "p>\n" --> (16:42) "\"p\", null, " -(27:8) "<" --> (16:53) "t(" -(27:9) "button " --> (16:55) "\"button\", {\n" -(27:9) "button " --> (17:0) " " -(27:16) "onClick={" --> (17:6) "onClick: " -(27:25) "this." --> (17:15) "this." -(27:30) "decrement_}>" --> (17:20) "r\n" -(27:30) "decrement_}>" --> (18:0) " }, " -(27:42) "-" --> (18:7) "\"-\"" -(27:43) "\n" --> (18:10) "), " -(28:9) "' '}\n" --> (18:13) "\" \", " -(29:9) "this." --> (18:18) "this." -(29:14) "state." --> (18:23) "state." -(29:20) "value_}\n" --> (18:29) "t, " -(30:9) "' '}\n" --> (18:32) "\" \", " -(31:8) "<" --> (18:37) "t(" -(31:9) "button " --> (18:39) "\"button\", {\n" -(31:9) "button " --> (19:0) " " -(31:16) "onClick={" --> (19:6) "onClick: " -(31:25) "this." --> (19:15) "this." -(31:30) "increment_}>" --> (19:20) "n\n" -(31:30) "increment_}>" --> (20:0) " }, " -(31:42) "+" --> (20:7) "\"+\"" -(31:43) "\n" --> (20:10) ")" -(32:6) "

\n" --> (20:11) ")" -(33:4) "\n" --> (20:12) ");\n" -(33:4) "\n" --> (21:0) " " -(34:2) "}\n" --> (21:2) "}\n" -(35:0) "}\n" --> (22:0) "}, " -(37:11) "CounterFunction = " --> (22:3) "s = " -(37:29) "(" --> (22:7) "(" -(37:30) "props: CounterProps) => " --> (22:8) "r) => " -(37:54) "{\n" --> (22:14) "{\n" -(38:2) "let " --> (23:0) " let " -(38:6) "[" --> (23:6) "[" -(38:7) "value, " --> (23:7) "o, " -(38:14) "setValue" --> (23:10) "e" -(38:22) "] = " --> (23:11) "] = " -(38:26) "useState(" --> (23:15) "a(" -(38:35) "props." --> (23:17) "r." -(38:41) "initialValue_" --> (23:19) "e" -(38:54) ")\n" --> (23:20) ");\n" -(39:2) "return " --> (24:0) " return " -(39:9) "<" --> (24:9) "t(" -(39:10) "div " --> (24:11) "\"div\", {\n" -(39:10) "div " --> (25:0) " " -(39:14) "class=" --> (25:4) "class: " -(39:20) "\"counter\">\n" --> (25:11) "\"counter\"\n" -(39:20) "\"counter\">\n" --> (26:0) " }, " -(40:4) "<" --> (26:5) "t(" -(40:5) "h1>{" --> (26:7) "\"h1\", null, " -(40:9) "props." --> (26:19) "r." -(40:15) "label_}" --> (26:21) "o" -(40:22) "\n" --> (26:22) "), " -(41:4) "<" --> (26:25) "t(" -(41:5) "p>\n" --> (26:27) "\"p\", null, " -(42:6) "<" --> (26:38) "t(" -(42:7) "button " --> (26:40) "\"button\", {\n" -(42:7) "button " --> (27:0) " " -(42:14) "onClick={" --> (27:4) "onClick: " -(42:23) "() => " --> (27:13) "() => " -(42:29) "setValue(" --> (27:19) "e(" -(42:38) "value - " --> (27:21) "o - " -(42:46) "1" --> (27:25) "1" -(42:47) ")}>" --> (27:26) ")\n" -(42:47) ")}>" --> (28:0) " }, " -(42:50) "-" --> (28:5) "\"-\"" -(42:51) "\n" --> (28:8) "), " -(43:7) "' '}\n" --> (28:11) "\" \", " -(44:7) "value}\n" --> (28:16) "o, " -(45:7) "' '}\n" --> (28:19) "\" \", " -(46:6) "<" --> (28:24) "t(" -(46:7) "button " --> (28:26) "\"button\", {\n" -(46:7) "button " --> (29:0) " " -(46:14) "onClick={" --> (29:4) "onClick: " -(46:23) "() => " --> (29:13) "() => " -(46:29) "setValue(" --> (29:19) "e(" -(46:38) "value + " --> (29:21) "o + " -(46:46) "1" --> (29:25) "1" -(46:47) ")}>" --> (29:26) ")\n" -(46:47) ")}>" --> (30:0) " }, " -(46:50) "+" --> (30:5) "\"+\"" -(46:51) "\n" --> (30:8) ")" -(47:4) "

\n" --> (30:9) ")" -(48:2) "\n" --> (30:10) ");\n" -(49:0) "}\n" --> (31:0) "};\n" -- index.tsx -(3:0) "render(\n" --> (34:0) "c(\n" -(3:0) "render(\n" --> (35:0) " " -(4:2) "<>\n" --> (35:2) "u(" -(4:2) "<>\n" --> (35:4) "l, " -(4:2) "<>\n" --> (35:7) "null, " -(5:4) "<" --> (35:13) "u(" -(5:5) "CounterClass " --> (35:15) "n, " -(5:5) "CounterClass " --> (35:18) "{\n" -(5:5) "CounterClass " --> (36:0) " " -(5:18) "label_=" --> (36:4) "o: " -(5:25) "\"Counter 1\" " --> (36:7) "\"Counter 1\",\n" -(5:25) "\"Counter 1\" " --> (37:0) " " -(5:37) "initialValue_={" --> (37:4) "e: " -(5:52) "100} " --> (37:7) "100\n" -(5:52) "100} " --> (38:0) " }" -(5:57) "/>\n" --> (38:3) "), " -(6:4) "<" --> (38:6) "u(" -(6:5) "CounterFunction " --> (38:8) "s, " -(6:5) "CounterFunction " --> (38:11) "{\n" -(6:5) "CounterFunction " --> (39:0) " " -(6:21) "label_=" --> (39:4) "o: " -(6:28) "\"Counter 2\" " --> (39:7) "\"Counter 2\",\n" -(6:28) "\"Counter 2\" " --> (40:0) " " -(6:40) "initialValue_={" --> (40:4) "e: " -(6:55) "200} " --> (40:7) "200\n" -(6:55) "200} " --> (41:0) " }" -(6:60) "/>\n" --> (41:3) ")" -(7:2) ",\n" --> (41:4) "),\n" -(7:2) ",\n" --> (42:0) " " -(8:2) "document." --> (42:2) "document." -(8:11) "getElementById(" --> (42:11) "getElementById(" -(8:26) "'root'" --> (42:26) "\"root\"" -(8:32) ")!,\n" --> (42:32) ")\n" -(9:0) ")\n" --> (43:0) ");\n" diff --git a/crates/oxc_sourcemap/tests/fixtures/swap/test.js b/crates/oxc_sourcemap/tests/fixtures/swap/test.js deleted file mode 100644 index 759a61de1c12f5..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/swap/test.js +++ /dev/null @@ -1,3 +0,0 @@ -z; -y; -x; diff --git a/crates/oxc_sourcemap/tests/fixtures/swap/test.js.map b/crates/oxc_sourcemap/tests/fixtures/swap/test.js.map deleted file mode 100644 index bbcfe11bc8c041..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/swap/test.js.map +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 3, - "names": ["z", "y", "x"], - "sources": ["test.js"], - "sourcesContent": ["x;\ny;\nz;\n"], - "mappings": "AAEAA,CAAC;AADDC,CAAC;AADDC,CAAC", - "ignoreList": [] -} diff --git a/crates/oxc_sourcemap/tests/fixtures/swap/visualizer.snap b/crates/oxc_sourcemap/tests/fixtures/swap/visualizer.snap deleted file mode 100644 index 75241b81d2720c..00000000000000 --- a/crates/oxc_sourcemap/tests/fixtures/swap/visualizer.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: crates/oxc_sourcemap/tests/main.rs -input_file: crates/oxc_sourcemap/tests/fixtures/swap/test.js -snapshot_kind: text ---- -- test.js -(2:0) "z" --> (0:0) "z" -(2:1) ";\n" --> (0:1) ";\n" -(1:0) "y" --> (1:0) "y" -(1:1) ";\n" --> (1:1) ";\n" -(0:0) "x" --> (2:0) "x" -(0:1) ";\n" --> (2:1) ";\n" diff --git a/crates/oxc_sourcemap/tests/main.rs b/crates/oxc_sourcemap/tests/main.rs deleted file mode 100644 index 973ef5791ef20f..00000000000000 --- a/crates/oxc_sourcemap/tests/main.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::fs; - -use oxc_sourcemap::{SourceMap, SourcemapVisualizer}; - -#[test] -fn snapshot_sourcemap_visualizer() { - insta::glob!("fixtures/**/*.js", |path| { - let js = fs::read_to_string(path).unwrap(); - let js_map = fs::read_to_string(path.with_extension("js.map")).unwrap(); - let sourcemap = SourceMap::from_json_string(&js_map).unwrap(); - let visualizer = SourcemapVisualizer::new(&js, &sourcemap); - let visualizer_text = visualizer.into_visualizer_text(); - insta::with_settings!({ snapshot_path => path.parent().unwrap(), prepend_module_to_snapshot => false, snapshot_suffix => "", omit_expression => true }, { - insta::assert_snapshot!("visualizer", visualizer_text); - }); - }); -} diff --git a/tasks/benchmark/Cargo.toml b/tasks/benchmark/Cargo.toml index b6103ced36f2aa..2046bf6ceae617 100644 --- a/tasks/benchmark/Cargo.toml +++ b/tasks/benchmark/Cargo.toml @@ -42,10 +42,6 @@ harness = false name = "codegen" harness = false -[[bench]] -name = "sourcemap" -harness = false - # Broken # [[bench]] # name = "prettier" @@ -76,7 +72,6 @@ oxc_minifier = { workspace = true, optional = true } oxc_parser = { workspace = true, features = ["benchmarking"], optional = true } oxc_prettier = { workspace = true, optional = true } oxc_semantic = { workspace = true, optional = true } -oxc_sourcemap = { workspace = true, features = ["concurrent"], optional = true } oxc_span = { workspace = true, optional = true, features = ["schemars", "serialize"] } oxc_tasks_common = { workspace = true, optional = true } oxc_transformer = { workspace = true, optional = true } @@ -97,7 +92,6 @@ default = [ "dep:oxc_parser", "dep:oxc_prettier", "dep:oxc_semantic", - "dep:oxc_sourcemap", "dep:oxc_span", "dep:oxc_tasks_common", "dep:oxc_transformer", @@ -127,14 +121,6 @@ minifier = [ "dep:oxc_tasks_common", ] codegen = ["dep:oxc_allocator", "dep:oxc_codegen", "dep:oxc_parser", "dep:oxc_span", "dep:oxc_tasks_common"] -sourcemap = [ - "dep:oxc_allocator", - "dep:oxc_codegen", - "dep:oxc_parser", - "dep:oxc_sourcemap", - "dep:oxc_span", - "dep:oxc_tasks_common", -] linter = [ "dep:oxc_allocator", "dep:oxc_linter", diff --git a/tasks/benchmark/benches/sourcemap.rs b/tasks/benchmark/benches/sourcemap.rs deleted file mode 100644 index 12110b9847b623..00000000000000 --- a/tasks/benchmark/benches/sourcemap.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::path::PathBuf; - -use oxc_allocator::Allocator; -use oxc_benchmark::{criterion_group, criterion_main, BenchmarkId, Criterion}; -use oxc_codegen::{CodeGenerator, CodegenOptions, CodegenReturn}; -use oxc_parser::Parser; -use oxc_sourcemap::ConcatSourceMapBuilder; -use oxc_span::SourceType; -use oxc_tasks_common::TestFiles; - -#[expect(clippy::cast_possible_truncation)] -fn bench_sourcemap(criterion: &mut Criterion) { - let mut group = criterion.benchmark_group("sourcemap"); - - for file in TestFiles::complicated_one(1).files() { - let id = BenchmarkId::from_parameter(&file.file_name); - let source_type = SourceType::from_path(&file.file_name).unwrap(); - group.bench_with_input(id, &file.source_text, |b, source_text| { - let allocator = Allocator::default(); - let ret = Parser::new(&allocator, source_text, source_type).parse(); - - let CodegenReturn { code: output_txt, .. } = CodeGenerator::new() - .with_options(CodegenOptions { - source_map_path: Some(PathBuf::from(&file.file_name)), - ..CodegenOptions::default() - }) - .build(&ret.program); - let lines = output_txt.matches('\n').count() as u32; - - b.iter(|| { - let CodegenReturn { map, .. } = CodeGenerator::new() - .with_options(CodegenOptions { - source_map_path: Some(PathBuf::from(&file.file_name)), - ..CodegenOptions::default() - }) - .build(&ret.program); - if let Some(sourcemap) = map { - let concat_sourcemap_builder = ConcatSourceMapBuilder::from_sourcemaps(&[ - (&sourcemap, 0), - (&sourcemap, lines), - ]); - concat_sourcemap_builder.into_sourcemap().to_json_string(); - } - }); - }); - } - - group.finish(); -} - -criterion_group!(sourcemap, bench_sourcemap); -criterion_main!(sourcemap); diff --git a/tasks/coverage/Cargo.toml b/tasks/coverage/Cargo.toml index 2109e27be6e43e..847e5b1a0ea77b 100644 --- a/tasks/coverage/Cargo.toml +++ b/tasks/coverage/Cargo.toml @@ -22,7 +22,7 @@ test = false doctest = false [dependencies] -oxc = { workspace = true, features = ["full", "isolated_declarations", "serialize", "sourcemap"] } +oxc = { workspace = true, features = ["full", "isolated_declarations", "serialize"] } oxc_prettier = { workspace = true } oxc_tasks_common = { workspace = true } oxc_tasks_transform_checker = { workspace = true }