Skip to content

Commit a2865e4

Browse files
mchmurski-rmsota-meshi
authored andcommitted
static-class-names-order rule (#886)
* class-order rule * support ascii whitespace, add tests * polish readme * polish the rule file * update rule parser usage * alphabetize * npm run update * fix typo
1 parent e802d9e commit a2865e4

File tree

5 files changed

+171
-0
lines changed

5 files changed

+171
-0
lines changed

Diff for: docs/rules/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ For example:
160160
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: |
161161
| [vue/space-infix-ops](./space-infix-ops.md) | require spacing around infix operators | :wrench: |
162162
| [vue/space-unary-ops](./space-unary-ops.md) | enforce consistent spacing before or after unary operators | :wrench: |
163+
| [vue/static-class-names-order](./static-class-names-order.md) | enforce static class names order | :wrench: |
163164
| [vue/v-on-function-call](./v-on-function-call.md) | enforce or forbid parentheses after method calls without arguments in `v-on` directives | :wrench: |
164165
| [vue/v-slot-style](./v-slot-style.md) | enforce `v-slot` directive style | :wrench: |
165166
| [vue/valid-v-slot](./valid-v-slot.md) | enforce valid `v-slot` directives | |

Diff for: docs/rules/static-class-names-order.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/static-class-names-order
5+
description: enforce static class names order
6+
---
7+
# vue/static-class-names-order
8+
> enforce static class names order
9+
10+
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule.
11+
12+
### Example
13+
14+
<eslint-code-block fix :rules="{'vue/static-class-names-order': ['error']}">
15+
16+
```vue
17+
<template>
18+
<!-- ✓ GOOD -->
19+
<div class="a b"></div>
20+
21+
<!-- ✗ BAD -->
22+
<div class="b a"></div>
23+
</template>
24+
```
25+
26+
</eslint-code-block>
27+
28+
## :books: Further reading
29+
30+
- [static-class-names-order]
31+
32+
[static-class-names-order]: https://eslint.org/docs/rules/static-class-names-order
33+
34+
## :mag: Implementation
35+
36+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/static-class-names-order.js)
37+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/static-class-names-order.js)

Diff for: lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ module.exports = {
7070
'singleline-html-element-content-newline': require('./rules/singleline-html-element-content-newline'),
7171
'space-infix-ops': require('./rules/space-infix-ops'),
7272
'space-unary-ops': require('./rules/space-unary-ops'),
73+
'static-class-names-order': require('./rules/static-class-names-order'),
7374
'this-in-template': require('./rules/this-in-template'),
7475
'use-v-on-exact': require('./rules/use-v-on-exact'),
7576
'v-bind-style': require('./rules/v-bind-style'),

Diff for: lib/rules/static-class-names-order.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @fileoverview Alphabetizes static class names.
3+
* @author Maciej Chmurski
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const { defineTemplateBodyVisitor } = require('../utils')
12+
13+
// ------------------------------------------------------------------------------
14+
// Rule Definition
15+
// ------------------------------------------------------------------------------
16+
module.exports = {
17+
meta: {
18+
type: 'suggestion',
19+
docs: {
20+
url: 'https://eslint.vuejs.org/rules/static-class-names-order.html',
21+
description: 'enforce static class names order',
22+
category: undefined
23+
},
24+
fixable: 'code',
25+
schema: []
26+
},
27+
create: context => {
28+
return defineTemplateBodyVisitor(context, {
29+
"VAttribute[directive=false][key.name='class']" (node) {
30+
const classList = node.value.value
31+
const classListWithWhitespace = classList.split(/(\s+)/)
32+
33+
// Detect and reuse any type of whitespace.
34+
let divider = ''
35+
if (classListWithWhitespace.length > 1) {
36+
divider = classListWithWhitespace[1]
37+
}
38+
39+
const classListNoWhitespace = classListWithWhitespace.filter(className => className.trim() !== '')
40+
const classListSorted = classListNoWhitespace.sort().join(divider)
41+
42+
if (classList !== classListSorted) {
43+
context.report({
44+
node,
45+
loc: node.loc,
46+
message: 'Classes should be ordered alphabetically.',
47+
fix: (fixer) => fixer.replaceTextRange(
48+
[node.value.range[0], node.value.range[1]], `"${classListSorted}"`
49+
)
50+
})
51+
}
52+
}
53+
})
54+
}
55+
}

Diff for: tests/lib/rules/static-class-names-order.js

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* @fileoverview enforce ordering of classes
3+
* @author Maciej Chmurski
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
var rule = require('../../../lib/rules/static-class-names-order')
12+
var RuleTester = require('eslint').RuleTester
13+
14+
// ------------------------------------------------------------------------------
15+
// Tests
16+
// ------------------------------------------------------------------------------
17+
18+
var tester = new RuleTester({
19+
parser: require.resolve('vue-eslint-parser'),
20+
parserOptions: { ecmaVersion: 2015 }
21+
})
22+
tester.run('static-class-names-order', rule, {
23+
24+
valid: [
25+
{
26+
filename: 'no-classes.vue',
27+
code: '<template><div></div></template>'
28+
},
29+
{
30+
filename: 'one-class.vue',
31+
code: '<template><div class="a"></div></template>'
32+
},
33+
{
34+
filename: 'single-space.vue',
35+
code: '<template><div class="a b c"></div></template>'
36+
},
37+
{
38+
filename: 'multiple-spaces.vue',
39+
code: '<template><div class="a b c"></div></template>'
40+
},
41+
{
42+
filename: 'tabs.vue',
43+
code: '<template><div class="a b c"></div></template>'
44+
}
45+
],
46+
47+
invalid: [
48+
{
49+
filename: 'two-classes.vue',
50+
code: '<template><div class="b a"></div></template>',
51+
output: '<template><div class="a b"></div></template>',
52+
errors: [{
53+
message: 'Classes should be ordered alphabetically.',
54+
type: 'VAttribute'
55+
}]
56+
},
57+
{
58+
filename: 'three-classes.vue',
59+
code:
60+
`<template>
61+
<div class="c b a">
62+
</div>
63+
</template>`,
64+
output:
65+
`<template>
66+
<div class="a b c">
67+
</div>
68+
</template>`,
69+
errors: [
70+
{
71+
message: 'Classes should be ordered alphabetically.',
72+
type: 'VAttribute'
73+
}
74+
]
75+
}
76+
]
77+
})

0 commit comments

Comments
 (0)