-
-
Notifications
You must be signed in to change notification settings - Fork 30
New: require-meta-docs-url (fixes #55) #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
not-an-aardvark
merged 5 commits into
eslint-community:master
from
mysticatea:require-meta-docs-url/new
Jan 14, 2018
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
4e5a868
New: require-meta-docs-url (fixes #55)
mysticatea 70c2660
Chore: disable self/require-meta-docs-url
mysticatea 3f17cf4
Docs: update README.md
mysticatea f88061b
Docs: add document for version-specific URLs
mysticatea 2fe9afb
fix typo
mysticatea File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
# require rules to implement a meta.docs.url property (require-meta-docs-url) | ||
|
||
`meta.docs.url` property is the official location to store a URL to their documentation in the rule metadata. | ||
Some integration tools will show the URL to users to understand rules. | ||
|
||
## Rule Details | ||
|
||
This rule aims to require ESLint rules to have a `meta.docs.url` property. | ||
|
||
This rule has an option. | ||
|
||
```json | ||
{ | ||
"eslint-plugin/require-meta-docs-url": ["error", { | ||
"pattern": "https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/{{name}}.md" | ||
}] | ||
} | ||
``` | ||
|
||
- `pattern` (`string`) ... A pattern to enforce rule's document URL. It replaces `{{name}}` placeholder by each rule name. The rule name is the basename of each rule file. Default is undefined. | ||
|
||
If you set the `pattern` option, this rule adds `meta.docs.url` property automatically when you executed `eslint --fix` command. | ||
|
||
The following patterns are considered warnings: | ||
|
||
```js | ||
|
||
/* eslint eslint-plugin/require-meta-docs-url: "error" */ | ||
|
||
module.exports = { | ||
meta: {}, | ||
create(context) { | ||
} | ||
}; | ||
|
||
``` | ||
|
||
```js | ||
|
||
/* eslint eslint-plugin/require-meta-docs-url: "error" */ | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
url: undefined | ||
} | ||
}, | ||
create(context) { | ||
} | ||
}; | ||
|
||
``` | ||
|
||
```js | ||
|
||
/* eslint eslint-plugin/require-meta-docs-url: ["error", {"pattern": "path/to/{{name}}.md"}] */ | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
url: "wrong URL" | ||
} | ||
}, | ||
create(context) { | ||
} | ||
}; | ||
|
||
``` | ||
|
||
The following patterns are not warnings: | ||
|
||
```js | ||
|
||
/* eslint eslint-plugin/require-meta-docs-url: "error" */ | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
url: "a URL" | ||
} | ||
}, | ||
create(context) { | ||
} | ||
}; | ||
|
||
``` | ||
|
||
```js | ||
|
||
/* eslint eslint-plugin/require-meta-docs-url: ["error", {"pattern": "path/to/{{name}}.md"}] */ | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
url: "path/to/rule-name.md" | ||
} | ||
}, | ||
create(context) { | ||
} | ||
}; | ||
|
||
``` | ||
|
||
## Version specific URL | ||
|
||
If you want to enforce version-specific URLs, it's feasible easily with `.eslintrc.js` and `npm version <type>` script. | ||
For example: | ||
|
||
**.eslintrc.js**: | ||
|
||
```js | ||
"use strict" | ||
|
||
const version = require("./package.json").version | ||
|
||
module.exports = { | ||
plugins: ["eslint-plugin"], | ||
// ... leaving out ... | ||
rules: { | ||
"eslint-plugin/require-meta-docs-url": ["error", { | ||
pattern: `path/to/v${version}/docs/rules/{{name}}.md`, | ||
}], | ||
} | ||
} | ||
``` | ||
|
||
**package.json**: | ||
|
||
```json | ||
{ | ||
"version": "1.0.0", | ||
"scripts": { | ||
"pretest": "eslint .", | ||
"test": "... leaving out ...", | ||
"preversion": "npm test", | ||
"version": "eslint . --fix && git add ." | ||
}, | ||
// ... leaving out ... | ||
} | ||
``` | ||
|
||
Then `npm version <type>` command will update every rule to the new version's URL. | ||
|
||
> npm runs `preversion` script on the current version, runs `version` script on the new version, and commits and makes a tag. | ||
> | ||
> Further reading: https://docs.npmjs.com/cli/version | ||
|
||
## When Not To Use It | ||
|
||
If you do not plan to provide rule's documentation in website, you can turn off this rule. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/** | ||
* @author Toru Nagashima <https://github.com/mysticatea> | ||
*/ | ||
|
||
'use strict'; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Requirements | ||
// ----------------------------------------------------------------------------- | ||
|
||
const path = require('path'); | ||
const util = require('../utils'); | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Rule Definition | ||
// ----------------------------------------------------------------------------- | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'require rules to implement a meta.docs.url property', | ||
category: 'Rules', | ||
recommended: false, | ||
}, | ||
fixable: 'code', | ||
schema: [{ | ||
type: 'object', | ||
properties: { | ||
pattern: { type: 'string' }, | ||
}, | ||
additionalProperties: false, | ||
}], | ||
}, | ||
|
||
/** | ||
* Creates AST event handlers for require-meta-docs-url. | ||
* @param {RuleContext} context - The rule context. | ||
* @returns {Object} AST event handlers. | ||
*/ | ||
create (context) { | ||
const options = context.options[0] || {}; | ||
const sourceCode = context.getSourceCode(); | ||
const filename = context.getFilename(); | ||
const ruleName = filename === '<input>' ? undefined : path.basename(filename, '.js'); | ||
const expectedUrl = !options.pattern || !ruleName | ||
? undefined | ||
: options.pattern.replace(/{{\s*name\s*}}/g, ruleName); | ||
|
||
/** | ||
* Check whether a given node is the expected URL. | ||
* @param {Node} node The node of property value to check. | ||
* @returns {boolean} `true` if the node is the expected URL. | ||
*/ | ||
function isExpectedUrl (node) { | ||
return Boolean( | ||
node && | ||
node.type === 'Literal' && | ||
typeof node.value === 'string' && | ||
( | ||
expectedUrl === undefined || | ||
node.value === expectedUrl | ||
) | ||
); | ||
} | ||
|
||
/** | ||
* Insert a given property into a given object literal. | ||
* @param {SourceCodeFixer} fixer The fixer. | ||
* @param {Node} node The ObjectExpression node to insert a property. | ||
* @param {string} propertyText The property code to insert. | ||
* @returns {void} | ||
*/ | ||
function insertProperty (fixer, node, propertyText) { | ||
if (node.properties.length === 0) { | ||
return fixer.replaceText(node, `{\n${propertyText}\n}`); | ||
} | ||
return fixer.insertTextAfter( | ||
sourceCode.getLastToken(node.properties[node.properties.length - 1]), | ||
`,\n${propertyText}` | ||
); | ||
} | ||
|
||
return { | ||
Program (node) { | ||
const info = util.getRuleInfo(node); | ||
if (info === null) { | ||
return; | ||
} | ||
|
||
const metaNode = info.meta; | ||
const docsPropNode = | ||
metaNode && | ||
metaNode.properties && | ||
metaNode.properties.find(p => p.type === 'Property' && util.getKeyName(p) === 'docs'); | ||
const urlPropNode = | ||
docsPropNode && | ||
docsPropNode.value.properties && | ||
docsPropNode.value.properties.find(p => p.type === 'Property' && util.getKeyName(p) === 'url'); | ||
|
||
if (isExpectedUrl(urlPropNode && urlPropNode.value)) { | ||
return; | ||
} | ||
|
||
context.report({ | ||
loc: | ||
(urlPropNode && urlPropNode.value.loc) || | ||
(docsPropNode && docsPropNode.value.loc) || | ||
(metaNode && metaNode.loc) || | ||
node.loc.start, | ||
|
||
message: | ||
!urlPropNode ? 'Rules should export a `meta.docs.url` property.' : | ||
!expectedUrl ? '`meta.docs.url` property must be a string.' : | ||
/* otherwise */ '`meta.docs.url` property must be `{{expectedUrl}}`.', | ||
|
||
data: { | ||
expectedUrl, | ||
}, | ||
|
||
fix (fixer) { | ||
if (expectedUrl) { | ||
const urlString = JSON.stringify(expectedUrl); | ||
if (urlPropNode) { | ||
return fixer.replaceText(urlPropNode.value, urlString); | ||
} | ||
if (docsPropNode && docsPropNode.value.type === 'ObjectExpression') { | ||
return insertProperty(fixer, docsPropNode.value, `url: ${urlString}`); | ||
} | ||
if (!docsPropNode && metaNode && metaNode.type === 'ObjectExpression') { | ||
return insertProperty(fixer, metaNode, `docs: {\nurl: ${urlString}\n}`); | ||
} | ||
} | ||
return null; | ||
}, | ||
}); | ||
}, | ||
}; | ||
}, | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: I think this should say "when you execute the
eslint --fix
command".There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, I fixed it!