handle unclosed blocks

pull/14691/head
Simon Holthausen 2 years ago
parent 6994021ef9
commit 7337612af4

@ -164,14 +164,15 @@ export class Parser {
/**
* @param {string} str
* @param {boolean} required
* @param {boolean} required_in_loose
*/
eat(str, required = false) {
eat(str, required = false, required_in_loose = true) {
if (this.match(str)) {
this.index += str.length;
return true;
}
if (required) {
if (required && (!this.loose || required_in_loose)) {
e.expected_token(this.index, str);
}

@ -454,43 +454,66 @@ function close(parser) {
const start = parser.index - 1;
let block = parser.current();
/** Only relevant/reached for loose parsing mode */
let matched;
switch (block.type) {
case 'IfBlock':
parser.eat('if', true);
matched = parser.eat('if', true, false);
if (!matched) {
block.end = start - 1;
parser.pop();
close(parser);
return;
}
parser.allow_whitespace();
parser.eat('}', true);
while (block.elseif) {
block.end = parser.index;
parser.stack.pop();
block = /** @type {AST.IfBlock} */ (parser.current());
}
block.end = parser.index;
parser.pop();
return;
case 'EachBlock':
parser.eat('each', true);
matched = parser.eat('each', true, false);
break;
case 'KeyBlock':
parser.eat('key', true);
matched = parser.eat('key', true, false);
break;
case 'AwaitBlock':
parser.eat('await', true);
matched = parser.eat('await', true, false);
break;
case 'SnippetBlock':
parser.eat('snippet', true);
matched = parser.eat('snippet', true, false);
break;
case 'RegularElement':
// TODO handle implicitly closed elements
e.block_unexpected_close(start);
if (parser.loose) {
matched = false;
} else {
// TODO handle implicitly closed elements
e.block_unexpected_close(start);
}
break;
default:
e.block_unexpected_close(start);
}
if (!matched) {
block.end = start - 1;
parser.pop();
close(parser);
return;
}
parser.allow_whitespace();
parser.eat('}', true);
block.end = parser.index;

@ -0,0 +1,20 @@
<div>
{#if foo}
</div>
<Comp>
{#key bar}
</Comp>
<div>
{#if foo}
{#if bar}
{/if}
</div>
{#if foo}
{#key bar}
{/if}
{#each x as y}
<p>hi</p>

@ -0,0 +1,276 @@
{
"html": {
"type": "Fragment",
"start": 0,
"end": 150,
"children": [
{
"type": "Element",
"start": 0,
"end": 23,
"name": "div",
"attributes": [],
"children": [
{
"type": "Text",
"start": 5,
"end": 7,
"raw": "\n\t",
"data": "\n\t"
},
{
"type": "IfBlock",
"start": 7,
"end": 17,
"expression": {
"type": "Identifier",
"start": 12,
"end": 15,
"loc": {
"start": {
"line": 2,
"column": 6
},
"end": {
"line": 2,
"column": 9
}
},
"name": "foo"
},
"children": []
}
]
},
{
"type": "Text",
"start": 23,
"end": 25,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "InlineComponent",
"start": 25,
"end": 51,
"name": "Comp",
"attributes": [],
"children": [
{
"type": "Text",
"start": 31,
"end": 33,
"raw": "\n\t",
"data": "\n\t"
},
{
"type": "KeyBlock",
"start": 33,
"end": 44,
"expression": {
"type": "Identifier",
"start": 39,
"end": 42,
"loc": {
"start": {
"line": 6,
"column": 7
},
"end": {
"line": 6,
"column": 10
}
},
"name": "bar"
},
"children": []
}
]
},
{
"type": "Text",
"start": 51,
"end": 53,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "Element",
"start": 53,
"end": 95,
"name": "div",
"attributes": [],
"children": [
{
"type": "Text",
"start": 58,
"end": 60,
"raw": "\n\t",
"data": "\n\t"
},
{
"type": "IfBlock",
"start": 60,
"end": 89,
"expression": {
"type": "Identifier",
"start": 65,
"end": 68,
"loc": {
"start": {
"line": 10,
"column": 6
},
"end": {
"line": 10,
"column": 9
}
},
"name": "foo"
},
"children": [
{
"type": "IfBlock",
"start": 72,
"end": 88,
"expression": {
"type": "Identifier",
"start": 77,
"end": 80,
"loc": {
"start": {
"line": 11,
"column": 7
},
"end": {
"line": 11,
"column": 10
}
},
"name": "bar"
},
"children": []
}
]
}
]
},
{
"type": "Text",
"start": 95,
"end": 97,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "IfBlock",
"start": 97,
"end": 124,
"expression": {
"type": "Identifier",
"start": 102,
"end": 105,
"loc": {
"start": {
"line": 15,
"column": 5
},
"end": {
"line": 15,
"column": 8
}
},
"name": "foo"
},
"children": [
{
"type": "KeyBlock",
"start": 108,
"end": 119,
"expression": {
"type": "Identifier",
"start": 114,
"end": 117,
"loc": {
"start": {
"line": 16,
"column": 7
},
"end": {
"line": 16,
"column": 10
}
},
"name": "bar"
},
"children": []
}
]
},
{
"type": "Text",
"start": 124,
"end": 126,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "EachBlock",
"start": 126,
"end": 150,
"children": [
{
"type": "Element",
"start": 141,
"end": 150,
"name": "p",
"attributes": [],
"children": [
{
"type": "Text",
"start": 144,
"end": 146,
"raw": "hi",
"data": "hi"
}
]
}
],
"context": {
"type": "Identifier",
"name": "y",
"start": 138,
"loc": {
"start": {
"line": 19,
"column": 12,
"character": 138
},
"end": {
"line": 19,
"column": 13,
"character": 139
}
},
"end": 139
},
"expression": {
"type": "Identifier",
"start": 133,
"end": 134,
"loc": {
"start": {
"line": 19,
"column": 7
},
"end": {
"line": 19,
"column": 8
}
},
"name": "x"
}
}
]
}
}

@ -6,5 +6,9 @@
<span>
</div>
{#if foo}
<div>
{/if}
<div>
<p>hi</p>

@ -2,7 +2,7 @@
"html": {
"type": "Fragment",
"start": 0,
"end": 59,
"end": 83,
"children": [
{
"type": "Element",
@ -83,30 +83,76 @@
"data": "\n\n"
},
{
"type": "Element",
"type": "IfBlock",
"start": 44,
"end": 59,
"end": 66,
"expression": {
"type": "Identifier",
"start": 49,
"end": 52,
"loc": {
"start": {
"line": 9,
"column": 5
},
"end": {
"line": 9,
"column": 8
}
},
"name": "foo"
},
"children": [
{
"type": "Element",
"start": 55,
"end": 61,
"name": "div",
"attributes": [],
"children": [
{
"type": "Text",
"start": 60,
"end": 61,
"raw": "\n",
"data": "\n"
}
]
}
]
},
{
"type": "Text",
"start": 66,
"end": 68,
"raw": "\n\n",
"data": "\n\n"
},
{
"type": "Element",
"start": 68,
"end": 83,
"name": "div",
"attributes": [],
"children": [
{
"type": "Text",
"start": 49,
"end": 50,
"start": 73,
"end": 74,
"raw": "\n",
"data": "\n"
},
{
"type": "Element",
"start": 50,
"end": 59,
"start": 74,
"end": 83,
"name": "p",
"attributes": [],
"children": [
{
"type": "Text",
"start": 53,
"end": 55,
"start": 77,
"end": 79,
"raw": "hi",
"data": "hi"
}

Loading…
Cancel
Save