版本

自定义格式化程序

自定义格式化程序让您可以按照最适合您需求的格式显示 lint 结果,无论是特定的文件格式、特定的显示样式,还是针对特定工具优化的格式。

ESLint 还具有 内置格式化程序,您可以直接使用。

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

创建自定义格式化程序

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

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

格式化程序也可以是一个异步函数(从 ESLint v8.4.0 开始),以下展示了一个简单的示例

//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

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

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

results 参数

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

[
    {
        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 对象

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

  • filePath:已 lint 文件的绝对路径。
  • messagesmessage 对象数组。有关消息的更多信息,请参见下文。
  • errorCount:给定文件的错误数。
  • warningCount:给定文件的警告数。
  • stats:可选的 stats 对象,仅当使用 stats 选项时才存在。
  • source:给定文件的源代码。如果此文件没有错误/警告或存在 output 属性,则省略此属性。
  • output:已应用尽可能多修复的给定文件的源代码。如果没有可用的修复,则省略此属性。
message 对象

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

  • ruleId:生成错误或警告的规则的 ID。如果错误或警告不是由规则产生的(例如,如果是解析错误),则为 null
  • severity:失败的严重程度,1 表示警告,2 表示错误。
  • message:错误的人类可读描述。
  • line:问题所在的行。
  • column:问题所在的列。
  • nodeType:(已弃用:此属性将在 ESLint 的未来版本中删除。)AST 中节点的类型,如果问题与特定 AST 节点无关,则为 null

context 参数

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

  • cwd:当前工作目录。此值来自 ESLint 类的 cwd 构造函数选项。
  • maxWarningsExceeded(可选):如果设置了 --max-warnings 并且警告数量超过了限制,则此属性的值是一个包含两个属性的对象
    • maxWarnings--max-warnings 选项的值
    • foundWarnings:lint 警告的数量
  • rulesMeta:规则的 meta 属性值。有关规则的更多信息,请参见自定义规则页面。

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

{
    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.org.cn/docs/rules/no-extra-semi"
            },
            fixable: "code",
            schema: [],
            messages: {
                unexpected: "Unnecessary semicolon."
            }
        }
    },
}

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

将参数传递给格式化程序

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

使用环境变量

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

这是一个示例,它使用 FORMATTER_SKIP_WARNINGS 环境变量来确定是否在结果中显示警告

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

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

输出将是

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

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

复杂参数传递

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

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

在此示例中,your-program-that-reads-json 程序可以接受 ESLint 结果的原始 JSON 并对其进行处理,然后再输出其自身格式的结果。您可以根据需要向该程序传递尽可能多的命令行参数,以自定义输出。

为终端格式化

iTerm2Guake 这样的现代终端期望特定的结果格式在单击文件名时自动打开它们。大多数终端都支持此目的的格式

file:line:column

打包自定义格式化程序

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

eslint -f awesome src/

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

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

  • main 入口点必须是实现您的自定义格式化程序的 JavaScript 文件。
  • 添加这些 keywords 以帮助用户找到您的格式化程序
    • "eslint"
    • "eslint-formatter"
    • "eslintformatter"

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

示例

摘要格式化程序

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

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

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

将产生以下输出

Errors: 2, Warnings: 4

详细格式化程序

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

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 时

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

输出是

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