这是接上一篇自定义ESLint规则开发与使用的后续扩展,之前文章中详细讲述了怎么创建一个自定义的规则,这篇文章讲述怎么实现ESLint在检测出有问题的代码时,怎么自动fix问题。
比如我们要检测项目中所有http的协议,将其替换为https协议。增加网页的安全性。
项目准备
所用的示例也是和上一篇文章中是一个项目。先进入eslint-plugin-demo的文件夹,使用脚手架回答一些交互式问题,建立ESLint规则文件.
创建link
我们在开发npm包的过程中,可以使用npm link将开发的包link到全局上,这样应用工程就可以直接使用了。具体详情请看npm link
我们在 eslint-plugin-diylint 根目录下执行 npm link。可以看到已近建立了全局的软连了
再cd到demo-app中直接npm link eslint-plugin-diylint 就可以在demo-app/node_modules安装eslint-plugin-diylint 这个插件了,我们可以直接在原文件(node_modules中customer-eslint-demo/eslint-plugin-demo/lib/rules/no-http-protocol.js)中打断点,直接调试会自动映射到node_modules对应的文件中,调试起来非常的方便。
规则实现
通过解析之后,我们选择’VariableDeclaration VariableDeclarator’作为visitor 来获取变量和变量的值。
将no-http-protocol.js中内容改为如下:
/**
* @fileoverview 不可使用http协议
* @author yjian
*/
"use strict";
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: 'problem', // `problem`, `suggestion`, or `layout`
docs: {
description: "不可使用http协议",
recommended: false,
url: null, // URL to the documentation page for this rule
},
fixable: null, // Or `code` or `whitespace`
schema: [], // Add a schema if the rule has options
// 报错信息描述
messages: {
avoidHttpProtocol: "'{{name}}' value avoid using http protocol.",
},
},
create(context) {
return {
// visitor functions for different types of nodes
'VariableDeclaration VariableDeclarator': (node) => {
if (node.init && node.init.value && node.init.value.includes('http://')) {
context.report({
node,
messageId: 'avoidHttpProtocol',
data: {
name: node.id && node.id.name,
},
});
}
}
};
},
};
rules/index.js中内容改为如下:
/**
* @fileoverview 自定义eslint规则
* @author yjian
*/
"use strict";
// import all rules in lib/rules
module.exports = {
rules: {
// 项目在使用时,对应的规则名称
'no-console-error': require('./rules/no-console-error'),
'no-http-protocol': require('./rules/no-http-protocol'),
},
configs: {
recommended: {
rules: {
'demo/no-console-error': 2, // 可以省略 eslint-plugin 前缀
'demo/no-http-protocol': 2,
},
},
},
}
规则使用
在demo-app/eslintrc.json中开启该规则
{
"env": {
"browser": true,
"es2021": true
},
"plugins": [
// 这是此前使用yo eslint:plugin 生成自定义插件的ID
"diylint"
],
"extends": "standard",
"overrides": [
],
"parserOptions": {
"ecmaVersion": "latest"
},
"rules": {
"diylint/no-console-error": 2,
// 不能使用http协议
"diylint/no-http-protocol": 2
}
}
然后重新加载一下vscode,发现我们自定义的lint已近发挥作用,检测出使用http协议的地方了。
然后我们下一步添加一个自动修改的功能,将使用http协议的全部自动改成https的
ESLint 自动修改
meta 修改
将meta中的fixable的值改为code, 这样在命令行上加上-- fix 参数就会自动修复该问题
实现fix函数
我们需要再content.report传入的对象参数中,实现一个fix的函数。
context.report({
node,
messageId: 'avoidHttpProtocol',
data: {
name: node.id && node.id.name,
},
fix(fixer) {
console.log(fixer.insertTextAfter);
return fixer.replaceText()
}
});
我们可以看到fixer中有这些方法。
这些方法归为三类
- 增:insertTextAfter、insertTextAfterRange、insertTextBefore、insertTextBeforeRange
- 删:remove、removeRange
- 改:replaceText、replaceTextRange
我们在这里需要将原来的http:修改为https:即可,所以使用的是replaceText方法
整个代码入下:
'VariableDeclaration VariableDeclarator': (node) => {
if (node.init && node.init.value && node.init.value.includes('http://')) {
// 将http:修改为 https:
const httpsProtocal = node.init.value.replace(/http:/g, 'https:');
context.report({
node,
messageId: 'avoidHttpProtocol',
data: {
name: node.id && node.id.name,
},
fix(fixer) {
return fixer.replaceText(node.init, `'${httpsProtocal}'`)
}
});
}
}
在此之前我们再对应的代码处选择快速修复的话,只有上图两个选项是通过改规则的。而没有对应的按照该规则自动修改代码的选项。我们实现上面的方法之后就有了自动修复的选项了,就会按照上面fix函数的逻辑去修复对应的代码。
效果如下所示:
或者在使用命令行加–fix 也是一样的。效果如下:
至此我们就完成了一个完整的自定义ESLint规则的编写和自动修复。
参考资料
ESLint 中文文档
ESLint英文文档
AST在线解析
AST语法解析(查看node & token)
ESLint创建规则-中文
ESLint创建规则-英文
RuleTester-中文文档
Babel解析AST 节点