diff --git a/docs/rules/attributes-order.md b/docs/rules/attributes-order.md
index 8c61d3688..879ec1d57 100644
--- a/docs/rules/attributes-order.md
+++ b/docs/rules/attributes-order.md
@@ -105,11 +105,57 @@ This rule aims to enforce ordering of component attributes. The default order is
"OTHER_ATTR",
"EVENTS",
"CONTENT"
- ]
+ ],
+ "alphabetical": true
}]
}
```
+### Alphabetical order
+
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+
### Custom orders
#### `['LIST_RENDERING', 'CONDITIONALS', 'RENDER_MODIFIERS', 'GLOBAL', 'UNIQUE', 'TWO_WAY_BINDING', 'DEFINITION', 'OTHER_DIRECTIVES', 'OTHER_ATTR', 'EVENTS', 'CONTENT']`
diff --git a/lib/rules/attributes-order.js b/lib/rules/attributes-order.js
index afa0b3c5a..ac8afe283 100644
--- a/lib/rules/attributes-order.js
+++ b/lib/rules/attributes-order.js
@@ -22,6 +22,14 @@ const ATTRS = {
CONTENT: 'CONTENT'
}
+function getAttributeName (attribute, sourceCode) {
+ const isBind = attribute.directive && attribute.key.name.name === 'bind'
+ debugger
+ return isBind
+ ? (attribute.key.argument ? sourceCode.getText(attribute.key.argument) : '')
+ : (attribute.directive ? sourceCode.getText(attribute.key.argument) : attribute.key.name)
+}
+
function getAttributeType (attribute, sourceCode) {
const isBind = attribute.directive && attribute.key.name.name === 'bind'
const name = isBind
@@ -64,6 +72,14 @@ function getPosition (attribute, attributePosition, sourceCode) {
return attributePosition.hasOwnProperty(attributeType) ? attributePosition[attributeType] : -1
}
+function isAlphabetical (prevNode, currNode, sourceCode) {
+ const isSameType = getAttributeType(prevNode, sourceCode) === getAttributeType(currNode, sourceCode)
+ if (isSameType) {
+ return getAttributeName(prevNode, sourceCode) < getAttributeName(currNode, sourceCode)
+ }
+ return true
+}
+
function create (context) {
const sourceCode = context.getSourceCode()
let attributeOrder = [ATTRS.DEFINITION, ATTRS.LIST_RENDERING, ATTRS.CONDITIONALS, ATTRS.RENDER_MODIFIERS, ATTRS.GLOBAL, ATTRS.UNIQUE, ATTRS.TWO_WAY_BINDING, ATTRS.OTHER_DIRECTIVES, ATTRS.OTHER_ATTR, ATTRS.EVENTS, ATTRS.CONTENT]
@@ -110,7 +126,11 @@ function create (context) {
previousNode = null
},
'VAttribute' (node) {
- if ((currentPosition === -1) || (currentPosition <= getPosition(node, attributePosition, sourceCode))) {
+ let inAlphaOrder = true
+ if (currentPosition !== -1 && (context.options[0] && context.options[0].alphabetical)) {
+ inAlphaOrder = isAlphabetical(previousNode, node, sourceCode)
+ }
+ if ((currentPosition === -1) || ((currentPosition <= getPosition(node, attributePosition, sourceCode)) && inAlphaOrder)) {
currentPosition = getPosition(node, attributePosition, sourceCode)
previousNode = node
} else {
diff --git a/tests/lib/rules/attributes-order.js b/tests/lib/rules/attributes-order.js
index 7ac9aaf59..481148f9d 100644
--- a/tests/lib/rules/attributes-order.js
+++ b/tests/lib/rules/attributes-order.js
@@ -293,6 +293,25 @@ tester.run('attributes-order', rule, {
v-text="textContent">
`
+ },
+ {
+ filename: 'test.vue',
+ code:
+ `
+
+
+ `,
+ options: [{ alphabetical: true }]
}
],
@@ -318,23 +337,23 @@ tester.run('attributes-order', rule, {
{
filename: 'test.vue',
code:
- `
-
-
- `,
+ `
+
+
+ `,
output:
- `
-
-
- `,
+ `
+
+
+ `,
errors: [{
message: 'Attribute "v-model" should go before "model".',
type: 'VDirectiveKey'
@@ -347,25 +366,25 @@ tester.run('attributes-order', rule, {
{
filename: 'test.vue',
code:
- `
-
-
- `,
+ `
+
+
+ `,
output:
- `
-
-
- `,
+ `
+
+
+ `,
errors: [{
message: 'Attribute "v-model" should go before "v-on".',
type: 'VDirectiveKey'
@@ -389,17 +408,17 @@ tester.run('attributes-order', rule, {
code: '',
options: [
{ order:
- ['LIST_RENDERING',
- 'CONDITIONALS',
- 'RENDER_MODIFIERS',
- 'GLOBAL',
- 'UNIQUE',
- 'TWO_WAY_BINDING',
- 'DEFINITION',
- 'OTHER_DIRECTIVES',
- 'OTHER_ATTR',
- 'EVENTS',
- 'CONTENT']
+ ['LIST_RENDERING',
+ 'CONDITIONALS',
+ 'RENDER_MODIFIERS',
+ 'GLOBAL',
+ 'UNIQUE',
+ 'TWO_WAY_BINDING',
+ 'DEFINITION',
+ 'OTHER_DIRECTIVES',
+ 'OTHER_ATTR',
+ 'EVENTS',
+ 'CONTENT']
}],
output: '',
errors: [{
@@ -410,17 +429,17 @@ tester.run('attributes-order', rule, {
{
filename: 'test.vue',
code:
- `
-
-
- `,
+ `
+
+
+ `,
output:
- `
-
-
- `,
+ `
+
+
+ `,
errors: [{
message: 'Attribute "is" should go before "v-cloak".',
type: 'VIdentifier'
@@ -429,37 +448,37 @@ tester.run('attributes-order', rule, {
{
filename: 'test.vue',
code:
- `
-
-
- `,
+ `
+
+
+ `,
output:
- `
-
-
- `,
+ `
+
+
+ `,
errors: [
{
message: 'Attribute "v-for" should go before "v-if".',
@@ -490,53 +509,53 @@ tester.run('attributes-order', rule, {
{
filename: 'test.vue',
code:
- `
-
-
- `,
+ `
+
+
+ `,
options: [
{ order:
- [
- 'EVENTS',
- 'TWO_WAY_BINDING',
- 'UNIQUE',
- 'DEFINITION',
- 'CONDITIONALS',
- 'LIST_RENDERING',
- 'RENDER_MODIFIERS',
- 'GLOBAL',
- 'OTHER_ATTR',
- 'OTHER_DIRECTIVES',
- 'CONTENT'
- ]
+ [
+ 'EVENTS',
+ 'TWO_WAY_BINDING',
+ 'UNIQUE',
+ 'DEFINITION',
+ 'CONDITIONALS',
+ 'LIST_RENDERING',
+ 'RENDER_MODIFIERS',
+ 'GLOBAL',
+ 'OTHER_ATTR',
+ 'OTHER_DIRECTIVES',
+ 'CONTENT'
+ ]
}],
output:
- `
-
-
- `,
+ `
+
+
+ `,
errors: [
{
message: 'Attribute "is" should go before "v-once".',
@@ -562,39 +581,39 @@ tester.run('attributes-order', rule, {
},
{
code:
- `
-
-
- `,
+ `
+
+
+ `,
options: [
{ order:
- [
- 'CONDITIONALS',
- 'LIST_RENDERING',
- 'RENDER_MODIFIERS',
- 'DEFINITION',
- 'EVENTS',
- 'UNIQUE',
- ['BINDING', 'OTHER_ATTR'],
- 'CONTENT',
- 'GLOBAL'
- ]
+ [
+ 'CONDITIONALS',
+ 'LIST_RENDERING',
+ 'RENDER_MODIFIERS',
+ 'DEFINITION',
+ 'EVENTS',
+ 'UNIQUE',
+ ['BINDING', 'OTHER_ATTR'],
+ 'CONTENT',
+ 'GLOBAL'
+ ]
}],
output:
- `
-
-
- `,
+ `
+
+
+ `,
errors: [
{
message: 'Attribute "v-if" should go before "class".',
@@ -604,29 +623,161 @@ tester.run('attributes-order', rule, {
},
{
code:
- `
-
-
- `,
+ `
+
+
+ `,
output:
- `
-
-
- `,
+ `
+
+
+ `,
errors: [
{
message: 'Attribute "v-slot" should go before "v-model".',
nodeType: 'VIdentifier'
}
]
+ },
+ {
+ filename: 'test.vue',
+ code:
+ `
+
+
+ `,
+ options: [{ alphabetical: true }],
+ output:
+ `
+
+
+ `,
+ errors: [{
+ message: 'Attribute "a-prop" should go before "z-prop".',
+ type: 'VIdentifier'
+ }]
+ },
+ {
+ filename: 'test.vue',
+ code:
+ `
+
+
+ `,
+ options: [{ alphabetical: true }],
+ output:
+ `
+
+
+ `,
+ errors: [{
+ message: 'Attribute ":a-prop" should go before ":z-prop".',
+ type: 'VDirectiveKey'
+ }]
+ },
+ {
+ filename: 'test.vue',
+ code:
+ `
+
+
+ `,
+ options: [{ alphabetical: true }],
+ output:
+ `
+
+
+ `,
+ errors: [{
+ message: 'Attribute "@change" should go before "@input".',
+ type: 'VDirectiveKey'
+ }]
+ },
+ {
+ filename: 'test.vue',
+ code:
+ `
+
+
+ `,
+ options: [{ alphabetical: true }],
+ output:
+ `
+
+
+ `,
+ errors: [{
+ message: 'Attribute "boolean-prop" should go before "z-prop".',
+ type: 'VIdentifier'
+ }]
+ },
+ {
+ filename: 'test.vue',
+ code:
+ `
+
+
+ `,
+ options: [{ alphabetical: true }],
+ output:
+ `
+
+
+ `,
+ errors: [{
+ message: 'Attribute "v-on:[c]" should go before "v-on:click".',
+ type: 'VDirectiveKey'
+ }]
+ },
+ {
+ filename: 'test.vue',
+ code:
+ `
+
+
+ `,
+ options: [{ alphabetical: true }],
+ output:
+ `
+
+
+ `,
+ errors: [{
+ message: 'Attribute "v-on:click" should go before "v-text".',
+ type: 'VDirectiveKey'
+ }]
}
]
})