diff --git a/Jakefile.js b/Jakefile.js index 1b34bc64e2f..050b40af6d1 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -47,6 +47,7 @@ var compilerSources = [ "transforms/ts.ts", "transforms/es6.ts", "declarationEmitter.ts", + "printer.ts", "emitter.ts", "program.ts", "commandLineParser.ts", @@ -72,6 +73,7 @@ var servicesSources = [ "transforms/ts.ts", "transforms/es6.ts", "declarationEmitter.ts", + "printer.ts", "emitter.ts", "program.ts", "commandLineParser.ts", diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6ee46a9389e..7458e82d395 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15274,7 +15274,7 @@ namespace ts { // Grammar checking for computedPropertName and shorthandPropertyAssignment checkGrammarForInvalidQuestionMark(prop, (prop).questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); if (name.kind === SyntaxKind.NumericLiteral) { - checkGrammarNumericLiteral(name); + checkGrammarNumericLiteral(name); } currentKind = Property; } @@ -15825,7 +15825,7 @@ namespace ts { } } - function checkGrammarNumericLiteral(node: Identifier): boolean { + function checkGrammarNumericLiteral(node: LiteralExpression): boolean { // Grammar checking if (node.flags & NodeFlags.OctalLiteral && languageVersion >= ScriptTarget.ES5) { return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 8b4fe5157a8..2ae48e664b5 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1,6 +1,7 @@ /// /// /// +/// /* @internal */ namespace ts { @@ -78,9 +79,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let shouldEmitJsx = (s: SourceFile) => (s.languageVariant === LanguageVariant.JSX && !jsxDesugaring); let transformationChain = getTransformationChain(compilerOptions); let sourceFiles: SourceFile[]; + let transformationResolver: TransformationResolver; if (targetSourceFile === undefined) { - sourceFiles = transformFilesIfNeeded(resolver, host, host.getSourceFiles(), transformationChain); + ({ sourceFiles, transformationResolver } = transformFilesIfNeeded(resolver, host, host.getSourceFiles(), transformationChain)); forEach(sourceFiles, sourceFile => { if (shouldEmitToOwnFile(sourceFile, compilerOptions)) { let jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, shouldEmitJsx(sourceFile) ? ".jsx" : ".js"); @@ -96,11 +98,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // targetSourceFile is specified (e.g calling emitter from language service or calling getSemanticDiagnostic from language service) if (shouldEmitToOwnFile(targetSourceFile, compilerOptions)) { let jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, shouldEmitJsx(targetSourceFile) ? ".jsx" : ".js"); - [targetSourceFile] = transformFilesIfNeeded(resolver, host, [targetSourceFile], transformationChain); + ({ sourceFiles: [targetSourceFile], transformationResolver } = transformFilesIfNeeded(resolver, host, [targetSourceFile], transformationChain)); emitFile(jsFilePath, targetSourceFile); } else if (!isDeclarationFile(targetSourceFile) && (compilerOptions.outFile || compilerOptions.out)) { - sourceFiles = transformFilesIfNeeded(resolver, host, host.getSourceFiles(), transformationChain); + ({ sourceFiles, transformationResolver } = transformFilesIfNeeded(resolver, host, host.getSourceFiles(), transformationChain)); emitFile(compilerOptions.outFile || compilerOptions.out); } } @@ -8000,7 +8002,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } function emitFile(jsFilePath: string, sourceFile?: SourceFile) { - emitJavaScript(jsFilePath, sourceFile); + if (compilerOptions.experimentalTransforms) { + let result = sourceFile + ? printFile(resolver, transformationResolver, host, [sourceFile], jsFilePath) + : printFile(resolver, transformationResolver, host, sourceFiles, jsFilePath); + + writeFile(host, diagnostics, result.fileName, result.text, compilerOptions.emitBOM); + } + else { + emitJavaScript(jsFilePath, sourceFile); + } if (compilerOptions.declaration) { writeDeclarationFile(jsFilePath, getOriginalNodeIf(sourceFile, isSourceFile), host, resolver, diagnostics); diff --git a/src/compiler/factory.generated.ts b/src/compiler/factory.generated.ts index ac95601bb2d..a5e33721b0c 100644 --- a/src/compiler/factory.generated.ts +++ b/src/compiler/factory.generated.ts @@ -666,7 +666,7 @@ namespace ts { if (name) node.name = name; return node; } - export function createNamedImports(elements?: Array, location?: TextRange, flags?: NodeFlags): NamedImports { + export function createNamedImports(elements?: Array, location?: TextRange, flags?: NodeFlags): NamedImports { let node = createNode(SyntaxKind.NamedImports, location, flags); if (elements) node.elements = createNodeArray(elements); return node; @@ -692,7 +692,7 @@ namespace ts { if (moduleSpecifier) node.moduleSpecifier = moduleSpecifier; return node; } - export function createNamedExports(elements?: Array, location?: TextRange, flags?: NodeFlags): NamedExports { + export function createNamedExports(elements?: Array, location?: TextRange, flags?: NodeFlags): NamedExports { let node = createNode(SyntaxKind.NamedExports, location, flags); if (elements) node.elements = createNodeArray(elements); return node; @@ -1557,7 +1557,7 @@ namespace ts { } return node; } - export function updateNamedImports(node: NamedImports, elements: Array): NamedImports { + export function updateNamedImports(node: NamedImports, elements: Array): NamedImports { if (elements !== node.elements) { let newNode = createNamedImports(elements); return updateFrom(node, newNode); @@ -1585,7 +1585,7 @@ namespace ts { } return node; } - export function updateNamedExports(node: NamedExports, elements: Array): NamedExports { + export function updateNamedExports(node: NamedExports, elements: Array): NamedExports { if (elements !== node.elements) { let newNode = createNamedExports(elements); return updateFrom(node, newNode); @@ -2338,11 +2338,108 @@ namespace ts { } return false; } + export function isExpressionNode(node: Node): node is Expression { + if (node) { + switch (node.kind) { + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + case SyntaxKind.StringLiteral: + case SyntaxKind.RawExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.FunctionExpression: + case SyntaxKind.TemplateExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.JsxElement: + case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.ClassExpression: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.DeleteExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.AwaitExpression: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.OmittedExpression: + case SyntaxKind.YieldExpression: + case SyntaxKind.BinaryExpression: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.AsExpression: + case SyntaxKind.JsxOpeningElement: + case SyntaxKind.JsxExpression: + return true; + } + } + return false; + } + export function isEntityName(node: Node): node is EntityName { + if (node) { + switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.QualifiedName: + return true; + } + } + return false; + } + export function isDeclarationNameNode(node: Node): node is DeclarationName { + if (node) { + switch (node.kind) { + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + case SyntaxKind.ComputedPropertyName: + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + case SyntaxKind.StringLiteral: + case SyntaxKind.RawExpression: + return true; + } + } + return false; + } + export function isPropertyName(node: Node): node is PropertyName { + if (node) { + switch (node.kind) { + case SyntaxKind.ComputedPropertyName: + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + case SyntaxKind.StringLiteral: + case SyntaxKind.RawExpression: + return true; + } + } + return false; + } export function isStatementNode(node: Node): node is Statement { if (node) { switch (node.kind) { - case SyntaxKind.EmptyStatement: - case SyntaxKind.DebuggerStatement: case SyntaxKind.FunctionDeclaration: case SyntaxKind.MissingDeclaration: case SyntaxKind.ClassDeclaration: @@ -2355,6 +2452,8 @@ namespace ts { case SyntaxKind.ExportAssignment: case SyntaxKind.Block: case SyntaxKind.RawStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.DebuggerStatement: case SyntaxKind.ModuleBlock: case SyntaxKind.VariableStatement: case SyntaxKind.ExpressionStatement: @@ -2378,23 +2477,6 @@ namespace ts { } return false; } - export function isUnaryExpression(node: Node): node is UnaryExpression { - if (node) { - switch (node.kind) { - case SyntaxKind.CallExpression: - case SyntaxKind.NewExpression: - case SyntaxKind.PostfixUnaryExpression: - case SyntaxKind.PrefixUnaryExpression: - case SyntaxKind.DeleteExpression: - case SyntaxKind.TypeOfExpression: - case SyntaxKind.VoidExpression: - case SyntaxKind.AwaitExpression: - case SyntaxKind.TypeAssertionExpression: - return true; - } - } - return false; - } export function isTypeNodeNode(node: Node): node is TypeNode { if (node) { switch (node.kind) { @@ -2486,10 +2568,9 @@ namespace ts { } return false; } - export function isExpressionNode(node: Node): node is Expression { + export function isUnaryExpression(node: Node): node is UnaryExpression { if (node) { switch (node.kind) { - case SyntaxKind.OmittedExpression: case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: case SyntaxKind.NullKeyword: @@ -2524,14 +2605,6 @@ namespace ts { case SyntaxKind.VoidExpression: case SyntaxKind.AwaitExpression: case SyntaxKind.TypeAssertionExpression: - case SyntaxKind.YieldExpression: - case SyntaxKind.BinaryExpression: - case SyntaxKind.ConditionalExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.SpreadElementExpression: - case SyntaxKind.AsExpression: - case SyntaxKind.JsxOpeningElement: - case SyntaxKind.JsxExpression: return true; } } @@ -2553,6 +2626,58 @@ namespace ts { } return false; } + export function isConciseBody(node: Node): node is ConciseBody { + if (node) { + switch (node.kind) { + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + case SyntaxKind.StringLiteral: + case SyntaxKind.RawExpression: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.FunctionExpression: + case SyntaxKind.TemplateExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.JsxElement: + case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.ClassExpression: + case SyntaxKind.PropertyAccessExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.DeleteExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.AwaitExpression: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.OmittedExpression: + case SyntaxKind.YieldExpression: + case SyntaxKind.BinaryExpression: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.AsExpression: + case SyntaxKind.JsxOpeningElement: + case SyntaxKind.JsxExpression: + case SyntaxKind.Block: + return true; + } + } + return false; + } export function isLiteralExpressionOrTemplateExpression(node: Node): node is LiteralExpression | TemplateExpression { if (node) { switch (node.kind) { @@ -2580,10 +2705,21 @@ namespace ts { } return false; } + export function isJsxChild(node: Node): node is JsxChild { + if (node) { + switch (node.kind) { + case SyntaxKind.JsxElement: + case SyntaxKind.JsxExpression: + case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxText: + return true; + } + } + return false; + } export function isExpressionOrVariableDeclarationList(node: Node): node is Expression | VariableDeclarationList { if (node) { switch (node.kind) { - case SyntaxKind.OmittedExpression: case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: case SyntaxKind.NullKeyword: @@ -2618,6 +2754,7 @@ namespace ts { case SyntaxKind.VoidExpression: case SyntaxKind.AwaitExpression: case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.OmittedExpression: case SyntaxKind.YieldExpression: case SyntaxKind.BinaryExpression: case SyntaxKind.ConditionalExpression: @@ -2632,6 +2769,26 @@ namespace ts { } return false; } + export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause { + if (node) { + switch (node.kind) { + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + return true; + } + } + return false; + } + export function isModuleBody(node: Node): node is ModuleBody { + if (node) { + switch (node.kind) { + case SyntaxKind.ModuleBlock: + case SyntaxKind.ModuleDeclaration: + return true; + } + } + return false; + } export function isIdentifierOrLiteralExpression(node: Node): node is Identifier | LiteralExpression { if (node) { switch (node.kind) { @@ -2652,6 +2809,8 @@ namespace ts { export function isEntityNameOrExternalModuleReference(node: Node): node is EntityName | ExternalModuleReference { if (node) { switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.QualifiedName: case SyntaxKind.ExternalModuleReference: return true; } @@ -2668,16 +2827,6 @@ namespace ts { } return false; } - export function isImportOrExportSpecifier(node: Node): node is ImportOrExportSpecifier { - if (node) { - switch (node.kind) { - case SyntaxKind.ImportSpecifier: - case SyntaxKind.ExportSpecifier: - return true; - } - } - return false; - } export function isJSDocType(node: Node): node is JSDocType { if (node) { switch (node.kind) { @@ -3186,7 +3335,7 @@ namespace ts { case SyntaxKind.NamespaceImport: return updateNamespaceImport(node, (node).name); case SyntaxKind.NamedImports: - return updateNamedImports(node, transformer.visitNodes((node).elements, visitor, isImportOrExportSpecifier)); + return updateNamedImports(node, transformer.visitNodes((node).elements, visitor, isImportSpecifier)); case SyntaxKind.ImportSpecifier: return updateImportSpecifier(node, (node).propertyName, (node).name); case SyntaxKind.ExportAssignment: @@ -3194,7 +3343,7 @@ namespace ts { case SyntaxKind.ExportDeclaration: return updateExportDeclaration(node, transformer.visitNodes((node).decorators, visitor, isDecorator), transformer.visitNodes((node).modifiers, visitor, isModifier), (node).exportClause, (node).moduleSpecifier); case SyntaxKind.NamedExports: - return updateNamedExports(node, transformer.visitNodes((node).elements, visitor, isImportOrExportSpecifier)); + return updateNamedExports(node, transformer.visitNodes((node).elements, visitor, isExportSpecifier)); case SyntaxKind.ExportSpecifier: return updateExportSpecifier(node, (node).propertyName, (node).name); case SyntaxKind.MissingDeclaration: diff --git a/src/compiler/printer.ts b/src/compiler/printer.ts index 00096e94b9a..faf7497f2c2 100644 --- a/src/compiler/printer.ts +++ b/src/compiler/printer.ts @@ -4,1617 +4,1988 @@ /* @internal */ namespace ts { + const brackets = createBracketsMap(); + const delimiters = createDelimiterMap(); - 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, + /** + * Pretty-prints a set of input source files to an output string. + * @param resolver The emit resolver. + * @param host The emit host + * @param sourceFiles The input source files. + * @param fileName The output file name. + */ + export function printFile(resolver: EmitResolver, transformationResolver: TransformationResolver, host: EmitHost, sourceFiles: SourceFile[], fileName: string) { + console.log("called printFile!"); - 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 writer = createTextWriter(host.getNewLine()); + let { write, writeTextOfNode, writeLine, increaseIndent, decreaseIndent } = writer; 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; + let currentSourceFile: SourceFile; + let parentNode: Node; + let currentNode: Node; + let assignmentSubstitution: (node: BinaryExpression) => Expression; + let expressionIdentifierSubstitution: (node: Identifier) => LeftHandSideExpression; + let bindingIdentifierSubstitution: (node: Identifier) => Identifier; + + /** Emit a node */ + let emit = emitNode; + + let emitDetachedComments = function (node: Node) { }; + let emitLeadingComments = function (node: Node) { }; + let emitTrailingComments = function (node: Node) { }; + let emitTrailingCommentsOfPosition = function (pos: number) { }; + + /** 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) { }; + + /** 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; + + if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) { + // initializeEmitterWithSourceMaps(); + } + + for (let sourceFile of sourceFiles) { + emit(sourceFile); + } + + writeLine(); + return { fileName, text: writer.getText(), sourceMapData }; + + function emitNode(node: Node) { + if (node) { + let savedParentNode = parentNode; + parentNode = currentNode; + emitNodeWorker(currentNode = node); + currentNode = parentNode; + parentNode = savedParentNode; } } + + function tryEmitSubstitute(node: T, substitution: (node: T) => Node) { + let substitute = substitution(node); + if (substitute && substitute !== node) { + let savedCurrentNode = currentNode; + emitNodeWorker(currentNode = substitute); + currentNode = savedCurrentNode; + return true; + } + + return false; + } + + function emitNodeWorker(node: Node) { + switch (node.kind) { + // Literals + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + return emitLiteral(node); + + // Pseudo-literals + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + return emitLiteral(node); + + // Identifiers + case SyntaxKind.Identifier: + return emitIdentifier(node); + + // Reserved words + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.ThisKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.VoidKeyword: + return writeTokenNode(node); + + // Contextual keywords + case SyntaxKind.AnyKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.SymbolKeyword: + return writeTokenNode(node); + + // Parse tree nodes + + // Names + case SyntaxKind.QualifiedName: + return emitQualifiedName(node); + case SyntaxKind.ComputedPropertyName: + return emitComputedPropertyName(node); + + // Signature elements + case SyntaxKind.TypeParameter: + return emitTypeParameter(node); + case SyntaxKind.Parameter: + return emitParameter(node); + case SyntaxKind.Decorator: + return emitDecorator(node); + + // Type members + case SyntaxKind.PropertySignature: + return emitPropertySignature(node); + case SyntaxKind.PropertyDeclaration: + return emitPropertyDeclaration(node); + case SyntaxKind.MethodSignature: + return emitMethodSignature(node); + case SyntaxKind.MethodDeclaration: + return emitMethodDeclaration(node); + case SyntaxKind.Constructor: + return emitConstructor(node); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return emitAccessorDeclaration(node); + case SyntaxKind.CallSignature: + return emitCallSignature(node); + case SyntaxKind.ConstructSignature: + return emitConstructSignature(node); + case SyntaxKind.IndexSignature: + return emitIndexSignature(node); + + // Types + case SyntaxKind.TypePredicate: + return emitTypePredicate(node); + case SyntaxKind.TypeReference: + return emitTypeReference(node); + case SyntaxKind.FunctionType: + return emitFunctionType(node); + case SyntaxKind.ConstructorType: + return emitConstructorType(node); + case SyntaxKind.TypeQuery: + return emitTypeQuery(node); + case SyntaxKind.TypeLiteral: + return emitTypeLiteral(node); + case SyntaxKind.ArrayType: + return emitArrayType(node); + case SyntaxKind.TupleType: + return emitTupleType(node); + case SyntaxKind.UnionType: + return emitUnionType(node); + case SyntaxKind.IntersectionType: + return emitIntersectionType(node); + case SyntaxKind.ParenthesizedType: + return emitParenthesizedType(node); + + // Binding patterns + case SyntaxKind.ObjectBindingPattern: + return emitObjectBindingPattern(node); + case SyntaxKind.ArrayBindingPattern: + return emitArrayBindingPattern(node); + case SyntaxKind.BindingElement: + return emitBindingElement(node); + + // Expressions + case SyntaxKind.ArrayLiteralExpression: + return emitArrayLiteralExpression(node); + case SyntaxKind.ObjectLiteralExpression: + return emitObjectLiteralExpression(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 emitTypeAssertionExpression(node); + case SyntaxKind.ParenthesizedExpression: + return emitParenthesizedExpression(node); + case SyntaxKind.FunctionExpression: + return emitFunctionExpression(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.TemplateExpression: + return emitTemplateExpression(node); + case SyntaxKind.YieldExpression: + return emitYieldExpression(node); + case SyntaxKind.SpreadElementExpression: + return emitSpreadElementExpression(node); + case SyntaxKind.ClassExpression: + return emitClassExpression(node); + case SyntaxKind.OmittedExpression: + return; + case SyntaxKind.ExpressionWithTypeArguments: + return emitExpressionWithTypeArguments(node); + case SyntaxKind.AsExpression: + return emitAsExpression(node); + + // Misc + case SyntaxKind.TemplateSpan: + return emitTemplateSpan(node); + case SyntaxKind.SemicolonClassElement: + return write(";"); + + // Statements + case SyntaxKind.Block: + return emitBlock(node); + case SyntaxKind.VariableStatement: + return emitVariableStatement(node); + case SyntaxKind.EmptyStatement: + return write(";"); + case SyntaxKind.ExpressionStatement: + return emitExpressionStatement(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.ForInStatement: + return emitForInStatement(node); + case SyntaxKind.ForOfStatement: + return emitForOfStatement(node); + case SyntaxKind.ContinueStatement: + return emitContinueStatement(node); + case SyntaxKind.BreakStatement: + return emitBreakStatement(node); + case SyntaxKind.ReturnStatement: + return emitReturnStatement(node); + case SyntaxKind.WithStatement: + return emitWithStatement(node); + case SyntaxKind.SwitchStatement: + return emitSwitchStatement(node); + case SyntaxKind.LabeledStatement: + return emitLabeledStatement(node); + case SyntaxKind.ThrowStatement: + return emitThrowStatement(node); + case SyntaxKind.TryStatement: + return emitTryStatement(node); + case SyntaxKind.DebuggerStatement: + return emitDebuggerStatement(node); + + // Declarations + case SyntaxKind.VariableDeclaration: + return emitVariableDeclaration(node); + case SyntaxKind.VariableDeclarationList: + return emitVariableDeclarationList(node); + case SyntaxKind.FunctionDeclaration: + return emitFunctionDeclaration(node); + case SyntaxKind.ClassDeclaration: + return emitClassDeclaration(node); + case SyntaxKind.InterfaceDeclaration: + return emitInterfaceDeclaration(node); + case SyntaxKind.TypeAliasDeclaration: + return emitTypeAliasDeclaration(node); + case SyntaxKind.EnumDeclaration: + return emitEnumDeclaration(node); + case SyntaxKind.ModuleDeclaration: + return emitModuleDeclaration(node); + case SyntaxKind.ModuleBlock: + return emitModuleBlock(node); + case SyntaxKind.CaseBlock: + return emitCaseBlock(node); + case SyntaxKind.ImportEqualsDeclaration: + return emitImportEqualsDeclaration(node); + case SyntaxKind.ImportDeclaration: + return emitImportDeclaration(node); + case SyntaxKind.ImportClause: + return emitImportClause(node); + case SyntaxKind.NamespaceImport: + return emitNamespaceImport(node); + case SyntaxKind.NamedImports: + return emitNamedImportsOrExports(node); + case SyntaxKind.ImportSpecifier: + return emitImportOrExportSpecifier(node); + case SyntaxKind.ExportAssignment: + return emitExportAssignment(node); + case SyntaxKind.ExportDeclaration: + return emitExportDeclaration(node); + case SyntaxKind.NamedExports: + return emitNamedImportsOrExports(node); + case SyntaxKind.ExportSpecifier: + return emitImportOrExportSpecifier(node); + case SyntaxKind.MissingDeclaration: + return; + + // Module references + case SyntaxKind.ExternalModuleReference: + return emitExternalModuleReference(node); + + // JSX + case SyntaxKind.JsxElement: + return emitJsxElement(node); + case SyntaxKind.JsxSelfClosingElement: + return emitJsxSelfClosingElement(node); + case SyntaxKind.JsxOpeningElement: + return emitJsxOpeningElement(node); + case SyntaxKind.JsxText: + return emitJsxText(node); + case SyntaxKind.JsxClosingElement: + return emitJsxClosingElement(node); + case SyntaxKind.JsxAttribute: + return emitJsxAttribute(node); + case SyntaxKind.JsxSpreadAttribute: + return emitJsxSpreadAttribute(node); + case SyntaxKind.JsxExpression: + return emitJsxExpression(node); + + // Clauses + case SyntaxKind.CaseClause: + return emitCaseClause(node); + case SyntaxKind.DefaultClause: + return emitDefaultClause(node); + case SyntaxKind.HeritageClause: + return emitHeritageClause(node); + case SyntaxKind.CatchClause: + return emitCatchClause(node); + + // Property assignments + case SyntaxKind.PropertyAssignment: + return emitPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignment(node); + + // Enum + case SyntaxKind.EnumMember: + return emitEnumMember(node); + + // Top-level nodes + case SyntaxKind.SourceFile: + return emitSourceFile(node); + + // JSDoc nodes (ignored) + // Raw nodes (deprecated) + } + } + + // + // Literals/Pseudo-literals + // + + // SyntaxKind.NumericLiteral + // SyntaxKind.StringLiteral + // SyntaxKind.RegularExpressionLiteral + // SyntaxKind.NoSubstitutionTemplateLiteral + // SyntaxKind.TemplateHead + // SyntaxKind.TemplateMiddle + // SyntaxKind.TemplateTail + function emitLiteral(node: LiteralExpression) { + let text = getLiteralText(node, currentSourceFile, languageVersion); + if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) + && (isStringLiteral(node) || isTemplateLiteralKind(node.kind))) { + writer.writeLiteral(text); + } + else { + write(text); + } + } + + // + // Identifiers + // + + function emitIdentifier(node: Identifier) { + if (isExpressionIdentifier(node)) { + emitExpressionIdentifier(node); + } + else if (tryEmitSubstitute(node, bindingIdentifierSubstitution)) { + return; + } + else if (nodeIsSynthesized(node)) { + write(node.text); + } + else { + writeTextOfNode(currentSourceFile, node); + } + } + + function isExpressionIdentifier(node: Node): boolean { + switch (parentNode.kind) { + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.BinaryExpression: + case SyntaxKind.CallExpression: + case SyntaxKind.CaseClause: + case SyntaxKind.ComputedPropertyName: + case SyntaxKind.ConditionalExpression: + case SyntaxKind.Decorator: + case SyntaxKind.DeleteExpression: + case SyntaxKind.DoStatement: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.ExportAssignment: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ExpressionWithTypeArguments: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxOpeningElement: + case SyntaxKind.JsxSpreadAttribute: + case SyntaxKind.JsxExpression: + case SyntaxKind.NewExpression: + case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.PostfixUnaryExpression: + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.ReturnStatement: + case SyntaxKind.ShorthandPropertyAssignment: + case SyntaxKind.SpreadElementExpression: + case SyntaxKind.SwitchStatement: + case SyntaxKind.TaggedTemplateExpression: + case SyntaxKind.TemplateSpan: + case SyntaxKind.ThrowStatement: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.TypeOfExpression: + case SyntaxKind.VoidExpression: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.YieldExpression: + return true; + case SyntaxKind.BindingElement: + case SyntaxKind.EnumMember: + case SyntaxKind.Parameter: + case SyntaxKind.PropertyAssignment: + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.VariableDeclaration: + return (parentNode).initializer === node; + case SyntaxKind.PropertyAccessExpression: + return (parentNode).expression === node; + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionExpression: + return (parentNode).body === node; + case SyntaxKind.ImportEqualsDeclaration: + return (parentNode).moduleReference === node; + case SyntaxKind.QualifiedName: + return (parentNode).left === node; + } + return false; + } + + function emitExpressionIdentifier(node: Identifier) { + if (tryEmitSubstitute(node, expressionIdentifierSubstitution)) { + return; + } + else if (nodeIsSynthesized(node)) { + write(node.text); + } + else { + writeTextOfNode(currentSourceFile, node); + } + } + + // + // Names + // + + function emitQualifiedName(node: QualifiedName) { + emit(node.left); + write("."); + emit(node.right); + } + + function emitComputedPropertyName(node: ComputedPropertyName) { + write("["); + emit(node.expression); + write("]"); + } + + // + // Signature elements + // + + function emitTypeParameter(node: TypeParameterDeclaration) { + emitStart(node); + emit(node.name); + emitWithPrefix("extends ", node.constraint); + emitEnd(node); + } + + function emitParameter(node: ParameterDeclaration) { + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + writeIfPresent(node.dotDotDotToken, "..."); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitWithPrefix(" = ", node.initializer); + emitWithPrefix(": ", node.type); + emitEnd(node); + } + + function emitDecorator(decorator: Decorator) { + emitLeadingComments(decorator); + emitStart(decorator); + write("@"); + emit(decorator.expression); + emitEnd(decorator); + emitTrailingComments(decorator); + } + + // + // Type members + // + + function emitPropertySignature(node: PropertySignature) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitWithPrefix(": ", node.type); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitPropertyDeclaration(node: PropertyDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + emit(node.name); + emitWithPrefix(": ", node.type); + emitWithPrefix(" = ", node.initializer); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitMethodSignature(node: MethodSignature) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.parameters, ListFormat.Parameters); + emitWithPrefix(": ", node.type); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitMethodDeclaration(node: MethodDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + writeIfPresent(node.asteriskToken, "*"); + emit(node.name); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.parameters, ListFormat.Parameters); + emitWithPrefix(": ", node.type); + emit(node.body); + writeIfMissing(node.body, ";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitConstructor(node: ConstructorDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitModifiers(node); + write("constructor"); + emitList(node, node.parameters, ListFormat.Parameters); + emit(node.body); + writeIfMissing(node.body, ";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitAccessorDeclaration(node: AccessorDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); + emit(node.name); + emitList(node, node.parameters, ListFormat.Parameters); + emitWithPrefix(": ", node.type); + emit(node.body); + writeIfMissing(node.body, ";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitCallSignature(node: CallSignatureDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.parameters, ListFormat.Parameters); + emitWithPrefix(": ", node.type); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitConstructSignature(node: ConstructSignatureDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + write("new "); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.parameters, ListFormat.Parameters); + emitWithPrefix(": ", node.type); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitIndexSignature(node: IndexSignatureDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + emitList(node, node.parameters, ListFormat.IndexSignatureParameters); + emitWithPrefix(": ", node.type); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + // + // Types + // + + function emitTypePredicate(node: TypePredicateNode) { + emitStart(node); + emit(node.parameterName); + write(" is "); + emit(node.type); + emitEnd(node); + } + + function emitTypeReference(node: TypeReferenceNode) { + emitStart(node); + emit(node.typeName); + emitList(node, node.typeArguments, ListFormat.TypeArguments); + emitEnd(node); + } + + function emitFunctionType(node: FunctionTypeNode) { + emitStart(node); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.parameters, ListFormat.ArrowParameters); + write(" => "); + emit(node.type); + emitEnd(node); + } + + function emitConstructorType(node: ConstructorTypeNode) { + emitStart(node); + write("new "); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.parameters, ListFormat.ArrowParameters); + write(" => "); + emit(node.type); + emitEnd(node); + } + + function emitTypeQuery(node: TypeQueryNode) { + emitStart(node); + write("typeof "); + emit(node.exprName); + emitEnd(node); + } + + function emitTypeLiteral(node: TypeLiteralNode) { + emitStart(node); + emitList(node, node.members, ListFormat.TypeElements); + emitEnd(node); + } + + function emitArrayType(node: ArrayTypeNode) { + emitStart(node); + emit(node.elementType); + write("[]"); + emitEnd(node); + } + + function emitTupleType(node: TupleTypeNode) { + emitStart(node); + emitList(node, node.elementTypes, ListFormat.TupleTypeElementTypes); + emitEnd(node); + } + + function emitUnionType(node: UnionTypeNode) { + emitStart(node); + emitList(node, node.types, ListFormat.UnionTypeConstituents) + emitEnd(node); + } + + function emitIntersectionType(node: IntersectionTypeNode) { + emitStart(node); + emitList(node, node.types, ListFormat.IntersectionTypeConstituents); + emitEnd(node); + } + + function emitParenthesizedType(node: ParenthesizedTypeNode) { + write("("); + emit(node.type); + write(")"); + } + + // + // Binding patterns + // + + function emitObjectBindingPattern(node: ObjectBindingPattern) { + emitList(node, node.elements, ListFormat.ObjectBindingPatternElements); + } + + function emitArrayBindingPattern(node: ArrayBindingPattern) { + emitList(node, node.elements, ListFormat.ArrayBindingPatternElements); + } + + function emitBindingElement(node: BindingElement) { + emitWithSuffix(node.propertyName, ": "); + writeIfPresent(node.dotDotDotToken, "..."); + emit(node.name); + emitWithPrefix(" = ", node.initializer); + } + + // + // Expressions + // + + function emitArrayLiteralExpression(node: ArrayLiteralExpression) { + emitList(node, node.elements, ListFormat.ArrayLiteralExpressionElements); + } + + function emitObjectLiteralExpression(node: ObjectLiteralExpression) { + emitList(node, node.properties, languageVersion < ScriptTarget.ES5 + ? ListFormat.ObjectLiteralExpressionProperties + : ListFormat.ObjectLiteralExpressionPropertiesForES5AndLater); + } + + 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 = getLiteralText(expression, currentSourceFile, languageVersion); + 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); + emitList(node, node.arguments, ListFormat.CallExpressionArguments); + } + + function emitNewExpression(node: NewExpression) { + write("new "); + emit(node.expression); + emitList(node, node.arguments, ListFormat.NewExpressionArguments); + } + + function emitTaggedTemplateExpression(node: TaggedTemplateExpression) { + emit(node.tag); + emit(node.template); + } + + function emitTypeAssertionExpression(node: TypeAssertion) { + write("<"); + emit(node.type); + write(">"); + emit(node.expression); + } + + function emitParenthesizedExpression(node: ParenthesizedExpression) { + write("("); + emit(node.expression); + write(")"); + } + + function emitFunctionExpression(node: FunctionExpression) { + emitFunctionDeclarationOrExpression(node); + } + + function emitArrowFunction(node: ArrowFunction) { + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.parameters, ListFormat.ArrowParameters); + emitWithPrefix(": ", node.type); + emit(node.body); + emitEnd(node); + } + + 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 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 emitBinaryExpression(node: BinaryExpression) { + // Allow transformers to substitute assignments to handle exports. + if (isAssignmentOperator(node.kind) && tryEmitSubstitute(node, assignmentSubstitution)) { + return; + } + + 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 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 emitTemplateExpression(node: TemplateExpression) { + emit(node.head); + emitList(node, node.templateSpans, ListFormat.TemplateExpressionTemplateSpans); + } + + function emitYieldExpression(node: YieldExpression) { + write(node.asteriskToken ? "yield*" : "yield"); + emitWithPrefix(" ", node.expression); + } + + function emitSpreadElementExpression(node: SpreadElementExpression) { + write("..."); + emit(node.expression); + } + + function emitClassExpression(node: ClassExpression) { + emitClassDeclarationOrExpression(node); + } + + function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) { + emitStart(node); + emit(node.expression); + emitList(node, node.typeArguments, ListFormat.TypeArguments); + emitEnd(node); + } + + function emitAsExpression(node: AsExpression) { + emit(node.expression); + write(" as "); + emit(node.type); + } + + // + // Misc + // + + function emitTemplateSpan(node: TemplateSpan) { + emit(node.expression); + emit(node.literal); + } + + // + // Statements + // + + function emitBlock(node: Block) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.statements, ListFormat.BlockStatements); + emitEnd(node); + emitTrailingComments(node); + } + + function emitVariableStatement(node: VariableStatement) { + emitLeadingComments(node); + emitStart(node); + emitModifiers(node); + emit(node.declarationList); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitExpressionStatement(node: ExpressionStatement) { + emit(node.expression); + write(";"); + } + + 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(";"); + emitWithPrefix(" ", node.condition); + write(";"); + emitWithPrefix(" ", 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 emitContinueStatement(node: ContinueStatement) { + write("continue"); + emitWithPrefix(" ", node.label); + write(";"); + } + + function emitBreakStatement(node: BreakStatement) { + write("break"); + emitWithPrefix(" ", node.label); + write(";"); + } + + function emitReturnStatement(node: ReturnStatement) { + write("return"); + emitWithPrefix(" ", node.expression); + write(";"); + } + + function emitWithStatement(node: WithStatement) { + write("with ("); + emit(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitSwitchStatement(node: SwitchStatement) { + write("switch ("); + emit(node.expression); + write(") "); + emit(node.caseBlock); + } + + function emitLabeledStatement(node: LabeledStatement) { + emit(node.label); + write(":"); + emitEmbeddedStatement(node.statement); + } + + function emitThrowStatement(node: ThrowStatement) { + write("throw"); + emitWithPrefix(" ", node.expression); + write(";"); + } + + function emitTryStatement(node: TryStatement) { + write("try "); + emit(node.tryBlock); + emit(node.catchClause); + if (node.finallyBlock) { + writeLine(); + write("finally "); + emit(node.finallyBlock); + } + } + + function emitDebuggerStatement(node: DebuggerStatement) { + write("debugger;"); + } + + // + // Declarations + // + + function emitVariableDeclaration(node: VariableDeclaration) { + emit(node.name); + emitWithPrefix(" = ", node.initializer); + } + + function emitVariableDeclarationList(node: VariableDeclarationList) { + write(isLet(node) ? "let " : isConst(node) ? "const " : "var "); + emitList(node, node.declarations, ListFormat.VariableDeclarations); + } + + function emitFunctionDeclaration(node: FunctionDeclaration) { + emitFunctionDeclarationOrExpression(node); + } + + function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + write(node.asteriskToken ? "function*" : "function"); + emitWithPrefix(" ", node.name); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.parameters, ListFormat.Parameters); + emitWithPrefix(": ", node.type); + emitWithPrefix(" ", node.body); + writeIfMissing(node.body, ";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitClassDeclaration(node: ClassDeclaration) { + emitClassDeclarationOrExpression(node); + } + + function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + write("class"); + emitWithPrefix(" ", node.name); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.heritageClauses, ListFormat.HeritageClauses); + write(" "); + emitList(node, node.members, ListFormat.ClassMembers); + emitEnd(node); + emitTrailingComments(node); + } + + function emitInterfaceDeclaration(node: InterfaceDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + write("interface "); + emit(node.name); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + emitList(node, node.heritageClauses, ListFormat.HeritageClauses); + write(" "); + emitList(node, node.members, ListFormat.TypeElements); + emitEnd(node); + emitTrailingComments(node); + } + + function emitTypeAliasDeclaration(node: TypeAliasDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitList(node, node.decorators, ListFormat.Decorators); + emitModifiers(node); + write("type "); + emit(node.name); + emitList(node, node.typeParameters, ListFormat.TypeParameters); + write(" = "); + emit(node.type); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitEnumDeclaration(node: EnumDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitModifiers(node); + write("enum "); + emit(node.name); + write(" "); + emitList(node, node.members, ListFormat.EnumMembers); + emitEnd(node); + emitTrailingComments(node); + } + + function emitModuleDeclaration(node: ModuleDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitModifiers(node); + write(node.flags & NodeFlags.Namespace ? "namespace " : "module "); + emit(node.name); + + let body = node.body; + while (isModuleDeclaration(body)) { + write("."); + emit((body).name); + body = (body).body; + } + + write(" "); + emit(body); + emitEnd(node); + emitTrailingComments(node); + } + + function emitModuleBlock(node: ModuleBlock) { + emitList(node, node.statements, ListFormat.ModuleBlockStatements); + } + + function emitCaseBlock(node: CaseBlock) { + emitList(node, node.clauses, ListFormat.CaseBlockClauses); + } + + function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitModifiers(node); + write("import "); + emit(node.name); + write(" = "); + emit(node.moduleReference); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + function emitImportDeclaration(node: ImportDeclaration) { + emitLeadingComments(node); + emitStart(node); + emitModifiers(node); + 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 emitNamedImports(node: NamedImports) { + emitNamedImportsOrExports(node); + } + + function emitImportSpecifier(node: ImportSpecifier) { + emitImportOrExportSpecifier(node); + } + + function emitExportAssignment(node: ExportAssignment) { + emitLeadingComments(node); + emitStart(node); + write(node.isExportEquals ? "export = " : "export default "); + emit(node.expression); + write(";"); + emitEnd(node); + emitTrailingComments(node); + } + + 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 emitNamedExports(node: NamedExports) { + emitNamedImportsOrExports(node); + } + + function emitExportSpecifier(node: ExportSpecifier) { + emitImportOrExportSpecifier(node); + } + + function emitNamedImportsOrExports(node: NamedImportsOrExports) { + emitStart(node); + emitList(node, node.elements, ListFormat.ImportOrExportSpecifiers); + emitEnd(node); + } + + function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) { + emitLeadingComments(node); + emitStart(node); + if (node.propertyName) { + emit(node.propertyName); + write(" as "); + } + + emit(node.name); + emitEnd(node); + emitTrailingComments(node); + } + + // + // Module references + // + + function emitExternalModuleReference(node: ExternalModuleReference) { + write("require("); + emit(node.expression); + write(")"); + } + + // + // JSX + // + + function emitJsxElement(node: JsxElement) { + emit(node.openingElement); + emitList(node, node.children, ListFormat.JsxElementChildren); + emit(node.closingElement); + } + + function emitJsxSelfClosingElement(node: JsxSelfClosingElement) { + write("<"); + emit(node.tagName); + write(" "); + emitList(node, node.attributes, ListFormat.JsxAttributes); + write("/>"); + } + + function emitJsxOpeningElement(node: JsxOpeningElement) { + write("<"); + emit(node.tagName); + writeIfAny(node.attributes, " "); + emitList(node, node.attributes, ListFormat.JsxAttributes); + write(">"); + } + + function emitJsxText(node: JsxText) { + writer.writeLiteral(getTextOfNode(node, /*includeTrivia*/ true)); + } + + function emitJsxClosingElement(node: JsxClosingElement) { + write(""); + } + + function emitJsxAttribute(node: JsxAttribute) { + emit(node.name); + emitWithPrefix("=", node.initializer); + } + + function emitJsxSpreadAttribute(node: JsxSpreadAttribute) { + write("{..."); + emit(node.expression); + write("}"); + } + + function emitJsxExpression(node: JsxExpression) { + write("{"); + emit(node.expression); + write("}"); + } + + // + // Clauses + // + + function emitCaseClause(node: CaseClause) { + write("case "); + emit(node.expression); + write(":"); + emitList(node, node.statements, ListFormat.CaseOrDefaultClauseStatements); + } + + function emitDefaultClause(node: DefaultClause) { + write("default:"); + emitList(node, node.statements, ListFormat.CaseOrDefaultClauseStatements); + } + + function emitHeritageClause(node: HeritageClause) { + emitStart(node); + writeToken(node.token); + write(" "); + emitList(node, node.types, ListFormat.HeritageClauseTypes); + emitEnd(node); + } + + function emitCatchClause(node: CatchClause) { + writeLine(); + write("catch ("); + emit(node.variableDeclaration); + write(") "); + emit(node.block); + } + + // + // Property assignments + // + + 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); + } + + // + // Enum + // + + function emitEnumMember(node: EnumMember) { + emitLeadingComments(node); + emitStart(node); + emit(node.name); + emitWithPrefix(" = ", node.initializer); + emitEnd(node); + emitTrailingComments(node); + } + + // + // Top-level nodes + // + + function emitSourceFile(node: SourceFile) { + currentSourceFile = node; + assignmentSubstitution = transformationResolver.getAssignmentSubstitution(currentSourceFile); + bindingIdentifierSubstitution = transformationResolver.getBindingIdentifierSubstitution(currentSourceFile); + expressionIdentifierSubstitution = transformationResolver.getExpressionIdentifierSubstitution(currentSourceFile); + + writeLine(); + emitShebang(); + emitDetachedComments(node); + emitList(node, node.statements, ListFormat.SourceFileStatements); + + currentSourceFile = undefined; + assignmentSubstitution = undefined; + bindingIdentifierSubstitution = undefined; + expressionIdentifierSubstitution = undefined; + } + + // + // Helpers + // + + function emitShebang() { + let shebang = getShebang(currentSourceFile.text); + if (shebang) { + write(shebang); + } + } + + function emitModifiers(node: Node) { + 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 emitWithPrefix(prefix: string, node: Node) { + if (node) { + write(prefix); + emit(node); + } + } + + function emitWithSuffix(node: Node, suffix: string) { + if (node) { + emit(node); + write(suffix); + } + } + + 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 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 && format & ListFormat.Optional) { + return; + } + + let containingRange: TextRange = format & ListFormat.Fragment ? children : parentNode; + + // Shortcut for an empty list. + if (!children || children.length === 0) { + // If the list is bracketed, emit the brackets and any interceeding whitespace. + if (format & ListFormat.BracketsMask) { + write(getBracket(format, ListFormat.LeadingBracketOffset)); + if (containingRange && !positionsAreOnSameLine(containingRange.pos, containingRange.end)) { + writeLine(); + } + else if (format & ListFormat.Whitespace) { + write(" "); + } + write(getBracket(format, ListFormat.TrailingBracketOffset)); + } + return; + } + + let previousSibling: Node; + let firstChild = firstOrUndefined(children); + let lastChild = lastOrUndefined(children); + + // Shortcut for a simple arrow function. + if (format & ListFormat.Arrow && + children.length === 1 && + isParameter(firstChild) && + firstChild.type === undefined && + firstChild.pos === parentNode.pos) { + emit(firstChild); + return; + } + + // Write the leading bracket. + write(getBracket(format, ListFormat.LeadingBracketOffset)); + + // Start the new scope, if requested. + if (format & ListFormat.Scoped) { + scopeEmitStart(parentNode); + } + + // Write the opening line terminator or leading whitespace. + if (shouldWriteLeadingLineTerminator(containingRange, firstChild, format)) { + writeLine(); + } + else if (format & ListFormat.LeadingWhitespace) { + write(" "); + } + + // Increase the indent, if requested. + if (format & ListFormat.Indented) { + increaseIndent(); + } + + // Emit each child. + let delimiter = getDelimiter(format); + for (let child of children) { + // Write the delimiter if this is not the first node. + if (previousSibling) { + write(delimiter); + + // Write either a line terminator or whitespace to separate the elements. + if (shouldWriteSeparatingLineTerminator(previousSibling, child, format)) { + writeLine(); + } + else if (previousSibling) { + write(" "); + } + } + + // Emit this child. + emit(child); + previousSibling = child; + } + + // Write a trailing comma, if requested. + let hasTrailingComma = (format & ListFormat.AllowTrailingComma) && children.hasTrailingComma; + if (format & ListFormat.CommaDelimited && hasTrailingComma) { + write(","); + } + + // Decrease the indent, if requested. + if (format & ListFormat.Indented) { + decreaseIndent(); + } + + // Write the closing line terminator or closing whitespace. + if (shouldWriteClosingLineTerminator(containingRange, lastChild, format)) { + writeLine(); + } + else if (format & ListFormat.TrailingWhitespace && (previousSibling || hasTrailingComma)) { + write(" "); + } + + // End the scope, if requested. + if (format & ListFormat.Scoped) { + scopeEmitEnd(); + } + + // Write the trailing bracket. + write(getBracket(format, ListFormat.TrailingBracketOffset)); + } + + function writeIfAny(nodes: NodeArray, text: string) { + if (nodes && nodes.length > 0) { + write(text); + } + } + + function writeIfPresent(node: Node, text: string) { + if (node !== undefined) { + write(text); + } + } + + function writeIfMissing(node: Node, text: string) { + if (node === undefined) { + write(text); + } + } + + function writeToken(token: SyntaxKind) { + write(tokenToString(token)); + } + + function writeTokenNode(node: Node) { + if (node) { + writeToken(node.kind); + } + } + + 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 shouldWriteLeadingLineTerminator(containingRange: TextRange, firstChild: Node, format?: ListFormat) { + if (containingRange === undefined) { + return false; + } + else if (firstChild === undefined) { + return !positionsAreOnSameLine(getStartPos(containingRange), getEndPos(containingRange)); + } + else if (positionIsSynthesized(containingRange.pos)) { + return format & ListFormat.PreferNewLine ? true : synthesizedNodeStartsOnNewLine(firstChild); + } + else if (nodeIsSynthesized(firstChild)) { + return format & ListFormat.PreferNewLine ? true : (firstChild).startsOnNewLine; + } + else { + return !rangeStartPositionsAreOnSameLine(containingRange, firstChild); + } + } + + function shouldWriteSeparatingLineTerminator(previousNode: Node, nextNode: Node, format?: ListFormat) { + if (previousNode === undefined || nextNode === undefined) { + return false; + } + else if (nodeIsSynthesized(previousNode) || nodeIsSynthesized(nextNode)) { + return format & ListFormat.PreferNewLine ? true : synthesizedNodeStartsOnNewLine(previousNode) || synthesizedNodeStartsOnNewLine(nextNode); + } + else { + return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode); + } + } + + function shouldWriteClosingLineTerminator(containingRange: TextRange, lastChild: Node, format?: ListFormat) { + if (lastChild === undefined) { + return false; + } + else if (positionIsSynthesized(containingRange.pos)) { + return format & ListFormat.PreferNewLine ? true : synthesizedNodeStartsOnNewLine(lastChild); + } + else if (nodeIsSynthesized(lastChild)) { + return format & ListFormat.PreferNewLine ? true : (lastChild).startsOnNewLine; + } + else { + return !rangeEndPositionsAreOnSameLine(containingRange, lastChild); + } + } + + function synthesizedNodeStartsOnNewLine(node: Node) { + return nodeIsSynthesized(node) && (node).startsOnNewLine; + } + + function rangeStartPositionsAreOnSameLine(range1: TextRange, range2: TextRange) { + return positionsAreOnSameLine(getStartPos(range1), getStartPos(range2)); + } + + function rangeEndPositionsAreOnSameLine(range1: TextRange, range2: TextRange) { + return positionsAreOnSameLine(getEndPos(range1), getEndPos(range2)); + } + + function rangeEndIsOnSameLineAsRangeStart(range1: TextRange, range2: TextRange) { + return positionsAreOnSameLine(getEndPos(range1), getStartPos(range2)); + } + + function positionsAreOnSameLine(pos1: number, pos2: number) { + return pos1 === pos2 || + getLineOfLocalPosition(currentSourceFile, pos1) === getLineOfLocalPosition(currentSourceFile, pos2); + } + + function getStartPos(range: TextRange) { + return skipTrivia(currentSourceFile.text, range.pos); + } + + function getEndPos(range: TextRange) { + return range.end; + } + + function needsIndentation(parent: Node, node1: Node, node2: Node): boolean { + // Always use a newline for synthesized code if the synthesizer desires it. + if (synthesizedNodeStartsOnNewLine(node2)) { + return true; + } + + return !nodeIsSynthesized(parent) + && !nodeIsSynthesized(node1) + && !nodeIsSynthesized(node2) + && !rangeEndIsOnSameLineAsRangeStart(node1, node2); + } + + function getTextOfNode(node: Node, includeTrivia?: boolean) { + if (nodeIsSynthesized(node) && (isLiteralExpression(node) || isIdentifier(node))) { + return node.text; + } + + return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia); + } + + function tryGetConstEnumValue(node: Node): number { + if (compilerOptions.isolatedModules) { + return undefined; + } + + return isPropertyAccessExpression(node) || isElementAccessExpression(node) + ? resolver.getConstantValue(node) + : undefined; + } + } + + function createDelimiterMap() { + let delimiters: string[] = []; + delimiters[ListFormat.None] = ""; + delimiters[ListFormat.CommaDelimited] = ","; + delimiters[ListFormat.BarDelimited] = " |"; + delimiters[ListFormat.AmpersandDelimited] = " &"; + return delimiters; + } + + function getDelimiter(format: ListFormat) { + return delimiters[format & ListFormat.DelimitersMask]; + } + + function createBracketsMap() { + let brackets: string[] = []; + brackets[ListFormat.None] = ""; + brackets[ListFormat.Parentheses << ListFormat.LeadingBracketOffset] = "("; + brackets[ListFormat.Parentheses << ListFormat.TrailingBracketOffset] = ")"; + brackets[ListFormat.SquareBrackets << ListFormat.LeadingBracketOffset] = "["; + brackets[ListFormat.SquareBrackets << ListFormat.TrailingBracketOffset] = "]"; + brackets[ListFormat.CurlyBrackets << ListFormat.LeadingBracketOffset] = "{"; + brackets[ListFormat.CurlyBrackets << ListFormat.TrailingBracketOffset] = "}"; + brackets[ListFormat.AngleBrackets << ListFormat.LeadingBracketOffset] = "<"; + brackets[ListFormat.AngleBrackets << ListFormat.TrailingBracketOffset] = ">"; + return brackets; + } + + function getBracket(format: ListFormat, offset: number) { + return brackets[(format & ListFormat.BracketsMask) << offset]; + } + + const enum ListFormat { + None = 0, + + // Brackets + Parentheses = 1 << 0, // The list is surrounded with parentheses ("(", ")"). + SquareBrackets = 1 << 1, // The list is surrounded with brackets ("[", "]"). + CurlyBrackets = 1 << 2, // The list is surrounded with braces ("{", "}"). + AngleBrackets = 1 << 3, // The list is surrounded with angle-brackets ("<", ">"). + + LeadingBracketOffset = 0, // Left-shift offset for a leading bracket. + TrailingBracketOffset = 4, // Left-shift offset for a trailing bracket. + BracketsMask = Parentheses | SquareBrackets | CurlyBrackets | AngleBrackets, + + // Delimiters + BarDelimited = 1 << 4, // Each list item is space-and-bar (" |") delimited. + AmpersandDelimited = 1 << 5, // Each list item is space-and-ampersand (" &") delimited. + CommaDelimited = 1 << 6, // Each list item is comma (",") delimited. + AllowTrailingComma = 1 << 7, // Write a trailing comma (",") if present. + DelimitersMask = BarDelimited | AmpersandDelimited | CommaDelimited, + + // Whitespace + Indented = 1 << 8, // The list should be indented. + LeadingWhitespace = 1 << 9, // Write a leading space (" ") before the first element if not indented. + TrailingWhitespace = 1 << 10, // Write a trailing space (" ") after the last element if not indented. + Whitespace = LeadingWhitespace | TrailingWhitespace, + + // Other + Optional = 1 << 11, // Skip writing brackets (if any) for an empty or missing list. + Scoped = 1 << 12, // The list starts a new scope (for Source Maps). + Arrow = 1 << 13, // The list is a parameter list for an arrow function. + Fragment = 1 << 14, // The list is a fragment of the node. Line terminators should be based on the node array positions. + PreferNewLine = 1 << 15, // Prefer adding LineTerminators between synthesized nodes. + + // List formats + Decorators = Indented | TrailingWhitespace | Fragment, + TypeParameters = AngleBrackets | CommaDelimited | Indented | Optional | Fragment, + Parameters = Parentheses | CommaDelimited | Indented | Fragment, + ArrowParameters = Parameters | Arrow, + IndexSignatureParameters = SquareBrackets | CommaDelimited | Indented | Fragment, + TypeArguments = AngleBrackets | CommaDelimited | Indented | Optional | Fragment, + TypeElements = CurlyBrackets | Indented | Whitespace | PreferNewLine, + TupleTypeElementTypes = SquareBrackets | CommaDelimited | Indented, + UnionTypeConstituents = BarDelimited | Indented, + IntersectionTypeConstituents = AmpersandDelimited | Indented, + ObjectBindingPatternElements = CurlyBrackets | CommaDelimited | AllowTrailingComma | Indented | LeadingWhitespace | TrailingWhitespace | PreferNewLine, + ArrayBindingPatternElements = SquareBrackets | CommaDelimited | AllowTrailingComma | Indented, + ArrayLiteralExpressionElements = SquareBrackets | CommaDelimited | AllowTrailingComma | Indented, + ObjectLiteralExpressionProperties = CurlyBrackets | CommaDelimited | Indented | LeadingWhitespace | TrailingWhitespace | PreferNewLine, + ObjectLiteralExpressionPropertiesForES5AndLater = ObjectLiteralExpressionProperties | AllowTrailingComma, + CallExpressionArguments = Parentheses | CommaDelimited | Indented | Fragment, + NewExpressionArguments = Parentheses | CommaDelimited | Indented | Optional | Fragment, + TemplateExpressionTemplateSpans = Fragment, + BlockStatements = CurlyBrackets | Indented | Whitespace | Scoped | PreferNewLine, + VariableDeclarations = CommaDelimited | Indented, + HeritageClauses = Indented | LeadingWhitespace | Fragment, + ClassMembers = CurlyBrackets | Indented | Whitespace | Scoped | PreferNewLine, + EnumMembers = CurlyBrackets | CommaDelimited | AllowTrailingComma | Indented | Scoped | Whitespace | PreferNewLine, + ModuleBlockStatements = CurlyBrackets | Indented | Whitespace | Scoped | PreferNewLine, + CaseBlockClauses = CurlyBrackets | Indented | Whitespace | Scoped | PreferNewLine, + ImportOrExportSpecifiers = CurlyBrackets | CommaDelimited | AllowTrailingComma | Indented | Whitespace, + CaseOrDefaultClauseStatements = Indented | Whitespace | PreferNewLine, + JsxElementChildren = PreferNewLine, + JsxAttributes = Fragment, + HeritageClauseTypes = CommaDelimited | Indented, + SourceFileStatements = PreferNewLine, } } \ No newline at end of file diff --git a/src/compiler/transform.ts b/src/compiler/transform.ts index 29a3e5f797f..371b38c5846 100644 --- a/src/compiler/transform.ts +++ b/src/compiler/transform.ts @@ -33,31 +33,31 @@ namespace ts { // Add the TypeScript and Module transforms to the chain. transforms.push(transformTypeScript); - // transforms.push(transformModule); + // // transforms.push(transformModule); - // Add the JSX transform to the chain. - if (jsx === JsxEmit.React) { - transforms.push(transformJsx); - } + // // Add the JSX transform to the chain. + // if (jsx === JsxEmit.React) { + // transforms.push(transformJsx); + // } - // Add the ES6 transform to the chain. - if (languageVersion < ScriptTarget.ES6) { - transforms.push(transformES6); - } + // // Add the ES6 transform to the chain. + // if (languageVersion < ScriptTarget.ES6) { + // transforms.push(transformES6); + // } return chainTransformations(transforms); } - export function transformFilesIfNeeded(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformationChain: TransformationChain) { + export function transformFilesIfNeeded(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformationChain: TransformationChain): TransformationResult { let compilerOptions = host.getCompilerOptions(); if (compilerOptions.experimentalTransforms) { return transformFiles(resolver, host, sourceFiles, transformationChain); } - return sourceFiles; + return { sourceFiles }; } - export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformationChain: TransformationChain) { + export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformationChain: TransformationChain): TransformationResult { // emit output for the __extends helper function const extendsHelper = ` var __extends = (this && this.__extends) || function (d, b) { @@ -114,8 +114,8 @@ function __export(m) { let transformFlags: TransformFlags; let generatedNameSet: Map; let tempVariableNameSet: Map; - let nodeToGeneratedName: string[]; - let nodeToGeneratedIdentifier: Identifier[]; + let nodeToGeneratedName: string[] = []; + let nodeToGeneratedIdentifier: Identifier[] = []; let lexicalEnvironmentStackSize: number; let lexicalEnvironmentStack: LexicalEnvironment[] = []; let tempFlags: TempFlags; @@ -131,6 +131,9 @@ function __export(m) { let updatedNode: Node; let updatedNodes: Node[]; let helpersEmitted: NodeCheckFlags; + let assignmentSubstitutions: ((node: BinaryExpression) => Expression)[] = []; + let bindingIdentifierSubstitutions: ((node: Identifier) => Identifier)[] = []; + let expressionIdentifierSubstitutions: ((node: Identifier) => LeftHandSideExpression)[] = []; let transformer: Transformer = { getEmitResolver: () => resolver, getCompilerOptions: () => compilerOptions, @@ -154,6 +157,12 @@ function __export(m) { hoistFunctionDeclaration, emitEmitHelpers, emitExportStarHelper, + getAssignmentSubstitution, + setAssignmentSubstitution, + getBindingIdentifierSubstitution, + setBindingIdentifierSubstitution, + getExpressionIdentifierSubstitution, + setExpressionIdentifierSubstitution, startLexicalEnvironment, endLexicalEnvironment, pipeNode, @@ -173,7 +182,14 @@ function __export(m) { } }; - return map(sourceFiles, transformSourceFile); + return { + sourceFiles: map(sourceFiles, transformSourceFile), + transformationResolver: { + getAssignmentSubstitution, + getBindingIdentifierSubstitution, + getExpressionIdentifierSubstitution, + } + }; function transformSourceFile(sourceFile: SourceFile) { if (isDeclarationFile(sourceFile)) { @@ -183,8 +199,6 @@ function __export(m) { currentSourceFile = sourceFile; generatedNameSet = {}; tempVariableNameSet = {}; - nodeToGeneratedName = []; - nodeToGeneratedIdentifier = []; lexicalEnvironmentStackSize = 0; nodeStack = createNodeStack(); helpersEmitted = undefined; @@ -198,8 +212,6 @@ function __export(m) { currentSourceFile = undefined; generatedNameSet = undefined; tempVariableNameSet = undefined; - nodeToGeneratedName = undefined; - nodeToGeneratedIdentifier = undefined; lexicalEnvironmentStackSize = undefined; nodeStack = undefined; helpersEmitted = undefined; @@ -207,6 +219,34 @@ function __export(m) { return visited; } + function getAssignmentSubstitution(sourceFile: SourceFile): (node: BinaryExpression) => Expression { + return assignmentSubstitutions[getNodeId(getOriginalNode(sourceFile))] || identitySubstitution; + } + + function setAssignmentSubstitution(sourceFile: SourceFile, substitution: (node: BinaryExpression) => Expression) { + assignmentSubstitutions[getNodeId(getOriginalNode(sourceFile))] = substitution; + } + + function getBindingIdentifierSubstitution(sourceFile: SourceFile): (node: Identifier) => Identifier { + return bindingIdentifierSubstitutions[getNodeId(getOriginalNode(sourceFile))] || identitySubstitution; + } + + function setBindingIdentifierSubstitution(sourceFile: SourceFile, substitution: (node: Identifier) => Identifier): void { + bindingIdentifierSubstitutions[getNodeId(getOriginalNode(sourceFile))] = substitution; + } + + function getExpressionIdentifierSubstitution(sourceFile: SourceFile): (node: Identifier) => LeftHandSideExpression { + return expressionIdentifierSubstitutions[getNodeId(getOriginalNode(sourceFile))] || identitySubstitution; + } + + function setExpressionIdentifierSubstitution(sourceFile: SourceFile, substitution: (node: Identifier) => LeftHandSideExpression) { + expressionIdentifierSubstitutions[getNodeId(getOriginalNode(sourceFile))] = substitution; + } + + function identitySubstitution(node: T): T { + return node; + } + // 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. diff --git a/src/compiler/transforms/ts.ts b/src/compiler/transforms/ts.ts index 65051767b87..7fb264f4047 100644 --- a/src/compiler/transforms/ts.ts +++ b/src/compiler/transforms/ts.ts @@ -46,6 +46,8 @@ namespace ts { let exportSpecifiers: Map; let exportEquals: ExportAssignment; let exportFunctionForFile: string; + let savedSubstituteExpressionIdentifier = transformer.getExpressionIdentifierSubstitution(node); + transformer.setExpressionIdentifierSubstitution(node, substituteExpressionIdentifier); // Mark that we are about to visit a new lexical environment. return visitSourceFile(node, visitor); @@ -869,21 +871,6 @@ namespace ts { } transformBindingElementToExpressionWithParenthesisIfNeeded(node, write, /*parenthesizeObjectLiteralAssignment*/ true); - - let name = node.name; - if (isBindingPattern(name)) { - let expr = mapNode(name, transformBindingPatternToExpression); - let initializer = visitNode(node.initializer, visitor, isExpressionNode); - let assignExpr = createAssignmentExpression(expr, initializer); - let parenExpr = createParenthesizedExpression(assignExpr); - write(parenExpr); - } - else { - let qualifiedName = getModuleMemberName(name); - let initializer = visitNode(node.initializer, visitor, isExpressionNode); - let assignExpr = createAssignmentExpression(qualifiedName, initializer); - write(assignExpr); - } } /** @@ -1026,6 +1013,15 @@ namespace ts { return !!(resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalModuleMergesWithClass); } + function substituteExpressionIdentifier(node: Identifier): LeftHandSideExpression { + let container = resolver.getReferencedExportContainer(node); + if (isModuleDeclaration(container)) { + return createPropertyAccessExpression2(getGeneratedNameForNode(container), node, node); + } + + return savedSubstituteExpressionIdentifier(node); + } + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration, write: (node: Statement) => void): void { Debug.assert(!isExternalModuleImportEqualsDeclaration(node)); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2bbb0ec066f..982bd3767bf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -507,7 +507,6 @@ namespace ts { // @factoryhidden("jsDocComment", true) // @factoryhidden("nextContainer", true) // @factoryorder("decorators", "modifiers") - // @nofactoryanynodetest export interface Node extends TextRange { kind: SyntaxKind; flags: NodeFlags; @@ -547,7 +546,8 @@ namespace ts { // @kind(SyntaxKind.PrivateKeyword, { create: false, update: false, test: false }) // @kind(SyntaxKind.ProtectedKeyword, { create: false, update: false, test: false }) // @kind(SyntaxKind.StaticKeyword, { create: false, update: false, test: false }) - export type Modifier = Node; + export interface Modifier extends Node { + } // @kind(SyntaxKind.Identifier) export interface Identifier extends PrimaryExpression { @@ -731,10 +731,12 @@ namespace ts { } // @kind(SyntaxKind.ObjectBindingPattern) - export type ObjectBindingPattern = BindingPattern; + export interface ObjectBindingPattern extends BindingPattern { + } // @kind(SyntaxKind.ArrayBindingPattern) - export type ArrayBindingPattern = BindingPattern; + export interface ArrayBindingPattern extends BindingPattern { + } /** * Several node kinds share function-like features such as a signature, @@ -823,14 +825,16 @@ namespace ts { // @factoryhidden("questionToken") // @factoryhidden("asteriskToken") // @factoryorder("decorators", "modifiers", "name", "parameters", "type", "body") - export type GetAccessorDeclaration = AccessorDeclaration; + export interface GetAccessorDeclaration extends AccessorDeclaration { + } // @kind(SyntaxKind.SetAccessor) // @factoryhidden("typeParameters") // @factoryhidden("questionToken") // @factoryhidden("asteriskToken") // @factoryorder("decorators", "modifiers", "name", "parameters", "type", "body") - export type SetAccessorDeclaration = AccessorDeclaration; + export interface SetAccessorDeclaration extends AccessorDeclaration { + } // @kind(SyntaxKind.IndexSignature) // @factoryhidden("typeParameters") @@ -852,13 +856,15 @@ namespace ts { // @factoryhidden("name") // @factoryhidden("decorators") // @factoryhidden("modifiers") - export type FunctionTypeNode = FunctionOrConstructorTypeNode; + export interface FunctionTypeNode extends FunctionOrConstructorTypeNode { + } // @kind(SyntaxKind.ConstructorType) // @factoryhidden("name") // @factoryhidden("decorators") // @factoryhidden("modifiers") - export type ConstructorTypeNode = FunctionOrConstructorTypeNode; + export interface ConstructorTypeNode extends FunctionOrConstructorTypeNode { + } // @kind(SyntaxKind.TypeReference) export interface TypeReferenceNode extends TypeNode { @@ -931,11 +937,10 @@ namespace ts { } // @kind(SyntaxKind.OmittedExpression) - export type OmittedExpression = Expression; + export interface OmittedExpression extends Expression { } // @kind(SyntaxKind.RawExpression) - export interface RawExpression extends LiteralExpression { - } + export interface RawExpression extends LiteralExpression { } export interface UnaryExpression extends Expression { _unaryExpressionBrand: any; @@ -1216,10 +1221,10 @@ namespace ts { } // @kind(SyntaxKind.EmptyStatement) - export type EmptyStatement = Statement; + export interface EmptyStatement extends Statement { } // @kind(SyntaxKind.DebuggerStatement) - export type DebuggerStatement = Statement; + export interface DebuggerStatement extends Statement { } // @kind(SyntaxKind.MissingDeclaration) // @factoryhidden("name", true) @@ -1287,15 +1292,17 @@ namespace ts { expression: Expression; } - export interface BreakOrContinueStatement extends Statement { + // @kind(SyntaxKind.BreakStatement) + export interface BreakStatement extends Statement { label?: Identifier; } - // @kind(SyntaxKind.BreakStatement) - export type BreakStatement = BreakOrContinueStatement; - // @kind(SyntaxKind.ContinueStatement) - export type ContinueStatement = BreakOrContinueStatement; + export interface ContinueStatement extends Statement { + label?: Identifier; + } + + export type BreakOrContinueStatement = BreakStatement | ContinueStatement; // @kind(SyntaxKind.ReturnStatement) export interface ReturnStatement extends Statement { @@ -1492,28 +1499,35 @@ namespace ts { moduleSpecifier?: Expression; } - export interface NamedImportsOrExports extends Node { - elements: NodeArray; + // @kind(SyntaxKind.NamedImports) + export interface NamedImports extends Node { + elements: NodeArray; } - // @kind(SyntaxKind.NamedImports) - export type NamedImports = NamedImportsOrExports; - // @kind(SyntaxKind.NamedExports) - export type NamedExports = NamedImportsOrExports; + export interface NamedExports extends Node { + elements: NodeArray; + } + export type NamedImportsOrExports = NamedImports | NamedExports; + + // @kind(SyntaxKind.ImportSpecifier) // @factoryhidden("decorators", true) // @factoryhidden("modifiers", true) - export interface ImportOrExportSpecifier extends Declaration { + export interface ImportSpecifier extends Declaration { propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) name: Identifier; // Declared name } - // @kind(SyntaxKind.ImportSpecifier) - export type ImportSpecifier = ImportOrExportSpecifier; - // @kind(SyntaxKind.ExportSpecifier) - export type ExportSpecifier = ImportOrExportSpecifier; + // @factoryhidden("decorators", true) + // @factoryhidden("modifiers", true) + export interface ExportSpecifier extends Declaration { + propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) + name: Identifier; // Declared name + } + + export type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier; // @kind(SyntaxKind.ExportAssignment) // @factoryhidden("name", true) @@ -2959,6 +2973,19 @@ namespace ts { write(node: T): void; } + // @internal + export interface TransformationResolver { + getAssignmentSubstitution(sourceFile: SourceFile): (node: BinaryExpression) => Expression; + getExpressionIdentifierSubstitution(sourceFile: SourceFile): (node: Identifier) => LeftHandSideExpression; + getBindingIdentifierSubstitution(sourceFile: SourceFile): (node: Identifier) => Identifier; + } + + // @internal + export interface TransformationResult { + sourceFiles: SourceFile[]; + transformationResolver?: TransformationResolver; + } + // @internal export interface Transformer { getEmitResolver(): EmitResolver; @@ -2988,6 +3015,15 @@ namespace ts { emitEmitHelpers(write: (node: Statement) => void): void; emitExportStarHelper(write: (node: Statement) => void): void; + getAssignmentSubstitution(sourceFile: SourceFile): (node: BinaryExpression) => Expression; + setAssignmentSubstitution(sourceFile: SourceFile, substitution: (node: BinaryExpression) => Expression): void; + + getExpressionIdentifierSubstitution(sourceFile: SourceFile): (node: Identifier) => LeftHandSideExpression; + setExpressionIdentifierSubstitution(sourceFile: SourceFile, substitution: (node: Identifier) => LeftHandSideExpression): void; + + getBindingIdentifierSubstitution(sourceFile: SourceFile): (node: Identifier) => Identifier; + setBindingIdentifierSubstitution(sourceFile: SourceFile, substitution: (node: Identifier) => Identifier): void; + startLexicalEnvironment(): void; endLexicalEnvironment(out: ((node: Statement) => void) | Statement[]): void; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 1d2a45fb7c0..58e39852a7e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1251,7 +1251,11 @@ namespace ts { // 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 (!nodeIsSynthesized(node) && node.parent) { - return getSourceTextOfNodeFromSourceFile(sourceFile, node); + let text = getSourceTextOfNodeFromSourceFile(sourceFile, node); + if (languageVersion < ScriptTarget.ES6 && isBinaryOrOctalIntegerLiteral(node, text)) { + return node.text; + } + return text; } // If we can't reach the original source text, use the canonical form if it's a number, @@ -1274,6 +1278,19 @@ namespace ts { Debug.fail(`Literal kind '${node.kind}' not accounted for.`); } + function isBinaryOrOctalIntegerLiteral(node: LiteralExpression, text: string) { + if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) { + switch (text.charCodeAt(1)) { + case CharacterCodes.b: + case CharacterCodes.B: + case CharacterCodes.o: + case CharacterCodes.O: + return true; + } + } + return false; + } + function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote; }