From 1b8f54183c883d6b3439e59e4a6f5e6e4255b697 Mon Sep 17 00:00:00 2001 From: magic-akari Date: Tue, 10 Oct 2023 23:05:45 +0800 Subject: [PATCH] feat(transformer): RegexpFlags --- crates/oxc_transformer/src/es2015/mod.rs | 2 - .../src/es2015/sticky_regex.rs | 43 ---------- crates/oxc_transformer/src/lib.rs | 11 ++- crates/oxc_transformer/src/options.rs | 3 + crates/oxc_transformer/src/regexp/mod.rs | 3 + .../src/regexp/regexp_flags.rs | 84 +++++++++++++++++++ 6 files changed, 98 insertions(+), 48 deletions(-) delete mode 100644 crates/oxc_transformer/src/es2015/sticky_regex.rs create mode 100644 crates/oxc_transformer/src/regexp/mod.rs create mode 100644 crates/oxc_transformer/src/regexp/regexp_flags.rs 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/es2015/sticky_regex.rs b/crates/oxc_transformer/src/es2015/sticky_regex.rs deleted file mode 100644 index 294713d1a7d72d..00000000000000 --- a/crates/oxc_transformer/src/es2015/sticky_regex.rs +++ /dev/null @@ -1,43 +0,0 @@ -use oxc_ast::{ast::*, AstBuilder}; -use oxc_span::{Atom, Span}; - -use std::rc::Rc; - -/// ES2015: Sticky Regex -/// -/// References: -/// * -/// * -pub struct StickyRegex<'a> { - ast: Rc>, -} - -impl<'a> StickyRegex<'a> { - pub fn new(ast: Rc>) -> Self { - Self { ast } - } - - 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) { - return; - } - - let ident = IdentifierReference::new(Span::default(), Atom::from("RegExp")); - let callee = self.ast.identifier_expression(ident); - let pattern_literal = self - .ast - .string_literal(Span::default(), Atom::from(reg_literal.regex.pattern.as_str())); - let flags_literal = self - .ast - .string_literal(Span::default(), Atom::from(reg_literal.regex.flags.to_string())); - let pattern_literal = self.ast.literal_string_expression(pattern_literal); - let flags_literal = self.ast.literal_string_expression(flags_literal); - - let mut arguments = self.ast.new_vec_with_capacity(2); - arguments.push(Argument::Expression(pattern_literal)); - arguments.push(Argument::Expression(flags_literal)); - - *expr = self.ast.new_expression(Span::default(), callee, arguments, None); - } -} 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..0609b2920c5112 100644 --- a/crates/oxc_transformer/src/options.rs +++ b/crates/oxc_transformer/src/options.rs @@ -10,9 +10,12 @@ pub enum TransformTarget { ES5, ES2015, ES2016, + ES2017, + 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/regexp/regexp_flags.rs b/crates/oxc_transformer/src/regexp/regexp_flags.rs new file mode 100644 index 00000000000000..9153a869a335b5 --- /dev/null +++ b/crates/oxc_transformer/src/regexp/regexp_flags.rs @@ -0,0 +1,84 @@ +use oxc_ast::{ast::*, AstBuilder}; +use oxc_span::{Atom, Span}; + +use std::rc::Rc; + +use crate::TransformTarget; + +/// Regexp +pub struct RegexpFlags<'a> { + ast: Rc>, + transform_flags: RegExpFlags, +} + +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.intersection(self.transform_flags).is_empty() { + return; + } + + let ident = IdentifierReference::new(Span::default(), Atom::from("RegExp")); + let callee = self.ast.identifier_expression(ident); + let pattern_literal = self + .ast + .string_literal(Span::default(), Atom::from(reg_literal.regex.pattern.as_str())); + let flags_literal = self + .ast + .string_literal(Span::default(), Atom::from(reg_literal.regex.flags.to_string())); + let pattern_literal = self.ast.literal_string_expression(pattern_literal); + let flags_literal = self.ast.literal_string_expression(flags_literal); + + let mut arguments = self.ast.new_vec_with_capacity(2); + arguments.push(Argument::Expression(pattern_literal)); + arguments.push(Argument::Expression(flags_literal)); + + *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::ES2017 { + flag |= RegExpFlags::U; + } + + if value < TransformTarget::ES2015 { + flag |= RegExpFlags::Y; + flag |= RegExpFlags::U; + } + + flag +}