Permalink
Browse files

Add a link to rule documentation

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...
1 parent 3f2b3d8 commit 3a1bbf0281147a4a106d44261a1acffb7efa806c @Arcanemagus Arcanemagus committed Jun 15, 2016
Showing with 94 additions and 15 deletions.
  1. +21 −0 docs/linkingNewRule.md
  2. +13 −0 docs/noRuleNamespace.md
  3. +40 −7 lib/index.js
  4. +1 −0 package.json
  5. +19 −8 spec/linter-stylelint-spec.js
@@ -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!
@@ -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
View
@@ -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
@@ -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();
@@ -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 => {
View
@@ -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"
@@ -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;
@@ -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]]);
})
@@ -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]]);
})
@@ -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]]);
})
@@ -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();
})
@@ -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);
@@ -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]]);
})
@@ -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]]);
})
@@ -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]]);
})
@@ -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]]);
})

0 comments on commit 3a1bbf0

Please sign in to comment.