构建节点

编写转换时,通常需要构建一些要插入的节点进入AST。 如前所述,您可以使用 babel-types 包中的 builder 方法。

构建器的方法名称就是您想要的节点类型的名称,除了第一个字母小写。 例如,如果您想建立一个 MemberExpression 您可以使用 t.memberExpression(…)

这些构建器的参数由节点定义决定。 有一些正在做的工作,以生成易于阅读的文件定义,但现在他们都可以在此处找到。.

节点定义如下所示:

  1. defineType("MemberExpression", {
  2. builder: ["object", "property", "computed"],
  3. visitor: ["object", "property"],
  4. aliases: ["Expression", "LVal"],
  5. fields: {
  6. object: {
  7. validate: assertNodeType("Expression")
  8. },
  9. property: {
  10. validate(node, key, val) {
  11. let expectedType = node.computed ? "Expression" : "Identifier";
  12. assertNodeType(expectedType)(node, key, val);
  13. }
  14. },
  15. computed: {
  16. default: false
  17. }
  18. }
  19. });
  20.  

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

通过查看 生成器 属性, 可以看到调用生成器方法所需的3个参数 (t. 情况).

  1. 生成器: ["object", "property", "computed"],

请注意,有时在节点上可以定制的属性比``构建器</>数组包含的属性更多。 这是为了防止生成器有太多的参数。 在这些情况下,您需要手动设置属性。 一个例子是 ClassMethod </>.


  1. // Example
  2. // because the builder doesn't contain `async` as a property
  3. var node = t.classMethod(
  4. "constructor",
  5. t.identifier("constructor"),
  6. params,
  7. body
  8. )
  9. // set it manually after creation
  10. node.async = true;

You can see the validation for the builder arguments with the fields object.

  1. fields: {
  2. object: {
  3. validate: assertNodeType("Expression")
  4. },
  5. property: {
  6. validate(node, key, val) {
  7. let expectedType = node.computed ? "Expression" : "Identifier";
  8. assertNodeType(expectedType)(node, key, val);
  9. }
  10. },
  11. computed: {
  12. default: false
  13. }
  14. }

You can see that object needs to be an Expression, property either needs to be an Expression or an Identifier depending on if the member expression is computed or not and computed is simply a boolean that defaults to false.

So we can construct a MemberExpression by doing the following:

  1. t.memberExpression(
  2. t.identifier('object'),
  3. t.identifier('property')
  4. // `computed` is optional
  5. );

Which will result in:

  1. object.property

However, we said that object needed to be an Expression so why is Identifier valid?

Well if we look at the definition of Identifier we can see that it has an aliases property which states that it is also an expression.

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

So since MemberExpression is a type of Expression, we could set it as the object of another MemberExpression:

  1. t.memberExpression(
  2. t.memberExpression(
  3. t.identifier('member'),
  4. t.identifier('expression')
  5. ),
  6. t.identifier('property')
  7. )

Which will result in:

  1. member.expression.property

It’s very unlikely that you will ever memorize the builder method signatures for every node type. So you should take some time and understand how they are generated from the node definitions.

You can find all of the actual definitions here and you can see them documented here