Skip to content

Commit

Permalink
feat: add settings overrideReplacesDocs, `augmentsExtendsReplacesDo…
Browse files Browse the repository at this point in the history
…cs`, `implementsReplacesDocs` and apply to `require-param`, `require-description`, `require-example`, and `require-returns` for exempting all of these from errors in the case of the presence of `@override`, `@augments`/`@extends`, or `@implements`, respectively.

This commit also adds the following new behavior: with `require-description`, `inheritdoc` will avoid erring.

This commit also causes the following non-breaking changes:

With `require-example` and `require-returns`, `@override` may now err if the setting `overrideReplacesDocs` is set to false
With `require-returns`, `@implements` may now err if the setting `implementsReplacesDocs` is set to false
With `require-example`, `require-returns`, and `require-description`, `@augments` or `@extends` may now avoid erring if the setting `augmentsExtendsReplacesDocs` is set to true

Deprecating `settings.jsdoc.allowOverrideWithoutParam`, `settings.jsdoc.allowImplementsWithoutParam`, and `settings.jsdoc.allowAugmentsExtendsWithoutParam` in favor of the more tag-independent settings.
  • Loading branch information
brettz9 committed May 24, 2019
1 parent 6d6e1fc commit 9cc49a2
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 84 deletions.
29 changes: 16 additions & 13 deletions .README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,18 +190,16 @@ tags in the rule `check-tag-names`. The format of the configuration is as follow
}
```

### Allow `@override` Without Accompanying `@param` Tags
### `@override`/`@augments`/`@extends`/`@implements` Without Accompanying `@param`/`@description`/`@example`/`@returns`

Use any of the following settings to override `require-param` and allow
`@param` to be omitted when the specified tags are present on the JSDoc
comment or the parent class comment. The default value for each is `false`.
The following settings allows the element(s) they reference to be omitted
on the JSDoc comment block of the function or that of its parent class
for any of the "require" rules (i.e., `require-param`, `require-description`,
`require-example`, or `require-returns`).

* `settings.jsdoc.allowOverrideWithoutParam` - Enables behavior with
`@override` tag
* `settings.jsdoc.allowImplementsWithoutParam` - Enables behavior with
`@implements` tag
* `settings.jsdoc.allowAugmentsExtendsWithoutParam` - Enables behavior with
`@augments` tag or its synonym `@extends`
* `settings.jsdoc.overrideReplacesDocs` (`@override`) - Defaults to `true`
* `settings.jsdoc.augmentsExtendsReplacesDocs` (`@augments` or its alias `@extends`) - Defaults to `false`.
* `settings.jsdoc.implementsReplacesDocs` (`@implements`) - Defaults to `false`

The format of the configuration is as follows:

Expand All @@ -210,14 +208,19 @@ The format of the configuration is as follows:
"rules": {},
"settings": {
"jsdoc": {
"allowOverrideWithoutParam": true,
"allowImplementsWithoutParam": true,
"allowAugmentsExtendsWithoutParam": true
"overrideReplacesDocs": true,
"augmentsExtendsReplacesDocs": true,
"implementsReplacesDocs": true
}
}
}
```

`settings.jsdoc.allowOverrideWithoutParam`,
`settings.jsdoc.allowImplementsWithoutParam`, and
`settings.jsdoc.allowAugmentsExtendsWithoutParam` performed a similar function
but restricted to `@param`. These settings are now deprecated.

### Settings to Configure `check-types` and `no-undefined-types`

- `settings.jsdoc.preferredTypes` An option map to indicate preferred
Expand Down
33 changes: 18 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ JSDoc linting rules for ESLint.
* [Exempting empty functions from `require-jsdoc`](#eslint-plugin-jsdoc-settings-exempting-empty-functions-from-require-jsdoc)
* [Alias Preference](#eslint-plugin-jsdoc-settings-alias-preference)
* [Additional Tag Names](#eslint-plugin-jsdoc-settings-additional-tag-names)
* [Allow `@override` Without Accompanying `@param` Tags](#eslint-plugin-jsdoc-settings-allow-override-without-accompanying-param-tags)
* [`@override`/`@augments`/`@extends`/`@implements` Without Accompanying `@param`/`@description`/`@example`/`@returns`](#eslint-plugin-jsdoc-settings-override-augments-extends-implements-without-accompanying-param-description-example-returns)
* [Settings to Configure `check-types` and `no-undefined-types`](#eslint-plugin-jsdoc-settings-settings-to-configure-check-types-and-no-undefined-types)
* [Settings to Configure `valid-types`](#eslint-plugin-jsdoc-settings-settings-to-configure-valid-types)
* [Settings to Configure `require-returns`](#eslint-plugin-jsdoc-settings-settings-to-configure-require-returns)
Expand Down Expand Up @@ -241,19 +241,17 @@ tags in the rule `check-tag-names`. The format of the configuration is as follow
}
```

<a name="eslint-plugin-jsdoc-settings-allow-override-without-accompanying-param-tags"></a>
### Allow <code>@override</code> Without Accompanying <code>@param</code> Tags
<a name="eslint-plugin-jsdoc-settings-override-augments-extends-implements-without-accompanying-param-description-example-returns"></a>
### <code>@override</code>/<code>@augments</code>/<code>@extends</code>/<code>@implements</code> Without Accompanying <code>@param</code>/<code>@description</code>/<code>@example</code>/<code>@returns</code>

Use any of the following settings to override `require-param` and allow
`@param` to be omitted when the specified tags are present on the JSDoc
comment or the parent class comment. The default value for each is `false`.
The following settings allows the element(s) they reference to be omitted
on the JSDoc comment block of the function or that of its parent class
for any of the "require" rules (i.e., `require-param`, `require-description`,
`require-example`, or `require-returns`).

* `settings.jsdoc.allowOverrideWithoutParam` - Enables behavior with
`@override` tag
* `settings.jsdoc.allowImplementsWithoutParam` - Enables behavior with
`@implements` tag
* `settings.jsdoc.allowAugmentsExtendsWithoutParam` - Enables behavior with
`@augments` tag or its synonym `@extends`
* `settings.jsdoc.overrideReplacesDocs` (`@override`) - Defaults to `true`
* `settings.jsdoc.augmentsExtendsReplacesDocs` (`@augments` or its alias `@extends`) - Defaults to `false`.
* `settings.jsdoc.implementsReplacesDocs` (`@implements`) - Defaults to `false`

The format of the configuration is as follows:

Expand All @@ -262,14 +260,19 @@ The format of the configuration is as follows:
"rules": {},
"settings": {
"jsdoc": {
"allowOverrideWithoutParam": true,
"allowImplementsWithoutParam": true,
"allowAugmentsExtendsWithoutParam": true
"overrideReplacesDocs": true,
"augmentsExtendsReplacesDocs": true,
"implementsReplacesDocs": true
}
}
}
```

`settings.jsdoc.allowOverrideWithoutParam`,
`settings.jsdoc.allowImplementsWithoutParam`, and
`settings.jsdoc.allowAugmentsExtendsWithoutParam` performed a similar function
but restricted to `@param`. These settings are now deprecated.

<a name="eslint-plugin-jsdoc-settings-settings-to-configure-check-types-and-no-undefined-types"></a>
### Settings to Configure <code>check-types</code> and <code>no-undefined-types</code>

Expand Down
63 changes: 52 additions & 11 deletions src/iterateJsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ const curryUtils = (
allowEmptyNamepaths,
reportUnusedDisableDirectives,
noDefaultExampleRules,
overrideReplacesDocs,
implementsReplacesDocs,
augmentsExtendsReplacesDocs,
allowOverrideWithoutParam,
allowImplementsWithoutParam,
allowAugmentsExtendsWithoutParam,
Expand Down Expand Up @@ -130,16 +133,46 @@ const curryUtils = (
return captionRequired;
};

utils.isOverrideAllowedWithoutParam = () => {
return allowOverrideWithoutParam;
};
// These settings are deprecated and may be removed in the future along with this method.
utils.avoidDocsParamOnly = () => {
// These three checks are all for deprecated settings and may be removed in the future

// When settings.jsdoc.allowOverrideWithoutParam is true, override implies that all documentation is inherited.
if ((utils.hasTag('override') || utils.classHasTag('override')) && allowOverrideWithoutParam !== false) {
return true;
}

utils.isImplementsAllowedWithoutParam = () => {
return allowImplementsWithoutParam;
// When settings.jsdoc.allowImplementsWithoutParam is true, implements implies that all documentation is inherited.
// See https://github.com/gajus/eslint-plugin-jsdoc/issues/100
if ((utils.hasTag('implements') || utils.classHasTag('implements')) && allowImplementsWithoutParam !== false) {
return true;
}

// When settings.jsdoc.allowAugmentsExtendsWithoutParam is true, augments or extends implies that all documentation is inherited.
if ((utils.hasTag('augments') || utils.hasTag('extends') ||
utils.classHasTag('augments') || utils.classHasTag('extends')) && allowAugmentsExtendsWithoutParam) {
return true;
}

return false;
};

utils.isAugmentsExtendsAllowedWithoutParam = () => {
return allowAugmentsExtendsWithoutParam;
utils.avoidDocs = (param) => {
return param && utils.avoidDocsParamOnly() ||

// inheritdoc implies that all documentation is inherited; see http://usejsdoc.org/tags-inheritdoc.html
utils.hasTag('inheritdoc') ||

// After deprecation, the `param` parameter can be removed, but for now,
// don't default for `param` as it may have its own explicit settings to the contrary
(param && overrideReplacesDocs || !param && overrideReplacesDocs !== false) &&
(utils.hasTag('override') || utils.classHasTag('override')) ||
(param && implementsReplacesDocs || !param && implementsReplacesDocs !== false) &&
(utils.hasTag('implements') || utils.classHasTag('implements')) ||
augmentsExtendsReplacesDocs &&
(utils.hasATag(['augments', 'extends']) ||
utils.classHasTag('augments') ||
utils.classHasTag('extends'));
};

utils.isNamepathDefiningTag = (tagName) => {
Expand Down Expand Up @@ -263,10 +296,15 @@ export default (iterator, opts = {}) => {
const captionRequired = Boolean(_.get(context, 'settings.jsdoc.captionRequired'));
const noDefaultExampleRules = Boolean(_.get(context, 'settings.jsdoc.noDefaultExampleRules'));

// `require-param` only
const allowOverrideWithoutParam = Boolean(_.get(context, 'settings.jsdoc.allowOverrideWithoutParam'));
const allowImplementsWithoutParam = Boolean(_.get(context, 'settings.jsdoc.allowImplementsWithoutParam'));
const allowAugmentsExtendsWithoutParam = Boolean(_.get(context, 'settings.jsdoc.allowAugmentsExtendsWithoutParam'));
// `require-param`, `require-description`, `require-example`, `require-returns`
const overrideReplacesDocs = _.get(context, 'settings.jsdoc.overrideReplacesDocs');
const implementsReplacesDocs = _.get(context, 'settings.jsdoc.implementsReplacesDocs');
const augmentsExtendsReplacesDocs = _.get(context, 'settings.jsdoc.augmentsExtendsReplacesDocs');

// `require-param` only (deprecated)
const allowOverrideWithoutParam = _.get(context, 'settings.jsdoc.allowOverrideWithoutParam');
const allowImplementsWithoutParam = _.get(context, 'settings.jsdoc.allowImplementsWithoutParam');
const allowAugmentsExtendsWithoutParam = _.get(context, 'settings.jsdoc.allowAugmentsExtendsWithoutParam');

// `valid-types` only
const allowEmptyNamepaths = _.get(context, 'settings.jsdoc.allowEmptyNamepaths') !== false;
Expand Down Expand Up @@ -342,6 +380,9 @@ export default (iterator, opts = {}) => {
allowEmptyNamepaths,
reportUnusedDisableDirectives,
noDefaultExampleRules,
overrideReplacesDocs,
implementsReplacesDocs,
augmentsExtendsReplacesDocs,
allowOverrideWithoutParam,
allowImplementsWithoutParam,
allowAugmentsExtendsWithoutParam,
Expand Down
4 changes: 4 additions & 0 deletions src/rules/requireDescription.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export default iterateJsdoc(({
report,
utils
}) => {
if (utils.avoidDocs()) {
return;
}

const targetTagName = utils.getPreferredTagName('description');

const functionExamples = _.filter(jsdoc.tags, {
Expand Down
11 changes: 4 additions & 7 deletions src/rules/requireExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,16 @@ export default iterateJsdoc(({
report,
utils
}) => {
if (utils.avoidDocs()) {
return;
}

const targetTagName = 'example';

const functionExamples = _.filter(jsdoc.tags, {
tag: targetTagName
});

if (utils.hasATag([
'inheritdoc',
'override'
])) {
return;
}

if (utils.avoidExampleOnConstructors() && (
utils.hasATag([
'class',
Expand Down
22 changes: 1 addition & 21 deletions src/rules/requireParam.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,7 @@ export default iterateJsdoc(({
const functionParameterNames = utils.getFunctionParameterNames();
const jsdocParameterNames = utils.getJsdocParameterNames();

// inheritdoc implies that all documentation is inherited; see http://usejsdoc.org/tags-inheritdoc.html
if (utils.hasTag('inheritdoc')) {
return;
}

// When settings.jsdoc.allowOverrideWithoutParam is true, override implies that all documentation is inherited.
// See https://github.com/gajus/eslint-plugin-jsdoc/issues/73
if ((utils.hasTag('override') || utils.classHasTag('override')) && utils.isOverrideAllowedWithoutParam()) {
return;
}

// When settings.jsdoc.allowImplementsWithoutParam is true, implements implies that all documentation is inherited.
// See https://github.com/gajus/eslint-plugin-jsdoc/issues/100
if ((utils.hasTag('implements') || utils.classHasTag('implements')) && utils.isImplementsAllowedWithoutParam()) {
return;
}

// When settings.jsdoc.allowAugmentsExtendsWithoutParam is true, augments or extends implies that all documentation is inherited.
// See https://github.com/gajus/eslint-plugin-jsdoc/issues/100
if ((utils.hasTag('augments') || utils.hasTag('extends') ||
utils.classHasTag('augments') || utils.classHasTag('extends')) && utils.isAugmentsExtendsAllowedWithoutParam()) {
if (utils.avoidDocs('param')) {
return;
}

Expand Down
17 changes: 4 additions & 13 deletions src/rules/requireReturns.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ const canSkip = (utils) => {
// inheritdoc implies that all documentation is inherited
// see http://usejsdoc.org/tags-inheritdoc.html
//
// As we do not know the parent method, we cannot perform any checks.
'inheritdoc',
'override',

// Different Tag similar story. Abstract methods are by definition incomplete,
// Abstract methods are by definition incomplete,
// so it is not an error if it declares a return value but does not implement it.
'abstract',
'virtual',
Expand All @@ -31,19 +27,14 @@ const canSkip = (utils) => {
'constructor',

// This seems to imply a class as well
'interface',

// While we may, in a future rule, err in the case of (regular) functions
// using @implements (see https://github.com/gajus/eslint-plugin-jsdoc/issues/201 ),
// this should not error for those using the tag to indicate implementation of
// a particular function signature
'implements'
'interface'
]) ||
utils.isConstructor() ||

// Though ESLint avoided getters: https://github.com/eslint/eslint/blob/master/lib/rules/valid-jsdoc.js#L435
// ... getters seem that they should, unlike setters, always return:
utils.isSetter();
utils.isSetter() ||
utils.avoidDocs();
};

export default iterateJsdoc(({
Expand Down

0 comments on commit 9cc49a2

Please sign in to comment.