如何在 babel 插件中遍历 Path 的范围

m90*_*m90 5 javascript babeljs babel-plugin

我正在尝试编写一个简单的 babel 插件,但是我很难用嵌套访问者遍历匹配的节点。我想require在需要某个模块的模块中找到所有调用,然后在同一范围内应用一些转换。

为了用一个人为的例子来说明这一点,我想转换源代码,如:

const f = require('foo-bar');
const result = f() * 2;
Run Code Online (Sandbox Code Playgroud)

变成类似的东西:

const result = 99 * 2; // as i "know" that calling f will always return 99
Run Code Online (Sandbox Code Playgroud)

我试图做到以下几点:

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!');
                        }
                    }
                });
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

我的方法是否有缺陷,或者我需要从代码角度做一些不同的事情?

Mac*_*eus 8

我知道这个问题很老了,但是这个答案对于通过谷歌到达这里的人来说可能很有用。您可以在另一个遍历中使用一个遍历node.scope.traverse,例如,如果您CallExpression只想在 的主体内部更改每个遍历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)
    }
  }
})
Run Code Online (Sandbox Code Playgroud)


Sou*_*nda 0

我似乎找不到太多关于path.scope.traverse.

已经快两年了,但我希望这能解决你的问题。

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))
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)