mirror of
https://github.com/danbulant/oxc
synced 2026-05-23 06:08:47 +00:00
feat(transformer): setup typescript and react transformers (#930)
This commit is contained in:
parent
46d2623c1f
commit
5973e5aede
7 changed files with 114 additions and 26 deletions
|
|
@ -4,7 +4,7 @@ use oxc_allocator::Allocator;
|
|||
use oxc_formatter::{Formatter, FormatterOptions};
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
use oxc_transformer::{TransformOptions, TransformTarget, Transformer};
|
||||
use oxc_transformer::{TransformOptions, TransformReactOptions, TransformTarget, Transformer};
|
||||
|
||||
// Instruction:
|
||||
// create a `test.js`,
|
||||
|
|
@ -33,8 +33,11 @@ fn main() {
|
|||
println!("Original:\n");
|
||||
println!("{printed}");
|
||||
|
||||
let transform_options = TransformOptions { target: TransformTarget::ES2015 };
|
||||
Transformer::new(&allocator, &transform_options).build(program);
|
||||
let transform_options = TransformOptions {
|
||||
target: TransformTarget::ES2015,
|
||||
react: Some(TransformReactOptions::default()),
|
||||
};
|
||||
Transformer::new(&allocator, source_type, transform_options).build(program);
|
||||
let printed = Formatter::new(source_text.len(), formatter_options).build(program);
|
||||
println!("Transformed:\n");
|
||||
println!("{printed}");
|
||||
|
|
|
|||
|
|
@ -10,33 +10,29 @@
|
|||
mod es2016;
|
||||
mod es2019;
|
||||
mod es2021;
|
||||
mod options;
|
||||
mod react_jsx;
|
||||
mod typescript;
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::{ast::*, AstBuilder, VisitMut};
|
||||
use oxc_span::SourceType;
|
||||
use std::rc::Rc;
|
||||
|
||||
use es2016::ExponentiationOperator;
|
||||
use es2019::OptionalCatchBinding;
|
||||
use es2021::LogicalAssignmentOperators;
|
||||
use react_jsx::ReactJsx;
|
||||
use typescript::TypeScript;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct TransformOptions {
|
||||
pub target: TransformTarget,
|
||||
}
|
||||
|
||||
/// See <https://www.typescriptlang.org/tsconfig#target>
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum TransformTarget {
|
||||
ES2015,
|
||||
ES2016,
|
||||
ES2019,
|
||||
ES2021,
|
||||
#[default]
|
||||
ESNext,
|
||||
}
|
||||
pub use crate::options::{
|
||||
TransformOptions, TransformReactOptions, TransformReactRuntime, TransformTarget,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Transformer<'a> {
|
||||
typescript: Option<TypeScript<'a>>,
|
||||
react_jsx: Option<ReactJsx<'a>>,
|
||||
// es2021
|
||||
es2021_logical_assignment_operators: Option<LogicalAssignmentOperators<'a>>,
|
||||
// es2019
|
||||
|
|
@ -46,10 +42,20 @@ pub struct Transformer<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Transformer<'a> {
|
||||
pub fn new(allocator: &'a Allocator, options: &TransformOptions) -> Self {
|
||||
pub fn new(
|
||||
allocator: &'a Allocator,
|
||||
source_type: SourceType,
|
||||
options: TransformOptions,
|
||||
) -> Self {
|
||||
let ast = Rc::new(AstBuilder::new(allocator));
|
||||
|
||||
let mut t = Self::default();
|
||||
if source_type.is_typescript() {
|
||||
t.typescript.replace(TypeScript::new(Rc::clone(&ast)));
|
||||
}
|
||||
if let Some(react_options) = options.react {
|
||||
t.react_jsx.replace(ReactJsx::new(Rc::clone(&ast), react_options));
|
||||
}
|
||||
if options.target < TransformTarget::ES2021 {
|
||||
t.es2021_logical_assignment_operators
|
||||
.replace(LogicalAssignmentOperators::new(Rc::clone(&ast)));
|
||||
|
|
@ -70,6 +76,8 @@ impl<'a> Transformer<'a> {
|
|||
|
||||
impl<'a, 'b> VisitMut<'a, 'b> for Transformer<'a> {
|
||||
fn visit_expression(&mut self, expr: &'b mut Expression<'a>) {
|
||||
// self.typescript.as_mut().map(|t| t.transform_expression(expr));
|
||||
// self.react_jsx.as_mut().map(|t| t.transform_expression(expr));
|
||||
self.es2021_logical_assignment_operators.as_mut().map(|t| t.transform_expression(expr));
|
||||
self.es2016_exponentiation_operator.as_mut().map(|t| t.transform_expression(expr));
|
||||
|
||||
|
|
|
|||
28
crates/oxc_transformer/src/options.rs
Normal file
28
crates/oxc_transformer/src/options.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#[derive(Debug, Default, Clone)]
|
||||
pub struct TransformOptions {
|
||||
pub target: TransformTarget,
|
||||
pub react: Option<TransformReactOptions>,
|
||||
}
|
||||
|
||||
/// See <https://www.typescriptlang.org/tsconfig#target>
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum TransformTarget {
|
||||
ES2015,
|
||||
ES2016,
|
||||
ES2019,
|
||||
ES2021,
|
||||
#[default]
|
||||
ESNext,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct TransformReactOptions {
|
||||
_runtime: TransformReactRuntime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub enum TransformReactRuntime {
|
||||
#[default]
|
||||
Classic,
|
||||
Automatic,
|
||||
}
|
||||
21
crates/oxc_transformer/src/react_jsx/mod.rs
Normal file
21
crates/oxc_transformer/src/react_jsx/mod.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use oxc_ast::AstBuilder;
|
||||
|
||||
use crate::TransformReactOptions;
|
||||
|
||||
/// Transform React JSX
|
||||
///
|
||||
/// References:
|
||||
/// * <https://babeljs.io/docs/babel-plugin-transform-react-jsx>
|
||||
/// * <https://github.com/babel/babel/tree/main/packages/babel-helper-builder-react-jsx>
|
||||
pub struct ReactJsx<'a> {
|
||||
_ast: Rc<AstBuilder<'a>>,
|
||||
_options: TransformReactOptions,
|
||||
}
|
||||
|
||||
impl<'a> ReactJsx<'a> {
|
||||
pub fn new(_ast: Rc<AstBuilder<'a>>, _options: TransformReactOptions) -> Self {
|
||||
Self { _ast, _options }
|
||||
}
|
||||
}
|
||||
18
crates/oxc_transformer/src/typescript/mod.rs
Normal file
18
crates/oxc_transformer/src/typescript/mod.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use oxc_ast::AstBuilder;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Transform TypeScript
|
||||
///
|
||||
/// References:
|
||||
/// * <https://babeljs.io/docs/babel-plugin-transform-typescript>
|
||||
/// * <https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-typescript>
|
||||
pub struct TypeScript<'a> {
|
||||
_ast: Rc<AstBuilder<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> TypeScript<'a> {
|
||||
pub fn new(_ast: Rc<AstBuilder<'a>>) -> Self {
|
||||
Self { _ast }
|
||||
}
|
||||
}
|
||||
|
|
@ -30,9 +30,10 @@ fn bench_transformer(criterion: &mut Criterion) {
|
|||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
let transform_options = TransformOptions::default();
|
||||
b.iter(|| {
|
||||
Transformer::new(&allocator, &transform_options).build(black_box(program));
|
||||
let transform_options = TransformOptions::default();
|
||||
Transformer::new(&allocator, source_type, transform_options)
|
||||
.build(black_box(program));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use oxc_formatter::{Formatter, FormatterOptions};
|
|||
use oxc_parser::Parser;
|
||||
use oxc_span::{SourceType, VALID_EXTENSIONS};
|
||||
use oxc_tasks_common::{normalize_path, project_root};
|
||||
use oxc_transformer::{TransformOptions, TransformTarget, Transformer};
|
||||
use oxc_transformer::{TransformOptions, TransformReactOptions, TransformTarget, Transformer};
|
||||
|
||||
pub struct BabelOptions {
|
||||
pub filter: Option<String>,
|
||||
|
|
@ -132,19 +132,28 @@ fn babel_test(input_path: &Path, options: &BabelOptions) -> bool {
|
|||
|
||||
let expected = output_path.and_then(|path| fs::read_to_string(path).ok());
|
||||
if let Some(expected) = &expected {
|
||||
let transform_options = TransformOptions { target: TransformTarget::ES2015 };
|
||||
let transform_options = TransformOptions {
|
||||
target: TransformTarget::ES2015,
|
||||
react: Some(TransformReactOptions::default()),
|
||||
};
|
||||
let program = allocator.alloc(ret.program);
|
||||
Transformer::new(&allocator, &transform_options).build(program);
|
||||
Transformer::new(&allocator, source_type, transform_options).build(program);
|
||||
|
||||
let formatter_options = FormatterOptions::default();
|
||||
let transformed = Formatter::new(source_text.len(), formatter_options).build(program);
|
||||
let trim_transformed = remove_whitespace(&transformed);
|
||||
let trim_expected = remove_whitespace(expected);
|
||||
let passed = trim_transformed == trim_expected;
|
||||
if filtered {
|
||||
println!("Expected:\n");
|
||||
println!("{expected:?}\n");
|
||||
println!("Transformed:\n");
|
||||
println!("{transformed}");
|
||||
println!("{transformed}\n");
|
||||
println!("Diff:\n");
|
||||
println!("{trim_transformed:?}");
|
||||
println!("{trim_expected:?}");
|
||||
}
|
||||
return remove_whitespace(&transformed) == remove_whitespace(expected);
|
||||
return passed;
|
||||
}
|
||||
|
||||
ret.errors.is_empty()
|
||||
|
|
|
|||
Loading…
Reference in a new issue