Skip to content

Commit

Permalink
New: allows plugins to specify the URLs to their docs (fixes eslint#6582
Browse files Browse the repository at this point in the history
)
  • Loading branch information
pmcelhaney committed Jul 4, 2016
1 parent ee7fcfa commit 7fbd017
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 6 deletions.
4 changes: 3 additions & 1 deletion docs/developer-guide/nodejs-api.md
Expand Up @@ -105,7 +105,8 @@ The `verify()` method returns an array of objects containing information about t
fix: {
range: [1, 15],
text: ";"
}
},
docURI: "http://eslint.org/docs/rules/semi"
}
```

Expand All @@ -120,6 +121,7 @@ The information available for each linting message is:
* `severity` - either 1 or 2, depending on your configuration.
* `source` - the line of code where the problem is (or empty string if it can't be found).
* `fix` - an object describing the fix for the problem (this property is omitted if no fix is available).
* `docURI` - where to find documentation for the rule (this property is omitted if the rule comes from a plugin that does not provide a URI via [getURI()](http://eslint.org/docs/developer-guide/working-with-plugins#rules-in-plugins))

You can also get an instance of the `SourceCode` object used inside of `linter` by using the `getSourceCode()` method:

Expand Down
17 changes: 17 additions & 0 deletions docs/developer-guide/working-with-plugins.md
Expand Up @@ -24,6 +24,21 @@ module.exports = {

To use the rule in ESLint, you would use the unprefixed plugin name, followed by a slash, followed by the rule name. So if this plugin were named `eslint-plugin-myplugin`, then in your configuration you'd refer to the rule by the name `myplugin/dollar-sign`. Example: `"rules": {"myplugin/dollar-sign": 2}`.

#### Linking to Rule Documentation

If your plugin has rules, you can tell ESLint where to find the documentation for those rules. The
URI will be passed on via the API so that editors and other clients can take advantage of it.

To specify where the documentation will be found, include a getDocURI function.

```js
module.exports = {
getDocURI: function(ruleName) {
return "http://path.to/docs/" + ruleName;
}
};
```

### Environments in Plugins

Plugins can expose additional environments for use in ESLint. To do so, the plugin must export an `environments` object. The keys of the `environments` object are the names of the different environments provided and the values are the environment settings. For example:
Expand Down Expand Up @@ -104,6 +119,8 @@ configs: {

**Note:** Please note that configuration will not automatically attach your rules and you have to specify your plugin name and any rules you want to enable that are part of the plugin. Any plugin rules must be prefixed with the short or long plugin name. See [Configuring Plugins](../user-guide/configuring#configuring-plugins)



### Peer Dependency

To make clear that the plugin requires ESLint to work correctly you have to declare ESLint as a `peerDependency` in your `package.json`.
Expand Down
17 changes: 15 additions & 2 deletions lib/eslint.js
Expand Up @@ -458,6 +458,10 @@ function prepareConfig(config) {
parserOptions: ConfigOps.merge(parserOptions, config.parserOptions || {})
};

if (config.getDocURI) {
preparedConfig.getDocURI = config.getDocURI;
}

if (preparedConfig.parserOptions.sourceType === "module") {
if (!preparedConfig.parserOptions.ecmaFeatures) {
preparedConfig.parserOptions.ecmaFeatures = {};
Expand Down Expand Up @@ -819,9 +823,11 @@ module.exports = (function() {
options = getRuleOptions(config.rules[key]);

try {

var ruleContext = new RuleContext(
key, api, severity, options,
config.settings, config.parserOptions, config.parser, ruleCreator.meta);
config.settings, config.parserOptions, config.parser, ruleCreator.meta, config.getDocURI);


rule = ruleCreator.create ? ruleCreator.create(ruleContext) :
ruleCreator(ruleContext);
Expand Down Expand Up @@ -937,9 +943,12 @@ module.exports = (function() {
* with symbols being replaced by this object's values.
* @param {Object} fix A fix command description.
* @param {Object} meta Metadata of the rule
* @param {Function} getDocURI generates the doc URI for the rule
* @returns {void}
*/
api.report = function(ruleId, severity, node, location, message, opts, fix, meta) {
api.report = function(ruleId, severity, node, location, message, opts, fix, meta, getDocURI) {


if (node) {
assert.strictEqual(typeof node, "object", "Node must be an object");
}
Expand Down Expand Up @@ -981,6 +990,10 @@ module.exports = (function() {
source: sourceCode.lines[location.line - 1] || ""
};

if (getDocURI) {
problem.docURI = getDocURI(ruleId);
}

// ensure there's range and text properties, otherwise it's not a valid fix
if (fix && Array.isArray(fix.range) && (typeof fix.text === "string")) {

Expand Down
14 changes: 11 additions & 3 deletions lib/rule-context.js
Expand Up @@ -71,8 +71,9 @@ var PASSTHROUGHS = [
* @param {Object} parserOptions The parserOptions settings passed from the config file.
* @param {Object} parserPath The parser setting passed from the config file.
* @param {Object} meta The metadata of the rule
* @param {Function} getDocURI generates the doc URI for the rule
*/
function RuleContext(ruleId, eslint, severity, options, settings, parserOptions, parserPath, meta) {
function RuleContext(ruleId, eslint, severity, options, settings, parserOptions, parserPath, meta, getDocURI) {

// public.
this.id = ruleId;
Expand All @@ -82,6 +83,10 @@ function RuleContext(ruleId, eslint, severity, options, settings, parserOptions,
this.parserPath = parserPath;
this.meta = meta;

if (getDocURI) {
this.getDocURI = getDocURI;
}

// private.
this.eslint = eslint;
this.severity = severity;
Expand Down Expand Up @@ -131,7 +136,8 @@ RuleContext.prototype = {
descriptor.message,
descriptor.data,
fix,
this.meta
this.meta,
this.getDocURI
);

return;
Expand All @@ -145,7 +151,9 @@ RuleContext.prototype = {
location,
message,
opts,
this.meta
fix,
this.meta,
this.getDocURI
);
}
};
Expand Down
15 changes: 15 additions & 0 deletions tests/lib/eslint.js
Expand Up @@ -1893,6 +1893,21 @@ describe("eslint", function() {
messages = eslint.verify(codeB, config, filename, false);
assert.equal(messages.length, 1);
});

it("should report the docURI provided by plugin", function() {
var config = {
rules: {"test-plugin/test-rule": 2},
getDocURI: function(ruleName) {
return "http://path.to/docs/" + ruleName;
}
};
var code = "var a = \"trigger violation\";";

eslint.reset();
var messages = eslint.verify(code, config, filename, false);

assert.equal(messages[0].docURI, "http://path.to/docs/test-plugin/test-rule");
});
});

describe("when evaluating code with comments to enable and disable all reporting", function() {
Expand Down

0 comments on commit 7fbd017

Please sign in to comment.