Как мне пройти путь Path в плагине Babel
Я пытаюсь написать простой плагин 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!');
}
}
});
}
}
}
});
Мой подход ошибочен или мне нужно что-то сделать иначе, чем с точки зрения кода?
3 ответа
Я знаю, что это очень старый вопрос, но этот ответ может быть полезен тем, кто прибыл сюда через Google. Вы можете использовать траверс внутри другого траверса, используя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)
}
}
})
Я не могу найти много документации по path.scope.traverse
,
Прошло почти 2 года, но я надеюсь, что это решит вашу проблему.
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))
}
}
}
});
Пройдите через
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)
}
}