当前位置: 首页 > 后端技术 > Node.js

教你写几个实用的AST插件,非常有用

时间:2023-04-03 12:11:21 Node.js

BackgroundAST。今天下午在群里听了一位老哥做的AST分享,深信不疑。为了加深印象,写了个总结,顺便分享给大家,希望能给小伙伴们一些启发。AST是有用的,但是空谈是没有根据的,我们来看几个具体的案例。不说了:Vue=>ReactReact=>Vue的代码转换方式,再来看看一个可以无痛升级老版本React的工具:react-codemod代码地址:https://github.com/reactjs/re...这个工具非常强大而且简单易用。你只需要运行一行命令:npxreact-codemod[...options]这些都是使用AST。让我们继续今天的内容。本文主要内容包括:1理论:AST概念2实践:使用AST实现一个代码转换工具,将var转换为let3实践:使用AST实现一个Eslint插件,禁用console4实践:使用AST实现一个Babel插件,过滤Debugger1。AST基本概念什么是ASTAST是一种按照编程语言的语法呈现源代码结构的层次化程序表示,每个AST节点对应源代码的一项。在计算机科学中,abstractsyntax和abstractsyntaxtree其实就是源代码的抽象语法结构的树状表示。常用的浏览器将js代码转化为抽象的语法树,以供进一步分析等操作。因此,将js转化为抽象语法树更有利于程序分析。AST能做什么代码语法检查代码风格检查代码格式代码高亮代码错误提示代码自动补全等等。AST生成AST的三种方式遍历更新AST重新生成AST源码为了便于理解,我们来看一个具体的例子。顺便给大家介绍一个很有用的网站:https://astexplorer.net/例如:声明、变量、类型等信息一应俱全。而且这里还提供了多种插件模板供您选择:非常方便。让我们根据这个例子做一点练习。2.实践:用AST实现一个代码转换工具,将var转换为let例如,现在你要重构一个老项目,你需要把项目中的所有var都换成let,你会怎么做?手动更换?还是用工具一键替换?下面教大家一招:一键替换大法。首先,我想介绍一个大杀器:jscodeshiftjscodeshift是一个JavscriptCodemod工具,Codemod的官方解释是:Codemodisatool/librarytoassistyouwithlarge-scalecodebaserefactorsthatcanbepartiallyautomatedbutstillrequirehuman监督和偶尔的干预。jscodeshift也是基于esprima的,它可以很容易地通过路径遍历AST上的节点。现在我们开始替换项目中的var。首先,转到https://astexplorer.net编写代码。我们选择模板:jscodeshift官方例子,反转变量名:我们现在要改变量,这个工具很贴心的一点就是可以突出显示实时对比。现在,找到kind===var的对象并将其替换为let:得到以下代码:exportdefaultfunctiontransformer(file,api){constj=api.jscodeshift;returnj(file.source).find(j.VariableDeclaration,{kind:'var'}).forEach(path=>{constletStatement=j.variableDeclaration('let',path.node.declarations)j(path).replaceWith(letStatement)}).toSource();}这也有效:path.node.kind='let';//传入的其实是一个引用Effect:大功告成!如果我的项目中有几个文件也需要同样的操作:简单安装:sudonpminstall-gjscodeshift执行:jscodeshift-ttransform.js./src/demo.js--dry--print--dry这里加上--print--dry后,新生成的代码不会马上覆盖源文件--print是打印出来看看。在实际项目中,需要在独立的分支中进行操作。新生成代码后,需要你检查检查一遍,review没有问题后才能合并。3.使用AST实现一个Eslint插件,禁用控制台和上面类似,我们也可以做一个eslint插件,功能也很简单:当使用控制台时,会报错。预期效果://不使用控制台方法(at1:9)console.log('haha')//--------^这次我们选择babel-eslint模板。代码实现:constdisallowMethods=["log","info","warn","error","dir"];exportdefaultfunction(context){return{Identifier(node){constisConsoleMethod=disallowMethods.includes(node.name)&&node.parent.type==="MemberExpression"&&node.parent.object.name==="控制台";如果(!isConsoleMethod)返回;context.report({node,message:"不要使用控制台方法"});}};}实际效果:简单有效。但是如果你想玩一些花哨的操作,比如自定义一个日志,那就没必要做了。最后,你可以把这段代码打包成一个完整的插件:教你写Eslint插件,你可以自己练习。4.使用AST实现一个Babel插件,过滤debugger最后一个是在源码中过滤debugger,Transform我们选择babelv7插件,我们期望达到的效果是:vara=1debuggerfunctiontest(){debuggera++}调试器:vara=1;functiontest(){a++;}这也是一个非常有用的函数。代码实现:exportdefaultfunction(babel){const{types:t}=babel;return{name:"ast-transform",//不需要visitor:{DebuggerStatement(path){path.remove()}}};}实际效果:总结内容就这么多,没什么难度,重点是理论和介绍。还没有精通AST的同学,希望这篇文章能对你有所帮助。后面会有AST在我们实际项目中的应用,我也会写一篇实用的文章,敬请期待!以上。延伸阅读https://www.toptal.com/javasc...关注我如果你觉得这篇内容对你很有启发,那就关注我吧~更多精彩:聊一聊ESM、Bundleless、Vite、Snowpack的“无限清单”滚动优化《采访三轴》代码分割(上)《采访三轴》缓存(上)《采访三轴》缓存(下)《采访三轴》HTTP(上)《采访HTTP(下)》“三斧头”和“采访三斧头”的这个