Creates an instance of the instruction coverage plugin
512740
def build_instruction_coverage_plugin() -> LaserPlugin:
        
        from mythril.laser.ethereum.plugins.implementations.coverage import (
            InstructionCoveragePlugin,
        )

        return InstructionCoveragePlugin()
303123
public static void main(String[] args) {
        // Parse arguments.
        String coverageDirName = null;
        if (args.length == 0) {
            System.out.println("Incorrect arguments.  Directory with coverage has to be specified.");
            System.exit(1);
        }
        coverageDirName = args[0];
        String mode = null;
        if (args.length > 1) {
            mode = args[1];
        }
        boolean forceCacheUse = false;
        if (args.length > 2) {
            forceCacheUse = args[2].equals(FORCE_CACHE_USE);
        }

        Set<String> allClasses = new HashSet<String>();
        Set<String> affectedClasses = new HashSet<String>();
        if (args.length > 3) {
            String options = args[3];
            Config.loadConfig(options, true);
        } else {
            Config.loadConfig();
        }

        List<String> nonAffectedClasses = findNonAffectedClasses(coverageDirName, forceCacheUse, allClasses, affectedClasses);
        
        // Print non affected classes.
        printNonAffectedClasses(allClasses, affectedClasses, nonAffectedClasses, mode);
    }
363070
function initPlugins(router, site) {
  return bluebird.all(module.exports.plugins.map(plugin => {
    return bluebird.try(() => {
      if (typeof plugin === 'function') {
        return plugin(router, pluginDBAdapter, publish, sites, site);
      } else {
        log('warn', 'Plugin is not a function');
        return bluebird.resolve();
      }
    });
  }));
}
1311507
def create_mcjit_compiler(module, target_machine):
    
    with ffi.OutputString() as outerr:
        engine = ffi.lib.LLVMPY_CreateMCJITCompiler(
                module, target_machine, outerr)
        if not engine:
            raise RuntimeError(str(outerr))

    target_machine._owned = True
    return ExecutionEngine(engine, module=module)
163592
private void simulateMethodHandle(final InvokeDynamicInstruction instruction) {
        final List<Element> arguments = IntStream.range(0, instruction.getDynamicIdentifier().getParameters().size())
                .mapToObj(t -> runtimeStack.pop()).collect(Collectors.toList());
        Collections.reverse(arguments);

        if (!instruction.getDynamicIdentifier().isStaticMethod())
            // first parameter is `this`
            arguments.remove(0);

        // adds the transferred arguments of the bootstrap call
        runtimeStack.push(new MethodHandle(instruction.getDynamicIdentifier().getReturnType(), instruction.getIdentifier(), arguments));
    }
190286
function(app, options) {
  app.post(WRITE_COVERAGE,
    bodyParser,
    (req, res) => {
      let map = istanbul.libCoverage.createCoverageMap();
      coverageHandler(map, options, req, res);
    },
    logError);
}
1298923
function createProviderInjector(cache) {
	const injector = createInjector(cache, function(name) {
		throw new Error(`Unknown provider: ${name}`);
	});

	injector.cache = cache;

	cache.$injector = injector;

	return injector;
}
1241141
private static InstallException create(String msg, Exception e, int rc) {
        InstallException ie = new InstallException(msg, e, rc);
        return ie;
    }
1179471
function compile (definition = {}, options = {}) {
  const { plugin } = options
  if (definition instanceof GraphQLFactoryDefinition) {
    return definition.registerPlugin(plugin).compile()
  }
  return define(definition, options).compile()
}
797012
function createCptWrapper(Ctl, cptArgs) {
    var cw = new CptWrapper(Ctl), att, t, v; // will also create a new controller instance
    if (cptArgs) {
        var cpt=cw.cpt, ni=cptArgs.nodeInstance;
        if (ni.isCptComponent || ni.isCptAttElement) {
            // set the nodeInstance reference on the component
            var $attributes=cptArgs.$attributes, $content=cptArgs.$content;
            cw.nodeInstance = ni;
            cw.cpt.nodeInstance = ni;

            if ($attributes) {
                for (var k in $attributes) {

                    // set the template attribute value on the component instance
                    if ($attributes.hasOwnProperty(k)) {
                        att=cw.cpt.$attributes[k];
                        t=att.type;
                        v=$attributes[k];

                        if (t && ATTRIBUTE_TYPES[t]) {
                            // in case of invalid type an error should already have been logged
                            // a type is defined - so let's convert the value
                            v=ATTRIBUTE_TYPES[t].convert(v, att);
                        }
                        json.set(cpt,k,v);
                    }
                }
            }

            if ($content) {
                if (cpt.$content) {
                  log.error(ni+" Component controller cannot use '$content' for another property than child attribute elements");
                } else {
                  // create the content property on the component instance
                  json.set(cpt,"$content",$content);
                }
            }
        }
    }
    return cw;
}
1031835
function injectPluginProvider(markup) {
  const componentRegex = /<([A-Z][A-Za-z]+)/;

  let match = componentRegex.exec(markup);

  while (match) {
    markup = markup.replace(
      componentRegex,
      "<pluginprovider name=!{'$1'!} plugins=!{props.plugins!}"
    );
    match = componentRegex.exec(markup);
  }

  return markup;
}
244415
def compile_with_coverage_instrumentation(self, # type: ignore
                                              manager_container,
                                              container: 'Container', # type: ignore

                                              verbose: bool = False
                                              ) -> CompilationOutcome:
        
        if self.__command_with_instrumentation:
            cmd = self.__command_with_instrumentation
        else:
            cmd = self.__command

        return self.__compile(manager_container, container, cmd, verbose)
351497
function configureCodeCoverage (config) {
  if (process.argv.indexOf("--coverage") === -1) {
    console.warn("Code-coverage is not enabled");
    return;
  }

  config.reporters.push("coverage");
  config.coverageReporter = {
    reporters: [
      { type: "text-summary" },
      { type: "lcov" }
    ]
  };

  config.files = config.files.map(function (file) {
    if (typeof file === "string") {
      file = file.replace(/^dist\/(.*)\.min\.js$/, "dist/$1.coverage.js");
    }
    return file;
  });
}
487756
public static StepExecutionItem createPluginStepItem(
            final String type,
            final Map configuration,
            final boolean keepgoingOnSuccess,
            final StepExecutionItem handler,
            final String label,
            final List<PluginConfiguration> filterConfigurations
    )
    {

        return new PluginStepExecutionItemImpl(
                type,
                configuration,
                keepgoingOnSuccess,
                handler,
                label,
                filterConfigurations
        );
    }
505521
def create(doc=None, error_text=None, exception_handlers=empty.dict, extend=Type, chain=True, auto_instance=True,
           accept_context=False):
    """"""
    extend = extend if type(extend) == type else type(extend)

    def new_type_handler(function):
        class NewType(extend):
            __slots__ = ()
            _accept_context = accept_context

            if chain and extend != Type:
                if error_text or exception_handlers:
                    if not accept_context:
                        def __call__(self, value):
                            try:
                                value = super(NewType, self).__call__(value)
                                return function(value)
                            except Exception as exception:
                                for take_exception, rewrite in exception_handlers.items():
                                    if isinstance(exception, take_exception):
                                        if isinstance(rewrite, str):
                                            raise ValueError(rewrite)
                                        else:
                                            raise rewrite(value)
                                if error_text:
                                    raise ValueError(error_text)
                                raise exception
                    else:
                        if extend._accept_context:
                            def __call__(self, value, context):
                                try:
                                    value = super(NewType, self).__call__(value, context)
                                    return function(value, context)
                                except Exception as exception:
                                    for take_exception, rewrite in exception_handlers.items():
                                        if isinstance(exception, take_exception):
                                            if isinstance(rewrite, str):
                                                raise ValueError(rewrite)
                                            else:
                                                raise rewrite(value)
                                    if error_text:
                                        raise ValueError(error_text)
                                    raise exception
                        else:
                            def __call__(self, value, context):
                                try:
                                    value = super(NewType, self).__call__(value)
                                    return function(value, context)
                                except Exception as exception:
                                    for take_exception, rewrite in exception_handlers.items():
                                        if isinstance(exception, take_exception):
                                            if isinstance(rewrite, str):
                                                raise ValueError(rewrite)
                                            else:
                                                raise rewrite(value)
                                    if error_text:
                                        raise ValueError(error_text)
                                    raise exception
                else:
                    if not accept_context:
                        def __call__(self, value):
                            value = super(NewType, self).__call__(value)
                            return function(value)
                    else:
                        if extend._accept_context:
                            def __call__(self, value, context):
                                value = super(NewType, self).__call__(value, context)
                                return function(value, context)
                        else:
                            def __call__(self, value, context):
                                value = super(NewType, self).__call__(value)
                                return function(value, context)
            else:
                if not accept_context:
                    if error_text or exception_handlers:
                        def __call__(self, value):
                            try:
                                return function(value)
                            except Exception as exception:
                                for take_exception, rewrite in exception_handlers.items():
                                    if isinstance(exception, take_exception):
                                        if isinstance(rewrite, str):
                                            raise ValueError(rewrite)
                                        else:
                                            raise rewrite(value)
                                if error_text:
                                    raise ValueError(error_text)
                                raise exception
                    else:
                        def __call__(self, value):
                            return function(value)
                else:
                    if error_text or exception_handlers:
                        def __call__(self, value, context):
                            try:
                                return function(value, context)
                            except Exception as exception:
                                for take_exception, rewrite in exception_handlers.items():
                                    if isinstance(exception, take_exception):
                                        if isinstance(rewrite, str):
                                            raise ValueError(rewrite)
                                        else:
                                            raise rewrite(value)
                                if error_text:
                                    raise ValueError(error_text)
                                raise exception
                    else:
                        def __call__(self, value, context):
                            return function(value, context)

        NewType.__doc__ = function.__doc__ if doc is None else doc
        if auto_instance and not (introspect.arguments(NewType.__init__, -1) or
                                  introspect.takes_kwargs(NewType.__init__) or
                                  introspect.takes_args(NewType.__init__)):
            return NewType()
        return NewType

    return new_type_handler
1148920
function createControllerFunction(_module, pluginName) {
        return function (name, inlineAnnotatedConstructor) {
            return _module.controller(pluginName + '.' + name, inlineAnnotatedConstructor);
        };
    }
1143437
function emitFiles(resolver, host, targetSourceFile, emitOnlyDtsFiles) {
        // 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};";
        var assignHelper = "\nvar __assign = (this && this.__assign) || Object.assign || function(t) {\n    for (var s, i = 1, n = arguments.length; i < n; i++) {\n        s = arguments[i];\n        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\n            t[p] = s[p];\n    }\n    return t;\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, P, generator) {\n    return new (P || (P = Promise))(function (resolve, reject) {\n        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n        function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } }\n        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }\n        step((generator = generator.apply(thisArg, _arguments)).next());\n    });\n};";
        var compilerOptions = host.getCompilerOptions();
        var languageVersion = ts.getEmitScriptTarget(compilerOptions);
        var modulekind = ts.getEmitModuleKind(compilerOptions);
        var sourceMapDataList = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined;
        var emittedFilesList = compilerOptions.listEmittedFiles ? [] : undefined;
        var emitterDiagnostics = ts.createDiagnosticCollection();
        var emitSkipped = false;
        var newLine = host.getNewLine();
        var emitJavaScript = createFileEmitter();
        ts.forEachExpectedEmitFile(host, emitFile, targetSourceFile, emitOnlyDtsFiles);
        return {
            emitSkipped: emitSkipped,
            diagnostics: emitterDiagnostics.getDiagnostics(),
            emittedFiles: emittedFilesList,
            sourceMaps: sourceMapDataList
        };
        function isUniqueLocalName(name, container) {
            for (var node = container; ts.isNodeDescendentOf(node, container); node = node.nextContainer) {
                if (node.locals && name in node.locals) {
                    // 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 setLabeledJump(state, isBreak, labelText, labelMarker) {
            if (isBreak) {
                if (!state.labeledNonLocalBreaks) {
                    state.labeledNonLocalBreaks = ts.createMap();
                }
                state.labeledNonLocalBreaks[labelText] = labelMarker;
            }
            else {
                if (!state.labeledNonLocalContinues) {
                    state.labeledNonLocalContinues = ts.createMap();
                }
                state.labeledNonLocalContinues[labelText] = labelMarker;
            }
        }
        function hoistVariableDeclarationFromLoop(state, declaration) {
            if (!state.hoistedLocalVariables) {
                state.hoistedLocalVariables = [];
            }
            visit(declaration.name);
            function visit(node) {
                if (node.kind === 69 /* Identifier */) {
                    state.hoistedLocalVariables.push(node);
                }
                else {
                    for (var _a = 0, _b = node.elements; _a < _b.length; _a++) {
                        var element = _b[_a];
                        visit(element.name);
                    }
                }
            }
        }
        function createFileEmitter() {
            var writer = ts.createTextWriter(newLine);
            var write = writer.write, writeTextOfNode = writer.writeTextOfNode, writeLine = writer.writeLine, increaseIndent = writer.increaseIndent, decreaseIndent = writer.decreaseIndent;
            var sourceMap = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? ts.createSourceMapWriter(host, writer) : ts.getNullSourceMapWriter();
            var setSourceFile = sourceMap.setSourceFile, emitStart = sourceMap.emitStart, emitEnd = sourceMap.emitEnd, emitPos = sourceMap.emitPos;
            var currentSourceFile;
            var currentText;
            var currentLineMap;
            var currentFileIdentifiers;
            var renamedDependencies;
            var isEs6Module;
            var isCurrentFileExternalModule;
            // 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 contextObjectForFile;
            var generatedNameSet;
            var nodeToGeneratedName;
            var computedPropertyNamesToGeneratedNames;
            var decoratedClassAliases;
            var convertedLoopState;
            var extendsEmitted;
            var assignEmitted;
            var decorateEmitted;
            var paramEmitted;
            var awaiterEmitted;
            var tempFlags = 0;
            var tempVariables;
            var tempParameters;
            var externalImports;
            var exportSpecifiers;
            var exportEquals;
            var hasExportStarsToExportValues;
            var detachedCommentsInfo;
            /** Sourcemap data that will get encoded */
            var sourceMapData;
            /** Is the file being emitted into its own file */
            var isOwnFileEmit;
            /** If removeComments is true, no leading-comments needed to be emitted **/
            var emitLeadingCommentsOfPosition = compilerOptions.removeComments ? function (pos) { } : emitLeadingCommentsOfPositionWorker;
            var setSourceMapWriterEmit = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? changeSourceMapEmit : function (writer) { };
            var moduleEmitDelegates = ts.createMap((_a = {},
                _a[ts.ModuleKind.ES6] = emitES6Module,
                _a[ts.ModuleKind.AMD] = emitAMDModule,
                _a[ts.ModuleKind.System] = emitSystemModule,
                _a[ts.ModuleKind.UMD] = emitUMDModule,
                _a[ts.ModuleKind.CommonJS] = emitCommonJSModule,
                _a
            ));
            var bundleEmitDelegates = ts.createMap((_b = {},
                _b[ts.ModuleKind.ES6] = function () { },
                _b[ts.ModuleKind.AMD] = emitAMDModule,
                _b[ts.ModuleKind.System] = emitSystemModule,
                _b[ts.ModuleKind.UMD] = function () { },
                _b[ts.ModuleKind.CommonJS] = function () { },
                _b
            ));
            return doEmit;
            function doEmit(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit) {
                sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
                generatedNameSet = ts.createMap();
                nodeToGeneratedName = [];
                decoratedClassAliases = [];
                isOwnFileEmit = !isBundledEmit;
                // Emit helpers from all the files
                if (isBundledEmit && modulekind) {
                    ts.forEach(sourceFiles, emitEmitHelpers);
                }
                // Do not call emit directly. It does not set the currentSourceFile.
                ts.forEach(sourceFiles, emitSourceFile);
                writeLine();
                var sourceMappingURL = sourceMap.getSourceMappingURL();
                if (sourceMappingURL) {
                    write("//# " + "sourceMappingURL" + "=" + sourceMappingURL); // Sometimes tools can sometimes see this line as a source mapping url comment
                }
                writeEmittedFiles(writer.getText(), jsFilePath, sourceMapFilePath, /*writeByteOrderMark*/ compilerOptions.emitBOM, sourceFiles);
                // reset the state
                sourceMap.reset();
                writer.reset();
                currentSourceFile = undefined;
                currentText = undefined;
                currentLineMap = undefined;
                exportFunctionForFile = undefined;
                contextObjectForFile = undefined;
                generatedNameSet = undefined;
                nodeToGeneratedName = undefined;
                decoratedClassAliases = undefined;
                computedPropertyNamesToGeneratedNames = undefined;
                convertedLoopState = undefined;
                extendsEmitted = false;
                decorateEmitted = false;
                paramEmitted = false;
                awaiterEmitted = false;
                assignEmitted = false;
                tempFlags = 0;
                tempVariables = undefined;
                tempParameters = undefined;
                externalImports = undefined;
                exportSpecifiers = undefined;
                exportEquals = undefined;
                hasExportStarsToExportValues = undefined;
                detachedCommentsInfo = undefined;
                sourceMapData = undefined;
                isEs6Module = false;
                renamedDependencies = undefined;
                isCurrentFileExternalModule = false;
            }
            function emitSourceFile(sourceFile) {
                currentSourceFile = sourceFile;
                currentText = sourceFile.text;
                currentLineMap = ts.getLineStarts(sourceFile);
                exportFunctionForFile = undefined;
                contextObjectForFile = undefined;
                isEs6Module = sourceFile.symbol && sourceFile.symbol.exports && !!sourceFile.symbol.exports["___esModule"];
                renamedDependencies = sourceFile.renamedDependencies;
                currentFileIdentifiers = sourceFile.identifiers;
                isCurrentFileExternalModule = ts.isExternalModule(sourceFile);
                setSourceFile(sourceFile);
                emitNodeWithCommentsAndWithoutSourcemap(sourceFile);
            }
            function isUniqueName(name) {
                return !resolver.hasGlobalName(name) &&
                    !(name in currentFileIdentifiers) &&
                    !(name in generatedNameSet);
            }
            // 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_24 = flags === 268435456 /* _i */ ? "_i" : "_n";
                    if (isUniqueName(name_24)) {
                        tempFlags |= flags;
                        return name_24;
                    }
                }
                while (true) {
                    var count = tempFlags & 268435455 /* CountMask */;
                    tempFlags++;
                    // Skip over 'i' and 'n'
                    if (count !== 8 && count !== 13) {
                        var name_25 = count < 26 ? "_" + String.fromCharCode(97 /* a */ + count) : "_" + (count - 26);
                        if (isUniqueName(name_25)) {
                            return name_25;
                        }
                    }
                }
            }
            // 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 225 /* ModuleDeclaration */:
                    case 224 /* EnumDeclaration */:
                        return generateNameForModuleOrEnum(node);
                    case 230 /* ImportDeclaration */:
                    case 236 /* ExportDeclaration */:
                        return generateNameForImportOrExportDeclaration(node);
                    case 220 /* FunctionDeclaration */:
                    case 221 /* ClassDeclaration */:
                    case 235 /* ExportAssignment */:
                        return generateNameForExportDefault();
                    case 192 /* ClassExpression */:
                        return generateNameForClassExpression();
                    default:
                        ts.Debug.fail();
                }
            }
            function getGeneratedNameForNode(node) {
                var id = ts.getNodeId(node);
                return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = ts.unescapeIdentifier(generateNameForNode(node)));
            }
            /** Write emitted output to disk */
            function writeEmittedFiles(emitOutput, jsFilePath, sourceMapFilePath, writeByteOrderMark, sourceFiles) {
                if (compilerOptions.sourceMap && !compilerOptions.inlineSourceMap) {
                    ts.writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap.getText(), /*writeByteOrderMark*/ false, sourceFiles);
                }
                if (sourceMapDataList) {
                    sourceMapDataList.push(sourceMap.getSourceMapData());
                }
                ts.writeFile(host, emitterDiagnostics, jsFilePath, emitOutput, writeByteOrderMark, sourceFiles);
            }
            // 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(";");
                }
            }
            /** 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 */
            function emitToken(tokenKind, startPos, emitFn) {
                var tokenStartPos = ts.skipTrivia(currentText, startPos);
                emitPos(tokenStartPos);
                var tokenString = ts.tokenToString(tokenKind);
                if (emitFn) {
                    emitFn();
                }
                else {
                    write(tokenString);
                }
                var tokenEndPos = tokenStartPos + tokenString.length;
                emitPos(tokenEndPos);
                return tokenEndPos;
            }
            function emitOptional(prefix, node) {
                if (node) {
                    write(prefix);
                    emit(node);
                }
            }
            function emitParenthesizedIf(node, parenthesized) {
                if (parenthesized) {
                    write("(");
                }
                emit(node);
                if (parenthesized) {
                    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.getTextOfNodeFromSourceText(currentText, 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.getTextOfNodeFromSourceText(currentText, node);
                // text contains the original source, it will also contain quotes ("`"), dollar 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 === 189 /* TemplateExpression */) {
                    ts.forEach(node.template.templateSpans, function (templateSpan) {
                        write(", ");
                        var needsParens = templateSpan.expression.kind === 187 /* 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 !== 178 /* 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 174 /* CallExpression */:
                        case 175 /* NewExpression */:
                            return parent.expression === template;
                        case 176 /* TaggedTemplateExpression */:
                        case 178 /* 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 187 /* 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 190 /* YieldExpression */:
                        case 188 /* 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)) {
                        emit(name);
                    }
                    else {
                        write('"');
                        emit(name);
                        write('"');
                    }
                }
                /// 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 = compilerOptions.reactNamespace ? compilerOptions.reactNamespace : "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 the __assign helper
                        var attrs = openingNode.attributes;
                        if (ts.forEach(attrs, function (attr) { return attr.kind === 247 /* JsxSpreadAttribute */; })) {
                            write("__assign(");
                            var haveOpenedObjectLiteral = false;
                            for (var i = 0; i < attrs.length; i++) {
                                if (attrs[i].kind === 247 /* JsxSpreadAttribute */) {
                                    // If this is the first argument, we need to emit a {} as the first argument
                                    if (i === 0) {
                                        write("{}, ");
                                    }
                                    if (haveOpenedObjectLiteral) {
                                        write("}");
                                        haveOpenedObjectLiteral = false;
                                    }
                                    if (i > 0) {
                                        write(", ");
                                    }
                                    emit(attrs[i].expression);
                                }
                                else {
                                    ts.Debug.assert(attrs[i].kind === 246 /* JsxAttribute */);
                                    if (haveOpenedObjectLiteral) {
                                        write(", ");
                                    }
                                    else {
                                        haveOpenedObjectLiteral = true;
                                        if (i > 0) {
                                            write(", ");
                                        }
                                        write("{");
                                    }
                                    emitJsxAttribute(attrs[i]);
                                }
                            }
                            if (haveOpenedObjectLiteral)
                                write("}");
                            write(")"); // closing paren to React.__spread(
                        }
                        else {
                            // One object literal with all the attributes in them
                            write("{");
                            for (var i = 0, n = attrs.length; i < n; i++) {
                                if (i > 0) {
                                    write(", ");
                                }
                                emitJsxAttribute(attrs[i]);
                            }
                            write("}");
                        }
                    }
                    // Children
                    if (children) {
                        var firstChild = void 0;
                        var multipleEmittableChildren = false;
                        for (var i = 0, n = children.length; i < n; i++) {
                            var jsxChild = children[i];
                            if (isJsxChildEmittable(jsxChild)) {
                                // we need to decide whether to emit in single line or multiple lines as indented list
                                // store firstChild reference, if we see another emittable child, then emit accordingly
                                if (!firstChild) {
                                    write(", ");
                                    firstChild = jsxChild;
                                }
                                else {
                                    // more than one emittable child, emit indented list
                                    if (!multipleEmittableChildren) {
                                        multipleEmittableChildren = true;
                                        increaseIndent();
                                        writeLine();
                                        emit(firstChild);
                                    }
                                    write(", ");
                                    writeLine();
                                    emit(jsxChild);
                                }
                            }
                        }
                        if (multipleEmittableChildren) {
                            decreaseIndent();
                        }
                        else if (firstChild) {
                            if (firstChild.kind !== 241 /* JsxElement */ && firstChild.kind !== 242 /* JsxSelfClosingElement */) {
                                emit(firstChild);
                            }
                            else {
                                // If the only child is jsx element, put it on a new indented line
                                increaseIndent();
                                writeLine();
                                emit(firstChild);
                                writeLine();
                                decreaseIndent();
                            }
                        }
                    }
                    // Closing paren
                    write(")"); // closes "React.createElement("
                    emitTrailingComments(openingNode);
                }
                if (node.kind === 241 /* JsxElement */) {
                    emitJsxElement(node.openingElement, node.children);
                }
                else {
                    ts.Debug.assert(node.kind === 242 /* 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 === 247 /* JsxSpreadAttribute */) {
                            emitJsxSpreadAttribute(attribs[i]);
                        }
                        else {
                            ts.Debug.assert(attribs[i].kind === 246 /* JsxAttribute */);
                            emitJsxAttribute(attribs[i]);
                        }
                    }
                }
                function emitJsxOpeningOrSelfClosingElement(node) {
                    write("<");
                    emit(node.tagName);
                    if (node.attributes.length > 0 || (node.kind === 242 /* JsxSelfClosingElement */)) {
                        write(" ");
                    }
                    emitAttributes(node.attributes);
                    if (node.kind === 242 /* 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 === 241 /* JsxElement */) {
                    emitJsxElement(node);
                }
                else {
                    ts.Debug.assert(node.kind === 242 /* 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 !== 169 /* BindingElement */);
                if (node.kind === 9 /* StringLiteral */) {
                    emitLiteral(node);
                }
                else if (node.kind === 140 /* 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(currentText, node);
                    }
                    write('"');
                }
            }
            function isExpressionIdentifier(node) {
                var parent = node.parent;
                switch (parent.kind) {
                    case 170 /* ArrayLiteralExpression */:
                    case 195 /* AsExpression */:
                    case 184 /* AwaitExpression */:
                    case 187 /* BinaryExpression */:
                    case 174 /* CallExpression */:
                    case 249 /* CaseClause */:
                    case 140 /* ComputedPropertyName */:
                    case 188 /* ConditionalExpression */:
                    case 143 /* Decorator */:
                    case 181 /* DeleteExpression */:
                    case 204 /* DoStatement */:
                    case 173 /* ElementAccessExpression */:
                    case 235 /* ExportAssignment */:
                    case 202 /* ExpressionStatement */:
                    case 194 /* ExpressionWithTypeArguments */:
                    case 206 /* ForStatement */:
                    case 207 /* ForInStatement */:
                    case 208 /* ForOfStatement */:
                    case 203 /* IfStatement */:
                    case 245 /* JsxClosingElement */:
                    case 242 /* JsxSelfClosingElement */:
                    case 243 /* JsxOpeningElement */:
                    case 247 /* JsxSpreadAttribute */:
                    case 248 /* JsxExpression */:
                    case 175 /* NewExpression */:
                    case 196 /* NonNullExpression */:
                    case 178 /* ParenthesizedExpression */:
                    case 186 /* PostfixUnaryExpression */:
                    case 185 /* PrefixUnaryExpression */:
                    case 211 /* ReturnStatement */:
                    case 254 /* ShorthandPropertyAssignment */:
                    case 191 /* SpreadElementExpression */:
                    case 213 /* SwitchStatement */:
                    case 176 /* TaggedTemplateExpression */:
                    case 197 /* TemplateSpan */:
                    case 215 /* ThrowStatement */:
                    case 177 /* TypeAssertionExpression */:
                    case 182 /* TypeOfExpression */:
                    case 183 /* VoidExpression */:
                    case 205 /* WhileStatement */:
                    case 212 /* WithStatement */:
                    case 190 /* YieldExpression */:
                        return true;
                    case 169 /* BindingElement */:
                    case 255 /* EnumMember */:
                    case 142 /* Parameter */:
                    case 253 /* PropertyAssignment */:
                    case 145 /* PropertyDeclaration */:
                    case 218 /* VariableDeclaration */:
                        return parent.initializer === node;
                    case 172 /* PropertyAccessExpression */:
                        return parent.expression === node;
                    case 180 /* ArrowFunction */:
                    case 179 /* FunctionExpression */:
                        return parent.body === node;
                    case 229 /* ImportEqualsDeclaration */:
                        return parent.moduleReference === node;
                    case 139 /* QualifiedName */:
                        return parent.left === node;
                }
                return false;
            }
            function emitExpressionIdentifier(node) {
                var container = resolver.getReferencedExportContainer(node);
                if (container) {
                    if (container.kind === 256 /* SourceFile */) {
                        // Identifier references module export
                        if (modulekind !== ts.ModuleKind.ES6 && modulekind !== ts.ModuleKind.System) {
                            write("exports.");
                        }
                    }
                    else {
                        // Identifier references namespace export
                        write(getGeneratedNameForNode(container));
                        write(".");
                    }
                }
                else {
                    if (modulekind !== ts.ModuleKind.ES6) {
                        var declaration = resolver.getReferencedImportDeclaration(node);
                        if (declaration) {
                            if (declaration.kind === 231 /* ImportClause */) {
                                // Identifier references default import
                                write(getGeneratedNameForNode(declaration.parent));
                                write(languageVersion === 0 /* ES3 */ ? '["default"]' : ".default");
                                return;
                            }
                            else if (declaration.kind === 234 /* ImportSpecifier */) {
                                // Identifier references named import
                                write(getGeneratedNameForNode(declaration.parent.parent.parent));
                                var name_26 = declaration.propertyName || declaration.name;
                                var identifier = ts.getTextOfNodeFromSourceText(currentText, name_26);
                                if (languageVersion === 0 /* ES3 */ && identifier === "default") {
                                    write('["default"]');
                                }
                                else {
                                    write(".");
                                    write(identifier);
                                }
                                return;
                            }
                        }
                    }
                    if (languageVersion < 2 /* ES6 */) {
                        var declaration = resolver.getReferencedDeclarationWithCollidingName(node);
                        if (declaration) {
                            write(getGeneratedNameForNode(declaration.name));
                            return;
                        }
                    }
                    else if (resolver.getNodeCheckFlags(node) & 1048576 /* BodyScopedClassBinding */) {
                        // Due to the emit for class decorators, any reference to the class from inside of the class body
                        // must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
                        // behavior of class names in ES6.
                        var declaration = resolver.getReferencedValueDeclaration(node);
                        if (declaration) {
                            var classAlias = decoratedClassAliases[ts.getNodeId(declaration)];
                            if (classAlias !== undefined) {
                                write(classAlias);
                                return;
                            }
                        }
                    }
                }
                if (ts.nodeIsSynthesized(node)) {
                    write(node.text);
                }
                else {
                    writeTextOfNode(currentText, node);
                }
            }
            function isNameOfNestedBlockScopedRedeclarationOrCapturedBinding(node) {
                if (languageVersion < 2 /* ES6 */) {
                    var parent_13 = node.parent;
                    switch (parent_13.kind) {
                        case 169 /* BindingElement */:
                        case 221 /* ClassDeclaration */:
                        case 224 /* EnumDeclaration */:
                        case 218 /* VariableDeclaration */:
                            return parent_13.name === node && resolver.isDeclarationWithCollidingName(parent_13);
                    }
                }
                return false;
            }
            function getClassExpressionInPropertyAccessInStaticPropertyDeclaration(node) {
                if (languageVersion >= 2 /* ES6 */) {
                    var parent_14 = node.parent;
                    if (parent_14.kind === 172 /* PropertyAccessExpression */ && parent_14.expression === node) {
                        parent_14 = parent_14.parent;
                        while (parent_14 && parent_14.kind !== 145 /* PropertyDeclaration */) {
                            parent_14 = parent_14.parent;
                        }
                        return parent_14 && parent_14.kind === 145 /* PropertyDeclaration */ && (parent_14.flags & 32 /* Static */) !== 0 &&
                            parent_14.parent.kind === 192 /* ClassExpression */ ? parent_14.parent : undefined;
                    }
                }
                return undefined;
            }
            function emitIdentifier(node) {
                if (convertedLoopState) {
                    if (node.text == "arguments" && resolver.isArgumentsLocalBinding(node)) {
                        // in converted loop body arguments cannot be used directly.
                        var name_27 = convertedLoopState.argumentsName || (convertedLoopState.argumentsName = makeUniqueName("arguments"));
                        write(name_27);
                        return;
                    }
                }
                if (!node.parent) {
                    write(node.text);
                }
                else if (isExpressionIdentifier(node)) {
                    var classExpression = getClassExpressionInPropertyAccessInStaticPropertyDeclaration(node);
                    if (classExpression) {
                        var declaration = resolver.getReferencedValueDeclaration(node);
                        if (declaration === classExpression) {
                            write(getGeneratedNameForNode(declaration.name));
                            return;
                        }
                    }
                    emitExpressionIdentifier(node);
                }
                else if (isNameOfNestedBlockScopedRedeclarationOrCapturedBinding(node)) {
                    write(getGeneratedNameForNode(node));
                }
                else if (ts.nodeIsSynthesized(node)) {
                    write(node.text);
                }
                else {
                    writeTextOfNode(currentText, node);
                }
            }
            function emitThis(node) {
                if (resolver.getNodeCheckFlags(node) & 2 /* LexicalThis */) {
                    write("_this");
                }
                else if (convertedLoopState) {
                    write(convertedLoopState.thisName || (convertedLoopState.thisName = makeUniqueName("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 === 187 /* BinaryExpression */ && !ts.isAssignmentOperator(node.parent.operatorToken.kind)) {
                    return true;
                }
                else if (node.parent.kind === 188 /* ConditionalExpression */ && node.parent.condition === node) {
                    return true;
                }
                else if (node.parent.kind === 185 /* PrefixUnaryExpression */ || node.parent.kind === 181 /* DeleteExpression */ ||
                    node.parent.kind === 182 /* TypeOfExpression */ || node.parent.kind === 183 /* VoidExpression */) {
                    return true;
                }
                return false;
            }
            function needsParenthesisForPropertyAccessOrInvocation(node) {
                switch (node.kind) {
                    case 69 /* Identifier */:
                    case 170 /* ArrayLiteralExpression */:
                    case 172 /* PropertyAccessExpression */:
                    case 173 /* ElementAccessExpression */:
                    case 174 /* CallExpression */:
                    case 178 /* 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 === 191 /* SpreadElementExpression */) {
                        e = e.expression;
                        emitParenthesizedIf(e, /*parenthesized*/ group === 0 && needsParenthesisForPropertyAccessOrInvocation(e));
                        pos++;
                        if (pos === length && group === 0 && needsUniqueCopy && e.kind !== 170 /* ArrayLiteralExpression */) {
                            write(".slice()");
                        }
                    }
                    else {
                        var i = pos;
                        while (i < length && elements[i].kind !== 191 /* 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 === 191 /* 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.multiLine, 
                    /*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.multiLine;
                        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.multiLine;
                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++) {
                    var property = properties[i];
                    if (property.kind === 149 /* GetAccessor */ || property.kind === 150 /* SetAccessor */) {
                        // TODO (drosen): Reconcile with 'emitMemberFunctions'.
                        var accessors = ts.getAllAccessorDeclarations(node.properties, property);
                        if (property !== accessors.firstAccessor) {
                            continue;
                        }
                        writeComma();
                        emitStart(property);
                        write("Object.defineProperty(");
                        emit(tempVar);
                        write(", ");
                        emitStart(property.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 {
                        writeComma();
                        emitStart(property);
                        emitLeadingComments(property);
                        emitStart(property.name);
                        emit(tempVar);
                        emitMemberAccessForPropertyName(property.name);
                        emitEnd(property.name);
                        write(" = ");
                        if (property.kind === 253 /* PropertyAssignment */) {
                            emit(property.initializer);
                        }
                        else if (property.kind === 254 /* ShorthandPropertyAssignment */) {
                            emitExpressionIdentifier(property.name);
                        }
                        else if (property.kind === 147 /* 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 === 140 /* 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(187 /* BinaryExpression */, startsOnNewLine);
                result.operatorToken = ts.createSynthesizedNode(operator);
                result.left = left;
                result.right = right;
                return result;
            }
            function createPropertyAccessExpression(expression, name) {
                var result = ts.createSynthesizedNode(172 /* PropertyAccessExpression */);
                result.expression = parenthesizeForAccess(expression);
                result.name = name;
                return result;
            }
            function createElementAccessExpression(expression, argumentExpression) {
                var result = ts.createSynthesizedNode(173 /* 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 === 177 /* TypeAssertionExpression */ ||
                    expr.kind === 195 /* AsExpression */ ||
                    expr.kind === 196 /* NonNullExpression */) {
                    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 !== 175 /* NewExpression */ &&
                    expr.kind !== 8 /* NumericLiteral */) {
                    return expr;
                }
                var node = ts.createSynthesizedNode(178 /* 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 isExportReference(node) {
                var container = resolver.getReferencedExportContainer(node);
                return !!container;
            }
            // Return true if identifier resolves to an imported identifier
            function isImportedReference(node) {
                var declaration = resolver.getReferencedImportDeclaration(node);
                return declaration && (declaration.kind === 231 /* ImportClause */ || declaration.kind === 234 /* ImportSpecifier */);
            }
            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(currentText, 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.
                // The same rules apply for imported identifiers when targeting module formats with indirect access to
                // the imported identifiers. For example, when targeting CommonJS:
                //
                //   import {foo} from './foo';
                //   export const baz = { foo };
                //
                // Must be transformed into:
                //
                //   const foo_1 = require('./foo');
                //   exports.baz = { foo: foo_1.foo };
                //
                if (languageVersion < 2 /* ES6 */ || (modulekind !== ts.ModuleKind.ES6 && isImportedReference(node.name)) || isExportReference(node.name)) {
                    // Emit identifier as an identifier
                    write(": ");
                    emitExpressionIdentifier(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 === 172 /* 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 === 172 /* PropertyAccessExpression */ || node.kind === 173 /* 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;
                }
                if (languageVersion === 2 /* ES6 */ &&
                    node.expression.kind === 95 /* SuperKeyword */ &&
                    isInAsyncMethodWithSuperInES6(node)) {
                    var name_28 = ts.createSynthesizedNode(9 /* StringLiteral */);
                    name_28.text = node.name.text;
                    emitSuperAccessInAsyncMethod(node.expression, name_28);
                    return;
                }
                emit(node.expression);
                var dotRangeStart = ts.nodeIsSynthesized(node.expression) ? -1 : node.expression.end;
                var dotRangeEnd = ts.nodeIsSynthesized(node.expression) ? -1 : ts.skipTrivia(currentText, node.expression.end) + 1;
                var dotToken = { pos: dotRangeStart, end: dotRangeEnd };
                var indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, 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 = false;
                if (!indentedBeforeDot) {
                    if (node.expression.kind === 8 /* NumericLiteral */) {
                        // check if numeric literal was originally written with a dot
                        var text = ts.getTextOfNodeFromSourceText(currentText, 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, 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 139 /* QualifiedName */:
                        emitQualifiedNameAsExpression(node, useFallback);
                        break;
                    default:
                        emitNodeWithoutSourceMap(node);
                        break;
                }
            }
            function emitIndexedAccess(node) {
                if (tryEmitConstantValue(node)) {
                    return;
                }
                if (languageVersion === 2 /* ES6 */ &&
                    node.expression.kind === 95 /* SuperKeyword */ &&
                    isInAsyncMethodWithSuperInES6(node)) {
                    emitSuperAccessInAsyncMethod(node.expression, node.argumentExpression);
                    return;
                }
                emit(node.expression);
                write("[");
                emit(node.argumentExpression);
                write("]");
            }
            function hasSpreadElement(elements) {
                return ts.forEach(elements, function (e) { return e.kind === 191 /* SpreadElementExpression */; });
            }
            function skipParentheses(node) {
                while (node.kind === 178 /* ParenthesizedExpression */ ||
                    node.kind === 177 /* TypeAssertionExpression */ ||
                    node.kind === 195 /* AsExpression */ ||
                    node.kind === 196 /* NonNullExpression */) {
                    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 === 172 /* PropertyAccessExpression */) {
                    // Target will be emitted as "this" argument
                    target = emitCallTarget(expr.expression);
                    write(".");
                    emit(expr.name);
                }
                else if (expr.kind === 173 /* 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 isInAsyncMethodWithSuperInES6(node) {
                if (languageVersion === 2 /* ES6 */) {
                    var container = ts.getSuperContainer(node, /*includeFunctions*/ false);
                    if (container && resolver.getNodeCheckFlags(container) & (2048 /* AsyncMethodWithSuper */ | 4096 /* AsyncMethodWithSuperBinding */)) {
                        return true;
                    }
                }
                return false;
            }
            function emitSuperAccessInAsyncMethod(superNode, argumentExpression) {
                var container = ts.getSuperContainer(superNode, /*includeFunctions*/ false);
                var isSuperBinding = resolver.getNodeCheckFlags(container) & 4096 /* AsyncMethodWithSuperBinding */;
                write("_super(");
                emit(argumentExpression);
                write(isSuperBinding ? ").value" : ")");
            }
            function emitCallExpression(node) {
                if (languageVersion < 2 /* ES6 */ && hasSpreadElement(node.arguments)) {
                    emitCallWithSpread(node);
                    return;
                }
                var expression = node.expression;
                var superCall = false;
                var isAsyncMethodWithSuper = false;
                if (expression.kind === 95 /* SuperKeyword */) {
                    emitSuper(expression);
                    superCall = true;
                }
                else {
                    superCall = ts.isSuperPropertyOrElementAccess(expression);
                    isAsyncMethodWithSuper = superCall && isInAsyncMethodWithSuperInES6(node);
                    emit(expression);
                }
                if (superCall && (languageVersion < 2 /* ES6 */ || isAsyncMethodWithSuper)) {
                    write(".call(");
                    emitThis(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 !== 180 /* ArrowFunction */) {
                    if (node.expression.kind === 177 /* TypeAssertionExpression */ ||
                        node.expression.kind === 195 /* AsExpression */ ||
                        node.expression.kind === 196 /* NonNullExpression */) {
                        var operand = node.expression.expression;
                        // Make sure we consider all nested cast expressions, e.g.:
                        // (<any><number><any>-A).x;
                        while (operand.kind === 177 /* TypeAssertionExpression */ ||
                            operand.kind === 195 /* AsExpression */ ||
                            operand.kind === 196 /* NonNullExpression */) {
                            operand = operand.expression;
                        }
                        // We have an expression of the form: (<Type>SubExpr) or (SubExpr as Type)
                        // 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 !== 185 /* PrefixUnaryExpression */ &&
                            operand.kind !== 183 /* VoidExpression */ &&
                            operand.kind !== 182 /* TypeOfExpression */ &&
                            operand.kind !== 181 /* DeleteExpression */ &&
                            operand.kind !== 186 /* PostfixUnaryExpression */ &&
                            operand.kind !== 175 /* NewExpression */ &&
                            !(operand.kind === 187 /* BinaryExpression */ && node.expression.kind === 195 /* AsExpression */) &&
                            !(operand.kind === 174 /* CallExpression */ && node.parent.kind === 175 /* NewExpression */) &&
                            !(operand.kind === 179 /* FunctionExpression */ && node.parent.kind === 174 /* CallExpression */) &&
                            !(operand.kind === 8 /* NumericLiteral */ && node.parent.kind === 172 /* 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 === 218 /* VariableDeclaration */ || node.parent.kind === 169 /* BindingElement */);
                var targetDeclaration = isVariableDeclarationOrBindingElement
                    ? node.parent
                    : resolver.getReferencedValueDeclaration(node);
                return isSourceFileLevelDeclarationInSystemJsModule(targetDeclaration, /*isExported*/ true);
            }
            function isNameOfExportedDeclarationInNonES6Module(node) {
                if (modulekind === ts.ModuleKind.System || node.kind !== 69 /* Identifier */ || ts.nodeIsSynthesized(node)) {
                    return false;
                }
                if (exportEquals || !exportSpecifiers || !(node.text in exportSpecifiers)) {
                    return false;
                }
                // check that referenced declaration is declared on source file level
                var declaration = resolver.getReferencedValueDeclaration(node);
                return declaration && ts.getEnclosingBlockScopeContainer(declaration).kind === 256 /* SourceFile */;
            }
            function emitPrefixUnaryExpression(node) {
                var isPlusPlusOrMinusMinus = (node.operator === 41 /* PlusPlusToken */
                    || node.operator === 42 /* MinusMinusToken */);
                var externalExportChanged = isPlusPlusOrMinusMinus &&
                    isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
                if (externalExportChanged) {
                    // emit
                    // ++x
                    // as
                    // exports('x', ++x)
                    write(exportFunctionForFile + "(\"");
                    emitNodeWithoutSourceMap(node.operand);
                    write("\", ");
                }
                var internalExportChanged = isPlusPlusOrMinusMinus &&
                    isNameOfExportedDeclarationInNonES6Module(node.operand);
                if (internalExportChanged) {
                    emitAliasEqual(node.operand);
                }
                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 === 185 /* 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 (externalExportChanged) {
                    write(")");
                }
            }
            function emitPostfixUnaryExpression(node) {
                var externalExportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
                var internalExportChanged = isNameOfExportedDeclarationInNonES6Module(node.operand);
                if (externalExportChanged) {
                    // 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 if (internalExportChanged) {
                    emitAliasEqual(node.operand);
                    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
             *   when we emit variable statement 'var' should be dropped.
             */
            function isSourceFileLevelDeclarationInSystemJsModule(node, isExported) {
                if (!node || !isCurrentFileSystemExternalModule()) {
                    return false;
                }
                var current = ts.getRootDeclaration(node).parent;
                while (current) {
                    if (current.kind === 256 /* SourceFile */) {
                        return !isExported || ((ts.getCombinedNodeFlags(node) & 1 /* Export */) !== 0);
                    }
                    else if (ts.isDeclaration(current)) {
                        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 = void 0;
                    var shouldEmitParentheses = false;
                    if (ts.isElementAccessExpression(leftHandSideExpression)) {
                        shouldEmitParentheses = true;
                        write("(");
                        synthesizedLHS = ts.createSynthesizedNode(173 /* ElementAccessExpression */, /*startsOnNewLine*/ false);
                        var identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ 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, leftHandSideExpression.expression);
                        }
                        else {
                            synthesizedLHS.argumentExpression = leftHandSideExpression.argumentExpression;
                        }
                        write(", ");
                    }
                    else if (ts.isPropertyAccessExpression(leftHandSideExpression)) {
                        shouldEmitParentheses = true;
                        write("(");
                        synthesizedLHS = ts.createSynthesizedNode(172 /* PropertyAccessExpression */, /*startsOnNewLine*/ false);
                        var identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false);
                        synthesizedLHS.expression = identifier;
                        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 emitAliasEqual(name) {
                for (var _a = 0, _b = exportSpecifiers[name.text]; _a < _b.length; _a++) {
                    var specifier = _b[_a];
                    emitStart(specifier.name);
                    emitContainingModuleName(specifier);
                    if (languageVersion === 0 /* ES3 */ && name.text === "default") {
                        write('["default"]');
                    }
                    else {
                        write(".");
                        emitNodeWithCommentsAndWithoutSourcemap(specifier.name);
                    }
                    emitEnd(specifier.name);
                    write(" = ");
                }
                return true;
            }
            function emitBinaryExpression(node) {
                if (languageVersion < 2 /* ES6 */ && node.operatorToken.kind === 56 /* EqualsToken */ &&
                    (node.left.kind === 171 /* ObjectLiteralExpression */ || node.left.kind === 170 /* ArrayLiteralExpression */)) {
                    emitDestructuring(node, node.parent.kind === 202 /* ExpressionStatement */);
                }
                else {
                    var isAssignment = ts.isAssignmentOperator(node.operatorToken.kind);
                    var externalExportChanged = isAssignment &&
                        isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left);
                    if (externalExportChanged) {
                        // emit assignment 'x <op> y' as 'exports("x", x <op> y)'
                        write(exportFunctionForFile + "(\"");
                        emitNodeWithoutSourceMap(node.left);
                        write("\", ");
                    }
                    var internalExportChanged = isAssignment &&
                        isNameOfExportedDeclarationInNonES6Module(node.left);
                    if (internalExportChanged) {
                        // export { foo }
                        // emit foo = 2 as exports.foo = foo = 2
                        emitAliasEqual(node.left);
                    }
                    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 (externalExportChanged) {
                        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 === 199 /* 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();
                if (node.kind === 226 /* ModuleBlock */) {
                    ts.Debug.assert(node.parent.kind === 225 /* ModuleDeclaration */);
                    emitCaptureThisForNodeIfNecessary(node.parent);
                }
                emitLines(node.statements);
                if (node.kind === 226 /* ModuleBlock */) {
                    emitTempDeclarations(/*newLine*/ true);
                }
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.statements.end);
            }
            function emitEmbeddedStatement(node) {
                if (node.kind === 199 /* Block */) {
                    write(" ");
                    emit(node);
                }
                else {
                    increaseIndent();
                    writeLine();
                    emit(node);
                    decreaseIndent();
                }
            }
            function emitExpressionStatement(node) {
                emitParenthesizedIf(node.expression, /*parenthesized*/ node.expression.kind === 180 /* 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 === 203 /* IfStatement */) {
                        write(" ");
                        emit(node.elseStatement);
                    }
                    else {
                        emitEmbeddedStatement(node.elseStatement);
                    }
                }
            }
            function emitDoStatement(node) {
                emitLoop(node, emitDoStatementWorker);
            }
            function emitDoStatementWorker(node, loop) {
                write("do");
                if (loop) {
                    emitConvertedLoopCall(loop, /*emitAsBlock*/ true);
                }
                else {
                    emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true);
                }
                if (node.statement.kind === 199 /* Block */) {
                    write(" ");
                }
                else {
                    writeLine();
                }
                write("while (");
                emit(node.expression);
                write(");");
            }
            function emitWhileStatement(node) {
                emitLoop(node, emitWhileStatementWorker);
            }
            function emitWhileStatementWorker(node, loop) {
                write("while (");
                emit(node.expression);
                write(")");
                if (loop) {
                    emitConvertedLoopCall(loop, /*emitAsBlock*/ true);
                }
                else {
                    emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true);
                }
            }
            /**
             * 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) {
                if (shouldHoistVariable(decl, /*checkIfSourceFileLevelDecl*/ true)) {
                    // variables in variable declaration list were already hoisted
                    return false;
                }
                if (convertedLoopState && (ts.getCombinedNodeFlags(decl) & 3072 /* BlockScoped */) === 0) {
                    // we are inside a converted loop - this can only happen in downlevel scenarios
                    // record names for all variable declarations
                    for (var _a = 0, _b = decl.declarations; _a < _b.length; _a++) {
                        var varDecl = _b[_a];
                        hoistVariableDeclarationFromLoop(convertedLoopState, varDecl);
                    }
                    return false;
                }
                emitStart(decl);
                if (decl && languageVersion >= 2 /* ES6 */) {
                    if (ts.isLet(decl)) {
                        write("let ");
                    }
                    else if (ts.isConst(decl)) {
                        write("const ");
                    }
                    else {
                        write("var ");
                    }
                }
                else {
                    write("var ");
                }
                // Note here we specifically dont emit end so that if we are going to emit binding pattern
                // we can alter the source map correctly
                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 shouldConvertLoopBody(node) {
                return languageVersion < 2 /* ES6 */ &&
                    (resolver.getNodeCheckFlags(node) & 65536 /* LoopWithCapturedBlockScopedBinding */) !== 0;
            }
            function emitLoop(node, loopEmitter) {
                var shouldConvert = shouldConvertLoopBody(node);
                if (!shouldConvert) {
                    loopEmitter(node, /* convertedLoop*/ undefined);
                }
                else {
                    var loop = convertLoopBody(node);
                    if (node.parent.kind === 214 /* LabeledStatement */) {
                        // if parent of the loop was labeled statement - attach the label to loop skipping converted loop body
                        emitLabelAndColon(node.parent);
                    }
                    loopEmitter(node, loop);
                }
            }
            function convertLoopBody(node) {
                var functionName = makeUniqueName("_loop");
                var loopInitializer;
                switch (node.kind) {
                    case 206 /* ForStatement */:
                    case 207 /* ForInStatement */:
                    case 208 /* ForOfStatement */:
                        var initializer = node.initializer;
                        if (initializer && initializer.kind === 219 /* VariableDeclarationList */) {
                            loopInitializer = node.initializer;
                        }
                        break;
                }
                var loopParameters;
                var loopOutParameters;
                if (loopInitializer && (ts.getCombinedNodeFlags(loopInitializer) & 3072 /* BlockScoped */)) {
                    // if loop initializer contains block scoped variables - they should be passed to converted loop body as parameters
                    loopParameters = [];
                    for (var _a = 0, _b = loopInitializer.declarations; _a < _b.length; _a++) {
                        var varDeclaration = _b[_a];
                        processVariableDeclaration(varDeclaration.name);
                    }
                }
                var bodyIsBlock = node.statement.kind === 199 /* Block */;
                var paramList = loopParameters ? loopParameters.join(", ") : "";
                writeLine();
                write("var " + functionName + " = function(" + paramList + ")");
                var convertedOuterLoopState = convertedLoopState;
                convertedLoopState = { loopOutParameters: loopOutParameters };
                if (convertedOuterLoopState) {
                    // convertedOuterLoopState !== undefined means that this converted loop is nested in another converted loop.
                    // if outer converted loop has already accumulated some state - pass it through
                    if (convertedOuterLoopState.argumentsName) {
                        // outer loop has already used 'arguments' so we've already have some name to alias it
                        // use the same name in all nested loops
                        convertedLoopState.argumentsName = convertedOuterLoopState.argumentsName;
                    }
                    if (convertedOuterLoopState.thisName) {
                        // outer loop has already used 'this' so we've already have some name to alias it
                        // use the same name in all nested loops
                        convertedLoopState.thisName = convertedOuterLoopState.thisName;
                    }
                    if (convertedOuterLoopState.hoistedLocalVariables) {
                        // we've already collected some non-block scoped variable declarations in enclosing loop
                        // use the same storage in nested loop
                        convertedLoopState.hoistedLocalVariables = convertedOuterLoopState.hoistedLocalVariables;
                    }
                }
                write(" {");
                writeLine();
                increaseIndent();
                if (bodyIsBlock) {
                    emitLines(node.statement.statements);
                }
                else {
                    emit(node.statement);
                }
                writeLine();
                // end of loop body -> copy out parameter
                copyLoopOutParameters(convertedLoopState, 1 /* ToOutParameter */, /*emitAsStatements*/ true);
                decreaseIndent();
                writeLine();
                write("};");
                writeLine();
                if (loopOutParameters) {
                    // declare variables to hold out params for loop body
                    write("var ");
                    for (var i = 0; i < loopOutParameters.length; i++) {
                        if (i !== 0) {
                            write(", ");
                        }
                        write(loopOutParameters[i].outParamName);
                    }
                    write(";");
                    writeLine();
                }
                if (convertedLoopState.argumentsName) {
                    // if alias for arguments is set
                    if (convertedOuterLoopState) {
                        // pass it to outer converted loop
                        convertedOuterLoopState.argumentsName = convertedLoopState.argumentsName;
                    }
                    else {
                        // this is top level converted loop and we need to create an alias for 'arguments' object
                        write("var " + convertedLoopState.argumentsName + " = arguments;");
                        writeLine();
                    }
                }
                if (convertedLoopState.thisName) {
                    // if alias for this is set
                    if (convertedOuterLoopState) {
                        // pass it to outer converted loop
                        convertedOuterLoopState.thisName = convertedLoopState.thisName;
                    }
                    else {
                        // this is top level converted loop so we need to create an alias for 'this' here
                        // NOTE:
                        // if converted loops were all nested in arrow function then we'll always emit '_this' so convertedLoopState.thisName will not be set.
                        // If it is set this means that all nested loops are not nested in arrow function and it is safe to capture 'this'.
                        write("var " + convertedLoopState.thisName + " = this;");
                        writeLine();
                    }
                }
                if (convertedLoopState.hoistedLocalVariables) {
                    // if hoistedLocalVariables !== undefined this means that we've possibly collected some variable declarations to be hoisted later
                    if (convertedOuterLoopState) {
                        // pass them to outer converted loop
                        convertedOuterLoopState.hoistedLocalVariables = convertedLoopState.hoistedLocalVariables;
                    }
                    else {
                        // deduplicate and hoist collected variable declarations
                        write("var ");
                        var seen = void 0;
                        for (var _c = 0, _d = convertedLoopState.hoistedLocalVariables; _c < _d.length; _c++) {
                            var id = _d[_c];
                            // Don't initialize seen unless we have at least one element.
                            // Emit a comma to separate for all but the first element.
                            if (!seen) {
                                seen = ts.createMap();
                            }
                            else {
                                write(", ");
                            }
                            if (!(id.text in seen)) {
                                emit(id);
                                seen[id.text] = id.text;
                            }
                        }
                        write(";");
                        writeLine();
                    }
                }
                var currentLoopState = convertedLoopState;
                convertedLoopState = convertedOuterLoopState;
                return { functionName: functionName, paramList: paramList, state: currentLoopState };
                function processVariableDeclaration(name) {
                    if (name.kind === 69 /* Identifier */) {
                        var nameText = isNameOfNestedBlockScopedRedeclarationOrCapturedBinding(name)
                            ? getGeneratedNameForNode(name)
                            : name.text;
                        loopParameters.push(nameText);
                        if (resolver.getNodeCheckFlags(name.parent) & 2097152 /* NeedsLoopOutParameter */) {
                            var reassignedVariable = { originalName: name, outParamName: makeUniqueName("out_" + nameText) };
                            (loopOutParameters || (loopOutParameters = [])).push(reassignedVariable);
                        }
                    }
                    else {
                        for (var _a = 0, _b = name.elements; _a < _b.length; _a++) {
                            var element = _b[_a];
                            processVariableDeclaration(element.name);
                        }
                    }
                }
            }
            function emitNormalLoopBody(node, emitAsEmbeddedStatement) {
                var saveAllowedNonLabeledJumps;
                if (convertedLoopState) {
                    // we get here if we are trying to emit normal loop loop inside converted loop
                    // set allowedNonLabeledJumps to Break | Continue to mark that break\continue inside the loop should be emitted as is
                    saveAllowedNonLabeledJumps = convertedLoopState.allowedNonLabeledJumps;
                    convertedLoopState.allowedNonLabeledJumps = 2 /* Break */ | 4 /* Continue */;
                }
                if (emitAsEmbeddedStatement) {
                    emitEmbeddedStatement(node.statement);
                }
                else if (node.statement.kind === 199 /* Block */) {
                    emitLines(node.statement.statements);
                }
                else {
                    writeLine();
                    emit(node.statement);
                }
                if (convertedLoopState) {
                    convertedLoopState.allowedNonLabeledJumps = saveAllowedNonLabeledJumps;
                }
            }
            function copyLoopOutParameters(state, copyDirection, emitAsStatements) {
                if (state.loopOutParameters) {
                    for (var _a = 0, _b = state.loopOutParameters; _a < _b.length; _a++) {
                        var outParam = _b[_a];
                        if (copyDirection === 0 /* ToOriginal */) {
                            emitIdentifier(outParam.originalName);
                            write(" = " + outParam.outParamName);
                        }
                        else {
                            write(outParam.outParamName + " = ");
                            emitIdentifier(outParam.originalName);
                        }
                        if (emitAsStatements) {
                            write(";");
                            writeLine();
                        }
                        else {
                            write(", ");
                        }
                    }
                }
            }
            function emitConvertedLoopCall(loop, emitAsBlock) {
                if (emitAsBlock) {
                    write(" {");
                    writeLine();
                    increaseIndent();
                }
                // loop is considered simple if it does not have any return statements or break\continue that transfer control outside of the loop
                // simple loops are emitted as just 'loop()';
                // NOTE: if loop uses only 'continue' it still will be emitted as simple loop
                var isSimpleLoop = !(loop.state.nonLocalJumps & ~4 /* Continue */) &&
                    !loop.state.labeledNonLocalBreaks &&
                    !loop.state.labeledNonLocalContinues;
                var loopResult = makeUniqueName("state");
                if (!isSimpleLoop) {
                    write("var " + loopResult + " = ");
                }
                write(loop.functionName + "(" + loop.paramList + ");");
                writeLine();
                copyLoopOutParameters(loop.state, 0 /* ToOriginal */, /*emitAsStatements*/ true);
                if (!isSimpleLoop) {
                    // for non simple loops we need to store result returned from converted loop function and use it to do dispatching
                    // converted loop function can return:
                    // - object - used when body of the converted loop contains return statement. Property "value" of this object stores retuned value
                    // - string - used to dispatch jumps. "break" and "continue" are used to non-labeled jumps, other values are used to transfer control to
                    //   different labels
                    writeLine();
                    if (loop.state.nonLocalJumps & 8 /* Return */) {
                        write("if (typeof " + loopResult + " === \"object\") ");
                        if (convertedLoopState) {
                            // we are currently nested in another converted loop - return unwrapped result
                            write("return " + loopResult + ";");
                            // propagate 'hasReturn' flag to outer loop
                            convertedLoopState.nonLocalJumps |= 8 /* Return */;
                        }
                        else {
                            // top level converted loop - return unwrapped value
                            write("return " + loopResult + ".value;");
                        }
                        writeLine();
                    }
                    if (loop.state.nonLocalJumps & 2 /* Break */) {
                        write("if (" + loopResult + " === \"break\") break;");
                        writeLine();
                    }
                    // in case of labeled breaks emit code that either breaks to some known label inside outer loop or delegates jump decision to outer loop
                    emitDispatchTableForLabeledJumps(loopResult, loop.state, convertedLoopState);
                }
                if (emitAsBlock) {
                    writeLine();
                    decreaseIndent();
                    write("}");
                }
                function emitDispatchTableForLabeledJumps(loopResultVariable, currentLoop, outerLoop) {
                    if (!currentLoop.labeledNonLocalBreaks && !currentLoop.labeledNonLocalContinues) {
                        return;
                    }
                    write("switch(" + loopResultVariable + ") {");
                    increaseIndent();
                    emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalBreaks, /*isBreak*/ true, loopResultVariable, outerLoop);
                    emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalContinues, /*isBreak*/ false, loopResultVariable, outerLoop);
                    decreaseIndent();
                    writeLine();
                    write("}");
                }
                function emitDispatchEntriesForLabeledJumps(table, isBreak, loopResultVariable, outerLoop) {
                    if (!table) {
                        return;
                    }
                    for (var labelText in table) {
                        var labelMarker = table[labelText];
                        writeLine();
                        write("case \"" + labelMarker + "\": ");
                        // if there are no outer converted loop or outer label in question is located inside outer converted loop
                        // then emit labeled break\continue
                        // otherwise propagate pair 'label -> marker' to outer converted loop and emit 'return labelMarker' so outer loop can later decide what to do
                        if (!outerLoop || (outerLoop.labels && outerLoop.labels[labelText])) {
                            if (isBreak) {
                                write("break ");
                            }
                            else {
                                write("continue ");
                            }
                            write(labelText + ";");
                        }
                        else {
                            setLabeledJump(outerLoop, isBreak, labelText, labelMarker);
                            write("return " + loopResultVariable + ";");
                        }
                    }
                }
            }
            function emitForStatement(node) {
                emitLoop(node, emitForStatementWorker);
            }
            function emitForStatementWorker(node, loop) {
                var endPos = emitToken(86 /* ForKeyword */, node.pos);
                write(" ");
                endPos = emitToken(17 /* OpenParenToken */, endPos);
                if (node.initializer && node.initializer.kind === 219 /* VariableDeclarationList */) {
                    var variableDeclarationList = node.initializer;
                    var startIsEmitted = tryEmitStartOfVariableDeclarationList(variableDeclarationList);
                    if (startIsEmitted) {
                        emitCommaList(variableDeclarationList.declarations);
                    }
                    else {
                        emitVariableDeclarationListSkippingUninitializedEntries(variableDeclarationList);
                    }
                }
                else if (node.initializer) {
                    emit(node.initializer);
                }
                write(";");
                emitOptional(" ", node.condition);
                write(";");
                emitOptional(" ", node.incrementor);
                write(")");
                if (loop) {
                    emitConvertedLoopCall(loop, /*emitAsBlock*/ true);
                }
                else {
                    emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true);
                }
            }
            function emitForInOrForOfStatement(node) {
                if (languageVersion < 2 /* ES6 */ && node.kind === 208 /* ForOfStatement */) {
                    emitLoop(node, emitDownLevelForOfStatementWorker);
                }
                else {
                    emitLoop(node, emitForInOrForOfStatementWorker);
                }
            }
            function emitForInOrForOfStatementWorker(node, loop) {
                var endPos = emitToken(86 /* ForKeyword */, node.pos);
                write(" ");
                endPos = emitToken(17 /* OpenParenToken */, endPos);
                if (node.initializer.kind === 219 /* VariableDeclarationList */) {
                    var variableDeclarationList = node.initializer;
                    if (variableDeclarationList.declarations.length >= 1) {
                        tryEmitStartOfVariableDeclarationList(variableDeclarationList);
                        emit(variableDeclarationList.declarations[0]);
                    }
                }
                else {
                    emit(node.initializer);
                }
                if (node.kind === 207 /* ForInStatement */) {
                    write(" in ");
                }
                else {
                    write(" of ");
                }
                emit(node.expression);
                emitToken(18 /* CloseParenToken */, node.expression.end);
                if (loop) {
                    emitConvertedLoopCall(loop, /*emitAsBlock*/ true);
                }
                else {
                    emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true);
                }
            }
            function emitDownLevelForOfStatementWorker(node, loop) {
                // 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 can't reuse 'arr' because it might be modified within the body of the loop.
                var counter = createTempVariable(268435456 /* _i */);
                var rhsReference = ts.createSynthesizedNode(69 /* Identifier */);
                rhsReference.text = node.expression.kind === 69 /* Identifier */ ?
                    makeUniqueName(node.expression.text) :
                    makeTempVariableName(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);
                // , _a = expr
                write(", ");
                emitStart(node.expression);
                emitNodeWithoutSourceMap(rhsReference);
                write(" = ");
                emitNodeWithoutSourceMap(node.expression);
                emitEnd(node.expression);
                write("; ");
                // _i < _a.length;
                emitStart(node.expression);
                emitNodeWithoutSourceMap(counter);
                write(" < ");
                emitNodeWithCommentsAndWithoutSourcemap(rhsReference);
                write(".length");
                emitEnd(node.expression);
                write("; ");
                // _i++)
                emitStart(node.expression);
                emitNodeWithoutSourceMap(counter);
                write("++");
                emitEnd(node.expression);
                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 === 219 /* 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 === 170 /* ArrayLiteralExpression */ || node.initializer.kind === 171 /* 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 (loop) {
                    writeLine();
                    emitConvertedLoopCall(loop, /*emitAsBlock*/ false);
                }
                else {
                    emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ false);
                }
                writeLine();
                decreaseIndent();
                write("}");
            }
            function emitBreakOrContinueStatement(node) {
                if (convertedLoopState) {
                    // check if we can emit break\continue as is
                    // it is possible if either
                    //   - break\continue is statement labeled and label is located inside the converted loop
                    //   - break\continue is non-labeled and located in non-converted loop\switch statement
                    var jump = node.kind === 210 /* BreakStatement */ ? 2 /* Break */ : 4 /* Continue */;
                    var canUseBreakOrContinue = (node.label && convertedLoopState.labels && convertedLoopState.labels[node.label.text]) ||
                        (!node.label && (convertedLoopState.allowedNonLabeledJumps & jump));
                    if (!canUseBreakOrContinue) {
                        write("return ");
                        // explicit exit from loop -> copy out parameters
                        copyLoopOutParameters(convertedLoopState, 1 /* ToOutParameter */, /*emitAsStatements*/ false);
                        if (!node.label) {
                            if (node.kind === 210 /* BreakStatement */) {
                                convertedLoopState.nonLocalJumps |= 2 /* Break */;
                                write("\"break\";");
                            }
                            else {
                                convertedLoopState.nonLocalJumps |= 4 /* Continue */;
                                // note: return value is emitted only to simplify debugging, call to converted loop body does not do any dispatching on it.
                                write("\"continue\";");
                            }
                        }
                        else {
                            var labelMarker = void 0;
                            if (node.kind === 210 /* BreakStatement */) {
                                labelMarker = "break-" + node.label.text;
                                setLabeledJump(convertedLoopState, /*isBreak*/ true, node.label.text, labelMarker);
                            }
                            else {
                                labelMarker = "continue-" + node.label.text;
                                setLabeledJump(convertedLoopState, /*isBreak*/ false, node.label.text, labelMarker);
                            }
                            write("\"" + labelMarker + "\";");
                        }
                        return;
                    }
                }
                emitToken(node.kind === 210 /* BreakStatement */ ? 70 /* BreakKeyword */ : 75 /* ContinueKeyword */, node.pos);
                emitOptional(" ", node.label);
                write(";");
            }
            function emitReturnStatement(node) {
                if (convertedLoopState) {
                    convertedLoopState.nonLocalJumps |= 8 /* Return */;
                    write("return { value: ");
                    if (node.expression) {
                        emit(node.expression);
                    }
                    else {
                        write("void 0");
                    }
                    write(" };");
                    return;
                }
                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(" ");
                var saveAllowedNonLabeledJumps;
                if (convertedLoopState) {
                    saveAllowedNonLabeledJumps = convertedLoopState.allowedNonLabeledJumps;
                    // for switch statement allow only non-labeled break
                    convertedLoopState.allowedNonLabeledJumps |= 2 /* Break */;
                }
                emitCaseBlock(node.caseBlock, endPos);
                if (convertedLoopState) {
                    convertedLoopState.allowedNonLabeledJumps = saveAllowedNonLabeledJumps;
                }
            }
            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.getLineOfLocalPositionFromLineMap(currentLineMap, ts.skipTrivia(currentText, node1.pos)) ===
                    ts.getLineOfLocalPositionFromLineMap(currentLineMap, ts.skipTrivia(currentText, node2.pos));
            }
            function nodeEndPositionsAreOnSameLine(node1, node2) {
                return ts.getLineOfLocalPositionFromLineMap(currentLineMap, node1.end) ===
                    ts.getLineOfLocalPositionFromLineMap(currentLineMap, node2.end);
            }
            function nodeEndIsOnSameLineAsNodeStart(node1, node2) {
                return ts.getLineOfLocalPositionFromLineMap(currentLineMap, node1.end) ===
                    ts.getLineOfLocalPositionFromLineMap(currentLineMap, ts.skipTrivia(currentText, node2.pos));
            }
            function emitCaseOrDefaultClause(node) {
                if (node.kind === 249 /* 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 emitLabelAndColon(node) {
                emit(node.label);
                write(": ");
            }
            function emitLabeledStatement(node) {
                if (!ts.isIterationStatement(node.statement, /* lookInLabeledStatements */ false) || !shouldConvertLoopBody(node.statement)) {
                    emitLabelAndColon(node);
                }
                if (convertedLoopState) {
                    if (!convertedLoopState.labels) {
                        convertedLoopState.labels = ts.createMap();
                    }
                    convertedLoopState.labels[node.label.text] = node.label.text;
                }
                emit(node.statement);
                if (convertedLoopState) {
                    convertedLoopState.labels[node.label.text] = undefined;
                }
            }
            function getContainingModule(node) {
                do {
                    node = node.parent;
                } while (node && node.kind !== 225 /* 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 !== ts.ModuleKind.ES6 && modulekind !== ts.ModuleKind.System) {
                        write("exports.");
                    }
                }
                emitNodeWithCommentsAndWithoutSourcemap(node.name);
                emitEnd(node.name);
            }
            function createVoidZero() {
                var zero = ts.createSynthesizedNode(8 /* NumericLiteral */);
                zero.text = "0";
                var result = ts.createSynthesizedNode(183 /* VoidExpression */);
                result.expression = zero;
                return result;
            }
            function emitEs6ExportDefaultCompat(node) {
                if (node.parent.kind === 256 /* SourceFile */) {
                    ts.Debug.assert(!!(node.flags & 512 /* Default */) || node.kind === 235 /* ExportAssignment */);
                    // only allow export default at a source file level
                    if (modulekind === ts.ModuleKind.CommonJS || modulekind === ts.ModuleKind.AMD || modulekind === ts.ModuleKind.UMD) {
                        if (!isEs6Module) {
                            if (languageVersion !== 0 /* ES3 */) {
                                // default value of configurable, enumerable, writable are `false`.
                                write('Object.defineProperty(exports, "__esModule", { value: true });');
                                writeLine();
                            }
                            else {
                                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 === ts.ModuleKind.System && node.parent === currentSourceFile) {
                        // emit export default <smth> as
                        // export("default", <smth>)
                        write(exportFunctionForFile + "(\"");
                        if (node.flags & 512 /* Default */) {
                            write("default");
                        }
                        else {
                            emitNodeWithCommentsAndWithoutSourcemap(node.name);
                        }
                        write("\", ");
                        emitDeclarationName(node);
                        write(")");
                    }
                    else {
                        if (node.flags & 512 /* 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 === ts.ModuleKind.System) {
                    return;
                }
                if (!exportEquals && exportSpecifiers && name.text in exportSpecifiers) {
                    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 === ts.ModuleKind.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, nodeForSourceMap) {
                if (shouldEmitCommaBeforeAssignment) {
                    write(", ");
                }
                var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name);
                if (exportChanged) {
                    write(exportFunctionForFile + "(\"");
                    emitNodeWithCommentsAndWithoutSourcemap(name);
                    write("\", ");
                }
                var isVariableDeclarationOrBindingElement = name.parent && (name.parent.kind === 218 /* VariableDeclaration */ || name.parent.kind === 169 /* BindingElement */);
                // If this is first var declaration, we need to start at var/let/const keyword instead
                // otherwise use nodeForSourceMap as the start position
                emitStart(isFirstVariableDeclaration(nodeForSourceMap) ? nodeForSourceMap.parent : nodeForSourceMap);
                withTemporaryNoSourceMap(function () {
                    if (isVariableDeclarationOrBindingElement) {
                        emitModuleMemberName(name.parent);
                    }
                    else {
                        emit(name);
                    }
                    write(" = ");
                    emit(value);
                });
                emitEnd(nodeForSourceMap, /*stopOverridingSpan*/ true);
                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, sourceMapNode) {
                var identifier = createTempVariable(0 /* Auto */);
                if (!canDefineTempVariablesInPlace) {
                    recordTempDeclaration(identifier);
                }
                emitAssignment(identifier, expression, shouldEmitCommaBeforeAssignment, sourceMapNode || expression.parent);
                return identifier;
            }
            function isFirstVariableDeclaration(root) {
                return root.kind === 218 /* VariableDeclaration */ &&
                    root.parent.kind === 219 /* VariableDeclarationList */ &&
                    root.parent.declarations[0] === root;
            }
            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 === 218 /* VariableDeclaration */) {
                    var isExported = ts.getCombinedNodeFlags(root) & 1 /* Export */;
                    var isSourceLevelForSystemModuleKind = shouldHoistDeclarationInSystemJsModule(root);
                    canDefineTempVariablesInPlace = !isExported && !isSourceLevelForSystemModuleKind;
                }
                else if (root.kind === 142 /* Parameter */) {
                    canDefineTempVariablesInPlace = true;
                }
                if (root.kind === 187 /* BinaryExpression */) {
                    emitAssignmentExpression(root);
                }
                else {
                    ts.Debug.assert(!isAssignmentExpressionStatement);
                    // If first variable declaration of variable statement correct the start location
                    if (isFirstVariableDeclaration(root)) {
                        // Use emit location of "var " as next emit start entry
                        sourceMap.changeEmitSourcePos();
                    }
                    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, sourceMapNode) {
                    if (expr.kind === 69 /* Identifier */ && reuseIdentifierExpressions) {
                        return expr;
                    }
                    var identifier = emitTempVariableAssignment(expr, canDefineTempVariablesInPlace, emitCount > 0, sourceMapNode);
                    emitCount++;
                    return identifier;
                }
                function createDefaultValueCheck(value, defaultValue, sourceMapNode) {
                    // The value expression will be evaluated twice, so for anything but a simple identifier
                    // we need to generate a temporary variable
                    // If the temporary variable needs to be emitted use the source Map node for assignment of that statement
                    value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, sourceMapNode);
                    // Return the expression 'value === void 0 ? defaultValue : value'
                    var equals = ts.createSynthesizedNode(187 /* 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(188 /* 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) {
                    var index;
                    var nameIsComputed = propName.kind === 140 /* ComputedPropertyName */;
                    if (nameIsComputed) {
                        // TODO to handle when we look into sourcemaps for computed properties, for now use propName
                        index = ensureIdentifier(propName.expression, /*reuseIdentifierExpressions*/ false, propName);
                    }
                    else {
                        // We create a synthetic copy of the identifier in order to avoid the rewriting that might
                        // otherwise occur when the identifier is emitted.
                        index = ts.createSynthesizedNode(propName.kind);
                        // We need to unescape identifier here because when parsing an identifier prefixing with "__"
                        // the parser need to append "_" in order to escape colliding with magic identifiers such as "__proto__"
                        // Therefore, in order to correctly emit identifiers that are written in original TypeScript file,
                        // we will unescapeIdentifier to remove additional underscore (if no underscore is added, the function will return original input string)
                        index.text = ts.unescapeIdentifier(propName.text);
                    }
                    return !nameIsComputed && index.kind === 69 /* Identifier */
                        ? createPropertyAccessExpression(object, index)
                        : createElementAccessExpression(object, index);
                }
                function createSliceCall(value, sliceIndex) {
                    var call = ts.createSynthesizedNode(174 /* 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, sourceMapNode) {
                    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.
                        // When doing so we want to highlight the passed in source map node since thats the one needing this temp assignment
                        value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, sourceMapNode);
                    }
                    for (var _a = 0, properties_5 = properties; _a < properties_5.length; _a++) {
                        var p = properties_5[_a];
                        if (p.kind === 253 /* PropertyAssignment */ || p.kind === 254 /* ShorthandPropertyAssignment */) {
                            var propName = p.name;
                            var target_1 = p.kind === 254 /* ShorthandPropertyAssignment */ ? p : p.initializer || propName;
                            // Assignment for target = value.propName should highlight whole property, hence use p as source map node
                            emitDestructuringAssignment(target_1, createPropertyAccessForDestructuringProperty(value, propName), p);
                        }
                    }
                }
                function emitArrayLiteralAssignment(target, value, sourceMapNode) {
                    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.
                        // When doing so we want to highlight the passed in source map node since thats the one needing this temp assignment
                        value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, sourceMapNode);
                    }
                    for (var i = 0; i < elements.length; i++) {
                        var e = elements[i];
                        if (e.kind !== 193 /* OmittedExpression */) {
                            // Assignment for target = value.propName should highlight whole property, hence use e as source map node
                            if (e.kind !== 191 /* SpreadElementExpression */) {
                                emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i)), e);
                            }
                            else if (i === elements.length - 1) {
                                emitDestructuringAssignment(e.expression, createSliceCall(value, i), e);
                            }
                        }
                    }
                }
                function emitDestructuringAssignment(target, value, sourceMapNode) {
                    // When emitting target = value use source map node to highlight, including any temporary assignments needed for this
                    if (target.kind === 254 /* ShorthandPropertyAssignment */) {
                        if (target.objectAssignmentInitializer) {
                            value = createDefaultValueCheck(value, target.objectAssignmentInitializer, sourceMapNode);
                        }
                        target = target.name;
                    }
                    else if (target.kind === 187 /* BinaryExpression */ && target.operatorToken.kind === 56 /* EqualsToken */) {
                        value = createDefaultValueCheck(value, target.right, sourceMapNode);
                        target = target.left;
                    }
                    if (target.kind === 171 /* ObjectLiteralExpression */) {
                        emitObjectLiteralAssignment(target, value, sourceMapNode);
                    }
                    else if (target.kind === 170 /* ArrayLiteralExpression */) {
                        emitArrayLiteralAssignment(target, value, sourceMapNode);
                    }
                    else {
                        emitAssignment(target, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0, sourceMapNode);
                        emitCount++;
                    }
                }
                function emitAssignmentExpression(root) {
                    var target = root.left;
                    var value = root.right;
                    if (ts.isEmptyObjectLiteralOrArrayLiteral(target)) {
                        emit(value);
                    }
                    else if (isAssignmentExpressionStatement) {
                        // Source map node for root.left = root.right is root
                        // but if root is synthetic, which could be in below case, use the target which is { a }
                        // for ({a} of {a: string}) {
                        // }
                        emitDestructuringAssignment(target, value, ts.nodeIsSynthesized(root) ? target : root);
                    }
                    else {
                        if (root.parent.kind !== 178 /* ParenthesizedExpression */) {
                            write("(");
                        }
                        // Temporary assignment needed to emit root should highlight whole binary expression
                        value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, root);
                        // Source map node for root.left = root.right is root
                        emitDestructuringAssignment(target, value, root);
                        write(", ");
                        emit(value);
                        if (root.parent.kind !== 178 /* ParenthesizedExpression */) {
                            write(")");
                        }
                    }
                }
                function emitBindingElement(target, value) {
                    // Any temporary assignments needed to emit target = value should point to target
                    if (target.initializer) {
                        // Combine value and initializer
                        value = value ? createDefaultValueCheck(value, target.initializer, target) : 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, target);
                        }
                        for (var i = 0; i < numElements; i++) {
                            var element = elements[i];
                            if (pattern.kind === 167 /* 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 !== 193 /* 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, target);
                        emitCount++;
                    }
                }
            }
            function emitVariableDeclaration(node) {
                if (ts.isBindingPattern(node.name)) {
                    var isExported = ts.getCombinedNodeFlags(node) & 1 /* Export */;
                    if (languageVersion >= 2 /* ES6 */ && (!isExported || modulekind === ts.ModuleKind.ES6)) {
                        // emit ES6 destructuring only if target module is ES6 or variable is not exported
                        // exported variables in CJS/AMD are prefixed with 'exports.' so result javascript { exports.toString } = 1; is illegal
                        var isTopLevelDeclarationInSystemModule = modulekind === ts.ModuleKind.System &&
                            shouldHoistVariable(node, /*checkIfSourceFileLevelDecl*/ true);
                        if (isTopLevelDeclarationInSystemModule) {
                            // In System modules top level variables are hoisted
                            // so variable declarations with destructuring are turned into destructuring assignments.
                            // As a result, they will need parentheses to disambiguate object binding assignments from blocks.
                            write("(");
                        }
                        emit(node.name);
                        emitOptional(" = ", node.initializer);
                        if (isTopLevelDeclarationInSystemModule) {
                            write(")");
                        }
                    }
                    else {
                        emitDestructuring(node, /*isAssignmentExpressionStatement*/ false);
                    }
                }
                else {
                    var initializer = node.initializer;
                    if (!initializer &&
                        languageVersion < 2 /* ES6 */ &&
                        // for names - binding patterns that lack initializer there is no point to emit explicit initializer
                        // since downlevel codegen for destructuring will fail in the absence of initializer so all binding elements will say uninitialized
                        node.name.kind === 69 /* Identifier */) {
                        var container = ts.getEnclosingBlockScopeContainer(node);
                        var flags = resolver.getNodeCheckFlags(node);
                        // nested let bindings might need to be initialized explicitly to preserve ES6 semantic
                        // { let x = 1; }
                        // { let x; } // x here should be undefined. not 1
                        // NOTES:
                        // Top level bindings never collide with anything and thus don't require explicit initialization.
                        // As for nested let bindings there are two cases:
                        // - nested let bindings that were not renamed definitely should be initialized explicitly
                        //   { let x = 1; }
                        //   { let x; if (some-condition) { x = 1}; if (x) { /*1*/ } }
                        //   Without explicit initialization code in /*1*/ can be executed even if some-condition is evaluated to false
                        // - renaming introduces fresh name that should not collide with any existing names, however renamed bindings sometimes also should be
                        //   explicitly initialized. One particular case: non-captured binding declared inside loop body (but not in loop initializer)
                        //   let x;
                        //   for (;;) {
                        //       let x;
                        //   }
                        //   in downlevel codegen inner 'x' will be renamed so it won't collide with outer 'x' however it will should be reset on every iteration
                        //   as if it was declared anew.
                        //   * Why non-captured binding - because if loop contains block scoped binding captured in some function then loop body will be rewritten
                        //   to have a fresh scope on every iteration so everything will just work.
                        //   * Why loop initializer is excluded - since we've introduced a fresh name it already will be undefined.
                        var isCapturedInFunction = flags & 131072 /* CapturedBlockScopedBinding */;
                        var isDeclaredInLoop = flags & 262144 /* BlockScopedBindingInLoop */;
                        var emittedAsTopLevel = ts.isBlockScopedContainerTopLevel(container) ||
                            (isCapturedInFunction && isDeclaredInLoop && container.kind === 199 /* Block */ && ts.isIterationStatement(container.parent, /*lookInLabeledStatements*/ false));
                        var emittedAsNestedLetDeclaration = ts.getCombinedNodeFlags(node) & 1024 /* Let */ &&
                            !emittedAsTopLevel;
                        var emitExplicitInitializer = emittedAsNestedLetDeclaration &&
                            container.kind !== 207 /* ForInStatement */ &&
                            container.kind !== 208 /* ForOfStatement */ &&
                            (!resolver.isDeclarationWithCollidingName(node) ||
                                (isDeclaredInLoop && !isCapturedInFunction && !ts.isIterationStatement(container, /*lookInLabeledStatements*/ false)));
                        if (emitExplicitInitializer) {
                            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 === 193 /* OmittedExpression */) {
                    return;
                }
                var name = node.name;
                if (name.kind === 69 /* Identifier */) {
                    emitExportMemberAssignments(name);
                }
                else if (ts.isBindingPattern(name)) {
                    ts.forEach(name.elements, emitExportVariableAssignments);
                }
            }
            function isES6ExportedDeclaration(node) {
                return !!(node.flags & 1 /* Export */) &&
                    modulekind === ts.ModuleKind.ES6 &&
                    node.parent.kind === 256 /* 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 !== ts.ModuleKind.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_29 = createTempVariable(0 /* Auto */);
                        if (!tempParameters) {
                            tempParameters = [];
                        }
                        tempParameters.push(name_29);
                        emit(name_29);
                    }
                    else {
                        emit(node.name);
                    }
                }
                else {
                    if (node.dotDotDotToken) {
                        write("...");
                    }
                    emit(node.name);
                    emitOptional(" = ", node.initializer);
                }
            }
            function emitDefaultValueAssignments(node) {
                if (languageVersion < 2 /* ES6 */) {
                    var tempIndex_1 = 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_1]);
                                }
                                else {
                                    emit(tempParameters[tempIndex_1]);
                                    write(" = ");
                                    emit(initializer);
                                }
                                write(";");
                            }
                            // Regardless of whether we will emit a var declaration for the binding pattern, we generate the temporary
                            // variable for the parameter (see: emitParameter)
                            tempIndex_1++;
                        }
                        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.hasDeclaredRestParameter(node)) {
                    var restParam = node.parameters[node.parameters.length - 1];
                    // A rest parameter cannot have a binding pattern, so let's just ignore it if it does.
                    if (ts.isBindingPattern(restParam.name)) {
                        return;
                    }
                    var skipThisCount = node.parameters.length && node.parameters[0].name.originalKeywordKind === 97 /* ThisKeyword */ ? 1 : 0;
                    var restIndex = node.parameters.length - 1 - skipThisCount;
                    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 === 149 /* GetAccessor */ ? "get " : "set ");
                emit(node.name);
                emitSignatureAndBody(node);
            }
            function shouldEmitAsArrowFunction(node) {
                return node.kind === 180 /* ArrowFunction */ && languageVersion >= 2 /* ES6 */;
            }
            function emitDeclarationName(node) {
                if (node.name) {
                    emitNodeWithCommentsAndWithoutSourcemap(node.name);
                }
                else {
                    write(getGeneratedNameForNode(node));
                }
            }
            function shouldEmitFunctionName(node) {
                if (node.kind === 179 /* FunctionExpression */) {
                    // Emit name if one is present
                    return !!node.name;
                }
                if (node.kind === 220 /* FunctionDeclaration */) {
                    // Emit name if one is present, or emit generated name in down-level case (for export default case)
                    return !!node.name || modulekind !== ts.ModuleKind.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.
                var kind = node.kind, parent = node.parent;
                if (kind !== 147 /* MethodDeclaration */ &&
                    kind !== 146 /* MethodSignature */ &&
                    parent &&
                    parent.kind !== 253 /* PropertyAssignment */ &&
                    parent.kind !== 174 /* CallExpression */ &&
                    parent.kind !== 170 /* ArrayLiteralExpression */) {
                    // 1. Methods will emit comments at their assignment declaration sites.
                    //
                    // 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:
                    //
                    //          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'.
                    //
                    // 4. If the function is in an array literal, 'emitLinePreservingList' will take care
                    //    of leading comments.
                    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 & 512 /* Default */) {
                            write("default ");
                        }
                    }
                    write("function");
                    if (languageVersion >= 2 /* ES6 */ && node.asteriskToken) {
                        write("*");
                    }
                    write(" ");
                }
                if (shouldEmitFunctionName(node)) {
                    emitDeclarationName(node);
                }
                emitSignatureAndBody(node);
                if (modulekind !== ts.ModuleKind.ES6 && kind === 220 /* FunctionDeclaration */ && parent === currentSourceFile && node.name) {
                    emitExportMemberAssignments(node.name);
                }
                emitEnd(node);
                if (kind !== 147 /* MethodDeclaration */ &&
                    kind !== 146 /* MethodSignature */ &&
                    kind !== 180 /* ArrowFunction */) {
                    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 skipCount = node.parameters.length && node.parameters[0].name.originalKeywordKind === 97 /* ThisKeyword */ ? 1 : 0;
                    var omitCount = languageVersion < 2 /* ES6 */ && ts.hasDeclaredRestParameter(node) ? 1 : 0;
                    emitList(parameters, skipCount, parameters.length - omitCount - skipCount, /*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 === 180 /* ArrowFunction */;
                var hasLexicalArguments = (resolver.getNodeCheckFlags(node) & 8192 /* CaptureArguments */) !== 0;
                // 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();
                    if (resolver.getNodeCheckFlags(node) & 4096 /* AsyncMethodWithSuperBinding */) {
                        writeLines("\nconst _super = (function (geti, seti) {\n    const cache = Object.create(null);\n    return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });\n})(name => super[name], (name, value) => super[name] = value);");
                        writeLine();
                    }
                    else if (resolver.getNodeCheckFlags(node) & 2048 /* AsyncMethodWithSuper */) {
                        write("const _super = name => super[name];");
                        writeLine();
                    }
                    write("return");
                }
                write(" __awaiter(this");
                if (hasLexicalArguments) {
                    write(", arguments, ");
                }
                else {
                    write(", void 0, ");
                }
                if (languageVersion >= 2 /* ES6 */ || !promiseConstructor) {
                    write("void 0");
                }
                else {
                    emitEntityNameAsExpression(promiseConstructor, /*useFallback*/ false);
                }
                // Emit the call to __awaiter.
                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 === 199 /* Block */) {
                        emitBlockFunctionBody(node, node.body);
                    }
                    else {
                        emitExpressionFunctionBody(node, node.body);
                    }
                }
            }
            function emitSignatureAndBody(node) {
                var saveConvertedLoopState = convertedLoopState;
                var saveTempFlags = tempFlags;
                var saveTempVariables = tempVariables;
                var saveTempParameters = tempParameters;
                convertedLoopState = undefined;
                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) {
                    emitAsyncFunctionBodyForES6(node);
                }
                else {
                    emitFunctionBody(node);
                }
                if (!isES6ExportedDeclaration(node)) {
                    emitExportMemberAssignment(node);
                }
                ts.Debug.assert(convertedLoopState === undefined);
                convertedLoopState = saveConvertedLoopState;
                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 & 256 /* 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 === 177 /* TypeAssertionExpression */) {
                    current = current.expression;
                }
                emitParenthesizedIf(body, current.kind === 171 /* ObjectLiteralExpression */);
            }
            function emitDownLevelExpressionFunctionBody(node, body) {
                write(" {");
                increaseIndent();
                var outPos = writer.getTextPos();
                emitDetachedCommentsAndUpdateCommentsInfo(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);
                    emitStart(body);
                    write("return ");
                    emit(body);
                    emitEnd(body);
                    write(";");
                    emitTrailingComments(node.body);
                    emitTempDeclarations(/*newLine*/ true);
                    decreaseIndent();
                    writeLine();
                }
                emitStart(node.body);
                write("}");
                emitEnd(node.body);
            }
            function emitBlockFunctionBody(node, body) {
                write(" {");
                var initialTextPos = writer.getTextPos();
                increaseIndent();
                emitDetachedCommentsAndUpdateCommentsInfo(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);
            }
            /**
             * Return the statement at a given index if it is a super-call statement
             * @param ctor a constructor declaration
             * @param index an index to constructor's body to check
             */
            function getSuperCallAtGivenIndex(ctor, index) {
                if (!ctor.body) {
                    return undefined;
                }
                var statements = ctor.body.statements;
                if (!statements || index >= statements.length) {
                    return undefined;
                }
                var statement = statements[index];
                if (statement.kind === 202 /* ExpressionStatement */) {
                    return ts.isSuperCallExpression(statement.expression) ? statement : undefined;
                }
            }
            function emitParameterPropertyAssignments(node) {
                ts.forEach(node.parameters, function (param) {
                    if (param.flags & 92 /* ParameterPropertyModifier */) {
                        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 === 140 /* 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 === 145 /* PropertyDeclaration */ && isStatic === ((member.flags & 32 /* Static */) !== 0) && member.initializer) {
                        properties.push(member);
                    }
                }
                return properties;
            }
            function emitPropertyDeclarations(node, properties) {
                for (var _a = 0, properties_6 = properties; _a < properties_6.length; _a++) {
                    var property = properties_6[_a];
                    emitPropertyDeclaration(node, property);
                }
            }
            function emitPropertyDeclaration(node, property, receiver, isExpression) {
                writeLine();
                emitLeadingComments(property);
                emitStart(property);
                emitStart(property.name);
                if (receiver) {
                    write(receiver);
                }
                else {
                    if (property.flags & 32 /* 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 === 198 /* SemicolonClassElement */) {
                        writeLine();
                        write(";");
                    }
                    else if (member.kind === 147 /* MethodDeclaration */ || node.kind === 146 /* 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 === 149 /* GetAccessor */ || member.kind === 150 /* 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 === 147 /* MethodDeclaration */ || node.kind === 146 /* MethodSignature */) && !member.body) {
                        emitCommentsOnNotEmittedNode(member);
                    }
                    else if (member.kind === 147 /* MethodDeclaration */ ||
                        member.kind === 149 /* GetAccessor */ ||
                        member.kind === 150 /* SetAccessor */) {
                        writeLine();
                        emitLeadingComments(member);
                        emitStart(member);
                        if (member.flags & 32 /* Static */) {
                            write("static ");
                        }
                        if (member.kind === 149 /* GetAccessor */) {
                            write("get ");
                        }
                        else if (member.kind === 150 /* SetAccessor */) {
                            write("set ");
                        }
                        if (member.asteriskToken) {
                            write("*");
                        }
                        emit(member.name);
                        emitSignatureAndBody(member);
                        emitEnd(member);
                        emitTrailingComments(member);
                    }
                    else if (member.kind === 198 /* SemicolonClassElement */) {
                        writeLine();
                        write(";");
                    }
                }
            }
            function emitConstructor(node, baseTypeElement) {
                var saveConvertedLoopState = convertedLoopState;
                var saveTempFlags = tempFlags;
                var saveTempVariables = tempVariables;
                var saveTempParameters = tempParameters;
                convertedLoopState = undefined;
                tempFlags = 0;
                tempVariables = undefined;
                tempParameters = undefined;
                emitConstructorWorker(node, baseTypeElement);
                ts.Debug.assert(convertedLoopState === undefined);
                convertedLoopState = saveConvertedLoopState;
                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 === 148 /* Constructor */ && !member.body) {
                        emitCommentsOnNotEmittedNode(member);
                    }
                    // Check if there is any non-static property assignment
                    if (member.kind === 145 /* PropertyDeclaration */ && member.initializer && (member.flags & 32 /* 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 {
                        // The ES2015 spec specifies in 14.5.14. Runtime Semantics: ClassDefinitionEvaluation:
                        // If constructor is empty, then
                        //     If ClassHeritag_eopt is present and protoParent is not null, then
                        //          Let constructor be the result of parsing the source text
                        //              constructor(...args) { super (...args);}
                        //          using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
                        //      Else,
                        //           Let constructor be the result of parsing the source text
                        //               constructor( ){ }
                        //           using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
                        //
                        // While we could emit the '...args' rest parameter, certain later tools in the pipeline might
                        // downlevel the '...args' portion less efficiently by naively copying the contents of 'arguments' to an array.
                        // Instead, we'll avoid using a rest parameter and spread into the super call as
                        // 'super(...arguments)' instead of 'super(...args)', as you can see below.
                        write("()");
                    }
                }
                var startIndex = 0;
                write(" {");
                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);
                    emitDetachedCommentsAndUpdateCommentsInfo(ctor.body.statements);
                }
                emitCaptureThisForNodeIfNecessary(node);
                var superCall;
                if (ctor) {
                    emitDefaultValueAssignments(ctor);
                    emitRestParameter(ctor);
                    if (baseTypeElement) {
                        superCall = getSuperCallAtGivenIndex(ctor, startIndex);
                        if (superCall) {
                            writeLine();
                            emit(superCall);
                        }
                    }
                    emitParameterPropertyAssignments(ctor);
                }
                else {
                    if (baseTypeElement) {
                        writeLine();
                        emitStart(baseTypeElement);
                        if (languageVersion < 2 /* ES6 */) {
                            write("_super.apply(this, arguments);");
                        }
                        else {
                            // See comment above on using '...arguments' instead of '...args'.
                            write("super(...arguments);");
                        }
                        emitEnd(baseTypeElement);
                    }
                }
                emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ 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);
                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 !== ts.ModuleKind.ES6 && node.parent === currentSourceFile && node.name) {
                    emitExportMemberAssignments(node.name);
                }
            }
            function emitClassLikeDeclarationForES6AndHigher(node) {
                var decoratedClassAlias;
                var isHoistedDeclarationInSystemModule = shouldHoistDeclarationInSystemJsModule(node);
                var isDecorated = ts.nodeIsDecorated(node);
                var rewriteAsClassExpression = isDecorated || isHoistedDeclarationInSystemModule;
                if (node.kind === 221 /* ClassDeclaration */) {
                    if (rewriteAsClassExpression) {
                        // When we emit an ES6 class that has a class decorator, we must tailor the
                        // emit to certain specific cases.
                        //
                        // In the simplest case, we emit the class declaration as a let declaration, and
                        // evaluate decorators after the close of the class body:
                        //
                        //  TypeScript                      | Javascript
                        //  --------------------------------|------------------------------------
                        //  @dec                            | let C = class C {
                        //  class C {                       | }
                        //  }                               | C = __decorate([dec], C);
                        //  --------------------------------|------------------------------------
                        //  @dec                            | export let C = class C {
                        //  export class C {                | }
                        //  }                               | C = __decorate([dec], C);
                        //  ---------------------------------------------------------------------
                        //  [Example 1]
                        //
                        // If a class declaration contains a reference to itself *inside* of the class body,
                        // this introduces two bindings to the class: One outside of the class body, and one
                        // inside of the class body. If we apply decorators as in [Example 1] above, there
                        // is the possibility that the decorator `dec` will return a new value for the
                        // constructor, which would result in the binding inside of the class no longer
                        // pointing to the same reference as the binding outside of the class.
                        //
                        // As a result, we must instead rewrite all references to the class *inside* of the
                        // class body to instead point to a local temporary alias for the class:
                        //
                        //  TypeScript                      | Javascript
                        //  --------------------------------|------------------------------------
                        //  @dec                            | let C_1 = class C {
                        //  class C {                       |   static x() { return C_1.y; }
                        //    static x() { return C.y; }    | }
                        //    static y = 1;                 | let C = C_1;
                        //  }                               | C.y = 1;
                        //                                  | C = C_1 = __decorate([dec], C);
                        //  --------------------------------|------------------------------------
                        //  @dec                            | let C_1 = class C {
                        //  export class C {                |   static x() { return C_1.y; }
                        //    static x() { return C.y; }    | }
                        //    static y = 1;                 | export let C = C_1;
                        //  }                               | C.y = 1;
                        //                                  | C = C_1 = __decorate([dec], C);
                        //  ---------------------------------------------------------------------
                        //  [Example 2]
                        //
                        // If a class declaration is the default export of a module, we instead emit
                        // the export after the decorated declaration:
                        //
                        //  TypeScript                      | Javascript
                        //  --------------------------------|------------------------------------
                        //  @dec                            | let default_1 = class {
                        //  export default class {          | }
                        //  }                               | default_1 = __decorate([dec], default_1);
                        //                                  | export default default_1;
                        //  --------------------------------|------------------------------------
                        //  @dec                            | let C = class C {
                        //  export default class {          | }
                        //  }                               | C = __decorate([dec], C);
                        //                                  | export default C;
                        //  ---------------------------------------------------------------------
                        //  [Example 3]
                        //
                        // If the class declaration is the default export and a reference to itself
                        // inside of the class body, we must emit both an alias for the class *and*
                        // move the export after the declaration:
                        //
                        //  TypeScript                      | Javascript
                        //  --------------------------------|------------------------------------
                        //  @dec                            | let C_1 = class C {
                        //  export default class C {        |   static x() { return C_1.y; }
                        //    static x() { return C.y; }    | };
                        //    static y = 1;                 | let C = C_1;
                        //  }                               | C.y = 1;
                        //                                  | C = C_1 = __decorate([dec], C);
                        //                                  | export default C;
                        //  ---------------------------------------------------------------------
                        //  [Example 4]
                        //
                        // NOTE: we reuse the same rewriting logic for cases when targeting ES6 and module kind is System.
                        // Because of hoisting top level class declaration need to be emitted as class expressions.
                        // Double bind case is only required if node is decorated.
                        if (isDecorated && resolver.getNodeCheckFlags(node) & 524288 /* ClassWithBodyScopedClassBinding */) {
                            decoratedClassAlias = ts.unescapeIdentifier(makeUniqueName(node.name ? node.name.text : "default"));
                            decoratedClassAliases[ts.getNodeId(node)] = decoratedClassAlias;
                        }
                        if (isES6ExportedDeclaration(node) && !(node.flags & 512 /* Default */) && decoratedClassAlias === undefined) {
                            write("export ");
                        }
                        if (decoratedClassAlias !== undefined) {
                            write("let " + decoratedClassAlias);
                        }
                        else {
                            if (!isHoistedDeclarationInSystemModule) {
                                write("let ");
                            }
                            emitDeclarationName(node);
                        }
                        write(" = ");
                    }
                    else if (isES6ExportedDeclaration(node)) {
                        write("export ");
                        if (node.flags & 512 /* 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:
                //
                //    ((C_1 = class C {
                //            // Normal class body
                //        },
                //        C_1.a = 1,
                //        C_1.b = 2,
                //        C_1));
                //    var C_1;
                //
                // 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, /*isStatic*/ true);
                var isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === 192 /* ClassExpression */;
                var generatedName;
                if (isClassExpressionWithStaticProperties) {
                    generatedName = node.name ? getGeneratedNameForNode(node.name) : makeUniqueName("classExpression");
                    var synthesizedNode = ts.createSynthesizedNode(69 /* Identifier */);
                    synthesizedNode.text = generatedName;
                    recordTempDeclaration(synthesizedNode);
                    write("(");
                    increaseIndent();
                    emit(synthesizedNode);
                    write(" = ");
                }
                write("class");
                // emit name if
                // - node has a name
                // - this is default export with static initializers
                if (node.name || (node.flags & 512 /* Default */ && (staticProperties.length > 0 || modulekind !== ts.ModuleKind.ES6) && !rewriteAsClassExpression)) {
                    write(" ");
                    emitDeclarationName(node);
                }
                var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node);
                if (baseTypeNode) {
                    write(" extends ");
                    emit(baseTypeNode.expression);
                }
                write(" {");
                increaseIndent();
                writeLine();
                emitConstructor(node, baseTypeNode);
                emitMemberFunctionsForES6AndHigher(node);
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.members.end);
                if (rewriteAsClassExpression) {
                    if (decoratedClassAlias !== undefined) {
                        write(";");
                        writeLine();
                        if (isES6ExportedDeclaration(node) && !(node.flags & 512 /* Default */)) {
                            write("export ");
                        }
                        write("let ");
                        emitDeclarationName(node);
                        write(" = " + decoratedClassAlias);
                    }
                    decoratedClassAliases[ts.getNodeId(node)] = undefined;
                    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, staticProperties_1 = staticProperties; _a < staticProperties_1.length; _a++) {
                        var property = staticProperties_1[_a];
                        write(",");
                        writeLine();
                        emitPropertyDeclaration(node, property, /*receiver*/ generatedName, /*isExpression*/ true);
                    }
                    write(",");
                    writeLine();
                    write(generatedName);
                    decreaseIndent();
                    write(")");
                }
                else {
                    writeLine();
                    emitPropertyDeclarations(node, staticProperties);
                    emitDecoratorsOfClass(node, decoratedClassAlias);
                }
                if (!(node.flags & 1 /* Export */)) {
                    return;
                }
                if (modulekind !== ts.ModuleKind.ES6) {
                    emitExportMemberAssignment(node);
                }
                else {
                    // If this is an exported class, but not on the top level (i.e. on an internal
                    // module), export it
                    if (node.flags & 512 /* Default */) {
                        // if this is a top level default export of decorated class, write the export after the declaration.
                        if (isDecorated) {
                            writeLine();
                            write("export default ");
                            emitDeclarationName(node);
                            write(";");
                        }
                    }
                    else if (node.parent.kind !== 256 /* SourceFile */) {
                        writeLine();
                        emitStart(node);
                        emitModuleMemberName(node);
                        write(" = ");
                        emitDeclarationName(node);
                        emitEnd(node);
                        write(";");
                    }
                }
            }
            function emitClassLikeDeclarationBelowES6(node) {
                var isES6ExportedClass = isES6ExportedDeclaration(node);
                if (node.kind === 221 /* ClassDeclaration */) {
                    if (isES6ExportedClass && !(node.flags & 512 /* Default */)) {
                        write("export ");
                    }
                    // 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;
                var saveConvertedLoopState = convertedLoopState;
                convertedLoopState = undefined;
                tempFlags = 0;
                tempVariables = undefined;
                tempParameters = undefined;
                computedPropertyNamesToGeneratedNames = undefined;
                increaseIndent();
                if (baseTypeNode) {
                    writeLine();
                    emitStart(baseTypeNode);
                    write("__extends(");
                    emitDeclarationName(node);
                    write(", _super);");
                    emitEnd(baseTypeNode);
                }
                writeLine();
                emitConstructor(node, baseTypeNode);
                emitMemberFunctionsForES5AndLower(node);
                emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ true));
                writeLine();
                emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined);
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.members.end, function () {
                    write("return ");
                    emitDeclarationName(node);
                });
                write(";");
                emitTempDeclarations(/*newLine*/ true);
                ts.Debug.assert(convertedLoopState === undefined);
                convertedLoopState = saveConvertedLoopState;
                tempFlags = saveTempFlags;
                tempVariables = saveTempVariables;
                tempParameters = saveTempParameters;
                computedPropertyNamesToGeneratedNames = saveComputedPropertyNamesToGeneratedNames;
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.members.end);
                emitStart(node);
                write("(");
                if (baseTypeNode) {
                    emit(baseTypeNode.expression);
                }
                write("))");
                if (node.kind === 221 /* ClassDeclaration */) {
                    write(";");
                }
                emitEnd(node);
                if (node.kind === 221 /* ClassDeclaration */ && !isES6ExportedClass) {
                    emitExportMemberAssignment(node);
                }
                else if (isES6ExportedClass && (node.flags & 512 /* Default */)) {
                    writeLine();
                    write("export default ");
                    emitDeclarationName(node);
                    write(";");
                }
            }
            function emitClassMemberPrefix(node, member) {
                emitDeclarationName(node);
                if (!(member.flags & 32 /* Static */)) {
                    write(".prototype");
                }
            }
            function emitDecoratorsOfClass(node, decoratedClassAlias) {
                emitDecoratorsOfMembers(node, /*staticFlag*/ 0);
                emitDecoratorsOfMembers(node, 32 /* Static */);
                emitDecoratorsOfConstructor(node, decoratedClassAlias);
            }
            function emitDecoratorsOfConstructor(node, decoratedClassAlias) {
                var decorators = node.decorators;
                var constructor = ts.getFirstConstructorWithBody(node);
                var firstParameterDecorator = constructor && ts.forEach(constructor.parameters, function (parameter) { return parameter.decorators; });
                // skip decoration of the constructor if neither it nor its parameters are decorated
                if (!decorators && !firstParameterDecorator) {
                    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.decorators || firstParameterDecorator);
                emitDeclarationName(node);
                if (decoratedClassAlias !== undefined) {
                    write(" = " + decoratedClassAlias);
                }
                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) { return emit(decorator.expression); });
                if (firstParameterDecorator) {
                    argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0);
                }
                emitSerializedTypeMetadata(node, /*leadingComma*/ argumentsWritten >= 0);
                decreaseIndent();
                writeLine();
                write("], ");
                emitDeclarationName(node);
                write(")");
                emitEnd(node.decorators || firstParameterDecorator);
                write(";");
                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 & 32 /* Static */) !== staticFlag) {
                        continue;
                    }
                    // skip members that cannot be decorated (such as the constructor)
                    if (!ts.nodeCanBeDecorated(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 === 147 /* MethodDeclaration */) {
                            functionLikeMember = member;
                        }
                    }
                    var firstParameterDecorator = functionLikeMember && ts.forEach(functionLikeMember.parameters, function (parameter) { return parameter.decorators; });
                    // skip a member if it or any of its parameters are not decorated
                    if (!decorators && !firstParameterDecorator) {
                        continue;
                    }
                    // 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(decorators || firstParameterDecorator);
                    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) { return emit(decorator.expression); });
                    if (firstParameterDecorator) {
                        argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0);
                    }
                    emitSerializedTypeMetadata(member, argumentsWritten > 0);
                    decreaseIndent();
                    writeLine();
                    write("], ");
                    emitClassMemberPrefix(node, member);
                    write(", ");
                    emitExpressionForPropertyName(member.name);
                    if (languageVersion > 0 /* ES3 */) {
                        if (member.kind !== 145 /* 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(decorators || firstParameterDecorator);
                    write(";");
                    writeLine();
                }
            }
            function emitDecoratorsOfParameters(node, leadingComma) {
                var argumentsWritten = 0;
                if (node) {
                    var parameterIndex_1 = 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) {
                                write("__param(" + parameterIndex_1 + ", ");
                                emit(decorator.expression);
                                write(")");
                            });
                            leadingComma = true;
                        }
                        parameterIndex_1++;
                    }
                }
                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 147 /* MethodDeclaration */:
                    case 149 /* GetAccessor */:
                    case 150 /* SetAccessor */:
                    case 145 /* 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 147 /* 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 221 /* ClassDeclaration */:
                    case 147 /* MethodDeclaration */:
                    case 150 /* 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 221 /* ClassDeclaration */:
                        write("Function");
                        return;
                    case 145 /* PropertyDeclaration */:
                        emitSerializedTypeNode(node.type);
                        return;
                    case 142 /* Parameter */:
                        emitSerializedTypeNode(node.type);
                        return;
                    case 149 /* GetAccessor */:
                        emitSerializedTypeNode(node.type);
                        return;
                    case 150 /* 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 164 /* ParenthesizedType */:
                            emitSerializedTypeNode(node.type);
                            return;
                        case 156 /* FunctionType */:
                        case 157 /* ConstructorType */:
                            write("Function");
                            return;
                        case 160 /* ArrayType */:
                        case 161 /* TupleType */:
                            write("Array");
                            return;
                        case 154 /* TypePredicate */:
                        case 120 /* BooleanKeyword */:
                            write("Boolean");
                            return;
                        case 132 /* StringKeyword */:
                        case 166 /* LiteralType */:
                            write("String");
                            return;
                        case 130 /* NumberKeyword */:
                            write("Number");
                            return;
                        case 133 /* SymbolKeyword */:
                            write("Symbol");
                            return;
                        case 155 /* TypeReference */:
                            emitSerializedTypeReferenceNode(node);
                            return;
                        case 158 /* TypeQuery */:
                        case 159 /* TypeLiteral */:
                        case 162 /* UnionType */:
                        case 163 /* IntersectionType */:
                        case 117 /* AnyKeyword */:
                        case 165 /* ThisType */:
                            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, 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 = void 0;
                    if (node.kind === 221 /* ClassDeclaration */) {
                        valueDeclaration = ts.getFirstConstructorWithBody(node);
                    }
                    else if (ts.isFunctionLike(node) && ts.nodeIsPresent(node.body)) {
                        valueDeclaration = node;
                    }
                    if (valueDeclaration) {
                        var parameters = valueDeclaration.parameters;
                        var skipThisCount = parameters.length && parameters[0].name.originalKeywordKind === 97 /* ThisKeyword */ ? 1 : 0;
                        var parameterCount = parameters.length;
                        if (parameterCount > skipThisCount) {
                            for (var i = skipThisCount; i < parameterCount; i++) {
                                if (i > skipThisCount) {
                                    write(", ");
                                }
                                if (parameters[i].dotDotDotToken) {
                                    var parameterType = parameters[i].type;
                                    if (parameterType && parameterType.kind === 160 /* ArrayType */) {
                                        parameterType = parameterType.elementType;
                                    }
                                    else if (parameterType && parameterType.kind === 155 /* 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)) {
                    if (node.type) {
                        emitSerializedTypeNode(node.type);
                        return;
                    }
                    else if (ts.isAsyncFunctionLike(node)) {
                        write("Promise");
                        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
                    var isES6ExportedEnum = isES6ExportedDeclaration(node);
                    if (!(node.flags & 1 /* Export */) || (isES6ExportedEnum && isFirstDeclarationOfKind(node, node.symbol && node.symbol.declarations, 224 /* EnumDeclaration */))) {
                        emitStart(node);
                        if (isES6ExportedEnum) {
                            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();
                emitLines(node.members);
                decreaseIndent();
                writeLine();
                emitToken(16 /* CloseBraceToken */, node.members.end);
                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 !== ts.ModuleKind.ES6 && node.parent === currentSourceFile) {
                    if (modulekind === ts.ModuleKind.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 && moduleDeclaration.body.kind === 225 /* 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 isFirstDeclarationOfKind(node, declarations, kind) {
                return !ts.forEach(declarations, function (declaration) { return declaration.kind === kind && declaration.pos < node.pos; });
            }
            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) {
                    var isES6ExportedNamespace = isES6ExportedDeclaration(node);
                    if (!isES6ExportedNamespace || isFirstDeclarationOfKind(node, node.symbol && node.symbol.declarations, 225 /* ModuleDeclaration */)) {
                        emitStart(node);
                        if (isES6ExportedNamespace) {
                            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(") ");
                ts.Debug.assert(node.body !== undefined); // node.body must exist, as this is a non-ambient module
                if (node.body.kind === 226 /* ModuleBlock */) {
                    var saveConvertedLoopState = convertedLoopState;
                    var saveTempFlags = tempFlags;
                    var saveTempVariables = tempVariables;
                    convertedLoopState = undefined;
                    tempFlags = 0;
                    tempVariables = undefined;
                    emit(node.body);
                    ts.Debug.assert(convertedLoopState === undefined);
                    convertedLoopState = saveConvertedLoopState;
                    tempFlags = saveTempFlags;
                    tempVariables = saveTempVariables;
                }
                else {
                    write("{");
                    increaseIndent();
                    emitCaptureThisForNodeIfNecessary(node);
                    writeLine();
                    emit(node.body);
                    decreaseIndent();
                    writeLine();
                    var moduleBlock = getInnerMostModuleDeclarationFromDottedModule(node).body;
                    emitToken(16 /* CloseBraceToken */, moduleBlock.statements.end);
                }
                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 === ts.ModuleKind.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 (renamedDependencies && moduleName.text in renamedDependencies) {
                    return "\"" + 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 === 229 /* ImportEqualsDeclaration */) {
                    return node;
                }
                var importClause = node.importClause;
                if (importClause && importClause.namedBindings && importClause.namedBindings.kind === 232 /* NamespaceImport */) {
                    return importClause.namedBindings;
                }
            }
            function isDefaultImport(node) {
                return node.kind === 230 /* 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 !== ts.ModuleKind.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 === 232 /* 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 === 229 /* ImportEqualsDeclaration */ && (node.flags & 1 /* Export */) !== 0;
                    var namespaceDeclaration = getNamespaceDeclarationNode(node);
                    var varOrConst = (languageVersion <= 1 /* ES5 */) ? "var " : "const ";
                    if (modulekind !== ts.ModuleKind.AMD) {
                        emitLeadingComments(node);
                        emitStart(node);
                        if (namespaceDeclaration && !isDefaultImport(node)) {
                            // import x = require("foo")
                            // import * as x from "foo"
                            if (!isExportedImport) {
                                write(varOrConst);
                            }
                            ;
                            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 = node.kind === 230 /* ImportDeclaration */ && !node.importClause;
                            if (!isNakedImport) {
                                write(varOrConst);
                                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(varOrConst);
                            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) ||
                    (!isCurrentFileExternalModule && 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 !== ts.ModuleKind.System);
                if (modulekind !== ts.ModuleKind.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 !== ts.ModuleKind.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"
                            if (hasExportStarsToExportValues && resolver.moduleExportsSomeValue(node.moduleSpecifier)) {
                                writeLine();
                                write("__export(");
                                if (modulekind !== ts.ModuleKind.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 === ts.ModuleKind.ES6);
                var needsComma = false;
                for (var _a = 0, specifiers_1 = specifiers; _a < specifiers_1.length; _a++) {
                    var specifier = specifiers_1[_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 === ts.ModuleKind.ES6) {
                        writeLine();
                        emitStart(node);
                        write("export default ");
                        var expression = node.expression;
                        emit(expression);
                        if (expression.kind !== 220 /* FunctionDeclaration */ &&
                            expression.kind !== 221 /* ClassDeclaration */) {
                            write(";");
                        }
                        emitEnd(node);
                    }
                    else {
                        writeLine();
                        emitStart(node);
                        if (modulekind === ts.ModuleKind.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 = ts.createMap();
                exportEquals = undefined;
                hasExportStarsToExportValues = false;
                for (var _a = 0, _b = sourceFile.statements; _a < _b.length; _a++) {
                    var node = _b[_a];
                    switch (node.kind) {
                        case 230 /* 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 229 /* ImportEqualsDeclaration */:
                            if (node.moduleReference.kind === 240 /* ExternalModuleReference */ && resolver.isReferencedAliasDeclaration(node)) {
                                // import x = require("mod") where x is referenced
                                externalImports.push(node);
                            }
                            break;
                        case 236 /* ExportDeclaration */:
                            if (node.moduleSpecifier) {
                                if (!node.exportClause) {
                                    // export * from "mod"
                                    if (resolver.moduleExportsSomeValue(node.moduleSpecifier)) {
                                        externalImports.push(node);
                                        hasExportStarsToExportValues = 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_30 = (specifier.propertyName || specifier.name).text;
                                    (exportSpecifiers[name_30] || (exportSpecifiers[name_30] = [])).push(specifier);
                                }
                            }
                            break;
                        case 235 /* ExportAssignment */:
                            if (node.isExportEquals && !exportEquals) {
                                // export = x
                                exportEquals = node;
                            }
                            break;
                    }
                }
            }
            function emitExportStarHelper() {
                if (hasExportStarsToExportValues) {
                    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.getTextOfNodeFromSourceText(currentText, namespaceDeclaration.name);
                }
                if (node.kind === 230 /* ImportDeclaration */ && node.importClause) {
                    return getGeneratedNameForNode(node);
                }
                if (node.kind === 236 /* ExportDeclaration */ && node.moduleSpecifier) {
                    return getGeneratedNameForNode(node);
                }
            }
            function getExternalModuleNameText(importNode, emitRelativePathAsModuleName) {
                if (emitRelativePathAsModuleName) {
                    var name_31 = getExternalModuleNameFromDeclaration(host, resolver, importNode);
                    if (name_31) {
                        return "\"" + name_31 + "\"";
                    }
                }
                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, externalImports_1 = externalImports; _a < externalImports_1.length; _a++) {
                    var importNode = externalImports_1[_a];
                    // do not create variable declaration for exports and imports that lack import clause
                    var skipNode = importNode.kind === 236 /* ExportDeclaration */ ||
                        (importNode.kind === 230 /* 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 exports.
                if (!hasExportStarsToExportValues) {
                    // 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.someProperties(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, externalImports_2 = externalImports; _a < externalImports_2.length; _a++) {
                        var externalImport = externalImports_2[_a];
                        if (externalImport.kind === 236 /* 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, externalImports_3 = externalImports; _d < externalImports_3.length; _d++) {
                    var externalImport = externalImports_3[_d];
                    if (externalImport.kind !== 236 /* 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 & 512 /* 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 = ts.createMap();
                    for (var i = 0; i < hoistedVars.length; i++) {
                        var local = hoistedVars[i];
                        var name_32 = local.kind === 69 /* Identifier */
                            ? local
                            : local.name;
                        if (name_32) {
                            // do not emit duplicate entries (in case of declaration merging) in the list of hoisted variables
                            var text = ts.unescapeIdentifier(name_32.text);
                            if (text in seen) {
                                continue;
                            }
                            else {
                                seen[text] = text;
                            }
                        }
                        if (i !== 0) {
                            write(", ");
                        }
                        if (local.kind === 221 /* ClassDeclaration */ || local.kind === 225 /* ModuleDeclaration */ || local.kind === 224 /* 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, hoistedFunctionDeclarations_1 = hoistedFunctionDeclarations; _a < hoistedFunctionDeclarations_1.length; _a++) {
                        var f = hoistedFunctionDeclarations_1[_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 === 220 /* FunctionDeclaration */) {
                        if (!hoistedFunctionDeclarations) {
                            hoistedFunctionDeclarations = [];
                        }
                        hoistedFunctionDeclarations.push(node);
                        return;
                    }
                    if (node.kind === 221 /* ClassDeclaration */) {
                        if (!hoistedVars) {
                            hoistedVars = [];
                        }
                        hoistedVars.push(node);
                        return;
                    }
                    if (node.kind === 224 /* EnumDeclaration */) {
                        if (shouldEmitEnumDeclaration(node)) {
                            if (!hoistedVars) {
                                hoistedVars = [];
                            }
                            hoistedVars.push(node);
                        }
                        return;
                    }
                    if (node.kind === 225 /* ModuleDeclaration */) {
                        if (shouldEmitModuleDeclaration(node)) {
                            if (!hoistedVars) {
                                hoistedVars = [];
                            }
                            hoistedVars.push(node);
                        }
                        return;
                    }
                    if (node.kind === 218 /* VariableDeclaration */ || node.kind === 169 /* BindingElement */) {
                        if (shouldHoistVariable(node, /*checkIfSourceFileLevelDecl*/ false)) {
                            var name_33 = node.name;
                            if (name_33.kind === 69 /* Identifier */) {
                                if (!hoistedVars) {
                                    hoistedVars = [];
                                }
                                hoistedVars.push(name_33);
                            }
                            else {
                                ts.forEachChild(name_33, 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) & 3072 /* BlockScoped */) === 0 ||
                    ts.getEnclosingBlockScopeContainer(node).kind === 256 /* SourceFile */;
            }
            function isCurrentFileSystemExternalModule() {
                return modulekind === ts.ModuleKind.System && isCurrentFileExternalModule;
            }
            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, group_1 = group; _a < group_1.length; _a++) {
                        var entry = group_1[_a];
                        var importVariableName = getLocalNameForExternalImport(entry) || "";
                        switch (entry.kind) {
                            case 230 /* ImportDeclaration */:
                                if (!entry.importClause) {
                                    // 'import "..."' case
                                    // module is imported only for side-effects, no emit required
                                    break;
                                }
                            // fall-through
                            case 229 /* ImportEqualsDeclaration */:
                                ts.Debug.assert(importVariableName !== "");
                                writeLine();
                                // save import into the local
                                write(importVariableName + " = " + parameterName + ";");
                                writeLine();
                                break;
                            case 236 /* 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_1 = 0, len = entry.exportClause.elements.length; i_1 < len; i_1++) {
                                        if (i_1 !== 0) {
                                            write(",");
                                            writeLine();
                                        }
                                        var e = entry.exportClause.elements[i_1];
                                        write("\"");
                                        emitNodeWithCommentsAndWithoutSourcemap(e.name);
                                        write("\": " + parameterName + "[\"");
                                        emitNodeWithCommentsAndWithoutSourcemap(e.propertyName || e.name);
                                        write("\"]");
                                    }
                                    decreaseIndent();
                                    writeLine();
                                    write("});");
                                }
                                else {
                                    // collectExternalModuleInfo prefilters star exports to keep only ones that export values
                                    // this means that check 'resolver.moduleExportsSomeValue' is redundant and can be omitted here
                                    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 220 /* FunctionDeclaration */:
                        case 230 /* ImportDeclaration */:
                            continue;
                        case 236 /* 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 229 /* 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 writeModuleName(node, emitRelativePathAsModuleName) {
                var moduleName = node.moduleName;
                if (moduleName || (emitRelativePathAsModuleName && (moduleName = getResolvedExternalModuleName(host, node)))) {
                    write("\"" + moduleName + "\", ");
                }
            }
            function emitSystemModule(node, emitRelativePathAsModuleName) {
                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");
                contextObjectForFile = makeUniqueName("context");
                writeLine();
                write("System.register(");
                writeModuleName(node, emitRelativePathAsModuleName);
                write("[");
                var groupIndices = ts.createMap();
                var dependencyGroups = [];
                for (var i = 0; i < externalImports.length; i++) {
                    var text = getExternalModuleNameText(externalImports[i], emitRelativePathAsModuleName);
                    if (text === undefined) {
                        continue;
                    }
                    // text should be quoted string
                    // for deduplication purposes in key remove leading and trailing quotes so 'a' and "a" will be considered the same
                    var key = text.substr(1, text.length - 2);
                    if (key in groupIndices) {
                        // deduplicate/group entries in dependency list by the dependency name
                        var groupIndex = groupIndices[key];
                        dependencyGroups[groupIndex].push(externalImports[i]);
                        continue;
                    }
                    else {
                        groupIndices[key] = dependencyGroups.length;
                        dependencyGroups.push([externalImports[i]]);
                    }
                    if (i !== 0) {
                        write(", ");
                    }
                    write(text);
                }
                write("], function(" + exportFunctionForFile + ", " + contextObjectForFile + ") {");
                writeLine();
                increaseIndent();
                var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ true, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
                writeLine();
                write("var __moduleName = " + contextObjectForFile + " && " + contextObjectForFile + ".id;");
                writeLine();
                emitEmitHelpers(node);
                emitCaptureThisForNodeIfNecessary(node);
                emitSystemModuleBody(node, dependencyGroups, startIndex);
                decreaseIndent();
                writeLine();
                write("});");
            }
            function getAMDDependencyNames(node, includeNonAmdDependencies, emitRelativePathAsModuleName) {
                // 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, externalImports_4 = externalImports; _c < externalImports_4.length; _c++) {
                    var importNode = externalImports_4[_c];
                    // Find the name of the external module
                    var externalModuleName = getExternalModuleNameText(importNode, emitRelativePathAsModuleName);
                    // 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, emitRelativePathAsModuleName) {
                // 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, emitRelativePathAsModuleName);
                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, emitRelativePathAsModuleName) {
                emitEmitHelpers(node);
                collectExternalModuleInfo(node);
                writeLine();
                write("define(");
                writeModuleName(node, emitRelativePathAsModuleName);
                emitAMDDependencies(node, /*includeNonAmdDependencies*/ true, emitRelativePathAsModuleName);
                increaseIndent();
                var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ true, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
                emitExportStarHelper();
                emitCaptureThisForNodeIfNecessary(node);
                emitLinesStartingAt(node.statements, startIndex);
                emitExportEquals(/*emitAsReturn*/ true);
                emitTempDeclarations(/*newLine*/ true);
                decreaseIndent();
                writeLine();
                write("});");
            }
            function emitCommonJSModule(node) {
                var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
                emitEmitHelpers(node);
                collectExternalModuleInfo(node);
                emitExportStarHelper();
                emitCaptureThisForNodeIfNecessary(node);
                emitLinesStartingAt(node.statements, startIndex);
                emitExportEquals(/*emitAsReturn*/ false);
                emitTempDeclarations(/*newLine*/ true);
            }
            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, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict);
                emitExportStarHelper();
                emitCaptureThisForNodeIfNecessary(node);
                emitLinesStartingAt(node.statements, startIndex);
                emitExportEquals(/*emitAsReturn*/ true);
                emitTempDeclarations(/*newLine*/ true);
                decreaseIndent();
                writeLine();
                write("});");
            }
            function emitES6Module(node) {
                externalImports = undefined;
                exportSpecifiers = undefined;
                exportEquals = undefined;
                hasExportStarsToExportValues = 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.isWhiteSpaceSingleLine(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 &nbsp;
                    result = result.replace(/&(\w+);/g, function (s, m) {
                        if (entities[m] !== undefined) {
                            var ch = String.fromCharCode(entities[m]);
                            // &quot; needs to be escaped
                            return ch === '"' ? "\\\"" : ch;
                        }
                        else {
                            return s;
                        }
                    });
                }
                return result;
            }
            function isJsxChildEmittable(child) {
                if (child.kind === 248 /* JsxExpression */) {
                    // Don't emit empty expressions
                    return !!child.expression;
                }
                else if (child.kind === 244 /* JsxText */) {
                    // Don't emit empty strings
                    return !!getTextToEmit(child);
                }
                return true;
            }
            ;
            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 isUseStrictPrologue(node) {
                return node.expression.text === "use strict";
            }
            function ensureUseStrictPrologue(startWithNewLine, writeUseStrict) {
                if (writeUseStrict) {
                    if (startWithNewLine) {
                        writeLine();
                    }
                    write("\"use strict\";");
                }
            }
            function emitDirectivePrologues(statements, startWithNewLine, ensureUseStrict) {
                var foundUseStrict = false;
                for (var i = 0; i < statements.length; i++) {
                    if (ts.isPrologueDirective(statements[i])) {
                        if (isUseStrictPrologue(statements[i])) {
                            foundUseStrict = true;
                        }
                        if (startWithNewLine || i > 0) {
                            writeLine();
                        }
                        emit(statements[i]);
                    }
                    else {
                        ensureUseStrictPrologue(startWithNewLine || i > 0, !foundUseStrict && ensureUseStrict);
                        // return index of the first non prologue directive
                        return i;
                    }
                }
                ensureUseStrictPrologue(startWithNewLine, !foundUseStrict && ensureUseStrict);
                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 && node.flags & 262144 /* HasClassExtends */) {
                        writeLines(extendsHelper);
                        extendsEmitted = true;
                    }
                    if (compilerOptions.jsx !== 1 /* Preserve */ && !assignEmitted && (node.flags & 1073741824 /* HasJsxSpreadAttribute */)) {
                        writeLines(assignHelper);
                        assignEmitted = true;
                    }
                    if (!decorateEmitted && node.flags & 524288 /* HasDecorators */) {
                        writeLines(decorateHelper);
                        if (compilerOptions.emitDecoratorMetadata) {
                            writeLines(metadataHelper);
                        }
                        decorateEmitted = true;
                    }
                    if (!paramEmitted && node.flags & 1048576 /* HasParamDecorators */) {
                        writeLines(paramHelper);
                        paramEmitted = true;
                    }
                    if (!awaiterEmitted && node.flags & 2097152 /* HasAsyncFunctions */) {
                        writeLines(awaiterHelper);
                        awaiterEmitted = true;
                    }
                }
            }
            function emitSourceFileNode(node) {
                // Start new file on new line
                writeLine();
                emitShebang();
                emitDetachedCommentsAndUpdateCommentsInfo(node);
                if (ts.isExternalModule(node) || compilerOptions.isolatedModules) {
                    if (isOwnFileEmit || (!ts.isExternalModule(node) && compilerOptions.isolatedModules)) {
                        var emitModule = moduleEmitDelegates[modulekind] || moduleEmitDelegates[ts.ModuleKind.CommonJS];
                        emitModule(node);
                    }
                    else {
                        bundleEmitDelegates[modulekind](node, /*emitRelativePathAsModuleName*/ true);
                    }
                }
                else {
                    // emit prologue directives prior to __extends
                    var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false);
                    externalImports = undefined;
                    exportSpecifiers = undefined;
                    exportEquals = undefined;
                    hasExportStarsToExportValues = false;
                    emitEmitHelpers(node);
                    emitCaptureThisForNodeIfNecessary(node);
                    emitLinesStartingAt(node.statements, startIndex);
                    emitTempDeclarations(/*newLine*/ true);
                }
                emitLeadingComments(node.endOfFileToken);
            }
            function emit(node) {
                emitNodeConsideringCommentsOption(node, emitNodeWithSourceMap);
            }
            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 emitNodeWithSourceMap(node) {
                if (node) {
                    emitStart(node);
                    emitNodeWithoutSourceMap(node);
                    emitEnd(node);
                }
            }
            function emitNodeWithoutSourceMap(node) {
                if (node) {
                    emitJavaScriptWorker(node);
                }
            }
            function changeSourceMapEmit(writer) {
                sourceMap = writer;
                emitStart = writer.emitStart;
                emitEnd = writer.emitEnd;
                emitPos = writer.emitPos;
                setSourceFile = writer.setSourceFile;
            }
            function withTemporaryNoSourceMap(callback) {
                var prevSourceMap = sourceMap;
                setSourceMapWriterEmit(ts.getNullSourceMapWriter());
                callback();
                setSourceMapWriterEmit(prevSourceMap);
            }
            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 222 /* InterfaceDeclaration */:
                    case 220 /* FunctionDeclaration */:
                    case 230 /* ImportDeclaration */:
                    case 229 /* ImportEqualsDeclaration */:
                    case 223 /* TypeAliasDeclaration */:
                    case 235 /* ExportAssignment */:
                        return true;
                }
            }
            function shouldEmitLeadingAndTrailingComments(node) {
                switch (node.kind) {
                    case 200 /* VariableStatement */:
                        return shouldEmitLeadingAndTrailingCommentsForVariableStatement(node);
                    case 225 /* ModuleDeclaration */:
                        // Only emit the leading/trailing comments for a module if we're actually
                        // emitting the module as well.
                        return shouldEmitModuleDeclaration(node);
                    case 224 /* 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 !== 199 /* Block */ &&
                    node.parent &&
                    node.parent.kind === 180 /* ArrowFunction */ &&
                    node.parent.body === node &&
                    languageVersion <= 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 142 /* Parameter */:
                        return emitParameter(node);
                    case 147 /* MethodDeclaration */:
                    case 146 /* MethodSignature */:
                        return emitMethod(node);
                    case 149 /* GetAccessor */:
                    case 150 /* 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 189 /* TemplateExpression */:
                        return emitTemplateExpression(node);
                    case 197 /* TemplateSpan */:
                        return emitTemplateSpan(node);
                    case 241 /* JsxElement */:
                    case 242 /* JsxSelfClosingElement */:
                        return emitJsxElement(node);
                    case 244 /* JsxText */:
                        return emitJsxText(node);
                    case 248 /* JsxExpression */:
                        return emitJsxExpression(node);
                    case 139 /* QualifiedName */:
                        return emitQualifiedName(node);
                    case 167 /* ObjectBindingPattern */:
                        return emitObjectBindingPattern(node);
                    case 168 /* ArrayBindingPattern */:
                        return emitArrayBindingPattern(node);
                    case 169 /* BindingElement */:
                        return emitBindingElement(node);
                    case 170 /* ArrayLiteralExpression */:
                        return emitArrayLiteral(node);
                    case 171 /* ObjectLiteralExpression */:
                        return emitObjectLiteral(node);
                    case 253 /* PropertyAssignment */:
                        return emitPropertyAssignment(node);
                    case 254 /* ShorthandPropertyAssignment */:
                        return emitShorthandPropertyAssignment(node);
                    case 140 /* ComputedPropertyName */:
                        return emitComputedPropertyName(node);
                    case 172 /* PropertyAccessExpression */:
                        return emitPropertyAccess(node);
                    case 173 /* ElementAccessExpression */:
                        return emitIndexedAccess(node);
                    case 174 /* CallExpression */:
                        return emitCallExpression(node);
                    case 175 /* NewExpression */:
                        return emitNewExpression(node);
                    case 176 /* TaggedTemplateExpression */:
                        return emitTaggedTemplateExpression(node);
                    case 177 /* TypeAssertionExpression */:
                    case 195 /* AsExpression */:
                    case 196 /* NonNullExpression */:
                        return emit(node.expression);
                    case 178 /* ParenthesizedExpression */:
                        return emitParenExpression(node);
                    case 220 /* FunctionDeclaration */:
                    case 179 /* FunctionExpression */:
                    case 180 /* ArrowFunction */:
                        return emitFunctionDeclaration(node);
                    case 181 /* DeleteExpression */:
                        return emitDeleteExpression(node);
                    case 182 /* TypeOfExpression */:
                        return emitTypeOfExpression(node);
                    case 183 /* VoidExpression */:
                        return emitVoidExpression(node);
                    case 184 /* AwaitExpression */:
                        return emitAwaitExpression(node);
                    case 185 /* PrefixUnaryExpression */:
                        return emitPrefixUnaryExpression(node);
                    case 186 /* PostfixUnaryExpression */:
                        return emitPostfixUnaryExpression(node);
                    case 187 /* BinaryExpression */:
                        return emitBinaryExpression(node);
                    case 188 /* ConditionalExpression */:
                        return emitConditionalExpression(node);
                    case 191 /* SpreadElementExpression */:
                        return emitSpreadElementExpression(node);
                    case 190 /* YieldExpression */:
                        return emitYieldExpression(node);
                    case 193 /* OmittedExpression */:
                        return;
                    case 199 /* Block */:
                    case 226 /* ModuleBlock */:
                        return emitBlock(node);
                    case 200 /* VariableStatement */:
                        return emitVariableStatement(node);
                    case 201 /* EmptyStatement */:
                        return write(";");
                    case 202 /* ExpressionStatement */:
                        return emitExpressionStatement(node);
                    case 203 /* IfStatement */:
                        return emitIfStatement(node);
                    case 204 /* DoStatement */:
                        return emitDoStatement(node);
                    case 205 /* WhileStatement */:
                        return emitWhileStatement(node);
                    case 206 /* ForStatement */:
                        return emitForStatement(node);
                    case 208 /* ForOfStatement */:
                    case 207 /* ForInStatement */:
                        return emitForInOrForOfStatement(node);
                    case 209 /* ContinueStatement */:
                    case 210 /* BreakStatement */:
                        return emitBreakOrContinueStatement(node);
                    case 211 /* ReturnStatement */:
                        return emitReturnStatement(node);
                    case 212 /* WithStatement */:
                        return emitWithStatement(node);
                    case 213 /* SwitchStatement */:
                        return emitSwitchStatement(node);
                    case 249 /* CaseClause */:
                    case 250 /* DefaultClause */:
                        return emitCaseOrDefaultClause(node);
                    case 214 /* LabeledStatement */:
                        return emitLabeledStatement(node);
                    case 215 /* ThrowStatement */:
                        return emitThrowStatement(node);
                    case 216 /* TryStatement */:
                        return emitTryStatement(node);
                    case 252 /* CatchClause */:
                        return emitCatchClause(node);
                    case 217 /* DebuggerStatement */:
                        return emitDebuggerStatement(node);
                    case 218 /* VariableDeclaration */:
                        return emitVariableDeclaration(node);
                    case 192 /* ClassExpression */:
                        return emitClassExpression(node);
                    case 221 /* ClassDeclaration */:
                        return emitClassDeclaration(node);
                    case 222 /* InterfaceDeclaration */:
                        return emitInterfaceDeclaration(node);
                    case 224 /* EnumDeclaration */:
                        return emitEnumDeclaration(node);
                    case 255 /* EnumMember */:
                        return emitEnumMember(node);
                    case 225 /* ModuleDeclaration */:
                        return emitModuleDeclaration(node);
                    case 230 /* ImportDeclaration */:
                        return emitImportDeclaration(node);
                    case 229 /* ImportEqualsDeclaration */:
                        return emitImportEqualsDeclaration(node);
                    case 236 /* ExportDeclaration */:
                        return emitExportDeclaration(node);
                    case 235 /* ExportAssignment */:
                        return emitExportAssignment(node);
                    case 256 /* 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(currentText, ts.lastOrUndefined(detachedCommentsInfo).detachedCommentEndPos);
                if (detachedCommentsInfo.length - 1) {
                    detachedCommentsInfo.pop();
                }
                else {
                    detachedCommentsInfo = undefined;
                }
                return leadingComments;
            }
            /**
             * 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 (currentText.charCodeAt(comment.pos + 1) === 47 /* slash */ &&
                    comment.pos + 2 < comment.end &&
                    currentText.charCodeAt(comment.pos + 2) === 47 /* slash */) {
                    var textSubStr = currentText.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 === 256 /* 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.getLeadingCommentRangesOfNodeFromText(node, currentText);
                        }
                    }
                }
            }
            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 === 256 /* SourceFile */ || node.end !== node.parent.end) {
                        return ts.getTrailingCommentRanges(currentText, 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 even though both node will not be emitted
                    if (node.pos === 0) {
                        leadingComments = ts.filter(getLeadingCommentsToEmit(node), isTripleSlashComment);
                    }
                }
                ts.emitNewLineBeforeLeadingComments(currentLineMap, writer, node, leadingComments);
                // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
                ts.emitComments(currentText, currentLineMap, 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(currentText, currentLineMap, 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(currentText, pos);
                // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
                ts.emitComments(currentText, currentLineMap, 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(currentText, pos);
                }
                ts.emitNewLineBeforeLeadingComments(currentLineMap, writer, { pos: pos, end: pos }, leadingComments);
                // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
                ts.emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment);
            }
            function emitDetachedCommentsAndUpdateCommentsInfo(node) {
                var currentDetachedCommentInfo = ts.emitDetachedComments(currentText, currentLineMap, writer, writeComment, node, newLine, compilerOptions.removeComments);
                if (currentDetachedCommentInfo) {
                    if (detachedCommentsInfo) {
                        detachedCommentsInfo.push(currentDetachedCommentInfo);
                    }
                    else {
                        detachedCommentsInfo = [currentDetachedCommentInfo];
                    }
                }
            }
            function writeComment(text, lineMap, writer, comment, newLine) {
                emitPos(comment.pos);
                ts.writeCommentRange(text, lineMap, writer, comment, newLine);
                emitPos(comment.end);
            }
            function emitShebang() {
                var shebang = ts.getShebang(currentText);
                if (shebang) {
                    write(shebang);
                    writeLine();
                }
            }
            var _a, _b;
        }
        function emitFile(_a, sourceFiles, isBundledEmit, emitOnlyDtsFiles) {
            var jsFilePath = _a.jsFilePath, sourceMapFilePath = _a.sourceMapFilePath, declarationFilePath = _a.declarationFilePath;
            if (!emitOnlyDtsFiles) {
                // Make sure not to write js File and source map file if any of them cannot be written
                if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) {
                    emitJavaScript(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
                }
                else {
                    emitSkipped = true;
                }
            }
            if (declarationFilePath) {
                emitSkipped = ts.writeDeclarationFile(declarationFilePath, sourceFiles, isBundledEmit, host, resolver, emitterDiagnostics, emitOnlyDtsFiles) || emitSkipped;
            }
            if (!emitSkipped && emittedFilesList) {
                if (!emitOnlyDtsFiles) {
                    emittedFilesList.push(jsFilePath);
                    if (sourceMapFilePath) {
                        emittedFilesList.push(sourceMapFilePath);
                    }
                }
                if (declarationFilePath) {
                    emittedFilesList.push(declarationFilePath);
                }
            }
        }
    }