Make watch use sourceFileHash so it can be used with --incremental as well

This commit is contained in:
Sheetal Nandi 2019-03-01 15:47:17 -08:00
parent 97fbc87e98
commit ec47859624
2 changed files with 39 additions and 40 deletions

View file

@ -451,15 +451,7 @@ namespace ts {
let readFileWithCache = (f: string) => host.readFile(f);
let projectCompilerOptions = baseCompilerOptions;
const compilerHost = createCompilerHostFromProgramHost(host, () => projectCompilerOptions);
const originalGetSourceFile = compilerHost.getSourceFile;
const computeHash = host.createHash || generateDjb2Hash;
compilerHost.getSourceFile = (...args) => {
const result = originalGetSourceFile.call(compilerHost, ...args);
if (result) {
result.version = computeHash.call(host, result.text);
}
return result;
};
setCreateSourceFileAsHashVersioned(compilerHost, host);
const buildInfoChecked = createFileMap<true>(toPath);

View file

@ -280,6 +280,18 @@ namespace ts {
}
}
export function setCreateSourceFileAsHashVersioned(compilerHost: CompilerHost, host: ProgramHost<any>) {
const originalGetSourceFile = compilerHost.getSourceFile;
const computeHash = host.createHash || generateDjb2Hash;
compilerHost.getSourceFile = (...args) => {
const result = originalGetSourceFile.call(compilerHost, ...args);
if (result) {
result.version = computeHash.call(host, result.text);
}
return result;
};
}
/**
* Creates the watch compiler host that can be extended with config file or root file names and options host
*/
@ -524,8 +536,6 @@ namespace ts {
}
}
const initialVersion = 1;
/**
* Creates the watch from the host for root files and compiler options
*/
@ -536,13 +546,14 @@ namespace ts {
export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile<T>): WatchOfConfigFile<T>;
export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions<T> & WatchCompilerHostOfConfigFile<T>): WatchOfFilesAndCompilerOptions<T> | WatchOfConfigFile<T> {
interface FilePresentOnHost {
version: number;
version: string;
sourceFile: SourceFile;
fileWatcher: FileWatcher;
}
type FileMissingOnHost = number;
type FileMissingOnHost = false;
interface FilePresenceUnknownOnHost {
version: number;
version: false;
fileWatcher?: FileWatcher;
}
type FileMayBePresentOnHost = FilePresentOnHost | FilePresenceUnknownOnHost;
type HostFileInfo = FilePresentOnHost | FileMissingOnHost | FilePresenceUnknownOnHost;
@ -597,6 +608,7 @@ namespace ts {
}
const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions, directoryStructureHost) as CompilerHost & ResolutionCacheHost;
setCreateSourceFileAsHashVersioned(compilerHost, host);
// Members for CompilerHost
const getNewSourceFile = compilerHost.getSourceFile;
compilerHost.getSourceFile = (fileName, ...args) => getVersionedSourceFileByPath(fileName, toPath(fileName), ...args);
@ -731,19 +743,19 @@ namespace ts {
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
}
function isFileMissingOnHost(hostSourceFile: HostFileInfo): hostSourceFile is FileMissingOnHost {
return typeof hostSourceFile === "number";
function isFileMissingOnHost(hostSourceFile: HostFileInfo | undefined): hostSourceFile is FileMissingOnHost {
return typeof hostSourceFile === "boolean";
}
function isFilePresentOnHost(hostSourceFile: FileMayBePresentOnHost): hostSourceFile is FilePresentOnHost {
return !!(hostSourceFile as FilePresentOnHost).sourceFile;
function isFilePresenceUnknownOnHost(hostSourceFile: FileMayBePresentOnHost): hostSourceFile is FilePresenceUnknownOnHost {
return typeof (hostSourceFile as FilePresenceUnknownOnHost).version === "boolean";
}
function fileExists(fileName: string) {
const path = toPath(fileName);
// If file is missing on host from cache, we can definitely say file doesnt exist
// otherwise we need to ensure from the disk
if (isFileMissingOnHost(sourceFilesCache.get(path)!)) {
if (isFileMissingOnHost(sourceFilesCache.get(path))) {
return true;
}
@ -751,44 +763,39 @@ namespace ts {
}
function getVersionedSourceFileByPath(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined {
const hostSourceFile = sourceFilesCache.get(path)!;
const hostSourceFile = sourceFilesCache.get(path);
// No source file on the host
if (isFileMissingOnHost(hostSourceFile)) {
return undefined;
}
// Create new source file if requested or the versions dont match
if (!hostSourceFile || shouldCreateNewSourceFile || !isFilePresentOnHost(hostSourceFile) || hostSourceFile.version.toString() !== hostSourceFile.sourceFile.version) {
if (hostSourceFile === undefined || shouldCreateNewSourceFile || isFilePresenceUnknownOnHost(hostSourceFile)) {
const sourceFile = getNewSourceFile(fileName, languageVersion, onError);
if (hostSourceFile) {
if (shouldCreateNewSourceFile) {
hostSourceFile.version++;
}
if (sourceFile) {
// Set the source file and create file watcher now that file was present on the disk
(hostSourceFile as FilePresentOnHost).sourceFile = sourceFile;
sourceFile.version = hostSourceFile.version.toString();
if (!(hostSourceFile as FilePresentOnHost).fileWatcher) {
(hostSourceFile as FilePresentOnHost).fileWatcher = watchFilePath(host, fileName, onSourceFileChange, PollingInterval.Low, path, WatchType.SourceFile);
hostSourceFile.version = sourceFile.version;
if (!hostSourceFile.fileWatcher) {
hostSourceFile.fileWatcher = watchFilePath(host, fileName, onSourceFileChange, PollingInterval.Low, path, WatchType.SourceFile);
}
}
else {
// There is no source file on host any more, close the watch, missing file paths will track it
if (isFilePresentOnHost(hostSourceFile)) {
if (hostSourceFile.fileWatcher) {
hostSourceFile.fileWatcher.close();
}
sourceFilesCache.set(path, hostSourceFile.version);
sourceFilesCache.set(path, false);
}
}
else {
if (sourceFile) {
sourceFile.version = initialVersion.toString();
const fileWatcher = watchFilePath(host, fileName, onSourceFileChange, PollingInterval.Low, path, WatchType.SourceFile);
sourceFilesCache.set(path, { sourceFile, version: initialVersion, fileWatcher });
sourceFilesCache.set(path, { sourceFile, version: sourceFile.version, fileWatcher });
}
else {
sourceFilesCache.set(path, initialVersion);
sourceFilesCache.set(path, false);
}
}
return sourceFile;
@ -801,17 +808,17 @@ namespace ts {
if (hostSourceFile !== undefined) {
if (isFileMissingOnHost(hostSourceFile)) {
// The next version, lets set it as presence unknown file
sourceFilesCache.set(path, { version: Number(hostSourceFile) + 1 });
sourceFilesCache.set(path, { version: false });
}
else {
hostSourceFile.version++;
(hostSourceFile as FilePresenceUnknownOnHost).version = false;
}
}
}
function getSourceVersion(path: Path): string | undefined {
const hostSourceFile = sourceFilesCache.get(path);
return !hostSourceFile || isFileMissingOnHost(hostSourceFile) ? undefined : hostSourceFile.version.toString();
return !hostSourceFile || !hostSourceFile.version ? undefined : hostSourceFile.version;
}
function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions, hasSourceFileByPath: boolean) {
@ -820,14 +827,14 @@ namespace ts {
// remove the cached entry.
// Note we arent deleting entry if file became missing in new program or
// there was version update and new source file was created.
if (hostSourceFileInfo) {
if (hostSourceFileInfo !== undefined) {
// record the missing file paths so they can be removed later if watchers arent tracking them
if (isFileMissingOnHost(hostSourceFileInfo)) {
(missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push(oldSourceFile.path);
}
else if ((hostSourceFileInfo as FilePresentOnHost).sourceFile === oldSourceFile) {
if ((hostSourceFileInfo as FilePresentOnHost).fileWatcher) {
(hostSourceFileInfo as FilePresentOnHost).fileWatcher.close();
if (hostSourceFileInfo.fileWatcher) {
hostSourceFileInfo.fileWatcher.close();
}
sourceFilesCache.delete(oldSourceFile.resolvedPath);
if (!hasSourceFileByPath) {
@ -924,7 +931,7 @@ namespace ts {
updateCachedSystemWithFile(fileName, path, eventKind);
// Update the source file cache
if (eventKind === FileWatcherEventKind.Deleted && sourceFilesCache.get(path)) {
if (eventKind === FileWatcherEventKind.Deleted && sourceFilesCache.has(path)) {
resolutionCache.invalidateResolutionOfFile(path);
}
resolutionCache.removeResolutionsFromProjectReferenceRedirects(path);