Babel unshiftcontainer 不创建元素

Babel unshiftcontainer not creating an element

玩转 babel 转换,我写了这个片段来在我的 path

之后插入一个 VariableDeclaration
export default function (babel) {
  const { types: t } = babel;

  return {
    name: "ast-transform", // not required
    visitor: {
      VariableDeclaration (path) {
        if (path.node.kind !== 'var') {
          return;
        }

        const _id = t.Identifier('qwe');
        const _init = t.numericLiteral(42);

        console.log(_id, _init);

        const _node = t.variableDeclaration('var', [
          t.variableDeclarator(
            t.identifier("uid"),
            t.numericLiteral(42)
          )
        ]);

        path
          .unshiftContainer(
            'body',
            _node
          )

      }
    }
  };
}

得到如下错误,

unknown: Cannot read property 'body' of undefined

编辑:

如果我执行以下操作而不是 unshiftContainer 它会起作用,

const _program = path.findParent(p => p.isProgram());
_program.node.body.unshift(_node);

为什么 unshiftContainer 不起作用?

Link 要点 ast-explorer

为了使用 unshiftContainer("body"),您必须有一个带有 "body" 的节点。例如,ProgramFunctionDeclaration (1, 2, 3)

但是您试图在 VariableDeclaration 上执行此操作,而 VariableDeclaration 没有 body,正如您在 ast-explorer.

中看到的那样

当您调用 path.get("body") 时,它会 returns {..., node: undefined, ...} 然后,当您调用 unshiftContainer("body") 时,它会尝试获取 "body" of [=24] =], 即 undefined: container: this.node[listKey],.

您的解决方案有效,因为您找到了 Program 对象,它有主体。 所以,如果你想使用 unshiftContainer:

const _program = path.findParent(p => p.isProgram());
_program.unshiftContainer("body", _node);

此外,您可以这样做:

const parentWithBody = path.findParent(
  (p) => p.node !== undefined && p.node.body !== undefined
);
parentWithBody.unshiftContainer("body", _node);

它不仅会检测Program,还会检测FunctionDeclaration:

来源:

var x = 10;
var y = 5;

function test() {
  var z = 1;
}

输出:

var uid = 42;
var uid = 42;
var x = 10;
var y = 5;

function test() {
  var uid = 42;
  var z = 1;
}

更新关于无限循环,

确实,当您取消移动容器时,您正在添加新的 VariableDeclaration,因此它将进入无限循环:

  1. 参见 var x = 10 -> 添加 var uid = 42
  2. 参见 var uid = 42 -> 添加 var uid = 42
  3. 等等...

为了打破这个循环,添加这个条件,检查 node.kind 是否为 var:

if (path.node.declarations[0].init.value === 42 && path.node.declarations[0].id.name === "uid") {
  return;
}

(gist)