Skip to content

feat: add svelte/no-restricted-html-elements rule #499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wise-flies-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-svelte": minor
---

feat: add `no-restricted-html-elements` rule
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
| [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: |
| [svelte/mustache-spacing](https://sveltejs.github.io/eslint-plugin-svelte/rules/mustache-spacing/) | enforce unified spacing in mustache | :wrench: |
| [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: |
| [svelte/no-restricted-html-elements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-restricted-html-elements/) | disallow specific HTML elements | |
| [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: |
| [svelte/prefer-class-directive](https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-class-directive/) | require class directives instead of ternary expressions | :wrench: |
| [svelte/prefer-style-directive](https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-style-directive/) | require style directives instead of style attribute | :wrench: |
Expand Down
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
| [svelte/max-attributes-per-line](./rules/max-attributes-per-line.md) | enforce the maximum number of attributes per line | :wrench: |
| [svelte/mustache-spacing](./rules/mustache-spacing.md) | enforce unified spacing in mustache | :wrench: |
| [svelte/no-extra-reactive-curlies](./rules/no-extra-reactive-curlies.md) | disallow wrapping single reactive statements in curly braces | :bulb: |
| [svelte/no-restricted-html-elements](./rules/no-restricted-html-elements.md) | disallow specific HTML elements | |
| [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: |
| [svelte/prefer-class-directive](./rules/prefer-class-directive.md) | require class directives instead of ternary expressions | :wrench: |
| [svelte/prefer-style-directive](./rules/prefer-style-directive.md) | require style directives instead of style attribute | :wrench: |
Expand Down
107 changes: 107 additions & 0 deletions docs/rules/no-restricted-html-elements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
pageClass: "rule-details"
sidebarDepth: 0
title: "svelte/no-restricted-html-elements"
description: "disallow specific HTML elements"
---

# svelte/no-restricted-html-elements

> disallow specific HTML elements

- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>

## :book: Rule Details

This rule reports to usage of resticted HTML elements.

<ESLintCodeBlock>

<!--eslint-skip-->

```svelte
<script>
/* eslint svelte/no-restricted-html-elements: ["error", "h1", "h2", "h3", "h4", "h5", "h6"] */
</script>

<!-- ✓ GOOD -->
<div>
<p>Hi!</p>
</div>

<!-- ✗ BAD -->
<h1>foo</h1>

<div>
<h2>bar</h2>
</div>
```

</ESLintCodeBlock>

---

<ESLintCodeBlock>

<!--eslint-skip-->

```svelte
<script>
/* eslint svelte/no-restricted-html-elements: ["error", { "elements": ["marquee"], "message": "Do not use deprecated HTML tags" }] */
</script>

<!-- ✓ GOOD -->
<div>
<p>Hi!</p>
</div>

<!-- ✗ BAD -->
<marquee>foo</marquee>

<div>
<marquee>bar</marquee>
</div>
```

</ESLintCodeBlock>

## :wrench: Options

This rule takes a list of strings, where each string is an HTML element name to be restricted:

```json
{
"svelte/no-restricted-html-elements": [
"error",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6"
]
}
```

Alternatively, the rule also accepts objects.

```json
{
"svelte/no-restricted-html-elements": [
"error",
{
"elements": ["h1", "h2", "h3", "h4", "h5", "h6"],
"message": "Prefer use of our custom <Heading /> component"
},
{
"elements": ["marquee"],
"message": "Do not use deprecated HTML tags"
}
]
}
```

## :mag: Implementation

- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/src/rules/no-restricted-html-elements.ts)
- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/tests/src/rules/no-restricted-html-elements.ts)
63 changes: 63 additions & 0 deletions src/rules/no-restricted-html-elements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { createRule } from "../utils"

export default createRule("no-restricted-html-elements", {
meta: {
docs: {
description: "disallow specific HTML elements",
category: "Stylistic Issues",
recommended: false,
conflictWithPrettier: false,
},
schema: {
type: "array",
items: {
oneOf: [
{ type: "string" },
{
type: "object",
properties: {
elements: {
type: "array",
items: {
type: ["string"],
},
uniqueItems: true,
minItems: 1,
},
message: { type: "string", minLength: 1 },
},
additionalProperties: false,
minItems: 1,
},
],
},
uniqueItems: true,
minItems: 1,
},
messages: {},
type: "suggestion",
},
create(context) {
return {
SvelteElement(node) {
if (node.kind !== "html") return
const { name } = node
if (name.type !== "SvelteName") return
for (const option of context.options) {
const message =
option.message ||
`Unexpected use of forbidden HTML element ${name.name}.`
const elements = option.elements || [option]
for (const element of elements) {
if (element === name.name) {
context.report({
message,
node: node.startTag,
})
}
}
}
},
}
},
})
2 changes: 2 additions & 0 deletions src/utils/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import noObjectInTextMustaches from "../rules/no-object-in-text-mustaches"
import noReactiveFunctions from "../rules/no-reactive-functions"
import noReactiveLiterals from "../rules/no-reactive-literals"
import noReactiveReassign from "../rules/no-reactive-reassign"
import noRestrictedHtmlElements from "../rules/no-restricted-html-elements"
import noShorthandStylePropertyOverrides from "../rules/no-shorthand-style-property-overrides"
import noSpacesAroundEqualSignsInAttribute from "../rules/no-spaces-around-equal-signs-in-attribute"
import noStoreAsync from "../rules/no-store-async"
Expand Down Expand Up @@ -93,6 +94,7 @@ export const rules = [
noReactiveFunctions,
noReactiveLiterals,
noReactiveReassign,
noRestrictedHtmlElements,
noShorthandStylePropertyOverrides,
noSpacesAroundEqualSignsInAttribute,
noStoreAsync,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"options": ["h1", "h2", "h3", "h4", "h5", "h6"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
- message: Unexpected use of forbidden HTML element h1.
line: 1
column: 1
suggestions: null
- message: Unexpected use of forbidden HTML element h2.
line: 2
column: 1
suggestions: null
- message: Unexpected use of forbidden HTML element h3.
line: 3
column: 1
suggestions: null
- message: Unexpected use of forbidden HTML element h4.
line: 4
column: 1
suggestions: null
- message: Unexpected use of forbidden HTML element h5.
line: 5
column: 1
suggestions: null
- message: Unexpected use of forbidden HTML element h6.
line: 6
column: 1
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<h1>Main Title - H1</h1>
<h2>Subtitle - H2</h2>
<h3>Subsection Title - H3</h3>
<h4>Sub-Subsection Title - H4</h4>
<h5>Minor Title - H5</h5>
<h6>Minor Subtitle - H6</h6>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"options": [
{
"elements": ["h1", "h2", "h3", "h4", "h5", "h6"],
"message": "Prefer use of our custom <Heading /> component"
},
{
"elements": ["marquee"],
"message": "Do not use deprecated HTML tags"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
- message: Prefer use of our custom <Heading /> component
line: 1
column: 1
suggestions: null
- message: Prefer use of our custom <Heading /> component
line: 2
column: 1
suggestions: null
- message: Prefer use of our custom <Heading /> component
line: 3
column: 1
suggestions: null
- message: Prefer use of our custom <Heading /> component
line: 4
column: 1
suggestions: null
- message: Prefer use of our custom <Heading /> component
line: 5
column: 1
suggestions: null
- message: Prefer use of our custom <Heading /> component
line: 6
column: 1
suggestions: null
- message: Do not use deprecated HTML tags
line: 8
column: 1
suggestions: null
- message: Do not use deprecated HTML tags
line: 10
column: 1
suggestions: null
- message: Do not use deprecated HTML tags
line: 12
column: 1
suggestions: null
- message: Do not use deprecated HTML tags
line: 19
column: 3
suggestions: null
- message: Do not use deprecated HTML tags
line: 23
column: 3
suggestions: null
- message: Prefer use of our custom <Heading /> component
line: 27
column: 3
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<h1>Main Title - H1</h1>
<h2>Subtitle - H2</h2>
<h3>Subsection Title - H3</h3>
<h4>Sub-Subsection Title - H4</h4>
<h5>Minor Title - H5</h5>
<h6>Minor Subtitle - H6</h6>

<marquee>This text will scroll from right to left</marquee>

<marquee direction="up">This text will scroll from bottom to top</marquee>

<marquee
direction="down"
width="250"
height="200"
behavior="alternate"
style="border:solid"
>
<marquee behavior="alternate"> This text will bounce </marquee>
</marquee>

<div>
<marquee>This text will scroll from right to left</marquee>
</div>

<div>
<h6>Minor Subtitle - H6</h6>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"options": ["h1", "h2", "h3", "h4", "h5", "h6"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div style="font-size: 2em; font-weight: bold;">This is a title</div>
<div style="font-size: 1.5em; font-weight: bold;">This is a subtitle</div>
<p>This is a paragraph. Some sample text goes here.</p>
<ul>
<li>This is</li>
<li>a list item</li>
</ul>
<table>
<tr>
<td>Table Cell 1</td>
<td>Table Cell 2</td>
</tr>
<tr>
<td>Table Cell 3</td>
<td>Table Cell 4</td>
</tr>
</table>
<a href="https://example.com">This is a hyperlink to example.com</a>
<form>
<label for="fname">First name:</label><br />
<input type="text" id="fname" name="fname" /><br />
<input type="submit" value="Submit" />
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"options": [
{
"elements": ["h1", "h2", "h3", "h4", "h5", "h6"],
"message": "Prefer use of our custom <Heading /> component"
},
{
"elements": ["marquee"],
"message": "Do not use deprecated HTML tags"
}
]
}
Loading