mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
refactor(minifier): move string methods to oxc_ecmascript (#6472)
This commit is contained in:
parent
856cab5000
commit
bbca743689
6 changed files with 107 additions and 208 deletions
|
|
@ -17,7 +17,7 @@ description.workspace = true
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
test = false
|
test = true
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
//! Methods defined in the [ECMAScript Language Specification](https://tc39.es/ecma262).
|
//! Methods defined in the [ECMAScript Language Specification](https://tc39.es/ecma262).
|
||||||
|
|
||||||
|
// [Syntax-Directed Operations](https://tc39.es/ecma262/#sec-syntax-directed-operations)
|
||||||
mod bound_names;
|
mod bound_names;
|
||||||
mod is_simple_parameter_list;
|
mod is_simple_parameter_list;
|
||||||
mod private_bound_identifiers;
|
mod private_bound_identifiers;
|
||||||
mod prop_name;
|
mod prop_name;
|
||||||
|
|
||||||
|
// Abstract Operations
|
||||||
|
mod string_index_of;
|
||||||
|
mod string_last_index_of;
|
||||||
mod to_int_32;
|
mod to_int_32;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
bound_names::BoundNames, is_simple_parameter_list::IsSimpleParameterList,
|
bound_names::BoundNames, is_simple_parameter_list::IsSimpleParameterList,
|
||||||
private_bound_identifiers::PrivateBoundIdentifiers, prop_name::PropName, to_int_32::ToInt32,
|
private_bound_identifiers::PrivateBoundIdentifiers, prop_name::PropName,
|
||||||
|
string_index_of::StringIndexOf, string_last_index_of::StringLastIndexOf, to_int_32::ToInt32,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
50
crates/oxc_ecmascript/src/string_index_of.rs
Normal file
50
crates/oxc_ecmascript/src/string_index_of.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
use crate::ToInt32;
|
||||||
|
|
||||||
|
pub trait StringIndexOf {
|
||||||
|
/// `String.prototype.indexOf ( searchString [ , position ] )`
|
||||||
|
/// <https://tc39.es/ecma262/#sec-string.prototype.indexof>
|
||||||
|
fn index_of(&self, search_value: Option<&str>, from_index: Option<f64>) -> isize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringIndexOf for &str {
|
||||||
|
#[expect(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
|
||||||
|
fn index_of(&self, search_value: Option<&str>, from_index: Option<f64>) -> isize {
|
||||||
|
let from_index = from_index.map_or(0, |x| x.to_int_32().max(0)) as usize;
|
||||||
|
let Some(search_value) = search_value else {
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
let result = self.chars().skip(from_index).collect::<String>().find(search_value);
|
||||||
|
result.map(|index| index + from_index).map_or(-1, |index| index as isize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
#[test]
|
||||||
|
fn test_string_index_of() {
|
||||||
|
use super::StringIndexOf;
|
||||||
|
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(0.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(1.0)), 3);
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(4.0)), 5);
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(4.1)), 5);
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(0.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(-1.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(-1.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(-1.1)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("t"), Some(-1_073_741_825.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("e"), Some(0.0)), 1);
|
||||||
|
assert_eq!("test test test".index_of(Some("s"), Some(0.0)), 2);
|
||||||
|
assert_eq!("test test test".index_of(Some("test"), Some(4.0)), 5);
|
||||||
|
assert_eq!("test test test".index_of(Some("test"), Some(5.0)), 5);
|
||||||
|
assert_eq!("test test test".index_of(Some("test"), Some(6.0)), 10);
|
||||||
|
assert_eq!("test test test".index_of(Some("test"), Some(0.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("test"), Some(-1.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("not found"), Some(-1.0)), -1);
|
||||||
|
assert_eq!("test test test".index_of(Some("test"), Some(-1.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("test"), Some(-1_073_741_825.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("test"), Some(0.0)), 0);
|
||||||
|
assert_eq!("test test test".index_of(Some("notpresent"), Some(0.0)), -1);
|
||||||
|
assert_eq!("test test test".index_of(None, Some(0.0)), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
crates/oxc_ecmascript/src/string_last_index_of.rs
Normal file
40
crates/oxc_ecmascript/src/string_last_index_of.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
use crate::ToInt32;
|
||||||
|
|
||||||
|
pub trait StringLastIndexOf {
|
||||||
|
/// `String.prototype.lastIndexOf ( searchString [ , position ] )`
|
||||||
|
/// <https://tc39.es/ecma262/#sec-string.prototype.lastindexof>
|
||||||
|
fn last_index_of(&self, search_value: Option<&str>, from_index: Option<f64>) -> isize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringLastIndexOf for &str {
|
||||||
|
#[expect(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
|
||||||
|
fn last_index_of(&self, search_value: Option<&str>, from_index: Option<f64>) -> isize {
|
||||||
|
let Some(search_value) = search_value else { return -1 };
|
||||||
|
let from_index =
|
||||||
|
from_index.map_or(usize::MAX, |x| x.to_int_32().max(0) as usize + search_value.len());
|
||||||
|
self.chars()
|
||||||
|
.take(from_index)
|
||||||
|
.collect::<String>()
|
||||||
|
.rfind(search_value)
|
||||||
|
.map_or(-1, |index| index as isize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
#[test]
|
||||||
|
fn test_prototype_last_index_of() {
|
||||||
|
use super::StringLastIndexOf;
|
||||||
|
assert_eq!("test test test".last_index_of(Some("test"), Some(15.0)), 10);
|
||||||
|
assert_eq!("test test test".last_index_of(Some("test"), Some(14.0)), 10);
|
||||||
|
assert_eq!("test test test".last_index_of(Some("test"), Some(10.0)), 10);
|
||||||
|
assert_eq!("test test test".last_index_of(Some("test"), Some(9.0)), 5);
|
||||||
|
assert_eq!("test test test".last_index_of(Some("test"), Some(6.0)), 5);
|
||||||
|
assert_eq!("test test test".last_index_of(Some("test"), Some(5.0)), 5);
|
||||||
|
assert_eq!("test test test".last_index_of(Some("test"), Some(4.0)), 0);
|
||||||
|
assert_eq!("test test test".last_index_of(Some("test"), Some(0.0)), 0);
|
||||||
|
assert_eq!("test test test".last_index_of(Some("notpresent"), Some(0.0)), -1);
|
||||||
|
assert_eq!("test test test".last_index_of(None, Some(1.0)), -1);
|
||||||
|
assert_eq!("abcdef".last_index_of(Some("b"), None), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
use cow_utils::CowUtils;
|
use cow_utils::CowUtils;
|
||||||
use oxc_ast::ast::*;
|
|
||||||
use oxc_traverse::{Traverse, TraverseCtx};
|
|
||||||
use string_methods::StringUtils;
|
|
||||||
|
|
||||||
mod string_methods;
|
use oxc_ast::ast::*;
|
||||||
|
use oxc_ecmascript::{StringIndexOf, StringLastIndexOf};
|
||||||
|
use oxc_traverse::{Traverse, TraverseCtx};
|
||||||
|
|
||||||
use crate::CompressorPass;
|
use crate::CompressorPass;
|
||||||
|
|
||||||
|
|
@ -110,18 +109,12 @@ impl PeepholeReplaceKnownMethods {
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = if member.property.name.as_str() == "indexOf" {
|
let result = match member.property.name.as_str() {
|
||||||
StringUtils::evaluate_string_index_of(
|
"indexOf" => string_lit.value.as_str().index_of(search_value, search_start_index),
|
||||||
&string_lit.value,
|
"lastIndexOf" => {
|
||||||
search_value,
|
string_lit.value.as_str().last_index_of(search_value, search_start_index)
|
||||||
search_start_index,
|
}
|
||||||
)
|
_ => unreachable!(),
|
||||||
} else {
|
|
||||||
StringUtils::evaluate_string_last_index_of(
|
|
||||||
&string_lit.value,
|
|
||||||
search_value,
|
|
||||||
search_start_index,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[expect(clippy::cast_precision_loss)]
|
#[expect(clippy::cast_precision_loss)]
|
||||||
|
|
@ -1,190 +0,0 @@
|
||||||
use oxc_ecmascript::ToInt32;
|
|
||||||
|
|
||||||
pub(super) struct StringUtils;
|
|
||||||
|
|
||||||
impl StringUtils {
|
|
||||||
#[expect(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
|
|
||||||
pub(super) fn evaluate_string_index_of(
|
|
||||||
string: &str,
|
|
||||||
search_value: Option<&str>,
|
|
||||||
from_index: Option<f64>,
|
|
||||||
) -> isize {
|
|
||||||
let from_index = from_index.map_or(0, |x| x.to_int_32().max(0)) as usize;
|
|
||||||
let Some(search_value) = search_value else {
|
|
||||||
return -1;
|
|
||||||
};
|
|
||||||
let result = string.chars().skip(from_index).collect::<String>().find(search_value);
|
|
||||||
result.map(|index| index + from_index).map_or(-1, |index| index as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[expect(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
|
|
||||||
pub(super) fn evaluate_string_last_index_of(
|
|
||||||
string: &str,
|
|
||||||
search_value: Option<&str>,
|
|
||||||
from_index: Option<f64>,
|
|
||||||
) -> isize {
|
|
||||||
let Some(search_value) = search_value else { return -1 };
|
|
||||||
|
|
||||||
let from_index =
|
|
||||||
from_index.map_or(usize::MAX, |x| x.to_int_32().max(0) as usize + search_value.len());
|
|
||||||
|
|
||||||
string
|
|
||||||
.chars()
|
|
||||||
.take(from_index)
|
|
||||||
.collect::<String>()
|
|
||||||
.rfind(search_value)
|
|
||||||
.map_or(-1, |index| index as isize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
#[test]
|
|
||||||
fn test_evaluate_string_index_of() {
|
|
||||||
use super::StringUtils;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("t"), Some(0.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("t"), Some(1.0)),
|
|
||||||
3
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("t"), Some(4.0)),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("t"), Some(4.1)),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("t"), Some(0.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("t"), Some(-1.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("t"), Some(-1.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("t"), Some(-1.1)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of(
|
|
||||||
"test test test",
|
|
||||||
Some("t"),
|
|
||||||
Some(-1_073_741_825.0)
|
|
||||||
),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("e"), Some(0.0)),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("s"), Some(0.0)),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("test"), Some(4.0)),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("test"), Some(5.0)),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("test"), Some(6.0)),
|
|
||||||
10
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("test"), Some(0.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("test"), Some(-1.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("not found"), Some(-1.0)),
|
|
||||||
-1
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("test"), Some(-1.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of(
|
|
||||||
"test test test",
|
|
||||||
Some("test"),
|
|
||||||
Some(-1_073_741_825.0)
|
|
||||||
),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("test"), Some(0.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_index_of("test test test", Some("notpresent"), Some(0.0)),
|
|
||||||
-1
|
|
||||||
);
|
|
||||||
assert_eq!(StringUtils::evaluate_string_index_of("test test test", None, Some(0.0)), -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_evaluate_string_last_index_of() {
|
|
||||||
use super::StringUtils;
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", Some("test"), Some(15.0)),
|
|
||||||
10
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", Some("test"), Some(14.0)),
|
|
||||||
10
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", Some("test"), Some(10.0)),
|
|
||||||
10
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", Some("test"), Some(9.0)),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", Some("test"), Some(6.0)),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", Some("test"), Some(5.0)),
|
|
||||||
5
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", Some("test"), Some(4.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", Some("test"), Some(0.0)),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of(
|
|
||||||
"test test test",
|
|
||||||
Some("notpresent"),
|
|
||||||
Some(0.0)
|
|
||||||
),
|
|
||||||
-1
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
StringUtils::evaluate_string_last_index_of("test test test", None, Some(1.0)),
|
|
||||||
-1
|
|
||||||
);
|
|
||||||
assert_eq!(StringUtils::evaluate_string_last_index_of("abcdef", Some("b"), None), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue