Skip to content
5 changes: 5 additions & 0 deletions .changeset/purple-lights-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'eslint-plugin-vue': minor
---

Added `ignorePattern` option to [`vue/no-v-html`](https://eslint.vuejs.org/rules/no-v-html.html)
10 changes: 9 additions & 1 deletion docs/rules/no-v-html.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ This rule reports all uses of `v-html` directive in order to reduce the risk of

## :wrench: Options

Nothing.
```json
{
"vue/no-v-html": ["error", {
"ignorePattern": "/Html$"
}]
}
```

- `ignorePattern` ... disables reporting when the v-html directive references a variable matching this pattern. By default, all v-html uses are forbidden.

## :mute: When Not To Use It

Expand Down
25 changes: 24 additions & 1 deletion lib/rules/no-v-html.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
'use strict'
const utils = require('../utils')
const { toRegExp } = require('../utils/regexp')

module.exports = {
meta: {
Expand All @@ -14,16 +15,38 @@ module.exports = {
url: 'https://eslint.vuejs.org/rules/no-v-html.html'
},
fixable: null,
schema: [],
schema: [
{
type: 'object',
properties: {
ignorePattern: {
type: 'string'
}
},
additionalProperties: false
}
],
messages: {
unexpected: "'v-html' directive can lead to XSS attack."
}
},
/** @param {RuleContext} context */
create(context) {
const options = context.options[0]
const ignoredVarMatcher = options?.ignorePattern
? toRegExp(options.ignorePattern, { remove: 'g' })
: undefined

return utils.defineTemplateBodyVisitor(context, {
/** @param {VDirective} node */
"VAttribute[directive=true][key.name.name='html']"(node) {
if (
ignoredVarMatcher &&
node.value.expression.type === 'Identifier' &&
ignoredVarMatcher.test(node.value.expression.name)
) {
return
}
context.report({
node,
loc: node.loc,
Expand Down
11 changes: 11 additions & 0 deletions tests/lib/rules/no-v-html.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ ruleTester.run('no-v-html', rule, {
{
filename: 'test.vue',
code: '<template><div v-if="foo" v-bind="bar"></div></template>'
},
{
filename: 'test.vue',
code: '<template><div v-html="knownHtml"></div></template>',
options: [{ ignorePattern: '/^(?:html|.+Html)$/' }]
}
],
invalid: [
Expand All @@ -45,6 +50,12 @@ ruleTester.run('no-v-html', rule, {
filename: 'test.vue',
code: '<template><section v-html/></template>',
errors: ["'v-html' directive can lead to XSS attack."]
},
{
filename: 'test.vue',
code: '<template><div v-html="unsafeString"></div></template>',
options: [{ ignorePattern: '^(?:html|.+Html)$' }],
errors: ["'v-html' directive can lead to XSS attack."]
}
]
})