Skip to content

Commit 6994021

Browse files
committed
handle unclosed tags
1 parent 6450737 commit 6994021

File tree

8 files changed

+289
-4
lines changed

8 files changed

+289
-4
lines changed

packages/svelte/src/compiler/phases/1-parse/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ export class Parser {
9999
if (this.stack.length > 1) {
100100
const current = this.current();
101101

102-
if (current.type === 'RegularElement') {
102+
if (this.loose) {
103+
current.end = this.template.length;
104+
} else if (current.type === 'RegularElement') {
103105
current.end = current.start + 1;
104106
e.element_unclosed(current, current.name);
105107
} else {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export default function element(parser) {
8080

8181
// close any elements that don't have their own closing tags, e.g. <div><p></div>
8282
while (/** @type {AST.RegularElement} */ (parent).name !== name) {
83-
if (parent.type !== 'RegularElement') {
83+
if (parent.type !== 'RegularElement' && !parser.loose) {
8484
if (parser.last_auto_closed_tag && parser.last_auto_closed_tag.tag === name) {
8585
e.element_invalid_closing_tag_autoclosed(start, name, parser.last_auto_closed_tag.reason);
8686
} else {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div>
2+
<Comp>
3+
</div>
4+
5+
<div>
6+
<span>
7+
</div>
8+
9+
<div>
10+
<p>hi</p>
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
{
2+
"html": {
3+
"type": "Fragment",
4+
"start": 0,
5+
"end": 59,
6+
"children": [
7+
{
8+
"type": "Element",
9+
"start": 0,
10+
"end": 20,
11+
"name": "div",
12+
"attributes": [],
13+
"children": [
14+
{
15+
"type": "Text",
16+
"start": 5,
17+
"end": 7,
18+
"raw": "\n\t",
19+
"data": "\n\t"
20+
},
21+
{
22+
"type": "InlineComponent",
23+
"start": 7,
24+
"end": 14,
25+
"name": "Comp",
26+
"attributes": [],
27+
"children": [
28+
{
29+
"type": "Text",
30+
"start": 13,
31+
"end": 14,
32+
"raw": "\n",
33+
"data": "\n"
34+
}
35+
]
36+
}
37+
]
38+
},
39+
{
40+
"type": "Text",
41+
"start": 20,
42+
"end": 22,
43+
"raw": "\n\n",
44+
"data": "\n\n"
45+
},
46+
{
47+
"type": "Element",
48+
"start": 22,
49+
"end": 42,
50+
"name": "div",
51+
"attributes": [],
52+
"children": [
53+
{
54+
"type": "Text",
55+
"start": 27,
56+
"end": 29,
57+
"raw": "\n\t",
58+
"data": "\n\t"
59+
},
60+
{
61+
"type": "Element",
62+
"start": 29,
63+
"end": 36,
64+
"name": "span",
65+
"attributes": [],
66+
"children": [
67+
{
68+
"type": "Text",
69+
"start": 35,
70+
"end": 36,
71+
"raw": "\n",
72+
"data": "\n"
73+
}
74+
]
75+
}
76+
]
77+
},
78+
{
79+
"type": "Text",
80+
"start": 42,
81+
"end": 44,
82+
"raw": "\n\n",
83+
"data": "\n\n"
84+
},
85+
{
86+
"type": "Element",
87+
"start": 44,
88+
"end": 59,
89+
"name": "div",
90+
"attributes": [],
91+
"children": [
92+
{
93+
"type": "Text",
94+
"start": 49,
95+
"end": 50,
96+
"raw": "\n",
97+
"data": "\n"
98+
},
99+
{
100+
"type": "Element",
101+
"start": 50,
102+
"end": 59,
103+
"name": "p",
104+
"attributes": [],
105+
"children": [
106+
{
107+
"type": "Text",
108+
"start": 53,
109+
"end": 55,
110+
"raw": "hi",
111+
"data": "hi"
112+
}
113+
]
114+
}
115+
]
116+
}
117+
]
118+
}
119+
}

packages/svelte/tests/parser-legacy/test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ const { test, run } = suite<ParserTest>(async (config, cwd) => {
1212
.replace(/\s+$/, '')
1313
.replace(/\r/g, '');
1414

15-
const actual = JSON.parse(JSON.stringify(parse(input)));
15+
const actual = JSON.parse(
16+
JSON.stringify(parse(input, { loose: cwd.split('/').pop()!.startsWith('loose-') }))
17+
);
1618

1719
// run `UPDATE_SNAPSHOTS=true pnpm test parser` to update parser tests
1820
if (process.env.UPDATE_SNAPSHOTS) {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div>
2+
<Comp>
3+
</div>
4+
5+
<div>
6+
<span>
7+
</div>
8+
9+
<div>
10+
<p>hi</p>
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
{
2+
"css": null,
3+
"js": [],
4+
"start": 0,
5+
"end": 59,
6+
"type": "Root",
7+
"fragment": {
8+
"type": "Fragment",
9+
"nodes": [
10+
{
11+
"type": "RegularElement",
12+
"start": 0,
13+
"end": 20,
14+
"name": "div",
15+
"attributes": [],
16+
"fragment": {
17+
"type": "Fragment",
18+
"nodes": [
19+
{
20+
"type": "Text",
21+
"start": 5,
22+
"end": 7,
23+
"raw": "\n\t",
24+
"data": "\n\t"
25+
},
26+
{
27+
"type": "Component",
28+
"start": 7,
29+
"end": 14,
30+
"name": "Comp",
31+
"attributes": [],
32+
"fragment": {
33+
"type": "Fragment",
34+
"nodes": [
35+
{
36+
"type": "Text",
37+
"start": 13,
38+
"end": 14,
39+
"raw": "\n",
40+
"data": "\n"
41+
}
42+
]
43+
}
44+
}
45+
]
46+
}
47+
},
48+
{
49+
"type": "Text",
50+
"start": 20,
51+
"end": 22,
52+
"raw": "\n\n",
53+
"data": "\n\n"
54+
},
55+
{
56+
"type": "RegularElement",
57+
"start": 22,
58+
"end": 42,
59+
"name": "div",
60+
"attributes": [],
61+
"fragment": {
62+
"type": "Fragment",
63+
"nodes": [
64+
{
65+
"type": "Text",
66+
"start": 27,
67+
"end": 29,
68+
"raw": "\n\t",
69+
"data": "\n\t"
70+
},
71+
{
72+
"type": "RegularElement",
73+
"start": 29,
74+
"end": 36,
75+
"name": "span",
76+
"attributes": [],
77+
"fragment": {
78+
"type": "Fragment",
79+
"nodes": [
80+
{
81+
"type": "Text",
82+
"start": 35,
83+
"end": 36,
84+
"raw": "\n",
85+
"data": "\n"
86+
}
87+
]
88+
}
89+
}
90+
]
91+
}
92+
},
93+
{
94+
"type": "Text",
95+
"start": 42,
96+
"end": 44,
97+
"raw": "\n\n",
98+
"data": "\n\n"
99+
},
100+
{
101+
"type": "RegularElement",
102+
"start": 44,
103+
"end": 59,
104+
"name": "div",
105+
"attributes": [],
106+
"fragment": {
107+
"type": "Fragment",
108+
"nodes": [
109+
{
110+
"type": "Text",
111+
"start": 49,
112+
"end": 50,
113+
"raw": "\n",
114+
"data": "\n"
115+
},
116+
{
117+
"type": "RegularElement",
118+
"start": 50,
119+
"end": 59,
120+
"name": "p",
121+
"attributes": [],
122+
"fragment": {
123+
"type": "Fragment",
124+
"nodes": [
125+
{
126+
"type": "Text",
127+
"start": 53,
128+
"end": 55,
129+
"raw": "hi",
130+
"data": "hi"
131+
}
132+
]
133+
}
134+
}
135+
]
136+
}
137+
}
138+
]
139+
},
140+
"options": null
141+
}

packages/svelte/tests/parser-modern/test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ const { test, run } = suite<ParserTest>(async (config, cwd) => {
1515
const actual = JSON.parse(
1616
JSON.stringify(
1717
parse(input, {
18-
modern: true
18+
modern: true,
19+
loose: cwd.split('/').pop()!.startsWith('loose-')
1920
})
2021
)
2122
);

0 commit comments

Comments
 (0)