Skip to content
This repository has been archived by the owner on Aug 7, 2023. It is now read-only.

Commit

Permalink
Add a link to rule documentation
Browse files Browse the repository at this point in the history
Changes the (ruleID) to a link to the documentation for core rules, and adds some pages to link to for plugin rules describing how to add them.
  • Loading branch information
Arcanemagus committed Jun 15, 2016
1 parent 3f2b3d8 commit 3a1bbf0
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 15 deletions.
21 changes: 21 additions & 0 deletions docs/linkingNewRule.md
@@ -0,0 +1,21 @@
# What happened

You arrived here after clicking on a stylelint plugin's rule name from a
linting error message.

Normally, clicking on a stylelint rule name in an error message takes you
to the [stylelint.io](http://stylelint.io/user-guide/rules/) or plugin's page
for that rule, so you can learn more about it. Unfortunately the plugin that
implements the rule you clicked on is not in the current list of plugins known
to the `linter-stylelint` package, so there is no way of knowing how to
automatically link to the rule's documentation.

## How you can help

Would you mind submitting a PR to add a mapping for the plugin you're using that
redirected you here? That way you, and everyone else using that plugin with
`linter-stylelint`, will be able to click the name and get to the documentation
quickly.

To do so simply add a new case to the `switch` statement in the
`generateHTMLMessage()` function, and send in your PR!
13 changes: 13 additions & 0 deletions docs/noRuleNamespace.md
@@ -0,0 +1,13 @@
# No Namespace Rules

Unfortunately the rule you have clicked on comes from a plugin, but that
plugin used the generic namespace of `plugin` instead of creating their own.
This means that it is impossible to determine a URL to link to the definition
of the rule.

You can try filing an issue on the repository of the rule if you know where it
came from asking them to use a namespace. If that happens then the new
namespace can be added to the list of known plugins by following the
instructions [here][linkingnewrule].

[linkingnewrule]: https://github.com/AtomLinter/linter-stylelint/tree/master/docs/linkingNewRule.md
47 changes: 40 additions & 7 deletions lib/index.js
Expand Up @@ -6,6 +6,7 @@ const stylelint = lazyReq('stylelint');
const { rangeFromLineNumber } = lazyReq('atom-linter')('rangeFromLineNumber');
const assignDeep = lazyReq('assign-deep');
const cosmiconfig = lazyReq('cosmiconfig');
const escapeHTML = lazyReq('escape-html');
/**
* Note that this can't be loaded lazily as `atom` doesn't export it correctly
* for that, however as this comes from app.asar it is pre-compiled and is
Expand Down Expand Up @@ -85,6 +86,35 @@ export function deactivate() {
subscriptions.dispose();
}

function generateHTMLMessage(message) {
if (!message.rule || message.rule === 'CssSyntaxError') {
return escapeHTML()(message.text);
}

const ruleParts = message.rule.split('/');
let url;

if (ruleParts.length === 1) {
// Core rule
url = `http://stylelint.io/user-guide/rules/${ruleParts[0]}`;
} else {
// Plugin rule
const pluginName = ruleParts[0];
// const ruleName = ruleParts[1];

switch (pluginName) {
case 'plugin':
url = 'https://github.com/AtomLinter/linter-stylelint/tree/master/docs/noRuleNamespace.md';
break;
default:
url = 'https://github.com/AtomLinter/linter-stylelint/tree/master/docs/linkingNewRule.md';
}
}

// Escape any HTML in the message, and replace the rule ID with a link
return escapeHTML()(message.text).replace(message.rule, `<a href="${url}">${message.rule}</a>`);
}

function runStylelint(editor, options, filePath) {
return stylelint().lint(options).then(data => {
const result = data.results.shift();
Expand All @@ -101,14 +131,17 @@ function runStylelint(editor, options, filePath) {
filePath
}));

const warnings = result.warnings.map(warning => ({
const warnings = result.warnings.map(warning => {
// stylelint only allows 'error' and 'warning' as severity values
type: !warning.severity || warning.severity === 'error' ? 'Error' : 'Warning',
severity: !warning.severity || warning.severity === 'error' ? 'error' : 'warning',
text: warning.text,
filePath,
range: createRange(editor, warning)
}));
const severity = !warning.severity || warning.severity === 'error' ? 'Error' : 'Warning';
return {
type: severity,
severity: severity.toLowerCase(),
html: generateHTMLMessage(warning),
filePath,
range: createRange(editor, warning)
};
});

return toReturn.concat(invalidOptions).concat(warnings);
}, error => {
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -36,6 +36,7 @@
"atom-linter": "^5.0.0",
"atom-package-deps": "^4.0.1",
"cosmiconfig": "^1.1.0",
"escape-html": "^1.0.3",
"lazy-req": "^1.1.0",
"stylelint": "6.6.0",
"stylelint-config-standard": "^9.0.0"
Expand Down
27 changes: 19 additions & 8 deletions spec/linter-stylelint-spec.js
Expand Up @@ -20,6 +20,8 @@ const configStandardHtmlPath = path.join(htmlDir, 'stylelint-config-standard.htm
const goodPostCSS = path.join(__dirname, 'fixtures', 'postcss', 'styles.pcss');
const issuesPostCSS = path.join(__dirname, 'fixtures', 'postcss', 'issues.pcss');

const blockNoEmpty = 'Unexpected empty block (<a href="http://stylelint.io/user-guide/rules/block-no-empty">block-no-empty</a>)';

describe('The stylelint provider for Linter', () => {
const lint = require(path.join('..', 'lib', 'index.js')).provideLinter().lint;

Expand All @@ -45,7 +47,8 @@ describe('The stylelint provider for Linter', () => {
// test only the first error
expect(messages[0].type).toBe('Error');
expect(messages[0].severity).toBe('error');
expect(messages[0].text).toBe('Unexpected empty block (block-no-empty)');
expect(messages[0].text).not.toBeDefined();
expect(messages[0].html).toBe(blockNoEmpty);
expect(messages[0].filePath).toBe(configStandardPath);
expect(messages[0].range).toEqual([[0, 5], [0, 7]]);
})
Expand All @@ -62,7 +65,8 @@ describe('The stylelint provider for Linter', () => {
// test only the first error
expect(messages[0].type).toBe('Warning');
expect(messages[0].severity).toBe('warning');
expect(messages[0].text).toBe('Unexpected empty block (block-no-empty)');
expect(messages[0].text).not.toBeDefined();
expect(messages[0].html).toBe(blockNoEmpty);
expect(messages[0].filePath).toMatch(/.+warn\.css$/);
expect(messages[0].range).toEqual([[0, 5], [0, 7]]);
})
Expand All @@ -84,7 +88,8 @@ describe('The stylelint provider for Linter', () => {

expect(messages[0].type).toBe('Error');
expect(messages[0].severity).toBe('error');
expect(messages[0].text).toBe('Unknown word (CssSyntaxError)');
expect(messages[0].text).not.toBeDefined();
expect(messages[0].html).toBe('Unknown word (CssSyntaxError)');
expect(messages[0].filePath).toBe(invalidPath);
expect(messages[0].range).toEqual([[0, 0], [0, 3]]);
})
Expand All @@ -101,6 +106,7 @@ describe('The stylelint provider for Linter', () => {
expect(messages[0].type).toBe('Error');
expect(messages[0].severity).toBe('error');
expect(messages[0].text).toBe(text);
expect(messages[0].html).not.toBeDefined();
expect(messages[0].filePath).toBe(invalidRulePath);
expect(messages[0].range).not.toBeDefined();
})
Expand Down Expand Up @@ -164,7 +170,8 @@ describe('The stylelint provider for Linter', () => {

expect(messages[0].type).toBe('Warning');
expect(messages[0].severity).toBe('warning');
expect(messages[0].text).toBe('This file is ignored');
expect(messages[0].text).not.toBeDefined();
expect(messages[0].html).toBe('This file is ignored');
expect(messages[0].filePath).toBe(ignorePath);
expect(messages[0].range).toEqual([[0, 0], [0, 7]]);
expect(atom.notifications.addError.calls.length).toBe(0);
Expand All @@ -185,7 +192,8 @@ describe('The stylelint provider for Linter', () => {
// test only the first error
expect(messages[0].type).toBe('Error');
expect(messages[0].severity).toBe('error');
expect(messages[0].text).toBe('Unexpected empty block (block-no-empty)');
expect(messages[0].text).not.toBeDefined();
expect(messages[0].html).toBe(blockNoEmpty);
expect(messages[0].filePath).toBe(configStandardPath);
expect(messages[0].range).toEqual([[0, 5], [0, 7]]);
})
Expand All @@ -201,7 +209,8 @@ describe('The stylelint provider for Linter', () => {
// test only the first error
expect(messages[0].type).toBe('Error');
expect(messages[0].severity).toBe('error');
expect(messages[0].text).toBe('Unexpected empty block (block-no-empty)');
expect(messages[0].text).not.toBeDefined();
expect(messages[0].html).toBe(blockNoEmpty);
expect(messages[0].filePath).toBe(configStandardLessPath);
expect(messages[0].range).toEqual([[0, 5], [0, 7]]);
})
Expand All @@ -227,7 +236,8 @@ describe('The stylelint provider for Linter', () => {
// test only the first error
expect(messages[0].type).toBe('Error');
expect(messages[0].severity).toBe('error');
expect(messages[0].text).toBe('Unexpected empty block (block-no-empty)');
expect(messages[0].text).not.toBeDefined();
expect(messages[0].html).toBe(blockNoEmpty);
expect(messages[0].filePath).toBe(configStandardHtmlPath);
expect(messages[0].range).toEqual([[1, 7], [1, 9]]);
})
Expand All @@ -254,7 +264,8 @@ describe('The stylelint provider for Linter', () => {
// test only the first error
expect(messages[0].type).toBe('Error');
expect(messages[0].severity).toBe('error');
expect(messages[0].text).toBe('Unexpected empty block (block-no-empty)');
expect(messages[0].text).not.toBeDefined();
expect(messages[0].html).toBe(blockNoEmpty);
expect(messages[0].filePath).toBe(issuesPostCSS);
expect(messages[0].range).toEqual([[0, 5], [0, 7]]);
})
Expand Down

0 comments on commit 3a1bbf0

Please sign in to comment.