-
Notifications
You must be signed in to change notification settings - Fork 189
/
RenameableNode.ts
66 lines (57 loc) · 2.86 KB
/
RenameableNode.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
66
import { errors, KeyValueCache, ts } from "@ts-morph/common";
import { Constructor } from "../../../../types";
import { TypeGuards } from "../../../../utils";
import { Node } from "../../common";
import { RenameOptions, RenameLocation } from "../../../tools";
import { replaceSourceFileTextForRename } from "../../../../manipulation";
import { SourceFile } from "../../module";
export type RenameableNodeExtensionType = Node<ts.Node>;
export interface RenameableNode {
/**
* Renames the name of the node.
* @param newName - New name.
* @param options - Options for renaming.
*/
rename(newName: string, options?: RenameOptions): this;
}
export function RenameableNode<T extends Constructor<RenameableNodeExtensionType>>(Base: T): Constructor<RenameableNode> & T {
return class extends Base implements RenameableNode {
rename(newName: string, options?: RenameOptions) {
const languageService = this._context.languageService;
renameNode(getNodeToRename(this));
return this;
function getNodeToRename(thisNode: Node) {
if (TypeGuards.isIdentifier(thisNode))
return thisNode;
else if ((thisNode as any).getNameNode != null) {
const node = (thisNode as any).getNameNode() as Node;
errors.throwIfNullOrUndefined(node, "Expected to find a name node when renaming.");
if (TypeGuards.isArrayBindingPattern(node) || TypeGuards.isObjectBindingPattern(node))
throw new errors.NotImplementedError(`Not implemented renameable scenario for ${node.getKindName()}.`);
return node;
}
else {
throw new errors.NotImplementedError(`Not implemented renameable scenario for ${thisNode.getKindName()}`);
}
}
function renameNode(node: Node) {
errors.throwIfWhitespaceOrNotString(newName, nameof(newName));
if (node.getText() === newName)
return;
const renameLocations = languageService.findRenameLocations(node, options);
const renameLocationsBySourceFile = new KeyValueCache<SourceFile, RenameLocation[]>();
for (const renameLocation of renameLocations) {
const locations = renameLocationsBySourceFile.getOrCreate<RenameLocation[]>(renameLocation.getSourceFile(), () => []);
locations.push(renameLocation);
}
for (const [sourceFile, locations] of renameLocationsBySourceFile.getEntries()) {
replaceSourceFileTextForRename({
sourceFile,
renameLocations: locations,
newName
});
}
}
}
};
}