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