From 494bd92f1b68950c246040bfcff4f0a18c4f05b0 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 21 Feb 2019 19:05:30 -0800 Subject: [PATCH] Report error if overwriting buildInfo of another project reference --- src/compiler/diagnosticMessages.json | 4 ++++ src/compiler/emitter.ts | 4 ++++ src/compiler/program.ts | 6 +++++ src/testRunner/unittests/tsbuild/outFile.ts | 26 +++++++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index bd971b1542d..f42baa79a82 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4016,6 +4016,10 @@ "category": "Message", "code": 6376 }, + "Cannot write file '{0}' because it will overwrite '.tsbuildinfo' of referenced project '{1}'": { + "category": "Error", + "code": 6377 + }, "The expected type comes from property '{0}' which is declared here on type '{1}'": { "category": "Message", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 9a2c0e111df..f392daf3c41 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -186,6 +186,10 @@ namespace ts { if (!buildInfoPath || targetSourceFile || emitSkipped) return; const program = host.getProgramBuildInfo(); if (!bundle && !program) return; + if (host.isEmitBlocked(buildInfoPath) || compilerOptions.noEmit) { + emitSkipped = true; + return; + } writeFile(host, emitterDiagnostics, buildInfoPath, getBuildInfoText({ bundle, program }), /*writeByteOrderMark*/ false); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 24aa9974ebf..c30317b1142 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -2941,6 +2941,7 @@ namespace ts { } function verifyProjectReferences() { + const buildInfoPath = !options.noEmit && !options.suppressOutputPathCheck ? getOutputPathForBuildInfo(options, projectReferences) : undefined; forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, index, parent) => { const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index]; const parentFile = parent && parent.sourceFile as JsonSourceFile; @@ -2967,6 +2968,11 @@ namespace ts { createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_prepend_project_0_because_it_does_not_have_outFile_set, ref.path); } } + const refBuildInfoPath = getOutputPathForBuildInfo(options, resolvedRef.commandLine.projectReferences); + if (refBuildInfoPath && refBuildInfoPath === buildInfoPath) { + createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_of_referenced_project_1, buildInfoPath, ref.path); + hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true); + } }); } diff --git a/src/testRunner/unittests/tsbuild/outFile.ts b/src/testRunner/unittests/tsbuild/outFile.ts index 787928d383d..d4970291785 100644 --- a/src/testRunner/unittests/tsbuild/outFile.ts +++ b/src/testRunner/unittests/tsbuild/outFile.ts @@ -478,6 +478,32 @@ namespace ts { ); }); + it("verify that if multiple projects write tsbuildinfo to same location, reports error", () => { + const fs = outFileFs.shadow(); + const host = new fakes.SolutionBuilderHost(fs); + replaceText(fs, sources[project.first][source.config], "./bin/first-output.js", "../bin/first-output.js"); + replaceText(fs, sources[project.second][source.config], "../2/second-output.js", "../bin/second-output.js"); + replaceText(fs, sources[project.third][source.config], "./thirdjs/output/third-output.js", "../bin/third-output.js"); + const builder = createSolutionBuilder(host); + builder.buildAllProjects(); + host.assertDiagnosticMessages( + getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]), + [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, relSources[project.first][source.config], "src/bin/first-output.js"], + [Diagnostics.Building_project_0, sources[project.first][source.config]], + [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, relSources[project.second][source.config], "src/bin/second-output.js"], + [Diagnostics.Building_project_0, sources[project.second][source.config]], + [Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, relSources[project.third][source.config], "src/bin/third-output.js"], + [Diagnostics.Building_project_0, sources[project.third][source.config]], + [Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_of_referenced_project_1, "/src/bin/.tsbuildinfo", "/src/first"], + [Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_of_referenced_project_1, "/src/bin/.tsbuildinfo", "/src/second"] + ); + // Verify they exist + for (const output of ["/src/bin/first-output.js", "/src/bin/second-output.js"]) { + assert(fs.existsSync(output), `Expect file ${output} to exist`); + } + assert.isFalse(fs.existsSync("/src/bin/third-output.js"), `Expect file "/src/bin/third-output.js" to not exist`); + }); + // Prologues function enableStrict(fs: vfs.FileSystem, path: string) { replaceText(fs, path, `"strict": false`, `"strict": true`);