Skip to content

Commit 400cea8

Browse files
committed
New: no-aggregating-enable rule
1 parent 54d5fa0 commit 400cea8

File tree

4 files changed

+190
-1
lines changed

4 files changed

+190
-1
lines changed

docs/rules/no-aggregating-enable.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# disallows `eslint-enable` comments for multiple `eslint-disable` comments (no-aggregating-enable)
2+
3+
`eslint-enable` directive-comments can enable rules which are disabled by different `eslint-disable` directive-comments.
4+
It can enable a rule unintentionally.
5+
6+
```js
7+
/*eslint-disable no-undef */
8+
f()
9+
/*eslint-disable no-var */
10+
var a
11+
/*eslint-enable */ "※ Enables both no-undef and no-var."
12+
```
13+
14+
This rule warns `eslint-enable` directive-comments which enable rules for multiple `eslint-disable` directive-comments.
15+
16+
## Rule Details
17+
18+
:-1: Examples of **incorrect** code for this rule:
19+
20+
```js
21+
/*eslint no-aggregating-enable: "error"*/
22+
23+
/*eslint-disable no-undef */
24+
f()
25+
/*eslint-disable no-var */
26+
var a
27+
/*eslint-enable */ "ERROR: This `eslint-enable` comment affects 2 `eslint-disable` comments. An `eslint-enable` comment should be for an `eslint-disable` comment."
28+
```
29+
30+
```js
31+
/*eslint no-aggregating-enable: "error"*/
32+
33+
/*eslint-disable no-undef */
34+
f()
35+
/*eslint-disable no-var */
36+
var a
37+
/*eslint-enable no-undef, no-var */ "ERROR: This `eslint-enable` comment affects 2 `eslint-disable` comments. An `eslint-enable` comment should be for an `eslint-disable` comment."
38+
```
39+
40+
:+1: Examples of **correct** code for this rule:
41+
42+
```js
43+
/*eslint no-aggregating-enable: "error"*/
44+
45+
/*eslint-disable no-undef */
46+
f()
47+
/*eslint-disable no-var */
48+
var a
49+
/*eslint-enable no-var */
50+
51+
/*eslint-enable no-undef */
52+
```

lib/disabled-area.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const utils = require("./utils")
1515
// Helpers
1616
//------------------------------------------------------------------------------
1717

18-
const COMMENT_DIRECTIVE = /^\s*(eslint-(?:en|dis)able(?:(?:-next)?-line)?)\s*(?:(\S[\s\S]+\S)\s*)?$/
18+
const COMMENT_DIRECTIVE = /^\s*(eslint-(?:en|dis)able(?:(?:-next)?-line)?)\s*(?:(\S|\S[\s\S]*\S)\s*)?$/
1919
const DELIMITER = /[\s,]+/g
2020
const pool = new WeakMap()
2121

@@ -49,6 +49,7 @@ module.exports = class DisabledArea {
4949
this.areas = []
5050
this.duplicateDisableDirectives = []
5151
this.unusedEnableDirectives = []
52+
this.numberOfRelatedDisableDirectives = new Map()
5253
}
5354

5455
/**
@@ -105,6 +106,8 @@ module.exports = class DisabledArea {
105106
* @private
106107
*/
107108
_enable(comment, location, ruleIds, kind) {
109+
const relatedDisableDirectives = new Set()
110+
108111
if (ruleIds) {
109112
for (const ruleId of ruleIds) {
110113
let used = false
@@ -113,6 +116,7 @@ module.exports = class DisabledArea {
113116
const area = this.areas[i]
114117

115118
if (area.end === null && area.kind === kind && area.ruleId === ruleId) {
119+
relatedDisableDirectives.add(area.comment)
116120
area.end = location
117121
used = true
118122
}
@@ -130,6 +134,7 @@ module.exports = class DisabledArea {
130134
const area = this.areas[i]
131135

132136
if (area.end === null && area.kind === kind) {
137+
relatedDisableDirectives.add(area.comment)
133138
area.end = location
134139
used = true
135140
}
@@ -139,6 +144,8 @@ module.exports = class DisabledArea {
139144
this.unusedEnableDirectives.push({ comment, ruleId: null })
140145
}
141146
}
147+
148+
this.numberOfRelatedDisableDirectives.set(comment, relatedDisableDirectives.size)
142149
}
143150

144151
/**

lib/rules/no-aggregating-enable.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* @author Toru Nagashima
3+
* @copyright 2016 Toru Nagashima. All rights reserved.
4+
* See LICENSE file in root directory for full license.
5+
*/
6+
"use strict"
7+
8+
//------------------------------------------------------------------------------
9+
// Requirements
10+
//------------------------------------------------------------------------------
11+
12+
const DisabledArea = require("../disabled-area")
13+
const utils = require("../utils")
14+
15+
//------------------------------------------------------------------------------
16+
// Rule Definition
17+
//------------------------------------------------------------------------------
18+
19+
/**
20+
* Creates AST event handlers for no-aggregating-enable.
21+
*
22+
* @param {RuleContext} context - The rule context.
23+
* @returns {object} AST event handlers.
24+
*/
25+
function create(context) {
26+
const sourceCode = context.getSourceCode()
27+
const disabledArea = DisabledArea.get(sourceCode)
28+
29+
return {
30+
Program() {
31+
for (const entry of disabledArea.numberOfRelatedDisableDirectives) {
32+
const comment = entry[0]
33+
const count = entry[1]
34+
35+
if (count >= 2) {
36+
context.report({
37+
loc: utils.toForceLocation(comment.loc),
38+
message: "This `eslint-enable` comment affects {{count}} `eslint-disable` comments. An `eslint-enable` comment should be for an `eslint-disable` comment.",
39+
data: { count },
40+
})
41+
}
42+
}
43+
},
44+
}
45+
}
46+
47+
module.exports = {
48+
create,
49+
meta: {
50+
docs: {
51+
description: "disallows `eslint-enable` comments for multiple `eslint-disable` comments",
52+
category: "Best Practices",
53+
recommended: false,
54+
},
55+
fixable: false,
56+
schema: [],
57+
},
58+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* @author Toru Nagashima
3+
* @copyright 2016 Toru Nagashima. All rights reserved.
4+
* See LICENSE file in root directory for full license.
5+
*/
6+
"use strict"
7+
8+
//------------------------------------------------------------------------------
9+
// Requirements
10+
//------------------------------------------------------------------------------
11+
12+
const RuleTester = require("eslint").RuleTester
13+
const rule = require("../../../lib/rules/no-aggregating-enable")
14+
15+
//------------------------------------------------------------------------------
16+
// Tests
17+
//------------------------------------------------------------------------------
18+
19+
const tester = new RuleTester()
20+
21+
tester.run("no-aggregating-enable", rule, {
22+
valid: [
23+
`
24+
/*eslint-disable a*/
25+
/*eslint-enable a*/
26+
`,
27+
`
28+
/*eslint-disable a*/
29+
/*eslint-enable b*/
30+
`,
31+
`
32+
/*eslint-disable a, b*/
33+
/*eslint-enable*/
34+
`,
35+
`
36+
/*eslint-disable a, b*/
37+
/*eslint-enable a, b*/
38+
`,
39+
`
40+
/*eslint-disable a, b*/
41+
/*eslint-enable a*/
42+
/*eslint-enable b*/
43+
`,
44+
],
45+
invalid: [
46+
{
47+
code: `
48+
/*eslint-disable a*/
49+
/*eslint-disable b*/
50+
/*eslint-enable*/
51+
`,
52+
errors: ["This `eslint-enable` comment affects 2 `eslint-disable` comments. An `eslint-enable` comment should be for an `eslint-disable` comment."],
53+
},
54+
{
55+
code: `
56+
/*eslint-disable a*/
57+
/*eslint-disable b*/
58+
/*eslint-disable c*/
59+
/*eslint-enable*/
60+
`,
61+
errors: ["This `eslint-enable` comment affects 3 `eslint-disable` comments. An `eslint-enable` comment should be for an `eslint-disable` comment."],
62+
},
63+
{
64+
code: `
65+
/*eslint-disable a*/
66+
/*eslint-disable b*/
67+
/*eslint-enable a, b*/
68+
`,
69+
errors: ["This `eslint-enable` comment affects 2 `eslint-disable` comments. An `eslint-enable` comment should be for an `eslint-disable` comment."],
70+
},
71+
],
72+
})

0 commit comments

Comments
 (0)