版本

语言

从 ESLint v9.7.0 开始,您可以通过插件使用其他语言扩展 ESLint。虽然 ESLint 最初是一个严格用于 JavaScript 的 linter,但 ESLint 核心是通用的,可以用于 lint 任何编程语言。每种语言都定义为一个对象,其中包含 lint 文件所需的所有解析、评估和遍历功能。然后,这些语言在插件中分发,以供用户配置使用。

语言要求

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

  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 对象必须实现 @eslint/core 包中定义的 TextSourceCode 接口。

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

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

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

  • visitorKeys - 仅特定于此 SourceCode 对象的访问者键。通常不是必需的,因为大多数时候使用 Language#visitorKeys
  • applyLanguageOptions(languageOptions) - 如果您有需要在解析后应用的特定语言选项,您可以在此方法中执行此操作。
  • getDisableDirectives() - 返回代码中的任何禁用指令。ESLint 使用它来应用禁用指令并跟踪未使用的指令。
  • getInlineConfigNodes() - 返回任何内联配置节点。当启用 noInlineConfig 时,ESLint 使用它来报告错误。
  • applyInlineConfig() - 将内联配置元素返回给 ESLint。ESLint 使用它来更改正在 lint 的文件的配置。
  • finalize() - 此方法在 linting 开始之前调用,是您修改 SourceCode 的最后机会。如果您已定义 applyLanguageOptions()applyInlineConfig(),那么您可能需要在 SourceCode 对象准备就绪之前应用其他更改。

此外,以下成员在 SourceCode 对象上很常见,建议实现

  • lines - 源代码的各个行,以字符串数组形式表示。
  • getParent(node) - 返回给定节点的父节点;如果节点是根节点,则返回 undefined
  • getAncestors(node) - 返回节点祖先的数组,第一个项目是树的根节点,每个后续项目是根节点的后代,一直到 node
  • getText(node, beforeCount, afterCount) - 返回表示给定节点的字符串,以及可选地,节点范围之前和之后指定数量的字符。

有关基本 SourceCode 类的示例,请参阅 JSONSourceCode

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 对象。在 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) - 接受经过验证的语言选项对象并规范化其值。当语言选项属性更改时,这有助于向后兼容。

有关基本 Language 类的示例,请参阅 JSONLanguage

在插件中发布语言

语言在插件中发布,类似于处理器和规则。在您的插件中将 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"
    }
];

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

更改语言