自定义解析器
ESLint 自定义解析器允许你扩展 ESLint,以支持对代码中新出现的非标准 JavaScript 语言特性或自定义语法进行 lint 检查。解析器负责获取你的代码并将其转换为 ESLint 可以分析和进行 lint 检查的抽象语法树(AST)。
🌐 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.
创建自定义解析器
🌐 Create a Custom Parser
自定义解析器中的方法
🌐 Methods in Custom Parsers
自定义解析器是一个 JavaScript 对象,具有 parse() 或 parseForESLint() 方法。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 be instance (own) properties and 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 和可选属性 services、scopeManager 和 visitorKeys 的对象。
🌐 The parseForESLint method should return an object that contains the required property ast and optional properties services, scopeManager, and visitorKeys.
ast应该包含 AST 对象。services可以包含任何依赖解析器的服务(例如节点的类型检查器)。services属性的值可以作为context.sourceCode.parserServices被规则使用。默认值是一个空对象。scopeManager可以是一个 ScopeManager 对象。自定义解析器可以使用定制的作用域分析来处理实验性/增强语法。默认是由 eslint-scope 创建的ScopeManager对象。- 在 ESLint v4.14.0 中添加了对
scopeManager的支持。支持scopeManager的 ESLint 版本将在parserOptions中提供一个eslintScopeManager: true属性,可用于功能检测。 - 自 ESLint v10.0.0 起,
ScopeManager必须自动解析代码中声明的全局变量的引用,并提供一个实例方法addGlobals(names: string[]),该方法可以在全局作用域中创建具有给定名称的变量并解析对它们的引用。
- 在 ESLint v4.14.0 中添加了对
visitorKeys可以作为一个对象来自定义 AST 遍历。该对象的键是 AST 节点的类型。每个值是一个应被遍历的属性名称数组。默认值是 KEYS ofeslint-visitor-keys。- 在 ESLint v4.14.0 中添加了对
visitorKeys的支持。支持visitorKeys的 ESLint 版本将在parserOptions中提供一个eslintVisitorKeys: true属性,可用于功能检测。
- 在 ESLint v4.14.0 中添加了对
自定义解析器中的元数据
🌐 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])必须是节点的文本。此范围不包括节点周围的空格/括号。loc(SourceLocation)不能是null。loc属性在 ESTree 中定义为可为空,但 ESLint 需要此属性。SourceLocation#source属性可以是undefined。ESLint 不使用SourceLocation#source属性。
所有节点的 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 节点必须具有 tokens 和 comments 属性。两个属性都是下面 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]排序。comments(Token[])是注释标记的数组。这个数组必须按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])相同。
打包自定义解析器
🌐 Packaging a Custom Parser
要将自定义解析器发布到 npm,请执行以下操作:
🌐 To publish your custom parser to npm, perform the following:
- 按照上面的 创建自定义解析器 部分创建一个自定义解析器。
- 为自定义解析器创建一个 npm 包。
- 在你的
package.json文件中,将main字段设置为导出你自定义解析器的文件。 - 发布 npm 包。
有关发布 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
npm install --save-dev eslint-parser-myparser
yarn
yarn add --dev eslint-parser-myparser
pnpm
pnpm add --save-dev eslint-parser-myparser
bun
bun add --dev eslint-parser-myparser
然后在 ESLint 配置文件中使用 languageOptions.parser 属性添加自定义解析器。例如:
🌐 Then add the custom parser to your ESLint configuration file with the languageOptions.parser property. For example:
// eslint.config.js
const { defineConfig } = require("eslint/config");
const myparser = require("eslint-parser-myparser");
module.exports = defineConfig([
{
languageOptions: {
parser: myparser,
},
// ... rest of configuration
},
]);
使用旧版配置时,将 parser 属性指定为字符串:
🌐 When using legacy configuration, specify the parser property as a string:
// .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:
// eslint.config.js
const { defineConfig } = require("eslint/config");
module.exports = defineConfig([
{
languageOptions: {
parser: require("./path/to/awesome-custom-parser"),
},
},
]);
或者如果使用旧配置:
🌐 Or if using legacy configuration:
// .eslintrc.json
{
"parser": "./path/to/awesome-custom-parser.js"
}