我正在尝试编写一个简单的babel插件,但是我很难通过嵌套访问者遍历匹配的节点。我想在一个需要某个模块的模块中找到所有require
个调用,然后在同一个范围内应用一些转换。
为了用一个人为的例子说明这一点,我想改变源代码,如:
const f = require('foo-bar');
const result = f() * 2;
成像:
const result = 99 * 2; // as i "know" that calling f will always return 99
我试图做以下事情:
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!');
}
}
});
}
}
}
});
我的方法是否存在缺陷,或者从代码的角度来看,我需要做些什么?
答案 0 :(得分:1)
我知道这个问题很老,但是这个答案对Google到这里来的人可能有用。
例如,如果您只想在node.scope.traverse
的主体内部进行更改,则可以使用CallExpression
在另一个导线的内部使用导线。
try
答案 1 :(得分: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))
}
}
}
});
答案 2 :(得分:0)
parent scope
,搜索节点: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)
}
}