diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index d40906fac1558..303e19595676e 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -380,7 +380,7 @@ namespace ts { createNewProgram(hasInvalidatedResolution); } - if (host.afterProgramCreate) { + if (host.afterProgramCreate && program !== builderProgram) { host.afterProgramCreate(builderProgram); } @@ -399,6 +399,7 @@ namespace ts { resolutionCache.startCachingPerDirectoryResolution(); compilerHost.hasInvalidatedResolution = hasInvalidatedResolution; compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames; + hasChangedAutomaticTypeDirectiveNames = false; builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences); resolutionCache.finishCachingPerDirectoryResolution(); diff --git a/src/testRunner/unittests/tsbuild/watchMode.ts b/src/testRunner/unittests/tsbuild/watchMode.ts index 0bdc20cff9776..7cc466bfaf1e7 100644 --- a/src/testRunner/unittests/tsbuild/watchMode.ts +++ b/src/testRunner/unittests/tsbuild/watchMode.ts @@ -598,7 +598,7 @@ let x: string = 10;`); } function verifyDependencies(watch: Watch, filePath: string, expected: readonly string[]) { - checkArray(`${filePath} dependencies`, watch.getBuilderProgram().getAllDependencies(watch().getSourceFile(filePath)!), expected); + checkArray(`${filePath} dependencies`, watch.getCurrentProgram().getAllDependencies(watch.getCurrentProgram().getSourceFile(filePath)!), expected); } describe("on sample project", () => { @@ -639,7 +639,7 @@ let x: string = 10;`); host.checkTimeoutQueueLengthAndRun(1); checkOutputErrorsIncremental(host, emptyArray); - checkProgramActualFiles(watch(), expectedProgramFilesAfterEdit()); + checkProgramActualFiles(watch.getCurrentProgram().getProgram(), expectedProgramFilesAfterEdit()); }); @@ -739,7 +739,7 @@ export function gfoo() { expectedWatchedDirectoriesRecursive: readonly string[], dependencies: readonly [string, readonly string[]][], expectedWatchedDirectories?: readonly string[]) { - checkProgramActualFiles(watch(), expectedProgramFiles); + checkProgramActualFiles(watch.getCurrentProgram().getProgram(), expectedProgramFiles); verifyWatchesOfProject(host, expectedWatchedFiles, expectedWatchedDirectoriesRecursive, expectedWatchedDirectories); for (const [file, deps] of dependencies) { verifyDependencies(watch, file, deps); diff --git a/src/testRunner/unittests/tscWatch/consoleClearing.ts b/src/testRunner/unittests/tscWatch/consoleClearing.ts index 27fffcd6e1272..66476b6a31776 100644 --- a/src/testRunner/unittests/tscWatch/consoleClearing.ts +++ b/src/testRunner/unittests/tscWatch/consoleClearing.ts @@ -49,10 +49,11 @@ namespace ts.tscWatch { subScenario: "when preserveWatchOutput is true in config file/createWatchOfConfigFile", commandLineArgs: ["--w", "-p", configFile.path], sys, - getPrograms: () => [[watch(), watch.getBuilderProgram()]], + getPrograms: () => [[watch.getCurrentProgram().getProgram(), watch.getCurrentProgram()]], changes: [ makeChangeToFile - ] + ], + watchOrSolution: watch }); }); verifyTscWatch({ diff --git a/src/testRunner/unittests/tscWatch/helpers.ts b/src/testRunner/unittests/tscWatch/helpers.ts index 34d278031b871..01d9d1c42621d 100644 --- a/src/testRunner/unittests/tscWatch/helpers.ts +++ b/src/testRunner/unittests/tscWatch/helpers.ts @@ -31,27 +31,18 @@ namespace ts.tscWatch { checkArray(`Program rootFileNames`, program.getRootFileNames(), expectedFiles); } - export interface Watch { - (): Program; - getBuilderProgram(): EmitAndSemanticDiagnosticsBuilderProgram; - close(): void; - } + export type Watch = WatchOfConfigFile | WatchOfFilesAndCompilerOptions; export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, optionsToExtend?: CompilerOptions, watchOptionsToExtend?: WatchOptions, maxNumberOfFilesToIterateForInvalidation?: number) { const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, optionsToExtend || {}, watchOptionsToExtend, host); compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation; - const watch = createWatchProgram(compilerHost); - const result = (() => watch.getCurrentProgram().getProgram()) as Watch; - result.getBuilderProgram = () => watch.getCurrentProgram(); - result.close = () => watch.close(); - return result; + return createWatchProgram(compilerHost); } export function createWatchOfFilesAndCompilerOptions(rootFiles: string[], host: WatchedSystem, options: CompilerOptions = {}, watchOptions?: WatchOptions, maxNumberOfFilesToIterateForInvalidation?: number) { const compilerHost = createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, watchOptions, host); compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation; - const watch = createWatchProgram(compilerHost); - return () => watch.getCurrentProgram().getProgram(); + return createWatchProgram(compilerHost); } const elapsedRegex = /^Elapsed:: [0-9]+ms/; @@ -281,7 +272,11 @@ namespace ts.tscWatch { return getDiagnosticOfFileFromProgram(program, file.path, file.content.indexOf(quotedModuleName), quotedModuleName.length, Diagnostics.Cannot_find_module_0, moduleName); } - export type TscWatchCompileChange = (sys: TestFSWithWatch.TestServerHostTrackingWrittenFiles, programs: readonly CommandLineProgram[]) => string; + export type TscWatchCompileChange = ( + sys: TestFSWithWatch.TestServerHostTrackingWrittenFiles, + programs: readonly CommandLineProgram[], + watchOrSolution: ReturnType + ) => string; export interface TscWatchCheckOptions { baselineSourceMap?: boolean; } @@ -309,7 +304,7 @@ namespace ts.tscWatch { } = input; const { cb, getPrograms } = commandLineCallbacks(sys); - executeCommandLine( + const watchOrSolution = executeCommandLine( sys, cb, commandLineArgs, @@ -322,7 +317,8 @@ namespace ts.tscWatch { sys, getPrograms, baselineSourceMap, - changes + changes, + watchOrSolution }); }); } @@ -330,12 +326,13 @@ namespace ts.tscWatch { export interface RunWatchBaseline extends TscWatchCompileBase { sys: TestFSWithWatch.TestServerHostTrackingWrittenFiles; getPrograms: () => readonly CommandLineProgram[]; + watchOrSolution: ReturnType; } export function runWatchBaseline({ scenario, subScenario, commandLineArgs, getPrograms, sys, baselineSourceMap, - changes + changes, watchOrSolution }: RunWatchBaseline) { const baseline: string[] = []; baseline.push(`${sys.getExecutingFilePath()} ${commandLineArgs.join(" ")}`); @@ -349,7 +346,7 @@ namespace ts.tscWatch { for (const change of changes) { const oldSnap = sys.snap(); - const caption = change(sys, programs); + const caption = change(sys, programs, watchOrSolution); baseline.push(`Change:: ${caption}`, ""); programs = watchBaseline({ baseline, diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index b500092269bb6..79e426163dd7e 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -497,13 +497,13 @@ export class A { }; const host = createWatchedSystem([file1, file2, file3]); const watch = createWatchOfFilesAndCompilerOptions([file2.path, file3.path], host); - checkProgramActualFiles(watch(), [file2.path, file3.path]); + checkProgramActualFiles(watch.getCurrentProgram().getProgram(), [file2.path, file3.path]); const watch2 = createWatchOfFilesAndCompilerOptions([file1.path], host); - checkProgramActualFiles(watch2(), [file1.path, file2.path, file3.path]); + checkProgramActualFiles(watch2.getCurrentProgram().getProgram(), [file1.path, file2.path, file3.path]); // Previous program shouldnt be updated - checkProgramActualFiles(watch(), [file2.path, file3.path]); + checkProgramActualFiles(watch.getCurrentProgram().getProgram(), [file2.path, file3.path]); host.checkTimeoutQueueLength(0); }); @@ -937,7 +937,7 @@ declare const eval: any` }; const host = createWatchedSystem([f, libFile]); const watch = createWatchOfFilesAndCompilerOptions([f.path], host, { allowNonTsExtensions: true }); - checkProgramActualFiles(watch(), [f.path, libFile.path]); + checkProgramActualFiles(watch.getCurrentProgram().getProgram(), [f.path, libFile.path]); }); verifyTscWatch({ diff --git a/src/testRunner/unittests/tscWatch/resolutionCache.ts b/src/testRunner/unittests/tscWatch/resolutionCache.ts index 2d974af594cf0..cb2c17cf065f2 100644 --- a/src/testRunner/unittests/tscWatch/resolutionCache.ts +++ b/src/testRunner/unittests/tscWatch/resolutionCache.ts @@ -15,8 +15,8 @@ namespace ts.tscWatch { const host = createWatchedSystem(files); const watch = createWatchOfFilesAndCompilerOptions([root.path], host, { module: ModuleKind.AMD }); - const f1IsNotModule = getDiagnosticOfFileFromProgram(watch(), root.path, root.content.indexOf('"f1"'), '"f1"'.length, Diagnostics.File_0_is_not_a_module, imported.path); - const cannotFindFoo = getDiagnosticOfFileFromProgram(watch(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo"); + const f1IsNotModule = getDiagnosticOfFileFromProgram(watch.getCurrentProgram().getProgram(), root.path, root.content.indexOf('"f1"'), '"f1"'.length, Diagnostics.File_0_is_not_a_module, imported.path); + const cannotFindFoo = getDiagnosticOfFileFromProgram(watch.getCurrentProgram().getProgram(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo"); // ensure that imported file was found checkOutputErrorsInitial(host, [f1IsNotModule, cannotFindFoo]); @@ -37,7 +37,7 @@ namespace ts.tscWatch { // ensure file has correct number of errors after edit checkOutputErrorsIncremental(host, [ f1IsNotModule, - getDiagnosticOfFileFromProgram(watch(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"), + getDiagnosticOfFileFromProgram(watch.getCurrentProgram().getProgram(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"), cannotFindFoo ]); } @@ -60,7 +60,7 @@ namespace ts.tscWatch { // ensure file has correct number of errors after edit checkOutputErrorsIncremental(host, [ - getDiagnosticModuleNotFoundOfFile(watch(), root, "f2") + getDiagnosticModuleNotFoundOfFile(watch.getCurrentProgram().getProgram(), root, "f2") ]); assert.isTrue(fileExistsIsCalled); @@ -118,7 +118,7 @@ namespace ts.tscWatch { assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called"); checkOutputErrorsInitial(host, [ - getDiagnosticModuleNotFoundOfFile(watch(), root, "bar") + getDiagnosticModuleNotFoundOfFile(watch.getCurrentProgram().getProgram(), root, "bar") ]); fileExistsCalledForBar = false; @@ -166,7 +166,7 @@ namespace ts.tscWatch { host.runQueuedTimeoutCallbacks(); assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called."); checkOutputErrorsIncremental(host, [ - getDiagnosticModuleNotFoundOfFile(watch(), root, "bar") + getDiagnosticModuleNotFoundOfFile(watch.getCurrentProgram().getProgram(), root, "bar") ]); fileExistsCalledForBar = false; @@ -391,6 +391,13 @@ declare namespace myapp { }); sys.checkTimeoutQueueLengthAndRun(1); return "npm install ts-types"; + }, + (sys, [[oldProgram, oldBuilderProgram]], watchorSolution) => { + sys.checkTimeoutQueueLength(0); + const newProgram = (watchorSolution as Watch).getProgram(); + assert.strictEqual(newProgram, oldBuilderProgram, "No change so builder program should be same"); + assert.strictEqual(newProgram.getProgram(), oldProgram, "No change so program should be same"); + return "No change, just check program"; } ] }); diff --git a/tests/baselines/reference/tscWatch/resolutionCache/when-types-in-compiler-option-are-global-and-installed-at-later-point.js b/tests/baselines/reference/tscWatch/resolutionCache/when-types-in-compiler-option-are-global-and-installed-at-later-point.js index b7a7e19b45b37..e5d2c3319283a 100644 --- a/tests/baselines/reference/tscWatch/resolutionCache/when-types-in-compiler-option-are-global-and-installed-at-later-point.js +++ b/tests/baselines/reference/tscWatch/resolutionCache/when-types-in-compiler-option-are-global-and-installed-at-later-point.js @@ -113,3 +113,28 @@ FsWatchesRecursive:: {"directoryName":"/user/username/projects/myproject","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}} exitCode:: ExitStatus.undefined + +Change:: No change, just check program + + +Output:: + +WatchedFiles:: +/user/username/projects/myproject/tsconfig.json: + {"fileName":"/user/username/projects/myproject/tsconfig.json","pollingInterval":250} +/user/username/projects/myproject/lib/app.ts: + {"fileName":"/user/username/projects/myproject/lib/app.ts","pollingInterval":250} +/a/lib/lib.d.ts: + {"fileName":"/a/lib/lib.d.ts","pollingInterval":250} +/user/username/projects/myproject/node_modules/@myapp/ts-types/types/somefile.define.d.ts: + {"fileName":"/user/username/projects/myproject/node_modules/@myapp/ts-types/types/somefile.define.d.ts","pollingInterval":250} + +FsWatches:: + +FsWatchesRecursive:: +/user/username/projects/myproject/node_modules: + {"directoryName":"/user/username/projects/myproject/node_modules","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}} +/user/username/projects/myproject: + {"directoryName":"/user/username/projects/myproject","fallbackPollingInterval":500,"fallbackOptions":{"watchFile":"PriorityPollingInterval"}} + +exitCode:: ExitStatus.undefined