Skip to content

Commit 33628b4

Browse files
committed
feat(no-blank-block-descriptions): add rule; fixes gajus#982
1 parent 47559e6 commit 33628b4

File tree

8 files changed

+304
-0
lines changed

8 files changed

+304
-0
lines changed

.README/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ selector).
606606
{"gitdown": "include", "file": "./rules/multiline-blocks.md"}
607607
{"gitdown": "include", "file": "./rules/newline-after-description.md"}
608608
{"gitdown": "include", "file": "./rules/no-bad-blocks.md"}
609+
{"gitdown": "include", "file": "./rules/no-blank-block-descriptions.md"}
609610
{"gitdown": "include", "file": "./rules/no-defaults.md"}
610611
{"gitdown": "include", "file": "./rules/no-missing-syntax.md"}
611612
{"gitdown": "include", "file": "./rules/no-multi-asterisks.md"}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
### `no-blank-block-descriptions`
2+
3+
If tags are present, this rule will prevent empty lines in the
4+
block description.
5+
6+
If no tags are present, this rule will prevent extra empty lines
7+
in the block description.
8+
9+
|||
10+
|---|---|
11+
|Context|everywhere|
12+
|Tags|(Block description)|
13+
|Recommended|false|
14+
|Settings||
15+
|Options||
16+
17+
<!-- assertions noBlankBlockDescriptions -->

README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ JSDoc linting rules for ESLint.
4343
* [`multiline-blocks`](#user-content-eslint-plugin-jsdoc-rules-multiline-blocks)
4444
* [`newline-after-description`](#user-content-eslint-plugin-jsdoc-rules-newline-after-description)
4545
* [`no-bad-blocks`](#user-content-eslint-plugin-jsdoc-rules-no-bad-blocks)
46+
* [`no-blank-block-descriptions`](#user-content-eslint-plugin-jsdoc-rules-no-blank-block-descriptions)
4647
* [`no-defaults`](#user-content-eslint-plugin-jsdoc-rules-no-defaults)
4748
* [`no-missing-syntax`](#user-content-eslint-plugin-jsdoc-rules-no-missing-syntax)
4849
* [`no-multi-asterisks`](#user-content-eslint-plugin-jsdoc-rules-no-multi-asterisks)
@@ -9225,6 +9226,76 @@ function quux (foo) {
92259226
````
92269227

92279228

9229+
<a name="user-content-eslint-plugin-jsdoc-rules-no-blank-block-descriptions"></a>
9230+
<a name="eslint-plugin-jsdoc-rules-no-blank-block-descriptions"></a>
9231+
### <code>no-blank-block-descriptions</code>
9232+
9233+
If tags are present, this rule will prevent empty lines in the
9234+
block description.
9235+
9236+
If no tags are present, this rule will prevent extra empty lines
9237+
in the block description.
9238+
9239+
|||
9240+
|---|---|
9241+
|Context|everywhere|
9242+
|Tags|(Block description)|
9243+
|Recommended|false|
9244+
|Settings||
9245+
|Options||
9246+
9247+
The following patterns are considered problems:
9248+
9249+
````js
9250+
/**
9251+
*
9252+
* @param {number} x
9253+
*/
9254+
function functionWithClearName(x) {}
9255+
// Message: There should be no blank lines in block descriptions followed by tags.
9256+
9257+
/**
9258+
*
9259+
*
9260+
*/
9261+
function functionWithClearName() {}
9262+
// Message: There should be no extra blank lines in block descriptions not followed by tags.
9263+
````
9264+
9265+
The following patterns are not considered problems:
9266+
9267+
````js
9268+
/**
9269+
* Non-empty description
9270+
* @param {number} x
9271+
*/
9272+
function functionWithClearName(x) {}
9273+
9274+
/**
9275+
* @param {number} x
9276+
*/
9277+
function functionWithClearName(x) {}
9278+
9279+
/**
9280+
*
9281+
*/
9282+
function functionWithClearName() {}
9283+
9284+
/**
9285+
*/
9286+
function functionWithClearName() {}
9287+
9288+
/** */
9289+
function functionWithClearName() {}
9290+
9291+
/** Some desc. */
9292+
function functionWithClearName() {}
9293+
9294+
/** @someTag */
9295+
function functionWithClearName() {}
9296+
````
9297+
9298+
92289299
<a name="user-content-eslint-plugin-jsdoc-rules-no-defaults"></a>
92299300
<a name="eslint-plugin-jsdoc-rules-no-defaults"></a>
92309301
### <code>no-defaults</code>

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import matchName from './rules/matchName';
1616
import multilineBlocks from './rules/multilineBlocks';
1717
import newlineAfterDescription from './rules/newlineAfterDescription';
1818
import noBadBlocks from './rules/noBadBlocks';
19+
import noBlankBlockDescriptions from './rules/noBlankBlockDescriptions';
1920
import noDefaults from './rules/noDefaults';
2021
import noMissingSyntax from './rules/noMissingSyntax';
2122
import noMultiAsterisks from './rules/noMultiAsterisks';
@@ -70,6 +71,7 @@ const index = {
7071
'multiline-blocks': multilineBlocks,
7172
'newline-after-description': newlineAfterDescription,
7273
'no-bad-blocks': noBadBlocks,
74+
'no-blank-block-descriptions': noBlankBlockDescriptions,
7375
'no-defaults': noDefaults,
7476
'no-missing-syntax': noMissingSyntax,
7577
'no-multi-asterisks': noMultiAsterisks,
@@ -129,6 +131,7 @@ const createRecommendedRuleset = (warnOrError) => {
129131
'jsdoc/multiline-blocks': warnOrError,
130132
'jsdoc/newline-after-description': warnOrError,
131133
'jsdoc/no-bad-blocks': 'off',
134+
'jsdoc/no-blank-block-descriptions': 'off',
132135
'jsdoc/no-defaults': 'off',
133136
'jsdoc/no-missing-syntax': 'off',
134137
'jsdoc/no-multi-asterisks': warnOrError,

src/iterateJsdoc.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,52 @@ const getUtils = (
254254
};
255255
};
256256

257+
utils.setBlockDescription = (setter) => {
258+
const descLines = [];
259+
let startIdx;
260+
let endIdx;
261+
let info;
262+
263+
jsdoc.source.some(({
264+
tokens: {
265+
description,
266+
start,
267+
delimiter,
268+
postDelimiter,
269+
tag,
270+
end,
271+
},
272+
}, idx) => {
273+
if (delimiter === '/**') {
274+
return false;
275+
}
276+
277+
if (startIdx === undefined) {
278+
startIdx = idx;
279+
info = {
280+
delimiter,
281+
postDelimiter,
282+
start,
283+
};
284+
}
285+
286+
if (tag || end) {
287+
endIdx = idx;
288+
return true;
289+
}
290+
291+
descLines.push(description);
292+
return false;
293+
});
294+
295+
/* istanbul ignore else -- Won't be called if missing */
296+
if (descLines.length) {
297+
jsdoc.source.splice(
298+
startIdx, endIdx - startIdx, ...setter(info, seedTokens, descLines),
299+
);
300+
}
301+
};
302+
257303
utils.setDescriptionLines = (matcher, setter) => {
258304
let finalIdx = 0;
259305
jsdoc.source.some(({

src/rules/noBlankBlockDescriptions.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import iterateJsdoc from '../iterateJsdoc';
2+
3+
const anyWhitespaceLines = /^\s*$/u;
4+
const atLeastTwoLinesWhitespace = /^[ \t]*\n[ \t]*\n\s*$/u;
5+
6+
export default iterateJsdoc(({
7+
jsdoc,
8+
utils,
9+
}) => {
10+
const {
11+
description,
12+
descriptions,
13+
lastDescriptionLine,
14+
} = utils.getDescription();
15+
16+
const regex = jsdoc.tags.length ?
17+
anyWhitespaceLines :
18+
atLeastTwoLinesWhitespace;
19+
20+
if (descriptions.length && regex.test(description)) {
21+
if (jsdoc.tags.length) {
22+
utils.reportJSDoc(
23+
'There should be no blank lines in block descriptions followed by tags.',
24+
{
25+
line: lastDescriptionLine,
26+
},
27+
() => {
28+
utils.setBlockDescription(() => {
29+
// Remove all lines
30+
return [];
31+
});
32+
},
33+
);
34+
} else {
35+
utils.reportJSDoc(
36+
'There should be no extra blank lines in block descriptions not followed by tags.',
37+
{
38+
line: lastDescriptionLine,
39+
},
40+
() => {
41+
utils.setBlockDescription((info, seedTokens) => {
42+
return [
43+
// Keep the starting line
44+
{
45+
tokens: seedTokens({
46+
...info,
47+
description: '',
48+
}),
49+
},
50+
];
51+
});
52+
},
53+
);
54+
}
55+
}
56+
}, {
57+
iterateAllJsdocs: true,
58+
meta: {
59+
docs: {
60+
description: 'Detects and removes extra lines of a blank block description',
61+
url: 'https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-no-blank-block-descriptions',
62+
},
63+
fixable: 'whitespace',
64+
schema: [],
65+
type: 'layout',
66+
},
67+
});
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
export default {
2+
invalid: [
3+
{
4+
code: `
5+
/**
6+
*
7+
* @param {number} x
8+
*/
9+
function functionWithClearName(x) {}
10+
`,
11+
errors: [
12+
{
13+
line: 3,
14+
message: 'There should be no blank lines in block descriptions followed by tags.',
15+
},
16+
],
17+
output: `
18+
/**
19+
* @param {number} x
20+
*/
21+
function functionWithClearName(x) {}
22+
`,
23+
},
24+
{
25+
code: `
26+
/**
27+
*
28+
*
29+
*/
30+
function functionWithClearName() {}
31+
`,
32+
errors: [
33+
{
34+
line: 4,
35+
message: 'There should be no extra blank lines in block descriptions not followed by tags.',
36+
},
37+
],
38+
output: `
39+
/**
40+
*
41+
*/
42+
function functionWithClearName() {}
43+
`,
44+
},
45+
],
46+
valid: [
47+
{
48+
code: `
49+
/**
50+
* Non-empty description
51+
* @param {number} x
52+
*/
53+
function functionWithClearName(x) {}
54+
`,
55+
},
56+
{
57+
code: `
58+
/**
59+
* @param {number} x
60+
*/
61+
function functionWithClearName(x) {}
62+
`,
63+
},
64+
{
65+
code: `
66+
/**
67+
*
68+
*/
69+
function functionWithClearName() {}
70+
`,
71+
},
72+
{
73+
code: `
74+
/**
75+
*/
76+
function functionWithClearName() {}
77+
`,
78+
},
79+
{
80+
code: `
81+
/** */
82+
function functionWithClearName() {}
83+
`,
84+
},
85+
{
86+
code: `
87+
/** Some desc. */
88+
function functionWithClearName() {}
89+
`,
90+
},
91+
{
92+
code: `
93+
/** @someTag */
94+
function functionWithClearName() {}
95+
`,
96+
},
97+
],
98+
};

test/rules/ruleNames.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"multiline-blocks",
1818
"newline-after-description",
1919
"no-bad-blocks",
20+
"no-blank-block-descriptions",
2021
"no-defaults",
2122
"no-missing-syntax",
2223
"no-multi-asterisks",

0 commit comments

Comments
 (0)