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