diff --git a/Jakefile b/Jakefile
index 3a19812b958..41f417618d7 100644
--- a/Jakefile
+++ b/Jakefile
@@ -39,6 +39,7 @@ var compilerSources = [
"utilities.ts",
"binder.ts",
"checker.ts",
+ "declarationEmitter.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
@@ -57,6 +58,7 @@ var servicesSources = [
"utilities.ts",
"binder.ts",
"checker.ts",
+ "declarationEmitter.ts",
"emitter.ts",
"program.ts",
"commandLineParser.ts",
@@ -65,7 +67,7 @@ var servicesSources = [
return path.join(compilerDirectory, f);
}).concat([
"breakpoints.ts",
- "navigateTo.ts",
+ "navigateTo.ts",
"navigationBar.ts",
"outliningElementsCollector.ts",
"patternMatcher.ts",
@@ -539,7 +541,7 @@ function cleanTestDirs() {
}
jake.mkdirP(localRwcBaseline);
- jake.mkdirP(localTest262Baseline);
+ jake.mkdirP(localTest262Baseline);
jake.mkdirP(localBaseline);
}
diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts
new file mode 100644
index 00000000000..cf75467e1c5
--- /dev/null
+++ b/src/compiler/declarationEmitter.ts
@@ -0,0 +1,1466 @@
+///
+
+module ts {
+
+ interface ModuleElementDeclarationEmitInfo {
+ node: Node;
+ outputPos: number;
+ indent: number;
+ asynchronousOutput?: string; // If the output for alias was written asynchronously, the corresponding output
+ subModuleElementDeclarationEmitInfo?: ModuleElementDeclarationEmitInfo[];
+ isVisible?: boolean;
+ }
+
+ interface DeclarationEmit {
+ reportedDeclarationError: boolean;
+ moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[];
+ synchronousDeclarationOutput: string;
+ referencePathsOutput: string;
+ }
+
+ type GetSymbolAccessibilityDiagnostic = (symbolAccesibilityResult: SymbolAccessiblityResult) => SymbolAccessibilityDiagnostic;
+
+ interface EmitTextWriterWithSymbolWriter extends EmitTextWriter, SymbolWriter {
+ getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic;
+ }
+
+ interface SymbolAccessibilityDiagnostic {
+ errorNode: Node;
+ diagnosticMessage: DiagnosticMessage;
+ typeName?: DeclarationName;
+ }
+
+ export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] {
+ let diagnostics: Diagnostic[] = [];
+ let jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js");
+ emitDeclarations(host, resolver, diagnostics, jsFilePath, targetSourceFile);
+ return diagnostics;
+ }
+
+ function emitDeclarations(host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit {
+ let newLine = host.getNewLine();
+ let compilerOptions = host.getCompilerOptions();
+ let languageVersion = compilerOptions.target || ScriptTarget.ES3;
+
+ let write: (s: string) => void;
+ let writeLine: () => void;
+ let increaseIndent: () => void;
+ let decreaseIndent: () => void;
+ let writeTextOfNode: (sourceFile: SourceFile, node: Node) => void;
+
+ let writer = createAndSetNewTextWriterWithSymbolWriter();
+
+ let enclosingDeclaration: Node;
+ let currentSourceFile: SourceFile;
+ let reportedDeclarationError = false;
+ let emitJsDocComments = compilerOptions.removeComments ? function (declaration: Node) { } : writeJsDocComments;
+ let emit = compilerOptions.stripInternal ? stripInternal : emitNode;
+
+ let moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
+ let asynchronousSubModuleDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[];
+
+ // Contains the reference paths that needs to go in the declaration file.
+ // Collecting this separately because reference paths need to be first thing in the declaration file
+ // and we could be collecting these paths from multiple files into single one with --out option
+ let referencePathsOutput = "";
+
+ if (root) {
+ // Emitting just a single file, so emit references in this file only
+ if (!compilerOptions.noResolve) {
+ let addedGlobalFileReference = false;
+ forEach(root.referencedFiles, fileReference => {
+ let referencedFile = tryResolveScriptReference(host, root, fileReference);
+
+ // All the references that are not going to be part of same file
+ if (referencedFile && ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference
+ shouldEmitToOwnFile(referencedFile, compilerOptions) || // This is referenced file is emitting its own js file
+ !addedGlobalFileReference)) { // Or the global out file corresponding to this reference was not added
+
+ writeReferencePath(referencedFile);
+ if (!isExternalModuleOrDeclarationFile(referencedFile)) {
+ addedGlobalFileReference = true;
+ }
+ }
+ });
+ }
+
+ emitSourceFile(root);
+
+ // create asynchronous output for the importDeclarations
+ if (moduleElementDeclarationEmitInfo.length) {
+ let oldWriter = writer;
+ forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
+ if (aliasEmitInfo.isVisible) {
+ Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration);
+ createAndSetNewTextWriterWithSymbolWriter();
+ Debug.assert(aliasEmitInfo.indent === 0);
+ writeImportDeclaration(aliasEmitInfo.node);
+ aliasEmitInfo.asynchronousOutput = writer.getText();
+ }
+ });
+ setWriter(oldWriter);
+ }
+ }
+ else {
+ // Emit references corresponding to this file
+ let emittedReferencedFiles: SourceFile[] = [];
+ forEach(host.getSourceFiles(), sourceFile => {
+ if (!isExternalModuleOrDeclarationFile(sourceFile)) {
+ // Check what references need to be added
+ if (!compilerOptions.noResolve) {
+ forEach(sourceFile.referencedFiles, fileReference => {
+ let referencedFile = tryResolveScriptReference(host, sourceFile, fileReference);
+
+ // If the reference file is a declaration file or an external module, emit that reference
+ if (referencedFile && (isExternalModuleOrDeclarationFile(referencedFile) &&
+ !contains(emittedReferencedFiles, referencedFile))) { // If the file reference was not already emitted
+
+ writeReferencePath(referencedFile);
+ emittedReferencedFiles.push(referencedFile);
+ }
+ });
+ }
+
+ emitSourceFile(sourceFile);
+ }
+ });
+ }
+
+ return {
+ reportedDeclarationError,
+ moduleElementDeclarationEmitInfo,
+ synchronousDeclarationOutput: writer.getText(),
+ referencePathsOutput,
+ }
+
+ function hasInternalAnnotation(range: CommentRange) {
+ let text = currentSourceFile.text;
+ let comment = text.substring(range.pos, range.end);
+ return comment.indexOf("@internal") >= 0;
+ }
+
+ function stripInternal(node: Node) {
+ if (node) {
+ let leadingCommentRanges = getLeadingCommentRanges(currentSourceFile.text, node.pos);
+ if (forEach(leadingCommentRanges, hasInternalAnnotation)) {
+ return;
+ }
+
+ emitNode(node);
+ }
+ }
+
+ function createAndSetNewTextWriterWithSymbolWriter(): EmitTextWriterWithSymbolWriter {
+ let writer = createTextWriter(newLine);
+ writer.trackSymbol = trackSymbol;
+ writer.writeKeyword = writer.write;
+ writer.writeOperator = writer.write;
+ writer.writePunctuation = writer.write;
+ writer.writeSpace = writer.write;
+ writer.writeStringLiteral = writer.writeLiteral;
+ writer.writeParameter = writer.write;
+ writer.writeSymbol = writer.write;
+ setWriter(writer);
+ return writer;
+ }
+
+ function setWriter(newWriter: EmitTextWriterWithSymbolWriter) {
+ writer = newWriter;
+ write = newWriter.write;
+ writeTextOfNode = newWriter.writeTextOfNode;
+ writeLine = newWriter.writeLine;
+ increaseIndent = newWriter.increaseIndent;
+ decreaseIndent = newWriter.decreaseIndent;
+ }
+
+ function writeAsynchronousModuleElements(nodes: Node[]) {
+ let oldWriter = writer;
+ forEach(nodes, declaration => {
+ let nodeToCheck: Node;
+ if (declaration.kind === SyntaxKind.VariableDeclaration) {
+ nodeToCheck = declaration.parent.parent;
+ } else if (declaration.kind === SyntaxKind.NamedImports || declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ImportClause) {
+ Debug.fail("We should be getting ImportDeclaration instead to write");
+ } else {
+ nodeToCheck = declaration;
+ }
+
+ let moduleElementEmitInfo = forEach(moduleElementDeclarationEmitInfo, declEmitInfo => declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined);
+ if (!moduleElementEmitInfo && asynchronousSubModuleDeclarationEmitInfo) {
+ moduleElementEmitInfo = forEach(asynchronousSubModuleDeclarationEmitInfo, declEmitInfo => declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined);
+ }
+
+ // If the alias was marked as not visible when we saw its declaration, we would have saved the aliasEmitInfo, but if we haven't yet visited the alias declaration
+ // then we don't need to write it at this point. We will write it when we actually see its declaration
+ // Eg.
+ // export function bar(a: foo.Foo) { }
+ // import foo = require("foo");
+ // Writing of function bar would mark alias declaration foo as visible but we haven't yet visited that declaration so do nothing,
+ // we would write alias foo declaration when we visit it since it would now be marked as visible
+ if (moduleElementEmitInfo) {
+ if (moduleElementEmitInfo.node.kind === SyntaxKind.ImportDeclaration) {
+ // we have to create asynchronous output only after we have collected complete information
+ // because it is possible to enable multiple bindings as asynchronously visible
+ moduleElementEmitInfo.isVisible = true;
+ }
+ else {
+ createAndSetNewTextWriterWithSymbolWriter();
+ for (let declarationIndent = moduleElementEmitInfo.indent; declarationIndent; declarationIndent--) {
+ increaseIndent();
+ }
+
+ if (nodeToCheck.kind === SyntaxKind.ModuleDeclaration) {
+ Debug.assert(asynchronousSubModuleDeclarationEmitInfo === undefined);
+ asynchronousSubModuleDeclarationEmitInfo = [];
+ }
+ writeModuleElement(nodeToCheck);
+ if (nodeToCheck.kind === SyntaxKind.ModuleDeclaration) {
+ moduleElementEmitInfo.subModuleElementDeclarationEmitInfo = asynchronousSubModuleDeclarationEmitInfo;
+ asynchronousSubModuleDeclarationEmitInfo = undefined;
+ }
+ moduleElementEmitInfo.asynchronousOutput = writer.getText();
+ }
+ }
+ });
+ setWriter(oldWriter);
+ }
+
+ function handleSymbolAccessibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
+ if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
+ // write the aliases
+ if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) {
+ writeAsynchronousModuleElements(symbolAccesibilityResult.aliasesToMakeVisible);
+ }
+ }
+ else {
+ // Report error
+ reportedDeclarationError = true;
+ let errorInfo = writer.getSymbolAccessibilityDiagnostic(symbolAccesibilityResult);
+ if (errorInfo) {
+ if (errorInfo.typeName) {
+ diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
+ errorInfo.diagnosticMessage,
+ getSourceTextOfNodeFromSourceFile(currentSourceFile, errorInfo.typeName),
+ symbolAccesibilityResult.errorSymbolName,
+ symbolAccesibilityResult.errorModuleName));
+ }
+ else {
+ diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
+ errorInfo.diagnosticMessage,
+ symbolAccesibilityResult.errorSymbolName,
+ symbolAccesibilityResult.errorModuleName));
+ }
+ }
+ }
+ }
+
+ function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
+ handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning));
+ }
+
+ function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode | StringLiteralExpression, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
+ writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
+ write(": ");
+ if (type) {
+ // Write the type
+ emitType(type);
+ }
+ else {
+ resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
+ }
+ }
+
+ function writeReturnTypeAtSignature(signature: SignatureDeclaration, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
+ writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
+ write(": ");
+ if (signature.type) {
+ // Write the type
+ emitType(signature.type);
+ }
+ else {
+ resolver.writeReturnTypeOfSignatureDeclaration(signature, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
+ }
+ }
+
+ function emitLines(nodes: Node[]) {
+ for (let node of nodes) {
+ emit(node);
+ }
+ }
+
+ function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
+ let currentWriterPos = writer.getTextPos();
+ for (let node of nodes) {
+ if (!canEmitFn || canEmitFn(node)) {
+ if (currentWriterPos !== writer.getTextPos()) {
+ write(separator);
+ }
+ currentWriterPos = writer.getTextPos();
+ eachNodeEmitFn(node);
+ }
+ }
+ }
+
+ function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
+ emitSeparatedList(nodes, ", ", eachNodeEmitFn, canEmitFn);
+ }
+
+ function writeJsDocComments(declaration: Node) {
+ if (declaration) {
+ let jsDocComments = getJsDocComments(declaration, currentSourceFile);
+ emitNewLineBeforeLeadingComments(currentSourceFile, writer, declaration, jsDocComments);
+ // jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space
+ emitComments(currentSourceFile, writer, jsDocComments, /*trailingSeparator*/ true, newLine, writeCommentRange);
+ }
+ }
+
+ function emitTypeWithNewGetSymbolAccessibilityDiagnostic(type: TypeNode | EntityName, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
+ writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
+ emitType(type);
+ }
+
+ function emitType(type: TypeNode | StringLiteralExpression | Identifier | QualifiedName) {
+ switch (type.kind) {
+ case SyntaxKind.AnyKeyword:
+ case SyntaxKind.StringKeyword:
+ case SyntaxKind.NumberKeyword:
+ case SyntaxKind.BooleanKeyword:
+ case SyntaxKind.SymbolKeyword:
+ case SyntaxKind.VoidKeyword:
+ case SyntaxKind.StringLiteral:
+ return writeTextOfNode(currentSourceFile, type);
+ case SyntaxKind.TypeReference:
+ return emitTypeReference(type);
+ case SyntaxKind.TypeQuery:
+ return emitTypeQuery(type);
+ case SyntaxKind.ArrayType:
+ return emitArrayType(type);
+ case SyntaxKind.TupleType:
+ return emitTupleType(type);
+ case SyntaxKind.UnionType:
+ return emitUnionType(type);
+ case SyntaxKind.ParenthesizedType:
+ return emitParenType(type);
+ case SyntaxKind.FunctionType:
+ case SyntaxKind.ConstructorType:
+ return emitSignatureDeclarationWithJsDocComments(type);
+ case SyntaxKind.TypeLiteral:
+ return emitTypeLiteral(type);
+ case SyntaxKind.Identifier:
+ return emitEntityName(type);
+ case SyntaxKind.QualifiedName:
+ return emitEntityName(type);
+ default:
+ Debug.fail("Unknown type annotation: " + type.kind);
+ }
+
+ function emitEntityName(entityName: EntityName) {
+ let visibilityResult = resolver.isEntityNameVisible(entityName,
+ // Aliases can be written asynchronously so use correct enclosing declaration
+ entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration);
+
+ handleSymbolAccessibilityError(visibilityResult);
+ writeEntityName(entityName);
+
+ function writeEntityName(entityName: EntityName) {
+ if (entityName.kind === SyntaxKind.Identifier) {
+ writeTextOfNode(currentSourceFile, entityName);
+ }
+ else {
+ let qualifiedName = entityName;
+ writeEntityName(qualifiedName.left);
+ write(".");
+ writeTextOfNode(currentSourceFile, qualifiedName.right);
+ }
+ }
+ }
+
+ function emitTypeReference(type: TypeReferenceNode) {
+ emitEntityName(type.typeName);
+ if (type.typeArguments) {
+ write("<");
+ emitCommaList(type.typeArguments, emitType);
+ write(">");
+ }
+ }
+
+ function emitTypeQuery(type: TypeQueryNode) {
+ write("typeof ");
+ emitEntityName(type.exprName);
+ }
+
+ function emitArrayType(type: ArrayTypeNode) {
+ emitType(type.elementType);
+ write("[]");
+ }
+
+ function emitTupleType(type: TupleTypeNode) {
+ write("[");
+ emitCommaList(type.elementTypes, emitType);
+ write("]");
+ }
+
+ function emitUnionType(type: UnionTypeNode) {
+ emitSeparatedList(type.types, " | ", emitType);
+ }
+
+ function emitParenType(type: ParenthesizedTypeNode) {
+ write("(");
+ emitType(type.type);
+ write(")");
+ }
+
+ function emitTypeLiteral(type: TypeLiteralNode) {
+ write("{");
+ if (type.members.length) {
+ writeLine();
+ increaseIndent();
+ // write members
+ emitLines(type.members);
+ decreaseIndent();
+ }
+ write("}");
+ }
+ }
+
+ function emitSourceFile(node: SourceFile) {
+ currentSourceFile = node;
+ enclosingDeclaration = node;
+ emitLines(node.statements);
+ }
+
+ function emitExportAssignment(node: ExportAssignment) {
+ write(node.isExportEquals ? "export = " : "export default ");
+ if (node.expression.kind === SyntaxKind.Identifier) {
+ writeTextOfNode(currentSourceFile, node.expression);
+ }
+ else {
+ write(": ");
+ if (node.type) {
+ emitType(node.type);
+ }
+ else {
+ writer.getSymbolAccessibilityDiagnostic = getDefaultExportAccessibilityDiagnostic;
+ resolver.writeTypeOfExpression(node.expression, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
+ }
+ }
+ write(";");
+ writeLine();
+
+ // Make all the declarations visible for the export name
+ if (node.expression.kind === SyntaxKind.Identifier) {
+ let nodes = resolver.collectLinkedAliases(node.expression);
+
+ // write each of these declarations asynchronously
+ writeAsynchronousModuleElements(nodes);
+ }
+
+ function getDefaultExportAccessibilityDiagnostic(diagnostic: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ return {
+ diagnosticMessage: Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0,
+ errorNode: node
+ };
+ }
+ }
+
+ function isModuleElementVisible(node: Declaration) {
+ return resolver.isDeclarationVisible(node);
+ }
+
+ function emitModuleElement(node: Node, isModuleElementVisible: boolean) {
+ if (isModuleElementVisible) {
+ writeModuleElement(node);
+ }
+ // Import equals declaration in internal module can become visible as part of any emit so lets make sure we add these irrespective
+ else if (node.kind === SyntaxKind.ImportEqualsDeclaration ||
+ (node.parent.kind === SyntaxKind.SourceFile && isExternalModule(currentSourceFile))) {
+ let isVisible: boolean;
+ if (asynchronousSubModuleDeclarationEmitInfo && node.parent.kind !== SyntaxKind.SourceFile) {
+ // Import declaration of another module that is visited async so lets put it in right spot
+ asynchronousSubModuleDeclarationEmitInfo.push({
+ node,
+ outputPos: writer.getTextPos(),
+ indent: writer.getIndent(),
+ isVisible
+ });
+ }
+ else {
+ if (node.kind === SyntaxKind.ImportDeclaration) {
+ let importDeclaration = node;
+ if (importDeclaration.importClause) {
+ isVisible = (importDeclaration.importClause.name && resolver.isDeclarationVisible(importDeclaration.importClause)) ||
+ isVisibleNamedBinding(importDeclaration.importClause.namedBindings);
+ }
+ }
+ moduleElementDeclarationEmitInfo.push({
+ node,
+ outputPos: writer.getTextPos(),
+ indent: writer.getIndent(),
+ isVisible
+ });
+ }
+ }
+ }
+
+ function writeModuleElement(node: Node) {
+ switch (node.kind) {
+ case SyntaxKind.FunctionDeclaration:
+ return writeFunctionDeclaration(node);
+ case SyntaxKind.VariableStatement:
+ return writeVariableStatement(node);
+ case SyntaxKind.InterfaceDeclaration:
+ return writeInterfaceDeclaration(node);
+ case SyntaxKind.ClassDeclaration:
+ return writeClassDeclaration(node);
+ case SyntaxKind.TypeAliasDeclaration:
+ return writeTypeAliasDeclaration(node);
+ case SyntaxKind.EnumDeclaration:
+ return writeEnumDeclaration(node);
+ case SyntaxKind.ModuleDeclaration:
+ return writeModuleDeclaration(node);
+ case SyntaxKind.ImportEqualsDeclaration:
+ return writeImportEqualsDeclaration(node);
+ case SyntaxKind.ImportDeclaration:
+ return writeImportDeclaration(node);
+ default:
+ Debug.fail("Unknown symbol kind");
+ }
+ }
+
+ function emitModuleElementDeclarationFlags(node: Node) {
+ // If the node is parented in the current source file we need to emit export declare or just export
+ if (node.parent === currentSourceFile) {
+ // If the node is exported
+ if (node.flags & NodeFlags.Export) {
+ write("export ");
+ }
+
+ if (node.flags & NodeFlags.Default) {
+ write("default ");
+ }
+ else if (node.kind !== SyntaxKind.InterfaceDeclaration) {
+ write("declare ");
+ }
+ }
+ }
+
+ function emitClassMemberDeclarationFlags(node: Declaration) {
+ if (node.flags & NodeFlags.Private) {
+ write("private ");
+ }
+ else if (node.flags & NodeFlags.Protected) {
+ write("protected ");
+ }
+
+ if (node.flags & NodeFlags.Static) {
+ write("static ");
+ }
+ }
+
+ function writeImportEqualsDeclaration(node: ImportEqualsDeclaration) {
+ // note usage of writer. methods instead of aliases created, just to make sure we are using
+ // correct writer especially to handle asynchronous alias writing
+ emitJsDocComments(node);
+ if (node.flags & NodeFlags.Export) {
+ write("export ");
+ }
+ write("import ");
+ writeTextOfNode(currentSourceFile, node.name);
+ write(" = ");
+ if (isInternalModuleImportEqualsDeclaration(node)) {
+ emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.moduleReference, getImportEntityNameVisibilityError);
+ write(";");
+ }
+ else {
+ write("require(");
+ writeTextOfNode(currentSourceFile, getExternalModuleImportEqualsDeclarationExpression(node));
+ write(");");
+ }
+ writer.writeLine();
+
+ function getImportEntityNameVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ return {
+ diagnosticMessage: Diagnostics.Import_declaration_0_is_using_private_name_1,
+ errorNode: node,
+ typeName: node.name
+ };
+ }
+ }
+
+ function isVisibleNamedBinding(namedBindings: NamespaceImport | NamedImports): boolean {
+ if (namedBindings) {
+ if (namedBindings.kind === SyntaxKind.NamespaceImport) {
+ return resolver.isDeclarationVisible(namedBindings);
+ }
+ else {
+ return forEach((namedBindings).elements, namedImport => resolver.isDeclarationVisible(namedImport));
+ }
+ }
+ }
+
+ function writeImportDeclaration(node: ImportDeclaration) {
+ if (!node.importClause && !(node.flags & NodeFlags.Export)) {
+ // do not write non-exported import declarations that don't have import clauses
+ return;
+ }
+ emitJsDocComments(node);
+ if (node.flags & NodeFlags.Export) {
+ write("export ");
+ }
+ write("import ");
+ if (node.importClause) {
+ let currentWriterPos = writer.getTextPos();
+ if (node.importClause.name && resolver.isDeclarationVisible(node.importClause)) {
+ writeTextOfNode(currentSourceFile, node.importClause.name);
+ }
+ if (node.importClause.namedBindings && isVisibleNamedBinding(node.importClause.namedBindings)) {
+ if (currentWriterPos !== writer.getTextPos()) {
+ // If the default binding was emitted, write the separated
+ write(", ");
+ }
+ if (node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
+ write("* as ");
+ writeTextOfNode(currentSourceFile, (node.importClause.namedBindings).name);
+ }
+ else {
+ write("{ ");
+ emitCommaList((node.importClause.namedBindings).elements, emitImportOrExportSpecifier, resolver.isDeclarationVisible);
+ write(" }");
+ }
+ }
+ write(" from ");
+ }
+ writeTextOfNode(currentSourceFile, node.moduleSpecifier);
+ write(";");
+ writer.writeLine();
+ }
+
+ function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) {
+ if (node.propertyName) {
+ writeTextOfNode(currentSourceFile, node.propertyName);
+ write(" as ");
+ }
+ writeTextOfNode(currentSourceFile, node.name);
+ }
+
+ function emitExportSpecifier(node: ExportSpecifier) {
+ emitImportOrExportSpecifier(node);
+
+ // Make all the declarations visible for the export name
+ let nodes = resolver.collectLinkedAliases(node.propertyName || node.name);
+
+ // write each of these declarations asynchronously
+ writeAsynchronousModuleElements(nodes);
+ }
+
+ function emitExportDeclaration(node: ExportDeclaration) {
+ emitJsDocComments(node);
+ write("export ");
+ if (node.exportClause) {
+ write("{ ");
+ emitCommaList(node.exportClause.elements, emitExportSpecifier);
+ write(" }");
+ }
+ else {
+ write("*");
+ }
+ if (node.moduleSpecifier) {
+ write(" from ");
+ writeTextOfNode(currentSourceFile, node.moduleSpecifier);
+ }
+ write(";");
+ writer.writeLine();
+ }
+
+ function writeModuleDeclaration(node: ModuleDeclaration) {
+ emitJsDocComments(node);
+ emitModuleElementDeclarationFlags(node);
+ write("module ");
+ writeTextOfNode(currentSourceFile, node.name);
+ while (node.body.kind !== SyntaxKind.ModuleBlock) {
+ node = node.body;
+ write(".");
+ writeTextOfNode(currentSourceFile, node.name);
+ }
+ let prevEnclosingDeclaration = enclosingDeclaration;
+ enclosingDeclaration = node;
+ write(" {");
+ writeLine();
+ increaseIndent();
+ emitLines((node.body).statements);
+ decreaseIndent();
+ write("}");
+ writeLine();
+ enclosingDeclaration = prevEnclosingDeclaration;
+ }
+
+ function writeTypeAliasDeclaration(node: TypeAliasDeclaration) {
+ emitJsDocComments(node);
+ emitModuleElementDeclarationFlags(node);
+ write("type ");
+ writeTextOfNode(currentSourceFile, node.name);
+ write(" = ");
+ emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.type, getTypeAliasDeclarationVisibilityError);
+ write(";");
+ writeLine();
+
+ function getTypeAliasDeclarationVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ return {
+ diagnosticMessage: Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1,
+ errorNode: node.type,
+ typeName: node.name
+ };
+ }
+ }
+
+ function writeEnumDeclaration(node: EnumDeclaration) {
+ emitJsDocComments(node);
+ emitModuleElementDeclarationFlags(node);
+ if (isConst(node)) {
+ write("const ")
+ }
+ write("enum ");
+ writeTextOfNode(currentSourceFile, node.name);
+ write(" {");
+ writeLine();
+ increaseIndent();
+ emitLines(node.members);
+ decreaseIndent();
+ write("}");
+ writeLine();
+ }
+
+ function emitEnumMemberDeclaration(node: EnumMember) {
+ emitJsDocComments(node);
+ writeTextOfNode(currentSourceFile, node.name);
+ let enumMemberValue = resolver.getConstantValue(node);
+ if (enumMemberValue !== undefined) {
+ write(" = ");
+ write(enumMemberValue.toString());
+ }
+ write(",");
+ writeLine();
+ }
+
+ function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) {
+ return node.parent.kind === SyntaxKind.MethodDeclaration && (node.parent.flags & NodeFlags.Private);
+ }
+
+ function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) {
+ function emitTypeParameter(node: TypeParameterDeclaration) {
+ increaseIndent();
+ emitJsDocComments(node);
+ decreaseIndent();
+ writeTextOfNode(currentSourceFile, node.name);
+ // If there is constraint present and this is not a type parameter of the private method emit the constraint
+ if (node.constraint && !isPrivateMethodTypeParameter(node)) {
+ write(" extends ");
+ if (node.parent.kind === SyntaxKind.FunctionType ||
+ node.parent.kind === SyntaxKind.ConstructorType ||
+ (node.parent.parent && node.parent.parent.kind === SyntaxKind.TypeLiteral)) {
+ Debug.assert(node.parent.kind === SyntaxKind.MethodDeclaration ||
+ node.parent.kind === SyntaxKind.MethodSignature ||
+ node.parent.kind === SyntaxKind.FunctionType ||
+ node.parent.kind === SyntaxKind.ConstructorType ||
+ node.parent.kind === SyntaxKind.CallSignature ||
+ node.parent.kind === SyntaxKind.ConstructSignature);
+ emitType(node.constraint);
+ }
+ else {
+ emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.constraint, getTypeParameterConstraintVisibilityError);
+ }
+ }
+
+ function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ // Type parameter constraints are named by user so we should always be able to name it
+ let diagnosticMessage: DiagnosticMessage;
+ switch (node.parent.kind) {
+ case SyntaxKind.ClassDeclaration:
+ diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_private_name_1;
+ break;
+
+ case SyntaxKind.InterfaceDeclaration:
+ diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1;
+ break;
+
+ case SyntaxKind.ConstructSignature:
+ diagnosticMessage = Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
+ break;
+
+ case SyntaxKind.CallSignature:
+ diagnosticMessage = Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
+ break;
+
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ if (node.parent.flags & NodeFlags.Static) {
+ diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
+ }
+ else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
+ diagnosticMessage = Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
+ }
+ else {
+ diagnosticMessage = Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
+ }
+ break;
+
+ case SyntaxKind.FunctionDeclaration:
+ diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1;
+ break;
+
+ default:
+ Debug.fail("This is unknown parent for type parameter: " + node.parent.kind);
+ }
+
+ return {
+ diagnosticMessage,
+ errorNode: node,
+ typeName: node.name
+ };
+ }
+ }
+
+ if (typeParameters) {
+ write("<");
+ emitCommaList(typeParameters, emitTypeParameter);
+ write(">");
+ }
+ }
+
+ function emitHeritageClause(typeReferences: TypeReferenceNode[], isImplementsList: boolean) {
+ if (typeReferences) {
+ write(isImplementsList ? " implements " : " extends ");
+ emitCommaList(typeReferences, emitTypeOfTypeReference);
+ }
+
+ function emitTypeOfTypeReference(node: TypeReferenceNode) {
+ emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError);
+
+ function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ let diagnosticMessage: DiagnosticMessage;
+ // Heritage clause is written by user so it can always be named
+ if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
+ // Class or Interface implemented/extended is inaccessible
+ diagnosticMessage = isImplementsList ?
+ Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 :
+ Diagnostics.Extends_clause_of_exported_class_0_has_or_is_using_private_name_1;
+ }
+ else {
+ // interface is inaccessible
+ diagnosticMessage = Diagnostics.Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1;
+ }
+
+ return {
+ diagnosticMessage,
+ errorNode: node,
+ typeName: (node.parent.parent).name
+ };
+ }
+ }
+ }
+
+ function writeClassDeclaration(node: ClassDeclaration) {
+ function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) {
+ if (constructorDeclaration) {
+ forEach(constructorDeclaration.parameters, param => {
+ if (param.flags & NodeFlags.AccessibilityModifier) {
+ emitPropertyDeclaration(param);
+ }
+ });
+ }
+ }
+
+ emitJsDocComments(node);
+ emitModuleElementDeclarationFlags(node);
+ write("class ");
+ writeTextOfNode(currentSourceFile, node.name);
+ let prevEnclosingDeclaration = enclosingDeclaration;
+ enclosingDeclaration = node;
+ emitTypeParameters(node.typeParameters);
+ let baseTypeNode = getClassBaseTypeNode(node);
+ if (baseTypeNode) {
+ emitHeritageClause([baseTypeNode], /*isImplementsList*/ false);
+ }
+ emitHeritageClause(getClassImplementedTypeNodes(node), /*isImplementsList*/ true);
+ write(" {");
+ writeLine();
+ increaseIndent();
+ emitParameterProperties(getFirstConstructorWithBody(node));
+ emitLines(node.members);
+ decreaseIndent();
+ write("}");
+ writeLine();
+ enclosingDeclaration = prevEnclosingDeclaration;
+ }
+
+ function writeInterfaceDeclaration(node: InterfaceDeclaration) {
+ emitJsDocComments(node);
+ emitModuleElementDeclarationFlags(node);
+ write("interface ");
+ writeTextOfNode(currentSourceFile, node.name);
+ let prevEnclosingDeclaration = enclosingDeclaration;
+ enclosingDeclaration = node;
+ emitTypeParameters(node.typeParameters);
+ emitHeritageClause(getInterfaceBaseTypeNodes(node), /*isImplementsList*/ false);
+ write(" {");
+ writeLine();
+ increaseIndent();
+ emitLines(node.members);
+ decreaseIndent();
+ write("}");
+ writeLine();
+ enclosingDeclaration = prevEnclosingDeclaration;
+ }
+
+ function emitPropertyDeclaration(node: Declaration) {
+ if (hasDynamicName(node)) {
+ return;
+ }
+
+ emitJsDocComments(node);
+ emitClassMemberDeclarationFlags(node);
+ emitVariableDeclaration(node);
+ write(";");
+ writeLine();
+ }
+
+ function emitVariableDeclaration(node: VariableDeclaration) {
+ // If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
+ // so there is no check needed to see if declaration is visible
+ if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
+ if (isBindingPattern(node.name)) {
+ emitBindingPattern(node.name);
+ }
+ else {
+ // If this node is a computed name, it can only be a symbol, because we've already skipped
+ // it if it's not a well known symbol. In that case, the text of the name will be exactly
+ // what we want, namely the name expression enclosed in brackets.
+ writeTextOfNode(currentSourceFile, node.name);
+ // If optional property emit ?
+ if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && hasQuestionToken(node)) {
+ write("?");
+ }
+ if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
+ emitTypeOfVariableDeclarationFromTypeLiteral(node);
+ }
+ else if (!(node.flags & NodeFlags.Private)) {
+ writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError);
+ }
+ }
+ }
+
+ function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult: SymbolAccessiblityResult) {
+ if (node.kind === SyntaxKind.VariableDeclaration) {
+ return symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Exported_variable_0_has_or_is_using_private_name_1;
+ }
+ // This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
+ else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) {
+ // TODO(jfreeman): Deal with computed properties in error reporting.
+ if (node.flags & NodeFlags.Static) {
+ return symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1;
+ }
+ else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
+ return symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1;
+ }
+ else {
+ // Interfaces cannot have types that cannot be named
+ return symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1;
+ }
+ }
+ }
+
+ function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ let diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult);
+ return diagnosticMessage !== undefined ? {
+ diagnosticMessage,
+ errorNode: node,
+ typeName: node.name
+ } : undefined;
+ }
+
+ function emitBindingPattern(bindingPattern: BindingPattern) {
+ emitCommaList(bindingPattern.elements, emitBindingElement);
+ }
+
+ function emitBindingElement(bindingElement: BindingElement) {
+ function getBindingElementTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ let diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult);
+ return diagnosticMessage !== undefined ? {
+ diagnosticMessage,
+ errorNode: bindingElement,
+ typeName: bindingElement.name
+ } : undefined;
+ }
+
+ if (bindingElement.name) {
+ if (isBindingPattern(bindingElement.name)) {
+ emitBindingPattern(bindingElement.name);
+ }
+ else {
+ writeTextOfNode(currentSourceFile, bindingElement.name);
+ writeTypeOfDeclaration(bindingElement, /*type*/ undefined, getBindingElementTypeVisibilityError);
+ }
+ }
+ }
+ }
+
+ function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableLikeDeclaration) {
+ // if this is property of type literal,
+ // or is parameter of method/call/construct/index signature of type literal
+ // emit only if type is specified
+ if (node.type) {
+ write(": ");
+ emitType(node.type);
+ }
+ }
+
+ function isVariableStatementVisible(node: VariableStatement) {
+ return forEach(node.declarationList.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration));
+ }
+
+ function writeVariableStatement(node: VariableStatement) {
+ emitJsDocComments(node);
+ emitModuleElementDeclarationFlags(node);
+ if (isLet(node.declarationList)) {
+ write("let ");
+ }
+ else if (isConst(node.declarationList)) {
+ write("const ");
+ }
+ else {
+ write("var ");
+ }
+ emitCommaList(node.declarationList.declarations, emitVariableDeclaration, resolver.isDeclarationVisible);
+ write(";");
+ writeLine();
+ }
+
+ function emitAccessorDeclaration(node: AccessorDeclaration) {
+ if (hasDynamicName(node)) {
+ return;
+ }
+
+ let accessors = getAllAccessorDeclarations((node.parent).members, node);
+ let accessorWithTypeAnnotation: AccessorDeclaration;
+
+ if (node === accessors.firstAccessor) {
+ emitJsDocComments(accessors.getAccessor);
+ emitJsDocComments(accessors.setAccessor);
+ emitClassMemberDeclarationFlags(node);
+ writeTextOfNode(currentSourceFile, node.name);
+ if (!(node.flags & NodeFlags.Private)) {
+ accessorWithTypeAnnotation = node;
+ let type = getTypeAnnotationFromAccessor(node);
+ if (!type) {
+ // couldn't get type for the first accessor, try the another one
+ let anotherAccessor = node.kind === SyntaxKind.GetAccessor ? accessors.setAccessor : accessors.getAccessor;
+ type = getTypeAnnotationFromAccessor(anotherAccessor);
+ if (type) {
+ accessorWithTypeAnnotation = anotherAccessor;
+ }
+ }
+ writeTypeOfDeclaration(node, type, getAccessorDeclarationTypeVisibilityError);
+ }
+ write(";");
+ writeLine();
+ }
+
+ function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode | StringLiteralExpression {
+ if (accessor) {
+ return accessor.kind === SyntaxKind.GetAccessor
+ ? accessor.type // Getter - return type
+ : accessor.parameters.length > 0
+ ? accessor.parameters[0].type // Setter parameter type
+ : undefined;
+ }
+ }
+
+ function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ let diagnosticMessage: DiagnosticMessage;
+ if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) {
+ // Setters have to have type named and cannot infer it so, the type should always be named
+ if (accessorWithTypeAnnotation.parent.flags & NodeFlags.Static) {
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1;
+ }
+ else {
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1;
+ }
+ return {
+ diagnosticMessage,
+ errorNode: accessorWithTypeAnnotation.parameters[0],
+ // TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name
+ typeName: accessorWithTypeAnnotation.name
+ };
+ }
+ else {
+ if (accessorWithTypeAnnotation.flags & NodeFlags.Static) {
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
+ Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0;
+ }
+ else {
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
+ Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0;
+ }
+ return {
+ diagnosticMessage,
+ errorNode: accessorWithTypeAnnotation.name,
+ typeName: undefined
+ };
+ }
+ }
+ }
+
+ function writeFunctionDeclaration(node: FunctionLikeDeclaration) {
+ if (hasDynamicName(node)) {
+ return;
+ }
+
+ // If we are emitting Method/Constructor it isn't moduleElement and hence already determined to be emitting
+ // so no need to verify if the declaration is visible
+ if (!resolver.isImplementationOfOverload(node)) {
+ emitJsDocComments(node);
+ if (node.kind === SyntaxKind.FunctionDeclaration) {
+ emitModuleElementDeclarationFlags(node);
+ }
+ else if (node.kind === SyntaxKind.MethodDeclaration) {
+ emitClassMemberDeclarationFlags(node);
+ }
+ if (node.kind === SyntaxKind.FunctionDeclaration) {
+ write("function ");
+ writeTextOfNode(currentSourceFile, node.name);
+ }
+ else if (node.kind === SyntaxKind.Constructor) {
+ write("constructor");
+ }
+ else {
+ writeTextOfNode(currentSourceFile, node.name);
+ if (hasQuestionToken(node)) {
+ write("?");
+ }
+ }
+ emitSignatureDeclaration(node);
+ }
+ }
+
+ function emitSignatureDeclarationWithJsDocComments(node: SignatureDeclaration) {
+ emitJsDocComments(node);
+ emitSignatureDeclaration(node);
+ }
+
+ function emitSignatureDeclaration(node: SignatureDeclaration) {
+ // Construct signature or constructor type write new Signature
+ if (node.kind === SyntaxKind.ConstructSignature || node.kind === SyntaxKind.ConstructorType) {
+ write("new ");
+ }
+ emitTypeParameters(node.typeParameters);
+ if (node.kind === SyntaxKind.IndexSignature) {
+ write("[");
+ }
+ else {
+ write("(");
+ }
+
+ let prevEnclosingDeclaration = enclosingDeclaration;
+ enclosingDeclaration = node;
+
+ // Parameters
+ emitCommaList(node.parameters, emitParameterDeclaration);
+
+ if (node.kind === SyntaxKind.IndexSignature) {
+ write("]");
+ }
+ else {
+ write(")");
+ }
+
+ // If this is not a constructor and is not private, emit the return type
+ let isFunctionTypeOrConstructorType = node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.ConstructorType;
+ if (isFunctionTypeOrConstructorType || node.parent.kind === SyntaxKind.TypeLiteral) {
+ // Emit type literal signature return type only if specified
+ if (node.type) {
+ write(isFunctionTypeOrConstructorType ? " => " : ": ");
+ emitType(node.type);
+ }
+ }
+ else if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) {
+ writeReturnTypeAtSignature(node, getReturnTypeVisibilityError);
+ }
+
+ enclosingDeclaration = prevEnclosingDeclaration;
+
+ if (!isFunctionTypeOrConstructorType) {
+ write(";");
+ writeLine();
+ }
+
+ function getReturnTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ let diagnosticMessage: DiagnosticMessage;
+ switch (node.kind) {
+ case SyntaxKind.ConstructSignature:
+ // Interfaces cannot have return types that cannot be named
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0;
+ break;
+
+ case SyntaxKind.CallSignature:
+ // Interfaces cannot have return types that cannot be named
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0;
+ break;
+
+ case SyntaxKind.IndexSignature:
+ // Interfaces cannot have return types that cannot be named
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0;
+ break;
+
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ if (node.flags & NodeFlags.Static) {
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
+ Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0;
+ }
+ else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
+ Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0;
+ }
+ else {
+ // Interfaces cannot have return types that cannot be named
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0;
+ }
+ break;
+
+ case SyntaxKind.FunctionDeclaration:
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
+ Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 :
+ Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0;
+ break;
+
+ default:
+ Debug.fail("This is unknown kind for signature: " + node.kind);
+ }
+
+ return {
+ diagnosticMessage,
+ errorNode: node.name || node,
+ };
+ }
+ }
+
+ function emitParameterDeclaration(node: ParameterDeclaration) {
+ increaseIndent();
+ emitJsDocComments(node);
+ if (node.dotDotDotToken) {
+ write("...");
+ }
+ if (isBindingPattern(node.name)) {
+ write("_" + indexOf((node.parent).parameters, node));
+ }
+ else {
+ writeTextOfNode(currentSourceFile, node.name);
+ }
+ if (node.initializer || hasQuestionToken(node)) {
+ write("?");
+ }
+ decreaseIndent();
+
+ if (node.parent.kind === SyntaxKind.FunctionType ||
+ node.parent.kind === SyntaxKind.ConstructorType ||
+ node.parent.parent.kind === SyntaxKind.TypeLiteral) {
+ emitTypeOfVariableDeclarationFromTypeLiteral(node);
+ }
+ else if (!(node.parent.flags & NodeFlags.Private)) {
+ writeTypeOfDeclaration(node, node.type, getParameterDeclarationTypeVisibilityError);
+ }
+
+ function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
+ let diagnosticMessage: DiagnosticMessage;
+ switch (node.parent.kind) {
+ case SyntaxKind.Constructor:
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1;
+ break;
+
+ case SyntaxKind.ConstructSignature:
+ // Interfaces cannot have parameter types that cannot be named
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
+ break;
+
+ case SyntaxKind.CallSignature:
+ // Interfaces cannot have parameter types that cannot be named
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
+ break;
+
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ if (node.parent.flags & NodeFlags.Static) {
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
+ }
+ else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
+ }
+ else {
+ // Interfaces cannot have parameter types that cannot be named
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
+ }
+ break;
+
+ case SyntaxKind.FunctionDeclaration:
+ diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
+ symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
+ Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1;
+ break;
+
+ default:
+ Debug.fail("This is unknown parent for parameter: " + node.parent.kind);
+ }
+
+ return {
+ diagnosticMessage,
+ errorNode: node,
+ typeName: node.name
+ };
+ }
+ }
+
+ function emitNode(node: Node) {
+ switch (node.kind) {
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.ModuleDeclaration:
+ case SyntaxKind.ImportEqualsDeclaration:
+ case SyntaxKind.InterfaceDeclaration:
+ case SyntaxKind.ClassDeclaration:
+ case SyntaxKind.TypeAliasDeclaration:
+ case SyntaxKind.EnumDeclaration:
+ return emitModuleElement(node, isModuleElementVisible(node));
+ case SyntaxKind.VariableStatement:
+ return emitModuleElement(node, isVariableStatementVisible(node));
+ case SyntaxKind.ImportDeclaration:
+ // Import declaration without import clause is visible, otherwise it is not visible
+ return emitModuleElement(node, /*isModuleElementVisible*/!(node).importClause);
+ case SyntaxKind.ExportDeclaration:
+ return emitExportDeclaration(node);
+ case SyntaxKind.Constructor:
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ return writeFunctionDeclaration(node);
+ case SyntaxKind.ConstructSignature:
+ case SyntaxKind.CallSignature:
+ case SyntaxKind.IndexSignature:
+ return emitSignatureDeclarationWithJsDocComments(node);
+ case SyntaxKind.GetAccessor:
+ case SyntaxKind.SetAccessor:
+ return emitAccessorDeclaration(node);
+ case SyntaxKind.PropertyDeclaration:
+ case SyntaxKind.PropertySignature:
+ return emitPropertyDeclaration(node);
+ case SyntaxKind.EnumMember:
+ return emitEnumMemberDeclaration(node);
+ case SyntaxKind.ExportAssignment:
+ return emitExportAssignment(node);
+ case SyntaxKind.SourceFile:
+ return emitSourceFile(node);
+ }
+ }
+
+ function writeReferencePath(referencedFile: SourceFile) {
+ let declFileName = referencedFile.flags & NodeFlags.DeclarationFile
+ ? referencedFile.fileName // Declaration file, use declaration file name
+ : shouldEmitToOwnFile(referencedFile, compilerOptions)
+ ? getOwnEmitOutputFilePath(referencedFile, host, ".d.ts") // Own output file so get the .d.ts file
+ : removeFileExtension(compilerOptions.out) + ".d.ts";// Global out file
+
+ declFileName = getRelativePathToDirectoryOrUrl(
+ getDirectoryPath(normalizeSlashes(jsFilePath)),
+ declFileName,
+ host.getCurrentDirectory(),
+ host.getCanonicalFileName,
+ /*isAbsolutePathAnUrl*/ false);
+
+ referencePathsOutput += "/// " + newLine;
+ }
+ }
+
+ // @internal
+ export function writeDeclarationFile(jsFilePath: string, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[]) {
+ let emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, jsFilePath, sourceFile);
+ // TODO(shkamat): Should we not write any declaration file if any of them can produce error,
+ // or should we just not write this file like we are doing now
+ if (!emitDeclarationResult.reportedDeclarationError) {
+ let declarationOutput = emitDeclarationResult.referencePathsOutput
+ + getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
+ writeFile(host, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, host.getCompilerOptions().emitBOM);
+ }
+
+ function getDeclarationOutput(synchronousDeclarationOutput: string, moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]) {
+ let appliedSyncOutputPos = 0;
+ let declarationOutput = "";
+ // apply asynchronous additions to the synchronous output
+ forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
+ if (aliasEmitInfo.asynchronousOutput) {
+ declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos, aliasEmitInfo.outputPos);
+ declarationOutput += getDeclarationOutput(aliasEmitInfo.asynchronousOutput, aliasEmitInfo.subModuleElementDeclarationEmitInfo);
+ appliedSyncOutputPos = aliasEmitInfo.outputPos;
+ }
+ });
+ declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos);
+ return declarationOutput;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index a1639ec3f40..e158856a46b 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -1,20 +1,7 @@
///
+///
module ts {
- interface EmitTextWriter {
- write(s: string): void;
- writeTextOfNode(sourceFile: SourceFile, node: Node): void;
- writeLine(): void;
- increaseIndent(): void;
- decreaseIndent(): void;
- getText(): string;
- rawWrite(s: string): void;
- writeLiteral(s: string): void;
- getTextPos(): number;
- getLine(): number;
- getColumn(): number;
- getIndent(): number;
- }
interface ExternalImportInfo {
rootNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration;
@@ -22,1748 +9,16 @@ module ts {
namedImports?: NamedImports;
}
- interface SymbolAccessibilityDiagnostic {
- errorNode: Node;
- diagnosticMessage: DiagnosticMessage;
- typeName?: DeclarationName;
- }
-
// represents one LexicalEnvironment frame to store unique generated names
interface ScopeFrame {
names: Map;
previous: ScopeFrame;
}
- type GetSymbolAccessibilityDiagnostic = (symbolAccesibilityResult: SymbolAccessiblityResult) => SymbolAccessibilityDiagnostic;
-
- interface EmitTextWriterWithSymbolWriter extends EmitTextWriter, SymbolWriter {
- getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic;
- }
-
- interface ModuleElementDeclarationEmitInfo {
- node: Node;
- outputPos: number;
- indent: number;
- asynchronousOutput?: string; // If the output for alias was written asynchronously, the corresponding output
- subModuleElementDeclarationEmitInfo?: ModuleElementDeclarationEmitInfo[];
- isVisible?: boolean;
- }
-
- interface DeclarationEmit {
- reportedDeclarationError: boolean;
- moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[];
- synchronousDeclarationOutput: string;
- referencePathsOutput: string;
- }
-
- let indentStrings: string[] = ["", " "];
- export function getIndentString(level: number) {
- if (indentStrings[level] === undefined) {
- indentStrings[level] = getIndentString(level - 1) + indentStrings[1];
- }
- return indentStrings[level];
- }
-
- function getIndentSize() {
- return indentStrings[1].length;
- }
-
- export function shouldEmitToOwnFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
- if (!isDeclarationFile(sourceFile)) {
- if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.fileName, ".js")) {
- return true;
- }
- return false;
- }
- return false;
- }
-
export function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) {
return isExternalModule(sourceFile) || isDeclarationFile(sourceFile);
}
- function createTextWriter(newLine: String): EmitTextWriter {
- let output = "";
- let indent = 0;
- let lineStart = true;
- let lineCount = 0;
- let linePos = 0;
-
- function write(s: string) {
- if (s && s.length) {
- if (lineStart) {
- output += getIndentString(indent);
- lineStart = false;
- }
- output += s;
- }
- }
-
- function rawWrite(s: string) {
- if (s !== undefined) {
- if (lineStart) {
- lineStart = false;
- }
- output += s;
- }
- }
-
- function writeLiteral(s: string) {
- if (s && s.length) {
- write(s);
- let lineStartsOfS = computeLineStarts(s);
- if (lineStartsOfS.length > 1) {
- lineCount = lineCount + lineStartsOfS.length - 1;
- linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1];
- }
- }
- }
-
- function writeLine() {
- if (!lineStart) {
- output += newLine;
- lineCount++;
- linePos = output.length;
- lineStart = true;
- }
- }
-
- function writeTextOfNode(sourceFile: SourceFile, node: Node) {
- write(getSourceTextOfNodeFromSourceFile(sourceFile, node));
- }
-
- return {
- write,
- rawWrite,
- writeTextOfNode,
- writeLiteral,
- writeLine,
- increaseIndent: () => indent++,
- decreaseIndent: () => indent--,
- getIndent: () => indent,
- getTextPos: () => output.length,
- getLine: () => lineCount + 1,
- getColumn: () => lineStart ? indent * getIndentSize() + 1 : output.length - linePos + 1,
- getText: () => output,
- };
- }
-
- function getLineOfLocalPosition(currentSourceFile: SourceFile, pos: number) {
- return getLineAndCharacterOfPosition(currentSourceFile, pos).line;
- }
-
- function emitNewLineBeforeLeadingComments(currentSourceFile: SourceFile, writer: EmitTextWriter, node: TextRange, leadingComments: CommentRange[]) {
- // If the leading comments start on different line than the start of node, write new line
- if (leadingComments && leadingComments.length && node.pos !== leadingComments[0].pos &&
- getLineOfLocalPosition(currentSourceFile, node.pos) !== getLineOfLocalPosition(currentSourceFile, leadingComments[0].pos)) {
- writer.writeLine();
- }
- }
-
- function emitComments(currentSourceFile: SourceFile, writer: EmitTextWriter, comments: CommentRange[], trailingSeparator: boolean, newLine: string,
- writeComment: (currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string) => void) {
- let emitLeadingSpace = !trailingSeparator;
- forEach(comments, comment => {
- if (emitLeadingSpace) {
- writer.write(" ");
- emitLeadingSpace = false;
- }
- writeComment(currentSourceFile, writer, comment, newLine);
- if (comment.hasTrailingNewLine) {
- writer.writeLine();
- }
- else if (trailingSeparator) {
- writer.write(" ");
- }
- else {
- // Emit leading space to separate comment during next comment emit
- emitLeadingSpace = true;
- }
- });
- }
-
- function writeCommentRange(currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string){
- if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
- let firstCommentLineAndCharacter = getLineAndCharacterOfPosition(currentSourceFile, comment.pos);
- let lineCount = getLineStarts(currentSourceFile).length;
- let firstCommentLineIndent: number;
- for (let pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) {
- let nextLineStart = (currentLine + 1) === lineCount
- ? currentSourceFile.text.length + 1
- : getStartPositionOfLine(currentLine + 1, currentSourceFile);
-
- if (pos !== comment.pos) {
- // If we are not emitting first line, we need to write the spaces to adjust the alignment
- if (firstCommentLineIndent === undefined) {
- firstCommentLineIndent = calculateIndent(getStartPositionOfLine(firstCommentLineAndCharacter.line, currentSourceFile), comment.pos);
- }
-
- // These are number of spaces writer is going to write at current indent
- let currentWriterIndentSpacing = writer.getIndent() * getIndentSize();
-
- // Number of spaces we want to be writing
- // eg: Assume writer indent
- // module m {
- // /* starts at character 9 this is line 1
- // * starts at character pos 4 line --1 = 8 - 8 + 3
- // More left indented comment */ --2 = 8 - 8 + 2
- // class c { }
- // }
- // module m {
- // /* this is line 1 -- Assume current writer indent 8
- // * line --3 = 8 - 4 + 5
- // More right indented comment */ --4 = 8 - 4 + 11
- // class c { }
- // }
- let spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + calculateIndent(pos, nextLineStart);
- if (spacesToEmit > 0) {
- let numberOfSingleSpacesToEmit = spacesToEmit % getIndentSize();
- let indentSizeSpaceString = getIndentString((spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize());
-
- // Write indent size string ( in eg 1: = "", 2: "" , 3: string with 8 spaces 4: string with 12 spaces
- writer.rawWrite(indentSizeSpaceString);
-
- // Emit the single spaces (in eg: 1: 3 spaces, 2: 2 spaces, 3: 1 space, 4: 3 spaces)
- while (numberOfSingleSpacesToEmit) {
- writer.rawWrite(" ");
- numberOfSingleSpacesToEmit--;
- }
- }
- else {
- // No spaces to emit write empty string
- writer.rawWrite("");
- }
- }
-
- // Write the comment line text
- writeTrimmedCurrentLine(pos, nextLineStart);
-
- pos = nextLineStart;
- }
- }
- else {
- // Single line comment of style //....
- writer.write(currentSourceFile.text.substring(comment.pos, comment.end));
- }
-
- function writeTrimmedCurrentLine(pos: number, nextLineStart: number) {
- let end = Math.min(comment.end, nextLineStart - 1);
- let currentLineText = currentSourceFile.text.substring(pos, end).replace(/^\s+|\s+$/g, '');
- if (currentLineText) {
- // trimmed forward and ending spaces text
- writer.write(currentLineText);
- if (end !== comment.end) {
- writer.writeLine();
- }
- }
- else {
- // Empty string - make sure we write empty line
- writer.writeLiteral(newLine);
- }
- }
-
- function calculateIndent(pos: number, end: number) {
- let currentLineIndent = 0;
- for (; pos < end && isWhiteSpace(currentSourceFile.text.charCodeAt(pos)); pos++) {
- if (currentSourceFile.text.charCodeAt(pos) === CharacterCodes.tab) {
- // Tabs = TabSize = indent size and go to next tabStop
- currentLineIndent += getIndentSize() - (currentLineIndent % getIndentSize());
- }
- else {
- // Single space
- currentLineIndent++;
- }
- }
-
- return currentLineIndent;
- }
- }
-
- function getFirstConstructorWithBody(node: ClassDeclaration): ConstructorDeclaration {
- return forEach(node.members, member => {
- if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member).body)) {
- return member;
- }
- });
- }
-
- function getAllAccessorDeclarations(declarations: NodeArray, accessor: AccessorDeclaration) {
- let firstAccessor: AccessorDeclaration;
- let getAccessor: AccessorDeclaration;
- let setAccessor: AccessorDeclaration;
- if (hasDynamicName(accessor)) {
- firstAccessor = accessor;
- if (accessor.kind === SyntaxKind.GetAccessor) {
- getAccessor = accessor;
- }
- else if (accessor.kind === SyntaxKind.SetAccessor) {
- setAccessor = accessor;
- }
- else {
- Debug.fail("Accessor has wrong kind");
- }
- }
- else {
- forEach(declarations, (member: Declaration) => {
- if ((member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor)
- && (member.flags & NodeFlags.Static) === (accessor.flags & NodeFlags.Static)) {
- let memberName = getPropertyNameForPropertyNameNode(member.name);
- let accessorName = getPropertyNameForPropertyNameNode(accessor.name);
- if (memberName === accessorName) {
- if (!firstAccessor) {
- firstAccessor = member;
- }
-
- if (member.kind === SyntaxKind.GetAccessor && !getAccessor) {
- getAccessor = member;
- }
-
- if (member.kind === SyntaxKind.SetAccessor && !setAccessor) {
- setAccessor = member;
- }
- }
- }
- });
- }
- return {
- firstAccessor,
- getAccessor,
- setAccessor
- };
- }
-
- function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
- let sourceFilePath = getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory());
- sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), "");
- return combinePaths(newDirPath, sourceFilePath);
- }
-
- function getOwnEmitOutputFilePath(sourceFile: SourceFile, host: EmitHost, extension: string){
- let compilerOptions = host.getCompilerOptions();
- let emitOutputFilePathWithoutExtension: string;
- if (compilerOptions.outDir) {
- emitOutputFilePathWithoutExtension = removeFileExtension(getSourceFilePathInNewDir(sourceFile, host, compilerOptions.outDir));
- }
- else {
- emitOutputFilePathWithoutExtension = removeFileExtension(sourceFile.fileName);
- }
-
- return emitOutputFilePathWithoutExtension + extension;
- }
-
- function writeFile(host: EmitHost, diagnostics: Diagnostic[], fileName: string, data: string, writeByteOrderMark: boolean) {
- host.writeFile(fileName, data, writeByteOrderMark, hostErrorMessage => {
- diagnostics.push(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
- });
- }
-
- function emitDeclarations(host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit {
- let newLine = host.getNewLine();
- let compilerOptions = host.getCompilerOptions();
- let languageVersion = compilerOptions.target || ScriptTarget.ES3;
-
- let write: (s: string) => void;
- let writeLine: () => void;
- let increaseIndent: () => void;
- let decreaseIndent: () => void;
- let writeTextOfNode: (sourceFile: SourceFile, node: Node) => void;
-
- let writer = createAndSetNewTextWriterWithSymbolWriter();
-
- let enclosingDeclaration: Node;
- let currentSourceFile: SourceFile;
- let reportedDeclarationError = false;
- let emitJsDocComments = compilerOptions.removeComments ? function (declaration: Node) { } : writeJsDocComments;
- let emit = compilerOptions.stripInternal ? stripInternal : emitNode;
-
- let moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
- let asynchronousSubModuleDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[];
-
- // Contains the reference paths that needs to go in the declaration file.
- // Collecting this separately because reference paths need to be first thing in the declaration file
- // and we could be collecting these paths from multiple files into single one with --out option
- let referencePathsOutput = "";
-
- if (root) {
- // Emitting just a single file, so emit references in this file only
- if (!compilerOptions.noResolve) {
- let addedGlobalFileReference = false;
- forEach(root.referencedFiles, fileReference => {
- let referencedFile = tryResolveScriptReference(host, root, fileReference);
-
- // All the references that are not going to be part of same file
- if (referencedFile && ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference
- shouldEmitToOwnFile(referencedFile, compilerOptions) || // This is referenced file is emitting its own js file
- !addedGlobalFileReference)) { // Or the global out file corresponding to this reference was not added
-
- writeReferencePath(referencedFile);
- if (!isExternalModuleOrDeclarationFile(referencedFile)) {
- addedGlobalFileReference = true;
- }
- }
- });
- }
-
- emitSourceFile(root);
-
- // create asynchronous output for the importDeclarations
- if (moduleElementDeclarationEmitInfo.length) {
- let oldWriter = writer;
- forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
- if (aliasEmitInfo.isVisible) {
- Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration);
- createAndSetNewTextWriterWithSymbolWriter();
- Debug.assert(aliasEmitInfo.indent === 0);
- writeImportDeclaration(aliasEmitInfo.node);
- aliasEmitInfo.asynchronousOutput = writer.getText();
- }
- });
- setWriter(oldWriter);
- }
- }
- else {
- // Emit references corresponding to this file
- let emittedReferencedFiles: SourceFile[] = [];
- forEach(host.getSourceFiles(), sourceFile => {
- if (!isExternalModuleOrDeclarationFile(sourceFile)) {
- // Check what references need to be added
- if (!compilerOptions.noResolve) {
- forEach(sourceFile.referencedFiles, fileReference => {
- let referencedFile = tryResolveScriptReference(host, sourceFile, fileReference);
-
- // If the reference file is a declaration file or an external module, emit that reference
- if (referencedFile && (isExternalModuleOrDeclarationFile(referencedFile) &&
- !contains(emittedReferencedFiles, referencedFile))) { // If the file reference was not already emitted
-
- writeReferencePath(referencedFile);
- emittedReferencedFiles.push(referencedFile);
- }
- });
- }
-
- emitSourceFile(sourceFile);
- }
- });
- }
-
- return {
- reportedDeclarationError,
- moduleElementDeclarationEmitInfo,
- synchronousDeclarationOutput: writer.getText(),
- referencePathsOutput,
- }
-
- function hasInternalAnnotation(range: CommentRange) {
- let text = currentSourceFile.text;
- let comment = text.substring(range.pos, range.end);
- return comment.indexOf("@internal") >= 0;
- }
-
- function stripInternal(node: Node) {
- if (node) {
- let leadingCommentRanges = getLeadingCommentRanges(currentSourceFile.text, node.pos);
- if (forEach(leadingCommentRanges, hasInternalAnnotation)) {
- return;
- }
-
- emitNode(node);
- }
- }
-
- function createAndSetNewTextWriterWithSymbolWriter(): EmitTextWriterWithSymbolWriter {
- let writer = createTextWriter(newLine);
- writer.trackSymbol = trackSymbol;
- writer.writeKeyword = writer.write;
- writer.writeOperator = writer.write;
- writer.writePunctuation = writer.write;
- writer.writeSpace = writer.write;
- writer.writeStringLiteral = writer.writeLiteral;
- writer.writeParameter = writer.write;
- writer.writeSymbol = writer.write;
- setWriter(writer);
- return writer;
- }
-
- function setWriter(newWriter: EmitTextWriterWithSymbolWriter) {
- writer = newWriter;
- write = newWriter.write;
- writeTextOfNode = newWriter.writeTextOfNode;
- writeLine = newWriter.writeLine;
- increaseIndent = newWriter.increaseIndent;
- decreaseIndent = newWriter.decreaseIndent;
- }
-
- function writeAsynchronousModuleElements(nodes: Node[]) {
- let oldWriter = writer;
- forEach(nodes, declaration => {
- let nodeToCheck: Node;
- if (declaration.kind === SyntaxKind.VariableDeclaration) {
- nodeToCheck = declaration.parent.parent;
- } else if (declaration.kind === SyntaxKind.NamedImports || declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ImportClause) {
- Debug.fail("We should be getting ImportDeclaration instead to write");
- } else {
- nodeToCheck = declaration;
- }
-
- let moduleElementEmitInfo = forEach(moduleElementDeclarationEmitInfo, declEmitInfo => declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined);
- if (!moduleElementEmitInfo && asynchronousSubModuleDeclarationEmitInfo) {
- moduleElementEmitInfo = forEach(asynchronousSubModuleDeclarationEmitInfo, declEmitInfo => declEmitInfo.node === nodeToCheck ? declEmitInfo : undefined);
- }
-
- // If the alias was marked as not visible when we saw its declaration, we would have saved the aliasEmitInfo, but if we haven't yet visited the alias declaration
- // then we don't need to write it at this point. We will write it when we actually see its declaration
- // Eg.
- // export function bar(a: foo.Foo) { }
- // import foo = require("foo");
- // Writing of function bar would mark alias declaration foo as visible but we haven't yet visited that declaration so do nothing,
- // we would write alias foo declaration when we visit it since it would now be marked as visible
- if (moduleElementEmitInfo) {
- if (moduleElementEmitInfo.node.kind === SyntaxKind.ImportDeclaration) {
- // we have to create asynchronous output only after we have collected complete information
- // because it is possible to enable multiple bindings as asynchronously visible
- moduleElementEmitInfo.isVisible = true;
- }
- else {
- createAndSetNewTextWriterWithSymbolWriter();
- for (let declarationIndent = moduleElementEmitInfo.indent; declarationIndent; declarationIndent--) {
- increaseIndent();
- }
-
- if (nodeToCheck.kind === SyntaxKind.ModuleDeclaration) {
- Debug.assert(asynchronousSubModuleDeclarationEmitInfo === undefined);
- asynchronousSubModuleDeclarationEmitInfo = [];
- }
- writeModuleElement(nodeToCheck);
- if (nodeToCheck.kind === SyntaxKind.ModuleDeclaration) {
- moduleElementEmitInfo.subModuleElementDeclarationEmitInfo = asynchronousSubModuleDeclarationEmitInfo;
- asynchronousSubModuleDeclarationEmitInfo = undefined;
- }
- moduleElementEmitInfo.asynchronousOutput = writer.getText();
- }
- }
- });
- setWriter(oldWriter);
- }
-
- function handleSymbolAccessibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
- if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
- // write the aliases
- if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) {
- writeAsynchronousModuleElements(symbolAccesibilityResult.aliasesToMakeVisible);
- }
- }
- else {
- // Report error
- reportedDeclarationError = true;
- let errorInfo = writer.getSymbolAccessibilityDiagnostic(symbolAccesibilityResult);
- if (errorInfo) {
- if (errorInfo.typeName) {
- diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
- errorInfo.diagnosticMessage,
- getSourceTextOfNodeFromSourceFile(currentSourceFile, errorInfo.typeName),
- symbolAccesibilityResult.errorSymbolName,
- symbolAccesibilityResult.errorModuleName));
- }
- else {
- diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
- errorInfo.diagnosticMessage,
- symbolAccesibilityResult.errorSymbolName,
- symbolAccesibilityResult.errorModuleName));
- }
- }
- }
- }
-
- function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
- handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning));
- }
-
- function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode | StringLiteralExpression, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
- writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
- write(": ");
- if (type) {
- // Write the type
- emitType(type);
- }
- else {
- resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
- }
- }
-
- function writeReturnTypeAtSignature(signature: SignatureDeclaration, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
- writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
- write(": ");
- if (signature.type) {
- // Write the type
- emitType(signature.type);
- }
- else {
- resolver.writeReturnTypeOfSignatureDeclaration(signature, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
- }
- }
-
- function emitLines(nodes: Node[]) {
- for (let node of nodes) {
- emit(node);
- }
- }
-
- function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
- let currentWriterPos = writer.getTextPos();
- for (let node of nodes) {
- if (!canEmitFn || canEmitFn(node)) {
- if (currentWriterPos !== writer.getTextPos()) {
- write(separator);
- }
- currentWriterPos = writer.getTextPos();
- eachNodeEmitFn(node);
- }
- }
- }
-
- function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void, canEmitFn?: (node: Node) => boolean) {
- emitSeparatedList(nodes, ", ", eachNodeEmitFn, canEmitFn);
- }
-
- function writeJsDocComments(declaration: Node) {
- if (declaration) {
- let jsDocComments = getJsDocComments(declaration, currentSourceFile);
- emitNewLineBeforeLeadingComments(currentSourceFile, writer, declaration, jsDocComments);
- // jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space
- emitComments(currentSourceFile, writer, jsDocComments, /*trailingSeparator*/ true, newLine, writeCommentRange);
- }
- }
-
- function emitTypeWithNewGetSymbolAccessibilityDiagnostic(type: TypeNode | EntityName, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
- writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
- emitType(type);
- }
-
- function emitType(type: TypeNode | StringLiteralExpression | Identifier | QualifiedName) {
- switch (type.kind) {
- case SyntaxKind.AnyKeyword:
- case SyntaxKind.StringKeyword:
- case SyntaxKind.NumberKeyword:
- case SyntaxKind.BooleanKeyword:
- case SyntaxKind.SymbolKeyword:
- case SyntaxKind.VoidKeyword:
- case SyntaxKind.StringLiteral:
- return writeTextOfNode(currentSourceFile, type);
- case SyntaxKind.TypeReference:
- return emitTypeReference(type);
- case SyntaxKind.TypeQuery:
- return emitTypeQuery(type);
- case SyntaxKind.ArrayType:
- return emitArrayType(type);
- case SyntaxKind.TupleType:
- return emitTupleType(type);
- case SyntaxKind.UnionType:
- return emitUnionType(type);
- case SyntaxKind.ParenthesizedType:
- return emitParenType(type);
- case SyntaxKind.FunctionType:
- case SyntaxKind.ConstructorType:
- return emitSignatureDeclarationWithJsDocComments(type);
- case SyntaxKind.TypeLiteral:
- return emitTypeLiteral(type);
- case SyntaxKind.Identifier:
- return emitEntityName(type);
- case SyntaxKind.QualifiedName:
- return emitEntityName(type);
- default:
- Debug.fail("Unknown type annotation: " + type.kind);
- }
-
- function emitEntityName(entityName: EntityName) {
- let visibilityResult = resolver.isEntityNameVisible(entityName,
- // Aliases can be written asynchronously so use correct enclosing declaration
- entityName.parent.kind === SyntaxKind.ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration);
-
- handleSymbolAccessibilityError(visibilityResult);
- writeEntityName(entityName);
-
- function writeEntityName(entityName: EntityName) {
- if (entityName.kind === SyntaxKind.Identifier) {
- writeTextOfNode(currentSourceFile, entityName);
- }
- else {
- let qualifiedName = entityName;
- writeEntityName(qualifiedName.left);
- write(".");
- writeTextOfNode(currentSourceFile, qualifiedName.right);
- }
- }
- }
-
- function emitTypeReference(type: TypeReferenceNode) {
- emitEntityName(type.typeName);
- if (type.typeArguments) {
- write("<");
- emitCommaList(type.typeArguments, emitType);
- write(">");
- }
- }
-
- function emitTypeQuery(type: TypeQueryNode) {
- write("typeof ");
- emitEntityName(type.exprName);
- }
-
- function emitArrayType(type: ArrayTypeNode) {
- emitType(type.elementType);
- write("[]");
- }
-
- function emitTupleType(type: TupleTypeNode) {
- write("[");
- emitCommaList(type.elementTypes, emitType);
- write("]");
- }
-
- function emitUnionType(type: UnionTypeNode) {
- emitSeparatedList(type.types, " | ", emitType);
- }
-
- function emitParenType(type: ParenthesizedTypeNode) {
- write("(");
- emitType(type.type);
- write(")");
- }
-
- function emitTypeLiteral(type: TypeLiteralNode) {
- write("{");
- if (type.members.length) {
- writeLine();
- increaseIndent();
- // write members
- emitLines(type.members);
- decreaseIndent();
- }
- write("}");
- }
- }
-
- function emitSourceFile(node: SourceFile) {
- currentSourceFile = node;
- enclosingDeclaration = node;
- emitLines(node.statements);
- }
-
- function emitExportAssignment(node: ExportAssignment) {
- write(node.isExportEquals ? "export = " : "export default ");
- if (node.expression.kind === SyntaxKind.Identifier) {
- writeTextOfNode(currentSourceFile, node.expression);
- }
- else {
- write(": ");
- if (node.type) {
- emitType(node.type);
- }
- else {
- writer.getSymbolAccessibilityDiagnostic = getDefaultExportAccessibilityDiagnostic;
- resolver.writeTypeOfExpression(node.expression, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
- }
- }
- write(";");
- writeLine();
-
- // Make all the declarations visible for the export name
- if (node.expression.kind === SyntaxKind.Identifier) {
- let nodes = resolver.collectLinkedAliases(node.expression);
-
- // write each of these declarations asynchronously
- writeAsynchronousModuleElements(nodes);
- }
-
- function getDefaultExportAccessibilityDiagnostic(diagnostic: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- return {
- diagnosticMessage: Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0,
- errorNode: node
- };
- }
- }
-
- function isModuleElementVisible(node: Declaration) {
- return resolver.isDeclarationVisible(node);
- }
-
- function emitModuleElement(node: Node, isModuleElementVisible: boolean) {
- if (isModuleElementVisible) {
- writeModuleElement(node);
- }
- // Import equals declaration in internal module can become visible as part of any emit so lets make sure we add these irrespective
- else if (node.kind === SyntaxKind.ImportEqualsDeclaration ||
- (node.parent.kind === SyntaxKind.SourceFile && isExternalModule(currentSourceFile))) {
- let isVisible: boolean;
- if (asynchronousSubModuleDeclarationEmitInfo && node.parent.kind !== SyntaxKind.SourceFile) {
- // Import declaration of another module that is visited async so lets put it in right spot
- asynchronousSubModuleDeclarationEmitInfo.push({
- node,
- outputPos: writer.getTextPos(),
- indent: writer.getIndent(),
- isVisible
- });
- }
- else {
- if (node.kind === SyntaxKind.ImportDeclaration) {
- let importDeclaration = node;
- if (importDeclaration.importClause) {
- isVisible = (importDeclaration.importClause.name && resolver.isDeclarationVisible(importDeclaration.importClause)) ||
- isVisibleNamedBinding(importDeclaration.importClause.namedBindings);
- }
- }
- moduleElementDeclarationEmitInfo.push({
- node,
- outputPos: writer.getTextPos(),
- indent: writer.getIndent(),
- isVisible
- });
- }
- }
- }
-
- function writeModuleElement(node: Node) {
- switch (node.kind) {
- case SyntaxKind.FunctionDeclaration:
- return writeFunctionDeclaration(node);
- case SyntaxKind.VariableStatement:
- return writeVariableStatement(node);
- case SyntaxKind.InterfaceDeclaration:
- return writeInterfaceDeclaration(node);
- case SyntaxKind.ClassDeclaration:
- return writeClassDeclaration(node);
- case SyntaxKind.TypeAliasDeclaration:
- return writeTypeAliasDeclaration(node);
- case SyntaxKind.EnumDeclaration:
- return writeEnumDeclaration(node);
- case SyntaxKind.ModuleDeclaration:
- return writeModuleDeclaration(node);
- case SyntaxKind.ImportEqualsDeclaration:
- return writeImportEqualsDeclaration(node);
- case SyntaxKind.ImportDeclaration:
- return writeImportDeclaration(node);
- default:
- Debug.fail("Unknown symbol kind");
- }
- }
-
- function emitModuleElementDeclarationFlags(node: Node) {
- // If the node is parented in the current source file we need to emit export declare or just export
- if (node.parent === currentSourceFile) {
- // If the node is exported
- if (node.flags & NodeFlags.Export) {
- write("export ");
- }
-
- if (node.flags & NodeFlags.Default) {
- write("default ");
- }
- else if (node.kind !== SyntaxKind.InterfaceDeclaration) {
- write("declare ");
- }
- }
- }
-
- function emitClassMemberDeclarationFlags(node: Declaration) {
- if (node.flags & NodeFlags.Private) {
- write("private ");
- }
- else if (node.flags & NodeFlags.Protected) {
- write("protected ");
- }
-
- if (node.flags & NodeFlags.Static) {
- write("static ");
- }
- }
-
- function writeImportEqualsDeclaration(node: ImportEqualsDeclaration) {
- // note usage of writer. methods instead of aliases created, just to make sure we are using
- // correct writer especially to handle asynchronous alias writing
- emitJsDocComments(node);
- if (node.flags & NodeFlags.Export) {
- write("export ");
- }
- write("import ");
- writeTextOfNode(currentSourceFile, node.name);
- write(" = ");
- if (isInternalModuleImportEqualsDeclaration(node)) {
- emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.moduleReference, getImportEntityNameVisibilityError);
- write(";");
- }
- else {
- write("require(");
- writeTextOfNode(currentSourceFile, getExternalModuleImportEqualsDeclarationExpression(node));
- write(");");
- }
- writer.writeLine();
-
- function getImportEntityNameVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- return {
- diagnosticMessage: Diagnostics.Import_declaration_0_is_using_private_name_1,
- errorNode: node,
- typeName: node.name
- };
- }
- }
-
- function isVisibleNamedBinding(namedBindings: NamespaceImport | NamedImports): boolean {
- if (namedBindings) {
- if (namedBindings.kind === SyntaxKind.NamespaceImport) {
- return resolver.isDeclarationVisible(namedBindings);
- }
- else {
- return forEach((namedBindings).elements, namedImport => resolver.isDeclarationVisible(namedImport));
- }
- }
- }
-
- function writeImportDeclaration(node: ImportDeclaration) {
- if (!node.importClause && !(node.flags & NodeFlags.Export)) {
- // do not write non-exported import declarations that don't have import clauses
- return;
- }
- emitJsDocComments(node);
- if (node.flags & NodeFlags.Export) {
- write("export ");
- }
- write("import ");
- if (node.importClause) {
- let currentWriterPos = writer.getTextPos();
- if (node.importClause.name && resolver.isDeclarationVisible(node.importClause)) {
- writeTextOfNode(currentSourceFile, node.importClause.name);
- }
- if (node.importClause.namedBindings && isVisibleNamedBinding(node.importClause.namedBindings)) {
- if (currentWriterPos !== writer.getTextPos()) {
- // If the default binding was emitted, write the separated
- write(", ");
- }
- if (node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
- write("* as ");
- writeTextOfNode(currentSourceFile, (node.importClause.namedBindings).name);
- }
- else {
- write("{ ");
- emitCommaList((node.importClause.namedBindings).elements, emitImportOrExportSpecifier, resolver.isDeclarationVisible);
- write(" }");
- }
- }
- write(" from ");
- }
- writeTextOfNode(currentSourceFile, node.moduleSpecifier);
- write(";");
- writer.writeLine();
- }
-
- function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) {
- if (node.propertyName) {
- writeTextOfNode(currentSourceFile, node.propertyName);
- write(" as ");
- }
- writeTextOfNode(currentSourceFile, node.name);
- }
-
- function emitExportSpecifier(node: ExportSpecifier) {
- emitImportOrExportSpecifier(node);
-
- // Make all the declarations visible for the export name
- let nodes = resolver.collectLinkedAliases(node.propertyName || node.name);
-
- // write each of these declarations asynchronously
- writeAsynchronousModuleElements(nodes);
- }
-
- function emitExportDeclaration(node: ExportDeclaration) {
- emitJsDocComments(node);
- write("export ");
- if (node.exportClause) {
- write("{ ");
- emitCommaList(node.exportClause.elements, emitExportSpecifier);
- write(" }");
- }
- else {
- write("*");
- }
- if (node.moduleSpecifier) {
- write(" from ");
- writeTextOfNode(currentSourceFile, node.moduleSpecifier);
- }
- write(";");
- writer.writeLine();
- }
-
- function writeModuleDeclaration(node: ModuleDeclaration) {
- emitJsDocComments(node);
- emitModuleElementDeclarationFlags(node);
- write("module ");
- writeTextOfNode(currentSourceFile, node.name);
- while (node.body.kind !== SyntaxKind.ModuleBlock) {
- node = node.body;
- write(".");
- writeTextOfNode(currentSourceFile, node.name);
- }
- let prevEnclosingDeclaration = enclosingDeclaration;
- enclosingDeclaration = node;
- write(" {");
- writeLine();
- increaseIndent();
- emitLines((node.body).statements);
- decreaseIndent();
- write("}");
- writeLine();
- enclosingDeclaration = prevEnclosingDeclaration;
- }
-
- function writeTypeAliasDeclaration(node: TypeAliasDeclaration) {
- emitJsDocComments(node);
- emitModuleElementDeclarationFlags(node);
- write("type ");
- writeTextOfNode(currentSourceFile, node.name);
- write(" = ");
- emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.type, getTypeAliasDeclarationVisibilityError);
- write(";");
- writeLine();
-
- function getTypeAliasDeclarationVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- return {
- diagnosticMessage: Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1,
- errorNode: node.type,
- typeName: node.name
- };
- }
- }
-
- function writeEnumDeclaration(node: EnumDeclaration) {
- emitJsDocComments(node);
- emitModuleElementDeclarationFlags(node);
- if (isConst(node)) {
- write("const ")
- }
- write("enum ");
- writeTextOfNode(currentSourceFile, node.name);
- write(" {");
- writeLine();
- increaseIndent();
- emitLines(node.members);
- decreaseIndent();
- write("}");
- writeLine();
- }
-
- function emitEnumMemberDeclaration(node: EnumMember) {
- emitJsDocComments(node);
- writeTextOfNode(currentSourceFile, node.name);
- let enumMemberValue = resolver.getConstantValue(node);
- if (enumMemberValue !== undefined) {
- write(" = ");
- write(enumMemberValue.toString());
- }
- write(",");
- writeLine();
- }
-
- function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) {
- return node.parent.kind === SyntaxKind.MethodDeclaration && (node.parent.flags & NodeFlags.Private);
- }
-
- function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) {
- function emitTypeParameter(node: TypeParameterDeclaration) {
- increaseIndent();
- emitJsDocComments(node);
- decreaseIndent();
- writeTextOfNode(currentSourceFile, node.name);
- // If there is constraint present and this is not a type parameter of the private method emit the constraint
- if (node.constraint && !isPrivateMethodTypeParameter(node)) {
- write(" extends ");
- if (node.parent.kind === SyntaxKind.FunctionType ||
- node.parent.kind === SyntaxKind.ConstructorType ||
- (node.parent.parent && node.parent.parent.kind === SyntaxKind.TypeLiteral)) {
- Debug.assert(node.parent.kind === SyntaxKind.MethodDeclaration ||
- node.parent.kind === SyntaxKind.MethodSignature ||
- node.parent.kind === SyntaxKind.FunctionType ||
- node.parent.kind === SyntaxKind.ConstructorType ||
- node.parent.kind === SyntaxKind.CallSignature ||
- node.parent.kind === SyntaxKind.ConstructSignature);
- emitType(node.constraint);
- }
- else {
- emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.constraint, getTypeParameterConstraintVisibilityError);
- }
- }
-
- function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- // Type parameter constraints are named by user so we should always be able to name it
- let diagnosticMessage: DiagnosticMessage;
- switch (node.parent.kind) {
- case SyntaxKind.ClassDeclaration:
- diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_private_name_1;
- break;
-
- case SyntaxKind.InterfaceDeclaration:
- diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1;
- break;
-
- case SyntaxKind.ConstructSignature:
- diagnosticMessage = Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
- break;
-
- case SyntaxKind.CallSignature:
- diagnosticMessage = Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
- break;
-
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- if (node.parent.flags & NodeFlags.Static) {
- diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
- }
- else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
- diagnosticMessage = Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
- }
- else {
- diagnosticMessage = Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
- }
- break;
-
- case SyntaxKind.FunctionDeclaration:
- diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1;
- break;
-
- default:
- Debug.fail("This is unknown parent for type parameter: " + node.parent.kind);
- }
-
- return {
- diagnosticMessage,
- errorNode: node,
- typeName: node.name
- };
- }
- }
-
- if (typeParameters) {
- write("<");
- emitCommaList(typeParameters, emitTypeParameter);
- write(">");
- }
- }
-
- function emitHeritageClause(typeReferences: TypeReferenceNode[], isImplementsList: boolean) {
- if (typeReferences) {
- write(isImplementsList ? " implements " : " extends ");
- emitCommaList(typeReferences, emitTypeOfTypeReference);
- }
-
- function emitTypeOfTypeReference(node: TypeReferenceNode) {
- emitTypeWithNewGetSymbolAccessibilityDiagnostic(node, getHeritageClauseVisibilityError);
-
- function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- let diagnosticMessage: DiagnosticMessage;
- // Heritage clause is written by user so it can always be named
- if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
- // Class or Interface implemented/extended is inaccessible
- diagnosticMessage = isImplementsList ?
- Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 :
- Diagnostics.Extends_clause_of_exported_class_0_has_or_is_using_private_name_1;
- }
- else {
- // interface is inaccessible
- diagnosticMessage = Diagnostics.Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1;
- }
-
- return {
- diagnosticMessage,
- errorNode: node,
- typeName: (node.parent.parent).name
- };
- }
- }
- }
-
- function writeClassDeclaration(node: ClassDeclaration) {
- function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) {
- if (constructorDeclaration) {
- forEach(constructorDeclaration.parameters, param => {
- if (param.flags & NodeFlags.AccessibilityModifier) {
- emitPropertyDeclaration(param);
- }
- });
- }
- }
-
- emitJsDocComments(node);
- emitModuleElementDeclarationFlags(node);
- write("class ");
- writeTextOfNode(currentSourceFile, node.name);
- let prevEnclosingDeclaration = enclosingDeclaration;
- enclosingDeclaration = node;
- emitTypeParameters(node.typeParameters);
- let baseTypeNode = getClassBaseTypeNode(node);
- if (baseTypeNode) {
- emitHeritageClause([baseTypeNode], /*isImplementsList*/ false);
- }
- emitHeritageClause(getClassImplementedTypeNodes(node), /*isImplementsList*/ true);
- write(" {");
- writeLine();
- increaseIndent();
- emitParameterProperties(getFirstConstructorWithBody(node));
- emitLines(node.members);
- decreaseIndent();
- write("}");
- writeLine();
- enclosingDeclaration = prevEnclosingDeclaration;
- }
-
- function writeInterfaceDeclaration(node: InterfaceDeclaration) {
- emitJsDocComments(node);
- emitModuleElementDeclarationFlags(node);
- write("interface ");
- writeTextOfNode(currentSourceFile, node.name);
- let prevEnclosingDeclaration = enclosingDeclaration;
- enclosingDeclaration = node;
- emitTypeParameters(node.typeParameters);
- emitHeritageClause(getInterfaceBaseTypeNodes(node), /*isImplementsList*/ false);
- write(" {");
- writeLine();
- increaseIndent();
- emitLines(node.members);
- decreaseIndent();
- write("}");
- writeLine();
- enclosingDeclaration = prevEnclosingDeclaration;
- }
-
- function emitPropertyDeclaration(node: Declaration) {
- if (hasDynamicName(node)) {
- return;
- }
-
- emitJsDocComments(node);
- emitClassMemberDeclarationFlags(node);
- emitVariableDeclaration(node);
- write(";");
- writeLine();
- }
-
- function emitVariableDeclaration(node: VariableDeclaration) {
- // If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
- // so there is no check needed to see if declaration is visible
- if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
- if (isBindingPattern(node.name)) {
- emitBindingPattern(node.name);
- }
- else {
- // If this node is a computed name, it can only be a symbol, because we've already skipped
- // it if it's not a well known symbol. In that case, the text of the name will be exactly
- // what we want, namely the name expression enclosed in brackets.
- writeTextOfNode(currentSourceFile, node.name);
- // If optional property emit ?
- if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && hasQuestionToken(node)) {
- write("?");
- }
- if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
- emitTypeOfVariableDeclarationFromTypeLiteral(node);
- }
- else if (!(node.flags & NodeFlags.Private)) {
- writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError);
- }
- }
- }
-
- function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult: SymbolAccessiblityResult) {
- if (node.kind === SyntaxKind.VariableDeclaration) {
- return symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
- Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Exported_variable_0_has_or_is_using_private_name_1;
- }
- // This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
- else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) {
- // TODO(jfreeman): Deal with computed properties in error reporting.
- if (node.flags & NodeFlags.Static) {
- return symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
- Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1;
- }
- else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
- return symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
- Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1;
- }
- else {
- // Interfaces cannot have types that cannot be named
- return symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1;
- }
- }
- }
-
- function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- let diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult);
- return diagnosticMessage !== undefined ? {
- diagnosticMessage,
- errorNode: node,
- typeName: node.name
- } : undefined;
- }
-
- function emitBindingPattern(bindingPattern: BindingPattern) {
- emitCommaList(bindingPattern.elements, emitBindingElement);
- }
-
- function emitBindingElement(bindingElement: BindingElement) {
- function getBindingElementTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- let diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccesibilityResult);
- return diagnosticMessage !== undefined ? {
- diagnosticMessage,
- errorNode: bindingElement,
- typeName: bindingElement.name
- } : undefined;
- }
-
- if (bindingElement.name) {
- if (isBindingPattern(bindingElement.name)) {
- emitBindingPattern(bindingElement.name);
- }
- else {
- writeTextOfNode(currentSourceFile, bindingElement.name);
- writeTypeOfDeclaration(bindingElement, /*type*/ undefined, getBindingElementTypeVisibilityError);
- }
- }
- }
- }
-
- function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableLikeDeclaration) {
- // if this is property of type literal,
- // or is parameter of method/call/construct/index signature of type literal
- // emit only if type is specified
- if (node.type) {
- write(": ");
- emitType(node.type);
- }
- }
-
- function isVariableStatementVisible(node: VariableStatement) {
- return forEach(node.declarationList.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration));
- }
-
- function writeVariableStatement(node: VariableStatement) {
- emitJsDocComments(node);
- emitModuleElementDeclarationFlags(node);
- if (isLet(node.declarationList)) {
- write("let ");
- }
- else if (isConst(node.declarationList)) {
- write("const ");
- }
- else {
- write("var ");
- }
- emitCommaList(node.declarationList.declarations, emitVariableDeclaration, resolver.isDeclarationVisible);
- write(";");
- writeLine();
- }
-
- function emitAccessorDeclaration(node: AccessorDeclaration) {
- if (hasDynamicName(node)) {
- return;
- }
-
- let accessors = getAllAccessorDeclarations((node.parent).members, node);
- let accessorWithTypeAnnotation: AccessorDeclaration;
-
- if (node === accessors.firstAccessor) {
- emitJsDocComments(accessors.getAccessor);
- emitJsDocComments(accessors.setAccessor);
- emitClassMemberDeclarationFlags(node);
- writeTextOfNode(currentSourceFile, node.name);
- if (!(node.flags & NodeFlags.Private)) {
- accessorWithTypeAnnotation = node;
- let type = getTypeAnnotationFromAccessor(node);
- if (!type) {
- // couldn't get type for the first accessor, try the another one
- let anotherAccessor = node.kind === SyntaxKind.GetAccessor ? accessors.setAccessor : accessors.getAccessor;
- type = getTypeAnnotationFromAccessor(anotherAccessor);
- if (type) {
- accessorWithTypeAnnotation = anotherAccessor;
- }
- }
- writeTypeOfDeclaration(node, type, getAccessorDeclarationTypeVisibilityError);
- }
- write(";");
- writeLine();
- }
-
- function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode | StringLiteralExpression {
- if (accessor) {
- return accessor.kind === SyntaxKind.GetAccessor
- ? accessor.type // Getter - return type
- : accessor.parameters.length > 0
- ? accessor.parameters[0].type // Setter parameter type
- : undefined;
- }
- }
-
- function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- let diagnosticMessage: DiagnosticMessage;
- if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) {
- // Setters have to have type named and cannot infer it so, the type should always be named
- if (accessorWithTypeAnnotation.parent.flags & NodeFlags.Static) {
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1;
- }
- else {
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1;
- }
- return {
- diagnosticMessage,
- errorNode: accessorWithTypeAnnotation.parameters[0],
- // TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name
- typeName: accessorWithTypeAnnotation.name
- };
- }
- else {
- if (accessorWithTypeAnnotation.flags & NodeFlags.Static) {
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
- Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0;
- }
- else {
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
- Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0;
- }
- return {
- diagnosticMessage,
- errorNode: accessorWithTypeAnnotation.name,
- typeName: undefined
- };
- }
- }
- }
-
- function writeFunctionDeclaration(node: FunctionLikeDeclaration) {
- if (hasDynamicName(node)) {
- return;
- }
-
- // If we are emitting Method/Constructor it isn't moduleElement and hence already determined to be emitting
- // so no need to verify if the declaration is visible
- if (!resolver.isImplementationOfOverload(node)) {
- emitJsDocComments(node);
- if (node.kind === SyntaxKind.FunctionDeclaration) {
- emitModuleElementDeclarationFlags(node);
- }
- else if (node.kind === SyntaxKind.MethodDeclaration) {
- emitClassMemberDeclarationFlags(node);
- }
- if (node.kind === SyntaxKind.FunctionDeclaration) {
- write("function ");
- writeTextOfNode(currentSourceFile, node.name);
- }
- else if (node.kind === SyntaxKind.Constructor) {
- write("constructor");
- }
- else {
- writeTextOfNode(currentSourceFile, node.name);
- if (hasQuestionToken(node)) {
- write("?");
- }
- }
- emitSignatureDeclaration(node);
- }
- }
-
- function emitSignatureDeclarationWithJsDocComments(node: SignatureDeclaration) {
- emitJsDocComments(node);
- emitSignatureDeclaration(node);
- }
-
- function emitSignatureDeclaration(node: SignatureDeclaration) {
- // Construct signature or constructor type write new Signature
- if (node.kind === SyntaxKind.ConstructSignature || node.kind === SyntaxKind.ConstructorType) {
- write("new ");
- }
- emitTypeParameters(node.typeParameters);
- if (node.kind === SyntaxKind.IndexSignature) {
- write("[");
- }
- else {
- write("(");
- }
-
- let prevEnclosingDeclaration = enclosingDeclaration;
- enclosingDeclaration = node;
-
- // Parameters
- emitCommaList(node.parameters, emitParameterDeclaration);
-
- if (node.kind === SyntaxKind.IndexSignature) {
- write("]");
- }
- else {
- write(")");
- }
-
- // If this is not a constructor and is not private, emit the return type
- let isFunctionTypeOrConstructorType = node.kind === SyntaxKind.FunctionType || node.kind === SyntaxKind.ConstructorType;
- if (isFunctionTypeOrConstructorType || node.parent.kind === SyntaxKind.TypeLiteral) {
- // Emit type literal signature return type only if specified
- if (node.type) {
- write(isFunctionTypeOrConstructorType ? " => " : ": ");
- emitType(node.type);
- }
- }
- else if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) {
- writeReturnTypeAtSignature(node, getReturnTypeVisibilityError);
- }
-
- enclosingDeclaration = prevEnclosingDeclaration;
-
- if (!isFunctionTypeOrConstructorType) {
- write(";");
- writeLine();
- }
-
- function getReturnTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- let diagnosticMessage: DiagnosticMessage;
- switch (node.kind) {
- case SyntaxKind.ConstructSignature:
- // Interfaces cannot have return types that cannot be named
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0;
- break;
-
- case SyntaxKind.CallSignature:
- // Interfaces cannot have return types that cannot be named
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0;
- break;
-
- case SyntaxKind.IndexSignature:
- // Interfaces cannot have return types that cannot be named
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0;
- break;
-
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- if (node.flags & NodeFlags.Static) {
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
- Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0;
- }
- else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
- Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0;
- }
- else {
- // Interfaces cannot have return types that cannot be named
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0;
- }
- break;
-
- case SyntaxKind.FunctionDeclaration:
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
- Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0;
- break;
-
- default:
- Debug.fail("This is unknown kind for signature: " + node.kind);
- }
-
- return {
- diagnosticMessage,
- errorNode: node.name || node,
- };
- }
- }
-
- function emitParameterDeclaration(node: ParameterDeclaration) {
- increaseIndent();
- emitJsDocComments(node);
- if (node.dotDotDotToken) {
- write("...");
- }
- if (isBindingPattern(node.name)) {
- write("_" + indexOf((node.parent).parameters, node));
- }
- else {
- writeTextOfNode(currentSourceFile, node.name);
- }
- if (node.initializer || hasQuestionToken(node)) {
- write("?");
- }
- decreaseIndent();
-
- if (node.parent.kind === SyntaxKind.FunctionType ||
- node.parent.kind === SyntaxKind.ConstructorType ||
- node.parent.parent.kind === SyntaxKind.TypeLiteral) {
- emitTypeOfVariableDeclarationFromTypeLiteral(node);
- }
- else if (!(node.parent.flags & NodeFlags.Private)) {
- writeTypeOfDeclaration(node, node.type, getParameterDeclarationTypeVisibilityError);
- }
-
- function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
- let diagnosticMessage: DiagnosticMessage;
- switch (node.parent.kind) {
- case SyntaxKind.Constructor:
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
- Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1;
- break;
-
- case SyntaxKind.ConstructSignature:
- // Interfaces cannot have parameter types that cannot be named
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
- break;
-
- case SyntaxKind.CallSignature:
- // Interfaces cannot have parameter types that cannot be named
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
- break;
-
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- if (node.parent.flags & NodeFlags.Static) {
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
- Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
- }
- else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
- Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
- }
- else {
- // Interfaces cannot have parameter types that cannot be named
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
- }
- break;
-
- case SyntaxKind.FunctionDeclaration:
- diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
- symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
- Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1;
- break;
-
- default:
- Debug.fail("This is unknown parent for parameter: " + node.parent.kind);
- }
-
- return {
- diagnosticMessage,
- errorNode: node,
- typeName: node.name
- };
- }
- }
-
- function emitNode(node: Node) {
- switch (node.kind) {
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.ImportEqualsDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.TypeAliasDeclaration:
- case SyntaxKind.EnumDeclaration:
- return emitModuleElement(node, isModuleElementVisible(node));
- case SyntaxKind.VariableStatement:
- return emitModuleElement(node, isVariableStatementVisible(node));
- case SyntaxKind.ImportDeclaration:
- // Import declaration without import clause is visible, otherwise it is not visible
- return emitModuleElement(node, /*isModuleElementVisible*/!(node).importClause);
- case SyntaxKind.ExportDeclaration:
- return emitExportDeclaration(node);
- case SyntaxKind.Constructor:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- return writeFunctionDeclaration(node);
- case SyntaxKind.ConstructSignature:
- case SyntaxKind.CallSignature:
- case SyntaxKind.IndexSignature:
- return emitSignatureDeclarationWithJsDocComments(node);
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- return emitAccessorDeclaration(node);
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- return emitPropertyDeclaration(node);
- case SyntaxKind.EnumMember:
- return emitEnumMemberDeclaration(node);
- case SyntaxKind.ExportAssignment:
- return emitExportAssignment(node);
- case SyntaxKind.SourceFile:
- return emitSourceFile(node);
- }
- }
-
- function writeReferencePath(referencedFile: SourceFile) {
- let declFileName = referencedFile.flags & NodeFlags.DeclarationFile
- ? referencedFile.fileName // Declaration file, use declaration file name
- : shouldEmitToOwnFile(referencedFile, compilerOptions)
- ? getOwnEmitOutputFilePath(referencedFile, host, ".d.ts") // Own output file so get the .d.ts file
- : removeFileExtension(compilerOptions.out) + ".d.ts";// Global out file
-
- declFileName = getRelativePathToDirectoryOrUrl(
- getDirectoryPath(normalizeSlashes(jsFilePath)),
- declFileName,
- host.getCurrentDirectory(),
- host.getCanonicalFileName,
- /*isAbsolutePathAnUrl*/ false);
-
- referencePathsOutput += "/// " + newLine;
- }
- }
-
- export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] {
- let diagnostics: Diagnostic[] = [];
- let jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js");
- emitDeclarations(host, resolver, diagnostics, jsFilePath, targetSourceFile);
- return diagnostics;
- }
-
// @internal
// 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): EmitResult {
@@ -6297,37 +4552,11 @@ module ts {
}
}
- function writeDeclarationFile(jsFilePath: string, sourceFile: SourceFile) {
- let emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, jsFilePath, sourceFile);
- // TODO(shkamat): Should we not write any declaration file if any of them can produce error,
- // or should we just not write this file like we are doing now
- if (!emitDeclarationResult.reportedDeclarationError) {
- let declarationOutput = emitDeclarationResult.referencePathsOutput
- + getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
- writeFile(host, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, compilerOptions.emitBOM);
- }
-
- function getDeclarationOutput(synchronousDeclarationOutput: string, moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]) {
- let appliedSyncOutputPos = 0;
- let declarationOutput = "";
- // apply asynchronous additions to the synchronous output
- forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
- if (aliasEmitInfo.asynchronousOutput) {
- declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos, aliasEmitInfo.outputPos);
- declarationOutput += getDeclarationOutput(aliasEmitInfo.asynchronousOutput, aliasEmitInfo.subModuleElementDeclarationEmitInfo);
- appliedSyncOutputPos = aliasEmitInfo.outputPos;
- }
- });
- declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos);
- return declarationOutput;
- }
- }
-
function emitFile(jsFilePath: string, sourceFile?: SourceFile) {
emitJavaScript(jsFilePath, sourceFile);
if (compilerOptions.declaration) {
- writeDeclarationFile(jsFilePath, sourceFile);
+ writeDeclarationFile(jsFilePath, sourceFile, host, resolver, diagnostics);
}
}
}
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index fd7e1304c85..bdd23f82746 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -1364,4 +1364,317 @@ module ts {
s.replace(nonAsciiCharacters, c => get16BitUnicodeEscapeSequence(c.charCodeAt(0))) :
s;
}
+
+ export interface EmitTextWriter {
+ write(s: string): void;
+ writeTextOfNode(sourceFile: SourceFile, node: Node): void;
+ writeLine(): void;
+ increaseIndent(): void;
+ decreaseIndent(): void;
+ getText(): string;
+ rawWrite(s: string): void;
+ writeLiteral(s: string): void;
+ getTextPos(): number;
+ getLine(): number;
+ getColumn(): number;
+ getIndent(): number;
+ }
+
+ let indentStrings: string[] = ["", " "];
+ export function getIndentString(level: number) {
+ if (indentStrings[level] === undefined) {
+ indentStrings[level] = getIndentString(level - 1) + indentStrings[1];
+ }
+ return indentStrings[level];
+ }
+
+ export function getIndentSize() {
+ return indentStrings[1].length;
+ }
+
+ export function createTextWriter(newLine: String): EmitTextWriter {
+ let output = "";
+ let indent = 0;
+ let lineStart = true;
+ let lineCount = 0;
+ let linePos = 0;
+
+ function write(s: string) {
+ if (s && s.length) {
+ if (lineStart) {
+ output += getIndentString(indent);
+ lineStart = false;
+ }
+ output += s;
+ }
+ }
+
+ function rawWrite(s: string) {
+ if (s !== undefined) {
+ if (lineStart) {
+ lineStart = false;
+ }
+ output += s;
+ }
+ }
+
+ function writeLiteral(s: string) {
+ if (s && s.length) {
+ write(s);
+ let lineStartsOfS = computeLineStarts(s);
+ if (lineStartsOfS.length > 1) {
+ lineCount = lineCount + lineStartsOfS.length - 1;
+ linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1];
+ }
+ }
+ }
+
+ function writeLine() {
+ if (!lineStart) {
+ output += newLine;
+ lineCount++;
+ linePos = output.length;
+ lineStart = true;
+ }
+ }
+
+ function writeTextOfNode(sourceFile: SourceFile, node: Node) {
+ write(getSourceTextOfNodeFromSourceFile(sourceFile, node));
+ }
+
+ return {
+ write,
+ rawWrite,
+ writeTextOfNode,
+ writeLiteral,
+ writeLine,
+ increaseIndent: () => indent++,
+ decreaseIndent: () => indent--,
+ getIndent: () => indent,
+ getTextPos: () => output.length,
+ getLine: () => lineCount + 1,
+ getColumn: () => lineStart ? indent * getIndentSize() + 1 : output.length - linePos + 1,
+ getText: () => output,
+ };
+ }
+
+ export function getOwnEmitOutputFilePath(sourceFile: SourceFile, host: EmitHost, extension: string) {
+ let compilerOptions = host.getCompilerOptions();
+ let emitOutputFilePathWithoutExtension: string;
+ if (compilerOptions.outDir) {
+ emitOutputFilePathWithoutExtension = removeFileExtension(getSourceFilePathInNewDir(sourceFile, host, compilerOptions.outDir));
+ }
+ else {
+ emitOutputFilePathWithoutExtension = removeFileExtension(sourceFile.fileName);
+ }
+
+ return emitOutputFilePathWithoutExtension + extension;
+ }
+
+ export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
+ let sourceFilePath = getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory());
+ sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), "");
+ return combinePaths(newDirPath, sourceFilePath);
+ }
+
+ export function writeFile(host: EmitHost, diagnostics: Diagnostic[], fileName: string, data: string, writeByteOrderMark: boolean) {
+ host.writeFile(fileName, data, writeByteOrderMark, hostErrorMessage => {
+ diagnostics.push(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
+ });
+ }
+
+ export function getLineOfLocalPosition(currentSourceFile: SourceFile, pos: number) {
+ return getLineAndCharacterOfPosition(currentSourceFile, pos).line;
+ }
+
+ export function getFirstConstructorWithBody(node: ClassDeclaration): ConstructorDeclaration {
+ return forEach(node.members, member => {
+ if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member).body)) {
+ return member;
+ }
+ });
+ }
+
+ export function shouldEmitToOwnFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
+ if (!isDeclarationFile(sourceFile)) {
+ if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.fileName, ".js")) {
+ return true;
+ }
+ return false;
+ }
+ return false;
+ }
+
+ export function getAllAccessorDeclarations(declarations: NodeArray, accessor: AccessorDeclaration) {
+ let firstAccessor: AccessorDeclaration;
+ let getAccessor: AccessorDeclaration;
+ let setAccessor: AccessorDeclaration;
+ if (hasDynamicName(accessor)) {
+ firstAccessor = accessor;
+ if (accessor.kind === SyntaxKind.GetAccessor) {
+ getAccessor = accessor;
+ }
+ else if (accessor.kind === SyntaxKind.SetAccessor) {
+ setAccessor = accessor;
+ }
+ else {
+ Debug.fail("Accessor has wrong kind");
+ }
+ }
+ else {
+ forEach(declarations, (member: Declaration) => {
+ if ((member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor)
+ && (member.flags & NodeFlags.Static) === (accessor.flags & NodeFlags.Static)) {
+ let memberName = getPropertyNameForPropertyNameNode(member.name);
+ let accessorName = getPropertyNameForPropertyNameNode(accessor.name);
+ if (memberName === accessorName) {
+ if (!firstAccessor) {
+ firstAccessor = member;
+ }
+
+ if (member.kind === SyntaxKind.GetAccessor && !getAccessor) {
+ getAccessor = member;
+ }
+
+ if (member.kind === SyntaxKind.SetAccessor && !setAccessor) {
+ setAccessor = member;
+ }
+ }
+ }
+ });
+ }
+ return {
+ firstAccessor,
+ getAccessor,
+ setAccessor
+ };
+ }
+
+ export function emitNewLineBeforeLeadingComments(currentSourceFile: SourceFile, writer: EmitTextWriter, node: TextRange, leadingComments: CommentRange[]) {
+ // If the leading comments start on different line than the start of node, write new line
+ if (leadingComments && leadingComments.length && node.pos !== leadingComments[0].pos &&
+ getLineOfLocalPosition(currentSourceFile, node.pos) !== getLineOfLocalPosition(currentSourceFile, leadingComments[0].pos)) {
+ writer.writeLine();
+ }
+ }
+
+ export function emitComments(currentSourceFile: SourceFile, writer: EmitTextWriter, comments: CommentRange[], trailingSeparator: boolean, newLine: string,
+ writeComment: (currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string) => void) {
+ let emitLeadingSpace = !trailingSeparator;
+ forEach(comments, comment => {
+ if (emitLeadingSpace) {
+ writer.write(" ");
+ emitLeadingSpace = false;
+ }
+ writeComment(currentSourceFile, writer, comment, newLine);
+ if (comment.hasTrailingNewLine) {
+ writer.writeLine();
+ }
+ else if (trailingSeparator) {
+ writer.write(" ");
+ }
+ else {
+ // Emit leading space to separate comment during next comment emit
+ emitLeadingSpace = true;
+ }
+ });
+ }
+
+ export function writeCommentRange(currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string) {
+ if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
+ let firstCommentLineAndCharacter = getLineAndCharacterOfPosition(currentSourceFile, comment.pos);
+ let lineCount = getLineStarts(currentSourceFile).length;
+ let firstCommentLineIndent: number;
+ for (let pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) {
+ let nextLineStart = (currentLine + 1) === lineCount
+ ? currentSourceFile.text.length + 1
+ : getStartPositionOfLine(currentLine + 1, currentSourceFile);
+
+ if (pos !== comment.pos) {
+ // If we are not emitting first line, we need to write the spaces to adjust the alignment
+ if (firstCommentLineIndent === undefined) {
+ firstCommentLineIndent = calculateIndent(getStartPositionOfLine(firstCommentLineAndCharacter.line, currentSourceFile), comment.pos);
+ }
+
+ // These are number of spaces writer is going to write at current indent
+ let currentWriterIndentSpacing = writer.getIndent() * getIndentSize();
+
+ // Number of spaces we want to be writing
+ // eg: Assume writer indent
+ // module m {
+ // /* starts at character 9 this is line 1
+ // * starts at character pos 4 line --1 = 8 - 8 + 3
+ // More left indented comment */ --2 = 8 - 8 + 2
+ // class c { }
+ // }
+ // module m {
+ // /* this is line 1 -- Assume current writer indent 8
+ // * line --3 = 8 - 4 + 5
+ // More right indented comment */ --4 = 8 - 4 + 11
+ // class c { }
+ // }
+ let spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + calculateIndent(pos, nextLineStart);
+ if (spacesToEmit > 0) {
+ let numberOfSingleSpacesToEmit = spacesToEmit % getIndentSize();
+ let indentSizeSpaceString = getIndentString((spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize());
+
+ // Write indent size string ( in eg 1: = "", 2: "" , 3: string with 8 spaces 4: string with 12 spaces
+ writer.rawWrite(indentSizeSpaceString);
+
+ // Emit the single spaces (in eg: 1: 3 spaces, 2: 2 spaces, 3: 1 space, 4: 3 spaces)
+ while (numberOfSingleSpacesToEmit) {
+ writer.rawWrite(" ");
+ numberOfSingleSpacesToEmit--;
+ }
+ }
+ else {
+ // No spaces to emit write empty string
+ writer.rawWrite("");
+ }
+ }
+
+ // Write the comment line text
+ writeTrimmedCurrentLine(pos, nextLineStart);
+
+ pos = nextLineStart;
+ }
+ }
+ else {
+ // Single line comment of style //....
+ writer.write(currentSourceFile.text.substring(comment.pos, comment.end));
+ }
+
+ function writeTrimmedCurrentLine(pos: number, nextLineStart: number) {
+ let end = Math.min(comment.end, nextLineStart - 1);
+ let currentLineText = currentSourceFile.text.substring(pos, end).replace(/^\s+|\s+$/g, '');
+ if (currentLineText) {
+ // trimmed forward and ending spaces text
+ writer.write(currentLineText);
+ if (end !== comment.end) {
+ writer.writeLine();
+ }
+ }
+ else {
+ // Empty string - make sure we write empty line
+ writer.writeLiteral(newLine);
+ }
+ }
+
+ function calculateIndent(pos: number, end: number) {
+ let currentLineIndent = 0;
+ for (; pos < end && isWhiteSpace(currentSourceFile.text.charCodeAt(pos)); pos++) {
+ if (currentSourceFile.text.charCodeAt(pos) === CharacterCodes.tab) {
+ // Tabs = TabSize = indent size and go to next tabStop
+ currentLineIndent += getIndentSize() - (currentLineIndent % getIndentSize());
+ }
+ else {
+ // Single space
+ currentLineIndent++;
+ }
+ }
+
+ return currentLineIndent;
+ }
+ }
+
}