@@ -3055,4 +3055,194 @@ namespace ts {
30553055 function tryGetModuleNameFromDeclaration ( declaration : ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration , host : EmitHost , resolver : EmitResolver , compilerOptions : CompilerOptions ) {
30563056 return tryGetModuleNameFromFile ( resolver . getExternalModuleFileFromDeclaration ( declaration ) , host , compilerOptions ) ;
30573057 }
3058+
3059+ export function convertForOf ( node : ForOfStatement , convertedLoopBodyStatements : Statement [ ] ,
3060+ visitor : ( node : Node ) => VisitResult < Node > ,
3061+ enableSubstitutionsForBlockScopedBindings : ( ) => void ,
3062+ context : TransformationContext ,
3063+ convertObjectRest ?: boolean ) : ForStatement | ForOfStatement {
3064+ // The following ES6 code:
3065+ //
3066+ // for (let v of expr) { }
3067+ //
3068+ // should be emitted as
3069+ //
3070+ // for (var _i = 0, _a = expr; _i < _a.length; _i++) {
3071+ // var v = _a[_i];
3072+ // }
3073+ //
3074+ // where _a and _i are temps emitted to capture the RHS and the counter,
3075+ // respectively.
3076+ // When the left hand side is an expression instead of a let declaration,
3077+ // the "let v" is not emitted.
3078+ // When the left hand side is a let/const, the v is renamed if there is
3079+ // another v in scope.
3080+ // Note that all assignments to the LHS are emitted in the body, including
3081+ // all destructuring.
3082+ // Note also that because an extra statement is needed to assign to the LHS,
3083+ // for-of bodies are always emitted as blocks.
3084+
3085+ const expression = visitNode ( node . expression , visitor , isExpression ) ;
3086+ const initializer = node . initializer ;
3087+ const statements : Statement [ ] = [ ] ;
3088+
3089+ // In the case where the user wrote an identifier as the RHS, like this:
3090+ //
3091+ // for (let v of arr) { }
3092+ //
3093+ // we don't want to emit a temporary variable for the RHS, just use it directly.
3094+ const counter = convertObjectRest ? undefined : createLoopVariable ( ) ;
3095+ const rhsReference = expression . kind === SyntaxKind . Identifier
3096+ ? createUniqueName ( ( < Identifier > expression ) . text )
3097+ : createTempVariable ( /*recordTempVariable*/ undefined ) ;
3098+ const elementAccess = convertObjectRest ? rhsReference : createElementAccess ( rhsReference , counter ) ;
3099+
3100+ // Initialize LHS
3101+ // var v = _a[_i];
3102+ if ( isVariableDeclarationList ( initializer ) ) {
3103+ if ( initializer . flags & NodeFlags . BlockScoped ) {
3104+ enableSubstitutionsForBlockScopedBindings ( ) ;
3105+ }
3106+
3107+ const firstOriginalDeclaration = firstOrUndefined ( initializer . declarations ) ;
3108+ if ( firstOriginalDeclaration && isBindingPattern ( firstOriginalDeclaration . name ) ) {
3109+ // This works whether the declaration is a var, let, or const.
3110+ // It will use rhsIterationValue _a[_i] as the initializer.
3111+ const declarations = flattenVariableDestructuring (
3112+ firstOriginalDeclaration ,
3113+ elementAccess ,
3114+ visitor ,
3115+ /*recordTempVariable*/ undefined ,
3116+ convertObjectRest
3117+ ) ;
3118+
3119+ const declarationList = createVariableDeclarationList ( declarations , /*location*/ initializer ) ;
3120+ setOriginalNode ( declarationList , initializer ) ;
3121+
3122+ // Adjust the source map range for the first declaration to align with the old
3123+ // emitter.
3124+ const firstDeclaration = declarations [ 0 ] ;
3125+ const lastDeclaration = lastOrUndefined ( declarations ) ;
3126+ setSourceMapRange ( declarationList , createRange ( firstDeclaration . pos , lastDeclaration . end ) ) ;
3127+
3128+ statements . push (
3129+ createVariableStatement (
3130+ /*modifiers*/ undefined ,
3131+ declarationList
3132+ )
3133+ ) ;
3134+ }
3135+ else {
3136+ // The following call does not include the initializer, so we have
3137+ // to emit it separately.
3138+ statements . push (
3139+ createVariableStatement (
3140+ /*modifiers*/ undefined ,
3141+ setOriginalNode (
3142+ createVariableDeclarationList ( [
3143+ createVariableDeclaration (
3144+ firstOriginalDeclaration ? firstOriginalDeclaration . name : createTempVariable ( /*recordTempVariable*/ undefined ) ,
3145+ /*type*/ undefined ,
3146+ createElementAccess ( rhsReference , counter )
3147+ )
3148+ ] , /*location*/ moveRangePos ( initializer , - 1 ) ) ,
3149+ initializer
3150+ ) ,
3151+ /*location*/ moveRangeEnd ( initializer , - 1 )
3152+ )
3153+ ) ;
3154+ }
3155+ }
3156+ else {
3157+ // Initializer is an expression. Emit the expression in the body, so that it's
3158+ // evaluated on every iteration.
3159+ const assignment = createAssignment ( initializer , elementAccess ) ;
3160+ if ( isDestructuringAssignment ( assignment ) ) {
3161+ // This is a destructuring pattern, so we flatten the destructuring instead.
3162+ statements . push (
3163+ createStatement (
3164+ flattenDestructuringAssignment (
3165+ context ,
3166+ assignment ,
3167+ /*needsValue*/ false ,
3168+ context . hoistVariableDeclaration ,
3169+ visitor ,
3170+ convertObjectRest
3171+ )
3172+ )
3173+ ) ;
3174+ }
3175+ else {
3176+ // Currently there is not way to check that assignment is binary expression of destructing assignment
3177+ // so we have to cast never type to binaryExpression
3178+ ( < BinaryExpression > assignment ) . end = initializer . end ;
3179+ statements . push ( createStatement ( assignment , /*location*/ moveRangeEnd ( initializer , - 1 ) ) ) ;
3180+ }
3181+ }
3182+
3183+ let bodyLocation : TextRange ;
3184+ let statementsLocation : TextRange ;
3185+ if ( convertedLoopBodyStatements ) {
3186+ addRange ( statements , convertedLoopBodyStatements ) ;
3187+ }
3188+ else {
3189+ const statement = visitNode ( node . statement , visitor , isStatement ) ;
3190+ if ( isBlock ( statement ) ) {
3191+ addRange ( statements , statement . statements ) ;
3192+ bodyLocation = statement ;
3193+ statementsLocation = statement . statements ;
3194+ }
3195+ else {
3196+ statements . push ( statement ) ;
3197+ }
3198+ }
3199+
3200+ // The old emitter does not emit source maps for the expression
3201+ setEmitFlags ( expression , EmitFlags . NoSourceMap | getEmitFlags ( expression ) ) ;
3202+
3203+ // The old emitter does not emit source maps for the block.
3204+ // We add the location to preserve comments.
3205+ const body = createBlock (
3206+ createNodeArray ( statements , /*location*/ statementsLocation ) ,
3207+ /*location*/ bodyLocation
3208+ ) ;
3209+
3210+ setEmitFlags ( body , EmitFlags . NoSourceMap | EmitFlags . NoTokenSourceMaps ) ;
3211+
3212+ let forStatement : ForStatement | ForOfStatement ;
3213+ if ( convertObjectRest ) {
3214+
3215+ forStatement = createForOf (
3216+ createVariableDeclarationList ( [
3217+ createVariableDeclaration ( rhsReference , /*type*/ undefined , /*initializer*/ undefined , /*location*/ node . expression )
3218+ ] , /*location*/ node . expression ) ,
3219+ node . expression ,
3220+ body ,
3221+ /*location*/ node
3222+ ) ;
3223+ }
3224+ else {
3225+ forStatement = createFor (
3226+ setEmitFlags (
3227+ createVariableDeclarationList ( [
3228+ createVariableDeclaration ( counter , /*type*/ undefined , createLiteral ( 0 ) , /*location*/ moveRangePos ( node . expression , - 1 ) ) ,
3229+ createVariableDeclaration ( rhsReference , /*type*/ undefined , expression , /*location*/ node . expression )
3230+ ] , /*location*/ node . expression ) ,
3231+ EmitFlags . NoHoisting
3232+ ) ,
3233+ createLessThan (
3234+ counter ,
3235+ createPropertyAccess ( rhsReference , "length" ) ,
3236+ /*location*/ node . expression
3237+ ) ,
3238+ createPostfixIncrement ( counter , /*location*/ node . expression ) ,
3239+ body ,
3240+ /*location*/ node
3241+ ) ;
3242+ }
3243+
3244+ // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter.
3245+ setEmitFlags ( forStatement , EmitFlags . NoTokenTrailingSourceMaps ) ;
3246+ return forStatement ;
3247+ }
30583248}
0 commit comments