You must pass a scope and parentPath
2024-12-03
webpack
58
背景
最近在利用 babel 分析代码过程中,遇到一个编译错误
throw new Error("You must pass a scope and parentPath unless traversing a Program/File. " + `Instead of that you tried to traverse a ${parent.type} node without ` + "passing scope and parentPath.");
^
Error: You must pass a scope and parentPath unless traversing a Program/File. Instead of that you tried to traverse a ExpressionStatement node without passing scope and parentPath.
核心还是这一句
You must pass a scope and parentPath unless traversing a Program/File
当时的代码
const babel = require("@babel/core");
const traverse = require("@babel/traverse").default;
const ast = babel.parseSync(code);
// 使用 traverse 正确遍历 AST
traverse(ast, {
// 遍历 BlockStatement
BlockStatement(path) {
createNewBlock(path)
}
});
function createNewBlock(astPath) {
const blockStr = astPath.node.body.reduce((pre, cur) => {
// 内部继续遍历
traverse(cur, {
enter(innerPath) {
...
}
})
return pre
}, '')
解决方案
traverse 不能直接遍历 子节点的path,需要加一个 scope
这里第二个 traverse
使用不对,需要设置在一个 scope 里调用
改为 astPath.scope.traverse
const blockStr = astPath.node.body.reduce((pre, cur) => {
// 内部继续遍历
astPath.scope.traverse(cur, {
enter(innerPath) {
...
}
})
原理
看了一下 traverse的源码
function traverse<Options extends TraverseOptions>(
parent: t.Node,
// @ts-expect-error provide {} as default value for Options
opts: Options = {},
scope?: Scope,
state?: any,
parentPath?: NodePath,
visitSelf?: boolean,
) {
if (!parent) return;
if (!opts.noScope && !scope) {
if (parent.type !== "Program" && parent.type !== "File") {
throw new Error(
"You must pass a scope and parentPath unless traversing a Program/File. " +
`Instead of that you tried to traverse a ${parent.type} node without ` +
"passing scope and parentPath.",
);
}
}
看起来需要把配置设置为 noScope 或者 加一个 scope 参数
所以问题也可以改为
// 方案一
traverse(cur, {
noScope: true
enter(innerPath) {
...
}
})
// 方案二
traverse(cur, {
enter(innerPath) {
...
}
}, astPath.scope)
至于 为什么非要这个scope,以后在学习深究
原文地址:https://webfem.com/post/babel-scope-fix,转载请注明出处