Skip to content

Commit 33ba250

Browse files
authored
Merge pull request #23753 from Microsoft/emptyOptions
Handle the test case when tsconfig file changes without needing to update the program
2 parents 8793b8c + 44066d6 commit 33ba250

File tree

5 files changed

+65
-26
lines changed

5 files changed

+65
-26
lines changed

src/compiler/builder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ namespace ts {
249249
export function createBuilderProgram(kind: BuilderProgramKind, { newProgram, host, oldProgram, configFileParsingDiagnostics }: BuilderCreationParameters) {
250250
// Return same program if underlying program doesnt change
251251
let oldState = oldProgram && oldProgram.getState();
252-
if (oldState && newProgram === oldState.program && configFileParsingDiagnostics !== newProgram.getConfigFileParsingDiagnostics()) {
252+
if (oldState && newProgram === oldState.program && configFileParsingDiagnostics === newProgram.getConfigFileParsingDiagnostics()) {
253253
newProgram = undefined;
254254
oldState = undefined;
255255
return oldProgram;

src/compiler/tsc.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,12 @@ namespace ts {
154154

155155
function updateWatchCompilationHost(watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>) {
156156
const compileUsingBuilder = watchCompilerHost.createProgram;
157-
watchCompilerHost.createProgram = (rootNames, options, host, oldProgram) => {
158-
enableStatistics(options);
159-
return compileUsingBuilder(rootNames, options, host, oldProgram);
157+
watchCompilerHost.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics) => {
158+
Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram));
159+
if (options !== undefined) {
160+
enableStatistics(options);
161+
}
162+
return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics);
160163
};
161164
const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate;
162165
watchCompilerHost.afterProgramCreate = builderProgram => {

src/compiler/watch.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -625,9 +625,19 @@ namespace ts {
625625
builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics);
626626
hasChangedConfigFileParsingErrors = false;
627627
}
628-
return builderProgram;
628+
}
629+
else {
630+
createNewProgram(program, hasInvalidatedResolution);
631+
}
632+
633+
if (host.afterProgramCreate) {
634+
host.afterProgramCreate(builderProgram);
629635
}
630636

637+
return builderProgram;
638+
}
639+
640+
function createNewProgram(program: Program, hasInvalidatedResolution: HasInvalidatedResolution) {
631641
// Compile the program
632642
if (watchLogLevel !== WatchLogLevel.None) {
633643
writeLog("CreatingProgramWith::");
@@ -663,12 +673,6 @@ namespace ts {
663673
}
664674
missingFilePathsRequestedForRelease = undefined;
665675
}
666-
667-
if (host.afterProgramCreate) {
668-
host.afterProgramCreate(builderProgram);
669-
}
670-
671-
return builderProgram;
672676
}
673677

674678
function updateRootFileNames(files: string[]) {

src/harness/unittests/tscWatchMode.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,28 @@ namespace ts.tscWatch {
418418
checkProgramRootFiles(watch(), [commonFile1.path]);
419419
});
420420

421+
it("works correctly when config file is changed but its content havent", () => {
422+
const configFile: FileOrFolder = {
423+
path: "/a/b/tsconfig.json",
424+
content: `{
425+
"compilerOptions": {},
426+
"files": ["${commonFile1.path}", "${commonFile2.path}"]
427+
}`
428+
};
429+
const files = [libFile, commonFile1, commonFile2, configFile];
430+
const host = createWatchedSystem(files);
431+
const watch = createWatchOfConfigFile(configFile.path, host);
432+
433+
checkProgramActualFiles(watch(), [libFile.path, commonFile1.path, commonFile2.path]);
434+
checkOutputErrorsInitial(host, emptyArray);
435+
436+
host.modifyFile(configFile.path, configFile.content);
437+
host.checkTimeoutQueueLengthAndRun(1); // reload the configured project
438+
439+
checkProgramActualFiles(watch(), [libFile.path, commonFile1.path, commonFile2.path]);
440+
checkOutputErrorsIncremental(host, emptyArray);
441+
});
442+
421443
it("files explicitly excluded in config file", () => {
422444
const configFile: FileOrFolder = {
423445
path: "/a/b/tsconfig.json",

src/harness/virtualFileSystemWithWatch.ts

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -393,21 +393,7 @@ interface Array<T> {}`
393393
if (isString(fileOrDirectory.content)) {
394394
// Update file
395395
if (currentEntry.content !== fileOrDirectory.content) {
396-
if (options && options.invokeFileDeleteCreateAsPartInsteadOfChange) {
397-
this.removeFileOrFolder(currentEntry, returnFalse);
398-
this.ensureFileOrFolder(fileOrDirectory);
399-
}
400-
else {
401-
currentEntry.content = fileOrDirectory.content;
402-
currentEntry.modifiedTime = this.now();
403-
this.fs.get(getDirectoryPath(currentEntry.path)).modifiedTime = this.now();
404-
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
405-
this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath);
406-
}
407-
else {
408-
this.invokeFileWatcher(currentEntry.fullPath, FileWatcherEventKind.Changed);
409-
}
410-
}
396+
this.modifyFile(fileOrDirectory.path, fileOrDirectory.content, options);
411397
}
412398
}
413399
else {
@@ -446,6 +432,30 @@ interface Array<T> {}`
446432
}
447433
}
448434

435+
modifyFile(filePath: string, content: string, options?: Partial<ReloadWatchInvokeOptions>) {
436+
const path = this.toFullPath(filePath);
437+
const currentEntry = this.fs.get(path);
438+
if (!currentEntry || !isFile(currentEntry)) {
439+
throw new Error(`file not present: ${filePath}`);
440+
}
441+
442+
if (options && options.invokeFileDeleteCreateAsPartInsteadOfChange) {
443+
this.removeFileOrFolder(currentEntry, returnFalse);
444+
this.ensureFileOrFolder({ path: filePath, content });
445+
}
446+
else {
447+
currentEntry.content = content;
448+
currentEntry.modifiedTime = this.now();
449+
this.fs.get(getDirectoryPath(currentEntry.path)).modifiedTime = this.now();
450+
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
451+
this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath);
452+
}
453+
else {
454+
this.invokeFileWatcher(currentEntry.fullPath, FileWatcherEventKind.Changed);
455+
}
456+
}
457+
}
458+
449459
renameFolder(folderName: string, newFolderName: string) {
450460
const fullPath = getNormalizedAbsolutePath(folderName, this.currentDirectory);
451461
const path = this.toPath(fullPath);

0 commit comments

Comments
 (0)