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,转载请注明出处