自定义格式化程序

自定义格式化程序允许你以最适合你需要的格式显示 linting 结果,无论是特定文件格式、特定显示样式还是针对特定工具优化的格式。

¥Custom formatters let you display linting results in a format that best fits your needs, whether that’s in a specific file format, a certain display style, or a format optimized for a particular tool.

ESLint 也有你可以使用的 内置格式化器

¥ESLint also has built-in formatters that you can use.

你可以直接在你的项目中包含自定义格式化程序,或者创建一个 npm 包来单独分发它们。

¥You can include custom formatters in your project directly or create an npm package to distribute them separately.

创建自定义格式化程序

¥Creating a Custom Formatter

每个格式化程序都是一个函数,它接收一个 results 对象和一个 context 作为参数并返回一个字符串。例如,下面是内置的 JSON 格式化程序 是如何实现的:

¥Each formatter is a function that receives a results object and a context as arguments and returns a string. For example, the following is how the built-in JSON formatter is implemented:

//my-awesome-formatter.js
module.exports = function(results, context) {
    return JSON.stringify(results, null, 2);
};

格式化程序也可以是异步函数(来自 ESLint v8.4.0),下面是一个简单的例子:

¥A formatter can also be an async function (from ESLint v8.4.0), the following shows a simple example:

//my-awesome-formatter.js
module.exports = async function(results) {
    const formatted = await asyncTask();
    return formatted;
};

要使用此格式化程序运行 ESLint,你可以使用 -f(或 --format 命令行标志。你必须以句点 (.) 开始指向局部定义的自定义格式化程序的路径,例如 ./my-awesome-formatter.js../formatters/my-awesome-formatter.js

¥To run ESLint with this formatter, you can use the -f (or --format) command line flag. You must begin the path to a locally defined custom formatter with a period (.), such as ./my-awesome-formatter.js or ../formatters/my-awesome-formatter.js.

eslint -f ./my-awesome-formatter.js src/

本节的其余部分包含有关如何使用自定义格式化程序函数的参考信息。

¥The remainder of this section contains reference information on how to work with custom formatter functions.

results 参数

¥The results Argument

传递给格式化程序的 results 对象是一个 result 对象数组,其中包含单个文件的 linting 结果。这是一个示例输出:

¥The results object passed into a formatter is an array of result objects containing the linting results for individual files. Here’s an example output:

[
    {
        filePath: "/path/to/a/file.js",
        messages: [
            {
                ruleId: "curly",
                severity: 2,
                message: "Expected { after 'if' condition.",
                line: 2,
                column: 1,
                nodeType: "IfStatement"
            },
            {
                ruleId: "no-process-exit",
                severity: 2,
                message: "Don't use process.exit(); throw an error instead.",
                line: 3,
                column: 1,
                nodeType: "CallExpression"
            }
        ],
        errorCount: 2,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0,
        source:
            "var err = doStuff();\nif (err) console.log('failed tests: ' + err);\nprocess.exit(1);\n"
    },
    {
        filePath: "/path/to/Gruntfile.js",
        messages: [],
        errorCount: 0,
        warningCount: 0,
        fixableErrorCount: 0,
        fixableWarningCount: 0
    }
]

result 对象

¥The result Object

results 数组中的每个对象都是一个 result 对象。每个 result 对象都包含被检查的文件的路径以及有关遇到的检查问题的信息。以下是每个 result 对象的可用属性:

¥Each object in the results array is a result object. Each result object contains the path of the file that was linted and information about linting issues that were encountered. Here are the properties available on each result object:

  • 文件路径:被检查的文件的绝对路径。

    ¥filePath: The absolute path to the file that was linted.

  • 消息:message 对象的数组。有关消息的更多信息,请参见下文。

    ¥messages: An array of message objects. See below for more info about messages.

  • 错误计数:给定文件的错误数。

    ¥errorCount: The number of errors for the given file.

  • 警告计数:给定文件的警告数。

    ¥warningCount: The number of warnings for the given file.

  • 统计数据:仅当使用 stats 选项时才存在的可选 stats 对象。

    ¥stats: The optional stats object that only exists when the stats option is used.

  • 来源:给定文件的源代码。如果此文件没有错误/警告或存在 output 属性,则省略此属性。

    ¥source: The source code for the given file. This property is omitted if this file has no errors/warnings or if the output property is present.

  • 输出:给定文件的源代码,应用了尽可能多的修复。如果没有修复可用,则省略此属性。

    ¥output: The source code for the given file with as many fixes applied as possible. This property is omitted if no fix is available.

message 对象

¥The message Object

每个 message 对象都包含有关由某些源代码触发的 ESLint 规则的信息。每个 message 对象上可用的属性是:

¥Each message object contains information about the ESLint rule that was triggered by some source code. The properties available on each message object are:

  • 规则 ID:产生错误或警告的规则的 ID。

    ¥ruleId: the ID of the rule that produced the error or warning.

  • 严重程度:失败的严重性,1 表示警告,2 表示错误。

    ¥severity: the severity of the failure, 1 for warnings and 2 for errors.

  • 信息:错误的人类可读描述。

    ¥message: the human readable description of the error.

  • 线:问题所在的行。

    ¥line: the line where the issue is located.

  • 柱子:问题所在的列。

    ¥column: the column where the issue is located.

  • 节点类型:AST 中节点的类型

    ¥nodeType: the type of the node in the AST

context 参数

¥The context Argument

格式化程序函数接收一个 context 对象作为它的第二个参数。该对象具有以下属性:

¥The formatter function receives a context object as its second argument. The object has the following properties:

  • cwd:当前工作目录。该值来自 ESLint 类的 cwd 构造函数选项。

    ¥cwd: The current working directory. This value comes from the cwd constructor option of the ESLint class.

  • maxWarningsExceeded(可选):如果设置了 --max-warnings 并且警告次数超过限制,则此属性的值是一个包含两个属性的对象:

    ¥maxWarningsExceeded (optional): If --max-warnings was set and the number of warnings exceeded the limit, this property’s value is an object containing two properties:

    • maxWarnings--max-warnings 选项的值

      ¥maxWarnings: the value of the --max-warnings option

    • foundWarnings:棉绒警告的数量

      ¥foundWarnings: the number of lint warnings

  • rulesMeta:规则的 meta 属性值。有关规则的更多信息,请参阅 自定义规则 页面。

    ¥rulesMeta: The meta property values of rules. See the Custom Rules page for more information about rules.

例如,如果运行规则 no-extra-semi,对象将如下所示:

¥For example, here’s what the object would look like if the rule no-extra-semi had been run:

{
    cwd: "/path/to/cwd",
    maxWarningsExceeded: {
        maxWarnings: 5,
        foundWarnings: 6
    },
    rulesMeta: {
        "no-extra-semi": {
            type: "suggestion",
            docs: {
                description: "disallow unnecessary semicolons",
                recommended: true,
                url: "https://eslint.nodejs.cn/docs/rules/no-extra-semi"
            },
            fixable: "code",
            schema: [],
            messages: {
                unexpected: "Unnecessary semicolon."
            }
        }
    },
}

注意:如果由已弃用的 CLIEngine 类执行 linting,则 context 参数可能是不同的值,因为它取决于 API 用户。如果你想支持旧版环境,请检查 context 参数是否为预期值。

¥Note: if a linting is executed by the deprecated CLIEngine class, the context argument may be a different value because it is up to the API users. Please check whether the context argument is an expected value or not if you want to support legacy environments.

将参数传递给格式化程序

¥Passing Arguments to Formatters

虽然格式化程序函数除了结果对象和上下文之外不接收参数,但可以使用下面描述的方法将其他数据传递到自定义格式化程序。

¥While formatter functions do not receive arguments in addition to the results object and the context, it is possible to pass additional data into custom formatters using the methods described below.

使用环境变量

¥Using Environment Variables

自定义格式化程序可以访问环境变量,因此可以根据环境变量数据更改其行为。

¥Custom formatters have access to environment variables and so can change their behavior based on environment variable data.

下面是一个使用 FORMATTER_SKIP_WARNINGS 环境变量来确定是否在结果中显示警告的示例:

¥Here’s an example that uses a FORMATTER_SKIP_WARNINGS environment variable to determine whether to show warnings in the results:

module.exports = function(results) {
    var skipWarnings = process.env.FORMATTER_SKIP_WARNINGS === "true";

    var results = results || [];
    var summary = results.reduce(
        function(seq, current) {
            current.messages.forEach(function(msg) {
                var logMessage = {
                    filePath: current.filePath,
                    ruleId: msg.ruleId,
                    message: msg.message,
                    line: msg.line,
                    column: msg.column
                };

                if (msg.severity === 1) {
                    logMessage.type = "warning";
                    seq.warnings.push(logMessage);
                }
                if (msg.severity === 2) {
                    logMessage.type = "error";
                    seq.errors.push(logMessage);
                }
            });
            return seq;
        },
        {
            errors: [],
            warnings: []
        }
    );

    if (summary.errors.length > 0 || summary.warnings.length > 0) {
        var warnings = !skipWarnings ? summary.warnings : []; // skip the warnings in that case

        var lines = summary.errors
            .concat(warnings)
            .map(function(msg) {
                return (
                    "\n" +
                    msg.type +
                    " " +
                    msg.ruleId +
                    "\n  " +
                    msg.filePath +
                    ":" +
                    msg.line +
                    ":" +
                    msg.column
                );
            })
            .join("\n");

        return lines + "\n";
    }
};

你将使用此自定义格式化程序和如下设置的环境变量运行 ESLint:

¥You would run ESLint with this custom formatter and an environment variable set like this:

FORMATTER_SKIP_WARNINGS=true eslint -f ./my-awesome-formatter.js src/

输出将是:

¥The output would be:

error space-infix-ops
  src/configs/bundler.js:6:8

error semi
  src/configs/bundler.js:6:10

复杂参数传递

¥Complex Argument Passing

如果你发现自定义格式化程序模式没有为你想要格式化 ESLint 结果的方式提供足够的选项,最好的选择是使用 ESLint 的内置 JSON 格式化程序 并将输出通过管道传输到第二个程序。例如:

¥If you find the custom formatter pattern doesn’t provide enough options for the way you’d like to format ESLint results, the best option is to use ESLint’s built-in JSON formatter and pipe the output to a second program. For example:

eslint -f json src/ | your-program-that-reads-JSON --option

在此示例中,your-program-that-reads-json 程序可以接受 ESLint 结果的原始 JSON 并在输出其自己的结果格式之前对其进行处理。你可以将任意数量的命令行参数传递给该程序以自定义输出。

¥In this example, the your-program-that-reads-json program can accept the raw JSON of ESLint results and process it before outputting its own format of the results. You can pass as many command line arguments to that program as are necessary to customize the output.

终端格式化

¥Formatting for Terminals

iTerm2Guake 等现代终端需要特定的结果格式,以便在单击它们时自动打开文件名。为此,大多数终端都支持这种格式:

¥Modern terminals like iTerm2 or Guake expect a specific results format to automatically open filenames when they are clicked. Most terminals support this format for that purpose:

file:line:column

打包自定义格式化程序

¥Packaging a Custom Formatter

自定义格式化程序可以通过 npm 包分发。为此,请创建一个名称格式为 eslint-formatter-* 的 npm 包,其中 * 是格式化程序的名称(例如 eslint-formatter-awesome)。然后项目应该安装包并使用带有 -f(或 --format 标志的自定义格式化程序,如下所示:

¥Custom formatters can be distributed through npm packages. To do so, create an npm package with a name in the format eslint-formatter-*, where * is the name of your formatter (such as eslint-formatter-awesome). Projects should then install the package and use the custom formatter with the -f (or --format) flag like this:

eslint -f awesome src/

因为 ESLint 知道在指定的格式化程序不以句点开头时查找以 eslint-formatter- 开头的包,所以在使用打包的自定义格式化程序时不需要键入 eslint-formatter-

¥Because ESLint knows to look for packages beginning with eslint-formatter- when the specified formatter doesn’t begin with a period, you do not need to type eslint-formatter- when using a packaged custom formatter.

自定义格式化程序的 package.json 提示:

¥Tips for the package.json of a custom formatter:

  • main 入口点必须是实现自定义格式化程序的 JavaScript 文件。

    ¥The main entry point must be the JavaScript file implementing your custom formatter.

  • 添加这些 keywords 以帮助用户找到你的格式化程序:

    ¥Add these keywords to help users find your formatter:

    • "eslint"

    • "eslint-formatter"

    • "eslintformatter"

查看所有 npm 上的自定义格式化程序

¥See all custom formatters on npm.

示例

¥Examples

摘要格式器

¥Summary Formatter

仅报告错误和警告总数的格式化程序如下所示:

¥A formatter that only reports on the total count of errors and warnings will look like this:

module.exports = function(results, context) {
    // accumulate the errors and warnings
    var summary = results.reduce(
        function(seq, current) {
            seq.errors += current.errorCount;
            seq.warnings += current.warningCount;
            return seq;
        },
        { errors: 0, warnings: 0 }
    );

    if (summary.errors > 0 || summary.warnings > 0) {
        return (
            "Errors: " +
            summary.errors +
            ", Warnings: " +
            summary.warnings +
            "\n"
        );
    }

    return "";
};

使用上面的摘要格式化程序运行 eslint

¥Run eslint with the above summary formatter:

eslint -f ./my-awesome-formatter.js src/

将产生以下输出:

¥Will produce the following output:

Errors: 2, Warnings: 4

详细格式化程序

¥Detailed Formatter

更复杂的报告可能如下所示:

¥A more complex report could look like this:

module.exports = function(results, context) {
    var results = results || [];

    var summary = results.reduce(
        function(seq, current) {
            current.messages.forEach(function(msg) {
                var logMessage = {
                    filePath: current.filePath,
                    ruleId: msg.ruleId,
                    ruleUrl: context.rulesMeta[msg.ruleId].docs.url,
                    message: msg.message,
                    line: msg.line,
                    column: msg.column
                };

                if (msg.severity === 1) {
                    logMessage.type = "warning";
                    seq.warnings.push(logMessage);
                }
                if (msg.severity === 2) {
                    logMessage.type = "error";
                    seq.errors.push(logMessage);
                }
            });
            return seq;
        },
        {
            errors: [],
            warnings: []
        }
    );

    if (summary.errors.length > 0 || summary.warnings.length > 0) {
        var lines = summary.errors
            .concat(summary.warnings)
            .map(function(msg) {
                return (
                    "\n" +
                    msg.type +
                    " " +
                    msg.ruleId + (msg.ruleUrl ? " (" + msg.ruleUrl + ")" : "") +
                    "\n  " +
                    msg.filePath +
                    ":" +
                    msg.line +
                    ":" +
                    msg.column
                );
            })
            .join("\n");

        return lines + "\n";
    }
};

当你使用此自定义格式化程序运行 ESLint 时:

¥When you run ESLint with this custom formatter:

eslint -f ./my-awesome-formatter.js src/

输出是:

¥The output is:

error space-infix-ops (https://eslint.nodejs.cn/docs/rules/space-infix-ops)
  src/configs/bundler.js:6:8
error semi (https://eslint.nodejs.cn/docs/rules/semi)
  src/configs/bundler.js:6:10
warning no-unused-vars (https://eslint.nodejs.cn/docs/rules/no-unused-vars)
  src/configs/bundler.js:5:6
warning no-unused-vars (https://eslint.nodejs.cn/docs/rules/no-unused-vars)
  src/configs/bundler.js:6:6
warning no-shadow (https://eslint.nodejs.cn/docs/rules/no-shadow)
  src/configs/bundler.js:65:32
warning no-unused-vars (https://eslint.nodejs.cn/docs/rules/no-unused-vars)
  src/configs/clean.js:3:6