Skip to content

Commit 4ce07d1

Browse files
committed
feat(no-bad-blocks): add rule to check for multi-line-style comments which fail to meet criteria of a jsdoc block
Expects jsdoc block to be a multiline-style comment beginning with two asterisks. If beginning with only one, while having whitespace followed by whitespace or asterisks, and an at-sign (`@`) and some non-whitespace (as with a jsdoc block tag), then report.
1 parent d7fec9a commit 4ce07d1

File tree

6 files changed

+163
-2
lines changed

6 files changed

+163
-2
lines changed

.README/rules/no-bad-blocks.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
### `no-bad-blocks`
2+
3+
This rule checks for multi-line-style comments which fail to meet the
4+
criteria of a jsdoc block, namely that it should begin with two asterisks,
5+
but which appear to be intended as jsdoc blocks due to the presence
6+
of whitespace followed by whitespace or asterisks, and
7+
an at-sign (`@`) and some non-whitespace (as with a jsdoc block tag).
8+
9+
|||
10+
|---|---|
11+
|Context|Everywhere|
12+
|Tags|N/A|
13+
14+
<!-- assertions noBadBlocks -->

src/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import emptyTags from './rules/emptyTags';
1313
import implementsOnClasses from './rules/implementsOnClasses';
1414
import matchDescription from './rules/matchDescription';
1515
import newlineAfterDescription from './rules/newlineAfterDescription';
16+
import noBadBlocks from './rules/noBadBlocks';
1617
import noDefaults from './rules/noDefaults';
1718
import noTypes from './rules/noTypes';
1819
import noUndefinedTypes from './rules/noUndefinedTypes';
@@ -55,6 +56,7 @@ export default {
5556
'jsdoc/implements-on-classes': 'warn',
5657
'jsdoc/match-description': 'off',
5758
'jsdoc/newline-after-description': 'warn',
59+
'jsdoc/no-bad-blocks': 'off',
5860
'jsdoc/no-defaults': 'off',
5961
'jsdoc/no-types': 'off',
6062
'jsdoc/no-undefined-types': 'warn',
@@ -95,6 +97,7 @@ export default {
9597
'implements-on-classes': implementsOnClasses,
9698
'match-description': matchDescription,
9799
'newline-after-description': newlineAfterDescription,
100+
'no-bad-blocks': noBadBlocks,
98101
'no-defaults': noDefaults,
99102
'no-types': noTypes,
100103
'no-undefined-types': noUndefinedTypes,

src/iterateJsdoc.js

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -568,8 +568,8 @@ const iterateAllJsdocs = (iterator, ruleConfig) => {
568568
callIterator(context, node, [comment], state);
569569
},
570570
'Program:exit' () {
571-
const allJsdocs = sourceCode.getAllComments();
572-
const untrackedJSdoc = allJsdocs.filter((node) => {
571+
const allComments = sourceCode.getAllComments();
572+
const untrackedJSdoc = allComments.filter((node) => {
573573
return !trackedJsdocs.includes(node);
574574
});
575575

@@ -581,6 +581,41 @@ const iterateAllJsdocs = (iterator, ruleConfig) => {
581581
};
582582
};
583583

584+
/**
585+
* Create an eslint rule that iterates over all JSDocs, regardless of whether
586+
* they are attached to a function-like node.
587+
*
588+
* @param {JsdocVisitor} iterator
589+
* @param {{meta: any}} ruleConfig
590+
*/
591+
const checkFile = (iterator, ruleConfig) => {
592+
return {
593+
create (context) {
594+
const sourceCode = context.getSourceCode();
595+
const settings = getSettings(context);
596+
597+
return {
598+
'Program:exit' () {
599+
const allComments = sourceCode.getAllComments();
600+
const {lines} = sourceCode;
601+
const utils = getBasicUtils(context, settings);
602+
603+
iterator({
604+
allComments,
605+
context,
606+
lines,
607+
makeReport,
608+
settings,
609+
sourceCode,
610+
utils,
611+
});
612+
},
613+
};
614+
},
615+
meta: ruleConfig.meta,
616+
};
617+
};
618+
584619
export {
585620
getSettings,
586621
parseComment,
@@ -603,6 +638,10 @@ export default function iterateJsdoc (iterator, ruleConfig) {
603638
throw new TypeError('The iterator argument must be a function.');
604639
}
605640

641+
if (ruleConfig.checkFile) {
642+
return checkFile(iterator, ruleConfig);
643+
}
644+
606645
if (ruleConfig.iterateAllJsdocs) {
607646
return iterateAllJsdocs(iterator, ruleConfig);
608647
}

src/rules/noBadBlocks.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import iterateJsdoc from '../iterateJsdoc';
2+
3+
export default iterateJsdoc(({
4+
context,
5+
sourceCode,
6+
allComments,
7+
makeReport,
8+
}) => {
9+
const nonJsdocNodes = allComments.filter((comment) => {
10+
return (/^\/\*(?!\*)[\s*]*@\w/).test(sourceCode.getText(comment));
11+
});
12+
if (!nonJsdocNodes.length) {
13+
return;
14+
}
15+
16+
nonJsdocNodes.forEach((node) => {
17+
const report = makeReport(context, node);
18+
19+
const fix = (fixer) => {
20+
const text = sourceCode.getText(node);
21+
22+
return fixer.replaceText(node, text.replace('/*', '/**'));
23+
};
24+
report('Expected JSDoc-like comment to begin with two asterisks.', fix);
25+
});
26+
}, {
27+
checkFile: true,
28+
meta: {
29+
fixable: 'code',
30+
type: 'layout',
31+
},
32+
});

test/rules/assertions/noBadBlocks.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
export default {
2+
invalid: [
3+
{
4+
code: `
5+
/*
6+
* @param foo
7+
*/
8+
function quux (foo) {
9+
10+
}
11+
`,
12+
errors: [
13+
{
14+
line: 2,
15+
message: 'Expected JSDoc-like comment to begin with two asterisks.',
16+
},
17+
],
18+
output: `
19+
/**
20+
* @param foo
21+
*/
22+
function quux (foo) {
23+
24+
}
25+
`,
26+
},
27+
{
28+
code: `
29+
/*
30+
* @property foo
31+
*/
32+
`,
33+
errors: [
34+
{
35+
line: 2,
36+
message: 'Expected JSDoc-like comment to begin with two asterisks.',
37+
},
38+
],
39+
output: `
40+
/**
41+
* @property foo
42+
*/
43+
`,
44+
},
45+
],
46+
valid: [
47+
{
48+
code: `
49+
/**
50+
* @property foo
51+
*/
52+
`,
53+
},
54+
{
55+
code: `
56+
/**
57+
* @param foo
58+
*/
59+
function quux () {
60+
61+
}
62+
`,
63+
},
64+
{
65+
code: `
66+
function quux () {
67+
68+
}
69+
`,
70+
},
71+
],
72+
};

test/rules/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const ruleTester = new RuleTester();
2222
'implements-on-classes',
2323
'match-description',
2424
'newline-after-description',
25+
'no-bad-blocks',
2526
'no-defaults',
2627
'no-types',
2728
'no-undefined-types',

0 commit comments

Comments
 (0)