前言
大概一周前,我在翻 github
的时候,发现了一个 大佬 - JoshuaKGoldberg 的 eslint
插件 eslint-plugin-package-json
,之前也没有正式搞过 eslint rule
,这里记录下我给这个插件添加新的 rule
的整个过程。
起因
我自己在github有个 组织,里面有两个repo,
仓库分别包含了 eslint
和 prettier
的 配置,所以关注有关插件多些。
无意间翻到了 eslint-plugin-package-json,这个仓库有一些针对 package.json
的规则。
简单看了 readme
和 issue
,发现这个仓库真的不错,而且还在积极维护,作者也是一个顶级大佬,还是 typescript-eslint
的作者
issue
列表里面不少都是接收pr的状态,于是,我想自己能不能动手去解决一些issue呢?几经翻阅,我选了一个看起来比较简单的 github.com/JoshuaKGold…(其实真的不简单)
准备
这个 rule
要做的很简单,去除一些值为空数组或者空对象的字段,比如
{
"main": "lib/index.js",
"scripts": {},
"files": []
}
转化为下面这样
{
"main": "lib/index.js"
}
为了确保自己的思路没问题,我就直接在issue下面留言问了下,
得到了肯定的答复,我就开始准备处理这个问题
过程
在开始写代码之前,我考虑了一些case,比如
{
"simple-git-hooks": {
"pre-commit": "pnpm exec nano-staged --allow-empty",
"preserveUnused": []
}
}
这里的 preserveUnused
该不该被移除呢?理论上是应该和根部分的保持一致,我最开始写的时候,就先写了一版基础的,只能处理根部分的内容,大概花了一两天的时间,我写出来了代码,加了测试用例,
思路是定义好要处理的 field
数组,比如
const arrayFields = ['files', 'keywords', ...]
const objectFields = ['scripts', 'dependencies', ...]
把 package.json
文本转化为对象,然后删除指定的 field
,再拼成一个对象,这样做的好处在于不用考虑 ,
的问题了,
{
"main": "lib/index.js",
"scripts": {},
"files": []
}
这个例子,要移除 scripts
,也要把它后面的 ,
移掉,然后移除 files
,要把 main
后面的 ,
也移掉,
不合理之处嘛,也多得很
作者告诉了我 This is a solid start
,指出了挺多代码不合理的地方,我看了下 review comment
,方向上出了一点问题,代码也不怎么合理,也没有考虑嵌套的情况。
于是在另一个 大佬 - michael faith 的指点下,我换了另外一种思路,从ast入手,处理 JSONArrayExpression
和 JSONObjectExpression
又折腾了一通之后,我又提交了一版代码,录了一个本地的测试视频
这次没啥大的问题,我也确实是走在了正确的方向,不过,JoshuaKGoldberg
提出了另外一个问题,
// package.json
{
"some-custom-array": [ [] ],
"some-custom-object": [ {} ],
}
这种case其实我第二次改的时候考虑到了,不过我在写的时候不是很清楚该怎么处理这种case,就直接没处理。我的想法是,这种case应该先不考虑支持,后面如果有人需要再考虑支持,因为添加特性简单,更改或移除难。
不过大佬说了自己的想法,支持起来不是很困难,我就在下面回复了我的思路,于是就有了昨天晚上的第三版代码
又更新了一波测试用例和文档,最后被合并并发布了🎉
这个pr前前后后搞了一个周,经过了反复讨论,代码也经过了反复修改,收获颇丰
结语
如有错误,欢迎指正。如有建议或想法,欢迎留言。