1
- use std:: { cmp:: Ordering , collections:: VecDeque } ;
1
+ use std:: { borrow :: Cow , cmp:: Ordering , collections:: VecDeque } ;
2
2
use wasm_bindgen:: prelude:: * ;
3
3
use oxc_parser:: { ParseOptions , Parser } ;
4
4
use oxc_allocator:: Allocator ;
5
5
use 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 } ;
7
7
use oxc_span:: GetSpan ;
8
8
use oxc_semantic:: { AstNode , Semantic , SemanticBuilder } ;
9
9
@@ -157,12 +157,8 @@ fn make_end_fn_insertion(offset: u32) -> Insertion {
157
157
158
158
fn fn_start_insertion ( body : & FunctionBody , has_block_body : bool ) -> InsertionList {
159
159
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 ) ) ;
166
162
ret. push_back ( make_start_fn_insertion ( offset) ) ;
167
163
if !has_block_body {
168
164
ret. push_back ( Insertion :: new (
@@ -174,32 +170,69 @@ fn fn_start_insertion(body: &FunctionBody, has_block_body: bool) -> InsertionLis
174
170
}
175
171
fn fn_end_insertion ( body : & FunctionBody , has_block_body : bool ) -> InsertionList {
176
172
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 ) ) ;
183
175
ret. push_back ( make_end_fn_insertion ( offset) ) ;
184
176
if !has_block_body {
185
- ret. push_back ( Insertion :: new ( offset, "} " , true ) ) ;
177
+ ret. push_back ( Insertion :: new ( offset, "), _functionState === 'async' ? _synchronousReturnValue : null); " , true ) ) ;
186
178
}
187
179
ret
188
180
}
189
181
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
+
190
205
fn 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
+
194
220
let get_parent = |node : & AstNode | ast_nodes. parent_node ( node. id ( ) ) ;
195
221
let get_parent_kind = |node : & AstNode | get_parent ( node) . map ( |p| p. kind ( ) ) ;
196
222
let get_parent_type = |node : & AstNode | get_parent_kind ( node) . map ( |p| p. ty ( ) ) . unwrap_or ( AstType :: Program ) ;
197
223
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
+
198
229
let span = node. span ( ) ;
199
- let kind = node. kind ( ) ;
230
+ let kind = & node. kind ( ) ;
200
231
let ty = kind. ty ( ) ;
232
+
233
+ let mut insertions = InsertionList :: new ( ) ;
234
+
201
235
{
202
- // XXX template literal handling?
203
236
insertions. push_back ( Insertion :: new_dynamic ( span. start ,
204
237
format ! ( " /*{ty:#?}*/ " )
205
238
, false ) ) ;
@@ -240,7 +273,6 @@ fn collect_insertions(node: &AstNode, semantic: &Semantic) -> Result<InsertionLi
240
273
insertions. push_back ( Insertion :: new_dynamic ( span. start ,
241
274
format ! ( "_cr = {name} = " , name = name. as_str( ) )
242
275
, false ) ) ;
243
- // XXX child insertions
244
276
insertions. push_back ( Insertion :: new ( span. end ,
245
277
";"
246
278
, true ) ) ;
@@ -270,17 +302,21 @@ fn collect_insertions(node: &AstNode, semantic: &Semantic) -> Result<InsertionLi
270
302
return Ok ( insertions) ;
271
303
}
272
304
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
+ }
278
315
}
279
- insertions. push_back ( Insertion :: new ( expr_span. end , ";" , true ) ) ;
280
316
return Ok ( insertions) ;
281
317
}
282
318
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 {
284
320
if let Some ( expr) = & as_ret_stmt. argument {
285
321
insertions. push_back (
286
322
Insertion :: new ( expr. span ( ) . start , "(_synchronousReturnValue = (" , false ) ) ;
@@ -292,10 +328,14 @@ fn collect_insertions(node: &AstNode, semantic: &Semantic) -> Result<InsertionLi
292
328
}
293
329
294
330
// This is where expression handling starts
295
- let mut wrap_expr_span: Option < Span > = None ;
331
+ let mut wrap_expr_span = None ;
296
332
let mut is_named_typeof_rhs = false ;
297
333
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
+ }
299
339
is_identifier = true ;
300
340
let name = expr. name . as_str ( ) ;
301
341
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
321
361
if is_identifier && unary_parent. operator == UnaryOperator :: Typeof {
322
362
is_named_typeof_rhs = true ;
323
363
}
364
+ if unary_parent. operator == UnaryOperator :: Delete {
365
+ wrap_expr_span = None ;
366
+ }
324
367
}
325
368
if get_parent_type ( node) == AstType :: ForStatementInit ||
326
369
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 ||
327
373
get_parent_type ( node) == AstType :: AwaitExpression ||
328
374
get_parent_type ( node) == AstType :: FormalParameter {
329
375
wrap_expr_span = None ;
330
376
}
331
377
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
- } ;
336
378
if is_named_typeof_rhs {
337
379
insertions. push_back ( Insertion :: new_dynamic ( get_parent_kind ( node) . unwrap ( ) . span ( ) . start ,
338
380
format ! ( "(typeof {original} === 'undefined' ? 'undefined' : " , original = get_source( node) ) , false
339
381
) ) ;
382
+ insertions. push_back ( Insertion :: new ( span. end , ")" , true ) ) ;
340
383
}
341
384
if let Some ( s) = wrap_expr_span {
342
385
insertions. push_back ( Insertion :: new ( s. start , "(_ex = " , false ) ) ;
343
386
insertions. push_back ( Insertion :: new ( s. end , ", _isp(_ex) ? await _ex : _ex)" , true ) ) ;
344
387
}
345
- if is_named_typeof_rhs {
346
- insertions. push_back ( Insertion :: new ( span. end , ")" , true ) ) ;
347
- }
348
388
349
389
return Ok ( insertions) ;
350
390
}
@@ -356,6 +396,9 @@ pub fn async_rewrite(input: &str, with_debug_tags: bool) -> Result<String, Strin
356
396
let parsed = Parser :: new ( & allocator, & input, source_type)
357
397
. with_options ( ParseOptions { parse_regular_expression : true , ..ParseOptions :: default ( ) } )
358
398
. 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
+ }
359
402
assert ! ( !parsed. panicked) ;
360
403
let semantic_ret = SemanticBuilder :: new ( ) . build ( allocator. alloc ( parsed. program ) ) ;
361
404
@@ -373,13 +416,16 @@ pub fn async_rewrite(input: &str, with_debug_tags: bool) -> Result<String, Strin
373
416
}
374
417
}
375
418
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
+ }
376
422
insertions. push_back ( Insertion :: new ( 0 , ";(() => { const __SymbolFor = Symbol.for;" , false ) ) ;
377
423
insertions. push_back ( make_start_fn_insertion ( 0 ) ) ;
378
424
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 ( ) ) ) ;
382
425
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) ;
383
429
384
430
insertions. sort ( ) ;
385
431
0 commit comments