【问题标题】:Can I prevent Babel from traversing code inserted by a plugin?我可以阻止 Babel 遍历插件插入的代码吗?
【发布时间】:2016-10-10 15:41:59
【问题描述】:

我正在构建一个插件,通过调用path.insertBefore 在每个现有函数调用前面插入enterFunction()。所以我的代码是从:

myFunction();

收件人:

enterFunction();
myFunction();

问题是当我插入节点时,Babel 再次遍历插入的节点。这是日志输出:

'CallExpression','myFunction'
'CallExpression', 'enterFunction'

如何防止 Babel 进入 enterFunction 调用表达式及其子代?

这是我目前用于 Babel 插件的代码:

function(babel) {
    return {
        visitor: {
            CallExpression: function(path) {
                console.log("CallExpression", path.node.callee.name)
                if (path.node.ignore) {
                    return;
                }
                path.node.ignore = true

                var enterCall = babel.types.callExpression(
                    babel.types.identifier("enterFunction"), []
                )
                enterCall.ignore = true;
                path.insertBefore(enterCall)
            }
        }
    }
}

【问题讨论】:

  • 某处,需要存储待遍历路径的信息。问题只是如何。关门怎么办? f = function () { var x = 0; return function () { if (x > 0) return; do_meaningful_things(); x++ } };
  • @meisterluk 我想知道的是,我怎样才能将它传达给 Babel? insertBefore 正在触发新的遍历。
  • 对不起,我应该在评论之前更好地理解您的示例代码。现在,我能找到的最佳答案是 github.com/babel/babel/issues/4956 也许 path.skip() 有效? astexplorer.net/#/efhJqnJv5a/1
  • @meisterluk 是的,skip() 和 skipKeys 正是我想要的!您可以将其发布为答案吗?
  • 完成 - 很高兴能提供任何帮助

标签: babeljs


【解决方案1】:

Babel Handbook 提到以下部分:

如果你的插件需要在某种情况下不运行,最简单的事情就是写一个提前返回。

BinaryExpression(path) {
  if (path.node.operator !== '**') return;
}

如果您在顶级路径中进行子遍历,您可以使用提供的 2 种 API 方法:

path.skip() 跳过遍历当前路径的孩子。 path.stop() 完全停止遍历。

outerPath.traverse({
  Function(innerPath) {
    innerPath.skip(); // if checking the children is irrelevant
  },
  ReferencedIdentifier(innerPath, state) {
    state.iife = true;
    innerPath.stop(); // if you want to save some state and then stop traversal, or deopt
  }
});

简而言之,使用path.skip() 跳过遍历当前路径的孩子。 this snippet using Visitors, CallExpression and skip() 中说明了这种方法的一个应用:

export default function (babel) {
  const { types: t } = babel;

  return {
    name: "ast-transform", // not required
    visitor: {
      CallExpression(path) {
        path.replaceWith(t.blockStatement([
          t.expressionStatement(t.yieldExpression(path.node))
        ]));
        path.skip();
      }
    }
  };
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 2017-11-02
    • 2021-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多