From 732d748d4eb7c19d11e37b06f5064d4eca5bf4d8 Mon Sep 17 00:00:00 2001 From: magic-akari Date: Sat, 6 Jul 2024 05:44:08 +0800 Subject: [PATCH] feat(es/typescript): Improve fast TS stripper (#9153) --- crates/swc_fast_ts_strip/src/lib.rs | 74 +++++++++++++++---- .../tests/fixture/this-param.js | 5 +- .../tests/fixture/this-param.ts | 5 +- .../tests/fixture/type-import.js | 7 ++ .../tests/fixture/type-import.ts | 7 ++ 5 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 crates/swc_fast_ts_strip/tests/fixture/type-import.js create mode 100644 crates/swc_fast_ts_strip/tests/fixture/type-import.ts diff --git a/crates/swc_fast_ts_strip/src/lib.rs b/crates/swc_fast_ts_strip/src/lib.rs index 92f1f0224a41..46ddbc35f73d 100644 --- a/crates/swc_fast_ts_strip/src/lib.rs +++ b/crates/swc_fast_ts_strip/src/lib.rs @@ -7,9 +7,9 @@ use swc_common::{ BytePos, FileName, SourceMap, Span, Spanned, }; use swc_ecma_ast::{ - BindingIdent, Decorator, EsVersion, Ident, Param, Pat, Program, TsAsExpr, TsConstAssertion, - TsEnumDecl, TsInstantiation, TsModuleDecl, TsModuleName, TsNamespaceDecl, TsNonNullExpr, - TsParamPropParam, TsSatisfiesExpr, TsTypeAliasDecl, TsTypeAnn, + BindingIdent, Decorator, EsVersion, Ident, ImportDecl, ImportSpecifier, Param, Pat, Program, + TsAsExpr, TsConstAssertion, TsEnumDecl, TsInstantiation, TsModuleDecl, TsModuleName, + TsNamespaceDecl, TsNonNullExpr, TsParamPropParam, TsSatisfiesExpr, TsTypeAliasDecl, TsTypeAnn, }; use swc_ecma_parser::{ parse_file_as_module, parse_file_as_program, parse_file_as_script, Syntax, TsSyntax, @@ -83,7 +83,7 @@ pub fn operate( } // Strip typescript types - let mut ts_strip = TsStrip::default(); + let mut ts_strip = TsStrip::new(fm.src.clone()); program.visit_with(&mut ts_strip); let replacements = ts_strip.replacements; @@ -92,22 +92,29 @@ pub fn operate( return Ok(fm.src.to_string()); } - let mut code = ::clone(&fm.src).into_bytes(); + let mut code = fm.src.to_string().into_bytes(); for r in replacements { - code[(r.0 .0 - 1) as usize..(r.1 .0 - 1) as usize] - .iter_mut() - .for_each(|b| *b = b' '); + code[(r.0 .0 - 1) as usize..(r.1 .0 - 1) as usize].fill(b' '); } String::from_utf8(code).map_err(|_| anyhow::anyhow!("failed to convert to utf-8")) } -#[derive(Default)] struct TsStrip { + src: Lrc, replacements: Vec<(BytePos, BytePos)>, } +impl TsStrip { + fn new(src: Lrc) -> Self { + TsStrip { + src, + replacements: Default::default(), + } + } +} + impl TsStrip { fn add_replacement(&mut self, span: Span) { self.replacements.push((span.lo, span.hi)); @@ -228,18 +235,59 @@ impl Visit for TsStrip { }) if &**sym == "this" ) }) { - let lo = p.span.lo; - let hi = n.get(1).map(|x| x.span.lo).unwrap_or(p.span.hi); - self.add_replacement(span(lo, hi)); + let mut span = p.span; + + if n.len() == 1 { + let bytes = self.src.as_bytes(); + span.hi.0 = skip_until(bytes, span.hi.0, b')'); + } else { + span.hi = n[1].span.lo; + n[1..].visit_children_with(self); + } + + self.add_replacement(span); + + return; + } + + n.visit_children_with(self); + } - n[1..].visit_children_with(self); + fn visit_import_decl(&mut self, n: &ImportDecl) { + if n.type_only { + self.add_replacement(n.span); return; } n.visit_children_with(self); } + + fn visit_import_specifiers(&mut self, n: &[ImportSpecifier]) { + for (i, import) in n.iter().enumerate() { + let ImportSpecifier::Named(import) = import else { + continue; + }; + + if import.is_type_only { + let mut span = import.span; + span.hi.0 = n.get(i + 1).map(|x| x.span_lo().0).unwrap_or_else(|| { + let bytes = self.src.as_bytes(); + skip_until(bytes, span.hi.0, b'}') + }); + self.add_replacement(span); + } + } + } } fn span(lo: BytePos, hi: BytePos) -> Span { Span::new(lo, hi, Default::default()) } + +fn skip_until(bytes: &[u8], mut pos: u32, stop: u8) -> u32 { + while bytes[(pos - 1) as usize] != stop { + pos += 1; + } + + pos +} diff --git a/crates/swc_fast_ts_strip/tests/fixture/this-param.js b/crates/swc_fast_ts_strip/tests/fixture/this-param.js index fc1c9fa0db1e..8a7ee0c00ae2 100644 --- a/crates/swc_fast_ts_strip/tests/fixture/this-param.js +++ b/crates/swc_fast_ts_strip/tests/fixture/this-param.js @@ -1,2 +1,5 @@ export function foo( ) {} -export function bar( x ) {} \ No newline at end of file +export function bar( x ) {} + +export function foo2( ) {} +export function bar2( x ,) {} diff --git a/crates/swc_fast_ts_strip/tests/fixture/this-param.ts b/crates/swc_fast_ts_strip/tests/fixture/this-param.ts index 8d8653d61c5b..0a126b3644d0 100644 --- a/crates/swc_fast_ts_strip/tests/fixture/this-param.ts +++ b/crates/swc_fast_ts_strip/tests/fixture/this-param.ts @@ -1,2 +1,5 @@ export function foo(this: number): void {} -export function bar(this: number, x: string): void {} \ No newline at end of file +export function bar(this: number, x: string): void {} + +export function foo2(this: number,): void {} +export function bar2(this: number, x: string,): void {} diff --git a/crates/swc_fast_ts_strip/tests/fixture/type-import.js b/crates/swc_fast_ts_strip/tests/fixture/type-import.js new file mode 100644 index 000000000000..02b89bf417c6 --- /dev/null +++ b/crates/swc_fast_ts_strip/tests/fixture/type-import.js @@ -0,0 +1,7 @@ + + +import { x4, } from "m3"; +import { x7, } from "m4"; +import { x9, } from "m5"; +import { } from "m6"; +import { x17 } from "m7"; diff --git a/crates/swc_fast_ts_strip/tests/fixture/type-import.ts b/crates/swc_fast_ts_strip/tests/fixture/type-import.ts new file mode 100644 index 000000000000..baae569fb66c --- /dev/null +++ b/crates/swc_fast_ts_strip/tests/fixture/type-import.ts @@ -0,0 +1,7 @@ +import type x1 from "m1"; +import type { x2, x3 } from "m2"; +import { x4, type x5, } from "m3"; +import { type x6, x7, } from "m4"; +import { type x8, x9, type x10 } from "m5"; +import { type x11, type x12, type x13, } from "m6"; +import { type x14, type x15, type x16, x17 } from "m7";