Skip to content

Commit

Permalink
feat: support async formatters (#15243)
Browse files Browse the repository at this point in the history
* feat: support async formatter

Fixes #15242

* test: add test for async formatter

* test: tweak async formatter fixture

* docs: support async formatter

* docs: fix formatter type

* test: move async formatter to formatters

* chore: add Formatter typedef

* style: remove extra space

* docs: update ESLint version for async formatter

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>

* chore: format is not optional

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>

* Update docs/developer-guide/working-with-custom-formatters.md

Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com>
  • Loading branch information
3 people committed Nov 24, 2021
1 parent 1e32ee5 commit f1b7499
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 8 deletions.
2 changes: 1 addition & 1 deletion docs/developer-guide/nodejs-api.md
Expand Up @@ -404,7 +404,7 @@ This edit information means replacing the range of the `range` property by the `

The `Formatter` value is the object to convert the [LintResult] objects to text. The [eslint.loadFormatter()][eslint-loadformatter] method returns it. It has the following method:

* `format` (`(results: LintResult[]) => string`)<br>
* `format` (`(results: LintResult[]) => string | Promise<string>`)<br>
The method to convert the [LintResult] objects to text.

---
Expand Down
10 changes: 10 additions & 0 deletions docs/developer-guide/working-with-custom-formatters.md
Expand Up @@ -11,6 +11,16 @@ module.exports = function(results) {
};
```

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

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

To run ESLint with this formatter, you can use the `-f` (or `--format`) command line flag:

```bash
Expand Down
2 changes: 1 addition & 1 deletion lib/cli.js
Expand Up @@ -178,7 +178,7 @@ async function printResults(engine, results, format, outputFile) {
return false;
}

const output = formatter.format(results);
const output = await formatter.format(results);

if (output) {
if (outputFile) {
Expand Down
9 changes: 7 additions & 2 deletions lib/eslint/eslint.js
Expand Up @@ -34,7 +34,12 @@ const { version } = require("../../package.json");
/** @typedef {import("../shared/types").LintMessage} LintMessage */
/** @typedef {import("../shared/types").Plugin} Plugin */
/** @typedef {import("../shared/types").Rule} Rule */
/** @typedef {import("./load-formatter").Formatter} Formatter */

/**
* The main formatter object.
* @typedef Formatter
* @property {function(LintResult[]): string | Promise<string>} format format function.
*/

/**
* The options with which to configure the ESLint instance.
Expand Down Expand Up @@ -629,7 +634,7 @@ class ESLint {
/**
* The main formatter method.
* @param {LintResults[]} results The lint results to format.
* @returns {string} The formatted lint results.
* @returns {string | Promise<string>} The formatted lint results.
*/
format(results) {
let rulesMeta = null;
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/formatters/async.js
@@ -0,0 +1,4 @@
/*global module*/
module.exports = function(results) {
return Promise.resolve('from async formatter');
};
10 changes: 7 additions & 3 deletions tests/lib/cli-engine/cli-engine.js
Expand Up @@ -1160,7 +1160,7 @@ describe("CLIEngine", () => {

const report = engine.executeOnFiles([getFixturePath("formatters")]);

assert.strictEqual(report.results.length, 3);
assert.strictEqual(report.results.length, 4);
assert.strictEqual(report.errorCount, 0);
assert.strictEqual(report.warningCount, 0);
assert.strictEqual(report.fixableErrorCount, 0);
Expand Down Expand Up @@ -1200,14 +1200,18 @@ describe("CLIEngine", () => {
assert.strictEqual(report.results[0].warningCount, 0);
assert.strictEqual(report.results[0].fixableErrorCount, 0);
assert.strictEqual(report.results[0].fixableWarningCount, 0);
assert.strictEqual(report.results[1].errorCount, 3);
assert.strictEqual(report.results[1].errorCount, 0);
assert.strictEqual(report.results[1].warningCount, 0);
assert.strictEqual(report.results[1].fixableErrorCount, 3);
assert.strictEqual(report.results[1].fixableErrorCount, 0);
assert.strictEqual(report.results[1].fixableWarningCount, 0);
assert.strictEqual(report.results[2].errorCount, 3);
assert.strictEqual(report.results[2].warningCount, 0);
assert.strictEqual(report.results[2].fixableErrorCount, 3);
assert.strictEqual(report.results[2].fixableWarningCount, 0);
assert.strictEqual(report.results[3].errorCount, 3);
assert.strictEqual(report.results[3].warningCount, 0);
assert.strictEqual(report.results[3].fixableErrorCount, 3);
assert.strictEqual(report.results[3].fixableWarningCount, 0);
});

it("should process when file is given by not specifying extensions", () => {
Expand Down
11 changes: 11 additions & 0 deletions tests/lib/cli.js
Expand Up @@ -287,6 +287,17 @@ describe("cli", () => {
});
});

describe("when given an async formatter path", () => {
it("should execute without any errors", async () => {
const formatterPath = getFixturePath("formatters", "async.js");
const filePath = getFixturePath("passing.js");
const exit = await cli.execute(`-f ${formatterPath} ${filePath}`);

assert.strictEqual(log.info.getCall(0).args[0], "from async formatter");
assert.strictEqual(exit, 0);
});
});

describe("when executing a file with a lint error", () => {
it("should exit with error", async () => {
const filePath = getFixturePath("undef.js");
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/eslint/eslint.js
Expand Up @@ -1212,7 +1212,7 @@ describe("ESLint", () => {
});
const results = await eslint.lintFiles([getFixturePath("formatters")]);

assert.strictEqual(results.length, 3);
assert.strictEqual(results.length, 4);
assert.strictEqual(results[0].messages.length, 0);
assert.strictEqual(results[1].messages.length, 0);
assert.strictEqual(results[2].messages.length, 0);
Expand Down

0 comments on commit f1b7499

Please sign in to comment.