版本

语言

从 ESLint v9.7.0 开始,您可以通过插件扩展 ESLint 以支持其他语言。虽然 ESLint 最初是作为专门用于 JavaScript 的代码风格检查器而诞生的,但 ESLint 核心是通用的,可以用于检查任何编程语言的代码。每种语言都定义为一个对象,其中包含检查文件所需的所有解析、评估和遍历功能。这些语言随后被打包到插件中,以便在用户配置中使用。

语言要求

为了创建语言,您需要

  1. 解析器。 解析器是将纯文本转换为数据结构的部分。ESLint 对数据结构的格式没有具体要求,因此您可以使用任何现有的解析器,或编写自己的解析器。
  2. SourceCode 对象。 ESLint 使用 SourceCode 对象与 AST 交互。每个 SourceCode 都有一些必需的方法,您还可以添加您想公开给规则的其他方法或属性。
  3. Language 对象。 Language 对象包含有关语言本身的信息,以及用于解析和创建 SourceCode 对象的方法。

语言的解析器要求

要开始,请确保您有一个可以从 JavaScript 调用 的解析器。解析器必须返回一个表示已解析代码的数据结构。大多数解析器返回一个 抽象语法树 (AST) 来表示代码,但它们也可以返回一个 具体语法树 (CST)。AST 或 CST 的返回与否对 ESLint 无关,重要的是存在一个可以遍历的数据结构。

虽然 AST 或 CST 没有必须遵循的特定结构,但当树中的每个节点包含以下信息时,更容易与 ESLint 集成

  1. 类型 - 每个节点上表示节点类型的属性是必需的。例如,在 JavaScript 中,type 属性包含每个节点的此信息。ESLint 规则使用节点类型来定义访问器方法,因此每个节点都必须通过字符串进行识别。属性的名称无关紧要(在下面进一步讨论),只要存在一个属性即可。此属性通常由大多数解析器命名为 typekind

  2. 位置 - 每个节点上表示节点在原始源代码中的位置的属性是必需的。位置必须包含

    • 节点开始的行
    • 节点开始的列
    • 节点结束的行
    • 节点结束的列

    与节点类型一样,属性名称无关紧要。两个常见的属性名称是 loc(如 ESTree)和 position(如 Unist)。ESLint 使用此信息来报告错误和规则违规情况。

  3. 范围 - 每个节点上表示节点源在源代码中的位置的属性是必需的。范围指示第一个字符找到的索引和最后一个字符之后的索引,这样调用 code.slice(start, end) 将返回节点表示的文本。同样,不需要特定的属性名称,甚至可以将此信息与位置信息合并。ESTree 使用 range 属性,而 Unist 将此信息包含在 position 上,以及位置信息。ESLint 使用此信息来应用自动修复。

SourceCode 对象

ESLint 在 SourceCode 对象中保存有关源代码的信息。此对象是 ESLint 内部使用的 API,也是编写用于处理代码的规则使用的 API(通过 context.sourceCode)。SourceCode 对象必须实现 @eslint/core 包中定义的 TextSourceCode 接口。

基本的 SourceCode 对象必须实现以下内容

  • ast - 包含源代码的 AST 或 CST 的属性。
  • text - 源代码的文本。
  • getLoc(nodeOrToken) - 返回给定节点或标记位置的方法。这必须与 ESTree 使用的 loc 结构匹配。
  • getRange(nodeOrToken) - 返回给定节点或标记范围的方法。这必须返回一个数组,其中第一个元素是起始索引,第二个元素是结束索引。
  • traverse() - 返回一个用于遍历 AST 或 CST 的可迭代对象的方法。迭代器必须返回实现 @eslint/coreVisitTraversalStepCallTraversalStep 的对象。

以下可选成员允许您自定义 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 对象必须实现 @eslint/core 包中定义的 Language 接口。

基本的 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 对象。 由 ESLint 在 parse() 之后内部调用,第二个参数是 parse() 的确切返回值。

以下可选成员允许您自定义 ESLint 与对象交互的方式

  • visitorKeys - 特定于 AST 或 CST 的访问者键。 这用于优化 ESLint 内部对 AST 或 CST 的遍历。 虽然不是必需的,但强烈建议,尤其是对于与 ESTree 格式有很大偏差的 AST 或 CST 格式。
  • defaultLanguageOptions - 使用语言时的默认 languageOptions。 计算正在检查的文件的配置时,用户指定的 languageOptions 与此对象合并。
  • matchesSelectorClass(className, node, ancestry) - 允许您指定选择器类,例如 :expression,它匹配多个节点。 只要 esquery 选择器包含一个 : 后跟一个标识符,就会调用此方法。

请参阅 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"
    }
];

有关更多详细信息,请参阅插件配置文档中的 指定语言

更改语言