forked from sveltejs/language-tools
/
UpdateImportsProvider.ts
65 lines (57 loc) · 2.75 KB
/
UpdateImportsProvider.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import {
OptionalVersionedTextDocumentIdentifier,
TextDocumentEdit,
TextEdit,
WorkspaceEdit
} from 'vscode-languageserver';
import { mapRangeToOriginal } from '../../../lib/documents';
import { urlToPath } from '../../../utils';
import { FileRename, UpdateImportsProvider } from '../../interfaces';
import { LSAndTSDocResolver } from '../LSAndTSDocResolver';
import { convertRange } from '../utils';
import { SnapshotFragmentMap } from './utils';
export class UpdateImportsProviderImpl implements UpdateImportsProvider {
constructor(private readonly lsAndTsDocResolver: LSAndTSDocResolver) {}
async updateImports(fileRename: FileRename): Promise<WorkspaceEdit | null> {
// TODO does this handle folder moves/renames correctly? old/new path isn't a file then
const oldPath = urlToPath(fileRename.oldUri);
const newPath = urlToPath(fileRename.newUri);
if (!oldPath || !newPath) {
return null;
}
const ls = await this.getLSForPath(newPath);
// `getEditsForFileRename` might take a while
const fileChanges = ls.getEditsForFileRename(oldPath, newPath, {}, {});
await this.lsAndTsDocResolver.updateSnapshotPath(oldPath, newPath);
const updateImportsChanges = fileChanges
// Assumption: Updating imports will not create new files, and to make sure just filter those out
// who - for whatever reason - might be new ones.
.filter((change) => !change.isNewFile || change.fileName === oldPath)
// The language service might want to do edits to the old path, not the new path -> rewire it.
// If there is a better solution for this, please file a PR :)
.map((change) => {
change.fileName = change.fileName.replace(oldPath, newPath);
return change;
});
const docs = new SnapshotFragmentMap(this.lsAndTsDocResolver);
const documentChanges = await Promise.all(
updateImportsChanges.map(async (change) => {
const fragment = await docs.retrieveFragment(change.fileName);
return TextDocumentEdit.create(
OptionalVersionedTextDocumentIdentifier.create(fragment.getURL(), null),
change.textChanges.map((edit) => {
const range = mapRangeToOriginal(
fragment,
convertRange(fragment, edit.span)
);
return TextEdit.replace(range, edit.newText);
})
);
})
);
return { documentChanges };
}
private async getLSForPath(path: string) {
return this.lsAndTsDocResolver.getLSForPath(path);
}
}