Skip to content

Commit 7fcce24

Browse files
committed
Add name-casing rule.
1 parent ce99b72 commit 7fcce24

File tree

3 files changed

+214
-0
lines changed

3 files changed

+214
-0
lines changed

docs/rules/name-casing.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Name property casing for consistency purposes (name-casing)
2+
3+
Define a style for the `name` property casing for consistency purposes
4+
5+
## :book: Rule Details
6+
7+
:+1: Examples of **correct** code for `PascalCase`:
8+
9+
```js
10+
export default {
11+
name: 'MyComponent'
12+
}
13+
```
14+
15+
:+1: Examples of **correct** code for `kebab-case`:
16+
17+
```js
18+
export default {
19+
name: 'my-component'
20+
}
21+
```
22+
23+
:+1: Examples of **correct** code for `camelCase`:
24+
25+
```js
26+
export default {
27+
name: 'myComponent'
28+
}
29+
```
30+
31+
## :wrench: Options
32+
33+
Default casing is set to `PascalCase`
34+
35+
```
36+
'vue/name-casing': [2, 'camelCase'|'kebab-case'|'PascalCase']
37+
```

lib/rules/name-casing.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @fileoverview Name property casing for consistency purposes
3+
* @author Armano
4+
*/
5+
'use strict'
6+
7+
const utils = require('../utils')
8+
9+
function kebabCase (str) {
10+
return str.replace(/([a-z])([A-Z])/g, match => match[0] + '-' + match[1]).replace(/\s+/g, '-').toLowerCase()
11+
}
12+
13+
function camelCase (str) {
14+
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => index === 0 ? letter.toLowerCase() : letter.toUpperCase()).replace(/[\s-]+/g, '')
15+
}
16+
17+
function pascalCase (str) {
18+
str = camelCase(str)
19+
return str.length > 0 ? str.charAt(0).toUpperCase() + str.slice(1) : ''
20+
}
21+
22+
function convertCase (str, caseType) {
23+
if (caseType === 'kebab-case') {
24+
return kebabCase(str)
25+
} else if (caseType === 'PascalCase') {
26+
return pascalCase(str)
27+
}
28+
return camelCase(str)
29+
}
30+
31+
// ------------------------------------------------------------------------------
32+
// Rule Definition
33+
// ------------------------------------------------------------------------------
34+
35+
function create (context) {
36+
const options = context.options[0]
37+
const caseType = ['camelCase', 'kebab-case', 'PascalCase'].indexOf(options) !== -1 ? options : 'PascalCase'
38+
39+
// ----------------------------------------------------------------------
40+
// Public
41+
// ----------------------------------------------------------------------
42+
43+
return utils.executeOnVueInstance(context, properties => {
44+
const node = properties.filter(item => item.type === 'Property' && item.key.name === 'name' && item.value.type === 'Literal')[0]
45+
if (node) {
46+
const value = convertCase(node.value.value, caseType)
47+
if (value !== node.value.value) {
48+
context.report({
49+
node: node.value,
50+
message: 'Property name "{{value}}" is not {{caseType}}.',
51+
data: {
52+
value: node.value.value,
53+
caseType: caseType
54+
},
55+
fix: fixer => fixer.replaceText(node.value, node.value.raw.replace(node.value.value, value))
56+
})
57+
}
58+
}
59+
})
60+
}
61+
62+
module.exports = {
63+
meta: {
64+
docs: {
65+
description: 'Name property casing for consistency purposes',
66+
category: 'Stylistic Issues',
67+
recommended: false
68+
},
69+
fixable: 'code', // or "code" or "whitespace"
70+
schema: [
71+
{
72+
enum: ['camelCase', 'kebab-case', 'PascalCase']
73+
}
74+
]
75+
},
76+
77+
create
78+
}

tests/lib/rules/name-casing.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* @fileoverview Define a style for the name property casing for consistency purposes
3+
* @author Armano
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const rule = require('../../../lib/rules/name-casing')
12+
const RuleTester = require('eslint').RuleTester
13+
14+
// ------------------------------------------------------------------------------
15+
// Tests
16+
// ------------------------------------------------------------------------------
17+
18+
const ruleTester = new RuleTester()
19+
ruleTester.run('name-casing', rule, {
20+
21+
valid: [
22+
{
23+
filename: 'test.vue',
24+
code: `
25+
export default {
26+
name: 'fooBar'
27+
}
28+
`,
29+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
30+
},
31+
{
32+
filename: 'test.vue',
33+
code: `
34+
export default {
35+
name: 'FooBar'
36+
}
37+
`,
38+
options: ['PascalCase'],
39+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
40+
},
41+
{
42+
filename: 'test.vue',
43+
code: `
44+
export default {
45+
name: 'foo-bar'
46+
}
47+
`,
48+
options: ['kebab-case'],
49+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
50+
}
51+
],
52+
53+
invalid: [
54+
{
55+
filename: 'test.vue',
56+
code: `
57+
export default {
58+
name: 'foo-bar'
59+
}
60+
`,
61+
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
62+
errors: [{
63+
message: 'Property name "foo-bar" is not camelCase.',
64+
type: 'Literal',
65+
line: 3
66+
}]
67+
},
68+
{
69+
filename: 'test.vue',
70+
code: `
71+
export default {
72+
name: 'foo bar'
73+
}
74+
`,
75+
options: ['PascalCase'],
76+
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
77+
errors: [{
78+
message: 'Property name "foo bar" is not PascalCase.',
79+
type: 'Literal',
80+
line: 3
81+
}]
82+
},
83+
{
84+
filename: 'test.vue',
85+
code: `
86+
export default {
87+
name: 'foo!bar'
88+
}
89+
`,
90+
options: ['camelCase'],
91+
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
92+
errors: [{
93+
message: 'Property name "foo!bar" is not camelCase.',
94+
type: 'Literal',
95+
line: 3
96+
}]
97+
}
98+
]
99+
})

0 commit comments

Comments
 (0)