ast-types
ast-types copied to clipboard
Implement Scope.prototype.rename(oldName, newName)
@OliverJAsh asked on https://gitter.im/benjamn/recast if it was possible to determine what declaration(s) were responsible for a given variable reference.
Here's the code I came up with at first:
types.visit(ast, {
visitIdentifier(path) {
var node = path.node;
if (node.name === "x") {
var xScope = path.scope.lookup("x");
if (xScope) {
// Iterate over all the Identifiers used to declare x and rename them to y.
// TODO Might need to be careful not to do this more than once?
xScope.getBindings().x.forEach(function (idPath) {
idPath.node.name = "y";
});
node.name = "y"; // Rename the identifier too!
}
}
this.traverse(path);
}
});
As I was writing it out, I realized the common case (renaming) could be accomplished with a much nicer API:
types.visit(ast, {
visitIdentifier(path) {
var node = path.node;
if (node.name === "x") {
var xScope = path.scope.lookup("x");
if (xScope) {
xScope.rename("x", "y");
}
}
this.traverse(path);
}
});
Open question: what should Scope.prototype.rename
return? Perhaps a list of paths to references, since scanning for references in nested scopes is potentially expensive?
FWIW, this is the implementation I use in jscodeshift: https://github.com/facebook/jscodeshift/blob/v0.3.8/src/collections/VariableDeclarator.js#L74-L102
Just for clarity, this is the problem I'm trying to solve. I have an object, foo
, which has renamed its method from a
to b
. I want to update all my usages:
var x = foo.a;
/*
Result:
var x = foo.b;
*/
I search for member expressions whereby the object matches foo
and update the property (from a
to b
). However, foo
may also be referenced elsewhere, in which case I need to update the properties for those usages, too. That's the part I'm struggling to do:
var ref = foo;
ref.a;
/*
Desired result:
var ref = foo;
ref.b;
*/
This year is 2021, Not support scope rename?
pr has been submitted.
https://github.com/benjamn/ast-types/pull/607
Add rename function into scope, like Babel function path.scope.rename(oldName, newName)