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 6 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 @@ -382,6 +382,7 @@ These rules extend the rules provided by ESLint itself, or other plugins to work
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/no-inner-declarations](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-inner-declarations/) | disallow variable or `function` declarations in nested blocks | :star: |
| [svelte/no-restricted-html-elements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-restricted-html-elements/) | disallow specific HTML elements | |
| [svelte/no-trailing-spaces](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-trailing-spaces/) | disallow trailing whitespace at the end of lines | :wrench: |

## Experimental
Expand Down
9 changes: 5 additions & 4 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,11 @@ These rules relate to style guidelines, and are therefore quite subjective:

These rules extend the rules provided by ESLint itself, or other plugins to work well in Svelte:

| Rule ID | Description | |
| :--------------------------------------------------------------- | :------------------------------------------------------------ | :------- |
| [svelte/no-inner-declarations](./rules/no-inner-declarations.md) | disallow variable or `function` declarations in nested blocks | :star: |
| [svelte/no-trailing-spaces](./rules/no-trailing-spaces.md) | disallow trailing whitespace at the end of lines | :wrench: |
| Rule ID | Description | |
| :--------------------------------------------------------------------------- | :------------------------------------------------------------ | :------- |
| [svelte/no-inner-declarations](./rules/no-inner-declarations.md) | disallow variable or `function` declarations in nested blocks | :star: |
| [svelte/no-restricted-html-elements](./rules/no-restricted-html-elements.md) | disallow specific HTML elements | |
| [svelte/no-trailing-spaces](./rules/no-trailing-spaces.md) | disallow trailing whitespace at the end of lines | :wrench: |

## Experimental

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",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"elements": "h1", "h2", "h3", "h4", "h5", "h6",
"elements": ["h1", "h2", "h3", "h4", "h5", "h6"],

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏

"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)
62 changes: 62 additions & 0 deletions src/rules/no-restricted-html-elements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { createRule } from "../utils"

export default createRule("no-restricted-html-elements", {
meta: {
docs: {
description: "disallow specific HTML elements",
category: "Extension Rules",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. I think the better category for this rule is Stylistic Issues among the categories we currently have, but we may need to create a new category 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I misunderstood the meaning of Extension Rules.
Just now I changed the category.
Should we refactor categories in the next major version?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we need to run pnpm run update.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we refactor categories in the next major version?

We can always make changes if we have ideas for categorization that make it easier for users to understand 😉

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about it a bit, but I think Stylistic Issues is fine for now.

recommended: 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