From cf966be6d5eb7b6b2d23012cc769cbcbc80e6ffc Mon Sep 17 00:00:00 2001 From: waynzh Date: Fri, 5 Sep 2025 16:24:50 +0800 Subject: [PATCH 1/4] feat(component-name-in-template-casing): `global` option support regex --- .../component-name-in-template-casing.md | 12 ++- .../component-name-in-template-casing.js | 24 +++-- .../component-name-in-template-casing.js | 95 +++++++++++++++++++ 3 files changed, 122 insertions(+), 9 deletions(-) diff --git a/docs/rules/component-name-in-template-casing.md b/docs/rules/component-name-in-template-casing.md index dd59d40e4..cc5a4256a 100644 --- a/docs/rules/component-name-in-template-casing.md +++ b/docs/rules/component-name-in-template-casing.md @@ -34,7 +34,7 @@ This rule aims to warn the tag names other than the configured casing in Vue.js - `registeredComponentsOnly` ... If `true`, only registered components (in PascalCase) are checked. If `false`, check all. default `true` - `ignores` (`string[]`) ... The element names to ignore. Sets the element name to allow. For example, custom elements or Vue components with special name. You can set the regexp by writing it like `"/^name/"`. -- `globals` (`string[]`) ... Globally registered component names to check. For example, `RouterView` and `RouterLink` are globally registered by `vue-router` and can't be detected as registered in a SFC file. +- `globals` (`string[]`) ... Globally registered component names to check. For example, `RouterView` and `RouterLink` are globally registered by `vue-router` and can't be detected as registered in a SFC file. You can set the regexp by writing it like `"/^c-/"` to match component names with patterns. ### `"PascalCase", { registeredComponentsOnly: true }` (default) @@ -143,17 +143,23 @@ export default { -### `"PascalCase", { globals: ["RouterView"] }` +### `"PascalCase", { globals: ["RouterView", "/^c-/"] }` - + ```vue ``` diff --git a/lib/rules/component-name-in-template-casing.js b/lib/rules/component-name-in-template-casing.js index c7267cd49..fe3fd5ff8 100644 --- a/lib/rules/component-name-in-template-casing.js +++ b/lib/rules/component-name-in-template-casing.js @@ -6,7 +6,7 @@ const utils = require('../utils') const casing = require('../utils/casing') -const { toRegExpGroupMatcher } = require('../utils/regexp') +const { toRegExpGroupMatcher, isRegExp } = require('../utils/regexp') const allowedCaseOptions = ['PascalCase', 'kebab-case'] const defaultCase = 'PascalCase' @@ -82,8 +82,18 @@ module.exports = { ? caseOption : defaultCase const isIgnored = toRegExpGroupMatcher(options.ignores) - /** @type {string[]} */ - const globals = (options.globals || []).map(casing.pascalCase) + + const globalStrings = [] + const globalPatterns = [] + for (const global of options.globals || []) { + if (isRegExp(global)) { + globalPatterns.push(global) + } else { + globalStrings.push(global) + } + } + + const isGlobalPattern = toRegExpGroupMatcher(globalPatterns) const registeredComponentsOnly = options.registeredComponentsOnly !== false const sourceCode = context.getSourceCode() const tokens = @@ -91,7 +101,7 @@ module.exports = { sourceCode.parserServices.getTemplateBodyTokenStore() /** @type { Set } */ - const registeredComponents = new Set(globals) + const registeredComponents = new Set(globalStrings.map(casing.pascalCase)) if (utils.isScriptSetup(context)) { // For setup> @@ -137,8 +147,10 @@ module.exports = { return true } - // We only verify the registered components. - return registeredComponents.has(casing.pascalCase(node.rawName)) + return ( + registeredComponents.has(casing.pascalCase(node.rawName)) || + isGlobalPattern(node.rawName) + ) } let hasInvalidEOF = false diff --git a/tests/lib/rules/component-name-in-template-casing.js b/tests/lib/rules/component-name-in-template-casing.js index 02ab287f6..ea66bca41 100644 --- a/tests/lib/rules/component-name-in-template-casing.js +++ b/tests/lib/rules/component-name-in-template-casing.js @@ -202,6 +202,21 @@ tester.run('component-name-in-template-casing', rule, { options: ['kebab-case', { globals: ['RouterView', 'router-link'] }] }, + // globals with regex patterns + { + code: ` + + `, + options: ['kebab-case', { globals: ['/^c-/', 'other-component'] }] + }, + // type-only imports ...(semver.gte( require('@typescript-eslint/parser/package.json').version, @@ -1223,6 +1238,86 @@ tester.run('component-name-in-template-casing', rule, { } ] }, + { + code: ` + + `, + output: ` + + `, + options: ['PascalCase', { globals: ['/^c-/'] }], + errors: [ + { + message: 'Component name "c-button" is not PascalCase.', + line: 3, + column: 11, + endLine: 3, + endColumn: 20 + }, + { + message: 'Component name "c-card" is not PascalCase.', + line: 4, + column: 11, + endLine: 4, + endColumn: 18 + }, + { + message: 'Component name "c-input" is not PascalCase.', + line: 5, + column: 11, + endLine: 5, + endColumn: 19 + } + ] + }, + { + code: ` + + `, + output: ` + + `, + options: ['kebab-case', { globals: ['/^C[A-Z]/', '/^c-/'] }], + errors: [ + { + message: 'Component name "CButton" is not kebab-case.', + line: 3, + column: 11, + endLine: 3, + endColumn: 19 + }, + { + message: 'Component name "CCard" is not kebab-case.', + line: 4, + column: 11, + endLine: 4, + endColumn: 17 + }, + { + message: 'Component name "CInput" is not kebab-case.', + line: 5, + column: 11, + endLine: 5, + endColumn: 18 + } + ] + }, // type-only imports ...(semver.gte( require('@typescript-eslint/parser/package.json').version, From a4c2384e7a4fde64c6efd32b5612c793865bb70e Mon Sep 17 00:00:00 2001 From: waynzh Date: Fri, 5 Sep 2025 16:25:02 +0800 Subject: [PATCH 2/4] chore: add changeset --- .changeset/rude-heads-serve.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rude-heads-serve.md diff --git a/.changeset/rude-heads-serve.md b/.changeset/rude-heads-serve.md new file mode 100644 index 000000000..b611a8c5d --- /dev/null +++ b/.changeset/rude-heads-serve.md @@ -0,0 +1,5 @@ +--- +'eslint-plugin-vue': minor +--- + +Changed vue/component-name-in-template-casing `globals` option to support regex patterns From b5c05c9bf95797ac5d100a0a138729f942f6f8d7 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Fri, 5 Sep 2025 17:24:47 +0800 Subject: [PATCH 3/4] Apply suggestion from @FloEdelmann Co-authored-by: Flo Edelmann --- .changeset/rude-heads-serve.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/rude-heads-serve.md b/.changeset/rude-heads-serve.md index b611a8c5d..861605ed7 100644 --- a/.changeset/rude-heads-serve.md +++ b/.changeset/rude-heads-serve.md @@ -2,4 +2,4 @@ 'eslint-plugin-vue': minor --- -Changed vue/component-name-in-template-casing `globals` option to support regex patterns +Changed `vue/component-name-in-template-casing` `globals` option to support regex patterns From 80f2630b70e44e9f862087480956c270dfd1fdd6 Mon Sep 17 00:00:00 2001 From: waynzh Date: Fri, 5 Sep 2025 17:25:19 +0800 Subject: [PATCH 4/4] update test --- .../rules/component-name-in-template-casing.js | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/tests/lib/rules/component-name-in-template-casing.js b/tests/lib/rules/component-name-in-template-casing.js index ea66bca41..34e3574fc 100644 --- a/tests/lib/rules/component-name-in-template-casing.js +++ b/tests/lib/rules/component-name-in-template-casing.js @@ -1243,7 +1243,7 @@ tester.run('component-name-in-template-casing', rule, { `, output: ` @@ -1268,13 +1268,6 @@ tester.run('component-name-in-template-casing', rule, { column: 11, endLine: 4, endColumn: 18 - }, - { - message: 'Component name "c-input" is not PascalCase.', - line: 5, - column: 11, - endLine: 5, - endColumn: 19 } ] }, @@ -1283,7 +1276,7 @@ tester.run('component-name-in-template-casing', rule, { `, output: ` @@ -1308,13 +1301,6 @@ tester.run('component-name-in-template-casing', rule, { column: 11, endLine: 4, endColumn: 17 - }, - { - message: 'Component name "CInput" is not kebab-case.', - line: 5, - column: 11, - endLine: 5, - endColumn: 18 } ] },

AltStyle によって変換されたページ (->オリジナル) /