Skip to content

Commit 8b56808

Browse files
refactor: comprehensive architecture improvements across all crates
- Centralize external dependencies in workspace Cargo.toml - Add debug_assert guards before all unsafe String::from_utf8_unchecked calls - Replace String error erasure with typed ScopesError in ParseError chain - Add #[inline] to hot-path functions across codec, scopes, sourcemap, generator - Add Hash, PartialOrd, Ord trait impls to Segment for completeness - Add single-char fast path to vlq_decode_unsigned - Use Box<RawValue> for indexed source map sections (avoid JSON re-serialize) - Add get_source/get_name safe accessor methods to SourceMap - Use impl Into<String> for flexible generator setter APIs - Extract resolve_sources/build_source_map helpers to eliminate duplication - Remove redundant dedup HashMaps from ConcatBuilder - Cache has_range_mappings boolean to avoid O(n) scan on every call - Convert find_nth_scope from recursive to iterative (stack overflow safety) - Change scopes definition field from usize to u32 for platform consistency - Replace .unwrap() with .expect() with descriptive messages - Fix CLI error handling: replace unwrap with proper CliError propagation
1 parent 006c7f9 commit 8b56808

27 files changed

Lines changed: 338 additions & 250 deletions

File tree

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ srcmap-remapping = { version = "0.1.3", path = "crates/remapping" }
1616
srcmap-scopes = { version = "0.1.3", path = "crates/scopes" }
1717
srcmap-symbolicate = { version = "0.1.3", path = "crates/symbolicate" }
1818
criterion = { version = "0.5", features = ["html_reports"] }
19+
serde = { version = "1", features = ["derive"] }
20+
serde_json = { version = "1", features = ["raw_value"] }
21+
rayon = "1"
22+
napi = { version = "2", default-features = false, features = ["napi6"] }
23+
napi-derive = "2"
24+
napi-build = "2"
25+
wasm-bindgen = "0.2"
26+
serde-wasm-bindgen = "0.6"
27+
js-sys = "0.3"
28+
clap = { version = "4", features = ["derive"] }
1929

2030
[profile.release]
2131
lto = true

crates/cli/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ srcmap-codec = { workspace = true }
1818
srcmap-sourcemap = { workspace = true }
1919
srcmap-remapping = { workspace = true }
2020
srcmap-symbolicate = { workspace = true }
21-
clap = { version = "4", features = ["derive"] }
22-
serde_json = "1"
21+
clap = { workspace = true }
22+
serde_json = { workspace = true }

crates/cli/src/main.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,9 @@ fn cmd_mappings(
687687
};
688688

689689
let filtered: Vec<_> = if let Some(source_name) = source_filter {
690-
let source_idx = sm.source_index(source_name).unwrap();
690+
let source_idx = sm
691+
.source_index(source_name)
692+
.ok_or_else(|| CliError::not_found(format!("source not found: {source_name}")))?;
691693
all.iter()
692694
.filter(|m| m.source == source_idx)
693695
.skip(offset)
@@ -812,7 +814,8 @@ fn cmd_concat(
812814
}
813815

814816
let map_json = builder.to_json();
815-
let result = SourceMap::from_json(&map_json).unwrap();
817+
let result = SourceMap::from_json(&map_json)
818+
.map_err(|e| CliError::parse(format!("failed to parse generated map: {e}")))?;
816819

817820
if dry_run {
818821
if json {

crates/codec/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ parallel = ["rayon"]
1717
crate-type = ["lib"]
1818

1919
[dependencies]
20-
rayon = { version = "1", optional = true }
20+
rayon = { workspace = true, optional = true }
2121

2222
[dev-dependencies]
2323
criterion = { workspace = true }

crates/codec/src/decode.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use crate::vlq::vlq_decode;
22
use crate::{DecodeError, Line, Segment, SourceMapMappings};
33

4-
54
/// Decode a VLQ-encoded source map mappings string into structured data.
65
///
76
/// The mappings string uses `;` to separate lines and `,` to separate

crates/codec/src/encode.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ pub fn encode(mappings: &SourceMapMappings) -> String {
6767
}
6868
}
6969

70-
// SAFETY: buf contains only ASCII base64 chars, semicolons, and commas
70+
// SAFETY: vlq_encode only pushes bytes from BASE64_ENCODE (all ASCII),
71+
// and we only add b';' and b',' — all valid UTF-8.
72+
debug_assert!(buf.is_ascii());
7173
unsafe { String::from_utf8_unchecked(buf) }
7274
}
7375

@@ -189,6 +191,8 @@ pub fn encode_parallel(mappings: &SourceMapMappings) -> String {
189191
buf.extend_from_slice(line_bytes);
190192
}
191193

192-
// SAFETY: VLQ output is always valid ASCII/UTF-8
194+
// SAFETY: vlq_encode only pushes bytes from BASE64_ENCODE (all ASCII),
195+
// and we only add b';' — all valid UTF-8.
196+
debug_assert!(buf.is_ascii());
193197
unsafe { String::from_utf8_unchecked(buf) }
194198
}

crates/codec/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,27 @@ pub struct Segment {
6262
len: u8,
6363
}
6464

65+
impl std::hash::Hash for Segment {
66+
#[inline]
67+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
68+
(**self).hash(state);
69+
}
70+
}
71+
72+
impl PartialOrd for Segment {
73+
#[inline]
74+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
75+
Some(self.cmp(other))
76+
}
77+
}
78+
79+
impl Ord for Segment {
80+
#[inline]
81+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
82+
(**self).cmp(&**other)
83+
}
84+
}
85+
6586
impl Segment {
6687
/// Create a 1-field segment (generated column only).
6788
#[inline]

crates/codec/src/vlq.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,34 @@ pub fn vlq_encode_unsigned(out: &mut Vec<u8>, value: u64) {
186186
/// Unlike signed VLQ, no sign bit extraction is performed.
187187
#[inline]
188188
pub fn vlq_decode_unsigned(input: &[u8], pos: usize) -> Result<(u64, usize), DecodeError> {
189-
let mut result: u64 = 0;
190-
let mut shift: u32 = 0;
191-
let mut i = pos;
189+
if pos >= input.len() {
190+
return Err(DecodeError::UnexpectedEof { offset: pos });
191+
}
192+
193+
let b0 = input[pos];
194+
if b0 >= 128 {
195+
return Err(DecodeError::InvalidBase64 {
196+
byte: b0,
197+
offset: pos,
198+
});
199+
}
200+
let d0 = BASE64_DECODE[b0 as usize];
201+
if d0 == 255 {
202+
return Err(DecodeError::InvalidBase64 {
203+
byte: b0,
204+
offset: pos,
205+
});
206+
}
207+
208+
// Fast path: single character (value fits in 5 bits, no continuation)
209+
if (d0 & 0x20) == 0 {
210+
return Ok((d0 as u64, 1));
211+
}
212+
213+
// Multi-character unsigned VLQ
214+
let mut result: u64 = (d0 & 0x1F) as u64;
215+
let mut shift: u32 = 5;
216+
let mut i = pos + 1;
192217

193218
loop {
194219
if i >= input.len() {
@@ -207,17 +232,16 @@ pub fn vlq_decode_unsigned(input: &[u8], pos: usize) -> Result<(u64, usize), Dec
207232
return Err(DecodeError::InvalidBase64 { byte, offset: i });
208233
}
209234

210-
let digit = digit as u64;
211235
i += 1;
212236

213237
if shift >= VLQ_MAX_SHIFT {
214238
return Err(DecodeError::VlqOverflow { offset: pos });
215239
}
216240

217-
result += (digit & VLQ_BASE_MASK) << shift;
241+
result += ((digit & 0x1F) as u64) << shift;
218242
shift += VLQ_BASE_SHIFT;
219243

220-
if (digit & VLQ_CONTINUATION_BIT) == 0 {
244+
if (digit & 0x20) == 0 {
221245
break;
222246
}
223247
}

crates/generator/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ crate-type = ["lib"]
2020
srcmap-codec = { workspace = true }
2121
srcmap-sourcemap = { workspace = true }
2222
srcmap-scopes = { workspace = true }
23-
rayon = { version = "1", optional = true }
23+
rayon = { workspace = true, optional = true }
2424

2525
[dev-dependencies]
26-
serde = { version = "1", features = ["derive"] }
27-
serde_json = "1"
26+
serde = { workspace = true }
27+
serde_json = { workspace = true }
2828
criterion = { workspace = true }
2929

3030
[[bench]]

0 commit comments

Comments
 (0)