Skip to content

Commit ae34c65

Browse files
authored
Add vue/no-v-text-v-html-on-component rule (#1760)
* Add `vue/no-v-text-v-html-on-component` rule * add test case
1 parent 9c6910e commit ae34c65

File tree

5 files changed

+241
-0
lines changed

5 files changed

+241
-0
lines changed

docs/rules/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ For example:
349349
| [vue/no-use-computed-property-like-method](./no-use-computed-property-like-method.md) | disallow use computed property like method | |
350350
| [vue/no-useless-mustaches](./no-useless-mustaches.md) | disallow unnecessary mustache interpolations | :wrench: |
351351
| [vue/no-useless-v-bind](./no-useless-v-bind.md) | disallow unnecessary `v-bind` directives | :wrench: |
352+
| [vue/no-v-text-v-html-on-component](./no-v-text-v-html-on-component.md) | disallow v-text / v-html on component | |
352353
| [vue/no-v-text](./no-v-text.md) | disallow use of v-text | |
353354
| [vue/padding-line-between-blocks](./padding-line-between-blocks.md) | require or disallow padding lines between blocks | :wrench: |
354355
| [vue/prefer-separate-static-class](./prefer-separate-static-class.md) | require static class names in template to be in a separate `class` attribute | :wrench: |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-v-text-v-html-on-component
5+
description: disallow v-text / v-html on component
6+
---
7+
# vue/no-v-text-v-html-on-component
8+
9+
> disallow v-text / v-html on component
10+
11+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge>
12+
13+
## :book: Rule Details
14+
15+
This rule disallows the use of v-text / v-html on component.
16+
17+
If you use v-text / v-html on a component, it will overwrite the component's content and may break the component.
18+
19+
<eslint-code-block :rules="{'vue/no-v-text-v-html-on-component': ['error']}">
20+
21+
```vue
22+
<template>
23+
<!-- ✓ GOOD -->
24+
<div v-text="content"></div>
25+
<div v-html="html"></div>
26+
<MyComponent>{{content}}</MyComponent>
27+
28+
<!-- ✗ BAD -->
29+
<MyComponent v-text="content"></MyComponent>
30+
<MyComponent v-html="html"></MyComponent>
31+
</template>
32+
```
33+
34+
</eslint-code-block>
35+
36+
## :wrench: Options
37+
38+
Nothing.
39+
40+
## :mag: Implementation
41+
42+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-v-text-v-html-on-component.js)
43+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-v-text-v-html-on-component.js)

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ module.exports = {
145145
'no-v-for-template-key': require('./rules/no-v-for-template-key'),
146146
'no-v-html': require('./rules/no-v-html'),
147147
'no-v-model-argument': require('./rules/no-v-model-argument'),
148+
'no-v-text-v-html-on-component': require('./rules/no-v-text-v-html-on-component'),
148149
'no-v-text': require('./rules/no-v-text'),
149150
'no-watch-after-await': require('./rules/no-watch-after-await'),
150151
'object-curly-newline': require('./rules/object-curly-newline'),
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* @author Yosuke Ota
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const utils = require('../utils')
12+
13+
// ------------------------------------------------------------------------------
14+
// Rule Definition
15+
// ------------------------------------------------------------------------------
16+
17+
module.exports = {
18+
meta: {
19+
type: 'problem',
20+
docs: {
21+
description: 'disallow v-text / v-html on component',
22+
// TODO We will change it in the next major version.
23+
// categories: ['essential', 'vue3-essential'],
24+
categories: undefined,
25+
url: 'https://eslint.vuejs.org/rules/no-v-text-v-html-on-component.html'
26+
},
27+
fixable: null,
28+
schema: [],
29+
messages: {
30+
disallow:
31+
"Using {{directiveName}} on component may break component's content."
32+
}
33+
},
34+
/** @param {RuleContext} context */
35+
create(context) {
36+
/**
37+
* Verify for v-text and v-html directive
38+
* @param {VDirective} node
39+
*/
40+
function verify(node) {
41+
const element = node.parent.parent
42+
if (utils.isCustomComponent(element)) {
43+
context.report({
44+
node,
45+
loc: node.loc,
46+
messageId: 'disallow',
47+
data: {
48+
directiveName: `v-${node.key.name.name}`
49+
}
50+
})
51+
}
52+
}
53+
54+
return utils.defineTemplateBodyVisitor(context, {
55+
"VAttribute[directive=true][key.name.name='text']": verify,
56+
"VAttribute[directive=true][key.name.name='html']": verify
57+
})
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/**
2+
* @author Yosuke Ota
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
'use strict'
6+
7+
const RuleTester = require('eslint').RuleTester
8+
const rule = require('../../../lib/rules/no-v-text-v-html-on-component')
9+
10+
const tester = new RuleTester({
11+
parser: require.resolve('vue-eslint-parser'),
12+
parserOptions: {
13+
ecmaVersion: 2020,
14+
sourceType: 'module'
15+
}
16+
})
17+
18+
tester.run('no-v-text-v-html-on-component', rule, {
19+
valid: [
20+
{
21+
filename: 'test.vue',
22+
code: `
23+
<template>
24+
<div v-text="content" />
25+
</template>
26+
`
27+
},
28+
{
29+
filename: 'test.vue',
30+
code: `
31+
<template>
32+
<div v-html="content" />
33+
</template>
34+
`
35+
},
36+
{
37+
filename: 'test.vue',
38+
code: `
39+
<template>
40+
<MyComponent v-if="content" />
41+
</template>
42+
`
43+
}
44+
],
45+
invalid: [
46+
{
47+
filename: 'test.vue',
48+
code: `
49+
<template>
50+
<MyComponent v-text="content" />
51+
</template>
52+
`,
53+
errors: [
54+
{
55+
message: "Using v-text on component may break component's content.",
56+
line: 3,
57+
column: 22
58+
}
59+
]
60+
},
61+
{
62+
filename: 'test.vue',
63+
code: `
64+
<template>
65+
<MyComponent v-html="content" />
66+
</template>
67+
`,
68+
errors: [
69+
{
70+
message: "Using v-html on component may break component's content.",
71+
line: 3,
72+
column: 22
73+
}
74+
]
75+
},
76+
{
77+
filename: 'test.vue',
78+
code: `
79+
<template>
80+
<component :is="component" v-text="content" />
81+
</template>
82+
`,
83+
errors: [
84+
{
85+
message: "Using v-text on component may break component's content.",
86+
line: 3,
87+
column: 36
88+
}
89+
]
90+
},
91+
{
92+
filename: 'test.vue',
93+
code: `
94+
<template>
95+
<component :is="component" v-html="content" />
96+
</template>
97+
`,
98+
errors: [
99+
{
100+
message: "Using v-html on component may break component's content.",
101+
line: 3,
102+
column: 36
103+
}
104+
]
105+
},
106+
{
107+
filename: 'test.vue',
108+
code: `
109+
<template>
110+
<div :is="component" v-text="content" />
111+
</template>
112+
`,
113+
errors: [
114+
{
115+
message: "Using v-text on component may break component's content.",
116+
line: 3,
117+
column: 30
118+
}
119+
]
120+
},
121+
{
122+
filename: 'test.vue',
123+
code: `
124+
<template>
125+
<div :is="component" v-html="content" />
126+
</template>
127+
`,
128+
errors: [
129+
{
130+
message: "Using v-html on component may break component's content.",
131+
line: 3,
132+
column: 30
133+
}
134+
]
135+
}
136+
]
137+
})

0 commit comments

Comments
 (0)