├── .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 [![Build Status](https://travis-ci.org/jfmengels/eslint-rule-documentation.svg?branch=master)](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 | --------------------------------------------------------------------------------