@@ -3056,6 +3056,351 @@ namespace ts {
30563056 return tryGetModuleNameFromFile ( resolver . getExternalModuleFileFromDeclaration ( declaration ) , host , compilerOptions ) ;
30573057 }
30583058
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+
30593404 export function convertForOf ( node : ForOfStatement , convertedLoopBodyStatements : Statement [ ] ,
30603405 visitor : ( node : Node ) => VisitResult < Node > ,
30613406 enableSubstitutionsForBlockScopedBindings : ( ) => void ,
0 commit comments