Plugins - Scope

How to use scoping and track variables

Checking if a local variable is bound

export default function ({ Plugin, types: t }) {
  return new Plugin("foo-bar", {
    visitor: {
      FunctionDeclaration(node, parent, scope) {
        scope.hasBinding("name");
      }
    }
  });
}

This will walk up the scope tree and check for that particular binding.

You can also check if a scope has it's own binding:

export default function ({ Plugin, types: t }) {
  return new Plugin("foo-bar", {
    visitor: {
      FunctionDeclaration(node, parent, scope) {
        scope.hasOwnBinding("name");
      }
    }
  });
}

Generating a UID

export default function ({ Plugin, types: t }) {
  return new Plugin("foo-bar", {
    visitor: {
      FunctionDeclaration(node, parent, scope) {
        scope.generateUidIdentifier("foo");
      }
    }
  });
}

This will generate an identifier that doesn't collide with any locally defined variables.

Pushing a variable declaration to a parent scope

Sometimes you may want to push a VariableDeclaration so you can assign to it inside of an expression.

For example the following transformer:

export default function ({ Plugin, types: t }) {
  return new Plugin("foo-bar", {
    visitor: {
      CallExpression(node, parent, scope) {
        var id = scope.generateUidIdentifierBasedOnNode(node);
        scope.push({ id });
        return t.assignmentExpression("=", id, node);
      }
    }
  });
}

Will transform:

function foo() {
  bar();
}

into:

function foo() {
  var _bar;
  _bar = bar();
}

Rename a binding and it's references

export default function ({ Plugin, types: t }) {
  return new Plugin("foo-bar", {
    visitor: {
      Program(node, parent, scope) {
        // no second argument passed so this will generate a uid based on `foo`
        scope.rename("foo");

        // rename bar to foobar
        scope.rename("bar", "foobar");
      }
    }
  });
}

Will transform:

function bar() {
  return "foo!";
}

function foo() {
  bar();
}

foo();

into:

function foobar() {
  return "foo!";
}

function _foo() {
  foobar();
}

_foo();