mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer): start on TypeScript annotation removal (#2951)
This commit is contained in:
parent
93ce5a919a
commit
e67355045e
7 changed files with 564 additions and 26 deletions
|
|
@ -113,6 +113,17 @@ pub enum Expression<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Expression<'a> {
|
impl<'a> Expression<'a> {
|
||||||
|
pub fn is_typescript_syntax(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
Self::TSAsExpression(_)
|
||||||
|
| Self::TSSatisfiesExpression(_)
|
||||||
|
| Self::TSTypeAssertion(_)
|
||||||
|
| Self::TSNonNullExpression(_)
|
||||||
|
| Self::TSInstantiationExpression(_)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_primary_expression(&self) -> bool {
|
pub fn is_primary_expression(&self) -> bool {
|
||||||
self.is_literal()
|
self.is_literal()
|
||||||
|| matches!(
|
|| matches!(
|
||||||
|
|
@ -1289,6 +1300,7 @@ impl<'a> Declaration<'a> {
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn modifiers(&self) -> Option<&Modifiers<'a>> {
|
pub fn modifiers(&self) -> Option<&Modifiers<'a>> {
|
||||||
match self {
|
match self {
|
||||||
Declaration::VariableDeclaration(decl) => Some(&decl.modifiers),
|
Declaration::VariableDeclaration(decl) => Some(&decl.modifiers),
|
||||||
|
|
@ -1659,6 +1671,10 @@ impl<'a> BindingPattern<'a> {
|
||||||
pub fn new_with_kind(kind: BindingPatternKind<'a>) -> Self {
|
pub fn new_with_kind(kind: BindingPatternKind<'a>) -> Self {
|
||||||
Self { kind, type_annotation: None, optional: false }
|
Self { kind, type_annotation: None, optional: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_identifier(&self) -> Option<&Atom<'a>> {
|
||||||
|
self.kind.get_identifier()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
|
@ -1679,6 +1695,14 @@ pub enum BindingPatternKind<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BindingPatternKind<'a> {
|
impl<'a> BindingPatternKind<'a> {
|
||||||
|
pub fn get_identifier(&self) -> Option<&Atom<'a>> {
|
||||||
|
match self {
|
||||||
|
Self::BindingIdentifier(ident) => Some(&ident.name),
|
||||||
|
Self::AssignmentPattern(assign) => assign.left.get_identifier(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_destructuring_pattern(&self) -> bool {
|
pub fn is_destructuring_pattern(&self) -> bool {
|
||||||
matches!(self, Self::ObjectPattern(_) | Self::ArrayPattern(_))
|
matches!(self, Self::ObjectPattern(_) | Self::ArrayPattern(_))
|
||||||
}
|
}
|
||||||
|
|
@ -1809,8 +1833,10 @@ pub struct Function<'a> {
|
||||||
|
|
||||||
impl<'a> Function<'a> {
|
impl<'a> Function<'a> {
|
||||||
pub fn is_typescript_syntax(&self) -> bool {
|
pub fn is_typescript_syntax(&self) -> bool {
|
||||||
self.r#type == FunctionType::TSDeclareFunction
|
matches!(
|
||||||
|| self.body.is_none()
|
self.r#type,
|
||||||
|
FunctionType::TSDeclareFunction | FunctionType::TSEmptyBodyFunctionExpression
|
||||||
|
) || self.body.is_none()
|
||||||
|| self.modifiers.contains(ModifierKind::Declare)
|
|| self.modifiers.contains(ModifierKind::Declare)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1007,6 +1007,12 @@ pub enum ModifierKind {
|
||||||
Override,
|
Override,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ModifierKind {
|
||||||
|
pub fn is_typescript_syntax(&self) -> bool {
|
||||||
|
!matches!(self, Self::Async | Self::Default | Self::Export | Self::Static)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||||
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
|
||||||
|
|
@ -1043,6 +1049,12 @@ impl<'a> Modifiers<'a> {
|
||||||
pub fn is_contains_declare(&self) -> bool {
|
pub fn is_contains_declare(&self) -> bool {
|
||||||
self.contains(ModifierKind::Declare)
|
self.contains(ModifierKind::Declare)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_type_modifiers(&mut self) {
|
||||||
|
if let Some(list) = &mut self.0 {
|
||||||
|
list.retain(|m| !m.kind.is_typescript_syntax());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Export Assignment in non-module files
|
/// Export Assignment in non-module files
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,11 @@ impl<'a> AstBuilder<'a> {
|
||||||
vec
|
vec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new_vec_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> Vec<'a, T> {
|
||||||
|
Vec::from_iter_in(iter, self.allocator)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_str(&self, value: &str) -> &'a str {
|
pub fn new_str(&self, value: &str) -> &'a str {
|
||||||
String::from_str_in(value, self.allocator).into_bump_str()
|
String::from_str_in(value, self.allocator).into_bump_str()
|
||||||
|
|
@ -210,6 +215,14 @@ impl<'a> AstBuilder<'a> {
|
||||||
Expression::TemplateLiteral(self.alloc(literal))
|
Expression::TemplateLiteral(self.alloc(literal))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn identifier_name(&self, span: Span, name: &str) -> IdentifierName<'a> {
|
||||||
|
IdentifierName::new(span, self.new_atom(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn identifier_reference(&self, span: Span, name: &str) -> IdentifierReference<'a> {
|
||||||
|
IdentifierReference::new(span, self.new_atom(name))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn identifier_reference_expression(
|
pub fn identifier_reference_expression(
|
||||||
&self,
|
&self,
|
||||||
ident: IdentifierReference<'a>,
|
ident: IdentifierReference<'a>,
|
||||||
|
|
@ -1195,6 +1208,22 @@ impl<'a> AstBuilder<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn plain_export_named_declaration(
|
||||||
|
&self,
|
||||||
|
span: Span,
|
||||||
|
specifiers: Vec<'a, ExportSpecifier<'a>>,
|
||||||
|
source: Option<StringLiteral<'a>>,
|
||||||
|
) -> Box<'a, ExportNamedDeclaration<'a>> {
|
||||||
|
self.export_named_declaration(
|
||||||
|
span,
|
||||||
|
None,
|
||||||
|
specifiers,
|
||||||
|
source,
|
||||||
|
ImportOrExportKind::Value,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- JSX ----------------- */
|
/* ---------- JSX ----------------- */
|
||||||
pub fn jsx_element(
|
pub fn jsx_element(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
||||||
|
|
@ -77,38 +77,135 @@ impl<'a> Transformer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VisitMut<'a> for Transformer<'a> {
|
impl<'a> VisitMut<'a> for Transformer<'a> {
|
||||||
fn visit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
fn visit_program(&mut self, program: &mut Program<'a>) {
|
||||||
self.x0_typescript.transform_statements(stmts);
|
walk_mut::walk_program_mut(self, program);
|
||||||
walk_mut::walk_statements_mut(self, stmts);
|
|
||||||
|
self.x0_typescript.transform_program_on_exit(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_statement(&mut self, stmt: &mut Statement<'a>) {
|
// ALPHASORT
|
||||||
self.x2_decorators.transform_statement(stmt);
|
|
||||||
walk_mut::walk_statement_mut(self, stmt);
|
fn visit_arrow_expression(&mut self, expr: &mut ArrowFunctionExpression<'a>) {
|
||||||
|
self.x0_typescript.transform_arrow_expression(expr);
|
||||||
|
|
||||||
|
walk_mut::walk_arrow_expression_mut(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_expression(&mut self, expr: &mut Expression<'a>) {
|
fn visit_binding_pattern(&mut self, pat: &mut BindingPattern<'a>) {
|
||||||
self.x1_react.transform_expression(expr);
|
self.x0_typescript.transform_binding_pattern(pat);
|
||||||
walk_mut::walk_expression_mut(self, expr);
|
|
||||||
|
walk_mut::walk_binding_pattern_mut(self, pat);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_variable_declarator(&mut self, declarator: &mut VariableDeclarator<'a>) {
|
fn visit_call_expression(&mut self, expr: &mut CallExpression<'a>) {
|
||||||
self.x1_react.transform_variable_declarator(declarator);
|
self.x0_typescript.transform_call_expression(expr);
|
||||||
walk_mut::walk_variable_declarator_mut(self, declarator);
|
|
||||||
|
walk_mut::walk_call_expression_mut(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_object_property(&mut self, prop: &mut ObjectProperty<'a>) {
|
fn visit_class(&mut self, class: &mut Class<'a>) {
|
||||||
self.x1_react.transform_object_property(prop);
|
self.x0_typescript.transform_class(class);
|
||||||
walk_mut::walk_object_property_mut(self, prop);
|
|
||||||
|
walk_mut::walk_class_mut(self, class);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_class_body(&mut self, body: &mut ClassBody<'a>) {
|
||||||
|
self.x0_typescript.transform_class_body(body);
|
||||||
|
|
||||||
|
walk_mut::walk_class_body_mut(self, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_export_default_declaration(&mut self, decl: &mut ExportDefaultDeclaration<'a>) {
|
fn visit_export_default_declaration(&mut self, decl: &mut ExportDefaultDeclaration<'a>) {
|
||||||
self.x1_react.transform_export_default_declaration(decl);
|
self.x1_react.transform_export_default_declaration(decl);
|
||||||
|
|
||||||
walk_mut::walk_export_default_declaration_mut(self, decl);
|
walk_mut::walk_export_default_declaration_mut(self, decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_export_named_declaration(&mut self, decl: &mut ExportNamedDeclaration<'a>) {
|
||||||
|
self.x0_typescript.transform_export_named_declaration(decl);
|
||||||
|
|
||||||
|
walk_mut::walk_export_named_declaration_mut(self, decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_expression(&mut self, expr: &mut Expression<'a>) {
|
||||||
|
self.x0_typescript.transform_expression(expr);
|
||||||
|
self.x1_react.transform_expression(expr);
|
||||||
|
|
||||||
|
walk_mut::walk_expression_mut(self, expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_formal_parameter(&mut self, param: &mut FormalParameter<'a>) {
|
||||||
|
self.x0_typescript.transform_formal_parameter(param);
|
||||||
|
|
||||||
|
walk_mut::walk_formal_parameter_mut(self, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_function(&mut self, func: &mut Function<'a>, flags: Option<oxc_semantic::ScopeFlags>) {
|
||||||
|
self.x0_typescript.transform_function(func, flags);
|
||||||
|
|
||||||
|
walk_mut::walk_function_mut(self, func, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_import_declaration(&mut self, decl: &mut ImportDeclaration<'a>) {
|
||||||
|
self.x0_typescript.transform_import_declaration(decl);
|
||||||
|
|
||||||
|
walk_mut::walk_import_declaration_mut(self, decl);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) {
|
fn visit_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) {
|
||||||
|
self.x0_typescript.transform_jsx_opening_element(elem);
|
||||||
self.x1_react.transform_jsx_opening_element(elem);
|
self.x1_react.transform_jsx_opening_element(elem);
|
||||||
|
|
||||||
walk_mut::walk_jsx_opening_element_mut(self, elem);
|
walk_mut::walk_jsx_opening_element_mut(self, elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_method_definition(&mut self, def: &mut MethodDefinition<'a>) {
|
||||||
|
self.x0_typescript.transform_method_definition(def);
|
||||||
|
|
||||||
|
walk_mut::walk_method_definition_mut(self, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_new_expression(&mut self, expr: &mut NewExpression<'a>) {
|
||||||
|
self.x0_typescript.transform_new_expression(expr);
|
||||||
|
|
||||||
|
walk_mut::walk_new_expression_mut(self, expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_object_property(&mut self, prop: &mut ObjectProperty<'a>) {
|
||||||
|
self.x1_react.transform_object_property(prop);
|
||||||
|
|
||||||
|
walk_mut::walk_object_property_mut(self, prop);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_property_definition(&mut self, def: &mut PropertyDefinition<'a>) {
|
||||||
|
self.x0_typescript.transform_property_definition(def);
|
||||||
|
|
||||||
|
walk_mut::walk_property_definition_mut(self, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
|
self.x0_typescript.transform_statements(stmts);
|
||||||
|
|
||||||
|
walk_mut::walk_statements_mut(self, stmts);
|
||||||
|
|
||||||
|
self.x0_typescript.transform_statements_on_exit(stmts);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_statement(&mut self, stmt: &mut Statement<'a>) {
|
||||||
|
self.x2_decorators.transform_statement(stmt);
|
||||||
|
|
||||||
|
walk_mut::walk_statement_mut(self, stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_tagged_template_expression(&mut self, expr: &mut TaggedTemplateExpression<'a>) {
|
||||||
|
self.x0_typescript.transform_tagged_template_expression(expr);
|
||||||
|
|
||||||
|
walk_mut::walk_tagged_template_expression_mut(self, expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_variable_declarator(&mut self, declarator: &mut VariableDeclarator<'a>) {
|
||||||
|
self.x1_react.transform_variable_declarator(declarator);
|
||||||
|
|
||||||
|
walk_mut::walk_variable_declarator_mut(self, declarator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
287
crates/oxc_transformer/src/typescript/annotations.rs
Normal file
287
crates/oxc_transformer/src/typescript/annotations.rs
Normal file
|
|
@ -0,0 +1,287 @@
|
||||||
|
#![allow(clippy::unused_self)]
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::context::Ctx;
|
||||||
|
use crate::TypeScriptOptions;
|
||||||
|
|
||||||
|
use oxc_allocator::Vec;
|
||||||
|
use oxc_ast::ast::*;
|
||||||
|
use oxc_span::{Atom, SPAN};
|
||||||
|
use oxc_syntax::operator::AssignmentOperator;
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
|
pub struct TypeScriptAnnotations<'a> {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
options: Rc<TypeScriptOptions>,
|
||||||
|
ctx: Ctx<'a>,
|
||||||
|
|
||||||
|
global_types: FxHashSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TypeScriptAnnotations<'a> {
|
||||||
|
pub fn new(options: &Rc<TypeScriptOptions>, ctx: &Ctx<'a>) -> Self {
|
||||||
|
Self {
|
||||||
|
options: Rc::clone(options),
|
||||||
|
ctx: Rc::clone(ctx),
|
||||||
|
global_types: FxHashSet::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_global_type(&self) -> bool {
|
||||||
|
self.global_types.contains("TODO")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert `export = expr` into `module.exports = expr`
|
||||||
|
fn create_module_exports(&self, exp: &TSExportAssignment<'a>) -> Statement<'a> {
|
||||||
|
let ast = &self.ctx.ast;
|
||||||
|
|
||||||
|
ast.expression_statement(
|
||||||
|
SPAN,
|
||||||
|
ast.assignment_expression(
|
||||||
|
SPAN,
|
||||||
|
AssignmentOperator::Assign,
|
||||||
|
ast.simple_assignment_target_member_expression(ast.static_member(
|
||||||
|
SPAN,
|
||||||
|
ast.identifier_reference_expression(ast.identifier_reference(SPAN, "module")),
|
||||||
|
ast.identifier_name(SPAN, "exports"),
|
||||||
|
false,
|
||||||
|
)),
|
||||||
|
ast.copy(&exp.expression),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates `this.name = name`
|
||||||
|
fn create_this_property_assignment(&self, name: &Atom<'a>) -> Statement<'a> {
|
||||||
|
let ast = &self.ctx.ast;
|
||||||
|
|
||||||
|
ast.expression_statement(
|
||||||
|
SPAN,
|
||||||
|
ast.assignment_expression(
|
||||||
|
SPAN,
|
||||||
|
AssignmentOperator::Assign,
|
||||||
|
ast.simple_assignment_target_member_expression(ast.static_member(
|
||||||
|
SPAN,
|
||||||
|
ast.this_expression(SPAN),
|
||||||
|
ast.identifier_name(SPAN, name),
|
||||||
|
false,
|
||||||
|
)),
|
||||||
|
ast.identifier_reference_expression(ast.identifier_reference(SPAN, name)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove type only imports/exports
|
||||||
|
pub fn transform_program_on_exit(&self, program: &mut Program<'a>) {
|
||||||
|
let mut module_count = 0;
|
||||||
|
|
||||||
|
let body =
|
||||||
|
self.ctx.ast.move_statement_vec(&mut program.body).into_iter().filter_map(|stmt| {
|
||||||
|
// If an import/export declaration, remove all that are type-only
|
||||||
|
if let Statement::ModuleDeclaration(decl) = &stmt {
|
||||||
|
let keep = match &**decl {
|
||||||
|
ModuleDeclaration::ImportDeclaration(inner) => !inner.import_kind.is_type(),
|
||||||
|
ModuleDeclaration::ExportAllDeclaration(inner) => {
|
||||||
|
!inner.is_typescript_syntax()
|
||||||
|
}
|
||||||
|
ModuleDeclaration::ExportNamedDeclaration(inner) => {
|
||||||
|
!(inner.is_typescript_syntax()
|
||||||
|
|| inner.specifiers.is_empty()
|
||||||
|
|| inner.specifiers.iter().all(|spec| spec.export_kind.is_type())
|
||||||
|
|| self.is_global_type())
|
||||||
|
}
|
||||||
|
ModuleDeclaration::ExportDefaultDeclaration(inner) => {
|
||||||
|
!inner.is_typescript_syntax()
|
||||||
|
}
|
||||||
|
ModuleDeclaration::TSNamespaceExportDeclaration(_) => false,
|
||||||
|
|
||||||
|
// Replace with `module.exports = expr`
|
||||||
|
ModuleDeclaration::TSExportAssignment(exp) => {
|
||||||
|
return Some(self.create_module_exports(exp));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if keep {
|
||||||
|
module_count += 1;
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(stmt)
|
||||||
|
});
|
||||||
|
|
||||||
|
program.body = self.ctx.ast.new_vec_from_iter(body);
|
||||||
|
|
||||||
|
// Determine if we still have import/export statements, otherwise we
|
||||||
|
// need to inject an empty statement (`export {}`) so that the file is
|
||||||
|
// still considered a module
|
||||||
|
if module_count == 0 && self.ctx.semantic.source_type().is_module() {
|
||||||
|
// FIXME
|
||||||
|
// program.body.push(self.ctx.ast.module_declaration(
|
||||||
|
// ModuleDeclaration::ExportNamedDeclaration(
|
||||||
|
// self.ctx.ast.plain_export_named_declaration(SPAN, self.ctx.ast.new_vec(), None),
|
||||||
|
// ),
|
||||||
|
// ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_arrow_expression(&mut self, expr: &mut ArrowFunctionExpression<'a>) {
|
||||||
|
expr.type_parameters = None;
|
||||||
|
expr.return_type = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_binding_pattern(&mut self, pat: &mut BindingPattern<'a>) {
|
||||||
|
pat.type_annotation = None;
|
||||||
|
|
||||||
|
if pat.kind.is_binding_identifier() {
|
||||||
|
pat.optional = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_call_expression(&mut self, expr: &mut CallExpression<'a>) {
|
||||||
|
expr.type_parameters = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_class(&mut self, class: &mut Class<'a>) {
|
||||||
|
class.type_parameters = None;
|
||||||
|
class.super_type_parameters = None;
|
||||||
|
class.implements = None;
|
||||||
|
class.modifiers.remove_type_modifiers();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_class_body(&mut self, body: &mut ClassBody<'a>) {
|
||||||
|
// Remove type only members
|
||||||
|
body.body.retain(|elem| match elem {
|
||||||
|
ClassElement::MethodDefinition(method) => {
|
||||||
|
matches!(method.r#type, MethodDefinitionType::MethodDefinition)
|
||||||
|
|| !method.value.is_typescript_syntax()
|
||||||
|
}
|
||||||
|
ClassElement::PropertyDefinition(prop) => {
|
||||||
|
if prop.value.as_ref().is_some_and(Expression::is_typescript_syntax)
|
||||||
|
|| prop.declare && prop.decorators.is_empty()
|
||||||
|
{
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
matches!(prop.r#type, PropertyDefinitionType::PropertyDefinition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClassElement::TSIndexSignature(_) => false,
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_export_named_declaration(&mut self, decl: &mut ExportNamedDeclaration<'a>) {
|
||||||
|
// Remove type only specifiers
|
||||||
|
decl.specifiers.retain(|spec| !spec.export_kind.is_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_expression(&mut self, expr: &mut Expression<'a>) {
|
||||||
|
*expr = self.ctx.ast.copy(expr.get_inner_expression());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_formal_parameter(&mut self, param: &mut FormalParameter<'a>) {
|
||||||
|
param.accessibility = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_function(
|
||||||
|
&mut self,
|
||||||
|
func: &mut Function<'a>,
|
||||||
|
_flags: Option<oxc_semantic::ScopeFlags>,
|
||||||
|
) {
|
||||||
|
func.this_param = None;
|
||||||
|
func.type_parameters = None;
|
||||||
|
func.return_type = None;
|
||||||
|
func.modifiers.remove_type_modifiers();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_import_declaration(&mut self, decl: &mut ImportDeclaration<'a>) {
|
||||||
|
// Remove type only specifiers
|
||||||
|
if let Some(specifiers) = &mut decl.specifiers {
|
||||||
|
specifiers.retain(|spec| match spec {
|
||||||
|
ImportDeclarationSpecifier::ImportSpecifier(inner) => !inner.import_kind.is_type(),
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) {
|
||||||
|
elem.type_parameters = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_method_definition(&mut self, def: &mut MethodDefinition<'a>) {
|
||||||
|
def.accessibility = None;
|
||||||
|
def.optional = false;
|
||||||
|
def.r#override = false;
|
||||||
|
|
||||||
|
// Collects parameter properties so that we can add an assignment
|
||||||
|
// for each of them in the constructor body.
|
||||||
|
if def.kind == MethodDefinitionKind::Constructor {
|
||||||
|
let mut assigns = self.ctx.ast.new_vec();
|
||||||
|
|
||||||
|
for param in &def.value.params.items {
|
||||||
|
if param.pattern.type_annotation.is_none() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(id) = param.pattern.get_identifier() {
|
||||||
|
assigns.push(self.create_this_property_assignment(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !assigns.is_empty() {
|
||||||
|
def.value
|
||||||
|
.body
|
||||||
|
.get_or_insert(self.ctx.ast.function_body(
|
||||||
|
SPAN,
|
||||||
|
self.ctx.ast.new_vec(),
|
||||||
|
self.ctx.ast.new_vec(),
|
||||||
|
))
|
||||||
|
.statements
|
||||||
|
.extend(assigns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_new_expression(&mut self, expr: &mut NewExpression<'a>) {
|
||||||
|
expr.type_parameters = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_property_definition(&mut self, def: &mut PropertyDefinition<'a>) {
|
||||||
|
assert!(
|
||||||
|
!(def.declare && def.value.is_some()),
|
||||||
|
"Fields with the 'declare' modifier cannot be initialized here, but only in the constructor"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!(def.definite && def.value.is_some()),
|
||||||
|
"Definitely assigned fields cannot be initialized here, but only in the constructor"
|
||||||
|
);
|
||||||
|
|
||||||
|
def.accessibility = None;
|
||||||
|
def.declare = false;
|
||||||
|
def.definite = false;
|
||||||
|
def.r#override = false;
|
||||||
|
def.optional = false;
|
||||||
|
def.readonly = false;
|
||||||
|
def.type_annotation = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_statements_on_exit(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
|
// Remove TS specific statements
|
||||||
|
stmts.retain(|stmt| match stmt {
|
||||||
|
Statement::ExpressionStatement(s) => !s.expression.is_typescript_syntax(),
|
||||||
|
Statement::Declaration(s) => !s.is_typescript_syntax(),
|
||||||
|
// Ignore ModuleDeclaration as it's handled in the program
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_tagged_template_expression(
|
||||||
|
&mut self,
|
||||||
|
expr: &mut TaggedTemplateExpression<'a>,
|
||||||
|
) {
|
||||||
|
expr.type_parameters = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod annotations;
|
||||||
mod namespace;
|
mod namespace;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -9,6 +10,8 @@ use oxc_ast::ast::*;
|
||||||
|
|
||||||
use crate::context::Ctx;
|
use crate::context::Ctx;
|
||||||
|
|
||||||
|
use self::annotations::TypeScriptAnnotations;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Deserialize)]
|
#[derive(Debug, Default, Clone, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TypeScriptOptions;
|
pub struct TypeScriptOptions;
|
||||||
|
|
@ -36,19 +39,102 @@ pub struct TypeScriptOptions;
|
||||||
/// Out: `const x = 0;`
|
/// Out: `const x = 0;`
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct TypeScript<'a> {
|
pub struct TypeScript<'a> {
|
||||||
options: TypeScriptOptions,
|
options: Rc<TypeScriptOptions>,
|
||||||
ctx: Ctx<'a>,
|
ctx: Ctx<'a>,
|
||||||
|
|
||||||
|
annotations: TypeScriptAnnotations<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TypeScript<'a> {
|
impl<'a> TypeScript<'a> {
|
||||||
pub fn new(options: TypeScriptOptions, ctx: &Ctx<'a>) -> Self {
|
pub fn new(options: TypeScriptOptions, ctx: &Ctx<'a>) -> Self {
|
||||||
Self { options, ctx: Rc::clone(ctx) }
|
let options = Rc::new(options);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
annotations: TypeScriptAnnotations::new(&options, ctx),
|
||||||
|
options,
|
||||||
|
ctx: Rc::clone(ctx),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transforms
|
// Transforms
|
||||||
impl<'a> TypeScript<'a> {
|
impl<'a> TypeScript<'a> {
|
||||||
|
pub fn transform_program_on_exit(&self, program: &mut Program<'a>) {
|
||||||
|
self.annotations.transform_program_on_exit(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_arrow_expression(&mut self, expr: &mut ArrowFunctionExpression<'a>) {
|
||||||
|
self.annotations.transform_arrow_expression(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_binding_pattern(&mut self, pat: &mut BindingPattern<'a>) {
|
||||||
|
self.annotations.transform_binding_pattern(pat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_call_expression(&mut self, expr: &mut CallExpression<'a>) {
|
||||||
|
self.annotations.transform_call_expression(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_class(&mut self, class: &mut Class<'a>) {
|
||||||
|
self.annotations.transform_class(class);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_class_body(&mut self, body: &mut ClassBody<'a>) {
|
||||||
|
self.annotations.transform_class_body(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_export_named_declaration(&mut self, decl: &mut ExportNamedDeclaration<'a>) {
|
||||||
|
self.annotations.transform_export_named_declaration(decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_expression(&mut self, expr: &mut Expression<'a>) {
|
||||||
|
self.annotations.transform_expression(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_formal_parameter(&mut self, param: &mut FormalParameter<'a>) {
|
||||||
|
self.annotations.transform_formal_parameter(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_function(
|
||||||
|
&mut self,
|
||||||
|
func: &mut Function<'a>,
|
||||||
|
flags: Option<oxc_semantic::ScopeFlags>,
|
||||||
|
) {
|
||||||
|
self.annotations.transform_function(func, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_import_declaration(&mut self, decl: &mut ImportDeclaration<'a>) {
|
||||||
|
self.annotations.transform_import_declaration(decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_jsx_opening_element(&mut self, elem: &mut JSXOpeningElement<'a>) {
|
||||||
|
self.annotations.transform_jsx_opening_element(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_method_definition(&mut self, def: &mut MethodDefinition<'a>) {
|
||||||
|
self.annotations.transform_method_definition(def);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_new_expression(&mut self, expr: &mut NewExpression<'a>) {
|
||||||
|
self.annotations.transform_new_expression(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_property_definition(&mut self, def: &mut PropertyDefinition<'a>) {
|
||||||
|
self.annotations.transform_property_definition(def);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
self.transform_statements_for_namespace(stmts);
|
self.transform_statements_for_namespace(stmts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transform_statements_on_exit(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
|
||||||
|
self.annotations.transform_statements_on_exit(stmts);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_tagged_template_expression(
|
||||||
|
&mut self,
|
||||||
|
expr: &mut TaggedTemplateExpression<'a>,
|
||||||
|
) {
|
||||||
|
self.annotations.transform_tagged_template_expression(expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
Passed: 77/178
|
Passed: 76/178
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-plugin-transform-react-jsx-source
|
* babel-plugin-transform-react-jsx-source
|
||||||
|
|
||||||
|
|
||||||
# babel-plugin-transform-typescript (60/158)
|
# babel-plugin-transform-typescript (59/158)
|
||||||
* class/abstract-class-decorated/input.ts
|
* class/abstract-class-decorated/input.ts
|
||||||
* class/abstract-class-decorated-method/input.ts
|
* class/abstract-class-decorated-method/input.ts
|
||||||
* class/abstract-class-decorated-parameter/input.ts
|
* class/abstract-class-decorated-parameter/input.ts
|
||||||
* class/accessor-allowDeclareFields-false/input.ts
|
* class/accessor-allowDeclareFields-false/input.ts
|
||||||
* class/accessor-allowDeclareFields-true/input.ts
|
* class/accessor-allowDeclareFields-true/input.ts
|
||||||
* class/declare/input.ts
|
|
||||||
* class/decorated-declare-properties/input.ts
|
* class/decorated-declare-properties/input.ts
|
||||||
* class/parameter-properties/input.ts
|
* class/parameter-properties/input.ts
|
||||||
* class/parameter-properties-late-super/input.ts
|
* class/parameter-properties-late-super/input.ts
|
||||||
|
|
@ -23,6 +22,8 @@ Passed: 77/178
|
||||||
* declarations/erased/input.ts
|
* declarations/erased/input.ts
|
||||||
* declarations/export-declare-enum/input.ts
|
* declarations/export-declare-enum/input.ts
|
||||||
* declarations/nested-namespace/input.mjs
|
* declarations/nested-namespace/input.mjs
|
||||||
|
* exports/declare-namespace/input.ts
|
||||||
|
* exports/declare-shadowed/input.ts
|
||||||
* exports/declared-types/input.ts
|
* exports/declared-types/input.ts
|
||||||
* exports/export-const-enums/input.ts
|
* exports/export-const-enums/input.ts
|
||||||
* exports/export-type/input.ts
|
* exports/export-type/input.ts
|
||||||
|
|
@ -33,9 +34,9 @@ Passed: 77/178
|
||||||
* exports/imported-types/input.ts
|
* exports/imported-types/input.ts
|
||||||
* exports/imported-types-only-remove-type-imports/input.ts
|
* exports/imported-types-only-remove-type-imports/input.ts
|
||||||
* exports/issue-9916-3/input.ts
|
* exports/issue-9916-3/input.ts
|
||||||
|
* exports/simple/input.ts
|
||||||
* exports/type-only-export-specifier-1/input.ts
|
* exports/type-only-export-specifier-1/input.ts
|
||||||
* exports/type-only-export-specifier-2/input.ts
|
* exports/type-only-export-specifier-2/input.ts
|
||||||
* exports/type-only-export-specifier-3/input.ts
|
|
||||||
* function/overloads-exports/input.mjs
|
* function/overloads-exports/input.mjs
|
||||||
* imports/elide-injected/input.ts
|
* imports/elide-injected/input.ts
|
||||||
* imports/elide-preact/input.ts
|
* imports/elide-preact/input.ts
|
||||||
|
|
@ -56,15 +57,12 @@ Passed: 77/178
|
||||||
* imports/import=-declaration/input.ts
|
* imports/import=-declaration/input.ts
|
||||||
* imports/import=-module/input.ts
|
* imports/import=-module/input.ts
|
||||||
* imports/import=-module-to-cjs/input.ts
|
* imports/import=-module-to-cjs/input.ts
|
||||||
* imports/only-remove-type-imports/input.ts
|
|
||||||
* imports/parameter-decorators/input.ts
|
* imports/parameter-decorators/input.ts
|
||||||
* imports/property-signature/input.ts
|
* imports/property-signature/input.ts
|
||||||
* imports/type-only-export-specifier-1/input.ts
|
* imports/type-only-export-specifier-1/input.ts
|
||||||
* imports/type-only-export-specifier-2/input.ts
|
* imports/type-only-export-specifier-2/input.ts
|
||||||
* imports/type-only-import-specifier-1/input.ts
|
|
||||||
* imports/type-only-import-specifier-2/input.ts
|
* imports/type-only-import-specifier-2/input.ts
|
||||||
* imports/type-only-import-specifier-3/input.ts
|
* imports/type-only-import-specifier-3/input.ts
|
||||||
* imports/type-only-import-specifier-4/input.ts
|
|
||||||
* namespace/alias/input.ts
|
* namespace/alias/input.ts
|
||||||
* namespace/ambient-module-nested/input.ts
|
* namespace/ambient-module-nested/input.ts
|
||||||
* namespace/ambient-module-nested-exported/input.ts
|
* namespace/ambient-module-nested-exported/input.ts
|
||||||
|
|
@ -74,7 +72,10 @@ Passed: 77/178
|
||||||
* namespace/clobber-export/input.ts
|
* namespace/clobber-export/input.ts
|
||||||
* namespace/clobber-import/input.ts
|
* namespace/clobber-import/input.ts
|
||||||
* namespace/contentious-names/input.ts
|
* namespace/contentious-names/input.ts
|
||||||
|
* namespace/declare/input.ts
|
||||||
|
* namespace/declare-global-nested-namespace/input.ts
|
||||||
* namespace/empty-removed/input.ts
|
* namespace/empty-removed/input.ts
|
||||||
|
* namespace/export/input.ts
|
||||||
* namespace/export-type-only/input.ts
|
* namespace/export-type-only/input.ts
|
||||||
* namespace/module-nested/input.ts
|
* namespace/module-nested/input.ts
|
||||||
* namespace/module-nested-export/input.ts
|
* namespace/module-nested-export/input.ts
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue