1- use std:: { cmp:: Ordering , collections:: VecDeque } ;
1+ use std:: { borrow :: Cow , cmp:: Ordering , collections:: VecDeque } ;
22use wasm_bindgen:: prelude:: * ;
33use oxc_parser:: { ParseOptions , Parser } ;
44use oxc_allocator:: Allocator ;
55use oxc_span:: { SourceType , Span } ;
6- use oxc_ast:: { ast:: { FunctionBody , UnaryOperator } , AstKind , AstType } ;
6+ use oxc_ast:: { ast:: { ArrowFunctionExpression , Expression , Function , FunctionBody , IdentifierReference , ParenthesizedExpression , UnaryOperator } , AstKind , AstType } ;
77use oxc_span:: GetSpan ;
88use oxc_semantic:: { AstNode , Semantic , SemanticBuilder } ;
99
@@ -157,12 +157,8 @@ fn make_end_fn_insertion(offset: u32) -> Insertion {
157157
158158fn fn_start_insertion ( body : & FunctionBody , has_block_body : bool ) -> InsertionList {
159159 let mut ret = InsertionList :: new ( ) ;
160- let mut offset = body. span ( ) . start ;
161- if !has_block_body {
162- ret. push_back ( Insertion :: new ( offset, "{" , false ) ) ;
163- } else {
164- offset = offset. checked_add ( 1 ) . unwrap ( ) ;
165- }
160+ let offset = body. span ( ) . start ;
161+ ret. push_back ( Insertion :: new ( offset, "{" , false ) ) ;
166162 ret. push_back ( make_start_fn_insertion ( offset) ) ;
167163 if !has_block_body {
168164 ret. push_back ( Insertion :: new (
@@ -174,32 +170,69 @@ fn fn_start_insertion(body: &FunctionBody, has_block_body: bool) -> InsertionLis
174170}
175171fn fn_end_insertion ( body : & FunctionBody , has_block_body : bool ) -> InsertionList {
176172 let mut ret = InsertionList :: new ( ) ;
177- let mut offset = body. span ( ) . end ;
178- if has_block_body {
179- offset = offset. checked_sub ( 1 ) . unwrap ( ) ;
180- } else {
181- ret. push_back ( Insertion :: new ( offset, "), _functionState === 'async' ? _synchronousReturnValue : null);" , true ) ) ;
182- }
173+ let offset = body. span ( ) . end ;
174+ ret. push_back ( Insertion :: new ( offset, "}" , true ) ) ;
183175 ret. push_back ( make_end_fn_insertion ( offset) ) ;
184176 if !has_block_body {
185- ret. push_back ( Insertion :: new ( offset, "} " , true ) ) ;
177+ ret. push_back ( Insertion :: new ( offset, "), _functionState === 'async' ? _synchronousReturnValue : null); " , true ) ) ;
186178 }
187179 ret
188180}
189181
182+ fn get_identifier_reference_from_parenthesized_expression < ' a > ( node : & ' a ParenthesizedExpression < ' a > ) -> Option < & ' a IdentifierReference < ' a > > {
183+ match node. expression {
184+ Expression :: Identifier ( ref expr) => Some ( expr) ,
185+ Expression :: ParenthesizedExpression ( ref expr) => get_identifier_reference_from_parenthesized_expression ( expr) ,
186+ _ => None
187+ }
188+ }
189+
190+ fn get_identifier_reference < ' a > ( node : & AstNode < ' a > ) -> Option < & ' a IdentifierReference < ' a > > {
191+ if let AstKind :: IdentifierReference ( expr) = node. kind ( ) {
192+ Some ( expr)
193+ } else if let AstKind :: ParenthesizedExpression ( expr) = node. kind ( ) {
194+ get_identifier_reference_from_parenthesized_expression ( expr)
195+ } else {
196+ None
197+ }
198+ }
199+
200+ enum AnyFunctionParent < ' a > {
201+ Function ( & ' a Function < ' a > ) ,
202+ ArrowFunction ( & ' a ArrowFunctionExpression < ' a > ) ,
203+ }
204+
190205fn collect_insertions ( node : & AstNode , semantic : & Semantic ) -> Result < InsertionList , & ' static str > {
191- let ast_nodes = semantic. nodes ( ) ;
192- let function_parent = ast_nodes. ancestor_kinds ( node. id ( ) ) . filter_map ( |n| n. as_function ( ) ) . find ( |_| true ) ;
193- let mut insertions = InsertionList :: new ( ) ;
206+ let ast_nodes = & semantic. nodes ( ) ;
207+ let function_parent =
208+ & ast_nodes. ancestor_kinds ( node. id ( ) )
209+ . skip ( 1 )
210+ . filter_map ( |n| n. as_function ( ) . map ( |f| AnyFunctionParent :: Function ( f) ) . or_else (
211+ || n. as_arrow_function_expression ( ) . map ( |f| AnyFunctionParent :: ArrowFunction ( f) )
212+ ) )
213+ . find ( |_| true ) ;
214+ let function_parent_is_async = match function_parent {
215+ Some ( AnyFunctionParent :: Function ( f) ) => f. r#async ,
216+ Some ( AnyFunctionParent :: ArrowFunction ( f) ) => f. r#async ,
217+ None => false ,
218+ } ;
219+
194220 let get_parent = |node : & AstNode | ast_nodes. parent_node ( node. id ( ) ) ;
195221 let get_parent_kind = |node : & AstNode | get_parent ( node) . map ( |p| p. kind ( ) ) ;
196222 let get_parent_type = |node : & AstNode | get_parent_kind ( node) . map ( |p| p. ty ( ) ) . unwrap_or ( AstType :: Program ) ;
197223
224+ let get_source = |node : & dyn GetSpan | {
225+ let Span { start, end, .. } = node. span ( ) ;
226+ return semantic. source_text ( ) [ ( start as usize ) ..( end as usize ) ] . to_string ( ) ;
227+ } ;
228+
198229 let span = node. span ( ) ;
199- let kind = node. kind ( ) ;
230+ let kind = & node. kind ( ) ;
200231 let ty = kind. ty ( ) ;
232+
233+ let mut insertions = InsertionList :: new ( ) ;
234+
201235 {
202- // XXX template literal handling?
203236 insertions. push_back ( Insertion :: new_dynamic ( span. start ,
204237 format ! ( " /*{ty:#?}*/ " )
205238 , false ) ) ;
@@ -240,7 +273,6 @@ fn collect_insertions(node: &AstNode, semantic: &Semantic) -> Result<InsertionLi
240273 insertions. push_back ( Insertion :: new_dynamic ( span. start ,
241274 format ! ( "_cr = {name} = " , name = name. as_str( ) )
242275 , false ) ) ;
243- // XXX child insertions
244276 insertions. push_back ( Insertion :: new ( span. end ,
245277 ";"
246278 , true ) ) ;
@@ -270,17 +302,21 @@ fn collect_insertions(node: &AstNode, semantic: &Semantic) -> Result<InsertionLi
270302 return Ok ( insertions) ;
271303 }
272304 if let AstKind :: ExpressionStatement ( as_expr_stmt) = node. kind ( ) {
273- let expr_span = as_expr_stmt. expression . span ( ) ;
274- insertions. push_back ( Insertion :: new ( expr_span. start , ";" , false ) ) ;
275- if !function_parent. is_some ( ) {
276- insertions. push_back ( Insertion :: new ( expr_span. start , "_cr = (" , false ) ) ;
277- insertions. push_back ( Insertion :: new ( expr_span. end , ")" , true ) ) ;
305+ if !( get_parent_type ( node) == AstType :: FunctionBody && get_parent_type ( get_parent ( node) . unwrap ( ) ) == AstType :: ArrowFunctionExpression ) {
306+ let expr_span = as_expr_stmt. expression . span ( ) ;
307+ insertions. push_back ( Insertion :: new ( expr_span. start , ";" , false ) ) ;
308+ if !function_parent. is_some ( ) {
309+ insertions. push_back ( Insertion :: new ( expr_span. start , "_cr = (" , false ) ) ;
310+ }
311+ insertions. push_back ( Insertion :: new ( expr_span. end , ";" , true ) ) ;
312+ if !function_parent. is_some ( ) {
313+ insertions. push_back ( Insertion :: new ( expr_span. end , ")" , true ) ) ;
314+ }
278315 }
279- insertions. push_back ( Insertion :: new ( expr_span. end , ";" , true ) ) ;
280316 return Ok ( insertions) ;
281317 }
282318 if let AstKind :: ReturnStatement ( as_ret_stmt) = node. kind ( ) {
283- if function_parent. map_or ( false , |f| !f . r#async ) {
319+ if function_parent. is_some ( ) && !function_parent_is_async {
284320 if let Some ( expr) = & as_ret_stmt. argument {
285321 insertions. push_back (
286322 Insertion :: new ( expr. span ( ) . start , "(_synchronousReturnValue = (" , false ) ) ;
@@ -292,10 +328,14 @@ fn collect_insertions(node: &AstNode, semantic: &Semantic) -> Result<InsertionLi
292328 }
293329
294330 // This is where expression handling starts
295- let mut wrap_expr_span: Option < Span > = None ;
331+ let mut wrap_expr_span = None ;
296332 let mut is_named_typeof_rhs = false ;
297333 let mut is_identifier = false ;
298- if let AstKind :: IdentifierReference ( expr) = node. kind ( ) {
334+
335+ if let Some ( expr) = get_identifier_reference ( node) {
336+ if get_parent_type ( node) == AstType :: ObjectProperty { // Handles shorthands `{ foo }`, TBD verify correctness
337+ return Ok ( insertions) ;
338+ }
299339 is_identifier = true ;
300340 let name = expr. name . as_str ( ) ;
301341 let is_eval_this_super_reference = [ "eval" , "this" , "super" ] . iter ( ) . any ( |n| * n == name) ;
@@ -321,30 +361,30 @@ fn collect_insertions(node: &AstNode, semantic: &Semantic) -> Result<InsertionLi
321361 if is_identifier && unary_parent. operator == UnaryOperator :: Typeof {
322362 is_named_typeof_rhs = true ;
323363 }
364+ if unary_parent. operator == UnaryOperator :: Delete {
365+ wrap_expr_span = None ;
366+ }
324367 }
325368 if get_parent_type ( node) == AstType :: ForStatementInit ||
326369 get_parent_type ( node) == AstType :: AssignmentTarget ||
370+ get_parent_type ( node) == AstType :: SimpleAssignmentTarget ||
371+ get_parent_type ( node) == AstType :: AssignmentTargetPattern ||
372+ get_parent_type ( node) == AstType :: AssignmentTargetWithDefault ||
327373 get_parent_type ( node) == AstType :: AwaitExpression ||
328374 get_parent_type ( node) == AstType :: FormalParameter {
329375 wrap_expr_span = None ;
330376 }
331377
332- let get_source = |node : & dyn GetSpan | {
333- let Span { start, end, .. } = node. span ( ) ;
334- return semantic. source_text ( ) [ ( start as usize ) ..( end as usize ) ] . to_string ( ) ;
335- } ;
336378 if is_named_typeof_rhs {
337379 insertions. push_back ( Insertion :: new_dynamic ( get_parent_kind ( node) . unwrap ( ) . span ( ) . start ,
338380 format ! ( "(typeof {original} === 'undefined' ? 'undefined' : " , original = get_source( node) ) , false
339381 ) ) ;
382+ insertions. push_back ( Insertion :: new ( span. end , ")" , true ) ) ;
340383 }
341384 if let Some ( s) = wrap_expr_span {
342385 insertions. push_back ( Insertion :: new ( s. start , "(_ex = " , false ) ) ;
343386 insertions. push_back ( Insertion :: new ( s. end , ", _isp(_ex) ? await _ex : _ex)" , true ) ) ;
344387 }
345- if is_named_typeof_rhs {
346- insertions. push_back ( Insertion :: new ( span. end , ")" , true ) ) ;
347- }
348388
349389 return Ok ( insertions) ;
350390}
@@ -356,6 +396,9 @@ pub fn async_rewrite(input: &str, with_debug_tags: bool) -> Result<String, Strin
356396 let parsed = Parser :: new ( & allocator, & input, source_type)
357397 . with_options ( ParseOptions { parse_regular_expression : true , ..ParseOptions :: default ( ) } )
358398 . parse ( ) ;
399+ if parsed. errors . len ( ) > 0 {
400+ return Err ( format ! ( "Parse errors: {:?}" , parsed. errors. iter( ) . map( |e| & e. message) . collect:: <Vec <& Cow <' static , str >>>( ) ) ) ;
401+ }
359402 assert ! ( !parsed. panicked) ;
360403 let semantic_ret = SemanticBuilder :: new ( ) . build ( allocator. alloc ( parsed. program ) ) ;
361404
@@ -373,13 +416,16 @@ pub fn async_rewrite(input: &str, with_debug_tags: bool) -> Result<String, Strin
373416 }
374417 }
375418 let end = input. len ( ) . try_into ( ) . unwrap ( ) ;
419+ for directive in & semantic_ret. semantic . nodes ( ) . root_node ( ) . unwrap ( ) . kind ( ) . as_program ( ) . unwrap ( ) . directives {
420+ insertions. push_back ( Insertion :: new_dynamic ( 0 , format ! ( "\" {}\" " , directive. directive. as_str( ) ) , false ) ) ;
421+ }
376422 insertions. push_back ( Insertion :: new ( 0 , ";(() => { const __SymbolFor = Symbol.for;" , false ) ) ;
377423 insertions. push_back ( make_start_fn_insertion ( 0 ) ) ;
378424 insertions. push_back ( Insertion :: new ( 0 , "var _cr;" , false ) ) ;
379- insertions. append ( & mut collected_insertions) ;
380- insertions. push_back ( Insertion :: new ( end, ";\n return _synchronousReturnValue = _cr;" , true ) ) ;
381- insertions. push_back ( make_end_fn_insertion ( input. len ( ) . try_into ( ) . unwrap ( ) ) ) ;
382425 insertions. push_back ( Insertion :: new ( end, "})()" , true ) ) ;
426+ insertions. push_back ( make_end_fn_insertion ( input. len ( ) . try_into ( ) . unwrap ( ) ) ) ;
427+ insertions. push_back ( Insertion :: new ( end, ";\n return _synchronousReturnValue = _cr;" , true ) ) ;
428+ insertions. append ( & mut collected_insertions) ;
383429
384430 insertions. sort ( ) ;
385431
0 commit comments