是否可以执行排除某些节点类型的 Babel "scope rename"?

Is it possible to do a Babel "scope rename" excluding certain node types?

我正在开发一个重新绑定(使用 bind)一些导入的 Babel 插件,这意味着我需要创建一个新变量来指向新绑定,因为导入是只读的。在那之后,我想做一个 nodePath.scope.rename 从原始导入名称到新的“被劫持”变量。这工作正常,但问题是原始导入也被重命名,因为它们在全局范围内。

有没有办法在排除 ImportDeclaration 类型的节点的同时执行 nodePath.scope.rename

获取绑定解决方案

我们不能重命名全局范围内的所有内容,而只能重命名绑定,它通过将范围限定到其父对象来排除原始节点:

const binding = matchingNodePath.scope.getBinding(currentName);

binding.referencePaths.forEach((referencePath) => {
  referencePath.scope.rename(
    currentName,
    hijackedNamespace,
    referencePath.parent
  );
});

节点替换方案

我在执行 scope.rename 时找不到任何方法来排除导入声明。所以我最后做的是先克隆节点:

// Get all import declarations.
const importDeclarationNodePaths = (nodePath.get('body') as NodePath[]).filter((node) =>
  node.isImportDeclaration()
) as NodePath<ImportDeclaration>[];

// Make a copy of the node so we can restore it later after we rename all matching variables.
const originalImportDeclarationNodes = importDeclarationNodePaths.map((nodePath) => {
  return cloneNode(nodePath.node, true);
}) as ImportDeclaration[];

然后我们可以重命名并恢复原来的说明符

nodePath.scope.rename('originalName', 'newName');

// Because of the global scope rename, we need to set back original import declarations.
for (const importPosition in importDeclarationNodePaths) {
  const hijackedImportDeclarationNodePath = importDeclarationNodePaths[importPosition];
  const originalImportDeclarationNode = originalImportDeclarationNodes[importPosition];

  // Replace the specifiers of the hijacked import declaration with its original value.
  hijackedImportDeclarationNodePath.replaceWith(
    importDeclaration(
      originalImportDeclarationNode.specifiers,
      hijackedImportDeclarationNodePath.node.source
    )
  );
}