语言

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

¥Starting with ESLint v9.7.0, you can extend ESLint with additional languages through plugins. While ESLint began as a linter strictly for JavaScript, the ESLint core is generic and can be used to lint any programming language. Each language is defined as an object that contains all of the parsing, evaluating, and traversal functionality required to lint a file. These languages are then distributed in plugins for use in user configurations.

语言要求

¥Language Requirements

为了创建一种语言,你需要:

¥In order to create a language, you need:

  1. 解析器。解析器是将纯文本转换为数据结构的部分。ESLint 不要求数据结构采用特定格式,因此你可以使用任何已经存在的解析器,也可以编写自己的解析器。

    ¥A parser. The parser is the piece that converts plain text into a data structure. There is no specific format that ESLint requires the data structure to be in, so you can use any already-existing parser, or write your own.

  2. 一个 SourceCode 对象。ESLint 与 AST 协同工作的方式是通过 SourceCode 对象。每个 SourceCode 上都有一些必需的方法,你还可以添加更多想要向规则公开的方法或属性。

    ¥A SourceCode object. The way ESLint works with an AST is through a SourceCode object. There are some required methods on each SourceCode, and you can also add more methods or properties that you’d like to expose to rules.

  3. 一个 Language 对象。Language 对象包含有关语言本身的信息以及解析和创建 SourceCode 对象的方法。

    ¥A Language object. The Language object contains information about the language itself along with methods for parsing and creating the SourceCode object.

语言的解析器要求

¥Parser Requirements for Languages

要开始使用,请确保你有一个可以从 JavaScript 调用的解析器。解析器必须返回表示已解析代码的数据结构。大多数解析器返回 抽象语法树 (AST) 来表示代码,但它们也可以返回 具体语法树 (CST)。对于 ESLint 来说,返回 AST 还是 CST 并不重要,重要的是要有一个要遍历的数据结构。

¥To get started, make sure you have a parser that can be called from JavaScript. The parser must return a data structure representing the code that was parsed. Most parsers return an abstract syntax tree (AST) to represent the code, but they can also return a concrete syntax tree (CST). Whether an AST or CST is returned doesn’t matter to ESLint, it only matters that there is a data structure to traverse.

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

¥While there is no specific structure an AST or CST must follow, it’s easier to integrate with ESLint when each node in the tree contains the following information:

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

    ¥Type - A property on each node representing the node type is required. For example, in JavaScript, the type property contains this information for each node. ESLint rules use node types to define the visitor methods, so it’s important that each node can be identified by a string. The name of the property doesn’t matter (discussed further below) so long as one exists. This property is typically named type or kind by most parsers.

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

    ¥Location - A property on each node representing the location of the node in the original source code is required. The location must contain:

    • 节点开始的行

      ¥The line on which the node starts

    • 节点开始的列

      ¥The column on which the node starts

    • 节点结束的行

      ¥The line on which the node ends

    • 节点结束的列

      ¥The column on which the node ends

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

    ¥As with the node type, the property name doesn’t matter. Two common property names are loc (as in ESTree) and position (as in Unist). This information is used by ESLint to report errors and rule violations.

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

    ¥Range - A property on each node representing the location of the node’s source inside the source code is required. The range indicates the index at which the first character is found and the index after the last character, such that calling code.slice(start, end) returns the text that the node represents. Once again, no specific property name is required, and this information may even be merged with location information. ESTree uses the range property while Unist includes this information on position along with the location information. This information is used by ESLint to apply autofixes.

SourceCode 对象

¥The SourceCode Object

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

¥ESLint holds information about source code in a SourceCode object. This object is the API used both by ESLint internally and by rules written to work on the code (via context.sourceCode). The SourceCode object must implement the TextSourceCode interface as defined in the @eslint/core package.

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

¥A basic SourceCode object must implement the following:

  • ast - 包含源代码的 AST 或 CST 的属性。

    ¥ast - a property containing the AST or CST for the source code.

  • text - 源代码的文本。

    ¥text - the text of the source code.

  • getLoc(nodeOrToken) - 一种返回给定节点或标记位置的方法。这必须与 ESTree 使用的 loc 结构匹配。

    ¥getLoc(nodeOrToken) - a method that returns the location of a given node or token. This must match the loc structure that ESTree uses.

  • getRange(nodeOrToken) - 一种返回给定节点或标记范围的方法。这必须返回一个数组,其中第一项是起始索引,第二项是结束索引。

    ¥getRange(nodeOrToken) - a method that returns the range of a given node or token. This must return an array where the first item is the start index and the second is the end index.

  • traverse() - 一种返回用于遍历 AST 或 CST 的可迭代对象的方法。迭代器必须返回从 @eslint/core 实现 VisitTraversalStepCallTraversalStep 的对象。

    ¥traverse() - a method that returns an iterable for traversing the AST or CST. The iterator must return objects that implement either VisitTraversalStep or CallTraversalStep from @eslint/core.

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

¥The following optional members allow you to customize how ESLint interacts with the object:

  • visitorKeys - 特定于此 SourceCode 对象的访问者键。通常没有必要,因为大多数时候都使用 Language#visitorKeys

    ¥visitorKeys - visitor keys that are specific to just this SourceCode object. Typically not necessary as Language#visitorKeys is used most of the time.

  • applyLanguageOptions(languageOptions) - 如果你有需要在解析后应用的特定语言选项,则可以使用此方法执行此操作。

    ¥applyLanguageOptions(languageOptions) - if you have specific language options that need to be applied after parsing, you can do so in this method.

  • getDisableDirectives() - 返回代码中的任何禁用指令。ESLint 使用它来应用禁用指令并跟踪未使用的指令。

    ¥getDisableDirectives() - returns any disable directives in the code. ESLint uses this to apply disable directives and track unused directives.

  • getInlineConfigNodes() - 返回任何内联配置节点。ESLint 在启用 noInlineConfig 时使用它来报告错误。

    ¥getInlineConfigNodes() - returns any inline config nodes. ESLint uses this to report errors when noInlineConfig is enabled.

  • applyInlineConfig() - 将内联配置元素返回到 ESLint。ESLint 使用它来更改正在 linted 的文件的配置。

    ¥applyInlineConfig() - returns inline configuration elements to ESLint. ESLint uses this to alter the configuration of the file being linted.

  • finalize() - 此方法在 linting 开始之前调用,这是你修改 SourceCode 的最后机会。如果你已定义 applyLanguageOptions()applyInlineConfig(),那么在 SourceCode 对象准备就绪之前,你可能需要应用其他更改。

    ¥finalize() - this method is called just before linting begins and is your last chance to modify SourceCode. If you’ve defined applyLanguageOptions() or applyInlineConfig(), then you may have additional changes to apply before the SourceCode object is ready.

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

¥Additionally, the following members are common on SourceCode objects and are recommended to implement:

  • lines - 源代码的各个行作为字符串数组。

    ¥lines - the individual lines of the source code as an array of strings.

  • getParent(node) - 返回给定节点的父节点,如果该节点是根节点,则返回 undefined

    ¥getParent(node) - returns the parent of the given node or undefined if the node is the root.

  • getAncestors(node) - 返回节点祖级的数组,其中第一个项作为树的根,每个后续项作为通向 node 的根的后代。

    ¥getAncestors(node) - returns an array of the ancestry of the node with the first item as the root of the tree and each subsequent item as the descendants of the root that lead to node.

  • getText(node, beforeCount, afterCount) - 返回表示给定节点的字符串,以及可选的节点范围前后指定数量的字符。

    ¥getText(node, beforeCount, afterCount) - returns the string that represents the given node, and optionally, a specified number of characters before and after the node’s range.

请参阅 JSONSourceCode 作为基本 SourceCode 类的示例。

¥See JSONSourceCode as an example of a basic SourceCode class.

Language 对象

¥The Language Object

Language 对象包含有关编程语言的所有信息以及与用该语言编写的代码交互的方法。ESLint 使用此对象来确定如何处理特定文件。Language 对象必须实现 @eslint/core 包中定义的 Language 接口。

¥The Language object contains all of the information about the programming language as well as methods for interacting with code written in that language. ESLint uses this object to determine how to deal with a particular file. The Language object must implement the Language interface as defined in the @eslint/core package.

基本 Language 对象必须实现以下内容:

¥A basic Language object must implement the following:

  • fileType - 应该是 "text"(将来,我们还将支持 "binary"

    ¥fileType - should be "text" (in the future, we will also support "binary")

  • lineStart - 0 或 1 表示 AST 如何表示文件中的第一行。ESLint 使用它来正确显示错误位置。

    ¥lineStart - either 0 or 1 to indicate how the AST represents the first line in the file. ESLint uses this to correctly display error locations.

  • columnStart - 0 或 1 表示 AST 如何表示每行的第一列。ESLint 使用它来正确显示错误位置。

    ¥columnStart - either 0 or 1 to indicate how the AST represents the first column in each line. ESLint uses this to correctly display error locations.

  • nodeTypeKey - 指示节点类型的属性名称(通常为 "type""kind")。

    ¥nodeTypeKey - the name of the property that indicates the node type (usually "type" or "kind").

  • validateLanguageOptions(languageOptions) - 验证该语言的语言选项。当预期的语言选项没有正确的类型或值时,此方法预计会抛出验证错误。意外的语言选项应被默默忽略,并且不应抛出任何错误。即使语言未指定任何选项,此方法也是必需的。

    ¥validateLanguageOptions(languageOptions) - validates language options for the language. This method is expected to throw a validation error when an expected language option doesn’t have the correct type or value. Unexpected language options should be silently ignored and no error should be thrown. This method is required even if the language doesn’t specify any options.

  • parse(file, context) - 将给定的文件解析为 AST 或 CST,还可以包含用于规则的其他值。由 ESLint 内部调用。

    ¥parse(file, context) - parses the given file into an AST or CST, and can also include additional values meant for use in rules. Called internally by ESLint.

  • createSourceCode(file, parseResult, context) - 创建一个 SourceCode 对象。在 parse() 之后由 ESLint 内部调用,第二个参数是 parse() 的确切返回值。

    ¥createSourceCode(file, parseResult, context) - creates a SourceCode object. Call internally by ESLint after parse(), and the second argument is the exact return value from parse().

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

¥The following optional members allow you to customize how ESLint interacts with the object:

  • visitorKeys - 特定于 AST 或 CST 的访问者键。这用于优化 ESLint 内部 AST 或 CST 的遍历。虽然不是必需的,但强烈建议这样做,尤其是对于与 ESTree 格式有很大偏差的 AST 或 CST 格式。

    ¥visitorKeys - visitor keys that are specific to the AST or CST. This is used to optimize traversal of the AST or CST inside of ESLint. While not required, it is strongly recommended, especially for AST or CST formats that deviate significantly from ESTree format.

  • matchesSelectorClass(className, node, ancestry) - 允许你指定匹配多个节点的选择器类,例如 :expression。每当 esquery 选择器包含 : 后跟标识符时,就会调用此方法。

    ¥matchesSelectorClass(className, node, ancestry) - allows you to specify selector classes, such as :expression, that match more than one node. This method is called whenever an esquery selector contains a : followed by an identifier.

请参阅 JSONLanguage 作为基本 Language 类的示例。

¥See JSONLanguage as an example of a basic Language class.

在插件中发布语言

¥Publish a Language in a Plugin

语言以类似于处理器和规则的方式发布在插件中。将插件中的 languages 键定义为一个对象,其名称是语言名称,值是语言对象。这是一个例子:

¥Languages are published in plugins similar to processors and rules. Define the languages key in your plugin as an object whose names are the language names and the values are the language objects. Here’s an example:

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 配置中的语言,如下所示:

¥In order to use a language from a plugin in a configuration file, import the plugin and include it in the plugins key, specifying a namespace. Then, use that namespace to reference the language in the language configuration, like this:

// eslint.config.js
import example from "eslint-plugin-example";

export default [
    {
        plugins: {
            example
        },
        language: "example/my"
    }
];

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

¥See Specify a Language in the Plugin Configuration documentation for more details.

ESLint 中文网
粤ICP备13048890号