一款检测代码中TODO的eslint插件
一款检测代码中TODO的eslint插件
前言
看了我标题进来的同学应该也知道我做的是个啥东西
没错是一个eslint插件,前端魔法师们日常所使用的工具之一
什么?你不知道eslint是干嘛的--吃鲸.jpg
- ESLint 是一个开源的 JavaScript 代码检查工具
- 能在多人协作项目中帮助统一代码风格
因为在工作中临时会插入许多其它的事,或者有些代码,接口是有时效性的需要手动下线
插件功能简单讲就是为不完善的代码做标记,提醒自己如期修改完善bug
想亲自尝试一下的同学戳这里---顺手Star
下面开始介绍为什么会写这个插件,以及过程中遇到的问题,和插件的一些核心方法
背景
前端魔法师们,经常不经意间就会在代码中下毒,坑害同事,甚至直接使"线上爆炸"
当时遇到一个线上问题就是如此:
- 一个有实效性的活动入口,需要到点下线,一个需要常驻的活动入口,不需要下线
- 由于实效性活动下线时间还有大半年
coder为了图方便,直接把实效性活动业务组件拿着复用,想着到时候改,反正时间还长
半年后的一天,客述就来了,说xx入口怎么不见了,彼时开发此页面的同事已经调走,目前的项目组基本都是后来的
第一反应是不是昨晚提交了什么代码,把入口吓掉了,然后就开始翻发布记录,发现并没有发版,就奇怪了,好好地怎么就不见了
然后同事们就开始排查代码了,不一会儿就发现了问题所在,然后快速的改掉上线,避免影响扩大
事后复盘
- Leader: 咱能不能用啥工具避免此类问题发生
- 菜鸡: 阿巴阿巴一堆话
- Leader: 那行你说了这么多,这个任务就交给你了,下周给个方案
- 菜鸡: ...哦豁,要被卷铺盖走人了
个人思考
在不完善的代码或有时效性的代码处搞一个flag,通过工具检测这个flag然后提醒此项目的所有开发者
开发者打开这个项目就能知道xx flag处有隐患
调研-可行方案
cli工具
项目启动后,跑一个npm script
扫描目标文件,然后通过正则匹配flag关键字基于提示
vs code插件
前端魔法师基本都用的Vs Code
项目启动后,自动扫描目标文件
通过正则匹配flag,然后基于提示
这个有现成的todo-tree
eslint规则
前端项目都会引入eslint 来统一团队成员的编码风格
只要编写一个自定义的规则,通过分析eslint 提供的AST,就能轻易的拿到标记的flag
对比
方案 | 优点 | 缺点 | 学习成本 |
---|---|---|---|
cli工具 | 不限制语言/文件类型,通过正则就能进行轻易的匹配 | 需要为每个项目单独编写一个指令,通过hook或者人工触发 | |
vs code插件 | 只需要用户为编辑器安装一个插件,即可在打开的时候进行提示 | 魔法师们可能用sublime/webStorm ,需要重复开发插件 | |
eslint规则 | 只需要在项目的配置文件中加入一行规则代码,即可实时的提示 | 需要安装依赖,首次需要手动引入 |
最终选择
基于eslint编写一个eslint-plugin来实现自定义校验规则
原因
- 前端项目都会引入eslint
- 不限制编辑器
- 理论上不限制前端开发常用的语言/框架的检测
- 标准化团队统一了所有仓库的lint规则,只需在标准化规则中加入即可
- 其余仓库,只要执行依赖安装(yarn/npm i) 就会将最新的规则引入项目,使用者能0配置接入
实现过程
下面会展开介绍插件的实现原理,会涉及到一些代码的展示
首先eslint会将响应的文件用AST描述出来,并且提供了一些简单的API进行操作
create(context) {
// 取得AST
const sourceCode = context.getSourceCode()
// 获取所有的注释节点
let comments = sourceCode.getAllComments()
}
注释节点有两种
// 注释
/**
* Block
**/
从注释节点中过滤出以flag关键字开始的注释节点
// 过滤出包含关键词的注释节点
comments = comments.filter(comment => {
let { value, type } = comment
// 展平块状注释
if (type === 'Block') {
value = value.replace(/\*|\n/g, '')
}
value = value.toLowerCase().trim()
// 保存格式化后的字符串
comment.newValue = value
for (const flag of dFlag) {
// 检测是否一关键字开头
if (value.startsWith(flag)) {
// 保存上flag
comment.flag = flag
return true
}
}
return false
})
此时过滤后的注释基本格式如下
// flag ddl:time xxxxx
接下来从中解析出ddl和提示信息
首先ddl也是一个可配置的关键字
需要检测的日期格式如下
format1 | demo | format2 | demo | format3 | demo |
---|---|---|---|---|---|
yyyy-mm-dd | 2020-06-01 | yyyy/mm/dd | 2020/06/01 | yyyymmdd | 20200601 |
2020-06-1 | 2020/06/1 | 200601 | |||
2020-6-01 | 2020/6/01 | ||||
20-06-01 | 20/06/01 | ||||
20-6-1 | 20/6/1 | ||||
20-6-01 | 20/6/01 |
所以代码中做了许多判断
- 代码可能有点shi,看官们可以给点建议优化下
// 匹配日期的正则
const rDate = [{
reg: /((\d{4})|(\d{2}))(-((0\d)|(\d{2})|(\d{1}))){2}/,
flag: '-' // yyyy-mm-dd|yy-mm-dd
},
{
reg: /((\d{4})|(\d{2}))(\/((0\d)|(\d{2})|(\d{1}))){2}/,
flag: '/'// yyyy/mm/dd|yy/mm/dd
},
{
reg: /(\d{8})|(\d{6})/,
flag: 'number'// yyyymmdd|yymmdd
}]
/**
* 获取TODO注释中的DDL,是则返回日期值及其todo内容
* @param {String} value 待操作字符串
* @param {String[]} ddlSymbol 截止时间标识符
* @param {STring} todoSymbol
* @return {Object}
*/
function getDDLAndText(value, ddlSymbol, todoSymbol) {
let text = value.slice(value.indexOf(ddlSymbol) + ddlSymbol.length),
date = ''
for (const rdate of rDate) {
const { reg, flag } = rdate
const res = text.match(reg)
if (res) {
const [dateStr] = res
// 再次校验匹配的日期日期是否合法
if (reg.test(dateStr)) {
let year, month, day
if (flag !== 'number') {
let ymd = dateStr.split(flag)
ymd = ymd.map(v => {
return v.length === 1 ? `0${v}` : v
})
year = ymd[0]
month = ymd[1]
day = ymd[2]
} else {
const { length } = dateStr
day = dateStr.slice(length - 2)
month = dateStr.slice(length - 4, length - 2)
year = dateStr.slice(0, length - 4)
}
if (year.length === 2) {
year = new Date().getFullYear().toString().slice(0, 2) + year
}
text = text.slice(text.indexOf(dateStr) + dateStr.length)
date = `${year}-${month}-${day}`
// 日期不合格也pass掉
if (month > 12 || day > 31) {
date = ''
}
break
}
}
}
return {
text,
date
}
}
这样就拿到了flag的截止日期与内容
接下来只需要根据设置的时间警戒线进行提示即可
// 未设置DDL或者DDL不合法情况
if (!date) {
errMsg = '没有设置有效的Deadline,设置方法(https://github.com/ATQQ/eslint-plugin-todo-ddl)'
} else {
const TODODate = new Date(date).getTime()
const interval = TODODate - Date.now()
// 如果已经到期
if (interval < 0 || interval < oneDay) {
errMsg = '已经过截止日期,请立即修改'
} else {
// 剩余天数(向下取整)
const theRestDays = ~~(interval / oneDay)
errMsg = theRestDays <= dWarnLine ? `还有${theRestDays}天截止,请尽快修改` : ''
}
}
if (errMsg) {
context.report({
node: comment,
message: `TODO WARN: ${errMsg} --> ${text}`
})
}
到此就大工搞成了,可以发包上线了
总结思考
不足之处
- 代码还有可改进之处
- 插件上线后并没大改过,功能感觉还可以增强,需要朋友们多给点意见
收获
- leader还是评价不错,毕竟那时候实习生身份刚入职几天
- 自己也有所提升,对eslint的工作原理有了新的认识
- 也为团队日后各种花式校验规则提供了技术积累
未来
- 找时间根据反馈,迭代一下插件,提高其可玩性
其它
一款检测代码中TODO的eslint插件的更多相关文章
- vscode中检测代码中的空白行并去除的方法【转】
按下ctrl+h键进行正则匹配:^\s*(?=\r?$)\n 然后直接替换,再看代码发现空行已经不见了.
- 检测浏览器中是否有Flash插件
由于IE和非IE浏览器检测方式不同,所以代码如下 function hasPlugin(name){ debugger; name = name.toLowerCase(); for(var i=0; ...
- 【转】代码中特殊的注释技术——TODO、FIXME和XXX的用处
(转自:http://blog.csdn.net/reille/article/details/7161942) 作者:reille 本博客网址:http://blog.csdn.net/reille ...
- 如何解救在异步Java代码中已检测的异常
Java语言通过已检测异常语法所提供的静态异常检测功能非常实用,通过它程序开发人员可以用很便捷的方式表达复杂的程序流程. 实际上,如果某个函数预期将返回某种类型的数据,通过已检测异常,很容易就可以扩展 ...
- 代码中特殊的注释技术——TODO、FIXME和XXX的用处
本文内容概要: 代码中特殊的注释技术--TODO.FIXME和XXX的用处. 前言:今天在阅读Qt Creator的源代码时,发现一些注释中有FIXME英文单词,用英文词典居然查不到其意义!实际上, ...
- 带你开发一款给Apk中自动注入代码工具icodetools(完善篇)【申明:来源于网络】
带你开发一款给Apk中自动注入代码工具icodetools(完善篇)[申明:来源于网络] 带你开发一款给Apk中自动注入代码工具icodetools(完善篇):http://blog.csdn.net ...
- 编程风格——代码中特殊的注释技术——TODO、FIXME和XXX的用处
代码中特殊的注释技术——TODO.FIXME和XXX的用处 前言:今天在阅读Qt Creator的源代码时,发现一些注释中有FIXME英文单词,用英文词典居然查不到其意义!实际上,在阅读一些开源代码时 ...
- 代码中特殊的注释技术——TODO、FIXME和XXX的用处 (转载)
转自:http://blog.csdn.net/reille/article/details/7161942 作者:reille 本博客网址:http://blog.csdn.net/reille/, ...
- 代码中特殊的注释技术——TODO、FIXME和XXX的用处 (转载)
转自:http://blog.csdn.net/reille/article/details/7161942 作者:reille 本博客网址:http://blog.csdn.net/reille/, ...
随机推荐
- Dockfile搭建极简LNMP环境
最近才发现ThinkPHP6.0和CI4.x都要求php版本为7.1以上了,本机的php版本还停留在7.0.3x,又懒得升级,于是考虑使用Docker来运行一个lnmp环境. 常规环境搭建的方式有两种 ...
- Linux下开发STM32单片机
一开始学习51单片机就是用的MDK这个IDE软件,IDE软件虽然看起来直观好像更加容易入门(因为有界面看起来很形象),但是实际上IDE却是向我们这些入门人员隐藏了背后真实存在的过程,让我们以为编译就是 ...
- js 快速排序 All In One
js 快速排序 All In One 快速排序 / Quick Sort "use strict"; /** * * @author xgqfrms * @license MIT ...
- How to implement an accurate countdown timer with js
How to implement an accurate countdown timer with js 如何用 js 实现一个精确的倒计时器 原理剖析 web worker js custom ti ...
- vs code & macOS services
vs code & macOS services Mac OS X, Open Folder With VS Code (right click) https://github.com/Mic ...
- CSS & SASS & SCSS & less
CSS & SASS & SCSS & less less vs scss https://github.com/vecerek/less2sass/wiki/Less-vs. ...
- TypeScript 3.7 RC & Nullish Coalescing
TypeScript 3.7 RC & Nullish Coalescing null, undefined default value https://devblogs.microsoft. ...
- Web Animations API & SVG & requestAnimationFrame
Web Animations API WWAPI https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API https:/ ...
- NGK全球启动大会正式启动,资产上链的前景与机会在哪?
据彭博社报道,加州时间11月25日,NGK全球启动大会在美国硅谷圆满落幕,本次NGK全球启动大会为NGK全球化进程正式拉开了帷幕. 众多业界人士共襄盛举,共同进行探讨未来公链发展的去向和契机. 当前, ...
- [C#] 尝鲜.net6.0的C#代码热重载
看到.NET 6 Preview 1 发布,里面"除了 XAML 热重载之外,还将支持 C# 代码的热重载"一句,觉得有必要试试看,因为XAML热重载功能用起来确实很爽. 首先要下 ...