不知道大家有没有用过eslint的注释配置方法:/*eslint-disableno-alert,no-console*/alert('foo');console.log('bar');/*eslint-enableno-alert,no-console*///eslint-disable-next-linealert('foo');eslint支持eslint-disable,eslint-enable,eslint-Disable-next-line等指定某条规则是否生效的内联配置称为inlineconfig。webpack中也有这种配置方式,可以配置动态引入模块时的代码拆分方式,称为magiccomment。import(/*webpackChunkName:"my-chunk-name"*//*webpackMode:"lazy"*//*webpackExports:["default","named"]*/'module');同样的,terser也有这种机制叫做annotation,可以指定一个api是否纯。如果没有使用纯函数,可以直接删除。vara=/*#__PURE__*/React.createElement("div",null);可以看到很多库都是通过注解来使用这种配置方式的,不管是叫注解,还是魔术注释,或者是Inlineconfig,或者两者都指的是同一个东西。既然是这么普通的配置方法,那他们是怎么实现的呢?对于注释中配置的实现原理,我们先看看eslint的inlineconfig的实现。eslint会将源代码解析成AST,然后将AST传递给一系列的规则进行检查,检查结果会用formatter进行格式化并输出。评论配置在哪一步生效?我简化了源码,是这样的:verify(text){//解析源码constast=parse(text);//调用规则获取lint问题constlintingProblems=runRules(ast);//得到TheconfigurationinthecommentthroughASTconstcommentDirectives=getDirectiveComments(ast);//根据注释中的配置过滤问题调用rule检查AST,得到lint问题,通过AST得到annotations中的dictives,通过directives过滤问题,就是最后需要报告的问题。如果在问题后生效,就对问题做过滤。那么如何从AST中提取指令呢?你如何过滤问题?让我们分别来看一下。从AST中获取的指令的源代码被简化如下:启用|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(comment.trim());if(match){constdirectiveText=match[1];...directives.push({type:xxx,line:loc.start.line,column:loc.start.column+1,ruleId});}}returndirectives;}实际上是为了AST对comments中的所有内容做正则匹配,如果是支持的指令,就收集起来,记录对应的行列号,之后就是问题的过滤了。简化的源代码如下:.length&&compareLocations(disableDirectives[nextIndex],problem)<=0){constdirective=disableDirectives[nextIndex++];switch(directive.type){case"disable":disabledRuleMap.set(directive.ruleId,directive);break;case"启用":disabledRuleMap.delete(directive.ruleId);break;}}//如果问题对应的规则没有被禁用,则返回if(!disabledRuleMap.has(problem.ruleId)){filteredProblems.push(problem);}}returnfilteredProblems;}functioncompareLocations(itemA,itemB){returnitemA.line-itemB.line||itemA.column-itemB.column;}梳理一下思路:我们需要过滤掉disabledruleproblem上报的问题,returns过滤后的问题。可以维护一个disabledRuleMap来表示禁用的规则。对于每一个问题,根据行列号从disableDirectives中取出指令信息,将对应的rule放入disabledRuleMap中。然后查看问题的规则是否被禁用,即是否在disabledRuleMap中,如果是则过滤掉。处理一次后,可以报告返回的问题。这是eslint的eslint-disable、eslint-enable、eslint-disable-next-line等注解可以配置规则是否生效的原理。eslint根据行号和列号找到对应的评论。事实上,许多AST记录了与每个节点关联的注释。比如babel的AST:这样就可以根据AST提取注释,然后通过正则化来判断是否是指令性的。按行号和列号查找注释,按AST查找关联注释。这是查找评论的两种方法。总结注释中的配置在eslint、webpack、terser等工具中使用。它们分别被称为inlineconfig、magiccomment和annotation,但它们指的是同一个东西。他们都是在AST中找到注释,通过正则匹配检查是否是supporteddirective(指令),然后取出相应的信息。找到指令后,需要找到指令生效的地方。可以使用两种方式来查找:一种是比较行列号,另一种是根据关联的AST来查找。找到指令和对应的有效位置后,就可以根据指令中的信息进行各种处理了。注释中的配置是比较常用的配置方式,适用于一些本地的配置。了解它们的实现原理可以让我们更好地掌握这个机制。
