@@ -3,12 +3,13 @@ use std::{mem::take, sync::Arc};
3
3
use swc_atoms:: Atom ;
4
4
use swc_common:: { util:: take:: Take , FileName , Span , Spanned , DUMMY_SP } ;
5
5
use swc_ecma_ast:: {
6
- BindingIdent , ClassMember , Decl , DefaultDecl , ExportDecl , ExportDefaultDecl , ExportDefaultExpr ,
7
- Expr , FnDecl , FnExpr , Ident , Lit , MethodKind , Module , ModuleDecl , ModuleItem , OptChainBase ,
8
- Pat , Prop , PropName , PropOrSpread , Stmt , TsEntityName , TsFnOrConstructorType , TsFnParam ,
9
- TsFnType , TsKeywordType , TsKeywordTypeKind , TsLit , TsLitType , TsNamespaceBody ,
10
- TsPropertySignature , TsTupleElement , TsTupleType , TsType , TsTypeAnn , TsTypeElement , TsTypeLit ,
11
- TsTypeOperator , TsTypeOperatorOp , TsTypeRef , VarDecl , VarDeclKind , VarDeclarator ,
6
+ AssignPat , BindingIdent , ClassMember , ComputedPropName , Decl , DefaultDecl , ExportDecl ,
7
+ ExportDefaultExpr , Expr , Ident , Lit , MethodKind , ModuleDecl , ModuleItem , OptChainBase , Param ,
8
+ ParamOrTsParamProp , Pat , Program , Prop , PropName , PropOrSpread , Stmt , TsEntityName ,
9
+ TsFnOrConstructorType , TsFnParam , TsFnType , TsKeywordType , TsKeywordTypeKind , TsLit , TsLitType ,
10
+ TsNamespaceBody , TsParamPropParam , TsPropertySignature , TsTupleElement , TsTupleType , TsType ,
11
+ TsTypeAnn , TsTypeElement , TsTypeLit , TsTypeOperator , TsTypeOperatorOp , TsTypeRef , VarDecl ,
12
+ VarDeclKind , VarDeclarator ,
12
13
} ;
13
14
14
15
use crate :: diagnostic:: { DtsIssue , SourceRange } ;
@@ -71,10 +72,32 @@ impl FastDts {
71
72
}
72
73
73
74
impl FastDts {
74
- pub fn transform ( & mut self , module : & mut Module ) -> Vec < DtsIssue > {
75
+ pub fn transform ( & mut self , program : & mut Program ) -> Vec < DtsIssue > {
75
76
self . is_top_level = true ;
76
77
77
- self . transform_module_items ( & mut module. body ) ;
78
+ match program {
79
+ Program :: Module ( module) => {
80
+ self . transform_module_items ( & mut module. body ) ;
81
+ }
82
+ Program :: Script ( script) => {
83
+ let mut last_function_name: Option < Atom > = None ;
84
+ script. body . retain_mut ( |stmt| {
85
+ if let Some ( fn_decl) = stmt. as_decl ( ) . and_then ( |decl| decl. as_fn_decl ( ) ) {
86
+ if fn_decl. function . body . is_some ( ) {
87
+ if last_function_name
88
+ . as_ref ( )
89
+ . is_some_and ( |last_name| last_name == & fn_decl. ident . sym )
90
+ {
91
+ return false ;
92
+ }
93
+ } else {
94
+ last_function_name = Some ( fn_decl. ident . sym . clone ( ) ) ;
95
+ }
96
+ }
97
+ self . transform_module_stmt ( stmt)
98
+ } )
99
+ }
100
+ }
78
101
79
102
take ( & mut self . diagnostics )
80
103
}
@@ -83,28 +106,10 @@ impl FastDts {
83
106
let orig_items = take ( items) ;
84
107
let mut new_items = Vec :: with_capacity ( orig_items. len ( ) ) ;
85
108
86
- let mut prev_is_overload = false ;
109
+ let mut last_function_name: Option < Atom > = None ;
110
+ let mut is_export_default_function_overloads = false ;
87
111
88
112
for mut item in orig_items {
89
- let is_overload = match & item {
90
- ModuleItem :: ModuleDecl ( ModuleDecl :: ExportDecl ( ExportDecl { decl, .. } ) )
91
- | ModuleItem :: Stmt ( Stmt :: Decl ( decl) ) => match decl {
92
- Decl :: Fn ( FnDecl {
93
- function, declare, ..
94
- } ) => !declare && function. body . is_none ( ) ,
95
- _ => false ,
96
- } ,
97
-
98
- ModuleItem :: ModuleDecl ( ModuleDecl :: ExportDefaultDecl ( ExportDefaultDecl {
99
- decl,
100
- ..
101
- } ) ) => {
102
- matches ! ( decl, DefaultDecl :: Fn ( FnExpr { function, .. } ) if function. body. is_none( ) )
103
- }
104
-
105
- _ => false ,
106
- } ;
107
-
108
113
match & mut item {
109
114
// Keep all these
110
115
ModuleItem :: ModuleDecl (
@@ -116,14 +121,39 @@ impl FastDts {
116
121
| ModuleDecl :: ExportAll ( _) ,
117
122
) => new_items. push ( item) ,
118
123
124
+ ModuleItem :: Stmt ( stmt) => {
125
+ if let Some ( fn_decl) = stmt. as_decl ( ) . and_then ( |decl| decl. as_fn_decl ( ) ) {
126
+ if fn_decl. function . body . is_some ( ) {
127
+ if last_function_name
128
+ . as_ref ( )
129
+ . is_some_and ( |last_name| last_name == & fn_decl. ident . sym )
130
+ {
131
+ continue ;
132
+ }
133
+ } else {
134
+ last_function_name = Some ( fn_decl. ident . sym . clone ( ) ) ;
135
+ }
136
+ }
137
+
138
+ if self . transform_module_stmt ( stmt) {
139
+ new_items. push ( item) ;
140
+ }
141
+ }
142
+
119
143
ModuleItem :: ModuleDecl ( ModuleDecl :: ExportDecl ( ExportDecl {
120
144
span, decl, ..
121
145
} ) ) => {
122
- let should_keep = prev_is_overload && !is_overload;
123
-
124
- if should_keep {
125
- prev_is_overload = is_overload;
126
- continue ;
146
+ if let Some ( fn_decl) = decl. as_fn_decl ( ) {
147
+ if fn_decl. function . body . is_some ( ) {
148
+ if last_function_name
149
+ . as_ref ( )
150
+ . is_some_and ( |last_name| last_name == & fn_decl. ident . sym )
151
+ {
152
+ continue ;
153
+ }
154
+ } else {
155
+ last_function_name = Some ( fn_decl. ident . sym . clone ( ) ) ;
156
+ }
127
157
}
128
158
129
159
if let Some ( ( ) ) = self . decl_to_type_decl ( decl) {
@@ -142,6 +172,17 @@ impl FastDts {
142
172
}
143
173
144
174
ModuleItem :: ModuleDecl ( ModuleDecl :: ExportDefaultDecl ( export) ) => {
175
+ if let Some ( fn_expr) = export. decl . as_fn_expr ( ) {
176
+ if is_export_default_function_overloads && fn_expr. function . body . is_some ( ) {
177
+ is_export_default_function_overloads = false ;
178
+ continue ;
179
+ } else {
180
+ is_export_default_function_overloads = true ;
181
+ }
182
+ } else {
183
+ is_export_default_function_overloads = false ;
184
+ }
185
+
145
186
match & mut export. decl {
146
187
DefaultDecl :: Class ( class_expr) => {
147
188
self . class_body_to_type ( & mut class_expr. class . body ) ;
@@ -152,22 +193,10 @@ impl FastDts {
152
193
DefaultDecl :: TsInterfaceDecl ( _) => { }
153
194
} ;
154
195
155
- let should_keep = prev_is_overload && !is_overload;
156
- prev_is_overload = is_overload;
157
- if should_keep {
158
- continue ;
159
- }
160
-
161
196
new_items. push ( item) ;
162
197
}
163
198
164
199
ModuleItem :: ModuleDecl ( ModuleDecl :: ExportDefaultExpr ( export) ) => {
165
- let should_keep = prev_is_overload && !is_overload;
166
- prev_is_overload = is_overload;
167
- if should_keep {
168
- continue ;
169
- }
170
-
171
200
let name = self . gen_unique_name ( ) ;
172
201
let name_ident = Ident :: new_no_ctxt ( name, DUMMY_SP ) ;
173
202
let type_ann = self
@@ -212,32 +241,29 @@ impl FastDts {
212
241
)
213
242
}
214
243
}
244
+ }
245
+ }
215
246
216
- ModuleItem :: Stmt ( Stmt :: Decl ( decl) ) => match decl {
217
- Decl :: TsEnum ( _)
218
- | Decl :: Class ( _)
219
- | Decl :: Fn ( _)
220
- | Decl :: Var ( _)
221
- | Decl :: TsModule ( _) => {
222
- if let Some ( ( ) ) = self . decl_to_type_decl ( decl) {
223
- new_items. push ( item) ;
224
- } else {
225
- self . mark_diagnostic_unable_to_infer ( decl. span ( ) )
226
- }
227
- }
247
+ * items = new_items;
248
+ }
228
249
229
- Decl :: TsInterface ( _ ) | Decl :: TsTypeAlias ( _ ) | Decl :: Using ( _ ) => {
230
- new_items . push ( item ) ;
231
- }
232
- } ,
250
+ fn transform_module_stmt ( & mut self , stmt : & mut Stmt ) -> bool {
251
+ let Stmt :: Decl ( ref mut decl ) = stmt else {
252
+ return false ;
253
+ } ;
233
254
234
- ModuleItem :: Stmt ( ..) => { }
255
+ match decl {
256
+ Decl :: TsEnum ( _) | Decl :: Class ( _) | Decl :: Fn ( _) | Decl :: Var ( _) | Decl :: TsModule ( _) => {
257
+ if let Some ( ( ) ) = self . decl_to_type_decl ( decl) {
258
+ true
259
+ } else {
260
+ self . mark_diagnostic_unable_to_infer ( decl. span ( ) ) ;
261
+ false
262
+ }
235
263
}
236
264
237
- prev_is_overload = is_overload ;
265
+ Decl :: TsInterface ( _ ) | Decl :: TsTypeAlias ( _ ) | Decl :: Using ( _ ) => true ,
238
266
}
239
-
240
- * items = new_items;
241
267
}
242
268
243
269
fn expr_to_ts_type (
@@ -445,64 +471,7 @@ impl FastDts {
445
471
Decl :: Fn ( fn_decl) => {
446
472
fn_decl. function . body = None ;
447
473
fn_decl. declare = is_declare;
448
-
449
- for param in & mut fn_decl. function . params {
450
- match & mut param. pat {
451
- Pat :: Ident ( ident) => {
452
- if ident. type_ann . is_none ( ) {
453
- self . mark_diagnostic_any_fallback ( ident. span ( ) ) ;
454
- ident. type_ann = Some ( any_type_ann ( ) ) ;
455
- }
456
- }
457
- Pat :: Assign ( assign_pat) => {
458
- match & mut * assign_pat. left {
459
- Pat :: Ident ( ident) => {
460
- if ident. type_ann . is_none ( ) {
461
- ident. type_ann = self . infer_expr_fallback_any (
462
- assign_pat. right . take ( ) ,
463
- false ,
464
- false ,
465
- ) ;
466
- }
467
-
468
- ident. optional = true ;
469
- param. pat = ident. clone ( ) . into ( ) ;
470
- }
471
- Pat :: Array ( arr_pat) => {
472
- if arr_pat. type_ann . is_none ( ) {
473
- arr_pat. type_ann = self . infer_expr_fallback_any (
474
- assign_pat. right . take ( ) ,
475
- false ,
476
- false ,
477
- ) ;
478
- }
479
-
480
- arr_pat. optional = true ;
481
- param. pat = arr_pat. clone ( ) . into ( ) ;
482
- }
483
- Pat :: Object ( obj_pat) => {
484
- if obj_pat. type_ann . is_none ( ) {
485
- obj_pat. type_ann = self . infer_expr_fallback_any (
486
- assign_pat. right . take ( ) ,
487
- false ,
488
- false ,
489
- ) ;
490
- }
491
-
492
- obj_pat. optional = true ;
493
- param. pat = obj_pat. clone ( ) . into ( ) ;
494
- }
495
- Pat :: Rest ( _) | Pat :: Assign ( _) | Pat :: Expr ( _) | Pat :: Invalid ( _) => { }
496
- } ;
497
- }
498
- Pat :: Array ( _)
499
- | Pat :: Rest ( _)
500
- | Pat :: Object ( _)
501
- | Pat :: Invalid ( _)
502
- | Pat :: Expr ( _) => { }
503
- }
504
- }
505
-
474
+ self . handle_func_params ( & mut fn_decl. function . params ) ;
506
475
Some ( ( ) )
507
476
}
508
477
Decl :: Var ( var_decl) => {
@@ -748,7 +717,8 @@ impl FastDts {
748
717
. into_iter ( )
749
718
. filter ( |member| match member {
750
719
ClassMember :: Constructor ( class_constructor) => {
751
- let is_overload = class_constructor. body . is_none ( ) ;
720
+ let is_overload =
721
+ class_constructor. body . is_none ( ) && !class_constructor. is_optional ;
752
722
if !prev_is_overload || is_overload {
753
723
prev_is_overload = is_overload;
754
724
true
@@ -758,7 +728,8 @@ impl FastDts {
758
728
}
759
729
}
760
730
ClassMember :: Method ( method) => {
761
- let is_overload = method. function . body . is_none ( ) && !method. is_abstract ;
731
+ let is_overload = method. function . body . is_none ( )
732
+ && !( method. is_abstract || method. is_optional ) ;
762
733
if !prev_is_overload || is_overload {
763
734
prev_is_overload = is_overload;
764
735
true
@@ -781,16 +752,30 @@ impl FastDts {
781
752
. filter_map ( |member| match member {
782
753
ClassMember :: Constructor ( mut class_constructor) => {
783
754
class_constructor. body = None ;
755
+ self . handle_ts_param_props ( & mut class_constructor. params ) ;
784
756
Some ( ClassMember :: Constructor ( class_constructor) )
785
757
}
786
758
ClassMember :: Method ( mut method) => {
759
+ if let Some ( new_prop_name) = valid_prop_name ( & method. key ) {
760
+ method. key = new_prop_name;
761
+ } else {
762
+ return None ;
763
+ }
764
+
787
765
method. function . body = None ;
788
766
if method. kind == MethodKind :: Setter {
789
767
method. function . return_type = None ;
790
768
}
769
+ self . handle_func_params ( & mut method. function . params ) ;
791
770
Some ( ClassMember :: Method ( method) )
792
771
}
793
772
ClassMember :: ClassProp ( mut prop) => {
773
+ if let Some ( new_prop_name) = valid_prop_name ( & prop. key ) {
774
+ prop. key = new_prop_name;
775
+ } else {
776
+ return None ;
777
+ }
778
+
794
779
if prop. type_ann . is_none ( ) {
795
780
if let Some ( value) = prop. value {
796
781
prop. type_ann = self
@@ -821,6 +806,101 @@ impl FastDts {
821
806
* body = new_body;
822
807
}
823
808
809
+ fn handle_ts_param_props ( & mut self , param_props : & mut Vec < ParamOrTsParamProp > ) {
810
+ for param in param_props {
811
+ match param {
812
+ ParamOrTsParamProp :: TsParamProp ( param) => {
813
+ match & mut param. param {
814
+ TsParamPropParam :: Ident ( ident) => {
815
+ self . handle_func_param_ident ( ident) ;
816
+ }
817
+ TsParamPropParam :: Assign ( assign) => {
818
+ if let Some ( new_pat) = self . handle_func_param_assign ( assign) {
819
+ match new_pat {
820
+ Pat :: Ident ( new_ident) => {
821
+ param. param = TsParamPropParam :: Ident ( new_ident)
822
+ }
823
+ Pat :: Assign ( new_assign) => {
824
+ param. param = TsParamPropParam :: Assign ( new_assign)
825
+ }
826
+ Pat :: Rest ( _)
827
+ | Pat :: Object ( _)
828
+ | Pat :: Array ( _)
829
+ | Pat :: Invalid ( _)
830
+ | Pat :: Expr ( _) => {
831
+ // should never happen for parameter properties
832
+ unreachable ! ( ) ;
833
+ }
834
+ }
835
+ }
836
+ }
837
+ }
838
+ }
839
+ ParamOrTsParamProp :: Param ( param) => self . handle_func_param ( param) ,
840
+ }
841
+ }
842
+ }
843
+
844
+ fn handle_func_params ( & mut self , params : & mut Vec < Param > ) {
845
+ for param in params {
846
+ self . handle_func_param ( param) ;
847
+ }
848
+ }
849
+
850
+ fn handle_func_param ( & mut self , param : & mut Param ) {
851
+ match & mut param. pat {
852
+ Pat :: Ident ( ident) => {
853
+ self . handle_func_param_ident ( ident) ;
854
+ }
855
+ Pat :: Assign ( assign_pat) => {
856
+ if let Some ( new_pat) = self . handle_func_param_assign ( assign_pat) {
857
+ param. pat = new_pat;
858
+ }
859
+ }
860
+ Pat :: Array ( _) | Pat :: Rest ( _) | Pat :: Object ( _) | Pat :: Invalid ( _) | Pat :: Expr ( _) => { }
861
+ }
862
+ }
863
+
864
+ fn handle_func_param_ident ( & mut self , ident : & mut BindingIdent ) {
865
+ if ident. type_ann . is_none ( ) {
866
+ self . mark_diagnostic_any_fallback ( ident. span ( ) ) ;
867
+ ident. type_ann = Some ( any_type_ann ( ) ) ;
868
+ }
869
+ }
870
+
871
+ fn handle_func_param_assign ( & mut self , assign_pat : & mut AssignPat ) -> Option < Pat > {
872
+ match & mut * assign_pat. left {
873
+ Pat :: Ident ( ident) => {
874
+ if ident. type_ann . is_none ( ) {
875
+ ident. type_ann =
876
+ self . infer_expr_fallback_any ( assign_pat. right . take ( ) , false , false ) ;
877
+ }
878
+
879
+ ident. optional = true ;
880
+ Some ( Pat :: Ident ( ident. clone ( ) ) )
881
+ }
882
+ Pat :: Array ( arr_pat) => {
883
+ if arr_pat. type_ann . is_none ( ) {
884
+ arr_pat. type_ann =
885
+ self . infer_expr_fallback_any ( assign_pat. right . take ( ) , false , false ) ;
886
+ }
887
+
888
+ arr_pat. optional = true ;
889
+ Some ( Pat :: Array ( arr_pat. clone ( ) ) )
890
+ }
891
+ Pat :: Object ( obj_pat) => {
892
+ if obj_pat. type_ann . is_none ( ) {
893
+ obj_pat. type_ann =
894
+ self . infer_expr_fallback_any ( assign_pat. right . take ( ) , false , false ) ;
895
+ }
896
+
897
+ obj_pat. optional = true ;
898
+ Some ( Pat :: Object ( obj_pat. clone ( ) ) )
899
+ }
900
+ Pat :: Rest ( _) | Pat :: Assign ( _) | Pat :: Expr ( _) | Pat :: Invalid ( _) => None ,
901
+ }
902
+ }
903
+
824
904
fn pat_to_ts_fn_param ( & mut self , pat : Pat ) -> Option < TsFnParam > {
825
905
match pat {
826
906
Pat :: Ident ( binding_id) => Some ( TsFnParam :: Ident ( binding_id) ) ,
@@ -939,3 +1019,69 @@ fn maybe_lit_to_ts_type(lit: &Lit) -> Option<Box<TsType>> {
939
1019
Lit :: JSXText ( _) => None ,
940
1020
}
941
1021
}
1022
+
1023
+ fn valid_prop_name ( prop_name : & PropName ) -> Option < PropName > {
1024
+ fn prop_name_from_expr ( expr : & Expr ) -> Option < PropName > {
1025
+ match expr {
1026
+ Expr :: Lit ( e) => match & e {
1027
+ Lit :: Str ( e) => Some ( PropName :: Str ( e. clone ( ) ) ) ,
1028
+ Lit :: Num ( e) => Some ( PropName :: Num ( e. clone ( ) ) ) ,
1029
+ Lit :: BigInt ( e) => Some ( PropName :: BigInt ( e. clone ( ) ) ) ,
1030
+ Lit :: Bool ( _) | Lit :: Null ( _) | Lit :: Regex ( _) | Lit :: JSXText ( _) => None ,
1031
+ } ,
1032
+ Expr :: Tpl ( e) => {
1033
+ if e. quasis . is_empty ( ) && e. exprs . len ( ) == 1 {
1034
+ prop_name_from_expr ( & e. exprs [ 0 ] )
1035
+ } else {
1036
+ None
1037
+ }
1038
+ }
1039
+ Expr :: Paren ( e) => prop_name_from_expr ( & e. expr ) ,
1040
+ Expr :: TsTypeAssertion ( e) => prop_name_from_expr ( & e. expr ) ,
1041
+ Expr :: TsConstAssertion ( e) => prop_name_from_expr ( & e. expr ) ,
1042
+ Expr :: TsNonNull ( e) => prop_name_from_expr ( & e. expr ) ,
1043
+ Expr :: TsAs ( e) => prop_name_from_expr ( & e. expr ) ,
1044
+ Expr :: TsSatisfies ( e) => prop_name_from_expr ( & e. expr ) ,
1045
+ Expr :: Ident ( _) => Some ( PropName :: Computed ( ComputedPropName {
1046
+ span : expr. span ( ) ,
1047
+ expr : Box :: new ( expr. clone ( ) ) ,
1048
+ } ) ) ,
1049
+ Expr :: TaggedTpl ( _)
1050
+ | Expr :: This ( _)
1051
+ | Expr :: Array ( _)
1052
+ | Expr :: Object ( _)
1053
+ | Expr :: Fn ( _)
1054
+ | Expr :: Unary ( _)
1055
+ | Expr :: Update ( _)
1056
+ | Expr :: Bin ( _)
1057
+ | Expr :: Assign ( _)
1058
+ | Expr :: Member ( _)
1059
+ | Expr :: SuperProp ( _)
1060
+ | Expr :: Cond ( _)
1061
+ | Expr :: Call ( _)
1062
+ | Expr :: New ( _)
1063
+ | Expr :: Seq ( _)
1064
+ | Expr :: Arrow ( _)
1065
+ | Expr :: Class ( _)
1066
+ | Expr :: Yield ( _)
1067
+ | Expr :: Await ( _)
1068
+ | Expr :: MetaProp ( _)
1069
+ | Expr :: JSXMember ( _)
1070
+ | Expr :: JSXNamespacedName ( _)
1071
+ | Expr :: JSXEmpty ( _)
1072
+ | Expr :: JSXElement ( _)
1073
+ | Expr :: JSXFragment ( _)
1074
+ | Expr :: TsInstantiation ( _)
1075
+ | Expr :: PrivateName ( _)
1076
+ | Expr :: OptChain ( _)
1077
+ | Expr :: Invalid ( _) => None ,
1078
+ }
1079
+ }
1080
+
1081
+ match prop_name {
1082
+ PropName :: Ident ( _) | PropName :: Str ( _) | PropName :: Num ( _) | PropName :: BigInt ( _) => {
1083
+ Some ( prop_name. clone ( ) )
1084
+ }
1085
+ PropName :: Computed ( computed) => prop_name_from_expr ( & computed. expr ) ,
1086
+ }
1087
+ }
0 commit comments