diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 7973a4cc8dd64..62dd670fbc5f6 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -64,7 +64,9 @@ namespace ts { const state = BuilderState.create(newProgram, getCanonicalFileName, oldState) as BuilderProgramState; state.program = newProgram; const compilerOptions = newProgram.getCompilerOptions(); - if (!compilerOptions.outFile && !compilerOptions.out) { + // With --out or --outFile, any change affects all semantic diagnostics so no need to cache them + // With --isolatedModules, emitting changed file doesnt emit dependent files so we cant know of dependent files to retrieve errors so dont cache the errors + if (!compilerOptions.outFile && !compilerOptions.out && !compilerOptions.isolatedModules) { state.semanticDiagnosticsPerFile = createMap>(); } state.changedFilesSet = createMap(); @@ -338,15 +340,19 @@ namespace ts { */ function getSemanticDiagnosticsOfFile(state: BuilderProgramState, sourceFile: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray { const path = sourceFile.path; - const cachedDiagnostics = state.semanticDiagnosticsPerFile!.get(path); - // Report the semantic diagnostics from the cache if we already have those diagnostics present - if (cachedDiagnostics) { - return cachedDiagnostics; + if (state.semanticDiagnosticsPerFile) { + const cachedDiagnostics = state.semanticDiagnosticsPerFile.get(path); + // Report the semantic diagnostics from the cache if we already have those diagnostics present + if (cachedDiagnostics) { + return cachedDiagnostics; + } } // Diagnostics werent cached, get them from program, and cache the result const diagnostics = state.program.getSemanticDiagnostics(sourceFile, cancellationToken); - state.semanticDiagnosticsPerFile!.set(path, diagnostics); + if (state.semanticDiagnosticsPerFile) { + state.semanticDiagnosticsPerFile.set(path, diagnostics); + } return diagnostics; } diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index 45ff6fba7c5b8..b322c08bfe7f8 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -1281,7 +1281,59 @@ interface Document { checkProgramActualFiles(watch(), [aFile.path, bFile.path, libFile.path]); } }); - }); + it("reports errors correctly with isolatedModules", () => { + const currentDirectory = "/user/username/projects/myproject"; + const aFile: File = { + path: `${currentDirectory}/a.ts`, + content: `export const a: string = "";` + }; + const bFile: File = { + path: `${currentDirectory}/b.ts`, + content: `import { a } from "./a"; +const b: string = a;` + }; + const configFile: File = { + path: `${currentDirectory}/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + isolatedModules: true + } + }) + }; + + const files = [aFile, bFile, libFile, configFile]; + const host = createWatchedSystem(files, { currentDirectory }); + const watch = createWatchOfConfigFile("tsconfig.json", host); + verifyProgramFiles(); + checkOutputErrorsInitial(host, emptyArray); + assert.equal(host.readFile(`${currentDirectory}/a.js`), `"use strict"; +exports.__esModule = true; +exports.a = ""; +`, "Contents of a.js"); + assert.equal(host.readFile(`${currentDirectory}/b.js`), `"use strict"; +exports.__esModule = true; +var a_1 = require("./a"); +var b = a_1.a; +`, "Contents of b.js"); + const modifiedTime = host.getModifiedTime(`${currentDirectory}/b.js`); + + host.writeFile(aFile.path, `export const a: number = 1`); + host.runQueuedTimeoutCallbacks(); + verifyProgramFiles(); + checkOutputErrorsIncremental(host, [ + getDiagnosticOfFileFromProgram(watch(), bFile.path, bFile.content.indexOf("b"), 1, Diagnostics.Type_0_is_not_assignable_to_type_1, "number", "string") + ]); + assert.equal(host.readFile(`${currentDirectory}/a.js`), `"use strict"; +exports.__esModule = true; +exports.a = 1; +`, "Contents of a.js"); + assert.equal(host.getModifiedTime(`${currentDirectory}/b.js`), modifiedTime, "Timestamp of b.js"); + + function verifyProgramFiles() { + checkProgramActualFiles(watch(), [aFile.path, bFile.path, libFile.path]); + } + }); + }); }