版本

语言

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

语言要求

为了创建一种语言,您需要

  1. 一个解析器。解析器是将纯文本转换为数据结构的部分。ESLint 对数据结构的格式没有特定要求,因此您可以使用任何现有的解析器,或者编写自己的解析器。
  2. 一个 SourceCode 对象。ESLint 与 AST 交互的方式是通过 SourceCode 对象。每个 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 在内部以及为在代码上工作的规则(通过 context.sourceCode)使用的 API。SourceCode 对象必须实现 TextSourceCode 接口,如 @eslint/core 包中所定义。

基本的 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 对象必须实现 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"
    }
];

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

更改语言