Skip to content
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

feat!: updated the html-self-closing rule to follow Svelte5 #982

Merged
merged 8 commits into from
Jan 13, 2025
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/soft-bears-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'eslint-plugin-svelte': major
---

feat!: Updated the `html-self-closing` rule to follow Svelte5
56 changes: 35 additions & 21 deletions docs/rules/html-self-closing.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ since: 'v2.5.0'

## :book: Rule Details

You can choose either two styles for elements without content
You can choose either two styles for elements without content.

- always: `<div />`
- never: `<div></div>`
- always: `<SomeComponent />`
- never: `<SomeComponent></SomeComponent>`

<!-- prettier-ignore-start -->
<!--eslint-skip-->
Expand All @@ -28,18 +28,21 @@ You can choose either two styles for elements without content
</script>

<!-- ✓ GOOD -->
<div />
<p>Hello</p>
<div><div /></div>
<div></div>
<img />
<svelte:head />
<svg><path /></svg>
<math><msup></msup></math>
<SomeComponent />

<!-- ✗ BAD -->
<div></div>
<p> </p>
<div><div></div></div>
<img>
<div />
<div><div /></div>
<svelte:body></svelte:body>
<svg><path></path></svg>
<math><msup /></math>
<SomeComponent></SomeComponent>
```

<!-- prettier-ignore-end -->
Expand All @@ -52,7 +55,7 @@ presets:
{
"svelte/html-self-closing": [
"error",
"all" // or "html" or "none"
"default" // or "all" or "html" or "none"
]
}
```
Expand All @@ -65,8 +68,9 @@ config object:
"error",
{
"void": "always", // or "never" or "ignore"
"normal": "always", // or "never" or "ignore"
"foreign": "always", // or "never" or "ignore"
"normal": "never", // or "always" or "ignore"
"svg": "always", // or "never" or "ignore"
"never": "never", // or "always" or "ignore"
"component": "always", // or "never" or "ignore"
"svelte": "always" // or "never" or "ignore"
}
Expand All @@ -76,23 +80,33 @@ config object:

presets:

- `all` - all elements should be self closing (unless they have children)
- `html` - html-compliant - only void elements and svelte special elements should be self closing
- `none` - no elements should be self closing
- `default` - MathML and non-void HTML elements should have a closing tag; otherwise, they should be self-closing.
- `all` - all elements should be self-closing (unless they have children)
- `html` - html-compliant - only void elements and svelte special elements should be self-closing
- `none` - no elements should be self-closing

::: warning Note
We recommend selecting `default` as the preset. Choosing any other option may result in settings that are inconsistent with the compiler when using Svelte5.
:::

config object:

- `void` (`"always"` in default preset)... Style of HTML void elements
- `foreign` (`"always"` in default preset)... Style of foreign elements (SVG and MathML)
- `normal` (`"never"` in default preset)... Style of other elements
- `svg` (`"always"` in default preset)... Style of SVG
- `math` (`never` in default preset)... Style of MathML
- `component` (`"always"` in default preset)... Style of svelte components
- `svelte` (`"always"` in default preset)... Style of svelte special elements (`<svelte:head>`, `<svelte:self>`)
- `normal` (`"always"` in default preset)... Style of other elements

Every config oject option can be set to
::: warning
`foreign` is removed in `eslint-plugin-svelte` v3.
:::

Every config object option can be set to

- "always" (`<div />`)
- "never" (`<div></div>`)
- "ignore" (either `<div />` or `<div></div>`)
- "always" (`<SomeComponent />`)
- "never" (`<SomeComponent></SomeComponent>`)
- "ignore" (either `<SomeComponent />` or `<SomeComponent></SomeComponent>`)

## :rocket: Version

Expand Down
3 changes: 2 additions & 1 deletion packages/eslint-plugin-svelte/src/rule-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,8 @@ type SvelteHtmlQuotes = []|[{
type SvelteHtmlSelfClosing = []|[({
void?: ("never" | "always" | "ignore")
normal?: ("never" | "always" | "ignore")
foreign?: ("never" | "always" | "ignore")
svg?: ("never" | "always" | "ignore")
math?: ("never" | "always" | "ignore")
component?: ("never" | "always" | "ignore")
svelte?: ("never" | "always" | "ignore")
} | ("all" | "html" | "none"))]
Expand Down
53 changes: 39 additions & 14 deletions packages/eslint-plugin-svelte/src/rules/html-self-closing.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import type { AST } from 'svelte-eslint-parser';
import { createRule } from '../utils/index.js';
import { getNodeName, isVoidHtmlElement, isForeignElement } from '../utils/ast-utils.js';
import {
getNodeName,
isVoidHtmlElement,
isSvgElement,
isMathMLElement
} from '../utils/ast-utils.js';
import { getSourceCode } from '../utils/compat.js';

const TYPE_MESSAGES = {
normal: 'HTML elements',
void: 'HTML void elements',
foreign: 'foreign (SVG or MathML) elements',
svg: 'SVG elements',
math: 'MathML elements',
component: 'Svelte custom components',
svelte: 'Svelte special elements'
};

type ElementTypes = 'normal' | 'void' | 'foreign' | 'component' | 'svelte';
type ElementTypes = 'normal' | 'void' | 'svg' | 'math' | 'component' | 'svelte';

export default createRule('html-self-closing', {
meta: {
Expand All @@ -38,7 +44,10 @@ export default createRule('html-self-closing', {
normal: {
enum: ['never', 'always', 'ignore']
},
foreign: {
svg: {
enum: ['never', 'always', 'ignore']
},
math: {
enum: ['never', 'always', 'ignore']
},
component: {
Expand All @@ -58,34 +67,49 @@ export default createRule('html-self-closing', {
]
},
create(context) {
// default
let options = {
void: 'always',
normal: 'always',
foreign: 'always',
normal: 'never',
svg: 'always',
math: 'never',
component: 'always',
svelte: 'always'
};

const option = context.options?.[0];
switch (option) {
case 'none':
case 'all':
options = {
void: 'never',
normal: 'never',
foreign: 'never',
component: 'never',
svelte: 'never'
void: 'always',
normal: 'always',
svg: 'always',
math: 'always',
component: 'always',
svelte: 'always'
};
break;
case 'html':
options = {
void: 'always',
normal: 'never',
foreign: 'always',
svg: 'always',
math: 'never',
component: 'never',
svelte: 'always'
};
break;
case 'none':
options = {
void: 'never',
normal: 'never',
svg: 'never',
math: 'never',
component: 'never',
svelte: 'never'
};
break;

default:
if (typeof option !== 'object' || option === null) break;

Expand All @@ -108,7 +132,8 @@ export default createRule('html-self-closing', {
if (node.kind === 'component') return 'component';
if (node.kind === 'special') return 'svelte';
if (isVoidHtmlElement(node)) return 'void';
if (isForeignElement(node)) return 'foreign';
if (isSvgElement(node)) return 'svg';
if (isMathMLElement(node)) return 'math';
return 'normal';
}

Expand Down
8 changes: 8 additions & 0 deletions packages/eslint-plugin-svelte/src/utils/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,14 @@ export function isForeignElement(node: SvAST.SvelteElement): boolean {
return svgElements.includes(getNodeName(node)) || mathmlElements.includes(getNodeName(node));
}

export function isSvgElement(node: SvAST.SvelteElement): boolean {
return svgElements.includes(getNodeName(node));
}

export function isMathMLElement(node: SvAST.SvelteElement): boolean {
return mathmlElements.includes(getNodeName(node));
}

/** Checks whether the given identifier node is used as an expression. */
export function isExpressionIdentifier(node: TSESTree.Identifier): boolean {
const parent = node.parent;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"options": [
{
"foreign": "never"
"math": "never"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Disallow self-closing on MathML elements.
line: 3
column: 13
suggestions: null
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!-- prettier-ignore -->
<svg><path ></path></svg>
<svg><path /></svg>
<math><msup ></msup></math>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"options": [
{
"normal": "always"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Require self-closing on HTML elements.
line: 3
column: 7
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!-- prettier-ignore -->
<div>
<div></div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!-- prettier-ignore -->
<div>
<div/>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
line: 5
column: 18
suggestions: null
- message: Require self-closing on foreign (SVG or MathML) elements.
- message: Require self-closing on SVG elements.
line: 6
column: 13
suggestions: null
- message: Require self-closing on foreign (SVG or MathML) elements.
- message: Disallow self-closing on MathML elements.
line: 7
column: 14
suggestions: null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<img>
<TestComponent />
<svg><path></path></svg>
<math><msup></msup></math>
<math><msup/></math>
</div>
<!-- prettier-ignore -->
<svelte:head></svelte:head>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<img/>
<TestComponent ></TestComponent>
<svg><path/></svg>
<math><msup/></math>
<math><msup></msup></math>
</div>
<!-- prettier-ignore -->
<svelte:head/>
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
line: 5
column: 8
suggestions: null
- message: Disallow self-closing on foreign (SVG or MathML) elements.
- message: Disallow self-closing on SVG elements.
line: 6
column: 14
suggestions: null
- message: Disallow self-closing on foreign (SVG or MathML) elements.
- message: Disallow self-closing on MathML elements.
line: 7
column: 15
suggestions: null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"options": [
{
"svg": "never"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Disallow self-closing on SVG elements.
line: 2
column: 12
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- prettier-ignore -->
<svg><path /></svg>
<math><msup></msup></math>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- prettier-ignore -->
<svg><path ></path></svg>
<math><msup></msup></math>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
- message: Require self-closing on HTML elements.
- message: Disallow self-closing on HTML elements.
line: 3
column: 7
suggestions: null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!-- prettier-ignore -->
<div>
<div></div>
<div/>
<CustomElement> </CustomElement>
<img>
</div>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!-- prettier-ignore -->
<div>
<div/>
<div></div>
<CustomElement/>
<img/>
</div>
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<div class="hello">
<div />
<div></div>
<div>hello</div>
<img />
<svg><path /></svg>
<math><msup /></math>
<math><msup></msup></math>
{#if true}
<svelte:self />
{/if}
Expand Down
Loading