构建节点
编写转换时,通常需要构建一些要插入的节点进入AST。 如前所述,您可以使用 babel-types 包中的 builder 方法。
构建器的方法名称就是您想要的节点类型的名称,除了第一个字母小写。 例如,如果您想建立一个MemberExpression
您可以使用t.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
}
}
});
在这里你可以看到关于这个特定节点类型的所有信息,包括如何构建它,遍历它,并验证它。
通过查看 生成器
属性, 可以看到调用生成器方法所需的3个参数 (t. 情况
).
生成器: ["object", "property", "computed"],
请注意,有时在节点上可以定制的属性比``构建器</>数组包含的属性更多。 这是为了防止生成器有太多的参数。 在这些情况下,您需要手动设置属性。 一个例子是 ClassMethod </>.
// Example
// because the builder doesn't contain `async` as a property
var node = t.classMethod(
"constructor",
t.identifier("constructor"),
params,
body
)
// set it manually after creation
node.async = true;
You can see the validation for the builder arguments with the
fields
object.
fields: {
object: {
validate: assertNodeType("Expression")
},
property: {
validate(node, key, val) {
let expectedType = node.computed ? "Expression" : "Identifier";
assertNodeType(expectedType)(node, key, val);
}
},
computed: {
default: false
}
}
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:
t.memberExpression(
t.identifier('object'),
t.identifier('property')
// `computed` is optional
);
Which will result in:
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.
aliases: ["Expression", "LVal"],
So since MemberExpression
is a type of Expression
, we could set it as the object
of another MemberExpression
:
t.memberExpression(
t.memberExpression(
t.identifier('member'),
t.identifier('expression')
),
t.identifier('property')
)
Which will result in:
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