|
| 1 | +/* @internal */ |
| 2 | +namespace ts { |
| 3 | + export function getEditsForFileRename(program: Program, oldFilePath: string, newFilePath: string, host: LanguageServiceHost, formatContext: formatting.FormatContext): ReadonlyArray<FileTextChanges> { |
| 4 | + const pathUpdater = getPathUpdater(oldFilePath, newFilePath, host); |
| 5 | + return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => { |
| 6 | + for (const { sourceFile, toUpdate } of getImportsToUpdate(program, oldFilePath)) { |
| 7 | + const newPath = pathUpdater(isRef(toUpdate) ? toUpdate.fileName : toUpdate.text); |
| 8 | + if (newPath !== undefined) { |
| 9 | + const range = isRef(toUpdate) ? toUpdate : createTextRange(toUpdate.getStart(sourceFile) + 1, toUpdate.end - 1); |
| 10 | + changeTracker.replaceRangeWithText(sourceFile, range, isRef(toUpdate) ? newPath : removeFileExtension(newPath)); |
| 11 | + } |
| 12 | + } |
| 13 | + }); |
| 14 | + } |
| 15 | + |
| 16 | + interface ToUpdate { |
| 17 | + readonly sourceFile: SourceFile; |
| 18 | + readonly toUpdate: StringLiteralLike | FileReference; |
| 19 | + } |
| 20 | + function isRef(toUpdate: StringLiteralLike | FileReference): toUpdate is FileReference { |
| 21 | + return "fileName" in toUpdate; |
| 22 | + } |
| 23 | + |
| 24 | + function getImportsToUpdate(program: Program, oldFilePath: string): ReadonlyArray<ToUpdate> { |
| 25 | + const checker = program.getTypeChecker(); |
| 26 | + const result: ToUpdate[] = []; |
| 27 | + for (const sourceFile of program.getSourceFiles()) { |
| 28 | + for (const ref of sourceFile.referencedFiles) { |
| 29 | + if (!program.getSourceFileFromReference(sourceFile, ref) && resolveTripleslashReference(ref.fileName, sourceFile.fileName) === oldFilePath) { |
| 30 | + result.push({ sourceFile, toUpdate: ref }); |
| 31 | + } |
| 32 | + } |
| 33 | + |
| 34 | + for (const importStringLiteral of sourceFile.imports) { |
| 35 | + // If it resolved to something already, ignore. |
| 36 | + if (checker.getSymbolAtLocation(importStringLiteral)) continue; |
| 37 | + |
| 38 | + const resolved = program.getResolvedModuleWithFailedLookupLocationsFromCache(importStringLiteral.text, sourceFile.fileName); |
| 39 | + if (contains(resolved.failedLookupLocations, oldFilePath)) { |
| 40 | + result.push({ sourceFile, toUpdate: importStringLiteral }); |
| 41 | + } |
| 42 | + } |
| 43 | + } |
| 44 | + return result; |
| 45 | + } |
| 46 | + |
| 47 | + function getPathUpdater(oldFilePath: string, newFilePath: string, host: LanguageServiceHost): (oldPath: string) => string | undefined { |
| 48 | + // Get the relative path from old to new location, and append it on to the end of imports and normalize. |
| 49 | + const rel = getRelativePath(newFilePath, getDirectoryPath(oldFilePath), createGetCanonicalFileName(hostUsesCaseSensitiveFileNames(host))); |
| 50 | + return oldPath => { |
| 51 | + if (!pathIsRelative(oldPath)) return; |
| 52 | + return ensurePathIsRelative(normalizePath(combinePaths(getDirectoryPath(oldPath), rel))); |
| 53 | + }; |
| 54 | + } |
| 55 | +} |
0 commit comments