swc_ecma_transforms_typescript/
strip_type.rs1use std::mem;
2
3use swc_common::util::take::Take;
4use swc_ecma_ast::*;
5use swc_ecma_utils::stack_size::maybe_grow_default;
6use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
7
8use crate::type_to_none;
9
10pub fn strip_type() -> impl VisitMut {
11 StripType::default()
12}
13
14#[derive(Default)]
19pub(crate) struct StripType {
20 in_namespace: bool,
21}
22
23impl VisitMut for StripType {
24 noop_visit_mut_type!(fail);
25
26 type_to_none!(visit_mut_opt_ts_type, Box<TsType>);
27
28 type_to_none!(visit_mut_opt_ts_type_ann, Box<TsTypeAnn>);
29
30 type_to_none!(visit_mut_opt_ts_type_param_decl, Box<TsTypeParamDecl>);
31
32 type_to_none!(
33 visit_mut_opt_ts_type_param_instantiation,
34 Box<TsTypeParamInstantiation>
35 );
36
37 fn visit_mut_array_pat(&mut self, n: &mut ArrayPat) {
38 n.visit_mut_children_with(self);
39 n.optional = false;
40 }
41
42 fn visit_mut_auto_accessor(&mut self, n: &mut AutoAccessor) {
43 n.type_ann = None;
44 n.accessibility = None;
45 n.definite = false;
46 n.is_override = false;
47 n.is_abstract = false;
48 n.visit_mut_children_with(self);
49 }
50
51 fn visit_mut_class(&mut self, n: &mut Class) {
52 n.is_abstract = false;
53 n.implements.clear();
54 n.visit_mut_children_with(self);
55 }
56
57 fn visit_mut_class_members(&mut self, n: &mut Vec<ClassMember>) {
58 n.retain(|member| match member {
59 ClassMember::TsIndexSignature(..) => false,
60 ClassMember::Constructor(Constructor { body: None, .. }) => false,
61
62 ClassMember::Method(ClassMethod {
63 is_abstract,
64 function,
65 ..
66 })
67 | ClassMember::PrivateMethod(PrivateMethod {
68 is_abstract,
69 function,
70 ..
71 }) => !is_abstract && function.body.is_some(),
72
73 ClassMember::ClassProp(
74 ClassProp { declare: true, .. }
75 | ClassProp {
76 is_abstract: true, ..
77 },
78 )
79 | ClassMember::AutoAccessor(AutoAccessor {
80 is_abstract: true, ..
81 }) => false,
82
83 _ => true,
84 });
85
86 n.visit_mut_children_with(self);
87 }
88
89 fn visit_mut_class_method(&mut self, n: &mut ClassMethod) {
90 n.accessibility = None;
91 n.is_override = false;
92 n.is_abstract = false;
93 n.is_optional = false;
94 n.visit_mut_children_with(self);
95 }
96
97 fn visit_mut_class_prop(&mut self, prop: &mut ClassProp) {
98 prop.declare = false;
99 prop.readonly = false;
100 prop.is_override = false;
101 prop.is_optional = false;
102 prop.is_abstract = false;
103 prop.definite = false;
104 prop.accessibility = None;
105 prop.visit_mut_children_with(self);
106 }
107
108 fn visit_mut_private_method(&mut self, n: &mut PrivateMethod) {
109 n.accessibility = None;
110 n.is_abstract = false;
111 n.is_optional = false;
112 n.is_override = false;
113 n.visit_mut_children_with(self);
114 }
115
116 fn visit_mut_constructor(&mut self, n: &mut Constructor) {
117 n.accessibility = None;
118 n.visit_mut_children_with(self);
119 }
120
121 fn visit_mut_export_specifiers(&mut self, n: &mut Vec<ExportSpecifier>) {
122 n.retain(|s| match s {
123 ExportSpecifier::Named(ExportNamedSpecifier { is_type_only, .. }) => !is_type_only,
124 _ => true,
125 })
126 }
127
128 fn visit_mut_expr(&mut self, n: &mut Expr) {
129 while let Expr::TsAs(TsAsExpr { expr, .. })
132 | Expr::TsNonNull(TsNonNullExpr { expr, .. })
133 | Expr::TsTypeAssertion(TsTypeAssertion { expr, .. })
134 | Expr::TsConstAssertion(TsConstAssertion { expr, .. })
135 | Expr::TsInstantiation(TsInstantiation { expr, .. })
136 | Expr::TsSatisfies(TsSatisfiesExpr { expr, .. }) = n
137 {
138 *n = *expr.take();
139 }
140
141 maybe_grow_default(|| n.visit_mut_children_with(self));
142 }
143
144 fn visit_mut_ident(&mut self, n: &mut Ident) {
146 n.optional = false;
147 }
148
149 fn visit_mut_import_specifiers(&mut self, n: &mut Vec<ImportSpecifier>) {
150 n.retain(|s| !matches!(s, ImportSpecifier::Named(named) if named.is_type_only));
151 }
152
153 fn visit_mut_ts_module_block(&mut self, node: &mut TsModuleBlock) {
154 let in_namespace = mem::replace(&mut self.in_namespace, true);
155 node.visit_mut_children_with(self);
156 self.in_namespace = in_namespace;
157 }
158
159 fn visit_mut_module_items(&mut self, n: &mut Vec<ModuleItem>) {
160 n.retain(|item| should_retain_module_item(item, self.in_namespace));
161 n.visit_mut_children_with(self);
162 }
163
164 fn visit_mut_object_pat(&mut self, pat: &mut ObjectPat) {
165 pat.visit_mut_children_with(self);
166 pat.optional = false;
167 }
168
169 fn visit_mut_params(&mut self, n: &mut Vec<Param>) {
171 if n.first()
172 .filter(|param| {
173 matches!(
174 ¶m.pat,
175 Pat::Ident(BindingIdent {
176 id: Ident { sym, .. },
177 ..
178 }) if &**sym == "this"
179 )
180 })
181 .is_some()
182 {
183 n.drain(0..1);
184 }
185
186 n.visit_mut_children_with(self);
187 }
188
189 fn visit_mut_private_prop(&mut self, prop: &mut PrivateProp) {
190 prop.readonly = false;
191 prop.is_override = false;
192 prop.is_optional = false;
193 prop.definite = false;
194 prop.accessibility = None;
195 prop.visit_mut_children_with(self);
196 }
197
198 fn visit_mut_setter_prop(&mut self, n: &mut SetterProp) {
199 n.this_param = None;
200
201 n.visit_mut_children_with(self);
202 }
203
204 fn visit_mut_simple_assign_target(&mut self, n: &mut SimpleAssignTarget) {
205 while let SimpleAssignTarget::TsAs(TsAsExpr { expr, .. })
208 | SimpleAssignTarget::TsNonNull(TsNonNullExpr { expr, .. })
209 | SimpleAssignTarget::TsTypeAssertion(TsTypeAssertion { expr, .. })
210 | SimpleAssignTarget::TsInstantiation(TsInstantiation { expr, .. })
211 | SimpleAssignTarget::TsSatisfies(TsSatisfiesExpr { expr, .. }) = n
212 {
213 *n = expr.take().try_into().unwrap();
214 }
215
216 n.visit_mut_children_with(self);
217 }
218
219 fn visit_mut_stmts(&mut self, n: &mut Vec<Stmt>) {
220 n.visit_mut_children_with(self);
221 n.retain(|s| !matches!(s, Stmt::Empty(e) if e.span.is_dummy()));
222 }
223
224 fn visit_mut_stmt(&mut self, n: &mut Stmt) {
225 if should_retain_stmt(n) {
226 n.visit_mut_children_with(self);
227 } else if !n.is_empty() {
228 n.take();
229 }
230 }
231
232 fn visit_mut_ts_import_equals_decl(&mut self, _: &mut TsImportEqualsDecl) {
233 }
235
236 fn visit_mut_ts_param_prop(&mut self, n: &mut TsParamProp) {
237 n.decorators.visit_mut_with(self);
239 n.param.visit_mut_with(self);
240 }
241}
242
243fn should_retain_module_item(module_item: &ModuleItem, in_namespace: bool) -> bool {
244 match module_item {
245 ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
246 if in_namespace && export_decl.decl.is_var() {
250 return true;
251 }
252
253 should_retain_decl(&export_decl.decl)
254 }
255 ModuleItem::Stmt(stmt) => should_retain_stmt(stmt),
256 _ => module_item.is_concrete(),
257 }
258}
259
260fn should_retain_stmt(stmt: &Stmt) -> bool {
261 match stmt {
262 Stmt::Decl(decl) => should_retain_decl(decl),
263 _ => stmt.is_concrete(),
264 }
265}
266
267fn should_retain_decl(decl: &Decl) -> bool {
268 if decl.is_declare() {
269 return false;
270 }
271
272 decl.is_concrete()
273}
274
275pub(crate) trait IsConcrete {
276 fn is_concrete(&self) -> bool;
277}
278
279impl IsConcrete for TsModuleDecl {
280 fn is_concrete(&self) -> bool {
281 self.body
282 .as_ref()
283 .map(|body| body.is_concrete())
284 .unwrap_or_default()
285 }
286}
287
288impl IsConcrete for TsNamespaceBody {
289 fn is_concrete(&self) -> bool {
290 match self {
291 Self::TsModuleBlock(ts_module_block) => {
292 ts_module_block.body.iter().any(|item| item.is_concrete())
293 }
294 Self::TsNamespaceDecl(ts_namespace_decl) => ts_namespace_decl.body.is_concrete(),
295 }
296 }
297}
298
299impl IsConcrete for ModuleItem {
300 fn is_concrete(&self) -> bool {
301 match self {
302 Self::ModuleDecl(module_decl) => module_decl.is_concrete(),
303 Self::Stmt(stmt) => stmt.is_concrete(),
304 }
305 }
306}
307
308impl IsConcrete for ModuleDecl {
309 fn is_concrete(&self) -> bool {
310 match self {
311 Self::Import(import_decl) => !import_decl.type_only,
312 Self::ExportDecl(export_decl) => export_decl.decl.is_concrete(),
313 Self::ExportNamed(named_export) => !named_export.type_only,
314 Self::ExportDefaultDecl(export_default_decl) => export_default_decl.decl.is_concrete(),
315 Self::ExportDefaultExpr(..) => true,
316 Self::ExportAll(export_all) => !export_all.type_only,
317 Self::TsImportEquals(ts_import_equals) => !ts_import_equals.is_type_only,
318 Self::TsExportAssignment(..) => true,
319 Self::TsNamespaceExport(..) => false,
320 }
321 }
322}
323
324impl IsConcrete for Decl {
325 fn is_concrete(&self) -> bool {
326 match self {
327 Self::TsInterface(..) | Self::TsTypeAlias(..) => false,
328 Self::Fn(r#fn) => r#fn.function.body.is_some(),
329 Self::Class(..) | Self::Var(..) | Self::Using(..) | Self::TsEnum(..) => true,
330 Self::TsModule(ts_module) => ts_module.is_concrete(),
331 }
332 }
333}
334
335impl IsConcrete for DefaultDecl {
336 fn is_concrete(&self) -> bool {
337 match self {
338 Self::Class(_) => true,
339 Self::Fn(r#fn) => r#fn.function.body.is_some(),
340 Self::TsInterfaceDecl(..) => false,
341 }
342 }
343}
344
345impl IsConcrete for Stmt {
346 fn is_concrete(&self) -> bool {
347 match self {
348 Self::Empty(..) => false,
349 Self::Decl(decl) => decl.is_concrete(),
350 _ => true,
351 }
352 }
353}
354
355trait IsDeclare {
356 fn is_declare(&self) -> bool;
357}
358
359impl IsDeclare for Decl {
360 fn is_declare(&self) -> bool {
361 match self {
362 Decl::Class(class) => class.declare,
363 Decl::Fn(r#fn) => r#fn.declare,
364 Decl::Var(var) => var.declare,
365 Decl::Using(_) => false,
366 Decl::TsInterface(_) | Decl::TsTypeAlias(_) => true,
368 Decl::TsEnum(ts_enum) => ts_enum.declare,
369 Decl::TsModule(ts_module) => ts_module.declare || ts_module.global,
370 }
371 }
372}