构建

当编写转换动作时你会时常需要构建一些节点然后把它们插入到 AST 中。 正如之前提到的,你可以使用 babel-types 模块里的 Builders(构建器) 方法。

建器的方法名称就是你想要构建的节点类型名称,只不过第一个字母是小写的。 比方说如果你要构建一个 MemberExpression 节点,你可以使用 t.memberExpression(...)

这些构建器的参数根据节点定义各有不同。比如 MemberExpression 节点

defineType("MemberExpression", {
  builder: ["object", "property", "computed"],
  visitor: ["object", "property"],
  aliases: ["Expression", "LVal"],
  fields: {
    object: {
      validate: assertNodeType("Expression")
    },
    property: {
      validate(node, key, val) {
        let expectedType = node.computed ? "Expression" : "Identifier";
        assertNodeType(expectedType)(node, key, val);
      }
    },
    computed: {
      default: false
    }
  }
});

你可以看到关于特定节点类型的所有信息,包括如何构建它,遍历它,以及验证它。

看一看 builder 属性,可以找到调用构建器方法时需要的 3 个参数:

builder: ["object", "property", "computed"],

可以通过 fields 对象查看构建器参数的验证条件。

fields: {
  object: {
    validate: assertNodeType("Expression")
  },
  property: {
    validate(node, key, val) {
      let expectedType = node.computed ? "Expression" : "Identifier";
      assertNodeType(expectedType)(node, key, val);
    }
  },
  computed: {
    default: false
  }
}

你可以看到 object 必须得是一个 Expression,property 要么得是一个 Expression 要么得是一个 Identifier,取决于其成员表达式是否是 computed,而 computed 是一个布尔值,缺省为 false。

于是我们可以这样来构造一个 MemberExpression

t.memberExpression(
  t.identifier("object"),
  t.identifier("property")
  // `computed` is optional
);

得到结果为:

object.property

可是我们说了 object 必须得是一个 Expression 那么为什么 Identifier 是合法的呢?

如果我们看一下 Identifier 的定义就知道它有一个 aliases 属性,声明了它也可以是一个表达式。

aliases: ["Expression", "LVal"],

所以由于 MemberExpression 是一个 Expression 类型,我们可以把它设置为另一个 MemberExpressionobject

t.memberExpression(
  t.memberExpression(t.identifier("member"), t.identifier("expression")),
  t.identifier("property")
);

得到结果为:

member.expression.property

你不太可能把每种节点类型的构建器方法签名都背下来,所以最好花些时间来理解它们是如何通过节点定义生成出来的。

你可以在这里找到所有的定义,也可以在这里查看它们的文档。

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress