swc_typescript/fast_dts/
decl.rs

1use swc_common::Spanned;
2use swc_ecma_ast::{
3    Decl, DefaultDecl, Expr, Lit, Pat, TsNamespaceBody, VarDeclKind, VarDeclarator,
4};
5use swc_ecma_visit::VisitMutWith;
6
7use super::{
8    type_ann,
9    util::{ast_ext::PatExt, types::any_type_ann},
10    visitors::internal_annotation::InternalAnnotationTransformer,
11    FastDts,
12};
13
14impl FastDts {
15    pub(crate) fn transform_decl(&mut self, decl: &mut Decl, check_binding: bool) {
16        let is_declare = self.is_top_level;
17        match decl {
18            Decl::Class(class_decl) => {
19                if class_decl.declare {
20                    return;
21                }
22
23                if check_binding && !self.used_refs.used(&class_decl.ident.to_id()) {
24                    return;
25                }
26
27                class_decl.declare = is_declare;
28                self.transform_class(&mut class_decl.class);
29            }
30            Decl::Fn(fn_decl) => {
31                if fn_decl.declare {
32                    return;
33                }
34
35                if check_binding && !self.used_refs.used_as_value(&fn_decl.ident.to_id()) {
36                    return;
37                }
38
39                fn_decl.declare = is_declare;
40                self.transform_fn(&mut fn_decl.function, Some(fn_decl.ident.span));
41            }
42            Decl::Var(var) => {
43                if var.declare {
44                    return;
45                }
46
47                var.declare = is_declare;
48                for decl in var.decls.iter_mut() {
49                    if check_binding
50                        && decl
51                            .name
52                            .as_ident()
53                            .is_some_and(|ident| !self.used_refs.used_as_value(&ident.to_id()))
54                    {
55                        return;
56                    }
57                    self.transform_variables_declarator(var.kind, decl, check_binding);
58                }
59            }
60            Decl::Using(using) => {
61                for decl in using.decls.iter_mut() {
62                    if check_binding
63                        && decl
64                            .name
65                            .as_ident()
66                            .is_some_and(|ident| !self.used_refs.used_as_value(&ident.to_id()))
67                    {
68                        return;
69                    }
70                    self.transform_variables_declarator(VarDeclKind::Const, decl, check_binding);
71                }
72            }
73            Decl::TsEnum(ts_enum) => {
74                ts_enum.declare = is_declare;
75                if check_binding && !self.used_refs.used(&ts_enum.id.to_id()) {
76                    return;
77                }
78                self.transform_enum(ts_enum.as_mut());
79            }
80            Decl::TsModule(ts_module) => {
81                if ts_module.declare {
82                    return;
83                }
84
85                if !ts_module.global
86                    && !ts_module.id.is_str()
87                    && check_binding
88                    && ts_module
89                        .id
90                        .as_ident()
91                        .is_some_and(|ident| !self.used_refs.used_as_type(&ident.to_id()))
92                {
93                    return;
94                }
95
96                ts_module.declare = is_declare;
97                if let Some(body) = ts_module.body.as_mut() {
98                    self.transform_ts_namespace_decl(
99                        body,
100                        ts_module.global || ts_module.id.is_str(),
101                    );
102                }
103            }
104            Decl::TsInterface(ts_interface) => {
105                if let Some(internal_annotations) = self.internal_annotations.as_ref() {
106                    ts_interface.visit_mut_children_with(&mut InternalAnnotationTransformer::new(
107                        internal_annotations,
108                    ))
109                }
110                for type_element in ts_interface.body.body.iter() {
111                    self.check_ts_signature(type_element);
112                }
113            }
114            Decl::TsTypeAlias(ts_type_alias) => {
115                if let Some(internal_annotations) = self.internal_annotations.as_ref() {
116                    ts_type_alias.visit_mut_children_with(&mut InternalAnnotationTransformer::new(
117                        internal_annotations,
118                    ))
119                }
120                if let Some(ts_lit) = ts_type_alias.type_ann.as_ts_type_lit() {
121                    for type_element in ts_lit.members.iter() {
122                        self.check_ts_signature(type_element);
123                    }
124                }
125            }
126            #[cfg(swc_ast_unknown)]
127            _ => panic!("unable to access unknown nodes"),
128        }
129    }
130
131    pub(crate) fn transform_variables_declarator(
132        &mut self,
133        kind: VarDeclKind,
134        decl: &mut VarDeclarator,
135        check_binding: bool,
136    ) {
137        let pat = match &decl.name {
138            Pat::Assign(assign_pat) => &assign_pat.left,
139            _ => &decl.name,
140        };
141
142        if matches!(pat, Pat::Array(_) | Pat::Object(_)) {
143            pat.bound_names(&mut |ident| {
144                if !check_binding || self.used_refs.used_as_value(&ident.to_id()) {
145                    self.binding_element_export(ident.span);
146                }
147            });
148            return;
149        }
150
151        let mut binding_type = None;
152        let mut init = None;
153
154        if pat.get_type_ann().is_none() {
155            if let Some(init_expr) = &decl.init {
156                if kind == VarDeclKind::Const
157                    && !Self::need_to_infer_type_from_expression(init_expr)
158                {
159                    if let Some(tpl) = init_expr.as_tpl() {
160                        init = self
161                            .tpl_to_string(tpl)
162                            .map(|s| Box::new(Expr::Lit(Lit::Str(s))));
163                    } else {
164                        init = Some(init_expr.clone());
165                    }
166                } else if kind != VarDeclKind::Const || !init_expr.is_tpl() {
167                    binding_type = self.infer_type_from_expr(init_expr).map(type_ann);
168                }
169            }
170
171            if init.is_none() && binding_type.is_none() {
172                binding_type = Some(any_type_ann());
173                if !decl
174                    .init
175                    .as_ref()
176                    .is_some_and(|init| init.is_fn_expr() || init.is_arrow())
177                {
178                    self.variable_must_have_explicit_type(decl.name.span());
179                }
180            }
181        }
182
183        decl.init = init;
184        if binding_type.is_some() {
185            decl.name.set_type_ann(binding_type);
186        }
187    }
188
189    pub(crate) fn transform_default_decl(&mut self, decl: &mut DefaultDecl) {
190        match decl {
191            DefaultDecl::Class(class_expr) => {
192                self.transform_class(&mut class_expr.class);
193            }
194            DefaultDecl::Fn(fn_expr) => {
195                self.transform_fn(
196                    &mut fn_expr.function,
197                    fn_expr.ident.as_ref().map(|ident| ident.span),
198                );
199            }
200            DefaultDecl::TsInterfaceDecl(_) => {}
201            #[cfg(swc_ast_unknown)]
202            _ => panic!("unable to access unknown nodes"),
203        };
204    }
205
206    pub(crate) fn transform_ts_namespace_decl(
207        &mut self,
208        body: &mut TsNamespaceBody,
209        in_global_or_lit_module: bool,
210    ) {
211        let original_is_top_level = self.is_top_level;
212        self.is_top_level = false;
213        match body {
214            TsNamespaceBody::TsModuleBlock(ts_module_block) => {
215                self.transform_module_body(&mut ts_module_block.body, in_global_or_lit_module);
216            }
217            TsNamespaceBody::TsNamespaceDecl(ts_ns) => {
218                self.transform_ts_namespace_decl(&mut ts_ns.body, ts_ns.global)
219            }
220            #[cfg(swc_ast_unknown)]
221            _ => panic!("unable to access unknown nodes"),
222        };
223        self.is_top_level = original_is_top_level;
224    }
225}