为什么要使用eslint?

  • 统一编码规范(命名、格式等等)
  • 统一语法
  • 减少git不必要的提交
  • 避免低级错误
  • 编译时进行语法检查

本文来自

ESLint 的配置文件

要配置ESLint 主要有一下两种方法:

  1. 在注释中直接配置
  2. 在配置文件中配置, JavaScript、JSON 或者 YAML 格式的.eslintrc.* 文件,或者直接在 package.json 文件里的 eslintConfig 字段指定配置,ESLint 会查找和自动读取它们,再者,你可以在命令行运行时指定一个任意的配置文件。

在用户的主目录中也可以有一个配置文件,当时ESlint 找不到其它配置的时候会使用这个配置文件。此功能在 8.0.0 已被废弃。

配置文件:eg.

module.exports = {
  env: {
    browser: true,
    commonjs: true,
    es2021: true
  },
  extends: 'standard',
  overrides: [
  ],
  parserOptions: {
    ecmaVersion: 'latest'
  },
  rules: {
  }
}

配置文件总主要配置三种数据:

  • Environments - 指定脚本的运行环境。每种环境都有一组特定的预定义全局变量。
  • Globals - 脚本在执行期间访问的额外的全局变量。
  • Rules - 启用的规则及其各自的错误级别。

parserOptions 解析器选项

解析器选可以在配置文件中 parserOptions 属性配置:

  • ecamVersion 可以设置为3, 5 (默认), 6, 7, 8, 9, 或者10 来指定你想要使用的ECMAScript版本。也可以用使用年份命名的版本号指定为 2015(同 6),2016(同 7),或 2017(同 8)或 2018(同 9)或 2019 (10)
  • sourceType - 设置为 “script” (默认) 或 “module”(如果你的代码是 ECMAScript 模块)。
  • ecmaFeatures - 这是个对象,表示你想使用的额外的语言特性:
    • globalReturn - 允许在全局作用域下使用 return 语句
    • impliedStrict - 启用全局 strict mode (如果 ecmaVersion 是 5 或更高)
    • jsx - 启用 JSX
    • experimentalObjectRestSpread - 启用实验性的 object rest/spread properties 支持。(重要:这是一个实验性的功能,在未来可能会有明显改变。 建议你写的规则 不要 依赖该功能,除非当它发生改变时你愿意承担维护成本。)
{
    "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全局变量。

parser 指定解析器

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"
}

为特定类型的文件指定处理器

为特定类型的文件指定处理器,需要使用 overridesprocessor,例如,下面对 \*.md 文件使用处理器 a-plugin/markdown

{
    "plugins": ["a-plugin"],
    "overrides": [
        {
            "files": ["*.md"],
            "processor": "a-plugin/markdown"
        }
    ]
}

处理器会将其他类型的代码生成为命名的代码块,如 0.js1.js ,ESLint 将这样的命名代码块作为原始文件的子文件处理,可以在 overrides 部分为已命名的代码块添加附加配置,例如

{
    "plugins": ["a-plugin"],
    "overrides": [
        {
            "files": ["*.md"],
            "processor": "a-plugin/markdown"
        },
        {
            "files": ["**/*.md/*.js"],
            "rules": {
                "strict": "off"
            }
        }
    ]
}

环境变量

指定环境变量就会启用对应环境的全局变量:

  • browser - 浏览器环境中的全局变量。
  • node - Node.js 全局变量和 Node.js 作用域。
  • commonjs - CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)。
  • shared-node-browser - Node.js 和 Browser 通用全局变量。
  • es6 - 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)。
  • worker - Web Workers 全局变量。
  • amd - 将 require() 和 define() 定义为像 amd 一样的全局变量。
  • mocha - 添加所有的 Mocha 测试全局变量。
  • jasmine - 添加所有的 Jasmine 版本 1.3 和 2.0 的测试全局变量。
  • jest - Jest 全局变量。
  • phantomjs - PhantomJS 全局变量。
  • protractor - Protractor 全局变量。
  • qunit - QUnit 全局变量。
  • jquery - jQuery 全局变量。
  • prototypejs - Prototype.js 全局变量。
  • shelljs - ShellJS 全局变量。
  • meteor - Meteor 全局变量。
  • mongo - MongoDB 全局变量。
  • applescript - AppleScript 全局变量。
  • nashorn - Java 8 Nashorn 全局变量。
  • serviceworker - Service Worker 全局变量。
  • atomtest - Atom 测试全局变量。
  • embertest - Ember 测试全局变量。
  • webextensions - WebExtensions 全局变量。
  • greasemonkey - GreaseMonkey 全局变量。

在注释中指定

/* 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 标记。

配置文件的格式

  • JavaScript - 使用 .eslintrc.js 然后输出一个配置对象。
  • YAML - 使用 .eslintrc.yaml 或 .eslintrc.yml 去定义配置的结构。
  • JSON - 使用 .eslintrc.json 去定义配置的结构,ESLint 的 JSON 文件允许 JavaScript 风格的注释。
  • (弃用) - 使用 .eslintrc,可以使 JSON 也可以是 YAML。
  • package.json - 在 package.json 里创建一个 eslintConfig属性,在那里定义你的配置。

如果 同一个目录下有多个配置,ESLint 只会使用一个。优先级顺序如下:

  1. .eslintrc.js
  2. .eslintrc.yaml
  3. .eslintrc.yml
  4. .eslintrc.json
  5. .eslintrc
  6. package.json

配置的层次结构

离被检测文件最近的配置优先级最高。

例如,如果在根目录的 package.json 文件中有一个 eslintConfig 字段,其中的配置将使用于所有子目录,但是当子目录中的 相关配置的规则与之发生冲突时,就会覆盖它。

注意:如果在你的主目录下有一个自定义的配置文件 (~/.eslintrc) ,如果没有其它配置文件时它才会被使用。因为个人配置将适用于用户目录下的所有目录和文件,包括第三方的代码,当 ESLint 运行时可能会导致问题。

eslint 停止向上查找

默认ESLint 会逐步向上查找配置文件,一直到文件系统根目录,或者指定root 为true 的ESLint配置 才会停止查找。

{
    "root": true
}

配置的优先级

完整的配置层次结构,从最高优先级最低的优先级,如下:

  1. 行内配置
    1.1 /eslint-disable/ 和 /eslint-enable/
    1.2 /global/
    1.3 /eslint/
    1.4 /eslint-env/
  2. 命令行选项(或 CLIEngine 等价物):
    2.1 --global
    2.2 --rule
    2.3 --env
    2.4 -c, --config
  3. 项目级配置:
    3.1 与要检测的文件在同一目录下的 .eslintrc.* 或 package.json 文件
    3.2 继续在父级目录寻找 .eslintrc 或 package.json文件,直到根目录(包括根目录)或直到发现一个有"root": true的配置。
  4. 如果不是(1)到(3)中的任何一种情况,退回到 ~/.eslintrc 中自定义的默认配置。

对 ~/.eslintrc 这个文件的支持 在8.0.0 已被废弃,大多数情况下它没什么用。

扩展配置文件

一个配置文件可以使用extends 继承其它配置文件。

extends

  • 指定配置的字符串(配置文件的路径、可共享配置的名称、eslint:recommended 或 eslint:all)
  • 字符串数组:每个配置继承它前面的配置

ESLint递归地扩展配置,因此基本配置也可以具有 extends 属性。extends 属性中的相对路径和可共享配置名从配置文件中出现的位置解析。
rules 配置扩展的时候的作用有:

  1. 启用额外的规则
  2. 改变继承的规则级别而不改变它的选项:
    • 基础配置:“eqeqeq”: [“error”, “allow-null”]
    • 派生的配置:“eqeqeq”: “warn”
    • 最后生成的配置:“eqeqeq”: [“warn”, “allow-null”]
  3. 覆盖基础配置中的规则的选项
    • 基础配置:“quotes”: [“error”, “single”, “avoid-escape”]
    • 派生的配置:“quotes”: [“error”, “single”]
    • 最后生成的配置:“quotes”: [“error”, “single”]

使用 “eslint:recommended”

将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 规则开发

一个ESLint 规则应该包含三个文件,以规则ID命名

  1. lib/rules 文件夹下的源码文件(xxx.js)
  2. tests/lib/rules/ 文件件下的测试文件(xxx.js)
  3. docs/rules 与规则相关的说明文件(xxx.md)
    规则源码的基本格式
/**
 * @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”
    • “problem” 指的是该规则识别的代码要么会导致错误,要么可能会导致令人困惑的行为。开发人员应该优先考虑解决这个问题。
    • “suggestion” 意味着规则确定了一些可以用更好的方法来完成的事情,但是如果代码没有更改,就不会发生错误。
    • “layout” 意味着规则主要关心空格、分号、逗号和括号,以及程序中决定代码外观而不是执行方式的所有部分。这些规则适用于AST中没有指定的代码部分。
  • docs(Object)对于ESLint 核心规则来说是必须的,检测到错误的时候会使用这里的报错信息。
    • description (string) 提供规则的简短描述在规则首页展示,
    • category (string) 指定规则在规则首页处于的分类
    • recommended (boolean) 配置文件中的 “extends”: "eslint:recommended"属性是否启用该规则
    • url (string) 指定可以访问完整文档的 url。
      在自定义的规则或插件中,你可以省略 docs 或包含你需要的任何属性。
  • fixable(string)‘code’ 或者 ‘whitespace’ 如果没有 fixable 属性,即使规则实现了 fix 功能,ESLint 也不会进行修复。如果规则不是可修复的,就省略 fixable 属性。
  • schema (array) 指定该选项 这样的 ESLint 可以避免无效的规则配置
  • deprecated (boolean) 表明规则是已被弃用。如果规则尚未被弃用,你可以省略 deprecated 属性。
  • replacedBy (array) 在不支持规则的情况下,指定替换的规则
  • create (function) 返回一个对象,其中包含了 ESLint 在遍历 JavaScript 代码的抽象语法树 AST (ESTree 定义的 AST) 时,用来访问节点的方法。
    • 如果一个 key 是个节点类型或 selector,在 向下 遍历树时,ESLint 调用 visitor 函数
    • 如果一个 key 是个节点类型或 selector,并带有 :exit,在 向上 遍历树时,ESLint 调用 visitor 函数
    • 如果一个 key 是个事件名字,ESLint 为代码路径分析调用 handler 函数,共有五个事件onCodePathStartonCodePathEndonCodePathSegmentStartonCodePathSegmentEndonCodePathSegmentLoop

这里是 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对象包含与规则上下文的相关信息,

context 对象具有一下属性:

  • parserOptions - 配置文件中的解析器选项parserOptions.
  • id - 规则 ID。
  • options - 此规则的 已配置的选项 数组。此数组不包含规则严重性,即规则的配置参数不包含第一个参数。有关更多信息,请参见此处
  • settings - 配置中的共享的设置,即配置文件中的settings属性。
  • parserPath - 配置中的 parser 的名称。
  • parserServices - 包含由解析器为规则提供的服务的对象。默认解析器不提供任何服务。然而,如果规则打算与自定义解析器一起使用,则可以使用 parserServices 访问该解析器提供的任何内容。(例如,TypeScript 解析器可以提供获取给定节点的计算类型的能力。)。

context 对象具有一下方法:

  • getAncestors() - 返回当前遍历节点的祖先数组,从 AST 的根节点开始,一直到当前节点的直接父节点。这个数组不包括当前遍历的节点本身。
  • getDeclaredVariables(node) - 返回由给定节点声明的变量 列表。此信息可用于跟踪对变量的引用。
    • 如果节点是 VariableDeclaration,则返回声明中声明的所有变量。
    • 如果节点是一个 VariableDeclarator,则返回 declarator 中声明的所有变量。
    • 如果节点是 FunctionDeclarationFunctionExpression,除了函数参数的变量外,还返回函数名的变量。
    • 如果节点是一个 ArrowFunctionExpression,则返回参数的变量。
    • 如果节点是 ClassDeclarationClassExpression,则返回类名的变量。
    • 如果节点是一个 CatchClause 子句,则返回异常的变量。
    • 如果节点是 ImportDeclaration,则返回其所有说明符的变量。
    • 如果节点是 ImportSpecifierImportDefaultSpecifier ImportNamespaceSpecifier,则返回声明的变量。
    • 否则,如果节点没有声明任何变量,则返回一个空数组。
  • getFilename() - 返回与源文件关联的文件名
  • getScope() - 返回当前遍历节点的 scope。此信息可用于跟踪对变量的引用
  • getSourceCode() - 返回一个SourceCode对象,你可以使用该对象处理传递给 ESLint 的源代码。
  • markVariableAsUsed(name) - 在当前作用域内用给定的名称标记一个变量。这将影响 no-unused-vars规则。如果找到一个具有给定名称的变量并将其标记为已使用,则返回 true,否则返回 false。
  • report(descriptor) - 报告问题的代码 (参见 dedicated section)。

context.getScope()

该方法返回的作用域具有一下类型:

context.report()

该方法主要用来发布错误或者警告,该方法接受一个对象包含一下属性:

  • message - 有问题的消息
  • node - (可选的) 与问题有关的 AST 节点。如果存在且没有指定 loc,那么该节点的开始位置被用来作为问题的位置。
    loc - (可选的) 用来指定问题位置的一个对象。如果同时指定的了 loc 和 node,那么位置将从loc获取而非node。
    • start -开始位置
      • line - 问题发生的行号,从 1 开始。
      • column - 问题发生的列号,从 0 开始。
    • end - 结束位置
      • line - 问题发生的行号,从 1 开始。
      • column - 问题发生的列号,从 0 开始。
  • data - (可选的) message的占位符。
  • fix - (可选的) 一个用来解决问题的修复函数
    请注意,nodeloc 至少有一个是必须的。
在消息中使用占位符

可以在消息中使用占位符和提供 data:

context.report({
    node: node,
    message: "Unexpected identifier: {{ identifier }}",
    data: {
        identifier: node.name
    }
});
messageIds

可以使用 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() 可以是一个生成器。

修复的最佳实践:

  1. 避免任何可能改变代码运行时行为和导致其停止工作的修复。
  2. 做尽可能小的修复。那些不必要的修复可能会与其他修复发生冲突,应该避免。
  3. 使每条消息只有一个修复。这是强制的,因为你必须从 fix() 返回修复操作的结果。
  4. 由于所有的规则只第一轮修复之后重新运行,所以规则就没必要去检查一个修复的代码风格是否会导致另一个规则报告错误。

context.options

有一些规则需要传入参数才可以正常运行,例如:

{
    "quotes": ["error", "double"]
}

context.getSourceCode()

可以使用getSourceCode()方法获取SourceCode 是获取被检查源码的更多信息的主要对象。

module.exports = {
    create: function(context) {
        var sourceCode = context.getSourceCode();

        // ...
    }
};

一旦你获取了 SourceCode 的一个实例,你可以在代码中使用它的方法:

  • getText(node) - 返回给定节点的源码。省略 node,返回整个源码。
  • getAllComments() - 返回一个包含源中所有注释的数组。
  • getCommentsBefore(nodeOrToken) - 返回一个在给定的节点或 token 之前的注释的数组。
  • getCommentsAfter(nodeOrToken) - 返回一个在给定的节点或 token 之后的注释的数组。
  • getCommentsInside(node) - 返回一个在给定的节点内的注释的数组。
  • getJSDocComment(node) - 返回给定节点的 JSDoc 注释,如果没有则返回 null。
  • isSpaceBetweenTokens(first, second) - 如果两个记号之间有空白,返回 true
  • getFirstToken(node, skipOptions) - 返回代表给定节点的第一个token。
  • getFirstTokens(node, countOptions) - 返回代表给定节点的第一个 count 数量的 token。
  • getLastToken(node, skipOptions) - 返回代表给定节点最后一个token。
  • getLastTokens(node, countOptions) - 返回代表给定节点的最后一个 count 数量的 token。
  • getTokenAfter(nodeOrToken, skipOptions) - 返回给定的节点或记号之后的第一个token。
  • getTokensAfter(nodeOrToken, countOptions) - 返回给定节点或记号之后的 count 数量的 token。
  • getTokenBefore(nodeOrToken, skipOptions) - 返回给定的节点或记号之前的第一个 token。
  • getTokensBefore(nodeOrToken, countOptions) - 返回给定节点或记号之前的 count 数量的 token。
  • getFirstTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions) - 返回两个节点或 token 之间的第一个 token。
  • getFirstTokensBetween(nodeOrToken1, nodeOrToken2, countOptions) - 返回两个节点或 token 之间的第一个 count 数量的 token。
  • getLastTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions) - 返回两个节点或 token 之间的最后一个 token。
  • getLastTokensBetween(nodeOrToken1, nodeOrToken2, countOptions) - 返回两个节点或 token 之间的最后一个 count 数量的 token。
  • getTokens(node) - 返回给定节点的所有 token。
  • getTokensBetween(nodeOrToken1, nodeOrToken2) - 返回两个节点间 token。
  • getTokenByRangeStart(index, rangeOptions) - 返回源中范围从给定的索引开始的token。
  • getNodeByRangeIndex(index) - 返回 AST 中包含给定的源的索引的最深节点。
  • getLocFromIndex(index) - 返回一个包含 line 和 column 属性的对象,对应给定的源的索引的位置。line 从 1 开始,column 从 0 开始。
  • getIndexFromLoc(loc) - 返回一个源码中的给定的位置的索引,loc 是个对象,包含一个从 1 开始的 line 键和一个从 0 开始的 column 键。
  • commentsExistBetween(nodeOrToken1, nodeOrToken2) - 如果两个节点间存在注释,返回 true。

参数描述:

  • skipOptions 是个对象,包含三个属性;skip、includeComments 和 filter。默认是 {skip: 0, includeComments: false, filter: null}。

    • skip 是个正整数,表示要跳过的 token 的数量。如果同时给出了 filter 选项,过滤掉的 token 不计入此值。
    • includeComments 是个布尔值,标记是否把注释 token 包含进返回结果中。
    • filter 是个函数,用一个 token 作为第一个参数,如果该函数返回 false,那么返回的结果将不包含那个 token。
  • countOptions 是个对象包含三个属性;count、includeComments 和 filter。默认为 {count: 0, includeComments: false, filter: null}。

    • count 是个正整数,返回的 token 的最大数量。
    • includeComments 是个布尔值,标记是否把注释 token 包含进返回结果中。
    • filter 是个函数,用一个 token 作为第一个参数,如果该函数返回 false,那么返回的结果将不包含那个 token。
  • rangeOptions 是个对象,包含一个属性: includeComments。

    • includeComments 是个布尔值,标记是否把注释 token 包含进返回结果中。
      也有一些属性可供你访问:
  • 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 选项来访问。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐