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/