@@ -3056,6 +3056,351 @@ namespace ts {
3056
3056
return tryGetModuleNameFromFile ( resolver . getExternalModuleFileFromDeclaration ( declaration ) , host , compilerOptions ) ;
3057
3057
}
3058
3058
3059
+ /**
3060
+ * Transforms the body of a function-like node.
3061
+ *
3062
+ * @param node A function-like node.
3063
+ */
3064
+ export function transformFunctionBody ( node : FunctionLikeDeclaration ,
3065
+ visitor : ( node : Node ) => VisitResult < Node > ,
3066
+ currentSourceFile : SourceFile ,
3067
+ context : TransformationContext ,
3068
+ enableSubstitutionsForCapturedThis : ( ) => void ,
3069
+ convertObjectRest ?: boolean ) {
3070
+ let multiLine = false ; // indicates whether the block *must* be emitted as multiple lines
3071
+ let singleLine = false ; // indicates whether the block *may* be emitted as a single line
3072
+ let statementsLocation : TextRange ;
3073
+ let closeBraceLocation : TextRange ;
3074
+
3075
+ const statements : Statement [ ] = [ ] ;
3076
+ const body = node . body ;
3077
+ let statementOffset : number ;
3078
+
3079
+ context . startLexicalEnvironment ( ) ;
3080
+ if ( isBlock ( body ) ) {
3081
+ // ensureUseStrict is false because no new prologue-directive should be added.
3082
+ // addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array
3083
+ statementOffset = addPrologueDirectives ( statements , body . statements , /*ensureUseStrict*/ false , visitor ) ;
3084
+ }
3085
+
3086
+ addCaptureThisForNodeIfNeeded ( statements , node , enableSubstitutionsForCapturedThis ) ;
3087
+ addDefaultValueAssignmentsIfNeeded ( statements , node , visitor , convertObjectRest ) ;
3088
+ addRestParameterIfNeeded ( statements , node , /*inConstructorWithSynthesizedSuper*/ false ) ;
3089
+
3090
+ // If we added any generated statements, this must be a multi-line block.
3091
+ if ( ! multiLine && statements . length > 0 ) {
3092
+ multiLine = true ;
3093
+ }
3094
+
3095
+ if ( isBlock ( body ) ) {
3096
+ statementsLocation = body . statements ;
3097
+ addRange ( statements , visitNodes ( body . statements , visitor , isStatement , statementOffset ) ) ;
3098
+
3099
+ // If the original body was a multi-line block, this must be a multi-line block.
3100
+ if ( ! multiLine && body . multiLine ) {
3101
+ multiLine = true ;
3102
+ }
3103
+ }
3104
+ else {
3105
+ Debug . assert ( node . kind === SyntaxKind . ArrowFunction ) ;
3106
+
3107
+ // To align with the old emitter, we use a synthetic end position on the location
3108
+ // for the statement list we synthesize when we down-level an arrow function with
3109
+ // an expression function body. This prevents both comments and source maps from
3110
+ // being emitted for the end position only.
3111
+ statementsLocation = moveRangeEnd ( body , - 1 ) ;
3112
+
3113
+ const equalsGreaterThanToken = ( < ArrowFunction > node ) . equalsGreaterThanToken ;
3114
+ if ( ! nodeIsSynthesized ( equalsGreaterThanToken ) && ! nodeIsSynthesized ( body ) ) {
3115
+ if ( rangeEndIsOnSameLineAsRangeStart ( equalsGreaterThanToken , body , currentSourceFile ) ) {
3116
+ singleLine = true ;
3117
+ }
3118
+ else {
3119
+ multiLine = true ;
3120
+ }
3121
+ }
3122
+
3123
+ const expression = visitNode ( body , visitor , isExpression ) ;
3124
+ const returnStatement = createReturn ( expression , /*location*/ body ) ;
3125
+ setEmitFlags ( returnStatement , EmitFlags . NoTokenSourceMaps | EmitFlags . NoTrailingSourceMap | EmitFlags . NoTrailingComments ) ;
3126
+ statements . push ( returnStatement ) ;
3127
+
3128
+ // To align with the source map emit for the old emitter, we set a custom
3129
+ // source map location for the close brace.
3130
+ closeBraceLocation = body ;
3131
+ }
3132
+
3133
+ const lexicalEnvironment = context . endLexicalEnvironment ( ) ;
3134
+ addRange ( statements , lexicalEnvironment ) ;
3135
+
3136
+ // If we added any final generated statements, this must be a multi-line block
3137
+ if ( ! multiLine && lexicalEnvironment && lexicalEnvironment . length ) {
3138
+ multiLine = true ;
3139
+ }
3140
+
3141
+ const block = createBlock ( createNodeArray ( statements , statementsLocation ) , node . body , multiLine ) ;
3142
+ if ( ! multiLine && singleLine ) {
3143
+ setEmitFlags ( block , EmitFlags . SingleLine ) ;
3144
+ }
3145
+
3146
+ if ( closeBraceLocation ) {
3147
+ setTokenSourceMapRange ( block , SyntaxKind . CloseBraceToken , closeBraceLocation ) ;
3148
+ }
3149
+
3150
+ setOriginalNode ( block , node . body ) ;
3151
+ return block ;
3152
+ }
3153
+
3154
+ /**
3155
+ * Adds a statement to capture the `this` of a function declaration if it is needed.
3156
+ *
3157
+ * @param statements The statements for the new function body.
3158
+ * @param node A node.
3159
+ */
3160
+ export function addCaptureThisForNodeIfNeeded ( statements : Statement [ ] , node : Node , enableSubstitutionsForCapturedThis : ( ) => void ) : void {
3161
+ if ( node . transformFlags & TransformFlags . ContainsCapturedLexicalThis && node . kind !== SyntaxKind . ArrowFunction ) {
3162
+ captureThisForNode ( statements , node , createThis ( ) , enableSubstitutionsForCapturedThis ) ;
3163
+ }
3164
+ }
3165
+
3166
+ export function captureThisForNode ( statements : Statement [ ] , node : Node , initializer : Expression | undefined , enableSubstitutionsForCapturedThis ?: ( ) => void , originalStatement ?: Statement ) : void {
3167
+ enableSubstitutionsForCapturedThis ( ) ;
3168
+ const captureThisStatement = createVariableStatement (
3169
+ /*modifiers*/ undefined ,
3170
+ createVariableDeclarationList ( [
3171
+ createVariableDeclaration (
3172
+ "_this" ,
3173
+ /*type*/ undefined ,
3174
+ initializer
3175
+ )
3176
+ ] ) ,
3177
+ originalStatement
3178
+ ) ;
3179
+
3180
+ setEmitFlags ( captureThisStatement , EmitFlags . NoComments | EmitFlags . CustomPrologue ) ;
3181
+ setSourceMapRange ( captureThisStatement , node ) ;
3182
+ statements . push ( captureThisStatement ) ;
3183
+ }
3184
+
3185
+ /**
3186
+ * Gets a value indicating whether we need to add default value assignments for a
3187
+ * function-like node.
3188
+ *
3189
+ * @param node A function-like node.
3190
+ */
3191
+ function shouldAddDefaultValueAssignments ( node : FunctionLikeDeclaration ) : boolean {
3192
+ return ( node . transformFlags & TransformFlags . ContainsDefaultValueAssignments ) !== 0 ;
3193
+ }
3194
+
3195
+ /**
3196
+ * Adds statements to the body of a function-like node if it contains parameters with
3197
+ * binding patterns or initializers.
3198
+ *
3199
+ * @param statements The statements for the new function body.
3200
+ * @param node A function-like node.
3201
+ */
3202
+ export function addDefaultValueAssignmentsIfNeeded ( statements : Statement [ ] ,
3203
+ node : FunctionLikeDeclaration ,
3204
+ visitor : ( node : Node ) => VisitResult < Node > ,
3205
+ convertObjectRest : boolean ) : void {
3206
+ if ( ! shouldAddDefaultValueAssignments ( node ) ) {
3207
+ return ;
3208
+ }
3209
+
3210
+ for ( const parameter of node . parameters ) {
3211
+ const { name, initializer, dotDotDotToken } = parameter ;
3212
+
3213
+ // A rest parameter cannot have a binding pattern or an initializer,
3214
+ // so let's just ignore it.
3215
+ if ( dotDotDotToken ) {
3216
+ continue ;
3217
+ }
3218
+
3219
+ if ( isBindingPattern ( name ) ) {
3220
+ addDefaultValueAssignmentForBindingPattern ( statements , parameter , name , initializer , visitor , convertObjectRest ) ;
3221
+ }
3222
+ else if ( initializer ) {
3223
+ addDefaultValueAssignmentForInitializer ( statements , parameter , name , initializer , visitor ) ;
3224
+ }
3225
+ }
3226
+ }
3227
+
3228
+ /**
3229
+ * Adds statements to the body of a function-like node for parameters with binding patterns
3230
+ *
3231
+ * @param statements The statements for the new function body.
3232
+ * @param parameter The parameter for the function.
3233
+ * @param name The name of the parameter.
3234
+ * @param initializer The initializer for the parameter.
3235
+ */
3236
+ function addDefaultValueAssignmentForBindingPattern ( statements : Statement [ ] ,
3237
+ parameter : ParameterDeclaration ,
3238
+ name : BindingPattern , initializer : Expression ,
3239
+ visitor : ( node : Node ) => VisitResult < Node > ,
3240
+ convertObjectRest : boolean ) : void {
3241
+ const temp = getGeneratedNameForNode ( parameter ) ;
3242
+
3243
+ // In cases where a binding pattern is simply '[]' or '{}',
3244
+ // we usually don't want to emit a var declaration; however, in the presence
3245
+ // of an initializer, we must emit that expression to preserve side effects.
3246
+ if ( name . elements . length > 0 ) {
3247
+ statements . push (
3248
+ setEmitFlags (
3249
+ createVariableStatement (
3250
+ /*modifiers*/ undefined ,
3251
+ createVariableDeclarationList (
3252
+ flattenParameterDestructuring ( parameter , temp , visitor , convertObjectRest )
3253
+ )
3254
+ ) ,
3255
+ EmitFlags . CustomPrologue
3256
+ )
3257
+ ) ;
3258
+ }
3259
+ else if ( initializer ) {
3260
+ statements . push (
3261
+ setEmitFlags (
3262
+ createStatement (
3263
+ createAssignment (
3264
+ temp ,
3265
+ visitNode ( initializer , visitor , isExpression )
3266
+ )
3267
+ ) ,
3268
+ EmitFlags . CustomPrologue
3269
+ )
3270
+ ) ;
3271
+ }
3272
+ }
3273
+
3274
+ /**
3275
+ * Adds statements to the body of a function-like node for parameters with initializers.
3276
+ *
3277
+ * @param statements The statements for the new function body.
3278
+ * @param parameter The parameter for the function.
3279
+ * @param name The name of the parameter.
3280
+ * @param initializer The initializer for the parameter.
3281
+ */
3282
+ function addDefaultValueAssignmentForInitializer ( statements : Statement [ ] ,
3283
+ parameter : ParameterDeclaration ,
3284
+ name : Identifier ,
3285
+ initializer : Expression ,
3286
+ visitor : ( node : Node ) => VisitResult < Node > ) : void {
3287
+ initializer = visitNode ( initializer , visitor , isExpression ) ;
3288
+ const statement = createIf (
3289
+ createStrictEquality (
3290
+ getSynthesizedClone ( name ) ,
3291
+ createVoidZero ( )
3292
+ ) ,
3293
+ setEmitFlags (
3294
+ createBlock ( [
3295
+ createStatement (
3296
+ createAssignment (
3297
+ setEmitFlags ( getMutableClone ( name ) , EmitFlags . NoSourceMap ) ,
3298
+ setEmitFlags ( initializer , EmitFlags . NoSourceMap | getEmitFlags ( initializer ) ) ,
3299
+ /*location*/ parameter
3300
+ )
3301
+ )
3302
+ ] , /*location*/ parameter ) ,
3303
+ EmitFlags . SingleLine | EmitFlags . NoTrailingSourceMap | EmitFlags . NoTokenSourceMaps
3304
+ ) ,
3305
+ /*elseStatement*/ undefined ,
3306
+ /*location*/ parameter
3307
+ ) ;
3308
+ statement . startsOnNewLine = true ;
3309
+ setEmitFlags ( statement , EmitFlags . NoTokenSourceMaps | EmitFlags . NoTrailingSourceMap | EmitFlags . CustomPrologue ) ;
3310
+ statements . push ( statement ) ;
3311
+ }
3312
+
3313
+ /**
3314
+ * Gets a value indicating whether we need to add statements to handle a rest parameter.
3315
+ *
3316
+ * @param node A ParameterDeclaration node.
3317
+ * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
3318
+ * part of a constructor declaration with a
3319
+ * synthesized call to `super`
3320
+ */
3321
+ function shouldAddRestParameter ( node : ParameterDeclaration , inConstructorWithSynthesizedSuper : boolean ) {
3322
+ return node && node . dotDotDotToken && node . name . kind === SyntaxKind . Identifier && ! inConstructorWithSynthesizedSuper ;
3323
+ }
3324
+
3325
+ /**
3326
+ * Adds statements to the body of a function-like node if it contains a rest parameter.
3327
+ *
3328
+ * @param statements The statements for the new function body.
3329
+ * @param node A function-like node.
3330
+ * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
3331
+ * part of a constructor declaration with a
3332
+ * synthesized call to `super`
3333
+ */
3334
+ export function addRestParameterIfNeeded ( statements : Statement [ ] , node : FunctionLikeDeclaration , inConstructorWithSynthesizedSuper : boolean ) : void {
3335
+ const parameter = lastOrUndefined ( node . parameters ) ;
3336
+ if ( ! shouldAddRestParameter ( parameter , inConstructorWithSynthesizedSuper ) ) {
3337
+ return ;
3338
+ }
3339
+
3340
+ // `declarationName` is the name of the local declaration for the parameter.
3341
+ const declarationName = getMutableClone ( < Identifier > parameter . name ) ;
3342
+ setEmitFlags ( declarationName , EmitFlags . NoSourceMap ) ;
3343
+
3344
+ // `expressionName` is the name of the parameter used in expressions.
3345
+ const expressionName = getSynthesizedClone ( < Identifier > parameter . name ) ;
3346
+ const restIndex = node . parameters . length - 1 ;
3347
+ const temp = createLoopVariable ( ) ;
3348
+
3349
+ // var param = [];
3350
+ statements . push (
3351
+ setEmitFlags (
3352
+ createVariableStatement (
3353
+ /*modifiers*/ undefined ,
3354
+ createVariableDeclarationList ( [
3355
+ createVariableDeclaration (
3356
+ declarationName ,
3357
+ /*type*/ undefined ,
3358
+ createArrayLiteral ( [ ] )
3359
+ )
3360
+ ] ) ,
3361
+ /*location*/ parameter
3362
+ ) ,
3363
+ EmitFlags . CustomPrologue
3364
+ )
3365
+ ) ;
3366
+
3367
+ // for (var _i = restIndex; _i < arguments.length; _i++) {
3368
+ // param[_i - restIndex] = arguments[_i];
3369
+ // }
3370
+ const forStatement = createFor (
3371
+ createVariableDeclarationList ( [
3372
+ createVariableDeclaration ( temp , /*type*/ undefined , createLiteral ( restIndex ) )
3373
+ ] , /*location*/ parameter ) ,
3374
+ createLessThan (
3375
+ temp ,
3376
+ createPropertyAccess ( createIdentifier ( "arguments" ) , "length" ) ,
3377
+ /*location*/ parameter
3378
+ ) ,
3379
+ createPostfixIncrement ( temp , /*location*/ parameter ) ,
3380
+ createBlock ( [
3381
+ startOnNewLine (
3382
+ createStatement (
3383
+ createAssignment (
3384
+ createElementAccess (
3385
+ expressionName ,
3386
+ createSubtract ( temp , createLiteral ( restIndex ) )
3387
+ ) ,
3388
+ createElementAccess ( createIdentifier ( "arguments" ) , temp )
3389
+ ) ,
3390
+ /*location*/ parameter
3391
+ )
3392
+ )
3393
+ ] )
3394
+ ) ;
3395
+
3396
+ setEmitFlags ( forStatement , EmitFlags . CustomPrologue ) ;
3397
+ startOnNewLine ( forStatement ) ;
3398
+ statements . push ( forStatement ) ;
3399
+ }
3400
+
3401
+
3402
+
3403
+
3059
3404
export function convertForOf ( node : ForOfStatement , convertedLoopBodyStatements : Statement [ ] ,
3060
3405
visitor : ( node : Node ) => VisitResult < Node > ,
3061
3406
enableSubstitutionsForBlockScopedBindings : ( ) => void ,
0 commit comments