Skip to content

Commit bed816b

Browse files
waynzhFloEdelmann
andauthored
feat: add restricted-component-names rule (#2611)
Co-authored-by: Flo Edelmann <[email protected]>
1 parent 9ddf3e5 commit bed816b

File tree

6 files changed

+230
-0
lines changed

6 files changed

+230
-0
lines changed

docs/rules/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ 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 specific in component names | | :warning: |
284285
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: | :lipstick: |
285286
| [vue/sort-keys](./sort-keys.md) | enforce sort-keys in a manner that is compatible with order-in-components | | :hammer: |
286287
| [vue/static-class-names-order](./static-class-names-order.md) | enforce static class names order | :wrench: | :hammer: |

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

+4
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ export default {
8484

8585
</eslint-code-block>
8686

87+
## :couple: Related Rules
88+
89+
- [vue/restricted-component-names](./restricted-component-names.md)
90+
8791
## :rocket: Version
8892

8993
This rule was introduced in eslint-plugin-vue v9.15.0
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/restricted-component-names
5+
description: enforce using only specific in component names
6+
---
7+
8+
# vue/restricted-component-names
9+
10+
> enforce using only specific in component names
11+
12+
- :exclamation: <badge text="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 consistency in component names.
17+
18+
<eslint-code-block :rules="{ 'vue/restricted-component-names': ['error'] }">
19+
20+
```vue
21+
<template>
22+
<!-- ✓ GOOD -->
23+
<button/>
24+
<keep-alive></keep-alive>
25+
26+
<!-- ✗ BAD -->
27+
<custom-component />
28+
</template>
29+
```
30+
31+
</eslint-code-block>
32+
33+
## :wrench: Options
34+
35+
```json
36+
{
37+
"vue/restricted-component-names": ["error", {
38+
"allow": []
39+
}]
40+
}
41+
```
42+
43+
### `"allow"`
44+
45+
<eslint-code-block :rules="{'vue/restricted-component-names': ['error', { 'allow': ['/^custom-/'] }]}">
46+
47+
```vue
48+
<template>
49+
<!-- ✓ GOOD -->
50+
<custom-component />
51+
52+
<!-- ✗ BAD -->
53+
<my-component />
54+
</template>
55+
```
56+
57+
</eslint-code-block>
58+
59+
## :couple: Related Rules
60+
61+
- [vue/no-restricted-component-names](./no-restricted-component-names.md)
62+
63+
## :mag: Implementation
64+
65+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/restricted-component-names.js)
66+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/restricted-component-names.js)

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ const plugin = {
231231
'require-typed-ref': require('./rules/require-typed-ref'),
232232
'require-v-for-key': require('./rules/require-v-for-key'),
233233
'require-valid-default-prop': require('./rules/require-valid-default-prop'),
234+
'restricted-component-names': require('./rules/restricted-component-names'),
234235
'return-in-computed-property': require('./rules/return-in-computed-property'),
235236
'return-in-emits-validator': require('./rules/return-in-emits-validator'),
236237
'script-indent': require('./rules/script-indent'),
+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* @author Wayne Zhang
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const utils = require('../utils')
8+
const { toRegExp } = require('../utils/regexp')
9+
10+
const htmlElements = require('../utils/html-elements.json')
11+
const deprecatedHtmlElements = require('../utils/deprecated-html-elements.json')
12+
const svgElements = require('../utils/svg-elements.json')
13+
const vue2builtinComponents = require('../utils/vue2-builtin-components')
14+
const vue3builtinComponents = require('../utils/vue3-builtin-components')
15+
16+
const reservedNames = new Set([
17+
...htmlElements,
18+
...deprecatedHtmlElements,
19+
...svgElements,
20+
...vue2builtinComponents,
21+
...vue3builtinComponents
22+
])
23+
24+
module.exports = {
25+
meta: {
26+
type: 'problem',
27+
docs: {
28+
description: 'enforce using only specific component names',
29+
categories: undefined,
30+
url: 'https://eslint.vuejs.org/rules/restricted-component-names.html'
31+
},
32+
fixable: null,
33+
schema: [
34+
{
35+
type: 'object',
36+
additionalProperties: false,
37+
properties: {
38+
allow: {
39+
type: 'array',
40+
items: { type: 'string' },
41+
uniqueItems: true,
42+
additionalItems: false
43+
}
44+
}
45+
}
46+
],
47+
messages: {
48+
invalidName: 'Component name "{{name}}" is not allowed.'
49+
}
50+
},
51+
/** @param {RuleContext} context */
52+
create(context) {
53+
const options = context.options[0] || {}
54+
/** @type {RegExp[]} */
55+
const allow = (options.allow || []).map(toRegExp)
56+
57+
/** @param {string} name */
58+
function isAllowedTarget(name) {
59+
return reservedNames.has(name) || allow.some((re) => re.test(name))
60+
}
61+
62+
return utils.defineTemplateBodyVisitor(context, {
63+
VElement(node) {
64+
const name = node.rawName
65+
if (isAllowedTarget(name)) {
66+
return
67+
}
68+
69+
context.report({
70+
node,
71+
loc: node.loc,
72+
messageId: 'invalidName',
73+
data: {
74+
name
75+
}
76+
})
77+
}
78+
})
79+
}
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @author Wayne Zhang
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const RuleTester = require('../../eslint-compat').RuleTester
8+
const rule = require('../../../lib/rules/restricted-component-names')
9+
10+
const tester = new RuleTester({
11+
languageOptions: {
12+
parser: require('vue-eslint-parser'),
13+
ecmaVersion: 2020,
14+
sourceType: 'module'
15+
}
16+
})
17+
18+
tester.run('restricted-component-names', rule, {
19+
valid: [
20+
'<template><keep-alive></keep-alive></template>',
21+
'<template><button/></template>',
22+
{
23+
filename: 'test.vue',
24+
code: `
25+
<template>
26+
<foo-button/>
27+
<div-bar/>
28+
</template>
29+
`,
30+
options: [{ allow: ['/^foo-/', '/-bar$/'] }]
31+
}
32+
],
33+
invalid: [
34+
{
35+
filename: 'test.vue',
36+
code: `
37+
<template>
38+
<Button/>
39+
<foo-button/>
40+
</template>
41+
`,
42+
errors: [
43+
{
44+
messageId: 'invalidName',
45+
data: { name: 'Button' },
46+
line: 3
47+
},
48+
{
49+
messageId: 'invalidName',
50+
data: { name: 'foo-button' },
51+
line: 4
52+
}
53+
]
54+
},
55+
{
56+
filename: 'test.vue',
57+
code: `
58+
<template>
59+
<bar-button/>
60+
<foo/>
61+
</template>
62+
`,
63+
options: [{ allow: ['/^foo-/', 'bar'] }],
64+
errors: [
65+
{
66+
messageId: 'invalidName',
67+
data: { name: 'bar-button' },
68+
line: 3
69+
},
70+
{
71+
messageId: 'invalidName',
72+
data: { name: 'foo' },
73+
line: 4
74+
}
75+
]
76+
}
77+
]
78+
})

0 commit comments

Comments
 (0)