Skip to content

Commit

Permalink
feat!: updated the html-self-closing rule to follow Svelte5 (#982)
Browse files Browse the repository at this point in the history
  • Loading branch information
baseballyama authored Jan 13, 2025
1 parent eae0e2e commit 04fc429
Show file tree
Hide file tree
Showing 26 changed files with 142 additions and 57 deletions.
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

0 comments on commit 04fc429

Please sign in to comment.