Skip to content

Commit

Permalink
feat: add restricted-component-names rule (#2611)
Browse files Browse the repository at this point in the history
Co-authored-by: Flo Edelmann <[email protected]>
  • Loading branch information
waynzh and FloEdelmann authored Nov 27, 2024
1 parent 9ddf3e5 commit bed816b
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ For example:
| [vue/require-prop-comment](./require-prop-comment.md) | require props to have a comment | | :hammer: |
| [vue/require-typed-object-prop](./require-typed-object-prop.md) | enforce adding type declarations to object props | :bulb: | :hammer: |
| [vue/require-typed-ref](./require-typed-ref.md) | require `ref` and `shallowRef` functions to be strongly typed | | :hammer: |
| [vue/restricted-component-names](./restricted-component-names.md) | enforce using only specific in component names | | :warning: |
| [vue/script-indent](./script-indent.md) | enforce consistent indentation in `<script>` | :wrench: | :lipstick: |
| [vue/sort-keys](./sort-keys.md) | enforce sort-keys in a manner that is compatible with order-in-components | | :hammer: |
| [vue/static-class-names-order](./static-class-names-order.md) | enforce static class names order | :wrench: | :hammer: |
Expand Down
4 changes: 4 additions & 0 deletions docs/rules/no-restricted-component-names.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export default {

</eslint-code-block>

## :couple: Related Rules

- [vue/restricted-component-names](./restricted-component-names.md)

## :rocket: Version

This rule was introduced in eslint-plugin-vue v9.15.0
Expand Down
66 changes: 66 additions & 0 deletions docs/rules/restricted-component-names.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/restricted-component-names
description: enforce using only specific in component names
---

# vue/restricted-component-names

> enforce using only specific in component names
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> _**This rule has not been released yet.**_ </badge>

## :book: Rule Details

This rule enforces consistency in component names.

<eslint-code-block :rules="{ 'vue/restricted-component-names': ['error'] }">

```vue
<template>
<!-- ✓ GOOD -->
<button/>
<keep-alive></keep-alive>
<!-- ✗ BAD -->
<custom-component />
</template>
```

</eslint-code-block>

## :wrench: Options

```json
{
"vue/restricted-component-names": ["error", {
"allow": []
}]
}
```

### `"allow"`

<eslint-code-block :rules="{'vue/restricted-component-names': ['error', { 'allow': ['/^custom-/'] }]}">

```vue
<template>
<!-- ✓ GOOD -->
<custom-component />
<!-- ✗ BAD -->
<my-component />
</template>
```

</eslint-code-block>

## :couple: Related Rules

- [vue/no-restricted-component-names](./no-restricted-component-names.md)

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/restricted-component-names.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/restricted-component-names.js)
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ const plugin = {
'require-typed-ref': require('./rules/require-typed-ref'),
'require-v-for-key': require('./rules/require-v-for-key'),
'require-valid-default-prop': require('./rules/require-valid-default-prop'),
'restricted-component-names': require('./rules/restricted-component-names'),
'return-in-computed-property': require('./rules/return-in-computed-property'),
'return-in-emits-validator': require('./rules/return-in-emits-validator'),
'script-indent': require('./rules/script-indent'),
Expand Down
80 changes: 80 additions & 0 deletions lib/rules/restricted-component-names.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* @author Wayne Zhang
* See LICENSE file in root directory for full license.
*/
'use strict'

const utils = require('../utils')
const { toRegExp } = require('../utils/regexp')

const htmlElements = require('../utils/html-elements.json')
const deprecatedHtmlElements = require('../utils/deprecated-html-elements.json')
const svgElements = require('../utils/svg-elements.json')
const vue2builtinComponents = require('../utils/vue2-builtin-components')
const vue3builtinComponents = require('../utils/vue3-builtin-components')

const reservedNames = new Set([
...htmlElements,
...deprecatedHtmlElements,
...svgElements,
...vue2builtinComponents,
...vue3builtinComponents
])

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'enforce using only specific component names',
categories: undefined,
url: 'https://eslint.vuejs.org/rules/restricted-component-names.html'
},
fixable: null,
schema: [
{
type: 'object',
additionalProperties: false,
properties: {
allow: {
type: 'array',
items: { type: 'string' },
uniqueItems: true,
additionalItems: false
}
}
}
],
messages: {
invalidName: 'Component name "{{name}}" is not allowed.'
}
},
/** @param {RuleContext} context */
create(context) {
const options = context.options[0] || {}
/** @type {RegExp[]} */
const allow = (options.allow || []).map(toRegExp)

/** @param {string} name */
function isAllowedTarget(name) {
return reservedNames.has(name) || allow.some((re) => re.test(name))
}

return utils.defineTemplateBodyVisitor(context, {
VElement(node) {
const name = node.rawName
if (isAllowedTarget(name)) {
return
}

context.report({
node,
loc: node.loc,
messageId: 'invalidName',
data: {
name
}
})
}
})
}
}
78 changes: 78 additions & 0 deletions tests/lib/rules/restricted-component-names.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* @author Wayne Zhang
* See LICENSE file in root directory for full license.
*/
'use strict'

const RuleTester = require('../../eslint-compat').RuleTester
const rule = require('../../../lib/rules/restricted-component-names')

const tester = new RuleTester({
languageOptions: {
parser: require('vue-eslint-parser'),
ecmaVersion: 2020,
sourceType: 'module'
}
})

tester.run('restricted-component-names', rule, {
valid: [
'<template><keep-alive></keep-alive></template>',
'<template><button/></template>',
{
filename: 'test.vue',
code: `
<template>
<foo-button/>
<div-bar/>
</template>
`,
options: [{ allow: ['/^foo-/', '/-bar$/'] }]
}
],
invalid: [
{
filename: 'test.vue',
code: `
<template>
<Button/>
<foo-button/>
</template>
`,
errors: [
{
messageId: 'invalidName',
data: { name: 'Button' },
line: 3
},
{
messageId: 'invalidName',
data: { name: 'foo-button' },
line: 4
}
]
},
{
filename: 'test.vue',
code: `
<template>
<bar-button/>
<foo/>
</template>
`,
options: [{ allow: ['/^foo-/', 'bar'] }],
errors: [
{
messageId: 'invalidName',
data: { name: 'bar-button' },
line: 3
},
{
messageId: 'invalidName',
data: { name: 'foo' },
line: 4
}
]
}
]
})

0 comments on commit bed816b

Please sign in to comment.