Skip to content Skip to sidebar Skip to footer

Js: Rename Variables For Refactor (using An Ast, Not Text)

I often need to rename variables when refactoring code, which I currently do in a somewhat hacky way using regexs - I end up having to come with silly text workaround workarounds f

Solution 1:

1. grasp.js

It looks like http://graspjs.com/ does exactly this.

grasp selector --replace replacement file.js

For example, to rename 'el' to 'element':

grasp '#el' --replace 'element' index.js

Official grasp.replace docs.

2. vscode

Visual Studio Code also includes a real replacement tool. Just right click a token and choose rename symbol.

enter image description here

Solution 2:

I know you've been asking for 'a tool'; but I think it's better to use just esprima itself and the various general purpose tools on top of esprima, and roll your own renamer. Because it's really really easy, and then you have more control. Here is a complete example in just 12 lines of code. It uses escodegen and estraverse, both on github, and, as far as I can see kind of 'the standard' to use in conjunction with esprima. While esprima essentially gives the parse function string -> abstract syntax tree, escodegen essentially gives the reverse of that, i.e. abstract syntax tree -> string. And estraverse 'walks the tree' with the traverse method, thus helping to analyze or modify it.

Here the code:

functionrename(code, renamingObj){
    var ast = esprima.parse(code);
    functioncallback(node){
        if (node.type==='Identifier') {
            if (node.namein renamingObj){
                node.name = renamingObj[node.name];
            }
        }
    }
    estraverse.traverse(ast, { enter: callback });
    return escodegen.generate(ast);
}

Testcase:

functionblah(x,y){
    var difference = x + y;
    var product    = x - y;
    var sum        = x * y;
    return42;
}
var renamingObj = {
    sum        : 'product',
    difference : 'sum',
    product    : 'difference'
};

run it:

rename(blah.toString(), renamingObj)

output:

functionblah(x, y) {
    var sum = x + y;
    var difference = x - y;
    var product = x * y;
    return42;
}

I would say, if you have something special to do, it's easier to modify above code than sifting through some tool documentation.

Solution 3:

Our JavaScript Formatter/Obfuscator will do this reliably. It parses JavaScript, builds an AST, and either prints a pretty version, or an ugly (obfuscated) version. [The reason these are together is because pretty and ugly are opposite sides of the same coin!).

One of the things it does is scramble (whole) identifier names. By using the AST, it only renames "whole identifiers"; it won't confuse "req" with "require", or modify string or comment content by accident.

You can tell it to build a map of all identifier names, and then rename them all to themselves; change just one, and you get your rename effect. The identifier map looks like this:

    x ->  y
    p -> q
    ...

directing that x gets renamed to y, p to q, etc. You want:

    x -> x
    p -> q
    ...

to change just p to q. Its pretty easy to produce the identity map as your starting place.

I wouldn't say this is convenient, but it does work. It obviously doesn't know anything about scopes. (someday!).

See my bio for details. Many SO moderators hate tool questions, and they especially seem to dislike it when I provide a tool answer that includes a link to the tool. So you'll have to track down the link yourself, sorry. (Complain on Meta if you think this is dumb).

Post a Comment for "Js: Rename Variables For Refactor (using An Ast, Not Text)"