Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita270df8

Browse files
feat: add slot-name-casing rule (#2620)
Co-authored-by: Flo Edelmann <git@flo-edelmann.de>
1 parentfdfffd6 commita270df8

File tree

6 files changed

+323
-3
lines changed

6 files changed

+323
-3
lines changed

‎docs/rules/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,9 @@ For example:
281281
|[vue/require-prop-comment](./require-prop-comment.md)| require props to have a comment||:hammer:|
282282
|[vue/require-typed-object-prop](./require-typed-object-prop.md)| enforce adding type declarations to object props|:bulb:|:hammer:|
283283
|[vue/require-typed-ref](./require-typed-ref.md)| require`ref` and`shallowRef` functions to be strongly typed||:hammer:|
284-
|[vue/restricted-component-names](./restricted-component-names.md)| enforce using only specificincomponent names||:warning:|
284+
|[vue/restricted-component-names](./restricted-component-names.md)| enforce using only specific component names||:warning:|
285285
|[vue/script-indent](./script-indent.md)| enforce consistent indentation in`<script>`|:wrench:|:lipstick:|
286+
|[vue/slot-name-casing](./slot-name-casing.md)| enforce specific casing for slot names||:hammer:|
286287
|[vue/sort-keys](./sort-keys.md)| enforce sort-keys in a manner that is compatible with order-in-components||:hammer:|
287288
|[vue/static-class-names-order](./static-class-names-order.md)| enforce static class names order|:wrench:|:hammer:|
288289
|[vue/v-for-delimiter-style](./v-for-delimiter-style.md)| enforce`v-for` directive's delimiter style|:wrench:|:lipstick:|

‎docs/rules/restricted-component-names.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
pageClass:rule-details
33
sidebarDepth:0
44
title:vue/restricted-component-names
5-
description:enforce using only specificincomponent names
5+
description:enforce using only specific component names
66
---
77

88
#vue/restricted-component-names
99

10-
>enforce using only specificincomponent names
10+
>enforce using only specific component names
1111
1212
-:exclamation: <badgetext="This rule has not been released yet."vertical="middle"type="error">_**This rule has not been released yet.**_ </badge>
1313

‎docs/rules/slot-name-casing.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
pageClass:rule-details
3+
sidebarDepth:0
4+
title:vue/slot-name-casing
5+
description:enforce specific casing for slot names
6+
---
7+
8+
#vue/slot-name-casing
9+
10+
>enforce specific casing for slot names
11+
12+
-:exclamation: <badgetext="This rule has not been released yet."vertical="middle"type="error">_**This rule has not been released yet.**_ </badge>
13+
14+
##:book: Rule Details
15+
16+
This rule enforces proper casing of slot names in Vue components.
17+
18+
<eslint-code-block:rules="{'vue/slot-name-casing': ['error']}">
19+
20+
```vue
21+
<template>
22+
<!-- ✓ GOOD -->
23+
<slot name="foo" />
24+
<slot name="fooBar" />
25+
26+
<!-- ✗ BAD -->
27+
<slot name="foo-bar" />
28+
<slot name="foo_bar" />
29+
<slot name="foo:bar" />
30+
</template>
31+
```
32+
33+
</eslint-code-block>
34+
35+
##:wrench: Options
36+
37+
```json
38+
{
39+
"vue/slot-name-casing": ["error","camelCase"| "kebab-case" | "singleword"]
40+
}
41+
```
42+
43+
-`"camelCase"` (default) ... Enforce slot name to be in camel case.
44+
-`"kebab-case"` ... Enforce slot name to be in kebab case.
45+
-`"singleword"` ... Enforce slot name to be a single word.
46+
47+
###`"kebab-case"`
48+
49+
<eslint-code-block:rules="{'vue/prop-name-casing': ['error', 'kebab-case']}">
50+
51+
```vue
52+
<template>
53+
<!-- ✓ GOOD -->
54+
<slot name="foo" />
55+
<slot name="foo-bar" />
56+
57+
<!-- ✗ BAD -->
58+
<slot name="fooBar" />
59+
<slot name="foo_bar" />
60+
<slot name="foo:bar" />
61+
</template>
62+
```
63+
64+
</eslint-code-block>
65+
66+
###`"singleword"`
67+
68+
<eslint-code-block:rules="{'vue/prop-name-casing': ['error', 'singleword']}">
69+
70+
```vue
71+
<template>
72+
<!-- ✓ GOOD -->
73+
<slot name="foo" />
74+
75+
<!-- ✗ BAD -->
76+
<slot name="foo-bar" />
77+
<slot name="fooBar" />
78+
<slot name="foo_bar" />
79+
<slot name="foo:bar" />
80+
</template>
81+
```
82+
83+
</eslint-code-block>
84+
85+
##:mag: Implementation
86+
87+
-[Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/slot-name-casing.js)
88+
-[Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/slot-name-casing.js)

‎lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ const plugin = {
237237
'script-indent':require('./rules/script-indent'),
238238
'script-setup-uses-vars':require('./rules/script-setup-uses-vars'),
239239
'singleline-html-element-content-newline':require('./rules/singleline-html-element-content-newline'),
240+
'slot-name-casing':require('./rules/slot-name-casing'),
240241
'sort-keys':require('./rules/sort-keys'),
241242
'space-in-parens':require('./rules/space-in-parens'),
242243
'space-infix-ops':require('./rules/space-infix-ops'),

‎lib/rules/slot-name-casing.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
*@author Wayne Zhang
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
constutils=require('../utils')
8+
constcasing=require('../utils/casing')
9+
10+
/**
11+
*@typedef { 'camelCase' | 'kebab-case' | 'singleword'} OptionType
12+
*@typedef { (str: string) => boolean} CheckerType
13+
*/
14+
15+
/**
16+
* Checks whether the given string is a single word.
17+
*@param {string} str
18+
*@return {boolean}
19+
*/
20+
functionisSingleWord(str){
21+
return/^[a-z]+$/u.test(str)
22+
}
23+
24+
/**@type {OptionType[]} */
25+
constallowedCaseOptions=['camelCase','kebab-case','singleword']
26+
27+
module.exports={
28+
meta:{
29+
type:'suggestion',
30+
docs:{
31+
description:'enforce specific casing for slot names',
32+
categories:undefined,
33+
url:'https://eslint.vuejs.org/rules/slot-name-casing.html'
34+
},
35+
fixable:null,
36+
schema:[
37+
{
38+
enum:allowedCaseOptions
39+
}
40+
],
41+
messages:{
42+
invalidCase:'Slot name "{{name}}" is not {{caseType}}.'
43+
}
44+
},
45+
/**@param {RuleContext} context */
46+
create(context){
47+
constoption=context.options[0]
48+
49+
/**@type {OptionType} */
50+
constcaseType=allowedCaseOptions.includes(option) ?option :'camelCase'
51+
52+
/**@type {CheckerType} */
53+
constchecker=
54+
caseType==='singleword' ?isSingleWord :casing.getChecker(caseType)
55+
56+
/**@param {VAttribute} node */
57+
functionprocessSlotNode(node){
58+
constname=node.value?.value
59+
if(name&&!checker(name)){
60+
context.report({
61+
node,
62+
loc:node.loc,
63+
messageId:'invalidCase',
64+
data:{
65+
name,
66+
caseType
67+
}
68+
})
69+
}
70+
}
71+
72+
returnutils.defineTemplateBodyVisitor(context,{
73+
/**@param {VElement} node */
74+
"VElement[name='slot']"(node){
75+
constslotName=utils.getAttribute(node,'name')
76+
if(slotName){
77+
processSlotNode(slotName)
78+
}
79+
}
80+
})
81+
}
82+
}

‎tests/lib/rules/slot-name-casing.js

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/**
2+
*@author WayneZhang
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
constRuleTester=require('../../eslint-compat').RuleTester
8+
construle=require('../../../lib/rules/slot-name-casing')
9+
10+
consttester=newRuleTester({
11+
languageOptions:{
12+
parser:require('vue-eslint-parser'),
13+
ecmaVersion:2020,
14+
sourceType:'module'
15+
}
16+
})
17+
18+
tester.run('slot-name-casing',rule,{
19+
valid:[
20+
`<template><slot key="foo" /></template>`,
21+
`<template><slot name /></template>`,
22+
`<template><slot name="foo" /></template>`,
23+
`<template><slot name="fooBar" /></template>`,
24+
`<template><slot :name="fooBar" /></template>`,
25+
{
26+
filename:'test.vue',
27+
code:`
28+
<template>
29+
<slot name="foo" />
30+
<slot name="foo-bar" />
31+
<slot :name="fooBar" />
32+
</template>
33+
`,
34+
options:['kebab-case']
35+
},
36+
{
37+
filename:'test.vue',
38+
code:`
39+
<template>
40+
<slot name="foo" />
41+
<slot :name="fooBar" />
42+
</template>
43+
`,
44+
options:['singleword']
45+
}
46+
],
47+
invalid:[
48+
{
49+
filename:'test.vue',
50+
code:`
51+
<template>
52+
<slot name="foo-bar" />
53+
<slot name="foo-Bar_baz" />
54+
</template>
55+
`,
56+
errors:[
57+
{
58+
messageId:'invalidCase',
59+
data:{
60+
name:'foo-bar',
61+
caseType:'camelCase'
62+
},
63+
line:3,
64+
column:17
65+
},
66+
{
67+
messageId:'invalidCase',
68+
data:{
69+
name:'foo-Bar_baz',
70+
caseType:'camelCase'
71+
},
72+
line:4,
73+
column:17
74+
}
75+
]
76+
},
77+
{
78+
filename:'test.vue',
79+
code:`
80+
<template>
81+
<slot name="fooBar" />
82+
<slot name="foo-Bar_baz" />
83+
</template>
84+
`,
85+
options:['kebab-case'],
86+
errors:[
87+
{
88+
messageId:'invalidCase',
89+
data:{
90+
name:'fooBar',
91+
caseType:'kebab-case'
92+
},
93+
line:3,
94+
column:17
95+
},
96+
{
97+
messageId:'invalidCase',
98+
data:{
99+
name:'foo-Bar_baz',
100+
caseType:'kebab-case'
101+
},
102+
line:4,
103+
column:17
104+
}
105+
]
106+
},
107+
{
108+
filename:'test.vue',
109+
code:`
110+
<template>
111+
<slot name="foo-bar" />
112+
<slot name="fooBar" />
113+
<slot name="foo-Bar_baz" />
114+
</template>
115+
`,
116+
options:['singleword'],
117+
errors:[
118+
{
119+
messageId:'invalidCase',
120+
data:{
121+
name:'foo-bar',
122+
caseType:'singleword'
123+
},
124+
line:3,
125+
column:17
126+
},
127+
{
128+
messageId:'invalidCase',
129+
data:{
130+
name:'fooBar',
131+
caseType:'singleword'
132+
},
133+
line:4,
134+
column:17
135+
},
136+
{
137+
messageId:'invalidCase',
138+
data:{
139+
name:'foo-Bar_baz',
140+
caseType:'singleword'
141+
},
142+
line:5,
143+
column:17
144+
}
145+
]
146+
}
147+
]
148+
})

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp