Skip to content

Commit ff5bfdc

Browse files
committed
New: directive comments (fixes #260)
1 parent dfcd26e commit ff5bfdc

10 files changed

+419
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi
9595

9696
| | Rule ID | Description |
9797
|:---|:--------|:------------|
98+
| | [comment-directive](./docs/rules/comment-directive.md) | support comment-directives in `<template>` |
9899
| | [jsx-uses-vars](./docs/rules/jsx-uses-vars.md) | prevent variables used in JSX to be marked as unused |
99100

100101

docs/rules/comment-directive.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# support comment-directives in `<template>` (comment-directive)
2+
3+
This rule supports the following comment directives in `<template>`:
4+
5+
- `eslint-disable`
6+
- `eslint-enable`
7+
- `eslint-disable-line`
8+
- `eslint-disable-next-line`
9+
10+
For example:
11+
12+
```html
13+
<template>
14+
<!-- eslint-disable-next-line vue/max-attributes-per-line -->
15+
<div a="1" b="2" c="3" d="4">
16+
</div>
17+
</template>
18+
```
19+
20+
This rule doesn't make any warning.
21+
22+
## Further reading
23+
24+
- [Disabling rules with inline comments](https://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments)

lib/base-rules.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
* in order to update it's content execute "npm run update"
55
*/
66
module.exports = {
7+
"vue/comment-directive": "error",
78
"vue/jsx-uses-vars": "error"
89
}

lib/essential-rules.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* in order to update it's content execute "npm run update"
55
*/
66
module.exports = {
7+
"vue/comment-directive": "error",
78
"vue/jsx-uses-vars": "error",
89
"vue/no-async-in-computed-properties": "error",
910
"vue/no-dupe-keys": "error",

lib/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ const configs = requireAll({
1111
dirname: resolve(__dirname, 'config'),
1212
filter: /^([\w\-]+)\.js$/
1313
})
14+
const processor = require('./processor')
1415

1516
module.exports = {
1617
rules,
17-
configs
18+
configs,
19+
processors: { '.vue': processor }
1820
}

lib/processor.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* @author Toru Nagashima <https://github.com/mysticatea>
3+
*/
4+
'use strict'
5+
6+
module.exports = {
7+
preprocess (code) {
8+
return [code]
9+
},
10+
11+
postprocess (messages) {
12+
const state = {
13+
block: {
14+
disableAll: false,
15+
disableRules: new Set()
16+
},
17+
line: {
18+
disableAll: false,
19+
disableRules: new Set()
20+
}
21+
}
22+
23+
// Filter messages which are in disabled area.
24+
return messages[0].filter(message => {
25+
if (message.ruleId === 'vue/comment-directive') {
26+
const rules = message.message.split(' ')
27+
const type = rules.shift()
28+
const group = rules.shift()
29+
switch (type) {
30+
case '--':
31+
state[group].disableAll = true
32+
break
33+
case '++':
34+
state[group].disableAll = false
35+
break
36+
case '-':
37+
for (const rule of rules) {
38+
state[group].disableRules.add(rule)
39+
}
40+
break
41+
case '+':
42+
for (const rule of rules) {
43+
state[group].disableRules.delete(rule)
44+
}
45+
break
46+
}
47+
return false
48+
} else {
49+
return !(
50+
state.block.disableAll ||
51+
state.line.disableAll ||
52+
state.block.disableRules.has(message.ruleId) ||
53+
state.line.disableRules.has(message.ruleId)
54+
)
55+
}
56+
})
57+
},
58+
59+
supportsAutofix: true
60+
}

lib/recommended-rules.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
module.exports = {
77
"vue/attribute-hyphenation": "error",
8+
"vue/comment-directive": "error",
89
"vue/html-end-tags": "error",
910
"vue/html-indent": "error",
1011
"vue/html-quotes": "error",

lib/rules/comment-directive.js

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/**
2+
* @author Toru Nagashima <https://github.com/mysticatea>
3+
*/
4+
5+
'use strict'
6+
7+
// -----------------------------------------------------------------------------
8+
// Helpers
9+
// -----------------------------------------------------------------------------
10+
11+
const COMMENT_DIRECTIVE_B = /^\s*(eslint-(?:en|dis)able)\s*(?:(\S|\S[\s\S]*\S)\s*)?$/
12+
const COMMENT_DIRECTIVE_L = /^\s*(eslint-disable(?:-next)?-line)\s*(?:(\S|\S[\s\S]*\S)\s*)?$/
13+
14+
/**
15+
* Parse a given comment.
16+
* @param {RegExp} pattern The RegExp pattern to parse.
17+
* @param {string} comment The comment value to parse.
18+
* @returns {({type:string,rules:string[]})|null} The parsing result.
19+
*/
20+
function parse (pattern, comment) {
21+
const match = pattern.exec(comment)
22+
if (match == null) {
23+
return null
24+
}
25+
26+
const type = match[1]
27+
const rules = (match[2] || '')
28+
.split(',')
29+
.map(s => s.trim())
30+
.filter(Boolean)
31+
32+
return { type, rules }
33+
}
34+
35+
/**
36+
* Enable rules.
37+
* @param {RuleContext} context The rule context.
38+
* @param {{line:number,column:number}} loc The location information to enable.
39+
* @param {string} group The group to enable.
40+
* @param {string[]} rules The rule IDs to enable.
41+
* @returns {void}
42+
*/
43+
function enable (context, loc, group, rules) {
44+
if (rules.length === 0) {
45+
context.report({ loc, message: '++ {{group}}', data: { group }})
46+
} else {
47+
context.report({ loc, message: '+ {{group}} {{rules}}', data: { group, rules: rules.join(' ') }})
48+
}
49+
}
50+
51+
/**
52+
* Disable rules.
53+
* @param {RuleContext} context The rule context.
54+
* @param {{line:number,column:number}} loc The location information to disable.
55+
* @param {string} group The group to disable.
56+
* @param {string[]} rules The rule IDs to disable.
57+
* @returns {void}
58+
*/
59+
function disable (context, loc, group, rules) {
60+
if (rules.length === 0) {
61+
context.report({ loc, message: '-- {{group}}', data: { group }})
62+
} else {
63+
context.report({ loc, message: '- {{group}} {{rules}}', data: { group, rules: rules.join(' ') }})
64+
}
65+
}
66+
67+
/**
68+
* Process a given comment token.
69+
* If the comment is `eslint-disable` or `eslint-enable` then it reports the comment.
70+
* @param {RuleContext} context The rule context.
71+
* @param {Token} comment The comment token to process.
72+
* @returns {void}
73+
*/
74+
function processBlock (context, comment) {
75+
const parsed = parse(COMMENT_DIRECTIVE_B, comment.value)
76+
if (parsed != null) {
77+
if (parsed.type === 'eslint-disable') {
78+
disable(context, comment.loc.start, 'block', parsed.rules)
79+
} else {
80+
enable(context, comment.loc.start, 'block', parsed.rules)
81+
}
82+
}
83+
}
84+
85+
/**
86+
* Process a given comment token.
87+
* If the comment is `eslint-disable-line` or `eslint-disable-next-line` then it reports the comment.
88+
* @param {RuleContext} context The rule context.
89+
* @param {Token} comment The comment token to process.
90+
* @returns {void}
91+
*/
92+
function processLine (context, comment) {
93+
const parsed = parse(COMMENT_DIRECTIVE_L, comment.value)
94+
if (parsed != null && comment.loc.start.line === comment.loc.end.line) {
95+
const line = comment.loc.start.line + (parsed.type === 'eslint-disable-line' ? 0 : 1)
96+
const column = -1
97+
disable(context, { line, column }, 'line', parsed.rules)
98+
enable(context, { line: line + 1, column }, 'line', parsed.rules)
99+
}
100+
}
101+
102+
/**
103+
* The implementation of `vue/comment-directive` rule.
104+
* @param {Program} node The program node to parse.
105+
* @returns {Object} The visitor of this rule.
106+
*/
107+
function create (context) {
108+
return {
109+
Program (node) {
110+
const comments = (node.templateBody && node.templateBody.comments) || []
111+
for (const comment of comments) {
112+
processBlock(context, comment)
113+
processLine(context, comment)
114+
}
115+
}
116+
}
117+
}
118+
119+
// -----------------------------------------------------------------------------
120+
// Rule Definition
121+
// -----------------------------------------------------------------------------
122+
123+
module.exports = {
124+
meta: {
125+
docs: {
126+
description: 'support comment-directives in `<template>`', // eslint-disable-line consistent-docs-description
127+
category: 'base'
128+
},
129+
schema: []
130+
},
131+
create
132+
}

lib/strongly-recommended-rules.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
module.exports = {
77
"vue/attribute-hyphenation": "error",
8+
"vue/comment-directive": "error",
89
"vue/html-end-tags": "error",
910
"vue/html-indent": "error",
1011
"vue/html-self-closing": "error",

0 commit comments

Comments
 (0)