Babylon-AST初探-代碼生成(Create)

  業餘時間寫了Babylon-AST的系列文章,這裏是第一篇,後面還有三篇。趁着今天有空都一塊兒發上來啦。vue

  最近想研究react小程序代碼的,後來感受跨度有些大,由於平時也會寫一些vue的代碼,並且vue小程序更接近一些,因此仍是先作了一個vue小程序的PoC。但是這些都不是重點啊,重點是在這一過程當中學習並使用了babylonAST。由於也是第一次接觸,因此想寫點筆記記錄一下,也但願能給你們一點參考。node

  代碼是寫出來的,必定必定多寫多練,因此我這裏仍是以實例代碼爲主,涉及到的點也是在vue小程序中用到的,或者是轉換的基礎。但是也會有不少超出此範圍的知識點,咱們這裏就先不作具體討論啦,這裏給出了一些參考資料,你們能夠參考下。react

涉及到的參考資料:git

  1. AST explorer: https://astexplorer.net/ 神器,閱讀和書寫AST操做全靠它
  2. Babel Plugin Handbook https://github.com/jamiebuild... 從這裏找到了一些API
  3. Babylon和babel-traverse詳解 https://github.com/xtx1130/bl... 其實也稱不上詳解,不過看到的比較早,算是篇啓蒙文章吧
  4. Babel types https://babeljs.io/docs/core-... 生成代碼時會大量用到

AST explorer查看代碼

  首先打開 https://astexplorer.net/ ,直接在代碼裏輸入1,查看基本效果。
圖片描述github

  咱們要作的只是代碼的轉換,這裏只需關心program.body部分便可(是否能夠操做tokens來更改代碼,尚未研究)。express

  如上圖,程序代碼裏只有一個表達式ExpressionStatement。點擊+展開,能夠看到內部的細節,以下圖:npm

圖片描述

  內部結構只有一個Literal,很是簡單。更復雜的代碼,咱們在後面再來解釋。小程序

AST 的CRUD(Create-Retrieve-Update-Delete)

1. Create

  實際上,Create是個相對複雜的操做,一般會結合RetrieveUpdate使用。能夠結合實際須要,選擇閱讀順序。數組

  首先,構造一個空的node工程,後續會基於該項目一步步拓展。babel

npm install babylon @babel/types @babel/generator @babel/traverse

測試代碼

const babylon = require('babylon')
const t = require('@babel/types')
const generate = require('@babel/generator').default
const traverse = require('@babel/traverse').default

const code = ''
const ast = babylon.parse(code)
// manipulate ast
const output = generate(ast, {}, code)  
console.log('Input \n', code)
console.log('Output \n', output.code)

由於這裏是空的code,因此InputOutput都沒有輸出,只是搭一個代碼結構。

構造一個1的代碼

  根據上面的兩個圖,只有1代碼由一個ExpressionStatement內嵌一個Literal組成。直接代碼以下,能夠參考下注釋。

const code = ''
const ast = babylon.parse(code)

// 生成literal
const literal = t.numericLiteral(1)
// 生成expressionStatement
const exp = t.expressionStatement(literal)  
// 將表達式放入body中
ast.program.body.push(exp)

const output = generate(ast, {}, code)
console.log('Input \n', code)
console.log('Output \n', output.code)

運行輸出

Input

Output
 1;

  這個例子中首先用到了t(babel-types)。能夠在 https://babeljs.io/docs/core-... 查看文檔。t裏面有類型判斷和生成實例等方法。
  如t.expressionStatement(literal)就是生成一個ExpressionStatement,這個函數要用到的參數在文檔中(https://babeljs.io/docs/core-... 有描述,但是文檔真心很差看,你們仍是根據AST explorer中查找對應的方法,而後在文檔看個參數就行了:

圖片描述

構造const a = 1的代碼

  上述1的代碼過於簡單,咱們來生成const a = 1的代碼。將const a = 1輸入到AST explorer中,查看語法樹信息以下圖:

圖片描述

  在這段代碼中涉及了VariableDeclaration, VariableDeclarator, Identifier, Literal幾個babel-typesLiteral中使用的是數字類型NumericLiteral。這時就能夠分別查看文檔了,好比:VariableDeclaration

圖片描述

  這個t.variableDeclaration有兩個參數kinddeclarations,第二個參數是個數組。

  根據語法樹,一層層的生成代碼以下:

const code = ''
const ast = babylon.parse(code)

// 生成 VariableDeclarator
const id = t.identifier('a')
const literal = t.numericLiteral(1)
const declarator = t.variableDeclarator(id, literal)

// 生成 VariableDeclaration
const declaration = t.variableDeclaration('const', [declarator])

// 將表達式放入body中
ast.program.body.push(declaration)

const output = generate(ast, {}, code)
console.log('Input \n', code)
console.log('Output \n', output.code)

執行結果以下:

Input

Output
 const a = 1;

Create總結

  根據AST explorer能夠完美生成代碼,常見的異常是參數沒有填對,特別是數組什麼的,必定要注意。多結合API文檔和從小的代碼片斷作起可以規避這類錯誤。

  最後,生成一個稍複雜一點的代碼。

function add(a, b) {
  return a + b
}

AST樹以下

圖片描述

  感興趣的同窗能夠先嚐試根據語法樹提示寫一寫,再看下面的對照代碼,若是上面看懂了其實寫這個真心不是很難了。

const code = ''
const ast = babylon.parse(code)

// BinaryExpression a + b
const binaryExp = t.binaryExpression('+', t.identifier('a'), t.identifier('b'))
const returnStatement = t.returnStatement(binaryExp)

// function body
const fnBody = t.blockStatement([returnStatement])
const params = [t.identifier('a'), t.identifier('b')]

const fnDeclaraton = t.functionDeclaration(t.identifier('add'), params, fnBody)
ast.program.body.push(fnDeclaraton)

const output = generate(ast, {}, code)
console.log('Input \n', code)
console.log('Output \n', output.code)

  以上,就是ASTCreate的介紹,想進一步學習的接着看後面幾篇文章哦

相關文章
相關標籤/搜索