Skip to content

Commit 8502971

Browse files
committed
Add name-casing rule.
1 parent 1d00dd6 commit 8502971

File tree

3 files changed

+241
-0
lines changed

3 files changed

+241
-0
lines changed

docs/rules/name-casing.md

+37
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

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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.executeOnVueComponent(context, (obj) => {
44+
const node = obj.properties
45+
.filter(item => item.type === 'Property' && item.key.name === 'name' && item.value.type === 'Literal')[0]
46+
if (node) {
47+
const value = convertCase(node.value.value, caseType)
48+
if (value !== node.value.value) {
49+
context.report({
50+
node: node.value,
51+
message: 'Property name "{{value}}" is not {{caseType}}.',
52+
data: {
53+
value: node.value.value,
54+
caseType: caseType
55+
},
56+
fix: fixer => fixer.replaceText(node.value, node.value.raw.replace(node.value.value, value))
57+
})
58+
}
59+
}
60+
})
61+
}
62+
63+
module.exports = {
64+
meta: {
65+
docs: {
66+
description: 'Name property casing for consistency purposes',
67+
category: 'Stylistic Issues',
68+
recommended: false
69+
},
70+
fixable: 'code', // or "code" or "whitespace"
71+
schema: [
72+
{
73+
enum: ['camelCase', 'kebab-case', 'PascalCase']
74+
}
75+
]
76+
},
77+
78+
create
79+
}

tests/lib/rules/name-casing.js

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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+
}
27+
`,
28+
options: ['camelCase'],
29+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
30+
},
31+
{
32+
filename: 'test.vue',
33+
code: `
34+
export default {
35+
name: 'fooBar'
36+
}
37+
`,
38+
options: ['camelCase'],
39+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
40+
},
41+
{
42+
filename: 'test.vue',
43+
code: `
44+
export default {
45+
name: 'FooBar'
46+
}
47+
`,
48+
options: ['PascalCase'],
49+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
50+
},
51+
{
52+
filename: 'test.vue',
53+
code: `
54+
export default {
55+
name: 'foo-bar'
56+
}
57+
`,
58+
options: ['kebab-case'],
59+
parserOptions: { ecmaVersion: 6, sourceType: 'module' }
60+
}
61+
],
62+
63+
invalid: [
64+
{
65+
filename: 'test.vue',
66+
code: `
67+
export default {
68+
name: 'foo-bar'
69+
}
70+
`,
71+
options: ['camelCase'],
72+
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
73+
errors: [{
74+
message: 'Property name "foo-bar" is not camelCase.',
75+
type: 'Literal',
76+
line: 3
77+
}]
78+
},
79+
{
80+
filename: 'test.vue',
81+
code: `
82+
export default {
83+
name: 'foo bar'
84+
}
85+
`,
86+
options: ['PascalCase'],
87+
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
88+
errors: [{
89+
message: 'Property name "foo bar" is not PascalCase.',
90+
type: 'Literal',
91+
line: 3
92+
}]
93+
},
94+
{
95+
filename: 'test.vue',
96+
code: `
97+
export default {
98+
name: 'foo!bar'
99+
}
100+
`,
101+
options: ['camelCase'],
102+
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
103+
errors: [{
104+
message: 'Property name "foo!bar" is not camelCase.',
105+
type: 'Literal',
106+
line: 3
107+
}]
108+
},
109+
{
110+
filename: 'test.js',
111+
code: `
112+
new Vue({
113+
name: 'foo!bar'
114+
})
115+
`,
116+
options: ['camelCase'],
117+
parserOptions: { ecmaVersion: 6 },
118+
errors: [{
119+
message: 'Property name "foo!bar" is not camelCase.',
120+
type: 'Literal',
121+
line: 3
122+
}]
123+
}
124+
]
125+
})

0 commit comments

Comments
 (0)