swc_typescript/fast_dts/
decl.rs1use 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}