• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*@internal*/
2namespace ts {
3    export function transformModule(context: TransformationContext) {
4        interface AsynchronousDependencies {
5            aliasedModuleNames: Expression[];
6            unaliasedModuleNames: Expression[];
7            importAliasNames: ParameterDeclaration[];
8        }
9
10        function getTransformModuleDelegate(moduleKind: ModuleKind): (node: SourceFile) => SourceFile {
11            switch (moduleKind) {
12                case ModuleKind.AMD: return transformAMDModule;
13                case ModuleKind.UMD: return transformUMDModule;
14                default: return transformCommonJSModule;
15            }
16        }
17
18        const {
19            factory,
20            getEmitHelperFactory: emitHelpers,
21            startLexicalEnvironment,
22            endLexicalEnvironment,
23            hoistVariableDeclaration
24        } = context;
25
26        const compilerOptions = context.getCompilerOptions();
27        const resolver = context.getEmitResolver();
28        const host = context.getEmitHost();
29        const languageVersion = getEmitScriptTarget(compilerOptions);
30        const moduleKind = getEmitModuleKind(compilerOptions);
31        const previousOnSubstituteNode = context.onSubstituteNode;
32        const previousOnEmitNode = context.onEmitNode;
33        context.onSubstituteNode = onSubstituteNode;
34        context.onEmitNode = onEmitNode;
35        context.enableSubstitution(SyntaxKind.Identifier); // Substitutes expression identifiers with imported/exported symbols.
36        context.enableSubstitution(SyntaxKind.BinaryExpression); // Substitutes assignments to exported symbols.
37        context.enableSubstitution(SyntaxKind.PrefixUnaryExpression); // Substitutes updates to exported symbols.
38        context.enableSubstitution(SyntaxKind.PostfixUnaryExpression); // Substitutes updates to exported symbols.
39        context.enableSubstitution(SyntaxKind.ShorthandPropertyAssignment); // Substitutes shorthand property assignments for imported/exported symbols.
40        context.enableEmitNotification(SyntaxKind.SourceFile); // Restore state when substituting nodes in a file.
41
42        const moduleInfoMap: ExternalModuleInfo[] = []; // The ExternalModuleInfo for each file.
43        const deferredExports: (Statement[] | undefined)[] = []; // Exports to defer until an EndOfDeclarationMarker is found.
44
45        let currentSourceFile: SourceFile; // The current file.
46        let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file.
47        let noSubstitution: boolean[]; // Set of nodes for which substitution rules should be ignored.
48        let needUMDDynamicImportHelper: boolean;
49
50        return chainBundle(context, transformSourceFile);
51
52        /**
53         * Transforms the module aspects of a SourceFile.
54         *
55         * @param node The SourceFile node.
56         */
57        function transformSourceFile(node: SourceFile) {
58            if (node.isDeclarationFile ||
59                !(isEffectiveExternalModule(node, compilerOptions) ||
60                    node.transformFlags & TransformFlags.ContainsDynamicImport ||
61                    (isJsonSourceFile(node) && hasJsonModuleEmitEnabled(compilerOptions) && outFile(compilerOptions)))) {
62                return node;
63            }
64
65            currentSourceFile = node;
66            currentModuleInfo = collectExternalModuleInfo(context, node, resolver, compilerOptions);
67            moduleInfoMap[getOriginalNodeId(node)] = currentModuleInfo;
68
69            // Perform the transformation.
70            const transformModule = getTransformModuleDelegate(moduleKind);
71            const updated = transformModule(node);
72            currentSourceFile = undefined!;
73            currentModuleInfo = undefined!;
74            needUMDDynamicImportHelper = false;
75            return updated;
76        }
77
78
79        function shouldEmitUnderscoreUnderscoreESModule() {
80            if (!currentModuleInfo.exportEquals && isExternalModule(currentSourceFile)) {
81                return true;
82            }
83            return false;
84        }
85
86        /**
87         * Transforms a SourceFile into a CommonJS module.
88         *
89         * @param node The SourceFile node.
90         */
91        function transformCommonJSModule(node: SourceFile) {
92            startLexicalEnvironment();
93
94            const statements: Statement[] = [];
95            const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile));
96            const statementOffset = factory.copyPrologue(node.statements, statements, ensureUseStrict && !isJsonSourceFile(node), sourceElementVisitor);
97
98            if (shouldEmitUnderscoreUnderscoreESModule()) {
99                append(statements, createUnderscoreUnderscoreESModule());
100            }
101            if (length(currentModuleInfo.exportedNames)) {
102                const chunkSize = 50;
103                for (let i=0; i<currentModuleInfo.exportedNames!.length; i += chunkSize) {
104                    append(
105                        statements,
106                        factory.createExpressionStatement(
107                            reduceLeft(
108                                currentModuleInfo.exportedNames!.slice(i, i + chunkSize),
109                                (prev, nextId) => factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev),
110                                factory.createVoidZero() as Expression
111                            )
112                        )
113                    );
114                }
115            }
116
117            append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement));
118            addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
119            addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false);
120            insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
121
122            const updated = factory.updateSourceFile(node, setTextRange(factory.createNodeArray(statements), node.statements));
123            addEmitHelpers(updated, context.readEmitHelpers());
124            return updated;
125        }
126
127        /**
128         * Transforms a SourceFile into an AMD module.
129         *
130         * @param node The SourceFile node.
131         */
132        function transformAMDModule(node: SourceFile) {
133            const define = factory.createIdentifier("define");
134            const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions);
135            const jsonSourceFile = isJsonSourceFile(node) && node;
136
137            // An AMD define function has the following shape:
138            //
139            //     define(id?, dependencies?, factory);
140            //
141            // This has the shape of the following:
142            //
143            //     define(name, ["module1", "module2"], function (module1Alias) { ... }
144            //
145            // The location of the alias in the parameter list in the factory function needs to
146            // match the position of the module name in the dependency list.
147            //
148            // To ensure this is true in cases of modules with no aliases, e.g.:
149            //
150            //     import "module"
151            //
152            // or
153            //
154            //     /// <amd-dependency path= "a.css" />
155            //
156            // we need to add modules without alias names to the end of the dependencies list
157
158            const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ true);
159
160            // Create an updated SourceFile:
161            //
162            //     define(mofactory.updateSourceFile", "module2"], function ...
163            const updated = factory.updateSourceFile(node,
164                setTextRange(
165                    factory.createNodeArray([
166                        factory.createExpressionStatement(
167                            factory.createCallExpression(
168                                define,
169                                /*typeArguments*/ undefined,
170                                [
171                                    // Add the module name (if provided).
172                                    ...(moduleName ? [moduleName] : []),
173
174                                    // Add the dependency array argument:
175                                    //
176                                    //     ["require", "exports", module1", "module2", ...]
177                                    factory.createArrayLiteralExpression(jsonSourceFile ? emptyArray : [
178                                        factory.createStringLiteral("require"),
179                                        factory.createStringLiteral("exports"),
180                                        ...aliasedModuleNames,
181                                        ...unaliasedModuleNames
182                                    ]),
183
184                                    // Add the module body function argument:
185                                    //
186                                    //     function (require, exports, module1, module2) ...
187                                    jsonSourceFile ?
188                                        jsonSourceFile.statements.length ? jsonSourceFile.statements[0].expression : factory.createObjectLiteralExpression() :
189                                        factory.createFunctionExpression(
190                                            /*modifiers*/ undefined,
191                                            /*asteriskToken*/ undefined,
192                                            /*name*/ undefined,
193                                            /*typeParameters*/ undefined,
194                                            [
195                                                factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"),
196                                                factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"),
197                                                ...importAliasNames
198                                            ],
199                                            /*type*/ undefined,
200                                            transformAsynchronousModuleBody(node)
201                                        )
202                                ]
203                            )
204                        )
205                    ]),
206                    /*location*/ node.statements
207                )
208            );
209
210            addEmitHelpers(updated, context.readEmitHelpers());
211            return updated;
212        }
213
214        /**
215         * Transforms a SourceFile into a UMD module.
216         *
217         * @param node The SourceFile node.
218         */
219        function transformUMDModule(node: SourceFile) {
220            const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ false);
221            const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions);
222            const umdHeader = factory.createFunctionExpression(
223                /*modifiers*/ undefined,
224                /*asteriskToken*/ undefined,
225                /*name*/ undefined,
226                /*typeParameters*/ undefined,
227                [factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "factory")],
228                /*type*/ undefined,
229                setTextRange(
230                    factory.createBlock(
231                        [
232                            factory.createIfStatement(
233                                factory.createLogicalAnd(
234                                    factory.createTypeCheck(factory.createIdentifier("module"), "object"),
235                                    factory.createTypeCheck(factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports"), "object")
236                                ),
237                                factory.createBlock([
238                                    factory.createVariableStatement(
239                                        /*modifiers*/ undefined,
240                                        [
241                                            factory.createVariableDeclaration(
242                                                "v",
243                                                /*exclamationToken*/ undefined,
244                                                /*type*/ undefined,
245                                                factory.createCallExpression(
246                                                    factory.createIdentifier("factory"),
247                                                    /*typeArguments*/ undefined,
248                                                    [
249                                                        factory.createIdentifier("require"),
250                                                        factory.createIdentifier("exports")
251                                                    ]
252                                                )
253                                            )
254                                        ]
255                                    ),
256                                    setEmitFlags(
257                                        factory.createIfStatement(
258                                            factory.createStrictInequality(
259                                                factory.createIdentifier("v"),
260                                                factory.createIdentifier("undefined")
261                                            ),
262                                            factory.createExpressionStatement(
263                                                factory.createAssignment(
264                                                    factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports"),
265                                                    factory.createIdentifier("v")
266                                                )
267                                            )
268                                        ),
269                                        EmitFlags.SingleLine
270                                    )
271                                ]),
272                                factory.createIfStatement(
273                                    factory.createLogicalAnd(
274                                        factory.createTypeCheck(factory.createIdentifier("define"), "function"),
275                                        factory.createPropertyAccessExpression(factory.createIdentifier("define"), "amd")
276                                    ),
277                                    factory.createBlock([
278                                        factory.createExpressionStatement(
279                                            factory.createCallExpression(
280                                                factory.createIdentifier("define"),
281                                                /*typeArguments*/ undefined,
282                                                [
283                                                    // Add the module name (if provided).
284                                                    ...(moduleName ? [moduleName] : []),
285                                                    factory.createArrayLiteralExpression([
286                                                        factory.createStringLiteral("require"),
287                                                        factory.createStringLiteral("exports"),
288                                                        ...aliasedModuleNames,
289                                                        ...unaliasedModuleNames
290                                                    ]),
291                                                    factory.createIdentifier("factory")
292                                                ]
293                                            )
294                                        )
295                                    ])
296                                )
297                            )
298                        ],
299                        /*multiLine*/ true
300                    ),
301                    /*location*/ undefined
302                )
303            );
304
305            // Create an updated SourceFile:
306            //
307            //  (function (factory) {
308            //      if (typeof module === "object" && typeof module.exports === "object") {
309            //          var v = factory(require, exports);
310            //          if (v !== undefined) module.exports = v;
311            //      }
312            //      else if (typeof define === 'function' && define.amd) {
313            //          define(["require", "exports"], factory);
314            //      }
315            //  })(function ...)
316
317            const updated = factory.updateSourceFile(
318                node,
319                setTextRange(
320                    factory.createNodeArray([
321                        factory.createExpressionStatement(
322                            factory.createCallExpression(
323                                umdHeader,
324                                /*typeArguments*/ undefined,
325                                [
326                                    // Add the module body function argument:
327                                    //
328                                    //     function (require, exports) ...
329                                    factory.createFunctionExpression(
330                                        /*modifiers*/ undefined,
331                                        /*asteriskToken*/ undefined,
332                                        /*name*/ undefined,
333                                        /*typeParameters*/ undefined,
334                                        [
335                                            factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"),
336                                            factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"),
337                                            ...importAliasNames
338                                        ],
339                                        /*type*/ undefined,
340                                        transformAsynchronousModuleBody(node)
341                                    )
342                                ]
343                            )
344                        )
345                    ]),
346                    /*location*/ node.statements
347                )
348            );
349
350            addEmitHelpers(updated, context.readEmitHelpers());
351            return updated;
352        }
353
354        /**
355         * Collect the additional asynchronous dependencies for the module.
356         *
357         * @param node The source file.
358         * @param includeNonAmdDependencies A value indicating whether to include non-AMD dependencies.
359         */
360        function collectAsynchronousDependencies(node: SourceFile, includeNonAmdDependencies: boolean): AsynchronousDependencies {
361            // names of modules with corresponding parameter in the factory function
362            const aliasedModuleNames: Expression[] = [];
363
364            // names of modules with no corresponding parameters in factory function
365            const unaliasedModuleNames: Expression[] = [];
366
367            // names of the parameters in the factory function; these
368            // parameters need to match the indexes of the corresponding
369            // module names in aliasedModuleNames.
370            const importAliasNames: ParameterDeclaration[] = [];
371
372            // Fill in amd-dependency tags
373            for (const amdDependency of node.amdDependencies) {
374                if (amdDependency.name) {
375                    aliasedModuleNames.push(factory.createStringLiteral(amdDependency.path));
376                    importAliasNames.push(factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, amdDependency.name));
377                }
378                else {
379                    unaliasedModuleNames.push(factory.createStringLiteral(amdDependency.path));
380                }
381            }
382
383            for (const importNode of currentModuleInfo.externalImports) {
384                // Find the name of the external module
385                const externalModuleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions);
386
387                // Find the name of the module alias, if there is one
388                const importAliasName = getLocalNameForExternalImport(factory, importNode, currentSourceFile);
389                // It is possible that externalModuleName is undefined if it is not string literal.
390                // This can happen in the invalid import syntax.
391                // E.g : "import * from alias from 'someLib';"
392                if (externalModuleName) {
393                    if (includeNonAmdDependencies && importAliasName) {
394                        // Set emitFlags on the name of the classDeclaration
395                        // This is so that when printer will not substitute the identifier
396                        setEmitFlags(importAliasName, EmitFlags.NoSubstitution);
397                        aliasedModuleNames.push(externalModuleName);
398                        importAliasNames.push(factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, importAliasName));
399                    }
400                    else {
401                        unaliasedModuleNames.push(externalModuleName);
402                    }
403                }
404            }
405
406            return { aliasedModuleNames, unaliasedModuleNames, importAliasNames };
407        }
408
409        function getAMDImportExpressionForImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration) {
410            if (isImportEqualsDeclaration(node) || isExportDeclaration(node) || !getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions)) {
411                return undefined;
412            }
413            const name = getLocalNameForExternalImport(factory, node, currentSourceFile)!; // TODO: GH#18217
414            const expr = getHelperExpressionForImport(node, name);
415            if (expr === name) {
416                return undefined;
417            }
418            return factory.createExpressionStatement(factory.createAssignment(name, expr));
419        }
420
421        /**
422         * Transforms a SourceFile into an AMD or UMD module body.
423         *
424         * @param node The SourceFile node.
425         */
426        function transformAsynchronousModuleBody(node: SourceFile) {
427            startLexicalEnvironment();
428
429            const statements: Statement[] = [];
430            const statementOffset = factory.copyPrologue(node.statements, statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, sourceElementVisitor);
431
432            if (shouldEmitUnderscoreUnderscoreESModule()) {
433                append(statements, createUnderscoreUnderscoreESModule());
434            }
435            if (length(currentModuleInfo.exportedNames)) {
436                append(statements, factory.createExpressionStatement(reduceLeft(currentModuleInfo.exportedNames, (prev, nextId) => factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev), factory.createVoidZero() as Expression)));
437            }
438
439            // Visit each statement of the module body.
440            append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, sourceElementVisitor, isStatement));
441            if (moduleKind === ModuleKind.AMD) {
442                addRange(statements, mapDefined(currentModuleInfo.externalImports, getAMDImportExpressionForImport));
443            }
444            addRange(statements, visitNodes(node.statements, sourceElementVisitor, isStatement, statementOffset));
445
446            // Append the 'export =' statement if provided.
447            addExportEqualsIfNeeded(statements, /*emitAsReturn*/ true);
448
449            // End the lexical environment for the module body
450            // and merge any new lexical declarations.
451            insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment());
452
453            const body = factory.createBlock(statements, /*multiLine*/ true);
454            if (needUMDDynamicImportHelper) {
455                addEmitHelper(body, dynamicImportUMDHelper);
456            }
457
458            return body;
459        }
460
461        /**
462         * Adds the down-level representation of `export=` to the statement list if one exists
463         * in the source file.
464         *
465         * @param statements The Statement list to modify.
466         * @param emitAsReturn A value indicating whether to emit the `export=` statement as a
467         * return statement.
468         */
469        function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) {
470            if (currentModuleInfo.exportEquals) {
471                const expressionResult = visitNode(currentModuleInfo.exportEquals.expression, moduleExpressionElementVisitor);
472                if (expressionResult) {
473                    if (emitAsReturn) {
474                        const statement = factory.createReturnStatement(expressionResult);
475                        setTextRange(statement, currentModuleInfo.exportEquals);
476                        setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments);
477                        statements.push(statement);
478                    }
479                    else {
480                        const statement = factory.createExpressionStatement(
481                            factory.createAssignment(
482                                factory.createPropertyAccessExpression(
483                                    factory.createIdentifier("module"),
484                                    "exports"
485                                ),
486                                expressionResult
487                            )
488                        );
489
490                        setTextRange(statement, currentModuleInfo.exportEquals);
491                        setEmitFlags(statement, EmitFlags.NoComments);
492                        statements.push(statement);
493                    }
494                }
495            }
496        }
497
498        //
499        // Top-Level Source Element Visitors
500        //
501
502        /**
503         * Visits a node at the top level of the source file.
504         *
505         * @param node The node to visit.
506         */
507        function sourceElementVisitor(node: Node): VisitResult<Node> {
508            switch (node.kind) {
509                case SyntaxKind.ImportDeclaration:
510                    return visitImportDeclaration(<ImportDeclaration>node);
511
512                case SyntaxKind.ImportEqualsDeclaration:
513                    return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
514
515                case SyntaxKind.ExportDeclaration:
516                    return visitExportDeclaration(<ExportDeclaration>node);
517
518                case SyntaxKind.ExportAssignment:
519                    return visitExportAssignment(<ExportAssignment>node);
520
521                case SyntaxKind.VariableStatement:
522                    return visitVariableStatement(<VariableStatement>node);
523
524                case SyntaxKind.FunctionDeclaration:
525                    return visitFunctionDeclaration(<FunctionDeclaration>node);
526
527                case SyntaxKind.ClassDeclaration:
528                    return visitClassDeclaration(<ClassDeclaration>node);
529
530                case SyntaxKind.MergeDeclarationMarker:
531                    return visitMergeDeclarationMarker(<MergeDeclarationMarker>node);
532
533                case SyntaxKind.EndOfDeclarationMarker:
534                    return visitEndOfDeclarationMarker(<EndOfDeclarationMarker>node);
535
536                default:
537                    return visitEachChild(node, moduleExpressionElementVisitor, context);
538            }
539        }
540
541        function moduleExpressionElementVisitor(node: Expression): VisitResult<Expression> {
542            // This visitor does not need to descend into the tree if there is no dynamic import or destructuring assignment,
543            // as export/import statements are only transformed at the top level of a file.
544            if (!(node.transformFlags & TransformFlags.ContainsDynamicImport) && !(node.transformFlags & TransformFlags.ContainsDestructuringAssignment)) {
545                return node;
546            }
547
548            if (isImportCall(node)) {
549                return visitImportCallExpression(node);
550            }
551            else if (isDestructuringAssignment(node)) {
552                return visitDestructuringAssignment(node);
553            }
554            else {
555                return visitEachChild(node, moduleExpressionElementVisitor, context);
556            }
557        }
558
559        function destructuringNeedsFlattening(node: Expression): boolean {
560            if (isObjectLiteralExpression(node)) {
561                for (const elem of node.properties) {
562                    switch (elem.kind) {
563                        case SyntaxKind.PropertyAssignment:
564                            if (destructuringNeedsFlattening(elem.initializer)) {
565                                return true;
566                            }
567                            break;
568                        case SyntaxKind.ShorthandPropertyAssignment:
569                            if (destructuringNeedsFlattening(elem.name)) {
570                                return true;
571                            }
572                            break;
573                        case SyntaxKind.SpreadAssignment:
574                            if (destructuringNeedsFlattening(elem.expression)) {
575                                return true;
576                            }
577                            break;
578                        case SyntaxKind.MethodDeclaration:
579                        case SyntaxKind.GetAccessor:
580                        case SyntaxKind.SetAccessor:
581                            return false;
582                        default: Debug.assertNever(elem, "Unhandled object member kind");
583                    }
584                }
585            }
586            else if (isArrayLiteralExpression(node)) {
587                for (const elem of node.elements) {
588                    if (isSpreadElement(elem)) {
589                        if (destructuringNeedsFlattening(elem.expression)) {
590                            return true;
591                        }
592                    }
593                    else if (destructuringNeedsFlattening(elem)) {
594                        return true;
595                    }
596                }
597            }
598            else if (isIdentifier(node)) {
599                return length(getExports(node)) > (isExportName(node) ? 1 : 0);
600            }
601            return false;
602        }
603
604        function visitDestructuringAssignment(node: DestructuringAssignment): Expression {
605            if (destructuringNeedsFlattening(node.left)) {
606                return flattenDestructuringAssignment(node, moduleExpressionElementVisitor, context, FlattenLevel.All, /*needsValue*/ false, createAllExportExpressions);
607            }
608            return visitEachChild(node, moduleExpressionElementVisitor, context);
609        }
610
611        function visitImportCallExpression(node: ImportCall): Expression {
612            const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions);
613            const firstArgument = visitNode(firstOrUndefined(node.arguments), moduleExpressionElementVisitor);
614            // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output.
615            const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument;
616            const containsLexicalThis = !!(node.transformFlags & TransformFlags.ContainsLexicalThis);
617            switch (compilerOptions.module) {
618                case ModuleKind.AMD:
619                    return createImportCallExpressionAMD(argument, containsLexicalThis);
620                case ModuleKind.UMD:
621                    return createImportCallExpressionUMD(argument ?? factory.createVoidZero(), containsLexicalThis);
622                case ModuleKind.CommonJS:
623                default:
624                    return createImportCallExpressionCommonJS(argument, containsLexicalThis);
625            }
626        }
627
628        function createImportCallExpressionUMD(arg: Expression, containsLexicalThis: boolean): Expression {
629            // (function (factory) {
630            //      ... (regular UMD)
631            // }
632            // })(function (require, exports, useSyncRequire) {
633            //      "use strict";
634            //      Object.defineProperty(exports, "__esModule", { value: true });
635            //      var __syncRequire = typeof module === "object" && typeof module.exports === "object";
636            //      var __resolved = new Promise(function (resolve) { resolve(); });
637            //      .....
638            //      __syncRequire
639            //          ? __resolved.then(function () { return require(x); }) /*CommonJs Require*/
640            //          : new Promise(function (_a, _b) { require([x], _a, _b); }); /*Amd Require*/
641            // });
642            needUMDDynamicImportHelper = true;
643            if (isSimpleCopiableExpression(arg)) {
644                const argClone = isGeneratedIdentifier(arg) ? arg : isStringLiteral(arg) ? factory.createStringLiteralFromNode(arg) : setEmitFlags(setTextRange(factory.cloneNode(arg), arg), EmitFlags.NoComments);
645                return factory.createConditionalExpression(
646                    /*condition*/ factory.createIdentifier("__syncRequire"),
647                    /*questionToken*/ undefined,
648                    /*whenTrue*/ createImportCallExpressionCommonJS(arg, containsLexicalThis),
649                    /*colonToken*/ undefined,
650                    /*whenFalse*/ createImportCallExpressionAMD(argClone, containsLexicalThis)
651                );
652            }
653            else {
654                const temp = factory.createTempVariable(hoistVariableDeclaration);
655                return factory.createComma(factory.createAssignment(temp, arg), factory.createConditionalExpression(
656                    /*condition*/ factory.createIdentifier("__syncRequire"),
657                    /*questionToken*/ undefined,
658                    /*whenTrue*/ createImportCallExpressionCommonJS(temp, containsLexicalThis),
659                    /*colonToken*/ undefined,
660                    /*whenFalse*/ createImportCallExpressionAMD(temp, containsLexicalThis)
661                ));
662            }
663        }
664
665        function createImportCallExpressionAMD(arg: Expression | undefined, containsLexicalThis: boolean): Expression {
666            // improt("./blah")
667            // emit as
668            // define(["require", "exports", "blah"], function (require, exports) {
669            //     ...
670            //     new Promise(function (_a, _b) { require([x], _a, _b); }); /*Amd Require*/
671            // });
672            const resolve = factory.createUniqueName("resolve");
673            const reject = factory.createUniqueName("reject");
674            const parameters = [
675                factory.createParameterDeclaration(/*decorator*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ resolve),
676                factory.createParameterDeclaration(/*decorator*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ reject)
677            ];
678            const body = factory.createBlock([
679                factory.createExpressionStatement(
680                    factory.createCallExpression(
681                        factory.createIdentifier("require"),
682                        /*typeArguments*/ undefined,
683                        [factory.createArrayLiteralExpression([arg || factory.createOmittedExpression()]), resolve, reject]
684                    )
685                )
686            ]);
687
688            let func: FunctionExpression | ArrowFunction;
689            if (languageVersion >= ScriptTarget.ES2015) {
690                func = factory.createArrowFunction(
691                    /*modifiers*/ undefined,
692                    /*typeParameters*/ undefined,
693                    parameters,
694                    /*type*/ undefined,
695                    /*equalsGreaterThanToken*/ undefined,
696                    body);
697            }
698            else {
699                func = factory.createFunctionExpression(
700                    /*modifiers*/ undefined,
701                    /*asteriskToken*/ undefined,
702                    /*name*/ undefined,
703                    /*typeParameters*/ undefined,
704                    parameters,
705                    /*type*/ undefined,
706                    body);
707
708                // if there is a lexical 'this' in the import call arguments, ensure we indicate
709                // that this new function expression indicates it captures 'this' so that the
710                // es2015 transformer will properly substitute 'this' with '_this'.
711                if (containsLexicalThis) {
712                    setEmitFlags(func, EmitFlags.CapturesThis);
713                }
714            }
715
716            const promise = factory.createNewExpression(factory.createIdentifier("Promise"), /*typeArguments*/ undefined, [func]);
717            if (compilerOptions.esModuleInterop) {
718                return factory.createCallExpression(factory.createPropertyAccessExpression(promise, factory.createIdentifier("then")), /*typeArguments*/ undefined, [emitHelpers().createImportStarCallbackHelper()]);
719            }
720            return promise;
721        }
722
723        function createImportCallExpressionCommonJS(arg: Expression | undefined, containsLexicalThis: boolean): Expression {
724            // import("./blah")
725            // emit as
726            // Promise.resolve().then(function () { return require(x); }) /*CommonJs Require*/
727            // We have to wrap require in then callback so that require is done in asynchronously
728            // if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately
729            const promiseResolveCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"), /*typeArguments*/ undefined, /*argumentsArray*/ []);
730            let requireCall: Expression = factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, arg ? [arg] : []);
731            if (compilerOptions.esModuleInterop) {
732                requireCall = emitHelpers().createImportStarHelper(requireCall);
733            }
734
735            let func: FunctionExpression | ArrowFunction;
736            if (languageVersion >= ScriptTarget.ES2015) {
737                func = factory.createArrowFunction(
738                    /*modifiers*/ undefined,
739                    /*typeParameters*/ undefined,
740                    /*parameters*/ [],
741                    /*type*/ undefined,
742                    /*equalsGreaterThanToken*/ undefined,
743                    requireCall);
744            }
745            else {
746                func = factory.createFunctionExpression(
747                    /*modifiers*/ undefined,
748                    /*asteriskToken*/ undefined,
749                    /*name*/ undefined,
750                    /*typeParameters*/ undefined,
751                    /*parameters*/ [],
752                    /*type*/ undefined,
753                    factory.createBlock([factory.createReturnStatement(requireCall)]));
754
755                // if there is a lexical 'this' in the import call arguments, ensure we indicate
756                // that this new function expression indicates it captures 'this' so that the
757                // es2015 transformer will properly substitute 'this' with '_this'.
758                if (containsLexicalThis) {
759                    setEmitFlags(func, EmitFlags.CapturesThis);
760                }
761            }
762
763            return factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]);
764        }
765
766        function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) {
767            if (!compilerOptions.esModuleInterop || getEmitFlags(node) & EmitFlags.NeverApplyImportHelper) {
768                return innerExpr;
769            }
770            if (getExportNeedsImportStarHelper(node)) {
771                return emitHelpers().createImportStarHelper(innerExpr);
772            }
773            return innerExpr;
774        }
775
776        function getHelperExpressionForImport(node: ImportDeclaration, innerExpr: Expression) {
777            if (!compilerOptions.esModuleInterop || getEmitFlags(node) & EmitFlags.NeverApplyImportHelper) {
778                return innerExpr;
779            }
780            if (getImportNeedsImportStarHelper(node)) {
781                return emitHelpers().createImportStarHelper(innerExpr);
782            }
783            if (getImportNeedsImportDefaultHelper(node)) {
784                return emitHelpers().createImportDefaultHelper(innerExpr);
785            }
786            return innerExpr;
787        }
788
789        /**
790         * Visits an ImportDeclaration node.
791         *
792         * @param node The node to visit.
793         */
794        function visitImportDeclaration(node: ImportDeclaration): VisitResult<Statement> {
795            let statements: Statement[] | undefined;
796            const namespaceDeclaration = getNamespaceDeclarationNode(node);
797            if (moduleKind !== ModuleKind.AMD) {
798                if (!node.importClause) {
799                    // import "mod";
800                    return setOriginalNode(setTextRange(factory.createExpressionStatement(createRequireCall(node)), node), node);
801                }
802                else {
803                    const variables: VariableDeclaration[] = [];
804                    if (namespaceDeclaration && !isDefaultImport(node)) {
805                        // import * as n from "mod";
806                        variables.push(
807                            factory.createVariableDeclaration(
808                                factory.cloneNode(namespaceDeclaration.name),
809                                /*exclamationToken*/ undefined,
810                                /*type*/ undefined,
811                                getHelperExpressionForImport(node, createRequireCall(node))
812                            )
813                        );
814                    }
815                    else {
816                        // import d from "mod";
817                        // import { x, y } from "mod";
818                        // import d, { x, y } from "mod";
819                        // import d, * as n from "mod";
820                        variables.push(
821                            factory.createVariableDeclaration(
822                                factory.getGeneratedNameForNode(node),
823                                /*exclamationToken*/ undefined,
824                                /*type*/ undefined,
825                                getHelperExpressionForImport(node, createRequireCall(node))
826                            )
827                        );
828
829                        if (namespaceDeclaration && isDefaultImport(node)) {
830                            variables.push(
831                                factory.createVariableDeclaration(
832                                    factory.cloneNode(namespaceDeclaration.name),
833                                    /*exclamationToken*/ undefined,
834                                    /*type*/ undefined,
835                                    factory.getGeneratedNameForNode(node)
836                                )
837                            );
838                        }
839                    }
840
841                    statements = append(statements,
842                        setOriginalNode(
843                            setTextRange(
844                                factory.createVariableStatement(
845                                    /*modifiers*/ undefined,
846                                    factory.createVariableDeclarationList(
847                                        variables,
848                                        languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None
849                                    )
850                                ),
851                                /*location*/ node),
852                            /*original*/ node
853                        )
854                    );
855                }
856            }
857            else if (namespaceDeclaration && isDefaultImport(node)) {
858                // import d, * as n from "mod";
859                statements = append(statements,
860                    factory.createVariableStatement(
861                        /*modifiers*/ undefined,
862                        factory.createVariableDeclarationList(
863                            [
864                                setOriginalNode(
865                                    setTextRange(
866                                        factory.createVariableDeclaration(
867                                            factory.cloneNode(namespaceDeclaration.name),
868                                            /*exclamationToken*/ undefined,
869                                            /*type*/ undefined,
870                                            factory.getGeneratedNameForNode(node)
871                                        ),
872                                        /*location*/ node),
873                                    /*original*/ node
874                                )
875                            ],
876                            languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None
877                        )
878                    )
879                );
880            }
881
882            if (hasAssociatedEndOfDeclarationMarker(node)) {
883                // Defer exports until we encounter an EndOfDeclarationMarker node
884                const id = getOriginalNodeId(node);
885                deferredExports[id] = appendExportsOfImportDeclaration(deferredExports[id], node);
886            }
887            else {
888                statements = appendExportsOfImportDeclaration(statements, node);
889            }
890
891            return singleOrMany(statements);
892        }
893
894        /**
895         * Creates a `require()` call to import an external module.
896         *
897         * @param importNode The declararation to import.
898         */
899        function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) {
900            const moduleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions);
901            const args: Expression[] = [];
902            if (moduleName) {
903                args.push(moduleName);
904            }
905
906            return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, args);
907        }
908
909        /**
910         * Visits an ImportEqualsDeclaration node.
911         *
912         * @param node The node to visit.
913         */
914        function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
915            Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer.");
916
917            let statements: Statement[] | undefined;
918            if (moduleKind !== ModuleKind.AMD) {
919                if (hasSyntacticModifier(node, ModifierFlags.Export)) {
920                    statements = append(statements,
921                        setOriginalNode(
922                            setTextRange(
923                                factory.createExpressionStatement(
924                                    createExportExpression(
925                                        node.name,
926                                        createRequireCall(node)
927                                    )
928                                ),
929                                node),
930                            node
931                        )
932                    );
933                }
934                else {
935                    statements = append(statements,
936                        setOriginalNode(
937                            setTextRange(
938                                factory.createVariableStatement(
939                                    /*modifiers*/ undefined,
940                                    factory.createVariableDeclarationList(
941                                        [
942                                            factory.createVariableDeclaration(
943                                                factory.cloneNode(node.name),
944                                                /*exclamationToken*/ undefined,
945                                                /*type*/ undefined,
946                                                createRequireCall(node)
947                                            )
948                                        ],
949                                        /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None
950                                    )
951                                ),
952                                node),
953                            node
954                        )
955                    );
956                }
957            }
958            else {
959                if (hasSyntacticModifier(node, ModifierFlags.Export)) {
960                    statements = append(statements,
961                        setOriginalNode(
962                            setTextRange(
963                                factory.createExpressionStatement(
964                                    createExportExpression(factory.getExportName(node), factory.getLocalName(node))
965                                ),
966                                node),
967                            node
968                        )
969                    );
970                }
971            }
972
973            if (hasAssociatedEndOfDeclarationMarker(node)) {
974                // Defer exports until we encounter an EndOfDeclarationMarker node
975                const id = getOriginalNodeId(node);
976                deferredExports[id] = appendExportsOfImportEqualsDeclaration(deferredExports[id], node);
977            }
978            else {
979                statements = appendExportsOfImportEqualsDeclaration(statements, node);
980            }
981
982            return singleOrMany(statements);
983        }
984
985        /**
986         * Visits an ExportDeclaration node.
987         *
988         * @param The node to visit.
989         */
990        function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> {
991            if (!node.moduleSpecifier) {
992                // Elide export declarations with no module specifier as they are handled
993                // elsewhere.
994                return undefined;
995            }
996
997            const generatedName = factory.getGeneratedNameForNode(node);
998
999            if (node.exportClause && isNamedExports(node.exportClause)) {
1000                const statements: Statement[] = [];
1001                // export { x, y } from "mod";
1002                if (moduleKind !== ModuleKind.AMD) {
1003                    statements.push(
1004                        setOriginalNode(
1005                            setTextRange(
1006                                factory.createVariableStatement(
1007                                    /*modifiers*/ undefined,
1008                                    factory.createVariableDeclarationList([
1009                                        factory.createVariableDeclaration(
1010                                            generatedName,
1011                                            /*exclamationToken*/ undefined,
1012                                            /*type*/ undefined,
1013                                            createRequireCall(node)
1014                                        )
1015                                    ])
1016                                ),
1017                                /*location*/ node),
1018                            /* original */ node
1019                        )
1020                    );
1021                }
1022                for (const specifier of node.exportClause.elements) {
1023                    if (languageVersion === ScriptTarget.ES3) {
1024                        statements.push(
1025                            setOriginalNode(
1026                                setTextRange(
1027                                    factory.createExpressionStatement(
1028                                        emitHelpers().createCreateBindingHelper(generatedName, factory.createStringLiteralFromNode(specifier.propertyName || specifier.name), specifier.propertyName ? factory.createStringLiteralFromNode(specifier.name) : undefined)
1029                                    ),
1030                                    specifier),
1031                                specifier
1032                            )
1033                        );
1034                    }
1035                    else {
1036                        const exportNeedsImportDefault =
1037                            !!compilerOptions.esModuleInterop &&
1038                            !(getEmitFlags(node) & EmitFlags.NeverApplyImportHelper) &&
1039                            idText(specifier.propertyName || specifier.name) === "default";
1040                        const exportedValue = factory.createPropertyAccessExpression(
1041                            exportNeedsImportDefault ? emitHelpers().createImportDefaultHelper(generatedName) : generatedName,
1042                            specifier.propertyName || specifier.name);
1043                        statements.push(
1044                            setOriginalNode(
1045                                setTextRange(
1046                                    factory.createExpressionStatement(
1047                                        createExportExpression(factory.getExportName(specifier), exportedValue, /* location */ undefined, /* liveBinding */ true)
1048                                    ),
1049                                    specifier),
1050                                specifier
1051                            )
1052                        );
1053                    }
1054                }
1055
1056                return singleOrMany(statements);
1057            }
1058            else if (node.exportClause) {
1059                const statements: Statement[] = [];
1060                // export * as ns from "mod";
1061                // export * as default from "mod";
1062                statements.push(
1063                    setOriginalNode(
1064                        setTextRange(
1065                            factory.createExpressionStatement(
1066                                createExportExpression(
1067                                    factory.cloneNode(node.exportClause.name),
1068                                    getHelperExpressionForExport(node, moduleKind !== ModuleKind.AMD ?
1069                                        createRequireCall(node) :
1070                                        isExportNamespaceAsDefaultDeclaration(node) ? generatedName :
1071                                            factory.createIdentifier(idText(node.exportClause.name)))
1072                                )
1073                            ),
1074                            node
1075                        ),
1076                        node
1077                    )
1078                );
1079
1080                return singleOrMany(statements);
1081            }
1082            else {
1083                // export * from "mod";
1084                return setOriginalNode(
1085                    setTextRange(
1086                        factory.createExpressionStatement(
1087                            emitHelpers().createExportStarHelper(moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName)
1088                        ),
1089                        node),
1090                    node
1091                );
1092            }
1093        }
1094
1095        /**
1096         * Visits an ExportAssignment node.
1097         *
1098         * @param node The node to visit.
1099         */
1100        function visitExportAssignment(node: ExportAssignment): VisitResult<Statement> {
1101            if (node.isExportEquals) {
1102                return undefined;
1103            }
1104
1105            let statements: Statement[] | undefined;
1106            const original = node.original;
1107            if (original && hasAssociatedEndOfDeclarationMarker(original)) {
1108                // Defer exports until we encounter an EndOfDeclarationMarker node
1109                const id = getOriginalNodeId(node);
1110                deferredExports[id] = appendExportStatement(deferredExports[id], factory.createIdentifier("default"), visitNode(node.expression, moduleExpressionElementVisitor), /*location*/ node, /*allowComments*/ true);
1111            }
1112            else {
1113                statements = appendExportStatement(statements, factory.createIdentifier("default"), visitNode(node.expression, moduleExpressionElementVisitor), /*location*/ node, /*allowComments*/ true);
1114            }
1115
1116            return singleOrMany(statements);
1117        }
1118
1119        /**
1120         * Visits a FunctionDeclaration node.
1121         *
1122         * @param node The node to visit.
1123         */
1124        function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult<Statement> {
1125            let statements: Statement[] | undefined;
1126            if (hasSyntacticModifier(node, ModifierFlags.Export)) {
1127                statements = append(statements,
1128                    setOriginalNode(
1129                        setTextRange(
1130                            factory.createFunctionDeclaration(
1131                                /*decorators*/ undefined,
1132                                visitNodes(node.modifiers, modifierVisitor, isModifier),
1133                                node.asteriskToken,
1134                                factory.getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
1135                                /*typeParameters*/ undefined,
1136                                visitNodes(node.parameters, moduleExpressionElementVisitor),
1137                                /*type*/ undefined,
1138                                visitEachChild(node.body, moduleExpressionElementVisitor, context)
1139                            ),
1140                            /*location*/ node
1141                        ),
1142                        /*original*/ node
1143                    )
1144                );
1145            }
1146            else {
1147                statements = append(statements, visitEachChild(node, moduleExpressionElementVisitor, context));
1148            }
1149
1150            if (hasAssociatedEndOfDeclarationMarker(node)) {
1151                // Defer exports until we encounter an EndOfDeclarationMarker node
1152                const id = getOriginalNodeId(node);
1153                deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node);
1154            }
1155            else {
1156                statements = appendExportsOfHoistedDeclaration(statements, node);
1157            }
1158
1159            return singleOrMany(statements);
1160        }
1161
1162        /**
1163         * Visits a ClassDeclaration node.
1164         *
1165         * @param node The node to visit.
1166         */
1167        function visitClassDeclaration(node: ClassDeclaration): VisitResult<Statement> {
1168            let statements: Statement[] | undefined;
1169            if (hasSyntacticModifier(node, ModifierFlags.Export)) {
1170                statements = append(statements,
1171                    setOriginalNode(
1172                        setTextRange(
1173                            factory.createClassDeclaration(
1174                                /*decorators*/ undefined,
1175                                visitNodes(node.modifiers, modifierVisitor, isModifier),
1176                                factory.getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true),
1177                                /*typeParameters*/ undefined,
1178                                visitNodes(node.heritageClauses, moduleExpressionElementVisitor),
1179                                visitNodes(node.members, moduleExpressionElementVisitor)
1180                            ),
1181                            node
1182                        ),
1183                        node
1184                    )
1185                );
1186            }
1187            else {
1188                statements = append(statements, visitEachChild(node, moduleExpressionElementVisitor, context));
1189            }
1190
1191            if (hasAssociatedEndOfDeclarationMarker(node)) {
1192                // Defer exports until we encounter an EndOfDeclarationMarker node
1193                const id = getOriginalNodeId(node);
1194                deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node);
1195            }
1196            else {
1197                statements = appendExportsOfHoistedDeclaration(statements, node);
1198            }
1199
1200            return singleOrMany(statements);
1201        }
1202
1203        /**
1204         * Visits a VariableStatement node.
1205         *
1206         * @param node The node to visit.
1207         */
1208        function visitVariableStatement(node: VariableStatement): VisitResult<Statement> {
1209            let statements: Statement[] | undefined;
1210            let variables: VariableDeclaration[] | undefined;
1211            let expressions: Expression[] | undefined;
1212
1213            if (hasSyntacticModifier(node, ModifierFlags.Export)) {
1214                let modifiers: NodeArray<Modifier> | undefined;
1215                let removeCommentsOnExpressions = false;
1216
1217                // If we're exporting these variables, then these just become assignments to 'exports.x'.
1218                for (const variable of node.declarationList.declarations) {
1219                    if (isIdentifier(variable.name) && isLocalName(variable.name)) {
1220                        if (!modifiers) {
1221                            modifiers = visitNodes(node.modifiers, modifierVisitor, isModifier);
1222                        }
1223
1224                        variables = append(variables, variable);
1225                    }
1226                    else if (variable.initializer) {
1227                        if (!isBindingPattern(variable.name) && (isArrowFunction(variable.initializer) || isFunctionExpression(variable.initializer) || isClassExpression(variable.initializer))) {
1228                            const expression = factory.createAssignment(
1229                                setTextRange(
1230                                    factory.createPropertyAccessExpression(
1231                                        factory.createIdentifier("exports"),
1232                                        variable.name
1233                                    ),
1234                                    /*location*/ variable.name
1235                                ),
1236                                factory.createIdentifier(getTextOfIdentifierOrLiteral(variable.name))
1237                            );
1238                            const updatedVariable = factory.createVariableDeclaration(
1239                                variable.name,
1240                                variable.exclamationToken,
1241                                variable.type,
1242                                visitNode(variable.initializer, moduleExpressionElementVisitor)
1243                            );
1244
1245                            variables = append(variables, updatedVariable);
1246                            expressions = append(expressions, expression);
1247                            removeCommentsOnExpressions = true;
1248                        }
1249                        else {
1250                            expressions = append(expressions, transformInitializedVariable(variable as InitializedVariableDeclaration));
1251                        }
1252                    }
1253                }
1254
1255                if (variables) {
1256                    statements = append(statements, factory.updateVariableStatement(node, modifiers, factory.updateVariableDeclarationList(node.declarationList, variables)));
1257                }
1258
1259                if (expressions) {
1260                    const statement = setOriginalNode(setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node), node);
1261                    if (removeCommentsOnExpressions) {
1262                        removeAllComments(statement);
1263                    }
1264                    statements = append(statements, statement);
1265                }
1266            }
1267            else {
1268                statements = append(statements, visitEachChild(node, moduleExpressionElementVisitor, context));
1269            }
1270
1271            if (hasAssociatedEndOfDeclarationMarker(node)) {
1272                // Defer exports until we encounter an EndOfDeclarationMarker node
1273                const id = getOriginalNodeId(node);
1274                deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node);
1275            }
1276            else {
1277                statements = appendExportsOfVariableStatement(statements, node);
1278            }
1279
1280            return singleOrMany(statements);
1281        }
1282
1283        function createAllExportExpressions(name: Identifier, value: Expression, location?: TextRange) {
1284            const exportedNames = getExports(name);
1285            if (exportedNames) {
1286                // For each additional export of the declaration, apply an export assignment.
1287                let expression: Expression = isExportName(name) ? value : factory.createAssignment(name, value);
1288                for (const exportName of exportedNames) {
1289                    // Mark the node to prevent triggering substitution.
1290                    setEmitFlags(expression, EmitFlags.NoSubstitution);
1291                    expression = createExportExpression(exportName, expression, /*location*/ location);
1292                }
1293
1294                return expression;
1295            }
1296            return factory.createAssignment(name, value);
1297        }
1298
1299        /**
1300         * Transforms an exported variable with an initializer into an expression.
1301         *
1302         * @param node The node to transform.
1303         */
1304        function transformInitializedVariable(node: InitializedVariableDeclaration): Expression {
1305            if (isBindingPattern(node.name)) {
1306                return flattenDestructuringAssignment(
1307                    visitNode(node, moduleExpressionElementVisitor),
1308                    /*visitor*/ undefined,
1309                    context,
1310                    FlattenLevel.All,
1311                    /*needsValue*/ false,
1312                    createAllExportExpressions
1313                );
1314            }
1315            else {
1316                return factory.createAssignment(
1317                    setTextRange(
1318                        factory.createPropertyAccessExpression(
1319                            factory.createIdentifier("exports"),
1320                            node.name
1321                        ),
1322                        /*location*/ node.name
1323                    ),
1324                    node.initializer ? visitNode(node.initializer, moduleExpressionElementVisitor) : factory.createVoidZero()
1325                );
1326            }
1327        }
1328
1329        /**
1330         * Visits a MergeDeclarationMarker used as a placeholder for the beginning of a merged
1331         * and transformed declaration.
1332         *
1333         * @param node The node to visit.
1334         */
1335        function visitMergeDeclarationMarker(node: MergeDeclarationMarker): VisitResult<Statement> {
1336            // For an EnumDeclaration or ModuleDeclaration that merges with a preceeding
1337            // declaration we do not emit a leading variable declaration. To preserve the
1338            // begin/end semantics of the declararation and to properly handle exports
1339            // we wrapped the leading variable declaration in a `MergeDeclarationMarker`.
1340            //
1341            // To balance the declaration, add the exports of the elided variable
1342            // statement.
1343            if (hasAssociatedEndOfDeclarationMarker(node) && node.original!.kind === SyntaxKind.VariableStatement) {
1344                const id = getOriginalNodeId(node);
1345                deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], <VariableStatement>node.original);
1346            }
1347
1348            return node;
1349        }
1350
1351        /**
1352         * Determines whether a node has an associated EndOfDeclarationMarker.
1353         *
1354         * @param node The node to test.
1355         */
1356        function hasAssociatedEndOfDeclarationMarker(node: Node) {
1357            return (getEmitFlags(node) & EmitFlags.HasEndOfDeclarationMarker) !== 0;
1358        }
1359
1360        /**
1361         * Visits a DeclarationMarker used as a placeholder for the end of a transformed
1362         * declaration.
1363         *
1364         * @param node The node to visit.
1365         */
1366        function visitEndOfDeclarationMarker(node: EndOfDeclarationMarker): VisitResult<Statement> {
1367            // For some transformations we emit an `EndOfDeclarationMarker` to mark the actual
1368            // end of the transformed declaration. We use this marker to emit any deferred exports
1369            // of the declaration.
1370            const id = getOriginalNodeId(node);
1371            const statements = deferredExports[id];
1372            if (statements) {
1373                delete deferredExports[id];
1374                return append(statements, node);
1375            }
1376
1377            return node;
1378        }
1379
1380        /**
1381         * Appends the exports of an ImportDeclaration to a statement list, returning the
1382         * statement list.
1383         *
1384         * @param statements A statement list to which the down-level export statements are to be
1385         * appended. If `statements` is `undefined`, a new array is allocated if statements are
1386         * appended.
1387         * @param decl The declaration whose exports are to be recorded.
1388         */
1389        function appendExportsOfImportDeclaration(statements: Statement[] | undefined, decl: ImportDeclaration): Statement[] | undefined {
1390            if (currentModuleInfo.exportEquals) {
1391                return statements;
1392            }
1393
1394            const importClause = decl.importClause;
1395            if (!importClause) {
1396                return statements;
1397            }
1398
1399            if (importClause.name) {
1400                statements = appendExportsOfDeclaration(statements, importClause);
1401            }
1402
1403            const namedBindings = importClause.namedBindings;
1404            if (namedBindings) {
1405                switch (namedBindings.kind) {
1406                    case SyntaxKind.NamespaceImport:
1407                        statements = appendExportsOfDeclaration(statements, namedBindings);
1408                        break;
1409
1410                    case SyntaxKind.NamedImports:
1411                        for (const importBinding of namedBindings.elements) {
1412                            statements = appendExportsOfDeclaration(statements, importBinding, /* liveBinding */ true);
1413                        }
1414
1415                        break;
1416                }
1417            }
1418
1419            return statements;
1420        }
1421
1422        /**
1423         * Appends the exports of an ImportEqualsDeclaration to a statement list, returning the
1424         * statement list.
1425         *
1426         * @param statements A statement list to which the down-level export statements are to be
1427         * appended. If `statements` is `undefined`, a new array is allocated if statements are
1428         * appended.
1429         * @param decl The declaration whose exports are to be recorded.
1430         */
1431        function appendExportsOfImportEqualsDeclaration(statements: Statement[] | undefined, decl: ImportEqualsDeclaration): Statement[] | undefined {
1432            if (currentModuleInfo.exportEquals) {
1433                return statements;
1434            }
1435
1436            return appendExportsOfDeclaration(statements, decl);
1437        }
1438
1439        /**
1440         * Appends the exports of a VariableStatement to a statement list, returning the statement
1441         * list.
1442         *
1443         * @param statements A statement list to which the down-level export statements are to be
1444         * appended. If `statements` is `undefined`, a new array is allocated if statements are
1445         * appended.
1446         * @param node The VariableStatement whose exports are to be recorded.
1447         */
1448        function appendExportsOfVariableStatement(statements: Statement[] | undefined, node: VariableStatement): Statement[] | undefined {
1449            if (currentModuleInfo.exportEquals) {
1450                return statements;
1451            }
1452
1453            for (const decl of node.declarationList.declarations) {
1454                statements = appendExportsOfBindingElement(statements, decl);
1455            }
1456
1457            return statements;
1458        }
1459
1460        /**
1461         * Appends the exports of a VariableDeclaration or BindingElement to a statement list,
1462         * returning the statement list.
1463         *
1464         * @param statements A statement list to which the down-level export statements are to be
1465         * appended. If `statements` is `undefined`, a new array is allocated if statements are
1466         * appended.
1467         * @param decl The declaration whose exports are to be recorded.
1468         */
1469        function appendExportsOfBindingElement(statements: Statement[] | undefined, decl: VariableDeclaration | BindingElement): Statement[] | undefined {
1470            if (currentModuleInfo.exportEquals) {
1471                return statements;
1472            }
1473
1474            if (isBindingPattern(decl.name)) {
1475                for (const element of decl.name.elements) {
1476                    if (!isOmittedExpression(element)) {
1477                        statements = appendExportsOfBindingElement(statements, element);
1478                    }
1479                }
1480            }
1481            else if (!isGeneratedIdentifier(decl.name)) {
1482                statements = appendExportsOfDeclaration(statements, decl);
1483            }
1484
1485            return statements;
1486        }
1487
1488        /**
1489         * Appends the exports of a ClassDeclaration or FunctionDeclaration to a statement list,
1490         * returning the statement list.
1491         *
1492         * @param statements A statement list to which the down-level export statements are to be
1493         * appended. If `statements` is `undefined`, a new array is allocated if statements are
1494         * appended.
1495         * @param decl The declaration whose exports are to be recorded.
1496         */
1497        function appendExportsOfHoistedDeclaration(statements: Statement[] | undefined, decl: ClassDeclaration | FunctionDeclaration): Statement[] | undefined {
1498            if (currentModuleInfo.exportEquals) {
1499                return statements;
1500            }
1501
1502            if (hasSyntacticModifier(decl, ModifierFlags.Export)) {
1503                const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) ? factory.createIdentifier("default") : factory.getDeclarationName(decl);
1504                statements = appendExportStatement(statements, exportName, factory.getLocalName(decl), /*location*/ decl);
1505            }
1506
1507            if (decl.name) {
1508                statements = appendExportsOfDeclaration(statements, decl);
1509            }
1510
1511            return statements;
1512        }
1513
1514        /**
1515         * Appends the exports of a declaration to a statement list, returning the statement list.
1516         *
1517         * @param statements A statement list to which the down-level export statements are to be
1518         * appended. If `statements` is `undefined`, a new array is allocated if statements are
1519         * appended.
1520         * @param decl The declaration to export.
1521         */
1522        function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration, liveBinding?: boolean): Statement[] | undefined {
1523            const name = factory.getDeclarationName(decl);
1524            const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(idText(name));
1525            if (exportSpecifiers) {
1526                for (const exportSpecifier of exportSpecifiers) {
1527                    statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name, /* allowComments */ undefined, liveBinding);
1528                }
1529            }
1530            return statements;
1531        }
1532
1533        /**
1534         * Appends the down-level representation of an export to a statement list, returning the
1535         * statement list.
1536         *
1537         * @param statements A statement list to which the down-level export statements are to be
1538         * appended. If `statements` is `undefined`, a new array is allocated if statements are
1539         * appended.
1540         * @param exportName The name of the export.
1541         * @param expression The expression to export.
1542         * @param location The location to use for source maps and comments for the export.
1543         * @param allowComments Whether to allow comments on the export.
1544         */
1545        function appendExportStatement(statements: Statement[] | undefined, exportName: Identifier, expression: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean): Statement[] | undefined {
1546            statements = append(statements, createExportStatement(exportName, expression, location, allowComments, liveBinding));
1547            return statements;
1548        }
1549
1550        function createUnderscoreUnderscoreESModule() {
1551            let statement: Statement;
1552            if (languageVersion === ScriptTarget.ES3) {
1553                statement = factory.createExpressionStatement(
1554                    createExportExpression(
1555                        factory.createIdentifier("__esModule"),
1556                        factory.createTrue()
1557                    )
1558                );
1559            }
1560            else {
1561                statement = factory.createExpressionStatement(
1562                    factory.createCallExpression(
1563                        factory.createPropertyAccessExpression(factory.createIdentifier("Object"), "defineProperty"),
1564                        /*typeArguments*/ undefined,
1565                        [
1566                            factory.createIdentifier("exports"),
1567                            factory.createStringLiteral("__esModule"),
1568                            factory.createObjectLiteralExpression([
1569                                factory.createPropertyAssignment("value", factory.createTrue())
1570                            ])
1571                        ]
1572                    )
1573                );
1574            }
1575            setEmitFlags(statement, EmitFlags.CustomPrologue);
1576            return statement;
1577        }
1578
1579        /**
1580         * Creates a call to the current file's export function to export a value.
1581         *
1582         * @param name The bound name of the export.
1583         * @param value The exported value.
1584         * @param location The location to use for source maps and comments for the export.
1585         * @param allowComments An optional value indicating whether to emit comments for the statement.
1586         */
1587        function createExportStatement(name: Identifier, value: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean) {
1588            const statement = setTextRange(factory.createExpressionStatement(createExportExpression(name, value, /* location */ undefined, liveBinding)), location);
1589            startOnNewLine(statement);
1590            if (!allowComments) {
1591                setEmitFlags(statement, EmitFlags.NoComments);
1592            }
1593
1594            return statement;
1595        }
1596
1597        /**
1598         * Creates a call to the current file's export function to export a value.
1599         *
1600         * @param name The bound name of the export.
1601         * @param value The exported value.
1602         * @param location The location to use for source maps and comments for the export.
1603         */
1604        function createExportExpression(name: Identifier, value: Expression, location?: TextRange, liveBinding?: boolean) {
1605            return setTextRange(
1606                liveBinding && languageVersion !== ScriptTarget.ES3 ? factory.createCallExpression(
1607                    factory.createPropertyAccessExpression(
1608                        factory.createIdentifier("Object"),
1609                        "defineProperty"
1610                    ),
1611                    /*typeArguments*/ undefined,
1612                    [
1613                        factory.createIdentifier("exports"),
1614                        factory.createStringLiteralFromNode(name),
1615                        factory.createObjectLiteralExpression([
1616                            factory.createPropertyAssignment("enumerable", factory.createTrue()),
1617                            factory.createPropertyAssignment("get", factory.createFunctionExpression(
1618                                /*modifiers*/ undefined,
1619                                /*asteriskToken*/ undefined,
1620                                /*name*/ undefined,
1621                                /*typeParameters*/ undefined,
1622                                /*parameters*/ [],
1623                                /*type*/ undefined,
1624                                factory.createBlock([factory.createReturnStatement(value)])
1625                            ))
1626                        ])
1627                    ]
1628                ) : factory.createAssignment(
1629                    factory.createPropertyAccessExpression(
1630                        factory.createIdentifier("exports"),
1631                        factory.cloneNode(name)
1632                    ),
1633                    value
1634                ),
1635                location
1636            );
1637        }
1638
1639        //
1640        // Modifier Visitors
1641        //
1642
1643        /**
1644         * Visit nodes to elide module-specific modifiers.
1645         *
1646         * @param node The node to visit.
1647         */
1648        function modifierVisitor(node: Node): VisitResult<Node> {
1649            // Elide module-specific modifiers.
1650            switch (node.kind) {
1651                case SyntaxKind.ExportKeyword:
1652                case SyntaxKind.DefaultKeyword:
1653                    return undefined;
1654            }
1655
1656            return node;
1657        }
1658
1659        //
1660        // Emit Notification
1661        //
1662
1663        /**
1664         * Hook for node emit notifications.
1665         *
1666         * @param hint A hint as to the intended usage of the node.
1667         * @param node The node to emit.
1668         * @param emit A callback used to emit the node in the printer.
1669         */
1670        function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void {
1671            if (node.kind === SyntaxKind.SourceFile) {
1672                currentSourceFile = <SourceFile>node;
1673                currentModuleInfo = moduleInfoMap[getOriginalNodeId(currentSourceFile)];
1674                noSubstitution = [];
1675
1676                previousOnEmitNode(hint, node, emitCallback);
1677
1678                currentSourceFile = undefined!;
1679                currentModuleInfo = undefined!;
1680                noSubstitution = undefined!;
1681            }
1682            else {
1683                previousOnEmitNode(hint, node, emitCallback);
1684            }
1685        }
1686
1687        //
1688        // Substitutions
1689        //
1690
1691        /**
1692         * Hooks node substitutions.
1693         *
1694         * @param hint A hint as to the intended usage of the node.
1695         * @param node The node to substitute.
1696         */
1697        function onSubstituteNode(hint: EmitHint, node: Node) {
1698            node = previousOnSubstituteNode(hint, node);
1699            if (node.id && noSubstitution[node.id]) {
1700                return node;
1701            }
1702
1703            if (hint === EmitHint.Expression) {
1704                return substituteExpression(<Expression>node);
1705            }
1706            else if (isShorthandPropertyAssignment(node)) {
1707                return substituteShorthandPropertyAssignment(node);
1708            }
1709
1710            return node;
1711        }
1712
1713        /**
1714         * Substitution for a ShorthandPropertyAssignment whose declaration name is an imported
1715         * or exported symbol.
1716         *
1717         * @param node The node to substitute.
1718         */
1719        function substituteShorthandPropertyAssignment(node: ShorthandPropertyAssignment): ObjectLiteralElementLike {
1720            const name = node.name;
1721            const exportedOrImportedName = substituteExpressionIdentifier(name);
1722            if (exportedOrImportedName !== name) {
1723                // A shorthand property with an assignment initializer is probably part of a
1724                // destructuring assignment
1725                if (node.objectAssignmentInitializer) {
1726                    const initializer = factory.createAssignment(exportedOrImportedName, node.objectAssignmentInitializer);
1727                    return setTextRange(factory.createPropertyAssignment(name, initializer), node);
1728                }
1729                return setTextRange(factory.createPropertyAssignment(name, exportedOrImportedName), node);
1730            }
1731            return node;
1732        }
1733
1734        /**
1735         * Substitution for an Expression that may contain an imported or exported symbol.
1736         *
1737         * @param node The node to substitute.
1738         */
1739        function substituteExpression(node: Expression) {
1740            switch (node.kind) {
1741                case SyntaxKind.Identifier:
1742                    return substituteExpressionIdentifier(<Identifier>node);
1743                case SyntaxKind.BinaryExpression:
1744                    return substituteBinaryExpression(<BinaryExpression>node);
1745                case SyntaxKind.PostfixUnaryExpression:
1746                case SyntaxKind.PrefixUnaryExpression:
1747                    return substituteUnaryExpression(<PrefixUnaryExpression | PostfixUnaryExpression>node);
1748            }
1749
1750            return node;
1751        }
1752
1753        /**
1754         * Substitution for an Identifier expression that may contain an imported or exported
1755         * symbol.
1756         *
1757         * @param node The node to substitute.
1758         */
1759        function substituteExpressionIdentifier(node: Identifier): Expression {
1760            if (getEmitFlags(node) & EmitFlags.HelperName) {
1761                const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile);
1762                if (externalHelpersModuleName) {
1763                    return factory.createPropertyAccessExpression(externalHelpersModuleName, node);
1764                }
1765
1766                return node;
1767            }
1768
1769            if (!(isGeneratedIdentifier(node) && !(node.autoGenerateFlags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node)) {
1770                const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node));
1771                if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) {
1772                    return setTextRange(
1773                        factory.createPropertyAccessExpression(
1774                            factory.createIdentifier("exports"),
1775                            factory.cloneNode(node)
1776                        ),
1777                        /*location*/ node
1778                    );
1779                }
1780
1781                const importDeclaration = resolver.getReferencedImportDeclaration(node);
1782                if (importDeclaration) {
1783                    if (isImportClause(importDeclaration)) {
1784                        return setTextRange(
1785                            factory.createPropertyAccessExpression(
1786                                factory.getGeneratedNameForNode(importDeclaration.parent),
1787                                factory.createIdentifier("default")
1788                            ),
1789                            /*location*/ node
1790                        );
1791                    }
1792                    else if (isImportSpecifier(importDeclaration)) {
1793                        const name = importDeclaration.propertyName || importDeclaration.name;
1794                        return setTextRange(
1795                            factory.createPropertyAccessExpression(
1796                                factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration),
1797                                factory.cloneNode(name)
1798                            ),
1799                            /*location*/ node
1800                        );
1801                    }
1802                }
1803            }
1804            return node;
1805        }
1806
1807        /**
1808         * Substitution for a BinaryExpression that may contain an imported or exported symbol.
1809         *
1810         * @param node The node to substitute.
1811         */
1812        function substituteBinaryExpression(node: BinaryExpression): Expression {
1813            // When we see an assignment expression whose left-hand side is an exported symbol,
1814            // we should ensure all exports of that symbol are updated with the correct value.
1815            //
1816            // - We do not substitute generated identifiers for any reason.
1817            // - We do not substitute identifiers tagged with the LocalName flag.
1818            // - We do not substitute identifiers that were originally the name of an enum or
1819            //   namespace due to how they are transformed in TypeScript.
1820            // - We only substitute identifiers that are exported at the top level.
1821            if (isAssignmentOperator(node.operatorToken.kind)
1822                && isIdentifier(node.left)
1823                && !isGeneratedIdentifier(node.left)
1824                && !isLocalName(node.left)
1825                && !isDeclarationNameOfEnumOrNamespace(node.left)) {
1826                const exportedNames = getExports(node.left);
1827                if (exportedNames) {
1828                    // For each additional export of the declaration, apply an export assignment.
1829                    let expression: Expression = node;
1830                    for (const exportName of exportedNames) {
1831                        // Mark the node to prevent triggering this rule again.
1832                        noSubstitution[getNodeId(expression)] = true;
1833                        expression = createExportExpression(exportName, expression, /*location*/ node);
1834                    }
1835
1836                    return expression;
1837                }
1838            }
1839
1840            return node;
1841        }
1842
1843        /**
1844         * Substitution for a UnaryExpression that may contain an imported or exported symbol.
1845         *
1846         * @param node The node to substitute.
1847         */
1848        function substituteUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression): Expression {
1849            // When we see a prefix or postfix increment expression whose operand is an exported
1850            // symbol, we should ensure all exports of that symbol are updated with the correct
1851            // value.
1852            //
1853            // - We do not substitute generated identifiers for any reason.
1854            // - We do not substitute identifiers tagged with the LocalName flag.
1855            // - We do not substitute identifiers that were originally the name of an enum or
1856            //   namespace due to how they are transformed in TypeScript.
1857            // - We only substitute identifiers that are exported at the top level.
1858            if ((node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken)
1859                && isIdentifier(node.operand)
1860                && !isGeneratedIdentifier(node.operand)
1861                && !isLocalName(node.operand)
1862                && !isDeclarationNameOfEnumOrNamespace(node.operand)) {
1863                const exportedNames = getExports(node.operand);
1864                if (exportedNames) {
1865                    let expression: Expression = node.kind === SyntaxKind.PostfixUnaryExpression
1866                        ? setTextRange(
1867                            factory.createBinaryExpression(
1868                                node.operand,
1869                                factory.createToken(node.operator === SyntaxKind.PlusPlusToken ? SyntaxKind.PlusEqualsToken : SyntaxKind.MinusEqualsToken),
1870                                factory.createNumericLiteral(1)
1871                            ),
1872                            /*location*/ node)
1873                        : node;
1874                    for (const exportName of exportedNames) {
1875                        // Mark the node to prevent triggering this rule again.
1876                        noSubstitution[getNodeId(expression)] = true;
1877                        expression = factory.createParenthesizedExpression(createExportExpression(exportName, expression));
1878                    }
1879                    return expression;
1880                }
1881            }
1882
1883            return node;
1884        }
1885
1886        /**
1887         * Gets the additional exports of a name.
1888         *
1889         * @param name The name.
1890         */
1891        function getExports(name: Identifier): Identifier[] | undefined {
1892            if (!isGeneratedIdentifier(name)) {
1893                const valueDeclaration = resolver.getReferencedImportDeclaration(name)
1894                    || resolver.getReferencedValueDeclaration(name);
1895                if (valueDeclaration) {
1896                    return currentModuleInfo
1897                        && currentModuleInfo.exportedBindings[getOriginalNodeId(valueDeclaration)];
1898                }
1899            }
1900        }
1901    }
1902
1903    // emit helper for dynamic import
1904    const dynamicImportUMDHelper: EmitHelper = {
1905        name: "typescript:dynamicimport-sync-require",
1906        scoped: true,
1907        text: `
1908            var __syncRequire = typeof module === "object" && typeof module.exports === "object";`
1909    };
1910}
1911