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 8e504d859..7d75eb9c9 100644 --- a/docs/rules/no-v-text-v-html-on-component.md +++ b/docs/rules/no-v-text-v-html-on-component.md @@ -25,11 +25,15 @@ If you use v-text / v-html on a component, it will overwrite the component's con
+ + {{ content }} + + ``` @@ -39,14 +43,15 @@ If you use v-text / v-html on a component, it will overwrite the component's con ```json { - "vue/no-v-text-v-html-on-component": [ - "error", - { "allow": ["router-link", "nuxt-link"] } - ] + "vue/no-v-text-v-html-on-component": ["error", { + "allow": ["router-link", "nuxt-link"], + "ignoreElementNamespaces": false + }] } ``` - `allow` (`string[]`) ... Specify a list of custom components for which the rule should not apply. +- `ignoreElementNamespaces` (`boolean`) ... If `true`, always treat SVG and MathML tag names as HTML elements, even if they are not used inside a SVG/MathML root element. Default is `false`. ### `{ "allow": ["router-link", "nuxt-link"] }` @@ -65,6 +70,20 @@ If you use v-text / v-html on a component, it will overwrite the component's con +### `{ "ignoreElementNamespaces": true }` + + + +```vue + +``` + + + ## :rocket: Version This rule was introduced in eslint-plugin-vue v8.4.0 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 50ef9c76e..e3f1f5409 100644 --- a/lib/rules/no-v-text-v-html-on-component.js +++ b/lib/rules/no-v-text-v-html-on-component.js @@ -26,6 +26,9 @@ module.exports = { type: 'string' }, uniqueItems: true + }, + ignoreElementNamespaces: { + type: 'boolean' } }, additionalProperties: false @@ -41,6 +44,8 @@ module.exports = { const options = context.options[0] || {} /** @type {Set} */ const allow = new Set(options.allow) + /** @type {boolean} */ + const ignoreElementNamespaces = options.ignoreElementNamespaces === true /** * Check whether the given node is an allowed component or not. @@ -62,7 +67,10 @@ module.exports = { */ function verify(node) { const element = node.parent.parent - if (utils.isCustomComponent(element) && !isAllowedComponent(element)) { + if ( + utils.isCustomComponent(element, ignoreElementNamespaces) && + !isAllowedComponent(element) + ) { context.report({ node, loc: node.loc, diff --git a/lib/utils/index.js b/lib/utils/index.js index 58cd32689..eb84c1279 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -941,19 +941,30 @@ module.exports = { /** * Check whether the given node is a custom component or not. * @param {VElement} node The start tag node to check. + * @param {boolean} [ignoreElementNamespaces=false] If `true`, ignore element namespaces. * @returns {boolean} `true` if the node is a custom component. */ - isCustomComponent(node) { - return ( - (this.isHtmlElementNode(node) && - !this.isHtmlWellKnownElementName(node.rawName)) || - (this.isSvgElementNode(node) && - !this.isSvgWellKnownElementName(node.rawName)) || - (this.isMathElementNode(node) && - !this.isMathWellKnownElementName(node.rawName)) || + isCustomComponent(node, ignoreElementNamespaces = false) { + if ( hasAttribute(node, 'is') || hasDirective(node, 'bind', 'is') || hasDirective(node, 'is') + ) { + return true + } + + const isHtmlName = this.isHtmlWellKnownElementName(node.rawName) + const isSvgName = this.isSvgWellKnownElementName(node.rawName) + const isMathName = this.isMathWellKnownElementName(node.rawName) + + if (ignoreElementNamespaces) { + return !isHtmlName && !isSvgName && !isMathName + } + + return ( + (this.isHtmlElementNode(node) && !isHtmlName) || + (this.isSvgElementNode(node) && !isSvgName) || + (this.isMathElementNode(node) && !isMathName) ) }, 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 ebf2901ba..bb403489e 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 @@ -59,6 +59,26 @@ tester.run('no-v-text-v-html-on-component', rule, { `, options: [{ allow: ['RouterLink', 'nuxt-link'] }] + }, + { + filename: 'test.vue', + code: ` + + ` + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ ignoreElementNamespaces: true }] } ], invalid: [ @@ -167,6 +187,28 @@ tester.run('no-v-text-v-html-on-component', rule, { column: 22 } ] + }, + { + filename: 'test.vue', + code: ` + + `, + options: [{ ignoreElementNamespaces: false }], + errors: [ + { + message: "Using v-text on component may break component's content.", + line: 3, + column: 12 + }, + { + message: "Using v-text on component may break component's content.", + line: 4, + column: 13 + } + ] } ] })