Skip to content

Commit b26cc8d

Browse files
committed
Use u32 and fix source map
1 parent e7dc5b1 commit b26cc8d

File tree

12 files changed

+207
-103
lines changed

12 files changed

+207
-103
lines changed

examples/source_map.rs

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,19 @@ fn main() {
66
</div>";
77
let mut s = MagicString::new(demo);
88

9-
// s.prepend("import React from 'react';\n")
109
let update_options = UpdateOptions {
1110
store_name: true,
1211
..Default::default()
1312
};
14-
s
15-
.update_with(
16-
1,
17-
2,
18-
"v",
19-
update_options.clone(),
20-
)
21-
.update_with(
22-
3,
23-
4,
24-
"d",
25-
update_options.clone(),
26-
)
27-
.update_with(
28-
demo.len() - 4,
29-
demo.len() - 1,
30-
"h1",
31-
UpdateOptions {
32-
store_name: true,
33-
..Default::default()
34-
},
35-
);
13+
s.update_with(1, 2, "v", update_options.clone())
14+
.update_with(3, 4, "d", update_options.clone())
15+
.update_with(demo.len() - 4, demo.len() - 1, "h1", update_options.clone());
3616

3717
let sm = s.source_map(SourceMapOptions {
3818
include_content: true,
3919
});
4020

41-
std::fs::write("./demo.jsx.map", sm.to_string()).unwrap();
21+
std::fs::write("./demo.map.json", sm.to_string()).unwrap();
4222
std::fs::write("./demo.jsx", s.to_string()).unwrap();
4323

4424
println!("{:#?}", s.to_string());

src/basic_types.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use std::borrow::Cow;
2+
3+
#[derive(Debug, Clone)]
4+
pub struct BasicCowStr<'text> {
5+
inner: Cow<'text, str>,
6+
}
7+
8+
impl<'text> BasicCowStr<'text> {
9+
pub fn new(inner: Cow<'text, str>) -> Self {
10+
assert!(
11+
u32::try_from(inner.len()).is_ok(),
12+
"We only support string up to 4GB in size, which is the maximum size of the u32."
13+
);
14+
Self { inner }
15+
}
16+
17+
pub fn len(&self) -> u32 {
18+
// We can safely do converting here because we have already asserted that
19+
// the length of the string is less than or equal `u32::MAX`
20+
self.inner.len() as u32
21+
}
22+
23+
pub fn as_str(&self) -> &str {
24+
self.inner.as_ref()
25+
}
26+
}
27+
28+
impl<'text> std::ops::Deref for BasicCowStr<'text> {
29+
type Target = Cow<'text, str>;
30+
31+
fn deref(&self) -> &Self::Target {
32+
&self.inner
33+
}
34+
}
35+
36+
impl<'text, T: Into<Cow<'text, str>>> From<T> for BasicCowStr<'text> {
37+
fn from(value: T) -> Self {
38+
Self::new(value.into())
39+
}
40+
}

src/chunk.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ impl<'str> Chunk<'str> {
100100
let intro_iter = self.intro.iter().map(|frag| frag.as_ref());
101101
let source_frag = self
102102
.edited_content
103-
.as_deref()
104-
.unwrap_or_else(|| self.span.text(original_source.as_ref()));
103+
.as_ref()
104+
.map(|s| s.as_str())
105+
.unwrap_or_else(|| self.span.text(original_source.as_str()));
105106
let outro_iter = self.outro.iter().map(|frag| frag.as_ref());
106107
intro_iter.chain(Some(source_frag)).chain(outro_iter)
107108
}

src/decoded_map.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use crate::{
2-
mappings::{Mappings, Segment},
3-
source_map::SourceMap,
4-
};
1+
use crate::{mappings::Mappings, source_map::SourceMap};
52

63
#[derive(Debug)]
74
pub struct DecodedMap {

src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ mod magic_string;
66
mod mappings;
77
mod source_map;
88
mod span;
9+
mod basic_types;
910

10-
type CowStr<'text> = std::borrow::Cow<'text, str>;
11+
type CowStr<'text> = BasicCowStr<'text>;
1112

12-
pub(crate) type TextSize = usize;
13+
pub(crate) type TextSize = u32;
14+
15+
use basic_types::BasicCowStr;
1316

1417
pub use crate::{
1518
joiner::{Joiner, JoinerOptions},

src/locator.rs

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
#[derive(Debug)]
12
pub struct Locator {
3+
/// offsets are calculated based on utf-16
24
line_offsets: Box<[usize]>,
35
}
46

@@ -8,14 +10,17 @@ impl Locator {
810
let mut line_start_pos = 0;
911
for line in source.lines() {
1012
line_offsets.push(line_start_pos);
11-
line_start_pos += 1 + line.len();
13+
line_start_pos += 1 + line.chars().map(|c| c.len_utf16()).sum::<usize>();
1214
}
1315
Self {
1416
line_offsets: line_offsets.into_boxed_slice(),
1517
}
1618
}
1719

18-
pub fn locate(&self, index: usize) -> Location {
20+
/// Pass the index based on utf-16 and return the [Location] based on utf-16
21+
pub fn locate(&self, index: u32) -> Location {
22+
let index = index as usize;
23+
1924
let mut left_cursor = 0;
2025
let mut right_cursor = self.line_offsets.len();
2126
while left_cursor < right_cursor {
@@ -28,14 +33,18 @@ impl Locator {
2833
}
2934
let line = left_cursor - 1;
3035
let column = index - self.line_offsets[line];
31-
Location { line, column }
36+
Location {
37+
line: line.try_into().unwrap(),
38+
column: column.try_into().unwrap(),
39+
}
3240
}
3341
}
3442

3543
#[derive(Debug, PartialEq)]
3644
pub struct Location {
37-
pub line: usize,
38-
pub column: usize,
45+
pub line: u32,
46+
// columns are calculated based on utf-16
47+
pub column: u32,
3948
}
4049

4150
impl Location {
@@ -47,23 +56,27 @@ impl Location {
4756

4857
#[test]
4958
fn basic() {
50-
use std::ops::Range;
5159
let source = "string\nwizard";
5260
let locator = Locator::new(source);
53-
let line_range = |line: usize| -> Range<usize> {
54-
assert!(line < locator.line_offsets.len());
55-
if line == locator.line_offsets.len() - 1 {
56-
locator.line_offsets[line]..source.len()
57-
} else {
58-
locator.line_offsets[line]..(locator.line_offsets[line + 1] - 1)
59-
}
60-
};
61-
assert_eq!(&source[line_range(0)], "string");
62-
assert_eq!(&source[line_range(1)], "wizard");
6361

6462
assert_eq!(locator.line_offsets[0], 0);
6563
assert_eq!(locator.line_offsets[1], 7);
6664

67-
assert_eq!(locator.locate(2), Location { line: 0, column: 2 });
65+
assert_eq!(locator.locate(0), Location { line: 0, column: 0 });
66+
assert_eq!(locator.locate(12), Location { line: 1, column: 5 });
67+
assert_eq!(locator.locate(7), Location { line: 1, column: 0 });
68+
assert_eq!(locator.locate(1), Location { line: 0, column: 1 });
6869
assert_eq!(locator.locate(8), Location { line: 1, column: 1 });
6970
}
71+
72+
#[test]
73+
fn special_chars() {
74+
let source = "ß💣\n💣ß";
75+
let locator = Locator::new(source);
76+
assert_eq!(locator.line_offsets[0], 0);
77+
assert_eq!(locator.line_offsets[1], 4);
78+
79+
assert_eq!(locator.locate(0), Location { line: 0, column: 0 });
80+
assert_eq!(locator.locate(4), Location { line: 1, column: 0 });
81+
assert_eq!(locator.locate(6), Location { line: 1, column: 2 });
82+
}

src/magic_string/mod.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ use std::collections::VecDeque;
66
use rustc_hash::FxHashMap;
77

88
use crate::{
9-
chunk::{Chunk, ChunkVec, ChunkIdx}, locator::Locator, mappings::Mappings, span::Span, CowStr,
10-
TextSize,
9+
chunk::{Chunk, ChunkIdx, ChunkVec},
10+
span::Span,
11+
CowStr, TextSize,
1112
};
1213

1314
#[derive(Debug, Default)]
@@ -157,8 +158,6 @@ impl<'s> MagicString<'s> {
157158
ret
158159
}
159160

160-
161-
162161
// --- private
163162

164163
fn prepend_intro(&mut self, content: impl Into<CowStr<'s>>) {
@@ -201,16 +200,17 @@ impl<'s> MagicString<'s> {
201200
///
202201
/// Chunk{span: (0, 3)} => "abc"
203202
/// Chunk{span: (3, 7)} => "defg"
204-
fn split_at(&mut self, text_index: TextSize) {
203+
fn split_at(&mut self, text_index: u32) {
205204
if text_index == 0 || self.chunk_by_end.contains_key(&text_index) {
206205
return;
207206
}
208207

209-
let (mut target, mut target_idx, search_right) = if (self.source.len() - text_index) > text_index {
210-
(self.first_chunk(), self.first_chunk_idx, true)
211-
} else {
212-
(self.last_chunk(), self.last_chunk_idx, false)
213-
};
208+
let (mut target, mut target_idx, search_right) =
209+
if (self.source.len() - text_index) > text_index {
210+
(self.first_chunk(), self.first_chunk_idx, true)
211+
} else {
212+
(self.last_chunk(), self.last_chunk_idx, false)
213+
};
214214

215215
while !target.contains(text_index) {
216216
let next_idx = if search_right {

src/magic_string/mutation.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{chunk::EditOptions, CowStr, MagicString, TextSize};
1+
use crate::{chunk::EditOptions, CowStr, MagicString};
22

33
#[derive(Debug, Default, Clone)]
44
pub struct UpdateOptions {
@@ -12,25 +12,25 @@ impl<'text> MagicString<'text> {
1212
/// A shorthand for `update_with(start, end, content, Default::default())`;
1313
pub fn update(
1414
&mut self,
15-
start: TextSize,
16-
end: TextSize,
15+
start: usize,
16+
end: usize,
1717
content: impl Into<CowStr<'text>>,
1818
) -> &mut Self {
1919
self.update_with(start, end, content, Default::default())
2020
}
2121

2222
pub fn update_with(
2323
&mut self,
24-
start: TextSize,
25-
end: TextSize,
24+
start: usize,
25+
end: usize,
2626
content: impl Into<CowStr<'text>>,
2727
opts: UpdateOptions,
2828
) -> &mut Self {
2929
self.update_with_inner(start, end, content.into(), opts, true);
3030
self
3131
}
3232

33-
pub fn remove(&mut self, start: TextSize, end: TextSize) -> &mut Self {
33+
pub fn remove(&mut self, start: usize, end: usize) -> &mut Self {
3434
self.update_with_inner(
3535
start,
3636
end,
@@ -49,12 +49,14 @@ impl<'text> MagicString<'text> {
4949

5050
fn update_with_inner(
5151
&mut self,
52-
start: TextSize,
53-
end: TextSize,
52+
start: usize,
53+
end: usize,
5454
content: CowStr<'text>,
5555
opts: UpdateOptions,
5656
panic_if_start_equal_end: bool,
5757
) -> &mut Self {
58+
let start = start as u32;
59+
let end = end as u32;
5860
if panic_if_start_equal_end && start == end {
5961
panic!(
6062
"Cannot overwrite a zero-length range – use append_left or prepend_right instead"

src/magic_string/source_map.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl<'s> MagicString<'s> {
3737
next_idx
3838
});
3939
debug_assert!(idx < names.len());
40-
Some(idx)
40+
Some(idx as u32)
4141
} else {
4242
None
4343
};
@@ -54,7 +54,7 @@ impl<'s> MagicString<'s> {
5454
sources: vec!["".to_string()],
5555
sources_content: opts
5656
.include_content
57-
.then(|| vec![self.source.clone().into_owned()])
57+
.then(|| vec![self.source.as_str().to_string()])
5858
.unwrap_or_default(),
5959
mappings,
6060
names,

0 commit comments

Comments
 (0)