From 235076b3fe5c9273bffad6e1d1949d6c889a6e53 Mon Sep 17 00:00:00 2001 From: waynzh Date: Sat, 16 Nov 2024 14:05:15 +0800 Subject: [PATCH 1/7] feat: init rule --- docs/rules/index.md | 1 + docs/rules/valid-component-name.md | 35 ++++++++ lib/index.js | 1 + lib/rules/valid-component-name.js | 101 ++++++++++++++++++++++++ tests/lib/rules/valid-component-name.js | 78 ++++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 docs/rules/valid-component-name.md create mode 100644 lib/rules/valid-component-name.js create mode 100644 tests/lib/rules/valid-component-name.js diff --git a/docs/rules/index.md b/docs/rules/index.md index e359f47ab..6b8064217 100644 --- a/docs/rules/index.md +++ b/docs/rules/index.md @@ -287,6 +287,7 @@ For example: | [vue/v-for-delimiter-style](./v-for-delimiter-style.md) | enforce `v-for` directive's delimiter style | :wrench: | :lipstick: | | [vue/v-if-else-key](./v-if-else-key.md) | require key attribute for conditionally rendered repeated components | :wrench: | :warning: | | [vue/v-on-handler-style](./v-on-handler-style.md) | enforce writing style for handlers in `v-on` directives | :wrench: | :hammer: | +| [vue/valid-component-name](./valid-component-name.md) | enforce consistency in component names | | :warning: | | [vue/valid-define-options](./valid-define-options.md) | enforce valid `defineOptions` compiler macro | | :warning: | diff --git a/docs/rules/valid-component-name.md b/docs/rules/valid-component-name.md new file mode 100644 index 000000000..4058d6f24 --- /dev/null +++ b/docs/rules/valid-component-name.md @@ -0,0 +1,35 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/valid-component-name +description: enforce consistency in component names +--- + +# vue/valid-component-name + +> enforce consistency in component names + +- :exclamation: _**This rule has not been released yet.**_ + +## :book: Rule Details + +This rule .... + + + +```vue + +``` + + + +## :wrench: Options + +Nothing. + +## :mag: Implementation + +- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/valid-component-name.js) +- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/valid-component-name.js) diff --git a/lib/index.js b/lib/index.js index b09e247d5..087ece860 100644 --- a/lib/index.js +++ b/lib/index.js @@ -253,6 +253,7 @@ const plugin = { 'v-on-style': require('./rules/v-on-style'), 'v-slot-style': require('./rules/v-slot-style'), 'valid-attribute-name': require('./rules/valid-attribute-name'), + 'valid-component-name': require('./rules/valid-component-name'), 'valid-define-emits': require('./rules/valid-define-emits'), 'valid-define-options': require('./rules/valid-define-options'), 'valid-define-props': require('./rules/valid-define-props'), diff --git a/lib/rules/valid-component-name.js b/lib/rules/valid-component-name.js new file mode 100644 index 000000000..c209e1e7d --- /dev/null +++ b/lib/rules/valid-component-name.js @@ -0,0 +1,101 @@ +/** + * @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 RESERVED_NAMES_IN_VUE = new Set( + require('../utils/vue2-builtin-components') +) +const RESERVED_NAMES_IN_VUE3 = new Set( + require('../utils/vue3-builtin-components') +) +const kebabCaseElements = [ + 'annotation-xml', + 'color-profile', + 'font-face', + 'font-face-src', + 'font-face-uri', + 'font-face-format', + 'font-face-name', + 'missing-glyph' +] + +const RESERVED_NAMES_IN_HTML = new Set(htmlElements) +const RESERVED_NAMES_IN_OTHERS = new Set([ + ...deprecatedHtmlElements, + ...kebabCaseElements, + ...svgElements +]) + +const reservedNames = new Set([ + ...RESERVED_NAMES_IN_HTML, + ...RESERVED_NAMES_IN_VUE, + ...RESERVED_NAMES_IN_VUE3, + ...RESERVED_NAMES_IN_OTHERS +]) + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'enforce consistency in component names', + categories: undefined, + url: 'https://eslint.vuejs.org/rules/valid-component-name.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 valid.' + } + }, + /** @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 + } + }) + } + }) + } +} diff --git a/tests/lib/rules/valid-component-name.js b/tests/lib/rules/valid-component-name.js new file mode 100644 index 000000000..d1ab21170 --- /dev/null +++ b/tests/lib/rules/valid-component-name.js @@ -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/valid-component-name') + +const tester = new RuleTester({ + languageOptions: { + parser: require('vue-eslint-parser'), + ecmaVersion: 2020, + sourceType: 'module' + } +}) + +tester.run('valid-component-name', rule, { + valid: [ + '', + '', + { + filename: 'test.vue', + code: ` + + `, + options: [{ allow: ['/^foo-/', '/-bar$/'] }] + } + ], + invalid: [ + { + filename: 'test.vue', + code: ` + + `, + errors: [ + { + messageId: 'invalidName', + data: { name: 'Button' }, + line: 3 + }, + { + messageId: 'invalidName', + data: { name: 'foo-button' }, + line: 4 + } + ] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ allow: ['/^foo-/', 'bar'] }], + errors: [ + { + messageId: 'invalidName', + data: { name: 'bar-button' }, + line: 3 + }, + { + messageId: 'invalidName', + data: { name: 'foo' }, + line: 4 + } + ] + } + ] +}) From 3f1ea34a30eac12c7c605b8392224dcaae4442d1 Mon Sep 17 00:00:00 2001 From: waynzh Date: Sat, 16 Nov 2024 14:47:20 +0800 Subject: [PATCH 2/7] docs: update --- docs/rules/valid-component-name.md | 33 +++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/docs/rules/valid-component-name.md b/docs/rules/valid-component-name.md index 4058d6f24..223385b5c 100644 --- a/docs/rules/valid-component-name.md +++ b/docs/rules/valid-component-name.md @@ -13,13 +13,18 @@ description: enforce consistency in component names ## :book: Rule Details -This rule .... +This rule enforces consistency in component names. - + ```vue ``` @@ -27,7 +32,29 @@ This rule .... ## :wrench: Options -Nothing. +```json +{ + "vue/valid-component-name": ["error", { + "allow": [] + }] +} +``` + +### `"allow"` + + + +```vue + +``` + + ## :mag: Implementation From 148cc44bb5a27d05d25142f2e8006decb60bce41 Mon Sep 17 00:00:00 2001 From: waynzh Date: Wed, 20 Nov 2024 00:44:53 +0800 Subject: [PATCH 3/7] refactor: rename --- docs/rules/index.md | 2 +- docs/rules/no-restricted-component-names.md | 4 ++++ ...t-name.md => restricted-component-names.md} | 18 +++++++++++------- lib/index.js | 2 +- ...t-name.js => restricted-component-names.js} | 2 +- ...t-name.js => restricted-component-names.js} | 4 ++-- 6 files changed, 20 insertions(+), 12 deletions(-) rename docs/rules/{valid-component-name.md => restricted-component-names.md} (64%) rename lib/rules/{valid-component-name.js => restricted-component-names.js} (96%) rename tests/lib/rules/{valid-component-name.js => restricted-component-names.js} (92%) diff --git a/docs/rules/index.md b/docs/rules/index.md index 6b8064217..e68c97b85 100644 --- a/docs/rules/index.md +++ b/docs/rules/index.md @@ -281,13 +281,13 @@ 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 consistency in component names | | :warning: | | [vue/script-indent](./script-indent.md) | enforce consistent indentation in `