swc_typescript/fast_dts/
function.rs1use std::mem;
2
3use swc_atoms::Atom;
4use swc_common::{Span, Spanned, DUMMY_SP};
5use swc_ecma_ast::{
6 AssignPat, Decl, ExportDecl, Function, ModuleDecl, ModuleItem, Param, Pat, Script, Stmt,
7 TsKeywordTypeKind, TsParenthesizedType, TsType, TsTypeAnn, TsUnionOrIntersectionType,
8 TsUnionType,
9};
10
11use super::{
12 type_ann,
13 util::types::{any_type_ann, ts_keyword_type},
14 FastDts,
15};
16
17impl FastDts {
18 pub(crate) fn transform_fn(&mut self, func: &mut Function, ident_span: Option<Span>) {
19 self.transform_fn_return_type(func);
20 if func.return_type.is_none() {
21 self.function_must_have_explicit_return_type(
22 ident_span.unwrap_or_else(|| Span::new(func.span_lo(), func.body.span_lo())),
23 );
24 }
25 self.transform_fn_params(&mut func.params);
26 func.is_async = false;
27 func.is_generator = false;
28 func.body = None
29 }
30
31 pub(crate) fn transform_fn_return_type(&mut self, func: &mut Function) {
32 if func.return_type.is_none() && !func.is_async && !func.is_generator {
33 func.return_type = self.infer_function_return_type(func);
34 }
35 }
36
37 pub(crate) fn transform_fn_params(&mut self, params: &mut [Param]) {
38 let mut is_required = false;
40 for param in params.iter_mut().rev() {
41 is_required |= match ¶m.pat {
42 Pat::Ident(binding_ident) => !binding_ident.optional,
43 Pat::Array(array_pat) => !array_pat.optional,
44 Pat::Object(object_pat) => !object_pat.optional,
45 Pat::Assign(_) | Pat::Invalid(_) | Pat::Expr(_) | Pat::Rest(_) => false,
46 #[cfg(swc_ast_unknown)]
47 _ => panic!("unable to access unknown nodes"),
48 };
49 self.transform_fn_param(param, is_required);
50 }
51 }
52
53 pub(crate) fn transform_fn_param(&mut self, param: &mut Param, is_required: bool) {
54 if let Pat::Assign(assign_pat) = &mut param.pat {
56 if self.check_assign_pat_param(assign_pat) {
57 self.parameter_must_have_explicit_type(param.span);
58 return;
59 }
60 }
61
62 let (should_add_undefined, type_ann) = match &mut param.pat {
64 Pat::Ident(ident) => {
65 if ident.type_ann.is_none() {
66 self.parameter_must_have_explicit_type(param.span);
67 }
68 (ident.type_ann.is_none(), ident.type_ann.as_mut())
69 }
70 Pat::Array(arr_pat) => {
71 if arr_pat.type_ann.is_none() {
72 self.parameter_must_have_explicit_type(param.span);
73 }
74 (arr_pat.type_ann.is_none(), arr_pat.type_ann.as_mut())
75 }
76 Pat::Object(obj_pat) => {
77 if obj_pat.type_ann.is_none() {
78 self.parameter_must_have_explicit_type(param.span);
79 }
80 (obj_pat.type_ann.is_none(), obj_pat.type_ann.as_mut())
81 }
82 Pat::Assign(assign_pat) => {
83 if !self.transform_assign_pat(assign_pat, is_required) {
84 self.parameter_must_have_explicit_type(param.span);
85 }
86
87 (
88 true,
89 match assign_pat.left.as_mut() {
90 Pat::Ident(ident) => ident.type_ann.as_mut(),
91 Pat::Array(array_pat) => array_pat.type_ann.as_mut(),
92 Pat::Object(object_pat) => object_pat.type_ann.as_mut(),
93 Pat::Assign(_) | Pat::Rest(_) | Pat::Invalid(_) | Pat::Expr(_) => return,
94 #[cfg(swc_ast_unknown)]
95 _ => panic!("unable to access unknown nodes"),
96 },
97 )
98 }
99 Pat::Rest(_) | Pat::Expr(_) | Pat::Invalid(_) => (false, None),
100 #[cfg(swc_ast_unknown)]
101 _ => panic!("unable to access unknown nodes"),
102 };
103
104 if let Some(type_ann) = type_ann {
106 if is_required && should_add_undefined && self.add_undefined_type_for_param(type_ann) {
107 self.implicitly_adding_undefined_to_type(param.span);
108 }
109 }
110
111 let pat = mem::take(&mut param.pat);
113 param.pat = match pat {
114 Pat::Assign(assign_pat) => *assign_pat.left,
115 _ => pat,
116 };
117 }
118
119 pub(crate) fn transform_assign_pat(
120 &mut self,
121 assign_pat: &mut AssignPat,
122 is_required: bool,
123 ) -> bool {
124 let left_type_ann = match assign_pat.left.as_mut() {
126 Pat::Ident(ident) => {
127 ident.optional |= !is_required;
128 &mut ident.type_ann
129 }
130 Pat::Array(array_pat) => {
131 array_pat.optional |= !is_required;
132 &mut array_pat.type_ann
133 }
134 Pat::Object(object_pat) => {
135 object_pat.optional |= !is_required;
136 &mut object_pat.type_ann
137 }
138 Pat::Assign(_) | Pat::Rest(_) | Pat::Invalid(_) | Pat::Expr(_) => return true,
140 #[cfg(swc_ast_unknown)]
141 _ => panic!("unable to access unknown nodes"),
142 };
143
144 let mut has_expclicit_type = true;
145 if left_type_ann.is_none() {
146 *left_type_ann = self
147 .infer_type_from_expr(&assign_pat.right)
148 .map(type_ann)
149 .or_else(|| {
150 has_expclicit_type = false;
151 Some(any_type_ann())
152 });
153 }
154 has_expclicit_type
155 }
156
157 pub(crate) fn check_assign_pat_param(&mut self, assign_pat: &AssignPat) -> bool {
158 assign_pat
159 .left
160 .as_array()
161 .map(|array_pat| array_pat.type_ann.is_none())
162 .unwrap_or(false)
163 || assign_pat
164 .left
165 .as_object()
166 .map(|object_pat| object_pat.type_ann.is_none())
167 .unwrap_or(false)
168 }
169
170 pub(crate) fn add_undefined_type_for_param(&mut self, type_ann: &mut TsTypeAnn) -> bool {
171 if type_ann.type_ann.is_ts_type_ref() {
172 return true;
173 }
174
175 if !is_maybe_undefined(&type_ann.type_ann) {
176 let mut ty = type_ann.type_ann.clone();
177 if ty.is_ts_fn_or_constructor_type() {
178 ty = Box::new(
179 TsParenthesizedType {
180 span: DUMMY_SP,
181 type_ann: Box::new(*ty),
182 }
183 .into(),
184 );
185 }
186 type_ann.type_ann = Box::new(TsType::TsUnionOrIntersectionType(
187 TsUnionOrIntersectionType::TsUnionType(TsUnionType {
188 span: DUMMY_SP,
189 types: vec![ty, ts_keyword_type(TsKeywordTypeKind::TsUndefinedKeyword)],
190 }),
191 ))
192 }
193
194 false
195 }
196
197 pub(crate) fn remove_function_overloads_in_module(items: &mut Vec<ModuleItem>) {
198 let mut last_function_name: Option<Atom> = None;
199 let mut is_export_default_function_overloads = false;
200
201 items.retain(|item| match item {
202 ModuleItem::Stmt(Stmt::Decl(Decl::Fn(fn_decl)))
203 | ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
204 decl: Decl::Fn(fn_decl),
205 ..
206 })) => {
207 if fn_decl.function.body.is_some() {
208 if last_function_name
209 .as_ref()
210 .is_some_and(|last_name| last_name == &fn_decl.ident.sym)
211 {
212 return false;
213 }
214 } else {
215 last_function_name = Some(fn_decl.ident.sym.clone());
216 }
217 true
218 }
219 ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(export)) => {
220 if let Some(fn_expr) = export.decl.as_fn_expr() {
221 if is_export_default_function_overloads && fn_expr.function.body.is_some() {
222 is_export_default_function_overloads = false;
223 false
224 } else {
225 is_export_default_function_overloads = true;
226 true
227 }
228 } else {
229 is_export_default_function_overloads = false;
230 true
231 }
232 }
233 _ => true,
234 });
235 }
236
237 pub(crate) fn remove_function_overloads_in_script(script: &mut Script) {
238 let mut last_function_name: Option<Atom> = None;
239 script.body.retain(|stmt| {
240 if let Some(fn_decl) = stmt.as_decl().and_then(|decl| decl.as_fn_decl()) {
241 if fn_decl.function.body.is_some() {
242 if last_function_name
243 .as_ref()
244 .is_some_and(|last_name| last_name == &fn_decl.ident.sym)
245 {
246 return false;
247 }
248 } else {
249 last_function_name = Some(fn_decl.ident.sym.clone());
250 }
251 }
252 true
253 });
254 }
255}
256
257fn is_maybe_undefined(ts_type: &TsType) -> bool {
258 match ts_type {
259 TsType::TsKeywordType(keyword_type) => matches!(
260 keyword_type.kind,
261 TsKeywordTypeKind::TsAnyKeyword
262 | TsKeywordTypeKind::TsUndefinedKeyword
263 | TsKeywordTypeKind::TsUnknownKeyword
264 ),
265 TsType::TsUnionOrIntersectionType(TsUnionOrIntersectionType::TsUnionType(union_type)) => {
266 union_type.types.iter().any(|ty| is_maybe_undefined(ty))
267 }
268 _ => false,
269 }
270}