From 94868a3060637440391b5f937c8861e6d3f4bc9b Mon Sep 17 00:00:00 2001 From: waynzh Date: Sat, 2 Dec 2023 17:14:14 +0800 Subject: [PATCH 1/3] feat(no-v-text-v-html-on-component): add `allow` option --- docs/rules/no-v-text-v-html-on-component.md | 36 ++++++++++++++++++- lib/rules/no-v-text-v-html-on-component.js | 33 +++++++++++++++-- .../rules/no-v-text-v-html-on-component.js | 26 ++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/docs/rules/no-v-text-v-html-on-component.md b/docs/rules/no-v-text-v-html-on-component.md index 420eefda6..6f1d9a609 100644 --- a/docs/rules/no-v-text-v-html-on-component.md +++ b/docs/rules/no-v-text-v-html-on-component.md @@ -36,7 +36,41 @@ If you use v-text / v-html on a component, it will overwrite the component's con ## :wrench: Options -Nothing. +```json +{ + "vue/no-v-text-v-html-on-component": [ + "error", + { "allow": ["router-link", "nuxt-link"] } + ] +} +``` + +- `allow` (`string[]`) ... Specify a list of custom components for which the rule should not apply. + +### `{ "allow": ["router-link", "nuxt-link"] }` + + + +```vue + + +``` + + + + + +```vue + + +``` + + ## :rocket: Version diff --git a/lib/rules/no-v-text-v-html-on-component.js b/lib/rules/no-v-text-v-html-on-component.js index c517167f1..f2b4d9796 100644 --- a/lib/rules/no-v-text-v-html-on-component.js +++ b/lib/rules/no-v-text-v-html-on-component.js @@ -15,7 +15,21 @@ module.exports = { url: 'https://eslint.vuejs.org/rules/no-v-text-v-html-on-component.html' }, fixable: null, - schema: [], + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + }, + uniqueItems: true + } + }, + additionalProperties: false + } + ], messages: { disallow: "Using {{directiveName}} on component may break component's content." @@ -23,13 +37,28 @@ module.exports = { }, /** @param {RuleContext} context */ create(context) { + /** @type {string[]} */ + let allowedComponent = [] + if (context.options[0] && context.options[0].allow) { + allowedComponent = [...context.options[0].allow] + } + + /** + * Check whether the given node is an allowed component or not. + * @param {VElement} node The start tag node to check. + * @returns {boolean} `true` if the node is an allowed component. + */ + function isAllowedComponent(node) { + return allowedComponent.includes(node.rawName) + } + /** * Verify for v-text and v-html directive * @param {VDirective} node */ function verify(node) { const element = node.parent.parent - if (utils.isCustomComponent(element)) { + if (utils.isCustomComponent(element) && !isAllowedComponent(element)) { context.report({ node, loc: node.loc, diff --git a/tests/lib/rules/no-v-text-v-html-on-component.js b/tests/lib/rules/no-v-text-v-html-on-component.js index c50071346..3b3da28b3 100644 --- a/tests/lib/rules/no-v-text-v-html-on-component.js +++ b/tests/lib/rules/no-v-text-v-html-on-component.js @@ -40,6 +40,16 @@ tester.run('no-v-text-v-html-on-component', rule, { ` + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ allow: ['router-link', 'nuxt-link'] }] } ], invalid: [ @@ -132,6 +142,22 @@ tester.run('no-v-text-v-html-on-component', rule, { column: 30 } ] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ allow: ['nuxt-link'] }], + errors: [ + { + message: "Using v-html on component may break component's content.", + line: 3, + column: 22 + } + ] } ] }) From d185ac1f151f1a52d74bf2465f43232b97c139f9 Mon Sep 17 00:00:00 2001 From: waynzh Date: Tue, 5 Dec 2023 13:01:50 +0800 Subject: [PATCH 2/3] feat: support pascalcase --- lib/rules/no-v-text-v-html-on-component.js | 16 ++++++++++------ tests/lib/rules/no-v-text-v-html-on-component.js | 13 +++++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/lib/rules/no-v-text-v-html-on-component.js b/lib/rules/no-v-text-v-html-on-component.js index f2b4d9796..92289f6bb 100644 --- a/lib/rules/no-v-text-v-html-on-component.js +++ b/lib/rules/no-v-text-v-html-on-component.js @@ -5,6 +5,7 @@ 'use strict' const utils = require('../utils') +const casing = require('../utils/casing') module.exports = { meta: { @@ -37,11 +38,9 @@ module.exports = { }, /** @param {RuleContext} context */ create(context) { - /** @type {string[]} */ - let allowedComponent = [] - if (context.options[0] && context.options[0].allow) { - allowedComponent = [...context.options[0].allow] - } + const options = context.options[0] || {} + /** @type {Set} */ + const allow = new Set(options.allow) /** * Check whether the given node is an allowed component or not. @@ -49,7 +48,12 @@ module.exports = { * @returns {boolean} `true` if the node is an allowed component. */ function isAllowedComponent(node) { - return allowedComponent.includes(node.rawName) + const componentName = node.rawName + return ( + allow.has(componentName) || + allow.has(casing.pascalCase(componentName)) || + allow.has(casing.kebabCase(componentName)) + ) } /** diff --git a/tests/lib/rules/no-v-text-v-html-on-component.js b/tests/lib/rules/no-v-text-v-html-on-component.js index 3b3da28b3..1dafc17d8 100644 --- a/tests/lib/rules/no-v-text-v-html-on-component.js +++ b/tests/lib/rules/no-v-text-v-html-on-component.js @@ -41,15 +41,24 @@ tester.run('no-v-text-v-html-on-component', rule, { ` }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ allow: ['router-link'] }] + }, { filename: 'test.vue', code: ` `, - options: [{ allow: ['router-link', 'nuxt-link'] }] + options: [{ allow: ['RouterLink', 'nuxt-link'] }] } ], invalid: [ From 26bd2587a7cbccd447adf9cb54ccb65fff70ca1d Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 5 Dec 2023 13:03:00 +0800 Subject: [PATCH 3/3] Update docs/rules/no-v-text-v-html-on-component.md Co-authored-by: Flo Edelmann --- docs/rules/no-v-text-v-html-on-component.md | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/docs/rules/no-v-text-v-html-on-component.md b/docs/rules/no-v-text-v-html-on-component.md index 6f1d9a609..376974b00 100644 --- a/docs/rules/no-v-text-v-html-on-component.md +++ b/docs/rules/no-v-text-v-html-on-component.md @@ -52,21 +52,13 @@ If you use v-text / v-html on a component, it will overwrite the component's con ```vue - -``` - - - - - -```vue - - ```