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