Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便可以运行在当前和旧版本的浏览器或其余环境中。node
在计算机科学中,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。 它以树状的形式表现编程语言的语法结构,树上的每一个节点都表示源代码中的一种结构。 之因此说语法是“抽象”的,是由于这里的语法并不会表示出真实语法中出现的每一个细节。
对于AST
的相关介绍:
推荐的介绍连接:
Leveling Up One’s Parsing Game With ASTs
中文翻译: https://segmentfault.com/a/1190000038511186git
维基百科里的介绍: https://en.wikipedia.org/wiki/Abstract_syntax_treegithub
相关 api 能够参考文档: https://babeljs.io/docs/en/babel-core#parse
使用 babel 的 API 将代码解析成 ast:编程
var babel = require("@babel/core"); const code = `const a = 1 + 2;` // code 解析成 ast const result = babel.transformSync(code, {ast: true}); console.log(result.ast)
固然 ast 也能够转换成代码:segmentfault
const { code } = babel.transformFromAstSync(result.ast, { presets: ["minify"], babelrc: false, configFile: false,}); console.log(code)
在这个在线网站,你能够更加直接地看到 code 和 ast 的比较:
https://lihautan.com/babel-ast-explorer
const n = 1
的 ast:api
-program:Program{ sourceType:"module" -body:[ -VariableDeclaration { -declarations:[ -VariableDeclarator{ -id:Identifier{ name:"n" } -init:NumericLiteral{ -extra:{ rawValue:1 raw:"1" } value:1 } } ] kind:"const" } ] directives:[]}
var babel = require("@babel/core"); const code = 'const n = 1'; const output = babel.transformSync(code, { plugins: [ function myCustomPlugin() { return { visitor: { Identifier(path) { // 在这个例子里咱们将全部变量 `n` 变为 `x` if (path.isIdentifier({ name: 'n' })) { path.node.name = 'x'; } }, }, }; }, ],}); console.log(output.code); // const x = 1;
经过 babel 的插件咱们能够对代码进行随心因此的修改
关于 visitor
使用的是访问者模式, 在遍历阶段,babel会先进行深度优先遍从来访问AST的每个节点。你能够为访问指定一个回调函数,而后每当访问某个节点的时候,babel会调用这个函数,并给函数传入当前访问的节点。浏览器
如今咱们添加另外一个函数: NumericLiteral
, 在刚刚的 ast 中咱们能够看到 const n = 1
是有 NumericLiteral
此节点的babel
function myCustomPlugin() { return { visitor: { Identifier(path) { console.log('identifier'); }, NumericLiteral(path) { console.log('NumericLiteral'); }, }, }; }
运行 plugin.js
, 打印结果:编程语言
Identifier NumericLiteral const x = 1;
即在碰到此节点的时候 就会触发插件中对应节点的回调, 关于回调函数的 path 能够在此文档中查看: https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#pathside
在插件方法 NumericLiteral
上添加操做:
visitor: { // 省略其余方法 NumericLiteral(path) { console.log('NumericLiteral'); const newNode = babel.types.binaryExpression('+', babel.types.NumericLiteral(path.node.value), babel.types.NumericLiteral(10)); path.replaceWith(newNode); path.skip(); // 由于咱们新增长了一个 NumericLiteral, 因此插件会检测到, 而且又会触发此回调,形成无限循环 // skip 的做用就是跳过对当前路径子节点的访问 } }
这里咱们新建了一个 binaryExpression, 将 const x = 1
转换为 const x = 1 + 10
这是关于 babel.types
的文件: https://www.babeljs.cn/docs/babel-types
本文代码记录: https://github.com/Grewer/JsDemo/tree/master/babel2AST
https://lihautan.com/step-by-step-guide-for-writing-a-babel-transformation/