mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
getEditsForFileRename: Do fresh module resolution instead of relying on cache (#24211)
* getEditsForFileRename: Do fresh module resolution instead of relying on cache * Add host.resolveModuleNameWithFailedLookupLocations method * Make host.resolveModuleNameWithFailedLookupLocations mandatory, and implement for Project * Add test, and no need to check host.fileExists * Change method name and always use cache * Update name in string
This commit is contained in:
@@ -6,6 +6,7 @@ namespace ts {
|
||||
finishRecordingFilesWithChangedResolutions(): Path[];
|
||||
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined): ResolvedModuleFull[];
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
|
||||
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
|
||||
invalidateResolutionOfFile(filePath: Path): void;
|
||||
@@ -73,7 +74,7 @@ namespace ts {
|
||||
export const maxNumberOfFilesToIterateForInvalidation = 256;
|
||||
|
||||
type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> =
|
||||
(resolution: T) => R;
|
||||
(resolution: T) => R | undefined;
|
||||
|
||||
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string, logChangesWhenResolvingModule: boolean): ResolutionCache {
|
||||
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
|
||||
@@ -124,6 +125,7 @@ namespace ts {
|
||||
startCachingPerDirectoryResolution: clearPerDirectoryResolutions,
|
||||
finishCachingPerDirectoryResolution,
|
||||
resolveModuleNames,
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache,
|
||||
resolveTypeReferenceDirectives,
|
||||
removeResolutionsOfFile,
|
||||
invalidateResolutionOfFile,
|
||||
@@ -320,7 +322,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
|
||||
return resolveNamesWithLocalCache(
|
||||
return resolveNamesWithLocalCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations, ResolvedTypeReferenceDirective>(
|
||||
typeDirectiveNames, containingFile,
|
||||
resolvedTypeReferenceDirectives, perDirectoryResolvedTypeReferenceDirectives,
|
||||
resolveTypeReferenceDirective, getResolvedTypeReferenceDirective,
|
||||
@@ -329,7 +331,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined): ResolvedModuleFull[] {
|
||||
return resolveNamesWithLocalCache(
|
||||
return resolveNamesWithLocalCache<ResolvedModuleWithFailedLookupLocations, ResolvedModuleFull>(
|
||||
moduleNames, containingFile,
|
||||
resolvedModuleNames, perDirectoryResolvedModuleNames,
|
||||
resolveModuleName, getResolvedModule,
|
||||
@@ -337,6 +339,11 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined {
|
||||
const cache = resolvedModuleNames.get(resolutionHost.toPath(containingFile));
|
||||
return cache && cache.get(moduleName);
|
||||
}
|
||||
|
||||
function isNodeModulesDirectory(dirPath: Path) {
|
||||
return endsWith(dirPath, "/node_modules");
|
||||
}
|
||||
|
||||
@@ -8383,4 +8383,35 @@ new C();`
|
||||
verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem getEditsForFileRename", () => {
|
||||
it("works for host implementing 'resolveModuleNames' and 'getResolvedModuleWithFailedLookupLocationsFromCache'", () => {
|
||||
const userTs: File = {
|
||||
path: "/user.ts",
|
||||
content: 'import { x } from "./old";',
|
||||
};
|
||||
|
||||
const host = createServerHost([userTs]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(userTs.path);
|
||||
const project = first(projectService.inferredProjects);
|
||||
|
||||
Debug.assert(!!project.resolveModuleNames);
|
||||
|
||||
const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatOptions);
|
||||
assert.deepEqual<ReadonlyArray<FileTextChanges>>(edits, [{
|
||||
fileName: "/user.ts",
|
||||
textChanges: [{
|
||||
span: textSpanFromSubstring(userTs.content, "./old"),
|
||||
newText: "./new",
|
||||
}],
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
function textSpanFromSubstring(str: string, substring: string): TextSpan {
|
||||
const start = str.indexOf(substring);
|
||||
Debug.assert(start !== -1);
|
||||
return createTextSpan(start, substring.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,6 +358,10 @@ namespace ts.server {
|
||||
return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames);
|
||||
}
|
||||
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations {
|
||||
return this.resolutionCache.getResolvedModuleWithFailedLookupLocationsFromCache(moduleName, containingFile);
|
||||
}
|
||||
|
||||
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
|
||||
return this.resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace ts {
|
||||
const pathUpdater = getPathUpdater(oldFilePath, newFilePath, host);
|
||||
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
|
||||
updateTsconfigFiles(program, changeTracker, oldFilePath, newFilePath);
|
||||
for (const { sourceFile, toUpdate } of getImportsToUpdate(program, oldFilePath)) {
|
||||
for (const { sourceFile, toUpdate } of getImportsToUpdate(program, oldFilePath, host)) {
|
||||
const newPath = pathUpdater(isRef(toUpdate) ? toUpdate.fileName : toUpdate.text);
|
||||
if (newPath !== undefined) {
|
||||
const range = isRef(toUpdate) ? toUpdate : createStringRange(toUpdate, sourceFile);
|
||||
@@ -30,7 +30,7 @@ namespace ts {
|
||||
return "fileName" in toUpdate;
|
||||
}
|
||||
|
||||
function getImportsToUpdate(program: Program, oldFilePath: string): ReadonlyArray<ToUpdate> {
|
||||
function getImportsToUpdate(program: Program, oldFilePath: string, host: LanguageServiceHost): ReadonlyArray<ToUpdate> {
|
||||
const checker = program.getTypeChecker();
|
||||
const result: ToUpdate[] = [];
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
@@ -44,7 +44,9 @@ namespace ts {
|
||||
// If it resolved to something already, ignore.
|
||||
if (checker.getSymbolAtLocation(importStringLiteral)) continue;
|
||||
|
||||
const resolved = program.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName);
|
||||
const resolved = host.resolveModuleNames
|
||||
? host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName)
|
||||
: program.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName);
|
||||
if (resolved && contains(resolved.failedLookupLocations, oldFilePath)) {
|
||||
result.push({ sourceFile, toUpdate: importStringLiteral });
|
||||
}
|
||||
|
||||
@@ -207,8 +207,11 @@ namespace ts {
|
||||
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
|
||||
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
|
||||
* host specific questions using 'getScriptSnapshot'.
|
||||
*
|
||||
* If this is implemented, `getResolvedModuleWithFailedLookupLocationsFromCache` should be too.
|
||||
*/
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
|
||||
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
||||
|
||||
@@ -4477,6 +4477,7 @@ declare namespace ts {
|
||||
fileExists?(path: string): boolean;
|
||||
getTypeRootsVersion?(): number;
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
|
||||
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getDirectories?(directoryName: string): string[];
|
||||
/**
|
||||
@@ -7864,6 +7865,7 @@ declare namespace ts.server {
|
||||
readFile(fileName: string): string | undefined;
|
||||
fileExists(file: string): boolean;
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModuleFull[];
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
|
||||
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
directoryExists(path: string): boolean;
|
||||
getDirectories(path: string): string[];
|
||||
|
||||
@@ -4477,6 +4477,7 @@ declare namespace ts {
|
||||
fileExists?(path: string): boolean;
|
||||
getTypeRootsVersion?(): number;
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations;
|
||||
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getDirectories?(directoryName: string): string[];
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user