From 97969e9e5806a9e8fedb4321c8b94e707245c7b8 Mon Sep 17 00:00:00 2001 From: ShuiRuTian <158983297@qq.com> Date: Thu, 14 Nov 2024 21:25:01 +0800 Subject: [PATCH] add numeric-separator transformer --- crates/oxc_transformer/src/es2021/mod.rs | 12 ++- .../src/es2021/numeric_separator.rs | 79 +++++++++++++++++++ crates/oxc_transformer/src/es2021/options.rs | 2 + .../src/options/babel/plugins.rs | 1 + crates/oxc_transformer/src/options/env.rs | 3 +- crates/oxc_transformer/src/options/mod.rs | 1 + tasks/transform_conformance/src/constants.rs | 2 +- 7 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 crates/oxc_transformer/src/es2021/numeric_separator.rs diff --git a/crates/oxc_transformer/src/es2021/mod.rs b/crates/oxc_transformer/src/es2021/mod.rs index b2698c99ee879..a1b2137cf55cd 100644 --- a/crates/oxc_transformer/src/es2021/mod.rs +++ b/crates/oxc_transformer/src/es2021/mod.rs @@ -4,9 +4,11 @@ use oxc_traverse::{Traverse, TraverseCtx}; use crate::TransformCtx; mod logical_assignment_operators; +mod numeric_separator; mod options; pub use logical_assignment_operators::LogicalAssignmentOperators; +pub use numeric_separator::NumericSeparator; pub use options::ES2021Options; pub struct ES2021<'a, 'ctx> { @@ -14,11 +16,16 @@ pub struct ES2021<'a, 'ctx> { // Plugins logical_assignment_operators: LogicalAssignmentOperators<'a, 'ctx>, + numeric_separator: NumericSeparator<'a, 'ctx>, } impl<'a, 'ctx> ES2021<'a, 'ctx> { pub fn new(options: ES2021Options, ctx: &'ctx TransformCtx<'a>) -> Self { - Self { logical_assignment_operators: LogicalAssignmentOperators::new(ctx), options } + Self { + logical_assignment_operators: LogicalAssignmentOperators::new(ctx), + numeric_separator: NumericSeparator::new(ctx), + options, + } } } @@ -27,5 +34,8 @@ impl<'a, 'ctx> Traverse<'a> for ES2021<'a, 'ctx> { if self.options.logical_assignment_operators { self.logical_assignment_operators.enter_expression(expr, ctx); } + if self.options.numeric_separator { + self.numeric_separator.enter_expression(expr, ctx); + } } } 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 0000000000000..01ee9d28d0432 --- /dev/null +++ b/crates/oxc_transformer/src/es2021/numeric_separator.rs @@ -0,0 +1,79 @@ +//! ES2021: Numeric Separator +//! +//! This plugin remove underscore(_) in number (100_0_0). +//! +//! > This plugin is included in `preset-env`, in ES2021 +//! +//! ## Example +//! +//! Input: +//! ```js +//! Decimal Literals +//! let budget = 1_000_000_000_000; +//! +//! Binary Literals +//! let nibbles = 0b1010_0001_1000_0101; +//! +//! Hex Literal +//! let message = 0xa0_b0_c0; +//! ``` +//! +//! Output: +//! ```js +//! Decimal Literals +//! let budget = 1000000000000; +//! +//! Binary Literals +//! let nibbles = 0b1010000110000101; +//! +//! Hex Literal +//! let message = 0xa0b0c0; +//! ``` +//! +//! ## Implementation +//! +//! Implementation based on [@babel/plugin-transform-numeric-separator](https://babel.dev/docs/babel-plugin-transform-numeric-separator). +//! +//! ## References: +//! * Babel plugin implementation: +//! * Numeric Separator TC39 proposal: + +use oxc_ast::ast::*; +use oxc_span::SPAN; +use oxc_traverse::{Traverse, TraverseCtx}; + +use crate::TransformCtx; + +pub struct NumericSeparator<'a, 'ctx> { + _ctx: &'ctx TransformCtx<'a>, +} + +impl<'a, 'ctx> NumericSeparator<'a, 'ctx> { + pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self { + Self { _ctx: ctx } + } +} + +const SEPARATOR: &str = "_"; + +impl<'a, 'ctx> Traverse<'a> for NumericSeparator<'a, 'ctx> { + fn enter_numeric_literal(&mut self, node: &mut NumericLiteral<'a>, ctx: &mut TraverseCtx<'a>) { + let raw = node.raw; + if !raw.contains(SEPARATOR) { + return; + } + let new_raw = raw.replace(SEPARATOR, ""); + let new_node = ctx.ast.numeric_literal(SPAN, node.value, new_raw, node.base); + *node = new_node; + } + + fn enter_big_int_literal(&mut self, node: &mut BigIntLiteral<'a>, ctx: &mut TraverseCtx<'a>) { + let raw = &node.raw; + if !raw.contains(SEPARATOR) { + return; + } + let new_raw = raw.replace(SEPARATOR, ""); + let new_node = ctx.ast.big_int_literal(SPAN, new_raw, node.base); + *node = new_node; + } +} diff --git a/crates/oxc_transformer/src/es2021/options.rs b/crates/oxc_transformer/src/es2021/options.rs index 6d1583dccc3cb..2f64da622e094 100644 --- a/crates/oxc_transformer/src/es2021/options.rs +++ b/crates/oxc_transformer/src/es2021/options.rs @@ -5,4 +5,6 @@ use serde::Deserialize; pub struct ES2021Options { #[serde(skip)] pub logical_assignment_operators: bool, + #[serde(skip)] + pub numeric_separator: bool, } diff --git a/crates/oxc_transformer/src/options/babel/plugins.rs b/crates/oxc_transformer/src/options/babel/plugins.rs index 79a70100012e2..339b8ef7c151c 100644 --- a/crates/oxc_transformer/src/options/babel/plugins.rs +++ b/crates/oxc_transformer/src/options/babel/plugins.rs @@ -65,6 +65,7 @@ pub struct BabelPlugins { pub nullish_coalescing_operator: bool, // ES2021 pub logical_assignment_operators: bool, + pub numeric_separator: bool, // ES2022 pub class_static_block: bool, pub class_properties: Option, diff --git a/crates/oxc_transformer/src/options/env.rs b/crates/oxc_transformer/src/options/env.rs index dbc88013e43ca..a24a5b43d8421 100644 --- a/crates/oxc_transformer/src/options/env.rs +++ b/crates/oxc_transformer/src/options/env.rs @@ -86,7 +86,7 @@ impl EnvOptions { // Turn this on would throw error for all bigints. big_int: false, }, - es2021: ES2021Options { logical_assignment_operators: true }, + es2021: ES2021Options { logical_assignment_operators: true, numeric_separator: true }, es2022: ES2022Options { class_static_block: true, class_properties: if include_unfinished_plugins { @@ -184,6 +184,7 @@ impl From for EnvOptions { }, es2021: ES2021Options { logical_assignment_operators: o.has_feature(ES2020LogicalAssignmentOperators), + numeric_separator: o.has_feature(ES2021NumericSeparator), }, es2022: ES2022Options { class_static_block: o.has_feature(ES2022ClassStaticBlock), diff --git a/crates/oxc_transformer/src/options/mod.rs b/crates/oxc_transformer/src/options/mod.rs index ba9d44a097e19..574dadc3dba6d 100644 --- a/crates/oxc_transformer/src/options/mod.rs +++ b/crates/oxc_transformer/src/options/mod.rs @@ -218,6 +218,7 @@ impl TryFrom<&BabelOptions> for TransformOptions { let es2021 = ES2021Options { logical_assignment_operators: options.plugins.logical_assignment_operators || env.es2021.logical_assignment_operators, + numeric_separator: options.plugins.numeric_separator || env.es2021.numeric_separator, }; let es2022 = ES2022Options { diff --git a/tasks/transform_conformance/src/constants.rs b/tasks/transform_conformance/src/constants.rs index dc0b3e7288cd9..f970eb198ba4a 100644 --- a/tasks/transform_conformance/src/constants.rs +++ b/tasks/transform_conformance/src/constants.rs @@ -10,7 +10,7 @@ pub(crate) const PLUGINS: &[&str] = &[ // // [Syntax] "babel-plugin-transform-syntax-top-level-await", // ES2021 "babel-plugin-transform-logical-assignment-operators", - // "babel-plugin-transform-numeric-separator", + "babel-plugin-transform-numeric-separator", // ES2020 // "babel-plugin-transform-export-namespace-from", // "babel-plugin-transform-dynamic-import",