Commit 86cf2136 authored by David Sveningsson's avatar David Sveningsson
Browse files

feat(formatters): `stylish` and `codeframe` displays links to error descriptions

fixes #113
parent 2073da04
......@@ -2,4 +2,5 @@ export { default as edgeCases } from "./edge-cases";
export { default as emptyMessages } from "./empty-messages";
export { default as emptyResult } from "./empty-result";
export { default as missingSource } from "./missing-source";
export { default as missingUrl } from "./missing-url";
export { default as regular } from "./regular";
import { Result } from "../../reporter";
const source = `<div id="foo"
class="bar"
name="baz">
`;
const results: Result[] = [
{
filePath: "missing-url.html",
errorCount: 2,
warningCount: 0,
source,
messages: [
{
ruleId: "foo",
severity: 2,
message: "An error",
offset: 5,
line: 1,
column: 6,
size: 2,
selector: "div",
},
{
ruleId: "bar",
severity: 1,
message: "A warning",
offset: 18,
line: 2,
column: 5,
size: 5,
selector: "div",
},
],
},
];
export default results;
......@@ -41,6 +41,17 @@ exports[`checkstyle formatter should handle empty result 1`] = `
"
`;
exports[`checkstyle formatter should handle missing rule url 1`] = `
"<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>
<checkstyle version=\\"4.3\\">
<file name=\\"missing-url.html\\">
<error line=\\"1\\" column=\\"6\\" severity=\\"error\\" message=\\"An error (foo)\\" source=\\"htmlvalidate.rules.foo\\" />
<error line=\\"2\\" column=\\"5\\" severity=\\"warning\\" message=\\"A warning (bar)\\" source=\\"htmlvalidate.rules.bar\\" />
</file>
</checkstyle>
"
`;
exports[`checkstyle formatter should handle missing source 1`] = `
"<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>
<checkstyle version=\\"4.3\\">
......
......@@ -7,6 +7,7 @@ exports[`codeframe formatter should generate output 1`] = `
2 | class=\\"bar\\"
3 | name=\\"baz\\">
4 |
<bold>Details:</> https://example.net/rule/foo.html
<yellow>warning</>: <bold>A warning</> <dim>(bar)</> at <green>first.html:2:5</>:
......@@ -15,12 +16,14 @@ exports[`codeframe formatter should generate output 1`] = `
| ^^^^^
3 | name=\\"baz\\">
4 |
<bold>Details:</> https://example.net/rule/bar.html
<red>error</>: <bold>Lorem ipsum is not allowed</> <dim>(no-lorem-ipsum)</> at <green>second.html:1:4</>:
> 1 | <p>lorem ipsum</p>
| ^^^^^^^^^^^
2 |
<bold>Details:</> https://example.net/rule/no-lorem-ipsum.html
<red><bold>2 errors and 1 warning found.</></>
......@@ -48,11 +51,34 @@ exports[`codeframe formatter should handle empty messages 1`] = `""`;
exports[`codeframe formatter should handle empty result 1`] = `""`;
exports[`codeframe formatter should handle missing rule url 1`] = `
"<red>error</>: <bold>An error</> <dim>(foo)</> at <green>missing-url.html:1:6</>:
> 1 | <div id=\\"foo\\"
| ^^
2 | class=\\"bar\\"
3 | name=\\"baz\\">
4 |
<yellow>warning</>: <bold>A warning</> <dim>(bar)</> at <green>missing-url.html:2:5</>:
1 | <div id=\\"foo\\"
> 2 | class=\\"bar\\"
| ^^^^^
3 | name=\\"baz\\">
4 |
<red><bold>2 errors found.</></>
"
`;
exports[`codeframe formatter should handle missing source 1`] = `
"<red>error</>: <bold>An error</> <dim>(foo)</> at <green>missing-source.html:1:6</>
<bold>Details:</> https://example.net/rule/foo.html
<yellow>warning</>: <bold>A warning</> <dim>(bar)</> at <green>missing-source.html:2:5</>
<bold>Details:</> https://example.net/rule/bar.html
<red><bold>2 errors found.</></>
......
......@@ -8,4 +8,6 @@ exports[`json formatter should handle empty messages 1`] = `"[{\\"filePath\\":\\
exports[`json formatter should handle empty result 1`] = `"[]"`;
exports[`json formatter should handle missing rule url 1`] = `"[{\\"filePath\\":\\"missing-url.html\\",\\"errorCount\\":2,\\"warningCount\\":0,\\"source\\":\\"<div id=\\\\\\"foo\\\\\\"\\\\n class=\\\\\\"bar\\\\\\"\\\\n name=\\\\\\"baz\\\\\\">\\\\n\\",\\"messages\\":[{\\"ruleId\\":\\"foo\\",\\"severity\\":2,\\"message\\":\\"An error\\",\\"offset\\":5,\\"line\\":1,\\"column\\":6,\\"size\\":2,\\"selector\\":\\"div\\"},{\\"ruleId\\":\\"bar\\",\\"severity\\":1,\\"message\\":\\"A warning\\",\\"offset\\":18,\\"line\\":2,\\"column\\":5,\\"size\\":5,\\"selector\\":\\"div\\"}]}]"`;
exports[`json formatter should handle missing source 1`] = `"[{\\"filePath\\":\\"missing-source.html\\",\\"errorCount\\":2,\\"warningCount\\":0,\\"source\\":null,\\"messages\\":[{\\"ruleId\\":\\"foo\\",\\"ruleUrl\\":\\"https://example.net/rule/foo.html\\",\\"severity\\":2,\\"message\\":\\"An error\\",\\"offset\\":5,\\"line\\":1,\\"column\\":6,\\"size\\":2,\\"selector\\":\\"div\\"},{\\"ruleId\\":\\"bar\\",\\"ruleUrl\\":\\"https://example.net/rule/bar.html\\",\\"severity\\":1,\\"message\\":\\"A warning\\",\\"offset\\":18,\\"line\\":2,\\"column\\":5,\\"size\\":5,\\"selector\\":\\"div\\"}]}]"`;
......@@ -10,7 +10,13 @@ exports[`stylish formatter should generate output 1`] = `
</> <dim>1:4</> <red>error</> Lorem ipsum is not allowed <dim>no-lorem-ipsum</></>
</></>
</><red><bold>✖ 3 problems (2 errors, 1 warning)</></></>
</><red><bold></></></>"
</><red><bold></></></>
<bold>More information</>:
https://example.net/rule/foo.html
https://example.net/rule/bar.html
https://example.net/rule/no-lorem-ipsum.html
"
`;
exports[`stylish formatter should handle edge cases 1`] = `
......@@ -27,6 +33,16 @@ exports[`stylish formatter should handle empty messages 1`] = `""`;
exports[`stylish formatter should handle empty result 1`] = `""`;
exports[`stylish formatter should handle missing rule url 1`] = `
"</></>
</>missing-url.html</>
</> <dim>1:6</> <red>error</> An error <dim>foo</></>
</> <dim>2:5</> <yellow>warning</> A warning <dim>bar</></>
</></>
</><red><bold>✖ 2 problems (2 errors, 0 warnings)</></></>
</><red><bold></></></>"
`;
exports[`stylish formatter should handle missing source 1`] = `
"</></>
</>missing-source.html</>
......@@ -34,5 +50,10 @@ exports[`stylish formatter should handle missing source 1`] = `
</> <dim>2:5</> <yellow>warning</> A warning <dim>bar</></>
</></>
</><red><bold>✖ 2 problems (2 errors, 0 warnings)</></></>
</><red><bold></></></>"
</><red><bold></></></>
<bold>More information</>:
https://example.net/rule/foo.html
https://example.net/rule/bar.html
"
`;
......@@ -17,6 +17,12 @@ exports[`text formatter should handle empty messages 1`] = `""`;
exports[`text formatter should handle empty result 1`] = `""`;
exports[`text formatter should handle missing rule url 1`] = `
"missing-url.html:1:6: error [foo] An error
missing-url.html:2:5: warning [bar] A warning
"
`;
exports[`text formatter should handle missing source 1`] = `
"missing-source.html:1:6: error [foo] An error
missing-source.html:2:5: warning [bar] A warning
......
import { edgeCases, emptyMessages, emptyResult, missingSource, regular } from "./__fixtures__";
import {
edgeCases,
emptyMessages,
emptyResult,
missingSource,
missingUrl,
regular,
} from "./__fixtures__";
import formatter from "./checkstyle";
describe("checkstyle formatter", () => {
......@@ -7,6 +14,11 @@ describe("checkstyle formatter", () => {
expect(formatter(regular)).toMatchSnapshot();
});
it("should handle missing rule url", () => {
expect.assertions(1);
expect(formatter(missingUrl)).toMatchSnapshot();
});
it("should handle missing source", () => {
expect.assertions(1);
expect(formatter(missingSource)).toMatchSnapshot();
......
import { edgeCases, emptyMessages, emptyResult, missingSource, regular } from "./__fixtures__";
import {
edgeCases,
emptyMessages,
emptyResult,
missingSource,
missingUrl,
regular,
} from "./__fixtures__";
/* force colors on when running stylish tests */
const defaultColor = process.env.FORCE_COLOR;
......@@ -15,6 +22,11 @@ describe("codeframe formatter", () => {
expect(formatter(regular)).toMatchSnapshot();
});
it("should handle missing rule url", () => {
expect.assertions(1);
expect(formatter(missingUrl)).toMatchSnapshot();
});
it("should handle missing source", () => {
expect.assertions(1);
expect(formatter(missingSource)).toMatchSnapshot();
......
......@@ -101,6 +101,10 @@ function formatMessage(message: Message, parentResult: Result): string {
);
}
if (message.ruleUrl) {
result.push(`${chalk.bold("Details:")} ${message.ruleUrl}`);
}
return result.join("\n");
}
......
import { edgeCases, emptyMessages, emptyResult, missingSource, regular } from "./__fixtures__";
import {
edgeCases,
emptyMessages,
emptyResult,
missingSource,
missingUrl,
regular,
} from "./__fixtures__";
import formatter from "./json";
describe("json formatter", () => {
......@@ -7,6 +14,11 @@ describe("json formatter", () => {
expect(formatter(regular)).toMatchSnapshot();
});
it("should handle missing rule url", () => {
expect.assertions(1);
expect(formatter(missingUrl)).toMatchSnapshot();
});
it("should handle missing source", () => {
expect.assertions(1);
expect(formatter(missingSource)).toMatchSnapshot();
......
import { edgeCases, emptyMessages, emptyResult, missingSource, regular } from "./__fixtures__";
import {
edgeCases,
emptyMessages,
emptyResult,
missingSource,
missingUrl,
regular,
} from "./__fixtures__";
/* force colors on when running stylish tests */
const defaultColor = process.env.FORCE_COLOR;
......@@ -15,6 +22,11 @@ describe("stylish formatter", () => {
expect(formatter(regular)).toMatchSnapshot();
});
it("should handle missing rule url", () => {
expect.assertions(1);
expect(formatter(missingUrl)).toMatchSnapshot();
});
it("should handle missing source", () => {
expect.assertions(1);
expect(formatter(missingSource)).toMatchSnapshot();
......
import stylishImpl from "@html-validate/stylish";
import chalk from "chalk";
import { Result } from "../reporter";
import { Formatter } from "./formatter";
function linkSummary(results: Result[]): string {
const urls = results.reduce((result, it): string[] => {
const urls: string[] = it.messages
.map((error) => error.ruleUrl)
.filter((error): error is string => Boolean(error));
return [...result, ...urls];
}, [] as string[]);
const unique = Array.from(new Set(urls));
if (unique.length === 0) {
return "";
}
const lines = unique.map((url) => ` ${url}\n`);
return `\n${chalk.bold("More information")}:\n${lines.join("")}\n`;
}
function stylish(results: Result[]): string {
return stylishImpl(
const errors = stylishImpl(
results.map((it) => ({
...it,
fixableErrorCount: 0,
fixableWarningCount: 0,
}))
);
const links = linkSummary(results);
return `${errors}${links}`;
}
const formatter: Formatter = stylish;
......
import { edgeCases, emptyMessages, emptyResult, missingSource, regular } from "./__fixtures__";
import {
edgeCases,
emptyMessages,
emptyResult,
missingSource,
missingUrl,
regular,
} from "./__fixtures__";
import formatter from "./text";
describe("text formatter", () => {
......@@ -7,6 +14,11 @@ describe("text formatter", () => {
expect(formatter(regular)).toMatchSnapshot();
});
it("should handle missing rule url", () => {
expect.assertions(1);
expect(formatter(missingUrl)).toMatchSnapshot();
});
it("should handle missing source", () => {
expect.assertions(1);
expect(formatter(missingSource)).toMatchSnapshot();
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment