自定义解析器

ESLint 自定义解析器让你可以扩展 ESLint 以支持在你的代码中检查新的非标准 JavaScript 语言功能或自定义语法。解析器负责获取你的代码并将其转换为抽象语法树 (AST),然后 ESLint 可以对其进行分析和 lint。

¥ESLint custom parsers let you extend ESLint to support linting new non-standard JavaScript language features or custom syntax in your code. A parser is responsible for taking your code and transforming it into an abstract syntax tree (AST) that ESLint can then analyze and lint.

创建自定义解析器

¥Creating a Custom Parser

自定义解析器中的方法

¥Methods in Custom Parsers

自定义解析器是具有 parseparseForESLint 方法的 JavaScript 对象。parse 方法只返回 AST,而 parseForESLint 还返回额外的值,让解析器更多地自定义 ESLint 的行为。

¥A custom parser is a JavaScript object with either a parse or parseForESLint method. The parse method only returns the AST, whereas parseForESLint also returns additional values that let the parser customize the behavior of ESLint even more.

这两种方法都应将源代码作为第一个参数,并将可选的配置对象作为第二个参数,该对象在配置文件中作为 parserOptions 提供。

¥Both methods should take in the source code as the first argument, and an optional configuration object as the second argument, which is provided as parserOptions in a configuration file.

// customParser.js

const espree = require("espree");

// Logs the duration it takes to parse each file.
function parse(code, options) {
    const label = `Parsing file "${options.filePath}"`;
    console.time(label);
    const ast = espree.parse(code, options);
    console.timeEnd(label);
    return ast; // Only the AST is returned.
};

module.exports = { parse };

parse 返回对象

¥parse Return Object

parse 方法应该简单地返回 AST 对象。

¥The parse method should simply return the AST object.

parseForESLint 返回对象

¥parseForESLint Return Object

parseForESLint 方法应返回一个对象,该对象包含必需属性 ast 和可选属性 servicesscopeManagervisitorKeys

¥The parseForESLint method should return an object that contains the required property ast and optional properties services, scopeManager, and visitorKeys.

  • ast 应包含 AST 对象。

    ¥ast should contain the AST object.

  • services 可以包含任何依赖于解析器的服务(例如节点的类型检查器)。services 属性的值可作为 context.sourceCode.parserServices 用于规则。默认为空对象。

    ¥services can contain any parser-dependent services (such as type checkers for nodes). The value of the services property is available to rules as context.sourceCode.parserServices. Default is an empty object.

  • scopeManager 可以是 ScopeManager 对象。自定义解析器可以对实验/增强语法使用自定义范围分析。默认是由 eslint-scope 创建的 ScopeManager 对象。

    ¥scopeManager can be a ScopeManager object. Custom parsers can use customized scope analysis for experimental/enhancement syntaxes. The default is the ScopeManager object which is created by eslint-scope.

    • 在 ESLint v4.14.0 中添加了对 scopeManager 的支持。支持 scopeManager 的 ESLint 版本会在 parserOptions 中提供一个 eslintScopeManager: true 属性,可用于特性检测。

      ¥Support for scopeManager was added in ESLint v4.14.0. ESLint versions that support scopeManager will provide an eslintScopeManager: true property in parserOptions, which can be used for feature detection.

  • visitorKeys 可以是自定义 AST 遍历的对象。对象的键是 AST 节点的类型。每个值都是应该遍历的属性名称数组。默认值为 eslint-visitor-keys 的键

    ¥visitorKeys can be an object to customize AST traversal. The keys of the object are the type of AST nodes. Each value is an array of the property names which should be traversed. The default is KEYS of eslint-visitor-keys.

    • 在 ESLint v4.14.0 中添加了对 visitorKeys 的支持。支持 visitorKeys 的 ESLint 版本会在 parserOptions 中提供一个 eslintVisitorKeys: true 属性,可用于特性检测。

      ¥Support for visitorKeys was added in ESLint v4.14.0. ESLint versions that support visitorKeys will provide an eslintVisitorKeys: true property in parserOptions, which can be used for feature detection.

自定义解析器中的元数据

¥Meta Data in Custom Parsers

为了更轻松地调试和更有效地缓存自定义解析器,建议在自定义解析器根目录的 meta 对象中提供名称和版本,如下所示:

¥For easier debugging and more effective caching of custom parsers, it’s recommended to provide a name and version in a meta object at the root of your custom parsers, like this:

// preferred location of name and version
module.exports = {
    meta: {
        name: "eslint-parser-custom",
        version: "1.2.3"
    }
};

meta.name 属性应与自定义解析器的 npm 包名称匹配,meta.version 属性应与自定义解析器的 npm 包版本匹配。完成此操作的最简单方法是从你的 package.json 读取此信息。

¥The meta.name property should match the npm package name for your custom parser and the meta.version property should match the npm package version for your custom parser. The easiest way to accomplish this is by reading this information from your package.json.

AST 规范

¥AST Specification

自定义解析器应创建的 AST 基于 ESTree。AST 需要一些关于源代码详细信息的附加属性。

¥The AST that custom parsers should create is based on ESTree. The AST requires some additional properties about detail information of the source code.

所有节点

¥All Nodes

所有节点都必须具有 range 属性。

¥All nodes must have range property.

  • range (number[]) 是两个数字的数组。这两个数字都是基于 0 的索引,它是源代码字符数组中的位置。第一个是节点的起始位置,第二个是节点的结束位置。code.slice(node.range[0], node.range[1]) 必须是节点的文本。此范围不包括节点周围的空格/括号。

    ¥range (number[]) is an array of two numbers. Both numbers are a 0-based index which is the position in the array of source code characters. The first is the start position of the node, the second is the end position of the node. code.slice(node.range[0], node.range[1]) must be the text of the node. This range does not include spaces/parentheses which are around the node.

  • loc (SourceLocation) 不能是 nullloc 属性被 ESTree 定义为可为空,但 ESLint 需要此属性。SourceLocation#source 属性可以是 undefined。ESLint 不使用 SourceLocation#source 属性。

    ¥loc (SourceLocation) must not be null. The loc property is defined as nullable by ESTree, but ESLint requires this property. The SourceLocation#source property can be undefined. ESLint does not use the SourceLocation#source property.

所有节点的 parent 属性必须是可重写的。在任何规则访问 AST 之前,ESLint 在遍历时将每个节点的 parent 属性设置为其父节点。

¥The parent property of all nodes must be rewritable. Before any rules have access to the AST, ESLint sets each node’s parent property to its parent node while traversing.

Program 节点

¥The Program Node

Program 节点必须具有 tokenscomments 属性。这两个属性都是以下 Token 接口的数组。

¥The Program node must have tokens and comments properties. Both properties are an array of the below Token interface.

interface Token {
    type: string;
    loc: SourceLocation;
    // See the "All Nodes" section for details of the `range` property.
    range: [number, number];
    value: string;
}
  • tokens (Token[]) 是影响程序行为的标记数组。标记之间可以存在任意空格,因此规则检查 Token#range 以检测标记之间的空格。这必须按 Token#range[0] 排序。

    ¥tokens (Token[]) is the array of tokens which affect the behavior of programs. Arbitrary spaces can exist between tokens, so rules check the Token#range to detect spaces between tokens. This must be sorted by Token#range[0].

  • comments (Token[]) 是注释标记数组。这必须按 Token#range[0] 排序。

    ¥comments (Token[]) is the array of comment tokens. This must be sorted by Token#range[0].

所有标记和注释的范围索引不得与其他标记和注释的范围重叠。

¥The range indexes of all tokens and comments must not overlap with the range of other tokens and comments.

Literal 节点

¥The Literal Node

Literal 节点必须具有 raw 属性。

¥The Literal node must have raw property.

  • raw (string) 是这个字面的源代码。这与 code.slice(node.range[0], node.range[1]) 相同。

    ¥raw (string) is the source code of this literal. This is the same as code.slice(node.range[0], node.range[1]).

打包自定义解析器

¥Packaging a Custom Parser

要将自定义解析器发布到 npm,请执行以下操作:

¥To publish your custom parser to npm, perform the following:

  1. 按照上面的 创建自定义解析器 部分创建自定义解析器。

    ¥Create a custom parser following the Creating a Custom Parser section above.

  2. 创建一个 npm 包 用于自定义解析器。

    ¥Create an npm package for the custom parser.

  3. 在你的 package.json 文件中,将 main 字段设置为导出自定义解析器的文件。

    ¥In your package.json file, set the main field as the file that exports your custom parser.

  4. 发布 npm 包。

    ¥Publish the npm package.

有关发布 npm 包的更多信息,请参阅 npm 文档

¥For more information on publishing an npm package, refer to the npm documentation.

发布 npm 包后,你可以通过将包添加到你的项目来使用它。例如:

¥Once you’ve published the npm package, you can use it by adding the package to your project. For example:

npm install eslint-parser-myparser --save-dev

然后使用 parser 属性将自定义解析器添加到你的 ESLint 配置文件中。例如:

¥Then add the custom parser to your ESLint configuration file with the parser property. For example:

// .eslintrc.js

module.exports = {
  parser: 'eslint-parser-myparser',
  // ... rest of configuration
};

要了解有关在项目中使用 ESLint 解析器的更多信息,请参阅 配置解析器

¥To learn more about using ESLint parsers in your project, refer to Configure a Parser.

示例

¥Example

有关自定义解析器的复杂示例,请参阅 @typescript-eslint/parser 源代码。

¥For a complex example of a custom parser, refer to the @typescript-eslint/parser source code.

一个简单的自定义解析器,为规则提供 context.sourceCode.parserServices.foo() 方法。

¥A simple custom parser that provides a context.sourceCode.parserServices.foo() method to rules.

// awesome-custom-parser.js
var espree = require("espree");
function parseForESLint(code, options) {
    return {
        ast: espree.parse(code, options),
        services: {
            foo: function() {
                console.log("foo");
            }
        },
        scopeManager: null,
        visitorKeys: null
    };
};

module.exports = { parseForESLint };

在 ESLint 配置文件中包含自定义解析器:

¥Include the custom parser in an ESLint configuration file:

// .eslintrc.json
{
    "parser": "./path/to/awesome-custom-parser.js"
}