Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/oxc_ast/src/ast/ts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,12 @@ impl<'a> Modifiers<'a> {
list.retain(|m| !m.kind.is_typescript_syntax());
}
}

pub fn add_modifier(&mut self, modifier: Modifier) {
if let Some(list) = self.0.as_mut() {
list.push(modifier);
}
}
}

/// Export Assignment in non-module files
Expand Down
11 changes: 3 additions & 8 deletions crates/oxc_transformer_dts/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,9 @@ impl<'a> TransformerDts<'a> {

let body = self.ctx.ast.class_body(decl.body.span, elements);

let modifiers = if decl.modifiers.is_contains_abstract() {
let modifiers = self.ctx.ast.new_vec_from_iter([
Modifier { span: SPAN, kind: ModifierKind::Declare },
Modifier { span: SPAN, kind: ModifierKind::Abstract },
]);
Modifiers::new(modifiers)
} else {
self.modifiers_declare()
let mut modifiers = self.modifiers_declare();
if decl.modifiers.is_contains_abstract() {
modifiers.add_modifier(Modifier { span: SPAN, kind: ModifierKind::Abstract });
};

Some(self.ctx.ast.class(
Expand Down
53 changes: 52 additions & 1 deletion crates/oxc_transformer_dts/src/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
use oxc_ast::ast::*;

use oxc_allocator::Box;
use oxc_ast::Visit;
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, SPAN};
use oxc_syntax::scope::ScopeFlags;

use crate::TransformerDts;

Expand Down Expand Up @@ -116,6 +118,53 @@ impl<'a> TransformerDts<'a> {
)
}

fn transform_ts_module_block(
&mut self,
block: &Box<'a, TSModuleBlock<'a>>,
) -> Box<'a, TSModuleBlock<'a>> {
// We need to enter a new scope for the module block, avoid add binding to the parent scope
self.scope.enter_scope(ScopeFlags::TsModuleBlock);
let stmts = self.transform_statements_on_demand(&block.body);
self.scope.leave_scope();
self.ctx.ast.ts_module_block(SPAN, stmts)
}

pub fn transform_ts_module_declaration(
&mut self,
decl: &Box<'a, TSModuleDeclaration<'a>>,
) -> Box<'a, TSModuleDeclaration<'a>> {
if decl.modifiers.is_contains_declare() {
return self.ctx.ast.copy(decl);
}

let Some(body) = &decl.body else {
return self.ctx.ast.copy(decl);
};

match body {
TSModuleDeclarationBody::TSModuleDeclaration(decl) => {
let inner = self.transform_ts_module_declaration(decl);
return self.ctx.ast.ts_module_declaration(
decl.span,
self.ctx.ast.copy(&decl.id),
Some(TSModuleDeclarationBody::TSModuleDeclaration(inner)),
decl.kind,
self.modifiers_declare(),
);
}
TSModuleDeclarationBody::TSModuleBlock(block) => {
let body = self.transform_ts_module_block(block);
return self.ctx.ast.ts_module_declaration(
decl.span,
self.ctx.ast.copy(&decl.id),
Some(TSModuleDeclarationBody::TSModuleBlock(body)),
decl.kind,
self.modifiers_declare(),
);
}
}
}

pub fn transform_declaration(
&mut self,
decl: &Declaration<'a>,
Expand Down Expand Up @@ -175,7 +224,9 @@ impl<'a> TransformerDts<'a> {
if self.scope.has_reference(&ident.name)
)
{
Some(Declaration::TSModuleDeclaration(self.ctx.ast.copy(decl)))
Some(Declaration::TSModuleDeclaration(
self.transform_ts_module_declaration(decl),
))
} else {
None
}
Expand Down
7 changes: 5 additions & 2 deletions crates/oxc_transformer_dts/src/inferrer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use oxc_ast::ast::{
TSType, TSTypeAnnotation,
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::SPAN;
use oxc_span::{GetSpan, SPAN};

use crate::{return_type::FunctionReturnType, TransformerDts};

Expand Down Expand Up @@ -78,7 +78,10 @@ impl<'a> TransformerDts<'a> {
} else {
if let Expression::TSAsExpression(expr) = &pattern.right {
if !expr.type_annotation.is_keyword_or_literal() {
self.ctx.error(OxcDiagnostic::error("Parameter must have an explicit type annotation with --isolatedDeclarations."));
self.ctx.error(
OxcDiagnostic::error("Parameter must have an explicit type annotation with --isolatedDeclarations.")
.with_label(expr.type_annotation.span())
);
}
}

Expand Down
62 changes: 37 additions & 25 deletions crates/oxc_transformer_dts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,31 @@ impl<'a> TransformerDts<'a> {
_trivias: Trivias,
) -> Self {
let ctx = Rc::new(TransformDtsCtx::new(allocator));
Self { ctx, scope: ScopeTree::new() }
Self { ctx, scope: ScopeTree::new(allocator) }
}

/// # Errors
///
/// Returns `Vec<Error>` if any errors were collected during the transformation.
pub fn build(mut self, program: &Program<'a>) -> TransformerDtsReturn {
let source_type = SourceType::default().with_module(true).with_typescript_definition(true);
let directives = self.ctx.ast.new_vec();
let stmts = self.transform_program(program);
let program = self.ctx.ast.program(SPAN, source_type, directives, None, stmts);
let source_text =
Codegen::<false>::new("", "", Trivias::default(), CodegenOptions::default())
.build(&program)
.source_text;

TransformerDtsReturn { source_text, errors: self.ctx.take_errors() }
}
}

impl<'a> TransformerDts<'a> {
pub fn transform_program(
&mut self,
program: &Program<'a>,
) -> oxc_allocator::Vec<'a, Statement<'a>> {
let has_import_or_export = program.body.iter().any(|stmt| {
matches!(
stmt,
Expand All @@ -63,30 +81,24 @@ impl<'a> TransformerDts<'a> {
)
});

let stmts = if has_import_or_export {
self.transform_program(program)
if has_import_or_export {
self.transform_statements_on_demand(&program.body)
} else {
self.transform_program_without_module_declaration(program)
};

let source_type = SourceType::default().with_module(true).with_typescript_definition(true);
let directives = self.ctx.ast.new_vec();
let program = self.ctx.ast.program(SPAN, source_type, directives, None, stmts);
let source_text =
Codegen::<false>::new("", "", Trivias::default(), CodegenOptions::default())
.build(&program)
.source_text;
TransformerDtsReturn { source_text, errors: self.ctx.take_errors() }
}
}

pub fn modifiers_declare(&self) -> Modifiers<'a> {
Modifiers::new(
self.ctx.ast.new_vec_single(Modifier { span: SPAN, kind: ModifierKind::Declare }),
)
if self.scope.is_ts_module_block_flag() {
// If we are in a module block, we don't need to add declare
Modifiers::empty()
} else {
Modifiers::new(
self.ctx.ast.new_vec_single(Modifier { span: SPAN, kind: ModifierKind::Declare }),
)
}
}
}

impl<'a> TransformerDts<'a> {
pub fn transform_program_without_module_declaration(
&mut self,
program: &Program<'a>,
Expand All @@ -104,9 +116,9 @@ impl<'a> TransformerDts<'a> {
new_ast_stmts
}

pub fn transform_program(
pub fn transform_statements_on_demand(
&mut self,
program: &Program<'a>,
stmts: &oxc_allocator::Vec<'a, Statement<'a>>,
) -> oxc_allocator::Vec<'a, Statement<'a>> {
let mut new_stmts = Vec::new();
let mut variables_declarations = VecDeque::new();
Expand All @@ -116,7 +128,7 @@ impl<'a> TransformerDts<'a> {
// 2. Transform export declarations
// 3. Collect all bindings / reference from module declarations
// 4. Collect transformed indexes
program.body.iter().for_each(|stmt| match stmt {
stmts.iter().for_each(|stmt| match stmt {
match_declaration!(Statement) => {
match stmt.to_declaration() {
Declaration::VariableDeclaration(decl) => {
Expand Down Expand Up @@ -229,9 +241,9 @@ impl<'a> TransformerDts<'a> {
}

// 6. Transform variable/using declarations, import statements, remove unused imports
// 7. Generate code
let mut new_ast_stmts = self.ctx.ast.new_vec::<Statement<'a>>();
for (index, stmt) in new_stmts.drain(..).enumerate() {
// 7. Return transformed statements
let mut new_ast_stmts = self.ctx.ast.new_vec_with_capacity(transformed_indexes.len());
for (index, stmt) in new_stmts.into_iter().enumerate() {
match stmt {
_ if transformed_indexes.contains(&index) => {
new_ast_stmts.push(stmt);
Expand Down Expand Up @@ -283,7 +295,7 @@ impl<'a> TransformerDts<'a> {
if decl.specifiers.is_none() {
new_ast_stmts.push(Statement::ImportDeclaration(decl));
} else if let Some(decl) = self.transform_import_declaration(&decl) {
new_ast_stmts.push(Statement::ImportDeclaration(self.ctx.ast.alloc(decl)));
new_ast_stmts.push(Statement::ImportDeclaration(decl));
}
}
_ => {}
Expand Down
17 changes: 9 additions & 8 deletions crates/oxc_transformer_dts/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[allow(clippy::wildcard_imports)]
use oxc_ast::ast::*;

use oxc_allocator::Box;
use oxc_span::{GetSpan, SPAN};

use crate::TransformerDts;
Expand Down Expand Up @@ -90,7 +91,7 @@ impl<'a> TransformerDts<'a> {
pub fn transform_import_declaration(
&self,
decl: &ImportDeclaration<'a>,
) -> Option<ImportDeclaration<'a>> {
) -> Option<Box<'a, ImportDeclaration<'a>>> {
let specifiers = decl.specifiers.as_ref()?;

let mut specifiers = self.ctx.ast.copy(specifiers);
Expand All @@ -109,13 +110,13 @@ impl<'a> TransformerDts<'a> {
// We don't need to print this import statement
None
} else {
Some(ImportDeclaration {
span: decl.span,
specifiers: Some(specifiers),
source: self.ctx.ast.copy(&decl.source),
with_clause: self.ctx.ast.copy(&decl.with_clause),
import_kind: decl.import_kind,
})
Some(self.ctx.ast.import_declaration(
decl.span,
Some(specifiers),
self.ctx.ast.copy(&decl.source),
self.ctx.ast.copy(&decl.with_clause),
decl.import_kind,
))
}
}
}
Loading