Skip to content

Commit b8743d0

Browse files
ydfzgyjmichalsnik
authored andcommitted
🐛Fix: v-bind order in vue/attribute-order rule (#421)
* Fix: v-bind order in `vue/attribute-order` rule * Fix: Including custom directives * Resolve conflict * Fix: Add a new group `OTHER_DIRECTIVES` * Fix: Typo * Fix: Resolve Conflict
1 parent 582b07b commit b8743d0

File tree

3 files changed

+55
-40
lines changed

3 files changed

+55
-40
lines changed

docs/rules/attributes-order.md

+23-20
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ ex: 'v-once', 'v-pre'
1818
ex: 'id'
1919
- UNIQUE
2020
ex: 'ref', 'key', 'slot'
21-
- BINDING
22-
ex: 'v-model', 'v-bind', ':property="foo"'
21+
- TWO\_WAY\_BINDING
22+
ex: 'v-model'
23+
- OTHER_DIRECTIVES
24+
ex: 'v-custom-directive'
2325
- OTHER_ATTR
24-
ex: 'customProp="foo"'
26+
ex: 'custom-prop="foo"', 'v-bind:prop="foo"', ':prop="foo"'
2527
- EVENTS
2628
ex: '@click="functionCall"', 'v-on="event"'
2729
- CONTENT
@@ -38,7 +40,7 @@ ex: 'v-text', 'v-html'
3840
id="uniqueID"
3941
ref="header"
4042
v-model="headerData"
41-
myProp="prop"
43+
my-prop="prop"
4244
@click="functionCall"
4345
v-text="textContent">
4446
</div>
@@ -48,19 +50,19 @@ ex: 'v-text', 'v-html'
4850
<div
4951
v-for="item in items"
5052
v-if="!visible"
51-
propOne="prop"
52-
propTwo="prop"
53-
propThree="prop"
53+
prop-one="prop"
54+
:prop-two="prop"
55+
prop-three="prop"
5456
@click="functionCall"
5557
v-text="textContent">
5658
</div>
5759
```
5860

5961
```html
6062
<div
61-
propOne="prop"
62-
propTwo="prop"
63-
propThree="prop">
63+
prop-one="prop"
64+
:prop-two="prop"
65+
prop-three="prop">
6466
</div>
6567
```
6668

@@ -70,9 +72,10 @@ ex: 'v-text', 'v-html'
7072
<div
7173
ref="header"
7274
v-for="item in items"
73-
v-once id="uniqueID"
75+
v-once
76+
id="uniqueID"
7477
v-model="headerData"
75-
myProp="prop"
78+
my-prop="prop"
7679
v-if="!visible"
7780
is="header"
7881
@click="functionCall"
@@ -87,31 +90,31 @@ Specify custom order of attribute groups
8790
:+1: Examples of **correct** code with custom order`:
8891

8992
```html
90-
<!-- 'vue/attributes-order': [2, { order: ['LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'BINDING', 'OTHER_ATTR', 'EVENTS', 'CONTENT', 'DEFINITION'] }] -->
93+
<!-- 'vue/attributes-order': [2, { order: ['LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'TWO_WAY_BINDING', 'OTHER_DIRECTIVES', 'OTHER_ATTR', 'EVENTS', 'CONTENT', 'DEFINITION'] }] -->
9194
<div
92-
propOne="prop"
93-
propTwo="prop"
95+
prop-one="prop"
96+
prop-two="prop"
9497
is="header">
9598
</div>
9699
```
97100

98101
```html
99-
<!-- 'vue/attributes-order': [2, { order: ['LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'BINDING', 'DEFINITION', 'OTHER_ATTR', 'EVENTS', 'CONTENT'] }] -->
102+
<!-- 'vue/attributes-order': [2, { order: ['LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'TWO_WAY_BINDING', 'DEFINITION', 'OTHER_DIRECTIVES', 'OTHER_ATTR', 'EVENTS', 'CONTENT'] }] -->
100103
<div
101104
ref="header"
102105
is="header"
103-
propOne="prop"
104-
propTwo="prop">
106+
prop-one="prop"
107+
prop-two="prop">
105108
</div>
106109
```
107110

108111
:-1: Examples of **incorrect** code with custom order`:
109112

110113
```html
111-
<!-- 'vue/attributes-order': [2, { order: ['LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'BINDING', 'DEFINITION', 'OTHER_ATTR', 'EVENTS', 'CONTENT'] }] -->
114+
<!-- 'vue/attributes-order': [2, { order: ['LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'TWO_WAY_BINDING', 'DEFINITION', 'OTHER_DIRECTIVES', 'OTHER_ATTR', 'EVENTS', 'CONTENT'] }] -->
112115
<div
113116
ref="header"
114-
propOne="prop"
117+
prop-one="prop"
115118
is="header">
116119
</div>
117120
```

lib/rules/attributes-order.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ function getAttributeType (name, isDirective) {
1717
return 'CONDITIONALS'
1818
} else if (name === 'pre' || name === 'once') {
1919
return 'RENDER_MODIFIERS'
20-
} else if (name === 'model' || name === 'bind') {
21-
return 'BINDING'
20+
} else if (name === 'model') {
21+
return 'TWO_WAY_BINDING'
2222
} else if (name === 'on') {
2323
return 'EVENTS'
2424
} else if (name === 'html' || name === 'text') {
2525
return 'CONTENT'
26+
} else {
27+
return 'OTHER_DIRECTIVES'
2628
}
2729
} else {
2830
if (name === 'is') {
@@ -37,13 +39,18 @@ function getAttributeType (name, isDirective) {
3739
}
3840
}
3941
function getPosition (attribute, attributeOrder) {
40-
const attributeType = getAttributeType(attribute.key.name, attribute.directive)
42+
let attributeType
43+
if (attribute.directive && attribute.key.name === 'bind') {
44+
attributeType = getAttributeType(attribute.key.argument, false)
45+
} else {
46+
attributeType = getAttributeType(attribute.key.name, attribute.directive)
47+
}
4148
return attributeOrder.indexOf(attributeType)
4249
}
4350

4451
function create (context) {
4552
const sourceCode = context.getSourceCode()
46-
let attributeOrder = ['DEFINITION', 'LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'BINDING', 'OTHER_ATTR', 'EVENTS', 'CONTENT']
53+
let attributeOrder = ['DEFINITION', 'LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'TWO_WAY_BINDING', 'OTHER_DIRECTIVES', 'OTHER_ATTR', 'EVENTS', 'CONTENT']
4754
if (context.options[0] && context.options[0].order) {
4855
attributeOrder = context.options[0].order
4956
}

tests/lib/rules/attributes-order.js

+21-16
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ tester.run('attributes-order', rule, {
8282
filename: 'test.vue',
8383
code: '<template><div v-model="toggle"></div></template>'
8484
},
85+
{
86+
filename: 'test.vue',
87+
code: '<template><div v-custom-directive></div></template>'
88+
},
8589
{
8690
filename: 'test.vue',
8791
code:
@@ -105,7 +109,7 @@ tester.run('attributes-order', rule, {
105109
{
106110
filename: 'test.vue',
107111
code:
108-
`<template>
112+
`<template>
109113
<div
110114
is="header"
111115
v-for="item in items"
@@ -164,7 +168,7 @@ tester.run('attributes-order', rule, {
164168
v-for="item in items"
165169
v-if="!visible"
166170
propone="prop"
167-
proptwo="prop"
171+
:proptwo="prop"
168172
propthree="prop"
169173
@click="functionCall"
170174
v-text="textContent">
@@ -185,7 +189,8 @@ tester.run('attributes-order', rule, {
185189
'RENDER_MODIFIERS',
186190
'GLOBAL',
187191
'UNIQUE',
188-
'BINDING',
192+
'TWO_WAY_BINDING',
193+
'OTHER_DIRECTIVES',
189194
'OTHER_ATTR',
190195
'EVENTS',
191196
'CONTENT',
@@ -202,8 +207,9 @@ tester.run('attributes-order', rule, {
202207
'RENDER_MODIFIERS',
203208
'GLOBAL',
204209
'UNIQUE',
205-
'BINDING',
210+
'TWO_WAY_BINDING',
206211
'DEFINITION',
212+
'OTHER_DIRECTIVES',
207213
'OTHER_ATTR',
208214
'EVENTS',
209215
'CONTENT']
@@ -220,9 +226,9 @@ tester.run('attributes-order', rule, {
220226
is="header"
221227
v-on:click="functionCall"
222228
ref="header"
223-
:prop="headerData"
224229
v-text="textContent"
225230
id="uniqueID"
231+
:prop="headerData"
226232
myProp="prop"
227233
>
228234
</div>
@@ -236,10 +242,11 @@ tester.run('attributes-order', rule, {
236242
'DEFINITION',
237243
'EVENTS',
238244
'UNIQUE',
239-
'BINDING',
245+
'TWO_WAY_BINDING',
240246
'CONTENT',
241247
'GLOBAL',
242-
'OTHER_ATTR'
248+
'OTHER_ATTR',
249+
'OTHER_DIRECTIVES'
243250
]
244251
}]
245252
}
@@ -272,15 +279,15 @@ tester.run('attributes-order', rule, {
272279
model="baz"
273280
v-model="toggle"
274281
propOne="bar"
275-
:bindingProp="foo">
282+
:id="foo">
276283
</div>
277284
</template>`,
278285
output:
279286
`<template>
280287
<div
281288
v-model="toggle"
282289
model="baz"
283-
:bindingProp="foo"
290+
:id="foo"
284291
propOne="bar">
285292
</div>
286293
</template>`,
@@ -289,7 +296,7 @@ tester.run('attributes-order', rule, {
289296
type: 'VDirectiveKey'
290297
},
291298
{
292-
message: 'Attribute ":bindingProp" should go before "propOne".',
299+
message: 'Attribute ":id" should go before "propOne".',
293300
type: 'VDirectiveKey'
294301
}]
295302
},
@@ -343,8 +350,9 @@ tester.run('attributes-order', rule, {
343350
'RENDER_MODIFIERS',
344351
'GLOBAL',
345352
'UNIQUE',
346-
'BINDING',
353+
'TWO_WAY_BINDING',
347354
'DEFINITION',
355+
'OTHER_DIRECTIVES',
348356
'OTHER_ATTR',
349357
'EVENTS',
350358
'CONTENT']
@@ -457,14 +465,15 @@ tester.run('attributes-order', rule, {
457465
{ order:
458466
[
459467
'EVENTS',
460-
'BINDING',
468+
'TWO_WAY_BINDING',
461469
'UNIQUE',
462470
'DEFINITION',
463471
'CONDITIONALS',
464472
'LIST_RENDERING',
465473
'RENDER_MODIFIERS',
466474
'GLOBAL',
467475
'OTHER_ATTR',
476+
'OTHER_DIRECTIVES',
468477
'CONTENT'
469478
]
470479
}],
@@ -497,10 +506,6 @@ tester.run('attributes-order', rule, {
497506
message: 'Attribute "ref" should go before "v-once".',
498507
nodeType: 'VIdentifier'
499508
},
500-
{
501-
message: 'Attribute ":prop" should go before "v-once".',
502-
nodeType: 'VDirectiveKey'
503-
},
504509
{
505510
message: 'Attribute "id" should go before "v-text".',
506511
nodeType: 'VIdentifier'

0 commit comments

Comments
 (0)