diff --git a/lib/rules/attributes-order.js b/lib/rules/attributes-order.js index e5cd19dd5..78efa4b4b 100644 --- a/lib/rules/attributes-order.js +++ b/lib/rules/attributes-order.js @@ -59,6 +59,31 @@ function create (context) { message: `Attribute "${currentNode}" should go before "${prevNode}".`, data: { currentNode + }, + + fix (fixer) { + const attributes = node.parent.attributes + const shiftAttrs = attributes.slice(attributes.indexOf(previousNode), attributes.indexOf(node) + 1) + + // If we can upgrade requirements to `eslint@>4.1.0`, this code can be replaced by: + // return shiftAttrs.map((attr, i) => { + // const text = attr === previousNode ? sourceCode.getText(node) : sourceCode.getText(shiftAttrs[i - 1]) + // return fixer.replaceText(attr, text) + // }) + const replaceDataList = shiftAttrs.map((attr, i) => { + const text = attr === previousNode ? sourceCode.getText(node) : sourceCode.getText(shiftAttrs[i - 1]) + return { + range: attr.range, + text + } + }) + const replaceRange = [previousNode.range[0], node.range[1]] + let text = sourceCode.text.slice(replaceRange[0], replaceRange[1]) + replaceDataList.reverse().forEach((data) => { + const textRange = data.range.map(r => r - replaceRange[0]) + text = text.slice(0, textRange[0]) + data.text + text.slice(textRange[1], text.length) + }) + return fixer.replaceTextRange(replaceRange, text) } }) } @@ -85,7 +110,7 @@ module.exports = { description: 'enforce order of attributes', category: 'recommended' }, - fixable: null, + fixable: 'code', schema: { type: 'array', properties: { diff --git a/tests/lib/rules/attributes-order.js b/tests/lib/rules/attributes-order.js index 39c207160..9366ac130 100644 --- a/tests/lib/rules/attributes-order.js +++ b/tests/lib/rules/attributes-order.js @@ -208,6 +208,40 @@ tester.run('attributes-order', rule, { 'EVENTS', 'CONTENT'] }] + }, + { + filename: 'test.vue', + code: + ``, + options: [ + { order: + [ + 'CONDITIONALS', + 'LIST_RENDERING', + 'RENDER_MODIFIERS', + 'DEFINITION', + 'EVENTS', + 'UNIQUE', + 'BINDING', + 'CONTENT', + 'GLOBAL', + 'OTHER_ATTR' + ] + }] } ], @@ -215,6 +249,7 @@ tester.run('attributes-order', rule, { { filename: 'test.vue', code: '', + output: '', errors: [{ message: 'Attribute "is" should go before "v-cloak".', type: 'VIdentifier' @@ -223,6 +258,7 @@ tester.run('attributes-order', rule, { { filename: 'test.vue', code: '', + output: '', errors: [{ message: 'Attribute "v-cloak" should go before "id".', type: 'VDirectiveKey' @@ -239,6 +275,15 @@ tester.run('attributes-order', rule, { :bindingProp="foo"> `, + output: + ``, errors: [{ message: 'Attribute "v-model" should go before "model".', type: 'VDirectiveKey' @@ -260,6 +305,16 @@ tester.run('attributes-order', rule, { propOne="bar"> `, + output: + ``, errors: [{ message: 'Attribute "v-model" should go before "v-on".', type: 'VDirectiveKey' @@ -272,6 +327,7 @@ tester.run('attributes-order', rule, { { filename: 'test.vue', code: '', + output: '', errors: [{ message: 'Attribute "is" should go before "aria-test".', type: 'VIdentifier' @@ -293,10 +349,167 @@ tester.run('attributes-order', rule, { 'EVENTS', 'CONTENT'] }], + output: '', errors: [{ message: 'Attribute "is" should go before "propone".', type: 'VIdentifier' }] + }, + { + filename: 'test.vue', + code: + ``, + output: + ``, + errors: [{ + message: 'Attribute "is" should go before "v-cloak".', + type: 'VIdentifier' + }] + }, + { + filename: 'test.vue', + code: + ``, + output: + ``, + errors: [ + { + message: 'Attribute "v-for" should go before "v-if".', + type: 'VDirectiveKey' + }, + { + message: 'Attribute "is" should go before "v-once".', + type: 'VIdentifier' + }, + { + message: 'Attribute "ref" should go before "v-on:click".', + type: 'VIdentifier' + }, + { + message: 'Attribute ":prop" should go before "v-on:click".', + type: 'VDirectiveKey' + }, + { + message: 'Attribute "id" should go before "v-text".', + type: 'VIdentifier' + }, + { + message: 'Attribute "myProp" should go before "v-text".', + type: 'VIdentifier' + } + ] + }, + { + filename: 'test.vue', + code: + ``, + options: [ + { order: + [ + 'EVENTS', + 'BINDING', + 'UNIQUE', + 'DEFINITION', + 'CONDITIONALS', + 'LIST_RENDERING', + 'RENDER_MODIFIERS', + 'GLOBAL', + 'OTHER_ATTR', + 'CONTENT' + ] + }], + output: + ``, + errors: [ + { + message: 'Attribute "is" should go before "v-once".', + nodeType: 'VIdentifier' + }, + { + message: 'Attribute "v-on:click" should go before "v-once".', + nodeType: 'VDirectiveKey' + }, + { + message: 'Attribute "ref" should go before "v-once".', + nodeType: 'VIdentifier' + }, + { + message: 'Attribute ":prop" should go before "v-once".', + nodeType: 'VDirectiveKey' + }, + { + message: 'Attribute "id" should go before "v-text".', + nodeType: 'VIdentifier' + }, + { + message: 'Attribute "myProp" should go before "v-text".', + nodeType: 'VIdentifier' + } + ] } ] })