@@ -52,7 +52,7 @@ namespace ts {
52
52
location = value ;
53
53
}
54
54
55
- flattenDestructuring ( node , value , location , emitAssignment , emitTempVariableAssignment , emitRestAssignment , transformRest , visitor ) ;
55
+ flattenDestructuring ( node , value , location , emitAssignment , emitTempVariableAssignment , recordTempVariable , emitRestAssignment , transformRest , visitor ) ;
56
56
57
57
if ( needsValue ) {
58
58
expressions . push ( value ) ;
@@ -98,7 +98,7 @@ namespace ts {
98
98
transformRest ?: boolean ) {
99
99
const declarations : VariableDeclaration [ ] = [ ] ;
100
100
101
- flattenDestructuring ( node , value , node , emitAssignment , emitTempVariableAssignment , emitRestAssignment , transformRest , visitor ) ;
101
+ flattenDestructuring ( node , value , node , emitAssignment , emitTempVariableAssignment , noop , emitRestAssignment , transformRest , visitor ) ;
102
102
103
103
return declarations ;
104
104
@@ -140,7 +140,7 @@ namespace ts {
140
140
const declarations : VariableDeclaration [ ] = [ ] ;
141
141
142
142
let pendingAssignments : Expression [ ] ;
143
- flattenDestructuring ( node , value , node , emitAssignment , emitTempVariableAssignment , emitRestAssignment , transformRest , visitor ) ;
143
+ flattenDestructuring ( node , value , node , emitAssignment , emitTempVariableAssignment , recordTempVariable , emitRestAssignment , transformRest , visitor ) ;
144
144
145
145
return declarations ;
146
146
@@ -201,7 +201,7 @@ namespace ts {
201
201
202
202
const pendingAssignments : Expression [ ] = [ ] ;
203
203
204
- flattenDestructuring ( node , /*value*/ undefined , node , emitAssignment , emitTempVariableAssignment , emitRestAssignment , /*transformRest*/ false , visitor ) ;
204
+ flattenDestructuring ( node , /*value*/ undefined , node , emitAssignment , emitTempVariableAssignment , noop , emitRestAssignment , /*transformRest*/ false , visitor ) ;
205
205
206
206
const expression = inlineExpressions ( pendingAssignments ) ;
207
207
aggregateTransformFlags ( expression ) ;
@@ -244,6 +244,7 @@ namespace ts {
244
244
location : TextRange ,
245
245
emitAssignment : ( name : Identifier , value : Expression , location : TextRange , original : Node ) => void ,
246
246
emitTempVariableAssignment : ( value : Expression , location : TextRange ) => Identifier ,
247
+ recordTempVariable : ( node : Identifier ) => void ,
247
248
emitRestAssignment : ( elements : ( ObjectLiteralElementLike [ ] | BindingElement [ ] ) , value : Expression , location : TextRange , original : Node ) => void ,
248
249
transformRest : boolean ,
249
250
visitor ?: ( node : Node ) => VisitResult < Node > ) {
@@ -307,48 +308,91 @@ namespace ts {
307
308
value = ensureIdentifier ( value , /*reuseIdentifierExpressions*/ true , location , emitTempVariableAssignment ) ;
308
309
}
309
310
310
- let es2015 : ObjectLiteralElementLike [ ] = [ ] ;
311
+ let bindingElements : ObjectLiteralElementLike [ ] = [ ] ;
311
312
for ( let i = 0 ; i < properties . length ; i ++ ) {
312
313
const p = properties [ i ] ;
313
314
if ( p . kind === SyntaxKind . PropertyAssignment || p . kind === SyntaxKind . ShorthandPropertyAssignment ) {
314
- if ( transformRest && ! ( p . transformFlags & TransformFlags . ContainsSpreadExpression ) ) {
315
- es2015 . push ( p ) ;
316
- }
317
- else {
318
- if ( es2015 . length ) {
319
- emitRestAssignment ( es2015 , value , location , target ) ;
320
- es2015 = [ ] ;
315
+ if ( ! transformRest ||
316
+ p . transformFlags & TransformFlags . ContainsSpreadExpression ||
317
+ ( p . kind === SyntaxKind . PropertyAssignment && p . initializer . transformFlags & TransformFlags . ContainsSpreadExpression ) ) {
318
+ if ( bindingElements . length ) {
319
+ emitRestAssignment ( bindingElements , value , location , target ) ;
320
+ bindingElements = [ ] ;
321
321
}
322
322
const propName = < Identifier | LiteralExpression > ( < PropertyAssignment > p ) . name ;
323
323
const bindingTarget = p . kind === SyntaxKind . ShorthandPropertyAssignment ? < ShorthandPropertyAssignment > p : ( < PropertyAssignment > p ) . initializer || propName ;
324
324
// Assignment for bindingTarget = value.propName should highlight whole property, hence use p as source map node
325
325
emitDestructuringAssignment ( bindingTarget , createDestructuringPropertyAccess ( value , propName ) , p ) ;
326
326
}
327
+ else {
328
+ bindingElements . push ( p ) ;
329
+ }
327
330
}
328
331
else if ( i === properties . length - 1 && p . kind === SyntaxKind . SpreadAssignment ) {
329
332
Debug . assert ( ( p as SpreadAssignment ) . expression . kind === SyntaxKind . Identifier ) ;
330
- if ( es2015 . length ) {
331
- emitRestAssignment ( es2015 , value , location , target ) ;
332
- es2015 = [ ] ;
333
+ if ( bindingElements . length ) {
334
+ emitRestAssignment ( bindingElements , value , location , target ) ;
335
+ bindingElements = [ ] ;
333
336
}
334
337
const propName = ( p as SpreadAssignment ) . expression as Identifier ;
335
338
const restCall = createRestCall ( value , target . properties , p => p . name , target ) ;
336
339
emitDestructuringAssignment ( propName , restCall , p ) ;
337
340
}
338
341
}
339
- if ( es2015 . length ) {
340
- emitRestAssignment ( es2015 , value , location , target ) ;
341
- es2015 = [ ] ;
342
+ if ( bindingElements . length ) {
343
+ emitRestAssignment ( bindingElements , value , location , target ) ;
344
+ bindingElements = [ ] ;
342
345
}
343
346
}
344
347
345
348
function emitArrayLiteralAssignment ( target : ArrayLiteralExpression , value : Expression , location : TextRange ) {
349
+ if ( transformRest ) {
350
+ emitESNextArrayLiteralAssignment ( target , value , location ) ;
351
+ }
352
+ else {
353
+ emitES2015ArrayLiteralAssignment ( target , value , location ) ;
354
+ }
355
+ }
356
+
357
+ function emitESNextArrayLiteralAssignment ( target : ArrayLiteralExpression , value : Expression , location : TextRange ) {
346
358
const elements = target . elements ;
347
359
const numElements = elements . length ;
348
360
if ( numElements !== 1 ) {
349
361
// For anything but a single element destructuring we need to generate a temporary
350
362
// to ensure value is evaluated exactly once.
351
- // When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment
363
+ // When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment
364
+ value = ensureIdentifier ( value , /*reuseIdentifierExpressions*/ true , location , emitTempVariableAssignment ) ;
365
+ }
366
+
367
+ const expressions : Expression [ ] = [ ] ;
368
+ const spreadContainingExpressions : [ Expression , Identifier ] [ ] = [ ] ;
369
+ for ( let i = 0 ; i < numElements ; i ++ ) {
370
+ const e = elements [ i ] ;
371
+ if ( e . kind === SyntaxKind . OmittedExpression ) {
372
+ continue ;
373
+ }
374
+ if ( e . transformFlags & TransformFlags . ContainsSpreadExpression && i < numElements - 1 ) {
375
+ const tmp = createTempVariable ( recordTempVariable ) ;
376
+ spreadContainingExpressions . push ( [ e , tmp ] ) ;
377
+ expressions . push ( tmp ) ;
378
+ }
379
+ else {
380
+ expressions . push ( e ) ;
381
+ }
382
+ }
383
+ emitAssignment ( updateArrayLiteral ( target , expressions ) as any as Identifier , value , undefined , undefined ) ;
384
+ for ( const [ e , tmp ] of spreadContainingExpressions ) {
385
+ emitDestructuringAssignment ( e , tmp , e ) ;
386
+ }
387
+ }
388
+
389
+ function emitES2015ArrayLiteralAssignment ( target : ArrayLiteralExpression , value : Expression , location : TextRange ) {
390
+ const elements = target . elements ;
391
+ const numElements = elements . length ;
392
+ if ( numElements !== 1 ) {
393
+ // For anything but a single element destructuring we need to generate a temporary
394
+ // to ensure value is evaluated exactly once.
395
+ // When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment
352
396
value = ensureIdentifier ( value , /*reuseIdentifierExpressions*/ true , location , emitTempVariableAssignment ) ;
353
397
}
354
398
@@ -413,15 +457,24 @@ namespace ts {
413
457
value = ensureIdentifier ( value , /*reuseIdentifierExpressions*/ numElements !== 0 , target , emitTempVariableAssignment ) ;
414
458
}
415
459
if ( name . kind === SyntaxKind . ArrayBindingPattern ) {
416
- emitArrayBindingElement ( name , value ) ;
460
+ emitArrayBindingElement ( name as ArrayBindingPattern , value ) ;
417
461
}
418
462
else {
419
463
emitObjectBindingElement ( target , value ) ;
420
464
}
421
465
}
422
466
}
423
467
424
- function emitArrayBindingElement ( name : BindingPattern , value : Expression ) {
468
+ function emitArrayBindingElement ( name : ArrayBindingPattern , value : Expression ) {
469
+ if ( transformRest ) {
470
+ emitESNextArrayBindingElement ( name , value ) ;
471
+ }
472
+ else {
473
+ emitES2015ArrayBindingElement ( name , value ) ;
474
+ }
475
+ }
476
+
477
+ function emitES2015ArrayBindingElement ( name : ArrayBindingPattern , value : Expression ) {
425
478
const elements = name . elements ;
426
479
const numElements = elements . length ;
427
480
for ( let i = 0 ; i < numElements ; i ++ ) {
@@ -439,20 +492,44 @@ namespace ts {
439
492
}
440
493
}
441
494
495
+ function emitESNextArrayBindingElement ( name : ArrayBindingPattern , value : Expression ) {
496
+ const elements = name . elements ;
497
+ const numElements = elements . length ;
498
+ const bindingElements : BindingElement [ ] = [ ] ;
499
+ const spreadContainingElements : BindingElement [ ] = [ ] ;
500
+ for ( let i = 0 ; i < numElements ; i ++ ) {
501
+ const element = elements [ i ] ;
502
+ if ( isOmittedExpression ( element ) ) {
503
+ continue ;
504
+ }
505
+ if ( element . transformFlags & TransformFlags . ContainsSpreadExpression && i < numElements - 1 ) {
506
+ spreadContainingElements . push ( element ) ;
507
+ bindingElements . push ( createBindingElement ( undefined , undefined , getGeneratedNameForNode ( element ) , undefined , value ) ) ;
508
+ }
509
+ else {
510
+ bindingElements . push ( element ) ;
511
+ }
512
+ }
513
+ emitAssignment ( updateArrayBindingPattern ( name , bindingElements ) as any as Identifier , value , undefined , undefined ) ;
514
+ for ( const element of spreadContainingElements ) {
515
+ emitBindingElement ( element , getGeneratedNameForNode ( element ) ) ;
516
+ }
517
+ }
518
+
442
519
function emitObjectBindingElement ( target : VariableDeclaration | ParameterDeclaration | BindingElement , value : Expression ) {
443
520
const name = target . name as BindingPattern ;
444
521
const elements = name . elements ;
445
522
const numElements = elements . length ;
446
- let es2015 : BindingElement [ ] = [ ] ;
523
+ let bindingElements : BindingElement [ ] = [ ] ;
447
524
for ( let i = 0 ; i < numElements ; i ++ ) {
448
525
const element = elements [ i ] ;
449
526
if ( isOmittedExpression ( element ) ) {
450
527
continue ;
451
528
}
452
529
if ( i === numElements - 1 && element . dotDotDotToken ) {
453
- if ( es2015 . length ) {
454
- emitRestAssignment ( es2015 , value , target , target ) ;
455
- es2015 = [ ] ;
530
+ if ( bindingElements . length ) {
531
+ emitRestAssignment ( bindingElements , value , target , target ) ;
532
+ bindingElements = [ ] ;
456
533
}
457
534
const restCall = createRestCall ( value ,
458
535
name . elements ,
@@ -462,21 +539,21 @@ namespace ts {
462
539
}
463
540
else if ( transformRest && ! ( element . transformFlags & TransformFlags . ContainsSpreadExpression ) ) {
464
541
// do not emit until we have a complete bundle of ES2015 syntax
465
- es2015 . push ( element ) ;
542
+ bindingElements . push ( element ) ;
466
543
}
467
544
else {
468
- if ( es2015 . length ) {
469
- emitRestAssignment ( es2015 , value , target , target ) ;
470
- es2015 = [ ] ;
545
+ if ( bindingElements . length ) {
546
+ emitRestAssignment ( bindingElements , value , target , target ) ;
547
+ bindingElements = [ ] ;
471
548
}
472
549
// Rewrite element to a declaration with an initializer that fetches property
473
550
const propName = element . propertyName || < Identifier > element . name ;
474
551
emitBindingElement ( element , createDestructuringPropertyAccess ( value , propName ) ) ;
475
552
}
476
553
}
477
- if ( es2015 . length ) {
478
- emitRestAssignment ( es2015 , value , target , target ) ;
479
- es2015 = [ ] ;
554
+ if ( bindingElements . length ) {
555
+ emitRestAssignment ( bindingElements , value , target , target ) ;
556
+ bindingElements = [ ] ;
480
557
}
481
558
}
482
559
0 commit comments