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..376974b00 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,33 @@ 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
+
+
+
+
+
+
+
+
+```
+
+
## :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..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: {
@@ -15,7 +16,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 +38,31 @@ module.exports = {
},
/** @param {RuleContext} context */
create(context) {
+ const options = context.options[0] || {}
+ /** @type {Set} */
+ const allow = new Set(options.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) {
+ const componentName = node.rawName
+ return (
+ allow.has(componentName) ||
+ allow.has(casing.pascalCase(componentName)) ||
+ allow.has(casing.kebabCase(componentName))
+ )
+ }
+
/**
* 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..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
@@ -40,6 +40,25 @@ tester.run('no-v-text-v-html-on-component', rule, {
`
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+
+
+ `,
+ options: [{ allow: ['router-link'] }]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+
+
+
+ `,
+ options: [{ allow: ['RouterLink', 'nuxt-link'] }]
}
],
invalid: [
@@ -132,6 +151,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
+ }
+ ]
}
]
})