├── .editorconfig
├── .gitattributes
├── .gitignore
├── .travis.yml
├── contributing.md
├── index.js
├── license
├── package.json
├── plugins.json
├── readme.md
└── test.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [{package.json,*.yml}]
11 | indent_style = space
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.js text eol=lf
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '6'
4 | - '4'
5 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | # Add support for a new plugin
2 |
3 | You may have arrived here after clicking on a rule name from a linting error message or a different tool. If so, you may have expected to find the documentation of a rule. Unfortunately, it is likely that the rule originated from an ESLint plugin that doesn't specify where it's own documentation is, or that is unknown to this tool.
4 |
5 | In order to improve the tool you were using and improve others, your help would be very valuable.
6 |
7 | ## How you can help
8 |
9 | The best way you can help is to file an issue or submit a PR to the rule in
10 | question asking them to support the `rule.meta.docs.url` property on their rule.
11 | This was added in [ESLint v4.15.0][]
12 | and provides a location where the entire ESLint ecosystem can get to the location
13 | of the rule's documentation.
14 |
15 | This package will continue to be maintained for rules that haven't updated to
16 | specify their own location though, so if you would like to add support here in
17 | `eslint-rule-documentation` you can submit a pull request.
18 |
19 | You'll need a [GitHub account][join github]!
20 |
21 | 1. Find out where the documentation for the rules of the plugin are located. Find the plugin on `npm`, then the location of the repository, then try to find out the generic URL for rule documentation. Very often, it is at `https://github.com/USERNAME/eslint-plugin-PLUGINNAME/blob/master/docs/rules/RULENAME.md`.
22 | 2. Edit `plugins.json`, the file containing the list of supported plugins, by clicking [this link][edit plugins].
23 | 3. Add a new entry for your plugin, using the link found in step 1, containing `RULENAME`as a placeholder for the name of the rule.
24 | - If the author uses the standard convention of hosting the documentation at `https://github.com/USERNAME/eslint-plugin-PLUGINNAME/blob/master/docs/rules/RULENAME.md`, then you can just put `"PLUGINNAME": "USERNAME",` in `plugins.json`. ([Example][import])
25 | - If the author did not follow the repository naming convention outlined above, but still puts the rule documentation in `docs/rules/RULENAME.md`, then you can put `"PLUGINNAME": "USERNAME/REPONAME",` in `plugins.json`. ([Example][xo])
26 | - If the author does not follow the convention for rule placement, then you must specify the path for the documentation.
27 | For example, if the rules for `eslint-plugin-foo` are documented under headings in `README.md`, you should specify that with `https://github.com/author/eslint-plugin-foo#RULENAME`, where `RULENAME` will get replaced with the name of the rule to open. ([Example][mozilla])
28 | 4. In the bottom-field, add a title like `Add support for eslint-plugin-XYZ`, maybe add a little message, and then click on submit.
29 |
30 | Thanks a lot for doing this! If you have any trouble with these steps, please describe your problem in a [new Issue][], and we'll try to help you for the last bit, or do it ourselves.
31 |
32 | [ESLint v4.15.0]: https://eslint.org/blog/2018/01/eslint-v4.15.0-released
33 | [join github]: https://github.com/join
34 | [edit plugins]: https://github.com/jfmengels/eslint-rule-documentation/edit/master/plugins.json
35 | [import]: https://github.com/jfmengels/eslint-rule-documentation/blob/9ddb2c9e6e4fc9e89518ac69fefd97fc9d79904b/plugins.json#L13
36 | [xo]: https://github.com/jfmengels/eslint-rule-documentation/blob/9ddb2c9e6e4fc9e89518ac69fefd97fc9d79904b/plugins.json#L38
37 | [mozilla]: https://github.com/jfmengels/eslint-rule-documentation/blob/9ddb2c9e6e4fc9e89518ac69fefd97fc9d79904b/plugins.json#L24
38 | [new Issue]: https://github.com/jfmengels/eslint-rule-documentation/issues/new
39 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var plugins = require('./plugins.json');
4 |
5 | for (var pluginName of Object.keys(plugins)) {
6 | var url = plugins[pluginName];
7 |
8 | if (!url.includes('/')) {
9 | url += '/eslint-plugin-' + pluginName;
10 | }
11 | if (url.split('/').length === 2) {
12 | url = 'https://github.com/' + url + '/blob/master/docs/rules/RULENAME.md';
13 | }
14 |
15 | plugins[pluginName] = url;
16 | }
17 |
18 | function getRuleURI(ruleId) {
19 | if (typeof ruleId !== 'string') {
20 | throw new TypeError(`ruleId must be a string, got ${typeof ruleId}`);
21 | }
22 |
23 | var ruleParts = ruleId.split('/');
24 |
25 | if (ruleParts.length === 1) {
26 | return {
27 | found: true,
28 | url: 'https://eslint.org/docs/rules/' + ruleId
29 | };
30 | }
31 |
32 | var pluginName = ruleParts[0];
33 | var ruleName = ruleParts[1];
34 | var url = plugins[pluginName];
35 |
36 | if (!url) {
37 | return {
38 | found: false,
39 | url: 'https://github.com/jfmengels/eslint-rule-documentation/blob/master/contributing.md'
40 | };
41 | }
42 |
43 | return {
44 | found: true,
45 | url: url.replace('RULENAME', ruleName)
46 | };
47 | }
48 |
49 | module.exports = getRuleURI;
50 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Jeroen Engels (github.com/jfmengels)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eslint-rule-documentation",
3 | "version": "1.0.23",
4 | "description": "Find the url for the documentation of an ESLint rule",
5 | "license": "MIT",
6 | "repository": "jfmengels/eslint-rule-documentation",
7 | "author": {
8 | "name": "Jeroen Engels",
9 | "email": "jfm.engels@gmail.com",
10 | "url": "github.com/jfmengels"
11 | },
12 | "engines": {
13 | "node": ">=4.0.0"
14 | },
15 | "scripts": {
16 | "test": "xo && ava"
17 | },
18 | "files": [
19 | "index.js",
20 | "plugins.json"
21 | ],
22 | "keywords": [
23 | "eslint",
24 | "eslintplugin",
25 | "eslint-plugin",
26 | "plugin",
27 | "plugins",
28 | "rule",
29 | "rules",
30 | "doc",
31 | "documentation"
32 | ],
33 | "devDependencies": {
34 | "ava": "^0.15.2",
35 | "xo": "^0.16.0"
36 | },
37 | "xo": {
38 | "space": 2
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/plugins.json:
--------------------------------------------------------------------------------
1 | {
2 | "angular": "Gillespie59",
3 | "ava": "avajs",
4 | "backbone": "ilyavolodin",
5 | "ember": "netguru",
6 | "es6-recommended": "https://github.com/mgtitimoli/eslint-plugin-es6-recommended#rules",
7 | "eslint-comments": "mysticatea",
8 | "eslint-plugin": "not-an-aardvark",
9 | "flowtype": "https://github.com/gajus/eslint-plugin-flowtype#RULENAME",
10 | "fp": "jfmengels",
11 | "github": "github",
12 | "immutable": "https://github.com/jhusain/eslint-plugin-immutable#RULENAME",
13 | "import": "benmosher",
14 | "import-order": "jfmengels",
15 | "jasmine": "tlvince",
16 | "jest": "jest-community",
17 | "jsdoc": "https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-RULENAME",
18 | "jsx-a11y": "evcohen",
19 | "lodash": "wix",
20 | "lodash-fp": "jfmengels",
21 | "meteor": "dferber90",
22 | "mocha": "lo1tuma",
23 | "mongodb": "https://github.com/nfroidure/eslint-plugin-mongodb#RULENAME",
24 | "mozilla": "https://gecko.readthedocs.io/en/latest/tools/lint/linters/eslint-plugin-mozilla.html#RULENAME",
25 | "netguru-ember": "https://github.com/netguru/eslint-plugin-netguru-ember/blob/master/docs/RULES.md#RULENAME",
26 | "no-unsanitized": "mozilla",
27 | "no-use-extend-native": "dustinspecker",
28 | "node": "mysticatea",
29 | "prettier": "https://github.com/prettier/eslint-plugin-prettier#options",
30 | "promise": "xjamundx",
31 | "protractor": "alecxe",
32 | "react": "yannickcr",
33 | "react-native": "Intellicode",
34 | "redux-saga": "pke",
35 | "requirejs": "cvisco",
36 | "security": "https://github.com/nodesecurity/eslint-plugin-security#rules",
37 | "standard": "https://github.com/xjamundx/eslint-plugin-standard#rules-explanations",
38 | "typescript": "nzakas",
39 | "unicorn": "sindresorhus",
40 | "xo": "sindresorhus/eslint-plugin-unicorn",
41 | "visualforce": "forcedotcom",
42 | "vue": "vuejs",
43 | "jsx-control-statements": "vkbansal"
44 | }
45 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # eslint-rule-documentation [](https://travis-ci.org/jfmengels/eslint-rule-documentation)
2 |
3 | > Find the url for the documentation of an [ESLint] rule
4 |
5 |
6 | ## Install
7 |
8 | ```
9 | $ npm install --save eslint-rule-documentation
10 | ```
11 |
12 |
13 | ## Usage
14 |
15 | ```js
16 | const getRuleURI = require('eslint-rule-documentation');
17 |
18 | // find url for core rules
19 | getRuleURI('no-var');
20 | // => { found: true, url: 'https://eslint.org/docs/rules/no-var' }
21 |
22 | // find url for known plugins
23 | getRuleURI('import/no-unresolved');
24 | // => { found: true, url: 'https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md' }
25 |
26 | // If the plugin is not known, get a link to help improve this
27 | getRuleURI('unknown-foo/bar');
28 | // => { found: false, url: 'https://github.com/jfmengels/eslint-rule-documentation/blob/master/contributing.md' }
29 | ```
30 |
31 | ## Contributing
32 |
33 | If you find a plugin that you use is not in the [list of supported plugins](./plugins.json), please consider adding it to the project by following the instructions [here](./contributing.md).
34 |
35 |
36 | ## API
37 |
38 | ### getRuleURI(ruleId)
39 |
40 |
41 |
42 | #### ruleId
43 |
44 | Type: `string`
45 |
46 | Id of an [ESLint] rule.
47 |
48 | Examples:
49 | - core rule: `no-var`
50 | - plugin rule: `import/no-unresolved` (from the [eslint-plugin-import] plugin).
51 |
52 | #### returns
53 |
54 | Type: `object`
55 |
56 | ```js
57 | {
58 | found: ,
59 | url:
60 | }
61 | ```
62 |
63 | - `found`: `true` if the rule is an ESLint core rule, or a rule of a known plugin, `false` otherwise.
64 | - `url`: if `found` is `true`, url of the documentation of a rule. If `found` is `false`, url of the [contribution guidelines](./contributing.md).
65 |
66 | ## Thanks
67 |
68 | Special thanks to the team behind [linter-eslint] for the original work, and the people who contributed there.
69 |
70 |
71 | ## License
72 |
73 | MIT © [Jeroen Engels](https://github.com/jfmengels)
74 |
75 | [eslint-plugin-import]: https://github.com/benmosher/eslint-plugin-import
76 | [ESLint]: https://eslint.org/
77 | [linter-eslint]: https://github.com/AtomLinter/linter-eslint
78 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import test from 'ava';
3 | import getRuleURI from './';
4 |
5 | test('should return url of core rules', t => {
6 | t.deepEqual(getRuleURI('no-var'),
7 | {
8 | found: true,
9 | url: 'https://eslint.org/docs/rules/no-var'
10 | });
11 | t.deepEqual(getRuleURI('no-console'),
12 | {
13 | found: true,
14 | url: 'https://eslint.org/docs/rules/no-console'
15 | });
16 | t.deepEqual(getRuleURI('array-callback-return'),
17 | {
18 | found: true,
19 | url: 'https://eslint.org/docs/rules/array-callback-return'
20 | });
21 | });
22 |
23 | test('should return url of found plugin rules', t => {
24 | t.deepEqual(getRuleURI('import/order'),
25 | {
26 | found: true,
27 | url: 'https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md'
28 | });
29 | t.deepEqual(getRuleURI('import/no-unresolved'),
30 | {
31 | found: true,
32 | url: 'https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md'
33 | });
34 |
35 | t.deepEqual(getRuleURI('ava/no-identical-title'),
36 | {
37 | found: true,
38 | url: 'https://github.com/avajs/eslint-plugin-ava/blob/master/docs/rules/no-identical-title.md'
39 | });
40 | t.deepEqual(getRuleURI('ava/no-todo-test'),
41 | {
42 | found: true,
43 | url: 'https://github.com/avajs/eslint-plugin-ava/blob/master/docs/rules/no-todo-test.md'
44 | });
45 | t.deepEqual(getRuleURI('eslint-comments/no-unlimited-disable'),
46 | {
47 | found: true,
48 | url: 'https://github.com/mysticatea/eslint-plugin-eslint-comments/blob/master/docs/rules/no-unlimited-disable.md'
49 | });
50 | t.deepEqual(getRuleURI('promise/no-native'),
51 | {
52 | found: true,
53 | url: 'https://github.com/xjamundx/eslint-plugin-promise/blob/master/docs/rules/no-native.md'
54 | });
55 | t.deepEqual(getRuleURI('promise/catch-or-return'),
56 | {
57 | found: true,
58 | url: 'https://github.com/xjamundx/eslint-plugin-promise/blob/master/docs/rules/catch-or-return.md'
59 | });
60 | t.deepEqual(getRuleURI('standard/array-bracket-even-spacing'),
61 | {
62 | found: true,
63 | url: 'https://github.com/xjamundx/eslint-plugin-standard#rules-explanations'
64 | });
65 | });
66 |
67 | test.cb('should be able to parse `plugin.json`', t => {
68 | fs.readFile('./plugins.json', 'utf8', (err, content) => {
69 | t.falsy(err);
70 | t.truthy(content);
71 | const parsedContent = JSON.parse(content);
72 | t.true(typeof parsedContent === 'object');
73 | t.end();
74 | });
75 | });
76 |
77 | test('should return url to help improve this tool', t => {
78 | t.deepEqual(getRuleURI('unknown-foo/bar'),
79 | {
80 | found: false,
81 | url: 'https://github.com/jfmengels/eslint-rule-documentation/blob/master/contributing.md'
82 | });
83 | });
84 |
85 | test('should throw when ruleId is not a string', t => {
86 | t.throws(() => getRuleURI(null), 'ruleId must be a string, got object');
87 | });
88 |
--------------------------------------------------------------------------------