Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(transformer): support optional-catch-binding plugin #4885

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions crates/oxc_transformer/src/es2019/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
mod optional_catch_binding;
mod options;

pub use optional_catch_binding::OptionalCatchBinding;
pub use options::ES2019Options;
use oxc_ast::ast::*;
use oxc_traverse::TraverseCtx;
use std::rc::Rc;

use crate::context::Ctx;

#[allow(dead_code)]
pub struct ES2019<'a> {
ctx: Ctx<'a>,
options: ES2019Options,

// Plugins
optional_catch_binding: OptionalCatchBinding<'a>,
}

impl<'a> ES2019<'a> {
pub fn new(options: ES2019Options, ctx: Ctx<'a>) -> Self {
Self { optional_catch_binding: OptionalCatchBinding::new(Rc::clone(&ctx)), ctx, options }
}

pub fn transform_catch_clause(
&mut self,
clause: &mut CatchClause<'a>,
ctx: &mut TraverseCtx<'a>,
) {
if self.options.optional_catch_binding {
self.optional_catch_binding.transform_catch_clause(clause, ctx);
}
}
}
52 changes: 52 additions & 0 deletions crates/oxc_transformer/src/es2019/optional_catch_binding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use std::cell::Cell;

use oxc_ast::ast::*;
use oxc_semantic::SymbolFlags;
use oxc_span::SPAN;
use oxc_traverse::TraverseCtx;

use crate::context::Ctx;

/// ES2019: Optional Catch Binding
///
/// References:
/// * <https://babel.dev/docs/babel-plugin-transform-optional-catch-binding>
/// * <https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-optional-catch-binding>
pub struct OptionalCatchBinding<'a> {
_ctx: Ctx<'a>,
}

impl<'a> OptionalCatchBinding<'a> {
pub fn new(ctx: Ctx<'a>) -> Self {
Self { _ctx: ctx }
}

/// If CatchClause has no param, add a parameter called `unused`.
///
/// ```ts
/// try {}
/// catch {}
/// ```
/// too
/// ```ts
/// try {}
/// catch (_unused) {}
/// ```
#[allow(clippy::unused_self)]
pub fn transform_catch_clause(&self, clause: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {
if clause.param.is_some() {
return;
}
let symbol_id =
ctx.generate_uid("unused", ctx.scoping.current_scope_id(), SymbolFlags::CatchVariable);
let name = ctx.ast.atom(ctx.symbols().get_name(symbol_id));
let binding_identifier =
BindingIdentifier { span: SPAN, symbol_id: Cell::new(Some(symbol_id)), name };
let binding_pattern_kind =
ctx.ast.binding_pattern_kind_from_binding_identifier(binding_identifier);
let binding_pattern =
ctx.ast.binding_pattern(binding_pattern_kind, None::<TSTypeAnnotation<'a>>, false);
let param = ctx.ast.catch_parameter(SPAN, binding_pattern);
clause.param = Some(param);
}
}
16 changes: 16 additions & 0 deletions crates/oxc_transformer/src/es2019/options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use serde::Deserialize;

#[derive(Debug, Default, Clone, Deserialize)]
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
pub struct ES2019Options {
#[serde(skip)]
pub optional_catch_binding: bool,
}

impl ES2019Options {
#[must_use]
pub fn with_optional_catch_binding(mut self, enable: bool) -> Self {
self.optional_catch_binding = enable;
self
}
}
10 changes: 9 additions & 1 deletion crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod options;
mod env;
mod es2015;
mod es2016;
mod es2019;
mod es2020;
mod react;
mod typescript;
Expand All @@ -28,6 +29,7 @@ mod helpers {
use std::{path::Path, rc::Rc};

use es2016::ES2016;
use es2019::ES2019;
use es2020::ES2020;
use oxc_allocator::{Allocator, Vec};
use oxc_ast::{ast::*, AstBuilder, Trivias};
Expand Down Expand Up @@ -63,6 +65,7 @@ pub struct Transformer<'a> {
x0_typescript: TypeScript<'a>,
x1_react: React<'a>,
x2_es2020: ES2020<'a>,
x2_es2019: ES2019<'a>,
x2_es2016: ES2016<'a>,
x3_es2015: ES2015<'a>,
}
Expand All @@ -88,8 +91,9 @@ impl<'a> Transformer<'a> {
ctx: Rc::clone(&ctx),
x0_typescript: TypeScript::new(options.typescript, Rc::clone(&ctx)),
x1_react: React::new(options.react, Rc::clone(&ctx)),
x2_es2016: ES2016::new(options.es2016, Rc::clone(&ctx)),
x2_es2020: ES2020::new(options.es2020, Rc::clone(&ctx)),
x2_es2019: ES2019::new(options.es2019, Rc::clone(&ctx)),
x2_es2016: ES2016::new(options.es2016, Rc::clone(&ctx)),
x3_es2015: ES2015::new(options.es2015, ctx),
}
}
Expand Down Expand Up @@ -317,6 +321,10 @@ impl<'a> Traverse<'a> for Transformer<'a> {
self.x0_typescript.transform_for_in_statement(stmt, ctx);
}

fn enter_catch_clause(&mut self, clause: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {
self.x2_es2019.transform_catch_clause(clause, ctx);
}

fn enter_ts_export_assignment(
&mut self,
export_assignment: &mut TSExportAssignment<'a>,
Expand Down
9 changes: 9 additions & 0 deletions crates/oxc_transformer/src/options/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
env::{can_enable_plugin, EnvOptions, Versions},
es2015::{ArrowFunctionsOptions, ES2015Options},
es2016::ES2016Options,
es2019::ES2019Options,
es2020::ES2020Options,
options::babel::BabelOptions,
react::ReactOptions,
Expand Down Expand Up @@ -39,6 +40,8 @@ pub struct TransformOptions {

pub es2016: ES2016Options,

pub es2019: ES2019Options,

pub es2020: ES2020Options,
}

Expand Down Expand Up @@ -115,6 +118,11 @@ impl TransformOptions {
enable_plugin(plugin_name, options, &env_options, &targets).is_some()
});

let es2019 = ES2019Options::default().with_optional_catch_binding({
let plugin_name = "transform-optional-catch-binding";
enable_plugin(plugin_name, options, &env_options, &targets).is_some()
});

let es2020 = ES2020Options::default().with_nullish_coalescing_operator({
let plugin_name = "transform-nullish-coalescing-operator";
enable_plugin(plugin_name, options, &env_options, &targets).is_some()
Expand Down Expand Up @@ -152,6 +160,7 @@ impl TransformOptions {
react,
es2015,
es2016,
es2019,
es2020,
})
}
Expand Down
3 changes: 2 additions & 1 deletion tasks/transform_conformance/babel.snap.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
commit: 12619ffe

Passed: 458/943
Passed: 462/947

# All Passed:
* babel-plugin-transform-optional-catch-binding
* babel-preset-react
* babel-plugin-transform-react-display-name
* babel-plugin-transform-react-jsx-self
Expand Down
3 changes: 2 additions & 1 deletion tasks/transform_conformance/babel_exec.snap.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
commit: 12619ffe

Passed: 12/18
Passed: 13/19

# All Passed:
* babel-plugin-transform-nullish-coalescing-operator
* babel-plugin-transform-optional-catch-binding
* babel-plugin-transform-exponentiation-operator
* babel-plugin-transform-arrow-functions

Expand Down
3 changes: 2 additions & 1 deletion tasks/transform_conformance/oxc.snap.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
commit: 12619ffe

Passed: 5/8
Passed: 6/9

# All Passed:
* babel-plugin-transform-optional-catch-binding
* babel-plugin-transform-react-jsx


Expand Down
2 changes: 1 addition & 1 deletion tasks/transform_conformance/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub(crate) const PLUGINS: &[&str] = &[
// // [Syntax] "babel-plugin-transform-syntax-dynamic-import",
// // [Syntax] "babel-plugin-transform-syntax-import-meta",
// // ES2019
// "babel-plugin-transform-optional-catch-binding",
"babel-plugin-transform-optional-catch-binding",
// "babel-plugin-transform-json-strings",
// // ES2018
// "babel-plugin-transform-async-generator-functions",
Expand Down