diff --git a/Jakefile.js b/Jakefile.js
index 3ee8476c842..a23b9cbe03c 100644
--- a/Jakefile.js
+++ b/Jakefile.js
@@ -84,6 +84,7 @@ var compilerSources = [
"sourcemap.ts",
"comments.ts",
"declarationEmitter.ts",
+ "printer.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
@@ -121,6 +122,7 @@ var servicesSources = [
"sourcemap.ts",
"comments.ts",
"declarationEmitter.ts",
+ "printer.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts
index bd9190dbec7..3106d3ccfec 100644
--- a/src/compiler/comments.ts
+++ b/src/compiler/comments.ts
@@ -5,17 +5,13 @@ namespace ts {
export interface CommentWriter {
reset(): void;
setSourceFile(sourceFile: SourceFile): void;
- emitNodeWithComments(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void;
+ emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void): void;
emitTrailingCommentsOfPosition(pos: number): void;
}
- export function createCommentWriter(host: EmitHost, writer: EmitTextWriter, sourceMap: SourceMapWriter): CommentWriter {
- const compilerOptions = host.getCompilerOptions();
+ export function createCommentWriter(writer: EmitTextWriter, compilerOptions: CompilerOptions, newLine: string, emitPos: (pos: number) => void): CommentWriter {
const extendedDiagnostics = compilerOptions.extendedDiagnostics;
- const newLine = host.getNewLine();
- const { emitPos } = sourceMap;
-
let containerPos = -1;
let containerEnd = -1;
let declarationListContainerEnd = -1;
@@ -34,9 +30,9 @@ namespace ts {
emitTrailingCommentsOfPosition,
};
- function emitNodeWithComments(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) {
+ function emitNodeWithComments(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
if (disabled) {
- emitCallback(emitContext, node);
+ emitCallback(hint, node);
return;
}
@@ -47,11 +43,11 @@ namespace ts {
// Both pos and end are synthesized, so just emit the node without comments.
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
- emitCallback(emitContext, node);
+ emitCallback(hint, node);
disabled = false;
}
else {
- emitCallback(emitContext, node);
+ emitCallback(hint, node);
}
}
else {
@@ -94,11 +90,11 @@ namespace ts {
if (emitFlags & EmitFlags.NoNestedComments) {
disabled = true;
- emitCallback(emitContext, node);
+ emitCallback(hint, node);
disabled = false;
}
else {
- emitCallback(emitContext, node);
+ emitCallback(hint, node);
}
if (extendedDiagnostics) {
diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts
index 46df4fed689..4b878adaff5 100644
--- a/src/compiler/declarationEmitter.ts
+++ b/src/compiler/declarationEmitter.ts
@@ -35,13 +35,15 @@ namespace ts {
forEachEmittedFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
return declarationDiagnostics.getDiagnostics(targetSourceFile ? targetSourceFile.fileName : undefined);
- function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sources: SourceFile[], isBundledEmit: boolean) {
- emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit, /*emitOnlyDtsFiles*/ false);
+ function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) {
+ emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sourceFileOrBundle, /*emitOnlyDtsFiles*/ false);
}
}
function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string,
- sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean): DeclarationEmit {
+ sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean): DeclarationEmit {
+ const sourceFiles = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle.sourceFiles : [sourceFileOrBundle];
+ const isBundledEmit = sourceFileOrBundle.kind === SyntaxKind.Bundle;
const newLine = host.getNewLine();
const compilerOptions = host.getCompilerOptions();
@@ -1803,8 +1805,9 @@ namespace ts {
}
return addedBundledEmitReference;
- function getDeclFileName(emitFileNames: EmitFileNames, _sourceFiles: SourceFile[], isBundledEmit: boolean) {
+ function getDeclFileName(emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) {
// Dont add reference path to this file if it is a bundled emit and caller asked not emit bundled file path
+ const isBundledEmit = sourceFileOrBundle.kind === SyntaxKind.Bundle;
if (isBundledEmit && !addBundledFileReference) {
return;
}
@@ -1817,10 +1820,11 @@ namespace ts {
}
/* @internal */
- export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) {
- const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit, emitOnlyDtsFiles);
+ export function writeDeclarationFile(declarationFilePath: string, sourceFileOrBundle: SourceFile | Bundle, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) {
+ const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFileOrBundle, emitOnlyDtsFiles);
const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath) || host.getCompilerOptions().noEmit;
if (!emitSkipped) {
+ const sourceFiles = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle.sourceFiles : [sourceFileOrBundle];
const declarationOutput = emitDeclarationResult.referencesOutput
+ getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
writeFile(host, emitterDiagnostics, declarationFilePath, declarationOutput, host.getCompilerOptions().emitBOM, sourceFiles);
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index 27285a4c2dc..dd823cf7994 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -1,61 +1,28 @@
-///
+///
///
-///
-///
+///
+///
///
+///
/* @internal */
namespace ts {
- // Flags enum to track count of temp variables and a few dedicated names
- const enum TempFlags {
- Auto = 0x00000000, // No preferred name
- CountMask = 0x0FFFFFFF, // Temp variable counter
- _i = 0x10000000, // Use/preference flag for '_i'
- }
-
const id = (s: SourceFile) => s;
const nullTransformers: Transformer[] = [_ => id];
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean): EmitResult {
- const delimiters = createDelimiterMap();
- const brackets = createBracketsMap();
const compilerOptions = host.getCompilerOptions();
- const languageVersion = getEmitScriptTarget(compilerOptions);
- const moduleKind = getEmitModuleKind(compilerOptions);
const sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined;
const emittedFilesList: string[] = compilerOptions.listEmittedFiles ? [] : undefined;
const emitterDiagnostics = createDiagnosticCollection();
const newLine = host.getNewLine();
const transformers: Transformer[] = emitOnlyDtsFiles ? nullTransformers : getTransformers(compilerOptions);
const writer = createTextWriter(newLine);
- const {
- write,
- writeLine,
- increaseIndent,
- decreaseIndent
- } = writer;
-
const sourceMap = createSourceMapWriter(host, writer);
- const {
- emitNodeWithSourceMap,
- emitTokenWithSourceMap
- } = sourceMap;
+ const comments = createCommentWriter(writer, compilerOptions, newLine, sourceMap.emitPos);
- const comments = createCommentWriter(host, writer, sourceMap);
- const {
- emitNodeWithComments,
- emitBodyWithDetachedComments,
- emitTrailingCommentsOfPosition
- } = comments;
-
- let nodeIdToGeneratedName: string[];
- let autoGeneratedIdToGeneratedName: string[];
- let generatedNameSet: Map;
- let tempFlags: TempFlags;
let currentSourceFile: SourceFile;
- let currentText: string;
- let currentFileIdentifiers: Map;
let bundledHelpers: Map;
let isOwnFileEmit: boolean;
let emitSkipped = false;
@@ -63,17 +30,34 @@ namespace ts {
const sourceFiles = getSourceFilesToEmit(host, targetSourceFile);
// Transform the source files
- performance.mark("beforeTransform");
- const {
- transformed,
- emitNodeWithSubstitution,
- emitNodeWithNotification
- } = transformFiles(resolver, host, sourceFiles, transformers);
- performance.measure("transformTime", "beforeTransform");
+ const transform = transformFiles(resolver, host, sourceFiles, transformers);
+
+ // Create a printer to print the nodes
+ const printer = createPrinter(writer, compilerOptions, {
+ // resolver hooks
+ hasGlobalName: resolver.hasGlobalName,
+
+ // transform hooks
+ onEmitNode: transform.emitNodeWithNotification,
+ onSubstituteNode: transform.emitNodeWithSubstitution,
+
+ // sourcemap hooks
+ onEmitSourceMapOfNode: sourceMap.emitNodeWithSourceMap,
+ onEmitSourceMapOfToken: sourceMap.emitTokenWithSourceMap,
+
+ // comment hooks
+ onEmitCommentsOfNode: comments.emitNodeWithComments,
+ onEmitDetachedCommentsOfNode: comments.emitBodyWithDetachedComments,
+ onEmitTrailingCommentsOfPosition: comments.emitTrailingCommentsOfPosition,
+
+ // emitter hooks
+ onEmitHelpers: emitHelpers,
+ onSetSourceFile: setSourceFile,
+ });
// Emit each output file
performance.mark("beforePrint");
- forEachEmittedFile(host, emitFile, transformed, emitOnlyDtsFiles);
+ forEachEmittedFile(host, emitSourceFileOrBundle, transform.transformed, emitOnlyDtsFiles);
performance.measure("printTime", "beforePrint");
// Clean up emit nodes on parse tree
@@ -88,11 +72,11 @@ namespace ts {
sourceMaps: sourceMapDataList
};
- function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath }: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) {
+ function emitSourceFileOrBundle({ jsFilePath, sourceMapFilePath, declarationFilePath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle) {
// Make sure not to write js file and source map file if any of them cannot be written
if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) {
if (!emitOnlyDtsFiles) {
- printFile(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
+ printSourceFileOrBundle(jsFilePath, sourceMapFilePath, sourceFileOrBundle);
}
}
else {
@@ -100,7 +84,7 @@ namespace ts {
}
if (declarationFilePath) {
- emitSkipped = writeDeclarationFile(declarationFilePath, getOriginalSourceFiles(sourceFiles), isBundledEmit, host, resolver, emitterDiagnostics, emitOnlyDtsFiles) || emitSkipped;
+ emitSkipped = writeDeclarationFile(declarationFilePath, getOriginalSourceFileOrBundle(sourceFileOrBundle), host, resolver, emitterDiagnostics, emitOnlyDtsFiles) || emitSkipped;
}
if (!emitSkipped && emittedFilesList) {
@@ -116,34 +100,32 @@ namespace ts {
}
}
- function printFile(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
- sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
- nodeIdToGeneratedName = [];
- autoGeneratedIdToGeneratedName = [];
- generatedNameSet = createMap();
- bundledHelpers = isBundledEmit ? createMap() : undefined;
- isOwnFileEmit = !isBundledEmit;
+ function printSourceFileOrBundle(jsFilePath: string, sourceMapFilePath: string, sourceFileOrBundle: SourceFile | Bundle) {
+ const bundle = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle : undefined;
+ const sourceFile = sourceFileOrBundle.kind === SyntaxKind.SourceFile ? sourceFileOrBundle : undefined;
+ const sourceFiles = bundle ? bundle.sourceFiles : [sourceFile];
+ sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFileOrBundle);
- // Emit helpers from all the files
- if (isBundledEmit && moduleKind) {
- for (const sourceFile of sourceFiles) {
- emitHelpers(sourceFile, /*isBundle*/ true);
- }
+ if (bundle) {
+ bundledHelpers = createMap();
+ isOwnFileEmit = false;
+ printer.printBundle(bundle);
+ }
+ else {
+ isOwnFileEmit = true;
+ printer.printFile(sourceFile);
}
- // Print each transformed source file.
- forEach(sourceFiles, printSourceFile);
-
- writeLine();
+ writer.writeLine();
const sourceMappingURL = sourceMap.getSourceMappingURL();
if (sourceMappingURL) {
- write(`//# ${"sourceMappingURL"}=${sourceMappingURL}`); // Sometimes tools can sometimes see this line as a source mapping url comment
+ writer.write(`//# ${"sourceMappingURL"}=${sourceMappingURL}`); // Sometimes tools can sometimes see this line as a source mapping url comment
}
// Write the source map
if (compilerOptions.sourceMap && !compilerOptions.inlineSourceMap) {
- writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap.getText(), /*writeByteOrderMark*/ false, sourceFiles);
+ writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap.getText(), /*writeByteOrderMark*/ false, sourceFiles);
}
// Record source map data for the test harness.
@@ -159,2654 +141,57 @@ namespace ts {
comments.reset();
writer.reset();
- tempFlags = TempFlags.Auto;
currentSourceFile = undefined;
- currentText = undefined;
+ bundledHelpers = undefined;
isOwnFileEmit = false;
}
- function printSourceFile(node: SourceFile) {
+ function setSourceFile(node: SourceFile) {
currentSourceFile = node;
- currentText = node.text;
- currentFileIdentifiers = node.identifiers;
sourceMap.setSourceFile(node);
comments.setSourceFile(node);
- pipelineEmitWithNotification(EmitContext.SourceFile, node);
}
- /**
- * Emits a node.
- */
- function emit(node: Node) {
- pipelineEmitWithNotification(EmitContext.Unspecified, node);
- }
-
- /**
- * Emits an IdentifierName.
- */
- function emitIdentifierName(node: Identifier) {
- pipelineEmitWithNotification(EmitContext.IdentifierName, node);
- }
-
- /**
- * Emits an expression node.
- */
- function emitExpression(node: Expression) {
- pipelineEmitWithNotification(EmitContext.Expression, node);
- }
-
- /**
- * Emits a node with possible notification.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called from printSourceFile, emit, emitExpression, or
- * emitIdentifierName.
- */
- function pipelineEmitWithNotification(emitContext: EmitContext, node: Node) {
- emitNodeWithNotification(emitContext, node, pipelineEmitWithComments);
- }
-
- /**
- * Emits a node with comments.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called indirectly from pipelineEmitWithNotification.
- */
- function pipelineEmitWithComments(emitContext: EmitContext, node: Node) {
- // Do not emit comments for SourceFile
- if (emitContext === EmitContext.SourceFile) {
- pipelineEmitWithSourceMap(emitContext, node);
- return;
- }
-
- emitNodeWithComments(emitContext, node, pipelineEmitWithSourceMap);
- }
-
- /**
- * Emits a node with source maps.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called indirectly from pipelineEmitWithComments.
- */
- function pipelineEmitWithSourceMap(emitContext: EmitContext, node: Node) {
- // Do not emit source mappings for SourceFile or IdentifierName
- if (emitContext === EmitContext.SourceFile
- || emitContext === EmitContext.IdentifierName) {
- pipelineEmitWithSubstitution(emitContext, node);
- return;
- }
-
- emitNodeWithSourceMap(emitContext, node, pipelineEmitWithSubstitution);
- }
-
- /**
- * Emits a node with possible substitution.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called indirectly from pipelineEmitWithSourceMap or
- * pipelineEmitInUnspecifiedContext (when picking a more specific context).
- */
- function pipelineEmitWithSubstitution(emitContext: EmitContext, node: Node) {
- emitNodeWithSubstitution(emitContext, node, pipelineEmitForContext);
- }
-
- /**
- * Emits a node.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called indirectly from pipelineEmitWithSubstitution.
- */
- function pipelineEmitForContext(emitContext: EmitContext, node: Node): void {
- switch (emitContext) {
- case EmitContext.SourceFile: return pipelineEmitInSourceFileContext(node);
- case EmitContext.IdentifierName: return pipelineEmitInIdentifierNameContext(node);
- case EmitContext.Unspecified: return pipelineEmitInUnspecifiedContext(node);
- case EmitContext.Expression: return pipelineEmitInExpressionContext(node);
- }
- }
-
- /**
- * Emits a node in the SourceFile EmitContext.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called indirectly from pipelineEmitForContext.
- */
- function pipelineEmitInSourceFileContext(node: Node): void {
- const kind = node.kind;
- switch (kind) {
- // Top-level nodes
- case SyntaxKind.SourceFile:
- return emitSourceFile(node);
- }
- }
-
- /**
- * Emits a node in the IdentifierName EmitContext.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called indirectly from pipelineEmitForContext.
- */
- function pipelineEmitInIdentifierNameContext(node: Node): void {
- const kind = node.kind;
- switch (kind) {
- // Identifiers
- case SyntaxKind.Identifier:
- return emitIdentifier(node);
- }
- }
-
- /**
- * Emits a node in the Unspecified EmitContext.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called indirectly from pipelineEmitForContext.
- */
- function pipelineEmitInUnspecifiedContext(node: Node): void {
- const kind = node.kind;
- switch (kind) {
- // 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.ConstKeyword:
- case SyntaxKind.DefaultKeyword:
- case SyntaxKind.ExportKeyword:
- case SyntaxKind.VoidKeyword:
-
- // Strict mode reserved words
- case SyntaxKind.PrivateKeyword:
- case SyntaxKind.ProtectedKeyword:
- case SyntaxKind.PublicKeyword:
- case SyntaxKind.StaticKeyword:
-
- // Contextual keywords
- case SyntaxKind.AbstractKeyword:
- case SyntaxKind.AsKeyword:
- case SyntaxKind.AnyKeyword:
- case SyntaxKind.AsyncKeyword:
- case SyntaxKind.AwaitKeyword:
- case SyntaxKind.BooleanKeyword:
- case SyntaxKind.ConstructorKeyword:
- case SyntaxKind.DeclareKeyword:
- case SyntaxKind.GetKeyword:
- case SyntaxKind.IsKeyword:
- case SyntaxKind.ModuleKeyword:
- case SyntaxKind.NamespaceKeyword:
- case SyntaxKind.NeverKeyword:
- case SyntaxKind.ReadonlyKeyword:
- case SyntaxKind.RequireKeyword:
- case SyntaxKind.NumberKeyword:
- case SyntaxKind.SetKeyword:
- case SyntaxKind.StringKeyword:
- case SyntaxKind.SymbolKeyword:
- case SyntaxKind.TypeKeyword:
- case SyntaxKind.UndefinedKeyword:
- case SyntaxKind.FromKeyword:
- case SyntaxKind.GlobalKeyword:
- case SyntaxKind.OfKeyword:
- writeTokenText(kind);
- return;
-
- // 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);
- case SyntaxKind.ExpressionWithTypeArguments:
- return emitExpressionWithTypeArguments(node);
- case SyntaxKind.ThisType:
- return emitThisType();
- case SyntaxKind.TypeOperator:
- return emitTypeOperator(node);
- case SyntaxKind.IndexedAccessType:
- return emitIndexedAccessType(node);
- case SyntaxKind.MappedType:
- return emitMappedType(node);
- case SyntaxKind.LiteralType:
- return emitLiteralType(node);
-
- // Binding patterns
- case SyntaxKind.ObjectBindingPattern:
- return emitObjectBindingPattern(node);
- case SyntaxKind.ArrayBindingPattern:
- return emitArrayBindingPattern(node);
- case SyntaxKind.BindingElement:
- return emitBindingElement(node);
-
- // Misc
- case SyntaxKind.TemplateSpan:
- return emitTemplateSpan(node);
- case SyntaxKind.SemicolonClassElement:
- return emitSemicolonClassElement();
-
- // Statements
- case SyntaxKind.Block:
- return emitBlock(node);
- case SyntaxKind.VariableStatement:
- return emitVariableStatement(node);
- case SyntaxKind.EmptyStatement:
- return emitEmptyStatement();
- 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 emitNamedImports(node);
- case SyntaxKind.ImportSpecifier:
- return emitImportSpecifier(node);
- case SyntaxKind.ExportAssignment:
- return emitExportAssignment(node);
- case SyntaxKind.ExportDeclaration:
- return emitExportDeclaration(node);
- case SyntaxKind.NamedExports:
- return emitNamedExports(node);
- case SyntaxKind.ExportSpecifier:
- return emitExportSpecifier(node);
- case SyntaxKind.MissingDeclaration:
- return;
-
- // Module references
- case SyntaxKind.ExternalModuleReference:
- return emitExternalModuleReference(node);
-
- // JSX (non-expression)
- case SyntaxKind.JsxText:
- return emitJsxText(node);
- case SyntaxKind.JsxOpeningElement:
- return emitJsxOpeningElement(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);
- case SyntaxKind.SpreadAssignment:
- return emitSpreadAssignment(node as SpreadAssignment);
-
- // Enum
- case SyntaxKind.EnumMember:
- return emitEnumMember(node);
-
- // JSDoc nodes (ignored)
- // Transformation nodes (ignored)
- }
-
- // If the node is an expression, try to emit it as an expression with
- // substitution.
- if (isExpression(node)) {
- return pipelineEmitWithSubstitution(EmitContext.Expression, node);
- }
- }
-
- /**
- * Emits a node in the Expression EmitContext.
- *
- * NOTE: Do not call this method directly. It is part of the emit pipeline
- * and should only be called indirectly from pipelineEmitForContext.
- */
- function pipelineEmitInExpressionContext(node: Node): void {
- const kind = node.kind;
- switch (kind) {
- // Literals
- case SyntaxKind.NumericLiteral:
- return emitNumericLiteral(node);
-
- case SyntaxKind.StringLiteral:
- case SyntaxKind.RegularExpressionLiteral:
- case SyntaxKind.NoSubstitutionTemplateLiteral:
- return emitLiteral(node);
-
- // Identifiers
- case SyntaxKind.Identifier:
- return emitIdentifier(node);
-
- // Reserved words
- case SyntaxKind.FalseKeyword:
- case SyntaxKind.NullKeyword:
- case SyntaxKind.SuperKeyword:
- case SyntaxKind.TrueKeyword:
- case SyntaxKind.ThisKeyword:
- writeTokenText(kind);
- return;
-
- // 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.SpreadElement:
- return emitSpreadExpression(node);
- case SyntaxKind.ClassExpression:
- return emitClassExpression(node);
- case SyntaxKind.OmittedExpression:
- return;
- case SyntaxKind.AsExpression:
- return emitAsExpression(node);
- case SyntaxKind.NonNullExpression:
- return emitNonNullExpression(node);
- case SyntaxKind.MetaProperty:
- return emitMetaProperty(node);
-
- // JSX
- case SyntaxKind.JsxElement:
- return emitJsxElement(node);
- case SyntaxKind.JsxSelfClosingElement:
- return emitJsxSelfClosingElement(node);
-
- // Transformation nodes
- case SyntaxKind.PartiallyEmittedExpression:
- return emitPartiallyEmittedExpression(node);
- }
- }
-
- //
- // Literals/Pseudo-literals
- //
-
- // SyntaxKind.NumericLiteral
- function emitNumericLiteral(node: NumericLiteral) {
- emitLiteral(node);
- if (node.trailingComment) {
- write(` /*${node.trailingComment}*/`);
- }
- }
-
- // SyntaxKind.StringLiteral
- // SyntaxKind.RegularExpressionLiteral
- // SyntaxKind.NoSubstitutionTemplateLiteral
- // SyntaxKind.TemplateHead
- // SyntaxKind.TemplateMiddle
- // SyntaxKind.TemplateTail
- function emitLiteral(node: LiteralLikeNode) {
- const text = getLiteralTextOfNode(node);
- if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap)
- && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
- writer.writeLiteral(text);
- }
- else {
- write(text);
- }
- }
-
- //
- // Identifiers
- //
-
- function emitIdentifier(node: Identifier) {
- write(getTextOfNode(node, /*includeTrivia*/ false));
- }
-
- //
- // Names
- //
-
- function emitQualifiedName(node: QualifiedName) {
- emitEntityName(node.left);
- write(".");
- emit(node.right);
- }
-
- function emitEntityName(node: EntityName) {
- if (node.kind === SyntaxKind.Identifier) {
- emitExpression(node);
- }
- else {
- emit(node);
- }
- }
-
- function emitComputedPropertyName(node: ComputedPropertyName) {
- write("[");
- emitExpression(node.expression);
- write("]");
- }
-
- //
- // Signature elements
- //
-
- function emitTypeParameter(node: TypeParameterDeclaration) {
- emit(node.name);
- emitWithPrefix(" extends ", node.constraint);
- }
-
- function emitParameter(node: ParameterDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- writeIfPresent(node.dotDotDotToken, "...");
- emit(node.name);
- writeIfPresent(node.questionToken, "?");
- emitExpressionWithPrefix(" = ", node.initializer);
- emitWithPrefix(": ", node.type);
- }
-
- function emitDecorator(decorator: Decorator) {
- write("@");
- emitExpression(decorator.expression);
- }
-
- //
- // Type members
- //
-
- function emitPropertySignature(node: PropertySignature) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- emit(node.name);
- writeIfPresent(node.questionToken, "?");
- emitWithPrefix(": ", node.type);
- write(";");
- }
-
- function emitPropertyDeclaration(node: PropertyDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- emit(node.name);
- emitWithPrefix(": ", node.type);
- emitExpressionWithPrefix(" = ", node.initializer);
- write(";");
- }
-
- function emitMethodSignature(node: MethodSignature) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- emit(node.name);
- writeIfPresent(node.questionToken, "?");
- emitTypeParameters(node, node.typeParameters);
- emitParameters(node, node.parameters);
- emitWithPrefix(": ", node.type);
- write(";");
- }
-
- function emitMethodDeclaration(node: MethodDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- writeIfPresent(node.asteriskToken, "*");
- emit(node.name);
- emitSignatureAndBody(node, emitSignatureHead);
- }
-
- function emitConstructor(node: ConstructorDeclaration) {
- emitModifiers(node, node.modifiers);
- write("constructor");
- emitSignatureAndBody(node, emitSignatureHead);
- }
-
- function emitAccessorDeclaration(node: AccessorDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- write(node.kind === SyntaxKind.GetAccessor ? "get " : "set ");
- emit(node.name);
- emitSignatureAndBody(node, emitSignatureHead);
- }
-
- function emitCallSignature(node: CallSignatureDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- emitTypeParameters(node, node.typeParameters);
- emitParameters(node, node.parameters);
- emitWithPrefix(": ", node.type);
- write(";");
- }
-
- function emitConstructSignature(node: ConstructSignatureDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- write("new ");
- emitTypeParameters(node, node.typeParameters);
- emitParameters(node, node.parameters);
- emitWithPrefix(": ", node.type);
- write(";");
- }
-
- function emitIndexSignature(node: IndexSignatureDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- emitParametersForIndexSignature(node, node.parameters);
- emitWithPrefix(": ", node.type);
- write(";");
- }
-
- function emitSemicolonClassElement() {
- write(";");
- }
-
- //
- // Types
- //
-
- function emitTypePredicate(node: TypePredicateNode) {
- emit(node.parameterName);
- write(" is ");
- emit(node.type);
- }
-
- function emitTypeReference(node: TypeReferenceNode) {
- emit(node.typeName);
- emitTypeArguments(node, node.typeArguments);
- }
-
- function emitFunctionType(node: FunctionTypeNode) {
- emitTypeParameters(node, node.typeParameters);
- emitParametersForArrow(node, node.parameters);
- write(" => ");
- emit(node.type);
- }
-
- function emitConstructorType(node: ConstructorTypeNode) {
- write("new ");
- emitTypeParameters(node, node.typeParameters);
- emitParametersForArrow(node, node.parameters);
- write(" => ");
- emit(node.type);
- }
-
- function emitTypeQuery(node: TypeQueryNode) {
- write("typeof ");
- emit(node.exprName);
- }
-
- function emitTypeLiteral(node: TypeLiteralNode) {
- write("{");
- emitList(node, node.members, ListFormat.TypeLiteralMembers);
- write("}");
- }
-
- function emitArrayType(node: ArrayTypeNode) {
- emit(node.elementType);
- write("[]");
- }
-
- function emitTupleType(node: TupleTypeNode) {
- write("[");
- emitList(node, node.elementTypes, ListFormat.TupleTypeElements);
- write("]");
- }
-
- function emitUnionType(node: UnionTypeNode) {
- emitList(node, node.types, ListFormat.UnionTypeConstituents);
- }
-
- function emitIntersectionType(node: IntersectionTypeNode) {
- emitList(node, node.types, ListFormat.IntersectionTypeConstituents);
- }
-
- function emitParenthesizedType(node: ParenthesizedTypeNode) {
- write("(");
- emit(node.type);
- write(")");
- }
-
- function emitThisType() {
- write("this");
- }
-
- function emitTypeOperator(node: TypeOperatorNode) {
- writeTokenText(node.operator);
- write(" ");
- emit(node.type);
- }
-
- function emitIndexedAccessType(node: IndexedAccessTypeNode) {
- emit(node.objectType);
- write("[");
- emit(node.indexType);
- write("]");
- }
-
- function emitMappedType(node: MappedTypeNode) {
- write("{");
- writeLine();
- increaseIndent();
- if (node.readonlyToken) {
- write("readonly ");
- }
- write("[");
- emit(node.typeParameter.name);
- write(" in ");
- emit(node.typeParameter.constraint);
- write("]");
- if (node.questionToken) {
- write("?");
- }
- write(": ");
- emit(node.type);
- write(";");
- writeLine();
- decreaseIndent();
- write("}");
- }
-
- function emitLiteralType(node: LiteralTypeNode) {
- emitExpression(node.literal);
- }
-
- //
- // Binding patterns
- //
-
- function emitObjectBindingPattern(node: ObjectBindingPattern) {
- const elements = node.elements;
- if (elements.length === 0) {
- write("{}");
- }
- else {
- write("{");
- emitList(node, elements, ListFormat.ObjectBindingPatternElements);
- write("}");
- }
- }
-
- function emitArrayBindingPattern(node: ArrayBindingPattern) {
- const elements = node.elements;
- if (elements.length === 0) {
- write("[]");
- }
- else {
- write("[");
- emitList(node, node.elements, ListFormat.ArrayBindingPatternElements);
- write("]");
- }
- }
-
- function emitBindingElement(node: BindingElement) {
- emitWithSuffix(node.propertyName, ": ");
- writeIfPresent(node.dotDotDotToken, "...");
- emit(node.name);
- emitExpressionWithPrefix(" = ", node.initializer);
- }
-
- //
- // Expressions
- //
-
- function emitArrayLiteralExpression(node: ArrayLiteralExpression) {
- const elements = node.elements;
- if (elements.length === 0) {
- write("[]");
- }
- else {
- const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
- emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine);
- }
- }
-
- function emitObjectLiteralExpression(node: ObjectLiteralExpression) {
- const properties = node.properties;
- if (properties.length === 0) {
- write("{}");
- }
- else {
- const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
- if (indentedFlag) {
- increaseIndent();
- }
-
- const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
- const allowTrailingComma = languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None;
- emitList(node, properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine);
-
- if (indentedFlag) {
- decreaseIndent();
- }
- }
- }
-
- function emitPropertyAccessExpression(node: PropertyAccessExpression) {
- let indentBeforeDot = false;
- let indentAfterDot = false;
- if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) {
- const dotRangeStart = node.expression.end;
- const dotRangeEnd = skipTrivia(currentText, node.expression.end) + 1;
- const dotToken = { kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd };
- indentBeforeDot = needsIndentation(node, node.expression, dotToken);
- indentAfterDot = needsIndentation(node, dotToken, node.name);
- }
-
- emitExpression(node.expression);
- increaseIndentIf(indentBeforeDot);
-
- const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression);
- 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 (expression.kind === SyntaxKind.NumericLiteral) {
- // check if numeric literal is a decimal literal that was originally written with a dot
- const text = getLiteralTextOfNode(expression);
- return getNumericLiteralFlags(text, /*hint*/ NumericLiteralFlags.All) === NumericLiteralFlags.None
- && !(expression).isOctalLiteral
- && text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0;
- }
- else if (isPropertyAccessExpression(expression) || isElementAccessExpression(expression)) {
- // check if constant enum value is integer
- const constantValue = getConstantValue(expression);
- // isFinite handles cases when constantValue is undefined
- return isFinite(constantValue)
- && Math.floor(constantValue) === constantValue
- && compilerOptions.removeComments;
- }
- }
-
- function emitElementAccessExpression(node: ElementAccessExpression) {
- emitExpression(node.expression);
- write("[");
- emitExpression(node.argumentExpression);
- write("]");
- }
-
- function emitCallExpression(node: CallExpression) {
- emitExpression(node.expression);
- emitTypeArguments(node, node.typeArguments);
- emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments);
- }
-
- function emitNewExpression(node: NewExpression) {
- write("new ");
- emitExpression(node.expression);
- emitTypeArguments(node, node.typeArguments);
- emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments);
- }
-
- function emitTaggedTemplateExpression(node: TaggedTemplateExpression) {
- emitExpression(node.tag);
- write(" ");
- emitExpression(node.template);
- }
-
- function emitTypeAssertionExpression(node: TypeAssertion) {
- if (node.type) {
- write("<");
- emit(node.type);
- write(">");
- }
-
- emitExpression(node.expression);
- }
-
- function emitParenthesizedExpression(node: ParenthesizedExpression) {
- write("(");
- emitExpression(node.expression);
- write(")");
- }
-
- function emitFunctionExpression(node: FunctionExpression) {
- emitFunctionDeclarationOrExpression(node);
- }
-
- function emitArrowFunction(node: ArrowFunction) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- emitSignatureAndBody(node, emitArrowFunctionHead);
- }
-
- function emitArrowFunctionHead(node: ArrowFunction) {
- emitTypeParameters(node, node.typeParameters);
- emitParametersForArrow(node, node.parameters);
- emitWithPrefix(": ", node.type);
- write(" =>");
- }
-
- function emitDeleteExpression(node: DeleteExpression) {
- write("delete ");
- emitExpression(node.expression);
- }
-
- function emitTypeOfExpression(node: TypeOfExpression) {
- write("typeof ");
- emitExpression(node.expression);
- }
-
- function emitVoidExpression(node: VoidExpression) {
- write("void ");
- emitExpression(node.expression);
- }
-
- function emitAwaitExpression(node: AwaitExpression) {
- write("await ");
- emitExpression(node.expression);
- }
-
- function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
- writeTokenText(node.operator);
- if (shouldEmitWhitespaceBeforeOperand(node)) {
- write(" ");
- }
- emitExpression(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.
- const operand = node.operand;
- return operand.kind === SyntaxKind.PrefixUnaryExpression
- && ((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) {
- emitExpression(node.operand);
- writeTokenText(node.operator);
- }
-
- function emitBinaryExpression(node: BinaryExpression) {
- const isCommaOperator = node.operatorToken.kind !== SyntaxKind.CommaToken;
- const indentBeforeOperator = needsIndentation(node, node.left, node.operatorToken);
- const indentAfterOperator = needsIndentation(node, node.operatorToken, node.right);
-
- emitExpression(node.left);
- increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
- writeTokenText(node.operatorToken.kind);
- increaseIndentIf(indentAfterOperator, " ");
- emitExpression(node.right);
- decreaseIndentIf(indentBeforeOperator, indentAfterOperator);
- }
-
- function emitConditionalExpression(node: ConditionalExpression) {
- const indentBeforeQuestion = needsIndentation(node, node.condition, node.questionToken);
- const indentAfterQuestion = needsIndentation(node, node.questionToken, node.whenTrue);
- const indentBeforeColon = needsIndentation(node, node.whenTrue, node.colonToken);
- const indentAfterColon = needsIndentation(node, node.colonToken, node.whenFalse);
-
- emitExpression(node.condition);
- increaseIndentIf(indentBeforeQuestion, " ");
- write("?");
- increaseIndentIf(indentAfterQuestion, " ");
- emitExpression(node.whenTrue);
- decreaseIndentIf(indentBeforeQuestion, indentAfterQuestion);
-
- increaseIndentIf(indentBeforeColon, " ");
- write(":");
- increaseIndentIf(indentAfterColon, " ");
- emitExpression(node.whenFalse);
- decreaseIndentIf(indentBeforeColon, indentAfterColon);
- }
-
- function emitTemplateExpression(node: TemplateExpression) {
- emit(node.head);
- emitList(node, node.templateSpans, ListFormat.TemplateExpressionSpans);
- }
-
- function emitYieldExpression(node: YieldExpression) {
- write(node.asteriskToken ? "yield*" : "yield");
- emitExpressionWithPrefix(" ", node.expression);
- }
-
- function emitSpreadExpression(node: SpreadElement) {
- write("...");
- emitExpression(node.expression);
- }
-
- function emitClassExpression(node: ClassExpression) {
- emitClassDeclarationOrExpression(node);
- }
-
- function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) {
- emitExpression(node.expression);
- emitTypeArguments(node, node.typeArguments);
- }
-
- function emitAsExpression(node: AsExpression) {
- emitExpression(node.expression);
- if (node.type) {
- write(" as ");
- emit(node.type);
- }
- }
-
- function emitNonNullExpression(node: NonNullExpression) {
- emitExpression(node.expression);
- write("!");
- }
-
- function emitMetaProperty(node: MetaProperty) {
- writeToken(node.keywordToken, node.pos);
- write(".");
- emit(node.name);
- }
-
- //
- // Misc
- //
-
- function emitTemplateSpan(node: TemplateSpan) {
- emitExpression(node.expression);
- emit(node.literal);
- }
-
- //
- // Statements
- //
-
- function emitBlock(node: Block) {
- if (isSingleLineEmptyBlock(node)) {
- writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node);
- write(" ");
- writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node);
- }
- else {
- writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node);
- emitBlockStatements(node);
- writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node);
- }
- }
-
- function emitBlockStatements(node: BlockLike) {
- if (getEmitFlags(node) & EmitFlags.SingleLine) {
- emitList(node, node.statements, ListFormat.SingleLineBlockStatements);
- }
- else {
- emitList(node, node.statements, ListFormat.MultiLineBlockStatements);
- }
- }
-
- function emitVariableStatement(node: VariableStatement) {
- emitModifiers(node, node.modifiers);
- emit(node.declarationList);
- write(";");
- }
-
- function emitEmptyStatement() {
- write(";");
- }
-
- function emitExpressionStatement(node: ExpressionStatement) {
- emitExpression(node.expression);
- write(";");
- }
-
- function emitIfStatement(node: IfStatement) {
- const openParenPos = writeToken(SyntaxKind.IfKeyword, node.pos, node);
- write(" ");
- writeToken(SyntaxKind.OpenParenToken, openParenPos, node);
- emitExpression(node.expression);
- writeToken(SyntaxKind.CloseParenToken, node.expression.end, node);
- emitEmbeddedStatement(node, node.thenStatement);
- if (node.elseStatement) {
- writeLineOrSpace(node);
- writeToken(SyntaxKind.ElseKeyword, node.thenStatement.end, node);
- if (node.elseStatement.kind === SyntaxKind.IfStatement) {
- write(" ");
- emit(node.elseStatement);
- }
- else {
- emitEmbeddedStatement(node, node.elseStatement);
- }
- }
- }
-
- function emitDoStatement(node: DoStatement) {
- write("do");
- emitEmbeddedStatement(node, node.statement);
- if (isBlock(node.statement)) {
- write(" ");
- }
- else {
- writeLineOrSpace(node);
- }
-
- write("while (");
- emitExpression(node.expression);
- write(");");
- }
-
- function emitWhileStatement(node: WhileStatement) {
- write("while (");
- emitExpression(node.expression);
- write(")");
- emitEmbeddedStatement(node, node.statement);
- }
-
- function emitForStatement(node: ForStatement) {
- const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos);
- write(" ");
- writeToken(SyntaxKind.OpenParenToken, openParenPos, /*contextNode*/ node);
- emitForBinding(node.initializer);
- write(";");
- emitExpressionWithPrefix(" ", node.condition);
- write(";");
- emitExpressionWithPrefix(" ", node.incrementor);
- write(")");
- emitEmbeddedStatement(node, node.statement);
- }
-
- function emitForInStatement(node: ForInStatement) {
- const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos);
- write(" ");
- writeToken(SyntaxKind.OpenParenToken, openParenPos);
- emitForBinding(node.initializer);
- write(" in ");
- emitExpression(node.expression);
- writeToken(SyntaxKind.CloseParenToken, node.expression.end);
- emitEmbeddedStatement(node, node.statement);
- }
-
- function emitForOfStatement(node: ForOfStatement) {
- const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos);
- write(" ");
- writeToken(SyntaxKind.OpenParenToken, openParenPos);
- emitForBinding(node.initializer);
- write(" of ");
- emitExpression(node.expression);
- writeToken(SyntaxKind.CloseParenToken, node.expression.end);
- emitEmbeddedStatement(node, node.statement);
- }
-
- function emitForBinding(node: VariableDeclarationList | Expression) {
- if (node !== undefined) {
- if (node.kind === SyntaxKind.VariableDeclarationList) {
- emit(node);
- }
- else {
- emitExpression(node);
- }
- }
- }
-
- function emitContinueStatement(node: ContinueStatement) {
- writeToken(SyntaxKind.ContinueKeyword, node.pos);
- emitWithPrefix(" ", node.label);
- write(";");
- }
-
- function emitBreakStatement(node: BreakStatement) {
- writeToken(SyntaxKind.BreakKeyword, node.pos);
- emitWithPrefix(" ", node.label);
- write(";");
- }
-
- function emitReturnStatement(node: ReturnStatement) {
- writeToken(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node);
- emitExpressionWithPrefix(" ", node.expression);
- write(";");
- }
-
- function emitWithStatement(node: WithStatement) {
- write("with (");
- emitExpression(node.expression);
- write(")");
- emitEmbeddedStatement(node, node.statement);
- }
-
- function emitSwitchStatement(node: SwitchStatement) {
- const openParenPos = writeToken(SyntaxKind.SwitchKeyword, node.pos);
- write(" ");
- writeToken(SyntaxKind.OpenParenToken, openParenPos);
- emitExpression(node.expression);
- writeToken(SyntaxKind.CloseParenToken, node.expression.end);
- write(" ");
- emit(node.caseBlock);
- }
-
- function emitLabeledStatement(node: LabeledStatement) {
- emit(node.label);
- write(": ");
- emit(node.statement);
- }
-
- function emitThrowStatement(node: ThrowStatement) {
- write("throw");
- emitExpressionWithPrefix(" ", node.expression);
- write(";");
- }
-
- function emitTryStatement(node: TryStatement) {
- write("try ");
- emit(node.tryBlock);
- if (node.catchClause) {
- writeLineOrSpace(node);
- emit(node.catchClause);
- }
- if (node.finallyBlock) {
- writeLineOrSpace(node);
- write("finally ");
- emit(node.finallyBlock);
- }
- }
-
- function emitDebuggerStatement(node: DebuggerStatement) {
- writeToken(SyntaxKind.DebuggerKeyword, node.pos);
- write(";");
- }
-
- //
- // Declarations
- //
-
- function emitVariableDeclaration(node: VariableDeclaration) {
- emit(node.name);
- emitWithPrefix(": ", node.type);
- emitExpressionWithPrefix(" = ", node.initializer);
- }
-
- function emitVariableDeclarationList(node: VariableDeclarationList) {
- write(isLet(node) ? "let " : isConst(node) ? "const " : "var ");
- emitList(node, node.declarations, ListFormat.VariableDeclarationList);
- }
-
- function emitFunctionDeclaration(node: FunctionDeclaration) {
- emitFunctionDeclarationOrExpression(node);
- }
-
- function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- write(node.asteriskToken ? "function* " : "function ");
- emitIdentifierName(node.name);
- emitSignatureAndBody(node, emitSignatureHead);
- }
-
- function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) {
- const body = node.body;
- if (body) {
- if (isBlock(body)) {
- const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
- if (indentedFlag) {
- increaseIndent();
- }
-
- if (getEmitFlags(node) & EmitFlags.ReuseTempVariableScope) {
- emitSignatureHead(node);
- emitBlockFunctionBody(body);
- }
- else {
- const savedTempFlags = tempFlags;
- tempFlags = 0;
- emitSignatureHead(node);
- emitBlockFunctionBody(body);
- tempFlags = savedTempFlags;
- }
-
- if (indentedFlag) {
- decreaseIndent();
- }
- }
- else {
- emitSignatureHead(node);
- write(" ");
- emitExpression(body);
- }
- }
- else {
- emitSignatureHead(node);
- write(";");
- }
-
- }
-
- function emitSignatureHead(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) {
- emitTypeParameters(node, node.typeParameters);
- emitParameters(node, node.parameters);
- emitWithPrefix(": ", node.type);
- }
-
- function shouldEmitBlockFunctionBodyOnSingleLine(body: Block) {
- // We must emit a function body as a single-line body in the following case:
- // * The body has NodeEmitFlags.SingleLine specified.
-
- // We must emit a function body as a multi-line body in the following cases:
- // * The body is explicitly marked as multi-line.
- // * A non-synthesized body's start and end position are on different lines.
- // * Any statement in the body starts on a new line.
-
- if (getEmitFlags(body) & EmitFlags.SingleLine) {
- return true;
- }
-
- if (body.multiLine) {
- return false;
- }
-
- if (!nodeIsSynthesized(body) && !rangeIsOnSingleLine(body, currentSourceFile)) {
- return false;
- }
-
- if (shouldWriteLeadingLineTerminator(body, body.statements, ListFormat.PreserveLines)
- || shouldWriteClosingLineTerminator(body, body.statements, ListFormat.PreserveLines)) {
- return false;
- }
-
- let previousStatement: Statement;
- for (const statement of body.statements) {
- if (shouldWriteSeparatingLineTerminator(previousStatement, statement, ListFormat.PreserveLines)) {
- return false;
- }
-
- previousStatement = statement;
- }
-
- return true;
- }
-
- function emitBlockFunctionBody(body: Block) {
- write(" {");
- increaseIndent();
-
- emitBodyWithDetachedComments(body, body.statements,
- shouldEmitBlockFunctionBodyOnSingleLine(body)
- ? emitBlockFunctionBodyOnSingleLine
- : emitBlockFunctionBodyWorker);
-
- decreaseIndent();
- writeToken(SyntaxKind.CloseBraceToken, body.statements.end, body);
- }
-
- function emitBlockFunctionBodyOnSingleLine(body: Block) {
- emitBlockFunctionBodyWorker(body, /*emitBlockFunctionBodyOnSingleLine*/ true);
- }
-
- function emitBlockFunctionBodyWorker(body: Block, emitBlockFunctionBodyOnSingleLine?: boolean) {
- // Emit all the prologue directives (like "use strict").
- const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true);
- const helpersEmitted = emitHelpers(body);
-
- if (statementOffset === 0 && !helpersEmitted && emitBlockFunctionBodyOnSingleLine) {
- decreaseIndent();
- emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements);
- increaseIndent();
- }
- else {
- emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset);
- }
- }
-
- function emitClassDeclaration(node: ClassDeclaration) {
- emitClassDeclarationOrExpression(node);
- }
-
- function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- write("class");
- emitNodeWithPrefix(" ", node.name, emitIdentifierName);
-
- const indentedFlag = getEmitFlags(node) & EmitFlags.Indented;
- if (indentedFlag) {
- increaseIndent();
- }
-
- emitTypeParameters(node, node.typeParameters);
- emitList(node, node.heritageClauses, ListFormat.ClassHeritageClauses);
-
- const savedTempFlags = tempFlags;
- tempFlags = 0;
-
- write(" {");
- emitList(node, node.members, ListFormat.ClassMembers);
- write("}");
-
- if (indentedFlag) {
- decreaseIndent();
- }
-
- tempFlags = savedTempFlags;
- }
-
- function emitInterfaceDeclaration(node: InterfaceDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- write("interface ");
- emit(node.name);
- emitTypeParameters(node, node.typeParameters);
- emitList(node, node.heritageClauses, ListFormat.HeritageClauses);
- write(" {");
- emitList(node, node.members, ListFormat.InterfaceMembers);
- write("}");
- }
-
- function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
- emitDecorators(node, node.decorators);
- emitModifiers(node, node.modifiers);
- write("type ");
- emit(node.name);
- emitTypeParameters(node, node.typeParameters);
- write(" = ");
- emit(node.type);
- write(";");
- }
-
- function emitEnumDeclaration(node: EnumDeclaration) {
- emitModifiers(node, node.modifiers);
- write("enum ");
- emit(node.name);
-
- const savedTempFlags = tempFlags;
- tempFlags = 0;
-
- write(" {");
- emitList(node, node.members, ListFormat.EnumMembers);
- write("}");
- tempFlags = savedTempFlags;
- }
-
- function emitModuleDeclaration(node: ModuleDeclaration) {
- emitModifiers(node, node.modifiers);
- write(node.flags & NodeFlags.Namespace ? "namespace " : "module ");
- emit(node.name);
-
- let body = node.body;
- while (body.kind === SyntaxKind.ModuleDeclaration) {
- write(".");
- emit((body).name);
- body = (body).body;
- }
-
- write(" ");
- emit(body);
- }
-
- function emitModuleBlock(node: ModuleBlock) {
- if (isEmptyBlock(node)) {
- write("{ }");
- }
- else {
- const savedTempFlags = tempFlags;
- tempFlags = 0;
- write("{");
- increaseIndent();
- emitBlockStatements(node);
- write("}");
- tempFlags = savedTempFlags;
- }
- }
-
- function emitCaseBlock(node: CaseBlock) {
- writeToken(SyntaxKind.OpenBraceToken, node.pos);
- emitList(node, node.clauses, ListFormat.CaseBlockClauses);
- writeToken(SyntaxKind.CloseBraceToken, node.clauses.end);
- }
-
- function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) {
- emitModifiers(node, node.modifiers);
- write("import ");
- emit(node.name);
- write(" = ");
- emitModuleReference(node.moduleReference);
- write(";");
- }
-
- function emitModuleReference(node: ModuleReference) {
- if (node.kind === SyntaxKind.Identifier) {
- emitExpression(node);
- }
- else {
- emit(node);
- }
- }
-
- function emitImportDeclaration(node: ImportDeclaration) {
- emitModifiers(node, node.modifiers);
- write("import ");
- if (node.importClause) {
- emit(node.importClause);
- write(" from ");
- }
- emitExpression(node.moduleSpecifier);
- write(";");
- }
-
- function emitImportClause(node: ImportClause) {
- emit(node.name);
- if (node.name && node.namedBindings) {
- write(", ");
- }
- emit(node.namedBindings);
- }
-
- function emitNamespaceImport(node: NamespaceImport) {
- write("* as ");
- emit(node.name);
- }
-
- function emitNamedImports(node: NamedImports) {
- emitNamedImportsOrExports(node);
- }
-
- function emitImportSpecifier(node: ImportSpecifier) {
- emitImportOrExportSpecifier(node);
- }
-
- function emitExportAssignment(node: ExportAssignment) {
- write(node.isExportEquals ? "export = " : "export default ");
- emitExpression(node.expression);
- write(";");
- }
-
- function emitExportDeclaration(node: ExportDeclaration) {
- write("export ");
- if (node.exportClause) {
- emit(node.exportClause);
- }
- else {
- write("*");
- }
- if (node.moduleSpecifier) {
- write(" from ");
- emitExpression(node.moduleSpecifier);
- }
- write(";");
- }
-
- function emitNamedExports(node: NamedExports) {
- emitNamedImportsOrExports(node);
- }
-
- function emitExportSpecifier(node: ExportSpecifier) {
- emitImportOrExportSpecifier(node);
- }
-
- function emitNamedImportsOrExports(node: NamedImportsOrExports) {
- write("{");
- emitList(node, node.elements, ListFormat.NamedImportsOrExportsElements);
- write("}");
- }
-
- function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) {
- if (node.propertyName) {
- emit(node.propertyName);
- write(" as ");
- }
-
- emit(node.name);
- }
-
- //
- // Module references
- //
-
- function emitExternalModuleReference(node: ExternalModuleReference) {
- write("require(");
- emitExpression(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("<");
- emitJsxTagName(node.tagName);
- write(" ");
- emitList(node, node.attributes, ListFormat.JsxElementAttributes);
- write("/>");
- }
-
- function emitJsxOpeningElement(node: JsxOpeningElement) {
- write("<");
- emitJsxTagName(node.tagName);
- writeIfAny(node.attributes, " ");
- emitList(node, node.attributes, ListFormat.JsxElementAttributes);
- write(">");
- }
-
- function emitJsxText(node: JsxText) {
- writer.writeLiteral(getTextOfNode(node, /*includeTrivia*/ true));
- }
-
- function emitJsxClosingElement(node: JsxClosingElement) {
- write("");
- emitJsxTagName(node.tagName);
- write(">");
- }
-
- function emitJsxAttribute(node: JsxAttribute) {
- emit(node.name);
- emitWithPrefix("=", node.initializer);
- }
-
- function emitJsxSpreadAttribute(node: JsxSpreadAttribute) {
- write("{...");
- emitExpression(node.expression);
- write("}");
- }
-
- function emitJsxExpression(node: JsxExpression) {
- if (node.expression) {
- write("{");
- if (node.dotDotDotToken) {
- write("...");
- }
- emitExpression(node.expression);
- write("}");
- }
- }
-
- function emitJsxTagName(node: JsxTagNameExpression) {
- if (node.kind === SyntaxKind.Identifier) {
- emitExpression(node);
- }
- else {
- emit(node);
- }
- }
-
- //
- // Clauses
- //
-
- function emitCaseClause(node: CaseClause) {
- write("case ");
- emitExpression(node.expression);
- write(":");
-
- emitCaseOrDefaultClauseStatements(node, node.statements);
- }
-
- function emitDefaultClause(node: DefaultClause) {
- write("default:");
- emitCaseOrDefaultClauseStatements(node, node.statements);
- }
-
- function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray) {
- const emitAsSingleStatement =
- statements.length === 1 &&
- (
- // treat synthesized nodes as located on the same line for emit purposes
- nodeIsSynthesized(parentNode) ||
- nodeIsSynthesized(statements[0]) ||
- rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile)
- );
-
- if (emitAsSingleStatement) {
- write(" ");
- emit(statements[0]);
- }
- else {
- emitList(parentNode, statements, ListFormat.CaseOrDefaultClauseStatements);
- }
- }
-
- function emitHeritageClause(node: HeritageClause) {
- write(" ");
- writeTokenText(node.token);
- write(" ");
- emitList(node, node.types, ListFormat.HeritageClauseTypes);
- }
-
- function emitCatchClause(node: CatchClause) {
- writeLine();
- const openParenPos = writeToken(SyntaxKind.CatchKeyword, node.pos);
- write(" ");
- writeToken(SyntaxKind.OpenParenToken, openParenPos);
- emit(node.variableDeclaration);
- writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration ? node.variableDeclaration.end : openParenPos);
- 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.
- const initializer = node.initializer;
- if ((getEmitFlags(initializer) & EmitFlags.NoLeadingComments) === 0) {
- const commentRange = getCommentRange(initializer);
- emitTrailingCommentsOfPosition(commentRange.pos);
- }
-
- emitExpression(initializer);
- }
-
- function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) {
- emit(node.name);
- if (node.objectAssignmentInitializer) {
- write(" = ");
- emitExpression(node.objectAssignmentInitializer);
- }
- }
-
- function emitSpreadAssignment(node: SpreadAssignment) {
- if (node.expression) {
- write("...");
- emitExpression(node.expression);
- }
- }
-
- //
- // Enum
- //
-
- function emitEnumMember(node: EnumMember) {
- emit(node.name);
- emitExpressionWithPrefix(" = ", node.initializer);
- }
-
- //
- // Top-level nodes
- //
-
- function emitSourceFile(node: SourceFile) {
- writeLine();
- emitShebang();
- emitBodyWithDetachedComments(node, node.statements, emitSourceFileWorker);
- }
-
- function emitSourceFileWorker(node: SourceFile) {
- const statements = node.statements;
- const statementOffset = emitPrologueDirectives(statements);
- const savedTempFlags = tempFlags;
- tempFlags = 0;
- emitHelpers(node);
- emitList(node, statements, ListFormat.MultiLine, statementOffset);
- tempFlags = savedTempFlags;
- }
-
- // Transformation nodes
-
- function emitPartiallyEmittedExpression(node: PartiallyEmittedExpression) {
- emitExpression(node.expression);
- }
-
- /**
- * Emits any prologue directives at the start of a Statement list, returning the
- * number of prologue directives written to the output.
- */
- function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean): number {
- for (let i = 0; i < statements.length; i++) {
- if (isPrologueDirective(statements[i])) {
- if (startWithNewLine || i > 0) {
- writeLine();
- }
- emit(statements[i]);
- }
- else {
- // return index of the first non prologue directive
- return i;
- }
- }
-
- return statements.length;
- }
-
- function emitHelpers(node: Node, isBundle?: boolean) {
- const sourceFile = isSourceFile(node) ? node : currentSourceFile;
- const shouldSkip = compilerOptions.noEmitHelpers || (sourceFile && getExternalHelpersModuleName(sourceFile) !== undefined);
- const shouldBundle = isSourceFile(node) && !isOwnFileEmit;
-
+ function emitHelpers(node: Node, writeLines: (text: string) => void) {
let helpersEmitted = false;
- const helpers = getEmitHelpers(node);
- if (helpers) {
- for (const helper of stableSort(helpers, compareEmitHelpers)) {
- if (!helper.scoped) {
- // Skip the helper if it can be skipped and the noEmitHelpers compiler
- // option is set, or if it can be imported and the importHelpers compiler
- // option is set.
- if (shouldSkip) continue;
+ const bundle = node.kind === SyntaxKind.Bundle ? node : undefined;
+ const numNodes = bundle ? bundle.sourceFiles.length : 1;
+ for (let i = 0; i < numNodes; i++) {
+ const currentNode = bundle ? bundle.sourceFiles[i] : node;
+ const sourceFile = isSourceFile(currentNode) ? currentNode : currentSourceFile;
+ const shouldSkip = compilerOptions.noEmitHelpers || (sourceFile && getExternalHelpersModuleName(sourceFile) !== undefined);
+ const shouldBundle = isSourceFile(currentNode) && !isOwnFileEmit;
+ const helpers = getEmitHelpers(currentNode);
+ if (helpers) {
+ for (const helper of stableSort(helpers, compareEmitHelpers)) {
+ if (!helper.scoped) {
+ // Skip the helper if it can be skipped and the noEmitHelpers compiler
+ // option is set, or if it can be imported and the importHelpers compiler
+ // option is set.
+ if (shouldSkip) continue;
- // Skip the helper if it can be bundled but hasn't already been emitted and we
- // are emitting a bundled module.
- if (shouldBundle) {
- if (bundledHelpers.get(helper.name)) {
- continue;
+ // Skip the helper if it can be bundled but hasn't already been emitted and we
+ // are emitting a bundled module.
+ if (shouldBundle) {
+ if (bundledHelpers.get(helper.name)) {
+ continue;
+ }
+
+ bundledHelpers.set(helper.name, true);
}
-
- bundledHelpers.set(helper.name, true);
}
- }
- else if (isBundle) {
- // Skip the helper if it is scoped and we are emitting bundled helpers
- continue;
- }
+ else if (bundle) {
+ // Skip the helper if it is scoped and we are emitting bundled helpers
+ continue;
+ }
- writeLines(helper.text);
- helpersEmitted = true;
+ writeLines(helper.text);
+ helpersEmitted = true;
+ }
}
}
- if (helpersEmitted) {
- writeLine();
- }
-
return helpersEmitted;
}
-
- function writeLines(text: string): void {
- const lines = text.split(/\r\n?|\n/g);
- const indentation = guessIndentation(lines);
- for (let i = 0; i < lines.length; i++) {
- const line = indentation ? lines[i].slice(indentation) : lines[i];
- if (line.length) {
- if (i > 0) {
- writeLine();
- }
- write(line);
- }
- }
- }
-
- function guessIndentation(lines: string[]) {
- let indentation: number;
- for (const line of lines) {
- for (let i = 0; i < line.length && (indentation === undefined || i < indentation); i++) {
- if (!isWhiteSpace(line.charCodeAt(i))) {
- if (indentation === undefined || i < indentation) {
- indentation = i;
- break;
- }
- }
- }
- }
- return indentation;
- }
-
- //
- // Helpers
- //
-
- function emitShebang() {
- const shebang = getShebang(currentText);
- if (shebang) {
- write(shebang);
- writeLine();
- }
- }
-
- function emitModifiers(node: Node, modifiers: NodeArray) {
- if (modifiers && modifiers.length) {
- emitList(node, modifiers, ListFormat.Modifiers);
- write(" ");
- }
- }
-
- function emitWithPrefix(prefix: string, node: Node) {
- emitNodeWithPrefix(prefix, node, emit);
- }
-
- function emitExpressionWithPrefix(prefix: string, node: Node) {
- emitNodeWithPrefix(prefix, node, emitExpression);
- }
-
- function emitNodeWithPrefix(prefix: string, node: Node, emit: (node: Node) => void) {
- if (node) {
- write(prefix);
- emit(node);
- }
- }
-
- function emitWithSuffix(node: Node, suffix: string) {
- if (node) {
- emit(node);
- write(suffix);
- }
- }
-
- function emitEmbeddedStatement(parent: Node, node: Statement) {
- if (isBlock(node) || getEmitFlags(parent) & EmitFlags.SingleLine) {
- write(" ");
- emit(node);
- }
- else {
- writeLine();
- increaseIndent();
- emit(node);
- decreaseIndent();
- }
- }
-
- function emitDecorators(parentNode: Node, decorators: NodeArray) {
- emitList(parentNode, decorators, ListFormat.Decorators);
- }
-
- function emitTypeArguments(parentNode: Node, typeArguments: NodeArray) {
- emitList(parentNode, typeArguments, ListFormat.TypeArguments);
- }
-
- function emitTypeParameters(parentNode: Node, typeParameters: NodeArray) {
- emitList(parentNode, typeParameters, ListFormat.TypeParameters);
- }
-
- function emitParameters(parentNode: Node, parameters: NodeArray) {
- emitList(parentNode, parameters, ListFormat.Parameters);
- }
-
- function emitParametersForArrow(parentNode: Node, parameters: NodeArray) {
- if (parameters &&
- parameters.length === 1 &&
- parameters[0].type === undefined &&
- parameters[0].pos === parentNode.pos) {
- emit(parameters[0]);
- }
- else {
- emitParameters(parentNode, parameters);
- }
- }
-
- function emitParametersForIndexSignature(parentNode: Node, parameters: NodeArray) {
- emitList(parentNode, parameters, ListFormat.IndexSignatureParameters);
- }
-
- function emitList(parentNode: Node, children: NodeArray, format: ListFormat, start?: number, count?: number) {
- emitNodeList(emit, parentNode, children, format, start, count);
- }
-
- function emitExpressionList(parentNode: Node, children: NodeArray, format: ListFormat, start?: number, count?: number) {
- emitNodeList(emitExpression, parentNode, children, format, start, count);
- }
-
- function emitNodeList(emit: (node: Node) => void, parentNode: Node, children: NodeArray, format: ListFormat, start = 0, count = children ? children.length - start : 0) {
- const isUndefined = children === undefined;
- if (isUndefined && format & ListFormat.OptionalIfUndefined) {
- return;
- }
-
- const isEmpty = isUndefined || children.length === 0 || start >= children.length || count === 0;
- if (isEmpty && format & ListFormat.OptionalIfEmpty) {
- return;
- }
-
- if (format & ListFormat.BracketsMask) {
- write(getOpeningBracket(format));
- }
-
- if (isEmpty) {
- // Write a line terminator if the parent node was multi-line
- if (format & ListFormat.MultiLine) {
- writeLine();
- }
- else if (format & ListFormat.SpaceBetweenBraces) {
- write(" ");
- }
- }
- else {
- // Write the opening line terminator or leading whitespace.
- const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0;
- let shouldEmitInterveningComments = mayEmitInterveningComments;
- if (shouldWriteLeadingLineTerminator(parentNode, children, format)) {
- writeLine();
- shouldEmitInterveningComments = false;
- }
- else if (format & ListFormat.SpaceBetweenBraces) {
- write(" ");
- }
-
- // Increase the indent, if requested.
- if (format & ListFormat.Indented) {
- increaseIndent();
- }
-
- // Emit each child.
- let previousSibling: Node;
- let shouldDecreaseIndentAfterEmit: boolean;
- const delimiter = getDelimiter(format);
- for (let i = 0; i < count; i++) {
- const child = children[start + i];
-
- // 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)) {
- // If a synthesized node in a single-line list starts on a new
- // line, we should increase the indent.
- if ((format & (ListFormat.LinesMask | ListFormat.Indented)) === ListFormat.SingleLine) {
- increaseIndent();
- shouldDecreaseIndentAfterEmit = true;
- }
-
- writeLine();
- shouldEmitInterveningComments = false;
- }
- else if (previousSibling && format & ListFormat.SpaceBetweenSiblings) {
- write(" ");
- }
- }
-
- if (shouldEmitInterveningComments) {
- const commentRange = getCommentRange(child);
- emitTrailingCommentsOfPosition(commentRange.pos);
- }
- else {
- shouldEmitInterveningComments = mayEmitInterveningComments;
- }
-
- // Emit this child.
- emit(child);
-
- if (shouldDecreaseIndentAfterEmit) {
- decreaseIndent();
- shouldDecreaseIndentAfterEmit = false;
- }
-
- previousSibling = child;
- }
-
- // Write a trailing comma, if requested.
- const 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(parentNode, children, format)) {
- writeLine();
- }
- else if (format & ListFormat.SpaceBetweenBraces) {
- write(" ");
- }
- }
-
- if (format & ListFormat.BracketsMask) {
- write(getClosingBracket(format));
- }
- }
-
- function writeLineOrSpace(node: Node) {
- if (getEmitFlags(node) & EmitFlags.SingleLine) {
- write(" ");
- }
- else {
- writeLine();
- }
- }
-
- 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 writeToken(token: SyntaxKind, pos: number, contextNode?: Node) {
- return emitTokenWithSourceMap(contextNode, token, pos, writeTokenText);
- }
-
- function writeTokenText(token: SyntaxKind, pos?: number) {
- const tokenString = tokenToString(token);
- write(tokenString);
- return pos < 0 ? pos : pos + tokenString.length;
- }
-
- 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(parentNode: Node, children: NodeArray, format: ListFormat) {
- if (format & ListFormat.MultiLine) {
- return true;
- }
-
- if (format & ListFormat.PreserveLines) {
- if (format & ListFormat.PreferNewLine) {
- return true;
- }
-
- const firstChild = children[0];
- if (firstChild === undefined) {
- return !rangeIsOnSingleLine(parentNode, currentSourceFile);
- }
- else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) {
- return synthesizedNodeStartsOnNewLine(firstChild, format);
- }
- else {
- return !rangeStartPositionsAreOnSameLine(parentNode, firstChild, currentSourceFile);
- }
- }
- else {
- return false;
- }
- }
-
- function shouldWriteSeparatingLineTerminator(previousNode: Node, nextNode: Node, format: ListFormat) {
- if (format & ListFormat.MultiLine) {
- return true;
- }
- else if (format & ListFormat.PreserveLines) {
- if (previousNode === undefined || nextNode === undefined) {
- return false;
- }
- else if (nodeIsSynthesized(previousNode) || nodeIsSynthesized(nextNode)) {
- return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format);
- }
- else {
- return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile);
- }
- }
- else {
- return nextNode.startsOnNewLine;
- }
- }
-
- function shouldWriteClosingLineTerminator(parentNode: Node, children: NodeArray, format: ListFormat) {
- if (format & ListFormat.MultiLine) {
- return (format & ListFormat.NoTrailingNewLine) === 0;
- }
- else if (format & ListFormat.PreserveLines) {
- if (format & ListFormat.PreferNewLine) {
- return true;
- }
-
- const lastChild = lastOrUndefined(children);
- if (lastChild === undefined) {
- return !rangeIsOnSingleLine(parentNode, currentSourceFile);
- }
- else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) {
- return synthesizedNodeStartsOnNewLine(lastChild, format);
- }
- else {
- return !rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile);
- }
- }
- else {
- return false;
- }
- }
-
- function synthesizedNodeStartsOnNewLine(node: Node, format?: ListFormat) {
- if (nodeIsSynthesized(node)) {
- const startsOnNewLine = node.startsOnNewLine;
- if (startsOnNewLine === undefined) {
- return (format & ListFormat.PreferNewLine) !== 0;
- }
-
- return startsOnNewLine;
- }
-
- return (format & ListFormat.PreferNewLine) !== 0;
- }
-
- function needsIndentation(parent: Node, node1: Node, node2: Node): boolean {
- parent = skipSynthesizedParentheses(parent);
- node1 = skipSynthesizedParentheses(node1);
- node2 = skipSynthesizedParentheses(node2);
-
- // Always use a newline for synthesized code if the synthesizer desires it.
- if (node2.startsOnNewLine) {
- return true;
- }
-
- return !nodeIsSynthesized(parent)
- && !nodeIsSynthesized(node1)
- && !nodeIsSynthesized(node2)
- && !rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile);
- }
-
- function skipSynthesizedParentheses(node: Node) {
- while (node.kind === SyntaxKind.ParenthesizedExpression && nodeIsSynthesized(node)) {
- node = (node).expression;
- }
-
- return node;
- }
-
- function getTextOfNode(node: Node, includeTrivia?: boolean): string {
- if (isGeneratedIdentifier(node)) {
- return getGeneratedIdentifier(node);
- }
- else if (isIdentifier(node) && (nodeIsSynthesized(node) || !node.parent)) {
- return unescapeIdentifier(node.text);
- }
- else if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) {
- return getTextOfNode((node).textSourceNode, includeTrivia);
- }
- else if (isLiteralExpression(node) && (nodeIsSynthesized(node) || !node.parent)) {
- return node.text;
- }
-
- return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia);
- }
-
- function getLiteralTextOfNode(node: LiteralLikeNode): string {
- if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) {
- const textSourceNode = (node).textSourceNode;
- if (isIdentifier(textSourceNode)) {
- return "\"" + escapeNonAsciiCharacters(escapeString(getTextOfNode(textSourceNode))) + "\"";
- }
- else {
- return getLiteralTextOfNode(textSourceNode);
- }
- }
-
- return getLiteralText(node, currentSourceFile, languageVersion);
- }
-
- function isSingleLineEmptyBlock(block: Block) {
- return !block.multiLine
- && isEmptyBlock(block);
- }
-
- function isEmptyBlock(block: BlockLike) {
- return block.statements.length === 0
- && rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile);
- }
-
- function isUniqueName(name: string): boolean {
- return !resolver.hasGlobalName(name) &&
- !currentFileIdentifiers.has(name) &&
- !generatedNameSet.has(name);
- }
-
- function isUniqueLocalName(name: string, container: Node): boolean {
- for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) {
- if (node.locals) {
- const local = node.locals.get(name);
- // We conservatively include alias symbols to cover cases where they're emitted as locals
- if (local && local.flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Return the next available name in the pattern _a ... _z, _0, _1, ...
- * TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name.
- * Note that names generated by makeTempVariableName and makeUniqueName will never conflict.
- */
- function makeTempVariableName(flags: TempFlags): string {
- if (flags && !(tempFlags & flags)) {
- const name = flags === TempFlags._i ? "_i" : "_n";
- if (isUniqueName(name)) {
- tempFlags |= flags;
- return name;
- }
- }
- while (true) {
- const count = tempFlags & TempFlags.CountMask;
- tempFlags++;
- // Skip over 'i' and 'n'
- if (count !== 8 && count !== 13) {
- const name = count < 26
- ? "_" + String.fromCharCode(CharacterCodes.a + count)
- : "_" + (count - 26);
- if (isUniqueName(name)) {
- return name;
- }
- }
- }
- }
-
- // Generate a name that is unique within the current file and doesn't conflict with any names
- // in global scope. The name is formed by adding an '_n' suffix to the specified base name,
- // where n is a positive integer. Note that names generated by makeTempVariableName and
- // makeUniqueName are guaranteed to never conflict.
- function makeUniqueName(baseName: string): string {
- // Find the first unique 'name_n', where n is a positive number
- if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) {
- baseName += "_";
- }
- let i = 1;
- while (true) {
- const generatedName = baseName + i;
- if (isUniqueName(generatedName)) {
- generatedNameSet.set(generatedName, generatedName);
- return generatedName;
- }
- i++;
- }
- }
-
- function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) {
- const name = getTextOfNode(node.name);
- // Use module/enum name itself if it is unique, otherwise make a unique variation
- return isUniqueLocalName(name, node) ? name : makeUniqueName(name);
- }
-
- function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) {
- const expr = getExternalModuleName(node);
- const baseName = expr.kind === SyntaxKind.StringLiteral ?
- escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module";
- return makeUniqueName(baseName);
- }
-
- function generateNameForExportDefault() {
- return makeUniqueName("default");
- }
-
- function generateNameForClassExpression() {
- return makeUniqueName("class");
- }
-
- function generateNameForMethodOrAccessor(node: MethodDeclaration | AccessorDeclaration) {
- if (isIdentifier(node.name)) {
- return generateNameForNodeCached(node.name);
- }
- return makeTempVariableName(TempFlags.Auto);
- }
-
- /**
- * Generates a unique name from a node.
- *
- * @param node A node.
- */
- function generateNameForNode(node: Node): string {
- switch (node.kind) {
- case SyntaxKind.Identifier:
- return makeUniqueName(getTextOfNode(node));
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.EnumDeclaration:
- return generateNameForModuleOrEnum(node);
- case SyntaxKind.ImportDeclaration:
- case SyntaxKind.ExportDeclaration:
- return generateNameForImportOrExportDeclaration(node);
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.ExportAssignment:
- return generateNameForExportDefault();
- case SyntaxKind.ClassExpression:
- return generateNameForClassExpression();
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- return generateNameForMethodOrAccessor(node);
- default:
- return makeTempVariableName(TempFlags.Auto);
- }
- }
-
- /**
- * Generates a unique identifier for a node.
- *
- * @param name A generated name.
- */
- function generateName(name: Identifier) {
- switch (name.autoGenerateKind) {
- case GeneratedIdentifierKind.Auto:
- return makeTempVariableName(TempFlags.Auto);
- case GeneratedIdentifierKind.Loop:
- return makeTempVariableName(TempFlags._i);
- case GeneratedIdentifierKind.Unique:
- return makeUniqueName(name.text);
- }
-
- Debug.fail("Unsupported GeneratedIdentifierKind.");
- }
-
- /**
- * Gets the node from which a name should be generated.
- *
- * @param name A generated name wrapper.
- */
- function getNodeForGeneratedName(name: Identifier) {
- const autoGenerateId = name.autoGenerateId;
- let node = name as Node;
- let original = node.original;
- while (original) {
- node = original;
-
- // if "node" is a different generated name (having a different
- // "autoGenerateId"), use it and stop traversing.
- if (isIdentifier(node)
- && node.autoGenerateKind === GeneratedIdentifierKind.Node
- && node.autoGenerateId !== autoGenerateId) {
- break;
- }
-
- original = node.original;
- }
-
- // otherwise, return the original node for the source;
- return node;
- }
-
- function generateNameForNodeCached(node: Node) {
- const nodeId = getNodeId(node);
- return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node)));
- }
-
- /**
- * Gets the generated identifier text from a generated identifier.
- *
- * @param name The generated identifier.
- */
- function getGeneratedIdentifier(name: Identifier) {
- if (name.autoGenerateKind === GeneratedIdentifierKind.Node) {
- // Generated names generate unique names based on their original node
- // and are cached based on that node's id
- const node = getNodeForGeneratedName(name);
- return generateNameForNodeCached(node);
- }
- else {
- // Auto, Loop, and Unique names are cached based on their unique
- // autoGenerateId.
- const autoGenerateId = name.autoGenerateId;
- return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = unescapeIdentifier(generateName(name)));
- }
- }
-
- function createDelimiterMap() {
- const 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() {
- const brackets: string[][] = [];
- brackets[ListFormat.Braces] = ["{", "}"];
- brackets[ListFormat.Parenthesis] = ["(", ")"];
- brackets[ListFormat.AngleBrackets] = ["<", ">"];
- brackets[ListFormat.SquareBrackets] = ["[", "]"];
- return brackets;
- }
-
- function getOpeningBracket(format: ListFormat) {
- return brackets[format & ListFormat.BracketsMask][0];
- }
-
- function getClosingBracket(format: ListFormat) {
- return brackets[format & ListFormat.BracketsMask][1];
- }
}
-
- const enum ListFormat {
- None = 0,
-
- // Line separators
- SingleLine = 0, // Prints the list on a single line (default).
- MultiLine = 1 << 0, // Prints the list on multiple lines.
- PreserveLines = 1 << 1, // Prints the list using line preservation if possible.
- LinesMask = SingleLine | MultiLine | PreserveLines,
-
- // Delimiters
- NotDelimited = 0, // There is no delimiter between list items (default).
- BarDelimited = 1 << 2, // Each list item is space-and-bar (" |") delimited.
- AmpersandDelimited = 1 << 3, // Each list item is space-and-ampersand (" &") delimited.
- CommaDelimited = 1 << 4, // Each list item is comma (",") delimited.
- DelimitersMask = BarDelimited | AmpersandDelimited | CommaDelimited,
-
- AllowTrailingComma = 1 << 5, // Write a trailing comma (",") if present.
-
- // Whitespace
- Indented = 1 << 6, // The list should be indented.
- SpaceBetweenBraces = 1 << 7, // Inserts a space after the opening brace and before the closing brace.
- SpaceBetweenSiblings = 1 << 8, // Inserts a space between each sibling node.
-
- // Brackets/Braces
- Braces = 1 << 9, // The list is surrounded by "{" and "}".
- Parenthesis = 1 << 10, // The list is surrounded by "(" and ")".
- AngleBrackets = 1 << 11, // The list is surrounded by "<" and ">".
- SquareBrackets = 1 << 12, // The list is surrounded by "[" and "]".
- BracketsMask = Braces | Parenthesis | AngleBrackets | SquareBrackets,
-
- OptionalIfUndefined = 1 << 13, // Do not emit brackets if the list is undefined.
- OptionalIfEmpty = 1 << 14, // Do not emit brackets if the list is empty.
- Optional = OptionalIfUndefined | OptionalIfEmpty,
-
- // Other
- PreferNewLine = 1 << 15, // Prefer adding a LineTerminator between synthesized nodes.
- NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list.
- NoInterveningComments = 1 << 17, // Do not emit comments between each node
-
- // Precomputed Formats
- Modifiers = SingleLine | SpaceBetweenSiblings,
- HeritageClauses = SingleLine | SpaceBetweenSiblings,
- TypeLiteralMembers = MultiLine | Indented,
- TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented,
- UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine,
- IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine,
- ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings,
- ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings,
- ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces,
- ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets,
- CallExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis,
- NewExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis | OptionalIfUndefined,
- TemplateExpressionSpans = SingleLine | NoInterveningComments,
- SingleLineBlockStatements = SpaceBetweenBraces | SpaceBetweenSiblings | SingleLine,
- MultiLineBlockStatements = Indented | MultiLine,
- VariableDeclarationList = CommaDelimited | SpaceBetweenSiblings | SingleLine,
- SingleLineFunctionBodyStatements = SingleLine | SpaceBetweenSiblings | SpaceBetweenBraces,
- MultiLineFunctionBodyStatements = MultiLine,
- ClassHeritageClauses = SingleLine | SpaceBetweenSiblings,
- ClassMembers = Indented | MultiLine,
- InterfaceMembers = Indented | MultiLine,
- EnumMembers = CommaDelimited | Indented | MultiLine,
- CaseBlockClauses = Indented | MultiLine,
- NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine | SpaceBetweenBraces,
- JsxElementChildren = SingleLine | NoInterveningComments,
- JsxElementAttributes = SingleLine | SpaceBetweenSiblings | NoInterveningComments,
- CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty,
- HeritageClauseTypes = CommaDelimited | SpaceBetweenSiblings | SingleLine,
- SourceFileStatements = MultiLine | NoTrailingNewLine,
- Decorators = MultiLine | Optional,
- TypeArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | AngleBrackets | Optional,
- TypeParameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | AngleBrackets | Optional,
- Parameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | Parenthesis,
- IndexSignatureParameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | SquareBrackets,
- }
-}
+}
\ No newline at end of file
diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts
index f63094ae16d..f2a8de3a93b 100644
--- a/src/compiler/factory.ts
+++ b/src/compiler/factory.ts
@@ -1530,6 +1530,19 @@ namespace ts {
return node;
}
+ export function createBundle(sourceFiles: SourceFile[]) {
+ const node = createNode(SyntaxKind.Bundle);
+ node.sourceFiles = sourceFiles;
+ return node;
+ }
+
+ export function updateBundle(node: Bundle, sourceFiles: SourceFile[]) {
+ if (node.sourceFiles !== sourceFiles) {
+ return createBundle(sourceFiles);
+ }
+ return node;
+ }
+
// Compound nodes
export function createComma(left: Expression, right: Expression) {
diff --git a/src/compiler/printer.ts b/src/compiler/printer.ts
new file mode 100644
index 00000000000..9ae824dac67
--- /dev/null
+++ b/src/compiler/printer.ts
@@ -0,0 +1,2659 @@
+///
+
+namespace ts {
+ // Flags enum to track count of temp variables and a few dedicated names
+ const enum TempFlags {
+ Auto = 0x00000000, // No preferred name
+ CountMask = 0x0FFFFFFF, // Temp variable counter
+ _i = 0x10000000, // Use/preference flag for '_i'
+ }
+
+ const delimiters = createDelimiterMap();
+ const brackets = createBracketsMap();
+
+ export function createPrinter(writer: EmitTextWriter, compilerOptions: CompilerOptions, printerOptions: PrinterOptions = {}): Printer {
+ const languageVersion = getEmitScriptTarget(compilerOptions);
+ const moduleKind = getEmitModuleKind(compilerOptions);
+ const {
+ hasGlobalName,
+ onEmitSourceMapOfNode,
+ onEmitSourceMapOfToken,
+ onEmitCommentsOfNode,
+ onEmitDetachedCommentsOfNode,
+ onEmitTrailingCommentsOfPosition,
+ onEmitNode,
+ onEmitHelpers,
+ onSetSourceFile,
+ onSubstituteNode,
+ } = printerOptions;
+ const {
+ write,
+ writeLine,
+ increaseIndent,
+ decreaseIndent
+ } = writer;
+
+ let currentSourceFile: SourceFile;
+ let nodeIdToGeneratedName: string[]; // Map of generated names for specific nodes.
+ let autoGeneratedIdToGeneratedName: string[]; // Map of generated names for temp and loop variables.
+ let generatedNames: Map; // Set of names generated by the NameGenerator.
+ let tempFlagsStack: TempFlags[]; // Stack of enclosing name generation scopes.
+ let tempFlags: TempFlags; // TempFlags for the current name generation scope.
+
+ return {
+ printNode,
+ printFile,
+ printBundle
+ };
+
+ function printNode(hint: EmitHint, node: Node, sourceFile: SourceFile) {
+ print(hint, node, sourceFile);
+ resetGeneratedNames();
+ }
+
+ function printBundle(bundle: Bundle) {
+ if (moduleKind) {
+ emitHelpersIndirect(bundle);
+ }
+ for (const sourceFile of bundle.sourceFiles) {
+ print(EmitHint.SourceFile, sourceFile, sourceFile);
+ }
+ resetGeneratedNames();
+ }
+
+ function printFile(sourceFile: SourceFile) {
+ print(EmitHint.SourceFile, sourceFile, sourceFile);
+ resetGeneratedNames();
+ }
+
+ function print(hint: EmitHint, node: Node, sourceFile: SourceFile) {
+ setSourceFile(sourceFile);
+ pipelineEmitWithNotification(hint, node);
+ }
+
+ function setSourceFile(sourceFile: SourceFile) {
+ currentSourceFile = sourceFile;
+
+ if (onSetSourceFile) {
+ onSetSourceFile(sourceFile);
+ }
+ }
+
+ function emit(node: Node, hint = EmitHint.Unspecified) {
+ pipelineEmitWithNotification(hint, node);
+ }
+
+ function emitIdentifierName(node: Identifier) {
+ pipelineEmitWithNotification(EmitHint.IdentifierName, node);
+ }
+
+ function emitExpression(node: Expression) {
+ pipelineEmitWithNotification(EmitHint.Expression, node);
+ }
+
+ function pipelineEmitWithNotification(hint: EmitHint, node: Node) {
+ if (onEmitNode) {
+ onEmitNode(hint, node, pipelineEmitWithComments);
+ }
+ else {
+ pipelineEmitWithComments(hint, node);
+ }
+ }
+
+ function pipelineEmitWithComments(hint: EmitHint, node: Node) {
+ if (onEmitCommentsOfNode && hint !== EmitHint.SourceFile) {
+ onEmitCommentsOfNode(hint, node, pipelineEmitWithSourceMap);
+ }
+ else {
+ pipelineEmitWithSourceMap(hint, node);
+ }
+ }
+
+ function pipelineEmitWithSourceMap(hint: EmitHint, node: Node) {
+ if (onEmitSourceMapOfNode && hint !== EmitHint.SourceFile && hint !== EmitHint.IdentifierName) {
+ onEmitSourceMapOfNode(hint, node, pipelineEmitWithSubstitution);
+ }
+ else {
+ pipelineEmitWithSubstitution(hint, node);
+ }
+ }
+
+ function pipelineEmitWithSubstitution(hint: EmitHint, node: Node) {
+ if (onSubstituteNode) {
+ onSubstituteNode(hint, node, pipelineEmitWithHint);
+ }
+ else {
+ pipelineEmitWithHint(hint, node);
+ }
+ }
+
+ function pipelineEmitWithHint(hint: EmitHint, node: Node): void {
+ switch (hint) {
+ case EmitHint.SourceFile: return pipelineEmitSourceFile(node);
+ case EmitHint.IdentifierName: return pipelineEmitIdentifierName(node);
+ case EmitHint.Expression: return pipelineEmitExpression(node);
+ case EmitHint.Unspecified: return pipelineEmitUnspecified(node);
+ }
+ }
+
+ function pipelineEmitSourceFile(node: Node): void {
+ Debug.assertNode(node, isSourceFile);
+ emitSourceFile(node);
+ }
+
+ function pipelineEmitIdentifierName(node: Node): void {
+ Debug.assertNode(node, isIdentifier);
+ emitIdentifier(node);
+ }
+
+ function pipelineEmitUnspecified(node: Node): void {
+ const kind = node.kind;
+ switch (kind) {
+ // 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.ConstKeyword:
+ case SyntaxKind.DefaultKeyword:
+ case SyntaxKind.ExportKeyword:
+ case SyntaxKind.VoidKeyword:
+
+ // Strict mode reserved words
+ case SyntaxKind.PrivateKeyword:
+ case SyntaxKind.ProtectedKeyword:
+ case SyntaxKind.PublicKeyword:
+ case SyntaxKind.StaticKeyword:
+
+ // Contextual keywords
+ case SyntaxKind.AbstractKeyword:
+ case SyntaxKind.AsKeyword:
+ case SyntaxKind.AnyKeyword:
+ case SyntaxKind.AsyncKeyword:
+ case SyntaxKind.AwaitKeyword:
+ case SyntaxKind.BooleanKeyword:
+ case SyntaxKind.ConstructorKeyword:
+ case SyntaxKind.DeclareKeyword:
+ case SyntaxKind.GetKeyword:
+ case SyntaxKind.IsKeyword:
+ case SyntaxKind.ModuleKeyword:
+ case SyntaxKind.NamespaceKeyword:
+ case SyntaxKind.NeverKeyword:
+ case SyntaxKind.ReadonlyKeyword:
+ case SyntaxKind.RequireKeyword:
+ case SyntaxKind.NumberKeyword:
+ case SyntaxKind.SetKeyword:
+ case SyntaxKind.StringKeyword:
+ case SyntaxKind.SymbolKeyword:
+ case SyntaxKind.TypeKeyword:
+ case SyntaxKind.UndefinedKeyword:
+ case SyntaxKind.FromKeyword:
+ case SyntaxKind.GlobalKeyword:
+ case SyntaxKind.OfKeyword:
+ writeTokenText(kind);
+ return;
+
+ // 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);
+ case SyntaxKind.ExpressionWithTypeArguments:
+ return emitExpressionWithTypeArguments(node);
+ case SyntaxKind.ThisType:
+ return emitThisType();
+ case SyntaxKind.TypeOperator:
+ return emitTypeOperator(node);
+ case SyntaxKind.IndexedAccessType:
+ return emitIndexedAccessType(node);
+ case SyntaxKind.MappedType:
+ return emitMappedType(node);
+ case SyntaxKind.LiteralType:
+ return emitLiteralType(node);
+
+ // Binding patterns
+ case SyntaxKind.ObjectBindingPattern:
+ return emitObjectBindingPattern(node);
+ case SyntaxKind.ArrayBindingPattern:
+ return emitArrayBindingPattern(node);
+ case SyntaxKind.BindingElement:
+ return emitBindingElement(node);
+
+ // Misc
+ case SyntaxKind.TemplateSpan:
+ return emitTemplateSpan(node);
+ case SyntaxKind.SemicolonClassElement:
+ return emitSemicolonClassElement();
+
+ // Statements
+ case SyntaxKind.Block:
+ return emitBlock(node);
+ case SyntaxKind.VariableStatement:
+ return emitVariableStatement(node);
+ case SyntaxKind.EmptyStatement:
+ return emitEmptyStatement();
+ 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 emitNamedImports(node);
+ case SyntaxKind.ImportSpecifier:
+ return emitImportSpecifier(node);
+ case SyntaxKind.ExportAssignment:
+ return emitExportAssignment(node);
+ case SyntaxKind.ExportDeclaration:
+ return emitExportDeclaration(node);
+ case SyntaxKind.NamedExports:
+ return emitNamedExports(node);
+ case SyntaxKind.ExportSpecifier:
+ return emitExportSpecifier(node);
+ case SyntaxKind.MissingDeclaration:
+ return;
+
+ // Module references
+ case SyntaxKind.ExternalModuleReference:
+ return emitExternalModuleReference(node);
+
+ // JSX (non-expression)
+ case SyntaxKind.JsxText:
+ return emitJsxText(node);
+ case SyntaxKind.JsxOpeningElement:
+ return emitJsxOpeningElement(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(