Skip to content

Commit a5391f1

Browse files
ota-meshimichalsnik
authored andcommitted
[Update] Make vue/attributes-order fixable (vuejs#405)
* Add Vue.extend support, add missing info about Vue.mixin check in readme * Docs: fixes wording in docs (vuejs#372) * Fix: fix script-indent to prevent removing <script> tag (fixes vuejs#367) (vuejs#374) * [Update] Make `vue/max-attributes-per-line` fixable (vuejs#380) * [Update] Make `vue/max-attributes-per-line` fixable * [fix] bug and style * [fix] Switch indent calculation method with node and attribute * [fix] don't handle indentation * [add] autofix test max-attributes-per-line.js * Update: make `vue/order-in-components` fixable (vuejs#381) * [Update] Make `vue/order-in-components` fixable This Commit makes `vue/order-in-components` fixable. In case of `The "A" property should be above the "B" property` error, autofix will move A before B * [fix] fail test at [email protected] * [fix] If there is a possibility of a side effect, don't autofix * [fix] failed test at node v4 * [update] use Traverser * [fix] failed test [email protected] * [fix] I used `output: null` to specify "not fix" * Fix: no-async-in-computed-properties crash (fixes vuejs#390) * Fix: valid-v-on false positive (fixes vuejs#351) * Fix: indent rules false positive (fixes vuejs#375) * [New] Add `prop-name-casing` * fix message and category * fix category * fix test message * Set category to undefined * Add more tests and fix edge case scenario * attribute order linting * updating docs, tests and category * [Update] Make `vue/attributes-order` fixable * [fix] That `vue/attributes-order` got duplicated when merging README * [add] messed order properties test case * [fix] unify input on test case
1 parent faaa69c commit a5391f1

File tree

2 files changed

+239
-1
lines changed

2 files changed

+239
-1
lines changed

lib/rules/attributes-order.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,31 @@ function create (context) {
5959
message: `Attribute "${currentNode}" should go before "${prevNode}".`,
6060
data: {
6161
currentNode
62+
},
63+
64+
fix (fixer) {
65+
const attributes = node.parent.attributes
66+
const shiftAttrs = attributes.slice(attributes.indexOf(previousNode), attributes.indexOf(node) + 1)
67+
68+
// If we can upgrade requirements to `eslint@>4.1.0`, this code can be replaced by:
69+
// return shiftAttrs.map((attr, i) => {
70+
// const text = attr === previousNode ? sourceCode.getText(node) : sourceCode.getText(shiftAttrs[i - 1])
71+
// return fixer.replaceText(attr, text)
72+
// })
73+
const replaceDataList = shiftAttrs.map((attr, i) => {
74+
const text = attr === previousNode ? sourceCode.getText(node) : sourceCode.getText(shiftAttrs[i - 1])
75+
return {
76+
range: attr.range,
77+
text
78+
}
79+
})
80+
const replaceRange = [previousNode.range[0], node.range[1]]
81+
let text = sourceCode.text.slice(replaceRange[0], replaceRange[1])
82+
replaceDataList.reverse().forEach((data) => {
83+
const textRange = data.range.map(r => r - replaceRange[0])
84+
text = text.slice(0, textRange[0]) + data.text + text.slice(textRange[1], text.length)
85+
})
86+
return fixer.replaceTextRange(replaceRange, text)
6287
}
6388
})
6489
}
@@ -85,7 +110,7 @@ module.exports = {
85110
description: 'enforce order of attributes',
86111
category: 'recommended'
87112
},
88-
fixable: null,
113+
fixable: 'code',
89114
schema: {
90115
type: 'array',
91116
properties: {

tests/lib/rules/attributes-order.js

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,48 @@ tester.run('attributes-order', rule, {
208208
'EVENTS',
209209
'CONTENT']
210210
}]
211+
},
212+
{
213+
filename: 'test.vue',
214+
code:
215+
`<template>
216+
<div
217+
v-if="!visible"
218+
v-for="item in items"
219+
v-once
220+
is="header"
221+
v-on:click="functionCall"
222+
ref="header"
223+
:prop="headerData"
224+
v-text="textContent"
225+
id="uniqueID"
226+
myProp="prop"
227+
>
228+
</div>
229+
</template>`,
230+
options: [
231+
{ order:
232+
[
233+
'CONDITIONALS',
234+
'LIST_RENDERING',
235+
'RENDER_MODIFIERS',
236+
'DEFINITION',
237+
'EVENTS',
238+
'UNIQUE',
239+
'BINDING',
240+
'CONTENT',
241+
'GLOBAL',
242+
'OTHER_ATTR'
243+
]
244+
}]
211245
}
212246
],
213247

214248
invalid: [
215249
{
216250
filename: 'test.vue',
217251
code: '<template><div v-cloak is="header"></div></template>',
252+
output: '<template><div is="header" v-cloak></div></template>',
218253
errors: [{
219254
message: 'Attribute "is" should go before "v-cloak".',
220255
type: 'VIdentifier'
@@ -223,6 +258,7 @@ tester.run('attributes-order', rule, {
223258
{
224259
filename: 'test.vue',
225260
code: '<template><div id="uniqueID" v-cloak></div></template>',
261+
output: '<template><div v-cloak id="uniqueID"></div></template>',
226262
errors: [{
227263
message: 'Attribute "v-cloak" should go before "id".',
228264
type: 'VDirectiveKey'
@@ -239,6 +275,15 @@ tester.run('attributes-order', rule, {
239275
:bindingProp="foo">
240276
</div>
241277
</template>`,
278+
output:
279+
`<template>
280+
<div
281+
v-model="toggle"
282+
model="baz"
283+
:bindingProp="foo"
284+
propOne="bar">
285+
</div>
286+
</template>`,
242287
errors: [{
243288
message: 'Attribute "v-model" should go before "model".',
244289
type: 'VDirectiveKey'
@@ -260,6 +305,16 @@ tester.run('attributes-order', rule, {
260305
propOne="bar">
261306
</div>
262307
</template>`,
308+
output:
309+
`<template>
310+
<div
311+
:bindingProp="foo"
312+
model="baz"
313+
v-model="toggle"
314+
v-on="functionCall"
315+
propOne="bar">
316+
</div>
317+
</template>`,
263318
errors: [{
264319
message: 'Attribute "v-model" should go before "v-on".',
265320
type: 'VDirectiveKey'
@@ -272,6 +327,7 @@ tester.run('attributes-order', rule, {
272327
{
273328
filename: 'test.vue',
274329
code: '<template><div data-id="foo" aria-test="bar" is="custom" myProp="prop"></div></template>',
330+
output: '<template><div data-id="foo" is="custom" aria-test="bar" myProp="prop"></div></template>',
275331
errors: [{
276332
message: 'Attribute "is" should go before "aria-test".',
277333
type: 'VIdentifier'
@@ -293,10 +349,167 @@ tester.run('attributes-order', rule, {
293349
'EVENTS',
294350
'CONTENT']
295351
}],
352+
output: '<template><div ref="header" is="header" propone="prop" ></div></template>',
296353
errors: [{
297354
message: 'Attribute "is" should go before "propone".',
298355
type: 'VIdentifier'
299356
}]
357+
},
358+
{
359+
filename: 'test.vue',
360+
code:
361+
`<template>
362+
<div v-cloak
363+
is="header">
364+
</div>
365+
</template>`,
366+
output:
367+
`<template>
368+
<div is="header"
369+
v-cloak>
370+
</div>
371+
</template>`,
372+
errors: [{
373+
message: 'Attribute "is" should go before "v-cloak".',
374+
type: 'VIdentifier'
375+
}]
376+
},
377+
{
378+
filename: 'test.vue',
379+
code:
380+
`<template>
381+
<div
382+
v-if="!visible"
383+
v-for="item in items"
384+
v-once
385+
is="header"
386+
v-on:click="functionCall"
387+
ref="header"
388+
:prop="headerData"
389+
v-text="textContent"
390+
id="uniqueID"
391+
myProp="prop"
392+
>
393+
</div>
394+
</template>`,
395+
output:
396+
`<template>
397+
<div
398+
v-for="item in items"
399+
v-if="!visible"
400+
is="header"
401+
v-once
402+
ref="header"
403+
v-on:click="functionCall"
404+
:prop="headerData"
405+
id="uniqueID"
406+
v-text="textContent"
407+
myProp="prop"
408+
>
409+
</div>
410+
</template>`,
411+
errors: [
412+
{
413+
message: 'Attribute "v-for" should go before "v-if".',
414+
type: 'VDirectiveKey'
415+
},
416+
{
417+
message: 'Attribute "is" should go before "v-once".',
418+
type: 'VIdentifier'
419+
},
420+
{
421+
message: 'Attribute "ref" should go before "v-on:click".',
422+
type: 'VIdentifier'
423+
},
424+
{
425+
message: 'Attribute ":prop" should go before "v-on:click".',
426+
type: 'VDirectiveKey'
427+
},
428+
{
429+
message: 'Attribute "id" should go before "v-text".',
430+
type: 'VIdentifier'
431+
},
432+
{
433+
message: 'Attribute "myProp" should go before "v-text".',
434+
type: 'VIdentifier'
435+
}
436+
]
437+
},
438+
{
439+
filename: 'test.vue',
440+
code:
441+
`<template>
442+
<div
443+
v-if="!visible"
444+
v-for="item in items"
445+
v-once
446+
is="header"
447+
v-on:click="functionCall"
448+
ref="header"
449+
:prop="headerData"
450+
v-text="textContent"
451+
id="uniqueID"
452+
myProp="prop"
453+
>
454+
</div>
455+
</template>`,
456+
options: [
457+
{ order:
458+
[
459+
'EVENTS',
460+
'BINDING',
461+
'UNIQUE',
462+
'DEFINITION',
463+
'CONDITIONALS',
464+
'LIST_RENDERING',
465+
'RENDER_MODIFIERS',
466+
'GLOBAL',
467+
'OTHER_ATTR',
468+
'CONTENT'
469+
]
470+
}],
471+
output:
472+
`<template>
473+
<div
474+
v-if="!visible"
475+
v-for="item in items"
476+
is="header"
477+
v-once
478+
v-on:click="functionCall"
479+
ref="header"
480+
:prop="headerData"
481+
id="uniqueID"
482+
v-text="textContent"
483+
myProp="prop"
484+
>
485+
</div>
486+
</template>`,
487+
errors: [
488+
{
489+
message: 'Attribute "is" should go before "v-once".',
490+
nodeType: 'VIdentifier'
491+
},
492+
{
493+
message: 'Attribute "v-on:click" should go before "v-once".',
494+
nodeType: 'VDirectiveKey'
495+
},
496+
{
497+
message: 'Attribute "ref" should go before "v-once".',
498+
nodeType: 'VIdentifier'
499+
},
500+
{
501+
message: 'Attribute ":prop" should go before "v-once".',
502+
nodeType: 'VDirectiveKey'
503+
},
504+
{
505+
message: 'Attribute "id" should go before "v-text".',
506+
nodeType: 'VIdentifier'
507+
},
508+
{
509+
message: 'Attribute "myProp" should go before "v-text".',
510+
nodeType: 'VIdentifier'
511+
}
512+
]
300513
}
301514
]
302515
})

0 commit comments

Comments
 (0)