Skip to content

Ensure rule docs mention all rule options #226

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
merged 1 commit into from
Oct 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions docs/rules/require-meta-docs-url.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,6 @@ A rule can store the URL to its documentation page in `meta.docs.url`. This enab

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` which allows any URL.

If you set the `pattern` option, this rule adds `meta.docs.url` property automatically when you execute `eslint --fix` command.

Examples of **incorrect** code for this rule:

```js
Expand Down Expand Up @@ -97,6 +83,22 @@ module.exports = {

```

## Options

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` which allows any URL.

If you set the `pattern` option, this rule adds `meta.docs.url` property automatically when you execute `eslint --fix` command.

## Version specific URL

If you want to enforce version-specific URLs, it's feasible easily with `.eslintrc.js` and `npm version <type>` script.
Expand Down
43 changes: 43 additions & 0 deletions tests/lib/rule-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,31 @@ function capitalizeFirstLetter (string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}

/**
* Get list of named options from a JSON schema (used for rule schemas).
* @param {Object|Array} jsonSchema - the JSON schema to check
* @returns {String[]} list of named options
*/
function getAllNamedOptions (jsonSchema) {
if (!jsonSchema) {
return [];
}

if (Array.isArray(jsonSchema)) {
return jsonSchema.flatMap(item => getAllNamedOptions(item));
}

if (jsonSchema.items) {
return getAllNamedOptions(jsonSchema.items);
}

if (jsonSchema.properties) {
return Object.keys(jsonSchema.properties);
}

return [];
}

describe('rule setup is correct', () => {
it('should have a list of exported rules and rules directory that match', () => {
const filePath = path.join(__dirname, '..', 'lib', 'rules');
Expand Down Expand Up @@ -131,6 +156,24 @@ describe('rule setup is correct', () => {
for (const unexpectedNotice of unexpectedNotices) {
assert.ok(!fileContents.includes(MESSAGES[unexpectedNotice]), 'does not include notice: ' + MESSAGES[unexpectedNotice]);
}

// Check if the rule has configuration options.
if (
(Array.isArray(rule.meta.schema) && rule.meta.schema.length > 0) ||
(typeof rule.meta.schema === 'object' && Object.keys(rule.meta.schema).length > 0)
) {
// Should have a configuration section header:
assert.ok(fileContents.includes('## Options'), 'Should have an "## Options" section');

// Ensure all configuration options are mentioned.
for (const namedOption of getAllNamedOptions(rule.meta.schema)) {
assert.ok(fileContents.includes(namedOption), 'Should mention the `' + namedOption + '` option');
}
} else {
// Should NOT have any options/config section headers:
assert.notOk(fileContents.includes('# Options'), 'Should not have an "Options" section');
assert.notOk(fileContents.includes('# Config'), 'Should not have a "Config" section');
}
});
});
}
Expand Down