docs: 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);
                  }
              }
          }
      }