本文来自
要配置ESLint 主要有一下两种方法:
.eslintrc.*
文件,或者直接在 package.json
文件里的 eslintConfig
字段指定配置,ESLint 会查找和自动读取它们,再者,你可以在命令行运行时指定一个任意的配置文件。在用户的主目录中也可以有一个配置文件,当时ESlint 找不到其它配置的时候会使用这个配置文件。配置文件:eg.
module.exports = {
env: {
browser: true,
commonjs: true,
es2021: true
},
extends: 'standard',
overrides: [
],
parserOptions: {
ecmaVersion: 'latest'
},
rules: {
}
}
配置文件总主要配置三种数据:
解析器选可以在配置文件中 parserOptions
属性配置:
{
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"semi": "error"
}
}
支持对应版本的语法,并不意味这支持对应的全局变量,例如:支持 ES6 语法并不意味着同时支持新的 ES6 全局变量或类型(比如 Set 等新类型),对于新的 ES6 全局变量,需要使用 { "env":{ "es6": true } }
。 配置{ "env": { "es6": true } }
将会自动启用ES6语法,但 { "parserOptions": { "ecmaVersion": 6 } }
不会自动启用ES6全局变量。
ESLint 默认使用Espree 作为解析器,可以在配置文件中使用parser
指定不同的解析器
{
"parser": "esprima",
"rules": {
"semi": "error"
}
}
插件可以提供处理器,处理器可以将另一种文件中转换为 JavaScript 代码,然后让ESLint 检测,有点类似webpack的loader将其它类型转换为JS然后可以继续处理。
可使用processor
选项来指定处理器,启用插件a-plugin提供的处理器 a-processor(处理器由插件提供)。
{
"plugins": ["a-plugin"],
"processor": "a-plugin/a-processor"
}
为特定类型的文件指定处理器,需要使用 overrides
和 processor
,例如,下面对 \*.md
文件使用处理器 a-plugin/markdown
{
"plugins": ["a-plugin"],
"overrides": [
{
"files": ["*.md"],
"processor": "a-plugin/markdown"
}
]
}
处理器会将其他类型的代码生成为命名的代码块,如 0.js
和 1.js
,ESLint 将这样的命名代码块作为原始文件的子文件处理,可以在 overrides
部分为已命名的代码块添加附加配置,例如
{
"plugins": ["a-plugin"],
"overrides": [
{
"files": ["*.md"],
"processor": "a-plugin/markdown"
},
{
"files": ["**/*.md/*.js"],
"rules": {
"strict": "off"
}
}
]
}
指定环境变量就会启用对应环境的全局变量:
在注释中指定
/* eslint-env node, mocha */
在配置文件中指定环境,
{
"env": {
"browser": true,
"node": true
}
}
在特定的插件中使用一种环境
{
"plugins": ["example"],
"env": {
"example/custom": true
}
}
在源文件中访问未定义变量的时候,no-undef 规则将发出警告,如果想要使用对应的全局变量,就需要在这里声明。
注释中指定
/* global var1, var2 */
/* global var1:writable, var2:writable */
配置文件中指定 writable
允许重写,readonly
不允许重写。off
禁用全局变量
{
"globals": {
"var1": "writable",
"var2": "readonly"
}
}
要启用 no-global-assign规则来禁止对只读的全局变量进行修改。
在npm 安装插件之后,在plugins 数组中开启插件,可以省略 elsint-plugin-
前缀
{
"plugins": [
"plugin1",
"eslint-plugin-plugin2"
]
}
"off"
或 0
- 关闭规则"warn"
或 1
- 开启规则,使用警告级别的错误:warn (不会导致程序退出)"error"
或 2
- 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)/* eslint eqeqeq: "off", curly: "error" */
/* eslint quotes: ["error", "double"], curly: 2 */
{
"rules": {
"eqeqeq": "off",
"curly": "error",
"quotes": ["error", "double"]
}
}
配置插件中的规则需要 插件名/规则ID
的形式指定
{
"plugins": [
"plugin1"
],
"rules": {
"eqeqeq": "off",
"curly": "error",
"quotes": ["error", "double"],
"plugin1/rule1": "error"
}
}
注意:当指定来自插件的规则时,确保删除 eslint-plugin- 前缀。ESLint 在内部只使用没有前缀的名称去定位规则。
在ESLint 中插件可以暴露额外的规则以供使用。
/* eslint-disable */
alert('foo');
/* eslint-enable */
/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');
/* eslint-enable no-alert, no-console */
alert('foo'); // eslint-disable-line
// eslint-disable-next-line
alert('foo');
/* eslint-disable-next-line */
alert('foo');
alert('foo'); /* eslint-disable-line */
alert('foo'); // eslint-disable-line no-alert
// eslint-disable-next-line no-alert
alert('foo');
alert('foo'); /* eslint-disable-line no-alert */
/* eslint-disable-next-line no-alert */
alert('foo');
alert('foo'); // eslint-disable-line no-alert, quotes, semi
// eslint-disable-next-line no-alert, quotes, semi
alert('foo');
alert('foo'); /* eslint-disable-line no-alert, quotes, semi */
/* eslint-disable-next-line no-alert, quotes, semi */
alert('foo');
{
"rules": {...},
"overrides": [
{
"files": ["*-test.js","*.spec.js"],
"rules": {
"no-unused-expressions": "off"
}
}
]
}
{
"settings": {
"sharedData": "Hello"
}
}
共享配置中的数据,可以被所有的规则访问到。
ESLint会自动在要检测的文件的目录下搜索对应的配置文件,然后搜索父级目录,一直到文件系统的根目录(或者遇到配置了 root:true
的配置文件)就会停止搜索,还可以使用 -c
在命令行中指定配置文件的位置:
eslint -c myconfig.json myfiletotest.js
如果你使用一个配置文件,想要 ESLint 忽略其它的 .eslintrc.* 文件,请确保使用 --no-eslintrc 的同时,加上 -c 标记。
如果 同一个目录
下有多个配置,ESLint 只会使用一个。优先级顺序如下:
离被检测文件最近的配置优先级最高。
例如,如果在根目录的 package.json 文件中有一个 eslintConfig 字段,其中的配置将使用于所有子目录,但是当子目录中的 相关配置的规则与之发生冲突时,就会覆盖它。
注意:如果在你的主目录下有一个自定义的配置文件 (~/.eslintrc) ,如果没有其它配置文件时它才会被使用。因为个人配置将适用于用户目录下的所有目录和文件,包括第三方的代码,当 ESLint 运行时可能会导致问题。
默认ESLint 会逐步向上查找配置文件,一直到文件系统根目录,或者指定root 为true 的ESLint配置 才会停止查找。
{
"root": true
}
完整的配置层次结构,从最高优先级最低的优先级,如下:
一个配置文件可以使用extends
继承其它配置文件。
extends
ESLint递归地扩展配置,因此基本配置也可以具有 extends 属性。extends 属性中的相对路径和可共享配置名从配置文件中出现的位置解析。
rules 配置扩展的时候的作用有:
将extends 值设置为 “eslint:recommended” 将会启用一系列核心规则,这些规则报告一些常见问题,在 规则页面 中被对号标记出来的规则。这个推荐的子集只能在 ESLint 主要版本进行更新。命令行的 --fix 选项用来自动修复规则所报告的问题(目前,大部分是对空白的修复),在下文中会有一个扳手的图标。
使用 eslint --init
命令可以创建一个ESLint配置,这样你就可以继承推荐的规则。
可分享的配置只是导出一个配置对象 npm 包 。首先创建一个 Node.js 模块。确保模块名称以 eslint-config- 开头,例如 eslint-config-myconfig。
创建一个新的 index.js 文件并 export 一个包含配置的对象。
module.exports = {
globals: {
MyGlobal: true
},
rules: {
semi: [2, "always"]
}
};
然后就可以通过npm 发布这些配置包,配置包中应该在 package.json 中用 peerDependencies 字段声明你依赖的 ESLint。推荐使用 “>=” 范围语法,即使用最低要求的 eslint 版本,声明该 依赖以向后兼容。
"peerDependencies": {
"eslint": ">= 3"
}
可共享配置被设计和 .eslintrc 文件的 extends 特性一起使用。使用模块名称作为 extends 取值而不是文件路径。例如:
{
"extends": "eslint-config-myconfig"
}
再配置文件中也可以忽略 eslint-config- 前缀,ESLint 会自动找到。例如:
{
"extends": "myconfig"
}
你可能想在同一个 npm 包中分享多个配置。你可以像第一个章节那样为 npm 包指定默认的配置。你可以指定额外的配置通过在你的 npm 包中添加一个新文件并在你的 ESLint 配置中引用它。
例如,你可以创建一个叫 my-special-config.js 在 npm 包的根目录并且导出一个配置对象。如下:
// my-special-config.js
module.exports = {
rules: {
quotes: [2, "double"]
}
};
随后,假设你使用的包的名称是 eslint-config-myconfig,你可以访问额外的配置通过:
{
"extends": "myconfig/my-special-config"
}
插件包应该包含一个默认的配置(index.js)以避免错误
.eslintignore
文件可用用来忽略一些文件,规则同.gitignore
一个ESLint 规则应该包含三个文件,以规则ID命名
/**
* @fileoverview Rule to disallow unnecessary semicolons
* @author Nicholas C. Zakas
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "disallow unnecessary semicolons",
category: "Possible Errors",
recommended: true,
url: "https://eslint.org/docs/rules/no-extra-semi"
},
fixable: "code",
schema: [] // no options
},
create: function(context) {
return {
// callback functions
};
}
};
规则导出一个对象包含以下属性:
meta
(Object)包含以下对象的元数据:
type
(string): 规则类型,值为 “problem”、“suggestion” 或 “layout”
docs
(Object)对于ESLint 核心规则来说是必须的,检测到错误的时候会使用这里的报错信息。
fixable
(string)‘code’ 或者 ‘whitespace’ 如果没有 fixable 属性,即使规则实现了 fix 功能,ESLint 也不会进行修复。如果规则不是可修复的,就省略 fixable 属性。schema
(array) 指定该选项 这样的 ESLint 可以避免无效的规则配置deprecated
(boolean) 表明规则是已被弃用。如果规则尚未被弃用,你可以省略 deprecated 属性。replacedBy
(array) 在不支持规则的情况下,指定替换的规则create
(function) 返回一个对象,其中包含了 ESLint 在遍历 JavaScript 代码的抽象语法树 AST (ESTree 定义的 AST) 时,用来访问节点的方法。
onCodePathStart
,onCodePathEnd
,onCodePathSegmentStart
,onCodePathSegmentEnd
,onCodePathSegmentLoop
这里是 array-callback-return 规则的一些方法:
function checkLastSegment (node) {
// report problem for function if last code path segment is reachable
}
module.exports = {
meta: { ... },
create: function(context) {
// declare the state of the rule
return {
ReturnStatement: function(node) {
// at a ReturnStatement node while going down
},
// at a function expression node while going up:
"FunctionExpression:exit": checkLastSegment,
"ArrowFunctionExpression:exit": checkLastSegment,
onCodePathStart: function (codePath, node) {
// at the start of analyzing a code path
},
onCodePathEnd: function(codePath, node) {
// at the end of analyzing a code path
}
};
}
};
context 对象包含额外功能,context对象包含与规则上下文的相关信息,
context 对象具有一下属性:
parserOptions
- 配置文件中的解析器选项parserOptions.id
- 规则 ID。options
- 此规则的 已配置的选项 数组。此数组不包含规则严重性,即规则的配置参数不包含第一个参数。有关更多信息,请参见此处。settings
- 配置中的共享的设置,即配置文件中的settings
属性。parserPath
- 配置中的 parser 的名称。parserServices
- 包含由解析器为规则提供的服务的对象。默认解析器不提供任何服务。然而,如果规则打算与自定义解析器一起使用,则可以使用 parserServices 访问该解析器提供的任何内容。(例如,TypeScript 解析器可以提供获取给定节点的计算类型的能力。)。context 对象具有一下方法:
getAncestors()
- 返回当前遍历节点的祖先数组,从 AST 的根节点开始,一直到当前节点的直接父节点。这个数组不包括当前遍历的节点本身。getDeclaredVariables(node)
- 返回由给定节点声明的变量 列表。此信息可用于跟踪对变量的引用。
VariableDeclaration
,则返回声明中声明的所有变量。VariableDeclarator
,则返回 declarator 中声明的所有变量。FunctionDeclaration
或 FunctionExpression
,除了函数参数的变量外,还返回函数名的变量。ArrowFunctionExpression
,则返回参数的变量。ClassDeclaration
或 ClassExpression
,则返回类名的变量。CatchClause
子句,则返回异常的变量。 ImportDeclaration
,则返回其所有说明符的变量。ImportSpecifier
,ImportDefaultSpecifier
或 ImportNamespaceSpecifier
,则返回声明的变量。getFilename()
- 返回与源文件关联的文件名getScope()
- 返回当前遍历节点的 scope。此信息可用于跟踪对变量的引用getSourceCode()
- 返回一个SourceCode对象,你可以使用该对象处理传递给 ESLint 的源代码。markVariableAsUsed(name)
- 在当前作用域内用给定的名称标记一个变量。这将影响 no-unused-vars规则。如果找到一个具有给定名称的变量并将其标记为已使用,则返回 true,否则返回 false。report(descriptor)
- 报告问题的代码 (参见 dedicated section)。该方法返回的作用域具有一下类型:
该方法主要用来发布错误或者警告,该方法接受一个对象包含一下属性:
message
- 有问题的消息node
- (可选的) 与问题有关的 AST 节点。如果存在且没有指定 loc,那么该节点的开始位置被用来作为问题的位置。loc
- (可选的) 用来指定问题位置的一个对象。如果同时指定的了 loc 和 node,那么位置将从loc获取而非node。
start
-开始位置
line
- 问题发生的行号,从 1 开始。column
- 问题发生的列号,从 0 开始。end
- 结束位置
line
- 问题发生的行号,从 1 开始。column
- 问题发生的列号,从 0 开始。data
- (可选的) message的占位符。fix
- (可选的) 一个用来解决问题的修复函数node
或 loc
至少有一个是必须的。可以在消息中使用占位符和提供 data:
context.report({
node: node,
message: "Unexpected identifier: {{ identifier }}",
data: {
identifier: node.name
}
});
可以使用 messageIds 来代替在 context.report() 调用和测试中键入消息。
这允许你避免重新键入错误消息。它还可以防止在规则的不同部分中报告的错误出现过期消息。
// in your rule
module.exports = {
meta: {
messages: {
avoidName: "Avoid using variables named '{{ name }}'"
}
},
create(context) {
return {
Identifier(node) {
if (node.name === "foo") {
context.report({
node,
messageId: "avoidName",
data: {
name: "foo",
}
});
}
}
};
}
};
如果想要使用ESLint 尝试修复你所报告的问题,可以在context.report()的时候指定fix函数,fix函数接受一个fixer 对象。
context.report({
node: node,
message: "Missing semicolon",
fix: function(fixer) {
return fixer.insertTextAfter(node, ";");
}
});
在这里,fix() 函数被用来在该节点之后插入一个分号。注意,此函数并不立即进行修复,如果与其它修复程序有冲突,可能根本就不进行修复。在应用修复之后,ESLint 将在所有启用的规则再次运行修复的代码,以应用更多的修复。这个过程将最多重复10次,直到找到更多的可修复的问题。之后,其他问题将照常进行报告。
fixer 对象有一下几个方法
insertTextAfter(nodeOrToken, text) - 在给定的节点或记号之后插入文本
insertTextAfterRange(range, text) - 在给定的范围之后插入文本
insertTextBefore(nodeOrToken, text) - 在给定的节点或记号之前插入文本
insertTextBeforeRange(range, text) - 在给定的范围之前插入文本
remove(nodeOrToken) - 删除给定的节点或记号
removeRange(range) - 删除给定范围内的文本
replaceText(nodeOrToken, text) - 替换给定的节点或记号内的文本
replaceTextRange(range, text) - 替换给定范围内的文本
以上方法返回一个 fixing 对象。
fix函数可以返回一下的值
一个 fixing 对象。
一个包含 fixing 对象的数组。
一个可迭代的对象,用来枚举 fixing 对象。特别是,fix() 可以是一个生成器。
修复的最佳实践:
- 避免任何可能改变代码运行时行为和导致其停止工作的修复。
- 做尽可能小的修复。那些不必要的修复可能会与其他修复发生冲突,应该避免。
- 使每条消息只有一个修复。这是强制的,因为你必须从 fix() 返回修复操作的结果。
- 由于所有的规则只第一轮修复之后重新运行,所以规则就没必要去检查一个修复的代码风格是否会导致另一个规则报告错误。
有一些规则需要传入参数才可以正常运行,例如:
{
"quotes": ["error", "double"]
}
可以使用getSourceCode()方法获取SourceCode 是获取被检查源码的更多信息的主要对象。
module.exports = {
create: function(context) {
var sourceCode = context.getSourceCode();
// ...
}
};
一旦你获取了 SourceCode 的一个实例,你可以在代码中使用它的方法:
参数描述:
skipOptions 是个对象,包含三个属性;skip、includeComments 和 filter。默认是 {skip: 0, includeComments: false, filter: null}。
countOptions 是个对象包含三个属性;count、includeComments 和 filter。默认为 {count: 0, includeComments: false, filter: null}。
rangeOptions 是个对象,包含一个属性: includeComments。
hasBOM - 标记源码中是否含有 Unicode BOM。
text - 被检查的代码全文,Unicode BOM 已经从该文本中剥离。
ast - AST 的 Program 节点,用于代码检查
visitorKeys - the visitor keys to traverse this AST.
lines - 一个包含所有行的数组,是根据规范中的换行符的定义划分的。
你应该使用 SourceCode 对象,无论在何时你需要获取有关被检查的代码的更多信息。
规则可以输出一个 schema
属性,遵循JSON schema
格式,用来控制规则的选项,ESLint 用它来验证配置规则中的选项是否有效。
// "yoda": [2, "never", { "exceptRange": true }]
module.exports = {
meta: {
schema: [
{
"enum": ["always", "never"]
},
{
"type": "object",
"properties": {
"exceptRange": {
"type": "boolean"
}
},
"additionalProperties": false
}
]
},
};
获取源码
// get all source
var source = sourceCode.getText();
// get source for just this AST node
var nodeSource = sourceCode.getText(node);
// get source for AST node plus previous two characters
var nodeSourceWithPrev = sourceCode.getText(node, 2);
// get source for AST node plus following two characters
var nodeSourceWithFollowing = sourceCode.getText(node, 0, 2);
访问注释
虽然从技术上说,评论并不是 AST 的一部分,但 ESLint 提供了一些方法来访问它们:
sourceCode.getAllComments()
这个方法返回一个在程序中找到的所有的注释的数组。这对于要检查所有注释的规则是有用的,无论这些注释在什么位置。
sourceCode.getCommentsBefore(), sourceCode.getCommentsAfter(), and sourceCode.getCommentsInside()
这些方法分别返回一个在节点之前,节点之后,节点内的注释的数组。这对于要检查给定的节点或 token 的注释的规则是有用的。
请记住,这些结果是按需计算的。
Token traversal methods
最后,注释可以通过很多 sourceCode 的方法使用 includeComments 选项来访问。