文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

聊聊Eslint 的 Disble、Enable 的注释配置是怎么实现的

2024-12-02 20:57

关注

不知道大家有没有用过 eslint 的注释的配置方式:

  1.  
  2. alert('foo'); 
  3. console.log('bar'); 
  4.  
  5.  
  6. // eslint-disable-next-line 
  7. alert('foo'); 

eslint 支持 eslint-disable、eslint-enable、eslint-disable-next-line 等指定某个 rule 是否生效的行内配置,叫做 inline config。

webpack 中也有这种配置方式,可以在动态引入一个模块的时候配置代码分割的方式,叫做 magic comment。

  1. import( 
  2.    
  3.    
  4.    
  5.   'module' 
  6. ); 

类似的,terser 也有这种机制,叫做 annotation,可以指定某个 api 是否是纯的,纯函数的话如果没用到可以直接删除。

  1. var a = React.createElement("div"null); 

可以看到,很多库都用到了这种通过注释来配置的方式,不管是叫 annotation 也好、magic comment 也好,或者 inline config 也好,都指的同一个东西。

既然是这么常见的配置方式,那么他们是怎么实现的呢?

注释中配置的实现原理

我们拿 eslint 的 inline config 的实现来看一下。

eslint 会把源码 parse 成 AST,然后对把 AST 传入一系列 rule 来做检查,检查结果会用 formatter 格式化后输出。

注释的配置是在哪一步生效的呢?

我简化了一下源码,是这样的:

  1. verify(text) { 
  2.     // parse 源码 
  3.     const ast = parse(text); 
  4.     // 调用 rule,拿到 lint 的问题 
  5.     const lintingProblems = runRules(ast); 
  6.     // 通过 AST 拿到注释中的配置 
  7.     const commentDirectives = getDirectiveComments(ast); 
  8.     // 根据注释中的配置过滤问题 
  9.     return applyDisableDirectives(lintingProblems, commentDirectives); 

可以看到,整体流程是:

也就是说 eslint 的 inline config 是在 lint 完 AST,拿到各种 problems 之后生效的,对 problems 做一次过滤。

那怎么从 AST 中取出 directives 的呢?又是怎么过滤 problems 的呢?

我们分别看一下。

从 AST 取出 directives 的源码简化以后是这样的:

  1. function getDirectiveComments(ast){ 
  2.     const directives = []; 
  3.     ast.comments.forEach(comment => { 
  4.         const match = /^[#@](eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(comment.trim()); 
  5.         if (match) { 
  6.             const directiveText = match[1]; 
  7.             ... 
  8.             directives.push({ type: xxx, line: loc.start.line, column: loc.start.column + 1, ruleId }); 
  9.         } 
  10.     } 
  11.     return directives; 

其实就是对 AST 中所有的 comments 的内容做一下正则的匹配,如果是支持的 directive,就把它收集起来,并且记录下对应的行列号。

之后就是对 problems 的过滤了。

简化后的源码是这样的:

  1. function applyDisableDirectives(problems, disableDirectives) { 
  2.     const filteredProblems = []; 
  3.  
  4.     const disabledRuleMap = new Map(); 
  5.  
  6.     let nextIndex = 0; 
  7.     for (const problem of problems) { 
  8.         // 对每一个 probelm,都要找到当前被禁用的 rule 
  9.         while ( 
  10.             nextIndex < disableDirectives.length && 
  11.             compareLocations(disableDirectives[nextIndex], problem) <= 0 
  12.         ) { 
  13.             const directive = disableDirectives[nextIndex++]; 
  14.  
  15.             switch (directive.type) { 
  16.                 case "disable"
  17.                     disabledRuleMap.set(directive.ruleId, directive); 
  18.                     break; 
  19.                 case "enable"
  20.                     disabledRuleMap.delete(directive.ruleId); 
  21.                     break; 
  22.             }        
  23.         } 
  24.         //如果 problem 对应的 rule 没有被禁用,则返回 
  25.         if (!disabledRuleMap.has(problem.ruleId)) { 
  26.             filteredProblems.push(problem); 
  27.         } 
  28.     } 
  29.     return filteredProblems; 
  30.  
  31. function compareLocations(itemA, itemB) { 
  32.     return itemA.line - itemB.line || itemA.column - itemB.column

我们理下思路:

我们要过滤掉 problems 中被 disabled 的 rule 报出的 problem,返回过滤后的 problems。

可以维护一个 disabledRuleMap,表示禁用的 rule。

对每一个 problem,都根据行列号来从 disableDirectives 中取出 directive 的信息,把对应的 rule 放入 disabledRuleMap。

然后看下该 problem 的 rule 是否是被禁用了,也就是是否在 disabledRuleMap 中,如果是,就过滤掉。

这样处理完一遍,返回的 problem 就是可以报出的了。

这就是 eslint 的 eslint-disable、eslint-enable、eslint-disable-next-line 等注释可以配置 rule 是否生效的原理。

eslint 是根据行列号找到对应的 comment 的,其实很多 AST 中会记录每个节点关联的 comment。

比如 babel 的 AST:

这样可以根据 AST 来取出注释,之后通过正则来判断是否是 directive。

通过行列号来查找 comment,通过 AST 找到关联的 comment,这是两种查找注释的方式。

总结

注释中的配置在 eslint、webpack、terser 等工具中都有应用,分别叫 inline config、magic comment、annotation,但都指的同一个东西。

它们都是找到 AST 中的 comments,通过正则匹配下是否是支持的 directive(指令),然后取出对应的信息。

找到 directive 之后,还要找到 directive 生效的地方,可以用两种方式来查找:一种是根据行列号的比较,一种是根据关联的 AST 来查找。

找到 directive 和对应生效的地方之后,就可以根据 directive 中的信息做各种处理了。

注释中的配置是一种比较常见的配置方式,适合一些局部的配置。理解了它们的实现原理,能够让我们更好的掌握这种机制。

 

来源:神光的编程秘籍内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯