From bc3e427ee8875c53eac6b6762884b50074f1adfc Mon Sep 17 00:00:00 2001
From: Chris Meyer <32752981+EasyRhinoMSFT@users.noreply.github.com>
Date: Fri, 29 Mar 2019 21:06:11 -0500
Subject: [PATCH] Update: pass rule meta to formatters RFC 10 (#11551)
* Update: pass rule meta to formatters (RFC #10)
* Fix html formatter & unit tests
* Update cli unit tests to stub getRules
* Update working-with-custom-formatters.md
* Update working-with-custom-formatters.md
* PR feedback
---
.../working-with-custom-formatters.md | 46 +-
lib/cli.js | 10 +-
lib/formatters/html-template-message.html | 2 +-
lib/formatters/html.js | 22 +-
lib/formatters/json-with-metadata.js | 16 +
tests/lib/cli.js | 9 +
tests/lib/formatters/html.js | 513 ++++++++++++------
tests/lib/formatters/json-with-metadata.js | 81 +++
8 files changed, 528 insertions(+), 171 deletions(-)
create mode 100644 lib/formatters/json-with-metadata.js
create mode 100644 tests/lib/formatters/json-with-metadata.js
diff --git a/docs/developer-guide/working-with-custom-formatters.md b/docs/developer-guide/working-with-custom-formatters.md
index 58fe5593678..8cb6738e828 100644
--- a/docs/developer-guide/working-with-custom-formatters.md
+++ b/docs/developer-guide/working-with-custom-formatters.md
@@ -19,6 +19,35 @@ eslint -f ./my-awesome-formatter.js src/
In order to use a local file as a custom formatter, you must begin the filename with a dot (such as `./my-awesome-formatter.js` or `../formatters/my-awesome-formatter.js`).
+### The `data` Argument
+
+The exported function receives an optional second argument named `data`. The `data` object provides extended information related to the analysis results. Currently, the `data` object consists of a single property named `rulesMeta`. This property is a dictionary of rule metadata, keyed with `ruleId`. The value for each entry is the `meta` property from the corresponding rule object. The dictionary contains an entry for each rule that was run during the analysis.
+
+Here's what the `data` object would look like if one rule, `no-extra-semi`, had been run:
+
+```js
+{
+ rulesMeta: {
+ "no-extra-semi": {
+ type: "suggestion",
+ docs: {
+ description: "disallow unnecessary semicolons",
+ category: "Possible Errors",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/no-extra-semi"
+ },
+ fixable: "code",
+ schema: [],
+ messages: {
+ unexpected: "Unnecessary semicolon."
+ }
+ }
+ }
+}
+```
+
+The [Using Rule metadata](#using-rule-metadata) example shows how to use the `data` object in a custom formatter. See the [Working with Rules](https://eslint.org/docs/developer-guide/working-with-rules) page for more information about rules.
+
## Packaging the Custom Formatter
Custom formatters can also be distributed through npm packages. To do so, create an npm package with a name in the format of `eslint-formatter-*`, where `*` is the name of your formatter (such as `eslint-formatter-awesome`). Projects should then install the package and can use the custom formatter with the `-f` (or `--formatter`) flag like this:
@@ -157,7 +186,7 @@ Errors: 2, Warnings: 4
A more complex report will look something like this:
```javascript
-module.exports = function(results) {
+module.exports = function(results, data) {
var results = results || [];
var summary = results.reduce(
@@ -166,6 +195,7 @@ module.exports = function(results) {
var logMessage = {
filePath: current.filePath,
ruleId: msg.ruleId,
+ ruleUrl: data.rulesMeta[msg.ruleId].url,
message: msg.message,
line: msg.line,
column: msg.column
@@ -196,7 +226,7 @@ module.exports = function(results) {
"\n" +
msg.type +
" " +
- msg.ruleId +
+ msg.ruleId + (msg.ruleUrl ? " (" + msg.ruleUrl + ")" : ""
"\n " +
msg.filePath +
":" +
@@ -221,17 +251,17 @@ eslint -f ./my-awesome-formatter.js src/
The output will be
```bash
-error space-infix-ops
+error space-infix-ops (https://eslint.org/docs/rules/space-infix-ops)
src/configs/bundler.js:6:8
-error semi
+error semi (https://eslint.org/docs/rules/semi)
src/configs/bundler.js:6:10
-warning no-unused-vars
+warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
src/configs/bundler.js:5:6
-warning no-unused-vars
+warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
src/configs/bundler.js:6:6
-warning no-shadow
+warning no-shadow (https://eslint.org/docs/rules/no-shadow)
src/configs/bundler.js:65:32
-warning no-unused-vars
+warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
src/configs/clean.js:3:6
```
diff --git a/lib/cli.js b/lib/cli.js
index f67eb7274ff..9ce81e55425 100644
--- a/lib/cli.js
+++ b/lib/cli.js
@@ -81,15 +81,23 @@ function translateOptions(cliOptions) {
*/
function printResults(engine, results, format, outputFile) {
let formatter;
+ let rules;
try {
formatter = engine.getFormatter(format);
+ rules = engine.getRules();
} catch (e) {
log.error(e.message);
return false;
}
- const output = formatter(results);
+ const rulesMeta = {};
+
+ rules.forEach((rule, ruleId) => {
+ rulesMeta[ruleId] = rule.meta;
+ });
+
+ const output = formatter(results, { rulesMeta });
if (output) {
if (outputFile) {
diff --git a/lib/formatters/html-template-message.html b/lib/formatters/html-template-message.html
index bc353502050..93795a1bdc8 100644
--- a/lib/formatters/html-template-message.html
+++ b/lib/formatters/html-template-message.html
@@ -3,6 +3,6 @@
<%= severityName %> |
<%- message %> |
- <%= ruleId %>
+ <%= ruleId %>
|
diff --git a/lib/formatters/html.js b/lib/formatters/html.js
index d450f9dee24..71b46cf5cfc 100644
--- a/lib/formatters/html.js
+++ b/lib/formatters/html.js
@@ -62,9 +62,10 @@ function renderColor(totalErrors, totalWarnings) {
* Get HTML (table rows) describing the messages.
* @param {Array} messages Messages.
* @param {int} parentIndex Index of the parent HTML row.
+ * @param {Object} rulesMeta Dictionary containing metadata for each rule executed by the analysis.
* @returns {string} HTML (table rows) describing the messages.
*/
-function renderMessages(messages, parentIndex) {
+function renderMessages(messages, parentIndex, rulesMeta) {
/**
* Get HTML (table row) describing a message.
@@ -74,6 +75,13 @@ function renderMessages(messages, parentIndex) {
return lodash.map(messages, message => {
const lineNumber = message.line || 0;
const columnNumber = message.column || 0;
+ let ruleUrl;
+
+ if (rulesMeta) {
+ const meta = rulesMeta[message.ruleId];
+
+ ruleUrl = lodash.get(meta, "docs.url", null);
+ }
return messageTemplate({
parentIndex,
@@ -82,30 +90,32 @@ function renderMessages(messages, parentIndex) {
severityNumber: message.severity,
severityName: message.severity === 1 ? "Warning" : "Error",
message: message.message,
- ruleId: message.ruleId
+ ruleId: message.ruleId,
+ ruleUrl
});
}).join("\n");
}
/**
* @param {Array} results Test results.
+ * @param {Object} rulesMeta Dictionary containing metadata for each rule executed by the analysis.
* @returns {string} HTML string describing the results.
*/
-function renderResults(results) {
+function renderResults(results, rulesMeta) {
return lodash.map(results, (result, index) => resultTemplate({
index,
color: renderColor(result.errorCount, result.warningCount),
filePath: result.filePath,
summary: renderSummary(result.errorCount, result.warningCount)
- }) + renderMessages(result.messages, index)).join("\n");
+ }) + renderMessages(result.messages, index, rulesMeta)).join("\n");
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
-module.exports = function(results) {
+module.exports = function(results, data) {
let totalErrors,
totalWarnings;
@@ -122,6 +132,6 @@ module.exports = function(results) {
date: new Date(),
reportColor: renderColor(totalErrors, totalWarnings),
reportSummary: renderSummary(totalErrors, totalWarnings),
- results: renderResults(results)
+ results: renderResults(results, data.rulesMeta)
});
};
diff --git a/lib/formatters/json-with-metadata.js b/lib/formatters/json-with-metadata.js
new file mode 100644
index 00000000000..6899471547a
--- /dev/null
+++ b/lib/formatters/json-with-metadata.js
@@ -0,0 +1,16 @@
+/**
+ * @fileoverview JSON reporter, including rules metadata
+ * @author Chris Meyer
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Public Interface
+//------------------------------------------------------------------------------
+
+module.exports = function(results, data) {
+ return JSON.stringify({
+ results,
+ metadata: data
+ });
+};
diff --git a/tests/lib/cli.js b/tests/lib/cli.js
index 110cc325ff1..65c98836550 100644
--- a/tests/lib/cli.js
+++ b/tests/lib/cli.js
@@ -726,6 +726,7 @@ describe("cli", () => {
results: []
});
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.outputFixes = sandbox.stub();
localCLI = proxyquire("../../lib/cli", {
@@ -762,6 +763,7 @@ describe("cli", () => {
results: []
});
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.outputFixes = sandbox.mock().once();
localCLI = proxyquire("../../lib/cli", {
@@ -799,6 +801,7 @@ describe("cli", () => {
fakeCLIEngine.prototype = leche.fake(CLIEngine.prototype);
sandbox.stub(fakeCLIEngine.prototype, "executeOnFiles").returns(report);
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.outputFixes = sandbox.mock().withExactArgs(report);
localCLI = proxyquire("../../lib/cli", {
@@ -835,6 +838,7 @@ describe("cli", () => {
fakeCLIEngine.prototype = leche.fake(CLIEngine.prototype);
sandbox.stub(fakeCLIEngine.prototype, "executeOnFiles").returns(report);
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.getErrorResults = sandbox.stub().returns([]);
fakeCLIEngine.outputFixes = sandbox.mock().withExactArgs(report);
@@ -886,6 +890,7 @@ describe("cli", () => {
results: []
});
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.outputFixes = sandbox.mock().never();
localCLI = proxyquire("../../lib/cli", {
@@ -916,6 +921,7 @@ describe("cli", () => {
results: []
});
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.outputFixes = sandbox.stub();
localCLI = proxyquire("../../lib/cli", {
@@ -951,6 +957,7 @@ describe("cli", () => {
fakeCLIEngine.prototype = leche.fake(CLIEngine.prototype);
sandbox.stub(fakeCLIEngine.prototype, "executeOnFiles").returns(report);
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.outputFixes = sandbox.mock().never();
localCLI = proxyquire("../../lib/cli", {
@@ -987,6 +994,7 @@ describe("cli", () => {
fakeCLIEngine.prototype = leche.fake(CLIEngine.prototype);
sandbox.stub(fakeCLIEngine.prototype, "executeOnFiles").returns(report);
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.getErrorResults = sandbox.stub().returns([]);
fakeCLIEngine.outputFixes = sandbox.mock().never();
@@ -1024,6 +1032,7 @@ describe("cli", () => {
fakeCLIEngine.prototype = leche.fake(CLIEngine.prototype);
sandbox.stub(fakeCLIEngine.prototype, "executeOnText").returns(report);
sandbox.stub(fakeCLIEngine.prototype, "getFormatter").returns(() => "done");
+ sandbox.stub(fakeCLIEngine.prototype, "getRules").returns(new Map());
fakeCLIEngine.outputFixes = sandbox.mock().never();
localCLI = proxyquire("../../lib/cli", {
diff --git a/tests/lib/formatters/html.js b/tests/lib/formatters/html.js
index fc76796cb56..ab829234e99 100644
--- a/tests/lib/formatters/html.js
+++ b/tests/lib/formatters/html.js
@@ -67,23 +67,43 @@ function checkContentRow($, rowObject, args) {
describe("formatter:html", () => {
describe("when passed a single error message", () => {
-
- const code = [{
- filePath: "foo.js",
- errorCount: 1,
- warningCount: 0,
- messages: [{
- message: "Unexpected foo.",
- severity: 2,
- line: 5,
- column: 10,
- ruleId: "foo",
- source: "foo"
- }]
- }];
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 1,
+ warningCount: 0,
+ messages: [{
+ message: "Unexpected foo.",
+ severity: 2,
+ line: 5,
+ column: 10,
+ ruleId: "foo",
+ source: "foo"
+ }]
+ }],
+ rulesMeta
+ };
it("should return a string in HTML format with 1 issue in 1 file and styled accordingly", () => {
- const result = formatter(code);
+ const result = formatter(code.results, { rulesMeta });
const $ = cheerio.load(result);
// Check overview
@@ -98,23 +118,43 @@ describe("formatter:html", () => {
});
describe("when passed a single warning message", () => {
-
- const code = [{
- filePath: "foo.js",
- errorCount: 0,
- warningCount: 1,
- messages: [{
- message: "Unexpected foo.",
- severity: 1,
- line: 5,
- column: 10,
- ruleId: "foo",
- source: "foo"
- }]
- }];
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 0,
+ warningCount: 1,
+ messages: [{
+ message: "Unexpected foo.",
+ severity: 1,
+ line: 5,
+ column: 10,
+ ruleId: "foo",
+ source: "foo"
+ }]
+ }],
+ rulesMeta
+ };
it("should return a string in HTML format with 1 issue in 1 file and styled accordingly", () => {
- const result = formatter(code);
+ const result = formatter(code.results, { rulesMeta });
const $ = cheerio.load(result);
// Check overview
@@ -129,23 +169,43 @@ describe("formatter:html", () => {
});
describe("when passed a single error message", () => {
-
- const code = [{
- filePath: "foo.js",
- errorCount: 1,
- warningCount: 0,
- messages: [{
- message: "Unexpected foo.",
- severity: 2,
- line: 5,
- column: 10,
- ruleId: "foo",
- source: "foo"
- }]
- }];
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 1,
+ warningCount: 0,
+ messages: [{
+ message: "Unexpected foo.",
+ severity: 2,
+ line: 5,
+ column: 10,
+ ruleId: "foo",
+ source: "foo"
+ }]
+ }],
+ rulesMeta
+ };
it("should return a string in HTML format with 1 issue in 1 file and styled accordingly", () => {
- const result = formatter(code);
+ const result = formatter(code.results, { rulesMeta });
const $ = cheerio.load(result);
// Check overview
@@ -160,16 +220,17 @@ describe("formatter:html", () => {
});
describe("when passed no error/warning messages", () => {
-
- const code = [{
- filePath: "foo.js",
- errorCount: 0,
- warningCount: 0,
- messages: []
- }];
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 0,
+ warningCount: 0,
+ messages: []
+ }]
+ };
it("should return a string in HTML format with 0 issues in 1 file and styled accordingly", () => {
- const result = formatter(code);
+ const result = formatter(code.results, {});
const $ = cheerio.load(result);
// Check overview
@@ -182,29 +243,63 @@ describe("formatter:html", () => {
});
describe("when passed multiple messages", () => {
- const code = [{
- filePath: "foo.js",
- errorCount: 1,
- warningCount: 1,
- messages: [{
- message: "Unexpected foo.",
- severity: 2,
- line: 5,
- column: 10,
- ruleId: "foo",
- source: "foo"
- }, {
- message: "Unexpected bar.",
- severity: 1,
- line: 6,
- column: 11,
- ruleId: "bar",
- source: "bar"
- }]
- }];
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ },
+ bar: {
+ type: "suggestion",
+
+ docs: {
+ description: "This is rule 'bar'",
+ category: "error",
+ recommended: false
+ },
+
+ messages: {
+ message1: "This is a message for rule 'bar'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 1,
+ warningCount: 1,
+ messages: [{
+ message: "Unexpected foo.",
+ severity: 2,
+ line: 5,
+ column: 10,
+ ruleId: "foo",
+ source: "foo"
+ }, {
+ message: "Unexpected bar.",
+ severity: 1,
+ line: 6,
+ column: 11,
+ ruleId: "bar",
+ source: "bar"
+ }]
+ }],
+ rulesMeta
+ };
it("should return a string in HTML format with 2 issues in 1 file and styled accordingly", () => {
- const result = formatter(code);
+ const result = formatter(code.results, { rulesMeta });
const $ = cheerio.load(result);
// Check overview
@@ -220,34 +315,68 @@ describe("formatter:html", () => {
});
describe("when passed multiple files with 1 error & warning message respectively", () => {
- const code = [{
- filePath: "foo.js",
- errorCount: 1,
- warningCount: 0,
- messages: [{
- message: "Unexpected foo.",
- severity: 2,
- line: 5,
- column: 10,
- ruleId: "foo",
- source: "foo"
- }]
- }, {
- filePath: "bar.js",
- errorCount: 0,
- warningCount: 1,
- messages: [{
- message: "Unexpected bar.",
- severity: 1,
- line: 6,
- column: 11,
- ruleId: "bar",
- source: "bar"
- }]
- }];
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ },
+ bar: {
+ type: "suggestion",
+
+ docs: {
+ description: "This is rule 'bar'",
+ category: "error",
+ recommended: false
+ },
+
+ messages: {
+ message1: "This is a message for rule 'bar'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 1,
+ warningCount: 0,
+ messages: [{
+ message: "Unexpected foo.",
+ severity: 2,
+ line: 5,
+ column: 10,
+ ruleId: "foo",
+ source: "foo"
+ }]
+ }, {
+ filePath: "bar.js",
+ errorCount: 0,
+ warningCount: 1,
+ messages: [{
+ message: "Unexpected bar.",
+ severity: 1,
+ line: 6,
+ column: 11,
+ ruleId: "bar",
+ source: "bar"
+ }]
+ }],
+ rulesMeta
+ };
it("should return a string in HTML format with 2 issues in 2 files and styled accordingly", () => {
- const result = formatter(code);
+ const result = formatter(code.results, { rulesMeta });
const $ = cheerio.load(result);
// Check overview
@@ -264,34 +393,68 @@ describe("formatter:html", () => {
});
describe("when passed multiple files with 1 warning message each", () => {
- const code = [{
- filePath: "foo.js",
- errorCount: 0,
- warningCount: 1,
- messages: [{
- message: "Unexpected foo.",
- severity: 1,
- line: 5,
- column: 10,
- ruleId: "foo",
- source: "foo"
- }]
- }, {
- filePath: "bar.js",
- errorCount: 0,
- warningCount: 1,
- messages: [{
- message: "Unexpected bar.",
- severity: 1,
- line: 6,
- column: 11,
- ruleId: "bar",
- source: "bar"
- }]
- }];
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ },
+ bar: {
+ type: "suggestion",
+
+ docs: {
+ description: "This is rule 'bar'",
+ category: "error",
+ recommended: false
+ },
+
+ messages: {
+ message1: "This is a message for rule 'bar'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 0,
+ warningCount: 1,
+ messages: [{
+ message: "Unexpected foo.",
+ severity: 1,
+ line: 5,
+ column: 10,
+ ruleId: "foo",
+ source: "foo"
+ }]
+ }, {
+ filePath: "bar.js",
+ errorCount: 0,
+ warningCount: 1,
+ messages: [{
+ message: "Unexpected bar.",
+ severity: 1,
+ line: 6,
+ column: 11,
+ ruleId: "bar",
+ source: "bar"
+ }]
+ }],
+ rulesMeta
+ };
it("should return a string in HTML format with 2 issues in 2 files and styled accordingly", () => {
- const result = formatter(code);
+ const result = formatter(code.results, { rulesMeta });
const $ = cheerio.load(result);
// Check overview
@@ -308,23 +471,43 @@ describe("formatter:html", () => {
});
describe("when passing a single message with illegal characters", () => {
-
- const code = [{
- filePath: "foo.js",
- errorCount: 1,
- warningCount: 0,
- messages: [{
- message: "Unexpected <&\"'> foo.",
- severity: 2,
- line: 5,
- column: 10,
- ruleId: "foo",
- source: "foo"
- }]
- }];
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 1,
+ warningCount: 0,
+ messages: [{
+ message: "Unexpected <&\"'> foo.",
+ severity: 2,
+ line: 5,
+ column: 10,
+ ruleId: "foo",
+ source: "foo"
+ }]
+ }],
+ rulesMeta
+ };
it("should return a string in HTML format with 1 issue in 1 file", () => {
- const result = formatter(code);
+ const result = formatter(code.results, { rulesMeta });
const $ = cheerio.load(result);
checkContentRow($, $("tr")[1], { group: "f-0", lineCol: "5:10", color: "clr-2", message: "Unexpected <&"'> foo.", ruleId: "foo" });
@@ -344,7 +527,7 @@ describe("formatter:html", () => {
}];
it("should return a string in HTML format with 1 issue in 1 file", () => {
- const result = formatter(code);
+ const result = formatter(code, {});
const $ = cheerio.load(result);
checkContentRow($, $("tr")[1], { group: "f-0", lineCol: "5:10", color: "clr-2", message: "", ruleId: "" });
@@ -352,21 +535,41 @@ describe("formatter:html", () => {
});
describe("when passed a single message with no line or column", () => {
-
- const code = [{
- filePath: "foo.js",
- errorCount: 1,
- warningCount: 0,
- messages: [{
- message: "Unexpected foo.",
- severity: 2,
- ruleId: "foo",
- source: "foo"
- }]
- }];
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ errorCount: 1,
+ warningCount: 0,
+ messages: [{
+ message: "Unexpected foo.",
+ severity: 2,
+ ruleId: "foo",
+ source: "foo"
+ }]
+ }],
+ rulesMeta
+ };
it("should return a string in HTML format with 1 issue in 1 file and styled accordingly", () => {
- const result = formatter(code);
+ const result = formatter(code.results, { rulesMeta });
const $ = cheerio.load(result);
checkContentRow($, $("tr")[1], { group: "f-0", lineCol: "0:0", color: "clr-2", message: "Unexpected foo.", ruleId: "foo" });
diff --git a/tests/lib/formatters/json-with-metadata.js b/tests/lib/formatters/json-with-metadata.js
new file mode 100644
index 00000000000..cf0692ed036
--- /dev/null
+++ b/tests/lib/formatters/json-with-metadata.js
@@ -0,0 +1,81 @@
+/**
+ * @fileoverview Tests for JSON reporter.
+ * @author Chris Meyer
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const assert = require("chai").assert,
+ formatter = require("../../../lib/formatters/json-with-metadata");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+describe("formatter:json", () => {
+ const rulesMeta = {
+ foo: {
+ type: "problem",
+
+ docs: {
+ description: "This is rule 'foo'",
+ category: "error",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/foo"
+ },
+
+ fixable: "code",
+
+ messages: {
+ message1: "This is a message for rule 'foo'."
+ }
+ },
+ bar: {
+ type: "suggestion",
+
+ docs: {
+ description: "This is rule 'bar'",
+ category: "error",
+ recommended: false
+ },
+
+ messages: {
+ message1: "This is a message for rule 'bar'."
+ }
+ }
+ };
+ const code = {
+ results: [{
+ filePath: "foo.js",
+ messages: [{
+ message: "Unexpected foo.",
+ severity: 2,
+ line: 5,
+ column: 10,
+ ruleId: "foo"
+ }]
+ }, {
+ filePath: "bar.js",
+ messages: [{
+ message: "Unexpected bar.",
+ severity: 1,
+ line: 6,
+ column: 11,
+ ruleId: "bar"
+ }]
+ }],
+ metadata: {
+ rulesMeta
+ }
+ };
+
+ it("should return passed results and data as a JSON string without any modification", () => {
+ const result = JSON.parse(formatter(code.results, code.metadata));
+
+ assert.deepStrictEqual(result, code);
+ });
+});