假设我要使用自定义Babel插件转换以下代码:
let c;
c = document;
console.log(c.readyState);
目标是用自定义函数(例如)替换所有出现的document.readyState
。 window.getDocumentReadyState()
。
因此输出应如下所示:
let c;
c = document;
console.log(window.getDocumentReadyState());
这里的困难在于确定对象c
在调用MemberExpression
时实际上具有哪个值,因为我只想用document
替换MemberExpressions。这就是为什么我需要找出c
的当前值为document
。
这是一个仅替换每个<obj>.readyState
MemberExpression的实现:
/**
* Replace document.readyState with
* window.getDocumentReadyState();
*/
MemberExpression(path) {
const { node, parent } = path;
const objName = node.object.name;
const propName = node.property.name;
if (t.isAssignmentExpression(parent)) {
return;
}
if (t.isCallExpression(parent)) {
const isCallee = parent.callee === node;
if (isCallee) return;
}
if (propName === 'readyState') {
const customReadyStateFn = t.callExpression(
t.memberExpression(
t.identifier('window'),
t.identifier('getDocumentReadyState'),
),
[t.identifier(objName)],
);
path.replaceWith(customReadyStateFn);
}
},
使用该实现,我执行运行时检查以确定对象document (HTMLDocument)
中是否为window.getDocumentReadyState
类型,因为我无法使用Babel进行相同的操作。
但是必须有一种方法可以通过静态分析可靠地判断此变量的值是否为document
,对吗?
基本上,我需要在当前作用域中找到此变量的最后一个AssignmentExpression。
我已经尝试使用path.scope.getBinding(<variableName>)
在范围中查找变量,但是问题是最后一个AssignmentExpression没有显示在binding.references
中。如果在声明(let c = document
期间分配了该值,那将没有问题,因为可以使用binding
来访问该引用。
我也尝试遍历该范围,但是没有调用AssignmentExpression访问者。
我对Babel和AST还是很陌生,到了一个我不知道下一步要做什么的地步,我真的想摆脱运行时检查。
您将如何解决这样的问题?