mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 07:45:18 -06:00
Factor out caching logic so tsc (without watch can use it and --watch has its own cache logic).
This commit is contained in:
parent
c7f8959034
commit
8d5d900567
@ -203,6 +203,114 @@ namespace ts {
|
||||
return compilerHost;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function changeCompilerHostToUseCache(
|
||||
host: CompilerHost,
|
||||
toPath: (fileName: string) => Path,
|
||||
useCacheForSourceFile: boolean
|
||||
) {
|
||||
const originalReadFile = host.readFile;
|
||||
const originalFileExists = host.fileExists;
|
||||
const originalDirectoryExists = host.directoryExists;
|
||||
const originalCreateDirectory = host.createDirectory;
|
||||
const originalWriteFile = host.writeFile;
|
||||
const originalGetSourceFile = host.getSourceFile;
|
||||
const readFileCache = createMap<string | false>();
|
||||
const fileExistsCache = createMap<boolean>();
|
||||
const directoryExistsCache = createMap<boolean>();
|
||||
const sourceFileCache = createMap<SourceFile>();
|
||||
|
||||
const readFileWithCache = (fileName: string): string | undefined => {
|
||||
const key = toPath(fileName);
|
||||
const value = readFileCache.get(key);
|
||||
if (value !== undefined) return value || undefined;
|
||||
return setReadFileCache(key, fileName);
|
||||
};
|
||||
const setReadFileCache = (key: Path, fileName: string) => {
|
||||
const newValue = originalReadFile.call(host, fileName);
|
||||
readFileCache.set(key, newValue || false);
|
||||
return newValue;
|
||||
};
|
||||
host.readFile = fileName => {
|
||||
const key = toPath(fileName);
|
||||
const value = readFileCache.get(key);
|
||||
if (value !== undefined) return value; // could be .d.ts from output
|
||||
if (!fileExtensionIs(fileName, Extension.Json)) {
|
||||
return originalReadFile.call(host, fileName);
|
||||
}
|
||||
|
||||
return setReadFileCache(key, fileName);
|
||||
};
|
||||
|
||||
if (useCacheForSourceFile) {
|
||||
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
||||
const key = toPath(fileName);
|
||||
const value = sourceFileCache.get(key);
|
||||
if (value) return value;
|
||||
|
||||
const sourceFile = originalGetSourceFile.call(host, fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
||||
if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) {
|
||||
sourceFileCache.set(key, sourceFile);
|
||||
}
|
||||
return sourceFile;
|
||||
};
|
||||
}
|
||||
|
||||
// fileExists for any kind of extension
|
||||
host.fileExists = fileName => {
|
||||
const key = toPath(fileName);
|
||||
const value = fileExistsCache.get(key);
|
||||
if (value !== undefined) return value;
|
||||
const newValue = originalFileExists.call(host, fileName);
|
||||
fileExistsCache.set(key, !!newValue);
|
||||
return newValue;
|
||||
};
|
||||
host.writeFile = (fileName, data, writeByteOrderMark, onError, sourceFiles) => {
|
||||
const key = toPath(fileName);
|
||||
fileExistsCache.delete(key);
|
||||
|
||||
const value = readFileCache.get(key);
|
||||
if (value && value !== data) {
|
||||
readFileCache.delete(key);
|
||||
sourceFileCache.delete(key);
|
||||
}
|
||||
else if (useCacheForSourceFile) {
|
||||
const sourceFile = sourceFileCache.get(key);
|
||||
if (sourceFile && sourceFile.text !== data) {
|
||||
sourceFileCache.delete(key);
|
||||
}
|
||||
}
|
||||
originalWriteFile.call(host, fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||
};
|
||||
|
||||
// directoryExists
|
||||
if (originalDirectoryExists && originalCreateDirectory) {
|
||||
host.directoryExists = directory => {
|
||||
const key = toPath(directory);
|
||||
const value = directoryExistsCache.get(key);
|
||||
if (value !== undefined) return value;
|
||||
const newValue = originalDirectoryExists.call(host, directory);
|
||||
directoryExistsCache.set(key, !!newValue);
|
||||
return newValue;
|
||||
};
|
||||
host.createDirectory = directory => {
|
||||
const key = toPath(directory);
|
||||
directoryExistsCache.delete(key);
|
||||
originalCreateDirectory.call(host, directory);
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
originalReadFile,
|
||||
originalFileExists,
|
||||
originalDirectoryExists,
|
||||
originalCreateDirectory,
|
||||
originalWriteFile,
|
||||
originalGetSourceFile,
|
||||
readFileWithCache
|
||||
};
|
||||
}
|
||||
|
||||
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
|
||||
const diagnostics = [
|
||||
...program.getConfigFileParsingDiagnostics(),
|
||||
|
||||
@ -1183,96 +1183,14 @@ namespace ts {
|
||||
|
||||
function buildAllProjects(): ExitStatus {
|
||||
if (options.watch) { reportWatchStatus(Diagnostics.Starting_compilation_in_watch_mode); }
|
||||
const originalReadFile = host.readFile;
|
||||
const originalFileExists = host.fileExists;
|
||||
const originalDirectoryExists = host.directoryExists;
|
||||
const originalCreateDirectory = host.createDirectory;
|
||||
const originalWriteFile = host.writeFile;
|
||||
const originalGetSourceFile = host.getSourceFile;
|
||||
const readFileCache = createMap<string | false>();
|
||||
const fileExistsCache = createMap<boolean>();
|
||||
const directoryExistsCache = createMap<boolean>();
|
||||
const sourceFileCache = createMap<SourceFile>();
|
||||
const savedReadFileWithCache = readFileWithCache;
|
||||
|
||||
// TODO:: In watch mode as well to use caches for incremental build once we can invalidate caches correctly and have right api
|
||||
// Override readFile for json files and output .d.ts to cache the text
|
||||
readFileWithCache = fileName => {
|
||||
const key = toPath(fileName);
|
||||
const value = readFileCache.get(key);
|
||||
if (value !== undefined) return value || undefined;
|
||||
return setReadFileCache(key, fileName);
|
||||
};
|
||||
const setReadFileCache = (key: Path, fileName: string) => {
|
||||
const newValue = originalReadFile.call(host, fileName);
|
||||
readFileCache.set(key, newValue || false);
|
||||
return newValue;
|
||||
};
|
||||
host.readFile = fileName => {
|
||||
const key = toPath(fileName);
|
||||
const value = readFileCache.get(key);
|
||||
if (value !== undefined) return value; // could be .d.ts from output
|
||||
if (!fileExtensionIs(fileName, Extension.Json)) {
|
||||
return originalReadFile.call(host, fileName);
|
||||
}
|
||||
|
||||
return setReadFileCache(key, fileName);
|
||||
};
|
||||
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
||||
const key = toPath(fileName);
|
||||
const value = sourceFileCache.get(key);
|
||||
if (value) return value;
|
||||
|
||||
const sourceFile = originalGetSourceFile.call(host, fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
||||
if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) {
|
||||
sourceFileCache.set(key, sourceFile);
|
||||
}
|
||||
return sourceFile;
|
||||
};
|
||||
|
||||
// fileExists for any kind of extension
|
||||
host.fileExists = fileName => {
|
||||
const key = toPath(fileName);
|
||||
const value = fileExistsCache.get(key);
|
||||
if (value !== undefined) return value;
|
||||
const newValue = originalFileExists.call(host, fileName);
|
||||
fileExistsCache.set(key, !!newValue);
|
||||
return newValue;
|
||||
};
|
||||
host.writeFile = (fileName, data, writeByteOrderMark, onError, sourceFiles) => {
|
||||
const key = toPath(fileName);
|
||||
fileExistsCache.delete(key);
|
||||
|
||||
const value = readFileCache.get(key);
|
||||
if (value && value !== data) {
|
||||
readFileCache.delete(key);
|
||||
sourceFileCache.delete(key);
|
||||
}
|
||||
else {
|
||||
const sourceFile = sourceFileCache.get(key);
|
||||
if (sourceFile && sourceFile.text !== data) {
|
||||
sourceFileCache.delete(key);
|
||||
}
|
||||
}
|
||||
originalWriteFile.call(host, fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||
};
|
||||
|
||||
// directoryExists
|
||||
if (originalDirectoryExists && originalCreateDirectory) {
|
||||
host.directoryExists = directory => {
|
||||
const key = toPath(directory);
|
||||
const value = directoryExistsCache.get(key);
|
||||
if (value !== undefined) return value;
|
||||
const newValue = originalDirectoryExists.call(host, directory);
|
||||
directoryExistsCache.set(key, !!newValue);
|
||||
return newValue;
|
||||
};
|
||||
host.createDirectory = directory => {
|
||||
const key = toPath(directory);
|
||||
directoryExistsCache.delete(key);
|
||||
originalCreateDirectory.call(host, directory);
|
||||
};
|
||||
}
|
||||
const { originalReadFile, originalFileExists, originalDirectoryExists,
|
||||
originalCreateDirectory, originalWriteFile, originalGetSourceFile,
|
||||
readFileWithCache: newReadFileWithCache
|
||||
} = changeCompilerHostToUseCache(host, toPath, /*useCacheForSourceFile*/ true);
|
||||
const savedReadFileWithCache = readFileWithCache;
|
||||
readFileWithCache = newReadFileWithCache;
|
||||
|
||||
const graph = getGlobalDependencyGraph();
|
||||
reportBuildQueue(graph);
|
||||
|
||||
@ -227,6 +227,9 @@ namespace ts {
|
||||
|
||||
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
const host = createCompilerHost(options);
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
|
||||
changeCompilerHostToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName), /*useCacheForSourceFile*/ false);
|
||||
enableStatistics(options);
|
||||
|
||||
const programOptions: CreateProgramOptions = {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user