简体   繁体   中英

How do I traverse the scope of a Path in a babel plugin

I'm trying to write a simple babel plugin, but I am having a hard time traversing a matched node with a nested visitor. I would like to find all require calls in a module that require a certain module and then apply some transformation in the same scope.

To illustrate this with a contrived example I'd like to transform source code like:

const f = require('foo-bar');
const result = f() * 2;

into something like:

const result = 99 * 2; // as i "know" that calling f will always return 99

I was trying to do the following:

module.exports = ({ types: t }) => ({
    visitor: {
        CallExpression(path) {
            if (path.node.callee.name === 'require'
                && path.node.arguments.length === 1
                && t.isStringLiteral(p.node.arguments[0])
                && path.node.arguments[0].value === 'foo-bar'
            ) {
                const localIdentifier = path.parent.id.name;
                // if i print here it will show me that it successfully
                // found all require calls
                p.scope.traverse({
                    Identifier(subp) {
                        // this will never run at all
                        if (subp.name === localIdentifier) {
                            console.log('MATCH!');
                        }
                    }
                });
            }
        }
    }
});

Is my approach flawed or is there something I need to do differently from a code perspective?

I know that this question is very old, but this answer could be useful for someone that arrived here by Google. You could use a traverse inside of another traverse using node.scope.traverse , for example, if you want to change each CallExpression only if inside at the body of try :

module.exports = ({ types: t }) => ({
  visitor: {
    TryStatement(path) {
      const { scope, node } = path

      const traversalHandler = {
        CallExpression(path) {
          path.replaceWith(t.Identifier('foo'))
        }
      }

      scope.traverse(node, traversalHandler, this)
    }
  }
})

I cant seem to find much documentation on path.scope.traverse .

It has been almost 2 years, but I hope this solves your problem.

module.exports = ({ types: t }) => ({
    visitor: {
        CallExpression(path) {
            if (path.node.callee.name === 'require'
                && path.node.arguments.length === 1
                && t.isStringLiteral(path.node.arguments[0])
                && path.node.arguments[0].value === 'foo-bar'
            ) {
                this.localIdentifier = path.parent.id.name;
            }
            if(path.node.callee.name === this.localIdentifier){
                path.replaceWith(t.NumericLiteral(99))
            }
        }
    }
});

Traverse the parent scope , search for node:

function inScope(scope, nodeName) {
  if (!scope || !scope.bindings) return false

  let ret = false
  let cur = scope
  while (cur) {
    ret = cur.bindings[nodeName]
    if (cur === scope.parent || ret) {
      break
    }
    cur = scope.parent
  }

  return ret
}


// your visitor.js
  return {
    visitor: {
      CallExpression(path) {
        inScope(path.scope, path.node.name)
      }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM