业余时间写了Babylon-AST的系列文章,这里是第一篇,后面还有三篇。趁着今天有空都一块儿发上来啦。vue
最近想研究react
转小程序
代码的,后来感受跨度有些大,由于平时也会写一些vue
的代码,并且vue
和小程序
更接近一些,因此仍是先作了一个vue
转小程序
的PoC。但是这些都不是重点啊,重点是在这一过程当中学习并使用了babylon
的AST
。由于也是第一次接触,因此想写点笔记记录一下,也但愿能给你们一点参考。node
代码是写出来的,必定必定多写多练,因此我这里仍是以实例代码为主,涉及到的点也是在vue
转小程序
中用到的,或者是转换的基础。但是也会有不少超出此范围的知识点,咱们这里就先不作具体讨论啦,这里给出了一些参考资料,你们能够参考下。react
涉及到的参考资料:git
AST
操做全靠它API
首先打开 https://astexplorer.net/ ,直接在代码里输入1
,查看基本效果。github
咱们要作的只是代码的转换,这里只需关心program.body
部分便可(是否能够操做tokens来更改代码,尚未研究)。express
如上图,程序代码里只有一个表达式ExpressionStatement
。点击+
展开,能够看到内部的细节,以下图:npm
内部结构只有一个Literal
,很是简单。更复杂的代码,咱们在后面再来解释。小程序
实际上,Create
是个相对复杂的操做,一般会结合Retrieve
和Update
使用。能够结合实际须要,选择阅读顺序。数组
首先,构造一个空的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
,因此Input
和Output
都没有输出,只是搭一个代码结构。
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-types
,Literal
中使用的是数字类型NumericLiteral
。这时就能够分别查看文档了,好比:VariableDeclaration
这个t.variableDeclaration
有两个参数kind
和declarations
,第二个参数是个数组。
根据语法树,一层层的生成代码以下:
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)
以上,就是AST
的Create
的介绍,想进一步学习的接着看后面几篇文章哦