function emitFiles(resolver, host, targetSourceFile) {
        // emit output for the __extends helper function
        var extendsHelper = "\nvar __extends = (this && this.__extends) || function (d, b) {\n    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];\n    function __() { this.constructor = d; }\n    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n};";
        // emit output for the __decorate helper function
        var decorateHelper = "\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n    if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n    return c > 3 && r && Object.defineProperty(target, key, r), r;\n};";
        // emit output for the __metadata helper function
        var metadataHelper = "\nvar __metadata = (this && this.__metadata) || function (k, v) {\n    if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(k, v);\n};";
        // emit output for the __param helper function
        var paramHelper = "\nvar __param = (this && this.__param) || function (paramIndex, decorator) {\n    return function (target, key) { decorator(target, key, paramIndex); }\n};";
        var awaiterHelper = "\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promise, generator) {\n    return new Promise(function (resolve, reject) {\n        generator = generator.call(thisArg, _arguments);\n        function cast(value) { return value instanceof Promise && value.constructor === Promise ? value : new Promise(function (resolve) { resolve(value); }); }\n        function onfulfill(value) { try { step(\"next\", value); } catch (e) { reject(e); } }\n        function onreject(value) { try { step(\"throw\", value); } catch (e) { reject(e); } }\n        function step(verb, value) {\n            var result = generator[verb](value);\n            result.done ? resolve(result.value) : cast(result.value).then(onfulfill, onreject);\n        }\n        step(\"next\", void 0);\n    });\n};";
        var compilerOptions = host.getCompilerOptions();
        var languageVersion = compilerOptions.target || 0 /* ES3 */;
        var modulekind = compilerOptions.module ? compilerOptions.module : languageVersion === 2 /* ES6 */ ? 5 /* ES6 */ : 0 /* None */;
        var sourceMapDataList = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined;
        var diagnostics = [];
        var newLine = host.getNewLine();
        var jsxDesugaring = host.getCompilerOptions().jsx !== 1 /* Preserve */;
        var shouldEmitJsx = function (s) { return (s.languageVariant === 1 /* JSX */ && !jsxDesugaring); };
        if (targetSourceFile === undefined) {
            ts.forEach(host.getSourceFiles(), function (sourceFile) {
                if (ts.shouldEmitToOwnFile(sourceFile, compilerOptions)) {
                    var jsFilePath = ts.getOwnEmitOutputFilePath(sourceFile, host, shouldEmitJsx(sourceFile) ? ".jsx" : ".js");
                    emitFile(jsFilePath, sourceFile);
                }
            });
            if (compilerOptions.outFile || compilerOptions.out) {
                emitFile(compilerOptions.outFile || compilerOptions.out);
            }
        }
        else {
            // targetSourceFile is specified (e.g calling emitter from language service or calling getSemanticDiagnostic from language service)
            if (ts.shouldEmitToOwnFile(targetSourceFile, compilerOptions)) {
                var jsFilePath = ts.getOwnEmitOutputFilePath(targetSourceFile, host, shouldEmitJsx(targetSourceFile) ? ".jsx" : ".js");
                emitFile(jsFilePath, targetSourceFile);
            }
            else if (!ts.isDeclarationFile(targetSourceFile) && (compilerOptions.outFile || compilerOptions.out)) {
                emitFile(compilerOptions.outFile || compilerOptions.out);
            }
        }
        // Sort and make the unique list of diagnostics
        diagnostics = ts.sortAndDeduplicateDiagnostics(diagnostics);
        return {
            emitSkipped: false,
            diagnostics: diagnostics,
            sourceMaps: sourceMapDataList
        };
        function isUniqueLocalName(name, container) {
            for (var node = container; ts.isNodeDescendentOf(node, container); node = node.nextContainer) {
                if (node.locals && ts.hasProperty(node.locals, name)) {
                    // We conservatively include alias symbols to cover cases where they're emitted as locals
                    if (node.locals[name].flags & (107455 /* Value */ | 1048576 /* ExportValue */ | 8388608 /* Alias */)) {
                        return false;
                    }
                }
            }
            return true;
        }
        function emitJavaScript(jsFilePath, root) {
            var writer = ts.createTextWriter(newLine);
            var write = writer.write, writeTextOfNode = writer.writeTextOfNode, writeLine = writer.writeLine, increaseIndent = writer.increaseIndent, decreaseIndent = writer.decreaseIndent;
            var currentSourceFile;
            // name of an exporter function if file is a System external module
            // System.register([...], function (<exporter>) {...})
            // exporting in System modules looks like:
            // export var x; ... x = 1
            // =>
            // var x;... exporter("x", x = 1)
            var exportFunctionForFile;
            var generatedNameSet = {};
            var nodeToGeneratedName = [];
            var computedPropertyNamesToGeneratedNames;
            var extendsEmitted = false;
            var decorateEmitted = false;
            var paramEmitted = false;
            var awaiterEmitted = false;
            var tempFlags = 0;
            var tempVariables;
            var tempParameters;
            var externalImports;
            var exportSpecifiers;
            var exportEquals;
            var hasExportStars;
            /** Write emitted output to disk */
            var writeEmittedFiles = writeJavaScriptFile;
            var detachedCommentsInfo;
            var writeComment = ts.writeCommentRange;
            /** Emit a node */
            var emit = emitNodeWithCommentsAndWithoutSourcemap;
            /** Called just before starting emit of a node */
            var emitStart = function (node) { };
            /** Called once the emit of the node is done */
            var emitEnd = function (node) { };
            /** Emit the text for the given token that comes after startPos
             * This by default writes the text provided with the given tokenKind
             * but if optional emitFn callback is provided the text is emitted using the callback instead of default text
             * @param tokenKind the kind of the token to search and emit
             * @param startPos the position in the source to start searching for the token
             * @param emitFn if given will be invoked to emit the text instead of actual token emit */
            var emitToken = emitTokenText;
            /** Called to before starting the lexical scopes as in function/class in the emitted code because of node
             * @param scopeDeclaration node that starts the lexical scope
             * @param scopeName Optional name of this scope instead of deducing one from the declaration node */
            var scopeEmitStart = function (scopeDeclaration, scopeName) { };
            /** Called after coming out of the scope */
            var scopeEmitEnd = function () { };
            /** Sourcemap data that will get encoded */
            var sourceMapData;
            /** If removeComments is true, no leading-comments needed to be emitted **/
            var emitLeadingCommentsOfPosition = compilerOptions.removeComments ? function (pos) { } : emitLeadingCommentsOfPositionWorker;
            var moduleEmitDelegates = (_a = {},
                    _a[5 /* ES6 */] = emitES6Module,
                    _a[2 /* AMD */] = emitAMDModule,
                    _a[4 /* System */] = emitSystemModule,
                    _a[3 /* UMD */] = emitUMDModule,
                    _a[1 /* CommonJS */] = emitCommonJSModule,
                    _a
            );
            if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
                initializeEmitterWithSourceMaps();
            }
            if (root) {
                // Do not call emit directly. It does not set the currentSourceFile.
                emitSourceFile(root);
            }
            else {
                ts.forEach(host.getSourceFiles(), function (sourceFile) {
                    if (!isExternalModuleOrDeclarationFile(sourceFile)) {
                        emitSourceFile(sourceFile);
                    }
                });
            }
            writeLine();
            writeEmittedFiles(writer.getText(), /*writeByteOrderMark*/ compilerOptions.emitBOM);
            return;
            function emitSourceFile(sourceFile) {
                currentSourceFile = sourceFile;
                exportFunctionForFile = undefined;
                emit(sourceFile);
            }
            function isUniqueName(name) {
                return !resolver.hasGlobalName(name) &&
                    !ts.hasProperty(currentSourceFile.identifiers, name) &&
                    !ts.hasProperty(generatedNameSet, name);
            }
            // Return the next available name in the pattern _a ... _z, _0, _1, ...
            // TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name.
            // Note that names generated by makeTempVariableName and makeUniqueName will never conflict.
            function makeTempVariableName(flags) {
                if (flags && !(tempFlags & flags)) {
                    var name_19 = flags === 268435456 /* _i */ ? "_i" : "_n";
                    if (isUniqueName(name_19)) {
                        tempFlags |= flags;
                        return name_19;
                    }
                }
                while (true) {
                    var count = tempFlags & 268435455 /* CountMask */;
                    tempFlags++;
                    // Skip over 'i' and 'n'
                    if (count !== 8 && count !== 13) {
                        var name_20 = count < 26 ? "_" + String.fromCharCode(97 /* a */ + count) : "_" + (count - 26);
                        if (isUniqueName(name_20)) {
                            return name_20;
                        }
                    }
                }
            }
            // Generate a name that is unique within the current file and doesn't conflict with any names
            // in global scope. The name is formed by adding an '_n' suffix to the specified base name,
            // where n is a positive integer. Note that names generated by makeTempVariableName and
            // makeUniqueName are guaranteed to never conflict.
            function makeUniqueName(baseName) {
                // Find the first unique 'name_n', where n is a positive number
                if (baseName.charCodeAt(baseName.length - 1) !== 95 /* _ */) {
                    baseName += "_";
                }
                var i = 1;
                while (true) {
                    var generatedName = baseName + i;
                    if (isUniqueName(generatedName)) {
                        return generatedNameSet[generatedName] = generatedName;
                    }
                    i++;
                }
            }
            function generateNameForModuleOrEnum(node) {
                var name = node.name.text;
                // Use module/enum name itself if it is unique, otherwise make a unique variation
                return isUniqueLocalName(name, node) ? name : makeUniqueName(name);
            }
            function generateNameForImportOrExportDeclaration(node) {
                var expr = ts.getExternalModuleName(node);
                var baseName = expr.kind === 9 /* StringLiteral */ ?
                    ts.escapeIdentifier(ts.makeIdentifierFromModuleName(expr.text)) : "module";
                return makeUniqueName(baseName);
            }
            function generateNameForExportDefault() {
                return makeUniqueName("default");
            }
            function generateNameForClassExpression() {
                return makeUniqueName("class");
            }
            function generateNameForNode(node) {
                switch (node.kind) {
                    case 69 /* Identifier */:
                        return makeUniqueName(node.text);
                    case 218 /* ModuleDeclaration */:
                    case 217 /* EnumDeclaration */:
                        return generateNameForModuleOrEnum(node);
                    case 222 /* ImportDeclaration */:
                    case 228 /* ExportDeclaration */:
                        return generateNameForImportOrExportDeclaration(node);
                    case 213 /* FunctionDeclaration */:
                    case 214 /* ClassDeclaration */:
                    case 227 /* ExportAssignment */:
                        return generateNameForExportDefault();
                    case 186 /* ClassExpression */:
                        return generateNameForClassExpression();
                }
            }
            function getGeneratedNameForNode(node) {
                var id = ts.getNodeId(node);
                return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = ts.unescapeIdentifier(generateNameForNode(node)));
            }
            function initializeEmitterWithSourceMaps() {
                var sourceMapDir; // The directory in which sourcemap will be
                // Current source map file and its index in the sources list
                var sourceMapSourceIndex = -1;
                // Names and its index map
                var sourceMapNameIndexMap = {};
                var sourceMapNameIndices = [];
                function getSourceMapNameIndex() {
                    return sourceMapNameIndices.length ? ts.lastOrUndefined(sourceMapNameIndices) : -1;
                }
                // Last recorded and encoded spans
                var lastRecordedSourceMapSpan;
                var lastEncodedSourceMapSpan = {
                    emittedLine: 1,
                    emittedColumn: 1,
                    sourceLine: 1,
                    sourceColumn: 1,
                    sourceIndex: 0
                };
                var lastEncodedNameIndex = 0;
                // Encoding for sourcemap span
                function encodeLastRecordedSourceMapSpan() {
                    if (!lastRecordedSourceMapSpan || lastRecordedSourceMapSpan === lastEncodedSourceMapSpan) {
                        return;
                    }
                    var prevEncodedEmittedColumn = lastEncodedSourceMapSpan.emittedColumn;
                    // Line/Comma delimiters
                    if (lastEncodedSourceMapSpan.emittedLine === lastRecordedSourceMapSpan.emittedLine) {
                        // Emit comma to separate the entry
                        if (sourceMapData.sourceMapMappings) {
                            sourceMapData.sourceMapMappings += ",";
                        }
                    }
                    else {
                        // Emit line delimiters
                        for (var encodedLine = lastEncodedSourceMapSpan.emittedLine; encodedLine < lastRecordedSourceMapSpan.emittedLine; encodedLine++) {
                            sourceMapData.sourceMapMappings += ";";
                        }
                        prevEncodedEmittedColumn = 1;
                    }
                    // 1. Relative Column 0 based
                    sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.emittedColumn - prevEncodedEmittedColumn);
                    // 2. Relative sourceIndex
                    sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceIndex - lastEncodedSourceMapSpan.sourceIndex);
                    // 3. Relative sourceLine 0 based
                    sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceLine - lastEncodedSourceMapSpan.sourceLine);
                    // 4. Relative sourceColumn 0 based
                    sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceColumn - lastEncodedSourceMapSpan.sourceColumn);
                    // 5. Relative namePosition 0 based
                    if (lastRecordedSourceMapSpan.nameIndex >= 0) {
                        sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.nameIndex - lastEncodedNameIndex);
                        lastEncodedNameIndex = lastRecordedSourceMapSpan.nameIndex;
                    }
                    lastEncodedSourceMapSpan = lastRecordedSourceMapSpan;
                    sourceMapData.sourceMapDecodedMappings.push(lastEncodedSourceMapSpan);
                    function base64VLQFormatEncode(inValue) {
                        function base64FormatEncode(inValue) {
                            if (inValue < 64) {
                                return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(inValue);
                            }
                            throw TypeError(inValue + ": not a 64 based value");
                        }
                        // Add a new least significant bit that has the sign of the value.
                        // if negative number the least significant bit that gets added to the number has value 1
                        // else least significant bit value that gets added is 0
                        // eg. -1 changes to binary : 01 [1] => 3
                        //     +1 changes to binary : 01 [0] => 2
                        if (inValue < 0) {
                            inValue = ((-inValue) << 1) + 1;
                        }
                        else {
                            inValue = inValue << 1;
                        }
                        // Encode 5 bits at a time starting from least significant bits
                        var encodedStr = "";
                        do {
                            var currentDigit = inValue & 31; // 11111
                            inValue = inValue >> 5;
                            if (inValue > 0) {
                                // There are still more digits to decode, set the msb (6th bit)
                                currentDigit = currentDigit | 32;
                            }
                            encodedStr = encodedStr + base64FormatEncode(currentDigit);
                        } while (inValue > 0);
                        return encodedStr;
                    }
                }
                function recordSourceMapSpan(pos) {
                    var sourceLinePos = ts.getLineAndCharacterOfPosition(currentSourceFile, pos);
                    // Convert the location to be one-based.
                    sourceLinePos.line++;
                    sourceLinePos.character++;
                    var emittedLine = writer.getLine();
                    var emittedColumn = writer.getColumn();
                    // If this location wasn't recorded or the location in source is going backwards, record the span
                    if (!lastRecordedSourceMapSpan ||
                        lastRecordedSourceMapSpan.emittedLine !== emittedLine ||
                        lastRecordedSourceMapSpan.emittedColumn !== emittedColumn ||
                        (lastRecordedSourceMapSpan.sourceIndex === sourceMapSourceIndex &&
                        (lastRecordedSourceMapSpan.sourceLine > sourceLinePos.line ||
                        (lastRecordedSourceMapSpan.sourceLine === sourceLinePos.line && lastRecordedSourceMapSpan.sourceColumn > sourceLinePos.character)))) {
                        // Encode the last recordedSpan before assigning new
                        encodeLastRecordedSourceMapSpan();
                        // New span
                        lastRecordedSourceMapSpan = {
                            emittedLine: emittedLine,
                            emittedColumn: emittedColumn,
                            sourceLine: sourceLinePos.line,
                            sourceColumn: sourceLinePos.character,
                            nameIndex: getSourceMapNameIndex(),
                            sourceIndex: sourceMapSourceIndex
                        };
                    }
                    else {
                        // Take the new pos instead since there is no change in emittedLine and column since last location
                        lastRecordedSourceMapSpan.sourceLine = sourceLinePos.line;
                        lastRecordedSourceMapSpan.sourceColumn = sourceLinePos.character;
                        lastRecordedSourceMapSpan.sourceIndex = sourceMapSourceIndex;
                    }
                }
                function recordEmitNodeStartSpan(node) {
                    // Get the token pos after skipping to the token (ignoring the leading trivia)
                    recordSourceMapSpan(ts.skipTrivia(currentSourceFile.text, node.pos));
                }
                function recordEmitNodeEndSpan(node) {
                    recordSourceMapSpan(node.end);
                }
                function writeTextWithSpanRecord(tokenKind, startPos, emitFn) {
                    var tokenStartPos = ts.skipTrivia(currentSourceFile.text, startPos);
                    recordSourceMapSpan(tokenStartPos);
                    var tokenEndPos = emitTokenText(tokenKind, tokenStartPos, emitFn);
                    recordSourceMapSpan(tokenEndPos);
                    return tokenEndPos;
                }
                function recordNewSourceFileStart(node) {
                    // Add the file to tsFilePaths
                    // If sourceroot option: Use the relative path corresponding to the common directory path
                    // otherwise source locations relative to map file location
                    var sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir;
                    sourceMapData.sourceMapSources.push(ts.getRelativePathToDirectoryOrUrl(sourcesDirectoryPath, node.fileName, host.getCurrentDirectory(), host.getCanonicalFileName,
                        /*isAbsolutePathAnUrl*/ true));
                    sourceMapSourceIndex = sourceMapData.sourceMapSources.length - 1;
                    // The one that can be used from program to get the actual source file
                    sourceMapData.inputSourceFileNames.push(node.fileName);
                    if (compilerOptions.inlineSources) {
                        if (!sourceMapData.sourceMapSourcesContent) {
                            sourceMapData.sourceMapSourcesContent = [];
                        }
                        sourceMapData.sourceMapSourcesContent.push(node.text);
                    }
                }
                function recordScopeNameOfNode(node, scopeName) {
                    function recordScopeNameIndex(scopeNameIndex) {
                        sourceMapNameIndices.push(scopeNameIndex);
                    }
                    function recordScopeNameStart(scopeName) {
                        var scopeNameIndex = -1;
                        if (scopeName) {
                            var parentIndex = getSourceMapNameIndex();
                            if (parentIndex !== -1) {
                                // Child scopes are always shown with a dot (even if they have no name),
                                // unless it is a computed property. Then it is shown with brackets,
                                // but the brackets are included in the name.
                                var name_21 = node.name;
                                if (!name_21 || name_21.kind !== 136 /* ComputedPropertyName */) {
                                    scopeName = "." + scopeName;
                                }
                                scopeName = sourceMapData.sourceMapNames[parentIndex] + scopeName;
                            }
                            scopeNameIndex = ts.getProperty(sourceMapNameIndexMap, scopeName);
                            if (scopeNameIndex === undefined) {
                                scopeNameIndex = sourceMapData.sourceMapNames.length;
                                sourceMapData.sourceMapNames.push(scopeName);
                                sourceMapNameIndexMap[scopeName] = scopeNameIndex;
                            }
                        }
                        recordScopeNameIndex(scopeNameIndex);
                    }
                    if (scopeName) {
                        // The scope was already given a name  use it
                        recordScopeNameStart(scopeName);
                    }
                    else if (node.kind === 213 /* FunctionDeclaration */ ||
                        node.kind === 173 /* FunctionExpression */ ||
                        node.kind === 143 /* MethodDeclaration */ ||
                        node.kind === 142 /* MethodSignature */ ||
                        node.kind === 145 /* GetAccessor */ ||
                        node.kind === 146 /* SetAccessor */ ||
                        node.kind === 218 /* ModuleDeclaration */ ||
                        node.kind === 214 /* ClassDeclaration */ ||
                        node.kind === 217 /* EnumDeclaration */) {
                        // Declaration and has associated name use it
                        if (node.name) {
                            var name_22 = node.name;
                            // For computed property names, the text will include the brackets
                            scopeName = name_22.kind === 136 /* ComputedPropertyName */
                                ? ts.getTextOfNode(name_22)
                                : node.name.text;
                        }
                        recordScopeNameStart(scopeName);
                    }
                    else {
                        // Block just use the name from upper level scope
                        recordScopeNameIndex(getSourceMapNameIndex());
                    }
                }
                function recordScopeNameEnd() {
                    sourceMapNameIndices.pop();
                }
                ;
                function writeCommentRangeWithMap(curentSourceFile, writer, comment, newLine) {
                    recordSourceMapSpan(comment.pos);
                    ts.writeCommentRange(currentSourceFile, writer, comment, newLine);
                    recordSourceMapSpan(comment.end);
                }
                function serializeSourceMapContents(version, file, sourceRoot, sources, names, mappings, sourcesContent) {
                    if (typeof JSON !== "undefined") {
                        var map_1 = {
                            version: version,
                            file: file,
                            sourceRoot: sourceRoot,
                            sources: sources,
                            names: names,
                            mappings: mappings
                        };
                        if (sourcesContent !== undefined) {
                            map_1.sourcesContent = sourcesContent;
                        }
                        return JSON.stringify(map_1);
                    }
                    return "{\"version\":" + version + ",\"file\":\"" + ts.escapeString(file) + "\",\"sourceRoot\":\"" + ts.escapeString(sourceRoot) + "\",\"sources\":[" + serializeStringArray(sources) + "],\"names\":[" + serializeStringArray(names) + "],\"mappings\":\"" + ts.escapeString(mappings) + "\" " + (sourcesContent !== undefined ? ",\"sourcesContent\":[" + serializeStringArray(sourcesContent) + "]" : "") + "}";
                    function serializeStringArray(list) {
                        var output = "";
                        for (var i = 0, n = list.length; i < n; i++) {
                            if (i) {
                                output += ",";
                            }
                            output += "\"" + ts.escapeString(list[i]) + "\"";
                        }
                        return output;
                    }
                }
                function writeJavaScriptAndSourceMapFile(emitOutput, writeByteOrderMark) {
                    encodeLastRecordedSourceMapSpan();
                    var sourceMapText = serializeSourceMapContents(3, sourceMapData.sourceMapFile, sourceMapData.sourceMapSourceRoot, sourceMapData.sourceMapSources, sourceMapData.sourceMapNames, sourceMapData.sourceMapMappings, sourceMapData.sourceMapSourcesContent);
                    sourceMapDataList.push(sourceMapData);
                    var sourceMapUrl;
                    if (compilerOptions.inlineSourceMap) {
                        // Encode the sourceMap into the sourceMap url
                        var base64SourceMapText = ts.convertToBase64(sourceMapText);
                        sourceMapUrl = "//# sourceMappingURL=data:application/json;base64," + base64SourceMapText;
                    }
                    else {
                        // Write source map file
                        ts.writeFile(host, diagnostics, sourceMapData.sourceMapFilePath, sourceMapText, /*writeByteOrderMark*/ false);
                        sourceMapUrl = "//# sourceMappingURL=" + sourceMapData.jsSourceMappingURL;
                    }
                    // Write sourcemap url to the js file and write the js file
                    writeJavaScriptFile(emitOutput + sourceMapUrl, writeByteOrderMark);
                }
                // Initialize source map data
                var sourceMapJsFile = ts.getBaseFileName(ts.normalizeSlashes(jsFilePath));
                sourceMapData = {
                    sourceMapFilePath: jsFilePath + ".map",
                    jsSourceMappingURL: sourceMapJsFile + ".map",
                    sourceMapFile: sourceMapJsFile,
                    sourceMapSourceRoot: compilerOptions.sourceRoot || "",
                    sourceMapSources: [],
                    inputSourceFileNames: [],
                    sourceMapNames: [],
                    sourceMapMappings: "",
                    sourceMapSourcesContent: undefined,
                    sourceMapDecodedMappings: []
                };
                // Normalize source root and make sure it has trailing "/" so that it can be used to combine paths with the
                // relative paths of the sources list in the sourcemap
                sourceMapData.sourceMapSourceRoot = ts.normalizeSlashes(sourceMapData.sourceMapSourceRoot);
                if (sourceMapData.sourceMapSourceRoot.length && sourceMapData.sourceMapSourceRoot.charCodeAt(sourceMapData.sourceMapSourceRoot.length - 1) !== 47 /* slash */) {
                    sourceMapData.sourceMapSourceRoot += ts.directorySeparator;
                }
                if (compilerOptions.mapRoot) {
                    sourceMapDir = ts.normalizeSlashes(compilerOptions.mapRoot);
                    if (root) {
                        // For modules or multiple emit files the mapRoot will have directory structure like the sources
                        // So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
                        sourceMapDir = ts.getDirectoryPath(ts.getSourceFilePathInNewDir(root, host, sourceMapDir));
                    }
                    if (!ts.isRootedDiskPath(sourceMapDir) && !ts.isUrl(sourceMapDir)) {
                        // The relative paths are relative to the common directory
                        sourceMapDir = ts.combinePaths(host.getCommonSourceDirectory(), sourceMapDir);
                        sourceMapData.jsSourceMappingURL = ts.getRelativePathToDirectoryOrUrl(ts.getDirectoryPath(ts.normalizePath(jsFilePath)), // get the relative sourceMapDir path based on jsFilePath
                            ts.combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL), // this is where user expects to see sourceMap
                            host.getCurrentDirectory(), host.getCanonicalFileName,
                            /*isAbsolutePathAnUrl*/ true);
                    }
                    else {
                        sourceMapData.jsSourceMappingURL = ts.combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL);
                    }
                }
                else {
                    sourceMapDir = ts.getDirectoryPath(ts.normalizePath(jsFilePath));
                }
                function emitNodeWithSourceMap(node) {
                    if (node) {
                        if (ts.nodeIsSynthesized(node)) {
                            return emitNodeWithoutSourceMap(node);
                        }
                        if (node.kind !== 248 /* SourceFile */) {
                            recordEmitNodeStartSpan(node);
                            emitNodeWithoutSourceMap(node);
                            recordEmitNodeEndSpan(node);
                        }
                        else {
                            recordNewSourceFileStart(node);
                            emitNodeWithoutSourceMap(node);
                        }
                    }
                }
                function emitNodeWithCommentsAndWithSourcemap(node) {
                    emitNodeConsideringCommentsOption(node, emitNodeWithSourceMap);
                }
                writeEmittedFiles = writeJavaScriptAndSourceMapFile;
                emit = emitNodeWithCommentsAndWithSourcemap;
                emitStart = recordEmitNodeStartSpan;
                emitEnd = recordEmitNodeEndSpan;
                emitToken = writeTextWithSpanRecord;
                scopeEmitStart = recordScopeNameOfNode;
                scopeEmitEnd = recordScopeNameEnd;
                writeComment = writeCommentRangeWithMap;
            }
            function writeJavaScriptFile(emitOutput, writeByteOrderMark) {
                ts.writeFile(host, diagnostics, jsFilePath, emitOutput, writeByteOrderMark);
            }
            // Create a temporary variable with a unique unused name.
            function createTempVariable(flags) {
                var result = ts.createSynthesizedNode(69 /* Identifier */);
                result.text = makeTempVariableName(flags);
                return result;
            }
            function recordTempDeclaration(name) {
                if (!tempVariables) {
                    tempVariables = [];
                }
                tempVariables.push(name);
            }
            function createAndRecordTempVariable(flags) {
                var temp = createTempVariable(flags);
                recordTempDeclaration(temp);
                return temp;
            }
            function emitTempDeclarations(newLine) {
                if (tempVariables) {
                    if (newLine) {
                        writeLine();
                    }
                    else {
                        write(" ");
                    }
                    write("var ");
                    emitCommaList(tempVariables);
                    write(";");
                }
            }
            function emitTokenText(tokenKind, startPos, emitFn) {
                var tokenString = ts.tokenToString(tokenKind);
                if (emitFn) {
                    emitFn();
                }
                else {
                    write(tokenString);
                }
                return startPos + tokenString.length;
            }
            function emitOptional(prefix, node) {
                if (node) {
                    write(prefix);
                    emit(node);
                }
            }
            function emitParenthesizedIf(node, parenthesized) {
                if (parenthesized) {
                    write("(");
                }
                emit(node);
                if (parenthesized) {
                    write(")");
                }
            }
            function emitTrailingCommaIfPresent(nodeList) {
                if (nodeList.hasTrailingComma) {
                    write(",");
                }
            }
            function emitLinePreservingList(parent, nodes, allowTrailingComma, spacesBetweenBraces) {
                ts.Debug.assert(nodes.length > 0);
                increaseIndent();
                if (nodeStartPositionsAreOnSameLine(parent, nodes[0])) {
                    if (spacesBetweenBraces) {
                        write(" ");
                    }
                }
                else {
                    writeLine();
                }
                for (var i = 0, n = nodes.length; i < n; i++) {
                    if (i) {
                        if (nodeEndIsOnSameLineAsNodeStart(nodes[i - 1], nodes[i])) {
                            write(", ");
                        }
                        else {
                            write(",");
                            writeLine();
                        }
                    }
                    emit(nodes[i]);
                }
                if (nodes.hasTrailingComma && allowTrailingComma) {
                    write(",");
                }
                decreaseIndent();
                if (nodeEndPositionsAreOnSameLine(parent, ts.lastOrUndefined(nodes))) {
                    if (spacesBetweenBraces) {
                        write(" ");
                    }
                }
                else {
                    writeLine();
                }
            }
            function emitList(nodes, start, count, multiLine, trailingComma, leadingComma, noTrailingNewLine, emitNode) {
                if (!emitNode) {
                    emitNode = emit;
                }
                for (var i = 0; i < count; i++) {
                    if (multiLine) {
                        if (i || leadingComma) {
                            write(",");
                        }
                        writeLine();
                    }
                    else {
                        if (i || leadingComma) {
                            write(", ");
                        }
                    }
                    var node = nodes[start + i];
                    // This emitting is to make sure we emit following comment properly
                    //   ...(x, /*comment1*/ y)...
                    //         ^ => node.pos
                    // "comment1" is not considered leading comment for "y" but rather
                    // considered as trailing comment of the previous node.
                    emitTrailingCommentsOfPosition(node.pos);
                    emitNode(node);
                    leadingComma = true;
                }
                if (trailingComma) {
                    write(",");
                }
                if (multiLine && !noTrailingNewLine) {
                    writeLine();
                }
                return count;
            }
            function emitCommaList(nodes) {
                if (nodes) {
                    emitList(nodes, 0, nodes.length, /*multiline*/ false, /*trailingComma*/ false);
                }
            }
            function emitLines(nodes) {
                emitLinesStartingAt(nodes, /*startIndex*/ 0);
            }
            function emitLinesStartingAt(nodes, startIndex) {
                for (var i = startIndex; i < nodes.length; i++) {
                    writeLine();
                    emit(nodes[i]);
                }
            }
            function isBinaryOrOctalIntegerLiteral(node, text) {
                if (node.kind === 8 /* NumericLiteral */ && text.length > 1) {
                    switch (text.charCodeAt(1)) {
                        case 98 /* b */:
                        case 66 /* B */:
                        case 111 /* o */:
                        case 79 /* O */:
                            return true;
                    }
                }
                return false;
            }
            function emitLiteral(node) {
                var text = getLiteralText(node);
                if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) && (node.kind === 9 /* StringLiteral */ || ts.isTemplateLiteralKind(node.kind))) {
                    writer.writeLiteral(text);
                }
                else if (languageVersion < 2 /* ES6 */ && isBinaryOrOctalIntegerLiteral(node, text)) {
                    write(node.text);
                }
                else {
                    write(text);
                }
            }
            function getLiteralText(node) {
                // Any template literal or string literal with an extended escape
                // (e.g. "\u{0067}") will need to be downleveled as a escaped string literal.
                if (languageVersion < 2 /* ES6 */ && (ts.isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) {
                    return getQuotedEscapedLiteralText("\"", node.text, "\"");
                }
                // If we don't need to downlevel and we can reach the original source text using
                // the node's parent reference, then simply get the text as it was originally written.
                if (node.parent) {
                    return ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, node);
                }
                // If we can't reach the original source text, use the canonical form if it's a number,
                // or an escaped quoted form of the original text if it's string-like.
                switch (node.kind) {
                    case 9 /* StringLiteral */:
                        return getQuotedEscapedLiteralText("\"", node.text, "\"");
                    case 11 /* NoSubstitutionTemplateLiteral */:
                        return getQuotedEscapedLiteralText("`", node.text, "`");
                    case 12 /* TemplateHead */:
                        return getQuotedEscapedLiteralText("`", node.text, "${");
                    case 13 /* TemplateMiddle */:
                        return getQuotedEscapedLiteralText("}", node.text, "${");
                    case 14 /* TemplateTail */:
                        return getQuotedEscapedLiteralText("}", node.text, "`");
                    case 8 /* NumericLiteral */:
                        return node.text;
                }
                ts.Debug.fail("Literal kind '" + node.kind + "' not accounted for.");
            }
            function getQuotedEscapedLiteralText(leftQuote, text, rightQuote) {
                return leftQuote + ts.escapeNonAsciiCharacters(ts.escapeString(text)) + rightQuote;
            }
            function emitDownlevelRawTemplateLiteral(node) {
                // Find original source text, since we need to emit the raw strings of the tagged template.
                // The raw strings contain the (escaped) strings of what the user wrote.
                // Examples: `\n` is converted to "\\n", a template string with a newline to "\n".
                var text = ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, node);
                // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"),
                // thus we need to remove those characters.
                // First template piece starts with "`", others with "}"
                // Last template piece ends with "`", others with "${"
                var isLast = node.kind === 11 /* NoSubstitutionTemplateLiteral */ || node.kind === 14 /* TemplateTail */;
                text = text.substring(1, text.length - (isLast ? 1 : 2));
                // Newline normalization:
                // ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's
                // <CR><LF> and <CR> LineTerminatorSequences are normalized to <LF> for both TV and TRV.
                text = text.replace(/\r\n?/g, "\n");
                text = ts.escapeString(text);
                write("\"" + text + "\"");
            }
            function emitDownlevelTaggedTemplateArray(node, literalEmitter) {
                write("[");
                if (node.template.kind === 11 /* NoSubstitutionTemplateLiteral */) {
                    literalEmitter(node.template);
                }
                else {
                    literalEmitter(node.template.head);
                    ts.forEach(node.template.templateSpans, function (child) {
                        write(", ");
                        literalEmitter(child.literal);
                    });
                }
                write("]");
            }
            function emitDownlevelTaggedTemplate(node) {
                var tempVariable = createAndRecordTempVariable(0 /* Auto */);
                write("(");
                emit(tempVariable);
                write(" = ");
                emitDownlevelTaggedTemplateArray(node, emit);
                write(", ");
                emit(tempVariable);
                write(".raw = ");
                emitDownlevelTaggedTemplateArray(node, emitDownlevelRawTemplateLiteral);
                write(", ");
                emitParenthesizedIf(node.tag, needsParenthesisForPropertyAccessOrInvocation(node.tag));
                write("(");
                emit(tempVariable);
                // Now we emit the expressions
                if (node.template.kind === 183 /* TemplateExpression */) {
                    ts.forEach(node.template.templateSpans, function (templateSpan) {
                        write(", ");
                        var needsParens = templateSpan.expression.kind === 181 /* BinaryExpression */
                            && templateSpan.expression.operatorToken.kind === 24 /* CommaToken */;
                        emitParenthesizedIf(templateSpan.expression, needsParens);
                    });
                }
                write("))");
            }
            function emitTemplateExpression(node) {
                // In ES6 mode and above, we can simply emit each portion of a template in order, but in
                // ES3 & ES5 we must convert the template expression into a series of string concatenations.
                if (languageVersion >= 2 /* ES6 */) {
                    ts.forEachChild(node, emit);
                    return;
                }
                var emitOuterParens = ts.isExpression(node.parent)
                    && templateNeedsParens(node, node.parent);
                if (emitOuterParens) {
                    write("(");
                }
                var headEmitted = false;
                if (shouldEmitTemplateHead()) {
                    emitLiteral(node.head);
                    headEmitted = true;
                }
                for (var i = 0, n = node.templateSpans.length; i < n; i++) {
                    var templateSpan = node.templateSpans[i];
                    // Check if the expression has operands and binds its operands less closely than binary '+'.
                    // If it does, we need to wrap the expression in parentheses. Otherwise, something like
                    //    `abc${ 1 << 2 }`
                    // becomes
                    //    "abc" + 1 << 2 + ""
                    // which is really
                    //    ("abc" + 1) << (2 + "")
                    // rather than
                    //    "abc" + (1 << 2) + ""
                    var needsParens = templateSpan.expression.kind !== 172 /* ParenthesizedExpression */
                        && comparePrecedenceToBinaryPlus(templateSpan.expression) !== 1 /* GreaterThan */;
                    if (i > 0 || headEmitted) {
                        // If this is the first span and the head was not emitted, then this templateSpan's
                        // expression will be the first to be emitted. Don't emit the preceding ' + ' in that
                        // case.
                        write(" + ");
                    }
                    emitParenthesizedIf(templateSpan.expression, needsParens);
                    // Only emit if the literal is non-empty.
                    // The binary '+' operator is left-associative, so the first string concatenation
                    // with the head will force the result up to this point to be a string.
                    // Emitting a '+ ""' has no semantic effect for middles and tails.
                    if (templateSpan.literal.text.length !== 0) {
                        write(" + ");
                        emitLiteral(templateSpan.literal);
                    }
                }
                if (emitOuterParens) {
                    write(")");
                }
                function shouldEmitTemplateHead() {
                    // If this expression has an empty head literal and the first template span has a non-empty
                    // literal, then emitting the empty head literal is not necessary.
                    //     `${ foo } and ${ bar }`
                    // can be emitted as
                    //     foo + " and " + bar
                    // This is because it is only required that one of the first two operands in the emit
                    // output must be a string literal, so that the other operand and all following operands
                    // are forced into strings.
                    //
                    // If the first template span has an empty literal, then the head must still be emitted.
                    //     `${ foo }${ bar }`
                    // must still be emitted as
                    //     "" + foo + bar
                    // There is always atleast one templateSpan in this code path, since
                    // NoSubstitutionTemplateLiterals are directly emitted via emitLiteral()
                    ts.Debug.assert(node.templateSpans.length !== 0);
                    return node.head.text.length !== 0 || node.templateSpans[0].literal.text.length === 0;
                }
                function templateNeedsParens(template, parent) {
                    switch (parent.kind) {
                        case 168 /* CallExpression */:
                        case 169 /* NewExpression */:
                            return parent.expression === template;
                        case 170 /* TaggedTemplateExpression */:
                        case 172 /* ParenthesizedExpression */:
                            return false;
                        default:
                            return comparePrecedenceToBinaryPlus(parent) !== -1 /* LessThan */;
                    }
                }
                /**
                 * Returns whether the expression has lesser, greater,
                 * or equal precedence to the binary '+' operator
                 */
                function comparePrecedenceToBinaryPlus(expression) {
                    // All binary expressions have lower precedence than '+' apart from '*', '/', and '%'
                    // which have greater precedence and '-' which has equal precedence.
                    // All unary operators have a higher precedence apart from yield.
                    // Arrow functions and conditionals have a lower precedence,
                    // although we convert the former into regular function expressions in ES5 mode,
                    // and in ES6 mode this function won't get called anyway.
                    //
                    // TODO (drosen): Note that we need to account for the upcoming 'yield' and
                    //                spread ('...') unary operators that are anticipated for ES6.
                    switch (expression.kind) {
                        case 181 /* BinaryExpression */:
                            switch (expression.operatorToken.kind) {
                                case 37 /* AsteriskToken */:
                                case 39 /* SlashToken */:
                                case 40 /* PercentToken */:
                                    return 1 /* GreaterThan */;
                                case 35 /* PlusToken */:
                                case 36 /* MinusToken */:
                                    return 0 /* EqualTo */;
                                default:
                                    return -1 /* LessThan */;
                            }
                        case 184 /* YieldExpression */:
                        case 182 /* ConditionalExpression */:
                            return -1 /* LessThan */;
                        default:
                            return 1 /* GreaterThan */;
                    }
                }
            }
            function emitTemplateSpan(span) {
                emit(span.expression);
                emit(span.literal);
            }
            function jsxEmitReact(node) {
                /// Emit a tag name, which is either '"div"' for lower-cased names, or
                /// 'Div' for upper-cased or dotted names
                function emitTagName(name) {
                    if (name.kind === 69 /* Identifier */ && ts.isIntrinsicJsxName(name.text)) {
                        write("\"");
                        emit(name);
                        write("\"");
                    }
                    else {
                        emit(name);
                    }
                }
                /// Emit an attribute name, which is quoted if it needs to be quoted. Because
                /// these emit into an object literal property name, we don't need to be worried
                /// about keywords, just non-identifier characters
                function emitAttributeName(name) {
                    if (/[A-Za-z_]+[\w*]/.test(name.text)) {
                        write("\"");
                        emit(name);
                        write("\"");
                    }
                    else {
                        emit(name);
                    }
                }
                /// Emit an name/value pair for an attribute (e.g. "x: 3")
                function emitJsxAttribute(node) {
                    emitAttributeName(node.name);
                    write(": ");
                    if (node.initializer) {
                        emit(node.initializer);
                    }
                    else {
                        write("true");
                    }
                }
                function emitJsxElement(openingNode, children) {
                    var syntheticReactRef = ts.createSynthesizedNode(69 /* Identifier */);
                    syntheticReactRef.text = "React";
                    syntheticReactRef.parent = openingNode;
                    // Call React.createElement(tag, ...
                    emitLeadingComments(openingNode);
                    emitExpressionIdentifier(syntheticReactRef);
                    write(".createElement(");
                    emitTagName(openingNode.tagName);
                    write(", ");
                    // Attribute list
                    if (openingNode.attributes.length === 0) {
                        // When there are no attributes, React wants "null"
                        write("null");
                    }
                    else {
                        // Either emit one big object literal (no spread attribs), or
                        // a call to React.__spread
                        var attrs = openingNode.attributes;
                        if (ts.forEach(attrs, function (attr) { return attr.kind === 239 /* JsxSpreadAttribute */; })) {
                            emitExpressionIdentifier(syntheticReactRef);
                            write(".__spread(");
                            var haveOpenedObjectLiteral = false;
                            for (var i_1 = 0; i_1 < attrs.length; i_1++) {
                                if (attrs[i_1].kind === 239 /* JsxSpreadAttribute */) {
                                    // If this is the first argument, we need to emit a {} as the first argument
                                    if (i_1 === 0) {
                                        write("{}, ");
                                    }
                                    if (haveOpenedObjectLiteral) {
                                        write("}");
                                        haveOpenedObjectLiteral = false;
                                    }
                                    if (i_1 > 0) {
                                        write(", ");
                                    }
                                    emit(attrs[i_1].expression);
                                }
                                else {
                                    ts.Debug.assert(attrs[i_1].kind === 238 /* JsxAttribute */);
                                    if (haveOpenedObjectLiteral) {
                                        write(", ");
                                    }
                                    else {
                                        haveOpenedObjectLiteral = true;
                                        if (i_1 > 0) {
                                            write(", ");
                                        }
                                        write("{");
                                    }
                                    emitJsxAttribute(attrs[i_1]);
                                }
                            }
                            if (haveOpenedObjectLiteral)
                                write("}");
                            write(")"); // closing paren to React.__spread(
                        }
                        else {
                            // One object literal with all the attributes in them
                            write("{");
                            for (var i = 0; i < attrs.length; i++) {
                                if (i > 0) {
                                    write(", ");
                                }
                                emitJsxAttribute(attrs[i]);
                            }
                            write("}");
                        }
                    }
                    // Children
                    if (children) {
                        for (var i = 0; i < children.length; i++) {
                            // Don't emit empty expressions
                            if (children[i].kind === 240 /* JsxExpression */ && !(children[i].expression)) {
                                continue;
                            }
                            // Don't emit empty strings
                            if (children[i].kind === 236 /* JsxText */) {
                                var text = getTextToEmit(children[i]);
                                if (text !== undefined) {
                                    write(", \"");
                                    write(text);
                                    write("\"");
                                }
                            }
                            else {
                                write(", ");
                                emit(children[i]);
                            }
                        }
                    }
                    // Closing paren
                    write(")"); // closes "React.createElement("
                    emitTrailingComments(openingNode);
                }
                if (node.kind === 233 /* JsxElement */) {
                    emitJsxElement(node.openingElement, node.children);
                }
                else {
                    ts.Debug.assert(node.kind === 234 /* JsxSelfClosingElement */);
                    emitJsxElement(node);
                }
            }
            function jsxEmitPreserve(node) {
                function emitJsxAttribute(node) {
                    emit(node.name);
                    if (node.initializer) {
                        write("=");
                        emit(node.initializer);
                    }
                }
                function emitJsxSpreadAttribute(node) {
                    write("{...");
                    emit(node.expression);
                    write("}");
                }
                function emitAttributes(attribs) {
                    for (var i = 0, n = attribs.length; i < n; i++) {
                        if (i > 0) {
                            write(" ");
                        }
                        if (attribs[i].kind === 239 /* JsxSpreadAttribute */) {
                            emitJsxSpreadAttribute(attribs[i]);
                        }
                        else {
                            ts.Debug.assert(attribs[i].kind === 238 /* JsxAttribute */);
                            emitJsxAttribute(attribs[i]);
                        }
                    }
                }
                function emitJsxOpeningOrSelfClosingElement(node) {
                    write("<");
                    emit(node.tagName);
                    if (node.attributes.length > 0 || (node.kind === 234 /* JsxSelfClosingElement */)) {
                        write(" ");
                    }
                    emitAttributes(node.attributes);
                    if (node.kind === 234 /* JsxSelfClosingElement */) {
                        write("/>");
                    }
                    else {
                        write(">");
                    }
                }
                function emitJsxClosingElement(node) {
                    write("</");
                    emit(node.tagName);
                    write(">");
                }
                function emitJsxElement(node) {
                    emitJsxOpeningOrSelfClosingElement(node.openingElement);
                    for (var i = 0, n = node.children.length; i < n; i++) {
                        emit(node.children[i]);
                    }
                    emitJsxClosingElement(node.closingElement);
                }
                if (node.kind === 233 /* JsxElement */) {
                    emitJsxElement(node);
                }
                else {
                    ts.Debug.assert(node.kind === 234 /* JsxSelfClosingElement */);
                    emitJsxOpeningOrSelfClosingElement(node);
                }
            }
            // This function specifically handles numeric/string literals for enum and accessor 'identifiers'.
            // In a sense, it does not actually emit identifiers as much as it declares a name for a specific property.
            // For example, this is utilized when feeding in a result to Object.defineProperty.
            function emitExpressionForPropertyName(node) {
                ts.Debug.assert(node.kind !== 163 /* BindingElement */);
                if (node.kind === 9 /* StringLiteral */) {
                    emitLiteral(node);
                }
                else if (node.kind === 136 /* ComputedPropertyName */) {
                    // if this is a decorated computed property, we will need to capture the result
                    // of the property expression so that we can apply decorators later. This is to ensure
                    // we don't introduce unintended side effects:
                    //
                    //   class C {
                    //     [_a = x]() { }
                    //   }
                    //
                    // The emit for the decorated computed property decorator is:
                    //
                    //   __decorate([dec], C.prototype, _a, Object.getOwnPropertyDescriptor(C.prototype, _a));
                    //
                    if (ts.nodeIsDecorated(node.parent)) {
                        if (!computedPropertyNamesToGeneratedNames) {
                            computedPropertyNamesToGeneratedNames = [];
                        }
                        var generatedName = computedPropertyNamesToGeneratedNames[ts.getNodeId(node)];
                        if (generatedName) {
                            // we have already generated a variable for this node, write that value instead.
                            write(generatedName);
                            return;
                        }
                        generatedName = createAndRecordTempVariable(0 /* Auto */).text;
                        computedPropertyNamesToGeneratedNames[ts.getNodeId(node)] = generatedName;
                        write(generatedName);
                        write(" = ");
                    }
                    emit(node.expression);
                }
                else {
                    write("\"");
                    if (node.kind === 8 /* NumericLiteral */) {
                        write(node.text);
                    }
                    else {
                        writeTextOfNode(currentSourceFile, node);
                    }
                    write("\"");
                }
            }
            function isExpressionIdentifier(node) {
                var parent = node.parent;
                switch (parent.kind) {
                    case 164 /* ArrayLiteralExpression */:
                    case 189 /* AsExpression */:
                    case 181 /* BinaryExpression */:
                    case 168 /* CallExpression */:
                    case 241 /* CaseClause */:
                    case 136 /* ComputedPropertyName */:
                    case 182 /* ConditionalExpression */:
                    case 139 /* Decorator */:
                    case 175 /* DeleteExpression */:
                    case 197 /* DoStatement */:
                    case 167 /* ElementAccessExpression */:
                    case 227 /* ExportAssignment */:
                    case 195 /* ExpressionStatement */:
                    case 188 /* ExpressionWithTypeArguments */:
                    case 199 /* ForStatement */:
                    case 200 /* ForInStatement */:
                    case 201 /* ForOfStatement */:
                    case 196 /* IfStatement */:
                    case 234 /* JsxSelfClosingElement */:
                    case 235 /* JsxOpeningElement */:
                    case 239 /* JsxSpreadAttribute */:
                    case 240 /* JsxExpression */:
                    case 169 /* NewExpression */:
                    case 172 /* ParenthesizedExpression */:
                    case 180 /* PostfixUnaryExpression */:
                    case 179 /* PrefixUnaryExpression */:
                    case 204 /* ReturnStatement */:
                    case 246 /* ShorthandPropertyAssignment */:
                    case 185 /* SpreadElementExpression */:
                    case 206 /* SwitchStatement */:
                    case 170 /* TaggedTemplateExpression */:
                    case 190 /* TemplateSpan */:
                    case 208 /* ThrowStatement */:
                    case 171 /* TypeAssertionExpression */:
                    case 176 /* TypeOfExpression */:
                    case 177 /* VoidExpression */:
                    case 198 /* WhileStatement */:
                    case 205 /* WithStatement */:
                    case 184 /* YieldExpression */:
                        return true;
                    case 163 /* BindingElement */:
                    case 247 /* EnumMember */:
                    case 138 /* Parameter */:
                    case 245 /* PropertyAssignment */:
                    case 141 /* PropertyDeclaration */:
                    case 211 /* VariableDeclaration */:
                        return parent.initializer === node;
                    case 166 /* PropertyAccessExpression */:
                        return parent.expression === node;
                    case 174 /* ArrowFunction */:
                    case 173 /* FunctionExpression */:
                        return parent.body === node;
                    case 221 /* ImportEqualsDeclaration */:
                        return parent.moduleReference === node;
                    case 135 /* QualifiedName */:
                        return parent.left === node;
                }
                return false;
            }
            function emitExpressionIdentifier(node) {
                if (resolver.getNodeCheckFlags(node) & 2048 /* LexicalArguments */) {
                    write("_arguments");
                    return;
                }
                var container = resolver.getReferencedExportContainer(node);
                if (container) {
                    if (container.kind === 248 /* SourceFile */) {
                        // Identifier references module export
                        if (modulekind !== 5 /* ES6 */ && modulekind !== 4 /* System */) {
                            write("exports.");
                        }
                    }
                    else {
                        // Identifier references namespace export
                        write(getGeneratedNameForNode(container));
                        write(".");
                    }
                }
                else {
                    if (modulekind !== 5 /* ES6 */) {
                        var declaration = resolver.getReferencedImportDeclaration(node);
                        if (declaration) {
                            if (declaration.kind === 223 /* ImportClause */) {
                                // Identifier references default import
                                write(getGeneratedNameForNode(declaration.parent));
                                write(languageVersion === 0 /* ES3 */ ? "[\"default\"]" : ".default");
                                return;
                            }
                            else if (declaration.kind === 226 /* ImportSpecifier */) {
                                // Identifier references named import
                                write(getGeneratedNameForNode(declaration.parent.parent.parent));
                                var name_23 = declaration.propertyName || declaration.name;
                                var identifier = ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, name_23);
                                if (languageVersion === 0 /* ES3 */ && identifier === "default") {
                                    write("[\"default\"]");
                                }
                                else {
                                    write(".");
                                    write(identifier);
                                }
                                return;
                            }
                        }
                    }
                    if (languageVersion !== 2 /* ES6 */) {
                        var declaration = resolver.getReferencedNestedRedeclaration(node);
                        if (declaration) {
                            write(getGeneratedNameForNode(declaration.name));
                            return;
                        }
                    }
                }
                if (ts.nodeIsSynthesized(node)) {
                    write(node.text);
                }
                else {
                    writeTextOfNode(currentSourceFile, node);
                }
            }
            function isNameOfNestedRedeclaration(node) {
                if (languageVersion < 2 /* ES6 */) {
                    var parent_6 = node.parent;
                    switch (parent_6.kind) {
                        case 163 /* BindingElement */:
                        case 214 /* ClassDeclaration */:
                        case 217 /* EnumDeclaration */:
                        case 211 /* VariableDeclaration */:
                            return parent_6.name === node && resolver.isNestedRedeclaration(parent_6);
                    }
                }
                return false;
            }
            function emitIdentifier(node) {
                if (!node.parent) {
                    write(node.text);
                }
                else if (isExpressionIdentifier(node)) {
                    emitExpressionIdentifier(node);
                }
                else if (isNameOfNestedRedeclaration(node)) {
                    write(getGeneratedNameForNode(node));
                }
                else if (ts.nodeIsSynthesized(node)) {
                    write(node.text);
                }
                else {
                    writeTextOfNode(currentSourceFile, node);
                }
            }
            function emitThis(node) {
                if (resolver.getNodeCheckFlags(node) & 2 /* LexicalThis */) {
                    write("_this");
                }
                else {
                    write("this");
                }
            }
            function emitSuper(node) {
                if (languageVersion >= 2 /* ES6 */) {
                    write("super");
                }
                else {
                    var flags = resolver.getNodeCheckFlags(node);
                    if (flags & 256 /* SuperInstance */) {
                        write("_super.prototype");
                    }
                    else {
                        write("_super");
                    }
                }
            }
            function emitObjectBindingPattern(node) {
                write("{ ");
                var elements = node.elements;
                emitList(elements, 0, elements.length, /*multiLine*/ false, /*trailingComma*/ elements.hasTrailingComma);
                write(" }");
            }
            function emitArrayBindingPattern(node) {
                write("[");
                var elements = node.elements;
                emitList(elements, 0, elements.length, /*multiLine*/ false, /*trailingComma*/ elements.hasTrailingComma);
                write("]");
            }
            function emitBindingElement(node) {
                if (node.propertyName) {
                    emit(node.propertyName);
                    write(": ");
                }
                if (node.dotDotDotToken) {
                    write("...");
                }
                if (ts.isBindingPattern(node.name)) {
                    emit(node.name);
                }
                else {
                    emitModuleMemberName(node);
                }
                emitOptional(" = ", node.initializer);
            }
            function emitSpreadElementExpression(node) {
                write("...");
                emit(node.expression);
            }
            function emitYieldExpression(node) {
                write(ts.tokenToString(114 /* YieldKeyword */));
                if (node.asteriskToken) {
                    write("*");
                }
                if (node.expression) {
                    write(" ");
                    emit(node.expression);
                }
            }
            function emitAwaitExpression(node) {
                var needsParenthesis = needsParenthesisForAwaitExpressionAsYield(node);
                if (needsParenthesis) {
                    write("(");
                }
                write(ts.tokenToString(114 /* YieldKeyword */));
                write(" ");
                emit(node.expression);
                if (needsParenthesis) {
                    write(")");
                }
            }
            function needsParenthesisForAwaitExpressionAsYield(node) {
                if (node.parent.kind === 181 /* BinaryExpression */ && !ts.isAssignmentOperator(node.parent.operatorToken.kind)) {
                    return true;
                }
                else if (node.parent.kind === 182 /* ConditionalExpression */ && node.parent.condition === node) {
                    return true;
                }
                return false;
            }
            function needsParenthesisForPropertyAccessOrInvocation(node) {
                switch (node.kind) {
                    case 69 /* Identifier */:
                    case 164 /* ArrayLiteralExpression */:
                    case 166 /* PropertyAccessExpression */:
                    case 167 /* ElementAccessExpression */:
                    case 168 /* CallExpression */:
                    case 172 /* ParenthesizedExpression */:
                        // This list is not exhaustive and only includes those cases that are relevant
                        // to the check in emitArrayLiteral. More cases can be added as needed.
                        return false;
                }
                return true;
            }
            function emitListWithSpread(elements, needsUniqueCopy, multiLine, trailingComma, useConcat) {
                var pos = 0;
                var group = 0;
                var length = elements.length;
                while (pos < length) {
                    // Emit using the pattern <group0>.concat(<group1>, <group2>, ...)
                    if (group === 1 && useConcat) {
                        write(".concat(");
                    }
                    else if (group > 0) {
                        write(", ");
                    }
                    var e = elements[pos];
                    if (e.kind === 185 /* SpreadElementExpression */) {
                        e = e.expression;
                        emitParenthesizedIf(e, /*parenthesized*/ group === 0 && needsParenthesisForPropertyAccessOrInvocation(e));
                        pos++;
                        if (pos === length && group === 0 && needsUniqueCopy && e.kind !== 164 /* ArrayLiteralExpression */) {
                            write(".slice()");
                        }
                    }
                    else {
                        var i = pos;
                        while (i < length && elements[i].kind !== 185 /* SpreadElementExpression */) {
                            i++;
                        }
                        write("[");
                        if (multiLine) {
                            increaseIndent();
                        }
                        emitList(elements, pos, i - pos, multiLine, trailingComma && i === length);
                        if (multiLine) {
                            decreaseIndent();
                        }
                        write("]");
                        pos = i;
                    }
                    group++;
                }
                if (group > 1) {
                    if (useConcat) {
                        write(")");
                    }
                }
            }
            function isSpreadElementExpression(node) {
                return node.kind === 185 /* SpreadElementExpression */;
            }
            function emitArrayLiteral(node) {
                var elements = node.elements;
                if (elements.length === 0) {
                    write("[]");
                }
                else if (languageVersion >= 2 /* ES6 */ || !ts.forEach(elements, isSpreadElementExpression)) {
                    write("[");
                    emitLinePreservingList(node, node.elements, elements.hasTrailingComma, /*spacesBetweenBraces:*/ false);
                    write("]");
                }
                else {
                    emitListWithSpread(elements, /*needsUniqueCopy*/ true, /*multiLine*/ (node.flags & 2048 /* MultiLine */) !== 0,
                        /*trailingComma*/ elements.hasTrailingComma, /*useConcat*/ true);
                }
            }
            function emitObjectLiteralBody(node, numElements) {
                if (numElements === 0) {
                    write("{}");
                    return;
                }
                write("{");
                if (numElements > 0) {
                    var properties = node.properties;
                    // If we are not doing a downlevel transformation for object literals,
                    // then try to preserve the original shape of the object literal.
                    // Otherwise just try to preserve the formatting.
                    if (numElements === properties.length) {
                        emitLinePreservingList(node, properties, /* allowTrailingComma */ languageVersion >= 1 /* ES5 */, /* spacesBetweenBraces */ true);
                    }
                    else {
                        var multiLine = (node.flags & 2048 /* MultiLine */) !== 0;
                        if (!multiLine) {
                            write(" ");
                        }
                        else {
                            increaseIndent();
                        }
                        emitList(properties, 0, numElements, /*multiLine*/ multiLine, /*trailingComma*/ false);
                        if (!multiLine) {
                            write(" ");
                        }
                        else {
                            decreaseIndent();
                        }
                    }
                }
                write("}");
            }
            function emitDownlevelObjectLiteralWithComputedProperties(node, firstComputedPropertyIndex) {
                var multiLine = (node.flags & 2048 /* MultiLine */) !== 0;
                var properties = node.properties;
                write("(");
                if (multiLine) {
                    increaseIndent();
                }
                // For computed properties, we need to create a unique handle to the object
                // literal so we can modify it without risking internal assignments tainting the object.
                var tempVar = createAndRecordTempVariable(0 /* Auto */);
                // Write out the first non-computed properties
                // (or all properties if none of them are computed),
                // then emit the rest through indexing on the temp variable.
                emit(tempVar);
                write(" = ");
                emitObjectLiteralBody(node, firstComputedPropertyIndex);
                for (var i = firstComputedPropertyIndex, n = properties.length; i < n; i++) {
                    writeComma();
                    var property = properties[i];
                    emitStart(property);
                    if (property.kind === 145 /* GetAccessor */ || property.kind === 146 /* SetAccessor */) {
                        // TODO (drosen): Reconcile with 'emitMemberFunctions'.
                        var accessors = ts.getAllAccessorDeclarations(node.properties, property);
                        if (property !== accessors.firstAccessor) {
                            continue;
                        }
                        write("Object.defineProperty(");
                        emit(tempVar);
                        write(", ");
                        emitStart(node.name);
                        emitExpressionForPropertyName(property.name);
                        emitEnd(property.name);
                        write(", {");
                        increaseIndent();
                        if (accessors.getAccessor) {
                            writeLine();
                            emitLeadingComments(accessors.getAccessor);
                            write("get: ");
                            emitStart(accessors.getAccessor);
                            write("function ");
                            emitSignatureAndBody(accessors.getAccessor);
                            emitEnd(accessors.getAccessor);
                            emitTrailingComments(accessors.getAccessor);
                            write(",");
                        }
                        if (accessors.setAccessor) {
                            writeLine();
                            emitLeadingComments(accessors.setAccessor);
                            write("set: ");
                            emitStart(accessors.setAccessor);
                            write("function ");
                            emitSignatureAndBody(accessors.setAccessor);
                            emitEnd(accessors.setAccessor);
                            emitTrailingComments(accessors.setAccessor);
                            write(",");
                        }
                        writeLine();
                        write("enumerable: true,");
                        writeLine();
                        write("configurable: true");
                        decreaseIndent();
                        writeLine();
                        write("})");
                        emitEnd(property);
                    }
                    else {
                        emitLeadingComments(property);
                        emitStart(property.name);
                        emit(tempVar);
                        emitMemberAccessForPropertyName(property.name);
                        emitEnd(property.name);
                        write(" = ");
                        if (property.kind === 245 /* PropertyAssignment */) {
                            emit(property.initializer);
                        }
                        else if (property.kind === 246 /* ShorthandPropertyAssignment */) {
                            emitExpressionIdentifier(property.name);
                        }
                        else if (property.kind === 143 /* MethodDeclaration */) {
                            emitFunctionDeclaration(property);
                        }
                        else {
                            ts.Debug.fail("ObjectLiteralElement type not accounted for: " + property.kind);
                        }
                    }
                    emitEnd(property);
                }
                writeComma();
                emit(tempVar);
                if (multiLine) {
                    decreaseIndent();
                    writeLine();
                }
                write(")");
                function writeComma() {
                    if (multiLine) {
                        write(",");
                        writeLine();
                    }
                    else {
                        write(", ");
                    }
                }
            }
            function emitObjectLiteral(node) {
                var properties = node.properties;
                if (languageVersion < 2 /* ES6 */) {
                    var numProperties = properties.length;
                    // Find the first computed property.
                    // Everything until that point can be emitted as part of the initial object literal.
                    var numInitialNonComputedProperties = numProperties;
                    for (var i = 0, n = properties.length; i < n; i++) {
                        if (properties[i].name.kind === 136 /* ComputedPropertyName */) {
                            numInitialNonComputedProperties = i;
                            break;
                        }
                    }
                    var hasComputedProperty = numInitialNonComputedProperties !== properties.length;
                    if (hasComputedProperty) {
                        emitDownlevelObjectLiteralWithComputedProperties(node, numInitialNonComputedProperties);
                        return;
                    }
                }
                // Ordinary case: either the object has no computed properties
                // or we're compiling with an ES6+ target.
                emitObjectLiteralBody(node, properties.length);
            }
            function createBinaryExpression(left, operator, right, startsOnNewLine) {
                var result = ts.createSynthesizedNode(181 /* BinaryExpression */, startsOnNewLine);
                result.operatorToken = ts.createSynthesizedNode(operator);
                result.left = left;
                result.right = right;
                return result;
            }
            function createPropertyAccessExpression(expression, name) {
                var result = ts.createSynthesizedNode(166 /* PropertyAccessExpression */);
                result.expression = parenthesizeForAccess(expression);
                result.dotToken = ts.createSynthesizedNode(21 /* DotToken */);
                result.name = name;
                return result;
            }
            function createElementAccessExpression(expression, argumentExpression) {
                var result = ts.createSynthesizedNode(167 /* ElementAccessExpression */);
                result.expression = parenthesizeForAccess(expression);
                result.argumentExpression = argumentExpression;
                return result;
            }
            function parenthesizeForAccess(expr) {
                // When diagnosing whether the expression needs parentheses, the decision should be based
                // on the innermost expression in a chain of nested type assertions.
                while (expr.kind === 171 /* TypeAssertionExpression */ || expr.kind === 189 /* AsExpression */) {
                    expr = expr.expression;
                }
                // isLeftHandSideExpression is almost the correct criterion for when it is not necessary
                // to parenthesize the expression before a dot. The known exceptions are:
                //
                //    NewExpression:
                //       new C.x        -> not the same as (new C).x
                //    NumberLiteral
                //       1.x            -> not the same as (1).x
                //
                if (ts.isLeftHandSideExpression(expr) &&
                    expr.kind !== 169 /* NewExpression */ &&
                    expr.kind !== 8 /* NumericLiteral */) {
                    return expr;
                }
                var node = ts.createSynthesizedNode(172 /* ParenthesizedExpression */);
                node.expression = expr;
                return node;
            }
            function emitComputedPropertyName(node) {
                write("[");
                emitExpressionForPropertyName(node);
                write("]");
            }
            function emitMethod(node) {
                if (languageVersion >= 2 /* ES6 */ && node.asteriskToken) {
                    write("*");
                }
                emit(node.name);
                if (languageVersion < 2 /* ES6 */) {
                    write(": function ");
                }
                emitSignatureAndBody(node);
            }
            function emitPropertyAssignment(node) {
                emit(node.name);
                write(": ");
                // This is to ensure that we emit comment in the following case:
                //      For example:
                //          obj = {
                //              id: /*comment1*/ ()=>void
                //          }
                // "comment1" is not considered to be leading comment for node.initializer
                // but rather a trailing comment on the previous node.
                emitTrailingCommentsOfPosition(node.initializer.pos);
                emit(node.initializer);
            }
            // Return true if identifier resolves to an exported member of a namespace
            function isNamespaceExportReference(node) {
                var container = resolver.getReferencedExportContainer(node);
                return container && container.kind !== 248 /* SourceFile */;
            }
            function emitShorthandPropertyAssignment(node) {
                // The name property of a short-hand property assignment is considered an expression position, so here
                // we manually emit the identifier to avoid rewriting.
                writeTextOfNode(currentSourceFile, node.name);
                // If emitting pre-ES6 code, or if the name requires rewriting when resolved as an expression identifier,
                // we emit a normal property assignment. For example:
                //   module m {
                //       export let y;
                //   }
                //   module m {
                //       let obj = { y };
                //   }
                // Here we need to emit obj = { y : m.y } regardless of the output target.
                if (languageVersion < 2 /* ES6 */ || isNamespaceExportReference(node.name)) {
                    // Emit identifier as an identifier
                    write(": ");
                    emit(node.name);
                }
                if (languageVersion >= 2 /* ES6 */ && node.objectAssignmentInitializer) {
                    write(" = ");
                    emit(node.objectAssignmentInitializer);
                }
            }
            function tryEmitConstantValue(node) {
                var constantValue = tryGetConstEnumValue(node);
                if (constantValue !== undefined) {
                    write(constantValue.toString());
                    if (!compilerOptions.removeComments) {
                        var propertyName = node.kind === 166 /* PropertyAccessExpression */ ? ts.declarationNameToString(node.name) : ts.getTextOfNode(node.argumentExpression);
                        write(" /* " + propertyName + " */");
                    }
                    return true;
                }
                return false;
            }
            function tryGetConstEnumValue(node) {
                if (compilerOptions.isolatedModules) {
                    return undefined;
                }
                return node.kind === 166 /* PropertyAccessExpression */ || node.kind === 167 /* ElementAccessExpression */
                    ? resolver.getConstantValue(node)
                    : undefined;
            }
            // Returns 'true' if the code was actually indented, false otherwise.
            // If the code is not indented, an optional valueToWriteWhenNotIndenting will be
            // emitted instead.
            function indentIfOnDifferentLines(parent, node1, node2, valueToWriteWhenNotIndenting) {
                var realNodesAreOnDifferentLines = !ts.nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2);
                // Always use a newline for synthesized code if the synthesizer desires it.
                var synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2);
                if (realNodesAreOnDifferentLines || synthesizedNodeIsOnDifferentLine) {
                    increaseIndent();
                    writeLine();
                    return true;
                }
                else {
                    if (valueToWriteWhenNotIndenting) {
                        write(valueToWriteWhenNotIndenting);
                    }
                    return false;
                }
            }
            function emitPropertyAccess(node) {
                if (tryEmitConstantValue(node)) {
                    return;
                }
                emit(node.expression);
                var indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken);
                // 1 .toString is a valid property access, emit a space after the literal
                // Also emit a space if expression is a integer const enum value - it will appear in generated code as numeric literal
                var shouldEmitSpace;
                if (!indentedBeforeDot) {
                    if (node.expression.kind === 8 /* NumericLiteral */) {
                        // check if numeric literal was originally written with a dot
                        var text = ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, node.expression);
                        shouldEmitSpace = text.indexOf(ts.tokenToString(21 /* DotToken */)) < 0;
                    }
                    else {
                        // check if constant enum value is integer
                        var constantValue = tryGetConstEnumValue(node.expression);
                        // isFinite handles cases when constantValue is undefined
                        shouldEmitSpace = isFinite(constantValue) && Math.floor(constantValue) === constantValue;
                    }
                }
                if (shouldEmitSpace) {
                    write(" .");
                }
                else {
                    write(".");
                }
                var indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name);
                emit(node.name);
                decreaseIndentIf(indentedBeforeDot, indentedAfterDot);
            }
            function emitQualifiedName(node) {
                emit(node.left);
                write(".");
                emit(node.right);
            }
            function emitQualifiedNameAsExpression(node, useFallback) {
                if (node.left.kind === 69 /* Identifier */) {
                    emitEntityNameAsExpression(node.left, useFallback);
                }
                else if (useFallback) {
                    var temp = createAndRecordTempVariable(0 /* Auto */);
                    write("(");
                    emitNodeWithoutSourceMap(temp);
                    write(" = ");
                    emitEntityNameAsExpression(node.left, /*useFallback*/ true);
                    write(") && ");
                    emitNodeWithoutSourceMap(temp);
                }
                else {
                    emitEntityNameAsExpression(node.left, /*useFallback*/ false);
                }
                write(".");
                emit(node.right);
            }
            function emitEntityNameAsExpression(node, useFallback) {
                switch (node.kind) {
                    case 69 /* Identifier */:
                        if (useFallback) {
                            write("typeof ");
                            emitExpressionIdentifier(node);
                            write(" !== 'undefined' && ");
                        }
                        emitExpressionIdentifier(node);
                        break;
                    case 135 /* QualifiedName */:
                        emitQualifiedNameAsExpression(node, useFallback);
                        break;
                }
            }
            function emitIndexedAccess(node) {
                if (tryEmitConstantValue(node)) {
                    return;
                }
                emit(node.expression);
                write("[");
                emit(node.argumentExpression);
                write("]");
            }
            function hasSpreadElement(elements) {
                return ts.forEach(elements, function (e) { return e.kind === 185 /* SpreadElementExpression */; });
            }
            function skipParentheses(node) {
                while (node.kind === 172 /* ParenthesizedExpression */ || node.kind === 171 /* TypeAssertionExpression */ || node.kind === 189 /* AsExpression */) {
                    node = node.expression;
                }
                return node;
            }
            function emitCallTarget(node) {
                if (node.kind === 69 /* Identifier */ || node.kind === 97 /* ThisKeyword */ || node.kind === 95 /* SuperKeyword */) {
                    emit(node);
                    return node;
                }
                var temp = createAndRecordTempVariable(0 /* Auto */);
                write("(");
                emit(temp);
                write(" = ");
                emit(node);
                write(")");
                return temp;
            }
            function emitCallWithSpread(node) {
                var target;
                var expr = skipParentheses(node.expression);
                if (expr.kind === 166 /* PropertyAccessExpression */) {
                    // Target will be emitted as "this" argument
                    target = emitCallTarget(expr.expression);
                    write(".");
                    emit(expr.name);
                }
                else if (expr.kind === 167 /* ElementAccessExpression */) {
                    // Target will be emitted as "this" argument
                    target = emitCallTarget(expr.expression);
                    write("[");
                    emit(expr.argumentExpression);
                    write("]");
                }
                else if (expr.kind === 95 /* SuperKeyword */) {
                    target = expr;
                    write("_super");
                }
                else {
                    emit(node.expression);
                }
                write(".apply(");
                if (target) {
                    if (target.kind === 95 /* SuperKeyword */) {
                        // Calls of form super(...) and super.foo(...)
                        emitThis(target);
                    }
                    else {
                        // Calls of form obj.foo(...)
                        emit(target);
                    }
                }
                else {
                    // Calls of form foo(...)
                    write("void 0");
                }
                write(", ");
                emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*trailingComma*/ false, /*useConcat*/ true);
                write(")");
            }
            function emitCallExpression(node) {
                if (languageVersion < 2 /* ES6 */ && hasSpreadElement(node.arguments)) {
                    emitCallWithSpread(node);
                    return;
                }
                var superCall = false;
                if (node.expression.kind === 95 /* SuperKeyword */) {
                    emitSuper(node.expression);
                    superCall = true;
                }
                else {
                    emit(node.expression);
                    superCall = node.expression.kind === 166 /* PropertyAccessExpression */ && node.expression.expression.kind === 95 /* SuperKeyword */;
                }
                if (superCall && languageVersion < 2 /* ES6 */) {
                    write(".call(");
                    emitThis(node.expression);
                    if (node.arguments.length) {
                        write(", ");
                        emitCommaList(node.arguments);
                    }
                    write(")");
                }
                else {
                    write("(");
                    emitCommaList(node.arguments);
                    write(")");
                }
            }
            function emitNewExpression(node) {
                write("new ");
                // Spread operator logic is supported in new expressions in ES5 using a combination
                // of Function.prototype.bind() and Function.prototype.apply().
                //
                //     Example:
                //
                //         var args = [1, 2, 3, 4, 5];
                //         new Array(...args);
                //
                //     is compiled into the following ES5:
                //
                //         var args = [1, 2, 3, 4, 5];
                //         new (Array.bind.apply(Array, [void 0].concat(args)));
                //
                // The 'thisArg' to 'bind' is ignored when invoking the result of 'bind' with 'new',
                // Thus, we set it to undefined ('void 0').
                if (languageVersion === 1 /* ES5 */ &&
                    node.arguments &&
                    hasSpreadElement(node.arguments)) {
                    write("(");
                    var target = emitCallTarget(node.expression);
                    write(".bind.apply(");
                    emit(target);
                    write(", [void 0].concat(");
                    emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiline*/ false, /*trailingComma*/ false, /*useConcat*/ false);
                    write(")))");
                    write("()");
                }
                else {
                    emit(node.expression);
                    if (node.arguments) {
                        write("(");
                        emitCommaList(node.arguments);
                        write(")");
                    }
                }
            }
            function emitTaggedTemplateExpression(node) {
                if (languageVersion >= 2 /* ES6 */) {
                    emit(node.tag);
                    write(" ");
                    emit(node.template);
                }
                else {
                    emitDownlevelTaggedTemplate(node);
                }
            }
            function emitParenExpression(node) {
                // If the node is synthesized, it means the emitter put the parentheses there,
                // not the user. If we didn't want them, the emitter would not have put them
                // there.
                if (!ts.nodeIsSynthesized(node) && node.parent.kind !== 174 /* ArrowFunction */) {
                    if (node.expression.kind === 171 /* TypeAssertionExpression */ || node.expression.kind === 189 /* AsExpression */) {
                        var operand = node.expression.expression;
                        // Make sure we consider all nested cast expressions, e.g.:
                        // (<any><number><any>-A).x;
                        while (operand.kind === 171 /* TypeAssertionExpression */ || operand.kind === 189 /* AsExpression */) {
                            operand = operand.expression;
                        }
                        // We have an expression of the form: (<Type>SubExpr)
                        // Emitting this as (SubExpr) is really not desirable. We would like to emit the subexpr as is.
                        // Omitting the parentheses, however, could cause change in the semantics of the generated
                        // code if the casted expression has a lower precedence than the rest of the expression, e.g.:
                        //      (<any>new A).foo should be emitted as (new A).foo and not new A.foo
                        //      (<any>typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString()
                        //      new (<any>A()) should be emitted as new (A()) and not new A()
                        //      (<any>function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} ()
                        if (operand.kind !== 179 /* PrefixUnaryExpression */ &&
                            operand.kind !== 177 /* VoidExpression */ &&
                            operand.kind !== 176 /* TypeOfExpression */ &&
                            operand.kind !== 175 /* DeleteExpression */ &&
                            operand.kind !== 180 /* PostfixUnaryExpression */ &&
                            operand.kind !== 169 /* NewExpression */ &&
                            !(operand.kind === 168 /* CallExpression */ && node.parent.kind === 169 /* NewExpression */) &&
                            !(operand.kind === 173 /* FunctionExpression */ && node.parent.kind === 168 /* CallExpression */) &&
                            !(operand.kind === 8 /* NumericLiteral */ && node.parent.kind === 166 /* PropertyAccessExpression */)) {
                            emit(operand);
                            return;
                        }
                    }
                }
                write("(");
                emit(node.expression);
                write(")");
            }
            function emitDeleteExpression(node) {
                write(ts.tokenToString(78 /* DeleteKeyword */));
                write(" ");
                emit(node.expression);
            }
            function emitVoidExpression(node) {
                write(ts.tokenToString(103 /* VoidKeyword */));
                write(" ");
                emit(node.expression);
            }
            function emitTypeOfExpression(node) {
                write(ts.tokenToString(101 /* TypeOfKeyword */));
                write(" ");
                emit(node.expression);
            }
            function isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node) {
                if (!isCurrentFileSystemExternalModule() || node.kind !== 69 /* Identifier */ || ts.nodeIsSynthesized(node)) {
                    return false;
                }
                var isVariableDeclarationOrBindingElement = node.parent && (node.parent.kind === 211 /* VariableDeclaration */ || node.parent.kind === 163 /* BindingElement */);
                var targetDeclaration = isVariableDeclarationOrBindingElement
                    ? node.parent
                    : resolver.getReferencedValueDeclaration(node);
                return isSourceFileLevelDeclarationInSystemJsModule(targetDeclaration, /*isExported*/ true);
            }
            function emitPrefixUnaryExpression(node) {
                var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
                if (exportChanged) {
                    // emit
                    // ++x
                    // as
                    // exports('x', ++x)
                    write(exportFunctionForFile + "(\"");
                    emitNodeWithoutSourceMap(node.operand);
                    write("\", ");
                }
                write(ts.tokenToString(node.operator));
                // In some cases, we need to emit a space between the operator and the operand. One obvious case
                // is when the operator is an identifier, like delete or typeof. We also need to do this for plus
                // and minus expressions in certain cases. Specifically, consider the following two cases (parens
                // are just for clarity of exposition, and not part of the source code):
                //
                //  (+(+1))
                //  (+(++1))
                //
                // We need to emit a space in both cases. In the first case, the absence of a space will make
                // the resulting expression a prefix increment operation. And in the second, it will make the resulting
                // expression a prefix increment whose operand is a plus expression - (++(+x))
                // The same is true of minus of course.
                if (node.operand.kind === 179 /* PrefixUnaryExpression */) {
                    var operand = node.operand;
                    if (node.operator === 35 /* PlusToken */ && (operand.operator === 35 /* PlusToken */ || operand.operator === 41 /* PlusPlusToken */)) {
                        write(" ");
                    }
                    else if (node.operator === 36 /* MinusToken */ && (operand.operator === 36 /* MinusToken */ || operand.operator === 42 /* MinusMinusToken */)) {
                        write(" ");
                    }
                }
                emit(node.operand);
                if (exportChanged) {
                    write(")");
                }
            }
            function emitPostfixUnaryExpression(node) {
                var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
                if (exportChanged) {
                    // export function returns the value that was passes as the second argument
                    // however for postfix unary expressions result value should be the value before modification.
                    // emit 'x++' as '(export('x', ++x) - 1)' and 'x--' as '(export('x', --x) + 1)'
                    write("(" + exportFunctionForFile + "(\"");
                    emitNodeWithoutSourceMap(node.operand);
                    write("\", ");
                    write(ts.tokenToString(node.operator));
                    emit(node.operand);
                    if (node.operator === 41 /* PlusPlusToken */) {
                        write(") - 1)");
                    }
                    else {
                        write(") + 1)");
                    }
                }
                else {
                    emit(node.operand);
                    write(ts.tokenToString(node.operator));
                }
            }
            function shouldHoistDeclarationInSystemJsModule(node) {
                return isSourceFileLevelDeclarationInSystemJsModule(node, /*isExported*/ false);
            }
            /*
             * Checks if given node is a source file level declaration (not nested in module/function).
             * If 'isExported' is true - then declaration must also be exported.
             * This function is used in two cases:
             * - check if node is a exported source file level value to determine
             *   if we should also export the value after its it changed
             * - check if node is a source level declaration to emit it differently,
             *   i.e non-exported variable statement 'var x = 1' is hoisted so
             *   we we emit variable statement 'var' should be dropped.
             */
            function isSourceFileLevelDeclarationInSystemJsModule(node, isExported) {
                if (!node || languageVersion >= 2 /* ES6 */ || !isCurrentFileSystemExternalModule()) {
                    return false;
                }
                var current = node;
                while (current) {
                    if (current.kind === 248 /* SourceFile */) {
                        return !isExported || ((ts.getCombinedNodeFlags(node) & 1 /* Export */) !== 0);
                    }
                    else if (ts.isFunctionLike(current) || current.kind === 219 /* ModuleBlock */) {
                        return false;
                    }
                    else {
                        current = current.parent;
                    }
                }
            }
            /**
             * Emit ES7 exponentiation operator downlevel using Math.pow
             * @param node a binary expression node containing exponentiationOperator (**, **=)
             */
            function emitExponentiationOperator(node) {
                var leftHandSideExpression = node.left;
                if (node.operatorToken.kind === 60 /* AsteriskAsteriskEqualsToken */) {
                    var synthesizedLHS;
                    var shouldEmitParentheses = false;
                    if (ts.isElementAccessExpression(leftHandSideExpression)) {
                        shouldEmitParentheses = true;
                        write("(");
                        synthesizedLHS = ts.createSynthesizedNode(167 /* ElementAccessExpression */, /*startsOnNewLine*/ false);
                        var identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldEmitCommaBeforeAssignment*/ false);
                        synthesizedLHS.expression = identifier;
                        if (leftHandSideExpression.argumentExpression.kind !== 8 /* NumericLiteral */ &&
                            leftHandSideExpression.argumentExpression.kind !== 9 /* StringLiteral */) {
                            var tempArgumentExpression = createAndRecordTempVariable(268435456 /* _i */);
                            synthesizedLHS.argumentExpression = tempArgumentExpression;
                            emitAssignment(tempArgumentExpression, leftHandSideExpression.argumentExpression, /*shouldEmitCommaBeforeAssignment*/ true);
                        }
                        else {
                            synthesizedLHS.argumentExpression = leftHandSideExpression.argumentExpression;
                        }
                        write(", ");
                    }
                    else if (ts.isPropertyAccessExpression(leftHandSideExpression)) {
                        shouldEmitParentheses = true;
                        write("(");
                        synthesizedLHS = ts.createSynthesizedNode(166 /* PropertyAccessExpression */, /*startsOnNewLine*/ false);
                        var identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldemitCommaBeforeAssignment*/ false);
                        synthesizedLHS.expression = identifier;
                        synthesizedLHS.dotToken = leftHandSideExpression.dotToken;
                        synthesizedLHS.name = leftHandSideExpression.name;
                        write(", ");
                    }
                    emit(synthesizedLHS || leftHandSideExpression);
                    write(" = ");
                    write("Math.pow(");
                    emit(synthesizedLHS || leftHandSideExpression);
                    write(", ");
                    emit(node.right);
                    write(")");
                    if (shouldEmitParentheses) {
                        write(")");
                    }
                }
                else {
                    write("Math.pow(");
                    emit(leftHandSideExpression);
                    write(", ");
                    emit(node.right);
                    write(")");
                }
            }
            function emitBinaryExpression(node) {
                if (languageVersion < 2 /* ES6 */ && node.operatorToken.kind === 56 /* EqualsToken */ &&
                    (node.left.kind === 165 /* ObjectLiteralExpression */ || node.left.kind === 164 /* ArrayLiteralExpression */)) {
                    emitDestructuring(node, node.parent.kind === 195 /* ExpressionStatement */);
                }
                else {
                    var exportChanged = node.operatorToken.kind >= 56 /* FirstAssignment */ &&
                        node.operatorToken.kind <= 68 /* LastAssignment */ &&
                        isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left);
                    if (exportChanged) {
                        // emit assignment 'x <op> y' as 'exports("x", x <op> y)'
                        write(exportFunctionForFile + "(\"");
                        emitNodeWithoutSourceMap(node.left);
                        write("\", ");
                    }
                    if (node.operatorToken.kind === 38 /* AsteriskAsteriskToken */ || node.operatorToken.kind === 60 /* AsteriskAsteriskEqualsToken */) {
                        // Downleveled emit exponentiation operator using Math.pow
                        emitExponentiationOperator(node);
                    }
                    else {
                        emit(node.left);
                        // Add indentation before emit the operator if the operator is on different line
                        // For example:
                        //      3
                        //      + 2;
                        //   emitted as
                        //      3
                        //          + 2;
                        var indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== 24 /* CommaToken */ ? " " : undefined);
                        write(ts.tokenToString(node.operatorToken.kind));
                        var indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " ");
                        emit(node.right);
                        decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
                    }
                    if (exportChanged) {
                        write(")");
                    }
                }
            }
            function synthesizedNodeStartsOnNewLine(node) {
                return ts.nodeIsSynthesized(node) && node.startsOnNewLine;
            }
            function emitConditionalExpression(node) {
                emit(node.condition);
                var indentedBeforeQuestion = indentIfOnDifferentLines(node, node.condition, node.questionToken, " ");
                write("?");
                var indentedAfterQuestion = indentIfOnDifferentLines(node, node.questionToken, node.whenTrue, " ");
                emit(node.whenTrue);
                decreaseIndentIf(indentedBeforeQuestion, indentedAfterQuestion);
                var indentedBeforeColon = indentIfOnDifferentLines(node, node.whenTrue, node.colonToken, " ");
                write(":");
                var indentedAfterColon = indentIfOnDifferentLines(node, node.colonToken, node.whenFalse, " ");
                emit(node.whenFalse);
                decreaseIndentIf(indentedBeforeColon, indentedAfterColon);
            }
            // Helper function to decrease the indent if we previously indented.  Allows multiple
            // previous indent values to be considered at a time.  This also allows caller to just
            // call this once, passing in all their appropriate indent values, instead of needing
            // to call this helper function multiple times.
            function decreaseIndentIf(value1, value2) {
                if (value1) {
                    decreaseIndent();
                }
                if (value2) {
                    decreaseIndent();
                }
            }
            function isSingleLineEmptyBlock(node) {
                if (node && node.kind === 192 /* Block */) {
                    var block = node;
                    return block.statements.length === 0 && nodeEndIsOnSameLineAsNodeStart(block, block);
                }
            }
            function emitBlock(node) {
                if (isSingleLineEmptyBlock(node)) {
                    emitToken(15 /* OpenBraceToken */, node.pos);
                    write(" ");
                    emitToken(16 /* CloseBraceToken */, node.statements.end);
                    return;
                }
                emitToken(15 /* OpenBraceToken */, node.pos);
                increaseIndent();
                scopeEmitStart(node.parent);
                if (node.kind === 219 /* ModuleBlock */) {
                    ts.Debug.assert(node.parent.kind === 218 /* ModuleDeclaration */);
                    emitCaptureThisForNodeIfNecessary(node.parent);
                }
                emitLines(node.statements);
                if (node.kind === 219 /* ModuleBlock */) {
                    emitTempDeclarations(/*newLine*/ true);
                }
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.statements.end);
                scopeEmitEnd();
            }
            function emitEmbeddedStatement(node) {
                if (node.kind === 192 /* Block */) {
                    write(" ");
                    emit(node);
                }
                else {
                    increaseIndent();
                    writeLine();
                    emit(node);
                    decreaseIndent();
                }
            }
            function emitExpressionStatement(node) {
                emitParenthesizedIf(node.expression, /*parenthesized*/ node.expression.kind === 174 /* ArrowFunction */);
                write(";");
            }
            function emitIfStatement(node) {
                var endPos = emitToken(88 /* IfKeyword */, node.pos);
                write(" ");
                endPos = emitToken(17 /* OpenParenToken */, endPos);
                emit(node.expression);
                emitToken(18 /* CloseParenToken */, node.expression.end);
                emitEmbeddedStatement(node.thenStatement);
                if (node.elseStatement) {
                    writeLine();
                    emitToken(80 /* ElseKeyword */, node.thenStatement.end);
                    if (node.elseStatement.kind === 196 /* IfStatement */) {
                        write(" ");
                        emit(node.elseStatement);
                    }
                    else {
                        emitEmbeddedStatement(node.elseStatement);
                    }
                }
            }
            function emitDoStatement(node) {
                write("do");
                emitEmbeddedStatement(node.statement);
                if (node.statement.kind === 192 /* Block */) {
                    write(" ");
                }
                else {
                    writeLine();
                }
                write("while (");
                emit(node.expression);
                write(");");
            }
            function emitWhileStatement(node) {
                write("while (");
                emit(node.expression);
                write(")");
                emitEmbeddedStatement(node.statement);
            }
            /**
             * Returns true if start of variable declaration list was emitted.
             * Returns false if nothing was written - this can happen for source file level variable declarations
             *     in system modules where such variable declarations are hoisted.
             */
            function tryEmitStartOfVariableDeclarationList(decl, startPos) {
                if (shouldHoistVariable(decl, /*checkIfSourceFileLevelDecl*/ true)) {
                    // variables in variable declaration list were already hoisted
                    return false;
                }
                var tokenKind = 102 /* VarKeyword */;
                if (decl && languageVersion >= 2 /* ES6 */) {
                    if (ts.isLet(decl)) {
                        tokenKind = 108 /* LetKeyword */;
                    }
                    else if (ts.isConst(decl)) {
                        tokenKind = 74 /* ConstKeyword */;
                    }
                }
                if (startPos !== undefined) {
                    emitToken(tokenKind, startPos);
                    write(" ");
                }
                else {
                    switch (tokenKind) {
                        case 102 /* VarKeyword */:
                            write("var ");
                            break;
                        case 108 /* LetKeyword */:
                            write("let ");
                            break;
                        case 74 /* ConstKeyword */:
                            write("const ");
                            break;
                    }
                }
                return true;
            }
            function emitVariableDeclarationListSkippingUninitializedEntries(list) {
                var started = false;
                for (var _a = 0, _b = list.declarations; _a < _b.length; _a++) {
                    var decl = _b[_a];
                    if (!decl.initializer) {
                        continue;
                    }
                    if (!started) {
                        started = true;
                    }
                    else {
                        write(", ");
                    }
                    emit(decl);
                }
                return started;
            }
            function emitForStatement(node) {
                var endPos = emitToken(86 /* ForKeyword */, node.pos);
                write(" ");
                endPos = emitToken(17 /* OpenParenToken */, endPos);
                if (node.initializer && node.initializer.kind === 212 /* VariableDeclarationList */) {
                    var variableDeclarationList = node.initializer;
                    var startIsEmitted = tryEmitStartOfVariableDeclarationList(variableDeclarationList, endPos);
                    if (startIsEmitted) {
                        emitCommaList(variableDeclarationList.declarations);
                    }
                    else {
                        emitVariableDeclarationListSkippingUninitializedEntries(variableDeclarationList);
                    }
                }
                else if (node.initializer) {
                    emit(node.initializer);
                }
                write(";");
                emitOptional(" ", node.condition);
                write(";");
                emitOptional(" ", node.incrementor);
                write(")");
                emitEmbeddedStatement(node.statement);
            }
            function emitForInOrForOfStatement(node) {
                if (languageVersion < 2 /* ES6 */ && node.kind === 201 /* ForOfStatement */) {
                    return emitDownLevelForOfStatement(node);
                }
                var endPos = emitToken(86 /* ForKeyword */, node.pos);
                write(" ");
                endPos = emitToken(17 /* OpenParenToken */, endPos);
                if (node.initializer.kind === 212 /* VariableDeclarationList */) {
                    var variableDeclarationList = node.initializer;
                    if (variableDeclarationList.declarations.length >= 1) {
                        tryEmitStartOfVariableDeclarationList(variableDeclarationList, endPos);
                        emit(variableDeclarationList.declarations[0]);
                    }
                }
                else {
                    emit(node.initializer);
                }
                if (node.kind === 200 /* ForInStatement */) {
                    write(" in ");
                }
                else {
                    write(" of ");
                }
                emit(node.expression);
                emitToken(18 /* CloseParenToken */, node.expression.end);
                emitEmbeddedStatement(node.statement);
            }
            function emitDownLevelForOfStatement(node) {
                // The following ES6 code:
                //
                //    for (let v of expr) { }
                //
                // should be emitted as
                //
                //    for (let _i = 0, _a = expr; _i < _a.length; _i++) {
                //        let v = _a[_i];
                //    }
                //
                // where _a and _i are temps emitted to capture the RHS and the counter,
                // respectively.
                // When the left hand side is an expression instead of a let declaration,
                // the "let v" is not emitted.
                // When the left hand side is a let/const, the v is renamed if there is
                // another v in scope.
                // Note that all assignments to the LHS are emitted in the body, including
                // all destructuring.
                // Note also that because an extra statement is needed to assign to the LHS,
                // for-of bodies are always emitted as blocks.
                var endPos = emitToken(86 /* ForKeyword */, node.pos);
                write(" ");
                endPos = emitToken(17 /* OpenParenToken */, endPos);
                // Do not emit the LHS let declaration yet, because it might contain destructuring.
                // Do not call recordTempDeclaration because we are declaring the temps
                // right here. Recording means they will be declared later.
                // In the case where the user wrote an identifier as the RHS, like this:
                //
                //     for (let v of arr) { }
                //
                // we don't want to emit a temporary variable for the RHS, just use it directly.
                var rhsIsIdentifier = node.expression.kind === 69 /* Identifier */;
                var counter = createTempVariable(268435456 /* _i */);
                var rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(0 /* Auto */);
                // This is the let keyword for the counter and rhsReference. The let keyword for
                // the LHS will be emitted inside the body.
                emitStart(node.expression);
                write("var ");
                // _i = 0
                emitNodeWithoutSourceMap(counter);
                write(" = 0");
                emitEnd(node.expression);
                if (!rhsIsIdentifier) {
                    // , _a = expr
                    write(", ");
                    emitStart(node.expression);
                    emitNodeWithoutSourceMap(rhsReference);
                    write(" = ");
                    emitNodeWithoutSourceMap(node.expression);
                    emitEnd(node.expression);
                }
                write("; ");
                // _i < _a.length;
                emitStart(node.initializer);
                emitNodeWithoutSourceMap(counter);
                write(" < ");
                emitNodeWithCommentsAndWithoutSourcemap(rhsReference);
                write(".length");
                emitEnd(node.initializer);
                write("; ");
                // _i++)
                emitStart(node.initializer);
                emitNodeWithoutSourceMap(counter);
                write("++");
                emitEnd(node.initializer);
                emitToken(18 /* CloseParenToken */, node.expression.end);
                // Body
                write(" {");
                writeLine();
                increaseIndent();
                // Initialize LHS
                // let v = _a[_i];
                var rhsIterationValue = createElementAccessExpression(rhsReference, counter);
                emitStart(node.initializer);
                if (node.initializer.kind === 212 /* VariableDeclarationList */) {
                    write("var ");
                    var variableDeclarationList = node.initializer;
                    if (variableDeclarationList.declarations.length > 0) {
                        var declaration = variableDeclarationList.declarations[0];
                        if (ts.isBindingPattern(declaration.name)) {
                            // This works whether the declaration is a var, let, or const.
                            // It will use rhsIterationValue _a[_i] as the initializer.
                            emitDestructuring(declaration, /*isAssignmentExpressionStatement*/ false, rhsIterationValue);
                        }
                        else {
                            // The following call does not include the initializer, so we have
                            // to emit it separately.
                            emitNodeWithCommentsAndWithoutSourcemap(declaration);
                            write(" = ");
                            emitNodeWithoutSourceMap(rhsIterationValue);
                        }
                    }
                    else {
                        // It's an empty declaration list. This can only happen in an error case, if the user wrote
                        //     for (let of []) {}
                        emitNodeWithoutSourceMap(createTempVariable(0 /* Auto */));
                        write(" = ");
                        emitNodeWithoutSourceMap(rhsIterationValue);
                    }
                }
                else {
                    // Initializer is an expression. Emit the expression in the body, so that it's
                    // evaluated on every iteration.
                    var assignmentExpression = createBinaryExpression(node.initializer, 56 /* EqualsToken */, rhsIterationValue, /*startsOnNewLine*/ false);
                    if (node.initializer.kind === 164 /* ArrayLiteralExpression */ || node.initializer.kind === 165 /* ObjectLiteralExpression */) {
                        // This is a destructuring pattern, so call emitDestructuring instead of emit. Calling emit will not work, because it will cause
                        // the BinaryExpression to be passed in instead of the expression statement, which will cause emitDestructuring to crash.
                        emitDestructuring(assignmentExpression, /*isAssignmentExpressionStatement*/ true, /*value*/ undefined);
                    }
                    else {
                        emitNodeWithCommentsAndWithoutSourcemap(assignmentExpression);
                    }
                }
                emitEnd(node.initializer);
                write(";");
                if (node.statement.kind === 192 /* Block */) {
                    emitLines(node.statement.statements);
                }
                else {
                    writeLine();
                    emit(node.statement);
                }
                writeLine();
                decreaseIndent();
                write("}");
            }
            function emitBreakOrContinueStatement(node) {
                emitToken(node.kind === 203 /* BreakStatement */ ? 70 /* BreakKeyword */ : 75 /* ContinueKeyword */, node.pos);
                emitOptional(" ", node.label);
                write(";");
            }
            function emitReturnStatement(node) {
                emitToken(94 /* ReturnKeyword */, node.pos);
                emitOptional(" ", node.expression);
                write(";");
            }
            function emitWithStatement(node) {
                write("with (");
                emit(node.expression);
                write(")");
                emitEmbeddedStatement(node.statement);
            }
            function emitSwitchStatement(node) {
                var endPos = emitToken(96 /* SwitchKeyword */, node.pos);
                write(" ");
                emitToken(17 /* OpenParenToken */, endPos);
                emit(node.expression);
                endPos = emitToken(18 /* CloseParenToken */, node.expression.end);
                write(" ");
                emitCaseBlock(node.caseBlock, endPos);
            }
            function emitCaseBlock(node, startPos) {
                emitToken(15 /* OpenBraceToken */, startPos);
                increaseIndent();
                emitLines(node.clauses);
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.clauses.end);
            }
            function nodeStartPositionsAreOnSameLine(node1, node2) {
                return ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node1.pos)) ===
                    ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node2.pos));
            }
            function nodeEndPositionsAreOnSameLine(node1, node2) {
                return ts.getLineOfLocalPosition(currentSourceFile, node1.end) ===
                    ts.getLineOfLocalPosition(currentSourceFile, node2.end);
            }
            function nodeEndIsOnSameLineAsNodeStart(node1, node2) {
                return ts.getLineOfLocalPosition(currentSourceFile, node1.end) ===
                    ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node2.pos));
            }
            function emitCaseOrDefaultClause(node) {
                if (node.kind === 241 /* CaseClause */) {
                    write("case ");
                    emit(node.expression);
                    write(":");
                }
                else {
                    write("default:");
                }
                if (node.statements.length === 1 && nodeStartPositionsAreOnSameLine(node, node.statements[0])) {
                    write(" ");
                    emit(node.statements[0]);
                }
                else {
                    increaseIndent();
                    emitLines(node.statements);
                    decreaseIndent();
                }
            }
            function emitThrowStatement(node) {
                write("throw ");
                emit(node.expression);
                write(";");
            }
            function emitTryStatement(node) {
                write("try ");
                emit(node.tryBlock);
                emit(node.catchClause);
                if (node.finallyBlock) {
                    writeLine();
                    write("finally ");
                    emit(node.finallyBlock);
                }
            }
            function emitCatchClause(node) {
                writeLine();
                var endPos = emitToken(72 /* CatchKeyword */, node.pos);
                write(" ");
                emitToken(17 /* OpenParenToken */, endPos);
                emit(node.variableDeclaration);
                emitToken(18 /* CloseParenToken */, node.variableDeclaration ? node.variableDeclaration.end : endPos);
                write(" ");
                emitBlock(node.block);
            }
            function emitDebuggerStatement(node) {
                emitToken(76 /* DebuggerKeyword */, node.pos);
                write(";");
            }
            function emitLabelledStatement(node) {
                emit(node.label);
                write(": ");
                emit(node.statement);
            }
            function getContainingModule(node) {
                do {
                    node = node.parent;
                } while (node && node.kind !== 218 /* ModuleDeclaration */);
                return node;
            }
            function emitContainingModuleName(node) {
                var container = getContainingModule(node);
                write(container ? getGeneratedNameForNode(container) : "exports");
            }
            function emitModuleMemberName(node) {
                emitStart(node.name);
                if (ts.getCombinedNodeFlags(node) & 1 /* Export */) {
                    var container = getContainingModule(node);
                    if (container) {
                        write(getGeneratedNameForNode(container));
                        write(".");
                    }
                    else if (modulekind !== 5 /* ES6 */ && modulekind !== 4 /* System */) {
                        write("exports.");
                    }
                }
                emitNodeWithCommentsAndWithoutSourcemap(node.name);
                emitEnd(node.name);
            }
            function createVoidZero() {
                var zero = ts.createSynthesizedNode(8 /* NumericLiteral */);
                zero.text = "0";
                var result = ts.createSynthesizedNode(177 /* VoidExpression */);
                result.expression = zero;
                return result;
            }
            function emitEs6ExportDefaultCompat(node) {
                if (node.parent.kind === 248 /* SourceFile */) {
                    ts.Debug.assert(!!(node.flags & 1024 /* Default */) || node.kind === 227 /* ExportAssignment */);
                    // only allow export default at a source file level
                    if (modulekind === 1 /* CommonJS */ || modulekind === 2 /* AMD */ || modulekind === 3 /* UMD */) {
                        if (!currentSourceFile.symbol.exports["___esModule"]) {
                            if (languageVersion === 1 /* ES5 */) {
                                // default value of configurable, enumerable, writable are `false`.
                                write("Object.defineProperty(exports, \"__esModule\", { value: true });");
                                writeLine();
                            }
                            else if (languageVersion === 0 /* ES3 */) {
                                write("exports.__esModule = true;");
                                writeLine();
                            }
                        }
                    }
                }
            }
            function emitExportMemberAssignment(node) {
                if (node.flags & 1 /* Export */) {
                    writeLine();
                    emitStart(node);
                    // emit call to exporter only for top level nodes
                    if (modulekind === 4 /* System */ && node.parent === currentSourceFile) {
                        // emit export default <smth> as
                        // export("default", <smth>)
                        write(exportFunctionForFile + "(\"");
                        if (node.flags & 1024 /* Default */) {
                            write("default");
                        }
                        else {
                            emitNodeWithCommentsAndWithoutSourcemap(node.name);
                        }
                        write("\", ");
                        emitDeclarationName(node);
                        write(")");
                    }
                    else {
                        if (node.flags & 1024 /* Default */) {
                            emitEs6ExportDefaultCompat(node);
                            if (languageVersion === 0 /* ES3 */) {
                                write("exports[\"default\"]");
                            }
                            else {
                                write("exports.default");
                            }
                        }
                        else {
                            emitModuleMemberName(node);
                        }
                        write(" = ");
                        emitDeclarationName(node);
                    }
                    emitEnd(node);
                    write(";");
                }
            }
            function emitExportMemberAssignments(name) {
                if (modulekind === 4 /* System */) {
                    return;
                }
                if (!exportEquals && exportSpecifiers && ts.hasProperty(exportSpecifiers, name.text)) {
                    for (var _a = 0, _b = exportSpecifiers[name.text]; _a < _b.length; _a++) {
                        var specifier = _b[_a];
                        writeLine();
                        emitStart(specifier.name);
                        emitContainingModuleName(specifier);
                        write(".");
                        emitNodeWithCommentsAndWithoutSourcemap(specifier.name);
                        emitEnd(specifier.name);
                        write(" = ");
                        emitExpressionIdentifier(name);
                        write(";");
                    }
                }
            }
            function emitExportSpecifierInSystemModule(specifier) {
                ts.Debug.assert(modulekind === 4 /* System */);
                if (!resolver.getReferencedValueDeclaration(specifier.propertyName || specifier.name) && !resolver.isValueAliasDeclaration(specifier)) {
                    return;
                }
                writeLine();
                emitStart(specifier.name);
                write(exportFunctionForFile + "(\"");
                emitNodeWithCommentsAndWithoutSourcemap(specifier.name);
                write("\", ");
                emitExpressionIdentifier(specifier.propertyName || specifier.name);
                write(")");
                emitEnd(specifier.name);
                write(";");
            }
            /**
             * Emit an assignment to a given identifier, 'name', with a given expression, 'value'.
             * @param name an identifier as a left-hand-side operand of the assignment
             * @param value an expression as a right-hand-side operand of the assignment
             * @param shouldEmitCommaBeforeAssignment a boolean indicating whether to prefix an assignment with comma
             */
            function emitAssignment(name, value, shouldEmitCommaBeforeAssignment) {
                if (shouldEmitCommaBeforeAssignment) {
                    write(", ");
                }
                var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name);
                if (exportChanged) {
                    write(exportFunctionForFile + "(\"");
                    emitNodeWithCommentsAndWithoutSourcemap(name);
                    write("\", ");
                }
                var isVariableDeclarationOrBindingElement = name.parent && (name.parent.kind === 211 /* VariableDeclaration */ || name.parent.kind === 163 /* BindingElement */);
                if (isVariableDeclarationOrBindingElement) {
                    emitModuleMemberName(name.parent);
                }
                else {
                    emit(name);
                }
                write(" = ");
                emit(value);
                if (exportChanged) {
                    write(")");
                }
            }
            /**
             * Create temporary variable, emit an assignment of the variable the given expression
             * @param expression an expression to assign to the newly created temporary variable
             * @param canDefineTempVariablesInPlace a boolean indicating whether you can define the temporary variable at an assignment location
             * @param shouldEmitCommaBeforeAssignment a boolean indicating whether an assignment should prefix with comma
             */
            function emitTempVariableAssignment(expression, canDefineTempVariablesInPlace, shouldEmitCommaBeforeAssignment) {
                var identifier = createTempVariable(0 /* Auto */);
                if (!canDefineTempVariablesInPlace) {
                    recordTempDeclaration(identifier);
                }
                emitAssignment(identifier, expression, shouldEmitCommaBeforeAssignment);
                return identifier;
            }
            function emitDestructuring(root, isAssignmentExpressionStatement, value) {
                var emitCount = 0;
                // An exported declaration is actually emitted as an assignment (to a property on the module object), so
                // temporary variables in an exported declaration need to have real declarations elsewhere
                // Also temporary variables should be explicitly allocated for source level declarations when module target is system
                // because actual variable declarations are hoisted
                var canDefineTempVariablesInPlace = false;
                if (root.kind === 211 /* VariableDeclaration */) {
                    var isExported = ts.getCombinedNodeFlags(root) & 1 /* Export */;
                    var isSourceLevelForSystemModuleKind = shouldHoistDeclarationInSystemJsModule(root);
                    canDefineTempVariablesInPlace = !isExported && !isSourceLevelForSystemModuleKind;
                }
                else if (root.kind === 138 /* Parameter */) {
                    canDefineTempVariablesInPlace = true;
                }
                if (root.kind === 181 /* BinaryExpression */) {
                    emitAssignmentExpression(root);
                }
                else {
                    ts.Debug.assert(!isAssignmentExpressionStatement);
                    emitBindingElement(root, value);
                }
                /**
                 * Ensures that there exists a declared identifier whose value holds the given expression.
                 * This function is useful to ensure that the expression's value can be read from in subsequent expressions.
                 * Unless 'reuseIdentifierExpressions' is false, 'expr' will be returned if it is just an identifier.
                 *
                 * @param expr the expression whose value needs to be bound.
                 * @param reuseIdentifierExpressions true if identifier expressions can simply be returned;
                 *                                   false if it is necessary to always emit an identifier.
                 */
                function ensureIdentifier(expr, reuseIdentifierExpressions) {
                    if (expr.kind === 69 /* Identifier */ && reuseIdentifierExpressions) {
                        return expr;
                    }
                    var identifier = emitTempVariableAssignment(expr, canDefineTempVariablesInPlace, emitCount > 0);
                    emitCount++;
                    return identifier;
                }
                function createDefaultValueCheck(value, defaultValue) {
                    // The value expression will be evaluated twice, so for anything but a simple identifier
                    // we need to generate a temporary variable
                    value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true);
                    // Return the expression 'value === void 0 ? defaultValue : value'
                    var equals = ts.createSynthesizedNode(181 /* BinaryExpression */);
                    equals.left = value;
                    equals.operatorToken = ts.createSynthesizedNode(32 /* EqualsEqualsEqualsToken */);
                    equals.right = createVoidZero();
                    return createConditionalExpression(equals, defaultValue, value);
                }
                function createConditionalExpression(condition, whenTrue, whenFalse) {
                    var cond = ts.createSynthesizedNode(182 /* ConditionalExpression */);
                    cond.condition = condition;
                    cond.questionToken = ts.createSynthesizedNode(53 /* QuestionToken */);
                    cond.whenTrue = whenTrue;
                    cond.colonToken = ts.createSynthesizedNode(54 /* ColonToken */);
                    cond.whenFalse = whenFalse;
                    return cond;
                }
                function createNumericLiteral(value) {
                    var node = ts.createSynthesizedNode(8 /* NumericLiteral */);
                    node.text = "" + value;
                    return node;
                }
                function createPropertyAccessForDestructuringProperty(object, propName) {
                    // We create a synthetic copy of the identifier in order to avoid the rewriting that might
                    // otherwise occur when the identifier is emitted.
                    var syntheticName = ts.createSynthesizedNode(propName.kind);
                    syntheticName.text = propName.text;
                    if (syntheticName.kind !== 69 /* Identifier */) {
                        return createElementAccessExpression(object, syntheticName);
                    }
                    return createPropertyAccessExpression(object, syntheticName);
                }
                function createSliceCall(value, sliceIndex) {
                    var call = ts.createSynthesizedNode(168 /* CallExpression */);
                    var sliceIdentifier = ts.createSynthesizedNode(69 /* Identifier */);
                    sliceIdentifier.text = "slice";
                    call.expression = createPropertyAccessExpression(value, sliceIdentifier);
                    call.arguments = ts.createSynthesizedNodeArray();
                    call.arguments[0] = createNumericLiteral(sliceIndex);
                    return call;
                }
                function emitObjectLiteralAssignment(target, value) {
                    var properties = target.properties;
                    if (properties.length !== 1) {
                        // For anything but a single element destructuring we need to generate a temporary
                        // to ensure value is evaluated exactly once.
                        value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true);
                    }
                    for (var _a = 0; _a < properties.length; _a++) {
                        var p = properties[_a];
                        if (p.kind === 245 /* PropertyAssignment */ || p.kind === 246 /* ShorthandPropertyAssignment */) {
                            var propName = p.name;
                            var target_1 = p.kind === 246 /* ShorthandPropertyAssignment */ ? p : p.initializer || propName;
                            emitDestructuringAssignment(target_1, createPropertyAccessForDestructuringProperty(value, propName));
                        }
                    }
                }
                function emitArrayLiteralAssignment(target, value) {
                    var elements = target.elements;
                    if (elements.length !== 1) {
                        // For anything but a single element destructuring we need to generate a temporary
                        // to ensure value is evaluated exactly once.
                        value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true);
                    }
                    for (var i = 0; i < elements.length; i++) {
                        var e = elements[i];
                        if (e.kind !== 187 /* OmittedExpression */) {
                            if (e.kind !== 185 /* SpreadElementExpression */) {
                                emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i)));
                            }
                            else if (i === elements.length - 1) {
                                emitDestructuringAssignment(e.expression, createSliceCall(value, i));
                            }
                        }
                    }
                }
                function emitDestructuringAssignment(target, value) {
                    if (target.kind === 246 /* ShorthandPropertyAssignment */) {
                        if (target.objectAssignmentInitializer) {
                            value = createDefaultValueCheck(value, target.objectAssignmentInitializer);
                        }
                        target = target.name;
                    }
                    else if (target.kind === 181 /* BinaryExpression */ && target.operatorToken.kind === 56 /* EqualsToken */) {
                        value = createDefaultValueCheck(value, target.right);
                        target = target.left;
                    }
                    if (target.kind === 165 /* ObjectLiteralExpression */) {
                        emitObjectLiteralAssignment(target, value);
                    }
                    else if (target.kind === 164 /* ArrayLiteralExpression */) {
                        emitArrayLiteralAssignment(target, value);
                    }
                    else {
                        emitAssignment(target, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0);
                        emitCount++;
                    }
                }
                function emitAssignmentExpression(root) {
                    var target = root.left;
                    var value = root.right;
                    if (ts.isEmptyObjectLiteralOrArrayLiteral(target)) {
                        emit(value);
                    }
                    else if (isAssignmentExpressionStatement) {
                        emitDestructuringAssignment(target, value);
                    }
                    else {
                        if (root.parent.kind !== 172 /* ParenthesizedExpression */) {
                            write("(");
                        }
                        value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true);
                        emitDestructuringAssignment(target, value);
                        write(", ");
                        emit(value);
                        if (root.parent.kind !== 172 /* ParenthesizedExpression */) {
                            write(")");
                        }
                    }
                }
                function emitBindingElement(target, value) {
                    if (target.initializer) {
                        // Combine value and initializer
                        value = value ? createDefaultValueCheck(value, target.initializer) : target.initializer;
                    }
                    else if (!value) {
                        // Use 'void 0' in absence of value and initializer
                        value = createVoidZero();
                    }
                    if (ts.isBindingPattern(target.name)) {
                        var pattern = target.name;
                        var elements = pattern.elements;
                        var numElements = elements.length;
                        if (numElements !== 1) {
                            // For anything other than a single-element destructuring we need to generate a temporary
                            // to ensure value is evaluated exactly once. Additionally, if we have zero elements
                            // we need to emit *something* to ensure that in case a 'var' keyword was already emitted,
                            // so in that case, we'll intentionally create that temporary.
                            value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0);
                        }
                        for (var i = 0; i < numElements; i++) {
                            var element = elements[i];
                            if (pattern.kind === 161 /* ObjectBindingPattern */) {
                                // Rewrite element to a declaration with an initializer that fetches property
                                var propName = element.propertyName || element.name;
                                emitBindingElement(element, createPropertyAccessForDestructuringProperty(value, propName));
                            }
                            else if (element.kind !== 187 /* OmittedExpression */) {
                                if (!element.dotDotDotToken) {
                                    // Rewrite element to a declaration that accesses array element at index i
                                    emitBindingElement(element, createElementAccessExpression(value, createNumericLiteral(i)));
                                }
                                else if (i === numElements - 1) {
                                    emitBindingElement(element, createSliceCall(value, i));
                                }
                            }
                        }
                    }
                    else {
                        emitAssignment(target.name, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0);
                        emitCount++;
                    }
                }
            }
            function emitVariableDeclaration(node) {
                if (ts.isBindingPattern(node.name)) {
                    if (languageVersion < 2 /* ES6 */) {
                        emitDestructuring(node, /*isAssignmentExpressionStatement*/ false);
                    }
                    else {
                        emit(node.name);
                        emitOptional(" = ", node.initializer);
                    }
                }
                else {
                    var initializer = node.initializer;
                    if (!initializer && languageVersion < 2 /* ES6 */) {
                        // downlevel emit for non-initialized let bindings defined in loops
                        // for (...) {  let x; }
                        // should be
                        // for (...) { var <some-uniqie-name> = void 0; }
                        // this is necessary to preserve ES6 semantic in scenarios like
                        // for (...) { let x; console.log(x); x = 1 } // assignment on one iteration should not affect other iterations
                        var isUninitializedLet = (resolver.getNodeCheckFlags(node) & 16384 /* BlockScopedBindingInLoop */) &&
                            (getCombinedFlagsForIdentifier(node.name) & 16384 /* Let */);
                        // NOTE: default initialization should not be added to let bindings in for-in\for-of statements
                        if (isUninitializedLet &&
                            node.parent.parent.kind !== 200 /* ForInStatement */ &&
                            node.parent.parent.kind !== 201 /* ForOfStatement */) {
                            initializer = createVoidZero();
                        }
                    }
                    var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.name);
                    if (exportChanged) {
                        write(exportFunctionForFile + "(\"");
                        emitNodeWithCommentsAndWithoutSourcemap(node.name);
                        write("\", ");
                    }
                    emitModuleMemberName(node);
                    emitOptional(" = ", initializer);
                    if (exportChanged) {
                        write(")");
                    }
                }
            }
            function emitExportVariableAssignments(node) {
                if (node.kind === 187 /* OmittedExpression */) {
                    return;
                }
                var name = node.name;
                if (name.kind === 69 /* Identifier */) {
                    emitExportMemberAssignments(name);
                }
                else if (ts.isBindingPattern(name)) {
                    ts.forEach(name.elements, emitExportVariableAssignments);
                }
            }
            function getCombinedFlagsForIdentifier(node) {
                if (!node.parent || (node.parent.kind !== 211 /* VariableDeclaration */ && node.parent.kind !== 163 /* BindingElement */)) {
                    return 0;
                }
                return ts.getCombinedNodeFlags(node.parent);
            }
            function isES6ExportedDeclaration(node) {
                return !!(node.flags & 1 /* Export */) &&
                    modulekind === 5 /* ES6 */ &&
                    node.parent.kind === 248 /* SourceFile */;
            }
            function emitVariableStatement(node) {
                var startIsEmitted = false;
                if (node.flags & 1 /* Export */) {
                    if (isES6ExportedDeclaration(node)) {
                        // Exported ES6 module member
                        write("export ");
                        startIsEmitted = tryEmitStartOfVariableDeclarationList(node.declarationList);
                    }
                }
                else {
                    startIsEmitted = tryEmitStartOfVariableDeclarationList(node.declarationList);
                }
                if (startIsEmitted) {
                    emitCommaList(node.declarationList.declarations);
                    write(";");
                }
                else {
                    var atLeastOneItem = emitVariableDeclarationListSkippingUninitializedEntries(node.declarationList);
                    if (atLeastOneItem) {
                        write(";");
                    }
                }
                if (modulekind !== 5 /* ES6 */ && node.parent === currentSourceFile) {
                    ts.forEach(node.declarationList.declarations, emitExportVariableAssignments);
                }
            }
            function shouldEmitLeadingAndTrailingCommentsForVariableStatement(node) {
                // If we're not exporting the variables, there's nothing special here.
                // Always emit comments for these nodes.
                if (!(node.flags & 1 /* Export */)) {
                    return true;
                }
                // If we are exporting, but it's a top-level ES6 module exports,
                // we'll emit the declaration list verbatim, so emit comments too.
                if (isES6ExportedDeclaration(node)) {
                    return true;
                }
                // Otherwise, only emit if we have at least one initializer present.
                for (var _a = 0, _b = node.declarationList.declarations; _a < _b.length; _a++) {
                    var declaration = _b[_a];
                    if (declaration.initializer) {
                        return true;
                    }
                }
                return false;
            }
            function emitParameter(node) {
                if (languageVersion < 2 /* ES6 */) {
                    if (ts.isBindingPattern(node.name)) {
                        var name_24 = createTempVariable(0 /* Auto */);
                        if (!tempParameters) {
                            tempParameters = [];
                        }
                        tempParameters.push(name_24);
                        emit(name_24);
                    }
                    else {
                        emit(node.name);
                    }
                }
                else {
                    if (node.dotDotDotToken) {
                        write("...");
                    }
                    emit(node.name);
                    emitOptional(" = ", node.initializer);
                }
            }
            function emitDefaultValueAssignments(node) {
                if (languageVersion < 2 /* ES6 */) {
                    var tempIndex = 0;
                    ts.forEach(node.parameters, function (parameter) {
                        // A rest parameter cannot have a binding pattern or an initializer,
                        // so let's just ignore it.
                        if (parameter.dotDotDotToken) {
                            return;
                        }
                        var paramName = parameter.name, initializer = parameter.initializer;
                        if (ts.isBindingPattern(paramName)) {
                            // In cases where a binding pattern is simply '[]' or '{}',
                            // we usually don't want to emit a var declaration; however, in the presence
                            // of an initializer, we must emit that expression to preserve side effects.
                            var hasBindingElements = paramName.elements.length > 0;
                            if (hasBindingElements || initializer) {
                                writeLine();
                                write("var ");
                                if (hasBindingElements) {
                                    emitDestructuring(parameter, /*isAssignmentExpressionStatement*/ false, tempParameters[tempIndex]);
                                }
                                else {
                                    emit(tempParameters[tempIndex]);
                                    write(" = ");
                                    emit(initializer);
                                }
                                write(";");
                                tempIndex++;
                            }
                        }
                        else if (initializer) {
                            writeLine();
                            emitStart(parameter);
                            write("if (");
                            emitNodeWithoutSourceMap(paramName);
                            write(" === void 0)");
                            emitEnd(parameter);
                            write(" { ");
                            emitStart(parameter);
                            emitNodeWithCommentsAndWithoutSourcemap(paramName);
                            write(" = ");
                            emitNodeWithCommentsAndWithoutSourcemap(initializer);
                            emitEnd(parameter);
                            write("; }");
                        }
                    });
                }
            }
            function emitRestParameter(node) {
                if (languageVersion < 2 /* ES6 */ && ts.hasRestParameter(node)) {
                    var restIndex = node.parameters.length - 1;
                    var restParam = node.parameters[restIndex];
                    // A rest parameter cannot have a binding pattern, so let's just ignore it if it does.
                    if (ts.isBindingPattern(restParam.name)) {
                        return;
                    }
                    var tempName = createTempVariable(268435456 /* _i */).text;
                    writeLine();
                    emitLeadingComments(restParam);
                    emitStart(restParam);
                    write("var ");
                    emitNodeWithCommentsAndWithoutSourcemap(restParam.name);
                    write(" = [];");
                    emitEnd(restParam);
                    emitTrailingComments(restParam);
                    writeLine();
                    write("for (");
                    emitStart(restParam);
                    write("var " + tempName + " = " + restIndex + ";");
                    emitEnd(restParam);
                    write(" ");
                    emitStart(restParam);
                    write(tempName + " < arguments.length;");
                    emitEnd(restParam);
                    write(" ");
                    emitStart(restParam);
                    write(tempName + "++");
                    emitEnd(restParam);
                    write(") {");
                    increaseIndent();
                    writeLine();
                    emitStart(restParam);
                    emitNodeWithCommentsAndWithoutSourcemap(restParam.name);
                    write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];");
                    emitEnd(restParam);
                    decreaseIndent();
                    writeLine();
                    write("}");
                }
            }
            function emitAccessor(node) {
                write(node.kind === 145 /* GetAccessor */ ? "get " : "set ");
                emit(node.name);
                emitSignatureAndBody(node);
            }
            function shouldEmitAsArrowFunction(node) {
                return node.kind === 174 /* ArrowFunction */ && languageVersion >= 2 /* ES6 */;
            }
            function emitDeclarationName(node) {
                if (node.name) {
                    emitNodeWithCommentsAndWithoutSourcemap(node.name);
                }
                else {
                    write(getGeneratedNameForNode(node));
                }
            }
            function shouldEmitFunctionName(node) {
                if (node.kind === 173 /* FunctionExpression */) {
                    // Emit name if one is present
                    return !!node.name;
                }
                if (node.kind === 213 /* FunctionDeclaration */) {
                    // Emit name if one is present, or emit generated name in down-level case (for export default case)
                    return !!node.name || languageVersion < 2 /* ES6 */;
                }
            }
            function emitFunctionDeclaration(node) {
                if (ts.nodeIsMissing(node.body)) {
                    return emitCommentsOnNotEmittedNode(node);
                }
                // TODO (yuisu) : we should not have special cases to condition emitting comments
                // but have one place to fix check for these conditions.
                if (node.kind !== 143 /* MethodDeclaration */ && node.kind !== 142 /* MethodSignature */ &&
                    node.parent && node.parent.kind !== 245 /* PropertyAssignment */ &&
                    node.parent.kind !== 168 /* CallExpression */) {
                    // 1. Methods will emit the comments as part of emitting method declaration
                    // 2. If the function is a property of object literal, emitting leading-comments
                    // is done by emitNodeWithoutSourceMap which then call this function.
                    // In particular, we would like to avoid emit comments twice in following case:
                    //      For example:
                    //          var obj = {
                    //              id:
                    //                  /*comment*/ () => void
                    //          }
                    // 3. If the function is an argument in call expression, emitting of comments will be
                    // taken care of in emit list of arguments inside of emitCallexpression
                    emitLeadingComments(node);
                }
                emitStart(node);
                // For targeting below es6, emit functions-like declaration including arrow function using function keyword.
                // When targeting ES6, emit arrow function natively in ES6 by omitting function keyword and using fat arrow instead
                if (!shouldEmitAsArrowFunction(node)) {
                    if (isES6ExportedDeclaration(node)) {
                        write("export ");
                        if (node.flags & 1024 /* Default */) {
                            write("default ");
                        }
                    }
                    write("function");
                    if (languageVersion >= 2 /* ES6 */ && node.asteriskToken) {
                        write("*");
                    }
                    write(" ");
                }
                if (shouldEmitFunctionName(node)) {
                    emitDeclarationName(node);
                }
                emitSignatureAndBody(node);
                if (modulekind !== 5 /* ES6 */ && node.kind === 213 /* FunctionDeclaration */ && node.parent === currentSourceFile && node.name) {
                    emitExportMemberAssignments(node.name);
                }
                emitEnd(node);
                if (node.kind !== 143 /* MethodDeclaration */ && node.kind !== 142 /* MethodSignature */) {
                    emitTrailingComments(node);
                }
            }
            function emitCaptureThisForNodeIfNecessary(node) {
                if (resolver.getNodeCheckFlags(node) & 4 /* CaptureThis */) {
                    writeLine();
                    emitStart(node);
                    write("var _this = this;");
                    emitEnd(node);
                }
            }
            function emitSignatureParameters(node) {
                increaseIndent();
                write("(");
                if (node) {
                    var parameters = node.parameters;
                    var omitCount = languageVersion < 2 /* ES6 */ && ts.hasRestParameter(node) ? 1 : 0;
                    emitList(parameters, 0, parameters.length - omitCount, /*multiLine*/ false, /*trailingComma*/ false);
                }
                write(")");
                decreaseIndent();
            }
            function emitSignatureParametersForArrow(node) {
                // Check whether the parameter list needs parentheses and preserve no-parenthesis
                if (node.parameters.length === 1 && node.pos === node.parameters[0].pos) {
                    emit(node.parameters[0]);
                    return;
                }
                emitSignatureParameters(node);
            }
            function emitAsyncFunctionBodyForES6(node) {
                var promiseConstructor = ts.getEntityNameFromTypeNode(node.type);
                var isArrowFunction = node.kind === 174 /* ArrowFunction */;
                var hasLexicalArguments = (resolver.getNodeCheckFlags(node) & 4096 /* CaptureArguments */) !== 0;
                var args;
                // An async function is emit as an outer function that calls an inner
                // generator function. To preserve lexical bindings, we pass the current
                // `this` and `arguments` objects to `__awaiter`. The generator function
                // passed to `__awaiter` is executed inside of the callback to the
                // promise constructor.
                //
                // The emit for an async arrow without a lexical `arguments` binding might be:
                //
                //  // input
                //  let a = async (b) => { await b; }
                //
                //  // output
                //  let a = (b) => __awaiter(this, void 0, void 0, function* () {
                //      yield b;
                //  });
                //
                // The emit for an async arrow with a lexical `arguments` binding might be:
                //
                //  // input
                //  let a = async (b) => { await arguments[0]; }
                //
                //  // output
                //  let a = (b) => __awaiter(this, arguments, void 0, function* (arguments) {
                //      yield arguments[0];
                //  });
                //
                // The emit for an async function expression without a lexical `arguments` binding
                // might be:
                //
                //  // input
                //  let a = async function (b) {
                //      await b;
                //  }
                //
                //  // output
                //  let a = function (b) {
                //      return __awaiter(this, void 0, void 0, function* () {
                //          yield b;
                //      });
                //  }
                //
                // The emit for an async function expression with a lexical `arguments` binding
                // might be:
                //
                //  // input
                //  let a = async function (b) {
                //      await arguments[0];
                //  }
                //
                //  // output
                //  let a = function (b) {
                //      return __awaiter(this, arguments, void 0, function* (_arguments) {
                //          yield _arguments[0];
                //      });
                //  }
                //
                // The emit for an async function expression with a lexical `arguments` binding
                // and a return type annotation might be:
                //
                //  // input
                //  let a = async function (b): MyPromise<any> {
                //      await arguments[0];
                //  }
                //
                //  // output
                //  let a = function (b) {
                //      return __awaiter(this, arguments, MyPromise, function* (_arguments) {
                //          yield _arguments[0];
                //      });
                //  }
                //
                // If this is not an async arrow, emit the opening brace of the function body
                // and the start of the return statement.
                if (!isArrowFunction) {
                    write(" {");
                    increaseIndent();
                    writeLine();
                    write("return");
                }
                write(" __awaiter(this");
                if (hasLexicalArguments) {
                    write(", arguments");
                }
                else {
                    write(", void 0");
                }
                if (promiseConstructor) {
                    write(", ");
                    emitNodeWithoutSourceMap(promiseConstructor);
                }
                else {
                    write(", Promise");
                }
                // Emit the call to __awaiter.
                if (hasLexicalArguments) {
                    write(", function* (_arguments)");
                }
                else {
                    write(", function* ()");
                }
                // Emit the signature and body for the inner generator function.
                emitFunctionBody(node);
                write(")");
                // If this is not an async arrow, emit the closing brace of the outer function body.
                if (!isArrowFunction) {
                    write(";");
                    decreaseIndent();
                    writeLine();
                    write("}");
                }
            }
            function emitFunctionBody(node) {
                if (!node.body) {
                    // There can be no body when there are parse errors.  Just emit an empty block
                    // in that case.
                    write(" { }");
                }
                else {
                    if (node.body.kind === 192 /* Block */) {
                        emitBlockFunctionBody(node, node.body);
                    }
                    else {
                        emitExpressionFunctionBody(node, node.body);
                    }
                }
            }
            function emitSignatureAndBody(node) {
                var saveTempFlags = tempFlags;
                var saveTempVariables = tempVariables;
                var saveTempParameters = tempParameters;
                tempFlags = 0;
                tempVariables = undefined;
                tempParameters = undefined;
                // When targeting ES6, emit arrow function natively in ES6
                if (shouldEmitAsArrowFunction(node)) {
                    emitSignatureParametersForArrow(node);
                    write(" =>");
                }
                else {
                    emitSignatureParameters(node);
                }
                var isAsync = ts.isAsyncFunctionLike(node);
                if (isAsync && languageVersion === 2 /* ES6 */) {
                    emitAsyncFunctionBodyForES6(node);
                }
                else {
                    emitFunctionBody(node);
                }
                if (!isES6ExportedDeclaration(node)) {
                    emitExportMemberAssignment(node);
                }
                tempFlags = saveTempFlags;
                tempVariables = saveTempVariables;
                tempParameters = saveTempParameters;
            }
            // Returns true if any preamble code was emitted.
            function emitFunctionBodyPreamble(node) {
                emitCaptureThisForNodeIfNecessary(node);
                emitDefaultValueAssignments(node);
                emitRestParameter(node);
            }
            function emitExpressionFunctionBody(node, body) {
                if (languageVersion < 2 /* ES6 */ || node.flags & 512 /* Async */) {
                    emitDownLevelExpressionFunctionBody(node, body);
                    return;
                }
                // For es6 and higher we can emit the expression as is.  However, in the case
                // where the expression might end up looking like a block when emitted, we'll
                // also wrap it in parentheses first.  For example if you have: a => <foo>{}
                // then we need to generate: a => ({})
                write(" ");
                // Unwrap all type assertions.
                var current = body;
                while (current.kind === 171 /* TypeAssertionExpression */) {
                    current = current.expression;
                }
                emitParenthesizedIf(body, current.kind === 165 /* ObjectLiteralExpression */);
            }
            function emitDownLevelExpressionFunctionBody(node, body) {
                write(" {");
                scopeEmitStart(node);
                increaseIndent();
                var outPos = writer.getTextPos();
                emitDetachedComments(node.body);
                emitFunctionBodyPreamble(node);
                var preambleEmitted = writer.getTextPos() !== outPos;
                decreaseIndent();
                // If we didn't have to emit any preamble code, then attempt to keep the arrow
                // function on one line.
                if (!preambleEmitted && nodeStartPositionsAreOnSameLine(node, body)) {
                    write(" ");
                    emitStart(body);
                    write("return ");
                    emit(body);
                    emitEnd(body);
                    write(";");
                    emitTempDeclarations(/*newLine*/ false);
                    write(" ");
                }
                else {
                    increaseIndent();
                    writeLine();
                    emitLeadingComments(node.body);
                    write("return ");
                    emit(body);
                    write(";");
                    emitTrailingComments(node.body);
                    emitTempDeclarations(/*newLine*/ true);
                    decreaseIndent();
                    writeLine();
                }
                emitStart(node.body);
                write("}");
                emitEnd(node.body);
                scopeEmitEnd();
            }
            function emitBlockFunctionBody(node, body) {
                write(" {");
                scopeEmitStart(node);
                var initialTextPos = writer.getTextPos();
                increaseIndent();
                emitDetachedComments(body.statements);
                // Emit all the directive prologues (like "use strict").  These have to come before
                // any other preamble code we write (like parameter initializers).
                var startIndex = emitDirectivePrologues(body.statements, /*startWithNewLine*/ true);
                emitFunctionBodyPreamble(node);
                decreaseIndent();
                var preambleEmitted = writer.getTextPos() !== initialTextPos;
                if (!preambleEmitted && nodeEndIsOnSameLineAsNodeStart(body, body)) {
                    for (var _a = 0, _b = body.statements; _a < _b.length; _a++) {
                        var statement = _b[_a];
                        write(" ");
                        emit(statement);
                    }
                    emitTempDeclarations(/*newLine*/ false);
                    write(" ");
                    emitLeadingCommentsOfPosition(body.statements.end);
                }
                else {
                    increaseIndent();
                    emitLinesStartingAt(body.statements, startIndex);
                    emitTempDeclarations(/*newLine*/ true);
                    writeLine();
                    emitLeadingCommentsOfPosition(body.statements.end);
                    decreaseIndent();
                }
                emitToken(16 /* CloseBraceToken */, body.statements.end);
                scopeEmitEnd();
            }
            function findInitialSuperCall(ctor) {
                if (ctor.body) {
                    var statement = ctor.body.statements[0];
                    if (statement && statement.kind === 195 /* ExpressionStatement */) {
                        var expr = statement.expression;
                        if (expr && expr.kind === 168 /* CallExpression */) {
                            var func = expr.expression;
                            if (func && func.kind === 95 /* SuperKeyword */) {
                                return statement;
                            }
                        }
                    }
                }
            }
            function emitParameterPropertyAssignments(node) {
                ts.forEach(node.parameters, function (param) {
                    if (param.flags & 112 /* AccessibilityModifier */) {
                        writeLine();
                        emitStart(param);
                        emitStart(param.name);
                        write("this.");
                        emitNodeWithoutSourceMap(param.name);
                        emitEnd(param.name);
                        write(" = ");
                        emit(param.name);
                        write(";");
                        emitEnd(param);
                    }
                });
            }
            function emitMemberAccessForPropertyName(memberName) {
                // This does not emit source map because it is emitted by caller as caller
                // is aware how the property name changes to the property access
                // eg. public x = 10; becomes this.x and static x = 10 becomes className.x
                if (memberName.kind === 9 /* StringLiteral */ || memberName.kind === 8 /* NumericLiteral */) {
                    write("[");
                    emitNodeWithCommentsAndWithoutSourcemap(memberName);
                    write("]");
                }
                else if (memberName.kind === 136 /* ComputedPropertyName */) {
                    emitComputedPropertyName(memberName);
                }
                else {
                    write(".");
                    emitNodeWithCommentsAndWithoutSourcemap(memberName);
                }
            }
            function getInitializedProperties(node, isStatic) {
                var properties = [];
                for (var _a = 0, _b = node.members; _a < _b.length; _a++) {
                    var member = _b[_a];
                    if (member.kind === 141 /* PropertyDeclaration */ && isStatic === ((member.flags & 128 /* Static */) !== 0) && member.initializer) {
                        properties.push(member);
                    }
                }
                return properties;
            }
            function emitPropertyDeclarations(node, properties) {
                for (var _a = 0; _a < properties.length; _a++) {
                    var property = properties[_a];
                    emitPropertyDeclaration(node, property);
                }
            }
            function emitPropertyDeclaration(node, property, receiver, isExpression) {
                writeLine();
                emitLeadingComments(property);
                emitStart(property);
                emitStart(property.name);
                if (receiver) {
                    emit(receiver);
                }
                else {
                    if (property.flags & 128 /* Static */) {
                        emitDeclarationName(node);
                    }
                    else {
                        write("this");
                    }
                }
                emitMemberAccessForPropertyName(property.name);
                emitEnd(property.name);
                write(" = ");
                emit(property.initializer);
                if (!isExpression) {
                    write(";");
                }
                emitEnd(property);
                emitTrailingComments(property);
            }
            function emitMemberFunctionsForES5AndLower(node) {
                ts.forEach(node.members, function (member) {
                    if (member.kind === 191 /* SemicolonClassElement */) {
                        writeLine();
                        write(";");
                    }
                    else if (member.kind === 143 /* MethodDeclaration */ || node.kind === 142 /* MethodSignature */) {
                        if (!member.body) {
                            return emitCommentsOnNotEmittedNode(member);
                        }
                        writeLine();
                        emitLeadingComments(member);
                        emitStart(member);
                        emitStart(member.name);
                        emitClassMemberPrefix(node, member);
                        emitMemberAccessForPropertyName(member.name);
                        emitEnd(member.name);
                        write(" = ");
                        emitFunctionDeclaration(member);
                        emitEnd(member);
                        write(";");
                        emitTrailingComments(member);
                    }
                    else if (member.kind === 145 /* GetAccessor */ || member.kind === 146 /* SetAccessor */) {
                        var accessors = ts.getAllAccessorDeclarations(node.members, member);
                        if (member === accessors.firstAccessor) {
                            writeLine();
                            emitStart(member);
                            write("Object.defineProperty(");
                            emitStart(member.name);
                            emitClassMemberPrefix(node, member);
                            write(", ");
                            emitExpressionForPropertyName(member.name);
                            emitEnd(member.name);
                            write(", {");
                            increaseIndent();
                            if (accessors.getAccessor) {
                                writeLine();
                                emitLeadingComments(accessors.getAccessor);
                                write("get: ");
                                emitStart(accessors.getAccessor);
                                write("function ");
                                emitSignatureAndBody(accessors.getAccessor);
                                emitEnd(accessors.getAccessor);
                                emitTrailingComments(accessors.getAccessor);
                                write(",");
                            }
                            if (accessors.setAccessor) {
                                writeLine();
                                emitLeadingComments(accessors.setAccessor);
                                write("set: ");
                                emitStart(accessors.setAccessor);
                                write("function ");
                                emitSignatureAndBody(accessors.setAccessor);
                                emitEnd(accessors.setAccessor);
                                emitTrailingComments(accessors.setAccessor);
                                write(",");
                            }
                            writeLine();
                            write("enumerable: true,");
                            writeLine();
                            write("configurable: true");
                            decreaseIndent();
                            writeLine();
                            write("});");
                            emitEnd(member);
                        }
                    }
                });
            }
            function emitMemberFunctionsForES6AndHigher(node) {
                for (var _a = 0, _b = node.members; _a < _b.length; _a++) {
                    var member = _b[_a];
                    if ((member.kind === 143 /* MethodDeclaration */ || node.kind === 142 /* MethodSignature */) && !member.body) {
                        emitCommentsOnNotEmittedNode(member);
                    }
                    else if (member.kind === 143 /* MethodDeclaration */ ||
                        member.kind === 145 /* GetAccessor */ ||
                        member.kind === 146 /* SetAccessor */) {
                        writeLine();
                        emitLeadingComments(member);
                        emitStart(member);
                        if (member.flags & 128 /* Static */) {
                            write("static ");
                        }
                        if (member.kind === 145 /* GetAccessor */) {
                            write("get ");
                        }
                        else if (member.kind === 146 /* SetAccessor */) {
                            write("set ");
                        }
                        if (member.asteriskToken) {
                            write("*");
                        }
                        emit(member.name);
                        emitSignatureAndBody(member);
                        emitEnd(member);
                        emitTrailingComments(member);
                    }
                    else if (member.kind === 191 /* SemicolonClassElement */) {
                        writeLine();
                        write(";");
                    }
                }
            }
            function emitConstructor(node, baseTypeElement) {
                var saveTempFlags = tempFlags;
                var saveTempVariables = tempVariables;
                var saveTempParameters = tempParameters;
                tempFlags = 0;
                tempVariables = undefined;
                tempParameters = undefined;
                emitConstructorWorker(node, baseTypeElement);
                tempFlags = saveTempFlags;
                tempVariables = saveTempVariables;
                tempParameters = saveTempParameters;
            }
            function emitConstructorWorker(node, baseTypeElement) {
                // Check if we have property assignment inside class declaration.
                // If there is property assignment, we need to emit constructor whether users define it or not
                // If there is no property assignment, we can omit constructor if users do not define it
                var hasInstancePropertyWithInitializer = false;
                // Emit the constructor overload pinned comments
                ts.forEach(node.members, function (member) {
                    if (member.kind === 144 /* Constructor */ && !member.body) {
                        emitCommentsOnNotEmittedNode(member);
                    }
                    // Check if there is any non-static property assignment
                    if (member.kind === 141 /* PropertyDeclaration */ && member.initializer && (member.flags & 128 /* Static */) === 0) {
                        hasInstancePropertyWithInitializer = true;
                    }
                });
                var ctor = ts.getFirstConstructorWithBody(node);
                // For target ES6 and above, if there is no user-defined constructor and there is no property assignment
                // do not emit constructor in class declaration.
                if (languageVersion >= 2 /* ES6 */ && !ctor && !hasInstancePropertyWithInitializer) {
                    return;
                }
                if (ctor) {
                    emitLeadingComments(ctor);
                }
                emitStart(ctor || node);
                if (languageVersion < 2 /* ES6 */) {
                    write("function ");
                    emitDeclarationName(node);
                    emitSignatureParameters(ctor);
                }
                else {
                    write("constructor");
                    if (ctor) {
                        emitSignatureParameters(ctor);
                    }
                    else {
                        // Based on EcmaScript6 section 14.5.14: Runtime Semantics: ClassDefinitionEvaluation.
                        // If constructor is empty, then,
                        //      If ClassHeritageopt is present, then
                        //          Let constructor be the result of parsing the String "constructor(... args){ super (...args);}" using the syntactic grammar with the goal symbol MethodDefinition.
                        //      Else,
                        //          Let constructor be the result of parsing the String "constructor( ){ }" using the syntactic grammar with the goal symbol MethodDefinition
                        if (baseTypeElement) {
                            write("(...args)");
                        }
                        else {
                            write("()");
                        }
                    }
                }
                var startIndex = 0;
                write(" {");
                scopeEmitStart(node, "constructor");
                increaseIndent();
                if (ctor) {
                    // Emit all the directive prologues (like "use strict").  These have to come before
                    // any other preamble code we write (like parameter initializers).
                    startIndex = emitDirectivePrologues(ctor.body.statements, /*startWithNewLine*/ true);
                    emitDetachedComments(ctor.body.statements);
                }
                emitCaptureThisForNodeIfNecessary(node);
                var superCall;
                if (ctor) {
                    emitDefaultValueAssignments(ctor);
                    emitRestParameter(ctor);
                    if (baseTypeElement) {
                        superCall = findInitialSuperCall(ctor);
                        if (superCall) {
                            writeLine();
                            emit(superCall);
                        }
                    }
                    emitParameterPropertyAssignments(ctor);
                }
                else {
                    if (baseTypeElement) {
                        writeLine();
                        emitStart(baseTypeElement);
                        if (languageVersion < 2 /* ES6 */) {
                            write("_super.apply(this, arguments);");
                        }
                        else {
                            write("super(...args);");
                        }
                        emitEnd(baseTypeElement);
                    }
                }
                emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ false));
                if (ctor) {
                    var statements = ctor.body.statements;
                    if (superCall) {
                        statements = statements.slice(1);
                    }
                    emitLinesStartingAt(statements, startIndex);
                }
                emitTempDeclarations(/*newLine*/ true);
                writeLine();
                if (ctor) {
                    emitLeadingCommentsOfPosition(ctor.body.statements.end);
                }
                decreaseIndent();
                emitToken(16 /* CloseBraceToken */, ctor ? ctor.body.statements.end : node.members.end);
                scopeEmitEnd();
                emitEnd(ctor || node);
                if (ctor) {
                    emitTrailingComments(ctor);
                }
            }
            function emitClassExpression(node) {
                return emitClassLikeDeclaration(node);
            }
            function emitClassDeclaration(node) {
                return emitClassLikeDeclaration(node);
            }
            function emitClassLikeDeclaration(node) {
                if (languageVersion < 2 /* ES6 */) {
                    emitClassLikeDeclarationBelowES6(node);
                }
                else {
                    emitClassLikeDeclarationForES6AndHigher(node);
                }
                if (modulekind !== 5 /* ES6 */ && node.parent === currentSourceFile && node.name) {
                    emitExportMemberAssignments(node.name);
                }
            }
            function emitClassLikeDeclarationForES6AndHigher(node) {
                var thisNodeIsDecorated = ts.nodeIsDecorated(node);
                if (node.kind === 214 /* ClassDeclaration */) {
                    if (thisNodeIsDecorated) {
                        // To preserve the correct runtime semantics when decorators are applied to the class,
                        // the emit needs to follow one of the following rules:
                        //
                        // * For a local class declaration:
                        //
                        //     @dec class C {
                        //     }
                        //
                        //   The emit should be:
                        //
                        //     let C = class {
                        //     };
                        //     C = __decorate([dec], C);
                        //
                        // * For an exported class declaration:
                        //
                        //     @dec export class C {
                        //     }
                        //
                        //   The emit should be:
                        //
                        //     export let C = class {
                        //     };
                        //     C = __decorate([dec], C);
                        //
                        // * For a default export of a class declaration with a name:
                        //
                        //     @dec default export class C {
                        //     }
                        //
                        //   The emit should be:
                        //
                        //     let C = class {
                        //     }
                        //     C = __decorate([dec], C);
                        //     export default C;
                        //
                        // * For a default export of a class declaration without a name:
                        //
                        //     @dec default export class {
                        //     }
                        //
                        //   The emit should be:
                        //
                        //     let _default = class {
                        //     }
                        //     _default = __decorate([dec], _default);
                        //     export default _default;
                        //
                        if (isES6ExportedDeclaration(node) && !(node.flags & 1024 /* Default */)) {
                            write("export ");
                        }
                        write("let ");
                        emitDeclarationName(node);
                        write(" = ");
                    }
                    else if (isES6ExportedDeclaration(node)) {
                        write("export ");
                        if (node.flags & 1024 /* Default */) {
                            write("default ");
                        }
                    }
                }
                // If the class has static properties, and it's a class expression, then we'll need
                // to specialize the emit a bit.  for a class expression of the form:
                //
                //      class C { static a = 1; static b = 2; ... }
                //
                // We'll emit:
                //
                //      (_temp = class C { ... }, _temp.a = 1, _temp.b = 2, _temp)
                //
                // This keeps the expression as an expression, while ensuring that the static parts
                // of it have been initialized by the time it is used.
                var staticProperties = getInitializedProperties(node, /*static:*/ true);
                var isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === 186 /* ClassExpression */;
                var tempVariable;
                if (isClassExpressionWithStaticProperties) {
                    tempVariable = createAndRecordTempVariable(0 /* Auto */);
                    write("(");
                    increaseIndent();
                    emit(tempVariable);
                    write(" = ");
                }
                write("class");
                // emit name if
                // - node has a name
                // - this is default export with static initializers
                if ((node.name || (node.flags & 1024 /* Default */ && staticProperties.length > 0)) && !thisNodeIsDecorated) {
                    write(" ");
                    emitDeclarationName(node);
                }
                var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node);
                if (baseTypeNode) {
                    write(" extends ");
                    emit(baseTypeNode.expression);
                }
                write(" {");
                increaseIndent();
                scopeEmitStart(node);
                writeLine();
                emitConstructor(node, baseTypeNode);
                emitMemberFunctionsForES6AndHigher(node);
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.members.end);
                scopeEmitEnd();
                // TODO(rbuckton): Need to go back to `let _a = class C {}` approach, removing the defineProperty call for now.
                // For a decorated class, we need to assign its name (if it has one). This is because we emit
                // the class as a class expression to avoid the double-binding of the identifier:
                //
                //   let C = class {
                //   }
                //   Object.defineProperty(C, "name", { value: "C", configurable: true });
                //
                if (thisNodeIsDecorated) {
                    write(";");
                }
                // Emit static property assignment. Because classDeclaration is lexically evaluated,
                // it is safe to emit static property assignment after classDeclaration
                // From ES6 specification:
                //      HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using
                //                                  a lexical declaration such as a LexicalDeclaration or a ClassDeclaration.
                if (isClassExpressionWithStaticProperties) {
                    for (var _a = 0; _a < staticProperties.length; _a++) {
                        var property = staticProperties[_a];
                        write(",");
                        writeLine();
                        emitPropertyDeclaration(node, property, /*receiver:*/ tempVariable, /*isExpression:*/ true);
                    }
                    write(",");
                    writeLine();
                    emit(tempVariable);
                    decreaseIndent();
                    write(")");
                }
                else {
                    writeLine();
                    emitPropertyDeclarations(node, staticProperties);
                    emitDecoratorsOfClass(node);
                }
                // If this is an exported class, but not on the top level (i.e. on an internal
                // module), export it
                if (!isES6ExportedDeclaration(node) && (node.flags & 1 /* Export */)) {
                    writeLine();
                    emitStart(node);
                    emitModuleMemberName(node);
                    write(" = ");
                    emitDeclarationName(node);
                    emitEnd(node);
                    write(";");
                }
                else if (isES6ExportedDeclaration(node) && (node.flags & 1024 /* Default */) && thisNodeIsDecorated) {
                    // if this is a top level default export of decorated class, write the export after the declaration.
                    writeLine();
                    write("export default ");
                    emitDeclarationName(node);
                    write(";");
                }
            }
            function emitClassLikeDeclarationBelowES6(node) {
                if (node.kind === 214 /* ClassDeclaration */) {
                    // source file level classes in system modules are hoisted so 'var's for them are already defined
                    if (!shouldHoistDeclarationInSystemJsModule(node)) {
                        write("var ");
                    }
                    emitDeclarationName(node);
                    write(" = ");
                }
                write("(function (");
                var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node);
                if (baseTypeNode) {
                    write("_super");
                }
                write(") {");
                var saveTempFlags = tempFlags;
                var saveTempVariables = tempVariables;
                var saveTempParameters = tempParameters;
                var saveComputedPropertyNamesToGeneratedNames = computedPropertyNamesToGeneratedNames;
                tempFlags = 0;
                tempVariables = undefined;
                tempParameters = undefined;
                computedPropertyNamesToGeneratedNames = undefined;
                increaseIndent();
                scopeEmitStart(node);
                if (baseTypeNode) {
                    writeLine();
                    emitStart(baseTypeNode);
                    write("__extends(");
                    emitDeclarationName(node);
                    write(", _super);");
                    emitEnd(baseTypeNode);
                }
                writeLine();
                emitConstructor(node, baseTypeNode);
                emitMemberFunctionsForES5AndLower(node);
                emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ true));
                writeLine();
                emitDecoratorsOfClass(node);
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.members.end, function () {
                    write("return ");
                    emitDeclarationName(node);
                });
                write(";");
                emitTempDeclarations(/*newLine*/ true);
                tempFlags = saveTempFlags;
                tempVariables = saveTempVariables;
                tempParameters = saveTempParameters;
                computedPropertyNamesToGeneratedNames = saveComputedPropertyNamesToGeneratedNames;
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.members.end);
                scopeEmitEnd();
                emitStart(node);
                write(")(");
                if (baseTypeNode) {
                    emit(baseTypeNode.expression);
                }
                write(")");
                if (node.kind === 214 /* ClassDeclaration */) {
                    write(";");
                }
                emitEnd(node);
                if (node.kind === 214 /* ClassDeclaration */) {
                    emitExportMemberAssignment(node);
                }
            }
            function emitClassMemberPrefix(node, member) {
                emitDeclarationName(node);
                if (!(member.flags & 128 /* Static */)) {
                    write(".prototype");
                }
            }
            function emitDecoratorsOfClass(node) {
                emitDecoratorsOfMembers(node, /*staticFlag*/ 0);
                emitDecoratorsOfMembers(node, 128 /* Static */);
                emitDecoratorsOfConstructor(node);
            }
            function emitDecoratorsOfConstructor(node) {
                var decorators = node.decorators;
                var constructor = ts.getFirstConstructorWithBody(node);
                var hasDecoratedParameters = constructor && ts.forEach(constructor.parameters, ts.nodeIsDecorated);
                // skip decoration of the constructor if neither it nor its parameters are decorated
                if (!decorators && !hasDecoratedParameters) {
                    return;
                }
                // Emit the call to __decorate. Given the class:
                //
                //   @dec
                //   class C {
                //   }
                //
                // The emit for the class is:
                //
                //   C = __decorate([dec], C);
                //
                writeLine();
                emitStart(node);
                emitDeclarationName(node);
                write(" = __decorate([");
                increaseIndent();
                writeLine();
                var decoratorCount = decorators ? decorators.length : 0;
                var argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, function (decorator) {
                    emitStart(decorator);
                    emit(decorator.expression);
                    emitEnd(decorator);
                });
                argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0);
                emitSerializedTypeMetadata(node, /*leadingComma*/ argumentsWritten >= 0);
                decreaseIndent();
                writeLine();
                write("], ");
                emitDeclarationName(node);
                write(");");
                emitEnd(node);
                writeLine();
            }
            function emitDecoratorsOfMembers(node, staticFlag) {
                for (var _a = 0, _b = node.members; _a < _b.length; _a++) {
                    var member = _b[_a];
                    // only emit members in the correct group
                    if ((member.flags & 128 /* Static */) !== staticFlag) {
                        continue;
                    }
                    // skip members that cannot be decorated (such as the constructor)
                    if (!ts.nodeCanBeDecorated(member)) {
                        continue;
                    }
                    // skip a member if it or any of its parameters are not decorated
                    if (!ts.nodeOrChildIsDecorated(member)) {
                        continue;
                    }
                    // skip an accessor declaration if it is not the first accessor
                    var decorators = void 0;
                    var functionLikeMember = void 0;
                    if (ts.isAccessor(member)) {
                        var accessors = ts.getAllAccessorDeclarations(node.members, member);
                        if (member !== accessors.firstAccessor) {
                            continue;
                        }
                        // get the decorators from the first accessor with decorators
                        decorators = accessors.firstAccessor.decorators;
                        if (!decorators && accessors.secondAccessor) {
                            decorators = accessors.secondAccessor.decorators;
                        }
                        // we only decorate parameters of the set accessor
                        functionLikeMember = accessors.setAccessor;
                    }
                    else {
                        decorators = member.decorators;
                        // we only decorate the parameters here if this is a method
                        if (member.kind === 143 /* MethodDeclaration */) {
                            functionLikeMember = member;
                        }
                    }
                    // Emit the call to __decorate. Given the following:
                    //
                    //   class C {
                    //     @dec method(@dec2 x) {}
                    //     @dec get accessor() {}
                    //     @dec prop;
                    //   }
                    //
                    // The emit for a method is:
                    //
                    //   __decorate([
                    //       dec,
                    //       __param(0, dec2),
                    //       __metadata("design:type", Function),
                    //       __metadata("design:paramtypes", [Object]),
                    //       __metadata("design:returntype", void 0)
                    //   ], C.prototype, "method", undefined);
                    //
                    // The emit for an accessor is:
                    //
                    //   __decorate([
                    //       dec
                    //   ], C.prototype, "accessor", undefined);
                    //
                    // The emit for a property is:
                    //
                    //   __decorate([
                    //       dec
                    //   ], C.prototype, "prop");
                    //
                    writeLine();
                    emitStart(member);
                    write("__decorate([");
                    increaseIndent();
                    writeLine();
                    var decoratorCount = decorators ? decorators.length : 0;
                    var argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, function (decorator) {
                        emitStart(decorator);
                        emit(decorator.expression);
                        emitEnd(decorator);
                    });
                    argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0);
                    emitSerializedTypeMetadata(member, argumentsWritten > 0);
                    decreaseIndent();
                    writeLine();
                    write("], ");
                    emitStart(member.name);
                    emitClassMemberPrefix(node, member);
                    write(", ");
                    emitExpressionForPropertyName(member.name);
                    emitEnd(member.name);
                    if (languageVersion > 0 /* ES3 */) {
                        if (member.kind !== 141 /* PropertyDeclaration */) {
                            // We emit `null` here to indicate to `__decorate` that it can invoke `Object.getOwnPropertyDescriptor` directly.
                            // We have this extra argument here so that we can inject an explicit property descriptor at a later date.
                            write(", null");
                        }
                        else {
                            // We emit `void 0` here to indicate to `__decorate` that it can invoke `Object.defineProperty` directly, but that it
                            // should not invoke `Object.getOwnPropertyDescriptor`.
                            write(", void 0");
                        }
                    }
                    write(");");
                    emitEnd(member);
                    writeLine();
                }
            }
            function emitDecoratorsOfParameters(node, leadingComma) {
                var argumentsWritten = 0;
                if (node) {
                    var parameterIndex = 0;
                    for (var _a = 0, _b = node.parameters; _a < _b.length; _a++) {
                        var parameter = _b[_a];
                        if (ts.nodeIsDecorated(parameter)) {
                            var decorators = parameter.decorators;
                            argumentsWritten += emitList(decorators, 0, decorators.length, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ leadingComma, /*noTrailingNewLine*/ true, function (decorator) {
                                emitStart(decorator);
                                write("__param(" + parameterIndex + ", ");
                                emit(decorator.expression);
                                write(")");
                                emitEnd(decorator);
                            });
                            leadingComma = true;
                        }
                        ++parameterIndex;
                    }
                }
                return argumentsWritten;
            }
            function shouldEmitTypeMetadata(node) {
                // This method determines whether to emit the "design:type" metadata based on the node's kind.
                // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
                // compiler option is set.
                switch (node.kind) {
                    case 143 /* MethodDeclaration */:
                    case 145 /* GetAccessor */:
                    case 146 /* SetAccessor */:
                    case 141 /* PropertyDeclaration */:
                        return true;
                }
                return false;
            }
            function shouldEmitReturnTypeMetadata(node) {
                // This method determines whether to emit the "design:returntype" metadata based on the node's kind.
                // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
                // compiler option is set.
                switch (node.kind) {
                    case 143 /* MethodDeclaration */:
                        return true;
                }
                return false;
            }
            function shouldEmitParamTypesMetadata(node) {
                // This method determines whether to emit the "design:paramtypes" metadata based on the node's kind.
                // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
                // compiler option is set.
                switch (node.kind) {
                    case 214 /* ClassDeclaration */:
                    case 143 /* MethodDeclaration */:
                    case 146 /* SetAccessor */:
                        return true;
                }
                return false;
            }
            /** Serializes the type of a declaration to an appropriate JS constructor value. Used by the __metadata decorator for a class member. */
            function emitSerializedTypeOfNode(node) {
                // serialization of the type of a declaration uses the following rules:
                //
                // * The serialized type of a ClassDeclaration is "Function"
                // * The serialized type of a ParameterDeclaration is the serialized type of its type annotation.
                // * The serialized type of a PropertyDeclaration is the serialized type of its type annotation.
                // * The serialized type of an AccessorDeclaration is the serialized type of the return type annotation of its getter or parameter type annotation of its setter.
                // * The serialized type of any other FunctionLikeDeclaration is "Function".
                // * The serialized type of any other node is "void 0".
                //
                // For rules on serializing type annotations, see `serializeTypeNode`.
                switch (node.kind) {
                    case 214 /* ClassDeclaration */:
                        write("Function");
                        return;
                    case 141 /* PropertyDeclaration */:
                        emitSerializedTypeNode(node.type);
                        return;
                    case 138 /* Parameter */:
                        emitSerializedTypeNode(node.type);
                        return;
                    case 145 /* GetAccessor */:
                        emitSerializedTypeNode(node.type);
                        return;
                    case 146 /* SetAccessor */:
                        emitSerializedTypeNode(ts.getSetAccessorTypeAnnotationNode(node));
                        return;
                }
                if (ts.isFunctionLike(node)) {
                    write("Function");
                    return;
                }
                write("void 0");
            }
            function emitSerializedTypeNode(node) {
                if (node) {
                    switch (node.kind) {
                        case 103 /* VoidKeyword */:
                            write("void 0");
                            return;
                        case 160 /* ParenthesizedType */:
                            emitSerializedTypeNode(node.type);
                            return;
                        case 152 /* FunctionType */:
                        case 153 /* ConstructorType */:
                            write("Function");
                            return;
                        case 156 /* ArrayType */:
                        case 157 /* TupleType */:
                            write("Array");
                            return;
                        case 150 /* TypePredicate */:
                        case 120 /* BooleanKeyword */:
                            write("Boolean");
                            return;
                        case 130 /* StringKeyword */:
                        case 9 /* StringLiteral */:
                            write("String");
                            return;
                        case 128 /* NumberKeyword */:
                            write("Number");
                            return;
                        case 131 /* SymbolKeyword */:
                            write("Symbol");
                            return;
                        case 151 /* TypeReference */:
                            emitSerializedTypeReferenceNode(node);
                            return;
                        case 154 /* TypeQuery */:
                        case 155 /* TypeLiteral */:
                        case 158 /* UnionType */:
                        case 159 /* IntersectionType */:
                        case 117 /* AnyKeyword */:
                            break;
                        default:
                            ts.Debug.fail("Cannot serialize unexpected type node.");
                            break;
                    }
                }
                write("Object");
            }
            /** Serializes a TypeReferenceNode to an appropriate JS constructor value. Used by the __metadata decorator. */
            function emitSerializedTypeReferenceNode(node) {
                var location = node.parent;
                while (ts.isDeclaration(location) || ts.isTypeNode(location)) {
                    location = location.parent;
                }
                // Clone the type name and parent it to a location outside of the current declaration.
                var typeName = ts.cloneEntityName(node.typeName);
                typeName.parent = location;
                var result = resolver.getTypeReferenceSerializationKind(typeName);
                switch (result) {
                    case ts.TypeReferenceSerializationKind.Unknown:
                        var temp = createAndRecordTempVariable(0 /* Auto */);
                        write("(typeof (");
                        emitNodeWithoutSourceMap(temp);
                        write(" = ");
                        emitEntityNameAsExpression(typeName, /*useFallback*/ true);
                        write(") === 'function' && ");
                        emitNodeWithoutSourceMap(temp);
                        write(") || Object");
                        break;
                    case ts.TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue:
                        emitEntityNameAsExpression(typeName, /*useFallback*/ false);
                        break;
                    case ts.TypeReferenceSerializationKind.VoidType:
                        write("void 0");
                        break;
                    case ts.TypeReferenceSerializationKind.BooleanType:
                        write("Boolean");
                        break;
                    case ts.TypeReferenceSerializationKind.NumberLikeType:
                        write("Number");
                        break;
                    case ts.TypeReferenceSerializationKind.StringLikeType:
                        write("String");
                        break;
                    case ts.TypeReferenceSerializationKind.ArrayLikeType:
                        write("Array");
                        break;
                    case ts.TypeReferenceSerializationKind.ESSymbolType:
                        if (languageVersion < 2 /* ES6 */) {
                            write("typeof Symbol === 'function' ? Symbol : Object");
                        }
                        else {
                            write("Symbol");
                        }
                        break;
                    case ts.TypeReferenceSerializationKind.TypeWithCallSignature:
                        write("Function");
                        break;
                    case ts.TypeReferenceSerializationKind.ObjectType:
                        write("Object");
                        break;
                }
            }
            /** Serializes the parameter types of a function or the constructor of a class. Used by the __metadata decorator for a method or set accessor. */
            function emitSerializedParameterTypesOfNode(node) {
                // serialization of parameter types uses the following rules:
                //
                // * If the declaration is a class, the parameters of the first constructor with a body are used.
                // * If the declaration is function-like and has a body, the parameters of the function are used.
                //
                // For the rules on serializing the type of each parameter declaration, see `serializeTypeOfDeclaration`.
                if (node) {
                    var valueDeclaration;
                    if (node.kind === 214 /* ClassDeclaration */) {
                        valueDeclaration = ts.getFirstConstructorWithBody(node);
                    }
                    else if (ts.isFunctionLike(node) && ts.nodeIsPresent(node.body)) {
                        valueDeclaration = node;
                    }
                    if (valueDeclaration) {
                        var parameters = valueDeclaration.parameters;
                        var parameterCount = parameters.length;
                        if (parameterCount > 0) {
                            for (var i = 0; i < parameterCount; i++) {
                                if (i > 0) {
                                    write(", ");
                                }
                                if (parameters[i].dotDotDotToken) {
                                    var parameterType = parameters[i].type;
                                    if (parameterType.kind === 156 /* ArrayType */) {
                                        parameterType = parameterType.elementType;
                                    }
                                    else if (parameterType.kind === 151 /* TypeReference */ && parameterType.typeArguments && parameterType.typeArguments.length === 1) {
                                        parameterType = parameterType.typeArguments[0];
                                    }
                                    else {
                                        parameterType = undefined;
                                    }
                                    emitSerializedTypeNode(parameterType);
                                }
                                else {
                                    emitSerializedTypeOfNode(parameters[i]);
                                }
                            }
                        }
                    }
                }
            }
            /** Serializes the return type of function. Used by the __metadata decorator for a method. */
            function emitSerializedReturnTypeOfNode(node) {
                if (node && ts.isFunctionLike(node) && node.type) {
                    emitSerializedTypeNode(node.type);
                    return;
                }
                write("void 0");
            }
            function emitSerializedTypeMetadata(node, writeComma) {
                // This method emits the serialized type metadata for a decorator target.
                // The caller should have already tested whether the node has decorators.
                var argumentsWritten = 0;
                if (compilerOptions.emitDecoratorMetadata) {
                    if (shouldEmitTypeMetadata(node)) {
                        if (writeComma) {
                            write(", ");
                        }
                        writeLine();
                        write("__metadata('design:type', ");
                        emitSerializedTypeOfNode(node);
                        write(")");
                        argumentsWritten++;
                    }
                    if (shouldEmitParamTypesMetadata(node)) {
                        if (writeComma || argumentsWritten) {
                            write(", ");
                        }
                        writeLine();
                        write("__metadata('design:paramtypes', [");
                        emitSerializedParameterTypesOfNode(node);
                        write("])");
                        argumentsWritten++;
                    }
                    if (shouldEmitReturnTypeMetadata(node)) {
                        if (writeComma || argumentsWritten) {
                            write(", ");
                        }
                        writeLine();
                        write("__metadata('design:returntype', ");
                        emitSerializedReturnTypeOfNode(node);
                        write(")");
                        argumentsWritten++;
                    }
                }
                return argumentsWritten;
            }
            function emitInterfaceDeclaration(node) {
                emitCommentsOnNotEmittedNode(node);
            }
            function shouldEmitEnumDeclaration(node) {
                var isConstEnum = ts.isConst(node);
                return !isConstEnum || compilerOptions.preserveConstEnums || compilerOptions.isolatedModules;
            }
            function emitEnumDeclaration(node) {
                // const enums are completely erased during compilation.
                if (!shouldEmitEnumDeclaration(node)) {
                    return;
                }
                if (!shouldHoistDeclarationInSystemJsModule(node)) {
                    // do not emit var if variable was already hoisted
                    if (!(node.flags & 1 /* Export */) || isES6ExportedDeclaration(node)) {
                        emitStart(node);
                        if (isES6ExportedDeclaration(node)) {
                            write("export ");
                        }
                        write("var ");
                        emit(node.name);
                        emitEnd(node);
                        write(";");
                    }
                }
                writeLine();
                emitStart(node);
                write("(function (");
                emitStart(node.name);
                write(getGeneratedNameForNode(node));
                emitEnd(node.name);
                write(") {");
                increaseIndent();
                scopeEmitStart(node);
                emitLines(node.members);
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.members.end);
                scopeEmitEnd();
                write(")(");
                emitModuleMemberName(node);
                write(" || (");
                emitModuleMemberName(node);
                write(" = {}));");
                emitEnd(node);
                if (!isES6ExportedDeclaration(node) && node.flags & 1 /* Export */ && !shouldHoistDeclarationInSystemJsModule(node)) {
                    // do not emit var if variable was already hoisted
                    writeLine();
                    emitStart(node);
                    write("var ");
                    emit(node.name);
                    write(" = ");
                    emitModuleMemberName(node);
                    emitEnd(node);
                    write(";");
                }
                if (modulekind !== 5 /* ES6 */ && node.parent === currentSourceFile) {
                    if (modulekind === 4 /* System */ && (node.flags & 1 /* Export */)) {
                        // write the call to exporter for enum
                        writeLine();
                        write(exportFunctionForFile + "(\"");
                        emitDeclarationName(node);
                        write("\", ");
                        emitDeclarationName(node);
                        write(");");
                    }
                    emitExportMemberAssignments(node.name);
                }
            }
            function emitEnumMember(node) {
                var enumParent = node.parent;
                emitStart(node);
                write(getGeneratedNameForNode(enumParent));
                write("[");
                write(getGeneratedNameForNode(enumParent));
                write("[");
                emitExpressionForPropertyName(node.name);
                write("] = ");
                writeEnumMemberDeclarationValue(node);
                write("] = ");
                emitExpressionForPropertyName(node.name);
                emitEnd(node);
                write(";");
            }
            function writeEnumMemberDeclarationValue(member) {
                var value = resolver.getConstantValue(member);
                if (value !== undefined) {
                    write(value.toString());
                    return;
                }
                else if (member.initializer) {
                    emit(member.initializer);
                }
                else {
                    write("undefined");
                }
            }
            function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration) {
                if (moduleDeclaration.body.kind === 218 /* ModuleDeclaration */) {
                    var recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration.body);
                    return recursiveInnerModule || moduleDeclaration.body;
                }
            }
            function shouldEmitModuleDeclaration(node) {
                return ts.isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.isolatedModules);
            }
            function isModuleMergedWithES6Class(node) {
                return languageVersion === 2 /* ES6 */ && !!(resolver.getNodeCheckFlags(node) & 32768 /* LexicalModuleMergesWithClass */);
            }
            function emitModuleDeclaration(node) {
                // Emit only if this module is non-ambient.
                var shouldEmit = shouldEmitModuleDeclaration(node);
                if (!shouldEmit) {
                    return emitCommentsOnNotEmittedNode(node);
                }
                var hoistedInDeclarationScope = shouldHoistDeclarationInSystemJsModule(node);
                var emitVarForModule = !hoistedInDeclarationScope && !isModuleMergedWithES6Class(node);
                if (emitVarForModule) {
                    emitStart(node);
                    if (isES6ExportedDeclaration(node)) {
                        write("export ");
                    }
                    write("var ");
                    emit(node.name);
                    write(";");
                    emitEnd(node);
                    writeLine();
                }
                emitStart(node);
                write("(function (");
                emitStart(node.name);
                write(getGeneratedNameForNode(node));
                emitEnd(node.name);
                write(") ");
                if (node.body.kind === 219 /* ModuleBlock */) {
                    var saveTempFlags = tempFlags;
                    var saveTempVariables = tempVariables;
                    tempFlags = 0;
                    tempVariables = undefined;
                    emit(node.body);
                    tempFlags = saveTempFlags;
                    tempVariables = saveTempVariables;
                }
                else {
                    write("{");
                    increaseIndent();
                    scopeEmitStart(node);
                    emitCaptureThisForNodeIfNecessary(node);
                    writeLine();
                    emit(node.body);
                    decreaseIndent();
                    writeLine();
                    var moduleBlock = getInnerMostModuleDeclarationFromDottedModule(node).body;
                    emitToken(16 /* CloseBraceToken */, moduleBlock.statements.end);
                    scopeEmitEnd();
                }
                write(")(");
                // write moduleDecl = containingModule.m only if it is not exported es6 module member
                if ((node.flags & 1 /* Export */) && !isES6ExportedDeclaration(node)) {
                    emit(node.name);
                    write(" = ");
                }
                emitModuleMemberName(node);
                write(" || (");
                emitModuleMemberName(node);
                write(" = {}));");
                emitEnd(node);
                if (!isES6ExportedDeclaration(node) && node.name.kind === 69 /* Identifier */ && node.parent === currentSourceFile) {
                    if (modulekind === 4 /* System */ && (node.flags & 1 /* Export */)) {
                        writeLine();
                        write(exportFunctionForFile + "(\"");
                        emitDeclarationName(node);
                        write("\", ");
                        emitDeclarationName(node);
                        write(");");
                    }
                    emitExportMemberAssignments(node.name);
                }
            }
            /*
             * Some bundlers (SystemJS builder) sometimes want to rename dependencies.
             * Here we check if alternative name was provided for a given moduleName and return it if possible.
             */
            function tryRenameExternalModule(moduleName) {
                if (currentSourceFile.renamedDependencies && ts.hasProperty(currentSourceFile.renamedDependencies, moduleName.text)) {
                    return "\"" + currentSourceFile.renamedDependencies[moduleName.text] + "\"";
                }
                return undefined;
            }
            function emitRequire(moduleName) {
                if (moduleName.kind === 9 /* StringLiteral */) {
                    write("require(");
                    var text = tryRenameExternalModule(moduleName);
                    if (text) {
                        write(text);
                    }
                    else {
                        emitStart(moduleName);
                        emitLiteral(moduleName);
                        emitEnd(moduleName);
                    }
                    emitToken(18 /* CloseParenToken */, moduleName.end);
                }
                else {
                    write("require()");
                }
            }
            function getNamespaceDeclarationNode(node) {
                if (node.kind === 221 /* ImportEqualsDeclaration */) {
                    return node;
                }
                var importClause = node.importClause;
                if (importClause && importClause.namedBindings && importClause.namedBindings.kind === 224 /* NamespaceImport */) {
                    return importClause.namedBindings;
                }
            }
            function isDefaultImport(node) {
                return node.kind === 222 /* ImportDeclaration */ && node.importClause && !!node.importClause.name;
            }
            function emitExportImportAssignments(node) {
                if (ts.isAliasSymbolDeclaration(node) && resolver.isValueAliasDeclaration(node)) {
                    emitExportMemberAssignments(node.name);
                }
                ts.forEachChild(node, emitExportImportAssignments);
            }
            function emitImportDeclaration(node) {
                if (modulekind !== 5 /* ES6 */) {
                    return emitExternalImportDeclaration(node);
                }
                // ES6 import
                if (node.importClause) {
                    var shouldEmitDefaultBindings = resolver.isReferencedAliasDeclaration(node.importClause);
                    var shouldEmitNamedBindings = node.importClause.namedBindings && resolver.isReferencedAliasDeclaration(node.importClause.namedBindings, /* checkChildren */ true);
                    if (shouldEmitDefaultBindings || shouldEmitNamedBindings) {
                        write("import ");
                        emitStart(node.importClause);
                        if (shouldEmitDefaultBindings) {
                            emit(node.importClause.name);
                            if (shouldEmitNamedBindings) {
                                write(", ");
                            }
                        }
                        if (shouldEmitNamedBindings) {
                            emitLeadingComments(node.importClause.namedBindings);
                            emitStart(node.importClause.namedBindings);
                            if (node.importClause.namedBindings.kind === 224 /* NamespaceImport */) {
                                write("* as ");
                                emit(node.importClause.namedBindings.name);
                            }
                            else {
                                write("{ ");
                                emitExportOrImportSpecifierList(node.importClause.namedBindings.elements, resolver.isReferencedAliasDeclaration);
                                write(" }");
                            }
                            emitEnd(node.importClause.namedBindings);
                            emitTrailingComments(node.importClause.namedBindings);
                        }
                        emitEnd(node.importClause);
                        write(" from ");
                        emit(node.moduleSpecifier);
                        write(";");
                    }
                }
                else {
                    write("import ");
                    emit(node.moduleSpecifier);
                    write(";");
                }
            }
            function emitExternalImportDeclaration(node) {
                if (ts.contains(externalImports, node)) {
                    var isExportedImport = node.kind === 221 /* ImportEqualsDeclaration */ && (node.flags & 1 /* Export */) !== 0;
                    var namespaceDeclaration = getNamespaceDeclarationNode(node);
                    if (modulekind !== 2 /* AMD */) {
                        emitLeadingComments(node);
                        emitStart(node);
                        if (namespaceDeclaration && !isDefaultImport(node)) {
                            // import x = require("foo")
                            // import * as x from "foo"
                            if (!isExportedImport)
                                write("var ");
                            emitModuleMemberName(namespaceDeclaration);
                            write(" = ");
                        }
                        else {
                            // import "foo"
                            // import x from "foo"
                            // import { x, y } from "foo"
                            // import d, * as x from "foo"
                            // import d, { x, y } from "foo"
                            var isNakedImport = 222 /* ImportDeclaration */ && !node.importClause;
                            if (!isNakedImport) {
                                write("var ");
                                write(getGeneratedNameForNode(node));
                                write(" = ");
                            }
                        }
                        emitRequire(ts.getExternalModuleName(node));
                        if (namespaceDeclaration && isDefaultImport(node)) {
                            // import d, * as x from "foo"
                            write(", ");
                            emitModuleMemberName(namespaceDeclaration);
                            write(" = ");
                            write(getGeneratedNameForNode(node));
                        }
                        write(";");
                        emitEnd(node);
                        emitExportImportAssignments(node);
                        emitTrailingComments(node);
                    }
                    else {
                        if (isExportedImport) {
                            emitModuleMemberName(namespaceDeclaration);
                            write(" = ");
                            emit(namespaceDeclaration.name);
                            write(";");
                        }
                        else if (namespaceDeclaration && isDefaultImport(node)) {
                            // import d, * as x from "foo"
                            write("var ");
                            emitModuleMemberName(namespaceDeclaration);
                            write(" = ");
                            write(getGeneratedNameForNode(node));
                            write(";");
                        }
                        emitExportImportAssignments(node);
                    }
                }
            }
            function emitImportEqualsDeclaration(node) {
                if (ts.isExternalModuleImportEqualsDeclaration(node)) {
                    emitExternalImportDeclaration(node);
                    return;
                }
                // preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when
                // - current file is not external module
                // - import declaration is top level and target is value imported by entity name
                if (resolver.isReferencedAliasDeclaration(node) ||
                    (!ts.isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportEqualsWithEntityName(node))) {
                    emitLeadingComments(node);
                    emitStart(node);
                    // variable declaration for import-equals declaration can be hoisted in system modules
                    // in this case 'var' should be omitted and emit should contain only initialization
                    var variableDeclarationIsHoisted = shouldHoistVariable(node, /*checkIfSourceFileLevelDecl*/ true);
                    // is it top level export import v = a.b.c in system module?
                    // if yes - it needs to be rewritten as exporter('v', v = a.b.c)
                    var isExported = isSourceFileLevelDeclarationInSystemJsModule(node, /*isExported*/ true);
                    if (!variableDeclarationIsHoisted) {
                        ts.Debug.assert(!isExported);
                        if (isES6ExportedDeclaration(node)) {
                            write("export ");
                            write("var ");
                        }
                        else if (!(node.flags & 1 /* Export */)) {
                            write("var ");
                        }
                    }
                    if (isExported) {
                        write(exportFunctionForFile + "(\"");
                        emitNodeWithoutSourceMap(node.name);
                        write("\", ");
                    }
                    emitModuleMemberName(node);
                    write(" = ");
                    emit(node.moduleReference);
                    if (isExported) {
                        write(")");
                    }
                    write(";");
                    emitEnd(node);
                    emitExportImportAssignments(node);
                    emitTrailingComments(node);
                }
            }
            function emitExportDeclaration(node) {
                ts.Debug.assert(modulekind !== 4 /* System */);
                if (modulekind !== 5 /* ES6 */) {
                    if (node.moduleSpecifier && (!node.exportClause || resolver.isValueAliasDeclaration(node))) {
                        emitStart(node);
                        var generatedName = getGeneratedNameForNode(node);
                        if (node.exportClause) {
                            // export { x, y, ... } from "foo"
                            if (modulekind !== 2 /* AMD */) {
                                write("var ");
                                write(generatedName);
                                write(" = ");
                                emitRequire(ts.getExternalModuleName(node));
                                write(";");
                            }
                            for (var _a = 0, _b = node.exportClause.elements; _a < _b.length; _a++) {
                                var specifier = _b[_a];
                                if (resolver.isValueAliasDeclaration(specifier)) {
                                    writeLine();
                                    emitStart(specifier);
                                    emitContainingModuleName(specifier);
                                    write(".");
                                    emitNodeWithCommentsAndWithoutSourcemap(specifier.name);
                                    write(" = ");
                                    write(generatedName);
                                    write(".");
                                    emitNodeWithCommentsAndWithoutSourcemap(specifier.propertyName || specifier.name);
                                    write(";");
                                    emitEnd(specifier);
                                }
                            }
                        }
                        else {
                            // export * from "foo"
                            writeLine();
                            write("__export(");
                            if (modulekind !== 2 /* AMD */) {
                                emitRequire(ts.getExternalModuleName(node));
                            }
                            else {
                                write(generatedName);
                            }
                            write(");");
                        }
                        emitEnd(node);
                    }
                }
                else {
                    if (!node.exportClause || resolver.isValueAliasDeclaration(node)) {
                        write("export ");
                        if (node.exportClause) {
                            // export { x, y, ... }
                            write("{ ");
                            emitExportOrImportSpecifierList(node.exportClause.elements, resolver.isValueAliasDeclaration);
                            write(" }");
                        }
                        else {
                            write("*");
                        }
                        if (node.moduleSpecifier) {
                            write(" from ");
                            emit(node.moduleSpecifier);
                        }
                        write(";");
                    }
                }
            }
            function emitExportOrImportSpecifierList(specifiers, shouldEmit) {
                ts.Debug.assert(modulekind === 5 /* ES6 */);
                var needsComma = false;
                for (var _a = 0; _a < specifiers.length; _a++) {
                    var specifier = specifiers[_a];
                    if (shouldEmit(specifier)) {
                        if (needsComma) {
                            write(", ");
                        }
                        if (specifier.propertyName) {
                            emit(specifier.propertyName);
                            write(" as ");
                        }
                        emit(specifier.name);
                        needsComma = true;
                    }
                }
            }
            function emitExportAssignment(node) {
                if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) {
                    if (modulekind === 5 /* ES6 */) {
                        writeLine();
                        emitStart(node);
                        write("export default ");
                        var expression = node.expression;
                        emit(expression);
                        if (expression.kind !== 213 /* FunctionDeclaration */ &&
                            expression.kind !== 214 /* ClassDeclaration */) {
                            write(";");
                        }
                        emitEnd(node);
                    }
                    else {
                        writeLine();
                        emitStart(node);
                        if (modulekind === 4 /* System */) {
                            write(exportFunctionForFile + "(\"default\",");
                            emit(node.expression);
                            write(")");
                        }
                        else {
                            emitEs6ExportDefaultCompat(node);
                            emitContainingModuleName(node);
                            if (languageVersion === 0 /* ES3 */) {
                                write("[\"default\"] = ");
                            }
                            else {
                                write(".default = ");
                            }
                            emit(node.expression);
                        }
                        write(";");
                        emitEnd(node);
                    }
                }
            }
            function collectExternalModuleInfo(sourceFile) {
                externalImports = [];
                exportSpecifiers = {};
                exportEquals = undefined;
                hasExportStars = false;
                for (var _a = 0, _b = sourceFile.statements; _a < _b.length; _a++) {
                    var node = _b[_a];
                    switch (node.kind) {
                        case 222 /* ImportDeclaration */:
                            if (!node.importClause ||
                                resolver.isReferencedAliasDeclaration(node.importClause, /*checkChildren*/ true)) {
                                // import "mod"
                                // import x from "mod" where x is referenced
                                // import * as x from "mod" where x is referenced
                                // import { x, y } from "mod" where at least one import is referenced
                                externalImports.push(node);
                            }
                            break;
                        case 221 /* ImportEqualsDeclaration */:
                            if (node.moduleReference.kind === 232 /* ExternalModuleReference */ && resolver.isReferencedAliasDeclaration(node)) {
                                // import x = require("mod") where x is referenced
                                externalImports.push(node);
                            }
                            break;
                        case 228 /* ExportDeclaration */:
                            if (node.moduleSpecifier) {
                                if (!node.exportClause) {
                                    // export * from "mod"
                                    externalImports.push(node);
                                    hasExportStars = true;
                                }
                                else if (resolver.isValueAliasDeclaration(node)) {
                                    // export { x, y } from "mod" where at least one export is a value symbol
                                    externalImports.push(node);
                                }
                            }
                            else {
                                // export { x, y }
                                for (var _c = 0, _d = node.exportClause.elements; _c < _d.length; _c++) {
                                    var specifier = _d[_c];
                                    var name_25 = (specifier.propertyName || specifier.name).text;
                                    (exportSpecifiers[name_25] || (exportSpecifiers[name_25] = [])).push(specifier);
                                }
                            }
                            break;
                        case 227 /* ExportAssignment */:
                            if (node.isExportEquals && !exportEquals) {
                                // export = x
                                exportEquals = node;
                            }
                            break;
                    }
                }
            }
            function emitExportStarHelper() {
                if (hasExportStars) {
                    writeLine();
                    write("function __export(m) {");
                    increaseIndent();
                    writeLine();
                    write("for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];");
                    decreaseIndent();
                    writeLine();
                    write("}");
                }
            }
            function getLocalNameForExternalImport(node) {
                var namespaceDeclaration = getNamespaceDeclarationNode(node);
                if (namespaceDeclaration && !isDefaultImport(node)) {
                    return ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name);
                }
                if (node.kind === 222 /* ImportDeclaration */ && node.importClause) {
                    return getGeneratedNameForNode(node);
                }
                if (node.kind === 228 /* ExportDeclaration */ && node.moduleSpecifier) {
                    return getGeneratedNameForNode(node);
                }
            }
            function getExternalModuleNameText(importNode) {
                var moduleName = ts.getExternalModuleName(importNode);
                if (moduleName.kind === 9 /* StringLiteral */) {
                    return tryRenameExternalModule(moduleName) || getLiteralText(moduleName);
                }
                return undefined;
            }
            function emitVariableDeclarationsForImports() {
                if (externalImports.length === 0) {
                    return;
                }
                writeLine();
                var started = false;
                for (var _a = 0; _a < externalImports.length; _a++) {
                    var importNode = externalImports[_a];
                    // do not create variable declaration for exports and imports that lack import clause
                    var skipNode = importNode.kind === 228 /* ExportDeclaration */ ||
                        (importNode.kind === 222 /* ImportDeclaration */ && !importNode.importClause);
                    if (skipNode) {
                        continue;
                    }
                    if (!started) {
                        write("var ");
                        started = true;
                    }
                    else {
                        write(", ");
                    }
                    write(getLocalNameForExternalImport(importNode));
                }
                if (started) {
                    write(";");
                }
            }
            function emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations) {
                // when resolving exports local exported entries/indirect exported entries in the module
                // should always win over entries with similar names that were added via star exports
                // to support this we store names of local/indirect exported entries in a set.
                // this set is used to filter names brought by star expors.
                if (!hasExportStars) {
                    // local names set is needed only in presence of star exports
                    return undefined;
                }
                // local names set should only be added if we have anything exported
                if (!exportedDeclarations && ts.isEmpty(exportSpecifiers)) {
                    // no exported declarations (export var ...) or export specifiers (export {x})
                    // check if we have any non star export declarations.
                    var hasExportDeclarationWithExportClause = false;
                    for (var _a = 0; _a < externalImports.length; _a++) {
                        var externalImport = externalImports[_a];
                        if (externalImport.kind === 228 /* ExportDeclaration */ && externalImport.exportClause) {
                            hasExportDeclarationWithExportClause = true;
                            break;
                        }
                    }
                    if (!hasExportDeclarationWithExportClause) {
                        // we still need to emit exportStar helper
                        return emitExportStarFunction(/*localNames*/ undefined);
                    }
                }
                var exportedNamesStorageRef = makeUniqueName("exportedNames");
                writeLine();
                write("var " + exportedNamesStorageRef + " = {");
                increaseIndent();
                var started = false;
                if (exportedDeclarations) {
                    for (var i = 0; i < exportedDeclarations.length; ++i) {
                        // write name of exported declaration, i.e 'export var x...'
                        writeExportedName(exportedDeclarations[i]);
                    }
                }
                if (exportSpecifiers) {
                    for (var n in exportSpecifiers) {
                        for (var _b = 0, _c = exportSpecifiers[n]; _b < _c.length; _b++) {
                            var specifier = _c[_b];
                            // write name of export specified, i.e. 'export {x}'
                            writeExportedName(specifier.name);
                        }
                    }
                }
                for (var _d = 0; _d < externalImports.length; _d++) {
                    var externalImport = externalImports[_d];
                    if (externalImport.kind !== 228 /* ExportDeclaration */) {
                        continue;
                    }
                    var exportDecl = externalImport;
                    if (!exportDecl.exportClause) {
                        // export * from ...
                        continue;
                    }
                    for (var _e = 0, _f = exportDecl.exportClause.elements; _e < _f.length; _e++) {
                        var element = _f[_e];
                        // write name of indirectly exported entry, i.e. 'export {x} from ...'
                        writeExportedName(element.name || element.propertyName);
                    }
                }
                decreaseIndent();
                writeLine();
                write("};");
                return emitExportStarFunction(exportedNamesStorageRef);
                function emitExportStarFunction(localNames) {
                    var exportStarFunction = makeUniqueName("exportStar");
                    writeLine();
                    // define an export star helper function
                    write("function " + exportStarFunction + "(m) {");
                    increaseIndent();
                    writeLine();
                    write("var exports = {};");
                    writeLine();
                    write("for(var n in m) {");
                    increaseIndent();
                    writeLine();
                    write("if (n !== \"default\"");
                    if (localNames) {
                        write("&& !" + localNames + ".hasOwnProperty(n)");
                    }
                    write(") exports[n] = m[n];");
                    decreaseIndent();
                    writeLine();
                    write("}");
                    writeLine();
                    write(exportFunctionForFile + "(exports);");
                    decreaseIndent();
                    writeLine();
                    write("}");
                    return exportStarFunction;
                }
                function writeExportedName(node) {
                    // do not record default exports
                    // they are local to module and never overwritten (explicitly skipped) by star export
                    if (node.kind !== 69 /* Identifier */ && node.flags & 1024 /* Default */) {
                        return;
                    }
                    if (started) {
                        write(",");
                    }
                    else {
                        started = true;
                    }
                    writeLine();
                    write("'");
                    if (node.kind === 69 /* Identifier */) {
                        emitNodeWithCommentsAndWithoutSourcemap(node);
                    }
                    else {
                        emitDeclarationName(node);
                    }
                    write("': true");
                }
            }
            function processTopLevelVariableAndFunctionDeclarations(node) {
                // per ES6 spec:
                // 15.2.1.16.4 ModuleDeclarationInstantiation() Concrete Method
                // - var declarations are initialized to undefined - 14.a.ii
                // - function/generator declarations are instantiated - 16.a.iv
                // this means that after module is instantiated but before its evaluation
                // exported functions are already accessible at import sites
                // in theory we should hoist only exported functions and its dependencies
                // in practice to simplify things we'll hoist all source level functions and variable declaration
                // including variables declarations for module and class declarations
                var hoistedVars;
                var hoistedFunctionDeclarations;
                var exportedDeclarations;
                visit(node);
                if (hoistedVars) {
                    writeLine();
                    write("var ");
                    var seen = {};
                    for (var i = 0; i < hoistedVars.length; ++i) {
                        var local = hoistedVars[i];
                        var name_26 = local.kind === 69 /* Identifier */
                            ? local
                            : local.name;
                        if (name_26) {
                            // do not emit duplicate entries (in case of declaration merging) in the list of hoisted variables
                            var text = ts.unescapeIdentifier(name_26.text);
                            if (ts.hasProperty(seen, text)) {
                                continue;
                            }
                            else {
                                seen[text] = text;
                            }
                        }
                        if (i !== 0) {
                            write(", ");
                        }
                        if (local.kind === 214 /* ClassDeclaration */ || local.kind === 218 /* ModuleDeclaration */ || local.kind === 217 /* EnumDeclaration */) {
                            emitDeclarationName(local);
                        }
                        else {
                            emit(local);
                        }
                        var flags = ts.getCombinedNodeFlags(local.kind === 69 /* Identifier */ ? local.parent : local);
                        if (flags & 1 /* Export */) {
                            if (!exportedDeclarations) {
                                exportedDeclarations = [];
                            }
                            exportedDeclarations.push(local);
                        }
                    }
                    write(";");
                }
                if (hoistedFunctionDeclarations) {
                    for (var _a = 0; _a < hoistedFunctionDeclarations.length; _a++) {
                        var f = hoistedFunctionDeclarations[_a];
                        writeLine();
                        emit(f);
                        if (f.flags & 1 /* Export */) {
                            if (!exportedDeclarations) {
                                exportedDeclarations = [];
                            }
                            exportedDeclarations.push(f);
                        }
                    }
                }
                return exportedDeclarations;
                function visit(node) {
                    if (node.flags & 2 /* Ambient */) {
                        return;
                    }
                    if (node.kind === 213 /* FunctionDeclaration */) {
                        if (!hoistedFunctionDeclarations) {
                            hoistedFunctionDeclarations = [];
                        }
                        hoistedFunctionDeclarations.push(node);
                        return;
                    }
                    if (node.kind === 214 /* ClassDeclaration */) {
                        if (!hoistedVars) {
                            hoistedVars = [];
                        }
                        hoistedVars.push(node);
                        return;
                    }
                    if (node.kind === 217 /* EnumDeclaration */) {
                        if (shouldEmitEnumDeclaration(node)) {
                            if (!hoistedVars) {
                                hoistedVars = [];
                            }
                            hoistedVars.push(node);
                        }
                        return;
                    }
                    if (node.kind === 218 /* ModuleDeclaration */) {
                        if (shouldEmitModuleDeclaration(node)) {
                            if (!hoistedVars) {
                                hoistedVars = [];
                            }
                            hoistedVars.push(node);
                        }
                        return;
                    }
                    if (node.kind === 211 /* VariableDeclaration */ || node.kind === 163 /* BindingElement */) {
                        if (shouldHoistVariable(node, /*checkIfSourceFileLevelDecl*/ false)) {
                            var name_27 = node.name;
                            if (name_27.kind === 69 /* Identifier */) {
                                if (!hoistedVars) {
                                    hoistedVars = [];
                                }
                                hoistedVars.push(name_27);
                            }
                            else {
                                ts.forEachChild(name_27, visit);
                            }
                        }
                        return;
                    }
                    if (ts.isInternalModuleImportEqualsDeclaration(node) && resolver.isValueAliasDeclaration(node)) {
                        if (!hoistedVars) {
                            hoistedVars = [];
                        }
                        hoistedVars.push(node.name);
                        return;
                    }
                    if (ts.isBindingPattern(node)) {
                        ts.forEach(node.elements, visit);
                        return;
                    }
                    if (!ts.isDeclaration(node)) {
                        ts.forEachChild(node, visit);
                    }
                }
            }
            function shouldHoistVariable(node, checkIfSourceFileLevelDecl) {
                if (checkIfSourceFileLevelDecl && !shouldHoistDeclarationInSystemJsModule(node)) {
                    return false;
                }
                // hoist variable if
                // - it is not block scoped
                // - it is top level block scoped
                // if block scoped variables are nested in some another block then
                // no other functions can use them except ones that are defined at least in the same block
                return (ts.getCombinedNodeFlags(node) & 49152 /* BlockScoped */) === 0 ||
                    ts.getEnclosingBlockScopeContainer(node).kind === 248 /* SourceFile */;
            }
            function isCurrentFileSystemExternalModule() {
                return modulekind === 4 /* System */ && ts.isExternalModule(currentSourceFile);
            }
            function emitSystemModuleBody(node, dependencyGroups, startIndex) {
                // shape of the body in system modules:
                // function (exports) {
                //     <list of local aliases for imports>
                //     <hoisted function declarations>
                //     <hoisted variable declarations>
                //     return {
                //         setters: [
                //             <list of setter function for imports>
                //         ],
                //         execute: function() {
                //             <module statements>
                //         }
                //     }
                //     <temp declarations>
                // }
                // I.e:
                // import {x} from 'file1'
                // var y = 1;
                // export function foo() { return y + x(); }
                // console.log(y);
                // will be transformed to
                // function(exports) {
                //     var file1; // local alias
                //     var y;
                //     function foo() { return y + file1.x(); }
                //     exports("foo", foo);
                //     return {
                //         setters: [
                //             function(v) { file1 = v }
                //         ],
                //         execute(): function() {
                //             y = 1;
                //             console.log(y);
                //         }
                //     };
                // }
                emitVariableDeclarationsForImports();
                writeLine();
                var exportedDeclarations = processTopLevelVariableAndFunctionDeclarations(node);
                var exportStarFunction = emitLocalStorageForExportedNamesIfNecessary(exportedDeclarations);
                writeLine();
                write("return {");
                increaseIndent();
                writeLine();
                emitSetters(exportStarFunction, dependencyGroups);
                writeLine();
                emitExecute(node, startIndex);
                decreaseIndent();
                writeLine();
                write("}"); // return
                emitTempDeclarations(/*newLine*/ true);
            }
            function emitSetters(exportStarFunction, dependencyGroups) {
                write("setters:[");
                for (var i = 0; i < dependencyGroups.length; ++i) {
                    if (i !== 0) {
                        write(",");
                    }
                    writeLine();
                    increaseIndent();
                    var group = dependencyGroups[i];
                    // derive a unique name for parameter from the first named entry in the group
                    var parameterName = makeUniqueName(ts.forEach(group, getLocalNameForExternalImport) || "");
                    write("function (" + parameterName + ") {");
                    increaseIndent();
                    for (var _a = 0; _a < group.length; _a++) {
                        var entry = group[_a];
                        var importVariableName = getLocalNameForExternalImport(entry) || "";
                        switch (entry.kind) {
                            case 222 /* ImportDeclaration */:
                                if (!entry.importClause) {
                                    // 'import "..."' case
                                    // module is imported only for side-effects, no emit required
                                    break;
                                }
                            // fall-through
                            case 221 /* ImportEqualsDeclaration */:
                                ts.Debug.assert(importVariableName !== "");
                                writeLine();
                                // save import into the local
                                write(importVariableName + " = " + parameterName + ";");
                                writeLine();
                                break;
                            case 228 /* ExportDeclaration */:
                                ts.Debug.assert(importVariableName !== "");
                                if (entry.exportClause) {
                                    // export {a, b as c} from 'foo'
                                    // emit as:
                                    // exports_({
                                    //    "a": _["a"],
                                    //    "c": _["b"]
                                    // });
                                    writeLine();
                                    write(exportFunctionForFile + "({");
                                    writeLine();
                                    increaseIndent();
                                    for (var i_2 = 0, len = entry.exportClause.elements.length; i_2 < len; ++i_2) {
                                        if (i_2 !== 0) {
                                            write(",");
                                            writeLine();
                                        }
                                        var e = entry.exportClause.elements[i_2];
                                        write("\"");
                                        emitNodeWithCommentsAndWithoutSourcemap(e.name);
                                        write("\": " + parameterName + "[\"");
                                        emitNodeWithCommentsAndWithoutSourcemap(e.propertyName || e.name);
                                        write("\"]");
                                    }
                                    decreaseIndent();
                                    writeLine();
                                    write("});");
                                }
                                else {
                                    writeLine();
                                    // export * from 'foo'
                                    // emit as:
                                    // exportStar(_foo);
                                    write(exportStarFunction + "(" + parameterName + ");");
                                }
                                writeLine();
                                break;
                        }
                    }
                    decreaseIndent();
                    write("}");
                    decreaseIndent();
                }
                write("],");
            }
            function emitExecute(node, startIndex) {
                write("execute: function() {");
                increaseIndent();
                writeLine();
                for (var i = startIndex; i < node.statements.length; ++i) {
                    var statement = node.statements[i];
                    switch (statement.kind) {
                        // - function declarations are not emitted because they were already hoisted
                        // - import declarations are not emitted since they are already handled in setters
                        // - export declarations with module specifiers are not emitted since they were already written in setters
                        // - export declarations without module specifiers are emitted preserving the order
                        case 213 /* FunctionDeclaration */:
                        case 222 /* ImportDeclaration */:
                            continue;
                        case 228 /* ExportDeclaration */:
                            if (!statement.moduleSpecifier) {
                                for (var _a = 0, _b = statement.exportClause.elements; _a < _b.length; _a++) {
                                    var element = _b[_a];
                                    // write call to exporter function for every export specifier in exports list
                                    emitExportSpecifierInSystemModule(element);
                                }
                            }
                            continue;
                        case 221 /* ImportEqualsDeclaration */:
                            if (!ts.isInternalModuleImportEqualsDeclaration(statement)) {
                                // - import equals declarations that import external modules are not emitted
                                continue;
                            }
                        // fall-though for import declarations that import internal modules
                        default:
                            writeLine();
                            emit(statement);
                    }
                }
                decreaseIndent();
                writeLine();
                write("}"); // execute
            }
            function emitSystemModule(node) {
                collectExternalModuleInfo(node);
                // System modules has the following shape
                // System.register(['dep-1', ... 'dep-n'], function(exports) {/* module body function */})
                // 'exports' here is a function 'exports<T>(name: string, value: T): T' that is used to publish exported values.
                // 'exports' returns its 'value' argument so in most cases expressions
                // that mutate exported values can be rewritten as:
                // expr -> exports('name', expr).
                // The only exception in this rule is postfix unary operators,
                // see comment to 'emitPostfixUnaryExpression' for more details
                ts.Debug.assert(!exportFunctionForFile);
                // make sure that  name of 'exports' function does not conflict with existing identifiers
                exportFunctionForFile = makeUniqueName("exports");
                writeLine();
                write("System.register(");
                if (node.moduleName) {
                    write("\"" + node.moduleName + "\", ");
                }
                write("[");
                var groupIndices = {};
                var dependencyGroups = [];
                for (var i = 0; i < externalImports.length; ++i) {
                    var text = getExternalModuleNameText(externalImports[i]);
                    if (ts.hasProperty(groupIndices, text)) {
                        // deduplicate/group entries in dependency list by the dependency name
                        var groupIndex = groupIndices[text];
                        dependencyGroups[groupIndex].push(externalImports[i]);
                        continue;
                    }
                    else {
                        groupIndices[text] = dependencyGroups.length;
                        dependencyGroups.push([externalImports[i]]);
                    }
                    if (i !== 0) {
                        write(", ");
                    }
                    write(text);
                }
                write("], function(" + exportFunctionForFile + ") {");
                writeLine();
                increaseIndent();
                var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ true);
                emitEmitHelpers(node);
                emitCaptureThisForNodeIfNecessary(node);
                emitSystemModuleBody(node, dependencyGroups, startIndex);
                decreaseIndent();
                writeLine();
                write("});");
            }
            function getAMDDependencyNames(node, includeNonAmdDependencies) {
                // names of modules with corresponding parameter in the factory function
                var aliasedModuleNames = [];
                // names of modules with no corresponding parameters in factory function
                var unaliasedModuleNames = [];
                var importAliasNames = []; // names of the parameters in the factory function; these
                // parameters need to match the indexes of the corresponding
                // module names in aliasedModuleNames.
                // Fill in amd-dependency tags
                for (var _a = 0, _b = node.amdDependencies; _a < _b.length; _a++) {
                    var amdDependency = _b[_a];
                    if (amdDependency.name) {
                        aliasedModuleNames.push("\"" + amdDependency.path + "\"");
                        importAliasNames.push(amdDependency.name);
                    }
                    else {
                        unaliasedModuleNames.push("\"" + amdDependency.path + "\"");
                    }
                }
                for (var _c = 0; _c < externalImports.length; _c++) {
                    var importNode = externalImports[_c];
                    // Find the name of the external module
                    var externalModuleName = getExternalModuleNameText(importNode);
                    // Find the name of the module alias, if there is one
                    var importAliasName = getLocalNameForExternalImport(importNode);
                    if (includeNonAmdDependencies && importAliasName) {
                        aliasedModuleNames.push(externalModuleName);
                        importAliasNames.push(importAliasName);
                    }
                    else {
                        unaliasedModuleNames.push(externalModuleName);
                    }
                }
                return { aliasedModuleNames: aliasedModuleNames, unaliasedModuleNames: unaliasedModuleNames, importAliasNames: importAliasNames };
            }
            function emitAMDDependencies(node, includeNonAmdDependencies) {
                // An AMD define function has the following shape:
                //     define(id?, dependencies?, factory);
                //
                // This has the shape of
                //     define(name, ["module1", "module2"], function (module1Alias) {
                // The location of the alias in the parameter list in the factory function needs to
                // match the position of the module name in the dependency list.
                //
                // To ensure this is true in cases of modules with no aliases, e.g.:
                // `import "module"` or `<amd-dependency path= "a.css" />`
                // we need to add modules without alias names to the end of the dependencies list
                var dependencyNames = getAMDDependencyNames(node, includeNonAmdDependencies);
                emitAMDDependencyList(dependencyNames);
                write(", ");
                emitAMDFactoryHeader(dependencyNames);
            }
            function emitAMDDependencyList(_a) {
                var aliasedModuleNames = _a.aliasedModuleNames, unaliasedModuleNames = _a.unaliasedModuleNames;
                write("[\"require\", \"exports\"");
                if (aliasedModuleNames.length) {
                    write(", ");
                    write(aliasedModuleNames.join(", "));
                }
                if (unaliasedModuleNames.length) {
                    write(", ");
                    write(unaliasedModuleNames.join(", "));
                }
                write("]");
            }
            function emitAMDFactoryHeader(_a) {
                var importAliasNames = _a.importAliasNames;
                write("function (require, exports");
                if (importAliasNames.length) {
                    write(", ");
                    write(importAliasNames.join(", "));
                }
                write(") {");
            }
            function emitAMDModule(node) {
                emitEmitHelpers(node);
                collectExternalModuleInfo(node);
                writeLine();
                write("define(");
                if (node.moduleName) {
                    write("\"" + node.moduleName + "\", ");
                }
                emitAMDDependencies(node, /*includeNonAmdDependencies*/ true);
                increaseIndent();
                var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ true);
                emitExportStarHelper();
                emitCaptureThisForNodeIfNecessary(node);
                emitLinesStartingAt(node.statements, startIndex);
                emitTempDeclarations(/*newLine*/ true);
                emitExportEquals(/*emitAsReturn*/ true);
                decreaseIndent();
                writeLine();
                write("});");
            }
            function emitCommonJSModule(node) {
                var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false);
                emitEmitHelpers(node);
                collectExternalModuleInfo(node);
                emitExportStarHelper();
                emitCaptureThisForNodeIfNecessary(node);
                emitLinesStartingAt(node.statements, startIndex);
                emitTempDeclarations(/*newLine*/ true);
                emitExportEquals(/*emitAsReturn*/ false);
            }
            function emitUMDModule(node) {
                emitEmitHelpers(node);
                collectExternalModuleInfo(node);
                var dependencyNames = getAMDDependencyNames(node, /*includeNonAmdDependencies*/ false);
                // Module is detected first to support Browserify users that load into a browser with an AMD loader
                writeLines("(function (factory) {\n    if (typeof module === 'object' && typeof module.exports === 'object') {\n        var v = factory(require, exports); if (v !== undefined) module.exports = v;\n    }\n    else if (typeof define === 'function' && define.amd) {\n        define(");
                emitAMDDependencyList(dependencyNames);
                write(", factory);");
                writeLines("    }\n})(");
                emitAMDFactoryHeader(dependencyNames);
                increaseIndent();
                var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ true);
                emitExportStarHelper();
                emitCaptureThisForNodeIfNecessary(node);
                emitLinesStartingAt(node.statements, startIndex);
                emitTempDeclarations(/*newLine*/ true);
                emitExportEquals(/*emitAsReturn*/ true);
                decreaseIndent();
                writeLine();
                write("});");
            }
            function emitES6Module(node) {
                externalImports = undefined;
                exportSpecifiers = undefined;
                exportEquals = undefined;
                hasExportStars = false;
                var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false);
                emitEmitHelpers(node);
                emitCaptureThisForNodeIfNecessary(node);
                emitLinesStartingAt(node.statements, startIndex);
                emitTempDeclarations(/*newLine*/ true);
                // Emit exportDefault if it exists will happen as part
                // or normal statement emit.
            }
            function emitExportEquals(emitAsReturn) {
                if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) {
                    writeLine();
                    emitStart(exportEquals);
                    write(emitAsReturn ? "return " : "module.exports = ");
                    emit(exportEquals.expression);
                    write(";");
                    emitEnd(exportEquals);
                }
            }
            function emitJsxElement(node) {
                switch (compilerOptions.jsx) {
                    case 2 /* React */:
                        jsxEmitReact(node);
                        break;
                    case 1 /* Preserve */:
                    // Fall back to preserve if None was specified (we'll error earlier)
                    default:
                        jsxEmitPreserve(node);
                        break;
                }
            }
            function trimReactWhitespaceAndApplyEntities(node) {
                var result = undefined;
                var text = ts.getTextOfNode(node, /*includeTrivia*/ true);
                var firstNonWhitespace = 0;
                var lastNonWhitespace = -1;
                // JSX trims whitespace at the end and beginning of lines, except that the
                // start/end of a tag is considered a start/end of a line only if that line is
                // on the same line as the closing tag. See examples in tests/cases/conformance/jsx/tsxReactEmitWhitespace.tsx
                for (var i = 0; i < text.length; i++) {
                    var c = text.charCodeAt(i);
                    if (ts.isLineBreak(c)) {
                        if (firstNonWhitespace !== -1 && (lastNonWhitespace - firstNonWhitespace + 1 > 0)) {
                            var part = text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1);
                            result = (result ? result + "\" + ' ' + \"" : "") + ts.escapeString(part);
                        }
                        firstNonWhitespace = -1;
                    }
                    else if (!ts.isWhiteSpace(c)) {
                        lastNonWhitespace = i;
                        if (firstNonWhitespace === -1) {
                            firstNonWhitespace = i;
                        }
                    }
                }
                if (firstNonWhitespace !== -1) {
                    var part = text.substr(firstNonWhitespace);
                    result = (result ? result + "\" + ' ' + \"" : "") + ts.escapeString(part);
                }
                if (result) {
                    // Replace entities like
                    result = result.replace(/&(\w+);/g, function (s, m) {
                        if (entities[m] !== undefined) {
                            return String.fromCharCode(entities[m]);
                        }
                        else {
                            return s;
                        }
                    });
                }
                return result;
            }
            function getTextToEmit(node) {
                switch (compilerOptions.jsx) {
                    case 2 /* React */:
                        var text = trimReactWhitespaceAndApplyEntities(node);
                        if (text === undefined || text.length === 0) {
                            return undefined;
                        }
                        else {
                            return text;
                        }
                    case 1 /* Preserve */:
                    default:
                        return ts.getTextOfNode(node, /*includeTrivia*/ true);
                }
            }
            function emitJsxText(node) {
                switch (compilerOptions.jsx) {
                    case 2 /* React */:
                        write("\"");
                        write(trimReactWhitespaceAndApplyEntities(node));
                        write("\"");
                        break;
                    case 1 /* Preserve */:
                    default:
                        writer.writeLiteral(ts.getTextOfNode(node, /*includeTrivia*/ true));
                        break;
                }
            }
            function emitJsxExpression(node) {
                if (node.expression) {
                    switch (compilerOptions.jsx) {
                        case 1 /* Preserve */:
                        default:
                            write("{");
                            emit(node.expression);
                            write("}");
                            break;
                        case 2 /* React */:
                            emit(node.expression);
                            break;
                    }
                }
            }
            function emitDirectivePrologues(statements, startWithNewLine) {
                for (var i = 0; i < statements.length; ++i) {
                    if (ts.isPrologueDirective(statements[i])) {
                        if (startWithNewLine || i > 0) {
                            writeLine();
                        }
                        emit(statements[i]);
                    }
                    else {
                        // return index of the first non prologue directive
                        return i;
                    }
                }
                return statements.length;
            }
            function writeLines(text) {
                var lines = text.split(/\r\n|\r|\n/g);
                for (var i = 0; i < lines.length; ++i) {
                    var line = lines[i];
                    if (line.length) {
                        writeLine();
                        write(line);
                    }
                }
            }
            function emitEmitHelpers(node) {
                // Only emit helpers if the user did not say otherwise.
                if (!compilerOptions.noEmitHelpers) {
                    // Only Emit __extends function when target ES5.
                    // For target ES6 and above, we can emit classDeclaration as is.
                    if ((languageVersion < 2 /* ES6 */) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & 8 /* EmitExtends */)) {
                        writeLines(extendsHelper);
                        extendsEmitted = true;
                    }
                    if (!decorateEmitted && resolver.getNodeCheckFlags(node) & 16 /* EmitDecorate */) {
                        writeLines(decorateHelper);
                        if (compilerOptions.emitDecoratorMetadata) {
                            writeLines(metadataHelper);
                        }
                        decorateEmitted = true;
                    }
                    if (!paramEmitted && resolver.getNodeCheckFlags(node) & 32 /* EmitParam */) {
                        writeLines(paramHelper);
                        paramEmitted = true;
                    }
                    if (!awaiterEmitted && resolver.getNodeCheckFlags(node) & 64 /* EmitAwaiter */) {
                        writeLines(awaiterHelper);
                        awaiterEmitted = true;
                    }
                }
            }
            function emitSourceFileNode(node) {
                // Start new file on new line
                writeLine();
                emitShebang();
                emitDetachedComments(node);
                if (ts.isExternalModule(node) || compilerOptions.isolatedModules) {
                    var emitModule = moduleEmitDelegates[modulekind] || moduleEmitDelegates[1 /* CommonJS */];
                    emitModule(node);
                }
                else {
                    // emit prologue directives prior to __extends
                    var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false);
                    externalImports = undefined;
                    exportSpecifiers = undefined;
                    exportEquals = undefined;
                    hasExportStars = false;
                    emitEmitHelpers(node);
                    emitCaptureThisForNodeIfNecessary(node);
                    emitLinesStartingAt(node.statements, startIndex);
                    emitTempDeclarations(/*newLine*/ true);
                }
                emitLeadingComments(node.endOfFileToken);
            }
            function emitNodeWithCommentsAndWithoutSourcemap(node) {
                emitNodeConsideringCommentsOption(node, emitNodeWithoutSourceMap);
            }
            function emitNodeConsideringCommentsOption(node, emitNodeConsideringSourcemap) {
                if (node) {
                    if (node.flags & 2 /* Ambient */) {
                        return emitCommentsOnNotEmittedNode(node);
                    }
                    if (isSpecializedCommentHandling(node)) {
                        // This is the node that will handle its own comments and sourcemap
                        return emitNodeWithoutSourceMap(node);
                    }
                    var emitComments_1 = shouldEmitLeadingAndTrailingComments(node);
                    if (emitComments_1) {
                        emitLeadingComments(node);
                    }
                    emitNodeConsideringSourcemap(node);
                    if (emitComments_1) {
                        emitTrailingComments(node);
                    }
                }
            }
            function emitNodeWithoutSourceMap(node) {
                if (node) {
                    emitJavaScriptWorker(node);
                }
            }
            function isSpecializedCommentHandling(node) {
                switch (node.kind) {
                    // All of these entities are emitted in a specialized fashion.  As such, we allow
                    // the specialized methods for each to handle the comments on the nodes.
                    case 215 /* InterfaceDeclaration */:
                    case 213 /* FunctionDeclaration */:
                    case 222 /* ImportDeclaration */:
                    case 221 /* ImportEqualsDeclaration */:
                    case 216 /* TypeAliasDeclaration */:
                    case 227 /* ExportAssignment */:
                        return true;
                }
            }
            function shouldEmitLeadingAndTrailingComments(node) {
                switch (node.kind) {
                    case 193 /* VariableStatement */:
                        return shouldEmitLeadingAndTrailingCommentsForVariableStatement(node);
                    case 218 /* ModuleDeclaration */:
                        // Only emit the leading/trailing comments for a module if we're actually
                        // emitting the module as well.
                        return shouldEmitModuleDeclaration(node);
                    case 217 /* EnumDeclaration */:
                        // Only emit the leading/trailing comments for an enum if we're actually
                        // emitting the module as well.
                        return shouldEmitEnumDeclaration(node);
                }
                // If the node is emitted in specialized fashion, dont emit comments as this node will handle
                // emitting comments when emitting itself
                ts.Debug.assert(!isSpecializedCommentHandling(node));
                // If this is the expression body of an arrow function that we're down-leveling,
                // then we don't want to emit comments when we emit the body.  It will have already
                // been taken care of when we emitted the 'return' statement for the function
                // expression body.
                if (node.kind !== 192 /* Block */ &&
                    node.parent &&
                    node.parent.kind === 174 /* ArrowFunction */ &&
                    node.parent.body === node &&
                    compilerOptions.target <= 1 /* ES5 */) {
                    return false;
                }
                // Emit comments for everything else.
                return true;
            }
            function emitJavaScriptWorker(node) {
                // Check if the node can be emitted regardless of the ScriptTarget
                switch (node.kind) {
                    case 69 /* Identifier */:
                        return emitIdentifier(node);
                    case 138 /* Parameter */:
                        return emitParameter(node);
                    case 143 /* MethodDeclaration */:
                    case 142 /* MethodSignature */:
                        return emitMethod(node);
                    case 145 /* GetAccessor */:
                    case 146 /* SetAccessor */:
                        return emitAccessor(node);
                    case 97 /* ThisKeyword */:
                        return emitThis(node);
                    case 95 /* SuperKeyword */:
                        return emitSuper(node);
                    case 93 /* NullKeyword */:
                        return write("null");
                    case 99 /* TrueKeyword */:
                        return write("true");
                    case 84 /* FalseKeyword */:
                        return write("false");
                    case 8 /* NumericLiteral */:
                    case 9 /* StringLiteral */:
                    case 10 /* RegularExpressionLiteral */:
                    case 11 /* NoSubstitutionTemplateLiteral */:
                    case 12 /* TemplateHead */:
                    case 13 /* TemplateMiddle */:
                    case 14 /* TemplateTail */:
                        return emitLiteral(node);
                    case 183 /* TemplateExpression */:
                        return emitTemplateExpression(node);
                    case 190 /* TemplateSpan */:
                        return emitTemplateSpan(node);
                    case 233 /* JsxElement */:
                    case 234 /* JsxSelfClosingElement */:
                        return emitJsxElement(node);
                    case 236 /* JsxText */:
                        return emitJsxText(node);
                    case 240 /* JsxExpression */:
                        return emitJsxExpression(node);
                    case 135 /* QualifiedName */:
                        return emitQualifiedName(node);
                    case 161 /* ObjectBindingPattern */:
                        return emitObjectBindingPattern(node);
                    case 162 /* ArrayBindingPattern */:
                        return emitArrayBindingPattern(node);
                    case 163 /* BindingElement */:
                        return emitBindingElement(node);
                    case 164 /* ArrayLiteralExpression */:
                        return emitArrayLiteral(node);
                    case 165 /* ObjectLiteralExpression */:
                        return emitObjectLiteral(node);
                    case 245 /* PropertyAssignment */:
                        return emitPropertyAssignment(node);
                    case 246 /* ShorthandPropertyAssignment */:
                        return emitShorthandPropertyAssignment(node);
                    case 136 /* ComputedPropertyName */:
                        return emitComputedPropertyName(node);
                    case 166 /* PropertyAccessExpression */:
                        return emitPropertyAccess(node);
                    case 167 /* ElementAccessExpression */:
                        return emitIndexedAccess(node);
                    case 168 /* CallExpression */:
                        return emitCallExpression(node);
                    case 169 /* NewExpression */:
                        return emitNewExpression(node);
                    case 170 /* TaggedTemplateExpression */:
                        return emitTaggedTemplateExpression(node);
                    case 171 /* TypeAssertionExpression */:
                        return emit(node.expression);
                    case 189 /* AsExpression */:
                        return emit(node.expression);
                    case 172 /* ParenthesizedExpression */:
                        return emitParenExpression(node);
                    case 213 /* FunctionDeclaration */:
                    case 173 /* FunctionExpression */:
                    case 174 /* ArrowFunction */:
                        return emitFunctionDeclaration(node);
                    case 175 /* DeleteExpression */:
                        return emitDeleteExpression(node);
                    case 176 /* TypeOfExpression */:
                        return emitTypeOfExpression(node);
                    case 177 /* VoidExpression */:
                        return emitVoidExpression(node);
                    case 178 /* AwaitExpression */:
                        return emitAwaitExpression(node);
                    case 179 /* PrefixUnaryExpression */:
                        return emitPrefixUnaryExpression(node);
                    case 180 /* PostfixUnaryExpression */:
                        return emitPostfixUnaryExpression(node);
                    case 181 /* BinaryExpression */:
                        return emitBinaryExpression(node);
                    case 182 /* ConditionalExpression */:
                        return emitConditionalExpression(node);
                    case 185 /* SpreadElementExpression */:
                        return emitSpreadElementExpression(node);
                    case 184 /* YieldExpression */:
                        return emitYieldExpression(node);
                    case 187 /* OmittedExpression */:
                        return;
                    case 192 /* Block */:
                    case 219 /* ModuleBlock */:
                        return emitBlock(node);
                    case 193 /* VariableStatement */:
                        return emitVariableStatement(node);
                    case 194 /* EmptyStatement */:
                        return write(";");
                    case 195 /* ExpressionStatement */:
                        return emitExpressionStatement(node);
                    case 196 /* IfStatement */:
                        return emitIfStatement(node);
                    case 197 /* DoStatement */:
                        return emitDoStatement(node);
                    case 198 /* WhileStatement */:
                        return emitWhileStatement(node);
                    case 199 /* ForStatement */:
                        return emitForStatement(node);
                    case 201 /* ForOfStatement */:
                    case 200 /* ForInStatement */:
                        return emitForInOrForOfStatement(node);
                    case 202 /* ContinueStatement */:
                    case 203 /* BreakStatement */:
                        return emitBreakOrContinueStatement(node);
                    case 204 /* ReturnStatement */:
                        return emitReturnStatement(node);
                    case 205 /* WithStatement */:
                        return emitWithStatement(node);
                    case 206 /* SwitchStatement */:
                        return emitSwitchStatement(node);
                    case 241 /* CaseClause */:
                    case 242 /* DefaultClause */:
                        return emitCaseOrDefaultClause(node);
                    case 207 /* LabeledStatement */:
                        return emitLabelledStatement(node);
                    case 208 /* ThrowStatement */:
                        return emitThrowStatement(node);
                    case 209 /* TryStatement */:
                        return emitTryStatement(node);
                    case 244 /* CatchClause */:
                        return emitCatchClause(node);
                    case 210 /* DebuggerStatement */:
                        return emitDebuggerStatement(node);
                    case 211 /* VariableDeclaration */:
                        return emitVariableDeclaration(node);
                    case 186 /* ClassExpression */:
                        return emitClassExpression(node);
                    case 214 /* ClassDeclaration */:
                        return emitClassDeclaration(node);
                    case 215 /* InterfaceDeclaration */:
                        return emitInterfaceDeclaration(node);
                    case 217 /* EnumDeclaration */:
                        return emitEnumDeclaration(node);
                    case 247 /* EnumMember */:
                        return emitEnumMember(node);
                    case 218 /* ModuleDeclaration */:
                        return emitModuleDeclaration(node);
                    case 222 /* ImportDeclaration */:
                        return emitImportDeclaration(node);
                    case 221 /* ImportEqualsDeclaration */:
                        return emitImportEqualsDeclaration(node);
                    case 228 /* ExportDeclaration */:
                        return emitExportDeclaration(node);
                    case 227 /* ExportAssignment */:
                        return emitExportAssignment(node);
                    case 248 /* SourceFile */:
                        return emitSourceFileNode(node);
                }
            }
            function hasDetachedComments(pos) {
                return detachedCommentsInfo !== undefined && ts.lastOrUndefined(detachedCommentsInfo).nodePos === pos;
            }
            function getLeadingCommentsWithoutDetachedComments() {
                // get the leading comments from detachedPos
                var leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, ts.lastOrUndefined(detachedCommentsInfo).detachedCommentEndPos);
                if (detachedCommentsInfo.length - 1) {
                    detachedCommentsInfo.pop();
                }
                else {
                    detachedCommentsInfo = undefined;
                }
                return leadingComments;
            }
            function isPinnedComments(comment) {
                return currentSourceFile.text.charCodeAt(comment.pos + 1) === 42 /* asterisk */ &&
                    currentSourceFile.text.charCodeAt(comment.pos + 2) === 33 /* exclamation */;
            }
            /**
             * Determine if the given comment is a triple-slash
             *
             * @return true if the comment is a triple-slash comment else false
             **/
            function isTripleSlashComment(comment) {
                // Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
                // so that we don't end up computing comment string and doing match for all // comments
                if (currentSourceFile.text.charCodeAt(comment.pos + 1) === 47 /* slash */ &&
                    comment.pos + 2 < comment.end &&
                    currentSourceFile.text.charCodeAt(comment.pos + 2) === 47 /* slash */) {
                    var textSubStr = currentSourceFile.text.substring(comment.pos, comment.end);
                    return textSubStr.match(ts.fullTripleSlashReferencePathRegEx) ||
                    textSubStr.match(ts.fullTripleSlashAMDReferencePathRegEx) ?
                        true : false;
                }
                return false;
            }
            function getLeadingCommentsToEmit(node) {
                // Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments
                if (node.parent) {
                    if (node.parent.kind === 248 /* SourceFile */ || node.pos !== node.parent.pos) {
                        if (hasDetachedComments(node.pos)) {
                            // get comments without detached comments
                            return getLeadingCommentsWithoutDetachedComments();
                        }
                        else {
                            // get the leading comments from the node
                            return ts.getLeadingCommentRangesOfNode(node, currentSourceFile);
                        }
                    }
                }
            }
            function getTrailingCommentsToEmit(node) {
                // Emit the trailing comments only if the parent's pos doesn't match because parent should take care of emitting these comments
                if (node.parent) {
                    if (node.parent.kind === 248 /* SourceFile */ || node.end !== node.parent.end) {
                        return ts.getTrailingCommentRanges(currentSourceFile.text, node.end);
                    }
                }
            }
            /**
             * Emit comments associated with node that will not be emitted into JS file
             */
            function emitCommentsOnNotEmittedNode(node) {
                emitLeadingCommentsWorker(node, /*isEmittedNode:*/ false);
            }
            function emitLeadingComments(node) {
                return emitLeadingCommentsWorker(node, /*isEmittedNode:*/ true);
            }
            function emitLeadingCommentsWorker(node, isEmittedNode) {
                if (compilerOptions.removeComments) {
                    return;
                }
                var leadingComments;
                if (isEmittedNode) {
                    leadingComments = getLeadingCommentsToEmit(node);
                }
                else {
                    // If the node will not be emitted in JS, remove all the comments(normal, pinned and ///) associated with the node,
                    // unless it is a triple slash comment at the top of the file.
                    // For Example:
                    //      /// <reference-path ...>
                    //      declare var x;
                    //      /// <reference-path ...>
                    //      interface F {}
                    //  The first /// will NOT be removed while the second one will be removed eventhough both node will not be emitted
                    if (node.pos === 0) {
                        leadingComments = ts.filter(getLeadingCommentsToEmit(node), isTripleSlashComment);
                    }
                }
                ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments);
                // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
                ts.emitComments(currentSourceFile, writer, leadingComments, /*trailingSeparator:*/ true, newLine, writeComment);
            }
            function emitTrailingComments(node) {
                if (compilerOptions.removeComments) {
                    return;
                }
                // Emit the trailing comments only if the parent's end doesn't match
                var trailingComments = getTrailingCommentsToEmit(node);
                // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
                ts.emitComments(currentSourceFile, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment);
            }
            /**
             * Emit trailing comments at the position. The term trailing comment is used here to describe following comment:
             *      x, /comment1/ y
             *        ^ => pos; the function will emit "comment1" in the emitJS
             */
            function emitTrailingCommentsOfPosition(pos) {
                if (compilerOptions.removeComments) {
                    return;
                }
                var trailingComments = ts.getTrailingCommentRanges(currentSourceFile.text, pos);
                // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
                ts.emitComments(currentSourceFile, writer, trailingComments, /*trailingSeparator*/ true, newLine, writeComment);
            }
            function emitLeadingCommentsOfPositionWorker(pos) {
                if (compilerOptions.removeComments) {
                    return;
                }
                var leadingComments;
                if (hasDetachedComments(pos)) {
                    // get comments without detached comments
                    leadingComments = getLeadingCommentsWithoutDetachedComments();
                }
                else {
                    // get the leading comments from the node
                    leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, pos);
                }
                ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, { pos: pos, end: pos }, leadingComments);
                // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
                ts.emitComments(currentSourceFile, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment);
            }
            function emitDetachedComments(node) {
                var leadingComments;
                if (compilerOptions.removeComments) {
                    // removeComments is true, only reserve pinned comment at the top of file
                    // For example:
                    //      /*! Pinned Comment */
                    //
                    //      var x = 10;
                    if (node.pos === 0) {
                        leadingComments = ts.filter(ts.getLeadingCommentRanges(currentSourceFile.text, node.pos), isPinnedComments);
                    }
                }
                else {
                    // removeComments is false, just get detached as normal and bypass the process to filter comment
                    leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, node.pos);
                }
                if (leadingComments) {
                    var detachedComments = [];
                    var lastComment;
                    ts.forEach(leadingComments, function (comment) {
                        if (lastComment) {
                            var lastCommentLine = ts.getLineOfLocalPosition(currentSourceFile, lastComment.end);
                            var commentLine = ts.getLineOfLocalPosition(currentSourceFile, comment.pos);
                            if (commentLine >= lastCommentLine + 2) {
                                // There was a blank line between the last comment and this comment.  This
                                // comment is not part of the copyright comments.  Return what we have so
                                // far.
                                return detachedComments;
                            }
                        }
                        detachedComments.push(comment);
                        lastComment = comment;
                    });
                    if (detachedComments.length) {
                        // All comments look like they could have been part of the copyright header.  Make
                        // sure there is at least one blank line between it and the node.  If not, it's not
                        // a copyright header.
                        var lastCommentLine = ts.getLineOfLocalPosition(currentSourceFile, ts.lastOrUndefined(detachedComments).end);
                        var nodeLine = ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node.pos));
                        if (nodeLine >= lastCommentLine + 2) {
                            // Valid detachedComments
                            ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments);
                            ts.emitComments(currentSourceFile, writer, detachedComments, /*trailingSeparator*/ true, newLine, writeComment);
                            var currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: ts.lastOrUndefined(detachedComments).end };
                            if (detachedCommentsInfo) {
                                detachedCommentsInfo.push(currentDetachedCommentInfo);
                            }
                            else {
                                detachedCommentsInfo = [currentDetachedCommentInfo];
                            }
                        }
                    }
                }
            }
            function emitShebang() {
                var shebang = ts.getShebang(currentSourceFile.text);
                if (shebang) {
                    write(shebang);
                }
            }
            var _a;
        }
        function emitFile(jsFilePath, sourceFile) {
            emitJavaScript(jsFilePath, sourceFile);
            if (compilerOptions.declaration) {
                ts.writeDeclarationFile(jsFilePath, sourceFile, host, resolver, diagnostics);
            }
        }
    }

targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature

targetSourceFile is when users only want one file in entire project to be emitted . This is used in compileOnSave feature