Skip to content

Commit 16d6816

Browse files
authored
feat: add svelte/no-restricted-html-elements rule (#499)
1 parent e386e34 commit 16d6816

17 files changed

+377
-0
lines changed

.changeset/wise-flies-lay.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-svelte": minor
3+
---
4+
5+
feat: add `no-restricted-html-elements` rule

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
367367
| [svelte/max-attributes-per-line](https://sveltejs.github.io/eslint-plugin-svelte/rules/max-attributes-per-line/) | enforce the maximum number of attributes per line | :wrench: |
368368
| [svelte/mustache-spacing](https://sveltejs.github.io/eslint-plugin-svelte/rules/mustache-spacing/) | enforce unified spacing in mustache | :wrench: |
369369
| [svelte/no-extra-reactive-curlies](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-extra-reactive-curlies/) | disallow wrapping single reactive statements in curly braces | :bulb: |
370+
| [svelte/no-restricted-html-elements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-restricted-html-elements/) | disallow specific HTML elements | |
370371
| [svelte/no-spaces-around-equal-signs-in-attribute](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-spaces-around-equal-signs-in-attribute/) | disallow spaces around equal signs in attribute | :wrench: |
371372
| [svelte/prefer-class-directive](https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-class-directive/) | require class directives instead of ternary expressions | :wrench: |
372373
| [svelte/prefer-style-directive](https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-style-directive/) | require style directives instead of style attribute | :wrench: |

docs/rules.md

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
8080
| [svelte/max-attributes-per-line](./rules/max-attributes-per-line.md) | enforce the maximum number of attributes per line | :wrench: |
8181
| [svelte/mustache-spacing](./rules/mustache-spacing.md) | enforce unified spacing in mustache | :wrench: |
8282
| [svelte/no-extra-reactive-curlies](./rules/no-extra-reactive-curlies.md) | disallow wrapping single reactive statements in curly braces | :bulb: |
83+
| [svelte/no-restricted-html-elements](./rules/no-restricted-html-elements.md) | disallow specific HTML elements | |
8384
| [svelte/no-spaces-around-equal-signs-in-attribute](./rules/no-spaces-around-equal-signs-in-attribute.md) | disallow spaces around equal signs in attribute | :wrench: |
8485
| [svelte/prefer-class-directive](./rules/prefer-class-directive.md) | require class directives instead of ternary expressions | :wrench: |
8586
| [svelte/prefer-style-directive](./rules/prefer-style-directive.md) | require style directives instead of style attribute | :wrench: |
+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
pageClass: "rule-details"
3+
sidebarDepth: 0
4+
title: "svelte/no-restricted-html-elements"
5+
description: "disallow specific HTML elements"
6+
---
7+
8+
# svelte/no-restricted-html-elements
9+
10+
> disallow specific HTML elements
11+
12+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>
13+
14+
## :book: Rule Details
15+
16+
This rule reports to usage of resticted HTML elements.
17+
18+
<ESLintCodeBlock>
19+
20+
<!--eslint-skip-->
21+
22+
```svelte
23+
<script>
24+
/* eslint svelte/no-restricted-html-elements: ["error", "h1", "h2", "h3", "h4", "h5", "h6"] */
25+
</script>
26+
27+
<!-- ✓ GOOD -->
28+
<div>
29+
<p>Hi!</p>
30+
</div>
31+
32+
<!-- ✗ BAD -->
33+
<h1>foo</h1>
34+
35+
<div>
36+
<h2>bar</h2>
37+
</div>
38+
```
39+
40+
</ESLintCodeBlock>
41+
42+
---
43+
44+
<ESLintCodeBlock>
45+
46+
<!--eslint-skip-->
47+
48+
```svelte
49+
<script>
50+
/* eslint svelte/no-restricted-html-elements: ["error", { "elements": ["marquee"], "message": "Do not use deprecated HTML tags" }] */
51+
</script>
52+
53+
<!-- ✓ GOOD -->
54+
<div>
55+
<p>Hi!</p>
56+
</div>
57+
58+
<!-- ✗ BAD -->
59+
<marquee>foo</marquee>
60+
61+
<div>
62+
<marquee>bar</marquee>
63+
</div>
64+
```
65+
66+
</ESLintCodeBlock>
67+
68+
## :wrench: Options
69+
70+
This rule takes a list of strings, where each string is an HTML element name to be restricted:
71+
72+
```json
73+
{
74+
"svelte/no-restricted-html-elements": [
75+
"error",
76+
"h1",
77+
"h2",
78+
"h3",
79+
"h4",
80+
"h5",
81+
"h6"
82+
]
83+
}
84+
```
85+
86+
Alternatively, the rule also accepts objects.
87+
88+
```json
89+
{
90+
"svelte/no-restricted-html-elements": [
91+
"error",
92+
{
93+
"elements": ["h1", "h2", "h3", "h4", "h5", "h6"],
94+
"message": "Prefer use of our custom <Heading /> component"
95+
},
96+
{
97+
"elements": ["marquee"],
98+
"message": "Do not use deprecated HTML tags"
99+
}
100+
]
101+
}
102+
```
103+
104+
## :mag: Implementation
105+
106+
- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/src/rules/no-restricted-html-elements.ts)
107+
- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/tests/src/rules/no-restricted-html-elements.ts)
+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { createRule } from "../utils"
2+
3+
export default createRule("no-restricted-html-elements", {
4+
meta: {
5+
docs: {
6+
description: "disallow specific HTML elements",
7+
category: "Stylistic Issues",
8+
recommended: false,
9+
conflictWithPrettier: false,
10+
},
11+
schema: {
12+
type: "array",
13+
items: {
14+
oneOf: [
15+
{ type: "string" },
16+
{
17+
type: "object",
18+
properties: {
19+
elements: {
20+
type: "array",
21+
items: {
22+
type: ["string"],
23+
},
24+
uniqueItems: true,
25+
minItems: 1,
26+
},
27+
message: { type: "string", minLength: 1 },
28+
},
29+
additionalProperties: false,
30+
minItems: 1,
31+
},
32+
],
33+
},
34+
uniqueItems: true,
35+
minItems: 1,
36+
},
37+
messages: {},
38+
type: "suggestion",
39+
},
40+
create(context) {
41+
return {
42+
SvelteElement(node) {
43+
if (node.kind !== "html") return
44+
const { name } = node
45+
if (name.type !== "SvelteName") return
46+
for (const option of context.options) {
47+
const message =
48+
option.message ||
49+
`Unexpected use of forbidden HTML element ${name.name}.`
50+
const elements = option.elements || [option]
51+
for (const element of elements) {
52+
if (element === name.name) {
53+
context.report({
54+
message,
55+
node: node.startTag,
56+
})
57+
}
58+
}
59+
}
60+
},
61+
}
62+
},
63+
})

src/utils/rules.ts

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import noObjectInTextMustaches from "../rules/no-object-in-text-mustaches"
3434
import noReactiveFunctions from "../rules/no-reactive-functions"
3535
import noReactiveLiterals from "../rules/no-reactive-literals"
3636
import noReactiveReassign from "../rules/no-reactive-reassign"
37+
import noRestrictedHtmlElements from "../rules/no-restricted-html-elements"
3738
import noShorthandStylePropertyOverrides from "../rules/no-shorthand-style-property-overrides"
3839
import noSpacesAroundEqualSignsInAttribute from "../rules/no-spaces-around-equal-signs-in-attribute"
3940
import noStoreAsync from "../rules/no-store-async"
@@ -93,6 +94,7 @@ export const rules = [
9394
noReactiveFunctions,
9495
noReactiveLiterals,
9596
noReactiveReassign,
97+
noRestrictedHtmlElements,
9698
noShorthandStylePropertyOverrides,
9799
noSpacesAroundEqualSignsInAttribute,
98100
noStoreAsync,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": ["h1", "h2", "h3", "h4", "h5", "h6"]
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
- message: Unexpected use of forbidden HTML element h1.
2+
line: 1
3+
column: 1
4+
suggestions: null
5+
- message: Unexpected use of forbidden HTML element h2.
6+
line: 2
7+
column: 1
8+
suggestions: null
9+
- message: Unexpected use of forbidden HTML element h3.
10+
line: 3
11+
column: 1
12+
suggestions: null
13+
- message: Unexpected use of forbidden HTML element h4.
14+
line: 4
15+
column: 1
16+
suggestions: null
17+
- message: Unexpected use of forbidden HTML element h5.
18+
line: 5
19+
column: 1
20+
suggestions: null
21+
- message: Unexpected use of forbidden HTML element h6.
22+
line: 6
23+
column: 1
24+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<h1>Main Title - H1</h1>
2+
<h2>Subtitle - H2</h2>
3+
<h3>Subsection Title - H3</h3>
4+
<h4>Sub-Subsection Title - H4</h4>
5+
<h5>Minor Title - H5</h5>
6+
<h6>Minor Subtitle - H6</h6>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"options": [
3+
{
4+
"elements": ["h1", "h2", "h3", "h4", "h5", "h6"],
5+
"message": "Prefer use of our custom <Heading /> component"
6+
},
7+
{
8+
"elements": ["marquee"],
9+
"message": "Do not use deprecated HTML tags"
10+
}
11+
]
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
- message: Prefer use of our custom <Heading /> component
2+
line: 1
3+
column: 1
4+
suggestions: null
5+
- message: Prefer use of our custom <Heading /> component
6+
line: 2
7+
column: 1
8+
suggestions: null
9+
- message: Prefer use of our custom <Heading /> component
10+
line: 3
11+
column: 1
12+
suggestions: null
13+
- message: Prefer use of our custom <Heading /> component
14+
line: 4
15+
column: 1
16+
suggestions: null
17+
- message: Prefer use of our custom <Heading /> component
18+
line: 5
19+
column: 1
20+
suggestions: null
21+
- message: Prefer use of our custom <Heading /> component
22+
line: 6
23+
column: 1
24+
suggestions: null
25+
- message: Do not use deprecated HTML tags
26+
line: 8
27+
column: 1
28+
suggestions: null
29+
- message: Do not use deprecated HTML tags
30+
line: 10
31+
column: 1
32+
suggestions: null
33+
- message: Do not use deprecated HTML tags
34+
line: 12
35+
column: 1
36+
suggestions: null
37+
- message: Do not use deprecated HTML tags
38+
line: 19
39+
column: 3
40+
suggestions: null
41+
- message: Do not use deprecated HTML tags
42+
line: 23
43+
column: 3
44+
suggestions: null
45+
- message: Prefer use of our custom <Heading /> component
46+
line: 27
47+
column: 3
48+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<h1>Main Title - H1</h1>
2+
<h2>Subtitle - H2</h2>
3+
<h3>Subsection Title - H3</h3>
4+
<h4>Sub-Subsection Title - H4</h4>
5+
<h5>Minor Title - H5</h5>
6+
<h6>Minor Subtitle - H6</h6>
7+
8+
<marquee>This text will scroll from right to left</marquee>
9+
10+
<marquee direction="up">This text will scroll from bottom to top</marquee>
11+
12+
<marquee
13+
direction="down"
14+
width="250"
15+
height="200"
16+
behavior="alternate"
17+
style="border:solid"
18+
>
19+
<marquee behavior="alternate"> This text will bounce </marquee>
20+
</marquee>
21+
22+
<div>
23+
<marquee>This text will scroll from right to left</marquee>
24+
</div>
25+
26+
<div>
27+
<h6>Minor Subtitle - H6</h6>
28+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"options": ["h1", "h2", "h3", "h4", "h5", "h6"]
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<div style="font-size: 2em; font-weight: bold;">This is a title</div>
2+
<div style="font-size: 1.5em; font-weight: bold;">This is a subtitle</div>
3+
<p>This is a paragraph. Some sample text goes here.</p>
4+
<ul>
5+
<li>This is</li>
6+
<li>a list item</li>
7+
</ul>
8+
<table>
9+
<tr>
10+
<td>Table Cell 1</td>
11+
<td>Table Cell 2</td>
12+
</tr>
13+
<tr>
14+
<td>Table Cell 3</td>
15+
<td>Table Cell 4</td>
16+
</tr>
17+
</table>
18+
<a href="https://example.com">This is a hyperlink to example.com</a>
19+
<form>
20+
<label for="fname">First name:</label><br />
21+
<input type="text" id="fname" name="fname" /><br />
22+
<input type="submit" value="Submit" />
23+
</form>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"options": [
3+
{
4+
"elements": ["h1", "h2", "h3", "h4", "h5", "h6"],
5+
"message": "Prefer use of our custom <Heading /> component"
6+
},
7+
{
8+
"elements": ["marquee"],
9+
"message": "Do not use deprecated HTML tags"
10+
}
11+
]
12+
}

0 commit comments

Comments
 (0)