Skip to content

Commit 418114b

Browse files
authored
✨ eslint-comments/require-description rule (fixes #29, fixes #40) (#44)
1 parent 027e20c commit 418114b

File tree

5 files changed

+357
-0
lines changed

5 files changed

+357
-0
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@
2020
|:--------|:------------|:---|
2121
| [eslint-comments/<wbr>no-restricted-disable](./no-restricted-disable.md) | disallow `eslint-disable` comments about specific rules | |
2222
| [eslint-comments/<wbr>no-use](./no-use.md) | disallow ESLint directive-comments | |
23+
| [eslint-comments/<wbr>require-description](./require-description.md) | require include descriptions in ESLint directive-comments | |
2324

docs/rules/require-description.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# eslint-comments/require-description
2+
3+
> require include descriptions in ESLint directive-comments
4+
5+
This rule warns directive comments without description.
6+
7+
:::warning
8+
This rule can only be used with ESLint v7.x or later.
9+
:::
10+
11+
## Rule Details
12+
13+
Examples of :-1: **incorrect** code for this rule:
14+
15+
<eslint-playground type="bad" code="/*eslint eslint-comments/require-description: error */
16+
17+
/* eslint no-undef: off */
18+
/* eslint-env browser */
19+
/* eslint-disable eqeqeq */
20+
/* eslint-enable eqeqeq */
21+
// eslint-disable-line
22+
// eslint-disable-next-line
23+
/* exported foo */
24+
/* global $ */
25+
/* globals a, b, c */
26+
" />
27+
28+
Examples of :+1: **correct** code for this rule:
29+
30+
<eslint-playground type="good" code="/*eslint eslint-comments/require-description: error -- If you use directive comments, you should explain why you use them. */
31+
32+
/* eslint no-undef: off -- Here's a description about why this directive-comment is necessary. */
33+
/* eslint-env browser -- This script works in browser. */
34+
// eslint-disable-next-line -- Temporarily avoids the lint error problem. See issue XXX.
35+
/* global $ -- This script using jQuery. */
36+
" />
37+
38+
## Options
39+
40+
You can specify ignored directive-comments.
41+
42+
```json
43+
{
44+
"eslint-comments/require-description": ["error", {"ignore": []}]
45+
}
46+
```
47+
48+
- `ignore` option is an array to ignore specified directive-comments. The value of the array is some of the following strings:
49+
- `"eslint"`
50+
- `"eslint-disable"`
51+
- `"eslint-disable-line"`
52+
- `"eslint-disable-next-line"`
53+
- `"eslint-enable"`
54+
- `"eslint-env"`
55+
- `"exported"`
56+
- `"global"`
57+
- `"globals"`
58+
59+
## Further Reading
60+
61+
- [ESLint RFCs - Description in directive comments]
62+
63+
[ESLint RFCs - Description in directive comments]: https://github.com/eslint/rfcs/blob/master/designs/2019-description-in-directive-comments/README.md

lib/rules.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ module.exports = {
1010
"no-unused-disable": require("./rules/no-unused-disable"),
1111
"no-unused-enable": require("./rules/no-unused-enable"),
1212
"no-use": require("./rules/no-use"),
13+
"require-description": require("./rules/require-description"),
1314
}

lib/rules/require-description.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @author Yosuke Ota <https://github.com/ota-meshi>
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
"use strict"
6+
7+
const utils = require("../internal/utils")
8+
9+
module.exports = {
10+
meta: {
11+
docs: {
12+
description:
13+
"require include descriptions in ESLint directive-comments",
14+
category: "Stylistic Issues",
15+
recommended: false,
16+
url:
17+
"https://mysticatea.github.io/eslint-plugin-eslint-comments/rules/require-description.html",
18+
},
19+
fixable: null,
20+
schema: [
21+
{
22+
type: "object",
23+
properties: {
24+
ignore: {
25+
type: "array",
26+
items: {
27+
enum: [
28+
"eslint",
29+
"eslint-disable",
30+
"eslint-disable-line",
31+
"eslint-disable-next-line",
32+
"eslint-enable",
33+
"eslint-env",
34+
"exported",
35+
"global",
36+
"globals",
37+
],
38+
},
39+
additionalItems: false,
40+
uniqueItems: true,
41+
},
42+
},
43+
additionalProperties: false,
44+
},
45+
],
46+
type: "suggestion",
47+
},
48+
49+
create(context) {
50+
const sourceCode = context.getSourceCode()
51+
const ignores = new Set(
52+
(context.options[0] && context.options[0].ignore) || []
53+
)
54+
55+
return {
56+
Program() {
57+
for (const comment of sourceCode.getAllComments()) {
58+
const directiveComment = utils.parseDirectiveComment(
59+
comment
60+
)
61+
if (directiveComment == null) {
62+
continue
63+
}
64+
if (ignores.has(directiveComment.kind)) {
65+
continue
66+
}
67+
if (!directiveComment.description) {
68+
context.report({
69+
loc: utils.toForceLocation(comment.loc),
70+
message:
71+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
72+
})
73+
}
74+
}
75+
},
76+
}
77+
},
78+
}
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/**
2+
* @author Yosuke Ota <https://github.com/ota-meshi>
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
"use strict"
6+
7+
const semver = require("semver")
8+
const eslintVersion = require("eslint/package").version
9+
const RuleTester = require("eslint").RuleTester
10+
const rule = require("../../../lib/rules/require-description")
11+
const tester = new RuleTester()
12+
13+
if (!semver.satisfies(eslintVersion, ">=7.0.0")) {
14+
// This rule can only be used with ESLint v7.x or later.
15+
return
16+
}
17+
18+
tester.run("require-description", rule, {
19+
valid: [
20+
'/* eslint eqeqeq: "off", curly: "error" -- Here\'s a description about why this configuration is necessary. */',
21+
"/* eslint-disable -- description */",
22+
"/* eslint-enable -- description */",
23+
"/* exported -- description */",
24+
"/* global -- description */",
25+
"/* globals -- description */",
26+
"/* eslint-env -- description */",
27+
"/* just eslint in a normal comment */",
28+
"// eslint-disable-line -- description",
29+
"// eslint-disable-next-line -- description",
30+
"/* eslint-disable-line -- description */",
31+
"/* eslint-disable-next-line -- description */",
32+
"// eslint-disable-line eqeqeq -- description",
33+
"// eslint-disable-next-line eqeqeq -- description",
34+
{
35+
code: "/* eslint */",
36+
options: [{ ignore: ["eslint"] }],
37+
},
38+
{
39+
code: "/* eslint-env */",
40+
options: [{ ignore: ["eslint-env"] }],
41+
},
42+
{
43+
code: "/* eslint-enable */",
44+
options: [{ ignore: ["eslint-enable"] }],
45+
},
46+
{
47+
code: "/* eslint-disable */",
48+
options: [{ ignore: ["eslint-disable"] }],
49+
},
50+
{
51+
code: "// eslint-disable-line",
52+
options: [{ ignore: ["eslint-disable-line"] }],
53+
},
54+
{
55+
code: "// eslint-disable-next-line",
56+
options: [{ ignore: ["eslint-disable-next-line"] }],
57+
},
58+
{
59+
code: "/* eslint-disable-line */",
60+
options: [{ ignore: ["eslint-disable-line"] }],
61+
},
62+
{
63+
code: "/* eslint-disable-next-line */",
64+
options: [{ ignore: ["eslint-disable-next-line"] }],
65+
},
66+
{
67+
code: "/* exported */",
68+
options: [{ ignore: ["exported"] }],
69+
},
70+
{
71+
code: "/* global */",
72+
options: [{ ignore: ["global"] }],
73+
},
74+
{
75+
code: "/* globals */",
76+
options: [{ ignore: ["globals"] }],
77+
},
78+
],
79+
invalid: [
80+
{
81+
code: "/* eslint */",
82+
errors: [
83+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
84+
],
85+
},
86+
{
87+
code: '/* eslint eqeqeq: "off", curly: "error" */',
88+
errors: [
89+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
90+
],
91+
},
92+
{
93+
code: "/* eslint-env */",
94+
errors: [
95+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
96+
],
97+
},
98+
{
99+
code: "/* eslint-env node */",
100+
errors: [
101+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
102+
],
103+
},
104+
{
105+
code: "/* eslint-enable */",
106+
errors: [
107+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
108+
],
109+
},
110+
{
111+
code: "/* eslint-enable eqeqeq */",
112+
errors: [
113+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
114+
],
115+
},
116+
{
117+
code: "/* eslint-disable */",
118+
errors: [
119+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
120+
],
121+
},
122+
{
123+
code: "/* eslint-disable eqeqeq */",
124+
errors: [
125+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
126+
],
127+
},
128+
{
129+
code: "// eslint-disable-line",
130+
errors: [
131+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
132+
],
133+
},
134+
{
135+
code: "// eslint-disable-line eqeqeq",
136+
errors: [
137+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
138+
],
139+
},
140+
{
141+
code: "// eslint-disable-next-line",
142+
errors: [
143+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
144+
],
145+
},
146+
{
147+
code: "// eslint-disable-next-line eqeqeq",
148+
errors: [
149+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
150+
],
151+
},
152+
{
153+
code: "/* eslint-disable-line */",
154+
errors: [
155+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
156+
],
157+
},
158+
{
159+
code: "/* eslint-disable-line eqeqeq */",
160+
errors: [
161+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
162+
],
163+
},
164+
{
165+
code: "/* eslint-disable-next-line */",
166+
errors: [
167+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
168+
],
169+
},
170+
{
171+
code: "/* eslint-disable-next-line eqeqeq */",
172+
errors: [
173+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
174+
],
175+
},
176+
{
177+
code: "/* exported */",
178+
errors: [
179+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
180+
],
181+
},
182+
{
183+
code: "/* global */",
184+
errors: [
185+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
186+
],
187+
},
188+
{
189+
code: "/* global _ */",
190+
errors: [
191+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
192+
],
193+
},
194+
{
195+
code: "/* globals */",
196+
errors: [
197+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
198+
],
199+
},
200+
{
201+
code: "/* globals _ */",
202+
errors: [
203+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
204+
],
205+
},
206+
// empty description
207+
{
208+
code: "/* eslint-disable-next-line eqeqeq -- */",
209+
errors: [
210+
"Unexpected undescribed directive comment. Include descriptions to explain why the comment is necessary.",
211+
],
212+
},
213+
],
214+
})

0 commit comments

Comments
 (0)