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

No-Func-Assign使用Eslint插件和Babel插件来实现

时间:2023-03-13 11:34:24 科技观察

Eslint有很多内置的规则,其中一个叫做no-func-assign,意思是函数不能赋值,目的是为了避免职能被重新分配。调用时出错。有两种方法可以实现此规则。我们使用Babel插件和Eslint插件来实现它。思维分析的目的是检查声明函数的重新分配。有两种思路:第一种方式是找到作用域内所有的函数声明,分析被引用的地方,如果是赋值语句就报错。第二种思路,反向查找所有的赋值语句,如果scope中左边变量的声明是一个函数,就会报错。Eslint这条规则的源码是用第一个思路实现的,我们使用Babel插件来实现第二个思路。Babel插件按照第二种思路实现lint,首先找到所有的赋值语句:constnoFuncAssignLint=(api,options)=>{return{visitor:{AssignmentExpression(path,state){}}}};module.exports=noFuncAssignLint;然后使用path.scope的作用域相关API,找到作用域左边部分的声明,也就是绑定,然后判断声明的类型是否为函数,如果是,则报错。constnoFuncAssignLint=(api,options)=>{return{visitor:{AssignmentExpression(path,state){constassignTarget=path.get('left').toString();constbinding=path.scope.getBinding(assignTarget);if(binding){if(binding.path.isFunctionDeclaration()||binding.path.isFunctionExpression()){//报错..}}}}}}};module.exports=noFuncAssignLint;Babel插件可以声明AST类型processingvisitor,遍历的时候会调用,里面可以进行AST的解析和转换。提供了path的API用于AST的增删改查,path.scope的API用于作用域解析。基于path和path.scope的API可以完成各种解析和转换功能。Eslint插件实现了lint的规则,本来就是用eslint实现的,也是基于第一个思路。也就是找到所有的函数声明,然后分析引用,如果是赋值就报错。eslint的规则包括两部分:meta部分是原始信息,包括文档、错误信息等。create部分是lint功能module.exports={meta:{type:"problem",docs:的实现{描述:“disallowreassigning`function`声明”,推荐:true,url:“https://eslint.org/docs/rules/no-func-assign”},模式:[],消息:{isAFunction:“'{{name}}'是一个函数。"}},create(context){functioncheckForFunction(node){}return{FunctionDeclaration:checkForFunction,FunctionExpression:checkForFunction};}};我们声明函数声明FunctionDeclaration和函数表达式FunctionExpression的处理,也就是通过contextapi到scope中的declaration,然后判断引用。如果引用的是赋值语句,则会报错。functioncheckForFunction(node){context.getDeclapanredVariables(node).forEach(checkVariable);}functioncheckVariable(variable){if(variable.defs[0].type==="FunctionName"){checkReference(variable.references);}}functioncheckReference(references){//如果是赋值语句如astUtils.getModifyingReferences(references).forEach(reference=>{context.report({node:reference.identifier,messageId:"isAFunction",data:{name:reference.identifier.name}});});}Eslint插件可以声明要处理的AST类型的监听器,遍历时会调用,可以对AST进行各种分析,然后上报一个错误。提供了contextAPI来分析ast,比如作用域分析,还提供了context.report来进行报错。Babel插件和Eslint插件的区别Babel和Eslint都是将源码解析成AST,然后遍历AST进行处理。Babel中的AST处理函数称为visitor,可以用来分析和修改AST。在Eslint中称为listener,因为它只能解析AST,不能修改。Babel插件提供了用于增删改AST的pathapi,以及用于分析作用域的path.scopeapi,包括声明和引用。Eslint插件提供了contextAPI,用于分析作用域等。Eslint的AST包含token信息,可用于格式检查,如空格、换行等,而Babel的AST没有,所以格式检查只能用Eslint实现。Eslint插件支持fix修改代码,但不是通过修改AST来实现的,而是通过字符串替换指定如何修改某个范围。综上所述,我们分析了两个围绕Eslint内置规则no-func-assign的思路,分别用Babel插件和Eslint插件实现。其实主要是作用域分析,Eslint插件和Babel插件都支持。Eslint和Babel插件的功能都是基于AST的,只不过Babel做的是AST的解析和转换,而Eslint只做AST的解析(包括格式检查)。需要注意的是,Eslint的fix函数并没有修改AST实现,只是简单的字符串替换。Eslint插件、Babel插件等都是基于AST实现的。他们有很多同质的部分,可以对比学习。