Skip to content

Commit 616bc83

Browse files
brettz9chiawendt
authored andcommitted
feat(require-description): add descriptionStyle option to accept implicit descriptions as satisfying the rule by default (fixes #301)
BREAKING CHANGE: To restore old behavior, set the option `descriptionStyle` to `"tag"`
1 parent 9263fba commit 616bc83

File tree

4 files changed

+295
-38
lines changed

4 files changed

+295
-38
lines changed

.README/rules/require-description.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,32 @@
22

33
Requires that all functions have a description.
44

5-
* All functions must have a `@description` tag.
6-
* Every description tag must have a non-empty description that explains the purpose of the method.
5+
* All functions must have an implicit description or have the option
6+
`descriptionStyle` set to `tag`.
7+
* Every jsdoc block description (or description tag if `descriptionStyle` is
8+
`"tag"`) must have a non-empty description that explains the purpose of the
9+
method.
710

811
#### Options
912

1013
An options object may have any of the following properties:
1114

1215
- `contexts` - Set to an array of strings representing the AST context
13-
where you wish the rule to be applied (e.g., `ClassDeclaration` for ES6 classes).
14-
Overrides the default contexts (see below).
15-
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
16-
block avoids the need for a `@description`. Defaults to an empty array.
16+
where you wish the rule to be applied (e.g., `ClassDeclaration` for ES6
17+
classes). Overrides the default contexts (see below).
18+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the
19+
document block avoids the need for a `@description`. Defaults to an
20+
empty array.
21+
- `descriptionStyle` - Whether to accept implicit descriptions (`"body"`) or
22+
`@description` tags (`"tag"`) as satisfying the rule. Set to `"any"` to
23+
accept either style. Defaults to `"body"`.
1724

1825
|||
1926
|---|---|
2027
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled|
21-
|Tags|`description`|
28+
|Tags|`description` or jsdoc block|
2229
|Aliases|`desc`|
23-
|Options|`contexts`, `exemptedBy`|
30+
|Options|`contexts`, `exemptedBy`, `descriptionStyle`|
2431
|Settings|`overrideReplacesDocs`, `augmentsExtendsReplacesDocs`, `implementsReplacesDocs`|
2532

2633
<!-- assertions requireDescription -->

README.md

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3788,26 +3788,33 @@ function quux () {
37883788

37893789
Requires that all functions have a description.
37903790

3791-
* All functions must have a `@description` tag.
3792-
* Every description tag must have a non-empty description that explains the purpose of the method.
3791+
* All functions must have an implicit description or have the option
3792+
`descriptionStyle` set to `tag`.
3793+
* Every jsdoc block description (or description tag if `descriptionStyle` is
3794+
`"tag"`) must have a non-empty description that explains the purpose of the
3795+
method.
37933796

37943797
<a name="eslint-plugin-jsdoc-rules-require-description-options-6"></a>
37953798
#### Options
37963799

37973800
An options object may have any of the following properties:
37983801

37993802
- `contexts` - Set to an array of strings representing the AST context
3800-
where you wish the rule to be applied (e.g., `ClassDeclaration` for ES6 classes).
3801-
Overrides the default contexts (see below).
3802-
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document
3803-
block avoids the need for a `@description`. Defaults to an empty array.
3803+
where you wish the rule to be applied (e.g., `ClassDeclaration` for ES6
3804+
classes). Overrides the default contexts (see below).
3805+
- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the
3806+
document block avoids the need for a `@description`. Defaults to an
3807+
empty array.
3808+
- `descriptionStyle` - Whether to accept implicit descriptions (`"body"`) or
3809+
`@description` tags (`"tag"`) as satisfying the rule. Set to `"any"` to
3810+
accept either style. Defaults to `"body"`.
38043811

38053812
|||
38063813
|---|---|
38073814
|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled|
3808-
|Tags|`description`|
3815+
|Tags|`description` or jsdoc block|
38093816
|Aliases|`desc`|
3810-
|Options|`contexts`, `exemptedBy`|
3817+
|Options|`contexts`, `exemptedBy`, `descriptionStyle`|
38113818
|Settings|`overrideReplacesDocs`, `augmentsExtendsReplacesDocs`, `implementsReplacesDocs`|
38123819

38133820
The following patterns are considered problems:
@@ -3819,15 +3826,34 @@ The following patterns are considered problems:
38193826
function quux () {
38203827

38213828
}
3829+
// Options: [{"descriptionStyle":"tag"}]
38223830
// Message: Missing JSDoc @description declaration.
38233831

3832+
/**
3833+
*
3834+
*/
3835+
function quux () {
3836+
3837+
}
3838+
// Options: [{"descriptionStyle":"any"}]
3839+
// Message: Missing JSDoc block description or @description declaration.
3840+
3841+
/**
3842+
*
3843+
*/
3844+
function quux () {
3845+
3846+
}
3847+
// Options: [{"descriptionStyle":"body"}]
3848+
// Message: Missing JSDoc block description.
3849+
38243850
/**
38253851
*
38263852
*/
38273853
class quux {
38283854

38293855
}
3830-
// Options: [{"contexts":["ClassDeclaration"]}]
3856+
// Options: [{"contexts":["ClassDeclaration"],"descriptionStyle":"tag"}]
38313857
// Message: Missing JSDoc @description declaration.
38323858

38333859
/**
@@ -3836,7 +3862,7 @@ class quux {
38363862
class quux {
38373863

38383864
}
3839-
// Options: [{"contexts":["ClassDeclaration"]}]
3865+
// Options: [{"contexts":["ClassDeclaration"],"descriptionStyle":"tag"}]
38403866
// Message: Missing JSDoc @description declaration.
38413867

38423868
/**
@@ -3845,7 +3871,7 @@ class quux {
38453871
class quux {
38463872

38473873
}
3848-
// Options: [{"contexts":["ClassDeclaration"]}]
3874+
// Options: [{"contexts":["ClassDeclaration"],"descriptionStyle":"tag"}]
38493875
// Message: Missing JSDoc @description declaration.
38503876

38513877
/**
@@ -3854,6 +3880,7 @@ class quux {
38543880
function quux () {
38553881

38563882
}
3883+
// Options: [{"descriptionStyle":"tag"}]
38573884
// Message: Missing JSDoc @description description.
38583885

38593886
/**
@@ -3862,7 +3889,7 @@ function quux () {
38623889
interface quux {
38633890

38643891
}
3865-
// Options: [{"contexts":["TSInterfaceDeclaration"]}]
3892+
// Options: [{"contexts":["TSInterfaceDeclaration"],"descriptionStyle":"tag"}]
38663893
// Message: Missing JSDoc @description declaration.
38673894

38683895
/**
@@ -3871,7 +3898,7 @@ interface quux {
38713898
var quux = class {
38723899

38733900
};
3874-
// Options: [{"contexts":["ClassExpression"]}]
3901+
// Options: [{"contexts":["ClassExpression"],"descriptionStyle":"tag"}]
38753902
// Message: Missing JSDoc @description declaration.
38763903

38773904
/**
@@ -3880,7 +3907,7 @@ var quux = class {
38803907
var quux = {
38813908

38823909
};
3883-
// Options: [{"contexts":["ObjectExpression"]}]
3910+
// Options: [{"contexts":["ObjectExpression"],"descriptionStyle":"tag"}]
38843911
// Message: Missing JSDoc @description declaration.
38853912

38863913
/**
@@ -3890,6 +3917,7 @@ function quux () {
38903917

38913918
}
38923919
// Settings: {"jsdoc":{"tagNamePreference":{"description":{"message":"Please avoid `{{tagName}}`; use `{{replacement}}` instead","replacement":"someDesc"}}}}
3920+
// Options: [{"descriptionStyle":"tag"}]
38933921
// Message: Missing JSDoc @someDesc description.
38943922

38953923
/**
@@ -3899,6 +3927,7 @@ function quux () {
38993927

39003928
}
39013929
// Settings: {"jsdoc":{"tagNamePreference":{"description":false}}}
3930+
// Options: [{"descriptionStyle":"tag"}]
39023931
// Message: Unexpected tag `@description`
39033932
````
39043933

@@ -3912,6 +3941,7 @@ The following patterns are not considered problems:
39123941
function quux () {
39133942

39143943
}
3944+
// Options: [{"descriptionStyle":"tag"}]
39153945

39163946
/**
39173947
* @description
@@ -3920,6 +3950,7 @@ function quux () {
39203950
function quux () {
39213951

39223952
}
3953+
// Options: [{"descriptionStyle":"tag"}]
39233954

39243955
/**
39253956
* @description <caption>Valid usage</caption>
@@ -3931,13 +3962,15 @@ function quux () {
39313962
function quux () {
39323963

39333964
}
3965+
// Options: [{"descriptionStyle":"tag"}]
39343966

39353967
/**
39363968
*
39373969
*/
39383970
class quux {
39393971

39403972
}
3973+
// Options: [{"descriptionStyle":"tag"}]
39413974

39423975
/**
39433976
*
@@ -3961,20 +3994,54 @@ function quux () {
39613994
interface quux {
39623995

39633996
}
3997+
// Options: [{"descriptionStyle":"tag"}]
39643998

39653999
/**
39664000
*
39674001
*/
39684002
var quux = class {
39694003

39704004
};
4005+
// Options: [{"descriptionStyle":"tag"}]
39714006

39724007
/**
39734008
*
39744009
*/
39754010
var quux = {
39764011

39774012
};
4013+
// Options: [{"descriptionStyle":"tag"}]
4014+
4015+
/**
4016+
* Has an implicit description
4017+
*/
4018+
function quux () {
4019+
4020+
}
4021+
// Options: [{"descriptionStyle":"body"}]
4022+
4023+
/**
4024+
* Has an implicit description
4025+
*/
4026+
function quux () {
4027+
4028+
}
4029+
4030+
/**
4031+
* Has an implicit description
4032+
*/
4033+
function quux () {
4034+
4035+
}
4036+
// Options: [{"descriptionStyle":"any"}]
4037+
4038+
/**
4039+
* @description Has an explicit description
4040+
*/
4041+
function quux () {
4042+
4043+
}
4044+
// Options: [{"descriptionStyle":"any"}]
39784045
````
39794046

39804047

src/rules/requireDescription.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import iterateJsdoc from '../iterateJsdoc';
44
export default iterateJsdoc(({
55
jsdoc,
66
report,
7-
utils
7+
utils,
8+
context
89
}) => {
910
if (utils.avoidDocs()) {
1011
return;
@@ -15,20 +16,42 @@ export default iterateJsdoc(({
1516
return;
1617
}
1718

19+
const checkDescription = (description) => {
20+
const exampleContent = _.compact(description.trim().split('\n'));
21+
22+
return exampleContent.length;
23+
};
24+
25+
const {descriptionStyle = 'body'} = context.options[0] || {};
26+
27+
if (descriptionStyle !== 'tag') {
28+
if (checkDescription(jsdoc.description || '')) {
29+
return;
30+
}
31+
32+
if (descriptionStyle === 'body') {
33+
report('Missing JSDoc block description.');
34+
35+
return;
36+
}
37+
}
38+
1839
const functionExamples = _.filter(jsdoc.tags, {
1940
tag: targetTagName
2041
});
2142

2243
if (!functionExamples.length) {
23-
report(`Missing JSDoc @${targetTagName} declaration.`);
44+
report(
45+
descriptionStyle === 'any' ?
46+
`Missing JSDoc block description or @${targetTagName} declaration.` :
47+
`Missing JSDoc @${targetTagName} declaration.`
48+
);
2449

2550
return;
2651
}
2752

2853
functionExamples.forEach((example) => {
29-
const exampleContent = _.compact(`${example.name} ${example.description}`.trim().split('\n'));
30-
31-
if (!exampleContent.length) {
54+
if (!checkDescription(`${example.name} ${example.description}`)) {
3255
report(`Missing JSDoc @${targetTagName} description.`);
3356
}
3457
});
@@ -45,6 +68,10 @@ export default iterateJsdoc(({
4568
},
4669
type: 'array'
4770
},
71+
descriptionStyle: {
72+
enum: ['body', 'tag', 'any'],
73+
type: 'string'
74+
},
4875
exemptedBy: {
4976
items: {
5077
type: 'string'

0 commit comments

Comments
 (0)