API

Babel 实际上是一组模块的集合。本节我们将探索一些主要的模块,解释它们是做什么的以及如何使用它们。

注意:本节内容不是详细的 API 文档的替代品,正式的 API 文档将很快提供出来。

babylon

Babylon 是 Babel 的解析器。最初是 从Acorn项目fork出来的。Acorn非常快,易于使用,并且针对非标准特性(以及那些未来的标准特性) 设计了一个基于插件的架构。

首先,让我们安装它。

  1. $ npm install --save babylon

先从解析一个代码字符串开始:

  1. import * as babylon from "babylon";
  2. const code = `function square(n) {
  3. return n * n;
  4. }`;
  5. babylon.parse(code);
  6. // Node {
  7. // type: "File",
  8. // start: 0,
  9. // end: 38,
  10. // loc: SourceLocation {...},
  11. // program: Node {...},
  12. // comments: [],
  13. // tokens: [...]
  14. // }

我们还能像下面这样传递选项给 parse()方法:

  1. babylon.parse(code, {
  2. sourceType: "module", // default: "script"
  3. plugins: ["jsx"] // default: []
  4. });

sourceType 可以是 "module" 或者 "script",它表示 Babylon 应该用哪种模式来解析。 "module" 将会在严格模式下解析并且允许模块定义,"script" 则不会。

注意: sourceType 的默认值是 "script" 并且在发现 importexport 时产生错误。 使用 scourceType: "module" 来避免这些错误。

由于 Babylon 使用了基于插件的架构,因此有一个 plugins 选项可以开关内置的插件。 注意 Babylon 尚未对外部插件开放此 API 接口,不排除未来会开放此API。

要查看完整的插件列表,请参见 Babylon README文件。.

babel-traverse

Babel Traverse(遍历)模块维护了整棵树的状态,并且负责替换、移除和添加节点。

运行以下命令安装:

  1. $ npm install --save babel-traverse

我们可以和 Babylon 一起使用来遍历和更新节点:

  1. import * as babylon from "babylon";
  2. import traverse from "babel-traverse";
  3. const code = `function square(n) {
  4. return n * n;
  5. }`;
  6. const ast = babylon.parse(code);
  7. traverse(ast, {
  8. enter(path) {
  9. if (
  10. path.node.type === "Identifier" &&
  11. path.node.name === "n"
  12. ) {
  13. path.node.name = "x";
  14. }
  15. }
  16. });

babel-types

Babel Types模块是一个用于 AST 节点的 Lodash 式工具库(译注:Lodash 是一个 JavaScript 函数工具库,提供了基于函数式编程风格的众多工具函数), 它包含了构造、验证以及变换 AST 节点的方法。 该工具库包含考虑周到的工具方法,对编写处理AST逻辑非常有用。

可以运行以下命令来安装它:

  1. $ npm install --save babel-types

然后按如下所示来使用:

  1. import traverse from "babel-traverse";
  2. import * as t from "babel-types";
  3. traverse(ast, {
  4. enter(path) {
  5. if (t.isIdentifier(path.node, { name: "n" })) {
  6. path.node.name = "x";
  7. }
  8. }
  9. });

Definitions(定义)

Babel Types模块拥有每一个单一类型节点的定义,包括节点包含哪些属性,什么是合法值,如何构建节点、遍历节点,以及节点的别名等信息。

单一节点类型的定义形式如下:

  1. defineType("BinaryExpression", {
  2. builder: ["operator", "left", "right"],
  3. fields: {
  4. operator: {
  5. validate: assertValueType("string")
  6. },
  7. left: {
  8. validate: assertNodeType("Expression")
  9. },
  10. right: {
  11. validate: assertNodeType("Expression")
  12. }
  13. },
  14. visitor: ["left", "right"],
  15. aliases: ["Binary", "Expression"]
  16. });

Builders(构建器)

你会注意到上面的 BinaryExpression 定义有一个 builder 字段。.

  1. builder: ["operator", "left", "right"]

这是由于每一个节点类型都有构造器方法builder,按类似下面的方式使用:

  1. t.binaryExpression("*", t.identifier("a"), t.identifier("b"));

可以创建如下所示的 AST:

  1. {
  2. type: "BinaryExpression",
  3. operator: "*",
  4. left: {
  5. type: "Identifier",
  6. name: "a"
  7. },
  8. right: {
  9. type: "Identifier",
  10. name: "b"
  11. }
  12. }

当打印出来之后是这样的:

  1. a * b

构造器还会验证自身创建的节点,并在错误使用的情形下会抛出描述性错误,这就引出了下一个方法类型。

Validators(验证器)

BinaryExpression 的定义还包含了节点的字段 fields 信息,以及如何验证这些字段。

  1. fields: {
  2. operator: {
  3. validate: assertValueType("string")
  4. },
  5. left: {
  6. validate: assertNodeType("Expression")
  7. },
  8. right: {
  9. validate: assertNodeType("Expression")
  10. }
  11. }

可以创建两种验证方法。第一种是 isX。.

  1. t.isBinaryExpression(maybeBinaryExpressionNode);

这个测试用来确保节点是一个二进制表达式,另外你也可以传入第二个参数来确保节点包含特定的属性和值。

  1. t.isBinaryExpression(maybeBinaryExpressionNode, { operator: "*" });

这些方法还有一种断言式的版本,会抛出异常而不是返回 truefalse。.

  1. t.assertBinaryExpression(maybeBinaryExpressionNode);
  2. t.assertBinaryExpression(maybeBinaryExpressionNode, { operator: "*" });
  3. // Error: Expected type "BinaryExpression" with option { "operator": "*" }

Converters(变换器)

[WIP]

babel-generator

Babel Generator模块是 Babel 的代码生成器,它读取AST并将其转换为代码和源码映射(sourcemaps)。

运行以下命令来安装它:

  1. $ npm install --save babel-generator

然后按如下方式使用:

  1. import * as babylon from "babylon";
  2. import generate from "babel-generator";
  3. const code = `function square(n) {
  4. return n * n;
  5. }`;
  6. const ast = babylon.parse(code);
  7. generate(ast, {}, code);
  8. // {
  9. // code: "...",
  10. // map: "..."
  11. // }

你也可以给 generate() 方法传递选项。.

  1. generate(ast, {
  2. retainLines: false,
  3. compact: "auto",
  4. concise: false,
  5. quotes: "double",
  6. // ...
  7. }, code);

babel-template

babel-template 是另一个虽然很小但却非常有用的模块。 它能让你编写字符串形式且带有占位符的代码来代替手动编码, 尤其是生成的大规模 AST的时候。 在计算机科学中,这种能力被称为准引用(quasiquotes)。

  1. $ npm install --save babel-template
  1. import template from "babel-template";
  2. import generate from "babel-generator";
  3. import * as t from "babel-types";
  4. const buildRequire = template(`
  5. var IMPORT_NAME = require(SOURCE);
  6. `);
  7. const ast = buildRequire({
  8. IMPORT_NAME: t.identifier("myModule"),
  9. SOURCE: t.stringLiteral("my-module")
  10. });
  11. console.log(generate(ast).code);
  1. var myModule = require("my-module");