Skip to content

Commit

Permalink
Watch extended configs if present
Browse files Browse the repository at this point in the history
  • Loading branch information
molisani committed Nov 11, 2020
1 parent b5b0437 commit bdf7c2e
Show file tree
Hide file tree
Showing 8 changed files with 600 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/compiler/watchPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ namespace ts {

let builderProgram: T;
let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc
let extendedConfigFilesMap: ESMap<Path, FileWatcher>; // Map of file watchers for the extended config files
let missingFilesMap: ESMap<Path, FileWatcher>; // Map of file watchers for the missing files
let watchedWildcardDirectories: ESMap<string, WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file
let timerToUpdateProgram: any; // timer callback to recompile the program
Expand Down Expand Up @@ -354,6 +355,10 @@ namespace ts {
configFileWatcher.close();
configFileWatcher = undefined;
}
if (extendedConfigFilesMap) {
clearMap(extendedConfigFilesMap, closeFileWatcher);
extendedConfigFilesMap = undefined!;
}
if (watchedWildcardDirectories) {
clearMap(watchedWildcardDirectories, closeFileWatcherOf);
watchedWildcardDirectories = undefined!;
Expand Down Expand Up @@ -419,6 +424,7 @@ namespace ts {
resolutionCache.finishCachingPerDirectoryResolution();

// Update watches
updateExtendedConfigFilePathsWatch(builderProgram.getProgram(), extendedConfigFilesMap || (extendedConfigFilesMap = new Map()), watchExtendedConfigFile);
updateMissingFilePathsWatch(builderProgram.getProgram(), missingFilesMap || (missingFilesMap = new Map()), watchMissingFilePath);
if (needsUpdateInTypeRootWatch) {
resolutionCache.updateTypeRootsWatch();
Expand Down Expand Up @@ -706,6 +712,10 @@ namespace ts {
}
}

function watchExtendedConfigFile(extendedConfigFile: string) {
return watchFile(host, extendedConfigFile, scheduleProgramReload, PollingInterval.High, watchOptions, WatchType.ConfigFile);
}

function watchMissingFilePath(missingFilePath: Path) {
return watchFilePath(missingFilePath, missingFilePath, onMissingFileChange, PollingInterval.Medium, watchOptions, WatchType.MissingFile);
}
Expand Down
24 changes: 24 additions & 0 deletions src/compiler/watchUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,30 @@ namespace ts {
Full
}

/**
* Updates the extended config file watches with the new set of extended config files after new program is created
*/
export function updateExtendedConfigFilePathsWatch(
program: Program,
extendedConfigFilesMap: ESMap<string, FileWatcher>,
createExtendedConfigFileWatch: (extendedConfigPath: string) => FileWatcher,
) {
const extendedSourceFiles = program.getCompilerOptions().configFile?.extendedSourceFiles || [];
// TODO(rbuckton): Should be a `Set` but that requires changing the below code that uses `mutateMap`
const newExtendedConfigFilesMap = arrayToMap(extendedSourceFiles, identity, returnTrue);
// Update the extended config files watcher
mutateMap(
extendedConfigFilesMap,
newExtendedConfigFilesMap,
{
// Watch the extended config files
createNewValue: createExtendedConfigFileWatch,
// Config files that are no longer extended should no longer be watched.
onDeleteValue: closeFileWatcher
}
);
}

/**
* Updates the existing missing file watches with the new set of missing files after new program is created
*/
Expand Down
156 changes: 156 additions & 0 deletions src/testRunner/unittests/tscWatch/watchEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -497,5 +497,161 @@ namespace ts.tscWatch {
verifyWorker("-extendedDiagnostics");
});
});

describe("handles watch for extended configs", () => {
verifyTscWatch({
scenario,
subScenario: "watchExtends/with several extended configs",
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
sys: () => {
const firstExtendedFile: File = {
path: "/a/b/first.tsconfig.json",
content: JSON.stringify({
compilerOptions: {
strict: false,
}
})
};
const secondExtendedFile: File = {
path: "/a/b/second.tsconfig.json",
content: JSON.stringify({
extends: "./first.tsconfig.json",
compilerOptions: {
strictNullChecks: true,
}
})
};
const thirdExtendedFile: File = {
path: "/a/b/third.tsconfig.json",
content: JSON.stringify({
extends: "./second.tsconfig.json",
compilerOptions: {
strictBindCallApply: true,
}
})
};
const fourthExtendedFile: File = {
path: "/a/b/fourth.tsconfig.json",
content: JSON.stringify({
extends: "./third.tsconfig.json",
compilerOptions: {
strictFunctionTypes: true,
}
})
};
const configFile: File = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({
extends: "./fourth.tsconfig.json",
compilerOptions: {
strictPropertyInitialization: true,
}
})
};
const files = [
libFile, commonFile1, commonFile2, firstExtendedFile, secondExtendedFile, thirdExtendedFile,
fourthExtendedFile, configFile
];
return createWatchedSystem(files);
},
changes: emptyArray
});

verifyTscWatch({
scenario,
subScenario: "watchExtends/with watchFile option",
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
sys: () => {
const extendedFile: File = {
path: "/a/b/extended.tsconfig.json",
content: JSON.stringify({
watchOptions: {
watchFile: "UseFsEvents"
}
})
};
const configFile: File = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({
extends: "./extended.tsconfig.json"
})
};
const files = [libFile, commonFile1, commonFile2, extendedFile, configFile];
return createWatchedSystem(files);
},
changes: emptyArray
});

verifyTscWatch({
scenario,
subScenario: "watchExtends/with watchDirectory option",
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
sys: () => {
const extendedFile: File = {
path: "/a/b/extended.tsconfig.json",
content: JSON.stringify({
watchOptions: {
watchDirectory: "UseFsEvents"
}
})
};
const configFile: File = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({
extends: "./extended.tsconfig.json"
})
};
const files = [libFile, commonFile1, commonFile2, extendedFile, configFile];
return createWatchedSystem(files, { runWithoutRecursiveWatches: true });
},
changes: emptyArray
});

verifyTscWatch({
scenario,
subScenario: "watchExtends/with fallbackPolling option",
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json"],
sys: () => {
const extendedFile: File = {
path: "/a/b/extended.tsconfig.json",
content: JSON.stringify({
watchOptions: {
fallbackPolling: "PriorityInterval"
}
})
};
const configFile: File = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({
extends: "./extended.tsconfig.json"
})
};
const files = [libFile, commonFile1, commonFile2, extendedFile, configFile];
return createWatchedSystem(files, { runWithoutRecursiveWatches: true, runWithFallbackPolling: true });
},
changes: emptyArray
});

verifyTscWatch({
scenario,
subScenario: "watchExtends/with watchFile as watch options to extend",
commandLineArgs: ["-w", "-p", "/a/b/tsconfig.json", "--watchFile", "UseFsEvents"],
sys: () => {
const extendedFile: File = {
path: "/a/b/extended.tsconfig.json",
content: "{}"
};
const configFile: File = {
path: "/a/b/tsconfig.json",
content: JSON.stringify({
extends: "./extended.tsconfig.json"
})
};
const files = [libFile, commonFile1, commonFile2, extendedFile, configFile];
return createWatchedSystem(files);
},
changes: emptyArray
});
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
Input::
//// [/a/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }

//// [/a/b/commonFile1.ts]
let x = 1

//// [/a/b/commonFile2.ts]
let y = 1

//// [/a/b/extended.tsconfig.json]
{"watchOptions":{"fallbackPolling":"PriorityInterval"}}

//// [/a/b/tsconfig.json]
{"extends":"./extended.tsconfig.json"}


/a/lib/tsc.js -w -p /a/b/tsconfig.json
Output::
>> Screen clear
[12:00:19 AM] Starting compilation in watch mode...

[12:00:24 AM] Found 0 errors. Watching for file changes.



Program root files: ["/a/b/commonFile1.ts","/a/b/commonFile2.ts"]
Program options: {"watch":true,"project":"/a/b/tsconfig.json","configFilePath":"/a/b/tsconfig.json"}
Program structureReused: Not
Program files::
/a/lib/lib.d.ts
/a/b/commonFile1.ts
/a/b/commonFile2.ts

Semantic diagnostics in builder refreshed for::
/a/lib/lib.d.ts
/a/b/commonFile1.ts
/a/b/commonFile2.ts

WatchedFiles::
/a/b/tsconfig.json:
{"fileName":"/a/b/tsconfig.json","pollingInterval":250}
/a/b/commonfile1.ts:
{"fileName":"/a/b/commonFile1.ts","pollingInterval":250}
/a/b/commonfile2.ts:
{"fileName":"/a/b/commonFile2.ts","pollingInterval":250}
/a/lib/lib.d.ts:
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
/a/b/extended.tsconfig.json:
{"fileName":"/a/b/extended.tsconfig.json","pollingInterval":250}
/a/b/node_modules/@types:
{"fileName":"/a/b/node_modules/@types","pollingInterval":500}
/a/b:
{"fileName":"/a/b","pollingInterval":500}

FsWatches::

FsWatchesRecursive::

exitCode:: ExitStatus.undefined

//// [/a/b/commonFile1.js]
var x = 1;


//// [/a/b/commonFile2.js]
var y = 1;


Loading

0 comments on commit bdf7c2e

Please sign in to comment.