diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index 49039a1d8e48..092d068c3025 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -1167,11 +1167,7 @@ fn print_non_negative_float(value: f64, _p: &Codegen<{ MINIF impl<'a, const MINIFY: bool> Gen for BigIntLiteral<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, _ctx: Context) { p.add_source_mapping(self.span.start); - if self.raw.contains('_') { - p.print_str(self.raw.replace('_', "").as_bytes()); - } else { - p.print_str(self.raw.as_bytes()); - } + p.print_str(self.raw.as_bytes()); } } diff --git a/crates/oxc_transformer/src/es2015/literals.rs b/crates/oxc_transformer/src/es2015/literals.rs index 56d160f4253d..75c439bdb829 100644 --- a/crates/oxc_transformer/src/es2015/literals.rs +++ b/crates/oxc_transformer/src/es2015/literals.rs @@ -33,7 +33,7 @@ impl<'a> Literals<'a> { if let [b'0', b'b' | b'B' | b'o' | b'O'] = lit.raw[0..2].as_bytes() { // Set binary and octal raw values to empty, It would force the codegen, - // to generate them from their value. + // go generate them from their value. lit.raw = ""; } } diff --git a/crates/oxc_transformer/src/es2021/mod.rs b/crates/oxc_transformer/src/es2021/mod.rs index 4818faba8cdf..9601b563fc94 100644 --- a/crates/oxc_transformer/src/es2021/mod.rs +++ b/crates/oxc_transformer/src/es2021/mod.rs @@ -1,3 +1,5 @@ mod logical_assignment_operators; +mod numeric_separator; pub use logical_assignment_operators::LogicalAssignmentOperators; +pub use numeric_separator::NumericSeparator; diff --git a/crates/oxc_transformer/src/es2021/numeric_separator.rs b/crates/oxc_transformer/src/es2021/numeric_separator.rs new file mode 100644 index 000000000000..3c31e2d7b5e9 --- /dev/null +++ b/crates/oxc_transformer/src/es2021/numeric_separator.rs @@ -0,0 +1,36 @@ +use oxc_ast::ast::*; +use oxc_span::Atom; + +use crate::{ + context::TransformerCtx, + options::{TransformOptions, TransformTarget}, +}; + +/// ES2021: Numeric Separator +/// +/// References: +/// * +pub struct NumericSeparator<'a> { + ctx: TransformerCtx<'a>, +} + +impl<'a> NumericSeparator<'a> { + #![allow(clippy::unused_self)] + + pub fn new(ctx: TransformerCtx<'a>, options: &TransformOptions) -> Option { + (options.target < TransformTarget::ES2021 || options.numeric_separator) + .then_some(Self { ctx }) + } + + pub fn transform_number_literal(&mut self, lit: &mut NumericLiteral<'a>) { + if !lit.raw.is_empty() { + lit.raw = self.ctx.ast.new_str(lit.raw.replace('_', "").as_str()); + } + } + + pub fn transform_bigint_literal(&mut self, lit: &mut BigIntLiteral<'a>) { + if !lit.raw.is_empty() { + lit.raw = Atom::from(self.ctx.ast.new_str(lit.raw.replace('_', "").as_str())); + } + } +} diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index f601c75247b2..9e6032e348f2 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -49,7 +49,7 @@ use crate::{ es2016::ExponentiationOperator, es2019::{JsonStrings, OptionalCatchBinding}, es2020::NullishCoalescingOperator, - es2021::LogicalAssignmentOperators, + es2021::{LogicalAssignmentOperators, NumericSeparator}, es2022::ClassStaticBlock, es3::PropertyLiteral, react_jsx::ReactJsx, @@ -78,6 +78,7 @@ pub struct Transformer<'a> { es2022_class_static_block: Option>, // es2021 es2021_logical_assignment_operators: Option>, + es2021_numeric_separator: Option>, // es2020 es2020_nullish_coalescing_operators: Option>, // es2019 @@ -120,6 +121,7 @@ impl<'a> Transformer<'a> { es2022_class_static_block: es2022::ClassStaticBlock::new(Rc::clone(&ast), &options), // es2021 es2021_logical_assignment_operators: LogicalAssignmentOperators::new(Rc::clone(&ast), ctx.clone(), &options), + es2021_numeric_separator: NumericSeparator::new(ctx.clone(), &options), // es2020 es2020_nullish_coalescing_operators: NullishCoalescingOperator::new(Rc::clone(&ast), ctx.clone(), &options), // es2019 @@ -247,21 +249,20 @@ impl<'a> VisitMut<'a> for Transformer<'a> { } fn visit_directive(&mut self, directive: &mut Directive<'a>) { - self.es2019_json_strings - .as_mut() - .map(|t: &mut JsonStrings| t.transform_directive(directive)); - // TODO: we didn't walk this through, but maybe we should? - // walk_directive_mut(self, directive); + self.es2019_json_strings.as_mut().map(|t| t.transform_directive(directive)); } fn visit_number_literal(&mut self, lit: &mut NumericLiteral<'a>) { + self.es2021_numeric_separator.as_mut().map(|t| t.transform_number_literal(lit)); self.es2015_literals.as_mut().map(|t| t.transform_number_literal(lit)); } + fn visit_bigint_literal(&mut self, lit: &mut BigIntLiteral<'a>) { + self.es2021_numeric_separator.as_mut().map(|t| t.transform_bigint_literal(lit)); + } + fn visit_string_literal(&mut self, lit: &mut StringLiteral<'a>) { - self.es2019_json_strings - .as_mut() - .map(|t: &mut JsonStrings| t.transform_string_literal(lit)); + self.es2019_json_strings.as_mut().map(|t| t.transform_string_literal(lit)); self.es2015_literals.as_mut().map(|t| t.transform_string_literal(lit)); } diff --git a/crates/oxc_transformer/src/options.rs b/crates/oxc_transformer/src/options.rs index 4127cb553bd3..1ce80b3625cf 100644 --- a/crates/oxc_transformer/src/options.rs +++ b/crates/oxc_transformer/src/options.rs @@ -18,6 +18,7 @@ pub struct TransformOptions { pub class_static_block: bool, // es2021 pub logical_assignment_operators: bool, + pub numeric_separator: bool, // es2020 pub nullish_coalescing_operator: Option, // es2019 diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index ae353bc18991..afb79a2fd20b 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,6 +1,7 @@ -Passed: 319/1415 +Passed: 320/1415 # All Passed: +* babel-plugin-transform-numeric-separator * babel-plugin-transform-optional-catch-binding * babel-plugin-transform-json-strings * babel-plugin-transform-shorthand-properties @@ -519,9 +520,6 @@ Passed: 319/1415 # babel-plugin-transform-logical-assignment-operators (5/6) * logical-assignment/null-coalescing/input.js -# babel-plugin-transform-numeric-separator (1/2) -* numeric-separator/used-with-transform-literals/input.js - # babel-plugin-transform-export-namespace-from (0/4) * export-namespace/namespace-default/input.mjs * export-namespace/namespace-es6/input.mjs diff --git a/tasks/transform_conformance/src/test_case.rs b/tasks/transform_conformance/src/test_case.rs index f67b44a998e8..23772a544646 100644 --- a/tasks/transform_conformance/src/test_case.rs +++ b/tasks/transform_conformance/src/test_case.rs @@ -109,6 +109,7 @@ pub trait TestCase { logical_assignment_operators: options .get_plugin("transform-logical-assignment-operators") .is_some(), + numeric_separator: options.get_plugin("transform-numeric-separator").is_some(), nullish_coalescing_operator: options .get_plugin("transform-nullish-coalescing-operator") .map(get_options::),