• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*@internal*/
2namespace ts {
3    /**
4     * Indicates whether to emit type metadata in the new format.
5     */
6    const USE_NEW_TYPE_METADATA_FORMAT = false;
7
8    const enum TypeScriptSubstitutionFlags {
9        /** Enables substitutions for decorated classes. */
10        ClassAliases = 1 << 0,
11        /** Enables substitutions for namespace exports. */
12        NamespaceExports = 1 << 1,
13        /* Enables substitutions for unqualified enum members */
14        NonQualifiedEnumMembers = 1 << 3
15    }
16
17    const enum ClassFacts {
18        None = 0,
19        HasStaticInitializedProperties = 1 << 0,
20        HasConstructorDecorators = 1 << 1,
21        HasMemberDecorators = 1 << 2,
22        IsExportOfNamespace = 1 << 3,
23        IsNamedExternalExport = 1 << 4,
24        IsDefaultExternalExport = 1 << 5,
25        IsDerivedClass = 1 << 6,
26        UseImmediatelyInvokedFunctionExpression = 1 << 7,
27
28        HasAnyDecorators = HasConstructorDecorators | HasMemberDecorators,
29        NeedsName = HasStaticInitializedProperties | HasMemberDecorators,
30        MayNeedImmediatelyInvokedFunctionExpression = HasAnyDecorators | HasStaticInitializedProperties,
31        IsExported = IsExportOfNamespace | IsDefaultExternalExport | IsNamedExternalExport,
32    }
33
34    export function transformTypeScript(context: TransformationContext) {
35        const {
36            factory,
37            getEmitHelperFactory: emitHelpers,
38            startLexicalEnvironment,
39            resumeLexicalEnvironment,
40            endLexicalEnvironment,
41            hoistVariableDeclaration,
42        } = context;
43
44        const resolver = context.getEmitResolver();
45        const compilerOptions = context.getCompilerOptions();
46        const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks");
47        const languageVersion = getEmitScriptTarget(compilerOptions);
48        const moduleKind = getEmitModuleKind(compilerOptions);
49
50        // Save the previous transformation hooks.
51        const previousOnEmitNode = context.onEmitNode;
52        const previousOnSubstituteNode = context.onSubstituteNode;
53
54        // Set new transformation hooks.
55        context.onEmitNode = onEmitNode;
56        context.onSubstituteNode = onSubstituteNode;
57
58        // Enable substitution for property/element access to emit const enum values.
59        context.enableSubstitution(SyntaxKind.PropertyAccessExpression);
60        context.enableSubstitution(SyntaxKind.ElementAccessExpression);
61
62        // These variables contain state that changes as we descend into the tree.
63        let currentSourceFile: SourceFile;
64        let currentNamespace: ModuleDeclaration;
65        let currentNamespaceContainerName: Identifier;
66        let currentLexicalScope: SourceFile | Block | ModuleBlock | CaseBlock;
67        let currentNameScope: ClassDeclaration | undefined;
68        let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap<Node> | undefined;
69        let currentClassHasParameterProperties: boolean | undefined;
70
71        /**
72         * Keeps track of whether expression substitution has been enabled for specific edge cases.
73         * They are persisted between each SourceFile transformation and should not be reset.
74         */
75        let enabledSubstitutions: TypeScriptSubstitutionFlags;
76
77        /**
78         * A map that keeps track of aliases created for classes with decorators to avoid issues
79         * with the double-binding behavior of classes.
80         */
81        let classAliases: Identifier[];
82
83        /**
84         * Keeps track of whether we are within any containing namespaces when performing
85         * just-in-time substitution while printing an expression identifier.
86         */
87        let applicableSubstitutions: TypeScriptSubstitutionFlags;
88
89        return transformSourceFileOrBundle;
90
91        function transformSourceFileOrBundle(node: SourceFile | Bundle) {
92            if (node.kind === SyntaxKind.Bundle) {
93                return transformBundle(node);
94            }
95            return transformSourceFile(node);
96        }
97
98        function transformBundle(node: Bundle) {
99            return factory.createBundle(node.sourceFiles.map(transformSourceFile), mapDefined(node.prepends, prepend => {
100                if (prepend.kind === SyntaxKind.InputFiles) {
101                    return createUnparsedSourceFile(prepend, "js");
102                }
103                return prepend;
104            }));
105        }
106
107        /**
108         * Transform TypeScript-specific syntax in a SourceFile.
109         *
110         * @param node A SourceFile node.
111         */
112        function transformSourceFile(node: SourceFile) {
113            if (node.isDeclarationFile) {
114                return node;
115            }
116
117            currentSourceFile = node;
118
119            const visited = saveStateAndInvoke(node, visitSourceFile);
120            addEmitHelpers(visited, context.readEmitHelpers());
121
122            currentSourceFile = undefined!;
123            return visited;
124        }
125
126        /**
127         * Visits a node, saving and restoring state variables on the stack.
128         *
129         * @param node The node to visit.
130         */
131        function saveStateAndInvoke<T>(node: Node, f: (node: Node) => T): T {
132            // Save state
133            const savedCurrentScope = currentLexicalScope;
134            const savedCurrentNameScope = currentNameScope;
135            const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName;
136            const savedCurrentClassHasParameterProperties = currentClassHasParameterProperties;
137
138            // Handle state changes before visiting a node.
139            onBeforeVisitNode(node);
140
141            const visited = f(node);
142
143            // Restore state
144            if (currentLexicalScope !== savedCurrentScope) {
145                currentScopeFirstDeclarationsOfName = savedCurrentScopeFirstDeclarationsOfName;
146            }
147
148            currentLexicalScope = savedCurrentScope;
149            currentNameScope = savedCurrentNameScope;
150            currentClassHasParameterProperties = savedCurrentClassHasParameterProperties;
151            return visited;
152        }
153
154        /**
155         * Performs actions that should always occur immediately before visiting a node.
156         *
157         * @param node The node to visit.
158         */
159        function onBeforeVisitNode(node: Node) {
160            switch (node.kind) {
161                case SyntaxKind.SourceFile:
162                case SyntaxKind.CaseBlock:
163                case SyntaxKind.ModuleBlock:
164                case SyntaxKind.Block:
165                    currentLexicalScope = <SourceFile | CaseBlock | ModuleBlock | Block>node;
166                    currentNameScope = undefined;
167                    currentScopeFirstDeclarationsOfName = undefined;
168                    break;
169
170                case SyntaxKind.ClassDeclaration:
171                case SyntaxKind.FunctionDeclaration:
172                    if (hasSyntacticModifier(node, ModifierFlags.Ambient)) {
173                        break;
174                    }
175
176                    // Record these declarations provided that they have a name.
177                    if ((node as ClassDeclaration | FunctionDeclaration).name) {
178                        recordEmittedDeclarationInScope(node as ClassDeclaration | FunctionDeclaration);
179                    }
180                    else {
181                        // These nodes should always have names unless they are default-exports;
182                        // however, class declaration parsing allows for undefined names, so syntactically invalid
183                        // programs may also have an undefined name.
184                        Debug.assert(node.kind === SyntaxKind.ClassDeclaration || hasSyntacticModifier(node, ModifierFlags.Default));
185                    }
186                    if (isClassDeclaration(node)) {
187                        // XXX: should probably also cover interfaces and type aliases that can have type variables?
188                        currentNameScope = node;
189                    }
190
191                    break;
192            }
193        }
194
195        /**
196         * General-purpose node visitor.
197         *
198         * @param node The node to visit.
199         */
200        function visitor(node: Node): VisitResult<Node> {
201            return saveStateAndInvoke(node, visitorWorker);
202        }
203
204        /**
205         * Visits and possibly transforms any node.
206         *
207         * @param node The node to visit.
208         */
209        function visitorWorker(node: Node): VisitResult<Node> {
210            if (node.transformFlags & TransformFlags.ContainsTypeScript) {
211                return visitTypeScript(node);
212            }
213            return node;
214        }
215
216        /**
217         * Specialized visitor that visits the immediate children of a SourceFile.
218         *
219         * @param node The node to visit.
220         */
221        function sourceElementVisitor(node: Node): VisitResult<Node> {
222            return saveStateAndInvoke(node, sourceElementVisitorWorker);
223        }
224
225        /**
226         * Specialized visitor that visits the immediate children of a SourceFile.
227         *
228         * @param node The node to visit.
229         */
230        function sourceElementVisitorWorker(node: Node): VisitResult<Node> {
231            switch (node.kind) {
232                case SyntaxKind.ImportDeclaration:
233                case SyntaxKind.ImportEqualsDeclaration:
234                case SyntaxKind.ExportAssignment:
235                case SyntaxKind.ExportDeclaration:
236                    return visitElidableStatement(<ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration>node);
237                default:
238                    return visitorWorker(node);
239            }
240        }
241
242        function visitElidableStatement(node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration): VisitResult<Node> {
243            const parsed = getParseTreeNode(node);
244            if (parsed !== node) {
245                // If the node has been transformed by a `before` transformer, perform no ellision on it
246                // As the type information we would attempt to lookup to perform ellision is potentially unavailable for the synthesized nodes
247                // We do not reuse `visitorWorker`, as the ellidable statement syntax kinds are technically unrecognized by the switch-case in `visitTypeScript`,
248                // and will trigger debug failures when debug verbosity is turned up
249                if (node.transformFlags & TransformFlags.ContainsTypeScript) {
250                    // This node contains TypeScript, so we should visit its children.
251                    return visitEachChild(node, visitor, context);
252                }
253                // Otherwise, we can just return the node
254                return node;
255            }
256            switch (node.kind) {
257                case SyntaxKind.ImportDeclaration:
258                    return visitImportDeclaration(node);
259                case SyntaxKind.ImportEqualsDeclaration:
260                    return visitImportEqualsDeclaration(node);
261                case SyntaxKind.ExportAssignment:
262                    return visitExportAssignment(node);
263                case SyntaxKind.ExportDeclaration:
264                    return visitExportDeclaration(node);
265                default:
266                    Debug.fail("Unhandled ellided statement");
267            }
268        }
269
270        /**
271         * Specialized visitor that visits the immediate children of a namespace.
272         *
273         * @param node The node to visit.
274         */
275        function namespaceElementVisitor(node: Node): VisitResult<Node> {
276            return saveStateAndInvoke(node, namespaceElementVisitorWorker);
277        }
278
279        /**
280         * Specialized visitor that visits the immediate children of a namespace.
281         *
282         * @param node The node to visit.
283         */
284        function namespaceElementVisitorWorker(node: Node): VisitResult<Node> {
285            if (node.kind === SyntaxKind.ExportDeclaration ||
286                node.kind === SyntaxKind.ImportDeclaration ||
287                node.kind === SyntaxKind.ImportClause ||
288                (node.kind === SyntaxKind.ImportEqualsDeclaration &&
289                 (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference)) {
290                // do not emit ES6 imports and exports since they are illegal inside a namespace
291                return undefined;
292            }
293            else if (node.transformFlags & TransformFlags.ContainsTypeScript || hasSyntacticModifier(node, ModifierFlags.Export)) {
294                return visitTypeScript(node);
295            }
296
297            return node;
298        }
299
300        /**
301         * Specialized visitor that visits the immediate children of a class with TypeScript syntax.
302         *
303         * @param node The node to visit.
304         */
305        function classElementVisitor(node: Node): VisitResult<Node> {
306            return saveStateAndInvoke(node, classElementVisitorWorker);
307        }
308
309        /**
310         * Specialized visitor that visits the immediate children of a class with TypeScript syntax.
311         *
312         * @param node The node to visit.
313         */
314        function classElementVisitorWorker(node: Node): VisitResult<Node> {
315            switch (node.kind) {
316                case SyntaxKind.Constructor:
317                    return visitConstructor(node as ConstructorDeclaration);
318
319                case SyntaxKind.PropertyDeclaration:
320                    // Property declarations are not TypeScript syntax, but they must be visited
321                    // for the decorator transformation.
322                    return visitPropertyDeclaration(node as PropertyDeclaration);
323                case SyntaxKind.IndexSignature:
324                case SyntaxKind.GetAccessor:
325                case SyntaxKind.SetAccessor:
326                case SyntaxKind.MethodDeclaration:
327                    // Fallback to the default visit behavior.
328                    return visitorWorker(node);
329
330                case SyntaxKind.SemicolonClassElement:
331                    return node;
332
333                default:
334                    return Debug.failBadSyntaxKind(node);
335            }
336        }
337
338        function modifierVisitor(node: Node): VisitResult<Node> {
339            if (modifierToFlag(node.kind) & ModifierFlags.TypeScriptModifier) {
340                return undefined;
341            }
342            else if (currentNamespace && node.kind === SyntaxKind.ExportKeyword) {
343                return undefined;
344            }
345
346            return node;
347        }
348
349        /**
350         * Branching visitor, visits a TypeScript syntax node.
351         *
352         * @param node The node to visit.
353         */
354        function visitTypeScript(node: Node): VisitResult<Node> {
355            if (isStatement(node) && hasSyntacticModifier(node, ModifierFlags.Ambient)) {
356                // TypeScript ambient declarations are elided, but some comments may be preserved.
357                // See the implementation of `getLeadingComments` in comments.ts for more details.
358                return factory.createNotEmittedStatement(node);
359            }
360
361            switch (node.kind) {
362                case SyntaxKind.ExportKeyword:
363                case SyntaxKind.DefaultKeyword:
364                    // ES6 export and default modifiers are elided when inside a namespace.
365                    return currentNamespace ? undefined : node;
366
367                case SyntaxKind.PublicKeyword:
368                case SyntaxKind.PrivateKeyword:
369                case SyntaxKind.ProtectedKeyword:
370                case SyntaxKind.AbstractKeyword:
371                case SyntaxKind.ConstKeyword:
372                case SyntaxKind.DeclareKeyword:
373                case SyntaxKind.ReadonlyKeyword:
374                // TypeScript accessibility and readonly modifiers are elided
375                // falls through
376                case SyntaxKind.ArrayType:
377                case SyntaxKind.TupleType:
378                case SyntaxKind.OptionalType:
379                case SyntaxKind.RestType:
380                case SyntaxKind.TypeLiteral:
381                case SyntaxKind.TypePredicate:
382                case SyntaxKind.TypeParameter:
383                case SyntaxKind.AnyKeyword:
384                case SyntaxKind.UnknownKeyword:
385                case SyntaxKind.BooleanKeyword:
386                case SyntaxKind.StringKeyword:
387                case SyntaxKind.NumberKeyword:
388                case SyntaxKind.NeverKeyword:
389                case SyntaxKind.VoidKeyword:
390                case SyntaxKind.SymbolKeyword:
391                case SyntaxKind.ConstructorType:
392                case SyntaxKind.FunctionType:
393                case SyntaxKind.TypeQuery:
394                case SyntaxKind.TypeReference:
395                case SyntaxKind.UnionType:
396                case SyntaxKind.IntersectionType:
397                case SyntaxKind.ConditionalType:
398                case SyntaxKind.ParenthesizedType:
399                case SyntaxKind.ThisType:
400                case SyntaxKind.TypeOperator:
401                case SyntaxKind.IndexedAccessType:
402                case SyntaxKind.MappedType:
403                case SyntaxKind.LiteralType:
404                    // TypeScript type nodes are elided.
405                    // falls through
406
407                case SyntaxKind.IndexSignature:
408                    // TypeScript index signatures are elided.
409                    // falls through
410
411                case SyntaxKind.Decorator:
412                    // TypeScript decorators are elided. They will be emitted as part of visitClassDeclaration.
413                    // falls through
414
415                case SyntaxKind.TypeAliasDeclaration:
416                    // TypeScript type-only declarations are elided.
417                    return undefined;
418
419                case SyntaxKind.PropertyDeclaration:
420                    // TypeScript property declarations are elided. However their names are still visited, and can potentially be retained if they could have sideeffects
421                    return visitPropertyDeclaration(node as PropertyDeclaration);
422
423                case SyntaxKind.NamespaceExportDeclaration:
424                    // TypeScript namespace export declarations are elided.
425                    return undefined;
426
427                case SyntaxKind.Constructor:
428                    return visitConstructor(<ConstructorDeclaration>node);
429
430                case SyntaxKind.InterfaceDeclaration:
431                    // TypeScript interfaces are elided, but some comments may be preserved.
432                    // See the implementation of `getLeadingComments` in comments.ts for more details.
433                    return factory.createNotEmittedStatement(node);
434
435                case SyntaxKind.ClassDeclaration:
436                    // This may be a class declaration with TypeScript syntax extensions.
437                    //
438                    // TypeScript class syntax extensions include:
439                    // - decorators
440                    // - optional `implements` heritage clause
441                    // - parameter property assignments in the constructor
442                    // - index signatures
443                    // - method overload signatures
444                    return visitClassDeclaration(<ClassDeclaration>node);
445
446                case SyntaxKind.ClassExpression:
447                    // This may be a class expression with TypeScript syntax extensions.
448                    //
449                    // TypeScript class syntax extensions include:
450                    // - decorators
451                    // - optional `implements` heritage clause
452                    // - parameter property assignments in the constructor
453                    // - index signatures
454                    // - method overload signatures
455                    return visitClassExpression(<ClassExpression>node);
456
457                case SyntaxKind.HeritageClause:
458                    // This may be a heritage clause with TypeScript syntax extensions.
459                    //
460                    // TypeScript heritage clause extensions include:
461                    // - `implements` clause
462                    return visitHeritageClause(<HeritageClause>node);
463
464                case SyntaxKind.ExpressionWithTypeArguments:
465                    // TypeScript supports type arguments on an expression in an `extends` heritage clause.
466                    return visitExpressionWithTypeArguments(<ExpressionWithTypeArguments>node);
467
468                case SyntaxKind.MethodDeclaration:
469                    // TypeScript method declarations may have decorators, modifiers
470                    // or type annotations.
471                    return visitMethodDeclaration(<MethodDeclaration>node);
472
473                case SyntaxKind.GetAccessor:
474                    // Get Accessors can have TypeScript modifiers, decorators, and type annotations.
475                    return visitGetAccessor(<GetAccessorDeclaration>node);
476
477                case SyntaxKind.SetAccessor:
478                    // Set Accessors can have TypeScript modifiers and type annotations.
479                    return visitSetAccessor(<SetAccessorDeclaration>node);
480
481                case SyntaxKind.FunctionDeclaration:
482                    // Typescript function declarations can have modifiers, decorators, and type annotations.
483                    return visitFunctionDeclaration(<FunctionDeclaration>node);
484
485                case SyntaxKind.FunctionExpression:
486                    // TypeScript function expressions can have modifiers and type annotations.
487                    return visitFunctionExpression(<FunctionExpression>node);
488
489                case SyntaxKind.ArrowFunction:
490                    // TypeScript arrow functions can have modifiers and type annotations.
491                    return visitArrowFunction(<ArrowFunction>node);
492
493                case SyntaxKind.Parameter:
494                    // This may be a parameter declaration with TypeScript syntax extensions.
495                    //
496                    // TypeScript parameter declaration syntax extensions include:
497                    // - decorators
498                    // - accessibility modifiers
499                    // - the question mark (?) token for optional parameters
500                    // - type annotations
501                    // - this parameters
502                    return visitParameter(<ParameterDeclaration>node);
503
504                case SyntaxKind.ParenthesizedExpression:
505                    // ParenthesizedExpressions are TypeScript if their expression is a
506                    // TypeAssertion or AsExpression
507                    return visitParenthesizedExpression(<ParenthesizedExpression>node);
508
509                case SyntaxKind.TypeAssertionExpression:
510                case SyntaxKind.AsExpression:
511                    // TypeScript type assertions are removed, but their subtrees are preserved.
512                    return visitAssertionExpression(<AssertionExpression>node);
513
514                case SyntaxKind.CallExpression:
515                    return visitCallExpression(<CallExpression>node);
516
517                case SyntaxKind.NewExpression:
518                    return visitNewExpression(<NewExpression>node);
519
520                case SyntaxKind.TaggedTemplateExpression:
521                    return visitTaggedTemplateExpression(<TaggedTemplateExpression>node);
522
523                case SyntaxKind.NonNullExpression:
524                    // TypeScript non-null expressions are removed, but their subtrees are preserved.
525                    return visitNonNullExpression(<NonNullExpression>node);
526
527                case SyntaxKind.EnumDeclaration:
528                    // TypeScript enum declarations do not exist in ES6 and must be rewritten.
529                    return visitEnumDeclaration(<EnumDeclaration>node);
530
531                case SyntaxKind.VariableStatement:
532                    // TypeScript namespace exports for variable statements must be transformed.
533                    return visitVariableStatement(<VariableStatement>node);
534
535                case SyntaxKind.VariableDeclaration:
536                    return visitVariableDeclaration(<VariableDeclaration>node);
537
538                case SyntaxKind.ModuleDeclaration:
539                    // TypeScript namespace declarations must be transformed.
540                    return visitModuleDeclaration(<ModuleDeclaration>node);
541
542                case SyntaxKind.ImportEqualsDeclaration:
543                    // TypeScript namespace or external module import.
544                    return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
545
546                case SyntaxKind.JsxSelfClosingElement:
547                    return visitJsxSelfClosingElement(<JsxSelfClosingElement>node);
548
549                case SyntaxKind.JsxOpeningElement:
550                    return visitJsxJsxOpeningElement(<JsxOpeningElement>node);
551
552                default:
553                    // node contains some other TypeScript syntax
554                    return visitEachChild(node, visitor, context);
555            }
556        }
557
558        function visitSourceFile(node: SourceFile) {
559            const alwaysStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") &&
560                !(isExternalModule(node) && moduleKind >= ModuleKind.ES2015) &&
561                !isJsonSourceFile(node);
562
563            return factory.updateSourceFile(
564                node,
565                visitLexicalEnvironment(node.statements, sourceElementVisitor, context, /*start*/ 0, alwaysStrict));
566        }
567
568        /**
569         * Tests whether we should emit a __decorate call for a class declaration.
570         */
571        function shouldEmitDecorateCallForClass(node: ClassDeclaration) {
572            if (node.decorators && node.decorators.length > 0) {
573                return true;
574            }
575
576            const constructor = getFirstConstructorWithBody(node);
577            if (constructor) {
578                return forEach(constructor.parameters, shouldEmitDecorateCallForParameter);
579            }
580
581            return false;
582        }
583
584        /**
585         * Tests whether we should emit a __decorate call for a parameter declaration.
586         */
587        function shouldEmitDecorateCallForParameter(parameter: ParameterDeclaration) {
588            return parameter.decorators !== undefined && parameter.decorators.length > 0;
589        }
590
591        function getClassFacts(node: ClassDeclaration, staticProperties: readonly PropertyDeclaration[]) {
592            let facts = ClassFacts.None;
593            if (some(staticProperties)) facts |= ClassFacts.HasStaticInitializedProperties;
594            const extendsClauseElement = getEffectiveBaseTypeNode(node);
595            if (extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword) facts |= ClassFacts.IsDerivedClass;
596            if (shouldEmitDecorateCallForClass(node)) facts |= ClassFacts.HasConstructorDecorators;
597            if (childIsDecorated(node)) facts |= ClassFacts.HasMemberDecorators;
598            if (isExportOfNamespace(node)) facts |= ClassFacts.IsExportOfNamespace;
599            else if (isDefaultExternalModuleExport(node)) facts |= ClassFacts.IsDefaultExternalExport;
600            else if (isNamedExternalModuleExport(node)) facts |= ClassFacts.IsNamedExternalExport;
601            if (languageVersion <= ScriptTarget.ES5 && (facts & ClassFacts.MayNeedImmediatelyInvokedFunctionExpression)) facts |= ClassFacts.UseImmediatelyInvokedFunctionExpression;
602            return facts;
603        }
604
605        function hasTypeScriptClassSyntax(node: Node) {
606            return !!(node.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax);
607        }
608
609        function isClassLikeDeclarationWithTypeScriptSyntax(node: ClassLikeDeclaration) {
610            return some(node.decorators)
611                || some(node.typeParameters)
612                || some(node.heritageClauses, hasTypeScriptClassSyntax)
613                || some(node.members, hasTypeScriptClassSyntax);
614        }
615
616        function visitClassDeclaration(node: ClassDeclaration): VisitResult<Statement> {
617            if (!isClassLikeDeclarationWithTypeScriptSyntax(node) && !(currentNamespace && hasSyntacticModifier(node, ModifierFlags.Export))) {
618                return visitEachChild(node, visitor, context);
619            }
620
621            const staticProperties = getProperties(node, /*requireInitializer*/ true, /*isStatic*/ true);
622            const facts = getClassFacts(node, staticProperties);
623
624            if (facts & ClassFacts.UseImmediatelyInvokedFunctionExpression) {
625                context.startLexicalEnvironment();
626            }
627
628            const name = node.name || (facts & ClassFacts.NeedsName ? factory.getGeneratedNameForNode(node) : undefined);
629            const classStatement = facts & ClassFacts.HasConstructorDecorators
630                ? createClassDeclarationHeadWithDecorators(node, name)
631                : createClassDeclarationHeadWithoutDecorators(node, name, facts);
632
633            let statements: Statement[] = [classStatement];
634
635
636            // Write any decorators of the node.
637            addClassElementDecorationStatements(statements, node, /*isStatic*/ false);
638            addClassElementDecorationStatements(statements, node, /*isStatic*/ true);
639            addConstructorDecorationStatement(statements, node);
640
641            if (facts & ClassFacts.UseImmediatelyInvokedFunctionExpression) {
642                // When we emit a TypeScript class down to ES5, we must wrap it in an IIFE so that the
643                // 'es2015' transformer can properly nest static initializers and decorators. The result
644                // looks something like:
645                //
646                //  var C = function () {
647                //      class C {
648                //      }
649                //      C.static_prop = 1;
650                //      return C;
651                //  }();
652                //
653                const closingBraceLocation = createTokenRange(skipTrivia(currentSourceFile.text, node.members.end), SyntaxKind.CloseBraceToken);
654                const localName = factory.getInternalName(node);
655
656                // The following partially-emitted expression exists purely to align our sourcemap
657                // emit with the original emitter.
658                const outer = factory.createPartiallyEmittedExpression(localName);
659                setTextRangeEnd(outer, closingBraceLocation.end);
660                setEmitFlags(outer, EmitFlags.NoComments);
661
662                const statement = factory.createReturnStatement(outer);
663                setTextRangePos(statement, closingBraceLocation.pos);
664                setEmitFlags(statement, EmitFlags.NoComments | EmitFlags.NoTokenSourceMaps);
665                statements.push(statement);
666
667                insertStatementsAfterStandardPrologue(statements, context.endLexicalEnvironment());
668
669                const iife = factory.createImmediatelyInvokedArrowFunction(statements);
670                setEmitFlags(iife, EmitFlags.TypeScriptClassWrapper);
671
672                const varStatement = factory.createVariableStatement(
673                    /*modifiers*/ undefined,
674                    factory.createVariableDeclarationList([
675                        factory.createVariableDeclaration(
676                            factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ false),
677                            /*exclamationToken*/ undefined,
678                            /*type*/ undefined,
679                            iife
680                        )
681                    ])
682                );
683
684                setOriginalNode(varStatement, node);
685                setCommentRange(varStatement, node);
686                setSourceMapRange(varStatement, moveRangePastDecorators(node));
687                startOnNewLine(varStatement);
688                statements = [varStatement];
689            }
690
691            // If the class is exported as part of a TypeScript namespace, emit the namespace export.
692            // Otherwise, if the class was exported at the top level and was decorated, emit an export
693            // declaration or export default for the class.
694            if (facts & ClassFacts.IsExportOfNamespace) {
695                addExportMemberAssignment(statements, node);
696            }
697            else if (facts & ClassFacts.UseImmediatelyInvokedFunctionExpression || facts & ClassFacts.HasConstructorDecorators) {
698                if (facts & ClassFacts.IsDefaultExternalExport) {
699                    statements.push(factory.createExportDefault(factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true)));
700                }
701                else if (facts & ClassFacts.IsNamedExternalExport) {
702                    statements.push(factory.createExternalModuleExport(factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true)));
703                }
704            }
705
706            if (statements.length > 1) {
707                // Add a DeclarationMarker as a marker for the end of the declaration
708                statements.push(factory.createEndOfDeclarationMarker(node));
709                setEmitFlags(classStatement, getEmitFlags(classStatement) | EmitFlags.HasEndOfDeclarationMarker);
710            }
711
712            return singleOrMany(statements);
713        }
714
715        /**
716         * Transforms a non-decorated class declaration and appends the resulting statements.
717         *
718         * @param node A ClassDeclaration node.
719         * @param name The name of the class.
720         * @param facts Precomputed facts about the class.
721         */
722        function createClassDeclarationHeadWithoutDecorators(node: ClassDeclaration, name: Identifier | undefined, facts: ClassFacts) {
723            //  ${modifiers} class ${name} ${heritageClauses} {
724            //      ${members}
725            //  }
726
727            // we do not emit modifiers on the declaration if we are emitting an IIFE
728            const modifiers = !(facts & ClassFacts.UseImmediatelyInvokedFunctionExpression)
729                ? visitNodes(node.modifiers, modifierVisitor, isModifier)
730                : undefined;
731
732            const classDeclaration = factory.createClassDeclaration(
733                /*decorators*/ undefined,
734                modifiers,
735                name,
736                /*typeParameters*/ undefined,
737                visitNodes(node.heritageClauses, visitor, isHeritageClause),
738                transformClassMembers(node)
739            );
740
741            // To better align with the old emitter, we should not emit a trailing source map
742            // entry if the class has static properties.
743            let emitFlags = getEmitFlags(node);
744            if (facts & ClassFacts.HasStaticInitializedProperties) {
745                emitFlags |= EmitFlags.NoTrailingSourceMap;
746            }
747
748            setTextRange(classDeclaration, node);
749            setOriginalNode(classDeclaration, node);
750            setEmitFlags(classDeclaration, emitFlags);
751            return classDeclaration;
752        }
753
754        /**
755         * Transforms a decorated class declaration and appends the resulting statements. If
756         * the class requires an alias to avoid issues with double-binding, the alias is returned.
757         */
758        function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined) {
759            // When we emit an ES6 class that has a class decorator, we must tailor the
760            // emit to certain specific cases.
761            //
762            // In the simplest case, we emit the class declaration as a let declaration, and
763            // evaluate decorators after the close of the class body:
764            //
765            //  [Example 1]
766            //  ---------------------------------------------------------------------
767            //  TypeScript                      | Javascript
768            //  ---------------------------------------------------------------------
769            //  @dec                            | let C = class C {
770            //  class C {                       | }
771            //  }                               | C = __decorate([dec], C);
772            //  ---------------------------------------------------------------------
773            //  @dec                            | let C = class C {
774            //  export class C {                | }
775            //  }                               | C = __decorate([dec], C);
776            //                                  | export { C };
777            //  ---------------------------------------------------------------------
778            //
779            // If a class declaration contains a reference to itself *inside* of the class body,
780            // this introduces two bindings to the class: One outside of the class body, and one
781            // inside of the class body. If we apply decorators as in [Example 1] above, there
782            // is the possibility that the decorator `dec` will return a new value for the
783            // constructor, which would result in the binding inside of the class no longer
784            // pointing to the same reference as the binding outside of the class.
785            //
786            // As a result, we must instead rewrite all references to the class *inside* of the
787            // class body to instead point to a local temporary alias for the class:
788            //
789            //  [Example 2]
790            //  ---------------------------------------------------------------------
791            //  TypeScript                      | Javascript
792            //  ---------------------------------------------------------------------
793            //  @dec                            | let C = C_1 = class C {
794            //  class C {                       |   static x() { return C_1.y; }
795            //    static x() { return C.y; }    | }
796            //    static y = 1;                 | C.y = 1;
797            //  }                               | C = C_1 = __decorate([dec], C);
798            //                                  | var C_1;
799            //  ---------------------------------------------------------------------
800            //  @dec                            | let C = class C {
801            //  export class C {                |   static x() { return C_1.y; }
802            //    static x() { return C.y; }    | }
803            //    static y = 1;                 | C.y = 1;
804            //  }                               | C = C_1 = __decorate([dec], C);
805            //                                  | export { C };
806            //                                  | var C_1;
807            //  ---------------------------------------------------------------------
808            //
809            // If a class declaration is the default export of a module, we instead emit
810            // the export after the decorated declaration:
811            //
812            //  [Example 3]
813            //  ---------------------------------------------------------------------
814            //  TypeScript                      | Javascript
815            //  ---------------------------------------------------------------------
816            //  @dec                            | let default_1 = class {
817            //  export default class {          | }
818            //  }                               | default_1 = __decorate([dec], default_1);
819            //                                  | export default default_1;
820            //  ---------------------------------------------------------------------
821            //  @dec                            | let C = class C {
822            //  export default class C {        | }
823            //  }                               | C = __decorate([dec], C);
824            //                                  | export default C;
825            //  ---------------------------------------------------------------------
826            //
827            // If the class declaration is the default export and a reference to itself
828            // inside of the class body, we must emit both an alias for the class *and*
829            // move the export after the declaration:
830            //
831            //  [Example 4]
832            //  ---------------------------------------------------------------------
833            //  TypeScript                      | Javascript
834            //  ---------------------------------------------------------------------
835            //  @dec                            | let C = class C {
836            //  export default class C {        |   static x() { return C_1.y; }
837            //    static x() { return C.y; }    | }
838            //    static y = 1;                 | C.y = 1;
839            //  }                               | C = C_1 = __decorate([dec], C);
840            //                                  | export default C;
841            //                                  | var C_1;
842            //  ---------------------------------------------------------------------
843            //
844
845            const location = moveRangePastDecorators(node);
846            const classAlias = getClassAliasIfNeeded(node);
847            const declName = factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
848
849            //  ... = class ${name} ${heritageClauses} {
850            //      ${members}
851            //  }
852            const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
853            const members = transformClassMembers(node);
854            const classExpression = factory.createClassExpression(/*decorators*/ undefined, /*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members);
855            setOriginalNode(classExpression, node);
856            setTextRange(classExpression, location);
857
858            //  let ${name} = ${classExpression} where name is either declaredName if the class doesn't contain self-reference
859            //                                         or decoratedClassAlias if the class contain self-reference.
860            const statement = factory.createVariableStatement(
861                /*modifiers*/ undefined,
862                factory.createVariableDeclarationList([
863                    factory.createVariableDeclaration(
864                        declName,
865                        /*exclamationToken*/ undefined,
866                        /*type*/ undefined,
867                        classAlias ? factory.createAssignment(classAlias, classExpression) : classExpression
868                    )
869                ], NodeFlags.Let)
870            );
871            setOriginalNode(statement, node);
872            setTextRange(statement, location);
873            setCommentRange(statement, node);
874            return statement;
875        }
876
877        function visitClassExpression(node: ClassExpression): Expression {
878            if (!isClassLikeDeclarationWithTypeScriptSyntax(node)) {
879                return visitEachChild(node, visitor, context);
880            }
881
882            const classExpression = factory.createClassExpression(
883                /*decorators*/ undefined,
884                /*modifiers*/ undefined,
885                node.name,
886                /*typeParameters*/ undefined,
887                visitNodes(node.heritageClauses, visitor, isHeritageClause),
888                transformClassMembers(node)
889            );
890
891            setOriginalNode(classExpression, node);
892            setTextRange(classExpression, node);
893
894            return classExpression;
895        }
896
897        /**
898         * Transforms the members of a class.
899         *
900         * @param node The current class.
901         */
902        function transformClassMembers(node: ClassDeclaration | ClassExpression) {
903            const members: ClassElement[] = [];
904            const constructor = getFirstConstructorWithBody(node);
905            const parametersWithPropertyAssignments = constructor &&
906                filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor));
907
908            if (parametersWithPropertyAssignments) {
909                for (const parameter of parametersWithPropertyAssignments) {
910                    if (isIdentifier(parameter.name)) {
911                        members.push(setOriginalNode(factory.createPropertyDeclaration(
912                            /*decorators*/ undefined,
913                            /*modifiers*/ undefined,
914                            parameter.name,
915                            /*questionOrExclamationToken*/ undefined,
916                            /*type*/ undefined,
917                            /*initializer*/ undefined), parameter));
918                    }
919                }
920            }
921
922            addRange(members, visitNodes(node.members, classElementVisitor, isClassElement));
923            return setTextRange(factory.createNodeArray(members), /*location*/ node.members);
924        }
925
926
927        /**
928         * Gets either the static or instance members of a class that are decorated, or have
929         * parameters that are decorated.
930         *
931         * @param node The class containing the member.
932         * @param isStatic A value indicating whether to retrieve static or instance members of
933         *                 the class.
934         */
935        function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): readonly ClassElement[] {
936            return filter(node.members, isStatic ? m => isStaticDecoratedClassElement(m, node) : m => isInstanceDecoratedClassElement(m, node));
937        }
938
939        /**
940         * Determines whether a class member is a static member of a class that is decorated, or
941         * has parameters that are decorated.
942         *
943         * @param member The class member.
944         */
945        function isStaticDecoratedClassElement(member: ClassElement, parent: ClassLikeDeclaration) {
946            return isDecoratedClassElement(member, /*isStatic*/ true, parent);
947        }
948
949        /**
950         * Determines whether a class member is an instance member of a class that is decorated,
951         * or has parameters that are decorated.
952         *
953         * @param member The class member.
954         */
955        function isInstanceDecoratedClassElement(member: ClassElement, parent: ClassLikeDeclaration) {
956            return isDecoratedClassElement(member, /*isStatic*/ false, parent);
957        }
958
959        /**
960         * Determines whether a class member is either a static or an instance member of a class
961         * that is decorated, or has parameters that are decorated.
962         *
963         * @param member The class member.
964         */
965        function isDecoratedClassElement(member: ClassElement, isStatic: boolean, parent: ClassLikeDeclaration) {
966            return nodeOrChildIsDecorated(member, parent)
967                && isStatic === hasSyntacticModifier(member, ModifierFlags.Static);
968        }
969
970        /**
971         * A structure describing the decorators for a class element.
972         */
973        interface AllDecorators {
974            decorators: readonly Decorator[] | undefined;
975            parameters?: readonly (readonly Decorator[] | undefined)[];
976        }
977
978        /**
979         * Gets an array of arrays of decorators for the parameters of a function-like node.
980         * The offset into the result array should correspond to the offset of the parameter.
981         *
982         * @param node The function-like node.
983         */
984        function getDecoratorsOfParameters(node: FunctionLikeDeclaration | undefined) {
985            let decorators: (readonly Decorator[] | undefined)[] | undefined;
986            if (node) {
987                const parameters = node.parameters;
988                const firstParameterIsThis = parameters.length > 0 && parameterIsThisKeyword(parameters[0]);
989                const firstParameterOffset = firstParameterIsThis ? 1 : 0;
990                const numParameters = firstParameterIsThis ? parameters.length - 1 : parameters.length;
991                for (let i = 0; i < numParameters; i++) {
992                    const parameter = parameters[i + firstParameterOffset];
993                    if (decorators || parameter.decorators) {
994                        if (!decorators) {
995                            decorators = new Array(numParameters);
996                        }
997
998                        decorators[i] = parameter.decorators;
999                    }
1000                }
1001            }
1002
1003            return decorators;
1004        }
1005
1006        /**
1007         * Gets an AllDecorators object containing the decorators for the class and the decorators for the
1008         * parameters of the constructor of the class.
1009         *
1010         * @param node The class node.
1011         */
1012        function getAllDecoratorsOfConstructor(node: ClassExpression | ClassDeclaration): AllDecorators | undefined {
1013            const decorators = node.decorators;
1014            const parameters = getDecoratorsOfParameters(getFirstConstructorWithBody(node));
1015            if (!decorators && !parameters) {
1016                return undefined;
1017            }
1018
1019            return {
1020                decorators,
1021                parameters
1022            };
1023        }
1024
1025        /**
1026         * Gets an AllDecorators object containing the decorators for the member and its parameters.
1027         *
1028         * @param node The class node that contains the member.
1029         * @param member The class member.
1030         */
1031        function getAllDecoratorsOfClassElement(node: ClassExpression | ClassDeclaration, member: ClassElement): AllDecorators | undefined {
1032            switch (member.kind) {
1033                case SyntaxKind.GetAccessor:
1034                case SyntaxKind.SetAccessor:
1035                    return getAllDecoratorsOfAccessors(node, <AccessorDeclaration>member);
1036
1037                case SyntaxKind.MethodDeclaration:
1038                    return getAllDecoratorsOfMethod(<MethodDeclaration>member);
1039
1040                case SyntaxKind.PropertyDeclaration:
1041                    return getAllDecoratorsOfProperty(<PropertyDeclaration>member);
1042
1043                default:
1044                    return undefined;
1045            }
1046        }
1047
1048        /**
1049         * Gets an AllDecorators object containing the decorators for the accessor and its parameters.
1050         *
1051         * @param node The class node that contains the accessor.
1052         * @param accessor The class accessor member.
1053         */
1054        function getAllDecoratorsOfAccessors(node: ClassExpression | ClassDeclaration, accessor: AccessorDeclaration): AllDecorators | undefined {
1055            if (!accessor.body) {
1056                return undefined;
1057            }
1058
1059            const { firstAccessor, secondAccessor, setAccessor } = getAllAccessorDeclarations(node.members, accessor);
1060            const firstAccessorWithDecorators = firstAccessor.decorators ? firstAccessor : secondAccessor && secondAccessor.decorators ? secondAccessor : undefined;
1061            if (!firstAccessorWithDecorators || accessor !== firstAccessorWithDecorators) {
1062                return undefined;
1063            }
1064
1065            const decorators = firstAccessorWithDecorators.decorators;
1066            const parameters = getDecoratorsOfParameters(setAccessor);
1067            if (!decorators && !parameters) {
1068                return undefined;
1069            }
1070
1071            return { decorators, parameters };
1072        }
1073
1074        /**
1075         * Gets an AllDecorators object containing the decorators for the method and its parameters.
1076         *
1077         * @param method The class method member.
1078         */
1079        function getAllDecoratorsOfMethod(method: MethodDeclaration): AllDecorators | undefined {
1080            if (!method.body) {
1081                return undefined;
1082            }
1083
1084            const decorators = method.decorators;
1085            const parameters = getDecoratorsOfParameters(method);
1086            if (!decorators && !parameters) {
1087                return undefined;
1088            }
1089
1090            return { decorators, parameters };
1091        }
1092
1093        /**
1094         * Gets an AllDecorators object containing the decorators for the property.
1095         *
1096         * @param property The class property member.
1097         */
1098        function getAllDecoratorsOfProperty(property: PropertyDeclaration): AllDecorators | undefined {
1099            const decorators = property.decorators;
1100            if (!decorators) {
1101                return undefined;
1102
1103            }
1104
1105            return { decorators };
1106        }
1107
1108        /**
1109         * Transforms all of the decorators for a declaration into an array of expressions.
1110         *
1111         * @param node The declaration node.
1112         * @param allDecorators An object containing all of the decorators for the declaration.
1113         */
1114        function transformAllDecoratorsOfDeclaration(node: Declaration, container: ClassLikeDeclaration, allDecorators: AllDecorators | undefined) {
1115            if (!allDecorators) {
1116                return undefined;
1117            }
1118
1119            const decoratorExpressions: Expression[] = [];
1120            addRange(decoratorExpressions, map(allDecorators.decorators, transformDecorator));
1121            addRange(decoratorExpressions, flatMap(allDecorators.parameters, transformDecoratorsOfParameter));
1122            addTypeMetadata(node, container, decoratorExpressions);
1123            return decoratorExpressions;
1124        }
1125
1126        /**
1127         * Generates statements used to apply decorators to either the static or instance members
1128         * of a class.
1129         *
1130         * @param node The class node.
1131         * @param isStatic A value indicating whether to generate statements for static or
1132         *                 instance members.
1133         */
1134        function addClassElementDecorationStatements(statements: Statement[], node: ClassDeclaration, isStatic: boolean) {
1135            addRange(statements, map(generateClassElementDecorationExpressions(node, isStatic), expressionToStatement));
1136        }
1137
1138        /**
1139         * Generates expressions used to apply decorators to either the static or instance members
1140         * of a class.
1141         *
1142         * @param node The class node.
1143         * @param isStatic A value indicating whether to generate expressions for static or
1144         *                 instance members.
1145         */
1146        function generateClassElementDecorationExpressions(node: ClassExpression | ClassDeclaration, isStatic: boolean) {
1147            const members = getDecoratedClassElements(node, isStatic);
1148            let expressions: Expression[] | undefined;
1149            for (const member of members) {
1150                const expression = generateClassElementDecorationExpression(node, member);
1151                if (expression) {
1152                    if (!expressions) {
1153                        expressions = [expression];
1154                    }
1155                    else {
1156                        expressions.push(expression);
1157                    }
1158                }
1159            }
1160            return expressions;
1161        }
1162
1163        /**
1164         * Generates an expression used to evaluate class element decorators at runtime.
1165         *
1166         * @param node The class node that contains the member.
1167         * @param member The class member.
1168         */
1169        function generateClassElementDecorationExpression(node: ClassExpression | ClassDeclaration, member: ClassElement) {
1170            const allDecorators = getAllDecoratorsOfClassElement(node, member);
1171            const decoratorExpressions = transformAllDecoratorsOfDeclaration(member, node, allDecorators);
1172            if (!decoratorExpressions) {
1173                return undefined;
1174            }
1175
1176            // Emit the call to __decorate. Given the following:
1177            //
1178            //   class C {
1179            //     @dec method(@dec2 x) {}
1180            //     @dec get accessor() {}
1181            //     @dec prop;
1182            //   }
1183            //
1184            // The emit for a method is:
1185            //
1186            //   __decorate([
1187            //       dec,
1188            //       __param(0, dec2),
1189            //       __metadata("design:type", Function),
1190            //       __metadata("design:paramtypes", [Object]),
1191            //       __metadata("design:returntype", void 0)
1192            //   ], C.prototype, "method", null);
1193            //
1194            // The emit for an accessor is:
1195            //
1196            //   __decorate([
1197            //       dec
1198            //   ], C.prototype, "accessor", null);
1199            //
1200            // The emit for a property is:
1201            //
1202            //   __decorate([
1203            //       dec
1204            //   ], C.prototype, "prop");
1205            //
1206
1207            const prefix = getClassMemberPrefix(node, member);
1208            const memberName = getExpressionForPropertyName(member, /*generateNameForComputedPropertyName*/ true);
1209            const descriptor = languageVersion > ScriptTarget.ES3
1210                ? member.kind === SyntaxKind.PropertyDeclaration
1211                    // We emit `void 0` here to indicate to `__decorate` that it can invoke `Object.defineProperty` directly, but that it
1212                    // should not invoke `Object.getOwnPropertyDescriptor`.
1213                    ? factory.createVoidZero()
1214
1215                    // We emit `null` here to indicate to `__decorate` that it can invoke `Object.getOwnPropertyDescriptor` directly.
1216                    // We have this extra argument here so that we can inject an explicit property descriptor at a later date.
1217                    : factory.createNull()
1218                : undefined;
1219
1220            const helper = emitHelpers().createDecorateHelper(
1221                decoratorExpressions,
1222                prefix,
1223                memberName,
1224                descriptor
1225            );
1226
1227            setTextRange(helper, moveRangePastDecorators(member));
1228            setEmitFlags(helper, EmitFlags.NoComments);
1229            return helper;
1230        }
1231
1232        /**
1233         * Generates a __decorate helper call for a class constructor.
1234         *
1235         * @param node The class node.
1236         */
1237        function addConstructorDecorationStatement(statements: Statement[], node: ClassDeclaration) {
1238            const expression = generateConstructorDecorationExpression(node);
1239            if (expression) {
1240                statements.push(setOriginalNode(factory.createExpressionStatement(expression), node));
1241            }
1242        }
1243
1244        /**
1245         * Generates a __decorate helper call for a class constructor.
1246         *
1247         * @param node The class node.
1248         */
1249        function generateConstructorDecorationExpression(node: ClassExpression | ClassDeclaration) {
1250            const allDecorators = getAllDecoratorsOfConstructor(node);
1251            const decoratorExpressions = transformAllDecoratorsOfDeclaration(node, node, allDecorators);
1252            if (!decoratorExpressions) {
1253                return undefined;
1254            }
1255
1256            const classAlias = classAliases && classAliases[getOriginalNodeId(node)];
1257            const localName = factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
1258            const decorate = emitHelpers().createDecorateHelper(decoratorExpressions, localName);
1259            const expression = factory.createAssignment(localName, classAlias ? factory.createAssignment(classAlias, decorate) : decorate);
1260            setEmitFlags(expression, EmitFlags.NoComments);
1261            setSourceMapRange(expression, moveRangePastDecorators(node));
1262            return expression;
1263        }
1264
1265        /**
1266         * Transforms a decorator into an expression.
1267         *
1268         * @param decorator The decorator node.
1269         */
1270        function transformDecorator(decorator: Decorator) {
1271            return visitNode(decorator.expression, visitor, isExpression);
1272        }
1273
1274        /**
1275         * Transforms the decorators of a parameter.
1276         *
1277         * @param decorators The decorators for the parameter at the provided offset.
1278         * @param parameterOffset The offset of the parameter.
1279         */
1280        function transformDecoratorsOfParameter(decorators: Decorator[], parameterOffset: number) {
1281            let expressions: Expression[] | undefined;
1282            if (decorators) {
1283                expressions = [];
1284                for (const decorator of decorators) {
1285                    const helper = emitHelpers().createParamHelper(
1286                        transformDecorator(decorator),
1287                        parameterOffset);
1288                    setTextRange(helper, decorator.expression);
1289                    setEmitFlags(helper, EmitFlags.NoComments);
1290                    expressions.push(helper);
1291                }
1292            }
1293
1294            return expressions;
1295        }
1296
1297        /**
1298         * Adds optional type metadata for a declaration.
1299         *
1300         * @param node The declaration node.
1301         * @param decoratorExpressions The destination array to which to add new decorator expressions.
1302         */
1303        function addTypeMetadata(node: Declaration, container: ClassLikeDeclaration, decoratorExpressions: Expression[]) {
1304            if (USE_NEW_TYPE_METADATA_FORMAT) {
1305                addNewTypeMetadata(node, container, decoratorExpressions);
1306            }
1307            else {
1308                addOldTypeMetadata(node, container, decoratorExpressions);
1309            }
1310        }
1311
1312        function addOldTypeMetadata(node: Declaration, container: ClassLikeDeclaration, decoratorExpressions: Expression[]) {
1313            if (compilerOptions.emitDecoratorMetadata) {
1314                if (shouldAddTypeMetadata(node)) {
1315                    decoratorExpressions.push(emitHelpers().createMetadataHelper("design:type", serializeTypeOfNode(node)));
1316                }
1317                if (shouldAddParamTypesMetadata(node)) {
1318                    decoratorExpressions.push(emitHelpers().createMetadataHelper("design:paramtypes", serializeParameterTypesOfNode(node, container)));
1319                }
1320                if (shouldAddReturnTypeMetadata(node)) {
1321                    decoratorExpressions.push(emitHelpers().createMetadataHelper("design:returntype", serializeReturnTypeOfNode(node)));
1322                }
1323            }
1324        }
1325
1326        function addNewTypeMetadata(node: Declaration, container: ClassLikeDeclaration, decoratorExpressions: Expression[]) {
1327            if (compilerOptions.emitDecoratorMetadata) {
1328                let properties: ObjectLiteralElementLike[] | undefined;
1329                if (shouldAddTypeMetadata(node)) {
1330                    (properties || (properties = [])).push(factory.createPropertyAssignment("type", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), serializeTypeOfNode(node))));
1331                }
1332                if (shouldAddParamTypesMetadata(node)) {
1333                    (properties || (properties = [])).push(factory.createPropertyAssignment("paramTypes", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), serializeParameterTypesOfNode(node, container))));
1334                }
1335                if (shouldAddReturnTypeMetadata(node)) {
1336                    (properties || (properties = [])).push(factory.createPropertyAssignment("returnType", factory.createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, factory.createToken(SyntaxKind.EqualsGreaterThanToken), serializeReturnTypeOfNode(node))));
1337                }
1338                if (properties) {
1339                    decoratorExpressions.push(emitHelpers().createMetadataHelper("design:typeinfo", factory.createObjectLiteralExpression(properties, /*multiLine*/ true)));
1340                }
1341            }
1342        }
1343
1344        /**
1345         * Determines whether to emit the "design:type" metadata based on the node's kind.
1346         * The caller should have already tested whether the node has decorators and whether the
1347         * emitDecoratorMetadata compiler option is set.
1348         *
1349         * @param node The node to test.
1350         */
1351        function shouldAddTypeMetadata(node: Declaration): boolean {
1352            const kind = node.kind;
1353            return kind === SyntaxKind.MethodDeclaration
1354                || kind === SyntaxKind.GetAccessor
1355                || kind === SyntaxKind.SetAccessor
1356                || kind === SyntaxKind.PropertyDeclaration;
1357        }
1358
1359        /**
1360         * Determines whether to emit the "design:returntype" metadata based on the node's kind.
1361         * The caller should have already tested whether the node has decorators and whether the
1362         * emitDecoratorMetadata compiler option is set.
1363         *
1364         * @param node The node to test.
1365         */
1366        function shouldAddReturnTypeMetadata(node: Declaration): boolean {
1367            return node.kind === SyntaxKind.MethodDeclaration;
1368        }
1369
1370        /**
1371         * Determines whether to emit the "design:paramtypes" metadata based on the node's kind.
1372         * The caller should have already tested whether the node has decorators and whether the
1373         * emitDecoratorMetadata compiler option is set.
1374         *
1375         * @param node The node to test.
1376         */
1377        function shouldAddParamTypesMetadata(node: Declaration): boolean {
1378            switch (node.kind) {
1379                case SyntaxKind.ClassDeclaration:
1380                case SyntaxKind.ClassExpression:
1381                    return getFirstConstructorWithBody(<ClassLikeDeclaration>node) !== undefined;
1382                case SyntaxKind.MethodDeclaration:
1383                case SyntaxKind.GetAccessor:
1384                case SyntaxKind.SetAccessor:
1385                    return true;
1386            }
1387            return false;
1388        }
1389
1390        type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression;
1391        type SerializedTypeNode = SerializedEntityNameAsExpression | VoidExpression | ConditionalExpression;
1392
1393        function getAccessorTypeNode(node: AccessorDeclaration) {
1394            const accessors = resolver.getAllAccessorDeclarations(node);
1395            return accessors.setAccessor && getSetAccessorTypeAnnotationNode(accessors.setAccessor)
1396                || accessors.getAccessor && getEffectiveReturnTypeNode(accessors.getAccessor);
1397        }
1398
1399        /**
1400         * Serializes the type of a node for use with decorator type metadata.
1401         *
1402         * @param node The node that should have its type serialized.
1403         */
1404        function serializeTypeOfNode(node: Node): SerializedTypeNode {
1405            switch (node.kind) {
1406                case SyntaxKind.PropertyDeclaration:
1407                case SyntaxKind.Parameter:
1408                    return serializeTypeNode((<PropertyDeclaration | ParameterDeclaration | GetAccessorDeclaration>node).type);
1409                case SyntaxKind.SetAccessor:
1410                case SyntaxKind.GetAccessor:
1411                    return serializeTypeNode(getAccessorTypeNode(node as AccessorDeclaration));
1412                case SyntaxKind.ClassDeclaration:
1413                case SyntaxKind.ClassExpression:
1414                case SyntaxKind.MethodDeclaration:
1415                    return factory.createIdentifier("Function");
1416                default:
1417                    return factory.createVoidZero();
1418            }
1419        }
1420
1421        /**
1422         * Serializes the types of the parameters of a node for use with decorator type metadata.
1423         *
1424         * @param node The node that should have its parameter types serialized.
1425         */
1426        function serializeParameterTypesOfNode(node: Node, container: ClassLikeDeclaration): ArrayLiteralExpression {
1427            const valueDeclaration =
1428                isClassLike(node)
1429                    ? getFirstConstructorWithBody(node)
1430                    : isFunctionLike(node) && nodeIsPresent((node as FunctionLikeDeclaration).body)
1431                        ? node
1432                        : undefined;
1433
1434            const expressions: SerializedTypeNode[] = [];
1435            if (valueDeclaration) {
1436                const parameters = getParametersOfDecoratedDeclaration(valueDeclaration, container);
1437                const numParameters = parameters.length;
1438                for (let i = 0; i < numParameters; i++) {
1439                    const parameter = parameters[i];
1440                    if (i === 0 && isIdentifier(parameter.name) && parameter.name.escapedText === "this") {
1441                        continue;
1442                    }
1443                    if (parameter.dotDotDotToken) {
1444                        expressions.push(serializeTypeNode(getRestParameterElementType(parameter.type)));
1445                    }
1446                    else {
1447                        expressions.push(serializeTypeOfNode(parameter));
1448                    }
1449                }
1450            }
1451
1452            return factory.createArrayLiteralExpression(expressions);
1453        }
1454
1455        function getParametersOfDecoratedDeclaration(node: SignatureDeclaration, container: ClassLikeDeclaration) {
1456            if (container && node.kind === SyntaxKind.GetAccessor) {
1457                const { setAccessor } = getAllAccessorDeclarations(container.members, <AccessorDeclaration>node);
1458                if (setAccessor) {
1459                    return setAccessor.parameters;
1460                }
1461            }
1462            return node.parameters;
1463        }
1464
1465        /**
1466         * Serializes the return type of a node for use with decorator type metadata.
1467         *
1468         * @param node The node that should have its return type serialized.
1469         */
1470        function serializeReturnTypeOfNode(node: Node): SerializedTypeNode {
1471            if (isFunctionLike(node) && node.type) {
1472                return serializeTypeNode(node.type);
1473            }
1474            else if (isAsyncFunction(node)) {
1475                return factory.createIdentifier("Promise");
1476            }
1477
1478            return factory.createVoidZero();
1479        }
1480
1481        /**
1482         * Serializes a type node for use with decorator type metadata.
1483         *
1484         * Types are serialized in the following fashion:
1485         * - Void types point to "undefined" (e.g. "void 0")
1486         * - Function and Constructor types point to the global "Function" constructor.
1487         * - Interface types with a call or construct signature types point to the global
1488         *   "Function" constructor.
1489         * - Array and Tuple types point to the global "Array" constructor.
1490         * - Type predicates and booleans point to the global "Boolean" constructor.
1491         * - String literal types and strings point to the global "String" constructor.
1492         * - Enum and number types point to the global "Number" constructor.
1493         * - Symbol types point to the global "Symbol" constructor.
1494         * - Type references to classes (or class-like variables) point to the constructor for the class.
1495         * - Anything else points to the global "Object" constructor.
1496         *
1497         * @param node The type node to serialize.
1498         */
1499        function serializeTypeNode(node: TypeNode | undefined): SerializedTypeNode {
1500            if (node === undefined) {
1501                return factory.createIdentifier("Object");
1502            }
1503
1504            switch (node.kind) {
1505                case SyntaxKind.VoidKeyword:
1506                case SyntaxKind.UndefinedKeyword:
1507                case SyntaxKind.NeverKeyword:
1508                    return factory.createVoidZero();
1509
1510                case SyntaxKind.ParenthesizedType:
1511                    return serializeTypeNode((<ParenthesizedTypeNode>node).type);
1512
1513                case SyntaxKind.FunctionType:
1514                case SyntaxKind.ConstructorType:
1515                    return factory.createIdentifier("Function");
1516
1517                case SyntaxKind.ArrayType:
1518                case SyntaxKind.TupleType:
1519                    return factory.createIdentifier("Array");
1520
1521                case SyntaxKind.TypePredicate:
1522                case SyntaxKind.BooleanKeyword:
1523                    return factory.createIdentifier("Boolean");
1524
1525                case SyntaxKind.StringKeyword:
1526                    return factory.createIdentifier("String");
1527
1528                case SyntaxKind.ObjectKeyword:
1529                    return factory.createIdentifier("Object");
1530
1531                case SyntaxKind.LiteralType:
1532                    switch ((<LiteralTypeNode>node).literal.kind) {
1533                        case SyntaxKind.StringLiteral:
1534                        case SyntaxKind.NoSubstitutionTemplateLiteral:
1535                            return factory.createIdentifier("String");
1536
1537                        case SyntaxKind.PrefixUnaryExpression:
1538                        case SyntaxKind.NumericLiteral:
1539                            return factory.createIdentifier("Number");
1540
1541                        case SyntaxKind.BigIntLiteral:
1542                            return getGlobalBigIntNameWithFallback();
1543
1544                        case SyntaxKind.TrueKeyword:
1545                        case SyntaxKind.FalseKeyword:
1546                            return factory.createIdentifier("Boolean");
1547
1548                        case SyntaxKind.NullKeyword:
1549                            return factory.createVoidZero();
1550
1551                        default:
1552                            return Debug.failBadSyntaxKind((<LiteralTypeNode>node).literal);
1553                    }
1554
1555                case SyntaxKind.NumberKeyword:
1556                    return factory.createIdentifier("Number");
1557
1558                case SyntaxKind.BigIntKeyword:
1559                    return getGlobalBigIntNameWithFallback();
1560
1561                case SyntaxKind.SymbolKeyword:
1562                    return languageVersion < ScriptTarget.ES2015
1563                        ? getGlobalSymbolNameWithFallback()
1564                        : factory.createIdentifier("Symbol");
1565
1566                case SyntaxKind.TypeReference:
1567                    return serializeTypeReferenceNode(<TypeReferenceNode>node);
1568
1569                case SyntaxKind.IntersectionType:
1570                case SyntaxKind.UnionType:
1571                    return serializeTypeList((<UnionOrIntersectionTypeNode>node).types);
1572
1573                case SyntaxKind.ConditionalType:
1574                    return serializeTypeList([(<ConditionalTypeNode>node).trueType, (<ConditionalTypeNode>node).falseType]);
1575
1576                case SyntaxKind.TypeOperator:
1577                    if ((<TypeOperatorNode>node).operator === SyntaxKind.ReadonlyKeyword) {
1578                        return serializeTypeNode((<TypeOperatorNode>node).type);
1579                    }
1580                    break;
1581
1582                case SyntaxKind.TypeQuery:
1583                case SyntaxKind.IndexedAccessType:
1584                case SyntaxKind.MappedType:
1585                case SyntaxKind.TypeLiteral:
1586                case SyntaxKind.AnyKeyword:
1587                case SyntaxKind.UnknownKeyword:
1588                case SyntaxKind.ThisType:
1589                case SyntaxKind.ImportType:
1590                    break;
1591
1592                // handle JSDoc types from an invalid parse
1593                case SyntaxKind.JSDocAllType:
1594                case SyntaxKind.JSDocUnknownType:
1595                case SyntaxKind.JSDocFunctionType:
1596                case SyntaxKind.JSDocVariadicType:
1597                case SyntaxKind.JSDocNamepathType:
1598                    break;
1599
1600                case SyntaxKind.JSDocNullableType:
1601                case SyntaxKind.JSDocNonNullableType:
1602                case SyntaxKind.JSDocOptionalType:
1603                    return serializeTypeNode((<JSDocNullableType | JSDocNonNullableType | JSDocOptionalType>node).type);
1604                default:
1605                    return Debug.failBadSyntaxKind(node);
1606            }
1607
1608            return factory.createIdentifier("Object");
1609        }
1610
1611        function serializeTypeList(types: readonly TypeNode[]): SerializedTypeNode {
1612            // Note when updating logic here also update getEntityNameForDecoratorMetadata
1613            // so that aliases can be marked as referenced
1614            let serializedUnion: SerializedTypeNode | undefined;
1615            for (let typeNode of types) {
1616                while (typeNode.kind === SyntaxKind.ParenthesizedType) {
1617                    typeNode = (typeNode as ParenthesizedTypeNode).type; // Skip parens if need be
1618                }
1619                if (typeNode.kind === SyntaxKind.NeverKeyword) {
1620                    continue; // Always elide `never` from the union/intersection if possible
1621                }
1622                if (!strictNullChecks && (typeNode.kind === SyntaxKind.LiteralType && (typeNode as LiteralTypeNode).literal.kind === SyntaxKind.NullKeyword || typeNode.kind === SyntaxKind.UndefinedKeyword)) {
1623                    continue; // Elide null and undefined from unions for metadata, just like what we did prior to the implementation of strict null checks
1624                }
1625                const serializedIndividual = serializeTypeNode(typeNode);
1626
1627                if (isIdentifier(serializedIndividual) && serializedIndividual.escapedText === "Object") {
1628                    // One of the individual is global object, return immediately
1629                    return serializedIndividual;
1630                }
1631                // If there exists union that is not void 0 expression, check if the the common type is identifier.
1632                // anything more complex and we will just default to Object
1633                else if (serializedUnion) {
1634                    // Different types
1635                    if (!isIdentifier(serializedUnion) ||
1636                        !isIdentifier(serializedIndividual) ||
1637                        serializedUnion.escapedText !== serializedIndividual.escapedText) {
1638                        return factory.createIdentifier("Object");
1639                    }
1640                }
1641                else {
1642                    // Initialize the union type
1643                    serializedUnion = serializedIndividual;
1644                }
1645            }
1646
1647            // If we were able to find common type, use it
1648            return serializedUnion || factory.createVoidZero(); // Fallback is only hit if all union constituients are null/undefined/never
1649        }
1650
1651        /**
1652         * Serializes a TypeReferenceNode to an appropriate JS constructor value for use with
1653         * decorator type metadata.
1654         *
1655         * @param node The type reference node.
1656         */
1657        function serializeTypeReferenceNode(node: TypeReferenceNode): SerializedTypeNode {
1658            const kind = resolver.getTypeReferenceSerializationKind(node.typeName, currentNameScope || currentLexicalScope);
1659            switch (kind) {
1660                case TypeReferenceSerializationKind.Unknown:
1661                    // From conditional type type reference that cannot be resolved is Similar to any or unknown
1662                    if (findAncestor(node, n => n.parent && isConditionalTypeNode(n.parent) && (n.parent.trueType === n || n.parent.falseType === n))) {
1663                        return factory.createIdentifier("Object");
1664                    }
1665
1666                    const serialized = serializeEntityNameAsExpressionFallback(node.typeName);
1667                    const temp = factory.createTempVariable(hoistVariableDeclaration);
1668                    return factory.createConditionalExpression(
1669                        factory.createTypeCheck(factory.createAssignment(temp, serialized), "function"),
1670                        /*questionToken*/ undefined,
1671                        temp,
1672                        /*colonToken*/ undefined,
1673                        factory.createIdentifier("Object")
1674                    );
1675
1676                case TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue:
1677                    return serializeEntityNameAsExpression(node.typeName);
1678
1679                case TypeReferenceSerializationKind.VoidNullableOrNeverType:
1680                    return factory.createVoidZero();
1681
1682                case TypeReferenceSerializationKind.BigIntLikeType:
1683                    return getGlobalBigIntNameWithFallback();
1684
1685                case TypeReferenceSerializationKind.BooleanType:
1686                    return factory.createIdentifier("Boolean");
1687
1688                case TypeReferenceSerializationKind.NumberLikeType:
1689                    return factory.createIdentifier("Number");
1690
1691                case TypeReferenceSerializationKind.StringLikeType:
1692                    return factory.createIdentifier("String");
1693
1694                case TypeReferenceSerializationKind.ArrayLikeType:
1695                    return factory.createIdentifier("Array");
1696
1697                case TypeReferenceSerializationKind.ESSymbolType:
1698                    return languageVersion < ScriptTarget.ES2015
1699                        ? getGlobalSymbolNameWithFallback()
1700                        : factory.createIdentifier("Symbol");
1701
1702                case TypeReferenceSerializationKind.TypeWithCallSignature:
1703                    return factory.createIdentifier("Function");
1704
1705                case TypeReferenceSerializationKind.Promise:
1706                    return factory.createIdentifier("Promise");
1707
1708                case TypeReferenceSerializationKind.ObjectType:
1709                    return factory.createIdentifier("Object");
1710                default:
1711                    return Debug.assertNever(kind);
1712            }
1713        }
1714
1715        function createCheckedValue(left: Expression, right: Expression) {
1716            return factory.createLogicalAnd(
1717                factory.createStrictInequality(factory.createTypeOfExpression(left), factory.createStringLiteral("undefined")),
1718                right
1719            );
1720        }
1721
1722        /**
1723         * Serializes an entity name which may not exist at runtime, but whose access shouldn't throw
1724         *
1725         * @param node The entity name to serialize.
1726         */
1727        function serializeEntityNameAsExpressionFallback(node: EntityName): BinaryExpression {
1728            if (node.kind === SyntaxKind.Identifier) {
1729                // A -> typeof A !== undefined && A
1730                const copied = serializeEntityNameAsExpression(node);
1731                return createCheckedValue(copied, copied);
1732            }
1733            if (node.left.kind === SyntaxKind.Identifier) {
1734                // A.B -> typeof A !== undefined && A.B
1735                return createCheckedValue(serializeEntityNameAsExpression(node.left), serializeEntityNameAsExpression(node));
1736            }
1737            // A.B.C -> typeof A !== undefined && (_a = A.B) !== void 0 && _a.C
1738            const left = serializeEntityNameAsExpressionFallback(node.left);
1739            const temp = factory.createTempVariable(hoistVariableDeclaration);
1740            return factory.createLogicalAnd(
1741                factory.createLogicalAnd(
1742                    left.left,
1743                    factory.createStrictInequality(factory.createAssignment(temp, left.right), factory.createVoidZero())
1744                ),
1745                factory.createPropertyAccessExpression(temp, node.right)
1746            );
1747        }
1748
1749        /**
1750         * Serializes an entity name as an expression for decorator type metadata.
1751         *
1752         * @param node The entity name to serialize.
1753         */
1754        function serializeEntityNameAsExpression(node: EntityName): SerializedEntityNameAsExpression {
1755            switch (node.kind) {
1756                case SyntaxKind.Identifier:
1757                    // Create a clone of the name with a new parent, and treat it as if it were
1758                    // a source tree node for the purposes of the checker.
1759                    const name = setParent(setTextRange(parseNodeFactory.cloneNode(node), node), node.parent);
1760                    name.original = undefined;
1761                    setParent(name, getParseTreeNode(currentLexicalScope)); // ensure the parent is set to a parse tree node.
1762                    return name;
1763
1764                case SyntaxKind.QualifiedName:
1765                    return serializeQualifiedNameAsExpression(node);
1766            }
1767        }
1768
1769        /**
1770         * Serializes an qualified name as an expression for decorator type metadata.
1771         *
1772         * @param node The qualified name to serialize.
1773         * @param useFallback A value indicating whether to use logical operators to test for the
1774         *                    qualified name at runtime.
1775         */
1776        function serializeQualifiedNameAsExpression(node: QualifiedName): SerializedEntityNameAsExpression {
1777            return factory.createPropertyAccessExpression(serializeEntityNameAsExpression(node.left), node.right);
1778        }
1779
1780        /**
1781         * Gets an expression that points to the global "Symbol" constructor at runtime if it is
1782         * available.
1783         */
1784        function getGlobalSymbolNameWithFallback(): ConditionalExpression {
1785            return factory.createConditionalExpression(
1786                factory.createTypeCheck(factory.createIdentifier("Symbol"), "function"),
1787                /*questionToken*/ undefined,
1788                factory.createIdentifier("Symbol"),
1789                /*colonToken*/ undefined,
1790                factory.createIdentifier("Object")
1791            );
1792        }
1793
1794        /**
1795         * Gets an expression that points to the global "BigInt" constructor at runtime if it is
1796         * available.
1797         */
1798        function getGlobalBigIntNameWithFallback(): SerializedTypeNode {
1799            return languageVersion < ScriptTarget.ESNext
1800                ? factory.createConditionalExpression(
1801                    factory.createTypeCheck(factory.createIdentifier("BigInt"), "function"),
1802                    /*questionToken*/ undefined,
1803                    factory.createIdentifier("BigInt"),
1804                    /*colonToken*/ undefined,
1805                    factory.createIdentifier("Object")
1806                )
1807                : factory.createIdentifier("BigInt");
1808        }
1809
1810        /**
1811         * Gets an expression that represents a property name (for decorated properties or enums).
1812         * For a computed property, a name is generated for the node.
1813         *
1814         * @param member The member whose name should be converted into an expression.
1815         */
1816        function getExpressionForPropertyName(member: ClassElement | EnumMember, generateNameForComputedPropertyName: boolean): Expression {
1817            const name = member.name!;
1818            if (isPrivateIdentifier(name)) {
1819                return factory.createIdentifier("");
1820            }
1821            else if (isComputedPropertyName(name)) {
1822                return generateNameForComputedPropertyName && !isSimpleInlineableExpression(name.expression)
1823                    ? factory.getGeneratedNameForNode(name)
1824                    : name.expression;
1825            }
1826            else if (isIdentifier(name)) {
1827                return factory.createStringLiteral(idText(name));
1828            }
1829            else {
1830                return factory.cloneNode(name);
1831            }
1832        }
1833
1834        /**
1835         * Visits the property name of a class element, for use when emitting property
1836         * initializers. For a computed property on a node with decorators, a temporary
1837         * value is stored for later use.
1838         *
1839         * @param member The member whose name should be visited.
1840         */
1841        function visitPropertyNameOfClassElement(member: ClassElement): PropertyName {
1842            const name = member.name!;
1843            // Computed property names need to be transformed into a hoisted variable when they are used more than once.
1844            // The names are used more than once when:
1845            //   - the property is non-static and its initializer is moved to the constructor (when there are parameter property assignments).
1846            //   - the property has a decorator.
1847            if (isComputedPropertyName(name) && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || some(member.decorators))) {
1848                const expression = visitNode(name.expression, visitor, isExpression);
1849                const innerExpression = skipPartiallyEmittedExpressions(expression);
1850                if (!isSimpleInlineableExpression(innerExpression)) {
1851                    const generatedName = factory.getGeneratedNameForNode(name);
1852                    hoistVariableDeclaration(generatedName);
1853                    return factory.updateComputedPropertyName(name, factory.createAssignment(generatedName, expression));
1854                }
1855            }
1856            return visitNode(name, visitor, isPropertyName);
1857        }
1858
1859        /**
1860         * Transforms a HeritageClause with TypeScript syntax.
1861         *
1862         * This function will only be called when one of the following conditions are met:
1863         * - The node is a non-`extends` heritage clause that should be elided.
1864         * - The node is an `extends` heritage clause that should be visited, but only allow a single type.
1865         *
1866         * @param node The HeritageClause to transform.
1867         */
1868        function visitHeritageClause(node: HeritageClause): HeritageClause | undefined {
1869            if (node.token === SyntaxKind.ImplementsKeyword) {
1870                // implements clauses are elided
1871                return undefined;
1872            }
1873            return visitEachChild(node, visitor, context);
1874        }
1875
1876        /**
1877         * Transforms an ExpressionWithTypeArguments with TypeScript syntax.
1878         *
1879         * This function will only be called when one of the following conditions are met:
1880         * - The node contains type arguments that should be elided.
1881         *
1882         * @param node The ExpressionWithTypeArguments to transform.
1883         */
1884        function visitExpressionWithTypeArguments(node: ExpressionWithTypeArguments): ExpressionWithTypeArguments {
1885            return factory.updateExpressionWithTypeArguments(
1886                node,
1887                visitNode(node.expression, visitor, isLeftHandSideExpression),
1888                /*typeArguments*/ undefined
1889            );
1890        }
1891
1892        /**
1893         * Determines whether to emit a function-like declaration. We should not emit the
1894         * declaration if it does not have a body.
1895         *
1896         * @param node The declaration node.
1897         */
1898        function shouldEmitFunctionLikeDeclaration<T extends FunctionLikeDeclaration>(node: T): node is T & { body: NonNullable<T["body"]> } {
1899            return !nodeIsMissing(node.body);
1900        }
1901
1902        function visitPropertyDeclaration(node: PropertyDeclaration) {
1903            if (node.flags & NodeFlags.Ambient || hasSyntacticModifier(node, ModifierFlags.Abstract)) {
1904                return undefined;
1905            }
1906            const updated = factory.updatePropertyDeclaration(
1907                node,
1908                /*decorators*/ undefined,
1909                visitNodes(node.modifiers, visitor, isModifier),
1910                visitPropertyNameOfClassElement(node),
1911                /*questionOrExclamationToken*/ undefined,
1912                /*type*/ undefined,
1913                visitNode(node.initializer, visitor)
1914            );
1915            if (updated !== node) {
1916                // While we emit the source map for the node after skipping decorators and modifiers,
1917                // we need to emit the comments for the original range.
1918                setCommentRange(updated, node);
1919                setSourceMapRange(updated, moveRangePastDecorators(node));
1920            }
1921            return updated;
1922        }
1923
1924        function visitConstructor(node: ConstructorDeclaration) {
1925            if (!shouldEmitFunctionLikeDeclaration(node)) {
1926                return undefined;
1927            }
1928
1929            return factory.updateConstructorDeclaration(
1930                node,
1931                /*decorators*/ undefined,
1932                /*modifiers*/ undefined,
1933                visitParameterList(node.parameters, visitor, context),
1934                transformConstructorBody(node.body, node)
1935            );
1936        }
1937
1938        function transformConstructorBody(body: Block, constructor: ConstructorDeclaration) {
1939            const parametersWithPropertyAssignments = constructor &&
1940                filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor));
1941            if (!some(parametersWithPropertyAssignments)) {
1942                return visitFunctionBody(body, visitor, context);
1943            }
1944
1945            let statements: Statement[] = [];
1946            let indexOfFirstStatement = 0;
1947
1948            resumeLexicalEnvironment();
1949
1950            indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(factory, constructor, statements, visitor);
1951
1952            // Add parameters with property assignments. Transforms this:
1953            //
1954            //  constructor (public x, public y) {
1955            //  }
1956            //
1957            // Into this:
1958            //
1959            //  constructor (x, y) {
1960            //      this.x = x;
1961            //      this.y = y;
1962            //  }
1963            //
1964            addRange(statements, map(parametersWithPropertyAssignments, transformParameterWithPropertyAssignment));
1965
1966            // Add the existing statements, skipping the initial super call.
1967            addRange(statements, visitNodes(body.statements, visitor, isStatement, indexOfFirstStatement));
1968
1969            // End the lexical environment.
1970            statements = factory.mergeLexicalEnvironment(statements, endLexicalEnvironment());
1971            const block = factory.createBlock(setTextRange(factory.createNodeArray(statements), body.statements), /*multiLine*/ true);
1972            setTextRange(block, /*location*/ body);
1973            setOriginalNode(block, body);
1974            return block;
1975        }
1976
1977        /**
1978         * Transforms a parameter into a property assignment statement.
1979         *
1980         * @param node The parameter declaration.
1981         */
1982        function transformParameterWithPropertyAssignment(node: ParameterPropertyDeclaration) {
1983            const name = node.name;
1984            if (!isIdentifier(name)) {
1985                return undefined;
1986            }
1987
1988            // TODO(rbuckton): Does this need to be parented?
1989            const propertyName = setParent(setTextRange(factory.cloneNode(name), name), name.parent);
1990            setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoSourceMap);
1991
1992            // TODO(rbuckton): Does this need to be parented?
1993            const localName = setParent(setTextRange(factory.cloneNode(name), name), name.parent);
1994            setEmitFlags(localName, EmitFlags.NoComments);
1995
1996            return startOnNewLine(
1997                removeAllComments(
1998                    setTextRange(
1999                        setOriginalNode(
2000                            factory.createExpressionStatement(
2001                                factory.createAssignment(
2002                                    setTextRange(
2003                                        factory.createPropertyAccessExpression(
2004                                            factory.createThis(),
2005                                            propertyName
2006                                        ),
2007                                        node.name
2008                                    ),
2009                                    localName
2010                                )
2011                            ),
2012                            node
2013                        ),
2014                        moveRangePos(node, -1)
2015                    )
2016                )
2017            );
2018        }
2019
2020        function visitMethodDeclaration(node: MethodDeclaration) {
2021            if (!shouldEmitFunctionLikeDeclaration(node)) {
2022                return undefined;
2023            }
2024            const updated = factory.updateMethodDeclaration(
2025                node,
2026                /*decorators*/ undefined,
2027                visitNodes(node.modifiers, modifierVisitor, isModifier),
2028                node.asteriskToken,
2029                visitPropertyNameOfClassElement(node),
2030                /*questionToken*/ undefined,
2031                /*typeParameters*/ undefined,
2032                visitParameterList(node.parameters, visitor, context),
2033                /*type*/ undefined,
2034                visitFunctionBody(node.body, visitor, context)
2035            );
2036            if (updated !== node) {
2037                // While we emit the source map for the node after skipping decorators and modifiers,
2038                // we need to emit the comments for the original range.
2039                setCommentRange(updated, node);
2040                setSourceMapRange(updated, moveRangePastDecorators(node));
2041            }
2042            return updated;
2043        }
2044
2045        /**
2046         * Determines whether to emit an accessor declaration. We should not emit the
2047         * declaration if it does not have a body and is abstract.
2048         *
2049         * @param node The declaration node.
2050         */
2051        function shouldEmitAccessorDeclaration(node: AccessorDeclaration) {
2052            return !(nodeIsMissing(node.body) && hasSyntacticModifier(node, ModifierFlags.Abstract));
2053        }
2054
2055        function visitGetAccessor(node: GetAccessorDeclaration) {
2056            if (!shouldEmitAccessorDeclaration(node)) {
2057                return undefined;
2058            }
2059            const updated = factory.updateGetAccessorDeclaration(
2060                node,
2061                /*decorators*/ undefined,
2062                visitNodes(node.modifiers, modifierVisitor, isModifier),
2063                visitPropertyNameOfClassElement(node),
2064                visitParameterList(node.parameters, visitor, context),
2065                /*type*/ undefined,
2066                visitFunctionBody(node.body, visitor, context) || factory.createBlock([])
2067            );
2068            if (updated !== node) {
2069                // While we emit the source map for the node after skipping decorators and modifiers,
2070                // we need to emit the comments for the original range.
2071                setCommentRange(updated, node);
2072                setSourceMapRange(updated, moveRangePastDecorators(node));
2073            }
2074            return updated;
2075        }
2076
2077        function visitSetAccessor(node: SetAccessorDeclaration) {
2078            if (!shouldEmitAccessorDeclaration(node)) {
2079                return undefined;
2080            }
2081            const updated = factory.updateSetAccessorDeclaration(
2082                node,
2083                /*decorators*/ undefined,
2084                visitNodes(node.modifiers, modifierVisitor, isModifier),
2085                visitPropertyNameOfClassElement(node),
2086                visitParameterList(node.parameters, visitor, context),
2087                visitFunctionBody(node.body, visitor, context) || factory.createBlock([])
2088            );
2089            if (updated !== node) {
2090                // While we emit the source map for the node after skipping decorators and modifiers,
2091                // we need to emit the comments for the original range.
2092                setCommentRange(updated, node);
2093                setSourceMapRange(updated, moveRangePastDecorators(node));
2094            }
2095            return updated;
2096        }
2097
2098        function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult<Statement> {
2099            if (!shouldEmitFunctionLikeDeclaration(node)) {
2100                return factory.createNotEmittedStatement(node);
2101            }
2102            const updated = factory.updateFunctionDeclaration(
2103                node,
2104                /*decorators*/ undefined,
2105                visitNodes(node.modifiers, modifierVisitor, isModifier),
2106                node.asteriskToken,
2107                node.name,
2108                /*typeParameters*/ undefined,
2109                visitParameterList(node.parameters, visitor, context),
2110                /*type*/ undefined,
2111                visitFunctionBody(node.body, visitor, context) || factory.createBlock([])
2112            );
2113            if (isExportOfNamespace(node)) {
2114                const statements: Statement[] = [updated];
2115                addExportMemberAssignment(statements, node);
2116                return statements;
2117            }
2118            return updated;
2119        }
2120
2121        function visitFunctionExpression(node: FunctionExpression): Expression {
2122            if (!shouldEmitFunctionLikeDeclaration(node)) {
2123                return factory.createOmittedExpression();
2124            }
2125            const updated = factory.updateFunctionExpression(
2126                node,
2127                visitNodes(node.modifiers, modifierVisitor, isModifier),
2128                node.asteriskToken,
2129                node.name,
2130                /*typeParameters*/ undefined,
2131                visitParameterList(node.parameters, visitor, context),
2132                /*type*/ undefined,
2133                visitFunctionBody(node.body, visitor, context) || factory.createBlock([])
2134            );
2135            return updated;
2136        }
2137
2138        function visitArrowFunction(node: ArrowFunction) {
2139            const updated = factory.updateArrowFunction(
2140                node,
2141                visitNodes(node.modifiers, modifierVisitor, isModifier),
2142                /*typeParameters*/ undefined,
2143                visitParameterList(node.parameters, visitor, context),
2144                /*type*/ undefined,
2145                node.equalsGreaterThanToken,
2146                visitFunctionBody(node.body, visitor, context),
2147            );
2148            return updated;
2149        }
2150
2151        function visitParameter(node: ParameterDeclaration) {
2152            if (parameterIsThisKeyword(node)) {
2153                return undefined;
2154            }
2155
2156            const updated = factory.updateParameterDeclaration(
2157                node,
2158                /*decorators*/ undefined,
2159                /*modifiers*/ undefined,
2160                node.dotDotDotToken,
2161                visitNode(node.name, visitor, isBindingName),
2162                /*questionToken*/ undefined,
2163                /*type*/ undefined,
2164                visitNode(node.initializer, visitor, isExpression)
2165            );
2166            if (updated !== node) {
2167                // While we emit the source map for the node after skipping decorators and modifiers,
2168                // we need to emit the comments for the original range.
2169                setCommentRange(updated, node);
2170                setTextRange(updated, moveRangePastModifiers(node));
2171                setSourceMapRange(updated, moveRangePastModifiers(node));
2172                setEmitFlags(updated.name, EmitFlags.NoTrailingSourceMap);
2173            }
2174            return updated;
2175        }
2176
2177        function visitVariableStatement(node: VariableStatement): Statement | undefined {
2178            if (isExportOfNamespace(node)) {
2179                const variables = getInitializedVariables(node.declarationList);
2180                if (variables.length === 0) {
2181                    // elide statement if there are no initialized variables.
2182                    return undefined;
2183                }
2184
2185                return setTextRange(
2186                    factory.createExpressionStatement(
2187                        factory.inlineExpressions(
2188                            map(variables, transformInitializedVariable)
2189                        )
2190                    ),
2191                    node
2192                );
2193            }
2194            else {
2195                return visitEachChild(node, visitor, context);
2196            }
2197        }
2198
2199        function transformInitializedVariable(node: InitializedVariableDeclaration): Expression {
2200            const name = node.name;
2201            if (isBindingPattern(name)) {
2202                return flattenDestructuringAssignment(
2203                    node,
2204                    visitor,
2205                    context,
2206                    FlattenLevel.All,
2207                    /*needsValue*/ false,
2208                    createNamespaceExportExpression
2209                );
2210            }
2211            else {
2212                return setTextRange(
2213                    factory.createAssignment(
2214                        getNamespaceMemberNameWithSourceMapsAndWithoutComments(name),
2215                        visitNode(node.initializer, visitor, isExpression)
2216                    ),
2217                    /*location*/ node
2218                );
2219            }
2220        }
2221
2222        function visitVariableDeclaration(node: VariableDeclaration) {
2223            return factory.updateVariableDeclaration(
2224                node,
2225                visitNode(node.name, visitor, isBindingName),
2226                /*exclamationToken*/ undefined,
2227                /*type*/ undefined,
2228                visitNode(node.initializer, visitor, isExpression));
2229        }
2230
2231        function visitParenthesizedExpression(node: ParenthesizedExpression): Expression {
2232            const innerExpression = skipOuterExpressions(node.expression, ~OuterExpressionKinds.Assertions);
2233            if (isAssertionExpression(innerExpression)) {
2234                // Make sure we consider all nested cast expressions, e.g.:
2235                // (<any><number><any>-A).x;
2236                const expression = visitNode(node.expression, visitor, isExpression);
2237
2238                // We have an expression of the form: (<Type>SubExpr). Emitting this as (SubExpr)
2239                // is really not desirable. We would like to emit the subexpression as-is. Omitting
2240                // the parentheses, however, could cause change in the semantics of the generated
2241                // code if the casted expression has a lower precedence than the rest of the
2242                // expression.
2243                //
2244                // To preserve comments, we return a "PartiallyEmittedExpression" here which will
2245                // preserve the position information of the original expression.
2246                //
2247                // Due to the auto-parenthesization rules used by the visitor and factory functions
2248                // we can safely elide the parentheses here, as a new synthetic
2249                // ParenthesizedExpression will be inserted if we remove parentheses too
2250                // aggressively.
2251                // HOWEVER - if there are leading comments on the expression itself, to handle ASI
2252                // correctly for return and throw, we must keep the parenthesis
2253                if (length(getLeadingCommentRangesOfNode(expression, currentSourceFile))) {
2254                    return factory.updateParenthesizedExpression(node, expression);
2255                }
2256                return factory.createPartiallyEmittedExpression(expression, node);
2257            }
2258
2259            return visitEachChild(node, visitor, context);
2260        }
2261
2262        function visitAssertionExpression(node: AssertionExpression): Expression {
2263            const expression = visitNode(node.expression, visitor, isExpression);
2264            return factory.createPartiallyEmittedExpression(expression, node);
2265        }
2266
2267        function visitNonNullExpression(node: NonNullExpression): Expression {
2268            const expression = visitNode(node.expression, visitor, isLeftHandSideExpression);
2269            return factory.createPartiallyEmittedExpression(expression, node);
2270        }
2271
2272        function visitCallExpression(node: CallExpression) {
2273            return factory.updateCallExpression(
2274                node,
2275                visitNode(node.expression, visitor, isExpression),
2276                /*typeArguments*/ undefined,
2277                visitNodes(node.arguments, visitor, isExpression));
2278        }
2279
2280        function visitNewExpression(node: NewExpression) {
2281            return factory.updateNewExpression(
2282                node,
2283                visitNode(node.expression, visitor, isExpression),
2284                /*typeArguments*/ undefined,
2285                visitNodes(node.arguments, visitor, isExpression));
2286        }
2287
2288        function visitTaggedTemplateExpression(node: TaggedTemplateExpression) {
2289            return factory.updateTaggedTemplateExpression(
2290                node,
2291                visitNode(node.tag, visitor, isExpression),
2292                /*typeArguments*/ undefined,
2293                visitNode(node.template, visitor, isExpression));
2294        }
2295
2296        function visitJsxSelfClosingElement(node: JsxSelfClosingElement) {
2297            return factory.updateJsxSelfClosingElement(
2298                node,
2299                visitNode(node.tagName, visitor, isJsxTagNameExpression),
2300                /*typeArguments*/ undefined,
2301                visitNode(node.attributes, visitor, isJsxAttributes));
2302        }
2303
2304        function visitJsxJsxOpeningElement(node: JsxOpeningElement) {
2305            return factory.updateJsxOpeningElement(
2306                node,
2307                visitNode(node.tagName, visitor, isJsxTagNameExpression),
2308                /*typeArguments*/ undefined,
2309                visitNode(node.attributes, visitor, isJsxAttributes));
2310        }
2311
2312        /**
2313         * Determines whether to emit an enum declaration.
2314         *
2315         * @param node The enum declaration node.
2316         */
2317        function shouldEmitEnumDeclaration(node: EnumDeclaration) {
2318            return !isEnumConst(node)
2319                || shouldPreserveConstEnums(compilerOptions);
2320        }
2321
2322        /**
2323         * Visits an enum declaration.
2324         *
2325         * This function will be called any time a TypeScript enum is encountered.
2326         *
2327         * @param node The enum declaration node.
2328         */
2329        function visitEnumDeclaration(node: EnumDeclaration): VisitResult<Statement> {
2330            if (!shouldEmitEnumDeclaration(node)) {
2331                return factory.createNotEmittedStatement(node);
2332            }
2333
2334            const statements: Statement[] = [];
2335
2336            // We request to be advised when the printer is about to print this node. This allows
2337            // us to set up the correct state for later substitutions.
2338            let emitFlags = EmitFlags.AdviseOnEmitNode;
2339
2340            // If needed, we should emit a variable declaration for the enum. If we emit
2341            // a leading variable declaration, we should not emit leading comments for the
2342            // enum body.
2343            const varAdded = addVarForEnumOrModuleDeclaration(statements, node);
2344            if (varAdded) {
2345                // We should still emit the comments if we are emitting a system module.
2346                if (moduleKind !== ModuleKind.System || currentLexicalScope !== currentSourceFile) {
2347                    emitFlags |= EmitFlags.NoLeadingComments;
2348                }
2349            }
2350
2351            // `parameterName` is the declaration name used inside of the enum.
2352            const parameterName = getNamespaceParameterName(node);
2353
2354            // `containerName` is the expression used inside of the enum for assignments.
2355            const containerName = getNamespaceContainerName(node);
2356
2357            // `exportName` is the expression used within this node's container for any exported references.
2358            const exportName = hasSyntacticModifier(node, ModifierFlags.Export)
2359                ? factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true)
2360                : factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
2361
2362            //  x || (x = {})
2363            //  exports.x || (exports.x = {})
2364            let moduleArg =
2365                factory.createLogicalOr(
2366                    exportName,
2367                    factory.createAssignment(
2368                        exportName,
2369                        factory.createObjectLiteralExpression()
2370                    )
2371                );
2372
2373            if (hasNamespaceQualifiedExportName(node)) {
2374                // `localName` is the expression used within this node's containing scope for any local references.
2375                const localName = factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
2376
2377                //  x = (exports.x || (exports.x = {}))
2378                moduleArg = factory.createAssignment(localName, moduleArg);
2379            }
2380
2381            //  (function (x) {
2382            //      x[x["y"] = 0] = "y";
2383            //      ...
2384            //  })(x || (x = {}));
2385            const enumStatement = factory.createExpressionStatement(
2386                factory.createCallExpression(
2387                    factory.createFunctionExpression(
2388                        /*modifiers*/ undefined,
2389                        /*asteriskToken*/ undefined,
2390                        /*name*/ undefined,
2391                        /*typeParameters*/ undefined,
2392                        [factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)],
2393                        /*type*/ undefined,
2394                        transformEnumBody(node, containerName)
2395                    ),
2396                    /*typeArguments*/ undefined,
2397                    [moduleArg]
2398                )
2399            );
2400
2401            setOriginalNode(enumStatement, node);
2402            if (varAdded) {
2403                // If a variable was added, synthetic comments are emitted on it, not on the moduleStatement.
2404                setSyntheticLeadingComments(enumStatement, undefined);
2405                setSyntheticTrailingComments(enumStatement, undefined);
2406            }
2407            setTextRange(enumStatement, node);
2408            addEmitFlags(enumStatement, emitFlags);
2409            statements.push(enumStatement);
2410
2411            // Add a DeclarationMarker for the enum to preserve trailing comments and mark
2412            // the end of the declaration.
2413            statements.push(factory.createEndOfDeclarationMarker(node));
2414            return statements;
2415        }
2416
2417        /**
2418         * Transforms the body of an enum declaration.
2419         *
2420         * @param node The enum declaration node.
2421         */
2422        function transformEnumBody(node: EnumDeclaration, localName: Identifier): Block {
2423            const savedCurrentNamespaceLocalName = currentNamespaceContainerName;
2424            currentNamespaceContainerName = localName;
2425
2426            const statements: Statement[] = [];
2427            startLexicalEnvironment();
2428            const members = map(node.members, transformEnumMember);
2429            insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
2430            addRange(statements, members);
2431
2432            currentNamespaceContainerName = savedCurrentNamespaceLocalName;
2433            return factory.createBlock(
2434                setTextRange(factory.createNodeArray(statements), /*location*/ node.members),
2435                /*multiLine*/ true
2436            );
2437        }
2438
2439        /**
2440         * Transforms an enum member into a statement.
2441         *
2442         * @param member The enum member node.
2443         */
2444        function transformEnumMember(member: EnumMember): Statement {
2445            // enums don't support computed properties
2446            // we pass false as 'generateNameForComputedPropertyName' for a backward compatibility purposes
2447            // old emitter always generate 'expression' part of the name as-is.
2448            const name = getExpressionForPropertyName(member, /*generateNameForComputedPropertyName*/ false);
2449            const valueExpression = transformEnumMemberDeclarationValue(member);
2450            const innerAssignment = factory.createAssignment(
2451                factory.createElementAccessExpression(
2452                    currentNamespaceContainerName,
2453                    name
2454                ),
2455                valueExpression
2456            );
2457            const outerAssignment = valueExpression.kind === SyntaxKind.StringLiteral ?
2458                innerAssignment :
2459                factory.createAssignment(
2460                    factory.createElementAccessExpression(
2461                        currentNamespaceContainerName,
2462                        innerAssignment
2463                    ),
2464                    name
2465                );
2466            return setTextRange(
2467                factory.createExpressionStatement(
2468                    setTextRange(
2469                        outerAssignment,
2470                        member
2471                    )
2472                ),
2473                member
2474            );
2475        }
2476
2477        /**
2478         * Transforms the value of an enum member.
2479         *
2480         * @param member The enum member node.
2481         */
2482        function transformEnumMemberDeclarationValue(member: EnumMember): Expression {
2483            const value = resolver.getConstantValue(member);
2484            if (value !== undefined) {
2485                return typeof value === "string" ? factory.createStringLiteral(value) : factory.createNumericLiteral(value);
2486            }
2487            else {
2488                enableSubstitutionForNonQualifiedEnumMembers();
2489                if (member.initializer) {
2490                    return visitNode(member.initializer, visitor, isExpression);
2491                }
2492                else {
2493                    return factory.createVoidZero();
2494                }
2495            }
2496        }
2497
2498        /**
2499         * Determines whether to elide a module declaration.
2500         *
2501         * @param node The module declaration node.
2502         */
2503        function shouldEmitModuleDeclaration(nodeIn: ModuleDeclaration) {
2504            const node = getParseTreeNode(nodeIn, isModuleDeclaration);
2505            if (!node) {
2506                // If we can't find a parse tree node, assume the node is instantiated.
2507                return true;
2508            }
2509            return isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions));
2510        }
2511
2512        /**
2513         * Determines whether an exported declaration will have a qualified export name (e.g. `f.x`
2514         * or `exports.x`).
2515         */
2516        function hasNamespaceQualifiedExportName(node: Node) {
2517            return isExportOfNamespace(node)
2518                || (isExternalModuleExport(node)
2519                    && moduleKind !== ModuleKind.ES2015
2520                    && moduleKind !== ModuleKind.ES2020
2521                    && moduleKind !== ModuleKind.ESNext
2522                    && moduleKind !== ModuleKind.System);
2523        }
2524
2525        /**
2526         * Records that a declaration was emitted in the current scope, if it was the first
2527         * declaration for the provided symbol.
2528         */
2529        function recordEmittedDeclarationInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration) {
2530            if (!currentScopeFirstDeclarationsOfName) {
2531                currentScopeFirstDeclarationsOfName = new Map();
2532            }
2533
2534            const name = declaredNameInScope(node);
2535            if (!currentScopeFirstDeclarationsOfName.has(name)) {
2536                currentScopeFirstDeclarationsOfName.set(name, node);
2537            }
2538        }
2539
2540        /**
2541         * Determines whether a declaration is the first declaration with
2542         * the same name emitted in the current scope.
2543         */
2544        function isFirstEmittedDeclarationInScope(node: ModuleDeclaration | EnumDeclaration) {
2545            if (currentScopeFirstDeclarationsOfName) {
2546                const name = declaredNameInScope(node);
2547                return currentScopeFirstDeclarationsOfName.get(name) === node;
2548            }
2549            return true;
2550        }
2551
2552        function declaredNameInScope(node: FunctionDeclaration | ClassDeclaration | ModuleDeclaration | EnumDeclaration): __String {
2553            Debug.assertNode(node.name, isIdentifier);
2554            return node.name.escapedText;
2555        }
2556
2557        /**
2558         * Adds a leading VariableStatement for a enum or module declaration.
2559         */
2560        function addVarForEnumOrModuleDeclaration(statements: Statement[], node: ModuleDeclaration | EnumDeclaration) {
2561            // Emit a variable statement for the module. We emit top-level enums as a `var`
2562            // declaration to avoid static errors in global scripts scripts due to redeclaration.
2563            // enums in any other scope are emitted as a `let` declaration.
2564            const statement = factory.createVariableStatement(
2565                visitNodes(node.modifiers, modifierVisitor, isModifier),
2566                factory.createVariableDeclarationList([
2567                    factory.createVariableDeclaration(
2568                        factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true)
2569                    )
2570                ], currentLexicalScope.kind === SyntaxKind.SourceFile ? NodeFlags.None : NodeFlags.Let)
2571            );
2572
2573            setOriginalNode(statement, node);
2574
2575            recordEmittedDeclarationInScope(node);
2576            if (isFirstEmittedDeclarationInScope(node)) {
2577                // Adjust the source map emit to match the old emitter.
2578                if (node.kind === SyntaxKind.EnumDeclaration) {
2579                    setSourceMapRange(statement.declarationList, node);
2580                }
2581                else {
2582                    setSourceMapRange(statement, node);
2583                }
2584
2585                // Trailing comments for module declaration should be emitted after the function closure
2586                // instead of the variable statement:
2587                //
2588                //     /** Module comment*/
2589                //     module m1 {
2590                //         function foo4Export() {
2591                //         }
2592                //     } // trailing comment module
2593                //
2594                // Should emit:
2595                //
2596                //     /** Module comment*/
2597                //     var m1;
2598                //     (function (m1) {
2599                //         function foo4Export() {
2600                //         }
2601                //     })(m1 || (m1 = {})); // trailing comment module
2602                //
2603                setCommentRange(statement, node);
2604                addEmitFlags(statement, EmitFlags.NoTrailingComments | EmitFlags.HasEndOfDeclarationMarker);
2605                statements.push(statement);
2606                return true;
2607            }
2608            else {
2609                // For an EnumDeclaration or ModuleDeclaration that merges with a preceeding
2610                // declaration we do not emit a leading variable declaration. To preserve the
2611                // begin/end semantics of the declararation and to properly handle exports
2612                // we wrap the leading variable declaration in a `MergeDeclarationMarker`.
2613                const mergeMarker = factory.createMergeDeclarationMarker(statement);
2614                setEmitFlags(mergeMarker, EmitFlags.NoComments | EmitFlags.HasEndOfDeclarationMarker);
2615                statements.push(mergeMarker);
2616                return false;
2617            }
2618        }
2619
2620        /**
2621         * Visits a module declaration node.
2622         *
2623         * This function will be called any time a TypeScript namespace (ModuleDeclaration) is encountered.
2624         *
2625         * @param node The module declaration node.
2626         */
2627        function visitModuleDeclaration(node: ModuleDeclaration): VisitResult<Statement> {
2628            if (!shouldEmitModuleDeclaration(node)) {
2629                return factory.createNotEmittedStatement(node);
2630            }
2631
2632            Debug.assertNode(node.name, isIdentifier, "A TypeScript namespace should have an Identifier name.");
2633            enableSubstitutionForNamespaceExports();
2634
2635            const statements: Statement[] = [];
2636
2637            // We request to be advised when the printer is about to print this node. This allows
2638            // us to set up the correct state for later substitutions.
2639            let emitFlags = EmitFlags.AdviseOnEmitNode;
2640
2641            // If needed, we should emit a variable declaration for the module. If we emit
2642            // a leading variable declaration, we should not emit leading comments for the
2643            // module body.
2644            const varAdded = addVarForEnumOrModuleDeclaration(statements, node);
2645            if (varAdded) {
2646                // We should still emit the comments if we are emitting a system module.
2647                if (moduleKind !== ModuleKind.System || currentLexicalScope !== currentSourceFile) {
2648                    emitFlags |= EmitFlags.NoLeadingComments;
2649                }
2650            }
2651
2652            // `parameterName` is the declaration name used inside of the namespace.
2653            const parameterName = getNamespaceParameterName(node);
2654
2655            // `containerName` is the expression used inside of the namespace for exports.
2656            const containerName = getNamespaceContainerName(node);
2657
2658            // `exportName` is the expression used within this node's container for any exported references.
2659            const exportName = hasSyntacticModifier(node, ModifierFlags.Export)
2660                ? factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true)
2661                : factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
2662
2663            //  x || (x = {})
2664            //  exports.x || (exports.x = {})
2665            let moduleArg =
2666                factory.createLogicalOr(
2667                    exportName,
2668                    factory.createAssignment(
2669                        exportName,
2670                        factory.createObjectLiteralExpression()
2671                    )
2672                );
2673
2674            if (hasNamespaceQualifiedExportName(node)) {
2675                // `localName` is the expression used within this node's containing scope for any local references.
2676                const localName = factory.getLocalName(node, /*allowComments*/ false, /*allowSourceMaps*/ true);
2677
2678                //  x = (exports.x || (exports.x = {}))
2679                moduleArg = factory.createAssignment(localName, moduleArg);
2680            }
2681
2682            //  (function (x_1) {
2683            //      x_1.y = ...;
2684            //  })(x || (x = {}));
2685            const moduleStatement = factory.createExpressionStatement(
2686                factory.createCallExpression(
2687                    factory.createFunctionExpression(
2688                        /*modifiers*/ undefined,
2689                        /*asteriskToken*/ undefined,
2690                        /*name*/ undefined,
2691                        /*typeParameters*/ undefined,
2692                        [factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, parameterName)],
2693                        /*type*/ undefined,
2694                        transformModuleBody(node, containerName)
2695                    ),
2696                    /*typeArguments*/ undefined,
2697                    [moduleArg]
2698                )
2699            );
2700
2701            setOriginalNode(moduleStatement, node);
2702            if (varAdded) {
2703                // If a variable was added, synthetic comments are emitted on it, not on the moduleStatement.
2704                setSyntheticLeadingComments(moduleStatement, undefined);
2705                setSyntheticTrailingComments(moduleStatement, undefined);
2706            }
2707            setTextRange(moduleStatement, node);
2708            addEmitFlags(moduleStatement, emitFlags);
2709            statements.push(moduleStatement);
2710
2711            // Add a DeclarationMarker for the namespace to preserve trailing comments and mark
2712            // the end of the declaration.
2713            statements.push(factory.createEndOfDeclarationMarker(node));
2714            return statements;
2715        }
2716
2717        /**
2718         * Transforms the body of a module declaration.
2719         *
2720         * @param node The module declaration node.
2721         */
2722        function transformModuleBody(node: ModuleDeclaration, namespaceLocalName: Identifier): Block {
2723            const savedCurrentNamespaceContainerName = currentNamespaceContainerName;
2724            const savedCurrentNamespace = currentNamespace;
2725            const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName;
2726            currentNamespaceContainerName = namespaceLocalName;
2727            currentNamespace = node;
2728            currentScopeFirstDeclarationsOfName = undefined;
2729
2730            const statements: Statement[] = [];
2731            startLexicalEnvironment();
2732
2733            let statementsLocation: TextRange | undefined;
2734            let blockLocation: TextRange | undefined;
2735            if (node.body) {
2736                if (node.body.kind === SyntaxKind.ModuleBlock) {
2737                    saveStateAndInvoke(node.body, body => addRange(statements, visitNodes((<ModuleBlock>body).statements, namespaceElementVisitor, isStatement)));
2738                    statementsLocation = node.body.statements;
2739                    blockLocation = node.body;
2740                }
2741                else {
2742                    const result = visitModuleDeclaration(<ModuleDeclaration>node.body);
2743                    if (result) {
2744                        if (isArray(result)) {
2745                            addRange(statements, result);
2746                        }
2747                        else {
2748                            statements.push(result);
2749                        }
2750                    }
2751
2752                    const moduleBlock = <ModuleBlock>getInnerMostModuleDeclarationFromDottedModule(node)!.body;
2753                    statementsLocation = moveRangePos(moduleBlock.statements, -1);
2754                }
2755            }
2756
2757            insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
2758            currentNamespaceContainerName = savedCurrentNamespaceContainerName;
2759            currentNamespace = savedCurrentNamespace;
2760            currentScopeFirstDeclarationsOfName = savedCurrentScopeFirstDeclarationsOfName;
2761
2762            const block = factory.createBlock(
2763                setTextRange(
2764                    factory.createNodeArray(statements),
2765                    /*location*/ statementsLocation
2766                ),
2767                /*multiLine*/ true
2768            );
2769            setTextRange(block, blockLocation);
2770
2771            // namespace hello.hi.world {
2772            //      function foo() {}
2773            //
2774            //      // TODO, blah
2775            // }
2776            //
2777            // should be emitted as
2778            //
2779            // var hello;
2780            // (function (hello) {
2781            //     var hi;
2782            //     (function (hi) {
2783            //         var world;
2784            //         (function (world) {
2785            //             function foo() { }
2786            //             // TODO, blah
2787            //         })(world = hi.world || (hi.world = {}));
2788            //     })(hi = hello.hi || (hello.hi = {}));
2789            // })(hello || (hello = {}));
2790            // We only want to emit comment on the namespace which contains block body itself, not the containing namespaces.
2791            if (!node.body || node.body.kind !== SyntaxKind.ModuleBlock) {
2792                setEmitFlags(block, getEmitFlags(block) | EmitFlags.NoComments);
2793            }
2794            return block;
2795        }
2796
2797        function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration | undefined {
2798            if (moduleDeclaration.body!.kind === SyntaxKind.ModuleDeclaration) {
2799                const recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(<ModuleDeclaration>moduleDeclaration.body);
2800                return recursiveInnerModule || <ModuleDeclaration>moduleDeclaration.body;
2801            }
2802        }
2803
2804        /**
2805         * Visits an import declaration, eliding it if it is not referenced and `importsNotUsedAsValues` is not 'preserve'.
2806         *
2807         * @param node The import declaration node.
2808         */
2809        function visitImportDeclaration(node: ImportDeclaration): VisitResult<Statement> {
2810            if (!node.importClause) {
2811                // Do not elide a side-effect only import declaration.
2812                //  import "foo";
2813                return node;
2814            }
2815            if (node.importClause.isTypeOnly) {
2816                // Always elide type-only imports
2817                return undefined;
2818            }
2819
2820            // Elide the declaration if the import clause was elided.
2821            const importClause = visitNode(node.importClause, visitImportClause, isImportClause);
2822            return importClause ||
2823                compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve ||
2824                compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error
2825                ? factory.updateImportDeclaration(
2826                    node,
2827                    /*decorators*/ undefined,
2828                    /*modifiers*/ undefined,
2829                    importClause,
2830                    node.moduleSpecifier)
2831                : undefined;
2832        }
2833
2834        /**
2835         * Visits an import clause, eliding it if it is not referenced.
2836         *
2837         * @param node The import clause node.
2838         */
2839        function visitImportClause(node: ImportClause): VisitResult<ImportClause> {
2840            if (node.isTypeOnly) {
2841                return undefined;
2842            }
2843            // Elide the import clause if we elide both its name and its named bindings.
2844            const name = resolver.isReferencedAliasDeclaration(node) ? node.name : undefined;
2845            const namedBindings = visitNode(node.namedBindings, visitNamedImportBindings, isNamedImportBindings);
2846            return (name || namedBindings) ? factory.updateImportClause(node, /*isTypeOnly*/ false, name, namedBindings) : undefined;
2847        }
2848
2849        /**
2850         * Visits named import bindings, eliding it if it is not referenced.
2851         *
2852         * @param node The named import bindings node.
2853         */
2854        function visitNamedImportBindings(node: NamedImportBindings): VisitResult<NamedImportBindings> {
2855            if (node.kind === SyntaxKind.NamespaceImport) {
2856                // Elide a namespace import if it is not referenced.
2857                return resolver.isReferencedAliasDeclaration(node) ? node : undefined;
2858            }
2859            else {
2860                // Elide named imports if all of its import specifiers are elided.
2861                const elements = visitNodes(node.elements, visitImportSpecifier, isImportSpecifier);
2862                return some(elements) ? factory.updateNamedImports(node, elements) : undefined;
2863            }
2864        }
2865
2866        /**
2867         * Visits an import specifier, eliding it if it is not referenced.
2868         *
2869         * @param node The import specifier node.
2870         */
2871        function visitImportSpecifier(node: ImportSpecifier): VisitResult<ImportSpecifier> {
2872            // Elide an import specifier if it is not referenced.
2873            return resolver.isReferencedAliasDeclaration(node) ? node : undefined;
2874        }
2875
2876        /**
2877         * Visits an export assignment, eliding it if it does not contain a clause that resolves
2878         * to a value.
2879         *
2880         * @param node The export assignment node.
2881         */
2882        function visitExportAssignment(node: ExportAssignment): VisitResult<Statement> {
2883            // Elide the export assignment if it does not reference a value.
2884            return resolver.isValueAliasDeclaration(node)
2885                ? visitEachChild(node, visitor, context)
2886                : undefined;
2887        }
2888
2889        /**
2890         * Visits an export declaration, eliding it if it does not contain a clause that resolves
2891         * to a value.
2892         *
2893         * @param node The export declaration node.
2894         */
2895        function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
2896            if (node.isTypeOnly) {
2897                return undefined;
2898            }
2899
2900            if (!node.exportClause || isNamespaceExport(node.exportClause)) {
2901                // never elide `export <whatever> from <whereever>` declarations -
2902                // they should be kept for sideffects/untyped exports, even when the
2903                // type checker doesn't know about any exports
2904                return node;
2905            }
2906
2907            if (!resolver.isValueAliasDeclaration(node)) {
2908                // Elide the export declaration if it does not export a value.
2909                return undefined;
2910            }
2911
2912            // Elide the export declaration if all of its named exports are elided.
2913            const exportClause = visitNode(node.exportClause, visitNamedExportBindings, isNamedExportBindings);
2914            return exportClause
2915                ? factory.updateExportDeclaration(
2916                    node,
2917                    /*decorators*/ undefined,
2918                    /*modifiers*/ undefined,
2919                    node.isTypeOnly,
2920                    exportClause,
2921                    node.moduleSpecifier)
2922                : undefined;
2923        }
2924
2925        /**
2926         * Visits named exports, eliding it if it does not contain an export specifier that
2927         * resolves to a value.
2928         *
2929         * @param node The named exports node.
2930         */
2931        function visitNamedExports(node: NamedExports): VisitResult<NamedExports> {
2932            // Elide the named exports if all of its export specifiers were elided.
2933            const elements = visitNodes(node.elements, visitExportSpecifier, isExportSpecifier);
2934            return some(elements) ? factory.updateNamedExports(node, elements) : undefined;
2935        }
2936
2937        function visitNamespaceExports(node: NamespaceExport): VisitResult<NamespaceExport> {
2938            return factory.updateNamespaceExport(node, visitNode(node.name, visitor, isIdentifier));
2939        }
2940
2941        function visitNamedExportBindings(node: NamedExportBindings): VisitResult<NamedExportBindings> {
2942            return isNamespaceExport(node) ? visitNamespaceExports(node) : visitNamedExports(node);
2943        }
2944
2945        /**
2946         * Visits an export specifier, eliding it if it does not resolve to a value.
2947         *
2948         * @param node The export specifier node.
2949         */
2950        function visitExportSpecifier(node: ExportSpecifier): VisitResult<ExportSpecifier> {
2951            // Elide an export specifier if it does not reference a value.
2952            return resolver.isValueAliasDeclaration(node) ? node : undefined;
2953        }
2954
2955        /**
2956         * Determines whether to emit an import equals declaration.
2957         *
2958         * @param node The import equals declaration node.
2959         */
2960        function shouldEmitImportEqualsDeclaration(node: ImportEqualsDeclaration) {
2961            // preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when
2962            // - current file is not external module
2963            // - import declaration is top level and target is value imported by entity name
2964            return resolver.isReferencedAliasDeclaration(node)
2965                || (!isExternalModule(currentSourceFile)
2966                    && resolver.isTopLevelValueImportEqualsWithEntityName(node));
2967        }
2968
2969        /**
2970         * Visits an import equals declaration.
2971         *
2972         * @param node The import equals declaration node.
2973         */
2974        function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
2975            // Always elide type-only imports
2976            if (node.isTypeOnly) {
2977                return undefined;
2978            }
2979
2980            if (isExternalModuleImportEqualsDeclaration(node)) {
2981                const isReferenced = resolver.isReferencedAliasDeclaration(node);
2982                // If the alias is unreferenced but we want to keep the import, replace with 'import "mod"'.
2983                if (!isReferenced && compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve) {
2984                    return setOriginalNode(
2985                        setTextRange(
2986                            factory.createImportDeclaration(
2987                                /*decorators*/ undefined,
2988                                /*modifiers*/ undefined,
2989                                /*importClause*/ undefined,
2990                                node.moduleReference.expression,
2991                            ),
2992                            node,
2993                        ),
2994                        node,
2995                    );
2996                }
2997
2998                return isReferenced ? visitEachChild(node, visitor, context) : undefined;
2999            }
3000
3001            if (!shouldEmitImportEqualsDeclaration(node)) {
3002                return undefined;
3003            }
3004
3005            const moduleReference = createExpressionFromEntityName(factory, <EntityName>node.moduleReference);
3006            setEmitFlags(moduleReference, EmitFlags.NoComments | EmitFlags.NoNestedComments);
3007
3008            if (isNamedExternalModuleExport(node) || !isExportOfNamespace(node)) {
3009                //  export var ${name} = ${moduleReference};
3010                //  var ${name} = ${moduleReference};
3011                return setOriginalNode(
3012                    setTextRange(
3013                        factory.createVariableStatement(
3014                            visitNodes(node.modifiers, modifierVisitor, isModifier),
3015                            factory.createVariableDeclarationList([
3016                                setOriginalNode(
3017                                    factory.createVariableDeclaration(
3018                                        node.name,
3019                                        /*exclamationToken*/ undefined,
3020                                        /*type*/ undefined,
3021                                        moduleReference
3022                                    ),
3023                                    node
3024                                )
3025                            ])
3026                        ),
3027                        node
3028                    ),
3029                    node
3030                );
3031            }
3032            else {
3033                // exports.${name} = ${moduleReference};
3034                return setOriginalNode(
3035                    createNamespaceExport(
3036                        node.name,
3037                        moduleReference,
3038                        node
3039                    ),
3040                    node
3041                );
3042            }
3043        }
3044
3045        /**
3046         * Gets a value indicating whether the node is exported from a namespace.
3047         *
3048         * @param node The node to test.
3049         */
3050        function isExportOfNamespace(node: Node) {
3051            return currentNamespace !== undefined && hasSyntacticModifier(node, ModifierFlags.Export);
3052        }
3053
3054        /**
3055         * Gets a value indicating whether the node is exported from an external module.
3056         *
3057         * @param node The node to test.
3058         */
3059        function isExternalModuleExport(node: Node) {
3060            return currentNamespace === undefined && hasSyntacticModifier(node, ModifierFlags.Export);
3061        }
3062
3063        /**
3064         * Gets a value indicating whether the node is a named export from an external module.
3065         *
3066         * @param node The node to test.
3067         */
3068        function isNamedExternalModuleExport(node: Node) {
3069            return isExternalModuleExport(node)
3070                && !hasSyntacticModifier(node, ModifierFlags.Default);
3071        }
3072
3073        /**
3074         * Gets a value indicating whether the node is the default export of an external module.
3075         *
3076         * @param node The node to test.
3077         */
3078        function isDefaultExternalModuleExport(node: Node) {
3079            return isExternalModuleExport(node)
3080                && hasSyntacticModifier(node, ModifierFlags.Default);
3081        }
3082
3083        /**
3084         * Creates a statement for the provided expression. This is used in calls to `map`.
3085         */
3086        function expressionToStatement(expression: Expression) {
3087            return factory.createExpressionStatement(expression);
3088        }
3089
3090        function addExportMemberAssignment(statements: Statement[], node: ClassDeclaration | FunctionDeclaration) {
3091            const expression = factory.createAssignment(
3092                factory.getExternalModuleOrNamespaceExportName(currentNamespaceContainerName, node, /*allowComments*/ false, /*allowSourceMaps*/ true),
3093                factory.getLocalName(node)
3094            );
3095            setSourceMapRange(expression, createRange(node.name ? node.name.pos : node.pos, node.end));
3096
3097            const statement = factory.createExpressionStatement(expression);
3098            setSourceMapRange(statement, createRange(-1, node.end));
3099            statements.push(statement);
3100        }
3101
3102        function createNamespaceExport(exportName: Identifier, exportValue: Expression, location?: TextRange) {
3103            return setTextRange(
3104                factory.createExpressionStatement(
3105                    factory.createAssignment(
3106                        factory.getNamespaceMemberName(currentNamespaceContainerName, exportName, /*allowComments*/ false, /*allowSourceMaps*/ true),
3107                        exportValue
3108                    )
3109                ),
3110                location
3111            );
3112        }
3113
3114        function createNamespaceExportExpression(exportName: Identifier, exportValue: Expression, location?: TextRange) {
3115            return setTextRange(factory.createAssignment(getNamespaceMemberNameWithSourceMapsAndWithoutComments(exportName), exportValue), location);
3116        }
3117
3118        function getNamespaceMemberNameWithSourceMapsAndWithoutComments(name: Identifier) {
3119            return factory.getNamespaceMemberName(currentNamespaceContainerName, name, /*allowComments*/ false, /*allowSourceMaps*/ true);
3120        }
3121
3122        /**
3123         * Gets the declaration name used inside of a namespace or enum.
3124         */
3125        function getNamespaceParameterName(node: ModuleDeclaration | EnumDeclaration) {
3126            const name = factory.getGeneratedNameForNode(node);
3127            setSourceMapRange(name, node.name);
3128            return name;
3129        }
3130
3131        /**
3132         * Gets the expression used to refer to a namespace or enum within the body
3133         * of its declaration.
3134         */
3135        function getNamespaceContainerName(node: ModuleDeclaration | EnumDeclaration) {
3136            return factory.getGeneratedNameForNode(node);
3137        }
3138
3139        /**
3140         * Gets a local alias for a class declaration if it is a decorated class with an internal
3141         * reference to the static side of the class. This is necessary to avoid issues with
3142         * double-binding semantics for the class name.
3143         */
3144        function getClassAliasIfNeeded(node: ClassDeclaration) {
3145            if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
3146                enableSubstitutionForClassAliases();
3147                const classAlias = factory.createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? idText(node.name) : "default");
3148                classAliases[getOriginalNodeId(node)] = classAlias;
3149                hoistVariableDeclaration(classAlias);
3150                return classAlias;
3151            }
3152        }
3153
3154        function getClassPrototype(node: ClassExpression | ClassDeclaration) {
3155            return factory.createPropertyAccessExpression(factory.getDeclarationName(node), "prototype");
3156        }
3157
3158        function getClassMemberPrefix(node: ClassExpression | ClassDeclaration, member: ClassElement) {
3159            return hasSyntacticModifier(member, ModifierFlags.Static)
3160                ? factory.getDeclarationName(node)
3161                : getClassPrototype(node);
3162        }
3163
3164        function enableSubstitutionForNonQualifiedEnumMembers() {
3165            if ((enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers) === 0) {
3166                enabledSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
3167                context.enableSubstitution(SyntaxKind.Identifier);
3168            }
3169        }
3170
3171        function enableSubstitutionForClassAliases() {
3172            if ((enabledSubstitutions & TypeScriptSubstitutionFlags.ClassAliases) === 0) {
3173                enabledSubstitutions |= TypeScriptSubstitutionFlags.ClassAliases;
3174
3175                // We need to enable substitutions for identifiers. This allows us to
3176                // substitute class names inside of a class declaration.
3177                context.enableSubstitution(SyntaxKind.Identifier);
3178
3179                // Keep track of class aliases.
3180                classAliases = [];
3181            }
3182        }
3183
3184        function enableSubstitutionForNamespaceExports() {
3185            if ((enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports) === 0) {
3186                enabledSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
3187
3188                // We need to enable substitutions for identifiers and shorthand property assignments. This allows us to
3189                // substitute the names of exported members of a namespace.
3190                context.enableSubstitution(SyntaxKind.Identifier);
3191                context.enableSubstitution(SyntaxKind.ShorthandPropertyAssignment);
3192
3193                // We need to be notified when entering and exiting namespaces.
3194                context.enableEmitNotification(SyntaxKind.ModuleDeclaration);
3195            }
3196        }
3197
3198        function isTransformedModuleDeclaration(node: Node): boolean {
3199            return getOriginalNode(node).kind === SyntaxKind.ModuleDeclaration;
3200        }
3201
3202        function isTransformedEnumDeclaration(node: Node): boolean {
3203            return getOriginalNode(node).kind === SyntaxKind.EnumDeclaration;
3204        }
3205
3206        /**
3207         * Hook for node emit.
3208         *
3209         * @param hint A hint as to the intended usage of the node.
3210         * @param node The node to emit.
3211         * @param emit A callback used to emit the node in the printer.
3212         */
3213        function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
3214            const savedApplicableSubstitutions = applicableSubstitutions;
3215            const savedCurrentSourceFile = currentSourceFile;
3216
3217            if (isSourceFile(node)) {
3218                currentSourceFile = node;
3219            }
3220
3221            if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) {
3222                applicableSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
3223            }
3224
3225            if (enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && isTransformedEnumDeclaration(node)) {
3226                applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
3227            }
3228
3229            previousOnEmitNode(hint, node, emitCallback);
3230
3231            applicableSubstitutions = savedApplicableSubstitutions;
3232            currentSourceFile = savedCurrentSourceFile;
3233        }
3234
3235        /**
3236         * Hooks node substitutions.
3237         *
3238         * @param hint A hint as to the intended usage of the node.
3239         * @param node The node to substitute.
3240         */
3241        function onSubstituteNode(hint: EmitHint, node: Node) {
3242            node = previousOnSubstituteNode(hint, node);
3243            if (hint === EmitHint.Expression) {
3244                return substituteExpression(<Expression>node);
3245            }
3246            else if (isShorthandPropertyAssignment(node)) {
3247                return substituteShorthandPropertyAssignment(node);
3248            }
3249
3250            return node;
3251        }
3252
3253        function substituteShorthandPropertyAssignment(node: ShorthandPropertyAssignment): ObjectLiteralElementLike {
3254            if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports) {
3255                const name = node.name;
3256                const exportedName = trySubstituteNamespaceExportedName(name);
3257                if (exportedName) {
3258                    // A shorthand property with an assignment initializer is probably part of a
3259                    // destructuring assignment
3260                    if (node.objectAssignmentInitializer) {
3261                        const initializer = factory.createAssignment(exportedName, node.objectAssignmentInitializer);
3262                        return setTextRange(factory.createPropertyAssignment(name, initializer), node);
3263                    }
3264                    return setTextRange(factory.createPropertyAssignment(name, exportedName), node);
3265                }
3266            }
3267            return node;
3268        }
3269
3270        function substituteExpression(node: Expression) {
3271            switch (node.kind) {
3272                case SyntaxKind.Identifier:
3273                    return substituteExpressionIdentifier(<Identifier>node);
3274                case SyntaxKind.PropertyAccessExpression:
3275                    return substitutePropertyAccessExpression(<PropertyAccessExpression>node);
3276                case SyntaxKind.ElementAccessExpression:
3277                    return substituteElementAccessExpression(<ElementAccessExpression>node);
3278            }
3279
3280            return node;
3281        }
3282
3283        function substituteExpressionIdentifier(node: Identifier): Expression {
3284            return trySubstituteClassAlias(node)
3285                || trySubstituteNamespaceExportedName(node)
3286                || node;
3287        }
3288
3289        function trySubstituteClassAlias(node: Identifier): Expression | undefined {
3290            if (enabledSubstitutions & TypeScriptSubstitutionFlags.ClassAliases) {
3291                if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ConstructorReferenceInClass) {
3292                    // Due to the emit for class decorators, any reference to the class from inside of the class body
3293                    // must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
3294                    // behavior of class names in ES6.
3295                    // Also, when emitting statics for class expressions, we must substitute a class alias for
3296                    // constructor references in static property initializers.
3297                    const declaration = resolver.getReferencedValueDeclaration(node);
3298                    if (declaration) {
3299                        const classAlias = classAliases[declaration.id!]; // TODO: GH#18217
3300                        if (classAlias) {
3301                            const clone = factory.cloneNode(classAlias);
3302                            setSourceMapRange(clone, node);
3303                            setCommentRange(clone, node);
3304                            return clone;
3305                        }
3306                    }
3307                }
3308            }
3309
3310            return undefined;
3311        }
3312
3313        function trySubstituteNamespaceExportedName(node: Identifier): Expression | undefined {
3314            // If this is explicitly a local name, do not substitute.
3315            if (enabledSubstitutions & applicableSubstitutions && !isGeneratedIdentifier(node) && !isLocalName(node)) {
3316                // If we are nested within a namespace declaration, we may need to qualifiy
3317                // an identifier that is exported from a merged namespace.
3318                const container = resolver.getReferencedExportContainer(node, /*prefixLocals*/ false);
3319                if (container && container.kind !== SyntaxKind.SourceFile) {
3320                    const substitute =
3321                        (applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) ||
3322                        (applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration);
3323                    if (substitute) {
3324                        return setTextRange(
3325                            factory.createPropertyAccessExpression(factory.getGeneratedNameForNode(container), node),
3326                            /*location*/ node
3327                        );
3328                    }
3329                }
3330            }
3331
3332            return undefined;
3333        }
3334
3335        function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
3336            return substituteConstantValue(node);
3337        }
3338
3339        function substituteElementAccessExpression(node: ElementAccessExpression) {
3340            return substituteConstantValue(node);
3341        }
3342
3343        function substituteConstantValue(node: PropertyAccessExpression | ElementAccessExpression): LeftHandSideExpression {
3344            const constantValue = tryGetConstEnumValue(node);
3345            if (constantValue !== undefined) {
3346                // track the constant value on the node for the printer in needsDotDotForPropertyAccess
3347                setConstantValue(node, constantValue);
3348
3349                const substitute = typeof constantValue === "string" ? factory.createStringLiteral(constantValue) : factory.createNumericLiteral(constantValue);
3350                if (!compilerOptions.removeComments) {
3351                    const originalNode = getOriginalNode(node, isAccessExpression);
3352                    const propertyName = isPropertyAccessExpression(originalNode)
3353                        ? declarationNameToString(originalNode.name)
3354                        : getTextOfNode(originalNode.argumentExpression);
3355
3356                    addSyntheticTrailingComment(substitute, SyntaxKind.MultiLineCommentTrivia, ` ${propertyName} `);
3357                }
3358
3359                return substitute;
3360            }
3361
3362            return node;
3363        }
3364
3365        function tryGetConstEnumValue(node: Node): string | number | undefined {
3366            if (compilerOptions.isolatedModules) {
3367                return undefined;
3368            }
3369
3370            return isPropertyAccessExpression(node) || isElementAccessExpression(node) ? resolver.getConstantValue(node) : undefined;
3371        }
3372    }
3373}
3374