Skip to content

Commit dbc1c34

Browse files
committed
- enhancement: add array option exemptedBy on rules require-description and require-example
Allow for specifying tags whose presence on block (e.g., `type`) will avoid need for the given rule. Also add schema to tighten checking on require-param and require-returns.
1 parent ca3d885 commit dbc1c34

15 files changed

+227
-17
lines changed

.README/rules/require-description.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ Requires that all functions have a description.
77

88
#### Options
99

10+
An options object may have any of the following properties:
11+
1012
- `contexts` - Set to a string or array of strings representing the AST context
1113
where you wish the rule to be applied (e.g., `ClassDeclaration` for ES6 classes).
14+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
15+
block avoids the need for a `@description`.
1216
- `noDefaults` - By default, `contexts` will permit `ArrowFunctionExpression`,
1317
`FunctionDeclaration`, and `FunctionExpression`. Set this instead to `true` to
1418
have `contexts` override these.
@@ -18,6 +22,6 @@ Requires that all functions have a description.
1822
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled|
1923
|Tags|`description`|
2024
|Aliases|`desc`|
21-
|Options|`contexts`, `noDefaults`|
25+
|Options|`contexts`, `exemptedBy`, `noDefaults`|
2226

2327
<!-- assertions requireDescription -->

.README/rules/require-example.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ Requires that all functions have examples.
55
* All functions must have one or more `@example` tags.
66
* Every example tag must have a non-empty description that explains the method's usage.
77

8+
#### Options
9+
10+
Has an object option with one optional property:
11+
12+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
13+
block avoids the need for an `@example`.
14+
815
|||
916
|---|---|
1017
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
1118
|Tags|`example`|
19+
|Options|`exemptedBy`|
1220
|Settings|`avoidExampleOnConstructors`|
1321

1422
<!-- assertions requireExample -->

.README/rules/require-param.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,19 @@
22

33
Requires that all function parameters are documented.
44

5+
#### Options
6+
7+
An options object accepts one optional property:
8+
9+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
10+
block avoids the need for a `@param`.
11+
512
|||
613
|---|---|
714
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
815
|Tags|`param`|
916
|Aliases|`arg`, `argument`|
17+
|Options|`exemptedBy`|
1018
|Settings|`allowOverrideWithoutParam`, `allowImplementsWithoutParam`, `allowAugmentsExtendsWithoutParam`|
1119

1220
<!-- assertions requireParam -->

.README/rules/require-returns.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
Requires returns are documented.
44

5-
By default `async` functions that do not explicitly return a value pass this rule. You can force all `async` functions to require return statements by setting `forceReturnsWithAsync` as true on the options object. This may be useful as an `async` function will always return a Promise, even if the Promise returns void.
5+
#### Options
6+
7+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
8+
block avoids the need for a `@returns`.
9+
- `forceReturnsWithAsync` - By default `async` functions that do not explicitly return a value pass this rule. You can force all `async` functions to require return statements by setting `forceReturnsWithAsync` as true on the options object. This may be useful as an `async` function will always return a Promise, even if the Promise returns void.
610

711
```js
812
'jsdoc/require-jsdoc': ['error', {forceReturnsWithAsync: true}]
@@ -14,6 +18,6 @@ By default `async` functions that do not explicitly return a value pass this rul
1418
|Tags|`returns`|
1519
|Aliases|`return`|
1620
|Settings|`forceRequireReturn`|
17-
|Options|`forceReturnsWithAsync`|
21+
|Options|`exemptedBy`, `forceReturnsWithAsync`|
1822

1923
<!-- assertions requireReturns -->

README.md

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3119,8 +3119,12 @@ Requires that all functions have a description.
31193119
<a name="eslint-plugin-jsdoc-rules-require-description-options-2"></a>
31203120
#### Options
31213121

3122+
An options object may have any of the following properties:
3123+
31223124
- `contexts` - Set to a string or array of strings representing the AST context
31233125
where you wish the rule to be applied (e.g., `ClassDeclaration` for ES6 classes).
3126+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
3127+
block avoids the need for a `@description`.
31243128
- `noDefaults` - By default, `contexts` will permit `ArrowFunctionExpression`,
31253129
`FunctionDeclaration`, and `FunctionExpression`. Set this instead to `true` to
31263130
have `contexts` override these.
@@ -3130,7 +3134,7 @@ Requires that all functions have a description.
31303134
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled|
31313135
|Tags|`description`|
31323136
|Aliases|`desc`|
3133-
|Options|`contexts`, `noDefaults`|
3137+
|Options|`contexts`, `exemptedBy`, `noDefaults`|
31343138

31353139
The following patterns are considered problems:
31363140

@@ -3223,6 +3227,14 @@ function quux () {
32233227

32243228
}
32253229
// Options: [{"noDefaults":true}]
3230+
3231+
/**
3232+
* @type {MyCallback}
3233+
*/
3234+
function quux () {
3235+
3236+
}
3237+
// Options: [{"exemptedBy":["type"]}]
32263238
````
32273239

32283240

@@ -3234,10 +3246,19 @@ Requires that all functions have examples.
32343246
* All functions must have one or more `@example` tags.
32353247
* Every example tag must have a non-empty description that explains the method's usage.
32363248

3249+
<a name="eslint-plugin-jsdoc-rules-require-example-options-3"></a>
3250+
#### Options
3251+
3252+
Has an object option with one optional property:
3253+
3254+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
3255+
block avoids the need for an `@example`.
3256+
32373257
|||
32383258
|---|---|
32393259
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
32403260
|Tags|`example`|
3261+
|Options|`exemptedBy`|
32413262
|Settings|`avoidExampleOnConstructors`|
32423263

32433264
The following patterns are considered problems:
@@ -3330,6 +3351,14 @@ function quux () {
33303351
function quux () {
33313352

33323353
}
3354+
3355+
/**
3356+
* @type {MyCallback}
3357+
*/
3358+
function quux () {
3359+
3360+
}
3361+
// Options: [{"exemptedBy":["type"]}]
33333362
````
33343363

33353364

@@ -3416,7 +3445,7 @@ function quux () {
34163445
Checks for presence of jsdoc comments, on class declarations as well as
34173446
functions.
34183447

3419-
<a name="eslint-plugin-jsdoc-rules-require-jsdoc-options-3"></a>
3448+
<a name="eslint-plugin-jsdoc-rules-require-jsdoc-options-4"></a>
34203449
#### Options
34213450

34223451
Accepts one optional options object, with two optional keys, `publicOnly`
@@ -4339,11 +4368,20 @@ function quux (foo) {
43394368

43404369
Requires that all function parameters are documented.
43414370

4371+
<a name="eslint-plugin-jsdoc-rules-require-param-options-5"></a>
4372+
#### Options
4373+
4374+
An options object accepts one optional property:
4375+
4376+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
4377+
block avoids the need for a `@param`.
4378+
43424379
|||
43434380
|---|---|
43444381
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`|
43454382
|Tags|`param`|
43464383
|Aliases|`arg`, `argument`|
4384+
|Options|`exemptedBy`|
43474385
|Settings|`allowOverrideWithoutParam`, `allowImplementsWithoutParam`, `allowAugmentsExtendsWithoutParam`|
43484386

43494387
The following patterns are considered problems:
@@ -4704,6 +4742,14 @@ const test = something?.find(_ => _)
47044742

47054743
/** @type {RequestHandler} */
47064744
function foo(req, res, next) {}
4745+
4746+
/**
4747+
* @type {MyCallback}
4748+
*/
4749+
function quux () {
4750+
4751+
}
4752+
// Options: [{"exemptedBy":["type"]}]
47074753
````
47084754

47094755

@@ -5016,7 +5062,12 @@ function quux () {
50165062

50175063
Requires returns are documented.
50185064

5019-
By default `async` functions that do not explicitly return a value pass this rule. You can force all `async` functions to require return statements by setting `forceReturnsWithAsync` as true on the options object. This may be useful as an `async` function will always return a Promise, even if the Promise returns void.
5065+
<a name="eslint-plugin-jsdoc-rules-require-returns-options-6"></a>
5066+
#### Options
5067+
5068+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
5069+
block avoids the need for a `@returns`.
5070+
- `forceReturnsWithAsync` - By default `async` functions that do not explicitly return a value pass this rule. You can force all `async` functions to require return statements by setting `forceReturnsWithAsync` as true on the options object. This may be useful as an `async` function will always return a Promise, even if the Promise returns void.
50205071

50215072
```js
50225073
'jsdoc/require-jsdoc': ['error', {forceReturnsWithAsync: true}]
@@ -5028,7 +5079,7 @@ By default `async` functions that do not explicitly return a value pass this rul
50285079
|Tags|`returns`|
50295080
|Aliases|`return`|
50305081
|Settings|`forceRequireReturn`|
5031-
|Options|`forceReturnsWithAsync`|
5082+
|Options|`exemptedBy`, `forceReturnsWithAsync`|
50325083

50335084
The following patterns are considered problems:
50345085

@@ -5386,6 +5437,14 @@ export default foo;
53865437
function quux () {
53875438
}
53885439
// Options: [{"forceReturnsWithAsync":true}]
5440+
5441+
/**
5442+
* @type {MyCallback}
5443+
*/
5444+
function quux () {
5445+
5446+
}
5447+
// Options: [{"exemptedBy":["type"]}]
53895448
````
53905449

53915450

src/iterateJsdoc.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ const curryUtils = (
117117
};
118118

119119
utils.avoidDocs = (param) => {
120-
return param && utils.avoidDocsParamOnly() ||
120+
if (param && utils.avoidDocsParamOnly() ||
121121
utils.avoidDocsParamConditionally(param) ||
122122

123123
// inheritdoc implies that all documentation is inherited; see https://jsdoc.app/tags-inheritdoc.html
@@ -126,7 +126,16 @@ const curryUtils = (
126126
augmentsExtendsReplacesDocs &&
127127
(utils.hasATag(['augments', 'extends']) ||
128128
utils.classHasTag('augments') ||
129-
utils.classHasTag('extends'));
129+
utils.classHasTag('extends'))) {
130+
return true;
131+
}
132+
133+
const exemptedBy = _.get(context, 'options[0].exemptedBy');
134+
if (exemptedBy && exemptedBy.length && utils.getPresentTags(exemptedBy).length) {
135+
return true;
136+
}
137+
138+
return false;
130139
};
131140

132141
utils.isNamepathDefiningTag = (tagName) => {
@@ -163,6 +172,12 @@ const curryUtils = (
163172
});
164173
};
165174

175+
utils.getPresentTags = (tagList) => {
176+
return utils.filterTags((tag) => {
177+
return tagList.includes(tag.tag);
178+
});
179+
};
180+
166181
utils.filterTags = (filter) => {
167182
return (jsdoc.tags || []).filter(filter);
168183
};
@@ -326,7 +341,8 @@ export default function iterateJsdoc (iterator, opts = {}) {
326341
jsdoc,
327342
settings,
328343
ancestors,
329-
sourceCode
344+
sourceCode,
345+
context
330346
);
331347

332348
if (

src/rules/noTypes.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ export default iterateJsdoc(({
44
utils,
55
report
66
}) => {
7-
const tags = utils.filterTags((tag) => {
8-
return ['param', 'arg', 'argument', 'returns', 'return'].includes(tag.tag);
9-
});
7+
const tags = utils.getPresentTags(['param', 'arg', 'argument', 'returns', 'return']);
8+
109
tags.forEach((tag) => {
1110
if (tag.type) {
1211
report(`Types are not permitted on @${tag.tag}.`, null, tag);

src/rules/requireDescription.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ export default iterateJsdoc(({
6565
}
6666
]
6767
},
68+
exemptedBy: {
69+
items: {
70+
type: 'string'
71+
},
72+
type: 'array'
73+
},
6874
noDefaults: {
6975
type: 'boolean'
7076
}

src/rules/requireExample.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,19 @@ export default iterateJsdoc(({
4343
}, {
4444
meta: {
4545
type: 'suggestion'
46-
}
46+
},
47+
schema: [
48+
{
49+
additionalProperties: false,
50+
properties: {
51+
exemptedBy: {
52+
items: {
53+
type: 'string'
54+
},
55+
type: 'array'
56+
}
57+
},
58+
type: 'object'
59+
}
60+
]
4761
});

src/rules/requireParam.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,19 @@ export default iterateJsdoc(({
3131
}, {
3232
meta: {
3333
type: 'suggestion'
34-
}
34+
},
35+
schema: [
36+
{
37+
additionalProperties: false,
38+
properties: {
39+
exemptedBy: {
40+
items: {
41+
type: 'string'
42+
},
43+
type: 'array'
44+
}
45+
},
46+
type: 'object'
47+
}
48+
]
3549
});

src/rules/requireReturns.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,30 @@ export default iterateJsdoc(({
6565
const [tag] = tags;
6666
const missingReturnTag = typeof tag === 'undefined' || tag === null;
6767
if (missingReturnTag &&
68-
((utils.isAsync() && !utils.hasReturnValue(true) ? Boolean(options.forceReturnsWithAsync) : utils.hasReturnValue()) || settings.forceRequireReturn)
68+
((utils.isAsync() && !utils.hasReturnValue(true) ? options.forceReturnsWithAsync : utils.hasReturnValue()) || settings.forceRequireReturn)
6969
) {
7070
report('Missing JSDoc @' + tagName + ' declaration.');
7171
}
7272
}, {
7373
meta: {
7474
type: 'suggestion'
75-
}
75+
},
76+
schema: [
77+
{
78+
additionalProperties: false,
79+
properties: {
80+
exemptedBy: {
81+
items: {
82+
type: 'string'
83+
},
84+
type: 'array'
85+
},
86+
forceReturnsWithAsync: {
87+
default: false,
88+
type: 'boolean'
89+
}
90+
},
91+
type: 'object'
92+
}
93+
]
7694
});

0 commit comments

Comments
 (0)