Skip to content

Commit e33af52

Browse files
committed
treat special elements that never have content as void elements
1 parent 669d2d7 commit e33af52

File tree

12 files changed

+242
-27
lines changed

12 files changed

+242
-27
lines changed

packages/svelte/src/compiler/errors.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,6 @@ const elements = {
229229
'invalid-textarea-content': () =>
230230
`A <textarea> can have either a value attribute or (equivalently) child content, but not both`,
231231
'invalid-void-content': () => `Void elements cannot have children or closing tags`,
232-
/** @param {string} name */
233-
'invalid-element-content': (name) => `<${name}> cannot have children`,
234232
'invalid-tag-name': () => 'Expected valid tag name',
235233
/**
236234
* @param {string} node

packages/svelte/src/compiler/phases/1-parse/state/element.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,7 @@ export default function tag(parser) {
9999
const name = read_tag_name(parser);
100100

101101
if (root_only_meta_tags.has(name)) {
102-
if (is_closing_tag) {
103-
if (
104-
(name === 'svelte:window' || name === 'svelte:body' || name === 'svelte:document') &&
105-
/** @type {import('#compiler').ElementLike} */ (parent).fragment.nodes.length
106-
) {
107-
error(
108-
/** @type {import('#compiler').ElementLike} */ (parent).fragment.nodes[0].start,
109-
'invalid-element-content',
110-
name
111-
);
112-
}
113-
} else {
102+
if (!is_closing_tag) {
114103
if (name in parser.meta_tags) {
115104
error(start, 'duplicate-svelte-element', name);
116105
}

packages/svelte/src/compiler/phases/1-parse/utils/names.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ const void_element_names = [
6565
'param',
6666
'source',
6767
'track',
68-
'wbr'
68+
'wbr',
69+
'svelte:options',
70+
'svelte:window',
71+
'svelte:document',
72+
'svelte:body'
6973
];
7074

7175
/** @param {string} name */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'invalid-void-content',
6+
message: 'Void elements cannot have children or closing tags',
7+
position: [23, 23]
8+
}
9+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
error: {
5+
code: 'invalid-void-content',
6+
message: 'Void elements cannot have children or closing tags',
7+
position: [33, 33]
8+
}
9+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<svelte:options immutable={true}></svelte:options>

packages/svelte/tests/compiler-errors/samples/window-children/_config.js

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<svelte:options immutable={false}>
2+
<svelte:window on:event={() => null}>
3+
<svelte:document on:event={() => null}>
4+
<svelte:body on:event={() => null}>
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
{
2+
"css": null,
3+
"js": [],
4+
"start": 0,
5+
"end": 148,
6+
"type": "Root",
7+
"fragment": {
8+
"type": "Fragment",
9+
"nodes": [
10+
{
11+
"type": "Text",
12+
"start": 34,
13+
"end": 35,
14+
"raw": "\n",
15+
"data": "\n"
16+
},
17+
{
18+
"type": "SvelteWindow",
19+
"start": 35,
20+
"end": 72,
21+
"name": "svelte:window",
22+
"attributes": [
23+
{
24+
"start": 50,
25+
"end": 71,
26+
"type": "OnDirective",
27+
"name": "event",
28+
"modifiers": [],
29+
"expression": {
30+
"type": "ArrowFunctionExpression",
31+
"start": 60,
32+
"end": 70,
33+
"loc": {
34+
"start": {
35+
"line": 2,
36+
"column": 25
37+
},
38+
"end": {
39+
"line": 2,
40+
"column": 35
41+
}
42+
},
43+
"id": null,
44+
"expression": true,
45+
"generator": false,
46+
"async": false,
47+
"params": [],
48+
"body": {
49+
"type": "Literal",
50+
"start": 66,
51+
"end": 70,
52+
"loc": {
53+
"start": {
54+
"line": 2,
55+
"column": 31
56+
},
57+
"end": {
58+
"line": 2,
59+
"column": 35
60+
}
61+
},
62+
"value": null,
63+
"raw": "null"
64+
}
65+
}
66+
}
67+
],
68+
"fragment": {
69+
"type": "Fragment",
70+
"nodes": [],
71+
"transparent": true
72+
}
73+
},
74+
{
75+
"type": "Text",
76+
"start": 72,
77+
"end": 73,
78+
"raw": "\n",
79+
"data": "\n"
80+
},
81+
{
82+
"type": "SvelteDocument",
83+
"start": 73,
84+
"end": 112,
85+
"name": "svelte:document",
86+
"attributes": [
87+
{
88+
"start": 90,
89+
"end": 111,
90+
"type": "OnDirective",
91+
"name": "event",
92+
"modifiers": [],
93+
"expression": {
94+
"type": "ArrowFunctionExpression",
95+
"start": 100,
96+
"end": 110,
97+
"loc": {
98+
"start": {
99+
"line": 3,
100+
"column": 27
101+
},
102+
"end": {
103+
"line": 3,
104+
"column": 37
105+
}
106+
},
107+
"id": null,
108+
"expression": true,
109+
"generator": false,
110+
"async": false,
111+
"params": [],
112+
"body": {
113+
"type": "Literal",
114+
"start": 106,
115+
"end": 110,
116+
"loc": {
117+
"start": {
118+
"line": 3,
119+
"column": 33
120+
},
121+
"end": {
122+
"line": 3,
123+
"column": 37
124+
}
125+
},
126+
"value": null,
127+
"raw": "null"
128+
}
129+
}
130+
}
131+
],
132+
"fragment": {
133+
"type": "Fragment",
134+
"nodes": [],
135+
"transparent": true
136+
}
137+
},
138+
{
139+
"type": "Text",
140+
"start": 112,
141+
"end": 113,
142+
"raw": "\n",
143+
"data": "\n"
144+
},
145+
{
146+
"type": "SvelteBody",
147+
"start": 113,
148+
"end": 148,
149+
"name": "svelte:body",
150+
"attributes": [
151+
{
152+
"start": 126,
153+
"end": 147,
154+
"type": "OnDirective",
155+
"name": "event",
156+
"modifiers": [],
157+
"expression": {
158+
"type": "ArrowFunctionExpression",
159+
"start": 136,
160+
"end": 146,
161+
"loc": {
162+
"start": {
163+
"line": 4,
164+
"column": 23
165+
},
166+
"end": {
167+
"line": 4,
168+
"column": 33
169+
}
170+
},
171+
"id": null,
172+
"expression": true,
173+
"generator": false,
174+
"async": false,
175+
"params": [],
176+
"body": {
177+
"type": "Literal",
178+
"start": 142,
179+
"end": 146,
180+
"loc": {
181+
"start": {
182+
"line": 4,
183+
"column": 29
184+
},
185+
"end": {
186+
"line": 4,
187+
"column": 33
188+
}
189+
},
190+
"value": null,
191+
"raw": "null"
192+
}
193+
}
194+
}
195+
],
196+
"fragment": {
197+
"type": "Fragment",
198+
"nodes": [],
199+
"transparent": true
200+
}
201+
}
202+
],
203+
"transparent": false
204+
},
205+
"options": {
206+
"start": 0,
207+
"end": 34,
208+
"immutable": false
209+
}
210+
}

packages/svelte/tests/runtime-legacy/samples/deconflict-globals/main.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
<title>Cute test</title>
1313
</svelte:head>
1414

15-
<svelte:window on:click></svelte:window>
16-
<svelte:body on:mouseenter></svelte:body>
15+
<svelte:window on:click>
16+
<svelte:body on:mouseenter>
1717

1818
{#each everyone as someone (someone)}
1919
<p>{someone}</p>

packages/svelte/tests/validator/samples/let-directive/input.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
{/if}
44
<Component let:x></Component>
55
<div let:x></div><!-- strictly speaking this is invalid, but it was never checked in Svelte 3/4 either, and is now deprecated, so don't mind -->
6-
<svelte:window let:x></svelte:window>
6+
<svelte:window let:x>

0 commit comments

Comments
 (0)