From 1b64e48ee1318804e22d5e7cafe4a8f493fd793e Mon Sep 17 00:00:00 2001 From: magic-akari Date: Thu, 26 Oct 2023 11:07:30 +0800 Subject: [PATCH] feat(transformer): strip implicit type import for typescript (#1058) --- crates/oxc_transformer/src/lib.rs | 3 +- crates/oxc_transformer/src/typescript/mod.rs | 69 +++++++++++++++++--- tasks/transform_conformance/babel.snap.md | 6 +- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 7cfa4506d..d78ad66dd 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -78,7 +78,8 @@ impl<'a> Transformer<'a> { scopes: Rc::clone(scopes), }; Self { - typescript: source_type.is_typescript().then(|| TypeScript::new(Rc::clone(&ast))), + // TODO: pass verbatim_module_syntax from user config + typescript: source_type.is_typescript().then(|| TypeScript::new(Rc::clone(&ast), ctx.clone(), false)), react_jsx: options.react_jsx.map(|options| ReactJsx::new(Rc::clone(&ast), options)), regexp_flags: RegexpFlags::new(Rc::clone(&ast), &options), es2022_class_static_block: es2022::ClassStaticBlock::new(Rc::clone(&ast), &options), diff --git a/crates/oxc_transformer/src/typescript/mod.rs b/crates/oxc_transformer/src/typescript/mod.rs index bac896805..ef954cc84 100644 --- a/crates/oxc_transformer/src/typescript/mod.rs +++ b/crates/oxc_transformer/src/typescript/mod.rs @@ -1,20 +1,29 @@ use oxc_ast::{ast::*, AstBuilder}; -use oxc_span::Span; +use oxc_span::{Atom, Span}; use std::rc::Rc; +use crate::context::TransformerCtx; + /// Transform TypeScript /// /// References: /// * /// * +/// * pub struct TypeScript<'a> { ast: Rc>, + ctx: TransformerCtx<'a>, + verbatim_module_syntax: bool, } impl<'a> TypeScript<'a> { - pub fn new(ast: Rc>) -> Self { - Self { ast } + pub fn new( + ast: Rc>, + ctx: TransformerCtx<'a>, + verbatim_module_syntax: bool, + ) -> Self { + Self { ast, ctx, verbatim_module_syntax } } #[allow(clippy::unused_self)] @@ -37,13 +46,31 @@ impl<'a> TypeScript<'a> { ModuleDeclaration::ExportNamedDeclaration(decl) => { decl.specifiers.retain(|specifier| specifier.export_kind.is_value()); } - ModuleDeclaration::ImportDeclaration(decl) => { + ModuleDeclaration::ImportDeclaration(decl) if decl.import_kind.is_value() => { if let Some(specifiers) = &mut decl.specifiers { specifiers.retain(|specifier| match specifier { ImportDeclarationSpecifier::ImportSpecifier(s) => { - s.import_kind.is_value() + if s.import_kind.is_type() { + return false; + } + + if self.verbatim_module_syntax { + return true; + } + + self.has_value_references(&s.local.name) } - _ => false, + ImportDeclarationSpecifier::ImportDefaultSpecifier(s) + if !self.verbatim_module_syntax => + { + self.has_value_references(&s.local.name) + } + ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) + if !self.verbatim_module_syntax => + { + self.has_value_references(&s.local.name) + } + _ => true, }); } } @@ -58,19 +85,26 @@ impl<'a> TypeScript<'a> { if decl.import_kind.is_type() { return false; } - if decl.specifiers.as_ref().is_some_and(|specifiers| specifiers.is_empty()) { - // TODO: verbatim_module_syntax - return false; + + if self.verbatim_module_syntax { + return true; } - true + + !decl.specifiers.as_ref().is_some_and(|specifiers| specifiers.is_empty()) } ModuleDeclaration::ExportNamedDeclaration(decl) => { if decl.export_kind.is_type() { return false; } + + if self.verbatim_module_syntax { + return true; + } + if decl.declaration.is_none() && decl.specifiers.is_empty() { return false; } + true } _ => true, @@ -92,4 +126,19 @@ impl<'a> TypeScript<'a> { program.body.push(self.ast.module_declaration(export_decl)); } } + + fn has_value_references(&self, name: &Atom) -> bool { + let root_scope_id = self.ctx.scopes().root_scope_id(); + + self.ctx + .scopes() + .get_binding(root_scope_id, name) + .map(|symbol_id| { + self.ctx + .symbols() + .get_resolved_references(symbol_id) + .any(|x| x.is_read() || x.is_write()) + }) + .unwrap_or_default() + } } diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index 2d66dddb9..1c0115594 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,4 +1,4 @@ -Passed: 173/1083 +Passed: 175/1083 # All Passed: * babel-plugin-transform-numeric-separator @@ -705,7 +705,7 @@ Passed: 173/1083 * unicode-regex/negated-set/input.js * unicode-regex/slash/input.js -# babel-plugin-transform-typescript (82/181) +# babel-plugin-transform-typescript (84/181) * class/abstract-class-decorated/input.ts * class/abstract-class-decorated-method/input.ts * class/abstract-class-decorated-parameter/input.ts @@ -752,9 +752,7 @@ Passed: 173/1083 * imports/elide-no-import-specifiers/input.ts * imports/elide-preact/input.ts * imports/elide-type-referenced-in-imports-equal-no/input.ts -* imports/elide-typeof/input.ts * imports/elision/input.ts -* imports/elision-export-type/input.ts * imports/elision-locations/input.ts * imports/elision-rename/input.ts * imports/enum-id/input.ts