mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer): add transform context to all plugins (#2931)
This commit is contained in:
parent
0a77d621e2
commit
255c74ccc5
9 changed files with 140 additions and 107 deletions
37
crates/oxc_transformer/src/context.rs
Normal file
37
crates/oxc_transformer/src/context.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
use std::{cell::RefCell, mem, rc::Rc};
|
||||||
|
|
||||||
|
use oxc_allocator::Allocator;
|
||||||
|
use oxc_ast::AstBuilder;
|
||||||
|
use oxc_diagnostics::Error;
|
||||||
|
use oxc_semantic::Semantic;
|
||||||
|
use oxc_span::SourceType;
|
||||||
|
|
||||||
|
pub type Ctx<'a> = Rc<TransformCtx<'a>>;
|
||||||
|
|
||||||
|
pub struct TransformCtx<'a> {
|
||||||
|
pub ast: AstBuilder<'a>,
|
||||||
|
pub source_type: SourceType,
|
||||||
|
pub semantic: Semantic<'a>,
|
||||||
|
errors: RefCell<Vec<Error>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TransformCtx<'a> {
|
||||||
|
pub fn new(allocator: &'a Allocator, source_type: SourceType, semantic: Semantic<'a>) -> Self {
|
||||||
|
Self {
|
||||||
|
ast: AstBuilder::new(allocator),
|
||||||
|
source_type,
|
||||||
|
semantic,
|
||||||
|
errors: RefCell::new(vec![]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_errors(&self) -> Vec<Error> {
|
||||||
|
mem::take(&mut self.errors.borrow_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add an Error
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn error<T: Into<Error>>(&self, error: T) {
|
||||||
|
self.errors.borrow_mut().push(error.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,26 +1,30 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
|
|
||||||
|
use crate::context::Ctx;
|
||||||
|
|
||||||
/// Only `"2023-11"` will be implemented because Babel 8 will only support "2023-11" and "legacy".
|
/// Only `"2023-11"` will be implemented because Babel 8 will only support "2023-11" and "legacy".
|
||||||
#[derive(Debug, Default, Clone, Deserialize)]
|
#[derive(Debug, Default, Clone, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DecoratorsOptions;
|
pub struct DecoratorsOptions;
|
||||||
|
|
||||||
/// [proposal-decorators](https://babeljs.io/docs/babel-plugin-proposal-decorators)
|
/// [proposal-decorators](https://babeljs.io/docs/babel-plugin-proposal-decorators)
|
||||||
#[derive(Debug, Default)]
|
#[allow(unused)]
|
||||||
pub struct Decorators {
|
pub struct Decorators<'a> {
|
||||||
#[allow(unused)]
|
|
||||||
options: DecoratorsOptions,
|
options: DecoratorsOptions,
|
||||||
|
ctx: Ctx<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decorators {
|
impl<'a> Decorators<'a> {
|
||||||
pub fn new(options: DecoratorsOptions) -> Self {
|
pub fn new(options: DecoratorsOptions, ctx: &Ctx<'a>) -> Self {
|
||||||
Self { options }
|
Self { options, ctx: Rc::clone(ctx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformers
|
// Transformers
|
||||||
impl Decorators {
|
impl<'a> Decorators<'a> {
|
||||||
pub fn transform_statement(&mut self, _stmt: &mut Statement<'_>) {}
|
pub fn transform_statement(&mut self, _stmt: &mut Statement<'_>) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,14 @@
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
mod compiler_assumptions;
|
mod compiler_assumptions;
|
||||||
// Plugins: <https://babeljs.io/docs/plugins-list>
|
mod context;
|
||||||
|
// Presets: <https://babel.dev/docs/presets>
|
||||||
mod decorators;
|
mod decorators;
|
||||||
mod react;
|
mod react;
|
||||||
mod typescript;
|
mod typescript;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use oxc_allocator::Allocator;
|
use oxc_allocator::Allocator;
|
||||||
use oxc_ast::{
|
use oxc_ast::{
|
||||||
ast::*,
|
ast::*,
|
||||||
|
|
@ -26,13 +29,12 @@ use oxc_span::SourceType;
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
compiler_assumptions::CompilerAssumptions,
|
compiler_assumptions::CompilerAssumptions,
|
||||||
decorators::{Decorators, DecoratorsOptions},
|
decorators::{Decorators, DecoratorsOptions},
|
||||||
react::{
|
react::{React, ReactDisplayName, ReactJsx, ReactJsxSelf, ReactJsxSource, ReactOptions},
|
||||||
React, ReactDisplayName, ReactDisplayNameOptions, ReactJsx, ReactJsxSelf, ReactJsxSource,
|
|
||||||
ReactJsxSourceOptions, ReactOptions,
|
|
||||||
},
|
|
||||||
typescript::{TypeScript, TypeScriptOptions},
|
typescript::{TypeScript, TypeScriptOptions},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::context::{Ctx, TransformCtx};
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct TransformOptions {
|
pub struct TransformOptions {
|
||||||
|
|
@ -54,15 +56,11 @@ pub struct TransformOptions {
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct Transformer<'a> {
|
pub struct Transformer<'a> {
|
||||||
allocator: &'a Allocator,
|
ctx: Ctx<'a>,
|
||||||
source_type: SourceType,
|
|
||||||
semantic: Semantic<'a>,
|
|
||||||
options: TransformOptions,
|
|
||||||
|
|
||||||
// NOTE: all callbacks must run in order.
|
// NOTE: all callbacks must run in order.
|
||||||
x0_typescript: TypeScript,
|
x0_typescript: TypeScript<'a>,
|
||||||
x1_react: React,
|
x1_react: React<'a>,
|
||||||
x2_decorators: Decorators,
|
x2_decorators: Decorators<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Transformer<'a> {
|
impl<'a> Transformer<'a> {
|
||||||
|
|
@ -72,14 +70,12 @@ impl<'a> Transformer<'a> {
|
||||||
semantic: Semantic<'a>,
|
semantic: Semantic<'a>,
|
||||||
options: TransformOptions,
|
options: TransformOptions,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let ctx = Rc::new(TransformCtx::new(allocator, source_type, semantic));
|
||||||
Self {
|
Self {
|
||||||
allocator,
|
ctx: Rc::clone(&ctx),
|
||||||
source_type,
|
x0_typescript: TypeScript::new(options.typescript, &ctx),
|
||||||
semantic,
|
x1_react: React::new(options.react, &ctx),
|
||||||
options,
|
x2_decorators: Decorators::new(options.decorators, &ctx),
|
||||||
x0_typescript: TypeScript::default(),
|
|
||||||
x1_react: React::default(),
|
|
||||||
x2_decorators: Decorators::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,7 +84,12 @@ impl<'a> Transformer<'a> {
|
||||||
/// Returns `Vec<Error>` if any errors were collected during the transformation.
|
/// Returns `Vec<Error>` if any errors were collected during the transformation.
|
||||||
pub fn build(mut self, program: &mut Program<'a>) -> Result<(), Vec<Error>> {
|
pub fn build(mut self, program: &mut Program<'a>) -> Result<(), Vec<Error>> {
|
||||||
self.visit_program(program);
|
self.visit_program(program);
|
||||||
Ok(())
|
let errors = self.ctx.take_errors();
|
||||||
|
if errors.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use serde::Deserialize;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Deserialize)]
|
use crate::context::Ctx;
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ReactDisplayNameOptions;
|
|
||||||
|
|
||||||
/// [plugin-transform-react-display-name](https://babeljs.io/docs/babel-plugin-transform-react-display-name)
|
/// [plugin-transform-react-display-name](https://babeljs.io/docs/babel-plugin-transform-react-display-name)
|
||||||
///
|
///
|
||||||
|
|
@ -12,14 +10,13 @@ pub struct ReactDisplayNameOptions;
|
||||||
///
|
///
|
||||||
/// In: `var bar = createReactClass({});`
|
/// In: `var bar = createReactClass({});`
|
||||||
/// Out: `var bar = createReactClass({ displayName: "bar" });`
|
/// Out: `var bar = createReactClass({ displayName: "bar" });`
|
||||||
#[derive(Debug, Default)]
|
#[allow(unused)]
|
||||||
pub struct ReactDisplayName {
|
pub struct ReactDisplayName<'a> {
|
||||||
#[allow(unused)]
|
ctx: Ctx<'a>,
|
||||||
options: ReactDisplayNameOptions,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReactDisplayName {
|
impl<'a> ReactDisplayName<'a> {
|
||||||
pub fn new(options: ReactDisplayNameOptions) -> Self {
|
pub fn new(ctx: &Ctx<'a>) -> Self {
|
||||||
Self { options }
|
Self { ctx: Rc::clone(ctx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::context::Ctx;
|
||||||
|
|
||||||
pub use super::options::ReactOptions;
|
pub use super::options::ReactOptions;
|
||||||
|
|
||||||
/// [plugin-transform-react-jsx](https://babeljs.io/docs/babel-plugin-transform-react-jsx)
|
/// [plugin-transform-react-jsx](https://babeljs.io/docs/babel-plugin-transform-react-jsx)
|
||||||
|
|
@ -13,14 +17,14 @@ pub use super::options::ReactOptions;
|
||||||
///
|
///
|
||||||
/// * <https://babeljs.io/docs/babel-plugin-transform-react-jsx>
|
/// * <https://babeljs.io/docs/babel-plugin-transform-react-jsx>
|
||||||
/// * <https://github.com/babel/babel/tree/main/packages/babel-helper-builder-react-jsx>
|
/// * <https://github.com/babel/babel/tree/main/packages/babel-helper-builder-react-jsx>
|
||||||
#[derive(Debug, Default)]
|
#[allow(unused)]
|
||||||
pub struct ReactJsx {
|
pub struct ReactJsx<'a> {
|
||||||
#[allow(unused)]
|
|
||||||
options: ReactOptions,
|
options: ReactOptions,
|
||||||
|
ctx: Ctx<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReactJsx {
|
impl<'a> ReactJsx<'a> {
|
||||||
pub fn new(options: ReactOptions) -> Self {
|
pub fn new(options: ReactOptions, ctx: &Ctx<'a>) -> Self {
|
||||||
Self { options }
|
Self { options, ctx: Rc::clone(ctx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use serde::Deserialize;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Deserialize)]
|
use crate::context::Ctx;
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ReactJsxSelfOptions;
|
|
||||||
|
|
||||||
/// [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self)
|
/// [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self)
|
||||||
///
|
///
|
||||||
|
|
@ -12,14 +10,13 @@ pub struct ReactJsxSelfOptions;
|
||||||
///
|
///
|
||||||
/// In: `<sometag />`
|
/// In: `<sometag />`
|
||||||
/// Out: `<sometag __self={this} />`
|
/// Out: `<sometag __self={this} />`
|
||||||
#[derive(Debug, Default)]
|
#[allow(unused)]
|
||||||
pub struct ReactJsxSelf {
|
pub struct ReactJsxSelf<'a> {
|
||||||
#[allow(unused)]
|
ctx: Ctx<'a>,
|
||||||
options: ReactJsxSelfOptions,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReactJsxSelf {
|
impl<'a> ReactJsxSelf<'a> {
|
||||||
pub fn new(options: ReactJsxSelfOptions) -> Self {
|
pub fn new(ctx: &Ctx<'a>) -> Self {
|
||||||
Self { options }
|
Self { ctx: Rc::clone(ctx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,15 @@
|
||||||
use serde::Deserialize;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Deserialize)]
|
use crate::context::Ctx;
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ReactJsxSourceOptions;
|
|
||||||
|
|
||||||
/// [plugin-transform-react-jsx-source](https://babeljs.io/docs/babel-plugin-transform-react-jsx-source)
|
/// [plugin-transform-react-jsx-source](https://babeljs.io/docs/babel-plugin-transform-react-jsx-source)
|
||||||
#[derive(Debug, Default)]
|
#[allow(unused)]
|
||||||
pub struct ReactJsxSource {
|
pub struct ReactJsxSource<'a> {
|
||||||
#[allow(unused)]
|
ctx: Ctx<'a>,
|
||||||
options: ReactJsxSourceOptions,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReactJsxSource {
|
impl<'a> ReactJsxSource<'a> {
|
||||||
pub fn new(options: ReactJsxSourceOptions) -> Self {
|
pub fn new(ctx: &Ctx<'a>) -> Self {
|
||||||
Self { options }
|
Self { ctx: Rc::clone(ctx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,15 @@ mod jsx_self;
|
||||||
mod jsx_source;
|
mod jsx_source;
|
||||||
mod options;
|
mod options;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
|
|
||||||
|
use crate::context::Ctx;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
display_name::{ReactDisplayName, ReactDisplayNameOptions},
|
display_name::ReactDisplayName, jsx::ReactJsx, jsx_self::ReactJsxSelf,
|
||||||
jsx::ReactJsx,
|
jsx_source::ReactJsxSource, options::ReactOptions,
|
||||||
jsx_self::{ReactJsxSelf, ReactJsxSelfOptions},
|
|
||||||
jsx_source::{ReactJsxSource, ReactJsxSourceOptions},
|
|
||||||
options::ReactOptions,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// [Preset React](https://babel.dev/docs/babel-preset-react)
|
/// [Preset React](https://babel.dev/docs/babel-preset-react)
|
||||||
|
|
@ -22,40 +23,31 @@ pub use self::{
|
||||||
/// * [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self)
|
/// * [plugin-transform-react-jsx-self](https://babeljs.io/docs/babel-plugin-transform-react-jsx-self)
|
||||||
/// * [plugin-transform-react-jsx](https://babeljs.io/docs/babel-plugin-transform-react-jsx)
|
/// * [plugin-transform-react-jsx](https://babeljs.io/docs/babel-plugin-transform-react-jsx)
|
||||||
/// * [plugin-transform-react-display-name](https://babeljs.io/docs/babel-plugin-transform-react-display-name)
|
/// * [plugin-transform-react-display-name](https://babeljs.io/docs/babel-plugin-transform-react-display-name)
|
||||||
#[derive(Default)]
|
#[allow(unused)]
|
||||||
pub struct React {
|
pub struct React<'a> {
|
||||||
jsx: ReactJsx,
|
ctx: Ctx<'a>,
|
||||||
jsx_self: ReactJsxSelf,
|
jsx: ReactJsx<'a>,
|
||||||
jsx_source: ReactJsxSource,
|
jsx_self: ReactJsxSelf<'a>,
|
||||||
display_name: ReactDisplayName,
|
jsx_source: ReactJsxSource<'a>,
|
||||||
|
display_name: ReactDisplayName<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
impl React {
|
impl<'a> React<'a> {
|
||||||
pub fn new(&mut self, options: ReactOptions) -> &mut Self {
|
pub fn new(options: ReactOptions, ctx: &Ctx<'a>) -> Self {
|
||||||
self.jsx = ReactJsx::new(options);
|
Self {
|
||||||
self
|
ctx: Rc::clone(ctx),
|
||||||
}
|
jsx: ReactJsx::new(options, ctx),
|
||||||
|
jsx_self: ReactJsxSelf::new(ctx),
|
||||||
pub fn with_jsx_self(&mut self, options: ReactJsxSelfOptions) -> &mut Self {
|
jsx_source: ReactJsxSource::new(ctx),
|
||||||
self.jsx_self = ReactJsxSelf::new(options);
|
display_name: ReactDisplayName::new(ctx),
|
||||||
self
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_jsx_source(&mut self, options: ReactJsxSourceOptions) -> &mut Self {
|
|
||||||
self.jsx_source = ReactJsxSource::new(options);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_display_name(&mut self, options: ReactDisplayNameOptions) -> &mut Self {
|
|
||||||
self.display_name = ReactDisplayName::new(options);
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformers
|
// Transformers
|
||||||
impl React {
|
impl<'a> React<'a> {
|
||||||
pub fn transform_expression(&mut self, expr: &mut Expression<'_>) {
|
pub fn transform_expression(&mut self, expr: &mut Expression<'a>) {
|
||||||
match expr {
|
match expr {
|
||||||
Expression::JSXElement(_e) => {
|
Expression::JSXElement(_e) => {
|
||||||
// *expr = unimplemented!();
|
// *expr = unimplemented!();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
|
|
||||||
|
use crate::context::Ctx;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Deserialize)]
|
#[derive(Debug, Default, Clone, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TypeScriptOptions;
|
pub struct TypeScriptOptions;
|
||||||
|
|
@ -27,19 +31,19 @@ pub struct TypeScriptOptions;
|
||||||
///
|
///
|
||||||
/// In: `const x: number = 0;`
|
/// In: `const x: number = 0;`
|
||||||
/// Out: `const x = 0;`
|
/// Out: `const x = 0;`
|
||||||
#[derive(Debug, Default)]
|
#[allow(unused)]
|
||||||
pub struct TypeScript {
|
pub struct TypeScript<'a> {
|
||||||
#[allow(unused)]
|
|
||||||
options: TypeScriptOptions,
|
options: TypeScriptOptions,
|
||||||
|
ctx: Ctx<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeScript {
|
impl<'a> TypeScript<'a> {
|
||||||
pub fn new(options: TypeScriptOptions) -> Self {
|
pub fn new(options: TypeScriptOptions, ctx: &Ctx<'a>) -> Self {
|
||||||
Self { options }
|
Self { options, ctx: Rc::clone(ctx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformers
|
// Transformers
|
||||||
impl TypeScript {
|
impl<'a> TypeScript<'a> {
|
||||||
pub fn transform_statement(&mut self, _stmt: &mut Statement<'_>) {}
|
pub fn transform_statement(&mut self, _stmt: &mut Statement<'a>) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue