当前位置: 首页 > 科技观察

Eslint的Fix函数中隐藏的算法题,可以用于面试_0

时间:2023-03-14 14:41:57 科技观察

我们知道eslint是支持fix的,在规则的--fix参数部分加上时,可以自动修复问题。你有没有想过这个功能是如何实现的?Babel也可以转换代码。和eslint生成代码的原理是一样的吗?Babelbabel分为解析、转换、生成三个步骤。AST代码在transform阶段转换后,AST会在generate阶段递归打印到目标代码中。generate的原理是根据每一个AST的信息递归拼接字符串:所以如果我们改变插件中的AST,最终的代码也会改变。eslinteslint的rule可以检查AST,然后通过context.report报错,同时指定如何修复:自定义规则格式如下:module.exports={meta:{fixable:true},create(context){return{//指定AST的类型ObjectExpression(node){//一系列检查context.report({node,message:'xxxhasanerror',loc:node.loc,*fix(fixer){yieldfixer.replaceTextRange([rangeStart,rangeEnd],'替换文本');}});}};}};fix选项用于通过fixerapi自动修复问题。修复程序具有以下可用API:insertTextAfter(nodeOrToken,text);insertTextAfterRange(range,text);insertTextBefore(nodeOrToken,text);insertTextBeforeRange(range,text);remove(nodeOrToken);removeRange(range);replaceText(nodeOrToken,text));replaceTextRange(range,text);便于记忆,分为增、删、改三种。加法分为前插和后插。每种类型都支持基于token或基于范围(下标范围)修改文本。AST中每个节点都保留了范围信息,即源代码的下标从哪里到哪里,这样可以根据范围修改代码,也可以根据找到范围后修改代码AST。知道什么范围做什么之后,怎么自动修改代码呢?下面是eslint中fix代码的源码://sourcecodeconstoriginalText=sourceCode.text;//第一个range的开头conststart=fixes[0].range[0];//最后一个的结尾rangeconstend=fixes[fixes.length-1].range[1];//被替换的文本lettext="";letlastPos=Number.MIN_SAFE_INTEGER;for(constfixoffixes){if(fix.range[0]>=0){//截取range左边的字符串,从当前range和上一个range的右边位置取大text+=originalText.slice(Math.max(0,start),lastPos),fix.range[0]);}//固定文本text+=fix.text;//范围右侧的位置lastPos=fix.range[1];}//用拼接的字符串替换字符串text+=originalText。slice(Math.max(0,start,lastPos),end)在范围内;其中一个比较有意思的点是当范围的两端有交点的时候:每一个fix都是针对一个线段(范围)以及有交点的时候怎么办,这个其实可以作为一个算法评估候选人的问题。从左到右应用fix,然后记录当前的rangeRight。应用下一段时,取rangeLeft和上一个rangeRight的最大值作为rangeLeft。这道题抽象出来之后,还是一道比较有意思的算法题。我觉得用来面试比较好,有真实的应用场景。回到正题,fix功能的实现是拼接各个范围的修改文本,然后替换源码字符串。综上所述,babel和eslint都可以修改代码。Babel在打印代码的时候会操作AST并生成不同的代码,而eslint支持对一些规则的自动修复,当启用--fix时会自动修复。babel生成代码的原理是递归打印AST并拼接字符串,所以如果AST发生变化,生成的代码也会发生变化。eslint修复代码的逻辑是替换一定范围的文本,然后拼接在一起。这与AST无关,所以eslint的fix函数是可选的。比较有意思的是eslint的多个规则返回的多个范围的修改是如何应用到代码的修改中的,有交集的时候怎么办。我觉得这道题可以作为一道算法题来考考面试官。