翻译自 《How To Write Your First ESLint Plugin》
推荐理由:言简意骇,是我入门ESLint的启蒙文章
本文是ESLint插件(Plugins)的简单介绍指南,包括它们是如何工作的,如何配置、编写和如何使用一个插件的。
什么是ESLint插件
它是ESLint的一个外部拓展,强制执行一些规则(rules),不是写在ESLint核心(core)里的。举个例子,大家都比较熟悉的插件eslint-plugin-babel
支持了ESLint核心中没有的实验性功能和linter(改进代码的工具)。插件通常存储为单独的NPM模块,它导出rule
对象,其中key
是规则名称,value
是另一个具有强制执行规则方法的对象:
module.exports = {
rules: {
"rule-name": {
create: function (context) {
// rule implementation ...
}
}
}
};
为什么你需要关心自己去写一个?
NPM已现存有非常多的插件,找到你需要的插件的概率会很高。但是在某些情况下,你可能需要针对你的代码库制定非常具体的规则。
最近,我们的开发团队决定强制执行关于异步函数的命名规范。这意味着,如果某个函数返回一个promise
或有一个async
声明前缀,那么这个函数命名必须有一个固定Async
后缀:function someFunctionAsync()
。
让我们以此为例,编写一个可以警告函数命名错误的ESLint插件,
创建一个插件
在本教程中,我们将创建一个本地插件包并在简单的node应用中使用。项目结构如下所示:
plugin-tutorial
│
└───my-eslint-rules
│ │ package.json
│ │ index.js
│
└───node-app
│ package.json
│ index.js
首先创建主文件夹 mkdir plugin-tutorial && cd plugin-tutorial
配置插件包
每一个有效的插件都应该满足以下条件:
- 单独的NPM包
- 遵循
eslint-plugin-
的命名格式 - 导出
rules
对象
- 创建插件项目(plugin package):
mkdir my-eslint-rules && cd my-eslint-rules && npm init --yes
- 在
package.json
中为其命名:{ "name": "eslint-plugin-my-eslint-rules" }
- 创建
index.js
入口文件并导出自定义规则rules
对象,暂命名为async-func-name
:
module.exports = {
rules: {
"async-func-name": {
create: function (context) {
return { /* ...rule methods */ }
}
}
}
};
编写rule规则对象
为了构建和测试规则,我们将使用一个工具AST explorer。
AST代表抽象语法树或者语法书,它是源代码的抽象语法结构的树状表现形式。 [注1]
将AST Explorer的解析器(parser)设置为eslint-babel
和转换器(transformer)设置为ESLint v4
。
现在在资源管理器中可以看到四个窗口:
- 左上角的窗口将用于编写源代码(source code)
- 右上角的窗口是源代码的资源管理器。将鼠标悬停在表达式上时,你可以看到代码中突出显示的部分
- 左下角就是我们要调试编辑的规则代码
- 右下角是规则后的输出,与源代码同步更新运行
规则函数会接受一个参数为context
的对象,该对象包含了关于规则上下文相关的附加功能和信息。
主要方法是context.report()
,
你将使用的主要方法是 context.report()
,它用来发布警告或错误(取决于你所使用的配置)。该方法只接收一个参数,是个对象,包含以下属性:message
,node
, loc
, data
, fix
[注2]
最简单的示例是只使用 node
和 message
:
context.report({
node: node,
message: "Async function name must end in 'Async'"
});
该规则必须返回一个对象,其中包含ESLint再遍历源代码语法树时调用的visitor
节点的方法。
在我们的示例中,有一个方法FunctionDeclaration
,它接受一个node
对象参数,该节点对象包含了函数信息,例如type
(类型)、name
(名称)、body
(主体)、locations
(每个值的位置)。
要检查函数名称是否具有Async
后缀,我们需要访问名称,该名称位于FunctionDeclaration
节点的id对象中:node.id.name
所以规则的主要逻辑应该是检查函数是否有async属性,如果不包含Async
后缀,则调用context.report()
方法。
应用规则后,AST explorer
输出警告消息:
在资源管理器中编写规则并确保它捕获到正确的规则条件后,将逻辑代码复制到插件包的index.js
中,即完成插件:
module.exports = {
rules: {
"async-func-name": {
create: function (context) {
return {
FunctionDeclaration(node) {
if (node.async && !/Async$/.test(node.id.name)) {
context.report({
node,
message: "Async function name must end in 'Async'"
});
}
}
}
}
}
}
};
将插件应用到项目中
首先,项目需要这样配置:
- 从
plugin-tutorial
执行命令mkdir node-app && cd node-app && npm init --yes && touch index.js
,并将AST explorer中的实例代码加入到index.js
中:
async function myFunction() {
return "";
}
- 安装ESLint依赖
npm i eslint --save-dev
- 安装刚刚创建的插件:
npm i ../my-eslint-rules --save-dev
- 通过创建配置文件
.eslintrc
告诉应用程序需要使用到的ESLint规则与插件
{
"parserOptions": {
"ecmaVersion": 2018
},
"rules": {
"my-eslint-rules/async-func-name": "warn"
},
"plugins": ["my-eslint-rules"]
}
- 在项目应用程序文件夹中打开终端并运行ESLint命令:
./node_modules/.bin/eslint index.js
差不多就是这样。如何您为异步函数设置了错误的名称,您应该在终端中运行它后看到ESLint警告。
在项目中使用插件的重要部分是.eslintrc
配置文件。插件的命名规则应该遵循"
。插件名称应添加到数组plugins
字段中。