benjamn / ast-types

Esprima-compatible implementation of the Mozilla JS Parser API

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Implement Scope.prototype.rename(oldName, newName)

benjamn opened this issue · comments

@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?

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.

#607

Add rename function into scope, like Babel function path.scope.rename(oldName, newName)