• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*@internal*/
2namespace ts {
3    const enum ES2015SubstitutionFlags {
4        /** Enables substitutions for captured `this` */
5        CapturedThis = 1 << 0,
6        /** Enables substitutions for block-scoped bindings. */
7        BlockScopedBindings = 1 << 1,
8    }
9
10    /**
11     * If loop contains block scoped binding captured in some function then loop body is converted to a function.
12     * Lexical bindings declared in loop initializer will be passed into the loop body function as parameters,
13     * however if this binding is modified inside the body - this new value should be propagated back to the original binding.
14     * This is done by declaring new variable (out parameter holder) outside of the loop for every binding that is reassigned inside the body.
15     * On every iteration this variable is initialized with value of corresponding binding.
16     * At every point where control flow leaves the loop either explicitly (break/continue) or implicitly (at the end of loop body)
17     * we copy the value inside the loop to the out parameter holder.
18     *
19     * for (let x;;) {
20     *     let a = 1;
21     *     let b = () => a;
22     *     x++
23     *     if (...) break;
24     *     ...
25     * }
26     *
27     * will be converted to
28     *
29     * var out_x;
30     * var loop = function(x) {
31     *     var a = 1;
32     *     var b = function() { return a; }
33     *     x++;
34     *     if (...) return out_x = x, "break";
35     *     ...
36     *     out_x = x;
37     * }
38     * for (var x;;) {
39     *     out_x = x;
40     *     var state = loop(x);
41     *     x = out_x;
42     *     if (state === "break") break;
43     * }
44     *
45     * NOTE: values to out parameters are not copies if loop is abrupted with 'return' - in this case this will end the entire enclosing function
46     * so nobody can observe this new value.
47     */
48    interface LoopOutParameter {
49        flags: LoopOutParameterFlags;
50        originalName: Identifier;
51        outParamName: Identifier;
52    }
53
54    const enum LoopOutParameterFlags {
55        Body = 1 << 0,          // Modified in the body of the iteration statement
56        Initializer = 1 << 1,   // Set in the initializer of a ForStatement
57    }
58
59    const enum CopyDirection {
60        ToOriginal,
61        ToOutParameter
62    }
63
64    const enum Jump {
65        Break       = 1 << 1,
66        Continue    = 1 << 2,
67        Return      = 1 << 3
68    }
69
70    interface ConvertedLoopState {
71        /*
72         * set of labels that occurred inside the converted loop
73         * used to determine if labeled jump can be emitted as is or it should be dispatched to calling code
74         */
75        labels?: ESMap<string, boolean>;
76        /*
77         * collection of labeled jumps that transfer control outside the converted loop.
78         * maps store association 'label -> labelMarker' where
79         * - label - value of label as it appear in code
80         * - label marker - return value that should be interpreted by calling code as 'jump to <label>'
81         */
82        labeledNonLocalBreaks?: ESMap<string, string>;
83        labeledNonLocalContinues?: ESMap<string, string>;
84
85        /*
86         * set of non-labeled jumps that transfer control outside the converted loop
87         * used to emit dispatching logic in the caller of converted loop
88         */
89        nonLocalJumps?: Jump;
90
91        /*
92         * set of non-labeled jumps that should be interpreted as local
93         * i.e. if converted loop contains normal loop or switch statement then inside this loop break should be treated as local jump
94         */
95        allowedNonLabeledJumps?: Jump;
96
97        /*
98         * alias for 'arguments' object from the calling code stack frame
99         * i.e.
100         * for (let x;;) <statement that captures x in closure and uses 'arguments'>
101         * should be converted to
102         * var loop = function(x) { <code where 'arguments' is replaced with 'arguments_1'> }
103         * var arguments_1 = arguments
104         * for (var x;;) loop(x);
105         * otherwise semantics of the code will be different since 'arguments' inside converted loop body
106         * will refer to function that holds converted loop.
107         * This value is set on demand.
108         */
109        argumentsName?: Identifier;
110
111        /*
112         * alias for 'this' from the calling code stack frame in case if this was used inside the converted loop
113         */
114        thisName?: Identifier;
115
116        /*
117         * set to true if node contains lexical 'this' so we can mark function that wraps convered loop body as 'CapturedThis' for subsequent substitution.
118         */
119        containsLexicalThis?: boolean;
120
121        /*
122         * list of non-block scoped variable declarations that appear inside converted loop
123         * such variable declarations should be moved outside the loop body
124         * for (let x;;) {
125         *     var y = 1;
126         *     ...
127         * }
128         * should be converted to
129         * var loop = function(x) {
130         *    y = 1;
131         *    ...
132         * }
133         * var y;
134         * for (var x;;) loop(x);
135         */
136        hoistedLocalVariables?: Identifier[];
137
138        conditionVariable?: Identifier;
139
140        loopParameters: ParameterDeclaration[];
141
142        /**
143         * List of loop out parameters - detailed descripion can be found in the comment to LoopOutParameter
144         */
145        loopOutParameters: LoopOutParameter[];
146    }
147
148    type LoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement;
149
150    // Facts we track as we traverse the tree
151    const enum HierarchyFacts {
152        None = 0,
153
154        //
155        // Ancestor facts
156        //
157
158        Function = 1 << 0,                      // Enclosed in a non-arrow function
159        ArrowFunction = 1 << 1,                 // Enclosed in an arrow function
160        AsyncFunctionBody = 1 << 2,             // Enclosed in an async function body
161        NonStaticClassElement = 1 << 3,         // Enclosed in a non-static, non-async class element
162        CapturesThis = 1 << 4,                  // Enclosed in a function that captures the lexical 'this' (used in substitution)
163        ExportedVariableStatement = 1 << 5,     // Enclosed in an exported variable statement in the current scope
164        TopLevel = 1 << 6,                      // Enclosing block-scoped container is a top-level container
165        Block = 1 << 7,                         // Enclosing block-scoped container is a Block
166        IterationStatement = 1 << 8,            // Immediately enclosed in an IterationStatement
167        IterationStatementBlock = 1 << 9,       // Enclosing Block is enclosed in an IterationStatement
168        IterationContainer = 1 << 10,           // Enclosed in an outer IterationStatement
169        ForStatement = 1 << 11,                 // Enclosing block-scoped container is a ForStatement
170        ForInOrForOfStatement = 1 << 12,        // Enclosing block-scoped container is a ForInStatement or ForOfStatement
171        ConstructorWithCapturedSuper = 1 << 13, // Enclosed in a constructor that captures 'this' for use with 'super'
172        // NOTE: do not add more ancestor flags without also updating AncestorFactsMask below.
173        // NOTE: when adding a new ancestor flag, be sure to update the subtree flags below.
174
175        //
176        // Ancestor masks
177        //
178
179        AncestorFactsMask = (ConstructorWithCapturedSuper << 1) - 1,
180
181        // We are always in *some* kind of block scope, but only specific block-scope containers are
182        // top-level or Blocks.
183        BlockScopeIncludes = None,
184        BlockScopeExcludes = TopLevel | Block | IterationStatement | IterationStatementBlock | ForStatement | ForInOrForOfStatement,
185
186        // A source file is a top-level block scope.
187        SourceFileIncludes = TopLevel,
188        SourceFileExcludes = BlockScopeExcludes & ~TopLevel | IterationContainer,
189
190        // Functions, methods, and accessors are both new lexical scopes and new block scopes.
191        FunctionIncludes = Function | TopLevel,
192        FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis | NonStaticClassElement | ConstructorWithCapturedSuper | IterationContainer,
193
194        AsyncFunctionBodyIncludes = FunctionIncludes | AsyncFunctionBody,
195        AsyncFunctionBodyExcludes = FunctionExcludes & ~NonStaticClassElement,
196
197        // Arrow functions are lexically scoped to their container, but are new block scopes.
198        ArrowFunctionIncludes = ArrowFunction | TopLevel,
199        ArrowFunctionExcludes = BlockScopeExcludes & ~TopLevel | ConstructorWithCapturedSuper,
200
201        // Constructors are both new lexical scopes and new block scopes. Constructors are also
202        // always considered non-static members of a class.
203        ConstructorIncludes = FunctionIncludes | NonStaticClassElement,
204        ConstructorExcludes = FunctionExcludes & ~NonStaticClassElement,
205
206        // 'do' and 'while' statements are not block scopes. We track that the subtree is contained
207        // within an IterationStatement to indicate whether the embedded statement is an
208        // IterationStatementBlock.
209        DoOrWhileStatementIncludes = IterationStatement | IterationContainer,
210        DoOrWhileStatementExcludes = None,
211
212        // 'for' statements are new block scopes and have special handling for 'let' declarations.
213        ForStatementIncludes = IterationStatement | ForStatement | IterationContainer,
214        ForStatementExcludes = BlockScopeExcludes & ~ForStatement,
215
216        // 'for-in' and 'for-of' statements are new block scopes and have special handling for
217        // 'let' declarations.
218        ForInOrForOfStatementIncludes = IterationStatement | ForInOrForOfStatement | IterationContainer,
219        ForInOrForOfStatementExcludes = BlockScopeExcludes & ~ForInOrForOfStatement,
220
221        // Blocks (other than function bodies) are new block scopes.
222        BlockIncludes = Block,
223        BlockExcludes = BlockScopeExcludes & ~Block,
224
225        IterationStatementBlockIncludes = IterationStatementBlock,
226        IterationStatementBlockExcludes = BlockScopeExcludes,
227
228        //
229        // Subtree facts
230        //
231
232        NewTarget = 1 << 14,                            // Contains a 'new.target' meta-property
233        CapturedLexicalThis = 1 << 15,                  // Contains a lexical `this` reference captured by an arrow function.
234
235        //
236        // Subtree masks
237        //
238
239        SubtreeFactsMask = ~AncestorFactsMask,
240
241        ArrowFunctionSubtreeExcludes = None,
242        FunctionSubtreeExcludes = NewTarget | CapturedLexicalThis,
243    }
244
245    export function transformES2015(context: TransformationContext) {
246        const {
247            factory,
248            getEmitHelperFactory: emitHelpers,
249            startLexicalEnvironment,
250            resumeLexicalEnvironment,
251            endLexicalEnvironment,
252            hoistVariableDeclaration,
253        } = context;
254
255        const compilerOptions = context.getCompilerOptions();
256        const resolver = context.getEmitResolver();
257        const previousOnSubstituteNode = context.onSubstituteNode;
258        const previousOnEmitNode = context.onEmitNode;
259        context.onEmitNode = onEmitNode;
260        context.onSubstituteNode = onSubstituteNode;
261
262        let currentSourceFile: SourceFile;
263        let currentText: string;
264        let hierarchyFacts: HierarchyFacts;
265        let taggedTemplateStringDeclarations: VariableDeclaration[];
266
267        function recordTaggedTemplateString(temp: Identifier) {
268            taggedTemplateStringDeclarations = append(
269                taggedTemplateStringDeclarations,
270                factory.createVariableDeclaration(temp));
271        }
272
273        /**
274         * Used to track if we are emitting body of the converted loop
275         */
276        let convertedLoopState: ConvertedLoopState | undefined;
277
278        /**
279         * Keeps track of whether substitutions have been enabled for specific cases.
280         * They are persisted between each SourceFile transformation and should not
281         * be reset.
282         */
283        let enabledSubstitutions: ES2015SubstitutionFlags;
284
285        return chainBundle(context, transformSourceFile);
286
287        function transformSourceFile(node: SourceFile) {
288            if (node.isDeclarationFile) {
289                return node;
290            }
291
292            currentSourceFile = node;
293            currentText = node.text;
294
295            const visited = visitSourceFile(node);
296            addEmitHelpers(visited, context.readEmitHelpers());
297
298            currentSourceFile = undefined!;
299            currentText = undefined!;
300            taggedTemplateStringDeclarations = undefined!;
301            hierarchyFacts = HierarchyFacts.None;
302            return visited;
303        }
304
305        /**
306         * Sets the `HierarchyFacts` for this node prior to visiting this node's subtree, returning the facts set prior to modification.
307         * @param excludeFacts The existing `HierarchyFacts` to reset before visiting the subtree.
308         * @param includeFacts The new `HierarchyFacts` to set before visiting the subtree.
309         */
310        function enterSubtree(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) {
311            const ancestorFacts = hierarchyFacts;
312            hierarchyFacts = (hierarchyFacts & ~excludeFacts | includeFacts) & HierarchyFacts.AncestorFactsMask;
313            return ancestorFacts;
314        }
315
316        /**
317         * Restores the `HierarchyFacts` for this node's ancestor after visiting this node's
318         * subtree, propagating specific facts from the subtree.
319         * @param ancestorFacts The `HierarchyFacts` of the ancestor to restore after visiting the subtree.
320         * @param excludeFacts The existing `HierarchyFacts` of the subtree that should not be propagated.
321         * @param includeFacts The new `HierarchyFacts` of the subtree that should be propagated.
322         */
323        function exitSubtree(ancestorFacts: HierarchyFacts, excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) {
324            hierarchyFacts = (hierarchyFacts & ~excludeFacts | includeFacts) & HierarchyFacts.SubtreeFactsMask | ancestorFacts;
325        }
326
327        function isReturnVoidStatementInConstructorWithCapturedSuper(node: Node): boolean {
328            return (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper) !== 0
329                && node.kind === SyntaxKind.ReturnStatement
330                && !(<ReturnStatement>node).expression;
331        }
332
333        function isOrMayContainReturnCompletion(node: Node) {
334            return node.transformFlags & TransformFlags.ContainsHoistedDeclarationOrCompletion
335                && (isReturnStatement(node)
336                    || isIfStatement(node)
337                    || isWithStatement(node)
338                    || isSwitchStatement(node)
339                    || isCaseBlock(node)
340                    || isCaseClause(node)
341                    || isDefaultClause(node)
342                    || isTryStatement(node)
343                    || isCatchClause(node)
344                    || isLabeledStatement(node)
345                    || isIterationStatement(node, /*lookInLabeledStatements*/ false)
346                    || isBlock(node));
347        }
348
349        function shouldVisitNode(node: Node): boolean {
350            return (node.transformFlags & TransformFlags.ContainsES2015) !== 0
351                || convertedLoopState !== undefined
352                || (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && isOrMayContainReturnCompletion(node))
353                || (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatement(node))
354                || (getEmitFlags(node) & EmitFlags.TypeScriptClassWrapper) !== 0;
355        }
356
357        function visitor(node: Node): VisitResult<Node> {
358            return shouldVisitNode(node) ? visitorWorker(node, /*expressionResultIsUnused*/ false) : node;
359        }
360
361        function visitorWithUnusedExpressionResult(node: Node): VisitResult<Node> {
362            return shouldVisitNode(node) ? visitorWorker(node, /*expressionResultIsUnused*/ true) : node;
363        }
364
365        function callExpressionVisitor(node: Node): VisitResult<Node> {
366            if (node.kind === SyntaxKind.SuperKeyword) {
367                return visitSuperKeyword(/*isExpressionOfCall*/ true);
368            }
369            return visitor(node);
370        }
371
372        function visitorWorker(node: Node, expressionResultIsUnused: boolean): VisitResult<Node> {
373            switch (node.kind) {
374                case SyntaxKind.StaticKeyword:
375                    return undefined; // elide static keyword
376
377                case SyntaxKind.ClassDeclaration:
378                    return visitClassDeclaration(<ClassDeclaration>node);
379
380                case SyntaxKind.ClassExpression:
381                    return visitClassExpression(<ClassExpression>node);
382
383                case SyntaxKind.Parameter:
384                    return visitParameter(<ParameterDeclaration>node);
385
386                case SyntaxKind.FunctionDeclaration:
387                    return visitFunctionDeclaration(<FunctionDeclaration>node);
388
389                case SyntaxKind.ArrowFunction:
390                    return visitArrowFunction(<ArrowFunction>node);
391
392                case SyntaxKind.FunctionExpression:
393                    return visitFunctionExpression(<FunctionExpression>node);
394
395                case SyntaxKind.VariableDeclaration:
396                    return visitVariableDeclaration(<VariableDeclaration>node);
397
398                case SyntaxKind.Identifier:
399                    return visitIdentifier(<Identifier>node);
400
401                case SyntaxKind.VariableDeclarationList:
402                    return visitVariableDeclarationList(<VariableDeclarationList>node);
403
404                case SyntaxKind.SwitchStatement:
405                    return visitSwitchStatement(<SwitchStatement>node);
406
407                case SyntaxKind.CaseBlock:
408                    return visitCaseBlock(<CaseBlock>node);
409
410                case SyntaxKind.Block:
411                    return visitBlock(<Block>node, /*isFunctionBody*/ false);
412
413                case SyntaxKind.BreakStatement:
414                case SyntaxKind.ContinueStatement:
415                    return visitBreakOrContinueStatement(<BreakOrContinueStatement>node);
416
417                case SyntaxKind.LabeledStatement:
418                    return visitLabeledStatement(<LabeledStatement>node);
419
420                case SyntaxKind.DoStatement:
421                case SyntaxKind.WhileStatement:
422                    return visitDoOrWhileStatement(<DoStatement | WhileStatement>node, /*outermostLabeledStatement*/ undefined);
423
424                case SyntaxKind.ForStatement:
425                    return visitForStatement(<ForStatement>node, /*outermostLabeledStatement*/ undefined);
426
427                case SyntaxKind.ForInStatement:
428                    return visitForInStatement(<ForInStatement>node, /*outermostLabeledStatement*/ undefined);
429
430                case SyntaxKind.ForOfStatement:
431                    return visitForOfStatement(<ForOfStatement>node, /*outermostLabeledStatement*/ undefined);
432
433                case SyntaxKind.ExpressionStatement:
434                    return visitExpressionStatement(<ExpressionStatement>node);
435
436                case SyntaxKind.ObjectLiteralExpression:
437                    return visitObjectLiteralExpression(<ObjectLiteralExpression>node);
438
439                case SyntaxKind.CatchClause:
440                    return visitCatchClause(<CatchClause>node);
441
442                case SyntaxKind.ShorthandPropertyAssignment:
443                    return visitShorthandPropertyAssignment(<ShorthandPropertyAssignment>node);
444
445                case SyntaxKind.ComputedPropertyName:
446                    return visitComputedPropertyName(<ComputedPropertyName>node);
447
448                case SyntaxKind.ArrayLiteralExpression:
449                    return visitArrayLiteralExpression(<ArrayLiteralExpression>node);
450
451                case SyntaxKind.CallExpression:
452                    return visitCallExpression(<CallExpression>node);
453
454                case SyntaxKind.NewExpression:
455                    return visitNewExpression(<NewExpression>node);
456
457                case SyntaxKind.ParenthesizedExpression:
458                    return visitParenthesizedExpression(<ParenthesizedExpression>node, expressionResultIsUnused);
459
460                case SyntaxKind.BinaryExpression:
461                    return visitBinaryExpression(<BinaryExpression>node, expressionResultIsUnused);
462
463                case SyntaxKind.CommaListExpression:
464                    return visitCommaListExpression(<CommaListExpression>node, expressionResultIsUnused);
465
466                case SyntaxKind.NoSubstitutionTemplateLiteral:
467                case SyntaxKind.TemplateHead:
468                case SyntaxKind.TemplateMiddle:
469                case SyntaxKind.TemplateTail:
470                    return visitTemplateLiteral(<LiteralExpression>node);
471
472                case SyntaxKind.StringLiteral:
473                    return visitStringLiteral(<StringLiteral>node);
474
475                case SyntaxKind.NumericLiteral:
476                    return visitNumericLiteral(<NumericLiteral>node);
477
478                case SyntaxKind.TaggedTemplateExpression:
479                    return visitTaggedTemplateExpression(<TaggedTemplateExpression>node);
480
481                case SyntaxKind.TemplateExpression:
482                    return visitTemplateExpression(<TemplateExpression>node);
483
484                case SyntaxKind.YieldExpression:
485                    return visitYieldExpression(<YieldExpression>node);
486
487                case SyntaxKind.SpreadElement:
488                    return visitSpreadElement(<SpreadElement>node);
489
490                case SyntaxKind.SuperKeyword:
491                    return visitSuperKeyword(/*isExpressionOfCall*/ false);
492
493                case SyntaxKind.ThisKeyword:
494                    return visitThisKeyword(node);
495
496                case SyntaxKind.MetaProperty:
497                    return visitMetaProperty(<MetaProperty>node);
498
499                case SyntaxKind.MethodDeclaration:
500                    return visitMethodDeclaration(<MethodDeclaration>node);
501
502                case SyntaxKind.GetAccessor:
503                case SyntaxKind.SetAccessor:
504                    return visitAccessorDeclaration(<AccessorDeclaration>node);
505
506                case SyntaxKind.VariableStatement:
507                    return visitVariableStatement(<VariableStatement>node);
508
509                case SyntaxKind.ReturnStatement:
510                    return visitReturnStatement(<ReturnStatement>node);
511
512                case SyntaxKind.VoidExpression:
513                    return visitVoidExpression(node as VoidExpression);
514
515                default:
516                    return visitEachChild(node, visitor, context);
517            }
518        }
519
520        function visitSourceFile(node: SourceFile): SourceFile {
521            const ancestorFacts = enterSubtree(HierarchyFacts.SourceFileExcludes, HierarchyFacts.SourceFileIncludes);
522            const prologue: Statement[] = [];
523            const statements: Statement[] = [];
524            startLexicalEnvironment();
525            const statementOffset = factory.copyPrologue(node.statements, prologue, /*ensureUseStrict*/ false, visitor);
526            addRange(statements, visitNodes(node.statements, visitor, isStatement, statementOffset));
527            if (taggedTemplateStringDeclarations) {
528                statements.push(
529                    factory.createVariableStatement(/*modifiers*/ undefined,
530                        factory.createVariableDeclarationList(taggedTemplateStringDeclarations)));
531            }
532            factory.mergeLexicalEnvironment(prologue, endLexicalEnvironment());
533            insertCaptureThisForNodeIfNeeded(prologue, node);
534            exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
535            return factory.updateSourceFile(
536                node,
537                setTextRange(factory.createNodeArray(concatenate(prologue, statements)), node.statements)
538            );
539        }
540
541        function visitSwitchStatement(node: SwitchStatement): SwitchStatement {
542            if (convertedLoopState !== undefined) {
543                const savedAllowedNonLabeledJumps = convertedLoopState.allowedNonLabeledJumps;
544                // for switch statement allow only non-labeled break
545                convertedLoopState.allowedNonLabeledJumps! |= Jump.Break;
546                const result = visitEachChild(node, visitor, context);
547                convertedLoopState.allowedNonLabeledJumps = savedAllowedNonLabeledJumps;
548                return result;
549            }
550            return visitEachChild(node, visitor, context);
551        }
552
553        function visitCaseBlock(node: CaseBlock): CaseBlock {
554            const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes);
555            const updated = visitEachChild(node, visitor, context);
556            exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
557            return updated;
558        }
559
560        function returnCapturedThis(node: Node): ReturnStatement {
561            return setOriginalNode(factory.createReturnStatement(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)), node);
562        }
563
564        function visitReturnStatement(node: ReturnStatement): Statement {
565            if (convertedLoopState) {
566                convertedLoopState.nonLocalJumps! |= Jump.Return;
567                if (isReturnVoidStatementInConstructorWithCapturedSuper(node)) {
568                    node = returnCapturedThis(node);
569                }
570                return factory.createReturnStatement(
571                    factory.createObjectLiteralExpression(
572                        [
573                            factory.createPropertyAssignment(
574                                factory.createIdentifier("value"),
575                                node.expression
576                                    ? visitNode(node.expression, visitor, isExpression)
577                                    : factory.createVoidZero()
578                            )
579                        ]
580                    )
581                );
582            }
583            else if (isReturnVoidStatementInConstructorWithCapturedSuper(node)) {
584                return returnCapturedThis(node);
585            }
586            return visitEachChild(node, visitor, context);
587        }
588
589        function visitThisKeyword(node: Node): Node {
590            if (hierarchyFacts & HierarchyFacts.ArrowFunction) {
591                hierarchyFacts |= HierarchyFacts.CapturedLexicalThis;
592            }
593            if (convertedLoopState) {
594                if (hierarchyFacts & HierarchyFacts.ArrowFunction) {
595                    // if the enclosing function is an ArrowFunction then we use the captured 'this' keyword.
596                    convertedLoopState.containsLexicalThis = true;
597                    return node;
598                }
599                return convertedLoopState.thisName || (convertedLoopState.thisName = factory.createUniqueName("this"));
600            }
601            return node;
602        }
603
604        function visitVoidExpression(node: VoidExpression): Expression {
605            return visitEachChild(node, visitorWithUnusedExpressionResult, context);
606        }
607
608        function visitIdentifier(node: Identifier): Identifier {
609            if (!convertedLoopState) {
610                return node;
611            }
612            if (resolver.isArgumentsLocalBinding(node)) {
613                return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = factory.createUniqueName("arguments"));
614            }
615            return node;
616        }
617
618        function visitBreakOrContinueStatement(node: BreakOrContinueStatement): Statement {
619            if (convertedLoopState) {
620                // check if we can emit break/continue as is
621                // it is possible if either
622                //   - break/continue is labeled and label is located inside the converted loop
623                //   - break/continue is non-labeled and located in non-converted loop/switch statement
624                const jump = node.kind === SyntaxKind.BreakStatement ? Jump.Break : Jump.Continue;
625                const canUseBreakOrContinue =
626                    (node.label && convertedLoopState.labels && convertedLoopState.labels.get(idText(node.label))) ||
627                    (!node.label && (convertedLoopState.allowedNonLabeledJumps! & jump));
628
629                if (!canUseBreakOrContinue) {
630                    let labelMarker: string;
631                    const label = node.label;
632                    if (!label) {
633                        if (node.kind === SyntaxKind.BreakStatement) {
634                            convertedLoopState.nonLocalJumps! |= Jump.Break;
635                            labelMarker = "break";
636                        }
637                        else {
638                            convertedLoopState.nonLocalJumps! |= Jump.Continue;
639                            // note: return value is emitted only to simplify debugging, call to converted loop body does not do any dispatching on it.
640                            labelMarker = "continue";
641                        }
642                    }
643                    else {
644                        if (node.kind === SyntaxKind.BreakStatement) {
645                            labelMarker = `break-${label.escapedText}`;
646                            setLabeledJump(convertedLoopState, /*isBreak*/ true, idText(label), labelMarker);
647                        }
648                        else {
649                            labelMarker = `continue-${label.escapedText}`;
650                            setLabeledJump(convertedLoopState, /*isBreak*/ false, idText(label), labelMarker);
651                        }
652                    }
653                    let returnExpression: Expression = factory.createStringLiteral(labelMarker);
654                    if (convertedLoopState.loopOutParameters.length) {
655                        const outParams = convertedLoopState.loopOutParameters;
656                        let expr: Expression | undefined;
657                        for (let i = 0; i < outParams.length; i++) {
658                            const copyExpr = copyOutParameter(outParams[i], CopyDirection.ToOutParameter);
659                            if (i === 0) {
660                                expr = copyExpr;
661                            }
662                            else {
663                                expr = factory.createBinaryExpression(expr!, SyntaxKind.CommaToken, copyExpr);
664                            }
665                        }
666                        returnExpression = factory.createBinaryExpression(expr!, SyntaxKind.CommaToken, returnExpression);
667                    }
668                    return factory.createReturnStatement(returnExpression);
669                }
670            }
671            return visitEachChild(node, visitor, context);
672        }
673
674        /**
675         * Visits a ClassDeclaration and transforms it into a variable statement.
676         *
677         * @param node A ClassDeclaration node.
678         */
679        function visitClassDeclaration(node: ClassDeclaration): VisitResult<Statement> {
680            // [source]
681            //      class C { }
682            //
683            // [output]
684            //      var C = (function () {
685            //          function C() {
686            //          }
687            //          return C;
688            //      }());
689
690            const variable = factory.createVariableDeclaration(
691                factory.getLocalName(node, /*allowComments*/ true),
692                /*exclamationToken*/ undefined,
693                /*type*/ undefined,
694                transformClassLikeDeclarationToExpression(node)
695            );
696
697            setOriginalNode(variable, node);
698
699            const statements: Statement[] = [];
700            const statement = factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([variable]));
701
702            setOriginalNode(statement, node);
703            setTextRange(statement, node);
704            startOnNewLine(statement);
705            statements.push(statement);
706
707            // Add an `export default` statement for default exports (for `--target es5 --module es6`)
708            if (hasSyntacticModifier(node, ModifierFlags.Export)) {
709                const exportStatement = hasSyntacticModifier(node, ModifierFlags.Default)
710                    ? factory.createExportDefault(factory.getLocalName(node))
711                    : factory.createExternalModuleExport(factory.getLocalName(node));
712
713                setOriginalNode(exportStatement, statement);
714                statements.push(exportStatement);
715            }
716
717            const emitFlags = getEmitFlags(node);
718            if ((emitFlags & EmitFlags.HasEndOfDeclarationMarker) === 0) {
719                // Add a DeclarationMarker as a marker for the end of the declaration
720                statements.push(factory.createEndOfDeclarationMarker(node));
721                setEmitFlags(statement, emitFlags | EmitFlags.HasEndOfDeclarationMarker);
722            }
723
724            return singleOrMany(statements);
725        }
726
727        /**
728         * Visits a ClassExpression and transforms it into an expression.
729         *
730         * @param node A ClassExpression node.
731         */
732        function visitClassExpression(node: ClassExpression): Expression {
733            // [source]
734            //      C = class { }
735            //
736            // [output]
737            //      C = (function () {
738            //          function class_1() {
739            //          }
740            //          return class_1;
741            //      }())
742
743            return transformClassLikeDeclarationToExpression(node);
744        }
745
746        /**
747         * Transforms a ClassExpression or ClassDeclaration into an expression.
748         *
749         * @param node A ClassExpression or ClassDeclaration node.
750         */
751        function transformClassLikeDeclarationToExpression(node: ClassExpression | ClassDeclaration): Expression {
752            // [source]
753            //      class C extends D {
754            //          constructor() {}
755            //          method() {}
756            //          get prop() {}
757            //          set prop(v) {}
758            //      }
759            //
760            // [output]
761            //      (function (_super) {
762            //          __extends(C, _super);
763            //          function C() {
764            //          }
765            //          C.prototype.method = function () {}
766            //          Object.defineProperty(C.prototype, "prop", {
767            //              get: function() {},
768            //              set: function() {},
769            //              enumerable: true,
770            //              configurable: true
771            //          });
772            //          return C;
773            //      }(D))
774
775            if (node.name) {
776                enableSubstitutionsForBlockScopedBindings();
777            }
778
779            const extendsClauseElement = getClassExtendsHeritageElement(node);
780            const classFunction = factory.createFunctionExpression(
781                /*modifiers*/ undefined,
782                /*asteriskToken*/ undefined,
783                /*name*/ undefined,
784                /*typeParameters*/ undefined,
785                extendsClauseElement ? [factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel))] : [],
786                /*type*/ undefined,
787                transformClassBody(node, extendsClauseElement)
788            );
789
790            // To preserve the behavior of the old emitter, we explicitly indent
791            // the body of the function here if it was requested in an earlier
792            // transformation.
793            setEmitFlags(classFunction, (getEmitFlags(node) & EmitFlags.Indented) | EmitFlags.ReuseTempVariableScope);
794
795            // "inner" and "outer" below are added purely to preserve source map locations from
796            // the old emitter
797            const inner = factory.createPartiallyEmittedExpression(classFunction);
798            setTextRangeEnd(inner, node.end);
799            setEmitFlags(inner, EmitFlags.NoComments);
800
801            const outer = factory.createPartiallyEmittedExpression(inner);
802            setTextRangeEnd(outer, skipTrivia(currentText, node.pos));
803            setEmitFlags(outer, EmitFlags.NoComments);
804
805            const result = factory.createParenthesizedExpression(
806                factory.createCallExpression(
807                    outer,
808                    /*typeArguments*/ undefined,
809                    extendsClauseElement
810                        ? [visitNode(extendsClauseElement.expression, visitor, isExpression)]
811                        : []
812                )
813            );
814            addSyntheticLeadingComment(result, SyntaxKind.MultiLineCommentTrivia, "* @class ");
815            return result;
816        }
817
818        /**
819         * Transforms a ClassExpression or ClassDeclaration into a function body.
820         *
821         * @param node A ClassExpression or ClassDeclaration node.
822         * @param extendsClauseElement The expression for the class `extends` clause.
823         */
824        function transformClassBody(node: ClassExpression | ClassDeclaration, extendsClauseElement: ExpressionWithTypeArguments | undefined): Block {
825            const statements: Statement[] = [];
826            const name = factory.getInternalName(node);
827            const constructorLikeName = isIdentifierANonContextualKeyword(name) ? factory.getGeneratedNameForNode(name) : name;
828            startLexicalEnvironment();
829            addExtendsHelperIfNeeded(statements, node, extendsClauseElement);
830            addConstructor(statements, node, constructorLikeName, extendsClauseElement);
831            addClassMembers(statements, node);
832
833            // Create a synthetic text range for the return statement.
834            const closingBraceLocation = createTokenRange(skipTrivia(currentText, node.members.end), SyntaxKind.CloseBraceToken);
835
836            // The following partially-emitted expression exists purely to align our sourcemap
837            // emit with the original emitter.
838            const outer = factory.createPartiallyEmittedExpression(constructorLikeName);
839            setTextRangeEnd(outer, closingBraceLocation.end);
840            setEmitFlags(outer, EmitFlags.NoComments);
841
842            const statement = factory.createReturnStatement(outer);
843            setTextRangePos(statement, closingBraceLocation.pos);
844            setEmitFlags(statement, EmitFlags.NoComments | EmitFlags.NoTokenSourceMaps);
845            statements.push(statement);
846
847            insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
848
849            const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), /*location*/ node.members), /*multiLine*/ true);
850            setEmitFlags(block, EmitFlags.NoComments);
851            return block;
852        }
853
854        /**
855         * Adds a call to the `__extends` helper if needed for a class.
856         *
857         * @param statements The statements of the class body function.
858         * @param node The ClassExpression or ClassDeclaration node.
859         * @param extendsClauseElement The expression for the class `extends` clause.
860         */
861        function addExtendsHelperIfNeeded(statements: Statement[], node: ClassExpression | ClassDeclaration, extendsClauseElement: ExpressionWithTypeArguments | undefined): void {
862            if (extendsClauseElement) {
863                statements.push(
864                    setTextRange(
865                        factory.createExpressionStatement(
866                            emitHelpers().createExtendsHelper(factory.getInternalName(node))
867                        ),
868                        /*location*/ extendsClauseElement
869                    )
870                );
871            }
872        }
873
874        /**
875         * Adds the constructor of the class to a class body function.
876         *
877         * @param statements The statements of the class body function.
878         * @param node The ClassExpression or ClassDeclaration node.
879         * @param extendsClauseElement The expression for the class `extends` clause.
880         */
881        function addConstructor(statements: Statement[], node: ClassExpression | ClassDeclaration, name: Identifier, extendsClauseElement: ExpressionWithTypeArguments | undefined): void {
882            const savedConvertedLoopState = convertedLoopState;
883            convertedLoopState = undefined;
884            const ancestorFacts = enterSubtree(HierarchyFacts.ConstructorExcludes, HierarchyFacts.ConstructorIncludes);
885            const constructor = getFirstConstructorWithBody(node);
886            const hasSynthesizedSuper = hasSynthesizedDefaultSuperCall(constructor, extendsClauseElement !== undefined);
887            const constructorFunction = factory.createFunctionDeclaration(
888                /*decorators*/ undefined,
889                /*modifiers*/ undefined,
890                /*asteriskToken*/ undefined,
891                name,
892                /*typeParameters*/ undefined,
893                transformConstructorParameters(constructor, hasSynthesizedSuper),
894                /*type*/ undefined,
895                transformConstructorBody(constructor, node, extendsClauseElement, hasSynthesizedSuper)
896            );
897
898            setTextRange(constructorFunction, constructor || node);
899            if (extendsClauseElement) {
900                setEmitFlags(constructorFunction, EmitFlags.CapturesThis);
901            }
902
903            statements.push(constructorFunction);
904            exitSubtree(ancestorFacts, HierarchyFacts.FunctionSubtreeExcludes, HierarchyFacts.None);
905            convertedLoopState = savedConvertedLoopState;
906        }
907
908        /**
909         * Transforms the parameters of the constructor declaration of a class.
910         *
911         * @param constructor The constructor for the class.
912         * @param hasSynthesizedSuper A value indicating whether the constructor starts with a
913         *                            synthesized `super` call.
914         */
915        function transformConstructorParameters(constructor: ConstructorDeclaration | undefined, hasSynthesizedSuper: boolean) {
916            // If the TypeScript transformer needed to synthesize a constructor for property
917            // initializers, it would have also added a synthetic `...args` parameter and
918            // `super` call.
919            // If this is the case, we do not include the synthetic `...args` parameter and
920            // will instead use the `arguments` object in ES5/3.
921            return visitParameterList(constructor && !hasSynthesizedSuper ? constructor.parameters : undefined, visitor, context)
922                || <ParameterDeclaration[]>[];
923        }
924
925        function createDefaultConstructorBody(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
926            // We must be here because the user didn't write a constructor
927            // but we needed to call 'super(...args)' anyway as per 14.5.14 of the ES2016 spec.
928            // If that's the case we can just immediately return the result of a 'super()' call.
929            const statements: Statement[] = [];
930            resumeLexicalEnvironment();
931            factory.mergeLexicalEnvironment(statements, endLexicalEnvironment());
932
933            if (isDerivedClass) {
934                // return _super !== null && _super.apply(this, arguments) || this;
935                statements.push(factory.createReturnStatement(createDefaultSuperCallOrThis()));
936            }
937
938            const statementsArray = factory.createNodeArray(statements);
939            setTextRange(statementsArray, node.members);
940
941            const block = factory.createBlock(statementsArray, /*multiLine*/ true);
942            setTextRange(block, node);
943            setEmitFlags(block, EmitFlags.NoComments);
944            return block;
945        }
946
947        /**
948         * Transforms the body of a constructor declaration of a class.
949         *
950         * @param constructor The constructor for the class.
951         * @param node The node which contains the constructor.
952         * @param extendsClauseElement The expression for the class `extends` clause.
953         * @param hasSynthesizedSuper A value indicating whether the constructor starts with a
954         *                            synthesized `super` call.
955         */
956        function transformConstructorBody(constructor: ConstructorDeclaration & { body: FunctionBody } | undefined, node: ClassDeclaration | ClassExpression, extendsClauseElement: ExpressionWithTypeArguments | undefined, hasSynthesizedSuper: boolean) {
957            // determine whether the class is known syntactically to be a derived class (e.g. a
958            // class that extends a value that is not syntactically known to be `null`).
959            const isDerivedClass = !!extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword;
960
961            // When the subclass does not have a constructor, we synthesize a *default* constructor using the following
962            // representation:
963            //
964            // ```
965            // // es2015 (source)
966            // class C extends Base { }
967            //
968            // // es5 (transformed)
969            // var C = (function (_super) {
970            //     function C() {
971            //         return _super.apply(this, arguments) || this;
972            //     }
973            //     return C;
974            // })(Base);
975            // ```
976            if (!constructor) return createDefaultConstructorBody(node, isDerivedClass);
977
978            // The prologue will contain all leading standard and custom prologue statements added by this transform
979            const prologue: Statement[] = [];
980            const statements: Statement[] = [];
981            resumeLexicalEnvironment();
982
983            // If a super call has already been synthesized,
984            // we're going to assume that we should just transform everything after that.
985            // The assumption is that no prior step in the pipeline has added any prologue directives.
986            let statementOffset = 0;
987            if (!hasSynthesizedSuper) statementOffset = factory.copyStandardPrologue(constructor.body.statements, prologue, /*ensureUseStrict*/ false);
988            addDefaultValueAssignmentsIfNeeded(statements, constructor);
989            addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper);
990            if (!hasSynthesizedSuper) statementOffset = factory.copyCustomPrologue(constructor.body.statements, statements, statementOffset, visitor);
991
992            // If the first statement is a call to `super()`, visit the statement directly
993            let superCallExpression: Expression | undefined;
994            if (hasSynthesizedSuper) {
995                superCallExpression = createDefaultSuperCallOrThis();
996            }
997            else if (isDerivedClass && statementOffset < constructor.body.statements.length) {
998                const firstStatement = constructor.body.statements[statementOffset];
999                if (isExpressionStatement(firstStatement) && isSuperCall(firstStatement.expression)) {
1000                    superCallExpression = visitImmediateSuperCallInBody(firstStatement.expression);
1001                }
1002            }
1003
1004            if (superCallExpression) {
1005                hierarchyFacts |= HierarchyFacts.ConstructorWithCapturedSuper;
1006                statementOffset++; // skip this statement, we will add it after visiting the rest of the body.
1007            }
1008
1009            // visit the remaining statements
1010            addRange(statements, visitNodes(constructor.body.statements, visitor, isStatement, /*start*/ statementOffset));
1011
1012            factory.mergeLexicalEnvironment(prologue, endLexicalEnvironment());
1013            insertCaptureNewTargetIfNeeded(prologue, constructor, /*copyOnWrite*/ false);
1014
1015            if (isDerivedClass) {
1016                if (superCallExpression && statementOffset === constructor.body.statements.length && !(constructor.body.transformFlags & TransformFlags.ContainsLexicalThis)) {
1017                    // If the subclass constructor does *not* contain `this` and *ends* with a `super()` call, we will use the
1018                    // following representation:
1019                    //
1020                    // ```
1021                    // // es2015 (source)
1022                    // class C extends Base {
1023                    //     constructor() {
1024                    //         super("foo");
1025                    //     }
1026                    // }
1027                    //
1028                    // // es5 (transformed)
1029                    // var C = (function (_super) {
1030                    //     function C() {
1031                    //         return _super.call(this, "foo") || this;
1032                    //     }
1033                    //     return C;
1034                    // })(Base);
1035                    // ```
1036                    const superCall = cast(cast(superCallExpression, isBinaryExpression).left, isCallExpression);
1037                    const returnStatement = factory.createReturnStatement(superCallExpression);
1038                    setCommentRange(returnStatement, getCommentRange(superCall));
1039                    setEmitFlags(superCall, EmitFlags.NoComments);
1040                    statements.push(returnStatement);
1041                }
1042                else {
1043                    // Otherwise, we will use the following transformed representation for calls to `super()` in a constructor:
1044                    //
1045                    // ```
1046                    // // es2015 (source)
1047                    // class C extends Base {
1048                    //     constructor() {
1049                    //         super("foo");
1050                    //         this.x = 1;
1051                    //     }
1052                    // }
1053                    //
1054                    // // es5 (transformed)
1055                    // var C = (function (_super) {
1056                    //     function C() {
1057                    //         var _this = _super.call(this, "foo") || this;
1058                    //         _this.x = 1;
1059                    //         return _this;
1060                    //     }
1061                    //     return C;
1062                    // })(Base);
1063                    // ```
1064
1065                    // Since the `super()` call was the first statement, we insert the `this` capturing call to
1066                    // `super()` at the top of the list of `statements` (after any pre-existing custom prologues).
1067                    insertCaptureThisForNode(statements, constructor, superCallExpression || createActualThis());
1068
1069                    if (!isSufficientlyCoveredByReturnStatements(constructor.body)) {
1070                        statements.push(factory.createReturnStatement(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel)));
1071                    }
1072                }
1073            }
1074            else {
1075                // If a class is not derived from a base class or does not have a call to `super()`, `this` is only
1076                // captured when necessitated by an arrow function capturing the lexical `this`:
1077                //
1078                // ```
1079                // // es2015
1080                // class C {}
1081                //
1082                // // es5
1083                // var C = (function () {
1084                //     function C() {
1085                //     }
1086                //     return C;
1087                // })();
1088                // ```
1089                insertCaptureThisForNodeIfNeeded(prologue, constructor);
1090            }
1091
1092            const block = factory.createBlock(
1093                setTextRange(
1094                    factory.createNodeArray(
1095                        concatenate(prologue, statements)
1096                    ),
1097                    /*location*/ constructor.body.statements
1098                ),
1099                /*multiLine*/ true
1100            );
1101
1102            setTextRange(block, constructor.body);
1103
1104            return block;
1105        }
1106
1107        /**
1108         * We want to try to avoid emitting a return statement in certain cases if a user already returned something.
1109         * It would generate obviously dead code, so we'll try to make things a little bit prettier
1110         * by doing a minimal check on whether some common patterns always explicitly return.
1111         */
1112        function isSufficientlyCoveredByReturnStatements(statement: Statement): boolean {
1113            // A return statement is considered covered.
1114            if (statement.kind === SyntaxKind.ReturnStatement) {
1115                return true;
1116            }
1117            // An if-statement with two covered branches is covered.
1118            else if (statement.kind === SyntaxKind.IfStatement) {
1119                const ifStatement = statement as IfStatement;
1120                if (ifStatement.elseStatement) {
1121                    return isSufficientlyCoveredByReturnStatements(ifStatement.thenStatement) &&
1122                        isSufficientlyCoveredByReturnStatements(ifStatement.elseStatement);
1123                }
1124            }
1125            // A block is covered if it has a last statement which is covered.
1126            else if (statement.kind === SyntaxKind.Block) {
1127                const lastStatement = lastOrUndefined((statement as Block).statements);
1128                if (lastStatement && isSufficientlyCoveredByReturnStatements(lastStatement)) {
1129                    return true;
1130                }
1131            }
1132
1133            return false;
1134        }
1135
1136        function createActualThis() {
1137            return setEmitFlags(factory.createThis(), EmitFlags.NoSubstitution);
1138        }
1139
1140        function createDefaultSuperCallOrThis() {
1141            return factory.createLogicalOr(
1142                factory.createLogicalAnd(
1143                    factory.createStrictInequality(
1144                        factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel),
1145                        factory.createNull()
1146                    ),
1147                    factory.createFunctionApplyCall(
1148                        factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel),
1149                        createActualThis(),
1150                        factory.createIdentifier("arguments"),
1151                    )
1152                ),
1153                createActualThis()
1154            );
1155        }
1156
1157        /**
1158         * Visits a parameter declaration.
1159         *
1160         * @param node A ParameterDeclaration node.
1161         */
1162        function visitParameter(node: ParameterDeclaration): ParameterDeclaration | undefined {
1163            if (node.dotDotDotToken) {
1164                // rest parameters are elided
1165                return undefined;
1166            }
1167            else if (isBindingPattern(node.name)) {
1168                // Binding patterns are converted into a generated name and are
1169                // evaluated inside the function body.
1170                return setOriginalNode(
1171                    setTextRange(
1172                        factory.createParameterDeclaration(
1173                            /*decorators*/ undefined,
1174                            /*modifiers*/ undefined,
1175                            /*dotDotDotToken*/ undefined,
1176                            factory.getGeneratedNameForNode(node),
1177                            /*questionToken*/ undefined,
1178                            /*type*/ undefined,
1179                            /*initializer*/ undefined
1180                        ),
1181                        /*location*/ node
1182                    ),
1183                    /*original*/ node
1184                );
1185            }
1186            else if (node.initializer) {
1187                // Initializers are elided
1188                return setOriginalNode(
1189                    setTextRange(
1190                        factory.createParameterDeclaration(
1191                            /*decorators*/ undefined,
1192                            /*modifiers*/ undefined,
1193                            /*dotDotDotToken*/ undefined,
1194                            node.name,
1195                            /*questionToken*/ undefined,
1196                            /*type*/ undefined,
1197                            /*initializer*/ undefined
1198                        ),
1199                        /*location*/ node
1200                    ),
1201                    /*original*/ node
1202                );
1203            }
1204            else {
1205                return node;
1206            }
1207        }
1208
1209        function hasDefaultValueOrBindingPattern(node: ParameterDeclaration) {
1210            return node.initializer !== undefined
1211                || isBindingPattern(node.name);
1212        }
1213
1214        /**
1215         * Adds statements to the body of a function-like node if it contains parameters with
1216         * binding patterns or initializers.
1217         *
1218         * @param statements The statements for the new function body.
1219         * @param node A function-like node.
1220         */
1221        function addDefaultValueAssignmentsIfNeeded(statements: Statement[], node: FunctionLikeDeclaration): boolean {
1222            if (!some(node.parameters, hasDefaultValueOrBindingPattern)) {
1223                return false;
1224            }
1225
1226            let added = false;
1227            for (const parameter of node.parameters) {
1228                const { name, initializer, dotDotDotToken } = parameter;
1229
1230                // A rest parameter cannot have a binding pattern or an initializer,
1231                // so let's just ignore it.
1232                if (dotDotDotToken) {
1233                    continue;
1234                }
1235
1236                if (isBindingPattern(name)) {
1237                    added = insertDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer) || added;
1238                }
1239                else if (initializer) {
1240                    insertDefaultValueAssignmentForInitializer(statements, parameter, name, initializer);
1241                    added = true;
1242                }
1243            }
1244            return added;
1245        }
1246
1247        /**
1248         * Adds statements to the body of a function-like node for parameters with binding patterns
1249         *
1250         * @param statements The statements for the new function body.
1251         * @param parameter The parameter for the function.
1252         * @param name The name of the parameter.
1253         * @param initializer The initializer for the parameter.
1254         */
1255        function insertDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression | undefined): boolean {
1256            // In cases where a binding pattern is simply '[]' or '{}',
1257            // we usually don't want to emit a var declaration; however, in the presence
1258            // of an initializer, we must emit that expression to preserve side effects.
1259            if (name.elements.length > 0) {
1260                insertStatementAfterCustomPrologue(
1261                    statements,
1262                    setEmitFlags(
1263                        factory.createVariableStatement(
1264                            /*modifiers*/ undefined,
1265                            factory.createVariableDeclarationList(
1266                                flattenDestructuringBinding(
1267                                    parameter,
1268                                    visitor,
1269                                    context,
1270                                    FlattenLevel.All,
1271                                    factory.getGeneratedNameForNode(parameter)
1272                                )
1273                            )
1274                        ),
1275                        EmitFlags.CustomPrologue
1276                    )
1277                );
1278                return true;
1279            }
1280            else if (initializer) {
1281                insertStatementAfterCustomPrologue(
1282                    statements,
1283                    setEmitFlags(
1284                        factory.createExpressionStatement(
1285                            factory.createAssignment(
1286                                factory.getGeneratedNameForNode(parameter),
1287                                visitNode(initializer, visitor, isExpression)
1288                            )
1289                        ),
1290                        EmitFlags.CustomPrologue
1291                    )
1292                );
1293                return true;
1294            }
1295            return false;
1296        }
1297
1298        /**
1299         * Adds statements to the body of a function-like node for parameters with initializers.
1300         *
1301         * @param statements The statements for the new function body.
1302         * @param parameter The parameter for the function.
1303         * @param name The name of the parameter.
1304         * @param initializer The initializer for the parameter.
1305         */
1306        function insertDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void {
1307            initializer = visitNode(initializer, visitor, isExpression);
1308            const statement = factory.createIfStatement(
1309                factory.createTypeCheck(factory.cloneNode(name), "undefined"),
1310                setEmitFlags(
1311                    setTextRange(
1312                        factory.createBlock([
1313                            factory.createExpressionStatement(
1314                                setEmitFlags(
1315                                    setTextRange(
1316                                        factory.createAssignment(
1317                                            // TODO(rbuckton): Does this need to be parented?
1318                                            setEmitFlags(setParent(setTextRange(factory.cloneNode(name), name), name.parent), EmitFlags.NoSourceMap),
1319                                            setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer) | EmitFlags.NoComments)
1320                                        ),
1321                                        parameter
1322                                    ),
1323                                    EmitFlags.NoComments
1324                                )
1325                            )
1326                        ]),
1327                        parameter
1328                    ),
1329                    EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments
1330                )
1331            );
1332
1333            startOnNewLine(statement);
1334            setTextRange(statement, parameter);
1335            setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue | EmitFlags.NoComments);
1336            insertStatementAfterCustomPrologue(statements, statement);
1337        }
1338
1339        /**
1340         * Gets a value indicating whether we need to add statements to handle a rest parameter.
1341         *
1342         * @param node A ParameterDeclaration node.
1343         * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
1344         *                                          part of a constructor declaration with a
1345         *                                          synthesized call to `super`
1346         */
1347        function shouldAddRestParameter(node: ParameterDeclaration | undefined, inConstructorWithSynthesizedSuper: boolean): node is ParameterDeclaration {
1348            return !!(node && node.dotDotDotToken && !inConstructorWithSynthesizedSuper);
1349        }
1350
1351        /**
1352         * Adds statements to the body of a function-like node if it contains a rest parameter.
1353         *
1354         * @param statements The statements for the new function body.
1355         * @param node A function-like node.
1356         * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
1357         *                                          part of a constructor declaration with a
1358         *                                          synthesized call to `super`
1359         */
1360        function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): boolean {
1361            const prologueStatements: Statement[] = [];
1362            const parameter = lastOrUndefined(node.parameters);
1363            if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) {
1364                return false;
1365            }
1366
1367            // `declarationName` is the name of the local declaration for the parameter.
1368            // TODO(rbuckton): Does this need to be parented?
1369            const declarationName = parameter.name.kind === SyntaxKind.Identifier ? setParent(setTextRange(factory.cloneNode(parameter.name), parameter.name), parameter.name.parent) : factory.createTempVariable(/*recordTempVariable*/ undefined);
1370            setEmitFlags(declarationName, EmitFlags.NoSourceMap);
1371
1372            // `expressionName` is the name of the parameter used in expressions.
1373            const expressionName = parameter.name.kind === SyntaxKind.Identifier ? factory.cloneNode(parameter.name) : declarationName;
1374            const restIndex = node.parameters.length - 1;
1375            const temp = factory.createLoopVariable();
1376
1377            // var param = [];
1378            prologueStatements.push(
1379                setEmitFlags(
1380                    setTextRange(
1381                        factory.createVariableStatement(
1382                            /*modifiers*/ undefined,
1383                            factory.createVariableDeclarationList([
1384                                factory.createVariableDeclaration(
1385                                    declarationName,
1386                                    /*exclamationToken*/ undefined,
1387                                    /*type*/ undefined,
1388                                    factory.createArrayLiteralExpression([])
1389                                )
1390                            ])
1391                        ),
1392                        /*location*/ parameter
1393                    ),
1394                    EmitFlags.CustomPrologue
1395                )
1396            );
1397
1398            // for (var _i = restIndex; _i < arguments.length; _i++) {
1399            //   param[_i - restIndex] = arguments[_i];
1400            // }
1401            const forStatement = factory.createForStatement(
1402                setTextRange(
1403                    factory.createVariableDeclarationList([
1404                        factory.createVariableDeclaration(temp, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(restIndex))
1405                    ]),
1406                    parameter
1407                ),
1408                setTextRange(
1409                    factory.createLessThan(
1410                        temp,
1411                        factory.createPropertyAccessExpression(factory.createIdentifier("arguments"), "length")
1412                    ),
1413                    parameter
1414                ),
1415                setTextRange(factory.createPostfixIncrement(temp), parameter),
1416                factory.createBlock([
1417                    startOnNewLine(
1418                        setTextRange(
1419                            factory.createExpressionStatement(
1420                                factory.createAssignment(
1421                                    factory.createElementAccessExpression(
1422                                        expressionName,
1423                                        restIndex === 0
1424                                            ? temp
1425                                            : factory.createSubtract(temp, factory.createNumericLiteral(restIndex))
1426                                    ),
1427                                    factory.createElementAccessExpression(factory.createIdentifier("arguments"), temp)
1428                                )
1429                            ),
1430                            /*location*/ parameter
1431                        )
1432                    )
1433                ])
1434            );
1435
1436            setEmitFlags(forStatement, EmitFlags.CustomPrologue);
1437            startOnNewLine(forStatement);
1438            prologueStatements.push(forStatement);
1439
1440            if (parameter.name.kind !== SyntaxKind.Identifier) {
1441                // do the actual destructuring of the rest parameter if necessary
1442                prologueStatements.push(
1443                    setEmitFlags(
1444                        setTextRange(
1445                            factory.createVariableStatement(
1446                                /*modifiers*/ undefined,
1447                                factory.createVariableDeclarationList(
1448                                    flattenDestructuringBinding(parameter, visitor, context, FlattenLevel.All, expressionName),
1449                                )
1450                            ),
1451                            parameter
1452                        ),
1453                        EmitFlags.CustomPrologue
1454                    )
1455                );
1456            }
1457
1458            insertStatementsAfterCustomPrologue(statements, prologueStatements);
1459            return true;
1460        }
1461
1462        /**
1463         * Adds a statement to capture the `this` of a function declaration if it is needed.
1464         * NOTE: This must be executed *after* the subtree has been visited.
1465         *
1466         * @param statements The statements for the new function body.
1467         * @param node A node.
1468         */
1469        function insertCaptureThisForNodeIfNeeded(statements: Statement[], node: Node): boolean {
1470            if (hierarchyFacts & HierarchyFacts.CapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) {
1471                insertCaptureThisForNode(statements, node, factory.createThis());
1472                return true;
1473            }
1474            return false;
1475        }
1476
1477        function insertCaptureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined): void {
1478            enableSubstitutionsForCapturedThis();
1479            const captureThisStatement = factory.createVariableStatement(
1480                /*modifiers*/ undefined,
1481                factory.createVariableDeclarationList([
1482                    factory.createVariableDeclaration(
1483                        factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel),
1484                        /*exclamationToken*/ undefined,
1485                        /*type*/ undefined,
1486                        initializer
1487                    )
1488                ])
1489            );
1490            setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue);
1491            setSourceMapRange(captureThisStatement, node);
1492            insertStatementAfterCustomPrologue(statements, captureThisStatement);
1493        }
1494
1495        function insertCaptureNewTargetIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, copyOnWrite: boolean): Statement[] {
1496            if (hierarchyFacts & HierarchyFacts.NewTarget) {
1497                let newTarget: Expression;
1498                switch (node.kind) {
1499                    case SyntaxKind.ArrowFunction:
1500                        return statements;
1501
1502                    case SyntaxKind.MethodDeclaration:
1503                    case SyntaxKind.GetAccessor:
1504                    case SyntaxKind.SetAccessor:
1505                        // Methods and accessors cannot be constructors, so 'new.target' will
1506                        // always return 'undefined'.
1507                        newTarget = factory.createVoidZero();
1508                        break;
1509
1510                    case SyntaxKind.Constructor:
1511                        // Class constructors can only be called with `new`, so `this.constructor`
1512                        // should be relatively safe to use.
1513                        newTarget = factory.createPropertyAccessExpression(
1514                            setEmitFlags(factory.createThis(), EmitFlags.NoSubstitution),
1515                            "constructor"
1516                        );
1517                        break;
1518
1519                    case SyntaxKind.FunctionDeclaration:
1520                    case SyntaxKind.FunctionExpression:
1521                        // Functions can be called or constructed, and may have a `this` due to
1522                        // being a member or when calling an imported function via `other_1.f()`.
1523                        newTarget = factory.createConditionalExpression(
1524                            factory.createLogicalAnd(
1525                                setEmitFlags(factory.createThis(), EmitFlags.NoSubstitution),
1526                                factory.createBinaryExpression(
1527                                    setEmitFlags(factory.createThis(), EmitFlags.NoSubstitution),
1528                                    SyntaxKind.InstanceOfKeyword,
1529                                    factory.getLocalName(node)
1530                                )
1531                            ),
1532                            /*questionToken*/ undefined,
1533                            factory.createPropertyAccessExpression(
1534                                setEmitFlags(factory.createThis(), EmitFlags.NoSubstitution),
1535                                "constructor"
1536                            ),
1537                            /*colonToken*/ undefined,
1538                            factory.createVoidZero()
1539                        );
1540                        break;
1541
1542                    default:
1543                        return Debug.failBadSyntaxKind(node);
1544                }
1545
1546                const captureNewTargetStatement = factory.createVariableStatement(
1547                    /*modifiers*/ undefined,
1548                    factory.createVariableDeclarationList([
1549                        factory.createVariableDeclaration(
1550                            factory.createUniqueName("_newTarget", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel),
1551                            /*exclamationToken*/ undefined,
1552                            /*type*/ undefined,
1553                            newTarget
1554                        )
1555                    ])
1556                );
1557
1558                setEmitFlags(captureNewTargetStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue);
1559
1560                if (copyOnWrite) {
1561                    statements = statements.slice();
1562                }
1563
1564                insertStatementAfterCustomPrologue(statements, captureNewTargetStatement);
1565            }
1566
1567            return statements;
1568        }
1569
1570        /**
1571         * Adds statements to the class body function for a class to define the members of the
1572         * class.
1573         *
1574         * @param statements The statements for the class body function.
1575         * @param node The ClassExpression or ClassDeclaration node.
1576         */
1577        function addClassMembers(statements: Statement[], node: ClassExpression | ClassDeclaration): void {
1578            for (const member of node.members) {
1579                switch (member.kind) {
1580                    case SyntaxKind.SemicolonClassElement:
1581                        statements.push(transformSemicolonClassElementToStatement(<SemicolonClassElement>member));
1582                        break;
1583
1584                    case SyntaxKind.MethodDeclaration:
1585                        statements.push(transformClassMethodDeclarationToStatement(getClassMemberPrefix(node, member), <MethodDeclaration>member, node));
1586                        break;
1587
1588                    case SyntaxKind.GetAccessor:
1589                    case SyntaxKind.SetAccessor:
1590                        const accessors = getAllAccessorDeclarations(node.members, <AccessorDeclaration>member);
1591                        if (member === accessors.firstAccessor) {
1592                            statements.push(transformAccessorsToStatement(getClassMemberPrefix(node, member), accessors, node));
1593                        }
1594
1595                        break;
1596
1597                    case SyntaxKind.Constructor:
1598                        // Constructors are handled in visitClassExpression/visitClassDeclaration
1599                        break;
1600
1601                    default:
1602                        Debug.failBadSyntaxKind(member, currentSourceFile && currentSourceFile.fileName);
1603                        break;
1604                }
1605            }
1606        }
1607
1608        /**
1609         * Transforms a SemicolonClassElement into a statement for a class body function.
1610         *
1611         * @param member The SemicolonClassElement node.
1612         */
1613        function transformSemicolonClassElementToStatement(member: SemicolonClassElement) {
1614            return setTextRange(factory.createEmptyStatement(), member);
1615        }
1616
1617        /**
1618         * Transforms a MethodDeclaration into a statement for a class body function.
1619         *
1620         * @param receiver The receiver for the member.
1621         * @param member The MethodDeclaration node.
1622         */
1623        function transformClassMethodDeclarationToStatement(receiver: LeftHandSideExpression, member: MethodDeclaration, container: Node) {
1624            const commentRange = getCommentRange(member);
1625            const sourceMapRange = getSourceMapRange(member);
1626            const memberFunction = transformFunctionLikeToExpression(member, /*location*/ member, /*name*/ undefined, container);
1627            const propertyName = visitNode(member.name, visitor, isPropertyName);
1628            let e: Expression;
1629            if (!isPrivateIdentifier(propertyName) && context.getCompilerOptions().useDefineForClassFields) {
1630                const name = isComputedPropertyName(propertyName) ? propertyName.expression
1631                    : isIdentifier(propertyName) ? factory.createStringLiteral(unescapeLeadingUnderscores(propertyName.escapedText))
1632                    : propertyName;
1633                e = factory.createObjectDefinePropertyCall(receiver, name, factory.createPropertyDescriptor({ value: memberFunction, enumerable: false, writable: true, configurable: true }));
1634            }
1635            else {
1636                const memberName = createMemberAccessForPropertyName(factory, receiver, propertyName, /*location*/ member.name);
1637                e = factory.createAssignment(memberName, memberFunction);
1638            }
1639            setEmitFlags(memberFunction, EmitFlags.NoComments);
1640            setSourceMapRange(memberFunction, sourceMapRange);
1641            const statement = setTextRange(factory.createExpressionStatement(e), /*location*/ member);
1642
1643            setOriginalNode(statement, member);
1644            setCommentRange(statement, commentRange);
1645
1646            // The location for the statement is used to emit comments only.
1647            // No source map should be emitted for this statement to align with the
1648            // old emitter.
1649            setEmitFlags(statement, EmitFlags.NoSourceMap);
1650            return statement;
1651        }
1652
1653        /**
1654         * Transforms a set of related of get/set accessors into a statement for a class body function.
1655         *
1656         * @param receiver The receiver for the member.
1657         * @param accessors The set of related get/set accessors.
1658         */
1659        function transformAccessorsToStatement(receiver: LeftHandSideExpression, accessors: AllAccessorDeclarations, container: Node): Statement {
1660            const statement = factory.createExpressionStatement(transformAccessorsToExpression(receiver, accessors, container, /*startsOnNewLine*/ false));
1661            // The location for the statement is used to emit source maps only.
1662            // No comments should be emitted for this statement to align with the
1663            // old emitter.
1664            setEmitFlags(statement, EmitFlags.NoComments);
1665            setSourceMapRange(statement, getSourceMapRange(accessors.firstAccessor));
1666            return statement;
1667        }
1668
1669        /**
1670         * Transforms a set of related get/set accessors into an expression for either a class
1671         * body function or an ObjectLiteralExpression with computed properties.
1672         *
1673         * @param receiver The receiver for the member.
1674         */
1675        function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations, container: Node, startsOnNewLine: boolean): Expression {
1676            // To align with source maps in the old emitter, the receiver and property name
1677            // arguments are both mapped contiguously to the accessor name.
1678            // TODO(rbuckton): Does this need to be parented?
1679            const target = setParent(setTextRange(factory.cloneNode(receiver), receiver), receiver.parent);
1680            setEmitFlags(target, EmitFlags.NoComments | EmitFlags.NoTrailingSourceMap);
1681            setSourceMapRange(target, firstAccessor.name);
1682
1683            const visitedAccessorName = visitNode(firstAccessor.name, visitor, isPropertyName);
1684            if (isPrivateIdentifier(visitedAccessorName)) {
1685                return Debug.failBadSyntaxKind(visitedAccessorName, "Encountered unhandled private identifier while transforming ES2015.");
1686            }
1687            const propertyName = createExpressionForPropertyName(factory, visitedAccessorName);
1688            setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoLeadingSourceMap);
1689            setSourceMapRange(propertyName, firstAccessor.name);
1690
1691            const properties: ObjectLiteralElementLike[] = [];
1692            if (getAccessor) {
1693                const getterFunction = transformFunctionLikeToExpression(getAccessor, /*location*/ undefined, /*name*/ undefined, container);
1694                setSourceMapRange(getterFunction, getSourceMapRange(getAccessor));
1695                setEmitFlags(getterFunction, EmitFlags.NoLeadingComments);
1696                const getter = factory.createPropertyAssignment("get", getterFunction);
1697                setCommentRange(getter, getCommentRange(getAccessor));
1698                properties.push(getter);
1699            }
1700
1701            if (setAccessor) {
1702                const setterFunction = transformFunctionLikeToExpression(setAccessor, /*location*/ undefined, /*name*/ undefined, container);
1703                setSourceMapRange(setterFunction, getSourceMapRange(setAccessor));
1704                setEmitFlags(setterFunction, EmitFlags.NoLeadingComments);
1705                const setter = factory.createPropertyAssignment("set", setterFunction);
1706                setCommentRange(setter, getCommentRange(setAccessor));
1707                properties.push(setter);
1708            }
1709
1710            properties.push(
1711                factory.createPropertyAssignment("enumerable", getAccessor || setAccessor ? factory.createFalse() : factory.createTrue()),
1712                factory.createPropertyAssignment("configurable", factory.createTrue())
1713            );
1714
1715            const call = factory.createCallExpression(
1716                factory.createPropertyAccessExpression(factory.createIdentifier("Object"), "defineProperty"),
1717                /*typeArguments*/ undefined,
1718                [
1719                    target,
1720                    propertyName,
1721                    factory.createObjectLiteralExpression(properties, /*multiLine*/ true)
1722                ]
1723            );
1724            if (startsOnNewLine) {
1725                startOnNewLine(call);
1726            }
1727
1728            return call;
1729        }
1730
1731        /**
1732         * Visits an ArrowFunction and transforms it into a FunctionExpression.
1733         *
1734         * @param node An ArrowFunction node.
1735         */
1736        function visitArrowFunction(node: ArrowFunction) {
1737            if (node.transformFlags & TransformFlags.ContainsLexicalThis) {
1738                hierarchyFacts |= HierarchyFacts.CapturedLexicalThis;
1739            }
1740
1741            const savedConvertedLoopState = convertedLoopState;
1742            convertedLoopState = undefined;
1743            const ancestorFacts = enterSubtree(HierarchyFacts.ArrowFunctionExcludes, HierarchyFacts.ArrowFunctionIncludes);
1744            const func = factory.createFunctionExpression(
1745                /*modifiers*/ undefined,
1746                /*asteriskToken*/ undefined,
1747                /*name*/ undefined,
1748                /*typeParameters*/ undefined,
1749                visitParameterList(node.parameters, visitor, context),
1750                /*type*/ undefined,
1751                transformFunctionBody(node)
1752            );
1753            setTextRange(func, node);
1754            setOriginalNode(func, node);
1755            setEmitFlags(func, EmitFlags.CapturesThis);
1756
1757            if (hierarchyFacts & HierarchyFacts.CapturedLexicalThis) {
1758                enableSubstitutionsForCapturedThis();
1759            }
1760
1761            // If an arrow function contains
1762            exitSubtree(ancestorFacts, HierarchyFacts.ArrowFunctionSubtreeExcludes, HierarchyFacts.None);
1763
1764            convertedLoopState = savedConvertedLoopState;
1765            return func;
1766        }
1767
1768        /**
1769         * Visits a FunctionExpression node.
1770         *
1771         * @param node a FunctionExpression node.
1772         */
1773        function visitFunctionExpression(node: FunctionExpression): Expression {
1774            const ancestorFacts = getEmitFlags(node) & EmitFlags.AsyncFunctionBody
1775                ? enterSubtree(HierarchyFacts.AsyncFunctionBodyExcludes, HierarchyFacts.AsyncFunctionBodyIncludes)
1776                : enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes);
1777            const savedConvertedLoopState = convertedLoopState;
1778            convertedLoopState = undefined;
1779
1780            const parameters = visitParameterList(node.parameters, visitor, context);
1781            const body = transformFunctionBody(node);
1782            const name = hierarchyFacts & HierarchyFacts.NewTarget
1783                ? factory.getLocalName(node)
1784                : node.name;
1785
1786            exitSubtree(ancestorFacts, HierarchyFacts.FunctionSubtreeExcludes, HierarchyFacts.None);
1787            convertedLoopState = savedConvertedLoopState;
1788            return factory.updateFunctionExpression(
1789                node,
1790                /*modifiers*/ undefined,
1791                node.asteriskToken,
1792                name,
1793                /*typeParameters*/ undefined,
1794                parameters,
1795                /*type*/ undefined,
1796                body
1797            );
1798        }
1799
1800        /**
1801         * Visits a FunctionDeclaration node.
1802         *
1803         * @param node a FunctionDeclaration node.
1804         */
1805        function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration {
1806            const savedConvertedLoopState = convertedLoopState;
1807            convertedLoopState = undefined;
1808            const ancestorFacts = enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes);
1809            const parameters = visitParameterList(node.parameters, visitor, context);
1810            const body = transformFunctionBody(node);
1811            const name = hierarchyFacts & HierarchyFacts.NewTarget
1812                ? factory.getLocalName(node)
1813                : node.name;
1814
1815            exitSubtree(ancestorFacts, HierarchyFacts.FunctionSubtreeExcludes, HierarchyFacts.None);
1816            convertedLoopState = savedConvertedLoopState;
1817            return factory.updateFunctionDeclaration(
1818                node,
1819                /*decorators*/ undefined,
1820                visitNodes(node.modifiers, visitor, isModifier),
1821                node.asteriskToken,
1822                name,
1823                /*typeParameters*/ undefined,
1824                parameters,
1825                /*type*/ undefined,
1826                body
1827            );
1828        }
1829
1830        /**
1831         * Transforms a function-like node into a FunctionExpression.
1832         *
1833         * @param node The function-like node to transform.
1834         * @param location The source-map location for the new FunctionExpression.
1835         * @param name The name of the new FunctionExpression.
1836         */
1837        function transformFunctionLikeToExpression(node: FunctionLikeDeclaration, location: TextRange | undefined, name: Identifier | undefined, container: Node | undefined): FunctionExpression {
1838            const savedConvertedLoopState = convertedLoopState;
1839            convertedLoopState = undefined;
1840            const ancestorFacts = container && isClassLike(container) && !hasSyntacticModifier(node, ModifierFlags.Static)
1841                ? enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes | HierarchyFacts.NonStaticClassElement)
1842                : enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes);
1843            const parameters = visitParameterList(node.parameters, visitor, context);
1844            const body = transformFunctionBody(node);
1845            if (hierarchyFacts & HierarchyFacts.NewTarget && !name && (node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression)) {
1846                name = factory.getGeneratedNameForNode(node);
1847            }
1848
1849            exitSubtree(ancestorFacts, HierarchyFacts.FunctionSubtreeExcludes, HierarchyFacts.None);
1850            convertedLoopState = savedConvertedLoopState;
1851            return setOriginalNode(
1852                setTextRange(
1853                    factory.createFunctionExpression(
1854                        /*modifiers*/ undefined,
1855                        node.asteriskToken,
1856                        name,
1857                        /*typeParameters*/ undefined,
1858                        parameters,
1859                        /*type*/ undefined,
1860                        body
1861                    ),
1862                    location
1863                ),
1864                /*original*/ node
1865            );
1866        }
1867
1868        /**
1869         * Transforms the body of a function-like node.
1870         *
1871         * @param node A function-like node.
1872         */
1873        function transformFunctionBody(node: FunctionLikeDeclaration) {
1874            let multiLine = false; // indicates whether the block *must* be emitted as multiple lines
1875            let singleLine = false; // indicates whether the block *may* be emitted as a single line
1876            let statementsLocation: TextRange;
1877            let closeBraceLocation: TextRange | undefined;
1878
1879            const prologue: Statement[] = [];
1880            const statements: Statement[] = [];
1881            const body = node.body!;
1882            let statementOffset: number | undefined;
1883
1884            resumeLexicalEnvironment();
1885            if (isBlock(body)) {
1886                // ensureUseStrict is false because no new prologue-directive should be added.
1887                // addStandardPrologue will put already-existing directives at the beginning of the target statement-array
1888                statementOffset = factory.copyStandardPrologue(body.statements, prologue, /*ensureUseStrict*/ false);
1889                statementOffset = factory.copyCustomPrologue(body.statements, statements, statementOffset, visitor, isHoistedFunction);
1890                statementOffset = factory.copyCustomPrologue(body.statements, statements, statementOffset, visitor, isHoistedVariableStatement);
1891            }
1892
1893            multiLine = addDefaultValueAssignmentsIfNeeded(statements, node) || multiLine;
1894            multiLine = addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false) || multiLine;
1895
1896            if (isBlock(body)) {
1897                // addCustomPrologue puts already-existing directives at the beginning of the target statement-array
1898                statementOffset = factory.copyCustomPrologue(body.statements, statements, statementOffset, visitor);
1899
1900                statementsLocation = body.statements;
1901                addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset));
1902
1903                // If the original body was a multi-line block, this must be a multi-line block.
1904                if (!multiLine && body.multiLine) {
1905                    multiLine = true;
1906                }
1907            }
1908            else {
1909                Debug.assert(node.kind === SyntaxKind.ArrowFunction);
1910
1911                // To align with the old emitter, we use a synthetic end position on the location
1912                // for the statement list we synthesize when we down-level an arrow function with
1913                // an expression function body. This prevents both comments and source maps from
1914                // being emitted for the end position only.
1915                statementsLocation = moveRangeEnd(body, -1);
1916
1917                const equalsGreaterThanToken = node.equalsGreaterThanToken;
1918                if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) {
1919                    if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) {
1920                        singleLine = true;
1921                    }
1922                    else {
1923                        multiLine = true;
1924                    }
1925                }
1926
1927                const expression = visitNode(body, visitor, isExpression);
1928                const returnStatement = factory.createReturnStatement(expression);
1929                setTextRange(returnStatement, body);
1930                moveSyntheticComments(returnStatement, body);
1931                setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments);
1932                statements.push(returnStatement);
1933
1934                // To align with the source map emit for the old emitter, we set a custom
1935                // source map location for the close brace.
1936                closeBraceLocation = body;
1937            }
1938
1939            factory.mergeLexicalEnvironment(prologue, endLexicalEnvironment());
1940            insertCaptureNewTargetIfNeeded(prologue, node, /*copyOnWrite*/ false);
1941            insertCaptureThisForNodeIfNeeded(prologue, node);
1942
1943            // If we added any final generated statements, this must be a multi-line block
1944            if (some(prologue)) {
1945                multiLine = true;
1946            }
1947
1948            statements.unshift(...prologue);
1949            if (isBlock(body) && arrayIsEqualTo(statements, body.statements)) {
1950                // no changes were made, preserve the tree
1951                return body;
1952            }
1953
1954            const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), statementsLocation), multiLine);
1955            setTextRange(block, node.body);
1956            if (!multiLine && singleLine) {
1957                setEmitFlags(block, EmitFlags.SingleLine);
1958            }
1959
1960            if (closeBraceLocation) {
1961                setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation);
1962            }
1963
1964            setOriginalNode(block, node.body);
1965            return block;
1966        }
1967
1968        function visitBlock(node: Block, isFunctionBody: boolean): Block {
1969            if (isFunctionBody) {
1970                // A function body is not a block scope.
1971                return visitEachChild(node, visitor, context);
1972            }
1973            const ancestorFacts = hierarchyFacts & HierarchyFacts.IterationStatement
1974                ? enterSubtree(HierarchyFacts.IterationStatementBlockExcludes, HierarchyFacts.IterationStatementBlockIncludes)
1975                : enterSubtree(HierarchyFacts.BlockExcludes, HierarchyFacts.BlockIncludes);
1976            const updated = visitEachChild(node, visitor, context);
1977            exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
1978            return updated;
1979        }
1980
1981        /**
1982         * Visits an ExpressionStatement that contains a destructuring assignment.
1983         *
1984         * @param node An ExpressionStatement node.
1985         */
1986        function visitExpressionStatement(node: ExpressionStatement): Statement {
1987            return visitEachChild(node, visitorWithUnusedExpressionResult, context);
1988        }
1989
1990        /**
1991         * Visits a ParenthesizedExpression that may contain a destructuring assignment.
1992         *
1993         * @param node A ParenthesizedExpression node.
1994         * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the
1995         * expression of an `ExpressionStatement`).
1996         */
1997        function visitParenthesizedExpression(node: ParenthesizedExpression, expressionResultIsUnused: boolean): ParenthesizedExpression {
1998            return visitEachChild(node, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, context);
1999        }
2000
2001        /**
2002         * Visits a BinaryExpression that contains a destructuring assignment.
2003         *
2004         * @param node A BinaryExpression node.
2005         * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the
2006         * expression of an `ExpressionStatement`).
2007         */
2008        function visitBinaryExpression(node: BinaryExpression, expressionResultIsUnused: boolean): Expression {
2009            // If we are here it is because this is a destructuring assignment.
2010            if (isDestructuringAssignment(node)) {
2011                return flattenDestructuringAssignment(
2012                    node,
2013                    visitor,
2014                    context,
2015                    FlattenLevel.All,
2016                    !expressionResultIsUnused);
2017            }
2018            if (node.operatorToken.kind === SyntaxKind.CommaToken) {
2019                return factory.updateBinaryExpression(
2020                    node,
2021                    visitNode(node.left, visitorWithUnusedExpressionResult, isExpression),
2022                    node.operatorToken,
2023                    visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression)
2024                );
2025            }
2026            return visitEachChild(node, visitor, context);
2027        }
2028
2029        /**
2030         * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the
2031         * expression of an `ExpressionStatement`).
2032         */
2033        function visitCommaListExpression(node: CommaListExpression, expressionResultIsUnused: boolean): Expression {
2034            if (expressionResultIsUnused) {
2035                return visitEachChild(node, visitorWithUnusedExpressionResult, context);
2036            }
2037            let result: Expression[] | undefined;
2038            for (let i = 0; i < node.elements.length; i++) {
2039                const element = node.elements[i];
2040                const visited = visitNode(element, i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, isExpression);
2041                if (result || visited !== element) {
2042                    result ||= node.elements.slice(0, i);
2043                    result.push(visited);
2044                }
2045            }
2046            const elements = result ? setTextRange(factory.createNodeArray(result), node.elements) : node.elements;
2047            return factory.updateCommaListExpression(node, elements);
2048        }
2049
2050        function isVariableStatementOfTypeScriptClassWrapper(node: VariableStatement) {
2051            return node.declarationList.declarations.length === 1
2052                && !!node.declarationList.declarations[0].initializer
2053                && !!(getEmitFlags(node.declarationList.declarations[0].initializer) & EmitFlags.TypeScriptClassWrapper);
2054        }
2055
2056        function visitVariableStatement(node: VariableStatement): Statement | undefined {
2057            const ancestorFacts = enterSubtree(HierarchyFacts.None, hasSyntacticModifier(node, ModifierFlags.Export) ? HierarchyFacts.ExportedVariableStatement : HierarchyFacts.None);
2058            let updated: Statement | undefined;
2059            if (convertedLoopState && (node.declarationList.flags & NodeFlags.BlockScoped) === 0 && !isVariableStatementOfTypeScriptClassWrapper(node)) {
2060                // we are inside a converted loop - hoist variable declarations
2061                let assignments: Expression[] | undefined;
2062                for (const decl of node.declarationList.declarations) {
2063                    hoistVariableDeclarationDeclaredInConvertedLoop(convertedLoopState, decl);
2064                    if (decl.initializer) {
2065                        let assignment: Expression;
2066                        if (isBindingPattern(decl.name)) {
2067                            assignment = flattenDestructuringAssignment(
2068                                decl,
2069                                visitor,
2070                                context,
2071                                FlattenLevel.All
2072                            );
2073                        }
2074                        else {
2075                            assignment = factory.createBinaryExpression(decl.name, SyntaxKind.EqualsToken, visitNode(decl.initializer, visitor, isExpression));
2076                            setTextRange(assignment, decl);
2077                        }
2078
2079                        assignments = append(assignments, assignment);
2080                    }
2081                }
2082                if (assignments) {
2083                    updated = setTextRange(factory.createExpressionStatement(factory.inlineExpressions(assignments)), node);
2084                }
2085                else {
2086                    // none of declarations has initializer - the entire variable statement can be deleted
2087                    updated = undefined;
2088                }
2089            }
2090            else {
2091                updated = visitEachChild(node, visitor, context);
2092            }
2093
2094            exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
2095            return updated;
2096        }
2097
2098        /**
2099         * Visits a VariableDeclarationList that is block scoped (e.g. `let` or `const`).
2100         *
2101         * @param node A VariableDeclarationList node.
2102         */
2103        function visitVariableDeclarationList(node: VariableDeclarationList): VariableDeclarationList {
2104            if (node.flags & NodeFlags.BlockScoped || node.transformFlags & TransformFlags.ContainsBindingPattern) {
2105                if (node.flags & NodeFlags.BlockScoped) {
2106                    enableSubstitutionsForBlockScopedBindings();
2107                }
2108
2109                const declarations = flatMap(node.declarations, node.flags & NodeFlags.Let
2110                    ? visitVariableDeclarationInLetDeclarationList
2111                    : visitVariableDeclaration);
2112
2113                const declarationList = factory.createVariableDeclarationList(declarations);
2114                setOriginalNode(declarationList, node);
2115                setTextRange(declarationList, node);
2116                setCommentRange(declarationList, node);
2117
2118                // If the first or last declaration is a binding pattern, we need to modify
2119                // the source map range for the declaration list.
2120                if (node.transformFlags & TransformFlags.ContainsBindingPattern
2121                    && (isBindingPattern(node.declarations[0].name) || isBindingPattern(last(node.declarations).name))) {
2122                    setSourceMapRange(declarationList, getRangeUnion(declarations));
2123                }
2124
2125                return declarationList;
2126            }
2127            return visitEachChild(node, visitor, context);
2128        }
2129
2130        function getRangeUnion(declarations: readonly Node[]): TextRange {
2131            // declarations may not be sorted by position.
2132            // pos should be the minimum* position over all nodes (that's not -1), end should be the maximum end over all nodes.
2133            let pos = -1, end = -1;
2134            for (const node of declarations) {
2135                pos = pos === -1 ? node.pos : node.pos === -1 ? pos : Math.min(pos, node.pos);
2136                end = Math.max(end, node.end);
2137            }
2138            return createRange(pos, end);
2139        }
2140
2141        /**
2142         * Gets a value indicating whether we should emit an explicit initializer for a variable
2143         * declaration in a `let` declaration list.
2144         *
2145         * @param node A VariableDeclaration node.
2146         */
2147        function shouldEmitExplicitInitializerForLetDeclaration(node: VariableDeclaration) {
2148            // Nested let bindings might need to be initialized explicitly to preserve
2149            // ES6 semantic:
2150            //
2151            //  { let x = 1; }
2152            //  { let x; } // x here should be undefined. not 1
2153            //
2154            // Top level bindings never collide with anything and thus don't require
2155            // explicit initialization. As for nested let bindings there are two cases:
2156            //
2157            // - Nested let bindings that were not renamed definitely should be
2158            //   initialized explicitly:
2159            //
2160            //    { let x = 1; }
2161            //    { let x; if (some-condition) { x = 1}; if (x) { /*1*/ } }
2162            //
2163            //   Without explicit initialization code in /*1*/ can be executed even if
2164            //   some-condition is evaluated to false.
2165            //
2166            // - Renaming introduces fresh name that should not collide with any
2167            //   existing names, however renamed bindings sometimes also should be
2168            //   explicitly initialized. One particular case: non-captured binding
2169            //   declared inside loop body (but not in loop initializer):
2170            //
2171            //    let x;
2172            //    for (;;) {
2173            //        let x;
2174            //    }
2175            //
2176            //   In downlevel codegen inner 'x' will be renamed so it won't collide
2177            //   with outer 'x' however it will should be reset on every iteration as
2178            //   if it was declared anew.
2179            //
2180            //   * Why non-captured binding?
2181            //     - Because if loop contains block scoped binding captured in some
2182            //       function then loop body will be rewritten to have a fresh scope
2183            //       on every iteration so everything will just work.
2184            //
2185            //   * Why loop initializer is excluded?
2186            //     - Since we've introduced a fresh name it already will be undefined.
2187
2188            const flags = resolver.getNodeCheckFlags(node);
2189            const isCapturedInFunction = flags & NodeCheckFlags.CapturedBlockScopedBinding;
2190            const isDeclaredInLoop = flags & NodeCheckFlags.BlockScopedBindingInLoop;
2191            const emittedAsTopLevel =
2192                (hierarchyFacts & HierarchyFacts.TopLevel) !== 0
2193                || (isCapturedInFunction
2194                    && isDeclaredInLoop
2195                    && (hierarchyFacts & HierarchyFacts.IterationStatementBlock) !== 0);
2196
2197            const emitExplicitInitializer =
2198                !emittedAsTopLevel
2199                && (hierarchyFacts & HierarchyFacts.ForInOrForOfStatement) === 0
2200                && (!resolver.isDeclarationWithCollidingName(node)
2201                    || (isDeclaredInLoop
2202                        && !isCapturedInFunction
2203                        && (hierarchyFacts & (HierarchyFacts.ForStatement | HierarchyFacts.ForInOrForOfStatement)) === 0));
2204
2205            return emitExplicitInitializer;
2206        }
2207
2208        /**
2209         * Visits a VariableDeclaration in a `let` declaration list.
2210         *
2211         * @param node A VariableDeclaration node.
2212         */
2213        function visitVariableDeclarationInLetDeclarationList(node: VariableDeclaration) {
2214            // For binding pattern names that lack initializers there is no point to emit
2215            // explicit initializer since downlevel codegen for destructuring will fail
2216            // in the absence of initializer so all binding elements will say uninitialized
2217            const name = node.name;
2218            if (isBindingPattern(name)) {
2219                return visitVariableDeclaration(node);
2220            }
2221
2222            if (!node.initializer && shouldEmitExplicitInitializerForLetDeclaration(node)) {
2223                return factory.updateVariableDeclaration(node, node.name, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createVoidZero());
2224            }
2225
2226            return visitEachChild(node, visitor, context);
2227        }
2228
2229        /**
2230         * Visits a VariableDeclaration node with a binding pattern.
2231         *
2232         * @param node A VariableDeclaration node.
2233         */
2234        function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
2235            const ancestorFacts = enterSubtree(HierarchyFacts.ExportedVariableStatement, HierarchyFacts.None);
2236            let updated: VisitResult<VariableDeclaration>;
2237            if (isBindingPattern(node.name)) {
2238                updated = flattenDestructuringBinding(
2239                    node,
2240                    visitor,
2241                    context,
2242                    FlattenLevel.All,
2243                    /*value*/ undefined,
2244                    (ancestorFacts & HierarchyFacts.ExportedVariableStatement) !== 0
2245                );
2246            }
2247            else {
2248                updated = visitEachChild(node, visitor, context);
2249            }
2250
2251            exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
2252            return updated;
2253        }
2254
2255        function recordLabel(node: LabeledStatement) {
2256            convertedLoopState!.labels!.set(idText(node.label), true);
2257        }
2258
2259        function resetLabel(node: LabeledStatement) {
2260            convertedLoopState!.labels!.set(idText(node.label), false);
2261        }
2262
2263        function visitLabeledStatement(node: LabeledStatement): VisitResult<Statement> {
2264            if (convertedLoopState && !convertedLoopState.labels) {
2265                convertedLoopState.labels = new Map<string, boolean>();
2266            }
2267            const statement = unwrapInnermostStatementOfLabel(node, convertedLoopState && recordLabel);
2268            return isIterationStatement(statement, /*lookInLabeledStatements*/ false)
2269                ? visitIterationStatement(statement, /*outermostLabeledStatement*/ node)
2270                : factory.restoreEnclosingLabel(visitNode(statement, visitor, isStatement, factory.liftToBlock), node, convertedLoopState && resetLabel);
2271        }
2272
2273        function visitIterationStatement(node: IterationStatement, outermostLabeledStatement: LabeledStatement) {
2274            switch (node.kind) {
2275                case SyntaxKind.DoStatement:
2276                case SyntaxKind.WhileStatement:
2277                    return visitDoOrWhileStatement(<DoStatement | WhileStatement>node, outermostLabeledStatement);
2278                case SyntaxKind.ForStatement:
2279                    return visitForStatement(<ForStatement>node, outermostLabeledStatement);
2280                case SyntaxKind.ForInStatement:
2281                    return visitForInStatement(<ForInStatement>node, outermostLabeledStatement);
2282                case SyntaxKind.ForOfStatement:
2283                    return visitForOfStatement(<ForOfStatement>node, outermostLabeledStatement);
2284            }
2285        }
2286
2287        function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter) {
2288            const ancestorFacts = enterSubtree(excludeFacts, includeFacts);
2289            const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, ancestorFacts, convert);
2290            exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
2291            return updated;
2292        }
2293
2294        function visitDoOrWhileStatement(node: DoStatement | WhileStatement, outermostLabeledStatement: LabeledStatement | undefined) {
2295            return visitIterationStatementWithFacts(
2296                HierarchyFacts.DoOrWhileStatementExcludes,
2297                HierarchyFacts.DoOrWhileStatementIncludes,
2298                node,
2299                outermostLabeledStatement);
2300        }
2301
2302        function visitForStatement(node: ForStatement, outermostLabeledStatement: LabeledStatement | undefined) {
2303            return visitIterationStatementWithFacts(
2304                HierarchyFacts.ForStatementExcludes,
2305                HierarchyFacts.ForStatementIncludes,
2306                node,
2307                outermostLabeledStatement);
2308        }
2309
2310        function visitEachChildOfForStatement(node: ForStatement) {
2311            return factory.updateForStatement(
2312                node,
2313                visitNode(node.initializer, visitorWithUnusedExpressionResult, isForInitializer),
2314                visitNode(node.condition, visitor, isExpression),
2315                visitNode(node.incrementor, visitorWithUnusedExpressionResult, isExpression),
2316                visitNode(node.statement, visitor, isStatement, factory.liftToBlock)
2317            );
2318        }
2319
2320        function visitForInStatement(node: ForInStatement, outermostLabeledStatement: LabeledStatement | undefined) {
2321            return visitIterationStatementWithFacts(
2322                HierarchyFacts.ForInOrForOfStatementExcludes,
2323                HierarchyFacts.ForInOrForOfStatementIncludes,
2324                node,
2325                outermostLabeledStatement);
2326        }
2327
2328        function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult<Statement> {
2329            return visitIterationStatementWithFacts(
2330                HierarchyFacts.ForInOrForOfStatementExcludes,
2331                HierarchyFacts.ForInOrForOfStatementIncludes,
2332                node,
2333                outermostLabeledStatement,
2334                compilerOptions.downlevelIteration ? convertForOfStatementForIterable : convertForOfStatementForArray);
2335        }
2336
2337        function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) {
2338            const statements: Statement[] = [];
2339            const initializer = node.initializer;
2340            if (isVariableDeclarationList(initializer)) {
2341                if (node.initializer.flags & NodeFlags.BlockScoped) {
2342                    enableSubstitutionsForBlockScopedBindings();
2343                }
2344
2345                const firstOriginalDeclaration = firstOrUndefined(initializer.declarations);
2346                if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) {
2347                    // This works whether the declaration is a var, let, or const.
2348                    // It will use rhsIterationValue _a[_i] as the initializer.
2349                    const declarations = flattenDestructuringBinding(
2350                        firstOriginalDeclaration,
2351                        visitor,
2352                        context,
2353                        FlattenLevel.All,
2354                        boundValue
2355                    );
2356
2357                    const declarationList = setTextRange(factory.createVariableDeclarationList(declarations), node.initializer);
2358                    setOriginalNode(declarationList, node.initializer);
2359
2360                    // Adjust the source map range for the first declaration to align with the old
2361                    // emitter.
2362                    setSourceMapRange(declarationList, createRange(declarations[0].pos, last(declarations).end));
2363
2364                    statements.push(
2365                        factory.createVariableStatement(
2366                            /*modifiers*/ undefined,
2367                            declarationList
2368                        )
2369                    );
2370                }
2371                else {
2372                    // The following call does not include the initializer, so we have
2373                    // to emit it separately.
2374                    statements.push(
2375                        setTextRange(
2376                            factory.createVariableStatement(
2377                                /*modifiers*/ undefined,
2378                                setOriginalNode(
2379                                    setTextRange(
2380                                        factory.createVariableDeclarationList([
2381                                            factory.createVariableDeclaration(
2382                                                firstOriginalDeclaration ? firstOriginalDeclaration.name : factory.createTempVariable(/*recordTempVariable*/ undefined),
2383                                                /*exclamationToken*/ undefined,
2384                                                /*type*/ undefined,
2385                                                boundValue
2386                                            )
2387                                        ]),
2388                                        moveRangePos(initializer, -1)
2389                                    ),
2390                                    initializer
2391                                )
2392                            ),
2393                            moveRangeEnd(initializer, -1)
2394                        )
2395                    );
2396                }
2397            }
2398            else {
2399                // Initializer is an expression. Emit the expression in the body, so that it's
2400                // evaluated on every iteration.
2401                const assignment = factory.createAssignment(initializer, boundValue);
2402                if (isDestructuringAssignment(assignment)) {
2403                    statements.push(factory.createExpressionStatement(visitBinaryExpression(assignment, /*expressionResultIsUnused*/ true)));
2404                }
2405                else {
2406                    setTextRangeEnd(assignment, initializer.end);
2407                    statements.push(setTextRange(factory.createExpressionStatement(visitNode(assignment, visitor, isExpression)), moveRangeEnd(initializer, -1)));
2408                }
2409            }
2410
2411            if (convertedLoopBodyStatements) {
2412                return createSyntheticBlockForConvertedStatements(addRange(statements, convertedLoopBodyStatements));
2413            }
2414            else {
2415                const statement = visitNode(node.statement, visitor, isStatement, factory.liftToBlock);
2416                if (isBlock(statement)) {
2417                    return factory.updateBlock(statement, setTextRange(factory.createNodeArray(concatenate(statements, statement.statements)), statement.statements));
2418                }
2419                else {
2420                    statements.push(statement);
2421                    return createSyntheticBlockForConvertedStatements(statements);
2422                }
2423            }
2424        }
2425
2426        function createSyntheticBlockForConvertedStatements(statements: Statement[]) {
2427            return setEmitFlags(
2428                factory.createBlock(
2429                    factory.createNodeArray(statements),
2430                    /*multiLine*/ true
2431                ),
2432                EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps
2433            );
2434        }
2435
2436        function convertForOfStatementForArray(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[]): Statement {
2437            // The following ES6 code:
2438            //
2439            //    for (let v of expr) { }
2440            //
2441            // should be emitted as
2442            //
2443            //    for (var _i = 0, _a = expr; _i < _a.length; _i++) {
2444            //        var v = _a[_i];
2445            //    }
2446            //
2447            // where _a and _i are temps emitted to capture the RHS and the counter,
2448            // respectively.
2449            // When the left hand side is an expression instead of a let declaration,
2450            // the "let v" is not emitted.
2451            // When the left hand side is a let/const, the v is renamed if there is
2452            // another v in scope.
2453            // Note that all assignments to the LHS are emitted in the body, including
2454            // all destructuring.
2455            // Note also that because an extra statement is needed to assign to the LHS,
2456            // for-of bodies are always emitted as blocks.
2457
2458            const expression = visitNode(node.expression, visitor, isExpression);
2459
2460            // In the case where the user wrote an identifier as the RHS, like this:
2461            //
2462            //     for (let v of arr) { }
2463            //
2464            // we don't want to emit a temporary variable for the RHS, just use it directly.
2465            const counter = factory.createLoopVariable();
2466            const rhsReference = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined);
2467
2468            // The old emitter does not emit source maps for the expression
2469            setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression));
2470
2471            const forStatement = setTextRange(
2472                factory.createForStatement(
2473                    /*initializer*/ setEmitFlags(
2474                        setTextRange(
2475                            factory.createVariableDeclarationList([
2476                                setTextRange(factory.createVariableDeclaration(counter, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(0)), moveRangePos(node.expression, -1)),
2477                                setTextRange(factory.createVariableDeclaration(rhsReference, /*exclamationToken*/ undefined, /*type*/ undefined, expression), node.expression)
2478                            ]),
2479                            node.expression
2480                        ),
2481                        EmitFlags.NoHoisting
2482                    ),
2483                    /*condition*/ setTextRange(
2484                        factory.createLessThan(
2485                            counter,
2486                            factory.createPropertyAccessExpression(rhsReference, "length")
2487                        ),
2488                        node.expression
2489                    ),
2490                    /*incrementor*/ setTextRange(factory.createPostfixIncrement(counter), node.expression),
2491                    /*statement*/ convertForOfStatementHead(
2492                        node,
2493                        factory.createElementAccessExpression(rhsReference, counter),
2494                        convertedLoopBodyStatements
2495                    )
2496                ),
2497                /*location*/ node
2498            );
2499
2500            // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter.
2501            setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps);
2502            setTextRange(forStatement, node);
2503            return factory.restoreEnclosingLabel(forStatement, outermostLabeledStatement, convertedLoopState && resetLabel);
2504        }
2505
2506        function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[], ancestorFacts: HierarchyFacts): Statement {
2507            const expression = visitNode(node.expression, visitor, isExpression);
2508            const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined);
2509            const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) : factory.createTempVariable(/*recordTempVariable*/ undefined);
2510            const errorRecord = factory.createUniqueName("e");
2511            const catchVariable = factory.getGeneratedNameForNode(errorRecord);
2512            const returnMethod = factory.createTempVariable(/*recordTempVariable*/ undefined);
2513            const values = setTextRange(emitHelpers().createValuesHelper(expression), node.expression);
2514            const next = factory.createCallExpression(factory.createPropertyAccessExpression(iterator, "next"), /*typeArguments*/ undefined, []);
2515
2516            hoistVariableDeclaration(errorRecord);
2517            hoistVariableDeclaration(returnMethod);
2518
2519            // if we are enclosed in an outer loop ensure we reset 'errorRecord' per each iteration
2520            const initializer = ancestorFacts & HierarchyFacts.IterationContainer
2521                ? factory.inlineExpressions([factory.createAssignment(errorRecord, factory.createVoidZero()), values])
2522                : values;
2523
2524            const forStatement = setEmitFlags(
2525                setTextRange(
2526                    factory.createForStatement(
2527                        /*initializer*/ setEmitFlags(
2528                            setTextRange(
2529                                factory.createVariableDeclarationList([
2530                                    setTextRange(factory.createVariableDeclaration(iterator, /*exclamationToken*/ undefined, /*type*/ undefined, initializer), node.expression),
2531                                    factory.createVariableDeclaration(result, /*exclamationToken*/ undefined, /*type*/ undefined, next)
2532                                ]),
2533                                node.expression
2534                            ),
2535                            EmitFlags.NoHoisting
2536                        ),
2537                        /*condition*/ factory.createLogicalNot(factory.createPropertyAccessExpression(result, "done")),
2538                        /*incrementor*/ factory.createAssignment(result, next),
2539                        /*statement*/ convertForOfStatementHead(
2540                            node,
2541                            factory.createPropertyAccessExpression(result, "value"),
2542                            convertedLoopBodyStatements
2543                        )
2544                    ),
2545                    /*location*/ node
2546                ),
2547                EmitFlags.NoTokenTrailingSourceMaps
2548            );
2549
2550            return factory.createTryStatement(
2551                factory.createBlock([
2552                    factory.restoreEnclosingLabel(
2553                        forStatement,
2554                        outermostLabeledStatement,
2555                        convertedLoopState && resetLabel
2556                    )
2557                ]),
2558                factory.createCatchClause(factory.createVariableDeclaration(catchVariable),
2559                    setEmitFlags(
2560                        factory.createBlock([
2561                            factory.createExpressionStatement(
2562                                factory.createAssignment(
2563                                    errorRecord,
2564                                    factory.createObjectLiteralExpression([
2565                                        factory.createPropertyAssignment("error", catchVariable)
2566                                    ])
2567                                )
2568                            )
2569                        ]),
2570                        EmitFlags.SingleLine
2571                    )
2572                ),
2573                factory.createBlock([
2574                    factory.createTryStatement(
2575                        /*tryBlock*/ factory.createBlock([
2576                            setEmitFlags(
2577                                factory.createIfStatement(
2578                                    factory.createLogicalAnd(
2579                                        factory.createLogicalAnd(
2580                                            result,
2581                                            factory.createLogicalNot(
2582                                                factory.createPropertyAccessExpression(result, "done")
2583                                            )
2584                                        ),
2585                                        factory.createAssignment(
2586                                            returnMethod,
2587                                            factory.createPropertyAccessExpression(iterator, "return")
2588                                        )
2589                                    ),
2590                                    factory.createExpressionStatement(
2591                                        factory.createFunctionCallCall(returnMethod, iterator, [])
2592                                    )
2593                                ),
2594                                EmitFlags.SingleLine
2595                            ),
2596                        ]),
2597                        /*catchClause*/ undefined,
2598                        /*finallyBlock*/ setEmitFlags(
2599                            factory.createBlock([
2600                                setEmitFlags(
2601                                    factory.createIfStatement(
2602                                        errorRecord,
2603                                        factory.createThrowStatement(
2604                                            factory.createPropertyAccessExpression(errorRecord, "error")
2605                                        )
2606                                    ),
2607                                    EmitFlags.SingleLine
2608                                )
2609                            ]),
2610                            EmitFlags.SingleLine
2611                        )
2612                    )
2613                ])
2614            );
2615        }
2616
2617        /**
2618         * Visits an ObjectLiteralExpression with computed property names.
2619         *
2620         * @param node An ObjectLiteralExpression node.
2621         */
2622        function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression {
2623            const properties = node.properties;
2624
2625            // Find the first computed property.
2626            // Everything until that point can be emitted as part of the initial object literal.
2627            let numInitialProperties = -1, hasComputed = false;
2628            for (let i = 0; i < properties.length; i++) {
2629                const property = properties[i];
2630                if ((property.transformFlags & TransformFlags.ContainsYield &&
2631                     hierarchyFacts & HierarchyFacts.AsyncFunctionBody)
2632                    || (hasComputed = Debug.checkDefined(property.name).kind === SyntaxKind.ComputedPropertyName)) {
2633                    numInitialProperties = i;
2634                    break;
2635                }
2636            }
2637
2638            if (numInitialProperties < 0) {
2639                return visitEachChild(node, visitor, context);
2640            }
2641
2642            // For computed properties, we need to create a unique handle to the object
2643            // literal so we can modify it without risking internal assignments tainting the object.
2644            const temp = factory.createTempVariable(hoistVariableDeclaration);
2645
2646            // Write out the first non-computed properties, then emit the rest through indexing on the temp variable.
2647            const expressions: Expression[] = [];
2648            const assignment = factory.createAssignment(
2649                temp,
2650                setEmitFlags(
2651                    factory.createObjectLiteralExpression(
2652                        visitNodes(properties, visitor, isObjectLiteralElementLike, 0, numInitialProperties),
2653                        node.multiLine
2654                    ),
2655                    hasComputed ? EmitFlags.Indented : 0
2656                )
2657            );
2658
2659            if (node.multiLine) {
2660                startOnNewLine(assignment);
2661            }
2662
2663            expressions.push(assignment);
2664
2665            addObjectLiteralMembers(expressions, node, temp, numInitialProperties);
2666
2667            // We need to clone the temporary identifier so that we can write it on a
2668            // new line
2669            expressions.push(node.multiLine ? startOnNewLine(setParent(setTextRange(factory.cloneNode(temp), temp), temp.parent)) : temp);
2670            return factory.inlineExpressions(expressions);
2671        }
2672
2673        interface ForStatementWithConvertibleInitializer extends ForStatement {
2674            initializer: VariableDeclarationList;
2675        }
2676
2677        interface ForStatementWithConvertibleCondition extends ForStatement {
2678            condition: Expression;
2679        }
2680
2681        interface ForStatementWithConvertibleIncrementor extends ForStatement {
2682            incrementor: Expression;
2683        }
2684
2685        function shouldConvertPartOfIterationStatement(node: Node) {
2686            return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsCapturedBlockScopeBinding) !== 0;
2687        }
2688
2689        function shouldConvertInitializerOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleInitializer {
2690            return isForStatement(node) && !!node.initializer && shouldConvertPartOfIterationStatement(node.initializer);
2691        }
2692
2693        function shouldConvertConditionOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleCondition {
2694            return isForStatement(node) && !!node.condition && shouldConvertPartOfIterationStatement(node.condition);
2695        }
2696
2697        function shouldConvertIncrementorOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleIncrementor {
2698            return isForStatement(node) && !!node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor);
2699        }
2700
2701        function shouldConvertIterationStatement(node: IterationStatement) {
2702            return shouldConvertBodyOfIterationStatement(node)
2703                || shouldConvertInitializerOfForStatement(node);
2704        }
2705
2706        function shouldConvertBodyOfIterationStatement(node: IterationStatement): boolean {
2707            return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LoopWithCapturedBlockScopedBinding) !== 0;
2708        }
2709
2710        /**
2711         * Records constituents of name for the given variable to be hoisted in the outer scope.
2712         */
2713        function hoistVariableDeclarationDeclaredInConvertedLoop(state: ConvertedLoopState, node: VariableDeclaration): void {
2714            if (!state.hoistedLocalVariables) {
2715                state.hoistedLocalVariables = [];
2716            }
2717
2718            visit(node.name);
2719
2720            function visit(node: Identifier | BindingPattern) {
2721                if (node.kind === SyntaxKind.Identifier) {
2722                    state.hoistedLocalVariables!.push(node);
2723                }
2724                else {
2725                    for (const element of node.elements) {
2726                        if (!isOmittedExpression(element)) {
2727                            visit(element.name);
2728                        }
2729                    }
2730                }
2731            }
2732        }
2733
2734        function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convert?: LoopConverter): VisitResult<Statement> {
2735            if (!shouldConvertIterationStatement(node)) {
2736                let saveAllowedNonLabeledJumps: Jump | undefined;
2737                if (convertedLoopState) {
2738                    // we get here if we are trying to emit normal loop loop inside converted loop
2739                    // set allowedNonLabeledJumps to Break | Continue to mark that break\continue inside the loop should be emitted as is
2740                    saveAllowedNonLabeledJumps = convertedLoopState.allowedNonLabeledJumps;
2741                    convertedLoopState.allowedNonLabeledJumps = Jump.Break | Jump.Continue;
2742                }
2743
2744                const result = convert
2745                    ? convert(node, outermostLabeledStatement, /*convertedLoopBodyStatements*/ undefined, ancestorFacts)
2746                    : factory.restoreEnclosingLabel(
2747                        isForStatement(node) ? visitEachChildOfForStatement(node) : visitEachChild(node, visitor, context),
2748                        outermostLabeledStatement,
2749                        convertedLoopState && resetLabel);
2750
2751                if (convertedLoopState) {
2752                    convertedLoopState.allowedNonLabeledJumps = saveAllowedNonLabeledJumps;
2753                }
2754                return result;
2755            }
2756
2757            const currentState = createConvertedLoopState(node);
2758            const statements: Statement[] = [];
2759
2760            const outerConvertedLoopState = convertedLoopState;
2761            convertedLoopState = currentState;
2762
2763            const initializerFunction = shouldConvertInitializerOfForStatement(node) ? createFunctionForInitializerOfForStatement(node, currentState) : undefined;
2764            const bodyFunction = shouldConvertBodyOfIterationStatement(node) ? createFunctionForBodyOfIterationStatement(node, currentState, outerConvertedLoopState) : undefined;
2765
2766            convertedLoopState = outerConvertedLoopState;
2767
2768            if (initializerFunction) statements.push(initializerFunction.functionDeclaration);
2769            if (bodyFunction) statements.push(bodyFunction.functionDeclaration);
2770
2771            addExtraDeclarationsForConvertedLoop(statements, currentState, outerConvertedLoopState);
2772
2773            if (initializerFunction) {
2774                statements.push(generateCallToConvertedLoopInitializer(initializerFunction.functionName, initializerFunction.containsYield));
2775            }
2776
2777            let loop: Statement;
2778            if (bodyFunction) {
2779                if (convert) {
2780                    loop = convert(node, outermostLabeledStatement, bodyFunction.part, ancestorFacts);
2781                }
2782                else {
2783                    const clone = convertIterationStatementCore(node, initializerFunction, factory.createBlock(bodyFunction.part, /*multiLine*/ true));
2784                    loop = factory.restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
2785                }
2786            }
2787            else {
2788                const clone = convertIterationStatementCore(node, initializerFunction, visitNode(node.statement, visitor, isStatement, factory.liftToBlock));
2789                loop = factory.restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
2790            }
2791
2792            statements.push(loop);
2793            return statements;
2794        }
2795
2796        function convertIterationStatementCore(node: IterationStatement, initializerFunction: IterationStatementPartFunction<VariableDeclarationList> | undefined, convertedLoopBody: Statement) {
2797            switch (node.kind) {
2798                case SyntaxKind.ForStatement: return convertForStatement(node as ForStatement, initializerFunction, convertedLoopBody);
2799                case SyntaxKind.ForInStatement: return convertForInStatement(node as ForInStatement, convertedLoopBody);
2800                case SyntaxKind.ForOfStatement: return convertForOfStatement(node as ForOfStatement, convertedLoopBody);
2801                case SyntaxKind.DoStatement: return convertDoStatement(node as DoStatement, convertedLoopBody);
2802                case SyntaxKind.WhileStatement: return convertWhileStatement(node as WhileStatement, convertedLoopBody);
2803                default: return Debug.failBadSyntaxKind(node, "IterationStatement expected");
2804            }
2805        }
2806
2807        function convertForStatement(node: ForStatement, initializerFunction: IterationStatementPartFunction<VariableDeclarationList> | undefined, convertedLoopBody: Statement) {
2808            const shouldConvertCondition = node.condition && shouldConvertPartOfIterationStatement(node.condition);
2809            const shouldConvertIncrementor = shouldConvertCondition || node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor);
2810            return factory.updateForStatement(
2811                node,
2812                visitNode(initializerFunction ? initializerFunction.part : node.initializer, visitorWithUnusedExpressionResult, isForInitializer),
2813                visitNode(shouldConvertCondition ? undefined : node.condition, visitor, isExpression),
2814                visitNode(shouldConvertIncrementor ? undefined : node.incrementor, visitorWithUnusedExpressionResult, isExpression),
2815                convertedLoopBody
2816            );
2817        }
2818
2819        function convertForOfStatement(node: ForOfStatement, convertedLoopBody: Statement) {
2820            return factory.updateForOfStatement(
2821                node,
2822                /*awaitModifier*/ undefined,
2823                visitNode(node.initializer, visitor, isForInitializer),
2824                visitNode(node.expression, visitor, isExpression),
2825                convertedLoopBody);
2826        }
2827
2828        function convertForInStatement(node: ForInStatement, convertedLoopBody: Statement) {
2829            return factory.updateForInStatement(
2830                node,
2831                visitNode(node.initializer, visitor, isForInitializer),
2832                visitNode(node.expression, visitor, isExpression),
2833                convertedLoopBody);
2834        }
2835
2836        function convertDoStatement(node: DoStatement, convertedLoopBody: Statement) {
2837            return factory.updateDoStatement(
2838                node,
2839                convertedLoopBody,
2840                visitNode(node.expression, visitor, isExpression));
2841        }
2842
2843        function convertWhileStatement(node: WhileStatement, convertedLoopBody: Statement) {
2844            return factory.updateWhileStatement(
2845                node,
2846                visitNode(node.expression, visitor, isExpression),
2847                convertedLoopBody);
2848        }
2849
2850        function createConvertedLoopState(node: IterationStatement) {
2851            let loopInitializer: VariableDeclarationList | undefined;
2852            switch (node.kind) {
2853                case SyntaxKind.ForStatement:
2854                case SyntaxKind.ForInStatement:
2855                case SyntaxKind.ForOfStatement:
2856                    const initializer = (<ForStatement | ForInStatement | ForOfStatement>node).initializer;
2857                    if (initializer && initializer.kind === SyntaxKind.VariableDeclarationList) {
2858                        loopInitializer = <VariableDeclarationList>initializer;
2859                    }
2860                    break;
2861            }
2862
2863            // variables that will be passed to the loop as parameters
2864            const loopParameters: ParameterDeclaration[] = [];
2865            // variables declared in the loop initializer that will be changed inside the loop
2866            const loopOutParameters: LoopOutParameter[] = [];
2867            if (loopInitializer && (getCombinedNodeFlags(loopInitializer) & NodeFlags.BlockScoped)) {
2868                const hasCapturedBindingsInForInitializer = shouldConvertInitializerOfForStatement(node);
2869                for (const decl of loopInitializer.declarations) {
2870                    processLoopVariableDeclaration(node, decl, loopParameters, loopOutParameters, hasCapturedBindingsInForInitializer);
2871                }
2872            }
2873
2874            const currentState: ConvertedLoopState = { loopParameters, loopOutParameters };
2875            if (convertedLoopState) {
2876                // convertedOuterLoopState !== undefined means that this converted loop is nested in another converted loop.
2877                // if outer converted loop has already accumulated some state - pass it through
2878                if (convertedLoopState.argumentsName) {
2879                    // outer loop has already used 'arguments' so we've already have some name to alias it
2880                    // use the same name in all nested loops
2881                    currentState.argumentsName = convertedLoopState.argumentsName;
2882                }
2883                if (convertedLoopState.thisName) {
2884                    // outer loop has already used 'this' so we've already have some name to alias it
2885                    // use the same name in all nested loops
2886                    currentState.thisName = convertedLoopState.thisName;
2887                }
2888                if (convertedLoopState.hoistedLocalVariables) {
2889                    // we've already collected some non-block scoped variable declarations in enclosing loop
2890                    // use the same storage in nested loop
2891                    currentState.hoistedLocalVariables = convertedLoopState.hoistedLocalVariables;
2892                }
2893            }
2894            return currentState;
2895        }
2896
2897        function addExtraDeclarationsForConvertedLoop(statements: Statement[], state: ConvertedLoopState, outerState: ConvertedLoopState | undefined) {
2898            let extraVariableDeclarations: VariableDeclaration[] | undefined;
2899            // propagate state from the inner loop to the outer loop if necessary
2900            if (state.argumentsName) {
2901                // if alias for arguments is set
2902                if (outerState) {
2903                    // pass it to outer converted loop
2904                    outerState.argumentsName = state.argumentsName;
2905                }
2906                else {
2907                    // this is top level converted loop and we need to create an alias for 'arguments' object
2908                    (extraVariableDeclarations || (extraVariableDeclarations = [])).push(
2909                        factory.createVariableDeclaration(
2910                            state.argumentsName,
2911                            /*exclamationToken*/ undefined,
2912                            /*type*/ undefined,
2913                            factory.createIdentifier("arguments")
2914                        )
2915                    );
2916                }
2917            }
2918
2919            if (state.thisName) {
2920                // if alias for this is set
2921                if (outerState) {
2922                    // pass it to outer converted loop
2923                    outerState.thisName = state.thisName;
2924                }
2925                else {
2926                    // this is top level converted loop so we need to create an alias for 'this' here
2927                    // NOTE:
2928                    // if converted loops were all nested in arrow function then we'll always emit '_this' so convertedLoopState.thisName will not be set.
2929                    // If it is set this means that all nested loops are not nested in arrow function and it is safe to capture 'this'.
2930                    (extraVariableDeclarations || (extraVariableDeclarations = [])).push(
2931                        factory.createVariableDeclaration(
2932                            state.thisName,
2933                            /*exclamationToken*/ undefined,
2934                            /*type*/ undefined,
2935                            factory.createIdentifier("this")
2936                        )
2937                    );
2938                }
2939            }
2940
2941            if (state.hoistedLocalVariables) {
2942                // if hoistedLocalVariables !== undefined this means that we've possibly collected some variable declarations to be hoisted later
2943                if (outerState) {
2944                    // pass them to outer converted loop
2945                    outerState.hoistedLocalVariables = state.hoistedLocalVariables;
2946                }
2947                else {
2948                    if (!extraVariableDeclarations) {
2949                        extraVariableDeclarations = [];
2950                    }
2951                    // hoist collected variable declarations
2952                    for (const identifier of state.hoistedLocalVariables) {
2953                        extraVariableDeclarations.push(factory.createVariableDeclaration(identifier));
2954                    }
2955                }
2956            }
2957
2958            // add extra variables to hold out parameters if necessary
2959            if (state.loopOutParameters.length) {
2960                if (!extraVariableDeclarations) {
2961                    extraVariableDeclarations = [];
2962                }
2963                for (const outParam of state.loopOutParameters) {
2964                    extraVariableDeclarations.push(factory.createVariableDeclaration(outParam.outParamName));
2965                }
2966            }
2967
2968            if (state.conditionVariable) {
2969                if (!extraVariableDeclarations) {
2970                    extraVariableDeclarations = [];
2971                }
2972                extraVariableDeclarations.push(factory.createVariableDeclaration(state.conditionVariable, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createFalse()));
2973            }
2974
2975            // create variable statement to hold all introduced variable declarations
2976            if (extraVariableDeclarations) {
2977                statements.push(factory.createVariableStatement(
2978                    /*modifiers*/ undefined,
2979                    factory.createVariableDeclarationList(extraVariableDeclarations)
2980                ));
2981            }
2982        }
2983
2984        interface IterationStatementPartFunction<T> {
2985            functionName: Identifier;
2986            functionDeclaration: Statement;
2987            containsYield: boolean;
2988            part: T;
2989        }
2990
2991        function createOutVariable(p: LoopOutParameter) {
2992            return factory.createVariableDeclaration(p.originalName, /*exclamationToken*/ undefined, /*type*/ undefined, p.outParamName);
2993        }
2994
2995        /**
2996         * Creates a `_loop_init` function for a `ForStatement` with a block-scoped initializer
2997         * that is captured in a closure inside of the initializer. The `_loop_init` function is
2998         * used to preserve the per-iteration environment semantics of
2999         * [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation).
3000         */
3001        function createFunctionForInitializerOfForStatement(node: ForStatementWithConvertibleInitializer, currentState: ConvertedLoopState): IterationStatementPartFunction<VariableDeclarationList> {
3002            const functionName = factory.createUniqueName("_loop_init");
3003
3004            const containsYield = (node.initializer.transformFlags & TransformFlags.ContainsYield) !== 0;
3005            let emitFlags = EmitFlags.None;
3006            if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis;
3007            if (containsYield && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) emitFlags |= EmitFlags.AsyncFunctionBody;
3008
3009            const statements: Statement[] = [];
3010            statements.push(factory.createVariableStatement(/*modifiers*/ undefined, node.initializer));
3011            copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Initializer, CopyDirection.ToOutParameter, statements);
3012
3013            // This transforms the following ES2015 syntax:
3014            //
3015            //  for (let i = (setImmediate(() => console.log(i)), 0); i < 2; i++) {
3016            //      // loop body
3017            //  }
3018            //
3019            // Into the following ES5 syntax:
3020            //
3021            //  var _loop_init_1 = function () {
3022            //      var i = (setImmediate(() => console.log(i)), 0);
3023            //      out_i_1 = i;
3024            //  };
3025            //  var out_i_1;
3026            //  _loop_init_1();
3027            //  for (var i = out_i_1; i < 2; i++) {
3028            //      // loop body
3029            //  }
3030            //
3031            // Which prevents mutations to `i` in the per-iteration environment of the body
3032            // from affecting the initial value for `i` outside of the per-iteration environment.
3033
3034            const functionDeclaration = factory.createVariableStatement(
3035                /*modifiers*/ undefined,
3036                setEmitFlags(
3037                    factory.createVariableDeclarationList([
3038                        factory.createVariableDeclaration(
3039                            functionName,
3040                            /*exclamationToken*/ undefined,
3041                            /*type*/ undefined,
3042                            setEmitFlags(
3043                                factory.createFunctionExpression(
3044                                    /*modifiers*/ undefined,
3045                                    containsYield ? factory.createToken(SyntaxKind.AsteriskToken) : undefined,
3046                                    /*name*/ undefined,
3047                                    /*typeParameters*/ undefined,
3048                                    /*parameters*/ undefined,
3049                                    /*type*/ undefined,
3050                                    visitNode(
3051                                        factory.createBlock(statements, /*multiLine*/ true),
3052                                        visitor,
3053                                        isBlock
3054                                    )
3055                                ),
3056                                emitFlags
3057                            )
3058                        )
3059                    ]),
3060                    EmitFlags.NoHoisting
3061                )
3062            );
3063
3064            const part = factory.createVariableDeclarationList(map(currentState.loopOutParameters, createOutVariable));
3065            return { functionName, containsYield, functionDeclaration, part };
3066        }
3067
3068        /**
3069         * Creates a `_loop` function for an `IterationStatement` with a block-scoped initializer
3070         * that is captured in a closure inside of the loop body. The `_loop` function is used to
3071         * preserve the per-iteration environment semantics of
3072         * [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation).
3073         */
3074        function createFunctionForBodyOfIterationStatement(node: IterationStatement, currentState: ConvertedLoopState, outerState: ConvertedLoopState | undefined): IterationStatementPartFunction<Statement[]> {
3075            const functionName = factory.createUniqueName("_loop");
3076            startLexicalEnvironment();
3077            const statement = visitNode(node.statement, visitor, isStatement, factory.liftToBlock);
3078            const lexicalEnvironment = endLexicalEnvironment();
3079
3080            const statements: Statement[] = [];
3081            if (shouldConvertConditionOfForStatement(node) || shouldConvertIncrementorOfForStatement(node)) {
3082                // If a block-scoped variable declared in the initializer of `node` is captured in
3083                // the condition or incrementor, we must move the condition and incrementor into
3084                // the body of the for loop.
3085                //
3086                // This transforms the following ES2015 syntax:
3087                //
3088                //  for (let i = 0; setImmediate(() => console.log(i)), i < 2; setImmediate(() => console.log(i)), i++) {
3089                //      // loop body
3090                //  }
3091                //
3092                // Into the following ES5 syntax:
3093                //
3094                //  var _loop_1 = function (i) {
3095                //      if (inc_1)
3096                //          setImmediate(() => console.log(i)), i++;
3097                //      else
3098                //          inc_1 = true;
3099                //      if (!(setImmediate(() => console.log(i)), i < 2))
3100                //          return out_i_1 = i, "break";
3101                //      // loop body
3102                //      out_i_1 = i;
3103                //  }
3104                //  var out_i_1, inc_1 = false;
3105                //  for (var i = 0;;) {
3106                //      var state_1 = _loop_1(i);
3107                //      i = out_i_1;
3108                //      if (state_1 === "break")
3109                //          break;
3110                //  }
3111                //
3112                // Which prevents mutations to `i` in the per-iteration environment of the body
3113                // from affecting the value of `i` in the previous per-iteration environment.
3114                //
3115                // Note that the incrementor of a `for` loop is evaluated in a *new* per-iteration
3116                // environment that is carried over to the next iteration of the loop. As a result,
3117                // we must indicate whether this is the first evaluation of the loop body so that
3118                // we only evaluate the incrementor on subsequent evaluations.
3119
3120                currentState.conditionVariable = factory.createUniqueName("inc");
3121                if (node.incrementor) {
3122                    statements.push(factory.createIfStatement(
3123                        currentState.conditionVariable,
3124                        factory.createExpressionStatement(visitNode(node.incrementor, visitor, isExpression)),
3125                        factory.createExpressionStatement(factory.createAssignment(currentState.conditionVariable, factory.createTrue()))
3126                    ));
3127                }
3128                else {
3129                    statements.push(factory.createIfStatement(
3130                        factory.createLogicalNot(currentState.conditionVariable),
3131                        factory.createExpressionStatement(factory.createAssignment(currentState.conditionVariable, factory.createTrue()))
3132                    ));
3133                }
3134
3135                if (shouldConvertConditionOfForStatement(node)) {
3136                    statements.push(factory.createIfStatement(
3137                        factory.createPrefixUnaryExpression(SyntaxKind.ExclamationToken, visitNode(node.condition, visitor, isExpression)),
3138                        visitNode(factory.createBreakStatement(), visitor, isStatement)
3139                    ));
3140                }
3141            }
3142
3143            if (isBlock(statement)) {
3144                addRange(statements, statement.statements);
3145            }
3146            else {
3147                statements.push(statement);
3148            }
3149
3150            copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOutParameter, statements);
3151            insertStatementsAfterStandardPrologue(statements, lexicalEnvironment);
3152
3153            const loopBody = factory.createBlock(statements, /*multiLine*/ true);
3154            if (isBlock(statement)) setOriginalNode(loopBody, statement);
3155
3156            const containsYield = (node.statement.transformFlags & TransformFlags.ContainsYield) !== 0;
3157
3158            let emitFlags: EmitFlags = EmitFlags.ReuseTempVariableScope;
3159            if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis;
3160            if (containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0) emitFlags |= EmitFlags.AsyncFunctionBody;
3161
3162            // This transforms the following ES2015 syntax (in addition to other variations):
3163            //
3164            //  for (let i = 0; i < 2; i++) {
3165            //      setImmediate(() => console.log(i));
3166            //  }
3167            //
3168            // Into the following ES5 syntax:
3169            //
3170            //  var _loop_1 = function (i) {
3171            //      setImmediate(() => console.log(i));
3172            //  };
3173            //  for (var i = 0; i < 2; i++) {
3174            //      _loop_1(i);
3175            //  }
3176
3177            const functionDeclaration =
3178                factory.createVariableStatement(
3179                    /*modifiers*/ undefined,
3180                    setEmitFlags(
3181                        factory.createVariableDeclarationList(
3182                            [
3183                                factory.createVariableDeclaration(
3184                                    functionName,
3185                                    /*exclamationToken*/ undefined,
3186                                    /*type*/ undefined,
3187                                    setEmitFlags(
3188                                        factory.createFunctionExpression(
3189                                            /*modifiers*/ undefined,
3190                                            containsYield ? factory.createToken(SyntaxKind.AsteriskToken) : undefined,
3191                                            /*name*/ undefined,
3192                                            /*typeParameters*/ undefined,
3193                                            currentState.loopParameters,
3194                                            /*type*/ undefined,
3195                                            loopBody
3196                                        ),
3197                                        emitFlags
3198                                    )
3199                                )
3200                            ]
3201                        ),
3202                        EmitFlags.NoHoisting
3203                    )
3204                );
3205
3206            const part = generateCallToConvertedLoop(functionName, currentState, outerState, containsYield);
3207            return { functionName, containsYield, functionDeclaration, part };
3208        }
3209
3210        function copyOutParameter(outParam: LoopOutParameter, copyDirection: CopyDirection): BinaryExpression {
3211            const source = copyDirection === CopyDirection.ToOriginal ? outParam.outParamName : outParam.originalName;
3212            const target = copyDirection === CopyDirection.ToOriginal ? outParam.originalName : outParam.outParamName;
3213            return factory.createBinaryExpression(target, SyntaxKind.EqualsToken, source);
3214        }
3215
3216        function copyOutParameters(outParams: LoopOutParameter[], partFlags: LoopOutParameterFlags, copyDirection: CopyDirection, statements: Statement[]): void {
3217            for (const outParam of outParams) {
3218                if (outParam.flags & partFlags) {
3219                    statements.push(factory.createExpressionStatement(copyOutParameter(outParam, copyDirection)));
3220                }
3221            }
3222        }
3223
3224        function generateCallToConvertedLoopInitializer(initFunctionExpressionName: Identifier, containsYield: boolean): Statement {
3225            const call = factory.createCallExpression(initFunctionExpressionName, /*typeArguments*/ undefined, []);
3226            const callResult = containsYield
3227                ? factory.createYieldExpression(
3228                    factory.createToken(SyntaxKind.AsteriskToken),
3229                    setEmitFlags(call, EmitFlags.Iterator)
3230                )
3231                : call;
3232            return factory.createExpressionStatement(callResult);
3233        }
3234
3235        function generateCallToConvertedLoop(loopFunctionExpressionName: Identifier, state: ConvertedLoopState, outerState: ConvertedLoopState | undefined, containsYield: boolean): Statement[] {
3236
3237            const statements: Statement[] = [];
3238            // loop is considered simple if it does not have any return statements or break\continue that transfer control outside of the loop
3239            // simple loops are emitted as just 'loop()';
3240            // NOTE: if loop uses only 'continue' it still will be emitted as simple loop
3241            const isSimpleLoop =
3242                !(state.nonLocalJumps! & ~Jump.Continue) &&
3243                !state.labeledNonLocalBreaks &&
3244                !state.labeledNonLocalContinues;
3245
3246            const call = factory.createCallExpression(loopFunctionExpressionName, /*typeArguments*/ undefined, map(state.loopParameters, p => <Identifier>p.name));
3247            const callResult = containsYield
3248                ? factory.createYieldExpression(
3249                    factory.createToken(SyntaxKind.AsteriskToken),
3250                    setEmitFlags(call, EmitFlags.Iterator)
3251                )
3252                : call;
3253            if (isSimpleLoop) {
3254                statements.push(factory.createExpressionStatement(callResult));
3255                copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements);
3256            }
3257            else {
3258                const loopResultName = factory.createUniqueName("state");
3259                const stateVariable = factory.createVariableStatement(
3260                    /*modifiers*/ undefined,
3261                    factory.createVariableDeclarationList(
3262                        [factory.createVariableDeclaration(loopResultName, /*exclamationToken*/ undefined, /*type*/ undefined, callResult)]
3263                    )
3264                );
3265                statements.push(stateVariable);
3266                copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements);
3267
3268                if (state.nonLocalJumps! & Jump.Return) {
3269                    let returnStatement: ReturnStatement;
3270                    if (outerState) {
3271                        outerState.nonLocalJumps! |= Jump.Return;
3272                        returnStatement = factory.createReturnStatement(loopResultName);
3273                    }
3274                    else {
3275                        returnStatement = factory.createReturnStatement(factory.createPropertyAccessExpression(loopResultName, "value"));
3276                    }
3277                    statements.push(
3278                        factory.createIfStatement(
3279                            factory.createTypeCheck(loopResultName, "object"),
3280                            returnStatement
3281                        )
3282                    );
3283                }
3284
3285                if (state.nonLocalJumps! & Jump.Break) {
3286                    statements.push(
3287                        factory.createIfStatement(
3288                            factory.createStrictEquality(
3289                                loopResultName,
3290                                factory.createStringLiteral("break")
3291                            ),
3292                            factory.createBreakStatement()
3293                        )
3294                    );
3295                }
3296
3297                if (state.labeledNonLocalBreaks || state.labeledNonLocalContinues) {
3298                    const caseClauses: CaseClause[] = [];
3299                    processLabeledJumps(state.labeledNonLocalBreaks!, /*isBreak*/ true, loopResultName, outerState, caseClauses);
3300                    processLabeledJumps(state.labeledNonLocalContinues!, /*isBreak*/ false, loopResultName, outerState, caseClauses);
3301                    statements.push(
3302                        factory.createSwitchStatement(
3303                            loopResultName,
3304                            factory.createCaseBlock(caseClauses)
3305                        )
3306                    );
3307                }
3308            }
3309            return statements;
3310        }
3311
3312        function setLabeledJump(state: ConvertedLoopState, isBreak: boolean, labelText: string, labelMarker: string): void {
3313            if (isBreak) {
3314                if (!state.labeledNonLocalBreaks) {
3315                    state.labeledNonLocalBreaks = new Map<string, string>();
3316                }
3317                state.labeledNonLocalBreaks.set(labelText, labelMarker);
3318            }
3319            else {
3320                if (!state.labeledNonLocalContinues) {
3321                    state.labeledNonLocalContinues = new Map<string, string>();
3322                }
3323                state.labeledNonLocalContinues.set(labelText, labelMarker);
3324            }
3325        }
3326
3327        function processLabeledJumps(table: ESMap<string, string>, isBreak: boolean, loopResultName: Identifier, outerLoop: ConvertedLoopState | undefined, caseClauses: CaseClause[]): void {
3328            if (!table) {
3329                return;
3330            }
3331            table.forEach((labelMarker, labelText) => {
3332                const statements: Statement[] = [];
3333                // if there are no outer converted loop or outer label in question is located inside outer converted loop
3334                // then emit labeled break\continue
3335                // otherwise propagate pair 'label -> marker' to outer converted loop and emit 'return labelMarker' so outer loop can later decide what to do
3336                if (!outerLoop || (outerLoop.labels && outerLoop.labels.get(labelText))) {
3337                    const label = factory.createIdentifier(labelText);
3338                    statements.push(isBreak ? factory.createBreakStatement(label) : factory.createContinueStatement(label));
3339                }
3340                else {
3341                    setLabeledJump(outerLoop, isBreak, labelText, labelMarker);
3342                    statements.push(factory.createReturnStatement(loopResultName));
3343                }
3344                caseClauses.push(factory.createCaseClause(factory.createStringLiteral(labelMarker), statements));
3345            });
3346        }
3347
3348        function processLoopVariableDeclaration(container: IterationStatement, decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[], hasCapturedBindingsInForInitializer: boolean) {
3349            const name = decl.name;
3350            if (isBindingPattern(name)) {
3351                for (const element of name.elements) {
3352                    if (!isOmittedExpression(element)) {
3353                        processLoopVariableDeclaration(container, element, loopParameters, loopOutParameters, hasCapturedBindingsInForInitializer);
3354                    }
3355                }
3356            }
3357            else {
3358                loopParameters.push(factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
3359                const checkFlags = resolver.getNodeCheckFlags(decl);
3360                if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForInitializer) {
3361                    const outParamName = factory.createUniqueName("out_" + idText(name));
3362                    let flags: LoopOutParameterFlags = 0;
3363                    if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter) {
3364                        flags |= LoopOutParameterFlags.Body;
3365                    }
3366                    if (isForStatement(container) && container.initializer && resolver.isBindingCapturedByNode(container.initializer, decl)) {
3367                        flags |= LoopOutParameterFlags.Initializer;
3368                    }
3369                    loopOutParameters.push({ flags, originalName: name, outParamName });
3370                }
3371            }
3372        }
3373
3374        /**
3375         * Adds the members of an object literal to an array of expressions.
3376         *
3377         * @param expressions An array of expressions.
3378         * @param node An ObjectLiteralExpression node.
3379         * @param receiver The receiver for members of the ObjectLiteralExpression.
3380         * @param numInitialNonComputedProperties The number of initial properties without
3381         *                                        computed property names.
3382         */
3383        function addObjectLiteralMembers(expressions: Expression[], node: ObjectLiteralExpression, receiver: Identifier, start: number) {
3384            const properties = node.properties;
3385            const numProperties = properties.length;
3386            for (let i = start; i < numProperties; i++) {
3387                const property = properties[i];
3388                switch (property.kind) {
3389                    case SyntaxKind.GetAccessor:
3390                    case SyntaxKind.SetAccessor:
3391                        const accessors = getAllAccessorDeclarations(node.properties, property);
3392                        if (property === accessors.firstAccessor) {
3393                            expressions.push(transformAccessorsToExpression(receiver, accessors, node, !!node.multiLine));
3394                        }
3395
3396                        break;
3397
3398                    case SyntaxKind.MethodDeclaration:
3399                        expressions.push(transformObjectLiteralMethodDeclarationToExpression(property, receiver, node, node.multiLine!));
3400                        break;
3401
3402                    case SyntaxKind.PropertyAssignment:
3403                        expressions.push(transformPropertyAssignmentToExpression(property, receiver, node.multiLine!));
3404                        break;
3405
3406                    case SyntaxKind.ShorthandPropertyAssignment:
3407                        expressions.push(transformShorthandPropertyAssignmentToExpression(property, receiver, node.multiLine!));
3408                        break;
3409
3410                    default:
3411                        Debug.failBadSyntaxKind(node);
3412                        break;
3413                }
3414            }
3415        }
3416
3417        /**
3418         * Transforms a PropertyAssignment node into an expression.
3419         *
3420         * @param node The ObjectLiteralExpression that contains the PropertyAssignment.
3421         * @param property The PropertyAssignment node.
3422         * @param receiver The receiver for the assignment.
3423         */
3424        function transformPropertyAssignmentToExpression(property: PropertyAssignment, receiver: Expression, startsOnNewLine: boolean) {
3425            const expression = factory.createAssignment(
3426                createMemberAccessForPropertyName(
3427                    factory,
3428                    receiver,
3429                    visitNode(property.name, visitor, isPropertyName)
3430                ),
3431                visitNode(property.initializer, visitor, isExpression)
3432            );
3433            setTextRange(expression, property);
3434            if (startsOnNewLine) {
3435                startOnNewLine(expression);
3436            }
3437            return expression;
3438        }
3439
3440        /**
3441         * Transforms a ShorthandPropertyAssignment node into an expression.
3442         *
3443         * @param node The ObjectLiteralExpression that contains the ShorthandPropertyAssignment.
3444         * @param property The ShorthandPropertyAssignment node.
3445         * @param receiver The receiver for the assignment.
3446         */
3447        function transformShorthandPropertyAssignmentToExpression(property: ShorthandPropertyAssignment, receiver: Expression, startsOnNewLine: boolean) {
3448            const expression = factory.createAssignment(
3449                createMemberAccessForPropertyName(
3450                    factory,
3451                    receiver,
3452                    visitNode(property.name, visitor, isPropertyName)
3453                ),
3454                factory.cloneNode(property.name)
3455            );
3456            setTextRange(expression, property);
3457            if (startsOnNewLine) {
3458                startOnNewLine(expression);
3459            }
3460            return expression;
3461        }
3462
3463        /**
3464         * Transforms a MethodDeclaration of an ObjectLiteralExpression into an expression.
3465         *
3466         * @param node The ObjectLiteralExpression that contains the MethodDeclaration.
3467         * @param method The MethodDeclaration node.
3468         * @param receiver The receiver for the assignment.
3469         */
3470        function transformObjectLiteralMethodDeclarationToExpression(method: MethodDeclaration, receiver: Expression, container: Node, startsOnNewLine: boolean) {
3471            const expression = factory.createAssignment(
3472                createMemberAccessForPropertyName(
3473                    factory,
3474                    receiver,
3475                    visitNode(method.name, visitor, isPropertyName)
3476                ),
3477                transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined, container)
3478            );
3479            setTextRange(expression, method);
3480            if (startsOnNewLine) {
3481                startOnNewLine(expression);
3482            }
3483            return expression;
3484        }
3485
3486        function visitCatchClause(node: CatchClause): CatchClause {
3487            const ancestorFacts = enterSubtree(HierarchyFacts.BlockScopeExcludes, HierarchyFacts.BlockScopeIncludes);
3488            let updated: CatchClause;
3489            Debug.assert(!!node.variableDeclaration, "Catch clause variable should always be present when downleveling ES2015.");
3490            if (isBindingPattern(node.variableDeclaration.name)) {
3491                const temp = factory.createTempVariable(/*recordTempVariable*/ undefined);
3492                const newVariableDeclaration = factory.createVariableDeclaration(temp);
3493                setTextRange(newVariableDeclaration, node.variableDeclaration);
3494                const vars = flattenDestructuringBinding(
3495                    node.variableDeclaration,
3496                    visitor,
3497                    context,
3498                    FlattenLevel.All,
3499                    temp
3500                );
3501                const list = factory.createVariableDeclarationList(vars);
3502                setTextRange(list, node.variableDeclaration);
3503                const destructure = factory.createVariableStatement(/*modifiers*/ undefined, list);
3504                updated = factory.updateCatchClause(node, newVariableDeclaration, addStatementToStartOfBlock(node.block, destructure));
3505            }
3506            else {
3507                updated = visitEachChild(node, visitor, context);
3508            }
3509
3510            exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
3511            return updated;
3512        }
3513
3514        function addStatementToStartOfBlock(block: Block, statement: Statement): Block {
3515            const transformedStatements = visitNodes(block.statements, visitor, isStatement);
3516            return factory.updateBlock(block, [statement, ...transformedStatements]);
3517        }
3518
3519        /**
3520         * Visits a MethodDeclaration of an ObjectLiteralExpression and transforms it into a
3521         * PropertyAssignment.
3522         *
3523         * @param node A MethodDeclaration node.
3524         */
3525        function visitMethodDeclaration(node: MethodDeclaration): ObjectLiteralElementLike {
3526            // We should only get here for methods on an object literal with regular identifier names.
3527            // Methods on classes are handled in visitClassDeclaration/visitClassExpression.
3528            // Methods with computed property names are handled in visitObjectLiteralExpression.
3529            Debug.assert(!isComputedPropertyName(node.name));
3530            const functionExpression = transformFunctionLikeToExpression(node, /*location*/ moveRangePos(node, -1), /*name*/ undefined, /*container*/ undefined);
3531            setEmitFlags(functionExpression, EmitFlags.NoLeadingComments | getEmitFlags(functionExpression));
3532            return setTextRange(
3533                factory.createPropertyAssignment(
3534                    node.name,
3535                    functionExpression
3536                ),
3537                /*location*/ node
3538            );
3539        }
3540
3541        /**
3542         * Visits an AccessorDeclaration of an ObjectLiteralExpression.
3543         *
3544         * @param node An AccessorDeclaration node.
3545         */
3546        function visitAccessorDeclaration(node: AccessorDeclaration): AccessorDeclaration {
3547            Debug.assert(!isComputedPropertyName(node.name));
3548            const savedConvertedLoopState = convertedLoopState;
3549            convertedLoopState = undefined;
3550            const ancestorFacts = enterSubtree(HierarchyFacts.FunctionExcludes, HierarchyFacts.FunctionIncludes);
3551            let updated: AccessorDeclaration;
3552            const parameters = visitParameterList(node.parameters, visitor, context);
3553            const body = transformFunctionBody(node);
3554            if (node.kind === SyntaxKind.GetAccessor) {
3555                updated = factory.updateGetAccessorDeclaration(node, node.decorators, node.modifiers, node.name, parameters, node.type, body);
3556            }
3557            else {
3558                updated = factory.updateSetAccessorDeclaration(node, node.decorators, node.modifiers, node.name, parameters, body);
3559            }
3560            exitSubtree(ancestorFacts, HierarchyFacts.FunctionSubtreeExcludes, HierarchyFacts.None);
3561            convertedLoopState = savedConvertedLoopState;
3562            return updated;
3563        }
3564
3565        /**
3566         * Visits a ShorthandPropertyAssignment and transforms it into a PropertyAssignment.
3567         *
3568         * @param node A ShorthandPropertyAssignment node.
3569         */
3570        function visitShorthandPropertyAssignment(node: ShorthandPropertyAssignment): ObjectLiteralElementLike {
3571            return setTextRange(
3572                factory.createPropertyAssignment(
3573                    node.name,
3574                    visitIdentifier(factory.cloneNode(node.name))
3575                ),
3576                /*location*/ node
3577            );
3578        }
3579
3580        function visitComputedPropertyName(node: ComputedPropertyName) {
3581            return visitEachChild(node, visitor, context);
3582        }
3583
3584        /**
3585         * Visits a YieldExpression node.
3586         *
3587         * @param node A YieldExpression node.
3588         */
3589        function visitYieldExpression(node: YieldExpression): Expression {
3590            // `yield` expressions are transformed using the generators transformer.
3591            return visitEachChild(node, visitor, context);
3592        }
3593
3594        /**
3595         * Visits an ArrayLiteralExpression that contains a spread element.
3596         *
3597         * @param node An ArrayLiteralExpression node.
3598         */
3599        function visitArrayLiteralExpression(node: ArrayLiteralExpression): Expression {
3600            if (some(node.elements, isSpreadElement)) {
3601                // We are here because we contain a SpreadElementExpression.
3602                return transformAndSpreadElements(node.elements, /*needsUniqueCopy*/ true, !!node.multiLine, /*hasTrailingComma*/ !!node.elements.hasTrailingComma);
3603            }
3604            return visitEachChild(node, visitor, context);
3605        }
3606
3607        /**
3608         * Visits a CallExpression that contains either a spread element or `super`.
3609         *
3610         * @param node a CallExpression.
3611         */
3612        function visitCallExpression(node: CallExpression) {
3613            if (getEmitFlags(node) & EmitFlags.TypeScriptClassWrapper) {
3614                return visitTypeScriptClassWrapper(node);
3615            }
3616
3617            const expression = skipOuterExpressions(node.expression);
3618            if (expression.kind === SyntaxKind.SuperKeyword ||
3619                isSuperProperty(expression) ||
3620                some(node.arguments, isSpreadElement)) {
3621                return visitCallExpressionWithPotentialCapturedThisAssignment(node, /*assignToCapturedThis*/ true);
3622            }
3623
3624            return factory.updateCallExpression(
3625                node,
3626                visitNode(node.expression, callExpressionVisitor, isExpression),
3627                /*typeArguments*/ undefined,
3628                visitNodes(node.arguments, visitor, isExpression)
3629            );
3630        }
3631
3632        function visitTypeScriptClassWrapper(node: CallExpression) {
3633            // This is a call to a class wrapper function (an IIFE) created by the 'ts' transformer.
3634            // The wrapper has a form similar to:
3635            //
3636            //  (function() {
3637            //      class C { // 1
3638            //      }
3639            //      C.x = 1; // 2
3640            //      return C;
3641            //  }())
3642            //
3643            // When we transform the class, we end up with something like this:
3644            //
3645            //  (function () {
3646            //      var C = (function () { // 3
3647            //          function C() {
3648            //          }
3649            //          return C; // 4
3650            //      }());
3651            //      C.x = 1;
3652            //      return C;
3653            //  }())
3654            //
3655            // We want to simplify the two nested IIFEs to end up with something like this:
3656            //
3657            //  (function () {
3658            //      function C() {
3659            //      }
3660            //      C.x = 1;
3661            //      return C;
3662            //  }())
3663
3664            // We skip any outer expressions in a number of places to get to the innermost
3665            // expression, but we will restore them later to preserve comments and source maps.
3666            const body = cast(cast(skipOuterExpressions(node.expression), isArrowFunction).body, isBlock);
3667
3668            // The class statements are the statements generated by visiting the first statement with initializer of the
3669            // body (1), while all other statements are added to remainingStatements (2)
3670            const isVariableStatementWithInitializer = (stmt: Statement) => isVariableStatement(stmt) && !!first(stmt.declarationList.declarations).initializer;
3671
3672            // visit the class body statements outside of any converted loop body.
3673            const savedConvertedLoopState = convertedLoopState;
3674            convertedLoopState = undefined;
3675            const bodyStatements = visitNodes(body.statements, visitor, isStatement);
3676            convertedLoopState = savedConvertedLoopState;
3677
3678            const classStatements = filter(bodyStatements, isVariableStatementWithInitializer);
3679            const remainingStatements = filter(bodyStatements, stmt => !isVariableStatementWithInitializer(stmt));
3680            const varStatement = cast(first(classStatements), isVariableStatement);
3681
3682            // We know there is only one variable declaration here as we verified this in an
3683            // earlier call to isTypeScriptClassWrapper
3684            const variable = varStatement.declarationList.declarations[0];
3685            const initializer = skipOuterExpressions(variable.initializer!);
3686
3687            // Under certain conditions, the 'ts' transformer may introduce a class alias, which
3688            // we see as an assignment, for example:
3689            //
3690            //  (function () {
3691            //      var C_1;
3692            //      var C = C_1 = (function () {
3693            //          function C() {
3694            //          }
3695            //          C.x = function () { return C_1; }
3696            //          return C;
3697            //      }());
3698            //      C = C_1 = __decorate([dec], C);
3699            //      return C;
3700            //  }())
3701            //
3702            const aliasAssignment = tryCast(initializer, isAssignmentExpression);
3703
3704            // The underlying call (3) is another IIFE that may contain a '_super' argument.
3705            const call = cast(aliasAssignment ? skipOuterExpressions(aliasAssignment.right) : initializer, isCallExpression);
3706            const func = cast(skipOuterExpressions(call.expression), isFunctionExpression);
3707
3708            const funcStatements = func.body.statements;
3709            let classBodyStart = 0;
3710            let classBodyEnd = -1;
3711
3712            const statements: Statement[] = [];
3713            if (aliasAssignment) {
3714                // If we have a class alias assignment, we need to move it to the down-level constructor
3715                // function we generated for the class.
3716                const extendsCall = tryCast(funcStatements[classBodyStart], isExpressionStatement);
3717                if (extendsCall) {
3718                    statements.push(extendsCall);
3719                    classBodyStart++;
3720                }
3721
3722                // The next statement is the function declaration.
3723                statements.push(funcStatements[classBodyStart]);
3724                classBodyStart++;
3725
3726                // Add the class alias following the declaration.
3727                statements.push(
3728                    factory.createExpressionStatement(
3729                        factory.createAssignment(
3730                            aliasAssignment.left,
3731                            cast(variable.name, isIdentifier)
3732                        )
3733                    )
3734                );
3735            }
3736
3737            // Find the trailing 'return' statement (4)
3738            while (!isReturnStatement(elementAt(funcStatements, classBodyEnd)!)) {
3739                classBodyEnd--;
3740            }
3741
3742            // When we extract the statements of the inner IIFE, we exclude the 'return' statement (4)
3743            // as we already have one that has been introduced by the 'ts' transformer.
3744            addRange(statements, funcStatements, classBodyStart, classBodyEnd);
3745
3746            if (classBodyEnd < -1) {
3747                // If there were any hoisted declarations following the return statement, we should
3748                // append them.
3749                addRange(statements, funcStatements, classBodyEnd + 1);
3750            }
3751
3752            // Add the remaining statements of the outer wrapper.
3753            addRange(statements, remainingStatements);
3754
3755            // The 'es2015' class transform may add an end-of-declaration marker. If so we will add it
3756            // after the remaining statements from the 'ts' transformer.
3757            addRange(statements, classStatements, /*start*/ 1);
3758
3759            // Recreate any outer parentheses or partially-emitted expressions to preserve source map
3760            // and comment locations.
3761            return factory.restoreOuterExpressions(node.expression,
3762                factory.restoreOuterExpressions(variable.initializer,
3763                    factory.restoreOuterExpressions(aliasAssignment && aliasAssignment.right,
3764                        factory.updateCallExpression(call,
3765                            factory.restoreOuterExpressions(call.expression,
3766                                factory.updateFunctionExpression(
3767                                    func,
3768                                    /*modifiers*/ undefined,
3769                                    /*asteriskToken*/ undefined,
3770                                    /*name*/ undefined,
3771                                    /*typeParameters*/ undefined,
3772                                    func.parameters,
3773                                    /*type*/ undefined,
3774                                    factory.updateBlock(
3775                                        func.body,
3776                                        statements
3777                                    )
3778                                )
3779                            ),
3780                            /*typeArguments*/ undefined,
3781                            call.arguments
3782                        )
3783                    )
3784                )
3785            );
3786        }
3787
3788        function visitImmediateSuperCallInBody(node: CallExpression) {
3789            return visitCallExpressionWithPotentialCapturedThisAssignment(node, /*assignToCapturedThis*/ false);
3790        }
3791
3792        function visitCallExpressionWithPotentialCapturedThisAssignment(node: CallExpression, assignToCapturedThis: boolean): CallExpression | BinaryExpression {
3793            // We are here either because SuperKeyword was used somewhere in the expression, or
3794            // because we contain a SpreadElementExpression.
3795            if (node.transformFlags & TransformFlags.ContainsRestOrSpread ||
3796                node.expression.kind === SyntaxKind.SuperKeyword ||
3797                isSuperProperty(skipOuterExpressions(node.expression))) {
3798
3799                const { target, thisArg } = factory.createCallBinding(node.expression, hoistVariableDeclaration);
3800                if (node.expression.kind === SyntaxKind.SuperKeyword) {
3801                    setEmitFlags(thisArg, EmitFlags.NoSubstitution);
3802                }
3803
3804                let resultingCall: CallExpression | BinaryExpression;
3805                if (node.transformFlags & TransformFlags.ContainsRestOrSpread) {
3806                    // [source]
3807                    //      f(...a, b)
3808                    //      x.m(...a, b)
3809                    //      super(...a, b)
3810                    //      super.m(...a, b) // in static
3811                    //      super.m(...a, b) // in instance
3812                    //
3813                    // [output]
3814                    //      f.apply(void 0, a.concat([b]))
3815                    //      (_a = x).m.apply(_a, a.concat([b]))
3816                    //      _super.apply(this, a.concat([b]))
3817                    //      _super.m.apply(this, a.concat([b]))
3818                    //      _super.prototype.m.apply(this, a.concat([b]))
3819
3820                    resultingCall = factory.createFunctionApplyCall(
3821                        visitNode(target, callExpressionVisitor, isExpression),
3822                        node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : visitNode(thisArg, visitor, isExpression),
3823                        transformAndSpreadElements(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*hasTrailingComma*/ false)
3824                    );
3825                }
3826                else {
3827                    // [source]
3828                    //      super(a)
3829                    //      super.m(a) // in static
3830                    //      super.m(a) // in instance
3831                    //
3832                    // [output]
3833                    //      _super.call(this, a)
3834                    //      _super.m.call(this, a)
3835                    //      _super.prototype.m.call(this, a)
3836                    resultingCall = setTextRange(
3837                        factory.createFunctionCallCall(
3838                            visitNode(target, callExpressionVisitor, isExpression),
3839                            node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : visitNode(thisArg, visitor, isExpression),
3840                            visitNodes(node.arguments, visitor, isExpression)
3841                        ),
3842                        node
3843                    );
3844                }
3845
3846                if (node.expression.kind === SyntaxKind.SuperKeyword) {
3847                    const initializer =
3848                        factory.createLogicalOr(
3849                            resultingCall,
3850                            createActualThis()
3851                        );
3852                    resultingCall = assignToCapturedThis
3853                        ? factory.createAssignment(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), initializer)
3854                        : initializer;
3855                }
3856                return setOriginalNode(resultingCall, node);
3857            }
3858
3859            return visitEachChild(node, visitor, context);
3860        }
3861
3862        /**
3863         * Visits a NewExpression that contains a spread element.
3864         *
3865         * @param node A NewExpression node.
3866         */
3867        function visitNewExpression(node: NewExpression): LeftHandSideExpression {
3868            if (some(node.arguments, isSpreadElement)) {
3869                // We are here because we contain a SpreadElementExpression.
3870                // [source]
3871                //      new C(...a)
3872                //
3873                // [output]
3874                //      new ((_a = C).bind.apply(_a, [void 0].concat(a)))()
3875
3876                const { target, thisArg } = factory.createCallBinding(factory.createPropertyAccessExpression(node.expression, "bind"), hoistVariableDeclaration);
3877                return factory.createNewExpression(
3878                    factory.createFunctionApplyCall(
3879                        visitNode(target, visitor, isExpression),
3880                        thisArg,
3881                        transformAndSpreadElements(factory.createNodeArray([factory.createVoidZero(), ...node.arguments!]), /*needsUniqueCopy*/ false, /*multiLine*/ false, /*hasTrailingComma*/ false)
3882                    ),
3883                    /*typeArguments*/ undefined,
3884                    []
3885                );
3886            }
3887            return visitEachChild(node, visitor, context);
3888        }
3889
3890        /**
3891         * Transforms an array of Expression nodes that contains a SpreadExpression.
3892         *
3893         * @param elements The array of Expression nodes.
3894         * @param needsUniqueCopy A value indicating whether to ensure that the result is a fresh array.
3895         * This should be `true` when spreading into an `ArrayLiteral`, and `false` when spreading into an
3896         * argument list.
3897         * @param multiLine A value indicating whether the result should be emitted on multiple lines.
3898         */
3899        function transformAndSpreadElements(elements: NodeArray<Expression>, needsUniqueCopy: boolean, multiLine: boolean, hasTrailingComma: boolean): Expression {
3900            // When there is no leading SpreadElement:
3901            //
3902            // [source]
3903            //      [a, ...b, c]
3904            //
3905            // [output (downlevelIteration)]
3906            //      __spreadArray(__spreadArray([a], __read(b)), [c])
3907            //
3908            // [output]
3909            //      __spreadArray(__spreadArray([a], b), [c])
3910            //
3911            // When there *is* a leading SpreadElement:
3912            //
3913            // [source]
3914            //      [...a, b]
3915            //
3916            // [output (downlevelIteration)]
3917            //      __spreadArray(__spreadArray([], __read(a)), [b])
3918            //
3919            // [output]
3920            //      __spreadArray(__spreadArray([], a), [b])
3921            //
3922            // NOTE: We use `isPackedArrayLiteral` below rather than just `isArrayLiteral`
3923            // because ES2015 spread will replace _missing_ array elements with `undefined`,
3924            // so we cannot just use an array as is. For example:
3925            //
3926            // `[1, ...[2, , 3]]` becomes `[1, 2, undefined, 3]`
3927            //
3928            // However, for packed array literals (i.e., an array literal with no OmittedExpression
3929            // elements), we can use the array as-is.
3930
3931            // Map spans of spread expressions into their expressions and spans of other
3932            // expressions into an array literal.
3933            const numElements = elements.length;
3934            const segments = flatten<Expression>(
3935                spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) =>
3936                    visitPartition(partition, multiLine, hasTrailingComma && end === numElements)
3937                )
3938            );
3939
3940            if (segments.length === 1) {
3941                const firstSegment = segments[0];
3942                // If we don't need a unique copy, then we are spreading into an argument list for
3943                // a CallExpression or NewExpression. When using `--downlevelIteration`, we need
3944                // to coerce this into an array for use with `apply`, so we will use the code path
3945                // that follows instead.
3946                if (!needsUniqueCopy && !compilerOptions.downlevelIteration
3947                    || isPackedArrayLiteral(firstSegment) // see NOTE (above)
3948                    || isCallToHelper(firstSegment, "___spreadArray" as __String)) {
3949                    return segments[0];
3950                }
3951            }
3952
3953            const helpers = emitHelpers();
3954            const startsWithSpread = isSpreadElement(elements[0]);
3955            let expression: Expression =
3956                startsWithSpread ? factory.createArrayLiteralExpression() :
3957                segments[0];
3958            for (let i = startsWithSpread ? 0 : 1; i < segments.length; i++) {
3959                expression = helpers.createSpreadArrayHelper(
3960                    expression,
3961                    compilerOptions.downlevelIteration && !isPackedArrayLiteral(segments[i]) ? // see NOTE (above)
3962                        helpers.createReadHelper(segments[i], /*count*/ undefined) :
3963                        segments[i]);
3964            }
3965
3966            return expression;
3967        }
3968
3969        function partitionSpread(node: Expression) {
3970            return isSpreadElement(node)
3971                ? visitSpanOfSpreads
3972                : visitSpanOfNonSpreads;
3973        }
3974
3975        function visitSpanOfSpreads(chunk: Expression[]): VisitResult<Expression> {
3976            return map(chunk, visitExpressionOfSpread);
3977        }
3978
3979        function visitSpanOfNonSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult<Expression> {
3980            return factory.createArrayLiteralExpression(
3981                visitNodes(factory.createNodeArray(chunk, hasTrailingComma), visitor, isExpression),
3982                multiLine
3983            );
3984        }
3985
3986        function visitSpreadElement(node: SpreadElement) {
3987            return visitNode(node.expression, visitor, isExpression);
3988        }
3989
3990        /**
3991         * Transforms the expression of a SpreadExpression node.
3992         *
3993         * @param node A SpreadExpression node.
3994         */
3995        function visitExpressionOfSpread(node: SpreadElement) {
3996            return visitNode(node.expression, visitor, isExpression);
3997        }
3998
3999        /**
4000         * Visits a template literal.
4001         *
4002         * @param node A template literal.
4003         */
4004        function visitTemplateLiteral(node: LiteralExpression): LeftHandSideExpression {
4005            return setTextRange(factory.createStringLiteral(node.text), node);
4006        }
4007
4008        /**
4009         * Visits a string literal with an extended unicode escape.
4010         *
4011         * @param node A string literal.
4012         */
4013        function visitStringLiteral(node: StringLiteral) {
4014            if (node.hasExtendedUnicodeEscape) {
4015                return setTextRange(factory.createStringLiteral(node.text), node);
4016            }
4017            return node;
4018        }
4019
4020        /**
4021         * Visits a binary or octal (ES6) numeric literal.
4022         *
4023         * @param node A string literal.
4024         */
4025        function visitNumericLiteral(node: NumericLiteral) {
4026            if (node.numericLiteralFlags & TokenFlags.BinaryOrOctalSpecifier) {
4027                return setTextRange(factory.createNumericLiteral(node.text), node);
4028            }
4029            return node;
4030        }
4031
4032        /**
4033         * Visits a TaggedTemplateExpression node.
4034         *
4035         * @param node A TaggedTemplateExpression node.
4036         */
4037        function visitTaggedTemplateExpression(node: TaggedTemplateExpression) {
4038            return processTaggedTemplateExpression(
4039                context,
4040                node,
4041                visitor,
4042                currentSourceFile,
4043                recordTaggedTemplateString,
4044                ProcessLevel.All
4045            );
4046        }
4047
4048        /**
4049         * Visits a TemplateExpression node.
4050         *
4051         * @param node A TemplateExpression node.
4052         */
4053        function visitTemplateExpression(node: TemplateExpression): Expression {
4054            const expressions: Expression[] = [];
4055            addTemplateHead(expressions, node);
4056            addTemplateSpans(expressions, node);
4057
4058            // createAdd will check if each expression binds less closely than binary '+'.
4059            // If it does, it wraps the expression in parentheses. Otherwise, something like
4060            //    `abc${ 1 << 2 }`
4061            // becomes
4062            //    "abc" + 1 << 2 + ""
4063            // which is really
4064            //    ("abc" + 1) << (2 + "")
4065            // rather than
4066            //    "abc" + (1 << 2) + ""
4067            const expression = reduceLeft(expressions, factory.createAdd)!;
4068            if (nodeIsSynthesized(expression)) {
4069                setTextRange(expression, node);
4070            }
4071
4072            return expression;
4073        }
4074
4075        /**
4076         * Gets a value indicating whether we need to include the head of a TemplateExpression.
4077         *
4078         * @param node A TemplateExpression node.
4079         */
4080        function shouldAddTemplateHead(node: TemplateExpression) {
4081            // If this expression has an empty head literal and the first template span has a non-empty
4082            // literal, then emitting the empty head literal is not necessary.
4083            //     `${ foo } and ${ bar }`
4084            // can be emitted as
4085            //     foo + " and " + bar
4086            // This is because it is only required that one of the first two operands in the emit
4087            // output must be a string literal, so that the other operand and all following operands
4088            // are forced into strings.
4089            //
4090            // If the first template span has an empty literal, then the head must still be emitted.
4091            //     `${ foo }${ bar }`
4092            // must still be emitted as
4093            //     "" + foo + bar
4094
4095            // There is always atleast one templateSpan in this code path, since
4096            // NoSubstitutionTemplateLiterals are directly emitted via emitLiteral()
4097            Debug.assert(node.templateSpans.length !== 0);
4098
4099            return node.head.text.length !== 0 || node.templateSpans[0].literal.text.length === 0;
4100        }
4101
4102        /**
4103         * Adds the head of a TemplateExpression to an array of expressions.
4104         *
4105         * @param expressions An array of expressions.
4106         * @param node A TemplateExpression node.
4107         */
4108        function addTemplateHead(expressions: Expression[], node: TemplateExpression): void {
4109            if (!shouldAddTemplateHead(node)) {
4110                return;
4111            }
4112
4113            expressions.push(factory.createStringLiteral(node.head.text));
4114        }
4115
4116        /**
4117         * Visits and adds the template spans of a TemplateExpression to an array of expressions.
4118         *
4119         * @param expressions An array of expressions.
4120         * @param node A TemplateExpression node.
4121         */
4122        function addTemplateSpans(expressions: Expression[], node: TemplateExpression): void {
4123            for (const span of node.templateSpans) {
4124                expressions.push(visitNode(span.expression, visitor, isExpression));
4125
4126                // Only emit if the literal is non-empty.
4127                // The binary '+' operator is left-associative, so the first string concatenation
4128                // with the head will force the result up to this point to be a string.
4129                // Emitting a '+ ""' has no semantic effect for middles and tails.
4130                if (span.literal.text.length !== 0) {
4131                    expressions.push(factory.createStringLiteral(span.literal.text));
4132                }
4133            }
4134        }
4135
4136        /**
4137         * Visits the `super` keyword
4138         */
4139        function visitSuperKeyword(isExpressionOfCall: boolean): LeftHandSideExpression {
4140            return hierarchyFacts & HierarchyFacts.NonStaticClassElement
4141                && !isExpressionOfCall
4142                    ? factory.createPropertyAccessExpression(factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), "prototype")
4143                    : factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel);
4144        }
4145
4146        function visitMetaProperty(node: MetaProperty) {
4147            if (node.keywordToken === SyntaxKind.NewKeyword && node.name.escapedText === "target") {
4148                hierarchyFacts |= HierarchyFacts.NewTarget;
4149                return factory.createUniqueName("_newTarget", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel);
4150            }
4151            return node;
4152        }
4153
4154        /**
4155         * Called by the printer just before a node is printed.
4156         *
4157         * @param hint A hint as to the intended usage of the node.
4158         * @param node The node to be printed.
4159         * @param emitCallback The callback used to emit the node.
4160         */
4161        function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
4162            if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis && isFunctionLike(node)) {
4163                // If we are tracking a captured `this`, keep track of the enclosing function.
4164                const ancestorFacts = enterSubtree(
4165                    HierarchyFacts.FunctionExcludes,
4166                    getEmitFlags(node) & EmitFlags.CapturesThis
4167                        ? HierarchyFacts.FunctionIncludes | HierarchyFacts.CapturesThis
4168                        : HierarchyFacts.FunctionIncludes);
4169                previousOnEmitNode(hint, node, emitCallback);
4170                exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
4171                return;
4172            }
4173            previousOnEmitNode(hint, node, emitCallback);
4174        }
4175
4176        /**
4177         * Enables a more costly code path for substitutions when we determine a source file
4178         * contains block-scoped bindings (e.g. `let` or `const`).
4179         */
4180        function enableSubstitutionsForBlockScopedBindings() {
4181            if ((enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings) === 0) {
4182                enabledSubstitutions |= ES2015SubstitutionFlags.BlockScopedBindings;
4183                context.enableSubstitution(SyntaxKind.Identifier);
4184            }
4185        }
4186
4187        /**
4188         * Enables a more costly code path for substitutions when we determine a source file
4189         * contains a captured `this`.
4190         */
4191        function enableSubstitutionsForCapturedThis() {
4192            if ((enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis) === 0) {
4193                enabledSubstitutions |= ES2015SubstitutionFlags.CapturedThis;
4194                context.enableSubstitution(SyntaxKind.ThisKeyword);
4195                context.enableEmitNotification(SyntaxKind.Constructor);
4196                context.enableEmitNotification(SyntaxKind.MethodDeclaration);
4197                context.enableEmitNotification(SyntaxKind.GetAccessor);
4198                context.enableEmitNotification(SyntaxKind.SetAccessor);
4199                context.enableEmitNotification(SyntaxKind.ArrowFunction);
4200                context.enableEmitNotification(SyntaxKind.FunctionExpression);
4201                context.enableEmitNotification(SyntaxKind.FunctionDeclaration);
4202            }
4203        }
4204
4205        /**
4206         * Hooks node substitutions.
4207         *
4208         * @param hint The context for the emitter.
4209         * @param node The node to substitute.
4210         */
4211        function onSubstituteNode(hint: EmitHint, node: Node) {
4212            node = previousOnSubstituteNode(hint, node);
4213
4214            if (hint === EmitHint.Expression) {
4215                return substituteExpression(node);
4216            }
4217
4218            if (isIdentifier(node)) {
4219                return substituteIdentifier(node);
4220            }
4221
4222            return node;
4223        }
4224
4225        /**
4226         * Hooks substitutions for non-expression identifiers.
4227         */
4228        function substituteIdentifier(node: Identifier) {
4229            // Only substitute the identifier if we have enabled substitutions for block-scoped
4230            // bindings.
4231            if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings && !isInternalName(node)) {
4232                const original = getParseTreeNode(node, isIdentifier);
4233                if (original && isNameOfDeclarationWithCollidingName(original)) {
4234                    return setTextRange(factory.getGeneratedNameForNode(original), node);
4235                }
4236            }
4237
4238            return node;
4239        }
4240
4241        /**
4242         * Determines whether a name is the name of a declaration with a colliding name.
4243         * NOTE: This function expects to be called with an original source tree node.
4244         *
4245         * @param node An original source tree node.
4246         */
4247        function isNameOfDeclarationWithCollidingName(node: Identifier) {
4248            switch (node.parent.kind) {
4249                case SyntaxKind.BindingElement:
4250                case SyntaxKind.ClassDeclaration:
4251                case SyntaxKind.EnumDeclaration:
4252                case SyntaxKind.VariableDeclaration:
4253                    return (<NamedDeclaration>node.parent).name === node
4254                        && resolver.isDeclarationWithCollidingName(<Declaration>node.parent);
4255            }
4256
4257            return false;
4258        }
4259
4260        /**
4261         * Substitutes an expression.
4262         *
4263         * @param node An Expression node.
4264         */
4265        function substituteExpression(node: Node) {
4266            switch (node.kind) {
4267                case SyntaxKind.Identifier:
4268                    return substituteExpressionIdentifier(<Identifier>node);
4269
4270                case SyntaxKind.ThisKeyword:
4271                    return substituteThisKeyword(<PrimaryExpression>node);
4272            }
4273
4274            return node;
4275        }
4276
4277        /**
4278         * Substitutes an expression identifier.
4279         *
4280         * @param node An Identifier node.
4281         */
4282        function substituteExpressionIdentifier(node: Identifier): Identifier {
4283            if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings && !isInternalName(node)) {
4284                const declaration = resolver.getReferencedDeclarationWithCollidingName(node);
4285                if (declaration && !(isClassLike(declaration) && isPartOfClassBody(declaration, node))) {
4286                    return setTextRange(factory.getGeneratedNameForNode(getNameOfDeclaration(declaration)), node);
4287                }
4288            }
4289
4290            return node;
4291        }
4292
4293        function isPartOfClassBody(declaration: ClassLikeDeclaration, node: Identifier) {
4294            let currentNode: Node | undefined = getParseTreeNode(node);
4295            if (!currentNode || currentNode === declaration || currentNode.end <= declaration.pos || currentNode.pos >= declaration.end) {
4296                // if the node has no correlation to a parse tree node, its definitely not
4297                // part of the body.
4298                // if the node is outside of the document range of the declaration, its
4299                // definitely not part of the body.
4300                return false;
4301            }
4302            const blockScope = getEnclosingBlockScopeContainer(declaration);
4303            while (currentNode) {
4304                if (currentNode === blockScope || currentNode === declaration) {
4305                    // if we are in the enclosing block scope of the declaration, we are definitely
4306                    // not inside the class body.
4307                    return false;
4308                }
4309                if (isClassElement(currentNode) && currentNode.parent === declaration) {
4310                    return true;
4311                }
4312                currentNode = currentNode.parent;
4313            }
4314            return false;
4315        }
4316
4317        /**
4318         * Substitutes `this` when contained within an arrow function.
4319         *
4320         * @param node The ThisKeyword node.
4321         */
4322        function substituteThisKeyword(node: PrimaryExpression): PrimaryExpression {
4323            if (enabledSubstitutions & ES2015SubstitutionFlags.CapturedThis
4324                && hierarchyFacts & HierarchyFacts.CapturesThis) {
4325                return setTextRange(factory.createUniqueName("_this", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), node);
4326            }
4327            return node;
4328        }
4329
4330        function getClassMemberPrefix(node: ClassExpression | ClassDeclaration, member: ClassElement) {
4331            return hasSyntacticModifier(member, ModifierFlags.Static)
4332                ? factory.getInternalName(node)
4333                : factory.createPropertyAccessExpression(factory.getInternalName(node), "prototype");
4334        }
4335
4336        function hasSynthesizedDefaultSuperCall(constructor: ConstructorDeclaration | undefined, hasExtendsClause: boolean) {
4337            if (!constructor || !hasExtendsClause) {
4338                return false;
4339            }
4340
4341            if (some(constructor.parameters)) {
4342                return false;
4343            }
4344
4345            const statement = firstOrUndefined(constructor.body!.statements);
4346            if (!statement || !nodeIsSynthesized(statement) || statement.kind !== SyntaxKind.ExpressionStatement) {
4347                return false;
4348            }
4349
4350            const statementExpression = (<ExpressionStatement>statement).expression;
4351            if (!nodeIsSynthesized(statementExpression) || statementExpression.kind !== SyntaxKind.CallExpression) {
4352                return false;
4353            }
4354
4355            const callTarget = (<CallExpression>statementExpression).expression;
4356            if (!nodeIsSynthesized(callTarget) || callTarget.kind !== SyntaxKind.SuperKeyword) {
4357                return false;
4358            }
4359
4360            const callArgument = singleOrUndefined((<CallExpression>statementExpression).arguments);
4361            if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadElement) {
4362                return false;
4363            }
4364
4365            const expression = (<SpreadElement>callArgument).expression;
4366            return isIdentifier(expression) && expression.escapedText === "arguments";
4367        }
4368    }
4369}
4370