diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 3642ee7f10a..648df9a702d 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -36,12 +36,12 @@ namespace ts { return declarationDiagnostics.getDiagnostics(targetSourceFile ? targetSourceFile.fileName : undefined); function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sources: SourceFile[], isBundledEmit: boolean) { - emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit); + emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit, /*emitOnlyDtsFiles*/ false); } } function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string, - sourceFiles: SourceFile[], isBundledEmit: boolean): DeclarationEmit { + sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean): DeclarationEmit { const newLine = host.getNewLine(); const compilerOptions = host.getCompilerOptions(); @@ -98,7 +98,7 @@ namespace ts { // global file reference is added only // - if it is not bundled emit (because otherwise it would be self reference) // - and it is not already added - if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference)) { + if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference, emitOnlyDtsFiles)) { addedGlobalFileReference = true; } emittedReferencedFiles.push(referencedFile); @@ -1713,7 +1713,7 @@ namespace ts { * @param referencedFile * @param addBundledFileReference Determines if global file reference corresponding to bundled file should be emitted or not */ - function writeReferencePath(referencedFile: SourceFile, addBundledFileReference: boolean): boolean { + function writeReferencePath(referencedFile: SourceFile, addBundledFileReference: boolean, emitOnlyDtsFiles: boolean): boolean { let declFileName: string; let addedBundledEmitReference = false; if (isDeclarationFile(referencedFile)) { @@ -1722,7 +1722,7 @@ namespace ts { } else { // Get the declaration file path - forEachExpectedEmitFile(host, getDeclFileName, referencedFile); + forEachExpectedEmitFile(host, getDeclFileName, referencedFile, emitOnlyDtsFiles); } if (declFileName) { @@ -1751,8 +1751,8 @@ namespace ts { } /* @internal */ - export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection) { - const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit); + export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) { + const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit, emitOnlyDtsFiles); const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath) || host.getCompilerOptions().noEmit; if (!emitSkipped) { const declarationOutput = emitDeclarationResult.referencesOutput diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index ca015edc73e..c3fac679048 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -8365,7 +8365,7 @@ const _super = (function (geti, seti) { } function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath }: EmitFileNames, - sourceFiles: SourceFile[], isBundledEmit: boolean) { + sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) { if (!emitOnlyDtsFiles) { // Make sure not to write js File and source map file if any of them cannot be written if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) { @@ -8377,7 +8377,7 @@ const _super = (function (geti, seti) { } if (declarationFilePath) { - emitSkipped = writeDeclarationFile(declarationFilePath, sourceFiles, isBundledEmit, host, resolver, emitterDiagnostics) || emitSkipped; + emitSkipped = writeDeclarationFile(declarationFilePath, sourceFiles, isBundledEmit, host, resolver, emitterDiagnostics, emitOnlyDtsFiles) || emitSkipped; } if (!emitSkipped && emittedFilesList) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9d60521d76b..b4e4418dac2 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2231,7 +2231,7 @@ namespace ts { } export function forEachExpectedEmitFile(host: EmitHost, - action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) => void, + action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void, targetSourceFile?: SourceFile, emitOnlyDtsFiles?: boolean) { const options = host.getCompilerOptions(); @@ -2272,7 +2272,7 @@ namespace ts { sourceMapFilePath: getSourceMapFilePath(jsFilePath, options), declarationFilePath }; - action(emitFileNames, [sourceFile], /*isBundledEmit*/false); + action(emitFileNames, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles); } function onBundledEmit(host: EmitHost) { @@ -2290,7 +2290,7 @@ namespace ts { sourceMapFilePath: getSourceMapFilePath(jsFilePath, options), declarationFilePath: options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined }; - action(emitFileNames, bundledSources, /*isBundledEmit*/true); + action(emitFileNames, bundledSources, /*isBundledEmit*/true, emitOnlyDtsFiles); } } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 8916c2d4189..736c087ec6a 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -1869,6 +1869,28 @@ namespace ts { session.executeCommand(changeFile1Consumer1ShapeRequest); sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [moduleFile1, file1Consumer1, file1Consumer1Consumer1]); }); + + it("should work fine for files with circular references", () => { + const file1: FileOrFolder = { + path: "/a/b/file1.ts", + content: ` + /// + export var t1 = 10;` + }; + const file2: FileOrFolder = { + path: "/a/b/file2.ts", + content: ` + /// + export var t2 = 10;` + }; + host = createServerHost([file1, file2, configFile]); + typingsInstaller = new TestTypingsInstaller("/a/data/", host); + session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false); + + openFilesForSession([file1, file2], session); + const file1AffectedListRequest = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); + sendAffectedFileRequestAndCheckResult(session, file1AffectedListRequest, [file1, file2]); + }); }); }); diff --git a/src/server/builder.ts b/src/server/builder.ts index 19e515c4459..9310976ddc0 100644 --- a/src/server/builder.ts +++ b/src/server/builder.ts @@ -243,7 +243,7 @@ namespace ts.server { const referencedFilePaths = this.project.getReferencedFiles(fileInfo.scriptInfo.path); if (referencedFilePaths.length > 0) { - return map(referencedFilePaths, f => this.getFileInfo(f)).sort(ModuleBuilderFileInfo.compareFileInfos); + return map(referencedFilePaths, f => this.getOrCreateFileInfo(f)).sort(ModuleBuilderFileInfo.compareFileInfos); } return []; }