Skip to content

Commit df67505

Browse files
committed
warn on implicitly closed tags
1 parent a5a0b49 commit df67505

File tree

6 files changed

+60
-1
lines changed

6 files changed

+60
-1
lines changed

documentation/docs/98-reference/.generated/compile-warnings.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,12 @@ In some situations a selector may target an element that is not 'visible' to the
632632
</style>
633633
```
634634

635+
### element_implicitly_closed
636+
637+
```
638+
The tag `<%name%>` was implicitly closed by the parent or a next element. This may cause DOM structure being other than expected one.
639+
```
640+
635641
### element_invalid_self_closing_tag
636642

637643
```

packages/svelte/messages/compile-warnings/template.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030

3131
> `<%name%>` will be treated as an HTML element unless it begins with a capital letter
3232
33+
## element_implicitly_closed
34+
35+
> The tag `<%name%>` was implicitly closed by the parent or a next element. This may cause DOM structure being other than expected one.
36+
3337
## element_invalid_self_closing_tag
3438

3539
> Self-closing HTML tags for non-void elements are ambiguous — use `<%name% ...></%name%>` rather than `<%name% ... />`

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ export default function element(parser) {
9393
}
9494
}
9595

96-
if (parent.type !== 'RegularElement' && !parser.loose) {
96+
if (parent.type === 'RegularElement') {
97+
if (!parser.last_auto_closed_tag || parser.last_auto_closed_tag.tag !== name) {
98+
const opening_tag_end = parent.fragment.nodes[0]?.start ?? parent.start + parent.name.length + 2;
99+
w.element_implicitly_closed({ start: parent.start, end: opening_tag_end }, parent.name);
100+
}
101+
} else if (!parser.loose) {
97102
if (parser.last_auto_closed_tag && parser.last_auto_closed_tag.tag === name) {
98103
e.element_invalid_closing_tag_autoclosed(start, name, parser.last_auto_closed_tag.reason);
99104
} else {
@@ -186,6 +191,8 @@ export default function element(parser) {
186191
parser.allow_whitespace();
187192

188193
if (parent.type === 'RegularElement' && closing_tag_omitted(parent.name, name)) {
194+
const opening_tag_end = parent.fragment.nodes[0]?.start ?? parent.start + parent.name.length + 2;
195+
w.element_implicitly_closed({ start: parent.start, end: opening_tag_end }, parent.name);
189196
parent.end = start;
190197
parser.pop();
191198
parser.last_auto_closed_tag = {

packages/svelte/src/compiler/warnings.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export const codes = [
114114
'bind_invalid_each_rest',
115115
'block_empty',
116116
'component_name_lowercase',
117+
'element_implicitly_closed',
117118
'element_invalid_self_closing_tag',
118119
'event_directive_deprecated',
119120
'node_invalid_placement_ssr',
@@ -746,6 +747,15 @@ export function component_name_lowercase(node, name) {
746747
w(node, 'component_name_lowercase', `\`<${name}>\` will be treated as an HTML element unless it begins with a capital letter\nhttps://svelte.dev/e/component_name_lowercase`);
747748
}
748749

750+
/**
751+
* The tag `<%name%>` was implicitly closed by the parent or a next element. This may cause DOM structure being other than expected one.
752+
* @param {null | NodeLike} node
753+
* @param {string} name
754+
*/
755+
export function element_implicitly_closed(node, name) {
756+
w(node, 'element_implicitly_closed', `The tag \`<${name}>\` was implicitly closed by the parent or a next element. This may cause DOM structure being other than expected one.\nhttps://svelte.dev/e/element_implicitly_closed`);
757+
}
758+
749759
/**
750760
* Self-closing HTML tags for non-void elements are ambiguous — use `<%name% ...></%name%>` rather than `<%name% ... />`
751761
* @param {null | NodeLike} node
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<main>
2+
<input>
3+
<div>
4+
<p>
5+
<p></p>
6+
</main>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
{
3+
"code": "element_implicitly_closed",
4+
"message": "The tag `<p>` was implicitly closed by the parent or a next element. This may cause DOM structure being other than expected one.",
5+
"start": {
6+
"line": 4,
7+
"column": 4
8+
},
9+
"end": {
10+
"line": 4,
11+
"column": 7
12+
}
13+
},
14+
{
15+
"code": "element_implicitly_closed",
16+
"message": "The tag `<div>` was implicitly closed by the parent or a next element. This may cause DOM structure being other than expected one.",
17+
"start": {
18+
"line": 3,
19+
"column": 4
20+
},
21+
"end": {
22+
"line": 3,
23+
"column": 9
24+
}
25+
}
26+
]

0 commit comments

Comments
 (0)