Skip to content

Commit f558b79

Browse files
authored
Fixed false positives for binded and unbinded attrs in 'vue/attributes-order' with alphabetical option. (#1055)
* Fixed false positives for binded and unbinded attrs in 'vue/attributes-order' with `alphabetical` option. * Fixed #1056 * test timeout to 300000ms * revert timeout
1 parent 667bb2e commit f558b79

File tree

3 files changed

+182
-7
lines changed

3 files changed

+182
-7
lines changed

docs/rules/attributes-order.md

+12-4
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,13 @@ This rule aims to enforce ordering of component attributes. The default order is
106106
"EVENTS",
107107
"CONTENT"
108108
],
109-
"alphabetical": true
109+
"alphabetical": false
110110
}]
111111
}
112112
```
113113

114-
### Alphabetical order
114+
### `"alphabetical": true`
115+
115116
<eslint-code-block fix :rules="{'vue/attributes-order': ['error', {alphabetical: true}]}">
116117

117118
```vue
@@ -122,6 +123,8 @@ This rule aims to enforce ordering of component attributes. The default order is
122123
:another-custom-prop="value"
123124
:blue-color="false"
124125
boolean-prop
126+
class="foo"
127+
:class="bar"
125128
z-prop="Z"
126129
v-on:[c]="functionCall"
127130
@change="functionCall"
@@ -147,8 +150,13 @@ This rule aims to enforce ordering of component attributes. The default order is
147150
</div>
148151
149152
<div
150-
:a-prop="A"
151-
:z-prop="Z">
153+
:z-prop="Z"
154+
:a-prop="A">
155+
</div>
156+
157+
<div
158+
:class="foo"
159+
class="bar">
152160
</div>
153161
154162
</template>

lib/rules/attributes-order.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,20 @@ const ATTRS = {
2424

2525
function getAttributeName (attribute, sourceCode) {
2626
const isBind = attribute.directive && attribute.key.name.name === 'bind'
27-
debugger
2827
return isBind
2928
? (attribute.key.argument ? sourceCode.getText(attribute.key.argument) : '')
30-
: (attribute.directive ? sourceCode.getText(attribute.key.argument) : attribute.key.name)
29+
: (attribute.directive ? getDirectiveKeyName(attribute.key, sourceCode) : attribute.key.name)
30+
}
31+
32+
function getDirectiveKeyName (directiveKey, sourceCode) {
33+
let text = 'v-' + directiveKey.name.name
34+
if (directiveKey.argument) {
35+
text += ':' + sourceCode.getText(directiveKey.argument)
36+
}
37+
for (const modifier of directiveKey.modifiers) {
38+
text += '.' + modifier.name
39+
}
40+
return text
3141
}
3242

3343
function getAttributeType (attribute, sourceCode) {
@@ -75,7 +85,14 @@ function getPosition (attribute, attributePosition, sourceCode) {
7585
function isAlphabetical (prevNode, currNode, sourceCode) {
7686
const isSameType = getAttributeType(prevNode, sourceCode) === getAttributeType(currNode, sourceCode)
7787
if (isSameType) {
78-
return getAttributeName(prevNode, sourceCode) < getAttributeName(currNode, sourceCode)
88+
const prevName = getAttributeName(prevNode, sourceCode)
89+
const currName = getAttributeName(currNode, sourceCode)
90+
if (prevName === currName) {
91+
const prevIsBind = Boolean(prevNode.directive && prevNode.key.name.name === 'bind')
92+
const currIsBind = Boolean(currNode.directive && currNode.key.name.name === 'bind')
93+
return prevIsBind <= currIsBind
94+
}
95+
return prevName < currName
7996
}
8097
return true
8198
}

tests/lib/rules/attributes-order.js

+150
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,72 @@ tester.run('attributes-order', rule, {
312312
</div>
313313
</template>`,
314314
options: [{ alphabetical: true }]
315+
},
316+
{
317+
filename: 'test.vue',
318+
code:
319+
`<template>
320+
<div
321+
class="foo"
322+
:class="bar">
323+
</div>
324+
</template>`,
325+
options: [{ alphabetical: true }]
326+
},
327+
{
328+
filename: 'duplicate.vue',
329+
code:
330+
`<template>
331+
<div
332+
class="foo"
333+
class="bar">
334+
</div>
335+
</template>`,
336+
options: [{ alphabetical: true }]
337+
},
338+
{
339+
filename: 'duplicate.vue',
340+
code:
341+
`<template>
342+
<div
343+
:class="foo"
344+
:class="bar">
345+
</div>
346+
</template>`,
347+
options: [{ alphabetical: true }]
348+
},
349+
{
350+
filename: 'test.vue',
351+
code:
352+
`<template>
353+
<div
354+
v-if="foo"
355+
v-show="bar">
356+
</div>
357+
</template>`,
358+
options: [{ alphabetical: true }]
359+
},
360+
{
361+
filename: 'test.vue',
362+
code:
363+
`<template>
364+
<div
365+
v-bar="bar"
366+
v-foo="foo">
367+
</div>
368+
</template>`,
369+
options: [{ alphabetical: true }]
370+
},
371+
{
372+
filename: 'test.vue',
373+
code:
374+
`<template>
375+
<div
376+
v-foo.a="a"
377+
v-foo.b="b">
378+
</div>
379+
</template>`,
380+
options: [{ alphabetical: true }]
315381
}
316382
],
317383

@@ -778,6 +844,90 @@ tester.run('attributes-order', rule, {
778844
message: 'Attribute "v-on:click" should go before "v-text".',
779845
type: 'VDirectiveKey'
780846
}]
847+
},
848+
{
849+
filename: 'test.vue',
850+
code:
851+
`<template>
852+
<div
853+
:class="foo"
854+
class="bar">
855+
</div>
856+
</template>`,
857+
options: [{ alphabetical: true }],
858+
output:
859+
`<template>
860+
<div
861+
class="bar"
862+
:class="foo">
863+
</div>
864+
</template>`,
865+
errors: [{
866+
message: 'Attribute "class" should go before ":class".'
867+
}]
868+
},
869+
{
870+
filename: 'test.vue',
871+
code:
872+
`<template>
873+
<div
874+
v-show="foo"
875+
v-if="bar">
876+
</div>
877+
</template>`,
878+
options: [{ alphabetical: true }],
879+
output:
880+
`<template>
881+
<div
882+
v-if="bar"
883+
v-show="foo">
884+
</div>
885+
</template>`,
886+
errors: [{
887+
message: 'Attribute "v-if" should go before "v-show".'
888+
}]
889+
},
890+
{
891+
filename: 'test.vue',
892+
code:
893+
`<template>
894+
<div
895+
v-foo="foo"
896+
v-bar="bar">
897+
</div>
898+
</template>`,
899+
options: [{ alphabetical: true }],
900+
output:
901+
`<template>
902+
<div
903+
v-bar="bar"
904+
v-foo="foo">
905+
</div>
906+
</template>`,
907+
errors: [{
908+
message: 'Attribute "v-bar" should go before "v-foo".'
909+
}]
910+
},
911+
{
912+
filename: 'test.vue',
913+
code:
914+
`<template>
915+
<div
916+
v-foo.b="b"
917+
v-foo.a="a">
918+
</div>
919+
</template>`,
920+
options: [{ alphabetical: true }],
921+
output:
922+
`<template>
923+
<div
924+
v-foo.a="a"
925+
v-foo.b="b">
926+
</div>
927+
</template>`,
928+
errors: [{
929+
message: 'Attribute "v-foo.a" should go before "v-foo.b".'
930+
}]
781931
}
782932
]
783933
})

0 commit comments

Comments
 (0)