From f8351c8865cede70161e75ee8590f60c0a345bea Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 10 Feb 2015 19:02:13 -0800 Subject: [PATCH] Set the declarations of export assignment visible on demand through dts emit Emit those new declarations asynchronously since they are otherwise not visible --- src/compiler/checker.ts | 94 ++-- src/compiler/emitter.ts | 432 ++++++++++-------- src/compiler/types.ts | 1 + .../baselines/reference/APISample_compile.js | 1 + .../reference/APISample_compile.types | 6 + tests/baselines/reference/APISample_linter.js | 1 + .../reference/APISample_linter.types | 6 + .../reference/APISample_transform.js | 1 + .../reference/APISample_transform.types | 6 + .../baselines/reference/APISample_watcher.js | 1 + .../reference/APISample_watcher.types | 6 + ...ationEmitImportInExportAssignmentModule.js | 39 ++ ...onEmitImportInExportAssignmentModule.types | 23 + ...ationEmitImportInExportAssignmentModule.ts | 12 + 14 files changed, 381 insertions(+), 248 deletions(-) create mode 100644 tests/baselines/reference/declarationEmitImportInExportAssignmentModule.js create mode 100644 tests/baselines/reference/declarationEmitImportInExportAssignmentModule.types create mode 100644 tests/cases/compiler/declarationEmitImportInExportAssignmentModule.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2e4553a4bc..249113e86f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1588,65 +1588,6 @@ module ts { } function isDeclarationVisible(node: Declaration): boolean { - function getContainingExternalModule(node: Node) { - for (; node; node = node.parent) { - if (node.kind === SyntaxKind.ModuleDeclaration) { - if ((node).name.kind === SyntaxKind.StringLiteral) { - return node; - } - } - else if (node.kind === SyntaxKind.SourceFile) { - return isExternalModule(node) ? node : undefined; - } - } - Debug.fail("getContainingModule cant reach here"); - } - - function isUsedInExportAssignment(node: Node) { - // Get source File and see if it is external module and has export assigned symbol - var externalModule = getContainingExternalModule(node); - if (externalModule) { - // This is export assigned symbol node - var externalModuleSymbol = getSymbolOfNode(externalModule); - var exportAssignmentSymbol = getExportAssignmentSymbol(externalModuleSymbol); - var resolvedExportSymbol: Symbol; - var symbolOfNode = getSymbolOfNode(node); - if (isSymbolUsedInExportAssignment(symbolOfNode)) { - return true; - } - - // if symbolOfNode is import declaration, resolve the symbol declaration and check - if (symbolOfNode.flags & SymbolFlags.Import) { - return isSymbolUsedInExportAssignment(resolveImport(symbolOfNode)); - } - } - - // Check if the symbol is used in export assignment - function isSymbolUsedInExportAssignment(symbol: Symbol) { - if (exportAssignmentSymbol === symbol) { - return true; - } - - if (exportAssignmentSymbol && !!(exportAssignmentSymbol.flags & SymbolFlags.Import)) { - // if export assigned symbol is import declaration, resolve the import - resolvedExportSymbol = resolvedExportSymbol || resolveImport(exportAssignmentSymbol); - if (resolvedExportSymbol === symbol) { - return true; - } - - // Container of resolvedExportSymbol is visible - return forEach(resolvedExportSymbol.declarations, (current: Node) => { - while (current) { - if (current === node) { - return true; - } - current = current.parent; - } - }); - } - } - } - function determineIfDeclarationIsVisible() { switch (node.kind) { case SyntaxKind.VariableDeclaration: @@ -1662,7 +1603,7 @@ module ts { // If the node is not exported or it is not ambient module element (except import declaration) if (!(getCombinedNodeFlags(node) & NodeFlags.Export) && !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) { - return isGlobalSourceFile(parent) || isUsedInExportAssignment(node); + return isGlobalSourceFile(parent); } // Exported members/ambient module elements (exception import declaration) are visible if parent is visible return isDeclarationVisible(parent); @@ -1696,11 +1637,11 @@ module ts { return isDeclarationVisible(node.parent); // Default binding, import specifier and namespace import is visible - // only if the import declaration is exported or it is used in export assignment + // only on demand so by default it is not visible case SyntaxKind.ImportClause: case SyntaxKind.NamespaceImport: case SyntaxKind.ImportSpecifier: - return (node.name && isUsedInExportAssignment(node)); + return false; // Type parameters are always visible case SyntaxKind.TypeParameter: @@ -1722,6 +1663,34 @@ module ts { } } + function setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]{ + if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) { + var exportSymbol = resolveName(node.parent, node.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, Diagnostics.Cannot_find_name_0, node); + var result: Node[] = []; + buildVisibleNodeList(exportSymbol.declarations); + return result; + } + + function buildVisibleNodeList(declarations: Declaration[]) { + forEach(declarations, declaration => { + getNodeLinks(declaration).isVisible = true; + var resultNode = getAnyImportSyntax(declaration) || declaration; + if (!contains(result, resultNode)) { + result.push(resultNode); + } + + if (isInternalModuleImportEqualsDeclaration(declaration)) { + // Add the referenced top container visible + var internalModuleReference = (declaration).moduleReference; + var firstIdentifier = getFirstIdentifier(internalModuleReference); + var importSymbol = resolveName(declaration, firstIdentifier.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, + Diagnostics.Cannot_find_name_0, firstIdentifier); + buildVisibleNodeList(importSymbol.declarations); + } + }); + } + } + function getRootDeclaration(node: Node): Node { while (node.kind === SyntaxKind.BindingElement) { node = node.parent.parent; @@ -10349,6 +10318,7 @@ module ts { isEntityNameVisible, getConstantValue, isUnknownIdentifier, + setDeclarationsOfIdentifierAsVisible }; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 63e6e992b3..fff78fbb77 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -34,17 +34,18 @@ module ts { getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic; } - interface AliasDeclarationEmitInfo { - declaration: AnyImportSyntax; + 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; - aliasDeclarationEmitInfo: AliasDeclarationEmitInfo[]; + moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]; synchronousDeclarationOutput: string; referencePathsOutput: string; } @@ -365,7 +366,8 @@ module ts { var emitJsDocComments = compilerOptions.removeComments ? function (declaration: Node) { } : writeJsDocComments; var emit = compilerOptions.stripInternal ? stripInternal : emitNode; - var aliasDeclarationEmitInfo: AliasDeclarationEmitInfo[] = []; + var moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = []; + var 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 @@ -395,14 +397,14 @@ module ts { emitSourceFile(root); // create asynchronous output for the importDeclarations - if (aliasDeclarationEmitInfo.length) { + if (moduleElementDeclarationEmitInfo.length) { var oldWriter = writer; - forEach(aliasDeclarationEmitInfo, aliasEmitInfo => { + forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => { if (aliasEmitInfo.isVisible) { - Debug.assert(aliasEmitInfo.declaration.kind === SyntaxKind.ImportDeclaration); + Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration); createAndSetNewTextWriterWithSymbolWriter(); Debug.assert(aliasEmitInfo.indent === 0); - writeImportDeclaration(aliasEmitInfo.declaration); + writeImportDeclaration(aliasEmitInfo.node); aliasEmitInfo.asynchronousOutput = writer.getText(); } }); @@ -436,7 +438,7 @@ module ts { return { reportedDeclarationError, - aliasDeclarationEmitInfo, + moduleElementDeclarationEmitInfo, synchronousDeclarationOutput: writer.getText(), referencePathsOutput, } @@ -481,10 +483,23 @@ module ts { decreaseIndent = newWriter.decreaseIndent; } - function writeAsychronousImportEqualsDeclarations(anyImportSyntax: AnyImportSyntax[]) { + function writeAsynchronousModuleElements(nodes: Node[]) { var oldWriter = writer; - forEach(anyImportSyntax, aliasToWrite => { - var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined); + forEach(nodes, declaration => { + var 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; + } + + var 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. @@ -492,19 +507,28 @@ module ts { // 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 (aliasEmitInfo) { - if (aliasToWrite.kind === SyntaxKind.ImportEqualsDeclaration) { - createAndSetNewTextWriterWithSymbolWriter(); - for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) { - increaseIndent(); - } - writeImportEqualsDeclaration(aliasToWrite); - aliasEmitInfo.asynchronousOutput = writer.getText(); - } - else { + 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 - aliasEmitInfo.isVisible = true; + moduleElementEmitInfo.isVisible = true; + } + else { + createAndSetNewTextWriterWithSymbolWriter(); + for (var 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(); } } }); @@ -515,7 +539,7 @@ module ts { if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) { // write the aliases if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) { - writeAsychronousImportEqualsDeclarations(symbolAccesibilityResult.aliasesToMakeVisible); + writeAsynchronousModuleElements(symbolAccesibilityResult.aliasesToMakeVisible); } } else { @@ -719,6 +743,77 @@ module ts { writeTextOfNode(currentSourceFile, node.exportName); write(";"); writeLine(); + + // Make all the declarations visible for the export name + var nodes = resolver.setDeclarationsOfIdentifierAsVisible(node.exportName); + + // write each of these declarations asynchronously + writeAsynchronousModuleElements(nodes); + } + + 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))) { + + 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 { + var isVisible: boolean; + if (node.kind === SyntaxKind.ImportDeclaration) { + var 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) { @@ -748,19 +843,6 @@ module ts { } } - function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { - if (resolver.isDeclarationVisible(node)) { - writeImportEqualsDeclaration(node); - } - else { - aliasDeclarationEmitInfo.push({ - declaration: node, - outputPos: writer.getTextPos(), - indent: writer.getIndent(), - }); - } - } - 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 @@ -791,21 +873,6 @@ module ts { } } - function emitImportDeclaration(node: ImportDeclaration) { - if (node.importClause) { - aliasDeclarationEmitInfo.push({ - declaration: node, - outputPos: writer.getTextPos(), - indent: writer.getIndent(), - isVisible: (node.importClause.name && resolver.isDeclarationVisible(node.importClause)) || - isVisibleNamedBinding(node.importClause.namedBindings) - }); - } - else { - writeImportDeclaration(node); - } - } - function isVisibleNamedBinding(namedBindings: NamespaceImport | NamedImports): boolean { if (namedBindings) { if (namedBindings.kind === SyntaxKind.NamespaceImport) { @@ -858,41 +925,38 @@ module ts { writeTextOfNode(currentSourceFile, node.name); } - function emitModuleDeclaration(node: ModuleDeclaration) { - if (resolver.isDeclarationVisible(node)) { - emitJsDocComments(node); - emitModuleElementDeclarationFlags(node); - write("module "); + 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); - while (node.body.kind !== SyntaxKind.ModuleBlock) { - node = node.body; - write("."); - writeTextOfNode(currentSourceFile, node.name); - } - var prevEnclosingDeclaration = enclosingDeclaration; - enclosingDeclaration = node; - write(" {"); - writeLine(); - increaseIndent(); - emitLines((node.body).statements); - decreaseIndent(); - write("}"); - writeLine(); - enclosingDeclaration = prevEnclosingDeclaration; } + var prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + write(" {"); + writeLine(); + increaseIndent(); + emitLines((node.body).statements); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; } - function emitTypeAliasDeclaration(node: TypeAliasDeclaration) { - if (resolver.isDeclarationVisible(node)) { - emitJsDocComments(node); - emitModuleElementDeclarationFlags(node); - write("type "); - writeTextOfNode(currentSourceFile, node.name); - write(" = "); - emitTypeWithNewGetSymbolAccessibilityDiagnostic(node.type, getTypeAliasDeclarationVisibilityError); - write(";"); - writeLine(); - } + 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, @@ -902,23 +966,21 @@ module ts { } } - function emitEnumDeclaration(node: EnumDeclaration) { - if (resolver.isDeclarationVisible(node)) { - 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 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) { @@ -1050,7 +1112,7 @@ module ts { } } - function emitClassDeclaration(node: ClassDeclaration) { + function writeClassDeclaration(node: ClassDeclaration) { function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) { if (constructorDeclaration) { forEach(constructorDeclaration.parameters, param => { @@ -1061,50 +1123,46 @@ module ts { } } - if (resolver.isDeclarationVisible(node)) { - emitJsDocComments(node); - emitModuleElementDeclarationFlags(node); - write("class "); - writeTextOfNode(currentSourceFile, node.name); - var prevEnclosingDeclaration = enclosingDeclaration; - enclosingDeclaration = node; - emitTypeParameters(node.typeParameters); - var 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; + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("class "); + writeTextOfNode(currentSourceFile, node.name); + var prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = node; + emitTypeParameters(node.typeParameters); + var 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 emitInterfaceDeclaration(node: InterfaceDeclaration) { - if (resolver.isDeclarationVisible(node)) { - emitJsDocComments(node); - emitModuleElementDeclarationFlags(node); - write("interface "); - writeTextOfNode(currentSourceFile, node.name); - var prevEnclosingDeclaration = enclosingDeclaration; - enclosingDeclaration = node; - emitTypeParameters(node.typeParameters); - emitHeritageClause(getInterfaceBaseTypeNodes(node), /*isImplementsList*/ false); - write(" {"); - writeLine(); - increaseIndent(); - emitLines(node.members); - decreaseIndent(); - write("}"); - writeLine(); - enclosingDeclaration = prevEnclosingDeclaration; - } + function writeInterfaceDeclaration(node: InterfaceDeclaration) { + emitJsDocComments(node); + emitModuleElementDeclarationFlags(node); + write("interface "); + writeTextOfNode(currentSourceFile, node.name); + var 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) { @@ -1187,24 +1245,25 @@ module ts { } } - function emitVariableStatement(node: VariableStatement) { - var hasDeclarationWithEmit = forEach(node.declarationList.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration)); - if (hasDeclarationWithEmit) { - 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 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) { @@ -1290,15 +1349,14 @@ module ts { } } - function emitFunctionDeclaration(node: FunctionLikeDeclaration) { + 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 ((node.kind !== SyntaxKind.FunctionDeclaration || resolver.isDeclarationVisible(node)) && - !resolver.isImplementationOfOverload(node)) { + if (!resolver.isImplementationOfOverload(node)) { emitJsDocComments(node); if (node.kind === SyntaxKind.FunctionDeclaration) { emitModuleElementDeclarationFlags(node); @@ -1538,11 +1596,23 @@ module ts { function emitNode(node: Node) { switch (node.kind) { - case SyntaxKind.Constructor: 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.Constructor: case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - return emitFunctionDeclaration(node); + return writeFunctionDeclaration(node); case SyntaxKind.ConstructSignature: case SyntaxKind.CallSignature: case SyntaxKind.IndexSignature: @@ -1550,29 +1620,13 @@ module ts { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: return emitAccessorDeclaration(node); - case SyntaxKind.VariableStatement: - return emitVariableStatement(node); case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: return emitPropertyDeclaration(node); - case SyntaxKind.InterfaceDeclaration: - return emitInterfaceDeclaration(node); - case SyntaxKind.ClassDeclaration: - return emitClassDeclaration(node); - case SyntaxKind.TypeAliasDeclaration: - return emitTypeAliasDeclaration(node); case SyntaxKind.EnumMember: return emitEnumMemberDeclaration(node); - case SyntaxKind.EnumDeclaration: - return emitEnumDeclaration(node); - case SyntaxKind.ModuleDeclaration: - return emitModuleDeclaration(node); - case SyntaxKind.ImportEqualsDeclaration: - return emitImportEqualsDeclaration(node); case SyntaxKind.ExportAssignment: return emitExportAssignment(node); - case SyntaxKind.ImportDeclaration: - return emitImportDeclaration(node); case SyntaxKind.SourceFile: return emitSourceFile(node); } @@ -4626,18 +4680,24 @@ module ts { // 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) { - var declarationOutput = emitDeclarationResult.referencePathsOutput; - // apply additions + var declarationOutput = emitDeclarationResult.referencePathsOutput + + getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo); + writeFile(host, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, compilerOptions.emitBOM); + } + + function getDeclarationOutput(synchronousDeclarationOutput: string, moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]) { var appliedSyncOutputPos = 0; - forEach(emitDeclarationResult.aliasDeclarationEmitInfo, aliasEmitInfo => { + var declarationOutput = ""; + // apply asynchronous additions to the synchronous output + forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => { if (aliasEmitInfo.asynchronousOutput) { - declarationOutput += emitDeclarationResult.synchronousDeclarationOutput.substring(appliedSyncOutputPos, aliasEmitInfo.outputPos); - declarationOutput += aliasEmitInfo.asynchronousOutput; + declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos, aliasEmitInfo.outputPos); + declarationOutput += getDeclarationOutput(aliasEmitInfo.asynchronousOutput, aliasEmitInfo.subModuleElementDeclarationEmitInfo); appliedSyncOutputPos = aliasEmitInfo.outputPos; } }); - declarationOutput += emitDeclarationResult.synchronousDeclarationOutput.substring(appliedSyncOutputPos); - writeFile(host, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, compilerOptions.emitBOM); + declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos); + return declarationOutput; } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1f7a8211df..1999c52e91 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1172,6 +1172,7 @@ module ts { isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration): boolean; + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index b9bc5d96d4..384e458d4b 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -910,6 +910,7 @@ declare module "typescript" { isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration): boolean; + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 5146cde791..b659edba90 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -2924,6 +2924,12 @@ declare module "typescript" { >node : Declaration >Declaration : Declaration + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; +>setDeclarationsOfIdentifierAsVisible : (node: Identifier) => Node[] +>node : Identifier +>Identifier : Identifier +>Node : Node + isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; >isImplementationOfOverload : (node: FunctionLikeDeclaration) => boolean >node : FunctionLikeDeclaration diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index 012d635e4c..12dffb8665 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -941,6 +941,7 @@ declare module "typescript" { isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration): boolean; + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 4292108fc7..810bbe2aa1 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -3068,6 +3068,12 @@ declare module "typescript" { >node : Declaration >Declaration : Declaration + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; +>setDeclarationsOfIdentifierAsVisible : (node: Identifier) => Node[] +>node : Identifier +>Identifier : Identifier +>Node : Node + isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; >isImplementationOfOverload : (node: FunctionLikeDeclaration) => boolean >node : FunctionLikeDeclaration diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 8a3951bb19..2e8e40442d 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -942,6 +942,7 @@ declare module "typescript" { isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration): boolean; + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index ab2e05ac05..a4a3e30480 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -3020,6 +3020,12 @@ declare module "typescript" { >node : Declaration >Declaration : Declaration + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; +>setDeclarationsOfIdentifierAsVisible : (node: Identifier) => Node[] +>node : Identifier +>Identifier : Identifier +>Node : Node + isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; >isImplementationOfOverload : (node: FunctionLikeDeclaration) => boolean >node : FunctionLikeDeclaration diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index 36eaccac6a..18c4a3f70f 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -979,6 +979,7 @@ declare module "typescript" { isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; isDeclarationVisible(node: Declaration): boolean; + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 99d84a928f..f338788a8e 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -3193,6 +3193,12 @@ declare module "typescript" { >node : Declaration >Declaration : Declaration + setDeclarationsOfIdentifierAsVisible(node: Identifier): Node[]; +>setDeclarationsOfIdentifierAsVisible : (node: Identifier) => Node[] +>node : Identifier +>Identifier : Identifier +>Node : Node + isImplementationOfOverload(node: FunctionLikeDeclaration): boolean; >isImplementationOfOverload : (node: FunctionLikeDeclaration) => boolean >node : FunctionLikeDeclaration diff --git a/tests/baselines/reference/declarationEmitImportInExportAssignmentModule.js b/tests/baselines/reference/declarationEmitImportInExportAssignmentModule.js new file mode 100644 index 0000000000..b41ca177b0 --- /dev/null +++ b/tests/baselines/reference/declarationEmitImportInExportAssignmentModule.js @@ -0,0 +1,39 @@ +//// [declarationEmitImportInExportAssignmentModule.ts] + +module m { + export module c { + export class c { + } + } + import x = c; + export var a: typeof x; +} +export = m; + +//// [declarationEmitImportInExportAssignmentModule.js] +var m; +(function (m) { + var c; + (function (_c) { + var c = (function () { + function c() { + } + return c; + })(); + _c.c = c; + })(c = m.c || (m.c = {})); + m.a; +})(m || (m = {})); +module.exports = m; + + +//// [declarationEmitImportInExportAssignmentModule.d.ts] +declare module m { + module c { + class c { + } + } + import x = c; + var a: typeof x; +} +export = m; diff --git a/tests/baselines/reference/declarationEmitImportInExportAssignmentModule.types b/tests/baselines/reference/declarationEmitImportInExportAssignmentModule.types new file mode 100644 index 0000000000..23176a0abe --- /dev/null +++ b/tests/baselines/reference/declarationEmitImportInExportAssignmentModule.types @@ -0,0 +1,23 @@ +=== tests/cases/compiler/declarationEmitImportInExportAssignmentModule.ts === + +module m { +>m : typeof m + + export module c { +>c : typeof x + + export class c { +>c : c + } + } + import x = c; +>x : typeof x +>c : typeof x + + export var a: typeof x; +>a : typeof x +>x : typeof x +} +export = m; +>m : typeof m + diff --git a/tests/cases/compiler/declarationEmitImportInExportAssignmentModule.ts b/tests/cases/compiler/declarationEmitImportInExportAssignmentModule.ts new file mode 100644 index 0000000000..b246ba32ba --- /dev/null +++ b/tests/cases/compiler/declarationEmitImportInExportAssignmentModule.ts @@ -0,0 +1,12 @@ +// @declaration: true +// @module: commonjs + +module m { + export module c { + export class c { + } + } + import x = c; + export var a: typeof x; +} +export = m; \ No newline at end of file