mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 01:04:49 -05:00
Invalidate the unresolved import resolutions when typing files are set
This has 3 changes: 1. In updateGraph when enqueue the typing installation request (depending on unresolved imports) 2. When ActionSet event is received, invalidate only files with unresolved imports and resolve those. 3. When ActionInvalidate event is received, typing installer has detected some change in global typing cache location, so just enqueue a new typing installation request. This will repeat the cycle of setting correct typings and pickiing unresolved imports
This commit is contained in:
@@ -524,13 +524,13 @@ namespace ts.server {
|
||||
}
|
||||
switch (response.kind) {
|
||||
case ActionSet:
|
||||
project.resolutionCache.clear();
|
||||
this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typeAcquisition, response.unresolvedImports, response.typings);
|
||||
// Update the typing files and update the project
|
||||
project.updateTypingFiles(this.typingsCache.updateTypingsForProject(response.projectName, response.compilerOptions, response.typeAcquisition, response.unresolvedImports, response.typings));
|
||||
break;
|
||||
case ActionInvalidate:
|
||||
project.resolutionCache.clear();
|
||||
this.typingsCache.deleteTypingsForProject(response.projectName);
|
||||
break;
|
||||
// Do not clear resolution cache, there was changes detected in typings, so enque typing request and let it get us correct results
|
||||
this.typingsCache.enqueueInstallTypingsForProject(project, project.lastCachedUnresolvedImportsList, /*forceRefresh*/ true);
|
||||
return;
|
||||
}
|
||||
this.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,18 @@ namespace ts.server {
|
||||
private plugins: PluginModule[] = [];
|
||||
|
||||
/*@internal*/
|
||||
/**
|
||||
* This is map from files to unresolved imports in it
|
||||
* Maop does not contain entries for files that do not have unresolved imports
|
||||
* This helps in containing the set of files to invalidate
|
||||
*/
|
||||
cachedUnresolvedImportsPerFile = createMap<ReadonlyArray<string>>();
|
||||
|
||||
/**
|
||||
* This is the set that has entry to true if file doesnt contain any unresolved import
|
||||
*/
|
||||
private filesWithNoUnresolvedImports = createMap<true>();
|
||||
|
||||
/*@internal*/
|
||||
lastCachedUnresolvedImportsList: SortedReadonlyArray<string>;
|
||||
/*@internal*/
|
||||
@@ -143,7 +154,8 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
hasChangedAutomaticTypeDirectiveNames = false;
|
||||
|
||||
private typingFiles: SortedReadonlyArray<string>;
|
||||
/*@internal*/
|
||||
typingFiles: SortedReadonlyArray<string> = emptyArray;
|
||||
|
||||
private readonly cancellationToken: ThrottledCancellationToken;
|
||||
|
||||
@@ -554,6 +566,7 @@ namespace ts.server {
|
||||
this.resolutionCache.clear();
|
||||
this.resolutionCache = undefined;
|
||||
this.cachedUnresolvedImportsPerFile = undefined;
|
||||
this.filesWithNoUnresolvedImports = undefined;
|
||||
this.directoryStructureHost = undefined;
|
||||
|
||||
// Clean up file watchers waiting for missing files
|
||||
@@ -714,6 +727,7 @@ namespace ts.server {
|
||||
else {
|
||||
this.resolutionCache.invalidateResolutionOfFile(info.path);
|
||||
}
|
||||
this.filesWithNoUnresolvedImports.delete(info.path);
|
||||
this.cachedUnresolvedImportsPerFile.delete(info.path);
|
||||
|
||||
if (detachFromProject) {
|
||||
@@ -735,16 +749,21 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
private extractUnresolvedImportsFromSourceFile(file: SourceFile, result: Push<string>, ambientModules: string[]) {
|
||||
private extractUnresolvedImportsFromSourceFile(file: SourceFile, result: string[] | undefined, ambientModules: string[]): string[] | undefined {
|
||||
// No unresolve imports in this file
|
||||
if (this.filesWithNoUnresolvedImports.has(file.path)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const cached = this.cachedUnresolvedImportsPerFile.get(file.path);
|
||||
if (cached) {
|
||||
// found cached result - use it and return
|
||||
for (const f of cached) {
|
||||
result.push(f);
|
||||
(result || (result = [])).push(f);
|
||||
}
|
||||
return;
|
||||
return result;
|
||||
}
|
||||
let unresolvedImports: string[];
|
||||
let unresolvedImports: string[] | undefined;
|
||||
if (file.resolvedModules) {
|
||||
file.resolvedModules.forEach((resolvedModule, name) => {
|
||||
// pick unresolved non-relative names
|
||||
@@ -760,11 +779,17 @@ namespace ts.server {
|
||||
trimmed = trimmed.substr(0, i);
|
||||
}
|
||||
(unresolvedImports || (unresolvedImports = [])).push(trimmed);
|
||||
result.push(trimmed);
|
||||
(result || (result = [])).push(trimmed);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.cachedUnresolvedImportsPerFile.set(file.path, unresolvedImports || emptyArray);
|
||||
if (unresolvedImports) {
|
||||
this.cachedUnresolvedImportsPerFile.set(file.path, unresolvedImports);
|
||||
}
|
||||
else {
|
||||
this.filesWithNoUnresolvedImports.set(file.path, true);
|
||||
}
|
||||
return result;
|
||||
|
||||
function isAmbientlyDeclaredModule(name: string) {
|
||||
return ambientModules.some(m => m === name);
|
||||
@@ -778,7 +803,7 @@ namespace ts.server {
|
||||
updateGraph(): boolean {
|
||||
this.resolutionCache.startRecordingFilesWithChangedResolutions();
|
||||
|
||||
let hasChanges = this.updateGraphWorker();
|
||||
const hasChanges = this.updateGraphWorker();
|
||||
const hasMoreOrLessScriptInfos = this.hasMoreOrLessScriptInfos;
|
||||
this.hasMoreOrLessScriptInfos = false;
|
||||
|
||||
@@ -787,6 +812,7 @@ namespace ts.server {
|
||||
for (const file of changedFiles) {
|
||||
// delete cached information for changed files
|
||||
this.cachedUnresolvedImportsPerFile.delete(file);
|
||||
this.filesWithNoUnresolvedImports.delete(file);
|
||||
}
|
||||
|
||||
// update builder only if language service is enabled
|
||||
@@ -799,20 +825,15 @@ namespace ts.server {
|
||||
// (can reuse cached imports for files that were not changed)
|
||||
// 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch
|
||||
if (hasChanges || changedFiles.length) {
|
||||
const result: string[] = [];
|
||||
let result: string[] | undefined;
|
||||
const ambientModules = this.program.getTypeChecker().getAmbientModules().map(mod => stripQuotes(mod.getName()));
|
||||
for (const sourceFile of this.program.getSourceFiles()) {
|
||||
this.extractUnresolvedImportsFromSourceFile(sourceFile, result, ambientModules);
|
||||
result = this.extractUnresolvedImportsFromSourceFile(sourceFile, result, ambientModules);
|
||||
}
|
||||
this.lastCachedUnresolvedImportsList = toDeduplicatedSortedArray(result);
|
||||
this.lastCachedUnresolvedImportsList = result ? toDeduplicatedSortedArray(result) : emptyArray;
|
||||
}
|
||||
|
||||
const cachedTypings = this.projectService.typingsCache.getTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasMoreOrLessScriptInfos);
|
||||
if (!arrayIsEqualTo(this.typingFiles, cachedTypings)) {
|
||||
this.typingFiles = cachedTypings;
|
||||
this.markAsDirty();
|
||||
hasChanges = this.updateGraphWorker() || hasChanges;
|
||||
}
|
||||
this.projectService.typingsCache.enqueueInstallTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasMoreOrLessScriptInfos);
|
||||
}
|
||||
else {
|
||||
this.lastCachedUnresolvedImportsList = undefined;
|
||||
@@ -824,6 +845,13 @@ namespace ts.server {
|
||||
return !hasChanges;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
updateTypingFiles(typingFiles: SortedReadonlyArray<string>) {
|
||||
this.typingFiles = typingFiles;
|
||||
// Invalidate files with unresolved imports
|
||||
this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
getCurrentProgram() {
|
||||
return this.program;
|
||||
@@ -959,15 +987,14 @@ namespace ts.server {
|
||||
setCompilerOptions(compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions) {
|
||||
compilerOptions.allowNonTsExtensions = true;
|
||||
if (changesAffectModuleResolution(this.compilerOptions, compilerOptions)) {
|
||||
// reset cached unresolved imports if changes in compiler options affected module resolution
|
||||
this.cachedUnresolvedImportsPerFile.clear();
|
||||
this.lastCachedUnresolvedImportsList = undefined;
|
||||
}
|
||||
const oldOptions = this.compilerOptions;
|
||||
this.compilerOptions = compilerOptions;
|
||||
this.setInternalCompilerOptionsForEmittingJsFiles();
|
||||
if (changesAffectModuleResolution(oldOptions, compilerOptions)) {
|
||||
// reset cached unresolved imports if changes in compiler options affected module resolution
|
||||
this.cachedUnresolvedImportsPerFile.clear();
|
||||
this.filesWithNoUnresolvedImports.clear();
|
||||
this.lastCachedUnresolvedImportsList = undefined;
|
||||
this.resolutionCache.clear();
|
||||
}
|
||||
this.markAsDirty();
|
||||
|
||||
@@ -95,15 +95,14 @@ namespace ts.server {
|
||||
return this.installer.installPackage(options);
|
||||
}
|
||||
|
||||
getTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray<string>, forceRefresh: boolean): SortedReadonlyArray<string> {
|
||||
enqueueInstallTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray<string>, forceRefresh: boolean) {
|
||||
const typeAcquisition = project.getTypeAcquisition();
|
||||
|
||||
if (!typeAcquisition || !typeAcquisition.enable) {
|
||||
return <any>emptyArray;
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = this.perProjectCache.get(project.getProjectName());
|
||||
const result: SortedReadonlyArray<string> = entry ? entry.typings : <any>emptyArray;
|
||||
if (forceRefresh ||
|
||||
!entry ||
|
||||
typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) ||
|
||||
@@ -114,28 +113,25 @@ namespace ts.server {
|
||||
this.perProjectCache.set(project.getProjectName(), {
|
||||
compilerOptions: project.getCompilationSettings(),
|
||||
typeAcquisition,
|
||||
typings: result,
|
||||
typings: entry ? entry.typings : emptyArray,
|
||||
unresolvedImports,
|
||||
poisoned: true
|
||||
});
|
||||
// something has been changed, issue a request to update typings
|
||||
this.installer.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>, newTypings: string[]) {
|
||||
const typings = toSortedArray(newTypings);
|
||||
this.perProjectCache.set(projectName, {
|
||||
compilerOptions,
|
||||
typeAcquisition,
|
||||
typings: toSortedArray(newTypings),
|
||||
typings,
|
||||
unresolvedImports,
|
||||
poisoned: false
|
||||
});
|
||||
}
|
||||
|
||||
deleteTypingsForProject(projectName: string) {
|
||||
this.perProjectCache.delete(projectName);
|
||||
return !typeAcquisition || !typeAcquisition.enable ? emptyArray : typings;
|
||||
}
|
||||
|
||||
onProjectClosed(project: Project) {
|
||||
|
||||
Reference in New Issue
Block a user