Skip to content

Commit 18dfd25

Browse files
committed
add separate config for foreign elements in html-self-closing
1 parent d117d7f commit 18dfd25

15 files changed

+207
-25
lines changed

packages/eslint-plugin-svelte/src/rules/html-self-closing.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import type { AST } from 'svelte-eslint-parser';
22
import { createRule } from '../utils';
3-
import { getNodeName, isVoidHtmlElement } from '../utils/ast-utils';
3+
import { getNodeName, isVoidHtmlElement, isForeignElement } from '../utils/ast-utils';
44
import { getSourceCode } from '../utils/compat';
55

66
const TYPE_MESSAGES = {
77
normal: 'HTML elements',
88
void: 'HTML void elements',
9+
foreign: 'foreign (SVG or MathML) elements',
910
component: 'Svelte custom components',
1011
svelte: 'Svelte special elements'
1112
};
1213

13-
type ElementTypes = 'normal' | 'void' | 'component' | 'svelte';
14+
type ElementTypes = 'normal' | 'void' | 'foreign' | 'component' | 'svelte';
1415

1516
export default createRule('html-self-closing', {
1617
meta: {
@@ -37,6 +38,9 @@ export default createRule('html-self-closing', {
3738
normal: {
3839
enum: ['never', 'always', 'ignore']
3940
},
41+
foreign: {
42+
enum: ['never', 'always', 'ignore']
43+
},
4044
component: {
4145
enum: ['never', 'always', 'ignore']
4246
},
@@ -57,6 +61,7 @@ export default createRule('html-self-closing', {
5761
let options = {
5862
void: 'always',
5963
normal: 'always',
64+
foreign: 'always',
6065
component: 'always',
6166
svelte: 'always'
6267
};
@@ -67,6 +72,7 @@ export default createRule('html-self-closing', {
6772
options = {
6873
void: 'never',
6974
normal: 'never',
75+
foreign: 'never',
7076
component: 'never',
7177
svelte: 'never'
7278
};
@@ -75,6 +81,7 @@ export default createRule('html-self-closing', {
7581
options = {
7682
void: 'always',
7783
normal: 'never',
84+
foreign: 'always',
7885
component: 'never',
7986
svelte: 'always'
8087
};
@@ -101,6 +108,7 @@ export default createRule('html-self-closing', {
101108
if (node.kind === 'component') return 'component';
102109
if (node.kind === 'special') return 'svelte';
103110
if (isVoidHtmlElement(node)) return 'void';
111+
if (isForeignElement(node)) return 'foreign';
104112
return 'normal';
105113
}
106114

packages/eslint-plugin-svelte/src/utils/ast-utils.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { TSESTree } from '@typescript-eslint/types';
33
import type { Scope, Variable } from '@typescript-eslint/scope-manager';
44
import type { AST as SvAST } from 'svelte-eslint-parser';
55
import * as eslintUtils from '@eslint-community/eslint-utils';
6-
import voidElements from './void-elements';
6+
import { voidElements, svgElements, mathmlElements } from './element-types';
77
import { getSourceCode } from './compat';
88

99
/**
@@ -560,6 +560,13 @@ export function isVoidHtmlElement(node: SvAST.SvelteElement): boolean {
560560
return voidElements.includes(getNodeName(node));
561561
}
562562

563+
/**
564+
* Returns true if element is known foreign (SVG or MathML) element
565+
*/
566+
export function isForeignElement(node: SvAST.SvelteElement): boolean {
567+
return svgElements.includes(getNodeName(node)) || mathmlElements.includes(getNodeName(node));
568+
}
569+
563570
/** Checks whether the given identifier node is used as an expression. */
564571
export function isExpressionIdentifier(node: TSESTree.Identifier): boolean {
565572
const parent = node.parent;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
export const voidElements = [
2+
'area',
3+
'base',
4+
'br',
5+
'col',
6+
'embed',
7+
'hr',
8+
'img',
9+
'input',
10+
'keygen',
11+
'link',
12+
'menuitem',
13+
'meta',
14+
'param',
15+
'source',
16+
'track',
17+
'wbr'
18+
];
19+
20+
export const svgElements = [
21+
'altGlyph',
22+
'altGlyphDef',
23+
'altGlyphItem',
24+
'animate',
25+
'animateColor',
26+
'animateMotion',
27+
'animateTransform',
28+
'circle',
29+
'clipPath',
30+
'color-profile',
31+
'cursor',
32+
'defs',
33+
'desc',
34+
'discard',
35+
'ellipse',
36+
'feBlend',
37+
'feColorMatrix',
38+
'feComponentTransfer',
39+
'feComposite',
40+
'feConvolveMatrix',
41+
'feDiffuseLighting',
42+
'feDisplacementMap',
43+
'feDistantLight',
44+
'feDropShadow',
45+
'feFlood',
46+
'feFuncA',
47+
'feFuncB',
48+
'feFuncG',
49+
'feFuncR',
50+
'feGaussianBlur',
51+
'feImage',
52+
'feMerge',
53+
'feMergeNode',
54+
'feMorphology',
55+
'feOffset',
56+
'fePointLight',
57+
'feSpecularLighting',
58+
'feSpotLight',
59+
'feTile',
60+
'feTurbulence',
61+
'filter',
62+
'font',
63+
'font-face',
64+
'font-face-format',
65+
'font-face-name',
66+
'font-face-src',
67+
'font-face-uri',
68+
'foreignObject',
69+
'g',
70+
'glyph',
71+
'glyphRef',
72+
'hatch',
73+
'hatchpath',
74+
'hkern',
75+
'image',
76+
'line',
77+
'linearGradient',
78+
'marker',
79+
'mask',
80+
'mesh',
81+
'meshgradient',
82+
'meshpatch',
83+
'meshrow',
84+
'metadata',
85+
'missing-glyph',
86+
'mpath',
87+
'path',
88+
'pattern',
89+
'polygon',
90+
'polyline',
91+
'radialGradient',
92+
'rect',
93+
'set',
94+
'solidcolor',
95+
'stop',
96+
'svg',
97+
'switch',
98+
'symbol',
99+
'text',
100+
'textPath',
101+
'tref',
102+
'tspan',
103+
'unknown',
104+
'use',
105+
'view',
106+
'vkern'
107+
];
108+
109+
export const mathmlElements = [
110+
'annotation',
111+
'annotation-xml',
112+
'maction',
113+
'math',
114+
'merror',
115+
'mfrac',
116+
'mi',
117+
'mmultiscripts',
118+
'mn',
119+
'mo',
120+
'mover',
121+
'mpadded',
122+
'mphantom',
123+
'mprescripts',
124+
'mroot',
125+
'mrow',
126+
'ms',
127+
'mspace',
128+
'msqrt',
129+
'mstyle',
130+
'msub',
131+
'msubsup',
132+
'msup',
133+
'mtable',
134+
'mtd',
135+
'mtext',
136+
'mtr',
137+
'munder',
138+
'munderover',
139+
'semantics'
140+
];

packages/eslint-plugin-svelte/src/utils/void-elements.ts

-20
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"options": [
3+
{
4+
"foreign": "never"
5+
}
6+
]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
- message: Disallow self-closing on foreign (SVG or MathML) elements.
2+
line: 2
3+
column: 12
4+
suggestions: null
5+
- message: Disallow self-closing on foreign (SVG or MathML) elements.
6+
line: 3
7+
column: 13
8+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<!-- prettier-ignore -->
2+
<svg><path /></svg>
3+
<math><msup /></math>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<!-- prettier-ignore -->
2+
<svg><path ></path></svg>
3+
<math><msup ></msup></math>

packages/eslint-plugin-svelte/tests/fixtures/rules/html-self-closing/invalid/presets/html/preset-html-errors.yaml

+9-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@
1010
line: 5
1111
column: 18
1212
suggestions: null
13+
- message: Require self-closing on foreign (SVG or MathML) elements.
14+
line: 6
15+
column: 13
16+
suggestions: null
17+
- message: Require self-closing on foreign (SVG or MathML) elements.
18+
line: 7
19+
column: 14
20+
suggestions: null
1321
- message: Require self-closing on Svelte special elements.
14-
line: 8
22+
line: 10
1523
column: 13
1624
suggestions: null

packages/eslint-plugin-svelte/tests/fixtures/rules/html-self-closing/invalid/presets/html/preset-html-input.svelte

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<div />
44
<img>
55
<TestComponent />
6+
<svg><path></path></svg>
7+
<math><msup></msup></math>
68
</div>
79
<!-- prettier-ignore -->
810
<svelte:head></svelte:head>

packages/eslint-plugin-svelte/tests/fixtures/rules/html-self-closing/invalid/presets/html/preset-html-output.svelte

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<div ></div>
44
<img/>
55
<TestComponent ></TestComponent>
6+
<svg><path/></svg>
7+
<math><msup/></math>
68
</div>
79
<!-- prettier-ignore -->
810
<svelte:head/>

packages/eslint-plugin-svelte/tests/fixtures/rules/html-self-closing/invalid/presets/none/preset-none-errors.yaml

+9-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@
1010
line: 5
1111
column: 8
1212
suggestions: null
13+
- message: Disallow self-closing on foreign (SVG or MathML) elements.
14+
line: 6
15+
column: 14
16+
suggestions: null
17+
- message: Disallow self-closing on foreign (SVG or MathML) elements.
18+
line: 7
19+
column: 15
20+
suggestions: null
1321
- message: Disallow self-closing on Svelte special elements.
14-
line: 8
22+
line: 10
1523
column: 14
1624
suggestions: null

packages/eslint-plugin-svelte/tests/fixtures/rules/html-self-closing/invalid/presets/none/preset-none-input.svelte

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<div />
44
<TestComponent />
55
<img />
6+
<svg><path /></svg>
7+
<math><msup /></math>
68
</div>
79
<!-- prettier-ignore -->
810
<svelte:head />

packages/eslint-plugin-svelte/tests/fixtures/rules/html-self-closing/invalid/presets/none/preset-none-output.svelte

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
<div ></div>
44
<TestComponent ></TestComponent>
55
<img >
6+
<svg><path ></path></svg>
7+
<math><msup ></msup></math>
68
</div>
79
<!-- prettier-ignore -->
810
<svelte:head ></svelte:head>

packages/eslint-plugin-svelte/tests/fixtures/rules/html-self-closing/valid/test01-input.svelte

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
<div />
33
<div>hello</div>
44
<img />
5+
<svg><path /></svg>
6+
<math><msup /></math>
57
{#if true}
68
<svelte:self />
79
{/if}

0 commit comments

Comments
 (0)