diff --git a/translations/zh-Hans/README.md b/translations/zh-Hans/README.md index 8b627912..fbcfae69 100644 --- a/translations/zh-Hans/README.md +++ b/translations/zh-Hans/README.md @@ -2,9 +2,9 @@ 这本手册分为两个部分: - * [用户手册](user-handbook.md)-如何安装/配置 Babel 及相关内容。 - * [插件手册](plugin-handbook.md)-如何为 Babel 创建插件。 + * [用户手册](user-handbook.md) - 如何安装 / 配置 Babel 及相关内容。 + * [插件手册](plugin-handbook.md) - 如何为 Babel 创建插件。 > 在 Twitter 上关注 [@thejameskyle](https://twitter.com/thejameskyle),第一时间获取更新。 -如果你正在阅读本手册的非英语版本,你或许会发现一些英文的部分还没有被翻译。 如果你想帮助翻译的话你需要通过 Crowdin 来完成。 请先阅读[贡献指导](/CONTRIBUTING.md)来了解这方面更多的信息。 你会发现有些英语单词代表特定的编程概念。 如果按照字面翻译这些单词会导致在阅读时缺乏一致性和流畅性。 在此情形下,字面翻译会写在原文后面的 `()` 内。 例如:抽象语法树(ASTs) \ No newline at end of file +如果你正在阅读本手册的非英语版本,你或许会发现一些英文的部分还没有被翻译。如果你想帮助翻译的话你需要通过 Crowdin 来完成。请先阅读[贡献指导](/CONTRIBUTING.md)来了解这方面更多的信息。你会发现有些英语单词代表特定的编程概念。如果按照字面翻译这些单词会导致在阅读时缺乏一致性和流畅性。在此情形下,字面翻译会写在原文后面的 `()` 内。例如:抽象语法树 (ASTs) \ No newline at end of file diff --git a/translations/zh-Hans/plugin-handbook.md b/translations/zh-Hans/plugin-handbook.md index 6e0a7c81..555315c8 100644 --- a/translations/zh-Hans/plugin-handbook.md +++ b/translations/zh-Hans/plugin-handbook.md @@ -1,80 +1,88 @@ # Babel 插件手册 -这篇文档涵盖了如何创建 [Babel](https://babeljs.io) [插件](https://babeljs.io/docs/advanced/plugins/)等方面的内容。. +这篇文档涵盖了如何创建 [Babel](https://babeljs.io) [插件](https://babeljs.io/docs/advanced/plugins/)等方面的内容。 [![cc-by-4.0](https://licensebuttons.net/l/by/4.0/80x15.png)](http://creativecommons.org/licenses/by/4.0/) -这本手册提供了多种语言的版本,查看 [自述文件](/README.md) 里的完整列表。 +这本手册提供了多种语言的版本,查看[自述文件](/README.md)里的完整列表。 # 目录 - * [介绍](#toc-introduction) - * [基础](#toc-basics) - * [抽象语法树(ASTs)](#toc-asts) - * [Babel 的处理步骤](#toc-stages-of-babel) - * [解析](#toc-parse) - * [词法分析](#toc-lexical-analysis) - * [语法分析](#toc-syntactic-analysis) - * [转换](#toc-transform) - * [生成](#toc-generate) - * [遍历](#toc-traversal) - * [Visitors(访问者)](#toc-visitors) - * [Paths(路径)](#toc-paths) - * [Paths in Visitors(存在于访问者中的路径)](#toc-paths-in-visitors) - * [State(状态)](#toc-state) - * [Scopes(作用域)](#toc-scopes) - * [Bindings(绑定)](#toc-bindings) - * [API](#toc-api) - * [babylon](#toc-babylon) - * [babel-traverse](#toc-babel-traverse) - * [babel-types](#toc-babel-types) - * [Definitions(定义)](#toc-definitions) - * [Builders(构建器)](#toc-builders) - * [Validators(验证器)](#toc-validators) - * [Converters(变换器)](#toc-converters) - * [babel-generator](#toc-babel-generator) - * [babel-template](#toc-babel-template) - * [编写你的第一个 Babel 插件](#toc-writing-your-first-babel-plugin) - * [转换操作](#toc-transformation-operations) - * [访问](#toc-visiting) - * [获取子节点的Path](#toc-get-the-path-of-a-sub-node) - * [检查节点(Node)类型](#toc-check-if-a-node-is-a-certain-type) - * [检查路径(Path)类型](#toc-check-if-a-path-is-a-certain-type) - * [检查标识符(Identifier)是否被引用](#toc-check-if-an-identifier-is-referenced) - * [找到特定的父路径](#toc-find-a-specific-parent-path) - * [获取同级路径](#toc-get-sibling-paths) - * [停止遍历](#toc-stopping-traversal) - * [处理](#toc-manipulation) - * [替换一个节点](#toc-replacing-a-node) - * [用多节点替换单节点](#toc-replacing-a-node-with-multiple-nodes) - * [用字符串源码替换节点](#toc-replacing-a-node-with-a-source-string) - * [插入兄弟节点](#toc-inserting-a-sibling-node) - * [插入到容器(container)中](#toc-inserting-into-a-container) - * [删除节点](#toc-removing-a-node) - * [替换父节点](#toc-replacing-a-parent) - * [删除父节点](#toc-removing-a-parent) - * [Scope(作用域)](#toc-scope) - * [检查本地变量是否被绑定](#toc-checking-if-a-local-variable-is-bound) - * [生成UID](#toc-generating-a-uid) - * [提升变量声明至父级作用域](#toc-pushing-a-variable-declaration-to-a-parent-scope) - * [重命名绑定及其引用](#toc-rename-a-binding-and-its-references) - * [插件选项](#toc-plugin-options) - * [插件的准备和收尾工作](#toc-pre-and-post-in-plugins) - * [在插件中启用其他语法](#toc-enabling-syntax-in-plugins) - * [构建节点](#toc-building-nodes) - * [最佳实践](#toc-best-practices) - * [尽量避免遍历抽象语法树(AST)](#toc-avoid-traversing-the-ast-as-much-as-possible) - * [及时合并访问者对象](#toc-merge-visitors-whenever-possible) - * [可以手动查找就不要遍历](#toc-do-not-traverse-when-manual-lookup-will-do) - * [优化嵌套的访问者对象](#toc-optimizing-nested-visitors) - * [留意嵌套结构](#toc-being-aware-of-nested-structures) - * [单元测试](#toc-unit-testing) +- [Babel 插件手册](#babel-插件手册) +- [目录](#目录) +- [介绍](#介绍) +- [基础](#基础) + - [抽象语法树 (ASTs)](#抽象语法树-asts) + - [Babel 的处理步骤](#babel-的处理步骤) + - [解析](#解析) + - [词法分析](#词法分析) + - [语法分析](#语法分析) + - [转换](#转换) + - [生成](#生成) + - [遍历](#遍历) + - [Visitors (访问者)](#visitors-访问者) + - [Paths (路径)](#paths-路径) + - [Paths in Visitors (存在于访问者中的路径)](#paths-in-visitors-存在于访问者中的路径) + - [State (状态)](#state-状态) + - [Scopes (作用域)](#scopes-作用域) + - [Bindings (绑定)](#bindings-绑定) +- [API](#api) + - [`babylon`](#babylon) + - [`babel-traverse`](#babel-traverse) + - [`babel-types`](#babel-types) + - [Definitions (定义)](#definitions-定义) + - [Builders (构建器)](#builders-构建器) + - [Validators (验证器)](#validators-验证器) + - [Converters (变换器)](#converters-变换器) + - [`babel-generator`](#babel-generator) + - [`babel-template`](#babel-template) +- [编写你的第一个 Babel 插件](#编写你的第一个-babel-插件) +- [转换操作](#转换操作) + - [访问](#访问) + - [获取子节点的 Path](#获取子节点的-path) + - [检查节点的类型](#检查节点的类型) + - [检查路径 (Path) 类型](#检查路径-path-类型) + - [检查标识符 (Identifier) 是否被引用](#检查标识符-identifier-是否被引用) + - [找到特定的父路径](#找到特定的父路径) + - [获取同级路径](#获取同级路径) + - [停止遍历](#停止遍历) + - [处理](#处理) + - [替换一个节点](#替换一个节点) + - [用多节点替换单节点](#用多节点替换单节点) + - [用字符串源码替换节点](#用字符串源码替换节点) + - [插入兄弟节点](#插入兄弟节点) + - [插入到容器 (container) 中](#插入到容器-container-中) + - [删除一个节点](#删除一个节点) + - [替换父节点](#替换父节点) + - [删除父节点](#删除父节点) + - [Scope (作用域)](#scope-作用域) + - [检查本地变量是否被绑定](#检查本地变量是否被绑定) + - [创建一个 UID](#创建一个-uid) + - [提升变量声明至父级作用域](#提升变量声明至父级作用域) + - [重命名绑定及其引用](#重命名绑定及其引用) +- [插件选项](#插件选项) + - [ 插件的准备和收尾工作](#-插件的准备和收尾工作) + - [ 在插件中启用其他语法](#-在插件中启用其他语法) + - [ 抛出一个语法错误](#-抛出一个语法错误) +- [构建节点](#构建节点) +- [最佳实践](#最佳实践) + - [ 创建 Helper Builders 和 Checkers](#-创建-helper-builders-和-checkers) + - [尽量避免遍历抽象语法树 (AST)](#尽量避免遍历抽象语法树-ast) + - [及时合并访问者对象](#及时合并访问者对象) + - [可以手动查找就不要遍历](#可以手动查找就不要遍历) + - [优化嵌套的访问者对象](#优化嵌套的访问者对象) + - [留意嵌套结构](#留意嵌套结构) + - [单元测试](#单元测试) + - [快照测试](#快照测试) + - [AST 测试](#ast-测试) + - [Exec Tests](#exec-tests) + - [`babel-plugin-tester`](#babel-plugin-tester) # 介绍 Babel 是一个通用的多功能的 JavaScript 编译器。此外它还拥有众多模块可用于不同形式的静态分析。 -> 静态分析是在不需要执行代码的前提下对代码进行分析的处理过程 (执行代码的同时进行代码分析即是动态分析)。 静态分析的目的是多种多样的, 它可用于语法检查,编译,代码高亮,代码转换,优化,压缩等等场景。 +> 静态分析是在不需要执行代码的前提下对代码进行分析的处理过程 (执行代码的同时进行代码分析即是动态分析)。静态分析的目的是多种多样的,它可用于语法检查,编译,代码高亮,代码转换,优化,压缩等等场景。 你可以使用 Babel 创建多种类型的工具来帮助你更有效率并且写出更好的程序。 @@ -84,13 +92,13 @@ Babel 是一个通用的多功能的 JavaScript 编译器。此外它还拥有 # 基础 -Babel 是 JavaScript 编译器,更确切地说是源码到源码的编译器,通常也叫做“转换编译器(transpiler)”。 意思是说你为 Babel 提供一些 JavaScript 代码,Babel 更改这些代码,然后返回给你新生成的代码。 +Babel 是 JavaScript 编译器,更确切地说是源码到源码的编译器,通常也叫做 “转换编译器 (transpiler)”。意思是说你为 Babel 提供一些 JavaScript 代码,Babel 更改这些代码,然后返回给你新生成的代码。 -## 抽象语法树(ASTs) +## 抽象语法树 (ASTs) 这个处理过程中的每一步都涉及到创建或是操作[抽象语法树](https://en.wikipedia.org/wiki/Abstract_syntax_tree),亦称 AST。 -> Babel 使用一个基于 [ESTree](https://github.com/estree/estree) 并修改过的 AST,它的内核说明文档可以在[这里](https://github. com/babel/babel/blob/master/doc/ast/spec. md)找到。. +> Babel 使用一个基于 [ESTree](https://github.com/estree/estree) 并修改过的 AST,它的内核说明文档可以在[这里](https://github.com/babel/babel/blob/master/doc/ast/spec.md)找到。 ```js function square(n) { @@ -98,7 +106,7 @@ function square(n) { } ``` -> [AST Explorer](http://astexplorer.net/) 可以让你对 AST 节点有一个更好的感性认识。 [这里](http://astexplorer.net/#/Z1exs6BWMq)是上述代码的一个示例链接。 +> [AST Explorer](http://astexplorer.net/) 可以让你对 AST 节点有一个更好的感性认识。[这里](http://astexplorer.net/#/Z1exs6BWMq)是上述代码的一个示例链接。 这个程序可以被表示成如下的一棵树: @@ -125,7 +133,7 @@ function square(n) { - name: n ``` -或是如下所示的 JavaScript Object(对象): +或是如下所示的 JavaScript Object (对象): ```js { @@ -188,9 +196,9 @@ function square(n) { > 注意:出于简化的目的移除了某些属性 -这样的每一层结构也被叫做 **节点(Node)**。 一个 AST 可以由单一的节点或是成百上千个节点构成。 它们组合在一起可以描述用于静态分析的程序语法。 +这样的每一层结构也被叫做**节点 (Node)**。一个 AST 可以由单一的节点或是成百上千个节点构成。它们组合在一起可以描述用于静态分析的程序语法。 -每一个节点都有如下所示的接口(Interface): +每一个节点都有如下所示的接口 (Interface): ```typescript interface Node { @@ -198,7 +206,7 @@ interface Node { } ``` -字符串形式的 `type` 字段表示节点的类型(如: `"FunctionDeclaration"`,`"Identifier"`,或 `"BinaryExpression"`)。 每一种类型的节点定义了一些附加属性用来进一步描述该节点类型。 +字符串形式的 `type` 字段表示节点的类型 (如:`"FunctionDeclaration"`,`"Identifier"`,或 `"BinaryExpression"`)。每一种类型的节点定义了一些附加属性用来进一步描述该节点类型。 Babel 还为每个节点额外生成了一些属性,用于描述该节点在原始代码中的位置。 @@ -225,15 +233,15 @@ Babel 还为每个节点额外生成了一些属性,用于描述该节点在 ## Babel 的处理步骤 -Babel 的三个主要处理步骤分别是: **解析(parse)**,**转换(transform)**,**生成(generate)**。. +Babel 的三个主要处理步骤分别是:**解析 (parse)**,**转换 (transform)**,**生成 (generate)**。 ### 解析 -**解析**步骤接收代码并输出 AST。 这个步骤分为两个阶段:[**词法分析(Lexical Analysis) **](https://en.wikipedia.org/wiki/Lexical_analysis)和 [**语法分析(Syntactic Analysis)**](https://en.wikipedia.org/wiki/Parsing)。. +**解析**步骤接收代码并输出 AST。这个步骤分为两个阶段:[**词法分析 (Lexical Analysis)**](https://en.wikipedia.org/wiki/Lexical_analysis) 和[**语法分析 (Syntactic Analysis)**](https://en.wikipedia.org/wiki/Parsing)。 #### 词法分析 -词法分析阶段把字符串形式的代码转换为 **令牌(tokens)** 流。. +词法分析阶段把字符串形式的代码转换为**令牌 (tokens)** 流。 你可以把令牌看作是一个扁平的语法片段数组: @@ -271,19 +279,19 @@ n * n; } ``` -和 AST 节点一样它们也有 `start`,`end`,`loc` 属性。. +和 AST 节点一样它们也有 `start`,`end`,`loc` 属性。。 #### 语法分析 -语法分析阶段会把一个令牌流转换成 AST 的形式。 这个阶段会使用令牌中的信息把它们转换成一个 AST 的表述结构,这样更易于后续的操作。 +语法分析阶段会把一个令牌流转换成 AST 的形式。这个阶段会使用令牌中的信息把它们转换成一个 AST 的表述结构,这样更易于后续的操作。 ### 转换 -[转换](https://en.wikipedia.org/wiki/Program_transformation)步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。 这是 Babel 或是其他编译器中最复杂的过程 同时也是插件将要介入工作的部分,这将是本手册的主要内容, 因此让我们慢慢来。 +[转换](https://en.wikipedia.org/wiki/Program_transformation)步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。这是 Babel 或是其他编译器中最复杂的过程同时也是插件将要介入工作的部分,这将是本手册的主要内容,因此让我们慢慢来。 ### 生成 -[代码生成](https://en.wikipedia.org/wiki/Code_generation_(compiler))步骤把最终(经过一系列转换之后)的 AST 转换成字符串形式的代码,同时还会创建[源码映射(source maps)](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/)。. +[代码生成](https://en.wikipedia.org/wiki/Code_generation_(compiler))步骤把最终 (经过一系列转换之后) 的 AST 转换成字符串形式的代码,同时还会创建[源码映射 (source maps)](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/)。。 代码生成其实很简单:深度优先遍历整个 AST,然后构建可以表示转换后代码的字符串。 @@ -325,25 +333,25 @@ n * n; } ``` -于是我们从 `FunctionDeclaration` 开始并且我们知道它的内部属性(即:`id`,`params`,`body`),所以我们依次访问每一个属性及它们的子节点。 +于是我们从 `FunctionDeclaration` 开始并且我们知道它的内部属性 (即:`id`,`params`,`body`),所以我们依次访问每一个属性及它们的子节点。 接着我们来到 `id`,它是一个 `Identifier`。`Identifier` 没有任何子节点属性,所以我们继续。 之后是 `params`,由于它是一个数组节点所以我们访问其中的每一个,它们都是 `Identifier` 类型的单一节点,然后我们继续。 -此时我们来到了 `body`,这是一个 `BlockStatement` 并且也有一个 `body`节点,而且也是一个数组节点,我们继续访问其中的每一个。 +此时我们来到了 `body`,这是一个 `BlockStatement` 并且也有一个 `body` 节点,而且也是一个数组节点,我们继续访问其中的每一个。 -这里唯一的一个属性是 `ReturnStatement` 节点,它有一个 `argument`,我们访问 `argument` 就找到了 `BinaryExpression`。. +这里唯一的一个属性是 `ReturnStatement` 节点,它有一个 `argument`,我们访问 `argument` 就找到了 `BinaryExpression`。。 -`BinaryExpression` 有一个 `operator`,一个 `left`,和一个 `right`。 Operator 不是一个节点,它只是一个值因此我们不用继续向内遍历,我们只需要访问 `left` 和 `right`。. +`BinaryExpression` 有一个 `operator`,一个 `left`,和一个 `right`。Operator 不是一个节点,它只是一个值因此我们不用继续向内遍历,我们只需要访问 `left` 和 `right`。 Babel 的转换步骤全都是这样的遍历过程。 -### Visitors(访问者) +### Visitors (访问者) -当我们谈及“进入”一个节点,实际上是说我们在**访问**它们, 之所以使用这样的术语是因为有一个[**访问者模式(visitor)**](https://en.wikipedia.org/wiki/Visitor_pattern)的概念。. +当我们谈及 “进入” 一个节点,实际上是说我们在**访问**它们,之所以使用这样的术语是因为有一个[**访问者模式 (visitor)**](https://en.wikipedia.org/wiki/Visitor_pattern) 的概念。 -访问者是一个用于 AST 遍历的跨语言的模式。 简单的说它们就是一个对象,定义了用于在一个树状结构中获取具体节点的方法。 这么说有些抽象所以让我们来看一个例子。 +访问者是一个用于 AST 遍历的跨语言的模式。简单的说它们就是一个对象,定义了用于在一个树状结构中获取具体节点的方法。这么说有些抽象所以让我们来看一个例子。 ```js const MyVisitor = { @@ -358,11 +366,11 @@ visitor.MemberExpression = function() {}; visitor.FunctionDeclaration = function() {} ``` -> **注意**: `Identifier() { ... }` 是 `Identifier: { enter() { ... } }` 的简写形式。. +> **注意**: `Identifier() { ... }` 是 `Identifier: { enter() { ... } }` 的简写形式。 这是一个简单的访问者,把它用于遍历中时,每当在树中遇见一个 `Identifier` 的时候会调用 `Identifier()` 方法。 -所以在下面的代码中 `Identifier()` 方法会被调用四次(包括 `square` 在内,总共有四个 `Identifier`)。). +所以在下面的代码中 `Identifier()` 方法会被调用四次 (包括 `square` 在内,总共有四个 `Identifier`)。)。 ```js function square(n) { @@ -378,7 +386,7 @@ Called! Called! ``` -这些调用都发生在**进入**节点时,不过有时候我们也可以在**退出**时调用访问者方法。. +这些调用都发生在**进入**节点时,不过有时候我们也可以在**退出**时调用访问者方法。 假设我们有一个树状结构: @@ -393,11 +401,11 @@ Called! - Identifier (right) ``` -当我们向下遍历这颗树的每一个分支时我们最终会走到尽头,于是我们需要往上遍历回去从而获取到下一个节点。 向下遍历这棵树我们**进入**每个节点,向上遍历回去时我们**退出**每个节点。 +当我们向下遍历这颗树的每一个分支时我们最终会走到尽头,于是我们需要往上遍历回去从而获取到下一个节点。向下遍历这棵树我们**进入**每个节点,向上遍历回去时我们**退出**每个节点。 让我们以上面那棵树为例子走一遍这个过程。 - * 进入 `FunctionDeclaration` + * 进入 `FunctionDeclaration` * 进入 `Identifier (id)` * 走到尽头 * 退出 `Identifier (id)` @@ -405,12 +413,12 @@ Called! * 走到尽头 * 退出 `Identifier (params[0])` * 进入 `BlockStatement (body)` - * 进入 `ReturnStatement (body)` + * 进入 `ReturnStatement (body)` * 进入 `BinaryExpression (argument)` - * 进入 `Identifier (left)` + * 进入 `Identifier (left)` * 走到尽头 * 退出 `Identifier (left)` - * 进入 `Identifier (right)` + * 进入 `Identifier (right)` * 走到尽头 * 退出 `Identifier (right)` * 退出 `BinaryExpression (argument)` @@ -433,9 +441,9 @@ const MyVisitor = { }; ``` -如有必要,你还可以把方法名用`|`分割成`Idenfifier |MemberExpression`形式的字符串,把同一个函数应用到多种访问节点。. +如有必要,你还可以把方法名用 `|` 分割成 `Idenfifier |MemberExpression` 形式的字符串,把同一个函数应用到多种访问节点。 -在[flow-comments](https://github.com/babel/babel/blob/2b6ff53459d97218b0cf16f8a51c14a165db1fd2/packages/babel-plugin-transform-flow-comments/src/index.js#L47) 插件中的例子如下: +在 [flow-comments](https://github.com/babel/babel/blob/2b6ff53459d97218b0cf16f8a51c14a165db1fd2/packages/babel-plugin-transform-flow-comments/src/index.js#L47) 插件中的例子如下: ```js const MyVisitor = { @@ -443,11 +451,11 @@ const MyVisitor = { }; ``` -你也可以在访问者中使用别名(如[babel-types](https://github.com/babel/babel/tree/master/packages/babel-types/src/definitions)定义). +你也可以在访问者中使用别名 (如 [babel-types](https://github.com/babel/babel/tree/master/packages/babel-types/src/definitions) 定义)。 例如, -`Function` is an alias for `FunctionDeclaration`, `FunctionExpression`, `ArrowFunctionExpression`, `ObjectMethod` and `ClassMethod`. +`Function` is an alias for `FunctionDeclaration`,`FunctionExpression`,`ArrowFunctionExpression`,`ObjectMethod` and `ClassMethod`。 ```js const MyVisitor = { @@ -455,9 +463,9 @@ const MyVisitor = { }; ``` -### Paths(路径) +### Paths (路径) -AST 通常会有许多节点,那么节点直接如何相互关联呢? 我们可以使用一个可操作和访问的巨大可变对象表示节点之间的关联关系,或者也可以用**Paths**(路径)来简化这件事情。. +AST 通常会有许多节点,那么节点直接如何相互关联呢?我们可以使用一个可操作和访问的巨大可变对象表示节点之间的关联关系,或者也可以用 **Paths** (路径) 来简化这件事情。 **Path** 是表示两个节点之间连接的对象。 @@ -474,7 +482,7 @@ AST 通常会有许多节点,那么节点直接如何相互关联呢? 我们 } ``` -将子节点 `Identifier` 表示为一个路径(Path)的话,看起来是这样的: +将子节点 `Identifier` 表示为一个路径 (Path) 的话,看起来是这样的: ```js { @@ -520,11 +528,11 @@ AST 通常会有许多节点,那么节点直接如何相互关联呢? 我们 当然路径对象还包含添加、更新、移动和删除节点有关的其他很多方法,稍后我们再来看这些方法。 -在某种意义上,路径是一个节点在树中的位置以及关于该节点各种信息的响应式 **Reactive** 表示。 当你调用一个修改树的方法后,路径信息也会被更新。 Babel 帮你管理这一切,从而使得节点操作简单,尽可能做到无状态。 +在某种意义上,路径是一个节点在树中的位置以及关于该节点各种信息的响应式 **Reactive** 表示。当你调用一个修改树的方法后,路径信息也会被更新。Babel 帮你管理这一切,从而使得节点操作简单,尽可能做到无状态。 -#### Paths in Visitors(存在于访问者中的路径) +#### Paths in Visitors (存在于访问者中的路径) -当你有一个 `Identifier()` 成员方法的访问者时,你实际上是在访问路径而非节点。 通过这种方式,你操作的就是节点的响应式表示(译注:即路径)而非节点本身。 +当你有一个 `Identifier()` 成员方法的访问者时,你实际上是在访问路径而非节点。通过这种方式,你操作的就是节点的响应式表示 (译注:即路径) 而非节点本身。 ```js const MyVisitor = { @@ -545,9 +553,9 @@ Visiting: b Visiting: c ``` -### State(状态) +### State (状态) -状态是抽象语法树AST转换的敌人,状态管理会不断牵扯你的精力,而且几乎所有你对状态的假设,总是会有一些未考虑到的语法最终证明你的假设是错误的。 +状态是抽象语法树 AST 转换的敌人,状态管理会不断牵扯你的精力,而且几乎所有你对状态的假设,总是会有一些未考虑到的语法最终证明你的假设是错误的。 考虑下列代码: @@ -557,7 +565,7 @@ function square(n) { } ``` -让我们写一个把 `n` 重命名为 `x` 的访问者的快速实现. +让我们写一个把 `n` 重命名为 `x` 的访问者的快速实现。 ```js let paramName; @@ -612,9 +620,9 @@ path.traverse(MyVisitor); 当然,这只是一个刻意编写的例子,不过它演示了如何从访问者中消除全局状态。 -### Scopes(作用域) +### Scopes (作用域) -接下来让我们介绍[**作用域(scope)**](https://en.wikipedia.org/wiki/Scope_(computer_science))的概念。 JavaScript 支持[词法作用域](https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping_vs._dynamic_scoping),在树状嵌套结构中代码块创建出新的作用域。 +接下来让我们介绍[**作用域 (scope)**](https://en.wikipedia.org/wiki/Scope_(computer_science)) 的概念。JavaScript 支持[词法作用域](https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping_vs._dynamic_scoping),在树状嵌套结构中代码块创建出新的作用域。 ```js // global scope @@ -628,7 +636,7 @@ function scopeOne() { } ``` -在 JavaScript 中,每当你创建了一个引用,不管是通过变量(variable)、函数(function)、类型(class)、参数(params)、模块导入(import)还是标签(label)等,它都属于当前作用域。 +在 JavaScript 中,每当你创建了一个引用,不管是通过变量 (variable)、函数 (function)、类型 (class)、参数 (params)、模块导入 (import) 还是标签 (label) 等,它都属于当前作用域。 ```js var global = "I am in the global scope"; @@ -668,7 +676,7 @@ function scopeOne() { 当编写一个转换时,必须小心作用域。我们得确保在改变代码的各个部分时不会破坏已经存在的代码。 -我们在添加一个新的引用时需要确保新增加的引用名字和已有的所有引用不冲突。 或者我们仅仅想找出使用一个变量的所有引用, 我们只想在给定的作用域(Scope)中找出这些引用。 +我们在添加一个新的引用时需要确保新增加的引用名字和已有的所有引用不冲突。或者我们仅仅想找出使用一个变量的所有引用,我们只想在给定的作用域 (Scope) 中找出这些引用。 作用域可以被表示为如下形式: @@ -682,13 +690,13 @@ function scopeOne() { } ``` -当你创建一个新的作用域时,需要给出它的路径和父作用域,之后在遍历过程中它会在该作用域内收集所有的引用(“绑定”)。 +当你创建一个新的作用域时,需要给出它的路径和父作用域,之后在遍历过程中它会在该作用域内收集所有的引用 (“绑定”)。 -一旦引用收集完毕,你就可以在作用域(Scopes)上使用各种方法,稍后我们会了解这些方法。 +一旦引用收集完毕,你就可以在作用域 (Scopes) 上使用各种方法,稍后我们会了解这些方法。 -#### Bindings(绑定) +#### Bindings (绑定) -所有引用属于特定的作用域,引用和作用域的这种关系被称作:**绑定(binding)**。. +所有引用属于特定的作用域,引用和作用域的这种关系被称作:**绑定 (binding)**。 ```js function scopeOnce() { @@ -721,7 +729,7 @@ Text for Translation } ``` -有了这些信息你就可以查找一个绑定的所有引用,并且知道这是什么类型的绑定(参数,定义等等),查找它所属的作用域,或者拷贝它的标识符。 你甚至可以知道它是不是常量,如果不是,那么是哪个路径修改了它。 +有了这些信息你就可以查找一个绑定的所有引用,并且知道这是什么类型的绑定 (参数,定义等等),查找它所属的作用域,或者拷贝它的标识符。你甚至可以知道它是不是常量,如果不是,那么是哪个路径修改了它。 在很多情况下,知道一个绑定是否是常量非常有用,最有用的一种情形就是代码压缩时。 @@ -748,7 +756,7 @@ Babel 实际上是一组模块的集合。本节我们将探索一些主要的 ## [`babylon`](https://github.com/babel/babylon) -Babylon 是 Babel 的解析器。最初是 从Acorn项目fork出来的。Acorn非常快,易于使用,并且针对非标准特性(以及那些未来的标准特性) 设计了一个基于插件的架构。 +Babylon 是 Babel 的解析器。最初是从 Acorn 项目 fork 出来的。Acorn 非常快,易于使用,并且针对非标准特性 (以及那些未来的标准特性) 设计了一个基于插件的架构。 首先,让我们安装它。 @@ -777,7 +785,7 @@ babylon.parse(code); // } ``` -我们还能像下面这样传递选项给 `parse()`方法: +我们还能像下面这样传递选项给 `parse()` 方法: ```js babylon.parse(code, { @@ -786,17 +794,17 @@ babylon.parse(code, { }); ``` -`sourceType` 可以是 `"module"` 或者 `"script"`,它表示 Babylon 应该用哪种模式来解析。 `"module"` 将会在严格模式下解析并且允许模块定义,`"script"` 则不会。 +`sourceType` 可以是 `"module"` 或者 `"script"`,它表示 Babylon 应该用哪种模式来解析。`"module"` 将会在严格模式下解析并且允许模块定义,`"script"` 则不会。 -> **注意:** `sourceType` 的默认值是 `"script"` 并且在发现 `import` 或 `export` 时产生错误。 使用 `scourceType: "module"` 来避免这些错误。 +> **注意:** `sourceType` 的默认值是 `"script"` 并且在发现 `import` 或 `export` 时产生错误。使用 `scourceType: "module"` 来避免这些错误。 -由于 Babylon 使用了基于插件的架构,因此有一个 `plugins` 选项可以开关内置的插件。 注意 Babylon 尚未对外部插件开放此 API 接口,不排除未来会开放此API。 +由于 Babylon 使用了基于插件的架构,因此有一个 `plugins` 选项可以开关内置的插件。注意 Babylon 尚未对外部插件开放此 API 接口,不排除未来会开放此 API。 -要查看完整的插件列表,请参见 [Babylon README](https://github.com/babel/babylon/blob/master/README.md#plugins)文件。. +要查看完整的插件列表,请参见 [Babylon README](https://github.com/babel/babylon/blob/master/README.md#plugins) 文件。 ## [`babel-traverse`](https://github.com/babel/babel/tree/master/packages/babel-traverse) -Babel Traverse(遍历)模块维护了整棵树的状态,并且负责替换、移除和添加节点。 +Babel Traverse (遍历) 模块维护了整棵树的状态,并且负责替换、移除和添加节点。 运行以下命令安装: @@ -830,7 +838,7 @@ traverse(ast, { ## [`babel-types`](https://github.com/babel/babel/tree/master/packages/babel-types) -Babel Types模块是一个用于 AST 节点的 Lodash 式工具库(译注:Lodash 是一个 JavaScript 函数工具库,提供了基于函数式编程风格的众多工具函数), 它包含了构造、验证以及变换 AST 节点的方法。 该工具库包含考虑周到的工具方法,对编写处理AST逻辑非常有用。 +Babel Types 模块是一个用于 AST 节点的 Lodash 式工具库 (译注:Lodash 是一个 JavaScript 函数工具库,提供了基于函数式编程风格的众多工具函数),它包含了构造、验证以及变换 AST 节点的方法。该工具库包含考虑周到的工具方法,对编写处理 AST 逻辑非常有用。 可以运行以下命令来安装它: @@ -853,9 +861,9 @@ traverse(ast, { }); ``` -### Definitions(定义) +### Definitions (定义) -Babel Types模块拥有每一个单一类型节点的定义,包括节点包含哪些属性,什么是合法值,如何构建节点、遍历节点,以及节点的别名等信息。 +Babel Types 模块拥有每一个单一类型节点的定义,包括节点包含哪些属性,什么是合法值,如何构建节点、遍历节点,以及节点的别名等信息。 单一节点类型的定义形式如下: @@ -878,15 +886,15 @@ defineType("BinaryExpression", { }); ``` -### Builders(构建器) +### Builders (构建器) -你会注意到上面的 `BinaryExpression` 定义有一个 `builder` 字段。. +你会注意到上面的 `BinaryExpression` 定义有一个 `builder` 字段。 ```js builder: ["operator", "left", "right"] ``` -这是由于每一个节点类型都有构造器方法builder,按类似下面的方式使用: +这是由于每一个节点类型都有构造器方法 builder,按类似下面的方式使用: ```js t.binaryExpression("*", t.identifier("a"), t.identifier("b")); @@ -917,7 +925,7 @@ a * b 构造器还会验证自身创建的节点,并在错误使用的情形下会抛出描述性错误,这就引出了下一个方法类型。 -### Validators(验证器) +### Validators (验证器) `BinaryExpression` 的定义还包含了节点的字段 `fields` 信息,以及如何验证这些字段。 @@ -935,7 +943,7 @@ fields: { } ``` -可以创建两种验证方法。第一种是 `isX`。. +可以创建两种验证方法。第一种是 `isX`。 ```js t.isBinaryExpression(maybeBinaryExpressionNode); @@ -947,7 +955,7 @@ t.isBinaryExpression(maybeBinaryExpressionNode); t.isBinaryExpression(maybeBinaryExpressionNode, { operator: "*" }); ``` -这些方法还有一种断言式的版本,会抛出异常而不是返回 `true` 或 `false`。. +这些方法还有一种断言式的版本,会抛出异常而不是返回 `true` 或 `false`。。 ```js t.assertBinaryExpression(maybeBinaryExpressionNode); @@ -955,13 +963,13 @@ t.assertBinaryExpression(maybeBinaryExpressionNode, { operator: "*" }); // Error: Expected type "BinaryExpression" with option { "operator": "*" } ``` -### Converters(变换器) +### Converters (变换器) > [WIP] ## [`babel-generator`](https://github.com/babel/babel/tree/master/packages/babel-generator) -Babel Generator模块是 Babel 的代码生成器,它读取AST并将其转换为代码和源码映射(sourcemaps)。 +Babel Generator 模块是 Babel 的代码生成器,它读取 AST 并将其转换为代码和源码映射 (sourcemaps)。 运行以下命令来安装它: @@ -988,7 +996,7 @@ generate(ast, {}, code); // } ``` -你也可以给 `generate()` 方法传递选项。. +你也可以给 `generate()` 方法传递选项。 ```js generate(ast, { @@ -1002,7 +1010,7 @@ generate(ast, { ## [`babel-template`](https://github.com/babel/babel/tree/master/packages/babel-template) -babel-template 是另一个虽然很小但却非常有用的模块。 它能让你编写字符串形式且带有占位符的代码来代替手动编码, 尤其是生成的大规模 AST的时候。 在计算机科学中,这种能力被称为准引用(quasiquotes)。 +babel-template 是另一个虽然很小但却非常有用的模块。它能让你编写字符串形式且带有占位符的代码来代替手动编码,尤其是生成的大规模 AST 的时候。在计算机科学中,这种能力被称为准引用 (quasiquotes)。 ```sh $ npm install --save babel-template @@ -1031,9 +1039,9 @@ var myModule = require("my-module"); # 编写你的第一个 Babel 插件 -现在你已经熟悉了 Babel 的所有基础知识了,让我们把这些知识和插件的 API融合在一起来编写第一个 Babel 插件吧。 +现在你已经熟悉了 Babel 的所有基础知识了,让我们把这些知识和插件的 API 融合在一起来编写第一个 Babel 插件吧。 -先从一个接收了当前`babel`对象作为参数的 [`function`](https://github.com/babel/babel/tree/master/packages/babel-core) 开始。 +先从一个接收了当前 `babel` 对象作为参数的 [`function`](https://github.com/babel/babel/tree/master/packages/babel-core) 开始。 ```js export default function(babel) { @@ -1041,7 +1049,7 @@ export default function(babel) { } ``` -由于你将会经常这样使用,所以直接取出 `babel.types` 会更方便:(译注:这是 ES2015 语法中的对象解构,即 Destructuring) +由于你将会经常这样使用,所以直接取出 `babel.types` 会更方便:(译注:这是 ES2015 语法中的对象解构,即 Destructuring) ```js export default function({ types: t }) { @@ -1061,7 +1069,7 @@ export default function({ types: t }) { }; ``` -Visitor 中的每个函数接收2个参数:`path` 和 `state` +Visitor 中的每个函数接收 2 个参数:`path` 和 `state` ```js export default function({ types: t }) { @@ -1171,9 +1179,9 @@ sebmck === dork; ## 访问 -### 获取子节点的Path +### 获取子节点的 Path -为了得到一个AST节点的属性值,我们一般先访问到该节点,然后利用 `path.node.property` 方法即可。 +为了得到一个 AST 节点的属性值,我们一般先访问到该节点,然后利用 `path.node.property` 方法即可。 ```js // the BinaryExpression AST node has properties: `left`, `right`, `operator` @@ -1184,7 +1192,7 @@ BinaryExpression(path) { } ``` -如果你想访问到该属性内部的`path`,使用path对象的`get`方法,传递该属性的字符串形式作为参数。 +如果你想访问到该属性内部的 `path`,使用 path 对象的 `get` 方法,传递该属性的字符串形式作为参数。 ```js BinaryExpression(path) { @@ -1231,7 +1239,7 @@ BinaryExpression(path) { } ``` -### 检查路径(Path)类型 +### 检查路径 (Path) 类型 一个路径具有相同的方法检查节点的类型: @@ -1253,7 +1261,7 @@ BinaryExpression(path) { } ``` -### 检查标识符(Identifier)是否被引用 +### 检查标识符 (Identifier) 是否被引用 ```js Identifier(path) { @@ -1277,7 +1285,7 @@ Identifier(path) { 有时你需要从一个路径向上遍历语法树,直到满足相应的条件。 -对于每一个父路径调用`callback`并将其`NodePath`当作参数,当`callback`返回真值时,则将其`NodePath`返回。. +对于每一个父路径调用 `callback` 并将其 `NodePath` 当作参数,当 `callback` 返回真值时,则将其 `NodePath` 返回。 ```js path.findParent((path) => path.isObjectExpression()); @@ -1303,17 +1311,17 @@ path.getStatementParent(); ### 获取同级路径 -如果一个路径是在一个 `Function`/`Program`中的列表里面,它就有同级节点。 +如果一个路径是在一个 `Function` / `Program` 中的列表里面,它就有同级节点。 - * 使用`path.inList`来判断路径是否有同级节点, - * 使用`path.getSibling(index)`来获得同级路径, - * 使用 `path.key`获取路径所在容器的索引, - * 使用 `path.container`获取路径的容器(包含所有同级节点的数组) - * 使用 `path.listKey`获取容器的key + * 使用 `path.inList` 来判断路径是否有同级节点, + * 使用 `path.getSibling(index)` 来获得同级路径, + * 使用 `path.key` 获取路径所在容器的索引, + * 使用 `path.container` 获取路径的容器 (包含所有同级节点的数组) + * 使用 `path.listKey` 获取容器的 key -> 这些API用于 babel-minify 中使用的 transform-merge-sibling-variables 插件.

-> -> ```js +> 这些 API 用于 [babel-minify](https://github.com/babel/babili) 中使用的 [transform-merge-sibling-variables](https://github.com/babel/babili/blob/master/packages/babel-plugin-transform-merge-sibling-variables/src/index.js) 插件。 + +```js var a = 1; // pathA, path.key = 0 var b = 2; // pathB, path.key = 1 var c = 3; // pathC, path.key = 2 @@ -1347,9 +1355,9 @@ BinaryExpression(path) { } ``` -如果您在顶级路径中进行子遍历,则可以使用2个提供的API方法: +如果您在顶级路径中进行子遍历,则可以使用 2 个提供的 API 方法: -`path.skip()` skips traversing the children of the current path. `path.stop()` stops traversal entirely. +`path.skip()` 跳过遍历当前路径的子节点。`path.stop()` 完全停止遍历。 ```js outerPath.traverse({ @@ -1403,11 +1411,11 @@ ReturnStatement(path) { } ``` -> **注意:当用多个节点替换一个表达式时,它们必须是   声明。 这是因为Babel在更换节点时广泛使用启发式算法,这意味着您可以做一些非常疯狂的转换,否则将会非常冗长。

-> -> ### 用字符串源码替换节点 -> -> ```js +> **注意:** 当用多个节点替换一个表达式时,它们必须是语句声明。这是因为 Babel 在更换节点时广泛使用启发式算法,这意味着您可以做一些非常疯狂的转换,否则将会非常冗长。 + +### 用字符串源码替换节点 + +```js FunctionDeclaration(path) { path.replaceWithSourceString(`function add(a, b) { return a + b; @@ -1423,11 +1431,11 @@ FunctionDeclaration(path) { } ``` -> **注意:不建议使用这个API,除非您正在处理动态的源码字符串,否则在访问者外部解析代码更有效率。

-> -> ### 插入兄弟节点 -> -> ```js +> **注意:** 不建议使用这个 API,除非您正在处理动态的源码字符串,否则在访问者外部解析代码更有效率。 + +### 插入兄弟节点 + +```js FunctionDeclaration(path) { path.insertBefore(t.expressionStatement(t.stringLiteral("Because I'm easy come, easy go."))); path.insertAfter(t.expressionStatement(t.stringLiteral("A little high, little low."))); @@ -1442,14 +1450,14 @@ FunctionDeclaration(path) { + "A little high, little low."; ``` -> 注意:这里同样应该使用声明或者一个声明数组。 这个使用了在用多个节点替换一个节点中提到的相同的启发式算法。.

-> -> ### 插入到容器(container)中 -> -> 如果您想要在AST节点属性中插入一个像` body 那样的数组。 -它与 insertBefore `/` insertAfter ` 类似, 但您必须指定 ` listKey ` (通常是 ` 正文 `). -> -> ```js +> **注意:** 这里同样应该使用声明或者一个声明数组。这个使用了在用多个节点替换一个节点中提到的相同的启发式算法。 + +### 插入到容器 (container) 中 + +如果您想要在 AST 节点属性中插入一个像 如果您想要在AST节点属性中插入一个像 如果您想要在 AST 节点属性中插入一个像` body 那样的数组。 +它与 insertBefore `/` insertAfter ` 类似,但您必须指定 ` listKey ` (通常是 ` 正文 `)。 + +```js ClassMethod(path) { path.get('body').unshiftContainer('body', t.expressionStatement(t.stringLiteral('before'))); path.get('body').pushContainer('body', t.expressionStatement(t.stringLiteral('after'))); @@ -1482,14 +1490,15 @@ FunctionDeclaration(path) { ### 替换父节点 -只需使用parentPath:` path.parentPath 调用 replaceWith 即可

+只需使用 parentPath:`path.parentPath` 调用> `replaceWith` 即可 -
BinaryExpression(path) {
+```js
+BinaryExpression(path) {
   path.parentPath.replaceWith(
     t.expressionStatement(t.stringLiteral("Anyway the wind blows, doesn't really matter to me, to me."))
   );
 }
-`
+``` ```diff function square(n) { @@ -1512,7 +1521,7 @@ BinaryExpression(path) { } ``` -## Scope(作用域) +## Scope (作用域) ### 检查本地变量是否被绑定 @@ -1526,7 +1535,7 @@ FunctionDeclaration(path) { 这将遍历范围树并检查特定的绑定。 -您也可以检查一个作用域是否有**自己的绑定:

+您也可以检查一个作用域是否有**自己的**绑定: ```js FunctionDeclaration(path) { @@ -1551,14 +1560,15 @@ FunctionDeclaration(path) { ### 提升变量声明至父级作用域 -有时你可能想要推送一个` VariableDeclaration ,这样你就可以分配给它。

+有时你可能想要推送一个 `VariableDeclaration`,这样你就可以给他赋值。 -
FunctionDeclaration(path) {
+```js
+FunctionDeclaration(path) {
   const id = path.scope.generateUidIdentifierBasedOnNode(path.node.id);
   path.remove();
   path.scope.parent.push({ id, init: path.node });
 }
-`
+``` ```diff - function square(n) { @@ -1604,7 +1614,7 @@ FunctionDeclaration(path) { # 插件选项 -如果您想让您的用户自定义您的Babel插件的行为您可以接受用户可以指定的插件特定选项,如下所示: +如果您想让您的用户自定义您的 Babel 插件的行为您可以接受用户可以指定的插件特定选项,如下所示: ```js { @@ -1617,9 +1627,10 @@ FunctionDeclaration(path) { } ``` -这些选项会通过`状态对象传递给插件访问者:

+这些选项会通过 `state` 对象传递给插件访问者: -
export default function({ types: t }) {
+```js
+export default function({ types: t }) {
   return {
     visitor: {
       FunctionDeclaration(path, state) {
@@ -1629,7 +1640,7 @@ FunctionDeclaration(path) {
     }
   }
 }
-`
+``` 这些选项是特定于插件的,您不能访问其他插件中的选项。 @@ -1657,7 +1668,7 @@ export default function({ types: t }) { ## 在插件中启用其他语法 -插件可以启用babylon plugins,以便用户不需要安装/启用它们。 这可以防止解析错误,而不会继承语法插件。

+插件可以启用 babylon plugins,以便用户不需要安装/启用它们。这可以防止解析错误,而不会继承语法插件。 ```js export default function({ types: t }) { @@ -1669,7 +1680,7 @@ export default function({ types: t }) { ## 抛出一个语法错误 -如果您想用babel-code-frame和一个消息抛出一个错误: +如果您想用 babel-code-frame 和一个消息抛出一个错误: ```js export default function({ types: t }) { @@ -1699,15 +1710,15 @@ export default function({ types: t }) { # 构建节点 -编写转换时,通常需要构建一些要插入的节点进入AST。 如前所述,您可以使用` babel-types 包中的builder 方法。

- -

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

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

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

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

节点定义如下所示:

+这些构建器的参数由节点定义决定。有一些正在做的工作,以生成易于阅读的文件定义,但现在他们都可以在[此处](https://github.com/babel/babel/tree/master/packages/babel-types/src/definitions)找到。 -
defineType("MemberExpression", {
+节点定义如下所示:
+```js
+defineType("MemberExpression", {
   builder: ["object", "property", "computed"],
   visitor: ["object", "property"],
   aliases: ["Expression", "LVal"],
@@ -1726,20 +1737,20 @@ export default function({ types: t }) {
     }
   }
 });
-`
+``` 在这里你可以看到关于这个特定节点类型的所有信息,包括如何构建它,遍历它,并验证它。 -通过查看 ` 生成器 ` 属性, 可以看到调用生成器方法所需的3个参数 (` t. 情况 `). +通过查看 `builder` 属性,可以看到调用生成器方法所需的 3 个参数 (`t. memberExpression`)。 ```js -生成器: ["object", "property", "computed"], +builder: ["object", "property", "computed"], ``` -> 请注意,有时在节点上可以定制的属性比``构建器数组包含的属性更多。 这是为了防止生成器有太多的参数。 在这些情况下,您需要手动设置属性。 一个例子是 ClassMethod .

- +> 请注意,有时在节点上可以定制的属性比 `builder` 数组包含的属性更多。这是为了防止生成器有太多的参数。在这些情况下,您需要手动设置属性。一个例子是 `ClassMethod` -
// Example
+```js
+// Example
 // because the builder doesn't contain `async` as a property
 var node = t.classMethod(
   "constructor",
@@ -1749,11 +1760,11 @@ var node = t.classMethod(
 )
 // set it manually after creation
 node.async = true;
-``
-> -> You can see the validation for the builder arguments with the `fields` object. -> -> ```js +``` + +你可以通过 `fields` 对象进行 builder 的参数校验。 + +```js fields: { object: { validate: assertNodeType("Expression") @@ -1770,9 +1781,9 @@ fields: { } ``` -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`. +你可以看到 `object` 可以是一个 `Expression`,`property` 需要是 `Expression` 或者 `Identifier` 这取决于成员表达式是否是 `computed`,`computed` 只是一个布尔值,默认为 `false`。 -So we can construct a `MemberExpression` by doing the following: +我们可以通过下面这种方式创建一个 `MemberExpression`: ```js t.memberExpression( @@ -1782,21 +1793,21 @@ t.memberExpression( ); ``` -Which will result in: +这将输出: ```js object.property ``` -However, we said that `object` needed to be an `Expression` so why is `Identifier` valid? +然而,我们说 `object` 需要是一个 `Expression`,所以为什么 `Identifier` 是合法的? -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. +如果我们看一下 `Identifier` 的定义,我们可以看到它有一个 `aliases` 属性,说明它也是一个表达式。 ```js aliases: ["Expression", "LVal"], ``` -So since `MemberExpression` is a type of `Expression`, we could set it as the `object` of another `MemberExpression`: +因此,由于 `MemberExpression` 是 `Expression` 的一个类型,我们可以把它设置为另一个 `MemberExpression` 的 `object`。 ```js t.memberExpression( @@ -1808,23 +1819,23 @@ t.memberExpression( ) ``` -Which will result in: +这将会输出: ```js 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](https://github.com/babel/babel/tree/master/packages/babel-types/src/definitions) and you can see them [documented here](https://github.com/babel/babel/blob/master/doc/ast/spec.md) +你可以在这里找到所有实际的[定义](https://github.com/babel/babel/tree/master/packages/babel-types/src/definitions),你可以看到它们[在这里有记录](https://github.com/babel/babel/blob/master/doc/ast/spec.md)。 * * * # 最佳实践 -## Create Helper Builders and Checkers +## 创建 Helper Builders 和 Checkers -It's pretty simple to extract certain checks (if a node is a certain type) into their own helper functions as well as extracting out helpers for specific node types. +将某些检查 (如果一个节点是某种类型) 提取到一个的 helper function 中,以及为特定的节点类型提取出 helper function,是非常简单的。 ```js function isAssignment(node) { @@ -1836,15 +1847,15 @@ function buildAssignment(left, right) { } ``` -## 尽量避免遍历抽象语法树(AST) +## 尽量避免遍历抽象语法树 (AST) -Traversing the AST is expensive, and it's easy to accidentally traverse the AST more than necessary. This could be thousands if not tens of thousands of extra operations. +遍历 AST 的成本很高,而且很容易意外地遍历 AST 的次数超过必要的次数。这可能是数以千计甚至数以万计的额外操作。 -Babel optimizes this as much as possible, merging visitors together if it can in order to do everything in a single traversal. +Babel 尽可能地优化这一点,如果可以的话,将 Visitor 合并在一起,以便在一次遍历中完成所有工作。 ### 及时合并访问者对象 -When writing visitors, it may be tempting to call `path.traverse` in multiple places where they are logically necessary. +在编写访问者时,可能很想在多个地方调用 `path.traverse`,而这些地方在逻辑上是必要的。 ```js path.traverse({ @@ -1859,8 +1870,7 @@ path.traverse({ } }); ``` - -However, it is far better to write these as a single visitor that only gets run once. Otherwise you are traversing the same tree multiple times for no reason. +然而,把这些写成一个只被运行一次的访问者要好得多。否则你就会无缘无故地多次遍历同一棵树。 ```js path.traverse({ @@ -1875,7 +1885,7 @@ path.traverse({ ### 可以手动查找就不要遍历 -It may also be tempting to call `path.traverse` when looking for a particular node type. +当寻找一个特定的节点类型时,调用 `path.traverse` 可能也是很诱人的。 ```js const nestedVisitor = { @@ -1891,7 +1901,7 @@ const MyVisitor = { }; ``` -However, if you are looking for something specific and shallow, there is a good chance you can manually lookup the nodes you need without performing a costly traversal. +然而,如果你正在寻找一些具体的、浅层的东西,你很有可能手动查找你需要的节点,而不需要进行昂贵的遍历。 ```js const MyVisitor = { @@ -1905,7 +1915,7 @@ const MyVisitor = { ## 优化嵌套的访问者对象 -当您嵌套访问者(visitor)时,把它们嵌套在您的代码中可能是有意义的。 +当您嵌套访问者 (visitor) 时,把它们嵌套在您的代码中可能是有意义的。 ```js const MyVisitor = { @@ -1919,14 +1929,10 @@ const MyVisitor = { }; ``` -但是,每当调用`FunctionDeclaration()时都会创建一个新的访问者对象。 That can be costly, because Babel does some processing each time a new -visitor object is passed in (such as exploding keys containing multiple types, -performing validation, and adjusting the object structure). Because Babel stores -flags on visitor objects indicating that it's already performed that processing, -it's better to store the visitor in a variable and pass the same object each -time.

+但是,每当调用 `FunctionDeclaration()` 时都会创建一个新的访问者对象。这可能是昂贵的,因为 Babel 在每次有新的访客对象被传入时,Babel 都会进行一些处理 (比如对包含多种类型的键进行编码、执行验证,并调整对象的结构)。因为 Babel 将识别访客对象上的标志,表明它已经进行了这些处理。因此,最好是将 visitor 存储在一个变量中,每次传递相同的对象。 -
const nestedVisitor = {
+```js
+const nestedVisitor = {
   Identifier(path) {
     // ...
   }
@@ -1937,7 +1943,7 @@ const MyVisitor = {
     path.traverse(nestedVisitor);
   }
 };
-`
+``` 如果您在嵌套的访问者中需要一些状态,像这样: @@ -1957,7 +1963,7 @@ const MyVisitor = { }; ``` -您可以将它作为状态传递给`traverse()方法,并有权访问this`在访问者中。 +您可以将它作为状态传递给 `traverse()` 方法,然后你就可以在 visitor 中访问 `this`。 ```js const nestedVisitor = { @@ -1980,7 +1986,7 @@ const MyVisitor = { 有时候在考虑给定的转换时,可能会忘记给定的转换结构可以是嵌套的。 -例如,想象一下,我们想要查找`构造函数` ` ClassMethod ` ` Foo ` ` ClassDeclaration `. +例如,想象一下,我们想要查找 ` Foo ` ` ClassDeclaration ` 的 `constructor` ` ClassMethod `。 ```js class Foo { @@ -2008,9 +2014,10 @@ const MyVisitor = { } ``` -我们忽略了类可以嵌套的事实,使用遍历的话,上面我们也会得到一个嵌套的`构造函数:

+我们忽略了类可以嵌套的事实,使用遍历的话,上面我们也会得到一个嵌套的 `constructor`。 -
class Foo {
+```js
+class Foo {
   constructor() {
     class Bar {
       constructor() {
@@ -2019,16 +2026,16 @@ const MyVisitor = {
     }
   }
 }
-`
+``` ## 单元测试 -有几种主要的方法来测试babel插件:快照测试,AST测试和执行测试。 对于这个例子,我们将使用 jest ,因为它支持盒外快照测试。 我们在这里创建的示例是托管在这个 repo.

+有几种主要的方法来测试 babel 插件:快照测试,AST 测试和执行测试。对于这个例子,我们将使用 [jest](https://jestjs.io),因为它支持快照测试。我们在这里创建的示例是托管在这个 [repo](https://github.com/brigand/babel-plugin-testing-example)。 -首先我们需要一个babel插件,我们将把它放在src / index.js中。 +首先我们需要一个 babel 插件,我们将把它放在 `src/index.js` 中。 ```js -
module.exports = function testPlugin(babel) { +module.exports = function testPlugin(babel) { return { visitor: { Identifier(path) { @@ -2043,10 +2050,10 @@ const MyVisitor = { ### 快照测试 -接下来,用`` npm install --save-dev babel-core jest 安装我们的依赖关系, -那么我们可以开始写我们的第一个测试:快照。 快照测试允许我们直观地检查我们的babel插件的输出。 我们给它一个输入,告诉它一个快照,并将其保存到一个文件。 我们检查快照到git中。 这允许我们来看看我们什么时候影响了我们任何试用例子测试的输出。 它也给出了使用差异在拉请求的时候。 当然,您可以用任何测试框架来做到这一点,但是要更新一下快照就像jest -u 一样简单.

+接下来,用 `npm install --save-dev babel-core jest` 安装依赖,那么我们可以开始写我们的第一个测试快照。快照测试允许我们直观地检查我们的 babel 插件的输出。我们给它一个输入,告诉它创建一个快照,并将其保存到一个文件。我们放在 git 中。这使我们能够看到我们何时影响了我们任何测试案例的输出。它还可以在拉动请求中使用 diff。当然,您可以用任何测试框架来做到这一点,但是使用 jest,想要更新快照只需要 `jest -u`。 -
// src/__tests__/index-test.js
+```js
+// src/__tests__/index-test.js
 const babel = require('babel-core');
 const plugin = require('../');
 
@@ -2059,22 +2066,22 @@ it('works', () => {
   const {code} = babel.transform(example, {plugins: [plugin]});
   expect(code).toMatchSnapshot();
 });
-``
+``` -这给了我们一个快照文件在`` src / __ tests __ / __ snapshots __ / index-test.js.snap .

+这将在 `src/__test__/__snapshots__/index-test.js.snap` 创建一个快照文件。 -
exports[`test works 1`] = `
+```js
+exports[`test works 1`] = `
 "
 var bar = 1;
 if (bar) console.log(bar);"
 `;
-``
+``` -如果我们在插件中将“bar”更改为“baz”并再次运行,则可以得到以下结果: +如果我们在插件中将 “bar” 更改为 “baz” 并再次运行,则可以得到以下结果: ```diff -接收到的值与存储的快照1不匹配。 - +Received value does not match stored snapshot 1. - Snapshot + Received @@ -2086,26 +2093,28 @@ if (bar) console.log(bar);" +if (baz) console.log(baz);" ``` -我们看到我们对插件代码的改变如何影响了我们插件的输出 如果输出看起来不错,我们可以运行`jest -u 来更新快照。

+我们看到我们对插件代码的改变如何影响了我们插件的输出如果输出看起来不错,我们可以运行 `jest -u` 来更新快照。 -

AST 测试

+### AST 测试 -

除了快照测试外,我们还可以手动检查AST。 这是一个简单但是脆弱的例子。 对于更多涉及的情况,您可能希望利用Babel-遍历。 它允许您用访问者键指定一个对象,就像您使用插件本身。

+除了快照测试之外,我们还可以手动检查 AST。这是一个简单而又脆弱的例子。对于更复杂的情况,你可能希望利用 babel-traverse。它允许你用 visitor 键来指定一个对象,就像你对插件本身的使用一样。 -
it('contains baz', () => {
+```js
+it('contains baz', () => {
   const {ast} = babel.transform(example, {plugins: [plugin]});
   const program = ast.program;
   const declaration = program.body[0].declarations[0];
   assert.equal(declaration.id.name, 'baz');
   // or babelTraverse(program, {visitor: ...})
 });
-`
+``` ### Exec Tests -在这里,我们将转换代码,然后评估它的行为是否正确。 请注意,我们在测试中没有使用``assert。 这确保如果我们的插件做了奇怪的操作,如意外删除断言线,但测试仍然失败。

+这确保了如果我们的插件做了一些奇怪的事情,比如意外地删除了断言行,测试仍然会失败。 -
it('foo is an alias to baz', () => {
+```js
+it('foo is an alias to baz', () => {
   var input = `
     var foo = 1;
     // test that foo was renamed to baz
@@ -2119,13 +2128,13 @@ if (bar) console.log(bar);"
   var res = f();
   assert(res === 1, 'res is 1');
 });
-``
+``` -Babel核心使用类似的方法去获取快照和执行测试。

+Babel core 使用类似的[方法](https://github.com/babel/babel/blob/7.0/CONTRIBUTING.md#writing-tests)去获取快照和执行测试。 ### [`babel-plugin-tester`](https://github.com/kentcdodds/babel-plugin-tester) -这个包使测试插件更容易。 如果您熟悉ESLint的[ RuleTester](http://eslint.org/docs/developer-guide/working-with-rules#rule-unit-tests)您应该对这是熟悉的。 您可以看看[the docs](https://github.com/kentcdodds/babel-plugin-tester/blob/master/README.md)去充分了解可能的情况,但这里有一个简单的例子: +这个包使测试插件更容易。如果您熟悉 ESLint 的 [RuleTester](http://eslint.org/docs/developer-guide/working-with-rules#rule-unit-tests) 您应该对这是熟悉的。您可以看看[文档](https://github.com/kentcdodds/babel-plugin-tester/blob/master/README.md)去充分了解可能的情况,这里有一个简单的例子: ```js import pluginTester from 'babel-plugin-tester'; @@ -2154,8 +2163,4 @@ pluginTester({ }, }, }); -``` - -* * * - -> ***对于将来的更新,请跟随 @thejameskyle 和 @babeljs 的Twitter。

\ No newline at end of file +``` \ No newline at end of file diff --git a/translations/zh-Hans/user-handbook.md b/translations/zh-Hans/user-handbook.md index 2a9183ed..ab1680c8 100644 --- a/translations/zh-Hans/user-handbook.md +++ b/translations/zh-Hans/user-handbook.md @@ -4,7 +4,7 @@ [![cc-by-4.0](https://licensebuttons.net/l/by/4.0/80x15.png)](http://creativecommons.org/licenses/by/4.0/) -这本手册提供了多种语言的版本,查看 [自述文件](/README.md) 里的完整列表。 +这本手册提供了多种语言的版本,查看[自述文件](/README.md)里的完整列表。 # 目录 @@ -44,11 +44,11 @@ # 介绍 -Babel 是一个通用的多用途 JavaScript 编译器。通过 Babel 你可以使用(并创建)下一代的 JavaScript,以及下一代的 JavaScript 工具。 +Babel 是一个通用的多用途 JavaScript 编译器。通过 Babel 你可以使用 (并创建) 下一代的 JavaScript,以及下一代的 JavaScript 工具。 -作为一种语言,JavaScript 在不断发展,新的标准/提案和新的特性层出不穷。 在得到广泛普及之前,Babel 能够让你提前(甚至数年)使用它们。 +作为一种语言,JavaScript 在不断发展,新的标准 / 提案和新的特性层出不穷。在得到广泛普及之前,Babel 能够让你提前 (甚至数年) 使用它们。 -Babel 把用最新标准编写的 JavaScript 代码向下编译成可以在今天随处可用的版本。 这一过程叫做“源码到源码”编译, 也被称为转换编译(transpiling,是一个自造合成词,即转换+编译。以下也简称为转译)。 +Babel 把用最新标准编写的 JavaScript 代码向下编译成可以在今天随处可用的版本。这一过程叫做 “源码到源码” 编译,也被称为转换编译 (transpiling,是一个自造合成词,即转换 + 编译。以下也简称为转译)。 例如,Babel 能够将新的 ES2015 箭头函数语法: @@ -64,13 +64,13 @@ const square = function square(n) { }; ``` -不过 Babel 的用途并不止于此,它支持语法扩展,能支持像 React 所用的 JSX 语法,同时还支持用于静态类型检查的流式语法(Flow Syntax)。 +不过 Babel 的用途并不止于此,它支持语法扩展,能支持像 React 所用的 JSX 语法,同时还支持用于静态类型检查的流式语法 (Flow Syntax)。 更重要的是,Babel 的一切都是简单的插件,谁都可以创建自己的插件,利用 Babel 的全部威力去做任何事情。 *再进一步*,Babel 自身被分解成了数个核心模块,任何人都可以利用它们来创建下一代的 JavaScript 工具。 -已经有很多人都这样做了,围绕着 Babel 涌现出了非常大规模和多样化的生态系统。 在这本手册中,我将介绍如何使用 Babel 的内建工具以及一些来自于社区的非常有用的东西。 +已经有很多人都这样做了,围绕着 Babel 涌现出了非常大规模和多样化的生态系统。在这本手册中,我将介绍如何使用 Babel 的内建工具以及一些来自于社区的非常有用的东西。 > ***在 Twitter 上关注 [@thejameskyle](https://twitter.com/thejameskyle),第一时间获取更新。*** @@ -78,7 +78,7 @@ const square = function square(n) { # 安装 Babel -由于 JavaScript 社区没有统一的构建工具、框架、平台等等,因此 Babel 正式集成了对所有主流工具的支持。 从 Gulp 到 Browserify,从 Ember 到 Meteor,不管你的环境设置如何,Babel 都有正式的集成支持。 +由于 JavaScript 社区没有统一的构建工具、框架、平台等等,因此 Babel 正式集成了对所有主流工具的支持。从 Gulp 到 Browserify,从 Ember 到 Meteor,不管你的环境设置如何,Babel 都有正式的集成支持。 本手册的目的主要是介绍 Babel 内建方式的安装,不过你可以访问交互式的[安装页面](http://babeljs.io/docs/setup)来查看其它的整合方式。 @@ -100,7 +100,7 @@ $ npm install --global babel-cli $ babel my-file.js ``` -这将把编译后的结果直接输出至终端。使用 `--out-file` 或着 `-o` 可以将结果写入到指定的文件。. +这将把编译后的结果直接输出至终端。使用 `--out-file` 或着 `-o` 可以将结果写入到指定的文件。 ```sh $ babel example.js --out-file compiled.js @@ -108,7 +108,7 @@ $ babel example.js --out-file compiled.js $ babel example.js -o compiled.js ``` -如果我们想要把一个目录整个编译成一个新的目录,可以使用 `--out-dir` 或者 `-d`。. +如果我们想要把一个目录整个编译成一个新的目录,可以使用 `--out-dir` 或者 `-d`。 ```sh $ babel src --out-dir lib @@ -125,15 +125,15 @@ $ babel src -d lib 1. 在同一台机器上的不同项目或许会依赖不同版本的 Babel 并允许你有选择的更新。 2. 这意味着你对工作环境没有隐式依赖,这让你的项目有很好的可移植性并且易于安装。 -要在(项目)本地安装 Babel CLI 可以运行: +要在 (项目) 本地安装 Babel CLI 可以运行: ```sh $ npm install --save-dev babel-cli ``` -> **注意:**因为全局运行 Babel 通常不是什么好习惯所以如果你想要卸载全局安装的 Babel 的话,可以运行: -> -> ```sh +> **注意:** 因为全局运行 Babel 通常不是什么好习惯所以如果你想要卸载全局安装的 Babel 的话,可以运行: + +```sh $ npm uninstall --global babel-cli ``` @@ -151,7 +151,7 @@ $ npm uninstall --global babel-cli 现在,我们不直接从命令行运行 Babel 了,取而代之我们将把运行命令写在 **npm scripts** 里,这样可以使用 Babel 的本地版本。 -只需将 `"scripts"` 字段添加到你的 `package.json` 文件内并且把 babel 命令写成 `build` 字段。. +只需将 `"scripts"` 字段添加到你的 `package.json` 文件内并且把 babel 命令写成 `build` 字段。 ```diff { @@ -178,7 +178,7 @@ npm run build 下一个常用的运行 Babel 的方法是通过 `babel-register`。这种方法只需要引入文件就可以运行 Babel,或许能更好地融入你的项目设置。 -但请注意这种方法并不适合正式产品环境使用。 直接部署用此方式编译的代码不是好的做法。 在部署之前预先编译会更好。 不过用在构建脚本或是其他本地运行的脚本中是非常合适的。 +但请注意这种方法并不适合正式产品环境使用。直接部署用此方式编译的代码不是好的做法。在部署之前预先编译会更好。不过用在构建脚本或是其他本地运行的脚本中是非常合适的。 让我们先在项目中创建 `index.js` 文件。 @@ -186,9 +186,9 @@ npm run build console.log("Hello world!"); ``` -如果我们用 `node index.js` 来运行它是不会使用 Babel 来编译的。所以我们需要设置 `babel-register`。. +如果我们用 `node index.js` 来运行它是不会使用 Babel 来编译的。所以我们需要设置 `babel-register`。 -首先安装 `babel-register`。. +首先安装 `babel-register`。 ```sh $ npm install --save-dev babel-register @@ -209,9 +209,9 @@ require("./index.js"); $ node register.js ``` -> **注意:**你不能在你要编译的文件内同时注册 Babel,因为 node 会在 Babel 编译它之前就将它执行了。 -> -> ```js +> **注意:** 你不能在你要编译的文件内同时注册 Babel,因为 node 会在 Babel 编译它之前就将它执行了。 + +```js require("babel-register"); // 未编译的: console.log("Hello world!"); @@ -221,7 +221,7 @@ console.log("Hello world!"); 如果你要用 `node` CLI 来运行代码,那么整合 Babel 最简单的方式就是使用 `babel-node` CLI,它是 `node` CLI 的替代品。 -但请注意这种方法并不适合正式产品环境使用。 直接部署用此方式编译的代码不是好的做法。 在部署之前预先编译会更好。 不过用在构建脚本或是其他本地运行的脚本中是非常合适的。 +但请注意这种方法并不适合正式产品环境使用。直接部署用此方式编译的代码不是好的做法。在部署之前预先编译会更好。不过用在构建脚本或是其他本地运行的脚本中是非常合适的。 首先确保 `babel-cli` 已经安装了。 @@ -229,9 +229,9 @@ console.log("Hello world!"); $ npm install --save-dev babel-cli ``` -> **注意:** 如果您想知道我们为什么要在本地安装,请阅读 上面[在项目内运行Babel CLI](#toc-running-babel-cli-from-within-a-project)的部分。 +> **注意:** 如果您想知道我们为什么要在本地安装,请阅读上面[在项目内运行 Babel CLI](#toc-running-babel-cli-from-within-a-project) 的部分。 -然后用 `babel-node` 来替代 `node` 运行所有的代码 。. +然后用 `babel-node` 来替代 `node` 运行所有的代码。 如果用 npm `scripts` 的话只需要这样做: @@ -251,13 +251,13 @@ $ npm install --save-dev babel-cli + ./node_modules/.bin/babel-node script.js ``` -> 提示:你可以使用 [`npm-run`](https://www.npmjs.com/package/npm-run)。. +> 提示:你可以使用 [`npm-run`](https://www.npmjs.com/package/npm-run)。。 ## `babel-core` 如果你需要以编程的方式来使用 Babel,可以使用 `babel-core` 这个包。 -首先安装 `babel-core`。. +首先安装 `babel-core`。 ```sh $ npm install babel-core @@ -267,7 +267,7 @@ $ npm install babel-core var babel = require("babel-core"); ``` -字符串形式的 JavaScript 代码可以直接使用 `babel.transform` 来编译。. +字符串形式的 JavaScript 代码可以直接使用 `babel.transform` 来编译。。 ```js babel.transform("code();", options); @@ -289,7 +289,7 @@ babel.transformFileSync("filename.js", options); // => { code, map, ast } ``` -要是已经有一个 Babel AST(抽象语法树)了就可以直接从 AST 进行转换。 +要是已经有一个 Babel AST (抽象语法树) 了就可以直接从 AST 进行转换。 ```js babel.transformFromAst(ast, code, options); @@ -302,13 +302,13 @@ babel.transformFromAst(ast, code, options); # 配置 Babel -你或许已经注意到了,目前为止通过运行 Babel 自己我们并没能“翻译”代码,而仅仅是把代码从一处拷贝到了另一处。 +你或许已经注意到了,目前为止通过运行 Babel 自己我们并没能 “翻译” 代码,而仅仅是把代码从一处拷贝到了另一处。 这是因为我们还没告诉 Babel 要做什么。 > 由于 Babel 是一个可以用各种花样去使用的通用编译器,因此默认情况下它反而什么都不做。你必须明确地告诉 Babel 应该要做什么。 -你可以通过安装**插件(plugins)**或**预设(presets,也就是一组插件)**来指示 Babel 去做什么事情。 +你可以通过安装**插件 (plugins)** 或**预设 (presets,也就是一组插件)** 来指示 Babel 去做什么事情。 ## `.babelrc` @@ -323,13 +323,13 @@ babel.transformFromAst(ast, code, options); 这个文件就是用来让 Babel 做你要它做的事情的配置文件。 -> **注意:**尽管你也可以用其他方式给 Babel 传递选项,但 `.babelrc` 文件是约定也是最好的方式。 +> **注意:** 尽管你也可以用其他方式给 Babel 传递选项,但 `.babelrc` 文件是约定也是最好的方式。 ## `babel-preset-es2015` -我们先从让 Babel 把 ES2015(最新版本的 JavaScript 标准,也叫做 ES6)编译成 ES5(现今在大多数 JavaScript 环境下可用的版本)开始吧。 +我们先从让 Babel 把 ES2015 (最新版本的 JavaScript 标准,也叫做 ES6) 编译成 ES5 (现今在大多数 JavaScript 环境下可用的版本) 开始吧。 -我们需要安装 "es2015" Babel 预设: +我们需要安装 “es2015” Babel 预设: ```sh $ npm install --save-dev babel-preset-es2015 @@ -368,11 +368,11 @@ $ npm install --save-dev babel-preset-react ## `babel-preset-stage-x` -JavaScript 还有一些提案,正在积极通过 TC39(ECMAScript 标准背后的技术委员会)的流程成为标准的一部分。 +JavaScript 还有一些提案,正在积极通过 TC39 (ECMAScript 标准背后的技术委员会) 的流程成为标准的一部分。 -这个流程分为 5(0-4)个阶段。 随着提案得到越多的关注就越有可能被标准采纳,于是他们就继续通过各个阶段,最终在阶段 4 被标准正式采纳。 +这个流程分为 5 (0-4) 个阶段。随着提案得到越多的关注就越有可能被标准采纳,于是他们就继续通过各个阶段,最终在阶段 4 被标准正式采纳。 -以下是4 个不同阶段的(打包的)预设: +以下是 4 个不同阶段的 (打包的) 预设: * `babel-preset-stage-0` * `babel-preset-stage-1` @@ -381,7 +381,7 @@ JavaScript 还有一些提案,正在积极通过 TC39(ECMAScript 标准背 > 注意 stage-4 预设是不存在的因为它就是上面的 `es2015` 预设。 -以上每种预设都依赖于紧随的后期阶段预设。例如,`babel-preset-stage-1` 依赖 `babel-preset-stage-2`,后者又依赖 `babel-preset-stage-3`。. +以上每种预设都依赖于紧随的后期阶段预设。例如,`babel-preset-stage-1` 依赖 `babel-preset-stage-2`,后者又依赖 `babel-preset-stage-3`。。 使用的时候只需要安装你想要的阶段就可以了: @@ -435,9 +435,9 @@ function addAll() { Uncaught TypeError: Array.from is not a function -为了解决这个问题,我们使用一种叫做 [Polyfill(代码填充,也可译作兼容性补丁)](https://remysharp.com/2010/10/08/what-is-a-polyfill) 的技术。 简单地说,polyfill 即是在当前运行环境中用来复制(意指模拟性的复制,而不是拷贝)尚不存在的原生 api 的代码。 能让你提前使用还不可用的 APIs,`Array.from` 就是一个例子。 +为了解决这个问题,我们使用一种叫做 [Polyfill (代码填充,也可译作兼容性补丁)](https://remysharp.com/2010/10/08/what-is-a-polyfill) 的技术。简单地说,polyfill 即是在当前运行环境中用来复制 (意指模拟性的复制,而不是拷贝) 尚不存在的原生 api 的代码。能让你提前使用还不可用的 APIs,`Array.from` 就是一个例子。 -Babel 用了优秀的 [core-js](https://github.com/zloirock/core-js) 用作 polyfill,并且还有定制化的 [regenerator](https://github.com/facebook/regenerator) 来让 generators(生成器)和 async functions(异步函数)正常工作。 +Babel 用了优秀的 [core-js](https://github.com/zloirock/core-js) 用作 polyfill,并且还有定制化的 [regenerator](https://github.com/facebook/regenerator) 来让 generators (生成器) 和 async functions (异步函数) 正常工作。 要使用 Babel polyfill,首先用 npm 安装它: @@ -453,9 +453,9 @@ import "babel-polyfill"; ## `babel-runtime` -为了实现 ECMAScript 规范的细节,Babel 会使用“助手”方法来保持生成代码的整洁。 +为了实现 ECMAScript 规范的细节,Babel 会使用 “助手” 方法来保持生成代码的整洁。 -由于这些助手方法可能会特别长并且会被添加到每一个文件的顶部,因此你可以把它们统一移动到一个单一的“运行时(runtime)”中去。 +由于这些助手方法可能会特别长并且会被添加到每一个文件的顶部,因此你可以把它们统一移动到一个单一的 “运行时 (runtime)” 中去。 通过安装 `babel-plugin-transform-runtime` 和 `babel-runtime` 来开始。 @@ -507,7 +507,7 @@ let Foo = function () { * * * -# 配置 Babel(进阶) +# 配置 Babel (进阶) 大多数人使用 Babel 的内建预设就足够了,不过 Babel 提供了更多更细粒度的能力。 @@ -521,7 +521,7 @@ Babel 预设就是一些预先配置好的插件的集合,如果你想要做 $ npm install --save-dev babel-plugin-transform-es2015-classes ``` -然后往 `.babelrc` 文件添加 `plugins` 字段。. +然后往 `.babelrc` 文件添加 `plugins` 字段。 ```diff { @@ -533,13 +533,13 @@ $ npm install --save-dev babel-plugin-transform-es2015-classes 这能让你对正在使用的转换器进行更细致的控制。 -完整的官方插件列表请见 [Babel 插件页面](http://babeljs.io/docs/plugins/)。. +完整的官方插件列表请见 [Babel 插件页面](http://babeljs.io/docs/plugins/)。。 -同时也别忘了看看[由社区构建的其他插件](https://www.npmjs.com/search?q=babel-plugin)。 如果你想学习如何编写自己的插件可以阅读 [Babel 插件手册](plugin-handbook.md)。. +同时也别忘了看看[由社区构建的其他插件](https://www.npmjs.com/search?q=babel-plugin)。如果你想学习如何编写自己的插件可以阅读 [Babel 插件手册](plugin-handbook.md)。 ## 插件选项 -很多插件也有选项用于配置他们自身的行为。 例如,很多转换器都有“宽松”模式,通过放弃一些标准中的行为来生成更简化且性能更好的代码。 +很多插件也有选项用于配置他们自身的行为。例如,很多转换器都有 “宽松” 模式,通过放弃一些标准中的行为来生成更简化且性能更好的代码。 要为插件添加选项,只需要做出以下更改: @@ -552,11 +552,11 @@ $ npm install --save-dev babel-plugin-transform-es2015-classes } ``` -> 接下来几周内我会更新插件文档来详细介绍每一个选项。[关注我以获知更新](https://twitter.com/thejameskyle)。. +> 接下来几周内我会更新插件文档来详细介绍每一个选项。[关注我以获知更新](https://twitter.com/thejameskyle)。 ## 基于环境自定义 Babel -Babel 插件解决许多不同的问题。 其中大多数是开发工具,可以帮助你调试代码或是与工具集成。 也有大量的插件用于在生产环境中优化你的代码。 +Babel 插件解决许多不同的问题。其中大多数是开发工具,可以帮助你调试代码或是与工具集成。也有大量的插件用于在生产环境中优化你的代码。 因此,想要基于环境来配置 Babel 是很常见的。你可以轻松的使用 `.babelrc` 文件来达成目的。 @@ -577,7 +577,7 @@ Babel 插件解决许多不同的问题。 其中大多数是开发工具,可 Babel 将根据当前环境来开启 `env` 下的配置。 -当前环境可以使用 `process.env.BABEL_ENV` 来获得。 如果 `BABEL_ENV` 不可用,将会替换成 `NODE_ENV`,并且如果后者也没有设置,那么缺省值是`"development"`。. +当前环境可以使用 `process.env.BABEL_ENV` 来获得。如果 `BABEL_ENV` 不可用,将会替换成 `NODE_ENV`,并且如果后者也没有设置,那么缺省值是 `"development"`。 **Unix** @@ -593,15 +593,15 @@ $ SET BABEL_ENV=production $ [COMMAND] ``` -> **注意:**`[COMMAND]` 指的是任意一个用来运行 Babel 的命令(如:`babel`,`babel-node`,或是 `node`,如果你使用了 register 钩子的话)。 +> **注意:** `[COMMAND]` 指的是任意一个用来运行 Babel 的命令 (如:`babel`,`babel-node`,或是 `node`,如果你使用了 register 钩子的话)。 > -> **提示:**如果你想要让命令能够跨 unix 和 windows 平台运行的话,可以使用 [`cross-env`](https://www.npmjs.com/package/cross-env)。. +> **提示:** 如果你想要让命令能够跨 unix 和 windows 平台运行的话,可以使用 [`cross-env`](https://www.npmjs.com/package/cross-env)。 -## 制作你自己的预设(preset) +## 制作你自己的预设 (preset) 手动指定插件?插件选项?环境特定设置?所有这些配置都会在你的项目里产生大量的重复工作。 -为此,我们鼓励社区创建自己的预设。 这可能是一个针对特定 [node 版本](https://github.com/leebenson/babel-preset-node5)的预设,或是适用于你[整个](https://github.com/cloudflare/babel-preset-cf)[公司](https://github.com/airbnb/babel-preset-airbnb)的预设。. +为此,我们鼓励社区创建自己的预设。这可能是一个针对特定 [node 版本](https://github.com/leebenson/babel-preset-node5)的预设,或是适用于你[整个](https://github.com/cloudflare/babel-preset-cf)[公司](https://github.com/airbnb/babel-preset-airbnb)的预设。。 创建预设非常容易。比方说你这样一个 `.babelrc` 文件: @@ -617,7 +617,7 @@ $ [COMMAND] } ``` -你要做的就是依循命名约定 `babel-preset-*` 来创建一个新项目(请务必对这个命名约定保持责任心,也就是说不要滥用这个命名空间),然后创建两个文件。 +你要做的就是依循命名约定 `babel-preset-*` 来创建一个新项目 (请务必对这个命名约定保持责任心,也就是说不要滥用这个命名空间),然后创建两个文件。 首先,创建一个 `package.json`,包括针对预设所必要的 `dependencies`。 @@ -654,23 +654,23 @@ module.exports = { # Babel 和其他工具 -一旦你掌握的窍门,安装 Babel 还是十分简明的,不过和其他工具搭配在一起就会变得困难多了。 不过我们一直在与其他项目密切合作以确保这种体验尽可能简单。 +一旦你掌握的了窍门,设置 Babel 还是十分简明的,不过和其他工具搭配在一起就会变得困难多了。不过我们一直在与其他项目密切合作以确保这种体验尽可能简单。 ## 静态分析工具 新标准为语言带来了许多新的语法,静态分析工具正在将此利用起来。 -### 语法检查(Linting) +### 语法检查 (Linting) [ESLint](http://eslint.org) 是最流行的语法检查工具之一,因此我们维护了一个官方的 [`babel-eslint`](https://github.com/babel/babel-eslint) 整合软件包。 -首先安装 `eslint` 和 `babel-eslint`。. +首先安装 `eslint` 和 `babel-eslint`。 ```sh $ npm install --save-dev eslint babel-eslint ``` -然后创建或使用项目现有的 `.eslintrc` 文件并设置 `parser` 为 `babel-eslint`。. +然后创建或使用项目现有的 `.eslintrc` 文件并设置 `parser` 为 `babel-eslint`。 ```diff { @@ -706,9 +706,9 @@ $ npm run lint ### 代码风格 -> JSCS已经和ESLint合并,所以请查看ESLint的代码风格。 +> JSCS 已经和 ESLint 合并,所以请查看 ESLint 的代码风格。 -JSCS 是一个极受欢迎的工具,在语法检查的基础上更进一步检查代码自身的风格。 Babel 和 JSCS 项目的核心维护者之一([@hzoo](https://github.com/hzoo))维护着 JSCS 的官方集成。 +JSCS 是一个极受欢迎的工具,在语法检查的基础上更进一步检查代码自身的风格。Babel 和 JSCS 项目的核心维护者之一 ([@hzoo](https://github.com/hzoo)) 维护着 JSCS 的官方集成。 更妙的是,JSCS 自己通过 `--esnext` 选项实现了这种集成,于是和 Babel 的集成就简化成了直接在命令行运行: @@ -746,11 +746,11 @@ Documentation.js 使用 Babel 来支持所有最新的语法,包括用于在 ### React -React 已经大幅改变了他们的 API 以适应 ES2015 的类语法([此处了解更新的 API](https://babeljs.io/blog/2015/06/07/react-on-es6-plus))。 特别是 React 现在依赖 Babel 编译它的 JSX 语法且弃用了它原有的自定义工具。 你可以按照[上述说明](#babel-preset-react)安装 `babel-preset-react` 包来开始。. +React 已经大幅改变了他们的 API 以适应 ES2015 的类语法 ([此处了解更新的 API](https://babeljs.io/blog/2015/06/07/react-on-es6-plus))。特别是 React 现在依赖 Babel 编译它的 JSX 语法且弃用了它原有的自定义工具。你可以按照[上述说明](#babel-preset-react)安装 `babel-preset-react` 包来开始。 -React 社区采用 Babel 并围绕它来运行,现在社区已经创建了[大量的转换器(transforms)](https://www.npmjs.com/search?q=babel-plugin+react)。. +React 社区采用 Babel 并围绕它来运行,现在社区已经创建了[大量的转换器 (transforms)](https://www.npmjs.com/search?q=babel-plugin+react)。 -最令人瞩目的是 [`babel-plugin-react-transform`](https://github.com/gaearon/babel-plugin-react-transform) 插件,它集成了大量 [React 专用转换器](https://github.com/gaearon/babel-plugin-react-transform#transforms)可以启用诸如 *热模块重载*等其他调试工具。 +最令人瞩目的是 [`babel-plugin-react-transform`](https://github.com/gaearon/babel-plugin-react-transform) 插件,它集成了大量 [React 专用转换器](https://github.com/gaearon/babel-plugin-react-transform#transforms)可以启用诸如*热模块重载*等其他调试工具。 -## 文本编辑器和 IDEs(集成开发环境) +## 文本编辑器和 IDEs (集成开发环境) -通过 Babel 引入 ES2015,JSX,和流式语法固然是大有裨益,可如果你的文本编辑不支持那可就糟糕透了。 因此,别忘了为你的文本编辑器或是 IDE 安装 Babel 插件。 +通过 Babel 引入 ES2015,JSX,和流式语法固然是大有裨益,可如果你的文本编辑不支持那可就糟糕透了。因此,别忘了为你的文本编辑器或是 IDE 安装 Babel 插件。 * [Sublime Text](https://github.com/babel/babel-sublime) * [Atom](https://atom.io/packages/language-babel) @@ -777,19 +777,19 @@ React 社区采用 Babel 并围绕它来运行,现在社区已经创建了[大 # Babel 支持 -Babel 的社区非常庞大并且增长速度很快,伴随着我们成长的同时我们希望保证人们总能获取他们需要的所有资源。 所以我们提供了数种途径来提供支持。 +Babel 的社区非常庞大并且增长速度很快,伴随着我们成长的同时我们希望保证人们总能获取他们需要的所有资源。所以我们提供了数种途径来提供支持。 -谨记在所有的这些沟通渠道里我们都共同遵守一套[行为准则](https://github.com/babel/babel/blob/master/CODE_OF_CONDUCT.md)。 破坏准则的行为会被处理。 所以请阅读它并在与他人互动时注意自己的行为。 +谨记在所有的这些沟通渠道里我们都共同遵守一套[行为准则](https://github.com/babel/babel/blob/master/CODE_OF_CONDUCT.md)。破坏准则的行为会被处理。所以请阅读它并在与他人互动时注意自己的行为。 -同时我们也在寻求发展一个自我支持式的社区,为那些始终热诚奉献的人们。 如果别人问的问题你恰好知道答案,请不吝花费几分钟帮帮他们。 在此过程中也请尽力保持友善与相互理解。 +同时我们也在寻求发展一个自我支持式的社区,为那些始终热诚奉献的人们。如果别人问的问题你恰好知道答案,请不吝花费几分钟帮帮他们。在此过程中也请尽力保持友善与相互理解。 ## Babel 论坛 -[Discourse](http://www.discourse.org) 免费为我们提供了一个托管版本的论坛(我们爱死他们了!)。 如果你是个论坛控请不要错过 [discuss.babeljs.io](https://discuss.babeljs.io)。. +[Discourse](http://www.discourse.org) 免费为我们提供了一个托管版本的论坛 (我们爱死他们了!)。如果你是个论坛控请不要错过 [discuss.babeljs.io](https://discuss.babeljs.io)。 ## Babel 聊天 -无人不爱 [Slack](https://slack.com)。如果你正在寻求来自社区的即时支持,那就来 [slack.babeljs.io](https://slack.babeljs.io) 和我们聊天吧。. +无人不爱 [Slack](https://slack.com)。如果你正在寻求来自社区的即时支持,那就来 [slack.babeljs.io](https://slack.babeljs.io) 和我们聊天吧。