diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 00085f16086..d66c4110336 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -104,6 +104,7 @@ namespace ts { else { // Emit references corresponding to this file let emittedReferencedFiles: SourceFile[] = []; + let prevModuleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = []; forEach(host.getSourceFiles(), sourceFile => { if (!isExternalModuleOrDeclarationFile(sourceFile)) { // Check what references need to be added @@ -123,7 +124,42 @@ namespace ts { emitSourceFile(sourceFile); } + else if (isExternalModule(sourceFile)) { + currentSourceFile = sourceFile; + write(`declare module "${sourceFile.moduleName}"`); + + let prevEnclosingDeclaration = enclosingDeclaration; + enclosingDeclaration = sourceFile; + write(" {"); + writeLine(); + increaseIndent(); + emitLines(sourceFile.statements); + decreaseIndent(); + write("}"); + writeLine(); + enclosingDeclaration = prevEnclosingDeclaration; + + // create asynchronous output for the importDeclarations + if (moduleElementDeclarationEmitInfo.length) { + let oldWriter = writer; + forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => { + if (aliasEmitInfo.isVisible && !aliasEmitInfo.asynchronousOutput) { + Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration); + createAndSetNewTextWriterWithSymbolWriter(); + Debug.assert(aliasEmitInfo.indent === 1); + increaseIndent(); + writeImportDeclaration(aliasEmitInfo.node); + aliasEmitInfo.asynchronousOutput = writer.getText(); + decreaseIndent(); + } + }); + setWriter(oldWriter); + } + prevModuleElementDeclarationEmitInfo = prevModuleElementDeclarationEmitInfo.concat(moduleElementDeclarationEmitInfo); + moduleElementDeclarationEmitInfo = []; + } }); + moduleElementDeclarationEmitInfo = moduleElementDeclarationEmitInfo.concat(prevModuleElementDeclarationEmitInfo); } return { @@ -601,7 +637,7 @@ namespace ts { if (node.flags & NodeFlags.Default) { write("default "); } - else if (node.kind !== SyntaxKind.InterfaceDeclaration) { + else if (node.kind !== SyntaxKind.InterfaceDeclaration && root) { write("declare "); } } @@ -696,7 +732,13 @@ namespace ts { } write(" from "); } - writeTextOfNode(currentSourceFile, node.moduleSpecifier); + let match: RegExpMatchArray; + if ((!root) && node.moduleSpecifier.kind === SyntaxKind.StringLiteral && (match = getTextOfNode(node.moduleSpecifier).match(/('|")(\.\/|\.\.\/)/))) { + write(makeModulePathSemiabsolute(host, currentSourceFile, getTextOfNode(node.moduleSpecifier))); + } + else { + writeTextOfNode(currentSourceFile, node.moduleSpecifier); + } write(";"); writer.writeLine(); } @@ -732,7 +774,13 @@ namespace ts { } if (node.moduleSpecifier) { write(" from "); - writeTextOfNode(currentSourceFile, node.moduleSpecifier); + let match: RegExpMatchArray; + if ((!root) && node.moduleSpecifier.kind === SyntaxKind.StringLiteral && (match = getTextOfNode(node.moduleSpecifier).match(/('|")(\.\/|\.\.\/)/))) { + write(makeModulePathSemiabsolute(host, currentSourceFile, getTextOfNode(node.moduleSpecifier))); + } + else { + writeTextOfNode(currentSourceFile, node.moduleSpecifier); + } } write(";"); writer.writeLine(); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 4ce0a39eb07..1b0492643bf 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -499,18 +499,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitConcatenatedModule(sourceFile: SourceFile): void { currentSourceFile = sourceFile; exportFunctionForFile = undefined; - let canonicalName = resolveToSemiabsolutePath(sourceFile.fileName); + let canonicalName = resolveToSemiabsolutePath(host, sourceFile.fileName); sourceFile.moduleName = sourceFile.moduleName || canonicalName; emit(sourceFile); } - function resolveToSemiabsolutePath(path: string): string { - let dir = host.getCurrentDirectory(); - return removeFileExtension( - getRelativePathToDirectoryOrUrl(dir, path, dir, f => host.getCanonicalFileName(f), /*isAbsolutePathAnUrl*/false) - ); - } - function isUniqueName(name: string): boolean { return !resolver.hasGlobalName(name) && !hasProperty(currentSourceFile.identifiers, name) && @@ -6681,7 +6674,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } if (resolvePath) { - text = makeModulePathSemiabsolute(text); + text = makeModulePathSemiabsolute(host, currentSourceFile, text); } write(text); } @@ -6702,17 +6695,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi importAliasNames: string[]; } - function makeModulePathSemiabsolute(externalModuleName: string): string { - let quotemark = externalModuleName.charAt(0); - let unquotedModuleName = externalModuleName.substring(1, externalModuleName.length - 1); - let resolvedFileName = host.resolveModuleName(unquotedModuleName, currentSourceFile.fileName); - if (resolvedFileName) { - let semiabsoluteName = resolveToSemiabsolutePath(resolvedFileName); - externalModuleName = quoteString(semiabsoluteName, quotemark); - } - return externalModuleName; - } - function getAMDDependencyNames(node: SourceFile, includeNonAmdDependencies: boolean, resolvePath?: boolean): AMDDependencyNames { // names of modules with corresponding parameter in the factory function let aliasedModuleNames: string[] = []; @@ -6738,7 +6720,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let externalModuleName = getExternalModuleNameText(importNode); if (resolvePath) { - externalModuleName = makeModulePathSemiabsolute(externalModuleName); + externalModuleName = makeModulePathSemiabsolute(host, currentSourceFile, externalModuleName); } // Find the name of the module alias, if there is one diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9ae65af046e..db30e4ca68e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1775,6 +1775,24 @@ namespace ts { }; } + export function makeModulePathSemiabsolute(host: EmitHost, currentSourceFile: SourceFile, externalModuleName: string): string { + let quotemark = externalModuleName.charAt(0); + let unquotedModuleName = externalModuleName.substring(1, externalModuleName.length - 1); + let resolvedFileName = host.resolveModuleName(unquotedModuleName, currentSourceFile.fileName); + if (resolvedFileName) { + let semiabsoluteName = resolveToSemiabsolutePath(host, resolvedFileName); + externalModuleName = quoteString(semiabsoluteName, quotemark); + } + return externalModuleName; + } + + export function resolveToSemiabsolutePath(host: EmitHost, path: string): string { + let dir = host.getCurrentDirectory(); + return removeFileExtension( + getRelativePathToDirectoryOrUrl(dir, path, dir, f => host.getCanonicalFileName(f), /*isAbsolutePathAnUrl*/false) + ); + } + export function getOwnEmitOutputFilePath(sourceFile: SourceFile, host: EmitHost, extension: string) { let compilerOptions = host.getCompilerOptions(); let emitOutputFilePathWithoutExtension: string;