One of the common refactoring activities is variable renaming. Many respectable IDEs have such a language-aware renaming feature. In some other cases, this is carried out via a simple search and replace. Manual search replace is error-prone and hence why a syntactically-correct rename refactoring tool can be useful.
We have seen how identifier highlighting is implemented in a simple Orion-based code editor. Renaming is the obvious next step, instead of just highlighting now we need to monitor any possible change to the code and appropriately rename the other identical references as well. For this purpose, there is a live rename refactoring demo you can try yourself at esprima.org/demo/rename.html.
Assume we have the following function. It is extremely simple, the function returns true if the specified character is a hexadecimal digit.
Later on, somebody decides that the name of the function parameter needs to change. All he needs to do is to place the cursor on any occurrence of that parameter (note the yellow highlight in two places) and start typing in the new name. Voila! Now both references get the new name. This renaming also works for normal declared variable as well as function name.
Because this demo uses escope (GitHub: github.com/Constellation/escope) from Yusuke Suzuki, the scope analysis follows the ECMAScript 5.1 specification faithfully. If there are other variables with the same name, if they are out of scope, those won’t be touched and got renamed. This is something that a blind search and replace will not recognize.
In a real-world application, functions are very likely more than just one-liner. Doing a renaming via an automated tool will save a lot of time, no need to hunt every single reference and to ensure that the scope is correct. The latter is practically quite tedious, especially for a deeply nested code polluted with some callbacks.
Be advised that JavaScript is a flexible and dynamic language. Because of that, automagic application-wide renaming is often not always possible, in particular because resolving of an identifier can’t be correctly carried out until the code is executed. Many strategies have been developed to mitigate the issues, from a comprehensive type analysis to a convention-based approach. This will push the renaming refactoring further to the best-effort level.
For programmatic renaming (perhaps you want to replace all obj
into the more descriptive object
or something more logical than that), you can use a convenient microlibrary called esrefactor (GitHub: github.com/ariya/esrefactor). This library internally uses escope to analyze the scope after the syntax tree is obtained via Esprima. For Node.js users, there is the new esrefactor package ready to use.
Once it is set up, the real renaming action is usually just taking just a few lines of code:
var ctx = new esrefactor.Context('var x; x = 42');
var id = ctx.identify(4);
var code = ctx.rename(id, 'answer');
In the above code fragment, we first locate the identifier (in this case, it is a variable) at the index position of 4 (right before x
in var x
). After that, we use the rename()
function to have it renamed to the new name. Predictably, what you get from code
is var answer; answer = 42
.
Next time you plan a semi-automatic renaming refactoring to your code, you know what to do!