diff --git a/src/compiler/printer.ts b/src/compiler/printer.ts
new file mode 100644
index 00000000000..00096e94b9a
--- /dev/null
+++ b/src/compiler/printer.ts
@@ -0,0 +1,1620 @@
+///
+///
+///
+
+/* @internal */
+namespace ts {
+
+ const enum ListFormat {
+ None = 0,
+ Comma = 1 << 0,
+ Bar = 1 << 1,
+ Ampersand = 1 << 2,
+ AllowTrailingComma = 1 << 3,
+ LeadingWhitespace = 1 << 4,
+ TrailingWhitespace = 1 << 5,
+ Indented = 1 << 6,
+
+ Whitespace = LeadingWhitespace | TrailingWhitespace,
+ ImportOrExportSpecifiers = Comma | AllowTrailingComma | Indented | Whitespace,
+ TupleElementTypes = Comma | Indented,
+ TypeElements = Indented | Whitespace,
+ UnionTypeElements = Indented | Bar,
+ IntersectionTypeElements = Indented | Ampersand,
+ EnumMembers = Comma | AllowTrailingComma | Indented,
+ VariableDeclarations = Comma | Indented,
+ HeritageClauses = Comma | Indented,
+ Decorators = Indented | TrailingWhitespace,
+ ClassElements = Indented | Whitespace,
+ HeritageClauseTypes = Comma | Indented,
+ TypeArguments = Comma | Indented,
+ TypeParameters = Comma | Indented,
+ Parameters = Comma | Indented,
+ BindingElements = Comma | AllowTrailingComma | Indented,
+ Statements = None,
+ BlockStatements = Indented | Whitespace,
+ CaseClauses = Indented | Whitespace,
+ CaseOrDefaultClauseStatements = Indented | Whitespace,
+ Arguments = Comma | Indented,
+
+ ArrayLiteralElements = Comma | Indented | AllowTrailingComma,
+
+ ObjectLiteralProperties = Comma | Indented | Whitespace,
+ ObjectLiteralPropertiesForES5AndLater = ObjectLiteralProperties | AllowTrailingComma,
+ }
+
+ export function printFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult {
+ let compilerOptions = host.getCompilerOptions();
+ let languageVersion = compilerOptions.target || ScriptTarget.ES3;
+ let sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined;
+ let diagnostics: Diagnostic[] = [];
+ let newLine = host.getNewLine();
+
+ // Sort and make the unique list of diagnostics
+ diagnostics = sortAndDeduplicateDiagnostics(diagnostics);
+
+ return {
+ emitSkipped: false,
+ diagnostics,
+ sourceMaps: sourceMapDataList
+ };
+
+ function emitJavaScript(jsFilePath: string) {
+ let writer = createTextWriter(newLine);
+ let { write, writeTextOfNode, writeLine, increaseIndent, decreaseIndent } = writer;
+
+ let currentSourceFile: SourceFile;
+
+ /** Emit a node */
+ let emit = emitNode;
+
+ /** Called just before starting emit of a node */
+ let emitStart = function (node: Node) { };
+
+ /** Called once the emit of the node is done */
+ let emitEnd = function (node: Node) { };
+
+ let emitDetachedComments = function (node: Node) { };
+ let emitLeadingComments = function (node: Node) { };
+ let emitTrailingComments = function (node: Node) { };
+ let emitTrailingCommentsOfPosition = function (pos: number) { };
+
+ /** Called to before starting the lexical scopes as in function/class in the emitted code because of node
+ * @param scopeDeclaration node that starts the lexical scope
+ * @param scopeName Optional name of this scope instead of deducing one from the declaration node */
+ let scopeEmitStart = function(scopeDeclaration: Node, scopeName?: string) { };
+
+ /** Called after coming out of the scope */
+ let scopeEmitEnd = function() { };
+
+ /** Sourcemap data that will get encoded */
+ let sourceMapData: SourceMapData;
+
+ function emitNode(node: Node) {
+ if (node) {
+ emitJavaScriptWorker(node);
+ }
+ }
+
+ function emitJavaScriptWorker(node: Node) {
+ switch (node.kind) {
+ // DONE
+ case SyntaxKind.SourceFile:
+ return emitSourceFileNode(node);
+ case SyntaxKind.TypeParameter:
+ return emitTypeParameter(node);
+ case SyntaxKind.TypeReference:
+ return emitTypeReference(node);
+ case SyntaxKind.ExpressionWithTypeArguments:
+ return emitExpressionWithTypeArguments(node);
+ case SyntaxKind.ArrayType:
+ return emitArrayType(node);
+ case SyntaxKind.TupleType:
+ return emitTupleType(node);
+ case SyntaxKind.FunctionType:
+ return emitFunctionType(node);
+ case SyntaxKind.ConstructorType:
+ return emitConstructorType(node);
+ case SyntaxKind.ParenthesizedType:
+ return emitParenthesizedType(node);
+ case SyntaxKind.UnionType:
+ return emitUnionType(node);
+ case SyntaxKind.IntersectionType:
+ return emitIntersectionType(node);
+ case SyntaxKind.TypePredicate:
+ return emitTypePredicate(node);
+ case SyntaxKind.TypeQuery:
+ return emitTypeQuery(node);
+ case SyntaxKind.TypeLiteral:
+ return emitTypeLiteral(node);
+ case SyntaxKind.ConstructSignature:
+ return emitConstructSignature(node);
+ case SyntaxKind.PropertySignature:
+ return emitPropertySignature(node);
+ case SyntaxKind.MethodSignature:
+ return emitMethodSignature(node);
+ case SyntaxKind.IndexSignature:
+ return emitIndexSignature(node);
+ case SyntaxKind.ImportDeclaration:
+ return emitImportDeclaration(node);
+ case SyntaxKind.ExportDeclaration:
+ return emitExportDeclaration(node);
+ case SyntaxKind.ImportClause:
+ return emitImportClause(node);
+ case SyntaxKind.NamespaceImport:
+ return emitNamespaceImport(node);
+ case SyntaxKind.NamedImports:
+ case SyntaxKind.NamedExports:
+ return emitNamedImportsOrExports(node);
+ case SyntaxKind.ImportSpecifier:
+ case SyntaxKind.ExportSpecifier:
+ return emitImportOrExportSpecifier(node);
+ case SyntaxKind.ImportEqualsDeclaration:
+ return emitImportEqualsDeclaration(node);
+ case SyntaxKind.ExternalModuleReference:
+ return emitExternalModuleReference(node);
+ case SyntaxKind.ExportAssignment:
+ return emitExportAssignment(node);
+ case SyntaxKind.ModuleDeclaration:
+ return emitModuleDeclaration(node);
+ case SyntaxKind.EnumDeclaration:
+ return emitEnumDeclaration(node);
+ case SyntaxKind.EnumMember:
+ return emitEnumMember(node);
+ case SyntaxKind.VariableStatement:
+ return emitVariableStatement(node);
+ case SyntaxKind.VariableDeclarationList:
+ return emitVariableDeclarationList(node);
+ case SyntaxKind.VariableDeclaration:
+ return emitVariableDeclaration(node);
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.FunctionExpression:
+ return emitFunctionDeclarationOrExpression(node);
+ case SyntaxKind.Parameter:
+ return emitParameter(node);
+ case SyntaxKind.ClassDeclaration:
+ case SyntaxKind.ClassExpression:
+ return emitClassDeclarationOrExpression(node);
+ case SyntaxKind.HeritageClause:
+ return emitHeritageClause(node);
+ case SyntaxKind.Constructor:
+ return emitConstructor(node);
+ case SyntaxKind.PropertyDeclaration:
+ return emitPropertyDeclaration(node);
+ case SyntaxKind.MethodDeclaration:
+ return emitMethodDeclaration(node);
+ case SyntaxKind.GetAccessor:
+ case SyntaxKind.SetAccessor:
+ return emitAccessorDeclaration(node);
+ case SyntaxKind.InterfaceDeclaration:
+ return emitInterfaceDeclaration(node);
+ case SyntaxKind.TypeAliasDeclaration:
+ return emitTypeAliasDeclaration(node);
+ case SyntaxKind.Block:
+ case SyntaxKind.ModuleBlock:
+ return emitBlock(node);
+ case SyntaxKind.TryStatement:
+ return emitTryStatement(node);
+ case SyntaxKind.CatchClause:
+ return emitCatchClause(node);
+ case SyntaxKind.SwitchStatement:
+ return emitSwitchStatement(node);
+ case SyntaxKind.CaseClause:
+ return emitCaseClause(node);
+ case SyntaxKind.DefaultClause:
+ return emitDefaultClause(node);
+ case SyntaxKind.WithStatement:
+ return emitWithStatement(node);
+ case SyntaxKind.LabeledStatement:
+ return emitLabeledStatement(node);
+ case SyntaxKind.IfStatement:
+ return emitIfStatement(node);
+ case SyntaxKind.DoStatement:
+ return emitDoStatement(node);
+ case SyntaxKind.WhileStatement:
+ return emitWhileStatement(node);
+ case SyntaxKind.ForStatement:
+ return emitForStatement(node);
+ case SyntaxKind.ForOfStatement:
+ return emitForOfStatement(node);
+ case SyntaxKind.ForInStatement:
+ return emitForInStatement(node);
+ case SyntaxKind.ReturnStatement:
+ return emitReturnStatement(node);
+ case SyntaxKind.ThrowStatement:
+ return emitThrowStatement(node);
+ case SyntaxKind.DebuggerStatement:
+ return emitDebuggerStatement(node);
+ case SyntaxKind.BreakStatement:
+ case SyntaxKind.ContinueStatement:
+ return emitBreakOrContinueStatement(node);
+ case SyntaxKind.EmptyStatement:
+ return write(";");
+ case SyntaxKind.ExpressionStatement:
+ return emitExpressionStatement(node);
+
+ // IN PROGRESS
+ case SyntaxKind.Identifier:
+ return emitIdentifier(node);
+ case SyntaxKind.ThisKeyword:
+ case SyntaxKind.SuperKeyword:
+ case SyntaxKind.NullKeyword:
+ case SyntaxKind.TrueKeyword:
+ case SyntaxKind.FalseKeyword:
+ return writeTokenNode(node);
+ case SyntaxKind.NumericLiteral:
+ case SyntaxKind.StringLiteral:
+ case SyntaxKind.RegularExpressionLiteral:
+ case SyntaxKind.NoSubstitutionTemplateLiteral:
+ case SyntaxKind.TemplateHead:
+ case SyntaxKind.TemplateMiddle:
+ case SyntaxKind.TemplateTail:
+ return emitLiteral(node);
+ case SyntaxKind.TemplateExpression:
+ return emitTemplateExpression(node);
+ case SyntaxKind.TemplateSpan:
+ return emitTemplateSpan(node);
+ // case SyntaxKind.JsxElement:
+ // case SyntaxKind.JsxSelfClosingElement:
+ // return emitJsxElement(node);
+ // case SyntaxKind.JsxText:
+ // return emitJsxText(node);
+ // case SyntaxKind.JsxExpression:
+ // return emitJsxExpression(node);
+ case SyntaxKind.QualifiedName:
+ return emitQualifiedName(node);
+ case SyntaxKind.ObjectBindingPattern:
+ return emitObjectBindingPattern(node);
+ case SyntaxKind.ArrayBindingPattern:
+ return emitArrayBindingPattern(node);
+ case SyntaxKind.BindingElement:
+ return emitBindingElement(node);
+ case SyntaxKind.ArrayLiteralExpression:
+ return emitArrayLiteralExpression(node);
+ case SyntaxKind.ObjectLiteralExpression:
+ return emitObjectLiteralExpression(node);
+ case SyntaxKind.PropertyAssignment:
+ return emitPropertyAssignment(node);
+ case SyntaxKind.ShorthandPropertyAssignment:
+ return emitShorthandPropertyAssignment(node);
+ case SyntaxKind.ComputedPropertyName:
+ return emitComputedPropertyName(node);
+ case SyntaxKind.PropertyAccessExpression:
+ return emitPropertyAccessExpression(node);
+ case SyntaxKind.ElementAccessExpression:
+ return emitElementAccessExpression(node);
+ case SyntaxKind.CallExpression:
+ return emitCallExpression(node);
+ case SyntaxKind.NewExpression:
+ return emitNewExpression(node);
+ case SyntaxKind.TaggedTemplateExpression:
+ return emitTaggedTemplateExpression(node);
+ case SyntaxKind.TypeAssertionExpression:
+ return emit((node).expression);
+ case SyntaxKind.AsExpression:
+ return emit((node).expression);
+ case SyntaxKind.ParenthesizedExpression:
+ return emitParenthesizedExpression(node);
+ case SyntaxKind.ArrowFunction:
+ return emitArrowFunction(node);
+ case SyntaxKind.DeleteExpression:
+ return emitDeleteExpression(node);
+ case SyntaxKind.TypeOfExpression:
+ return emitTypeOfExpression(node);
+ case SyntaxKind.VoidExpression:
+ return emitVoidExpression(node);
+ case SyntaxKind.AwaitExpression:
+ return emitAwaitExpression(node);
+ case SyntaxKind.PrefixUnaryExpression:
+ return emitPrefixUnaryExpression(node);
+ case SyntaxKind.PostfixUnaryExpression:
+ return emitPostfixUnaryExpression(node);
+ case SyntaxKind.BinaryExpression:
+ return emitBinaryExpression(node);
+ case SyntaxKind.ConditionalExpression:
+ return emitConditionalExpression(node);
+ case SyntaxKind.SpreadElementExpression:
+ return emitSpreadElementExpression(node);
+ case SyntaxKind.YieldExpression:
+ return emitYieldExpression(node);
+ case SyntaxKind.OmittedExpression:
+ return;
+ }
+ }
+
+ function emitSourceFileNode(node: SourceFile) {
+ writeLine();
+ emitShebang();
+ emitDetachedComments(node);
+ emitStatements(node, node.statements);
+ }
+
+ function emitShebang() {
+ let shebang = getShebang(currentSourceFile.text);
+ if (shebang) {
+ write(shebang);
+ }
+ }
+
+ function emitStatements(parentNode: Node, statements: NodeArray) {
+ emitList(parentNode, statements, ListFormat.Statements);
+ }
+
+ function emitTypeParameters(parentNode: Node, typeParameters: NodeArray) {
+ if (typeParameters && typeParameters.length > 0) {
+ write("<");
+ emitList(parentNode, typeParameters, ListFormat.TypeParameters);
+ write(">");
+ }
+ }
+
+ function emitTypeParameter(node: TypeParameterDeclaration) {
+ emitStart(node);
+ emit(node.name);
+ emitOptional("extends ", node.constraint);
+ emitEnd(node);
+ }
+
+ function emitTypeReference(node: TypeReferenceNode) {
+ emitStart(node);
+ emit(node.typeName);
+ emitTypeArguments(node, node.typeArguments);
+ emitEnd(node);
+ }
+
+ function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) {
+ emitStart(node);
+ emit(node.expression);
+ emitTypeArguments(node, node.typeArguments);
+ emitEnd(node);
+ }
+
+ function emitTypeArguments(parentNode: Node, typeArguments: NodeArray) {
+ if (typeArguments) {
+ write("<");
+ emitList(parentNode, typeArguments, ListFormat.TypeArguments)
+ write(">");
+ }
+ }
+
+ function emitArrayType(node: ArrayTypeNode) {
+ emitStart(node);
+ emit(node.elementType);
+ write("[]");
+ emitEnd(node);
+ }
+
+ function emitTupleType(node: TupleTypeNode) {
+ emitStart(node);
+ emitTupleElementTypes(node, node.elementTypes);
+ emitEnd(node);
+ }
+
+ function emitTupleElementTypes(parentNode: Node, elementTypes: NodeArray) {
+ write("[");
+ emitList(parentNode, elementTypes, ListFormat.TupleElementTypes);
+ write("]");
+ }
+
+ function emitTypeLiteral(node: TypeLiteralNode) {
+ emitStart(node);
+ emitTypeElements(node, node.members);
+ emitEnd(node);
+ }
+
+ function emitTypeElements(parentNode: Node, members: NodeArray) {
+ write("{");
+ emitList(parentNode, members, ListFormat.TypeElements);
+ write("}");
+ }
+
+ function emitFunctionType(node: FunctionTypeNode) {
+ emitStart(node);
+ emitTypeParameters(node, node.typeParameters);
+ emitParametersForArrow(node, node.parameters);
+ write(" => ");
+ emit(node.type);
+ emitEnd(node);
+ }
+
+ function emitConstructorType(node: ConstructorTypeNode) {
+ emitStart(node);
+ write("new ");
+ emitTypeParameters(node, node.typeParameters);
+ emitParametersForArrow(node, node.parameters);
+ write(" => ");
+ emit(node.type);
+ emitEnd(node);
+ }
+
+ function emitParametersForArrow(parentNode: Node, parameters: NodeArray) {
+ if (parameters.length === 1
+ && parameters[0].type === undefined
+ && parameters[0].pos === parentNode.pos) {
+ emit(parameters[0]);
+ return;
+ }
+
+ emitParameters(parentNode, parameters);
+ }
+
+ function emitParameters(parentNode: Node, parameters: NodeArray) {
+ write("(");
+ emitList(parentNode, parameters, ListFormat.Parameters);
+ write(")");
+ }
+
+ function emitParameter(node: ParameterDeclaration) {
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ if (node.dotDotDotToken) write("...");
+ emit(node.name);
+ if (node.questionToken) write("?");
+ emitInitializer(node.initializer);
+ emitTypeAnnotation(node.type);
+ emitEnd(node);
+ }
+
+ function emitParenthesizedType(node: ParenthesizedTypeNode) {
+ write("(");
+ emit(node.type);
+ write(")");
+ }
+
+ function emitUnionType(node: UnionTypeNode) {
+ emitStart(node);
+ emitUnionTypeElements(node, node.types);
+ emitEnd(node);
+ }
+
+ function emitUnionTypeElements(parentNode: Node, types: NodeArray) {
+ emitList(parentNode, types, ListFormat.UnionTypeElements)
+ }
+
+ function emitIntersectionType(node: IntersectionTypeNode) {
+ emitStart(node);
+ emitIntersectionTypeElements(node, node.types);
+ emitEnd(node);
+ }
+
+ function emitIntersectionTypeElements(parentNode: Node, types: NodeArray) {
+ emitList(parentNode, types, ListFormat.IntersectionTypeElements)
+ }
+
+ function emitTypePredicate(node: TypePredicateNode) {
+ emitStart(node);
+ emit(node.parameterName);
+ write(" is ");
+ emit(node.type);
+ emitEnd(node);
+ }
+
+ function emitTypeQuery(node: TypeQueryNode) {
+ emitStart(node);
+ write("typeof ");
+ emit(node.exprName);
+ emitEnd(node);
+ }
+
+ function emitConstructSignature(node: ConstructSignatureDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ write("constructor");
+ emitTypeParameters(node, node.typeParameters);
+ emitParameters(node, node.parameters);
+ emitTypeAnnotation(node.type);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitPropertySignature(node: PropertySignature) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ emit(node.name);
+ if(node.questionToken) write("?");
+ emitTypeAnnotation(node.type);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitMethodSignature(node: MethodSignature) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ emit(node.name);
+ if (node.questionToken) write("?");
+ emitTypeParameters(node, node.typeParameters);
+ emitParameters(node, node.parameters);
+ emitTypeAnnotation(node.type);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitIndexSignature(node: IndexSignatureDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ emitBracketedParameters(node, node.parameters);
+ emitTypeAnnotation(node.type);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitBracketedParameters(parentNode: Node, parameters: NodeArray) {
+ write("[");
+ emitList(parentNode, parameters, ListFormat.Parameters);
+ write("]");
+ }
+
+ function emitImportDeclaration(node: ImportDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitModifiers(node, node.modifiers);
+ write("import ");
+ emit(node.importClause);
+ emit(node.moduleSpecifier);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitImportClause(node: ImportClause) {
+ emitStart(node);
+ emit(node.name);
+ if (node.name && node.namedBindings) {
+ write(", ");
+ }
+ emit(node.namedBindings);
+ emitEnd(node);
+ write(" from ");
+ }
+
+ function emitNamespaceImport(node: NamespaceImport) {
+ emitStart(node);
+ write("* as ");
+ emit(node.name);
+ emitEnd(node);
+ }
+
+ function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitModifiers(node, node.modifiers);
+ write("import ");
+ emit(node.name);
+ write(" = ");
+ emit(node.moduleReference);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitExternalModuleReference(node: ExternalModuleReference) {
+ write("require(");
+ emit(node.expression);
+ write(")");
+ }
+
+ function emitExportDeclaration(node: ExportDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ write("export ");
+ if (node.exportClause) {
+ emit(node.exportClause);
+ write(" from ");
+ }
+ else {
+ write("* from ");
+ }
+ emit(node.moduleSpecifier);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitNamedImportsOrExports(node: NamedImportsOrExports) {
+ emitStart(node);
+ emitImportOrExportSpecifiers(node, node.elements);
+ emitEnd(node);
+ }
+
+ function emitImportOrExportSpecifiers(parentNode: Node, elements: NodeArray) {
+ write("{");
+ emitList(parentNode, elements, ListFormat.ImportOrExportSpecifiers);
+ write("}");
+ }
+
+ function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) {
+ emitLeadingComments(node);
+ emitStart(node);
+ if (node.propertyName) {
+ emit(node.propertyName);
+ write(" as ");
+ }
+
+ emit(node.name);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitExportAssignment(node: ExportAssignment) {
+ emitLeadingComments(node);
+ emitStart(node);
+ write(node.isExportEquals ? "export = " : "export default ");
+ emit(node.expression);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitModuleDeclaration(node: ModuleDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitModifiers(node, node.modifiers);
+ write(node.flags & NodeFlags.Namespace ? "namespace " : "module ");
+ emit(node.name);
+
+ let body = node.body;
+ while (isModuleDeclaration(body)) {
+ write(".");
+ emit((body).name);
+ body = node.body;
+ }
+
+ emit(body);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitEnumDeclaration(node: EnumDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitModifiers(node, node.modifiers);
+ write("enum ");
+ emit(node.name);
+ write(" ");
+ emitEnumMembers(node, node.members);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitEnumMembers(parentNode: Node, members: NodeArray) {
+ write("{");
+ scopeEmitStart(parentNode);
+ emitList(parentNode, members, ListFormat.EnumMembers);
+ scopeEmitEnd();
+ write("}");
+ }
+
+ function emitEnumMember(node: EnumMember) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emit(node.name);
+ emitInitializer(node.initializer);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitVariableStatement(node: VariableStatement) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitModifiers(node, node.modifiers);
+ emit(node.declarationList);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitVariableDeclarationList(node: VariableDeclarationList) {
+ write(isLet(node) ? "let " : isConst(node) ? "const " : "var ");
+ emitList(node, node.declarations, ListFormat.VariableDeclarations);
+ }
+
+ function emitVariableDeclaration(node: VariableDeclaration) {
+ emit(node.name);
+ emitInitializer(node.initializer);
+ }
+
+ function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ write(node.asteriskToken ? "function*" : "function");
+ emitOptional(" ", node.name);
+ emitTypeParameters(node, node.typeParameters);
+ emitParameters(node, node.parameters);
+ emitTypeAnnotation(node.type);
+ emitFunctionBody(node, node.body);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ write("class");
+ emitOptional(" ", node.name);
+ emitTypeParameters(node, node.typeParameters);
+ emitHeritageClauses(node, node.heritageClauses);
+ write(" ");
+ emitClassMembers(node, node.members);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitHeritageClauses(parentNode: Node, heritageClauses: NodeArray) {
+ emitList(parentNode, heritageClauses, ListFormat.HeritageClauses);
+ }
+
+ function emitHeritageClause(node: HeritageClause) {
+ write(" ");
+ emitStart(node);
+ writeToken(node.token);
+ emitHeritageClauseTypes(node, node.types);
+ emitEnd(node);
+ }
+
+ function emitHeritageClauseTypes(parentNode: Node, types: NodeArray) {
+ emitList(parentNode, types, ListFormat.HeritageClauseTypes)
+ }
+
+ function emitClassMembers(parentNode: Node, members: NodeArray) {
+ write("{");
+ scopeEmitStart(parentNode);
+ emitList(parentNode, members, ListFormat.ClassElements);
+ scopeEmitEnd();
+ write("}");
+ }
+
+ function emitConstructor(node: ConstructorDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitModifiers(node, node.modifiers);
+ write("constructor");
+ emitParameters(node, node.parameters);
+ emitFunctionBody(node, node.body);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitPropertyDeclaration(node: PropertyDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ emit(node.name);
+ emitTypeAnnotation(node.type);
+ emitInitializer(node.initializer);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitMethodDeclaration(node: MethodDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ if (node.asteriskToken) write("*");
+ emit(node.name);
+ emitTypeParameters(node, node.typeParameters);
+ emitParameters(node, node.parameters);
+ emitTypeAnnotation(node.type);
+ emitFunctionBody(node, node.body);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitAccessorDeclaration(node: AccessorDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ write(node.kind === SyntaxKind.GetAccessor ? "get " : "set ");
+ emit(node.name);
+ emitParameters(node, node.parameters);
+ emitTypeAnnotation(node.type);
+ emitFunctionBody(node, node.body);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitInterfaceDeclaration(node: InterfaceDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ write("interface ");
+ emit(node.name);
+ emitTypeParameters(node, node.typeParameters);
+ emitHeritageClauses(node, node.heritageClauses);
+ emitTypeElements(node, node.members);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ write("type ");
+ emit(node.name);
+ emitTypeParameters(node, node.typeParameters);
+ write(" = ");
+ emit(node.type);
+ write(";");
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitBlock(node: Block) {
+ emitLeadingComments(node);
+ emitStart(node);
+ emitBlockStatements(node, node.statements);
+ emitEnd(node);
+ emitTrailingComments(node);
+ }
+
+ function emitTryStatement(node: TryStatement) {
+ write("try ");
+ emit(node.tryBlock);
+ emit(node.catchClause);
+ if (node.finallyBlock) {
+ writeLine();
+ write("finally ");
+ emit(node.finallyBlock);
+ }
+ }
+
+ function emitCatchClause(node: CatchClause) {
+ writeLine();
+ write("catch (");
+ emit(node.variableDeclaration);
+ write(") ");
+ emit(node.block);
+ }
+
+ function emitSwitchStatement(node: SwitchStatement) {
+ write("switch (");
+ emit(node.expression);
+ write(") ");
+ emit(node.caseBlock);
+ }
+
+ function emitCaseBlock(node: CaseBlock) {
+ emitCaseClauses(node, node.clauses);
+ }
+
+ function emitCaseClauses(parentNode: Node, clauses: NodeArray) {
+ write("{");
+ scopeEmitStart(parentNode);
+ emitList(parentNode, clauses, ListFormat.CaseClauses)
+ scopeEmitEnd();
+ write("}");
+ }
+
+ function emitCaseClause(node: CaseClause) {
+ write("case ");
+ emit(node.expression);
+ write(":");
+ emitCaseOrDefaultClauseStatements(node, node.statements);
+ }
+
+ function emitDefaultClause(node: DefaultClause) {
+ emitStart(node);
+ write("default:");
+ emitCaseOrDefaultClauseStatements(node, node.statements);
+ emitEnd(node);
+ }
+
+ function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray) {
+ emitList(parentNode, statements, ListFormat.CaseOrDefaultClauseStatements)
+ }
+
+ function emitWithStatement(node: WithStatement) {
+ write("with (");
+ emit(node.expression);
+ write(")");
+ emitEmbeddedStatement(node.statement);
+ }
+
+ function emitLabeledStatement(node: LabeledStatement) {
+ emit(node.label);
+ write(":");
+ emitEmbeddedStatement(node.statement);
+ }
+
+ function emitIfStatement(node: IfStatement) {
+ write("if (");
+ emit(node.expression);
+ write(")");
+ emitEmbeddedStatement(node.thenStatement);
+ if (node.elseStatement) {
+ writeLine();
+ write("else");
+ emitEmbeddedStatement(node.elseStatement);
+ }
+ }
+
+ function emitDoStatement(node: DoStatement) {
+ write("do");
+ emitEmbeddedStatement(node.statement);
+ if (isBlock(node.statement)) {
+ write(" ");
+ }
+ else {
+ writeLine();
+ }
+ write("while (");
+ emit(node.expression);
+ write(");");
+ }
+
+ function emitWhileStatement(node: WhileStatement) {
+ write("while (");
+ emit(node.expression);
+ write(")");
+ emitEmbeddedStatement(node.statement);
+ }
+
+ function emitForStatement(node: ForStatement) {
+ write("for (");
+ emit(node.initializer);
+ write(";");
+ emitOptional(" ", node.condition);
+ write(";");
+ emitOptional(" ", node.incrementor);
+ write(")");
+ emitEmbeddedStatement(node.statement);
+ }
+
+ function emitForInStatement(node: ForInStatement) {
+ write("for (");
+ emit(node.initializer);
+ write(" in ");
+ emit(node.expression);
+ write(")");
+ emitEmbeddedStatement(node.statement);
+ }
+
+ function emitForOfStatement(node: ForOfStatement) {
+ write("for (");
+ emit(node.initializer);
+ write(" of ");
+ emit(node.expression);
+ write(")");
+ emitEmbeddedStatement(node.statement);
+ }
+
+ function emitBreakOrContinueStatement(node: BreakOrContinueStatement) {
+ write(isBreakStatement(node) ? "break" : "continue");
+ emitOptional(" ", node.label);
+ write(";");
+ }
+
+ function emitReturnStatement(node: ReturnStatement) {
+ write("return");
+ emitOptional(" ", node.expression);
+ write(";");
+ }
+
+ function emitThrowStatement(node: ThrowStatement) {
+ write("throw");
+ emitOptional(" ", node.expression);
+ write(";");
+ }
+
+ function emitDebuggerStatement(node: DebuggerStatement) {
+ write("debugger;");
+ }
+
+ function emitExpressionStatement(node: ExpressionStatement) {
+ emit(node.expression);
+ write(";");
+ }
+
+ function emitParenthesizedExpression(node: ParenthesizedExpression) {
+ write("(");
+ emit(node.expression);
+ write(")");
+ }
+
+ function emitTypeAssertion(node: TypeAssertion) {
+ write("<");
+ emit(node.type);
+ write(">");
+ emit(node.expression);
+ }
+
+ function emitAsExpression(node: AsExpression) {
+ emit(node.expression);
+ write(" as ");
+ emit(node.type);
+ }
+
+ function emitYieldExpression(node: YieldExpression) {
+ write(node.asteriskToken ? "yield*" : "yield");
+ emitOptional(" ", node.expression);
+ }
+
+ function emitConditionalExpression(node: ConditionalExpression) {
+ let indentBeforeQuestion = needsIndentation(node, node.condition, node.questionToken);
+ let indentAfterQuestion = needsIndentation(node, node.questionToken, node.whenTrue);
+ let indentBeforeColon = needsIndentation(node, node.whenTrue, node.colonToken);
+ let indentAfterColon = needsIndentation(node, node.colonToken, node.whenFalse);
+ emit(node.condition);
+ increaseIndentIf(indentBeforeQuestion, " ");
+ write("?");
+ increaseIndentIf(indentAfterQuestion, " ");
+ emit(node.whenTrue);
+ decreaseIndentIf(indentBeforeQuestion, indentAfterQuestion);
+ increaseIndentIf(indentBeforeColon, " ");
+ write(":");
+ increaseIndentIf(indentAfterColon);
+ emit(node.whenFalse);
+ decreaseIndentIf(indentBeforeColon, indentAfterColon);
+ }
+
+ function emitBinaryExpression(node: BinaryExpression) {
+ let isCommaOperator = node.operatorToken.kind !== SyntaxKind.CommaToken;
+ let indentBeforeOperator = needsIndentation(node, node.left, node.operatorToken);
+ let indentAfterOperator = needsIndentation(node, node.operatorToken, node.right);
+ emit(node.left);
+ increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
+ writeTokenNode(node.operatorToken);
+ increaseIndentIf(indentAfterOperator, " ");
+ emit(node.right);
+ decreaseIndentIf(indentBeforeOperator, indentAfterOperator);
+ }
+
+ function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
+ writeToken(node.operator);
+ if (shouldEmitWhitespaceBeforeOperand(node)) write(" ");
+ emit(node.operand);
+ }
+
+ function shouldEmitWhitespaceBeforeOperand(node: PrefixUnaryExpression) {
+ // 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.
+ let operand = node.operand;
+ return isPrefixUnaryExpression(operand)
+ && ((node.operator === SyntaxKind.PlusToken && (operand.operator === SyntaxKind.PlusToken || operand.operator === SyntaxKind.PlusPlusToken))
+ || (node.operator === SyntaxKind.MinusToken && (operand.operator === SyntaxKind.MinusToken || operand.operator === SyntaxKind.MinusMinusToken)));
+ }
+
+ function emitPostfixUnaryExpression(node: PostfixUnaryExpression) {
+ emit(node.operand);
+ writeToken(node.operator);
+ }
+
+ function emitDeleteExpression(node: DeleteExpression) {
+ write("delete ");
+ emit(node.expression);
+ }
+
+ function emitTypeOfExpression(node: TypeOfExpression) {
+ write("typeof ");
+ emit(node.expression);
+ }
+
+ function emitVoidExpression(node: VoidExpression) {
+ write("void ");
+ emit(node.expression);
+ }
+
+ function emitAwaitExpression(node: AwaitExpression) {
+ write("await ");
+ emit(node.expression);
+ }
+
+ function emitSpreadElementExpression(node: SpreadElementExpression) {
+ write("...");
+ emit(node.expression);
+ }
+
+ function emitArrayLiteralExpression(node: ArrayLiteralExpression) {
+ write("[");
+ emitArrayLiteralElements(node, node.elements);
+ write("]");
+ }
+
+ function emitArrayLiteralElements(parentNode: Node, elements: NodeArray) {
+ emitList(parentNode, elements, ListFormat.ArrayLiteralElements);
+ }
+
+ function emitObjectLiteralExpression(node: ObjectLiteralExpression) {
+ write("{");
+ emitObjectLiteralProperties(node, node.properties);
+ write("}");
+ }
+
+ function emitObjectLiteralProperties(parentNode: Node, properties: NodeArray) {
+ let listFormat = languageVersion >= ScriptTarget.ES5
+ ? ListFormat.ObjectLiteralPropertiesForES5AndLater
+ : ListFormat.ObjectLiteralProperties;
+ emitList(parentNode, properties, listFormat);
+ }
+
+ function emitPropertyAssignment(node: PropertyAssignment) {
+ 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);
+ }
+
+ function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) {
+ emit(node.name);
+ }
+
+ function emitComputedPropertyName(node: ComputedPropertyName) {
+ write("[");
+ emit(node.expression);
+ write("]");
+ }
+
+ function emitPropertyAccessExpression(node: PropertyAccessExpression) {
+ if (tryEmitConstantValue(node)) {
+ return;
+ }
+
+ let indentBeforeDot = needsIndentation(node, node.expression, node.dotToken);
+ let indentAfterDot = needsIndentation(node, node.dotToken, node.name);
+ let shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression);
+ emit(node.expression);
+ increaseIndentIf(indentBeforeDot);
+ write(shouldEmitDotDot ? ".." : ".");
+ increaseIndentIf(indentAfterDot);
+ emit(node.name);
+ decreaseIndentIf(indentBeforeDot, indentAfterDot);
+ }
+
+ // 1..toString is a valid property access, emit a dot after the literal
+ // Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal
+ function needsDotDotForPropertyAccess(expression: Expression) {
+ if (isNumericLiteral(expression)) {
+ // check if numeric literal was originally written with a dot
+ let text = getTextOfNode(expression);
+ return text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0;
+ }
+ else {
+ // check if constant enum value is integer
+ let constantValue = tryGetConstEnumValue(expression);
+ // isFinite handles cases when constantValue is undefined
+ return isFinite(constantValue) && Math.floor(constantValue) === constantValue;
+ }
+ return false;
+ }
+
+ function emitElementAccessExpression(node: ElementAccessExpression) {
+ if (tryEmitConstantValue(node)) {
+ return;
+ }
+
+ emit(node.expression);
+ write("[");
+ emit(node.argumentExpression);
+ write("]");
+ }
+
+ function emitCallExpression(node: CallExpression) {
+ emit(node.expression);
+ emitArguments(node, node.arguments);
+ }
+
+ function emitNewExpression(node: NewExpression) {
+ write("new ");
+ emit(node.expression);
+ if (node.arguments) {
+ emitArguments(node, node.arguments);
+ }
+ }
+
+ function emitArguments(parentNode: Node, _arguments: NodeArray) {
+ write("(");
+ emitList(parentNode, _arguments, ListFormat.Arguments);
+ write(")");
+ }
+
+ function emitTaggedTemplateExpression(node: TaggedTemplateExpression) {
+ emit(node.tag);
+ emit(node.template);
+ }
+
+ function emitArrowFunction(node: ArrowFunction) {
+ emitStart(node);
+ emitDecorators(node, node.decorators);
+ emitModifiers(node, node.modifiers);
+ emitTypeParameters(node, node.typeParameters);
+ emitParametersForArrow(node, node.parameters);
+ emitTypeAnnotation(node.type);
+ emitConciseBody(node, node.body);
+ emitEnd(node);
+ }
+
+ function writeToken(token: SyntaxKind) {
+ write(tokenToString(token));
+ }
+
+ function writeTokenNode(node: Node) {
+ if (node) {
+ writeToken(node.kind);
+ }
+ }
+
+ function emitIdentifier(node: Identifier) {
+ // TODO
+ write(getTextOfNode(node));
+ }
+
+ function emitLiteral(node: LiteralExpression) {
+ // TODO
+ write(getTextOfNode(node));
+ }
+
+ function emitDecorators(parentNode: Node, decorators: NodeArray) {
+ emitList(parentNode, decorators, ListFormat.Decorators);
+ }
+
+ function emitDecorator(decorator: Decorator) {
+ emitLeadingComments(decorator);
+ emitStart(decorator);
+ write("@");
+ emit(decorator.expression);
+ emitEnd(decorator);
+ emitTrailingComments(decorator);
+ }
+
+ function emitModifiers(node: Node, modifiers: ModifiersArray) {
+ if (node.flags & NodeFlags.Export) {
+ write("export ");
+ }
+ if (node.flags & NodeFlags.Default) {
+ write("default ");
+ }
+ if (node.flags & NodeFlags.Ambient) {
+ write("declare ");
+ }
+ if (isConstEnumDeclaration(node)) {
+ write("const ");
+ }
+ if (node.flags & NodeFlags.Public) {
+ write("public ");
+ }
+ else if (node.flags & NodeFlags.Protected) {
+ write("protected ");
+ }
+ else if (node.flags & NodeFlags.Private) {
+ write("private ");
+ }
+ if (node.flags & NodeFlags.Static) {
+ write("static ");
+ }
+ if (node.flags & NodeFlags.Async) {
+ write("async ");
+ }
+ if (node.flags & NodeFlags.Abstract) {
+ write("abstract ");
+ }
+ }
+
+ function emitInitializer(initializer: Expression) {
+ if (initializer) {
+ write(" = ");
+ emit(initializer);
+ }
+ }
+
+ function emitTypeAnnotation(type: TypeNode) {
+ if (type) {
+ write(": ");
+ emit(type);
+ }
+ }
+
+ function emitFunctionBody(parentNode: Node, body: FunctionBody) {
+ if (!body) {
+ write(";");
+ return;
+ }
+
+ emit(body);
+ }
+
+ function emitConciseBody(parentNode: Node, body: ConciseBody) {
+ emit(body);
+ }
+
+ function emitBlockStatements(parentNode: Node, statements: NodeArray) {
+ write("{");
+ scopeEmitStart(parentNode);
+ emitList(parentNode, statements, ListFormat.BlockStatements);
+ scopeEmitEnd();
+ write("}");
+ }
+
+ function emitTemplateExpression(node: TemplateExpression) {
+ emit(node.head);
+ emitTemplateSpans(node.templateSpans);
+ }
+
+ function emitTemplateSpans(templateSpans: NodeArray) {
+ for (let node of templateSpans) {
+ emit(node);
+ }
+ }
+
+ function emitTemplateSpan(node: TemplateSpan) {
+ emit(node.expression);
+ emit(node.literal);
+ }
+
+ function emitQualifiedName(node: QualifiedName) {
+ emit(node.left);
+ write(".");
+ emit(node.right);
+ }
+
+ function emitObjectBindingPattern(node: ObjectBindingPattern) {
+ write("{");
+ emitList(node, node.elements, ListFormat.BindingElements | ListFormat.Whitespace);
+ write("}");
+ }
+
+ function emitArrayBindingPattern(node: ArrayBindingPattern) {
+ write("[");
+ emitList(node, node.elements, ListFormat.BindingElements);
+ write("]");
+ }
+
+ function emitBindingElement(node: BindingElement) {
+ if (node.propertyName) {
+ emit(node.propertyName);
+ write(": ");
+ }
+
+ if (node.dotDotDotToken) write("...");
+ emit(node.name);
+ emitInitializer(node.initializer);
+ }
+
+ function emitOptional(prefix: string, node: Node) {
+ if (node) {
+ write(prefix);
+ emit(node);
+ }
+ }
+
+ function emitEmbeddedStatement(node: Statement) {
+ if (isBlock(node)) {
+ write(" ");
+ emit(node);
+ }
+ else {
+ writeLine();
+ increaseIndent();
+ emit(node);
+ decreaseIndent();
+ }
+ }
+
+ function emitList(parentNode: Node, children: NodeArray, format?: ListFormat) {
+ if (children) {
+ let previousSibling: Node;
+ let firstChild = firstOrUndefined(children);
+ let lastChild = lastOrUndefined(children);
+ let hasTrailingComma = (format & ListFormat.AllowTrailingComma) && children.hasTrailingComma;
+ let separator = format & ListFormat.Comma ? "," : format & ListFormat.Bar ? "|" : format & ListFormat.Ampersand ? "&" : undefined;
+
+ if (shouldEmitOpeningLineTerminator(parentNode, firstChild)) {
+ writeLine();
+ }
+ else if (format & ListFormat.LeadingWhitespace) {
+ write(" ");
+ }
+
+ if (format & ListFormat.Indented) {
+ increaseIndent();
+ }
+
+ for (let child of children) {
+ if (child) {
+ if (shouldEmitSeparatingLineTerminator(previousSibling, child)) {
+ if (separator) {
+ write(separator);
+ }
+
+ writeLine();
+ }
+ else if (previousSibling) {
+ if (separator) {
+ write(separator);
+ }
+
+ write(" ");
+ }
+
+ emit(child);
+ previousSibling = child;
+ }
+ }
+
+ if (hasTrailingComma) {
+ write(",");
+ }
+
+ if (format & ListFormat.Indented) {
+ decreaseIndent();
+ }
+
+ if (shouldEmitClosingLineTerminator(parentNode, lastChild)) {
+ writeLine();
+ }
+ else if (format & ListFormat.TrailingWhitespace && (previousSibling || hasTrailingComma)) {
+ write(" ");
+ }
+ }
+ }
+
+ function shouldEmitOpeningLineTerminator(parentNode: Node, firstChild: Node) {
+ if (firstChild === undefined) {
+ return false;
+ }
+ else if (nodeIsSynthesized(parentNode)) {
+ return synthesizedNodeStartsOnNewLine(firstChild);
+ }
+ else if (nodeIsSynthesized(firstChild)) {
+ return (firstChild).startsOnNewLine;
+ }
+ else {
+ return !nodeStartPositionsAreOnSameLine(parentNode, firstChild);
+ }
+ }
+
+ function shouldEmitSeparatingLineTerminator(previousNode: Node, nextNode: Node) {
+ if (previousNode === undefined || nextNode === undefined) {
+ return false;
+ }
+ else if (nodeIsSynthesized(previousNode) || nodeIsSynthesized(nextNode)) {
+ return synthesizedNodeStartsOnNewLine(previousNode) || synthesizedNodeStartsOnNewLine(nextNode);
+ }
+ else {
+ return !nodeEndIsOnSameLineAsNodeStart(previousNode, nextNode);
+ }
+ }
+
+ function shouldEmitClosingLineTerminator(parentNode: Node, lastChild: Node) {
+ if (lastChild === undefined) {
+ return false;
+ }
+ else if (nodeIsSynthesized(parentNode)) {
+ return synthesizedNodeStartsOnNewLine(lastChild);
+ }
+ else if (nodeIsSynthesized(lastChild)) {
+ return (lastChild).startsOnNewLine;
+ }
+ else {
+ return !nodeEndPositionsAreOnSameLine(parentNode, lastChild);
+ }
+ }
+
+ function synthesizedNodeStartsOnNewLine(node: Node) {
+ return nodeIsSynthesized(node) && (node).startsOnNewLine;
+ }
+
+ function nodeStartPositionsAreOnSameLine(node1: Node, node2: Node) {
+ return getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node1.pos)) ===
+ getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node2.pos));
+ }
+
+ function nodeEndPositionsAreOnSameLine(node1: Node, node2: Node) {
+ return getLineOfLocalPosition(currentSourceFile, node1.end) ===
+ getLineOfLocalPosition(currentSourceFile, node2.end);
+ }
+
+ function nodeEndIsOnSameLineAsNodeStart(node1: Node, node2: Node) {
+ return getLineOfLocalPosition(currentSourceFile, node1.end) ===
+ getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node2.pos));
+ }
+
+ // Returns 'true' if the code needs to be indented, false otherwise.
+ function needsIndentation(parent: Node, node1: Node, node2: Node): boolean {
+ let realNodesAreOnDifferentLines = !nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2);
+
+ // Always use a newline for synthesized code if the synthesizer desires it.
+ let synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2);
+
+ return realNodesAreOnDifferentLines || synthesizedNodeIsOnDifferentLine;
+ }
+
+ function increaseIndentIf(value: boolean, valueToWriteWhenNotIndenting?: string) {
+ if (value) {
+ increaseIndent();
+ writeLine();
+ }
+ else if (valueToWriteWhenNotIndenting) {
+ write(valueToWriteWhenNotIndenting);
+ }
+ }
+
+ // 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: boolean, value2?: boolean) {
+ if (value1) {
+ decreaseIndent();
+ }
+ if (value2) {
+ decreaseIndent();
+ }
+ }
+
+ function getTextOfNode(node: Node, includeTrivia?: boolean) {
+ if (nodeIsSynthesized(node) && (isLiteralExpression(node) || isIdentifier(node))) {
+ return node.text;
+ }
+
+ return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia);
+ }
+
+ function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean {
+ let constantValue = tryGetConstEnumValue(node);
+ if (constantValue !== undefined) {
+ write(String(constantValue));
+ if (!compilerOptions.removeComments) {
+ let propertyName = isPropertyAccessExpression(node)
+ ? declarationNameToString(node.name)
+ : getTextOfNode(node.argumentExpression);
+ write(` /* ${propertyName} */`);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ function tryGetConstEnumValue(node: Node): number {
+ if (compilerOptions.isolatedModules) {
+ return undefined;
+ }
+
+ return isPropertyAccessExpression(node) || isElementAccessExpression(node)
+ ? resolver.getConstantValue(node)
+ : undefined;
+ }
+ }
+ }
+}
\ No newline at end of file