Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

feat: support slice api #21

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions core/src/magic_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,89 @@ impl MagicString {
Ok(self)
}

/// ## Slice
/// Get a slice of the modified string.
/// Example:
/// ```
/// use magic_string::MagicString;
/// let mut s = MagicString::new("abcdefghijkl");
///
///
/// ```
///
pub fn slice(&mut self, start: i64, end: i64) -> Result<String> {
let start = normalize_index(self.original_str.as_str(), start)?;
let end = normalize_index(self.original_str.as_str(), end)?;

let start = start as u32;
let end = end as u32;

if start > end {
return Err(Error::new_with_reason(
MagicStringErrorType::MagicStringOutOfRangeError,
"Start must be greater than end.",
));
}

let mut result = String::new();
let mut chunk = Some(Rc::clone(&self.first_chunk));
while let Some(c) = chunk.clone() {
if c.borrow().start > start || c.borrow().end <= start {
chunk = c.borrow().clone().next;
} else {
break;
}
}
if let Some(c) = chunk.clone() {
if c.borrow().is_content_edited() && c.borrow().start != start {
return Err(Error::new_with_reason(
MagicStringErrorType::MagicStringUnknownError,
"Cannot move a selection inside itself",
));
}
}
let start_chunk = chunk.clone().unwrap();
Chunk::try_each_next(Rc::clone(&chunk.unwrap()), |chunk| {
let str: &str;

if chunk.borrow().intro.len() != 0 && (start_chunk != chunk || chunk.borrow().start == start)
{
result.push_str(chunk.borrow().intro.as_str());
};

let contain_end = chunk.borrow().end >= end;

let slice_start = if chunk.borrow().start < start {
start - chunk.borrow().start
} else {
0
};
let slice_end = if contain_end {
chunk.borrow().content.len() as u32 + end - chunk.borrow().end
} else {
chunk.borrow().content.len() as u32
};

let chunk_str = chunk.borrow().content.clone();

if contain_end && chunk.borrow().is_content_edited() && chunk.borrow().end != end {
return Err(Error::new_with_reason(
MagicStringErrorType::MagicStringUnknownError,
"Cannot use replaced character ${end} as slice end anchor.",
));
}

str = &chunk_str.as_str()[slice_start as usize..slice_end as usize];
result.push_str(str);
if chunk.borrow().outro.len() != 0 && (!contain_end || chunk.borrow().end == end) {
result.push_str(chunk.borrow().outro.as_str())
}

Ok(chunk.borrow().end >= end)
})?;

Ok(result)
}
/// ## Is empty
///
/// Returns `true` if the resulting source is empty (disregarding white space).
Expand Down
104 changes: 104 additions & 0 deletions core/tests/slice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#[cfg(test)]

mod slice {
use magic_string::{MagicString, OverwriteOptions, Result};

#[test]
fn should_return_the_generated_content_between_the_specified_original_characters() -> Result {
let mut s = MagicString::new("abcdefghijkl");

assert_eq!(s.slice(3, 9)?, "defghi");
s.overwrite(4, 8, "XX", OverwriteOptions::default())?;
assert_eq!(s.slice(3, 9)?, "dXXi");
s.overwrite(2, 10, "ZZ", OverwriteOptions::default())?;
assert_eq!(s.slice(1, 11)?, "bZZk");
assert_eq!(s.slice(2, 10)?, "ZZ");

Ok(())
}

// #[test]
// fn defaults_end_to_the_original_string_length() -> Result {
// let mut s = MagicString::new("abcdefghijkl");
// assert_eq!(s.slice(3)?, "defghijkl");
// }

#[test]
fn allow_negative_numbers_as_params() -> Result {
let mut s = MagicString::new("abcdefghijkl");

assert_eq!(s.slice(0, -3)?, "abcdefghi");
// assert_eq!(s.slice(-3)?, "jkl");
Ok(())
}
#[test]
fn includes_inserted_characters_respecting_insertion_direction() -> Result {
let mut s = MagicString::new("abefij");

s.prepend_right(2, "cd")?;
s.append_left(4, "gh")?;

// assert_eq!(s.slice(), "abcdefghij");
assert_eq!(s.slice(1, 5)?, "bcdefghi");
assert_eq!(s.slice(2, 4)?, "cdefgh");
assert_eq!(s.slice(3, 4)?, "fgh");
assert_eq!(s.slice(0, 2)?, "ab");
assert_eq!(s.slice(0, 3)?, "abcde");
assert_eq!(s.slice(4, 6)?, "ij");
assert_eq!(s.slice(3, 6)?, "fghij");
Ok(())
}

// wating for move to be implemented
// #[test]
// fn supports_characters_moved_outward() -> Result {
// let mut s = MagicString::new("abcdEFghIJklmn");

// s._move(4, 6, 2)?;
// s._move(8, 10, 12)?;
// assert_eq!(s.to_string(), "abEFcdghklIJmn");

// assert_eq!(s.slice(1, -1)?, "bEFcdghklIJm");
// assert_eq!(s.slice(2, -2)?, "cdghkl");
// assert_eq!(s.slice(3, -3)?, "dghk");
// assert_eq!(s.slice(4, -4)?, "EFcdghklIJ");
// assert_eq!(s.slice(5, -5)?, "FcdghklI");
// assert_eq!(s.slice(6, -6)?, "gh");
// Ok(())
// }

// #[test]
// fn supports_characters_moved_inward() -> Result {
// let mut s = MagicString::new("abCDefghijKLmn");
// s._move(2, 4, 6)?;
// s._move(10, 12, 8)?;
// assert_eq!(s.to_string(), "abefCDghKLijmn");

// assert_eq!(s.slice(1, -1)?, "befCDghKLijm");
// assert_eq!(s.slice(2, -2)?, "CDghKL");
// assert_eq!(s.slice(3, -3)?, "DghK");
// assert_eq!(s.slice(4, -4)?, "efCDghKLij");
// assert_eq!(s.slice(5, -5)?, "fCDghKLi");
// assert_eq!(s.slice(6, -6)?, "gh");
// Ok(())
// }

// #[test]
// fn supports_characters_moved_inward() -> Result {
// let mut s = MagicString::new("abCDefghIJkl");
// // s._move(2, 4, 8)?;
// // s._move(8, 10, 4)?;
// assert_eq!(s.to_string(), "abIJefghCDkl");

// assert_eq!(s.slice(1, -1)?, "bIJefghCDk");
// assert_eq!(s.slice(2, -2)?, "");
// assert_eq!(s.slice(3, -3)?, "");
// assert_eq!(s.slice(-3, 3)?, "JefghC");
// assert_eq!(s.slice(4, -4)?, "efgh");
// assert_eq!(s.slice(0, 3)?, "abIJefghC");
// // assert_eq!(s.slice(3)?, "Dkl");
// assert_eq!(s.slice(0, -3)?, "abI");
// // assert_eq!(s.slice(-3)?, "JefghCDkl");
// Ok(())
// }
}
1 change: 1 addition & 0 deletions node/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export class MagicString {
trimEnd(pattern?: string | undefined | null): this
trimLines(): this
remove(start: number, end: number): this
slice(start: number, end: number): string
isEmpty(): boolean
generateMap(options?: Partial<GenerateDecodedMapOptions>): {
toString: () => string
Expand Down
5 changes: 5 additions & 0 deletions node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ impl MagicString {
Ok(self)
}

#[napi]
pub fn slice(&mut self, start: i64, end: i64) -> Result<String> {
Ok(self.0.slice(start, end)?)
}

#[napi]
pub fn is_empty(&self) -> Result<bool> {
Ok(self.0.is_empty())
Expand Down
Loading