From c965683f07c46bae572c527fc4b44559ddb2190c Mon Sep 17 00:00:00 2001 From: DongYun Kang Date: Wed, 19 Nov 2025 15:44:41 -0500 Subject: [PATCH 1/6] API for optional catch binding --- crates/swc_ecma_transformer/src/es2019/mod.rs | 20 ++++++++++--------- .../src/es2019/optional_catch_binding.rs | 11 ++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs diff --git a/crates/swc_ecma_transformer/src/es2019/mod.rs b/crates/swc_ecma_transformer/src/es2019/mod.rs index 9cb5e904c876..2e585353e913 100644 --- a/crates/swc_ecma_transformer/src/es2019/mod.rs +++ b/crates/swc_ecma_transformer/src/es2019/mod.rs @@ -1,17 +1,19 @@ use swc_ecma_hooks::VisitMutHook; -use crate::TraverseCtx; +use crate::{hook_utils::OptionalHook, TraverseCtx}; + +mod optional_catch_binding; #[derive(Debug, Default)] #[non_exhaustive] -pub struct Es2019Options {} - -pub fn hook(options: Es2019Options) -> impl VisitMutHook { - Es2019Pass { options } +pub struct Es2019Options { + pub optional_catch_binding: bool, } -struct Es2019Pass { - options: Es2019Options, +pub(crate) fn hook(options: Es2019Options) -> impl VisitMutHook { + OptionalHook(if options.optional_catch_binding { + Some(self::optional_catch_binding::hook()) + } else { + None + }) } - -impl VisitMutHook for Es2019Pass {} diff --git a/crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs b/crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs new file mode 100644 index 000000000000..ca312dc205de --- /dev/null +++ b/crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs @@ -0,0 +1,11 @@ +use swc_ecma_hooks::VisitMutHook; + +use crate::TraverseCtx; + +pub fn hook() -> impl VisitMutHook { + OptionalCatchBindingPass {} +} + +struct OptionalCatchBindingPass {} + +impl VisitMutHook for OptionalCatchBindingPass {} From cb744fa319f6028f1ba29ec1c0f0f4266138a390 Mon Sep 17 00:00:00 2001 From: DongYun Kang Date: Wed, 19 Nov 2025 15:44:46 -0500 Subject: [PATCH 2/6] compat --- crates/swc_ecma_compat_es2019/Cargo.toml | 1 + .../src/optional_catch_binding.rs | 20 +++---------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/crates/swc_ecma_compat_es2019/Cargo.toml b/crates/swc_ecma_compat_es2019/Cargo.toml index 2e08bd0f3ddb..ddae839709be 100644 --- a/crates/swc_ecma_compat_es2019/Cargo.toml +++ b/crates/swc_ecma_compat_es2019/Cargo.toml @@ -18,6 +18,7 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] } [dependencies] swc_common = { version = "17.0.1", path = "../swc_common" } swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" } +swc_ecma_transformer = { version = "0.1.0", path = "../swc_ecma_transformer" } swc_ecma_transforms_base = { version = "30.0.0", path = "../swc_ecma_transforms_base" } swc_ecma_utils = { version = "24.0.0", path = "../swc_ecma_utils" } swc_ecma_visit = { version = "18.0.1", path = "../swc_ecma_visit" } diff --git a/crates/swc_ecma_compat_es2019/src/optional_catch_binding.rs b/crates/swc_ecma_compat_es2019/src/optional_catch_binding.rs index 5eeede447ba4..e28dd44c0cc3 100644 --- a/crates/swc_ecma_compat_es2019/src/optional_catch_binding.rs +++ b/crates/swc_ecma_compat_es2019/src/optional_catch_binding.rs @@ -3,24 +3,10 @@ use swc_ecma_utils::private_ident; use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith}; use swc_trace_macro::swc_trace; -struct OptionalCatchBinding; - pub fn optional_catch_binding() -> impl Pass { - visit_mut_pass(OptionalCatchBinding) -} - -#[swc_trace] -impl VisitMut for OptionalCatchBinding { - noop_visit_mut_type!(fail); - - fn visit_mut_catch_clause(&mut self, cc: &mut CatchClause) { - cc.visit_mut_children_with(self); - - if cc.param.is_some() { - return; - } - cc.param = Some(private_ident!("e").into()); - } + let mut options = swc_ecma_transformer::Options::default(); + options.env.es2019.optional_catch_binding = true; + options.into_pass() } #[cfg(test)] From 8ca58f3bf078101a67127145a278a6b4c2fcf58e Mon Sep 17 00:00:00 2001 From: DongYun Kang Date: Wed, 19 Nov 2025 15:44:49 -0500 Subject: [PATCH 3/6] preset-env --- crates/swc_ecma_preset_env/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/swc_ecma_preset_env/src/lib.rs b/crates/swc_ecma_preset_env/src/lib.rs index 609a8998a114..7ffd38f37a67 100644 --- a/crates/swc_ecma_preset_env/src/lib.rs +++ b/crates/swc_ecma_preset_env/src/lib.rs @@ -185,7 +185,9 @@ where ); // ES2019 - let pass = add!(pass, OptionalCatchBinding, es2019::optional_catch_binding()); + if !caniuse(Feature::OptionalCatchBinding) { + options.env.es2019.optional_catch_binding = true; + } // ES2018 if !caniuse(Feature::ObjectRestSpread) { From cac22d2a2f8b1aeca2029260f909c1eae0b6451d Mon Sep 17 00:00:00 2001 From: DongYun Kang Date: Wed, 19 Nov 2025 15:44:53 -0500 Subject: [PATCH 4/6] lockfile --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index d0234badceab..c0ccf174b614 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5966,6 +5966,7 @@ dependencies = [ "swc_common", "swc_ecma_ast", "swc_ecma_parser", + "swc_ecma_transformer", "swc_ecma_transforms_base", "swc_ecma_transforms_testing", "swc_ecma_utils", From 3d0d323a6533c0ca56e49d8411ca459019f0457d Mon Sep 17 00:00:00 2001 From: DongYun Kang Date: Wed, 19 Nov 2025 16:19:29 -0500 Subject: [PATCH 5/6] invoke --- crates/swc_ecma_transformer/src/hook_utils.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/swc_ecma_transformer/src/hook_utils.rs b/crates/swc_ecma_transformer/src/hook_utils.rs index 7743c462700c..523c80dbc893 100644 --- a/crates/swc_ecma_transformer/src/hook_utils.rs +++ b/crates/swc_ecma_transformer/src/hook_utils.rs @@ -50,6 +50,8 @@ where optional_method!(enter_script, exit_script, Script); optional_method!(enter_program, exit_program, Program); + + optional_method!(enter_catch_clause, exit_catch_clause, CatchClause); } pub(crate) struct NoopHook; From 7854d9739ad62138a9ae84b30ffb675e1a0c1723 Mon Sep 17 00:00:00 2001 From: DongYun Kang Date: Wed, 19 Nov 2025 16:21:20 -0500 Subject: [PATCH 6/6] impl --- .../src/es2019/optional_catch_binding.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs b/crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs index ca312dc205de..749acfd07f98 100644 --- a/crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs +++ b/crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs @@ -1,4 +1,6 @@ +use swc_ecma_ast::*; use swc_ecma_hooks::VisitMutHook; +use swc_ecma_utils::private_ident; use crate::TraverseCtx; @@ -8,4 +10,12 @@ pub fn hook() -> impl VisitMutHook { struct OptionalCatchBindingPass {} -impl VisitMutHook for OptionalCatchBindingPass {} +impl VisitMutHook for OptionalCatchBindingPass { + fn enter_catch_clause(&mut self, node: &mut CatchClause, _: &mut TraverseCtx) { + if node.param.is_none() { + // TODO: Do not use private_ident! here. + // All private identifiers should be tracked using TraverseCtx. + node.param = Some(Pat::Ident(private_ident!("unused"))); + } + } +}