@@ -59,6 +59,7 @@ namespace ts {
59
59
let exportedVariableStatement = false ;
60
60
let enabledSubstitutions : ESNextSubstitutionFlags ;
61
61
let enclosingFunctionFlags : FunctionFlags ;
62
+ let parameterHasPrecedingObjectRestOrSpread : Set < ParameterDeclaration > | undefined ;
62
63
let enclosingSuperContainerFlags : NodeCheckFlags = 0 ;
63
64
let hierarchyFacts : HierarchyFacts = 0 ;
64
65
@@ -785,7 +786,24 @@ namespace ts {
785
786
) ;
786
787
}
787
788
789
+ function parameterVisitor ( node : Node ) {
790
+ Debug . assertNode ( node , isParameter ) ;
791
+ return visitParameter ( node ) ;
792
+ }
793
+
788
794
function visitParameter ( node : ParameterDeclaration ) : ParameterDeclaration {
795
+ if ( parameterHasPrecedingObjectRestOrSpread ?. has ( node ) ) {
796
+ return factory . updateParameterDeclaration (
797
+ node ,
798
+ /*decorators*/ undefined ,
799
+ /*modifiers*/ undefined ,
800
+ node . dotDotDotToken ,
801
+ isBindingPattern ( node . name ) ? factory . getGeneratedNameForNode ( node ) : node . name ,
802
+ /*questionToken*/ undefined ,
803
+ /*type*/ undefined ,
804
+ /*initializer*/ undefined
805
+ ) ;
806
+ }
789
807
if ( node . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
790
808
// Binding patterns are converted into a generated name and are
791
809
// evaluated inside the function body.
@@ -803,54 +821,76 @@ namespace ts {
803
821
return visitEachChild ( node , visitor , context ) ;
804
822
}
805
823
824
+ function recordParameterHasPrecedingObjectRestOrSpread ( node : SignatureDeclaration ) {
825
+ for ( const parameter of node . parameters ) {
826
+ if ( parameterHasPrecedingObjectRestOrSpread ) {
827
+ parameterHasPrecedingObjectRestOrSpread . add ( parameter ) ;
828
+ }
829
+ else if ( parameter . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
830
+ parameterHasPrecedingObjectRestOrSpread = new Set ( ) ;
831
+ }
832
+ }
833
+ }
834
+
806
835
function visitConstructorDeclaration ( node : ConstructorDeclaration ) {
807
836
const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
808
- enclosingFunctionFlags = FunctionFlags . Normal ;
837
+ const savedParameterHasPrecedingObjectRestOrSpread = parameterHasPrecedingObjectRestOrSpread ;
838
+ enclosingFunctionFlags = getFunctionFlags ( node ) ;
839
+ recordParameterHasPrecedingObjectRestOrSpread ( node ) ;
809
840
const updated = factory . updateConstructorDeclaration (
810
841
node ,
811
842
/*decorators*/ undefined ,
812
843
node . modifiers ,
813
- visitParameterList ( node . parameters , visitor , context ) ,
844
+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
814
845
transformFunctionBody ( node )
815
846
) ;
816
847
enclosingFunctionFlags = savedEnclosingFunctionFlags ;
848
+ parameterHasPrecedingObjectRestOrSpread = savedParameterHasPrecedingObjectRestOrSpread ;
817
849
return updated ;
818
850
}
819
851
820
852
function visitGetAccessorDeclaration ( node : GetAccessorDeclaration ) {
821
853
const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
822
- enclosingFunctionFlags = FunctionFlags . Normal ;
854
+ const savedParameterHasPrecedingObjectRestOrSpread = parameterHasPrecedingObjectRestOrSpread ;
855
+ enclosingFunctionFlags = getFunctionFlags ( node ) ;
856
+ recordParameterHasPrecedingObjectRestOrSpread ( node ) ;
823
857
const updated = factory . updateGetAccessorDeclaration (
824
858
node ,
825
859
/*decorators*/ undefined ,
826
860
node . modifiers ,
827
861
visitNode ( node . name , visitor , isPropertyName ) ,
828
- visitParameterList ( node . parameters , visitor , context ) ,
862
+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
829
863
/*type*/ undefined ,
830
864
transformFunctionBody ( node )
831
865
) ;
832
866
enclosingFunctionFlags = savedEnclosingFunctionFlags ;
867
+ parameterHasPrecedingObjectRestOrSpread = savedParameterHasPrecedingObjectRestOrSpread ;
833
868
return updated ;
834
869
}
835
870
836
871
function visitSetAccessorDeclaration ( node : SetAccessorDeclaration ) {
837
872
const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
838
- enclosingFunctionFlags = FunctionFlags . Normal ;
873
+ const savedParameterHasPrecedingObjectRestOrSpread = parameterHasPrecedingObjectRestOrSpread ;
874
+ enclosingFunctionFlags = getFunctionFlags ( node ) ;
875
+ recordParameterHasPrecedingObjectRestOrSpread ( node ) ;
839
876
const updated = factory . updateSetAccessorDeclaration (
840
877
node ,
841
878
/*decorators*/ undefined ,
842
879
node . modifiers ,
843
880
visitNode ( node . name , visitor , isPropertyName ) ,
844
- visitParameterList ( node . parameters , visitor , context ) ,
881
+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
845
882
transformFunctionBody ( node )
846
883
) ;
847
884
enclosingFunctionFlags = savedEnclosingFunctionFlags ;
885
+ parameterHasPrecedingObjectRestOrSpread = savedParameterHasPrecedingObjectRestOrSpread ;
848
886
return updated ;
849
887
}
850
888
851
889
function visitMethodDeclaration ( node : MethodDeclaration ) {
852
890
const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
891
+ const savedParameterHasPrecedingObjectRestOrSpread = parameterHasPrecedingObjectRestOrSpread ;
853
892
enclosingFunctionFlags = getFunctionFlags ( node ) ;
893
+ recordParameterHasPrecedingObjectRestOrSpread ( node ) ;
854
894
const updated = factory . updateMethodDeclaration (
855
895
node ,
856
896
/*decorators*/ undefined ,
@@ -863,19 +903,22 @@ namespace ts {
863
903
visitNode ( node . name , visitor , isPropertyName ) ,
864
904
visitNode < Token < SyntaxKind . QuestionToken > > ( /*questionToken*/ undefined , visitor , isToken ) ,
865
905
/*typeParameters*/ undefined ,
866
- visitParameterList ( node . parameters , visitor , context ) ,
906
+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
867
907
/*type*/ undefined ,
868
908
enclosingFunctionFlags & FunctionFlags . Async && enclosingFunctionFlags & FunctionFlags . Generator
869
909
? transformAsyncGeneratorFunctionBody ( node )
870
910
: transformFunctionBody ( node )
871
911
) ;
872
912
enclosingFunctionFlags = savedEnclosingFunctionFlags ;
913
+ parameterHasPrecedingObjectRestOrSpread = savedParameterHasPrecedingObjectRestOrSpread ;
873
914
return updated ;
874
915
}
875
916
876
917
function visitFunctionDeclaration ( node : FunctionDeclaration ) {
877
918
const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
919
+ const savedParameterHasPrecedingObjectRestOrSpread = parameterHasPrecedingObjectRestOrSpread ;
878
920
enclosingFunctionFlags = getFunctionFlags ( node ) ;
921
+ recordParameterHasPrecedingObjectRestOrSpread ( node ) ;
879
922
const updated = factory . updateFunctionDeclaration (
880
923
node ,
881
924
/*decorators*/ undefined ,
@@ -887,35 +930,41 @@ namespace ts {
887
930
: node . asteriskToken ,
888
931
node . name ,
889
932
/*typeParameters*/ undefined ,
890
- visitParameterList ( node . parameters , visitor , context ) ,
933
+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
891
934
/*type*/ undefined ,
892
935
enclosingFunctionFlags & FunctionFlags . Async && enclosingFunctionFlags & FunctionFlags . Generator
893
936
? transformAsyncGeneratorFunctionBody ( node )
894
937
: transformFunctionBody ( node )
895
938
) ;
896
939
enclosingFunctionFlags = savedEnclosingFunctionFlags ;
940
+ parameterHasPrecedingObjectRestOrSpread = savedParameterHasPrecedingObjectRestOrSpread ;
897
941
return updated ;
898
942
}
899
943
900
944
function visitArrowFunction ( node : ArrowFunction ) {
901
945
const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
946
+ const savedParameterHasPrecedingObjectRestOrSpread = parameterHasPrecedingObjectRestOrSpread ;
902
947
enclosingFunctionFlags = getFunctionFlags ( node ) ;
948
+ recordParameterHasPrecedingObjectRestOrSpread ( node ) ;
903
949
const updated = factory . updateArrowFunction (
904
950
node ,
905
951
node . modifiers ,
906
952
/*typeParameters*/ undefined ,
907
- visitParameterList ( node . parameters , visitor , context ) ,
953
+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
908
954
/*type*/ undefined ,
909
955
node . equalsGreaterThanToken ,
910
956
transformFunctionBody ( node ) ,
911
957
) ;
912
958
enclosingFunctionFlags = savedEnclosingFunctionFlags ;
959
+ parameterHasPrecedingObjectRestOrSpread = savedParameterHasPrecedingObjectRestOrSpread ;
913
960
return updated ;
914
961
}
915
962
916
963
function visitFunctionExpression ( node : FunctionExpression ) {
917
964
const savedEnclosingFunctionFlags = enclosingFunctionFlags ;
965
+ const savedParameterHasPrecedingObjectRestOrSpread = parameterHasPrecedingObjectRestOrSpread ;
918
966
enclosingFunctionFlags = getFunctionFlags ( node ) ;
967
+ recordParameterHasPrecedingObjectRestOrSpread ( node ) ;
919
968
const updated = factory . updateFunctionExpression (
920
969
node ,
921
970
enclosingFunctionFlags & FunctionFlags . Generator
@@ -926,13 +975,14 @@ namespace ts {
926
975
: node . asteriskToken ,
927
976
node . name ,
928
977
/*typeParameters*/ undefined ,
929
- visitParameterList ( node . parameters , visitor , context ) ,
978
+ visitParameterList ( node . parameters , parameterVisitor , context ) ,
930
979
/*type*/ undefined ,
931
980
enclosingFunctionFlags & FunctionFlags . Async && enclosingFunctionFlags & FunctionFlags . Generator
932
981
? transformAsyncGeneratorFunctionBody ( node )
933
982
: transformFunctionBody ( node )
934
983
) ;
935
984
enclosingFunctionFlags = savedEnclosingFunctionFlags ;
985
+ parameterHasPrecedingObjectRestOrSpread = savedParameterHasPrecedingObjectRestOrSpread ;
936
986
return updated ;
937
987
}
938
988
@@ -1007,6 +1057,7 @@ namespace ts {
1007
1057
statementOffset = factory . copyPrologue ( body . statements , statements , /*ensureUseStrict*/ false , visitor ) ;
1008
1058
}
1009
1059
addRange ( statements , appendObjectRestAssignmentsIfNeeded ( /*statements*/ undefined , node ) ) ;
1060
+
1010
1061
const leadingStatements = endLexicalEnvironment ( ) ;
1011
1062
if ( statementOffset > 0 || some ( statements ) || some ( leadingStatements ) ) {
1012
1063
const block = factory . converters . convertToFunctionBlock ( body , /*multiLine*/ true ) ;
@@ -1018,25 +1069,76 @@ namespace ts {
1018
1069
}
1019
1070
1020
1071
function appendObjectRestAssignmentsIfNeeded ( statements : Statement [ ] | undefined , node : FunctionLikeDeclaration ) : Statement [ ] | undefined {
1072
+ let containsPrecedingObjectRestOrSpread = false ;
1021
1073
for ( const parameter of node . parameters ) {
1022
- if ( parameter . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
1023
- const temp = factory . getGeneratedNameForNode ( parameter ) ;
1074
+ if ( containsPrecedingObjectRestOrSpread ) {
1075
+ if ( isBindingPattern ( parameter . name ) ) {
1076
+ // In cases where a binding pattern is simply '[]' or '{}',
1077
+ // we usually don't want to emit a var declaration; however, in the presence
1078
+ // of an initializer, we must emit that expression to preserve side effects.
1079
+ //
1080
+ // NOTE: see `insertDefaultValueAssignmentForBindingPattern` in es2015.ts
1081
+ if ( parameter . name . elements . length > 0 ) {
1082
+ const declarations = flattenDestructuringBinding (
1083
+ parameter ,
1084
+ visitor ,
1085
+ context ,
1086
+ FlattenLevel . All ,
1087
+ factory . getGeneratedNameForNode ( parameter ) ) ;
1088
+ if ( some ( declarations ) ) {
1089
+ const declarationList = factory . createVariableDeclarationList ( declarations ) ;
1090
+ const statement = factory . createVariableStatement ( /*modifiers*/ undefined , declarationList ) ;
1091
+ setEmitFlags ( statement , EmitFlags . CustomPrologue ) ;
1092
+ statements = append ( statements , statement ) ;
1093
+ }
1094
+ }
1095
+ else if ( parameter . initializer ) {
1096
+ const name = factory . getGeneratedNameForNode ( parameter ) ;
1097
+ const initializer = visitNode ( parameter . initializer , visitor , isExpression ) ;
1098
+ const assignment = factory . createAssignment ( name , initializer ) ;
1099
+ const statement = factory . createExpressionStatement ( assignment ) ;
1100
+ setEmitFlags ( statement , EmitFlags . CustomPrologue ) ;
1101
+ statements = append ( statements , statement ) ;
1102
+ }
1103
+ }
1104
+ else if ( parameter . initializer ) {
1105
+ const name = factory . cloneNode ( parameter . name ) ;
1106
+ setTextRange ( name , parameter . name ) ;
1107
+ setEmitFlags ( name , EmitFlags . NoSourceMap ) ;
1108
+
1109
+ const initializer = visitNode ( parameter . initializer , visitor , isExpression ) ;
1110
+ addEmitFlags ( initializer , EmitFlags . NoSourceMap | EmitFlags . NoComments ) ;
1111
+
1112
+ const assignment = factory . createAssignment ( name , initializer ) ;
1113
+ setTextRange ( assignment , parameter ) ;
1114
+ setEmitFlags ( assignment , EmitFlags . NoComments ) ;
1115
+
1116
+ const block = factory . createBlock ( [ factory . createExpressionStatement ( assignment ) ] ) ;
1117
+ setTextRange ( block , parameter ) ;
1118
+ setEmitFlags ( block , EmitFlags . SingleLine | EmitFlags . NoTrailingSourceMap | EmitFlags . NoTokenSourceMaps | EmitFlags . NoComments ) ;
1119
+
1120
+ const typeCheck = factory . createTypeCheck ( factory . cloneNode ( parameter . name ) , "undefined" ) ;
1121
+ const statement = factory . createIfStatement ( typeCheck , block ) ;
1122
+ startOnNewLine ( statement ) ;
1123
+ setTextRange ( statement , parameter ) ;
1124
+ setEmitFlags ( statement , EmitFlags . NoTokenSourceMaps | EmitFlags . NoTrailingSourceMap | EmitFlags . CustomPrologue | EmitFlags . NoComments ) ;
1125
+ statements = append ( statements , statement ) ;
1126
+ }
1127
+ }
1128
+ else if ( parameter . transformFlags & TransformFlags . ContainsObjectRestOrSpread ) {
1129
+ containsPrecedingObjectRestOrSpread = true ;
1024
1130
const declarations = flattenDestructuringBinding (
1025
1131
parameter ,
1026
1132
visitor ,
1027
1133
context ,
1028
1134
FlattenLevel . ObjectRest ,
1029
- temp ,
1135
+ factory . getGeneratedNameForNode ( parameter ) ,
1030
1136
/*doNotRecordTempVariablesInLine*/ false ,
1031
1137
/*skipInitializer*/ true ,
1032
1138
) ;
1033
1139
if ( some ( declarations ) ) {
1034
- const statement = factory . createVariableStatement (
1035
- /*modifiers*/ undefined ,
1036
- factory . createVariableDeclarationList (
1037
- declarations
1038
- )
1039
- ) ;
1140
+ const declarationList = factory . createVariableDeclarationList ( declarations ) ;
1141
+ const statement = factory . createVariableStatement ( /*modifiers*/ undefined , declarationList ) ;
1040
1142
setEmitFlags ( statement , EmitFlags . CustomPrologue ) ;
1041
1143
statements = append ( statements , statement ) ;
1042
1144
}
0 commit comments