From 79ca6feca9745d3a32696d70cc06bd8c4fbb93ba Mon Sep 17 00:00:00 2001 From: Boshen Date: Wed, 10 Apr 2024 11:06:49 +0800 Subject: [PATCH] feat(transformer): add transform callback methods (#2929) For milestone 1, I think it's safe to just layout all the transformations manually. In TypeScript, the transformers are collected dynamically and ran on each ast node; this achieves a single AST pass. https://github.com/microsoft/TypeScript/blob/main/src/compiler/transformer.ts#L129-L145 To maximize performance and reduce confusion, I think it's safe to layout all the transformations manually for milestone 1. The next PR will add transformation context to all presets so we can start adding "context". --- crates/oxc_transformer/src/decorators/mod.rs | 7 ++++ crates/oxc_transformer/src/lib.rs | 36 +++++++++++++++----- crates/oxc_transformer/src/react/mod.rs | 18 ++++++++++ crates/oxc_transformer/src/typescript/mod.rs | 7 ++++ 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/crates/oxc_transformer/src/decorators/mod.rs b/crates/oxc_transformer/src/decorators/mod.rs index 8fbe511f7..05ac442d7 100644 --- a/crates/oxc_transformer/src/decorators/mod.rs +++ b/crates/oxc_transformer/src/decorators/mod.rs @@ -1,5 +1,7 @@ use serde::Deserialize; +use oxc_ast::ast::*; + /// Only `"2023-11"` will be implemented because Babel 8 will only support "2023-11" and "legacy". #[derive(Debug, Default, Clone, Deserialize)] #[serde(rename_all = "camelCase")] @@ -17,3 +19,8 @@ impl Decorators { Self { options } } } + +// Transformers +impl Decorators { + pub fn transform_statement(&mut self, _stmt: &mut Statement<'_>) {} +} diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 5748c6840..9eb61af4e 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::wildcard_imports)] + //! Transformer / Transpiler //! //! References: @@ -13,7 +15,10 @@ mod react; mod typescript; use oxc_allocator::Allocator; -use oxc_ast::ast::Program; +use oxc_ast::{ + ast::*, + visit::{walk_mut, VisitMut}, +}; use oxc_diagnostics::Error; use oxc_semantic::Semantic; use oxc_span::SourceType; @@ -54,9 +59,10 @@ pub struct Transformer<'a> { semantic: Semantic<'a>, options: TransformOptions, - decorators: Decorators, - typescript: TypeScript, - react: React, + // NOTE: all callbacks must run in order. + x0_typescript: TypeScript, + x1_react: React, + x2_decorators: Decorators, } impl<'a> Transformer<'a> { @@ -71,16 +77,30 @@ impl<'a> Transformer<'a> { source_type, semantic, options, - decorators: Decorators::default(), - typescript: TypeScript::default(), - react: React::default(), + x0_typescript: TypeScript::default(), + x1_react: React::default(), + x2_decorators: Decorators::default(), } } /// # Errors /// /// Returns `Vec` if any errors were collected during the transformation. - pub fn build(self, _program: &mut Program<'a>) -> Result<(), Vec> { + pub fn build(mut self, program: &mut Program<'a>) -> Result<(), Vec> { + self.visit_program(program); Ok(()) } } + +impl<'a> VisitMut<'a> for Transformer<'a> { + fn visit_statement(&mut self, stmt: &mut Statement<'a>) { + self.x0_typescript.transform_statement(stmt); + self.x2_decorators.transform_statement(stmt); + walk_mut::walk_statement_mut(self, stmt); + } + + fn visit_expression(&mut self, expr: &mut Expression<'a>) { + self.x1_react.transform_expression(expr); + walk_mut::walk_expression_mut(self, expr); + } +} diff --git a/crates/oxc_transformer/src/react/mod.rs b/crates/oxc_transformer/src/react/mod.rs index 6a0cae35c..7bd07cd0e 100644 --- a/crates/oxc_transformer/src/react/mod.rs +++ b/crates/oxc_transformer/src/react/mod.rs @@ -4,6 +4,8 @@ mod jsx_self; mod jsx_source; mod options; +use oxc_ast::ast::*; + pub use self::{ display_name::{ReactDisplayName, ReactDisplayNameOptions}, jsx::ReactJsx, @@ -28,6 +30,7 @@ pub struct React { display_name: ReactDisplayName, } +// Constructors impl React { pub fn new(&mut self, options: ReactOptions) -> &mut Self { self.jsx = ReactJsx::new(options); @@ -49,3 +52,18 @@ impl React { self } } + +// Transformers +impl React { + pub fn transform_expression(&mut self, expr: &mut Expression<'_>) { + match expr { + Expression::JSXElement(_e) => { + // *expr = unimplemented!(); + } + Expression::JSXFragment(_e) => { + // *expr = unimplemented!(); + } + _ => {} + } + } +} diff --git a/crates/oxc_transformer/src/typescript/mod.rs b/crates/oxc_transformer/src/typescript/mod.rs index 197e79a80..0fb7d1683 100644 --- a/crates/oxc_transformer/src/typescript/mod.rs +++ b/crates/oxc_transformer/src/typescript/mod.rs @@ -1,5 +1,7 @@ use serde::Deserialize; +use oxc_ast::ast::*; + #[derive(Debug, Default, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TypeScriptOptions; @@ -36,3 +38,8 @@ impl TypeScript { Self { options } } } + +// Transformers +impl TypeScript { + pub fn transform_statement(&mut self, _stmt: &mut Statement<'_>) {} +}