Skip to content

Commit 1ce68fa

Browse files
doug-wadeFloEdelmannota-meshi
authored
Add new rule: no-restricted-html-elements (#1820)
* Add new rule: html-forbid-elements * PR Feedback * Update lib/rules/no-restricted-html-elements.js Co-authored-by: Flo Edelmann <[email protected]> * Update docs/rules/no-restricted-html-elements.md Co-authored-by: Flo Edelmann <[email protected]> * Update lib/rules/no-restricted-html-elements.js Co-authored-by: Flo Edelmann <[email protected]> * Update tests/lib/rules/no-restricted-html-elements.js Co-authored-by: Yosuke Ota <[email protected]> * Update tests/lib/rules/no-restricted-html-elements.js Co-authored-by: Yosuke Ota <[email protected]> * Update tests/lib/rules/no-restricted-html-elements.js Co-authored-by: Yosuke Ota <[email protected]> * Update tests/lib/rules/no-restricted-html-elements.js Co-authored-by: Yosuke Ota <[email protected]> * Update tests/lib/rules/no-restricted-html-elements.js Co-authored-by: Yosuke Ota <[email protected]> * Update tests/lib/rules/no-restricted-html-elements.js Co-authored-by: Yosuke Ota <[email protected]> * Update docs/rules/no-restricted-html-elements.md Co-authored-by: Yosuke Ota <[email protected]> * Update tests/lib/rules/no-restricted-html-elements.js Co-authored-by: Yosuke Ota <[email protected]> * Update docs/rules/no-restricted-html-elements.md Co-authored-by: Flo Edelmann <[email protected]> * Update docs/rules/no-restricted-html-elements.md Co-authored-by: Flo Edelmann <[email protected]> * Update docs/rules/no-restricted-html-elements.md Co-authored-by: Flo Edelmann <[email protected]> * run npm update * Remove messages block * Update docs/rules/no-restricted-html-elements.md * Update docs/rules/no-restricted-html-elements.md * Fix demo site Co-authored-by: Flo Edelmann <[email protected]> Co-authored-by: Yosuke Ota <[email protected]>
1 parent f5f4f97 commit 1ce68fa

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
@@ -334,6 +334,7 @@ For example:
334334
| [vue/no-restricted-class](./no-restricted-class.md) | disallow specific classes in Vue components | |
335335
| [vue/no-restricted-component-options](./no-restricted-component-options.md) | disallow specific component option | |
336336
| [vue/no-restricted-custom-event](./no-restricted-custom-event.md) | disallow specific custom event | :bulb: |
337+
| [vue/no-restricted-html-elements](./no-restricted-html-elements.md) | disallow specific HTML elements | |
337338
| [vue/no-restricted-props](./no-restricted-props.md) | disallow specific props | :bulb: |
338339
| [vue/no-restricted-static-attribute](./no-restricted-static-attribute.md) | disallow specific attribute | |
339340
| [vue/no-restricted-v-bind](./no-restricted-v-bind.md) | disallow specific argument in `v-bind` | |
+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/no-restricted-html-elements
5+
description: disallow specific HTML elements
6+
---
7+
# vue/no-restricted-html-elements
8+
9+
> disallow specific HTML elements
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 allows you to specify HTML elements that you don't want to use in your application.
16+
17+
<eslint-code-block :rules="{'vue/no-restricted-html-elements': ['error', 'marquee', 'button'] }">
18+
19+
```vue
20+
<template>
21+
<!-- ✓ GOOD -->
22+
<p></p>
23+
<input />
24+
<br />
25+
26+
<!-- ✗ BAD -->
27+
<button></button>
28+
<marquee></marquee>
29+
</template>
30+
```
31+
32+
</eslint-code-block>
33+
34+
## :wrench: Options
35+
36+
This rule takes a list of strings, where each string is an HTML element name to be restricted:
37+
38+
```json
39+
{
40+
"vue/no-restricted-html-elements": ["error", "button", "marquee"]
41+
}
42+
```
43+
44+
<eslint-code-block :rules="{'vue/no-restricted-html-elements': ['error', 'button', 'marquee']}">
45+
46+
```vue
47+
<template>
48+
<!-- ✗ BAD -->
49+
<button></button>
50+
<marquee></marquee>
51+
</template>
52+
```
53+
54+
</eslint-code-block>
55+
56+
Alternatively, the rule also accepts objects.
57+
58+
```json
59+
{
60+
"vue/no-restricted-html-elements": [
61+
"error",
62+
{
63+
"element": "button",
64+
"message": "Prefer use of our custom <AppButton /> component"
65+
},
66+
{
67+
"element": "marquee",
68+
"message": "Do not use deprecated HTML tags"
69+
}
70+
]
71+
}
72+
```
73+
74+
The following properties can be specified for the object.
75+
76+
- `element` ... Specify the html element.
77+
- `message` ... Specify an optional custom message.
78+
79+
### `{ "element": "marquee" }, { "element": "button" }`
80+
81+
<eslint-code-block :rules="{'vue/no-restricted-html-elements': ['error', { element: 'marquee' }, { element: 'button' }]}">
82+
83+
```vue
84+
<template>
85+
<!-- ✗ BAD -->
86+
<marquee></marquee>
87+
<button></button>
88+
</template>
89+
```
90+
91+
</eslint-code-block>
92+
93+
## :mag: Implementation
94+
95+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-restricted-html-elements.js)
96+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-restricted-html-elements.js)

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ module.exports = {
113113
'no-restricted-class': require('./rules/no-restricted-class'),
114114
'no-restricted-component-options': require('./rules/no-restricted-component-options'),
115115
'no-restricted-custom-event': require('./rules/no-restricted-custom-event'),
116+
'no-restricted-html-elements': require('./rules/no-restricted-html-elements'),
116117
'no-restricted-props': require('./rules/no-restricted-props'),
117118
'no-restricted-static-attribute': require('./rules/no-restricted-static-attribute'),
118119
'no-restricted-syntax': require('./rules/no-restricted-syntax'),
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* @author Doug Wade <[email protected]>
3+
*/
4+
5+
'use strict'
6+
7+
const utils = require('../utils')
8+
9+
module.exports = {
10+
meta: {
11+
type: 'suggestion',
12+
docs: {
13+
description: 'disallow specific HTML elements',
14+
categories: undefined,
15+
url: 'https://eslint.vuejs.org/rules/no-restricted-html-elements.html'
16+
},
17+
fixable: null,
18+
schema: {
19+
type: 'array',
20+
items: {
21+
oneOf: [
22+
{ type: 'string' },
23+
{
24+
type: 'object',
25+
properties: {
26+
element: { type: 'string' },
27+
message: { type: 'string', minLength: 1 }
28+
},
29+
required: ['element'],
30+
additionalProperties: false
31+
}
32+
]
33+
},
34+
uniqueItems: true,
35+
minItems: 0
36+
}
37+
},
38+
/**
39+
* @param {RuleContext} context - The rule context.
40+
* @returns {RuleListener} AST event handlers.
41+
*/
42+
create(context) {
43+
return utils.defineTemplateBodyVisitor(context, {
44+
/**
45+
* @param {VElement} node
46+
*/
47+
VElement(node) {
48+
if (!utils.isHtmlElementNode(node)) {
49+
return
50+
}
51+
52+
context.options.forEach((option) => {
53+
const message =
54+
option.message ||
55+
`Unexpected use of forbidden HTML element ${node.rawName}.`
56+
const element = option.element || option
57+
58+
if (element === node.rawName) {
59+
context.report({
60+
message,
61+
node: node.startTag
62+
})
63+
}
64+
})
65+
}
66+
})
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @author Doug Wade
3+
*/
4+
'use strict'
5+
6+
const RuleTester = require('eslint').RuleTester
7+
const rule = require('../../../lib/rules/no-restricted-html-elements')
8+
9+
const tester = new RuleTester({
10+
parser: require.resolve('vue-eslint-parser'),
11+
parserOptions: { ecmaVersion: 2015 }
12+
})
13+
14+
tester.run('no-restricted-html-elements', rule, {
15+
valid: [
16+
{
17+
filename: 'test.vue',
18+
code: '',
19+
options: ['button']
20+
},
21+
{
22+
filename: 'test.vue',
23+
code: '<template><div class="foo"></div></template>',
24+
options: ['button']
25+
},
26+
{
27+
filename: 'test.vue',
28+
code: '<template><button type="button"></button></template>',
29+
options: ['div']
30+
},
31+
{
32+
filename: 'test.vue',
33+
code: '<template><div class="foo"><Button type="button"></Button></div></template>',
34+
options: ['button']
35+
}
36+
],
37+
invalid: [
38+
{
39+
filename: 'test.vue',
40+
code: '<template><div><button type="button"></button><div></template>',
41+
errors: [
42+
{
43+
message: 'Unexpected use of forbidden HTML element button.',
44+
line: 1,
45+
column: 16
46+
}
47+
],
48+
options: ['button']
49+
},
50+
{
51+
filename: 'test.vue',
52+
code: '<template><div class="foo"><button type="button"></button></div></template>',
53+
errors: [
54+
{
55+
message: 'Unexpected use of forbidden HTML element div.',
56+
line: 1,
57+
column: 11
58+
}
59+
],
60+
options: ['div']
61+
},
62+
{
63+
filename: 'test.vue',
64+
code: '<template><marquee>foo</marquee></template>',
65+
errors: [
66+
{
67+
message: 'Custom error',
68+
line: 1,
69+
column: 11
70+
}
71+
],
72+
options: [{ element: 'marquee', message: 'Custom error' }]
73+
}
74+
]
75+
})

0 commit comments

Comments
 (0)