# ast **Repository Path**: XiMoon/ast ## Basic Information - **Project Name**: ast - **Description**: ast - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2023-03-26 - **Last Updated**: 2023-03-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 1.抽象语法树(Abstract Syntax Tree) `webpack`和`Lint`等很多的工具和库的核心都是通过`Abstract Syntax Tree`抽象语法树这个概念来实现对代码的检查、分析等操作的。通过了解抽象语法树这个概念,你也可以随手编写类似的工具 ## 2.抽象语法树用途 - 代码语法的检查、代码风格的检查、代码的格式化、代码的高亮、代码错误提示、代码自动补全等等 - 如JSLint、JSHint对代码错误或风格的检查,发现一些潜在的错误 - IDE的错误提示、格式化、高亮、自动补全等等 - 代码混淆压缩 - UglifyJS2等 - 优化变更代码,改变代码结构使达到想要的结构 - 代码打包工具webpack、rollup等等 - CommonJS、AMD、CMD、UMD等代码规范之间的转化 - CoffeeScript、TypeScript、JSX等转化为原生Javascript ## 3.抽象语法树定义 这些工具的原理都是通过JavaScript Parser把代码转化为一颗抽象语法树(AST),这颗树定义了代码的结构,通过操纵这颗树,我们可以精准的定位到声明语句、赋值语句、运算语句等等,实现对代码的分析、优化、变更等操作 > 在计算机科学中,抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。 > Javascript的语法是为了给开发者更好的编程而设计的,但是不适合程序的理解。所以需要转化为AST来更适合程序分析,浏览器编译器一般会把源码转化为AST来进行进一步的分析等其他操作。 ![ast](http://img.zhufengpeixun.cn/ast.jpg) ## 4.JavaScript Parser - JavaScript Parser,把js源码转化为抽象语法树的解析器。 - 浏览器会把js源码通过解析器转为抽象语法树,再进一步转化为字节码或直接生成机器码。 - 一般来说每个js引擎都会有自己的抽象语法树格式,Chrome的v8引擎,firefox的SpiderMonkey引擎等等,MDN提供了详细SpiderMonkey AST format的详细说明,算是业界的标准。 ### 4.1 常用的JavaScript Parser有: - esprima - traceur - acorn - shift ### 4.2 esprima - 通过 esprima 把源码转化为AST - 通过 estraverse 遍历并更新AST - 通过 escodegen 将AST重新生成源码 ```js let esprima = require('esprima'); var estraverse = require('estraverse'); var escodegen = require("escodegen"); let code = 'function ast(){}'; let ast = esprima.parse(code); console.log(ast); estraverse.traverse(ast,{ enter(node){ node.name += '_ext'; } }); let generated = escodegen.generate(ast); console.log(generated); ``` ## 5. 转换箭头函数 ```js let babel = require('babel-core'); let types = require('babel-types'); const code = `const sum = (a,b)=>a+b`; const visitor = { ArrowFunctionExpression:{ enter(path) { let node = path.node; let expression = node.body; let params = node.params; //console.log(expression); let returnStatement = types.returnStatement(expression); let block = types.blockStatement([ returnStatement ]); let func = types.functionExpression(null,params, block,false, false); path.replaceWith(func); } } } const result = babel.transform(code,{ plugins:[ {visitor} ] }); console.log(result.code); ``` ## 6. babel插件 预计算简单表达式的插件 ```js const result = 1 + 2; ``` ```js const result = 3; ``` ```js let babel = require('babel-core'); let types = require('babel-types'); const visitor = { BinaryExpression(path){ let node = path.node; if(!types.isBinaryExpression(node))return; let result; let left = node.left; let right = node.right; if(!(isNaN(left.value) || isNaN(right.value))){ result = eval(left.value+node.operator+right.value); path.replaceWith(types.numericLiteral(result)); let parent = path.parentPath; parent && visitor.BinaryExpression.call(this,parent); } } } module.exports = function(babel){ return { visitor } } ``` ```js const babel = require('babel-core'); const result = babel.transform('const sum = 1+2+3',{ plugins:[ require('./plugin') ] }); console.log(result.code); ``` ## 7. webpack babel插件 ### 7.1 实现按需加载 ```js import { flatten } from "lodash" ``` ```js import flatten from "lodash/flatten"; ``` ### 7.2 babel配置 ```json { "presets":["react","stage-0","env"], "plugins":[ ["extract", {"library":"lodash"}], ["transform-runtime", {}] ] } ``` > 编译顺序为首先plugins从左往右然后presets从右往左 ### 7.3 babel插件 ```js let babel = require('babel-core'); let types = require('babel-types'); const visitor = { ImportDeclaration:{ enter(path,ref={opts:{}}){ const specifiers = path.node.specifiers; const source = path.node.source; if(ref.opts.library == source.value && !types.isImportDefaultSpecifier(specifiers[0])){ const declarations = specifiers.map((specifier,index)=>{ return types.ImportDeclaration( [types.importDefaultSpecifier(specifier.local)], types.StringLiteral(`${source.value}/${specifier.local.name}`) ) }); path.replaceWithMultiple(declarations); } } } } module.exports = function(babel){ return { visitor } } ``` ##备注 - [Babel 插件手册](https://github.com/brigand/babel-plugin-handbook/blob/master/translations/zh-Hans/README.md#asts) - [babel-types](https://github.com/babel/babel/tree/master/packages/babel-types) - [不同的parser解析js代码后得到的AST](https://astexplorer.net/) - [在线可视化的看到AST](http://resources.jointjs.com/demos/javascript-ast) - [babel从入门到入门的知识归纳](https://zhuanlan.zhihu.com/p/28143410) - [Babel 内部原理分析](https://octman.com/blog/2016-08-27-babel-notes/) - [babel-plugin-react-scope-binding](https://github.com/chikara-chan/babel-plugin-react-scope-binding)