1
+ use std:: cell:: Cell ;
2
+
1
3
use oxc_allocator:: Vec ;
2
4
use oxc_ast:: { ast:: * , visit:: walk_mut, VisitMut } ;
3
- use oxc_span:: { Atom , SPAN } ;
5
+ use oxc_span:: { Atom , Span , SPAN } ;
4
6
use oxc_syntax:: {
5
7
number:: { NumberBase , ToJsInt32 , ToJsString } ,
6
8
operator:: { AssignmentOperator , BinaryOperator , LogicalOperator , UnaryOperator } ,
9
+ reference:: ReferenceFlag ,
10
+ symbol:: SymbolFlags ,
7
11
} ;
8
12
use oxc_traverse:: TraverseCtx ;
9
13
use rustc_hash:: FxHashMap ;
@@ -20,14 +24,14 @@ impl<'a> TypeScriptEnum<'a> {
20
24
Self { ctx, enums : FxHashMap :: default ( ) }
21
25
}
22
26
23
- pub fn transform_statement ( & mut self , stmt : & mut Statement < ' a > , ctx : & TraverseCtx < ' a > ) {
27
+ pub fn transform_statement ( & mut self , stmt : & mut Statement < ' a > , ctx : & mut TraverseCtx < ' a > ) {
24
28
let new_stmt = match stmt {
25
29
Statement :: TSEnumDeclaration ( ts_enum_decl) => {
26
- self . transform_ts_enum ( ts_enum_decl, false , ctx)
30
+ self . transform_ts_enum ( ts_enum_decl, None , ctx)
27
31
}
28
32
Statement :: ExportNamedDeclaration ( decl) => {
29
33
if let Some ( Declaration :: TSEnumDeclaration ( ts_enum_decl) ) = & decl. declaration {
30
- self . transform_ts_enum ( ts_enum_decl, true , ctx)
34
+ self . transform_ts_enum ( ts_enum_decl, Some ( decl . span ) , ctx)
31
35
} else {
32
36
None
33
37
}
@@ -56,16 +60,29 @@ impl<'a> TypeScriptEnum<'a> {
56
60
fn transform_ts_enum (
57
61
& mut self ,
58
62
decl : & TSEnumDeclaration < ' a > ,
59
- is_export : bool ,
60
- ctx : & TraverseCtx < ' a > ,
63
+ export_span : Option < Span > ,
64
+ ctx : & mut TraverseCtx < ' a > ,
61
65
) -> Option < Statement < ' a > > {
62
66
if decl. declare {
63
67
return None ;
64
68
}
65
69
70
+ let is_export = export_span. is_some ( ) ;
66
71
let is_not_top_scope = !ctx. scopes ( ) . get_flags ( ctx. current_scope_id ( ) ) . is_top ( ) ;
67
- let span = decl. span ;
68
- let ident = decl. id . clone ( ) ;
72
+
73
+ let enum_name = decl. id . name . clone ( ) ;
74
+ let func_scope_id = decl. scope_id . get ( ) . unwrap ( ) ;
75
+ let param_symbol_id = ctx. symbols_mut ( ) . create_symbol (
76
+ decl. id . span ,
77
+ enum_name. to_compact_str ( ) ,
78
+ SymbolFlags :: FunctionScopedVariable ,
79
+ func_scope_id,
80
+ ) ;
81
+ let ident = BindingIdentifier {
82
+ span : decl. id . span ,
83
+ name : decl. id . name . clone ( ) ,
84
+ symbol_id : Cell :: new ( Some ( param_symbol_id) ) ,
85
+ } ;
69
86
let kind = self . ctx . ast . binding_pattern_identifier ( ident) ;
70
87
let id = self . ctx . ast . binding_pattern ( kind, None , false ) ;
71
88
@@ -81,25 +98,39 @@ impl<'a> TypeScriptEnum<'a> {
81
98
) ;
82
99
83
100
// Foo[Foo["X"] = 0] = "X";
84
- let enum_name = decl. id . name . clone ( ) ;
85
101
let is_already_declared = self . enums . contains_key ( & enum_name) ;
86
102
let statements = self . transform_ts_enum_members ( & decl. members , enum_name. clone ( ) , ctx) ;
87
103
let body = self . ctx . ast . function_body ( decl. span , self . ctx . ast . new_vec ( ) , statements) ;
88
- let r#type = FunctionType :: FunctionExpression ;
89
- let callee = self . ctx . ast . plain_function ( r#type, SPAN , None , params, Some ( body) ) ;
90
- let callee = Expression :: FunctionExpression ( callee) ;
104
+ let callee = Expression :: FunctionExpression ( ctx. alloc ( Function {
105
+ r#type : FunctionType :: FunctionExpression ,
106
+ span : SPAN ,
107
+ id : None ,
108
+ generator : false ,
109
+ r#async : false ,
110
+ declare : false ,
111
+ this_param : None ,
112
+ params,
113
+ body : Some ( body) ,
114
+ type_parameters : None ,
115
+ return_type : None ,
116
+ scope_id : Cell :: new ( Some ( func_scope_id) ) ,
117
+ } ) ) ;
91
118
119
+ let var_symbol_id = decl. id . symbol_id . get ( ) . unwrap ( ) ;
92
120
let arguments = if ( is_export || is_not_top_scope) && !is_already_declared {
93
121
// }({});
94
122
let object_expr = self . ctx . ast . object_expression ( SPAN , self . ctx . ast . new_vec ( ) , None ) ;
95
123
self . ctx . ast . new_vec_single ( Argument :: from ( object_expr) )
96
124
} else {
97
125
// }(Foo || {});
98
126
let op = LogicalOperator :: Or ;
99
- let left = self
100
- . ctx
101
- . ast
102
- . identifier_reference_expression ( IdentifierReference :: new ( SPAN , enum_name. clone ( ) ) ) ;
127
+ let left = ctx. create_bound_reference_id (
128
+ decl. id . span ,
129
+ enum_name. clone ( ) ,
130
+ var_symbol_id,
131
+ ReferenceFlag :: Read ,
132
+ ) ;
133
+ let left = ctx. ast . identifier_reference_expression ( left) ;
103
134
let right = self . ctx . ast . object_expression ( SPAN , self . ctx . ast . new_vec ( ) , None ) ;
104
135
let expression = self . ctx . ast . logical_expression ( SPAN , left, op, right) ;
105
136
self . ctx . ast . new_vec_single ( Argument :: from ( expression) )
@@ -109,12 +140,15 @@ impl<'a> TypeScriptEnum<'a> {
109
140
110
141
if is_already_declared {
111
142
let op = AssignmentOperator :: Assign ;
112
- let left = self . ctx . ast . simple_assignment_target_identifier ( IdentifierReference :: new (
113
- SPAN ,
143
+ let left = ctx. create_bound_reference_id (
144
+ decl . id . span ,
114
145
enum_name. clone ( ) ,
115
- ) ) ;
146
+ var_symbol_id,
147
+ ReferenceFlag :: Write ,
148
+ ) ;
149
+ let left = ctx. ast . simple_assignment_target_identifier ( left) ;
116
150
let expr = self . ctx . ast . assignment_expression ( SPAN , op, left, call_expression) ;
117
- return Some ( self . ctx . ast . expression_statement ( SPAN , expr) ) ;
151
+ return Some ( self . ctx . ast . expression_statement ( decl . span , expr) ) ;
118
152
}
119
153
120
154
let kind = if is_export || is_not_top_scope {
@@ -123,25 +157,21 @@ impl<'a> TypeScriptEnum<'a> {
123
157
VariableDeclarationKind :: Var
124
158
} ;
125
159
let decls = {
126
- let mut decls = self . ctx . ast . new_vec ( ) ;
127
-
128
- let binding_identifier = BindingIdentifier :: new ( SPAN , enum_name. clone ( ) ) ;
160
+ let binding_identifier = decl. id . clone ( ) ;
129
161
let binding_pattern_kind = self . ctx . ast . binding_pattern_identifier ( binding_identifier) ;
130
162
let binding = self . ctx . ast . binding_pattern ( binding_pattern_kind, None , false ) ;
131
163
let decl =
132
164
self . ctx . ast . variable_declarator ( SPAN , kind, binding, Some ( call_expression) , false ) ;
133
-
134
- decls. push ( decl) ;
135
- decls
165
+ ctx. ast . new_vec_single ( decl)
136
166
} ;
137
- let variable_declaration = self . ctx . ast . variable_declaration ( span, kind, decls, false ) ;
167
+ let variable_declaration = self . ctx . ast . variable_declaration ( decl . span , kind, decls, false ) ;
138
168
let variable_declaration = Declaration :: VariableDeclaration ( variable_declaration) ;
139
169
140
- let stmt = if is_export {
141
- let declaration =
142
- self . ctx . ast . plain_export_named_declaration_declaration ( SPAN , variable_declaration ) ;
143
-
144
- self . ctx . ast . module_declaration ( ModuleDeclaration :: ExportNamedDeclaration ( declaration) )
170
+ let stmt = if let Some ( export_span ) = export_span {
171
+ let declaration = ctx
172
+ . ast
173
+ . plain_export_named_declaration_declaration ( export_span , variable_declaration ) ;
174
+ Statement :: ExportNamedDeclaration ( declaration)
145
175
} else {
146
176
Statement :: from ( variable_declaration)
147
177
} ;
@@ -154,6 +184,8 @@ impl<'a> TypeScriptEnum<'a> {
154
184
enum_name : Atom < ' a > ,
155
185
ctx : & TraverseCtx < ' a > ,
156
186
) -> Vec < ' a , Statement < ' a > > {
187
+ // TODO: Set `span` and `references_id` on all `IdentifierReference`s created here
188
+
157
189
let mut statements = self . ctx . ast . new_vec ( ) ;
158
190
let mut prev_constant_value = Some ( ConstantValue :: Number ( -1.0 ) ) ;
159
191
let mut previous_enum_members = self . enums . entry ( enum_name. clone ( ) ) . or_default ( ) . clone ( ) ;
0 commit comments