Skip to content

Commit 1ed8113

Browse files
committed
Add prefer-true-attribute-shorthand rule
1 parent 7ebbd85 commit 1ed8113

File tree

5 files changed

+272
-0
lines changed

5 files changed

+272
-0
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ For example:
353353
| [vue/no-v-text](./no-v-text.md) | disallow use of v-text | |
354354
| [vue/padding-line-between-blocks](./padding-line-between-blocks.md) | require or disallow padding lines between blocks | :wrench: |
355355
| [vue/prefer-separate-static-class](./prefer-separate-static-class.md) | require static class names in template to be in a separate `class` attribute | :wrench: |
356+
| [vue/prefer-true-attribute-shorthand](./prefer-true-attribute-shorthand.md) | require shorthand form attribute when `v-bind` value is `true`. | :bulb: |
356357
| [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | |
357358
| [vue/require-emit-validator](./require-emit-validator.md) | require type definitions in emits | :bulb: |
358359
| [vue/require-expose](./require-expose.md) | require declare public properties using `expose` | :bulb: |
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/prefer-true-attribute-shorthand
5+
description: require shorthand form attribute when `v-bind` value is `true`.
6+
---
7+
# vue/prefer-true-attribute-shorthand
8+
9+
> require shorthand form attribute when `v-bind` value is `true`.
10+
11+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
12+
- :bulb: Some problems reported by this rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
13+
14+
## :book: Rule Details
15+
16+
`v-bind` attribute with `true` value usually can be written in shorthand form. This can reduce verbosity.
17+
18+
<eslint-code-block :rules="{'vue/prefer-true-attribute-shorthand': ['error']}">
19+
20+
```vue
21+
<template>
22+
<!-- ✗ BAD -->
23+
<MyComponent v-bind:show="true" />
24+
<MyComponent :show="true" />
25+
26+
<!-- ✓ GOOD -->
27+
<MyComponent show />
28+
<MyComponent another-prop="true" />
29+
</template>
30+
```
31+
32+
</eslint-code-block>
33+
34+
However, those two representations are not always equivalent.
35+
This case will be occurred if the definition of a prop include `String`:
36+
37+
```vue
38+
<template>
39+
<pre>{{ prop }}</pre>
40+
</template>
41+
42+
<script>
43+
export default {
44+
name: 'MyComponent',
45+
props: {
46+
prop: [String, Boolean]
47+
}
48+
}
49+
</script>
50+
```
51+
52+
```vue
53+
<template>
54+
<MyComponent prop />
55+
<MyComponent :prop="true"/>
56+
</template>
57+
```
58+
59+
Those two calls will introduce different render result. See [this demo](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCBNeUNvbXBvbmVudCBmcm9tICcuL015Q29tcG9uZW50LnZ1ZSdcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxNeUNvbXBvbmVudCBhIGIvPlxuICA8TXlDb21wb25lbnQgOmE9XCJ0cnVlXCIgOmI9XCJ0cnVlXCIvPlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59IiwiTXlDb21wb25lbnQudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgcHJvcHM6IHtcbiAgICBhOiBCb29sZWFuLFxuICAgIGI6IFtTdHJpbmcsIEJvb2xlYW5dXG4gIH1cbn1cbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG4gIDxwcmU+XG5hOiB7e2F9fVxuYjoge3tifX1cbiAgPC9wcmU+XG48L3RlbXBsYXRlPiJ9).
60+
61+
## :wrench: Options
62+
63+
Nothing.
64+
65+
## :mag: Implementation
66+
67+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/prefer-true-attribute-shorthand.js)
68+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/prefer-true-attribute-shorthand.js)

lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ module.exports = {
159159
'padding-line-between-blocks': require('./rules/padding-line-between-blocks'),
160160
'prefer-separate-static-class': require('./rules/prefer-separate-static-class'),
161161
'prefer-template': require('./rules/prefer-template'),
162+
'prefer-true-attribute-shorthand': require('./rules/prefer-true-attribute-shorthand'),
162163
'prop-name-casing': require('./rules/prop-name-casing'),
163164
'quote-props': require('./rules/quote-props'),
164165
'require-component-is': require('./rules/require-component-is'),
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @author Pig Fang
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const utils = require('../utils')
12+
13+
// ------------------------------------------------------------------------------
14+
// Rule Definition
15+
// ------------------------------------------------------------------------------
16+
17+
module.exports = {
18+
meta: {
19+
type: 'problem',
20+
docs: {
21+
description:
22+
'require shorthand form attribute when `v-bind` value is `true`.',
23+
categories: undefined,
24+
url: 'https://eslint.vuejs.org/rules/prefer-true-attribute-shorthand.html'
25+
},
26+
fixable: null,
27+
hasSuggestions: true,
28+
schema: [],
29+
messages: {
30+
report:
31+
"Boolean prop with 'true' value can be written in shorthand form.",
32+
fix: 'Rewrite this prop into shorthand form.'
33+
}
34+
},
35+
/** @param {RuleContext} context */
36+
create(context) {
37+
// ...
38+
39+
return utils.defineTemplateBodyVisitor(context, {
40+
/** @param {VDirective} node */
41+
"VAttribute[directive=true][key.name.name='bind']"(node) {
42+
const { argument } = node.key
43+
if (
44+
!argument ||
45+
!node.value ||
46+
!node.value.expression ||
47+
node.value.expression.type !== 'Literal' ||
48+
node.value.expression.value !== true
49+
) {
50+
return
51+
}
52+
53+
context.report({
54+
node,
55+
messageId: 'report',
56+
suggest: [
57+
{
58+
messageId: 'fix',
59+
fix: (fixer) => {
60+
const sourceCode = context.getSourceCode()
61+
return fixer.replaceText(node, sourceCode.getText(argument))
62+
}
63+
}
64+
]
65+
})
66+
}
67+
})
68+
}
69+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/**
2+
* @author Pig Fang
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const RuleTester = require('eslint').RuleTester
8+
const rule = require('../../../lib/rules/prefer-true-attribute-shorthand')
9+
10+
const tester = new RuleTester({
11+
parser: require.resolve('vue-eslint-parser'),
12+
parserOptions: {
13+
ecmaVersion: 2020,
14+
sourceType: 'module'
15+
}
16+
})
17+
18+
tester.run('prefer-true-attribute-shorthand', rule, {
19+
valid: [
20+
{
21+
filename: 'test.vue',
22+
code: `
23+
<template>
24+
<MyComp v-if="true" />
25+
</template>
26+
`
27+
},
28+
{
29+
filename: 'test.vue',
30+
code: `
31+
<template>
32+
<MyComp v-bind="true" />
33+
</template>
34+
`
35+
},
36+
{
37+
filename: 'test.vue',
38+
code: `
39+
<template>
40+
<MyComp v-loading="true" />
41+
</template>
42+
`
43+
},
44+
{
45+
filename: 'test.vue',
46+
code: `
47+
<template>
48+
<MyComp show="true" />
49+
</template>
50+
`
51+
},
52+
{
53+
filename: 'test.vue',
54+
code: `
55+
<template>
56+
<MyComp v-bind:show="value" />
57+
</template>
58+
`
59+
},
60+
{
61+
filename: 'test.vue',
62+
code: `
63+
<template>
64+
<MyComp :show="value" />
65+
</template>
66+
`
67+
},
68+
{
69+
filename: 'test.vue',
70+
code: `
71+
<template>
72+
<MyComp v-bind:show="false" />
73+
</template>
74+
`
75+
},
76+
{
77+
filename: 'test.vue',
78+
code: `
79+
<template>
80+
<MyComp :show="false" />
81+
</template>
82+
`
83+
}
84+
],
85+
invalid: [
86+
{
87+
filename: 'test.vue',
88+
code: `
89+
<template>
90+
<MyComp v-bind:show="true" />
91+
</template>`,
92+
errors: [
93+
{
94+
messageId: 'report',
95+
line: 3,
96+
column: 17,
97+
suggestions: [
98+
{
99+
messageId: 'fix',
100+
output: `
101+
<template>
102+
<MyComp show />
103+
</template>`
104+
}
105+
]
106+
}
107+
]
108+
},
109+
{
110+
filename: 'test.vue',
111+
code: `
112+
<template>
113+
<MyComp :show="true" />
114+
</template>`,
115+
errors: [
116+
{
117+
messageId: 'report',
118+
line: 3,
119+
column: 17,
120+
suggestions: [
121+
{
122+
messageId: 'fix',
123+
output: `
124+
<template>
125+
<MyComp show />
126+
</template>`
127+
}
128+
]
129+
}
130+
]
131+
}
132+
]
133+
})

0 commit comments

Comments
 (0)