oxc_transformer/
lib.rs

1//! Transformer / Transpiler
2//!
3//! References:
4//! * <https://www.typescriptlang.org/tsconfig#target>
5//! * <https://babel.dev/docs/presets>
6//! * <https://github.com/microsoft/TypeScript/blob/v5.6.3/src/compiler/transformer.ts>
7
8use std::path::Path;
9
10use oxc_allocator::{Allocator, TakeIn, Vec as ArenaVec};
11use oxc_ast::{AstBuilder, ast::*};
12use oxc_diagnostics::OxcDiagnostic;
13use oxc_semantic::Scoping;
14use oxc_span::SPAN;
15use oxc_traverse::{Traverse, traverse_mut};
16
17// Core
18mod common;
19mod compiler_assumptions;
20mod context;
21mod options;
22mod state;
23mod utils;
24
25// Presets: <https://babel.dev/docs/presets>
26mod es2015;
27mod es2016;
28mod es2017;
29mod es2018;
30mod es2019;
31mod es2020;
32mod es2021;
33mod es2022;
34mod es2026;
35mod jsx;
36mod proposals;
37mod regexp;
38mod typescript;
39
40mod decorator;
41mod plugins;
42
43use common::Common;
44use context::{TransformCtx, TraverseCtx};
45use decorator::Decorator;
46use es2015::ES2015;
47use es2016::ES2016;
48use es2017::ES2017;
49use es2018::ES2018;
50use es2019::ES2019;
51use es2020::ES2020;
52use es2021::ES2021;
53use es2022::ES2022;
54use es2026::ES2026;
55use jsx::Jsx;
56use regexp::RegExp;
57use rustc_hash::FxHashMap;
58use state::TransformState;
59use typescript::TypeScript;
60
61use crate::plugins::Plugins;
62pub use crate::{
63    common::helper_loader::{Helper, HelperLoaderMode, HelperLoaderOptions},
64    compiler_assumptions::CompilerAssumptions,
65    decorator::DecoratorOptions,
66    es2015::{ArrowFunctionsOptions, ES2015Options},
67    es2016::ES2016Options,
68    es2017::ES2017Options,
69    es2018::ES2018Options,
70    es2019::ES2019Options,
71    es2020::ES2020Options,
72    es2021::ES2021Options,
73    es2022::{ClassPropertiesOptions, ES2022Options},
74    es2026::ES2026Options,
75    jsx::{JsxOptions, JsxRuntime, ReactRefreshOptions},
76    options::{
77        ESTarget, Engine, EngineTargets, EnvOptions, Module, TransformOptions,
78        babel::{BabelEnvOptions, BabelOptions},
79    },
80    plugins::{PluginsOptions, StyledComponentsOptions},
81    proposals::ProposalOptions,
82    typescript::{RewriteExtensionsMode, TypeScriptOptions},
83};
84
85#[non_exhaustive]
86pub struct TransformerReturn {
87    pub errors: std::vec::Vec<OxcDiagnostic>,
88    pub scoping: Scoping,
89    /// Helpers used by this transform.
90    #[deprecated = "Internal usage only"]
91    pub helpers_used: FxHashMap<Helper, String>,
92}
93
94pub struct Transformer<'a> {
95    ctx: TransformCtx<'a>,
96    allocator: &'a Allocator,
97
98    typescript: TypeScriptOptions,
99    decorator: DecoratorOptions,
100    plugins: PluginsOptions,
101    jsx: JsxOptions,
102    env: EnvOptions,
103    #[expect(dead_code)]
104    proposals: ProposalOptions,
105}
106
107impl<'a> Transformer<'a> {
108    pub fn new(allocator: &'a Allocator, source_path: &Path, options: &TransformOptions) -> Self {
109        let ctx = TransformCtx::new(source_path, options);
110        Self {
111            ctx,
112            allocator,
113            typescript: options.typescript.clone(),
114            decorator: options.decorator,
115            plugins: options.plugins.clone(),
116            jsx: options.jsx.clone(),
117            env: options.env,
118            proposals: options.proposals,
119        }
120    }
121
122    pub fn build_with_scoping(
123        mut self,
124        scoping: Scoping,
125        program: &mut Program<'a>,
126    ) -> TransformerReturn {
127        let allocator = self.allocator;
128        let ast_builder = AstBuilder::new(allocator);
129
130        self.ctx.source_type = program.source_type;
131        self.ctx.source_text = program.source_text;
132
133        if program.source_type.is_jsx() {
134            jsx::update_options_with_comments(
135                &program.comments,
136                &mut self.typescript,
137                &mut self.jsx,
138                &self.ctx,
139            );
140        }
141
142        let mut transformer = TransformerImpl {
143            common: Common::new(&self.env, &self.ctx),
144            decorator: Decorator::new(self.decorator, &self.ctx),
145            plugins: Plugins::new(self.plugins, &self.ctx),
146            x0_typescript: program
147                .source_type
148                .is_typescript()
149                .then(|| TypeScript::new(&self.typescript, &self.ctx)),
150            x1_jsx: Jsx::new(self.jsx, self.env.es2018.object_rest_spread, ast_builder, &self.ctx),
151            x2_es2026: ES2026::new(self.env.es2026, &self.ctx),
152            x2_es2022: ES2022::new(
153                self.env.es2022,
154                !self.typescript.allow_declare_fields
155                    || self.typescript.remove_class_fields_without_initializer,
156                &self.ctx,
157            ),
158            x2_es2021: ES2021::new(self.env.es2021, &self.ctx),
159            x2_es2020: ES2020::new(self.env.es2020, &self.ctx),
160            x2_es2019: ES2019::new(self.env.es2019),
161            x2_es2018: ES2018::new(self.env.es2018, &self.ctx),
162            x2_es2016: ES2016::new(self.env.es2016, &self.ctx),
163            x2_es2017: ES2017::new(self.env.es2017, &self.ctx),
164            x3_es2015: ES2015::new(self.env.es2015, &self.ctx),
165            x4_regexp: RegExp::new(self.env.regexp, &self.ctx),
166        };
167
168        let state = TransformState::default();
169        let scoping = traverse_mut(&mut transformer, allocator, program, scoping, state);
170        let helpers_used = self.ctx.helper_loader.used_helpers.borrow_mut().drain().collect();
171        #[expect(deprecated)]
172        TransformerReturn { errors: self.ctx.take_errors(), scoping, helpers_used }
173    }
174}
175
176struct TransformerImpl<'a, 'ctx> {
177    // NOTE: all callbacks must run in order.
178    x0_typescript: Option<TypeScript<'a, 'ctx>>,
179    decorator: Decorator<'a, 'ctx>,
180    plugins: Plugins<'a, 'ctx>,
181    x1_jsx: Jsx<'a, 'ctx>,
182    x2_es2026: ES2026<'a, 'ctx>,
183    x2_es2022: ES2022<'a, 'ctx>,
184    x2_es2021: ES2021<'a, 'ctx>,
185    x2_es2020: ES2020<'a, 'ctx>,
186    x2_es2019: ES2019,
187    x2_es2018: ES2018<'a, 'ctx>,
188    x2_es2017: ES2017<'a, 'ctx>,
189    x2_es2016: ES2016<'a, 'ctx>,
190    #[expect(unused)]
191    x3_es2015: ES2015<'a, 'ctx>,
192    x4_regexp: RegExp<'a, 'ctx>,
193    common: Common<'a, 'ctx>,
194}
195
196impl<'a> Traverse<'a, TransformState<'a>> for TransformerImpl<'a, '_> {
197    fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
198        if let Some(typescript) = self.x0_typescript.as_mut() {
199            typescript.enter_program(program, ctx);
200        }
201        self.plugins.enter_program(program, ctx);
202        self.x1_jsx.enter_program(program, ctx);
203        self.x2_es2026.enter_program(program, ctx);
204    }
205
206    fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
207        self.decorator.exit_program(program, ctx);
208        self.x1_jsx.exit_program(program, ctx);
209        if let Some(typescript) = self.x0_typescript.as_mut() {
210            typescript.exit_program(program, ctx);
211        }
212        self.x2_es2022.exit_program(program, ctx);
213        self.x2_es2020.exit_program(program, ctx);
214        self.x2_es2018.exit_program(program, ctx);
215        self.common.exit_program(program, ctx);
216    }
217
218    // ALPHASORT
219    fn enter_arrow_function_expression(
220        &mut self,
221        arrow: &mut ArrowFunctionExpression<'a>,
222        ctx: &mut TraverseCtx<'a>,
223    ) {
224        self.common.enter_arrow_function_expression(arrow, ctx);
225        if let Some(typescript) = self.x0_typescript.as_mut() {
226            typescript.enter_arrow_function_expression(arrow, ctx);
227        }
228        self.x2_es2018.enter_arrow_function_expression(arrow, ctx);
229    }
230
231    fn enter_variable_declaration(
232        &mut self,
233        decl: &mut VariableDeclaration<'a>,
234        ctx: &mut TraverseCtx<'a>,
235    ) {
236        self.x2_es2018.enter_variable_declaration(decl, ctx);
237    }
238
239    fn enter_variable_declarator(
240        &mut self,
241        decl: &mut VariableDeclarator<'a>,
242        ctx: &mut TraverseCtx<'a>,
243    ) {
244        if let Some(typescript) = self.x0_typescript.as_mut() {
245            typescript.enter_variable_declarator(decl, ctx);
246        }
247        self.plugins.enter_variable_declarator(decl, ctx);
248    }
249
250    fn enter_big_int_literal(&mut self, node: &mut BigIntLiteral<'a>, ctx: &mut TraverseCtx<'a>) {
251        self.x2_es2020.enter_big_int_literal(node, ctx);
252    }
253
254    fn enter_await_expression(
255        &mut self,
256        node: &mut AwaitExpression<'a>,
257        ctx: &mut TraverseCtx<'a>,
258    ) {
259        self.x2_es2022.enter_await_expression(node, ctx);
260    }
261
262    fn enter_import_specifier(
263        &mut self,
264        node: &mut ImportSpecifier<'a>,
265        ctx: &mut TraverseCtx<'a>,
266    ) {
267        self.x2_es2020.enter_import_specifier(node, ctx);
268    }
269
270    fn enter_export_specifier(
271        &mut self,
272        node: &mut ExportSpecifier<'a>,
273        ctx: &mut TraverseCtx<'a>,
274    ) {
275        self.x2_es2020.enter_export_specifier(node, ctx);
276    }
277
278    fn enter_binding_identifier(
279        &mut self,
280        node: &mut BindingIdentifier<'a>,
281        ctx: &mut TraverseCtx<'a>,
282    ) {
283        self.common.enter_binding_identifier(node, ctx);
284    }
285
286    fn enter_identifier_reference(
287        &mut self,
288        node: &mut IdentifierReference<'a>,
289        ctx: &mut TraverseCtx<'a>,
290    ) {
291        self.common.enter_identifier_reference(node, ctx);
292    }
293
294    fn enter_binding_pattern(&mut self, pat: &mut BindingPattern<'a>, ctx: &mut TraverseCtx<'a>) {
295        if let Some(typescript) = self.x0_typescript.as_mut() {
296            typescript.enter_binding_pattern(pat, ctx);
297        }
298    }
299
300    fn enter_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) {
301        if let Some(typescript) = self.x0_typescript.as_mut() {
302            typescript.enter_call_expression(expr, ctx);
303        }
304        self.plugins.enter_call_expression(expr, ctx);
305        self.x1_jsx.enter_call_expression(expr, ctx);
306    }
307
308    fn enter_chain_element(&mut self, element: &mut ChainElement<'a>, ctx: &mut TraverseCtx<'a>) {
309        if let Some(typescript) = self.x0_typescript.as_mut() {
310            typescript.enter_chain_element(element, ctx);
311        }
312    }
313
314    fn enter_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
315        self.decorator.enter_class(class, ctx);
316        if let Some(typescript) = self.x0_typescript.as_mut() {
317            typescript.enter_class(class, ctx);
318        }
319    }
320
321    fn exit_class(&mut self, class: &mut Class<'a>, ctx: &mut TraverseCtx<'a>) {
322        self.decorator.exit_class(class, ctx);
323        if let Some(typescript) = self.x0_typescript.as_mut() {
324            typescript.exit_class(class, ctx);
325        }
326        self.x2_es2022.exit_class(class, ctx);
327        // `decorator` has some statements should be inserted after `class-properties` plugin.
328        self.decorator.exit_class_at_end(class, ctx);
329    }
330
331    fn enter_class_body(&mut self, body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) {
332        self.x2_es2022.enter_class_body(body, ctx);
333    }
334
335    fn enter_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) {
336        self.common.enter_static_block(block, ctx);
337        self.x2_es2022.enter_static_block(block, ctx);
338    }
339
340    fn exit_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) {
341        self.common.exit_static_block(block, ctx);
342        self.x2_es2026.exit_static_block(block, ctx);
343        self.x2_es2022.exit_static_block(block, ctx);
344    }
345
346    #[inline]
347    fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
348        self.common.enter_expression(expr, ctx);
349        if let Some(typescript) = self.x0_typescript.as_mut() {
350            typescript.enter_expression(expr, ctx);
351        }
352        self.plugins.enter_expression(expr, ctx);
353        self.x2_es2022.enter_expression(expr, ctx);
354        self.x2_es2021.enter_expression(expr, ctx);
355        self.x2_es2020.enter_expression(expr, ctx);
356        self.x2_es2018.enter_expression(expr, ctx);
357        self.x2_es2016.enter_expression(expr, ctx);
358        self.x4_regexp.enter_expression(expr, ctx);
359    }
360
361    fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
362        self.common.exit_expression(expr, ctx);
363        self.x1_jsx.exit_expression(expr, ctx);
364        self.x2_es2022.exit_expression(expr, ctx);
365        self.x2_es2018.exit_expression(expr, ctx);
366        self.x2_es2017.exit_expression(expr, ctx);
367    }
368
369    fn enter_simple_assignment_target(
370        &mut self,
371        node: &mut SimpleAssignmentTarget<'a>,
372        ctx: &mut TraverseCtx<'a>,
373    ) {
374        if let Some(typescript) = self.x0_typescript.as_mut() {
375            typescript.enter_simple_assignment_target(node, ctx);
376        }
377    }
378
379    fn enter_assignment_target(
380        &mut self,
381        node: &mut AssignmentTarget<'a>,
382        ctx: &mut TraverseCtx<'a>,
383    ) {
384        if let Some(typescript) = self.x0_typescript.as_mut() {
385            typescript.enter_assignment_target(node, ctx);
386        }
387        self.x2_es2022.enter_assignment_target(node, ctx);
388    }
389
390    fn enter_formal_parameters(
391        &mut self,
392        node: &mut FormalParameters<'a>,
393        ctx: &mut TraverseCtx<'a>,
394    ) {
395        self.x2_es2020.enter_formal_parameters(node, ctx);
396    }
397
398    fn exit_formal_parameters(
399        &mut self,
400        node: &mut FormalParameters<'a>,
401        ctx: &mut TraverseCtx<'a>,
402    ) {
403        self.x2_es2020.exit_formal_parameters(node, ctx);
404    }
405
406    fn enter_formal_parameter(
407        &mut self,
408        param: &mut FormalParameter<'a>,
409        ctx: &mut TraverseCtx<'a>,
410    ) {
411        if let Some(typescript) = self.x0_typescript.as_mut() {
412            typescript.enter_formal_parameter(param, ctx);
413        }
414    }
415
416    fn enter_function(&mut self, func: &mut Function<'a>, ctx: &mut TraverseCtx<'a>) {
417        self.common.enter_function(func, ctx);
418        self.x2_es2018.enter_function(func, ctx);
419    }
420
421    fn exit_function(&mut self, func: &mut Function<'a>, ctx: &mut TraverseCtx<'a>) {
422        if let Some(typescript) = self.x0_typescript.as_mut() {
423            typescript.exit_function(func, ctx);
424        }
425        self.x1_jsx.exit_function(func, ctx);
426        self.x2_es2018.exit_function(func, ctx);
427        self.x2_es2017.exit_function(func, ctx);
428        self.common.exit_function(func, ctx);
429    }
430
431    fn enter_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) {
432        self.common.enter_function_body(body, ctx);
433        self.x2_es2026.enter_function_body(body, ctx);
434    }
435
436    fn exit_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) {
437        self.common.exit_function_body(body, ctx);
438    }
439
440    fn enter_jsx_element(&mut self, node: &mut JSXElement<'a>, ctx: &mut TraverseCtx<'a>) {
441        if let Some(typescript) = self.x0_typescript.as_mut() {
442            typescript.enter_jsx_element(node, ctx);
443        }
444    }
445
446    fn enter_jsx_element_name(&mut self, node: &mut JSXElementName<'a>, ctx: &mut TraverseCtx<'a>) {
447        self.common.enter_jsx_element_name(node, ctx);
448    }
449
450    fn enter_jsx_member_expression_object(
451        &mut self,
452        node: &mut JSXMemberExpressionObject<'a>,
453        ctx: &mut TraverseCtx<'a>,
454    ) {
455        self.common.enter_jsx_member_expression_object(node, ctx);
456    }
457
458    fn enter_jsx_fragment(&mut self, node: &mut JSXFragment<'a>, ctx: &mut TraverseCtx<'a>) {
459        if let Some(typescript) = self.x0_typescript.as_mut() {
460            typescript.enter_jsx_fragment(node, ctx);
461        }
462    }
463
464    fn enter_jsx_opening_element(
465        &mut self,
466        elem: &mut JSXOpeningElement<'a>,
467        ctx: &mut TraverseCtx<'a>,
468    ) {
469        if let Some(typescript) = self.x0_typescript.as_mut() {
470            typescript.enter_jsx_opening_element(elem, ctx);
471        }
472        self.x1_jsx.enter_jsx_opening_element(elem, ctx);
473    }
474
475    fn enter_method_definition(
476        &mut self,
477        def: &mut MethodDefinition<'a>,
478        ctx: &mut TraverseCtx<'a>,
479    ) {
480        self.decorator.enter_method_definition(def, ctx);
481        if let Some(typescript) = self.x0_typescript.as_mut() {
482            typescript.enter_method_definition(def, ctx);
483        }
484    }
485
486    fn exit_method_definition(
487        &mut self,
488        def: &mut MethodDefinition<'a>,
489        ctx: &mut TraverseCtx<'a>,
490    ) {
491        self.decorator.exit_method_definition(def, ctx);
492    }
493
494    fn enter_new_expression(&mut self, expr: &mut NewExpression<'a>, ctx: &mut TraverseCtx<'a>) {
495        if let Some(typescript) = self.x0_typescript.as_mut() {
496            typescript.enter_new_expression(expr, ctx);
497        }
498    }
499
500    fn enter_property_definition(
501        &mut self,
502        def: &mut PropertyDefinition<'a>,
503        ctx: &mut TraverseCtx<'a>,
504    ) {
505        self.decorator.enter_property_definition(def, ctx);
506        if let Some(typescript) = self.x0_typescript.as_mut() {
507            typescript.enter_property_definition(def, ctx);
508        }
509        self.x2_es2022.enter_property_definition(def, ctx);
510    }
511
512    fn exit_property_definition(
513        &mut self,
514        def: &mut PropertyDefinition<'a>,
515        ctx: &mut TraverseCtx<'a>,
516    ) {
517        self.decorator.exit_property_definition(def, ctx);
518        self.x2_es2022.exit_property_definition(def, ctx);
519    }
520
521    fn enter_accessor_property(
522        &mut self,
523        node: &mut AccessorProperty<'a>,
524        ctx: &mut TraverseCtx<'a>,
525    ) {
526        self.decorator.enter_accessor_property(node, ctx);
527        if let Some(typescript) = self.x0_typescript.as_mut() {
528            typescript.enter_accessor_property(node, ctx);
529        }
530    }
531
532    fn exit_accessor_property(
533        &mut self,
534        node: &mut AccessorProperty<'a>,
535        ctx: &mut TraverseCtx<'a>,
536    ) {
537        self.decorator.exit_accessor_property(node, ctx);
538    }
539
540    fn enter_statements(
541        &mut self,
542        stmts: &mut ArenaVec<'a, Statement<'a>>,
543        ctx: &mut TraverseCtx<'a>,
544    ) {
545        self.common.enter_statements(stmts, ctx);
546        if let Some(typescript) = self.x0_typescript.as_mut() {
547            typescript.enter_statements(stmts, ctx);
548        }
549    }
550
551    fn exit_arrow_function_expression(
552        &mut self,
553        arrow: &mut ArrowFunctionExpression<'a>,
554        ctx: &mut TraverseCtx<'a>,
555    ) {
556        self.common.exit_arrow_function_expression(arrow, ctx);
557
558        // Some plugins may add new statements to the ArrowFunctionExpression's body,
559        // which can cause issues with the `() => x;` case, as it only allows a single statement.
560        // To address this, we wrap the last statement in a return statement and set the expression to false.
561        // This transforms the arrow function into the form `() => { return x; };`.
562        let statements = &mut arrow.body.statements;
563        if arrow.expression && statements.len() > 1 {
564            arrow.expression = false;
565
566            // Reverse looping to find the expression statement, because other plugins could
567            // insert new statements after the expression statement.
568            // `() => x;`
569            // ->
570            // ```
571            // () => {
572            //    var new_insert_variable;
573            //    return x;
574            //    function new_insert_function() {}
575            // };
576            // ```
577            for stmt in statements.iter_mut().rev() {
578                let Statement::ExpressionStatement(expr_stmt) = stmt else {
579                    continue;
580                };
581                let expression = Some(expr_stmt.expression.take_in(ctx.ast));
582                *stmt = ctx.ast.statement_return(SPAN, expression);
583                return;
584            }
585            unreachable!("At least one statement should be expression statement")
586        }
587    }
588
589    fn exit_statements(
590        &mut self,
591        stmts: &mut ArenaVec<'a, Statement<'a>>,
592        ctx: &mut TraverseCtx<'a>,
593    ) {
594        if let Some(typescript) = self.x0_typescript.as_mut() {
595            typescript.exit_statements(stmts, ctx);
596        }
597        self.common.exit_statements(stmts, ctx);
598    }
599
600    fn exit_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
601        if let Some(typescript) = self.x0_typescript.as_mut() {
602            typescript.exit_statement(stmt, ctx);
603        }
604        self.decorator.exit_statement(stmt, ctx);
605        self.x2_es2018.exit_statement(stmt, ctx);
606        self.x2_es2017.exit_statement(stmt, ctx);
607    }
608
609    fn enter_tagged_template_expression(
610        &mut self,
611        expr: &mut TaggedTemplateExpression<'a>,
612        ctx: &mut TraverseCtx<'a>,
613    ) {
614        if let Some(typescript) = self.x0_typescript.as_mut() {
615            typescript.enter_tagged_template_expression(expr, ctx);
616        }
617    }
618
619    fn enter_statement(&mut self, stmt: &mut Statement<'a>, ctx: &mut TraverseCtx<'a>) {
620        self.decorator.enter_statement(stmt, ctx);
621        if let Some(typescript) = self.x0_typescript.as_mut() {
622            typescript.enter_statement(stmt, ctx);
623        }
624        self.x2_es2018.enter_statement(stmt, ctx);
625        self.x2_es2026.enter_statement(stmt, ctx);
626    }
627
628    fn enter_declaration(&mut self, decl: &mut Declaration<'a>, ctx: &mut TraverseCtx<'a>) {
629        if let Some(typescript) = self.x0_typescript.as_mut() {
630            typescript.enter_declaration(decl, ctx);
631        }
632    }
633
634    fn enter_if_statement(&mut self, stmt: &mut IfStatement<'a>, ctx: &mut TraverseCtx<'a>) {
635        if let Some(typescript) = self.x0_typescript.as_mut() {
636            typescript.enter_if_statement(stmt, ctx);
637        }
638    }
639
640    fn enter_while_statement(&mut self, stmt: &mut WhileStatement<'a>, ctx: &mut TraverseCtx<'a>) {
641        if let Some(typescript) = self.x0_typescript.as_mut() {
642            typescript.enter_while_statement(stmt, ctx);
643        }
644    }
645
646    fn enter_do_while_statement(
647        &mut self,
648        stmt: &mut DoWhileStatement<'a>,
649        ctx: &mut TraverseCtx<'a>,
650    ) {
651        if let Some(typescript) = self.x0_typescript.as_mut() {
652            typescript.enter_do_while_statement(stmt, ctx);
653        }
654    }
655
656    fn enter_for_statement(&mut self, stmt: &mut ForStatement<'a>, ctx: &mut TraverseCtx<'a>) {
657        if let Some(typescript) = self.x0_typescript.as_mut() {
658            typescript.enter_for_statement(stmt, ctx);
659        }
660    }
661
662    fn enter_for_of_statement(&mut self, stmt: &mut ForOfStatement<'a>, ctx: &mut TraverseCtx<'a>) {
663        if let Some(typescript) = self.x0_typescript.as_mut() {
664            typescript.enter_for_of_statement(stmt, ctx);
665        }
666        self.x2_es2026.enter_for_of_statement(stmt, ctx);
667        self.x2_es2018.enter_for_of_statement(stmt, ctx);
668    }
669
670    fn enter_for_in_statement(&mut self, stmt: &mut ForInStatement<'a>, ctx: &mut TraverseCtx<'a>) {
671        if let Some(typescript) = self.x0_typescript.as_mut() {
672            typescript.enter_for_in_statement(stmt, ctx);
673        }
674        self.x2_es2018.enter_for_in_statement(stmt, ctx);
675    }
676
677    fn enter_try_statement(&mut self, stmt: &mut TryStatement<'a>, ctx: &mut TraverseCtx<'a>) {
678        self.x2_es2026.enter_try_statement(stmt, ctx);
679    }
680
681    fn enter_catch_clause(&mut self, clause: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {
682        self.x2_es2019.enter_catch_clause(clause, ctx);
683        self.x2_es2018.enter_catch_clause(clause, ctx);
684    }
685
686    fn enter_import_declaration(
687        &mut self,
688        node: &mut ImportDeclaration<'a>,
689        ctx: &mut TraverseCtx<'a>,
690    ) {
691        if let Some(typescript) = self.x0_typescript.as_mut() {
692            typescript.enter_import_declaration(node, ctx);
693        }
694    }
695
696    fn enter_export_all_declaration(
697        &mut self,
698        node: &mut ExportAllDeclaration<'a>,
699        ctx: &mut TraverseCtx<'a>,
700    ) {
701        if let Some(typescript) = self.x0_typescript.as_mut() {
702            typescript.enter_export_all_declaration(node, ctx);
703        }
704        self.x2_es2020.enter_export_all_declaration(node, ctx);
705    }
706
707    fn enter_export_named_declaration(
708        &mut self,
709        node: &mut ExportNamedDeclaration<'a>,
710        ctx: &mut TraverseCtx<'a>,
711    ) {
712        if let Some(typescript) = self.x0_typescript.as_mut() {
713            typescript.enter_export_named_declaration(node, ctx);
714        }
715    }
716
717    fn enter_ts_export_assignment(
718        &mut self,
719        export_assignment: &mut TSExportAssignment<'a>,
720        ctx: &mut TraverseCtx<'a>,
721    ) {
722        if let Some(typescript) = self.x0_typescript.as_mut() {
723            typescript.enter_ts_export_assignment(export_assignment, ctx);
724        }
725    }
726
727    fn enter_decorator(
728        &mut self,
729        node: &mut oxc_ast::ast::Decorator<'a>,
730        ctx: &mut TraverseCtx<'a>,
731    ) {
732        self.decorator.enter_decorator(node, ctx);
733    }
734}