diff --git a/crates/oxc_transformer/src/es2015/mod.rs b/crates/oxc_transformer/src/es2015/mod.rs index 5c64a1361f132a..7ff2ccadb763f3 100644 --- a/crates/oxc_transformer/src/es2015/mod.rs +++ b/crates/oxc_transformer/src/es2015/mod.rs @@ -1,5 +1,3 @@ mod shorthand_properties; -mod sticky_regex; pub use shorthand_properties::ShorthandProperties; -pub use sticky_regex::StickyRegex; diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index c95c966aedde0e..b7b1b3f4c83a72 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -14,11 +14,13 @@ mod es2021; mod es2022; mod options; mod react_jsx; +mod regexp; mod typescript; use oxc_allocator::Allocator; use oxc_ast::{ast::*, AstBuilder, VisitMut}; use oxc_span::SourceType; +use regexp::RegexpFlags; use std::rc::Rc; use es2015::ShorthandProperties; @@ -35,6 +37,7 @@ pub use crate::options::{ #[derive(Default)] pub struct Transformer<'a> { typescript: Option>, + regexp_flags: Option>, react_jsx: Option>, // es2022 es2022_class_static_block: Option>, @@ -46,7 +49,6 @@ pub struct Transformer<'a> { es2016_exponentiation_operator: Option>, // es2015 es2015_shorthand_properties: Option>, - es2015_sticky_regex: Option>, } impl<'a> Transformer<'a> { @@ -64,6 +66,9 @@ impl<'a> Transformer<'a> { if let Some(react_options) = options.react { t.react_jsx.replace(ReactJsx::new(Rc::clone(&ast), react_options)); } + + t.regexp_flags = RegexpFlags::new_with_transform_target(Rc::clone(&ast), options.target); + if options.target < TransformTarget::ES2022 { t.es2022_class_static_block.replace(es2022::ClassStaticBlock::new(Rc::clone(&ast))); } @@ -79,7 +84,6 @@ impl<'a> Transformer<'a> { } if options.target < TransformTarget::ES2015 { t.es2015_shorthand_properties.replace(ShorthandProperties::new(Rc::clone(&ast))); - t.es2015_sticky_regex.replace(es2015::StickyRegex::new(Rc::clone(&ast))); } t } @@ -93,9 +97,10 @@ impl<'a> VisitMut<'a> for Transformer<'a> { fn visit_expression(&mut self, expr: &mut Expression<'a>) { // self.typescript.as_mut().map(|t| t.transform_expression(expr)); // self.react_jsx.as_mut().map(|t| t.transform_expression(expr)); + self.regexp_flags.as_mut().map(|t| t.transform_expression(expr)); + self.es2021_logical_assignment_operators.as_mut().map(|t| t.transform_expression(expr)); self.es2016_exponentiation_operator.as_mut().map(|t| t.transform_expression(expr)); - self.es2015_sticky_regex.as_mut().map(|t| t.transform_expression(expr)); self.visit_expression_match(expr); } diff --git a/crates/oxc_transformer/src/options.rs b/crates/oxc_transformer/src/options.rs index 01aa5ee78a6eb1..f9d7e8c9df5e18 100644 --- a/crates/oxc_transformer/src/options.rs +++ b/crates/oxc_transformer/src/options.rs @@ -10,9 +10,11 @@ pub enum TransformTarget { ES5, ES2015, ES2016, + ES2018, ES2019, ES2021, ES2022, + ES2024, #[default] ESNext, } diff --git a/crates/oxc_transformer/src/regexp/mod.rs b/crates/oxc_transformer/src/regexp/mod.rs new file mode 100644 index 00000000000000..8d924a96549b0e --- /dev/null +++ b/crates/oxc_transformer/src/regexp/mod.rs @@ -0,0 +1,3 @@ +mod regexp_flags; + +pub use regexp_flags::RegexpFlags; diff --git a/crates/oxc_transformer/src/es2015/sticky_regex.rs b/crates/oxc_transformer/src/regexp/regexp_flags.rs similarity index 50% rename from crates/oxc_transformer/src/es2015/sticky_regex.rs rename to crates/oxc_transformer/src/regexp/regexp_flags.rs index 294713d1a7d72d..033ad3448c6645 100644 --- a/crates/oxc_transformer/src/es2015/sticky_regex.rs +++ b/crates/oxc_transformer/src/regexp/regexp_flags.rs @@ -3,23 +3,32 @@ use oxc_span::{Atom, Span}; use std::rc::Rc; -/// ES2015: Sticky Regex -/// -/// References: -/// * -/// * -pub struct StickyRegex<'a> { +use crate::TransformTarget; + +/// Regexp +pub struct RegexpFlags<'a> { ast: Rc>, + transform_flags: RegExpFlags, } -impl<'a> StickyRegex<'a> { - pub fn new(ast: Rc>) -> Self { - Self { ast } +impl<'a> RegexpFlags<'a> { + pub fn new_with_transform_target( + ast: Rc>, + transform_target: TransformTarget, + ) -> Option { + let transform_flags = from_transform_target(transform_target); + + if transform_flags.is_empty() { + None + } else { + Some(Self { ast, transform_flags }) + } } pub fn transform_expression<'b>(&mut self, expr: &'b mut Expression<'a>) { let Expression::RegExpLiteral(reg_literal) = expr else { return }; - if !reg_literal.regex.flags.contains(RegExpFlags::Y) { + + if reg_literal.regex.flags.intersection(self.transform_flags).is_empty() { return; } @@ -41,3 +50,31 @@ impl<'a> StickyRegex<'a> { *expr = self.ast.new_expression(Span::default(), callee, arguments, None); } } + +fn from_transform_target(value: TransformTarget) -> RegExpFlags { + let mut flag = RegExpFlags::empty(); + + if value < TransformTarget::ESNext { + flag |= RegExpFlags::I; + flag |= RegExpFlags::M; + } + + if value < TransformTarget::ES2024 { + flag |= RegExpFlags::V; + } + + if value < TransformTarget::ES2022 { + flag |= RegExpFlags::D; + } + + if value < TransformTarget::ES2018 { + flag |= RegExpFlags::S; + } + + if value < TransformTarget::ES2015 { + flag |= RegExpFlags::Y; + flag |= RegExpFlags::U; + } + + flag +}