mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-13 16:34:39 -06:00
Partial implementation for invalidating the program (instead of source file as that would involve more work) so the files are picked up
This commit is contained in:
parent
d55150cbd3
commit
8dc62484ec
@ -9,6 +9,7 @@ namespace ts {
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string, logChanges: boolean): ResolvedModuleFull[];
|
||||
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
invalidateResolutionOfDeletedFile(filePath: Path): void;
|
||||
invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation: string): void;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
@ -33,8 +34,7 @@ namespace ts {
|
||||
export function createResolutionCache(
|
||||
toPath: (fileName: string) => Path,
|
||||
getCompilerOptions: () => CompilerOptions,
|
||||
clearProgramAndScheduleUpdate: () => void,
|
||||
watchForFailedLookupLocation: (fileName: string, callback: FileWatcherCallback) => FileWatcher,
|
||||
watchForFailedLookupLocation: (failedLookupLocation: string, containingFile: string, name: string) => FileWatcher,
|
||||
log: (s: string) => void,
|
||||
resolveWithGlobalCache?: ResolverWithGlobalCache): ResolutionCache {
|
||||
|
||||
@ -54,6 +54,7 @@ namespace ts {
|
||||
resolveModuleNames,
|
||||
resolveTypeReferenceDirectives,
|
||||
invalidateResolutionOfDeletedFile,
|
||||
invalidateResolutionOfChangedFailedLookupLocation,
|
||||
clear
|
||||
};
|
||||
|
||||
@ -185,11 +186,8 @@ namespace ts {
|
||||
log(`Watcher: FailedLookupLocations: Status: Using existing watcher: Location: ${failedLookupLocation}, containingFile: ${containingFile}, name: ${name} refCount: ${failedLookupLocationWatcher.refCount}`);
|
||||
}
|
||||
else {
|
||||
const fileWatcher = watchForFailedLookupLocation(failedLookupLocation, (__fileName, eventKind) => {
|
||||
log(`Watcher: FailedLookupLocations: Status: ${FileWatcherEventKind[eventKind]}: Location: ${failedLookupLocation}, containingFile: ${containingFile}, name: ${name}`);
|
||||
// There is some kind of change in the failed lookup location, update the program
|
||||
clearProgramAndScheduleUpdate();
|
||||
});
|
||||
log(`Watcher: FailedLookupLocations: Status: new watch: Location: ${failedLookupLocation}, containingFile: ${containingFile}, name: ${name}`);
|
||||
const fileWatcher = watchForFailedLookupLocation(failedLookupLocation, containingFile, name);
|
||||
failedLookupLocationsWatches.set(failedLookupLocationPath, { fileWatcher, refCount: 1 });
|
||||
}
|
||||
}
|
||||
@ -260,7 +258,7 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
else if (value) {
|
||||
value.forEach((resolution) => {
|
||||
value.forEach((resolution, __name) => {
|
||||
if (resolution && !resolution.isInvalidated) {
|
||||
const result = getResult(resolution);
|
||||
if (result) {
|
||||
@ -274,9 +272,31 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function invalidateResolutionCacheOfChangedFailedLookupLocation<T extends NameResolutionWithFailedLookupLocations>(
|
||||
failedLookupLocation: string,
|
||||
cache: Map<Map<T>>) {
|
||||
cache.forEach((value, _containingFilePath) => {
|
||||
if (value) {
|
||||
value.forEach((resolution, __name) => {
|
||||
if (resolution && !resolution.isInvalidated && contains(resolution.failedLookupLocations, failedLookupLocation)) {
|
||||
// TODO: mark the file as needing re-evaluation of module resolution instead of using it blindly.
|
||||
// Note: Right now this invalidation path is not used at all as it doesnt matter as we are anyways clearing the program,
|
||||
// which means all the resolutions will be discarded.
|
||||
resolution.isInvalidated = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function invalidateResolutionOfDeletedFile(filePath: Path) {
|
||||
invalidateResolutionCacheOfDeletedFile(filePath, resolvedModuleNames, m => m.resolvedModule, r => r.resolvedFileName);
|
||||
invalidateResolutionCacheOfDeletedFile(filePath, resolvedTypeReferenceDirectives, m => m.resolvedTypeReferenceDirective, r => r.resolvedFileName);
|
||||
}
|
||||
|
||||
function invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation: string) {
|
||||
invalidateResolutionCacheOfChangedFailedLookupLocation(failedLookupLocation, resolvedModuleNames);
|
||||
invalidateResolutionCacheOfChangedFailedLookupLocation(failedLookupLocation, resolvedTypeReferenceDirectives);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,6 +255,7 @@ namespace ts {
|
||||
let timerToUpdateProgram: any; // timer callback to recompile the program
|
||||
|
||||
const sourceFilesCache = createMap<HostFileInfo | string>(); // Cache that stores the source file and version info
|
||||
let missingFilePathsRequestedForRelease: Path[]; // These paths are held temparirly so that we can remove the entry from source file cache if the file is not tracked by missing files
|
||||
|
||||
watchingHost = watchingHost || createWatchingSystemHost(compilerOptions.pretty);
|
||||
const { system, parseConfigFile, reportDiagnostic, reportWatchDiagnostic, beforeCompile, afterCompile } = watchingHost;
|
||||
@ -274,8 +275,7 @@ namespace ts {
|
||||
const resolutionCache = createResolutionCache(
|
||||
fileName => toPath(fileName),
|
||||
() => compilerOptions,
|
||||
() => clearExistingProgramAndScheduleProgramUpdate(),
|
||||
(fileName, callback) => system.watchFile(fileName, callback),
|
||||
watchFailedLookupLocation,
|
||||
s => writeLog(s)
|
||||
);
|
||||
|
||||
@ -310,6 +310,19 @@ namespace ts {
|
||||
|
||||
// Update watches
|
||||
missingFilesMap = updateMissingFilePathsWatch(program, missingFilesMap, watchMissingFilePath, closeMissingFilePathWatcher);
|
||||
if (missingFilePathsRequestedForRelease) {
|
||||
// These are the paths that program creater told us as not in use any more but were missing on the disk.
|
||||
// We didnt remove the entry for them from sourceFiles cache so that we dont have to do File IO,
|
||||
// if there is already watcher for it (for missing files)
|
||||
// At that point our watches were updated, hence now we know that these paths are not tracked and need to be removed
|
||||
// so that at later time we have correct result of their presence
|
||||
for (const missingFilePath of missingFilePathsRequestedForRelease) {
|
||||
if (!missingFilesMap.has(missingFilePath)) {
|
||||
sourceFilesCache.delete(missingFilePath);
|
||||
}
|
||||
}
|
||||
missingFilePathsRequestedForRelease = undefined;
|
||||
}
|
||||
|
||||
afterCompile(host, program, builder);
|
||||
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes));
|
||||
@ -446,8 +459,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 && !isString(hostSourceFileInfo) && hostSourceFileInfo.sourceFile === oldSourceFile) {
|
||||
sourceFilesCache.delete(oldSourceFile.path);
|
||||
if (hostSourceFileInfo) {
|
||||
// record the missing file paths so they can be removed later if watchers arent tracking them
|
||||
if (isString(hostSourceFileInfo)) {
|
||||
(missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push(oldSourceFile.path);
|
||||
}
|
||||
else if (hostSourceFileInfo.sourceFile === oldSourceFile) {
|
||||
sourceFilesCache.delete(oldSourceFile.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -471,11 +490,6 @@ namespace ts {
|
||||
scheduleProgramUpdate();
|
||||
}
|
||||
|
||||
function clearExistingProgramAndScheduleProgramUpdate() {
|
||||
program = undefined;
|
||||
scheduleProgramUpdate();
|
||||
}
|
||||
|
||||
function updateProgram() {
|
||||
timerToUpdateProgram = undefined;
|
||||
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation));
|
||||
@ -547,6 +561,24 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function watchFailedLookupLocation(failedLookupLocation: string, containingFile: string, name: string) {
|
||||
return host.watchFile(failedLookupLocation, (fileName, eventKind) => onFailedLookupLocationChange(fileName, eventKind, failedLookupLocation, containingFile, name));
|
||||
}
|
||||
|
||||
function onFailedLookupLocationChange(fileName: string, eventKind: FileWatcherEventKind, failedLookupLocation: string, containingFile: string, name: string) {
|
||||
writeLog(`Failed lookup location : ${failedLookupLocation} changed: ${FileWatcherEventKind[eventKind]}, fileName: ${fileName} containingFile: ${containingFile}, name: ${name}`);
|
||||
const path = toPath(failedLookupLocation);
|
||||
updateCachedSystem(failedLookupLocation, path);
|
||||
|
||||
// TODO: We need more intensive approach wherein we are able to comunicate to the program structure reuser that the even though the source file
|
||||
// refering to this failed location hasnt changed, it needs to re-evaluate the module resolutions for the invalidated resolutions.
|
||||
// For now just clear existing program, that should still reuse the source files but atleast compute the resolutions again.
|
||||
|
||||
// resolutionCache.invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation);
|
||||
program = undefined;
|
||||
scheduleProgramUpdate();
|
||||
}
|
||||
|
||||
function watchMissingFilePath(missingFilePath: Path) {
|
||||
return host.watchFile(missingFilePath, (fileName, eventKind) => onMissingFileChange(fileName, missingFilePath, eventKind));
|
||||
}
|
||||
|
||||
@ -335,7 +335,8 @@ namespace ts.projectSystem {
|
||||
checkFileNames("inferred project", project.getFileNames(), [appFile.path, libFile.path, moduleFile.path]);
|
||||
const configFileLocations = ["/a/b/c/", "/a/b/", "/a/", "/"];
|
||||
const configFiles = flatMap(configFileLocations, location => [location + "tsconfig.json", location + "jsconfig.json"]);
|
||||
checkWatchedFiles(host, configFiles.concat(libFile.path, moduleFile.path));
|
||||
const moduleLookupLocations = ["/a/b/c/module.ts", "/a/b/c/module.tsx"];
|
||||
checkWatchedFiles(host, configFiles.concat(libFile.path, moduleFile.path, ...moduleLookupLocations));
|
||||
});
|
||||
|
||||
it("can handle tsconfig file name with difference casing", () => {
|
||||
|
||||
@ -247,7 +247,8 @@ namespace ts.server {
|
||||
WildCardDirectories = "Wild card directory",
|
||||
TypeRoot = "Type root of the project",
|
||||
ClosedScriptInfo = "Closed Script info",
|
||||
ConfigFileForInferredRoot = "Config file for the inferred project root"
|
||||
ConfigFileForInferredRoot = "Config file for the inferred project root",
|
||||
FailedLookupLocation = "Failed lookup locations in module resolution"
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@ -217,8 +217,7 @@ namespace ts.server {
|
||||
this.resolutionCache = createResolutionCache(
|
||||
fileName => this.projectService.toPath(fileName),
|
||||
() => this.compilerOptions,
|
||||
() => this.markAsDirty(),
|
||||
(fileName, callback) => host.watchFile(fileName, callback),
|
||||
(failedLookupLocation, containingFile, name) => this.watchFailedLookupLocation(failedLookupLocation, containingFile, name),
|
||||
s => this.projectService.logger.info(s),
|
||||
(primaryResult, moduleName, compilerOptions, host) => resolveWithGlobalCache(primaryResult, moduleName, compilerOptions, host,
|
||||
this.getTypeAcquisition().enable ? this.projectService.typingsInstaller.globalTypingsCacheLocation : undefined, this.getProjectName())
|
||||
@ -235,6 +234,23 @@ namespace ts.server {
|
||||
this.markAsDirty();
|
||||
}
|
||||
|
||||
private watchFailedLookupLocation(failedLookupLocation: string, containingFile: string, name: string) {
|
||||
// There is some kind of change in the failed lookup location, update the program
|
||||
return this.projectService.addFileWatcher(WatchType.FailedLookupLocation, this, failedLookupLocation, (__fileName, eventKind) => {
|
||||
this.projectService.logger.info(`Watcher: FailedLookupLocations: Status: ${FileWatcherEventKind[eventKind]}: Location: ${failedLookupLocation}, containingFile: ${containingFile}, name: ${name}`);
|
||||
if (this.projectKind === ProjectKind.Configured) {
|
||||
(this.lsHost.host as CachedServerHost).addOrDeleteFileOrFolder(toNormalizedPath(failedLookupLocation));
|
||||
}
|
||||
this.updateTypes();
|
||||
// TODO: We need more intensive approach wherein we are able to comunicate to the program structure reuser that the even though the source file
|
||||
// refering to this failed location hasnt changed, it needs to re-evaluate the module resolutions for the invalidated resolutions.
|
||||
// For now just clear existing program, that should still reuse the source files but atleast compute the resolutions again.
|
||||
// this.resolutionCache.invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation);
|
||||
// this.markAsDirty();
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
});
|
||||
}
|
||||
|
||||
private setInternalCompilerOptionsForEmittingJsFiles() {
|
||||
if (this.projectKind === ProjectKind.Inferred || this.projectKind === ProjectKind.External) {
|
||||
this.compilerOptions.noEmitForJsFiles = true;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user