mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer/typescript): support for transform enum (#2997)
The current implementation is copied from the previous implementation
This commit is contained in:
parent
e43c245388
commit
6732e8b9af
5 changed files with 1109 additions and 0 deletions
|
|
@ -14,6 +14,7 @@ mod options;
|
|||
// Presets: <https://babel.dev/docs/presets>
|
||||
mod react;
|
||||
mod typescript;
|
||||
mod utils;
|
||||
|
||||
mod helpers {
|
||||
pub mod module_imports;
|
||||
|
|
@ -210,4 +211,9 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
|
|||
self.x0_typescript.transform_statement(stmt);
|
||||
walk_mut::walk_statement_mut(self, stmt);
|
||||
}
|
||||
|
||||
fn visit_declaration(&mut self, decl: &mut Declaration<'a>) {
|
||||
self.x0_typescript.transform_declaration(decl);
|
||||
walk_mut::walk_declaration_mut(self, decl);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
230
crates/oxc_transformer/src/typescript/enum.rs
Normal file
230
crates/oxc_transformer/src/typescript/enum.rs
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
use std::mem;
|
||||
|
||||
use oxc_allocator::{Box, Vec};
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_span::{Atom, SPAN};
|
||||
use oxc_syntax::{
|
||||
operator::{AssignmentOperator, BinaryOperator, LogicalOperator},
|
||||
NumberBase,
|
||||
};
|
||||
|
||||
use crate::utils::is_valid_identifier;
|
||||
|
||||
use super::TypeScript;
|
||||
|
||||
impl<'a> TypeScript<'a> {
|
||||
/// ```TypeScript
|
||||
/// enum Foo {
|
||||
/// X
|
||||
/// }
|
||||
/// ```
|
||||
/// ```JavaScript
|
||||
/// var Foo = ((Foo) => {
|
||||
/// const X = 0; Foo[Foo["X"] = X] = "X";
|
||||
/// return Foo;
|
||||
/// })(Foo || {});
|
||||
/// ```
|
||||
pub fn transform_ts_enum(
|
||||
&self,
|
||||
decl: &mut Box<'a, TSEnumDeclaration<'a>>,
|
||||
) -> Option<Declaration<'a>> {
|
||||
if decl.modifiers.contains(ModifierKind::Declare) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let span = decl.span;
|
||||
let ident = decl.id.clone();
|
||||
let kind = self.ctx.ast.binding_pattern_identifier(ident);
|
||||
let id = self.ctx.ast.binding_pattern(kind, None, false);
|
||||
|
||||
let mut params = self.ctx.ast.new_vec();
|
||||
|
||||
// ((Foo) => {
|
||||
params.push(self.ctx.ast.formal_parameter(
|
||||
SPAN,
|
||||
id,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
self.ctx.ast.new_vec(),
|
||||
));
|
||||
|
||||
let params = self.ctx.ast.formal_parameters(
|
||||
SPAN,
|
||||
FormalParameterKind::ArrowFormalParameters,
|
||||
params,
|
||||
None,
|
||||
);
|
||||
|
||||
// Foo[Foo["X"] = 0] = "X";
|
||||
let enum_name = decl.id.name.clone();
|
||||
let statements = self.transform_ts_enum_members(&mut decl.members, &enum_name);
|
||||
let body = self.ctx.ast.function_body(decl.span, self.ctx.ast.new_vec(), statements);
|
||||
|
||||
let callee =
|
||||
self.ctx.ast.arrow_function_expression(SPAN, false, false, params, body, None, None);
|
||||
|
||||
// })(Foo || {});
|
||||
let mut arguments = self.ctx.ast.new_vec();
|
||||
let op = LogicalOperator::Or;
|
||||
let left = self
|
||||
.ctx
|
||||
.ast
|
||||
.identifier_reference_expression(IdentifierReference::new(SPAN, enum_name.clone()));
|
||||
let right = self.ctx.ast.object_expression(SPAN, self.ctx.ast.new_vec(), None);
|
||||
let expression = self.ctx.ast.logical_expression(SPAN, left, op, right);
|
||||
arguments.push(Argument::Expression(expression));
|
||||
|
||||
let call_expression = self.ctx.ast.call_expression(SPAN, callee, arguments, false, None);
|
||||
|
||||
let kind = VariableDeclarationKind::Var;
|
||||
let decls = {
|
||||
let mut decls = self.ctx.ast.new_vec();
|
||||
|
||||
let binding_identifier = BindingIdentifier::new(SPAN, enum_name.clone());
|
||||
let binding_pattern_kind = self.ctx.ast.binding_pattern_identifier(binding_identifier);
|
||||
let binding = self.ctx.ast.binding_pattern(binding_pattern_kind, None, false);
|
||||
let decl =
|
||||
self.ctx.ast.variable_declarator(SPAN, kind, binding, Some(call_expression), false);
|
||||
|
||||
decls.push(decl);
|
||||
decls
|
||||
};
|
||||
let variable_declaration =
|
||||
self.ctx.ast.variable_declaration(span, kind, decls, Modifiers::empty());
|
||||
|
||||
Some(Declaration::VariableDeclaration(variable_declaration))
|
||||
}
|
||||
|
||||
pub fn transform_ts_enum_members(
|
||||
&self,
|
||||
members: &mut Vec<'a, TSEnumMember<'a>>,
|
||||
enum_name: &Atom<'a>,
|
||||
) -> Vec<'a, Statement<'a>> {
|
||||
let mut default_init = self.ctx.ast.literal_number_expression(NumericLiteral {
|
||||
span: SPAN,
|
||||
value: 0.0,
|
||||
raw: "0",
|
||||
base: NumberBase::Decimal,
|
||||
});
|
||||
let mut statements = self.ctx.ast.new_vec();
|
||||
|
||||
for member in members.iter_mut() {
|
||||
let (member_name, member_span) = match &member.id {
|
||||
TSEnumMemberName::Identifier(id) => (&id.name, id.span),
|
||||
TSEnumMemberName::StringLiteral(str) => (&str.value, str.span),
|
||||
TSEnumMemberName::ComputedPropertyName(..)
|
||||
| TSEnumMemberName::NumericLiteral(..) => unreachable!(),
|
||||
};
|
||||
|
||||
let mut init = self
|
||||
.ctx
|
||||
.ast
|
||||
.move_expression(member.initializer.as_mut().unwrap_or(&mut default_init));
|
||||
|
||||
let is_str = init.is_string_literal();
|
||||
|
||||
let mut self_ref = {
|
||||
let obj = self.ctx.ast.identifier_reference_expression(IdentifierReference::new(
|
||||
SPAN,
|
||||
enum_name.clone(),
|
||||
));
|
||||
let expr = self
|
||||
.ctx
|
||||
.ast
|
||||
.literal_string_expression(StringLiteral::new(SPAN, member_name.clone()));
|
||||
self.ctx.ast.computed_member_expression(SPAN, obj, expr, false)
|
||||
};
|
||||
|
||||
if is_valid_identifier(member_name, true) {
|
||||
let ident = IdentifierReference::new(member_span, member_name.clone());
|
||||
|
||||
self_ref = self.ctx.ast.identifier_reference_expression(ident.clone());
|
||||
let init =
|
||||
mem::replace(&mut init, self.ctx.ast.identifier_reference_expression(ident));
|
||||
|
||||
let kind = VariableDeclarationKind::Const;
|
||||
let decls = {
|
||||
let mut decls = self.ctx.ast.new_vec();
|
||||
|
||||
let binding_identifier = BindingIdentifier::new(SPAN, member_name.clone());
|
||||
let binding_pattern_kind =
|
||||
self.ctx.ast.binding_pattern_identifier(binding_identifier);
|
||||
let binding = self.ctx.ast.binding_pattern(binding_pattern_kind, None, false);
|
||||
let decl =
|
||||
self.ctx.ast.variable_declarator(SPAN, kind, binding, Some(init), false);
|
||||
|
||||
decls.push(decl);
|
||||
decls
|
||||
};
|
||||
let decl = self.ctx.ast.variable_declaration(SPAN, kind, decls, Modifiers::empty());
|
||||
let stmt: Statement<'_> =
|
||||
Statement::Declaration(Declaration::VariableDeclaration(decl));
|
||||
|
||||
statements.push(stmt);
|
||||
}
|
||||
|
||||
// Foo["x"] = init
|
||||
let member_expr = {
|
||||
let obj = self.ctx.ast.identifier_reference_expression(IdentifierReference::new(
|
||||
SPAN,
|
||||
enum_name.clone(),
|
||||
));
|
||||
let expr = self
|
||||
.ctx
|
||||
.ast
|
||||
.literal_string_expression(StringLiteral::new(SPAN, member_name.clone()));
|
||||
|
||||
self.ctx.ast.computed_member(SPAN, obj, expr, false)
|
||||
};
|
||||
let left = self.ctx.ast.simple_assignment_target_member_expression(member_expr);
|
||||
let mut expr =
|
||||
self.ctx.ast.assignment_expression(SPAN, AssignmentOperator::Assign, left, init);
|
||||
|
||||
// Foo[Foo["x"] = init] = "x"
|
||||
if !is_str {
|
||||
let member_expr = {
|
||||
let obj = self.ctx.ast.identifier_reference_expression(
|
||||
IdentifierReference::new(SPAN, enum_name.clone()),
|
||||
);
|
||||
self.ctx.ast.computed_member(SPAN, obj, expr, false)
|
||||
};
|
||||
let left = self.ctx.ast.simple_assignment_target_member_expression(member_expr);
|
||||
let right = self
|
||||
.ctx
|
||||
.ast
|
||||
.literal_string_expression(StringLiteral::new(SPAN, member_name.clone()));
|
||||
expr = self.ctx.ast.assignment_expression(
|
||||
SPAN,
|
||||
AssignmentOperator::Assign,
|
||||
left,
|
||||
right,
|
||||
);
|
||||
}
|
||||
|
||||
statements.push(self.ctx.ast.expression_statement(member.span, expr));
|
||||
|
||||
// 1 + Foo["x"]
|
||||
default_init = {
|
||||
let one = self.ctx.ast.literal_number_expression(NumericLiteral {
|
||||
span: SPAN,
|
||||
value: 1.0,
|
||||
raw: "1",
|
||||
base: NumberBase::Decimal,
|
||||
});
|
||||
|
||||
self.ctx.ast.binary_expression(SPAN, one, BinaryOperator::Addition, self_ref)
|
||||
};
|
||||
}
|
||||
|
||||
let enum_ref = self
|
||||
.ctx
|
||||
.ast
|
||||
.identifier_reference_expression(IdentifierReference::new(SPAN, enum_name.clone()));
|
||||
// return Foo;
|
||||
let return_stmt = self.ctx.ast.return_statement(SPAN, Some(enum_ref));
|
||||
statements.push(return_stmt);
|
||||
|
||||
statements
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
mod annotations;
|
||||
mod collector;
|
||||
mod r#enum;
|
||||
mod namespace;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
|
@ -148,4 +149,21 @@ impl<'a> TypeScript<'a> {
|
|||
pub fn transform_statement(&mut self, stmt: &mut Statement<'a>) {
|
||||
self.annotations.transform_statement(stmt);
|
||||
}
|
||||
|
||||
pub fn transform_declaration(&mut self, decl: &mut Declaration<'a>) {
|
||||
match decl {
|
||||
Declaration::TSImportEqualsDeclaration(ts_import_equals)
|
||||
if ts_import_equals.import_kind.is_value() =>
|
||||
{
|
||||
// TODO: support for transform_ts_import_equals function
|
||||
// *decl = self.transform_ts_import_equals(ts_import_equals);
|
||||
}
|
||||
Declaration::TSEnumDeclaration(ts_enum_declaration) => {
|
||||
if let Some(expr) = self.transform_ts_enum(ts_enum_declaration) {
|
||||
*decl = expr;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
crates/oxc_transformer/src/utils.rs
Normal file
12
crates/oxc_transformer/src/utils.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use oxc_syntax::{identifier::is_identifier_name, keyword::is_keyword};
|
||||
|
||||
pub fn is_valid_identifier(name: &str, reserved: bool) -> bool {
|
||||
if reserved && (is_keyword(name) || is_reserved_word(name, true)) {
|
||||
return false;
|
||||
}
|
||||
is_identifier_name(name)
|
||||
}
|
||||
|
||||
pub fn is_reserved_word(name: &str, in_module: bool) -> bool {
|
||||
(in_module && name == "await") || name == "enum"
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue