语言
从 ESLint v9.7.0 开始,您可以通过插件扩展 ESLint 以支持其他语言。虽然 ESLint 最初是一个专门针对 JavaScript 的代码检查工具,但 ESLint 的核心是通用的,可以用于检查任何编程语言的代码。每种语言都定义为一个对象,其中包含检查文件所需的所有解析、评估和遍历功能。然后,这些语言被打包成插件,供用户在配置中使用。
语言要求
为了创建一种语言,您需要
- 一个解析器。解析器是将纯文本转换为数据结构的部分。ESLint 对数据结构的格式没有特定要求,因此您可以使用任何现有的解析器,或者编写自己的解析器。
- 一个
SourceCode
对象。ESLint 与 AST 交互的方式是通过SourceCode
对象。每个SourceCode
都有一些必需的方法,您还可以添加更多方法或属性,以便将其公开给规则。 - 一个
Language
对象。Language
对象包含有关语言本身的信息以及用于解析和创建SourceCode
对象的方法。
语言的解析器要求
首先,请确保您有一个可以从 JavaScript 调用的解析器。解析器必须返回一个表示已解析代码的数据结构。大多数解析器返回一个抽象语法树 (AST) 来表示代码,但它们也可以返回一个具体语法树 (CST)。AST 或 CST 是否返回对 ESLint 来说并不重要,重要的是有一个数据结构可以遍历。
虽然 AST 或 CST 不必遵循任何特定的结构,但当树中的每个节点都包含以下信息时,更容易与 ESLint 集成
-
类型 - 每个节点上表示节点类型的属性是必需的。例如,在 JavaScript 中,
type
属性包含每个节点的此信息。ESLint 规则使用节点类型来定义访问者方法,因此每个节点都必须可以通过字符串进行识别这一点非常重要。属性的名称并不重要(在下面进一步讨论),只要存在一个属性即可。此属性通常由大多数解析器命名为type
或kind
。 -
位置 - 每个节点上表示节点在原始源代码中的位置的属性是必需的。位置必须包含
- 节点开始的行号
- 节点开始的列号
- 节点结束的行号
- 节点结束的列号
与节点类型一样,属性名称并不重要。两个常见的属性名称是
loc
(如ESTree)和position
(如Unist)。此信息由 ESLint 用于报告错误和规则违规。 -
范围 - 每个节点上表示节点源在源代码中的位置的属性是必需的。范围指示第一个字符所在索引和最后一个字符之后的索引,以便调用
code.slice(start, end)
返回节点表示的文本。再次强调,不需要特定的属性名称,此信息甚至可以与位置信息合并。ESTree 使用range
属性,而 Unist 将此信息与位置信息一起包含在position
中。此信息由 ESLint 用于应用自动修复。
SourceCode
对象
ESLint 在 SourceCode
对象中保存有关源代码的信息。此对象是 ESLint 在内部以及为在代码上工作的规则(通过 context.sourceCode
)使用的 API。SourceCode
对象必须实现 TextSourceCode
接口,如 @eslint/core
包中所定义。
基本的 SourceCode
对象必须实现以下内容
ast
- 包含源代码的 AST 或 CST 的属性。text
- 源代码的文本。getLoc(nodeOrToken)
- 返回给定节点或标记位置的方法。这必须与 ESTree 使用的loc
结构匹配。getRange(nodeOrToken)
- 返回给定节点或标记范围的方法。这必须返回一个数组,其中第一项是起始索引,第二项是结束索引。traverse()
- 返回用于遍历 AST 或 CST 的可迭代对象的方法。迭代器必须返回实现@eslint/core
中VisitTraversalStep
或CallTraversalStep
的对象。
以下可选成员允许您自定义 ESLint 与对象交互的方式
visitorKeys
- 仅特定于此SourceCode
对象的访问者键。通常不需要,因为大多数时候使用Language#visitorKeys
。applyLanguageOptions(languageOptions)
- 如果您有在解析后需要应用的特定语言选项,您可以在此方法中执行此操作。getDisableDirectives()
- 返回代码中的任何禁用指令。ESLint 使用此功能来应用禁用指令并跟踪未使用的指令。getInlineConfigNodes()
- 返回任何内联配置节点。ESLint 使用此功能在启用noInlineConfig
时报告错误。applyInlineConfig()
- 返回内联配置元素到 ESLint。ESLint 使用此功能来更改正在检查的文件的配置。finalize()
- 此方法在 linting 开始之前调用,是您修改SourceCode
的最后机会。如果您已定义applyLanguageOptions()
或applyInlineConfig()
,那么您可能需要在SourceCode
对象准备好之前应用其他更改。
此外,以下成员在 SourceCode
对象上很常见,建议实现
lines
- 源代码的各个行,作为字符串数组。getParent(node)
- 返回给定节点的父节点,如果节点是根节点,则返回undefined
。getAncestors(node)
- 返回节点祖先的数组,其中第一项是树的根节点,后续每一项是导致node
的根节点的后代。getText(node, beforeCount, afterCount)
- 返回表示给定节点的字符串,以及可选地在节点范围之前和之后指定的字符数量。
请参阅 JSONSourceCode
作为基本 SourceCode
类的示例。
Language
对象
Language
对象包含有关编程语言的所有信息,以及与用该语言编写的代码进行交互的方法。ESLint 使用此对象来确定如何处理特定文件。Language
对象必须实现 Language
接口,如 @eslint/core
包中所定义。
基本的 Language
对象必须实现以下内容
fileType
- 应为"text"
(将来,我们还将支持"binary"
)lineStart
- 0 或 1,用于指示 AST 如何表示文件中的第一行。ESLint 使用此功能来正确显示错误位置。columnStart
- 0 或 1,用于指示 AST 如何表示每行中的第一列。ESLint 使用此功能来正确显示错误位置。nodeTypeKey
- 指示节点类型的属性的名称(通常为"type"
或"kind"
)。validateLanguageOptions(languageOptions)
- 验证语言的语言选项。此方法预期在预期语言选项没有正确类型或值时抛出验证错误。意外的语言选项应被静默忽略,并且不应抛出错误。即使语言没有指定任何选项,也需要此方法。parse(file, context)
- 将给定文件解析为 AST 或 CST,并且还可以包含用于规则的其他值。由 ESLint 内部调用。createSourceCode(file, parseResult, context)
- 创建一个SourceCode
对象。在parse()
后由 ESLint 内部调用,第二个参数是parse()
的确切返回值。
以下可选成员允许您自定义 ESLint 与对象交互的方式
visitorKeys
- AST 或 CST 特定的访问者键。这用于优化 ESLint 内部 AST 或 CST 的遍历。虽然不是必需的,但强烈建议使用,特别是对于与 ESTree 格式有很大偏差的 AST 或 CST 格式。defaultLanguageOptions
- 使用语言时的默认languageOptions
。在计算要 lint 文件的配置时,用户指定的languageOptions
会与此对象合并。matchesSelectorClass(className, node, ancestry)
- 允许您指定选择器类,例如:expression
,这些类匹配多个节点。每当 esquery 选择器包含:
后跟标识符时,就会调用此方法。normalizeLanguageOptions(languageOptions)
- 获取经过验证的语言选项对象并标准化其值。这在语言选项属性更改时有助于向后兼容。
请参阅 JSONLanguage
作为 Language
类的基本示例。
在插件中发布语言
语言发布在类似于处理器和规则的插件中。在您的插件中定义 languages
键作为对象,其名称为语言名称,值为语言对象。这是一个示例
import { myLanguage } from "../languages/my.js";
const plugin = {
// preferred location of name and version
meta: {
name: "eslint-plugin-example",
version: "1.2.3"
},
languages: {
my: myLanguage
},
rules: {
// add rules here
}
};
// for ESM
export default plugin;
// OR for CommonJS
module.exports = plugin;
为了在配置文件中使用来自插件的语言,请导入插件并将其包含在 plugins
键中,并指定一个命名空间。然后,使用该命名空间在 language
配置中引用该语言,如下所示
// eslint.config.js
import example from "eslint-plugin-example";
export default [
{
plugins: {
example
},
language: "example/my"
}
];
有关更多详细信息,请参阅插件配置文档中的 指定语言。