diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4f5851e91d7..cde348c5c11 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5707,7 +5707,7 @@ module ts { } function isReferencedInExportAssignment(node: Declaration): boolean { - var exportAssignedSymbol = getExportAssignmentSymbol(getSymbolOfNode(node.parent)); + var exportAssignedSymbol = getExportAssignmentSymbol(getSymbolOfNode(getContainerOfModuleElementDeclaration(node))); if (exportAssignedSymbol) { var symbol = getSymbolOfNode(node); if (exportAssignedSymbol === symbol) { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 3667b43805b..01ca11ecb4b 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1857,28 +1857,17 @@ module ts { } } - function emitCommaList(nodes: Node[]) { + function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void) { + var currentWriterPos = writer.getTextPos(); for (var i = 0, n = nodes.length; i < n; i++) { - if (i) { + if (currentWriterPos !== writer.getTextPos()) { write(", "); } - emitNode(nodes[i]); + currentWriterPos = writer.getTextPos(); + eachNodeEmitFn(nodes[i]); } } - function emitCommaSeparatedSymbolToString(nodes: Node[]) { - if (nodes) { - for (var i = 0, n = nodes.length; i < n; i++) { - if (i) { - write(", "); - } - // TODO(shkamat): get the symbol name in the scope for this node - emitSourceTextOfNode(nodes[i]); - } - } - } - - function emitSourceTextOfNode(node: Node) { write(getSourceTextOfLocalNode(node)); } @@ -1902,7 +1891,7 @@ module ts { } // If this node is in external module, check if this is export assigned - if (node.parent.flags & NodeFlags.ExternalModule) { + if (getContainerOfModuleElementDeclaration(node).flags & NodeFlags.ExternalModule) { return resolver.isReferencedInExportAssignment(node); } @@ -1915,8 +1904,9 @@ module ts { return true; } - // emit the declaration if this is global source file - return node.parent.kind === SyntaxKind.SourceFile && !(node.parent.flags & NodeFlags.ExternalModule); + // emit the declaration if this is in global scope source file + var moduleDeclaration = getContainerOfModuleElementDeclaration(node); + return moduleDeclaration.kind === SyntaxKind.SourceFile && !(moduleDeclaration.flags & NodeFlags.ExternalModule); } function emitDeclarationFlags(node: Declaration) { @@ -2013,9 +2003,18 @@ module ts { } function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) { + function emitTypeParameter(node: TypeParameterDeclaration) { + emitSourceTextOfNode(node.name); + if (node.constraint) { + write(" extends "); + // TODO(shkamat): emit constraint using type + emitSourceTextOfNode(node.constraint); + } + } + if (typeParameters) { write("<"); - emitCommaSeparatedSymbolToString(typeParameters); + emitCommaList(typeParameters, emitTypeParameter); write(">"); } } @@ -2023,7 +2022,8 @@ module ts { function emitHeritageClause(typeReferences: TypeReferenceNode[], isImplementsList: boolean) { if (typeReferences) { write(isImplementsList ? " implments " : " extends "); - emitCommaSeparatedSymbolToString(typeReferences); + // TODO(shkamat): get the symbol name in the scope for this node + emitCommaList(typeReferences, emitSourceTextOfNode); } } @@ -2083,21 +2083,24 @@ module ts { } function emitVariableDeclaration(node: VariableDeclaration) { - emitSourceTextOfNode(node.name); - // If optional property emit ? - if (node.kind === SyntaxKind.Property && (node.flags & NodeFlags.QuestionMark)) { - write("?"); - } - if (!(node.flags & NodeFlags.Private)) { - // TODO(shkamat): emit type of the node in given scope + if (node.kind !== SyntaxKind.VariableDeclaration || canEmitModuleElementDeclaration(node)) { + emitSourceTextOfNode(node.name); + // If optional property emit ? + if (node.kind === SyntaxKind.Property && (node.flags & NodeFlags.QuestionMark)) { + write("?"); + } + if (!(node.flags & NodeFlags.Private)) { + // TODO(shkamat): emit type of the node in given scope + } } } function emitVariableStatement(node: VariableStatement) { - if (canEmitModuleElementDeclaration(node)) { + var hasDeclarationWithEmit = forEach(node.declarations, varDeclaration => canEmitModuleElementDeclaration(varDeclaration)); + if (hasDeclarationWithEmit) { emitDeclarationFlags(node); write("var "); - emitCommaList(node.declarations); + emitCommaList(node.declarations, emitVariableDeclaration); write(";"); writeLine(); } @@ -2154,7 +2157,7 @@ module ts { } // Parameters - emitCommaList(node.parameters); + emitCommaList(node.parameters, emitParameterDeclaration); if (node.kind === SyntaxKind.IndexSignature) { write("]"); @@ -2186,8 +2189,6 @@ module ts { function emitNode(node: Node) { switch (node.kind) { - case SyntaxKind.Parameter: - return emitParameterDeclaration(node); case SyntaxKind.Constructor: case SyntaxKind.FunctionDeclaration: case SyntaxKind.Method: @@ -2202,8 +2203,6 @@ module ts { return emitAccessorDeclaration(node); case SyntaxKind.VariableStatement: return emitVariableStatement(node); - case SyntaxKind.VariableDeclaration: - return emitVariableDeclaration(node); case SyntaxKind.Property: return emitPropertyDeclaration(node); case SyntaxKind.InterfaceDeclaration: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e39d8ab3694..004c22a3b96 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -273,6 +273,11 @@ module ts { return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0; } + export function getContainerOfModuleElementDeclaration(node: Declaration) { + // If the declaration is var declaration, then the parent is variable statement but we actually want the module + return node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent : node.parent; + } + enum ParsingContext { SourceElements, // Elements in source file ModuleElements, // Elements in module declaration diff --git a/tests/baselines/reference/declFileImportModuleWithExportAssignment.js b/tests/baselines/reference/declFileImportModuleWithExportAssignment.js index 0421feed885..89d76ff874e 100644 --- a/tests/baselines/reference/declFileImportModuleWithExportAssignment.js +++ b/tests/baselines/reference/declFileImportModuleWithExportAssignment.js @@ -45,6 +45,7 @@ declare module m2 { listen; } } +declare var m2; export = m2; //// [declFileImportModuleWithExportAssignment_1.d.ts] export declare var a; diff --git a/tests/baselines/reference/declareFileExportAssignment.js b/tests/baselines/reference/declareFileExportAssignment.js index 49a1771d4e6..85b0ada1438 100644 --- a/tests/baselines/reference/declareFileExportAssignment.js +++ b/tests/baselines/reference/declareFileExportAssignment.js @@ -33,4 +33,5 @@ declare module m2 { listen; } } +declare var m2; export = m2; diff --git a/tests/baselines/reference/declareFileExportAssignmentWithVarFromVariableStatement.js b/tests/baselines/reference/declareFileExportAssignmentWithVarFromVariableStatement.js new file mode 100644 index 00000000000..314371de59a --- /dev/null +++ b/tests/baselines/reference/declareFileExportAssignmentWithVarFromVariableStatement.js @@ -0,0 +1,37 @@ +//// [declareFileExportAssignmentWithVarFromVariableStatement.ts] +module m2 { + export interface connectModule { + (res, req, next): void; + } + export interface connectExport { + use: (mod: connectModule) => connectExport; + listen: (port: number) => void; + } + +} + +var x = 10, m2: { + (): m2.connectExport; + test1: m2.connectModule; + test2(): m2.connectModule; +}; + +export = m2; + +//// [declareFileExportAssignmentWithVarFromVariableStatement.js] +var x = 10, m2; +module.exports = m2; + + +//// [declareFileExportAssignmentWithVarFromVariableStatement.d.ts] +declare module m2 { + interface connectModule { + (res, req, next); + } + interface connectExport { + use; + listen; + } +} +declare var m2; +export = m2; diff --git a/tests/cases/compiler/declareFileExportAssignmentWithVarFromVariableStatement.ts b/tests/cases/compiler/declareFileExportAssignmentWithVarFromVariableStatement.ts new file mode 100644 index 00000000000..4333b9c1050 --- /dev/null +++ b/tests/cases/compiler/declareFileExportAssignmentWithVarFromVariableStatement.ts @@ -0,0 +1,20 @@ +//@module: commonjs +// @declaration: true +module m2 { + export interface connectModule { + (res, req, next): void; + } + export interface connectExport { + use: (mod: connectModule) => connectExport; + listen: (port: number) => void; + } + +} + +var x = 10, m2: { + (): m2.connectExport; + test1: m2.connectModule; + test2(): m2.connectModule; +}; + +export = m2; \ No newline at end of file