mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
feat(transformer/typescript): support only_remove_type_imports option (#2077)
This commit is contained in:
parent
f5bf5dece1
commit
7711f7abaf
6 changed files with 58 additions and 20 deletions
|
|
@ -44,6 +44,7 @@ pub use crate::{
|
|||
es2020::NullishCoalescingOperatorOptions,
|
||||
options::{TransformOptions, TransformTarget},
|
||||
react_jsx::{ReactJsxOptions, ReactJsxRuntime, ReactJsxRuntimeOption},
|
||||
typescript::TypescriptOptions,
|
||||
};
|
||||
|
||||
pub struct Transformer<'a> {
|
||||
|
|
@ -90,7 +91,7 @@ impl<'a> Transformer<'a> {
|
|||
Self {
|
||||
ctx: ctx.clone(),
|
||||
// TODO: pass verbatim_module_syntax from user config
|
||||
typescript: source_type.is_typescript().then(|| TypeScript::new(Rc::clone(&ast), ctx.clone(), false)),
|
||||
typescript: source_type.is_typescript().then(|| TypeScript::new(Rc::clone(&ast), ctx.clone(), false, &options)),
|
||||
regexp_flags: RegexpFlags::new(Rc::clone(&ast), &options),
|
||||
// es2022
|
||||
es2022_class_static_block: es2022::ClassStaticBlock::new(Rc::clone(&ast), &options),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use oxc_syntax::assumptions::CompilerAssumptions;
|
|||
|
||||
use crate::{
|
||||
es2015::ArrowFunctionsOptions, es2020::NullishCoalescingOperatorOptions,
|
||||
react_jsx::ReactJsxOptions,
|
||||
react_jsx::ReactJsxOptions, typescript::TypescriptOptions,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
|
|
@ -12,6 +12,8 @@ pub struct TransformOptions {
|
|||
|
||||
pub react_jsx: Option<ReactJsxOptions>,
|
||||
|
||||
pub typescript: Option<TypescriptOptions>,
|
||||
|
||||
// es2022
|
||||
pub class_static_block: bool,
|
||||
// es2021
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ use oxc_syntax::{
|
|||
use rustc_hash::FxHashSet;
|
||||
use std::{mem, rc::Rc};
|
||||
|
||||
use crate::{context::TransformerCtx, utils::is_valid_identifier};
|
||||
mod options;
|
||||
|
||||
pub use self::options::TypescriptOptions;
|
||||
use crate::{context::TransformerCtx, utils::is_valid_identifier, TransformOptions};
|
||||
|
||||
/// Transform TypeScript
|
||||
///
|
||||
|
|
@ -22,6 +25,7 @@ pub struct TypeScript<'a> {
|
|||
ctx: TransformerCtx<'a>,
|
||||
verbatim_module_syntax: bool,
|
||||
export_name_set: FxHashSet<Atom>,
|
||||
options: TypescriptOptions,
|
||||
}
|
||||
|
||||
impl<'a> TypeScript<'a> {
|
||||
|
|
@ -29,8 +33,15 @@ impl<'a> TypeScript<'a> {
|
|||
ast: Rc<AstBuilder<'a>>,
|
||||
ctx: TransformerCtx<'a>,
|
||||
verbatim_module_syntax: bool,
|
||||
options: &TransformOptions,
|
||||
) -> Self {
|
||||
Self { ast, ctx, verbatim_module_syntax, export_name_set: FxHashSet::default() }
|
||||
Self {
|
||||
ast,
|
||||
ctx,
|
||||
verbatim_module_syntax,
|
||||
export_name_set: FxHashSet::default(),
|
||||
options: options.typescript.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_declaration(&mut self, decl: &mut Declaration<'a>) {
|
||||
|
|
@ -142,11 +153,11 @@ impl<'a> TypeScript<'a> {
|
|||
|
||||
let mut import_type_names = FxHashSet::default();
|
||||
let mut delete_indexes = vec![];
|
||||
let mut import_len = 0;
|
||||
let mut module_declaration_len = 0;
|
||||
|
||||
for (index, stmt) in program.body.iter_mut().enumerate() {
|
||||
if let Statement::ModuleDeclaration(module_decl) = stmt {
|
||||
import_len += 1;
|
||||
module_declaration_len += 1;
|
||||
match &mut **module_decl {
|
||||
ModuleDeclaration::ExportNamedDeclaration(decl) => {
|
||||
decl.specifiers.retain(|specifier| {
|
||||
|
|
@ -173,6 +184,7 @@ impl<'a> TypeScript<'a> {
|
|||
}
|
||||
ModuleDeclaration::ImportDeclaration(decl) => {
|
||||
let is_type = decl.import_kind.is_type();
|
||||
|
||||
let is_specifiers_empty =
|
||||
decl.specifiers.as_ref().is_some_and(|s| s.is_empty());
|
||||
|
||||
|
|
@ -184,12 +196,14 @@ impl<'a> TypeScript<'a> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if export_type_names.contains(&s.local.name) {
|
||||
return false;
|
||||
if self.verbatim_module_syntax
|
||||
|| self.options.only_remove_type_imports
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.verbatim_module_syntax {
|
||||
return true;
|
||||
if export_type_names.contains(&s.local.name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.has_value_references(&s.local.name)
|
||||
|
|
@ -200,6 +214,11 @@ impl<'a> TypeScript<'a> {
|
|||
{
|
||||
if is_type {
|
||||
import_type_names.insert(s.local.name.clone());
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.options.only_remove_type_imports {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.has_value_references(&s.local.name)
|
||||
|
|
@ -212,15 +231,23 @@ impl<'a> TypeScript<'a> {
|
|||
import_type_names.insert(s.local.name.clone());
|
||||
}
|
||||
|
||||
if self.options.only_remove_type_imports {
|
||||
return true;
|
||||
}
|
||||
|
||||
if export_names.contains(&s.local.name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.has_value_references(&s.local.name)
|
||||
|| export_names.contains(&s.local.name)
|
||||
}
|
||||
_ => true,
|
||||
});
|
||||
}
|
||||
|
||||
if decl.import_kind.is_type()
|
||||
|| (!is_specifiers_empty
|
||||
|| (!self.options.only_remove_type_imports
|
||||
&& !is_specifiers_empty
|
||||
&& decl
|
||||
.specifiers
|
||||
.as_ref()
|
||||
|
|
@ -242,7 +269,7 @@ impl<'a> TypeScript<'a> {
|
|||
}
|
||||
|
||||
// explicit esm
|
||||
if import_len > 0 && import_len == delete_indexes_len {
|
||||
if module_declaration_len > 0 && module_declaration_len == delete_indexes_len {
|
||||
let empty_export = self.ast.export_named_declaration(
|
||||
SPAN,
|
||||
None,
|
||||
|
|
|
|||
9
crates/oxc_transformer/src/typescript/options.rs
Normal file
9
crates/oxc_transformer/src/typescript/options.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TypescriptOptions {
|
||||
/// When set to true, the transform will only remove [type-only](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-exports) imports (introduced in TypeScript 3.8). This should only be used if you are using TypeScript >= 3.8.
|
||||
/// defaults to false
|
||||
pub only_remove_type_imports: bool,
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
Passed: 318/1179
|
||||
Passed: 322/1179
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-numeric-separator
|
||||
|
|
@ -832,7 +832,7 @@ Passed: 318/1179
|
|||
* general/function-duplicate-name/input.js
|
||||
* general/object/input.js
|
||||
|
||||
# babel-plugin-transform-typescript (87/158)
|
||||
# babel-plugin-transform-typescript (91/158)
|
||||
* class/abstract-class-decorated/input.ts
|
||||
* class/abstract-class-decorated-method/input.ts
|
||||
* class/abstract-class-decorated-parameter/input.ts
|
||||
|
|
@ -858,14 +858,10 @@ Passed: 318/1179
|
|||
* imports/elide-injected/input.ts
|
||||
* imports/enum-id/input.ts
|
||||
* imports/enum-value/input.ts
|
||||
* imports/import-named-type/input.ts
|
||||
* imports/import-named-type-default-and-named/input.ts
|
||||
* imports/import=-module/input.ts
|
||||
* imports/import=-module-to-cjs/input.ts
|
||||
* imports/only-remove-type-imports/input.ts
|
||||
* imports/parameter-decorators/input.ts
|
||||
* imports/type-only-export-specifier-2/input.ts
|
||||
* imports/type-only-import-specifier-4/input.ts
|
||||
* namespace/ambient-module-nested/input.ts
|
||||
* namespace/ambient-module-nested-exported/input.ts
|
||||
* namespace/canonical/input.ts
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use oxc_span::{SourceType, VALID_EXTENSIONS};
|
|||
use oxc_tasks_common::{normalize_path, print_diff_in_terminal, BabelOptions};
|
||||
use oxc_transformer::{
|
||||
ArrowFunctionsOptions, NullishCoalescingOperatorOptions, ReactJsxOptions, TransformOptions,
|
||||
TransformTarget, Transformer,
|
||||
TransformTarget, Transformer, TypescriptOptions,
|
||||
};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_json::Value;
|
||||
|
|
@ -92,6 +92,9 @@ pub trait TestCase {
|
|||
react_jsx: options
|
||||
.get_plugin("transform-react-jsx")
|
||||
.map(get_options::<ReactJsxOptions>),
|
||||
typescript: options
|
||||
.get_plugin("transform-typescript")
|
||||
.map(get_options::<TypescriptOptions>),
|
||||
assumptions: options.assumptions,
|
||||
class_static_block: options.get_plugin("transform-class-static-block").is_some(),
|
||||
instanceof: options.get_plugin("transform-instanceof").is_some(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue