Skip to content

Commit

Permalink
static-class-names-order rule (#886)
Browse files Browse the repository at this point in the history
* class-order rule

* support ascii whitespace, add tests

* polish readme

* polish the rule file

* update rule parser usage

* alphabetize

* npm run update

* fix typo
  • Loading branch information
mchmurski-rms authored and ota-meshi committed Dec 26, 2019
1 parent e802d9e commit a2865e4
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/rules/README.md
Expand Up @@ -160,6 +160,7 @@ For example:
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: |
| [vue/space-infix-ops](./space-infix-ops.md) | require spacing around infix operators | :wrench: |
| [vue/space-unary-ops](./space-unary-ops.md) | enforce consistent spacing before or after unary operators | :wrench: |
| [vue/static-class-names-order](./static-class-names-order.md) | enforce static class names order | :wrench: |
| [vue/v-on-function-call](./v-on-function-call.md) | enforce or forbid parentheses after method calls without arguments in `v-on` directives | :wrench: |
| [vue/v-slot-style](./v-slot-style.md) | enforce `v-slot` directive style | :wrench: |
| [vue/valid-v-slot](./valid-v-slot.md) | enforce valid `v-slot` directives | |
Expand Down
37 changes: 37 additions & 0 deletions docs/rules/static-class-names-order.md
@@ -0,0 +1,37 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/static-class-names-order
description: enforce static class names order
---
# vue/static-class-names-order
> enforce static class names order
- :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.

### Example

<eslint-code-block fix :rules="{'vue/static-class-names-order': ['error']}">

```vue
<template>
<!-- ✓ GOOD -->
<div class="a b"></div>
<!-- ✗ BAD -->
<div class="b a"></div>
</template>
```

</eslint-code-block>

## :books: Further reading

- [static-class-names-order]

[static-class-names-order]: https://eslint.org/docs/rules/static-class-names-order

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/static-class-names-order.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/static-class-names-order.js)
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -70,6 +70,7 @@ module.exports = {
'singleline-html-element-content-newline': require('./rules/singleline-html-element-content-newline'),
'space-infix-ops': require('./rules/space-infix-ops'),
'space-unary-ops': require('./rules/space-unary-ops'),
'static-class-names-order': require('./rules/static-class-names-order'),
'this-in-template': require('./rules/this-in-template'),
'use-v-on-exact': require('./rules/use-v-on-exact'),
'v-bind-style': require('./rules/v-bind-style'),
Expand Down
55 changes: 55 additions & 0 deletions lib/rules/static-class-names-order.js
@@ -0,0 +1,55 @@
/**
* @fileoverview Alphabetizes static class names.
* @author Maciej Chmurski
*/
'use strict'

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

const { defineTemplateBodyVisitor } = require('../utils')

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
module.exports = {
meta: {
type: 'suggestion',
docs: {
url: 'https://eslint.vuejs.org/rules/static-class-names-order.html',
description: 'enforce static class names order',
category: undefined
},
fixable: 'code',
schema: []
},
create: context => {
return defineTemplateBodyVisitor(context, {
"VAttribute[directive=false][key.name='class']" (node) {
const classList = node.value.value
const classListWithWhitespace = classList.split(/(\s+)/)

// Detect and reuse any type of whitespace.
let divider = ''
if (classListWithWhitespace.length > 1) {
divider = classListWithWhitespace[1]
}

const classListNoWhitespace = classListWithWhitespace.filter(className => className.trim() !== '')
const classListSorted = classListNoWhitespace.sort().join(divider)

if (classList !== classListSorted) {
context.report({
node,
loc: node.loc,
message: 'Classes should be ordered alphabetically.',
fix: (fixer) => fixer.replaceTextRange(
[node.value.range[0], node.value.range[1]], `"${classListSorted}"`
)
})
}
}
})
}
}
77 changes: 77 additions & 0 deletions tests/lib/rules/static-class-names-order.js
@@ -0,0 +1,77 @@
/**
* @fileoverview enforce ordering of classes
* @author Maciej Chmurski
*/
'use strict'

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

var rule = require('../../../lib/rules/static-class-names-order')
var RuleTester = require('eslint').RuleTester

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

var tester = new RuleTester({
parser: require.resolve('vue-eslint-parser'),
parserOptions: { ecmaVersion: 2015 }
})
tester.run('static-class-names-order', rule, {

valid: [
{
filename: 'no-classes.vue',
code: '<template><div></div></template>'
},
{
filename: 'one-class.vue',
code: '<template><div class="a"></div></template>'
},
{
filename: 'single-space.vue',
code: '<template><div class="a b c"></div></template>'
},
{
filename: 'multiple-spaces.vue',
code: '<template><div class="a b c"></div></template>'
},
{
filename: 'tabs.vue',
code: '<template><div class="a b c"></div></template>'
}
],

invalid: [
{
filename: 'two-classes.vue',
code: '<template><div class="b a"></div></template>',
output: '<template><div class="a b"></div></template>',
errors: [{
message: 'Classes should be ordered alphabetically.',
type: 'VAttribute'
}]
},
{
filename: 'three-classes.vue',
code:
`<template>
<div class="c b a">
</div>
</template>`,
output:
`<template>
<div class="a b c">
</div>
</template>`,
errors: [
{
message: 'Classes should be ordered alphabetically.',
type: 'VAttribute'
}
]
}
]
})

0 comments on commit a2865e4

Please sign in to comment.