feat(transformer): support all /regex/ to new RegExp transforms (#5387)

related: #4754

The implementation port from [esbuild](332727499e/internal/js_parser/js_parser.go (L12820-L12840)). And cover all babel's regexp plugins

---

## The following description was generated by `Graphite` 😋

### TL;DR

Added support for transforming various RegExp features to ensure compatibility with older JavaScript environments.

### What changed?

- Implemented a new `RegExp` transformer to handle unsupported RegExp literal features
- Added options to control different RegExp transformations (e.g., sticky flag, unicode flag, dot-all flag, etc.)
- Updated the transformer to convert unsupported RegExp literals into `new RegExp()` constructor calls
- Added test cases for different RegExp transformations
- Integrated the new RegExp transformer into the existing transformation pipeline

### How to test?

1. Run the existing test suite to ensure no regressions
2. Execute the new RegExp-specific tests in the `tasks/transform_conformance/tests/esbuild-tests/test/fixtures/regexp/` directory
3. Try transforming code with various RegExp features using different target environments to verify correct transformations
This commit is contained in:
Dunqing 2024-09-05 11:04:45 +00:00
parent d9d29f8705
commit c59d8b3c9b
35 changed files with 477 additions and 44 deletions

1
Cargo.lock generated
View file

@ -1955,6 +1955,7 @@ dependencies = [
"oxc_codegen",
"oxc_diagnostics",
"oxc_parser",
"oxc_regular_expression",
"oxc_semantic",
"oxc_span",
"oxc_syntax",

View file

@ -21,13 +21,14 @@ test = false
doctest = false
[dependencies]
oxc_ast = { workspace = true }
oxc_span = { workspace = true }
oxc_allocator = { workspace = true }
oxc_diagnostics = { workspace = true }
oxc_syntax = { workspace = true, features = ["to_js_string"] }
oxc_traverse = { workspace = true }
oxc_semantic = { workspace = true }
oxc_ast = { workspace = true }
oxc_span = { workspace = true }
oxc_allocator = { workspace = true }
oxc_diagnostics = { workspace = true }
oxc_syntax = { workspace = true, features = ["to_js_string"] }
oxc_traverse = { workspace = true }
oxc_semantic = { workspace = true }
oxc_regular_expression = { workspace = true }
dashmap = { workspace = true }
indexmap = { workspace = true }

View file

@ -8,10 +8,17 @@ use crate::env::{targets::version::Version, Versions};
fn features() -> &'static FxHashMap<String, Versions> {
static FEATURES: OnceLock<FxHashMap<String, Versions>> = OnceLock::new();
FEATURES.get_or_init(|| {
let map: FxHashMap<String, FxHashMap<String, String>> =
let mut map: FxHashMap<String, FxHashMap<String, String>> =
serde_json::from_str(include_str!("./@babel/compat_data/data/plugins.json"))
.expect("failed to parse json");
map.extend(
serde_json::from_str::<FxHashMap<String, FxHashMap<String, String>>>(include_str!(
"./esbuild/features.json"
))
.expect("failed to parse json"),
);
map.into_iter()
.map(|(feature, mut versions)| {
(feature, {

View file

@ -0,0 +1,23 @@
{
"esbuild-regexp-lookbehind-assertions": {
"chrome": "62",
"deno": "1.0",
"edge": "79",
"firefox": "78",
"hermes": "0.7",
"ios": "16.4",
"node": "8.10",
"opera": "49",
"safari": "16.4"
},
"esbuild-regexp-match-indices": {
"chrome": "90",
"deno": "1.8",
"edge": "90",
"firefox": "88",
"ios": "15.0",
"node": "16.0",
"opera": "76",
"safari": "15.0"
}
}

View file

@ -21,6 +21,7 @@ mod es2019;
mod es2020;
mod es2021;
mod react;
mod regexp;
mod typescript;
mod helpers {
@ -41,6 +42,7 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_semantic::{ScopeTree, SymbolTable};
use oxc_span::{SourceType, SPAN};
use oxc_traverse::{traverse_mut, Traverse, TraverseCtx};
use regexp::RegExp;
pub use crate::{
compiler_assumptions::CompilerAssumptions,
@ -74,6 +76,7 @@ pub struct Transformer<'a> {
x2_es2018: ES2018<'a>,
x2_es2016: ES2016<'a>,
x3_es2015: ES2015<'a>,
x4_regexp: RegExp<'a>,
}
impl<'a> Transformer<'a> {
@ -102,7 +105,8 @@ impl<'a> Transformer<'a> {
x2_es2019: ES2019::new(options.es2019, Rc::clone(&ctx)),
x2_es2018: ES2018::new(options.es2018, Rc::clone(&ctx)),
x2_es2016: ES2016::new(options.es2016, Rc::clone(&ctx)),
x3_es2015: ES2015::new(options.es2015, ctx),
x3_es2015: ES2015::new(options.es2015, Rc::clone(&ctx)),
x4_regexp: RegExp::new(options.regexp, ctx),
}
}
@ -177,6 +181,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
self.x2_es2018.enter_expression(expr, ctx);
self.x2_es2016.enter_expression(expr, ctx);
self.x3_es2015.enter_expression(expr, ctx);
self.x4_regexp.enter_expression(expr, ctx);
}
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {

View file

@ -14,6 +14,7 @@ use crate::{
es2021::ES2021Options,
options::babel::BabelOptions,
react::ReactOptions,
regexp::RegExpOptions,
typescript::TypeScriptOptions,
};
@ -38,6 +39,8 @@ pub struct TransformOptions {
/// [preset-react](https://babeljs.io/docs/babel-preset-react)
pub react: ReactOptions,
pub regexp: RegExpOptions,
pub es2015: ES2015Options,
pub es2016: ES2016Options,
@ -60,6 +63,7 @@ impl TransformOptions {
es2019: ES2019Options::from_targets_and_bugfixes(targets, bugfixes),
es2020: ES2020Options::from_targets_and_bugfixes(targets, bugfixes),
es2021: ES2021Options::from_targets_and_bugfixes(targets, bugfixes),
regexp: RegExpOptions::from_targets_and_bugfixes(targets, bugfixes),
..Default::default()
}
}
@ -215,6 +219,29 @@ impl TransformOptions {
}
};
let regexp = transformer_options.regexp;
if !regexp.sticky_flag {
transformer_options.regexp.sticky_flag = options.has_plugin("transform-sticky-regex");
}
if !regexp.unicode_flag {
transformer_options.regexp.unicode_flag = options.has_plugin("transform-unicode-regex");
}
if !regexp.dot_all_flag {
transformer_options.regexp.dot_all_flag = options.has_plugin("transform-dotall-regex");
}
if !regexp.named_capture_groups {
transformer_options.regexp.named_capture_groups =
options.has_plugin("transform-named-capturing-groups-regex");
}
if !regexp.unicode_property_escapes {
transformer_options.regexp.unicode_property_escapes =
options.has_plugin("transform-unicode-property-regex");
}
if !regexp.set_notation {
transformer_options.regexp.set_notation =
options.has_plugin("transform-unicode-sets-regex");
}
transformer_options.assumptions = if options.assumptions.is_null() {
CompilerAssumptions::default()
} else {

View file

@ -0,0 +1,218 @@
//! RegExp Transformer
//!
//! This module supports various RegExp plugins to handle unsupported RegExp literal features.
//! When an unsupported feature is detected, these plugins convert the RegExp literal into
//! a `new RegExp()` constructor call to avoid syntax errors.
//!
//! Note: You will need to include a polyfill for the `RegExp` constructor in your code to have the correct runtime behavior.
//!
//! ### ES2015
//!
//! #### Sticky flag (`y`)
//! - @babel/plugin-transform-sticky-regex: <https://babeljs.io/docs/en/babel-plugin-transform-sticky-regex>
//!
//! #### Unicode flag (`u`)
//! - @babel/plugin-transform-unicode-regex: <https://babeljs.io/docs/en/babel-plugin-transform-unicode-regex>
//!
//! ### ES2018
//!
//! #### DotAll flag (`s`)
//! - @babel/plugin-transform-dotall-regex: <https://babeljs.io/docs/en/babel-plugin-transform-dotall-regex>
//! - Spec: ECMAScript 2018: <https://262.ecma-international.org/9.0/#sec-get-regexp.prototype.dotAll>
//!
//! #### Lookbehind assertions (`/(?<=x)/` and `/(?<!x)/`)
//! - Implementation: Same as esbuild's handling
//!
//! #### Named capture groups (`(?<name>x)`)
//! - @babel/plugin-transform-named-capturing-groups-regex: <https://babeljs.io/docs/en/babel-plugin-transform-named-capturing-groups-regex>
//!
//! #### Unicode property escapes (`\p{...}` and `\P{...}`)
//! - @babel/plugin-transform-unicode-property-regex: <https://babeljs.io/docs/en/babel-plugin-proposal-unicode-property-regex>
//!
//! ### ES2022
//!
//! #### Match indices flag (`d`)
//! - Implementation: Same as esbuild's handling
//!
//! ### ES2024
//!
//! #### Set notation + properties of strings (`v`)
//! - @babel/plugin-transform-unicode-sets-regex: <https://babeljs.io/docs/en/babel-plugin-proposal-unicode-sets-regex>
//! - TC39 Proposal: <https://github.com/tc39/proposal-regexp-set-notation>
mod options;
use std::borrow::Cow;
use std::mem;
pub use options::RegExpOptions;
use oxc_allocator::Box;
use oxc_allocator::Vec;
use oxc_ast::ast::*;
use oxc_regular_expression::ast::{
CharacterClass, CharacterClassContents, LookAroundAssertionKind, Pattern, Term,
};
use oxc_semantic::ReferenceFlags;
use oxc_span::Atom;
use oxc_traverse::{Traverse, TraverseCtx};
use crate::context::Ctx;
pub struct RegExp<'a> {
_ctx: Ctx<'a>,
options: RegExpOptions,
}
impl<'a> RegExp<'a> {
pub fn new(options: RegExpOptions, ctx: Ctx<'a>) -> Self {
Self { _ctx: ctx, options }
}
}
impl<'a> Traverse<'a> for RegExp<'a> {
fn enter_expression(
&mut self,
expr: &mut Expression<'a>,
ctx: &mut oxc_traverse::TraverseCtx<'a>,
) {
let Expression::RegExpLiteral(ref mut regexp) = expr else {
return;
};
if !self.has_unsupported_regular_expression_flags(regexp.regex.flags)
&& self.requires_pattern_analysis()
{
match try_parse_pattern(regexp, ctx) {
Ok(pattern) => {
let is_unsupported = self.has_unsupported_regular_expression_pattern(&pattern);
regexp.regex.pattern = RegExpPattern::Pattern(pattern);
if !is_unsupported {
return;
}
}
Err(err) => {
regexp.regex.pattern = RegExpPattern::Invalid(err);
return;
}
}
};
let pattern_source: Cow<'_, str> = match &regexp.regex.pattern {
RegExpPattern::Raw(raw) | RegExpPattern::Invalid(raw) => Cow::Borrowed(raw),
RegExpPattern::Pattern(p) => Cow::Owned(p.to_string()),
};
let callee = {
let symbol_id = ctx.scopes().find_binding(ctx.current_scope_id(), "RegExp");
let ident = ctx.create_reference_id(
regexp.span,
Atom::from("RegExp"),
symbol_id,
ReferenceFlags::read(),
);
ctx.ast.expression_from_identifier_reference(ident)
};
let mut arguments = ctx.ast.vec_with_capacity(2);
arguments.push(
ctx.ast.argument_expression(
ctx.ast.expression_string_literal(regexp.span, pattern_source),
),
);
let flags = regexp.regex.flags.to_string();
let flags =
ctx.ast.argument_expression(ctx.ast.expression_string_literal(regexp.span, flags));
arguments.push(flags);
*expr = ctx.ast.expression_new(
regexp.span,
callee,
arguments,
None::<TSTypeParameterInstantiation>,
);
}
}
impl<'a> RegExp<'a> {
fn requires_pattern_analysis(&self) -> bool {
self.options.named_capture_groups
|| self.options.unicode_property_escapes
|| self.options.look_behind_assertions
}
/// Check if the regular expression contains any unsupported flags.
fn has_unsupported_regular_expression_flags(&self, flags: RegExpFlags) -> bool {
flags.iter().any(|f| match f {
RegExpFlags::S if self.options.dot_all_flag => true,
RegExpFlags::Y if self.options.sticky_flag => true,
RegExpFlags::U if self.options.unicode_flag => true,
RegExpFlags::D if self.options.match_indices => true,
RegExpFlags::V if self.options.set_notation => true,
_ => false,
})
}
/// Check if the regular expression contains any unsupported syntax.
///
/// Based on parsed regular expression pattern.
fn has_unsupported_regular_expression_pattern(&self, pattern: &Pattern<'a>) -> bool {
let check_terms = |terms: &Vec<'a, Term>| {
terms.iter().any(|element| match element {
Term::CapturingGroup(_) if self.options.named_capture_groups => true,
Term::UnicodePropertyEscape(_) if self.options.unicode_property_escapes => true,
Term::CharacterClass(character_class) if self.options.unicode_property_escapes => {
has_unicode_property_escape_character_class(character_class)
}
Term::LookAroundAssertion(assertion)
if self.options.look_behind_assertions
&& matches!(
assertion.kind,
LookAroundAssertionKind::Lookbehind
| LookAroundAssertionKind::NegativeLookbehind
) =>
{
true
}
_ => false,
})
};
pattern.body.body.iter().any(|alternative| check_terms(&alternative.body))
}
}
fn has_unicode_property_escape_character_class(character_class: &CharacterClass) -> bool {
character_class.body.iter().any(|element| match element {
CharacterClassContents::UnicodePropertyEscape(_) => true,
CharacterClassContents::NestedCharacterClass(character_class) => {
has_unicode_property_escape_character_class(character_class)
}
_ => false,
})
}
fn try_parse_pattern<'a>(
literal: &mut RegExpLiteral<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Result<Box<'a, Pattern<'a>>, &'a str> {
// Take the ownership of the pattern
let regexp_pattern = mem::replace(&mut literal.regex.pattern, RegExpPattern::Raw(""));
match regexp_pattern {
RegExpPattern::Raw(raw) => {
use oxc_regular_expression::{ParserOptions, PatternParser};
let options = ParserOptions {
span_offset: literal.span.start + 1, // exclude `/`
unicode_mode: literal.regex.flags.contains(RegExpFlags::U)
|| literal.regex.flags.contains(RegExpFlags::V),
unicode_sets_mode: literal.regex.flags.contains(RegExpFlags::V),
};
PatternParser::new(ctx.ast.allocator, raw, options)
.parse()
.map_or_else(|_| Err(raw), |p| Ok(ctx.alloc(p)))
}
RegExpPattern::Pattern(pattern) => Ok(pattern),
RegExpPattern::Invalid(raw) => Err(raw),
}
}

View file

@ -0,0 +1,49 @@
use crate::env::{can_enable_plugin, Versions};
#[derive(Default, Debug, Clone, Copy)]
pub struct RegExpOptions {
/// Enables plugin to transform the RegExp literal has `y` flag
pub sticky_flag: bool,
/// Enables plugin to transform the RegExp literal has `u` flag
pub unicode_flag: bool,
/// Enables plugin to transform the RegExp literal has `s` flag
pub dot_all_flag: bool,
/// Enables plugin to transform the RegExp literal has `(?<=)` or `(?<!)` lookbehind assertions
pub look_behind_assertions: bool,
/// Enables plugin to transform the RegExp literal has `(?<name>x)` named capture groups
pub named_capture_groups: bool,
/// Enables plugin to transform the RegExp literal has `\p{}` and `\P{}` unicode property escapes
pub unicode_property_escapes: bool,
/// Enables plugin to transform `d` flag
pub match_indices: bool,
/// Enables plugin to transform the RegExp literal has `v` flag
pub set_notation: bool,
}
impl RegExpOptions {
#[must_use]
pub fn from_targets_and_bugfixes(targets: Option<&Versions>, bugfixes: bool) -> Self {
Self {
sticky_flag: can_enable_plugin("transform-sticky-regex", targets, bugfixes),
unicode_flag: can_enable_plugin("transform-unicode-regex", targets, bugfixes),
dot_all_flag: can_enable_plugin("transform-dotall-regex", targets, bugfixes),
look_behind_assertions: can_enable_plugin(
"esbuild-regexp-lookbehind-assertions",
targets,
bugfixes,
),
named_capture_groups: can_enable_plugin(
"transform-named-capturing-groups-regex",
targets,
bugfixes,
),
unicode_property_escapes: can_enable_plugin(
"transform-unicode-property-regex",
targets,
bugfixes,
),
match_indices: can_enable_plugin("esbuild-regexp-match-indices", targets, bugfixes),
set_notation: can_enable_plugin("transform-unicode-sets-regex", targets, bugfixes),
}
}
}

View file

@ -46,10 +46,10 @@ after transform: ScopeId(0): [ScopeId(1), ScopeId(8), ScopeId(9), ScopeId(14), S
rebuilt : ScopeId(0): [ScopeId(1), ScopeId(8), ScopeId(13), ScopeId(19), ScopeId(22), ScopeId(23)]
Symbol reference IDs mismatch:
after transform: SymbolId(1): [ReferenceId(0), ReferenceId(20), ReferenceId(22), ReferenceId(26), ReferenceId(34), ReferenceId(46), ReferenceId(48), ReferenceId(49), ReferenceId(51), ReferenceId(53), ReferenceId(55), ReferenceId(56), ReferenceId(58), ReferenceId(60), ReferenceId(65), ReferenceId(67), ReferenceId(68), ReferenceId(70), ReferenceId(74), ReferenceId(76), ReferenceId(77), ReferenceId(78), ReferenceId(80), ReferenceId(81), ReferenceId(83), ReferenceId(86), ReferenceId(89), ReferenceId(91), ReferenceId(97)]
rebuilt : SymbolId(0): [ReferenceId(38), ReferenceId(39), ReferenceId(42), ReferenceId(44), ReferenceId(47), ReferenceId(53), ReferenceId(54), ReferenceId(56), ReferenceId(60), ReferenceId(62), ReferenceId(65), ReferenceId(68), ReferenceId(71), ReferenceId(73), ReferenceId(79)]
rebuilt : SymbolId(0): [ReferenceId(39), ReferenceId(40), ReferenceId(43), ReferenceId(45), ReferenceId(48), ReferenceId(54), ReferenceId(55), ReferenceId(57), ReferenceId(61), ReferenceId(63), ReferenceId(66), ReferenceId(69), ReferenceId(72), ReferenceId(74), ReferenceId(80)]
Unresolved references mismatch:
after transform: ["Object", "true", "undefined"]
rebuilt : ["Object", "undefined"]
after transform: ["Object", "RegExp", "true", "undefined"]
rebuilt : ["Object", "RegExp", "undefined"]
tasks/coverage/typescript/tests/cases/compiler/APISample_linter.ts
semantic error: Bindings mismatch:
@ -1496,43 +1496,43 @@ after transform: ScopeId(1): ["Tany"]
rebuilt : ScopeId(1): []
Reference symbol mismatch:
after transform: ReferenceId(0): Some("a")
rebuilt : ReferenceId(0): None
Reference symbol mismatch:
after transform: ReferenceId(1): Some("a")
rebuilt : ReferenceId(1): None
Reference symbol mismatch:
after transform: ReferenceId(2): Some("a")
after transform: ReferenceId(1): Some("a")
rebuilt : ReferenceId(2): None
Reference symbol mismatch:
after transform: ReferenceId(3): Some("a")
after transform: ReferenceId(2): Some("a")
rebuilt : ReferenceId(3): None
Reference symbol mismatch:
after transform: ReferenceId(4): Some("a")
after transform: ReferenceId(3): Some("a")
rebuilt : ReferenceId(4): None
Reference symbol mismatch:
after transform: ReferenceId(5): Some("A")
after transform: ReferenceId(4): Some("a")
rebuilt : ReferenceId(5): None
Reference symbol mismatch:
after transform: ReferenceId(6): Some("A")
after transform: ReferenceId(5): Some("A")
rebuilt : ReferenceId(6): None
Reference symbol mismatch:
after transform: ReferenceId(7): Some("A")
after transform: ReferenceId(6): Some("A")
rebuilt : ReferenceId(7): None
Reference symbol mismatch:
after transform: ReferenceId(8): Some("A")
after transform: ReferenceId(7): Some("A")
rebuilt : ReferenceId(8): None
Reference symbol mismatch:
after transform: ReferenceId(9): Some("A")
after transform: ReferenceId(8): Some("A")
rebuilt : ReferenceId(9): None
Reference symbol mismatch:
after transform: ReferenceId(10): Some("A")
after transform: ReferenceId(9): Some("A")
rebuilt : ReferenceId(10): None
Reference symbol mismatch:
after transform: ReferenceId(11): Some("A")
after transform: ReferenceId(10): Some("A")
rebuilt : ReferenceId(11): None
Reference symbol mismatch:
after transform: ReferenceId(11): Some("A")
rebuilt : ReferenceId(12): None
Unresolved references mismatch:
after transform: []
rebuilt : ["A", "a"]
after transform: ["RegExp"]
rebuilt : ["A", "RegExp", "a"]
tasks/coverage/typescript/tests/cases/compiler/castNewObjectBug.ts
semantic error: Bindings mismatch:
@ -5108,8 +5108,8 @@ Reference symbol mismatch:
after transform: ReferenceId(0): Some("require")
rebuilt : ReferenceId(0): None
Unresolved references mismatch:
after transform: ["Error", "JSON"]
rebuilt : ["Error", "JSON", "require"]
after transform: ["Error", "JSON", "RegExp"]
rebuilt : ["Error", "JSON", "RegExp", "require"]
tasks/coverage/typescript/tests/cases/compiler/controlFlowUnionContainingTypeParameter1.ts
semantic error: Bindings mismatch:
@ -31707,7 +31707,10 @@ rebuilt : ["undefined"]
tasks/coverage/typescript/tests/cases/conformance/controlFlow/controlFlowDoWhileStatement.ts
semantic error: Unresolved references mismatch:
after transform: ["Function", "RegExp", "undefined"]
rebuilt : ["undefined"]
rebuilt : ["RegExp", "undefined"]
Unresolved reference IDs mismatch for "RegExp":
after transform: [ReferenceId(23), ReferenceId(33), ReferenceId(42), ReferenceId(43)]
rebuilt : [ReferenceId(29), ReferenceId(38)]
tasks/coverage/typescript/tests/cases/conformance/controlFlow/controlFlowElementAccess2.ts
semantic error: Bindings mismatch:
@ -31746,7 +31749,10 @@ rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)]
tasks/coverage/typescript/tests/cases/conformance/controlFlow/controlFlowForInStatement.ts
semantic error: Unresolved references mismatch:
after transform: ["Function", "RegExp"]
rebuilt : []
rebuilt : ["RegExp"]
Unresolved reference IDs mismatch for "RegExp":
after transform: [ReferenceId(0), ReferenceId(11)]
rebuilt : [ReferenceId(1)]
tasks/coverage/typescript/tests/cases/conformance/controlFlow/controlFlowForInStatement2.ts
semantic error: Bindings mismatch:
@ -31809,10 +31815,10 @@ after transform: ScopeId(12): ["T", "data"]
rebuilt : ScopeId(12): ["data"]
Symbol reference IDs mismatch:
after transform: SymbolId(15): [ReferenceId(29), ReferenceId(30)]
rebuilt : SymbolId(11): [ReferenceId(23)]
Unresolved references mismatch:
after transform: ["Error", "JSON", "RegExp"]
rebuilt : ["Error", "JSON"]
rebuilt : SymbolId(11): [ReferenceId(24)]
Unresolved reference IDs mismatch for "RegExp":
after transform: [ReferenceId(0), ReferenceId(31)]
rebuilt : [ReferenceId(1)]
tasks/coverage/typescript/tests/cases/conformance/controlFlow/controlFlowInOperator.ts
semantic error: Bindings mismatch:
@ -31971,8 +31977,8 @@ Symbol reference IDs mismatch:
after transform: SymbolId(0): [ReferenceId(0), ReferenceId(1), ReferenceId(5), ReferenceId(6), ReferenceId(16)]
rebuilt : SymbolId(0): [ReferenceId(11)]
Unresolved references mismatch:
after transform: ["Object", "RegExpExecArray", "getFooOrNull", "getStringOrNumberOrNull"]
rebuilt : ["getFooOrNull", "getStringOrNumberOrNull"]
after transform: ["Object", "RegExp", "RegExpExecArray", "getFooOrNull", "getStringOrNumberOrNull"]
rebuilt : ["RegExp", "getFooOrNull", "getStringOrNumberOrNull"]
tasks/coverage/typescript/tests/cases/conformance/controlFlow/typeGuardsTypeParameters.ts
semantic error: Bindings mismatch:
@ -35668,9 +35674,9 @@ rebuilt : ScopeId(0): ["a", "arr", "x"]
Scope children mismatch:
after transform: ScopeId(0): [ScopeId(1), ScopeId(3)]
rebuilt : ScopeId(0): [ScopeId(1)]
Unresolved references mismatch:
after transform: ["RegExp"]
rebuilt : []
Unresolved reference IDs mismatch for "RegExp":
after transform: [ReferenceId(0), ReferenceId(22)]
rebuilt : [ReferenceId(13)]
tasks/coverage/typescript/tests/cases/conformance/expressions/binaryOperators/additionOperator/additionOperatorWithAnyAndEveryType.ts
semantic error: Namespaces exporting non-const are not supported by Babel. Change to const or see: https://babeljs.io/docs/en/babel-plugin-transform-typescript
@ -42468,8 +42474,8 @@ Reference symbol mismatch:
after transform: ReferenceId(1): Some("a")
rebuilt : ReferenceId(1): None
Unresolved references mismatch:
after transform: []
rebuilt : ["a"]
after transform: ["RegExp"]
rebuilt : ["RegExp", "a"]
tasks/coverage/typescript/tests/cases/conformance/parser/ecmascript5/Symbols/parserES5SymbolIndexer1.ts
semantic error: Bindings mismatch:
@ -43194,7 +43200,7 @@ after transform: ScopeId(10): ["T", "x"]
rebuilt : ScopeId(9): ["x"]
Symbol reference IDs mismatch:
after transform: SymbolId(2): [ReferenceId(2), ReferenceId(4), ReferenceId(5), ReferenceId(21), ReferenceId(42)]
rebuilt : SymbolId(1): [ReferenceId(20), ReferenceId(40)]
rebuilt : SymbolId(1): [ReferenceId(20), ReferenceId(41)]
Symbol flags mismatch:
after transform: SymbolId(7): SymbolFlags(Export | Class)
rebuilt : SymbolId(6): SymbolFlags(Class)

View file

@ -1,11 +1,12 @@
commit: 3bcfee23
Passed: 13/41
Passed: 21/49
# All Passed:
* babel-plugin-transform-nullish-coalescing-operator
* babel-plugin-transform-optional-catch-binding
* babel-preset-typescript
* esbuild-tests
# babel-plugin-transform-arrow-functions (1/2)

View file

@ -56,6 +56,9 @@ pub(crate) const PLUGINS: &[&str] = &[
"babel-plugin-transform-react-jsx-development",
// // Proposal
// "babel-plugin-proposal-decorators",
// Tests port from esbuild
"esbuild-tests",
];
pub(crate) const PLUGINS_NOT_SUPPORTED_YET: &[&str] = &[

View file

@ -0,0 +1,21 @@
// ES2015
// RegExpSticky
x1 = /./y
// RegExpUnicode
x2 = /./u
// ES2018
// RegExpDotAllFlag
a1 = /a.b/s
// RegExpLookbehindAssertions
b1 = /(?<!x)/
b2 = /(?<=x)/
// RegExpNamedCaptureGroups
c1 = /(?<a>b)/
// RegExpUnicodePropertyEscapes
d1 = /\p{Emoji}/u
// ES2022
// RegExpMatchIndices
f1 = /y/d
// ES2024
// RegExpSetNotation
g1 = /[\p{White_Space}&&\p{ASCII}]/v

View file

@ -0,0 +1,9 @@
{
"presets": [
["env", {
"targets": {
"chrome": "40"
}
}]
]
}

View file

@ -0,0 +1,9 @@
x1 = new RegExp(".", "y");
x2 = new RegExp(".", "u");
a1 = new RegExp("a.b", "s");
b1 = new RegExp("(?<!x)", "");
b2 = new RegExp("(?<=x)", "");
c1 = new RegExp("(?<a>b)", "");
d1 = new RegExp("\\p{Emoji}", "u");
f1 = new RegExp("y", "d");
g1 = new RegExp("[\\p{White_Space}&&\\p{ASCII}]", "v");

View file

@ -0,0 +1 @@
a1 = /a.b/igm;

View file

@ -0,0 +1,9 @@
{
"presets": [
["env", {
"targets": {
"chrome": "40"
}
}]
]
}

View file

@ -0,0 +1 @@
a1 = /a.b/igm;

View file

@ -0,0 +1,5 @@
{
"plugins": [
"transform-dotall-regex"
]
}

View file

@ -0,0 +1 @@
a1 = new RegExp("a.b", "s");

View file

@ -0,0 +1,5 @@
{
"plugins": [
"transform-named-capturing-groups-regex"
]
}

View file

@ -0,0 +1 @@
c1 = new RegExp("(?<a>b)", "");

View file

@ -0,0 +1,5 @@
{
"plugins": [
"transform-sticky-regex"
]
}

View file

@ -0,0 +1 @@
x1 = new RegExp(".", "y");

View file

@ -0,0 +1,5 @@
{
"plugins": [
"transform-unicode-property-regex"
]
}

View file

@ -0,0 +1 @@
d1 = new RegExp("\\p{Emoji}", "u");

View file

@ -0,0 +1,5 @@
{
"plugins": [
"transform-unicode-regex"
]
}

View file

@ -0,0 +1 @@
x2 = new RegExp(".", "u");

View file

@ -0,0 +1 @@
g1 = /[\p{White_Space}&&\p{ASCII}]/v

View file

@ -0,0 +1,5 @@
{
"plugins": [
"transform-unicode-sets-regex"
]
}

View file

@ -0,0 +1 @@
g1 = new RegExp("[\\p{White_Space}&&\\p{ASCII}]", "v");