
不知道大家有没有用过 eslint 的注释的配置方式:
- /*eslint-disableno-alert,no-console*/
- alert('foo');
- console.log('bar');
- /*eslint-enableno-alert,no-console*/
- //eslint-disable-next-line
- alert('foo');
eslint 支持 eslint-disable、eslint-enable、eslint-disable-next-line 等指定某个 rule 是否生效的行内配置,叫做 inline config。
webpack 中也有这种配置方式,可以在动态引入一个模块的时候配置代码分割的方式,叫做 magic comment。
- import(
- /*webpackChunkName:"my-chunk-name"*/
- /*webpackMode:"lazy"*/
- /*webpackExports:["default","named"]*/
- 'module'
- );
类似的,terser 也有这种机制,叫做 annotation,可以指定某个 api 是否是纯的,纯函数的话如果没用到可以直接删除。
- vara=/*#__PURE__*/React.createElement("div",null);
可以看到,很多库都用到了这种通过注释来配置的方式,不管是叫 annotation 也好、magic comment 也好,或者 inline config 也好,都指的同一个东西。
既然是这么常见的配置方式,那么他们是怎么实现的呢?
注释中配置的实现原理
我们拿 eslint 的 inline config 的实现来看一下。
eslint 会把源码 parse 成 AST,然后对把 AST 传入一系列 rule 来做检查,检查结果会用 formatter 格式化后输出。
注释的配置是在哪一步生效的呢?
我简化了一下源码,是这样的:
- verify(text){
- //parse源码
- constast=parse(text);
- //调用rule,拿到lint的问题
- constlintingProblems=runRules(ast);
- //通过AST拿到注释中的配置
- constcommentDirectives=getDirectiveComments(ast);
- //根据注释中的配置过滤问题
- returnapplyDisableDirectives(lintingProblems,commentDirectives);
- }
可以看到,整体流程是:
- 把源码 parse 成 AST
- 调用 rule 对 AST 做检查,拿到 lint 的 problems
- 通过 AST 拿到注释中的 diectives
- 通过 directives 过滤 problems,就是最终需要报出的问题
也就是说 eslint 的 inline config 是在 lint 完 AST,拿到各种 problems 之后生效的,对 problems 做一次过滤。
那怎么从 AST 中取出 directives 的呢?又是怎么过滤 problems 的呢?
我们分别看一下。
从 AST 取出 directives 的源码简化以后是这样的:
- functiongetDirectiveComments(ast){
- constdirectives=[];
- ast.comments.forEach(comment=>{
- constmatch=/^[#@](eslint(?:-env|-enable|-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 的内容做一下正则的匹配,如果是支持的 directive,就把它收集起来,并且记录下对应的行列号。
之后就是对 problems 的过滤了。
简化后的源码是这样的:
- functionapplyDisableDirectives(problems,disableDirectives){
- constfilteredProblems=[];
- constdisabledRuleMap=newMap();
- letnextIndex=0;
- for(constproblemofproblems){
- //对每一个probelm,都要找到当前被禁用的rule
- while(
- nextIndex








发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。