Skip to content

Commit

Permalink
feat better error message for else,elseif,then,catch with unclosed tag
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau committed Dec 21, 2019
1 parent 109639c commit 03e9ad4
Show file tree
Hide file tree
Showing 23 changed files with 164 additions and 1 deletion.
9 changes: 9 additions & 0 deletions src/compiler/parse/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ export class Parser {
return this.stack[this.stack.length - 1];
}

find_in_stack(fn) {
for (let i=this.stack.length -1; i>=0; i--) {
if (fn(this.stack[i])) {
return true;
}
}
return false;
}

acorn_error(err: any) {
this.error({
code: `parse-error`,
Expand Down
30 changes: 29 additions & 1 deletion src/compiler/parse/state/mustache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import read_expression from '../read/expression';
import { closing_tag_omitted } from '../utils/html';
import { whitespace } from '../../utils/patterns';
import { trim_start, trim_end } from '../../utils/trim';
import { to_string } from '../utils/node';
import { Parser } from '../index';
import { TemplateNode } from '../../interfaces';

Expand Down Expand Up @@ -106,11 +107,19 @@ export default function mustache(parser: Parser) {
// :else if
if (parser.eat('if')) {
const block = parser.current();
if (block.type !== 'IfBlock')
if (block.type !== 'IfBlock') {
if (parser.find_in_stack(block => block.type === 'IfBlock')) {
parser.error({
code: 'unclosed-open-tag',
message: `Expect to close ${to_string(block)} before {:else if ...} block`
});
}

parser.error({
code: `invalid-elseif-placement`,
message: 'Cannot have an {:else if ...} block outside an {#if ...} block'
});
}

parser.require_whitespace();

Expand Down Expand Up @@ -142,6 +151,13 @@ export default function mustache(parser: Parser) {
else {
const block = parser.current();
if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
if (parser.find_in_stack(block => block.type === 'IfBlock' || block.type === 'EachBlock')) {
parser.error({
code: 'unclosed-open-tag',
message: `Expect to close ${to_string(block)} before {:else} block`
});
}

parser.error({
code: `invalid-else-placement`,
message: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block'
Expand All @@ -166,13 +182,25 @@ export default function mustache(parser: Parser) {

if (is_then) {
if (block.type !== 'PendingBlock') {
if (parser.find_in_stack(block => block.type === 'PendingBlock')) {
parser.error({
code: 'unclosed-open-tag',
message: `Expect to close ${to_string(block)} before {:then} block`
});
}
parser.error({
code: `invalid-then-placement`,
message: 'Cannot have an {:then} block outside an {#await ...} block'
});
}
} else {
if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') {
if (parser.find_in_stack(block => block.type === 'ThenBlock' || block.type === 'PendingBlock')) {
parser.error({
code: 'unclosed-open-tag',
message: `Expect to close ${to_string(block)} before {:catch} block`
});
}
parser.error({
code: `invalid-catch-placement`,
message: 'Cannot have an {:catch} block outside an {#await ...} block'
Expand Down
30 changes: 30 additions & 0 deletions src/compiler/parse/utils/node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { TemplateNode } from '../../interfaces';

export function to_string(node: TemplateNode) {
switch (node.type) {
case 'IfBlock':
return '{#if} block';
case 'ThenBlock':
return '{:then} block';
case 'ElseBlock':
return '{:else} block';
case 'PendingBlock':
case 'AwaitBlock':
return '{#await} block';
case 'CatchBlock':
return '{:catch} block';
case 'EachBlock':
return '{#each} block';
case 'RawMustacheTag':
return '{@html} block';
case 'DebugTag':
return '{@debug} block';
case 'Element':
case 'InlineComponent':
case 'Slot':
case 'Title':
return `<${node.name}> tag`;
default:
return node.type;
}
}
6 changes: 6 additions & 0 deletions test/parser/samples/error-catch-before-closing/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "unclosed-open-tag",
"message": "Expect to close {#each} block before {:catch} block",
"start": { "line": 3, "column": 9, "character": 44 },
"pos": 44
}
4 changes: 4 additions & 0 deletions test/parser/samples/error-catch-before-closing/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{#await true}
{#each foo as bar}
{:catch f}
{/await}
6 changes: 6 additions & 0 deletions test/parser/samples/error-else-before-closing-2/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "unclosed-open-tag",
"message": "Expect to close {#await} block before {:else} block",
"start": { "line": 3, "column": 8, "character": 32 },
"pos": 32
}
4 changes: 4 additions & 0 deletions test/parser/samples/error-else-before-closing-2/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{#if true}
{#await p}
{:else}
{/if}
6 changes: 6 additions & 0 deletions test/parser/samples/error-else-before-closing-3/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "invalid-else-placement",
"message": "Cannot have an {:else} block outside an {#if ...} or {#each ...} block",
"start": { "line": 2, "column": 6, "character": 11 },
"pos": 11
}
2 changes: 2 additions & 0 deletions test/parser/samples/error-else-before-closing-3/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<li>
{:else}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "unclosed-open-tag",
"message": "Expect to close {#await} block before {:else} block",
"start": { "line": 3, "column": 8, "character": 32 },
"pos": 32
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{#if true}
{#await p}
{:else}
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "invalid-else-placement",
"message": "Cannot have an {:else} block outside an {#if ...} or {#each ...} block",
"start": { "line": 2, "column": 6, "character": 11 },
"pos": 11
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<li>
{:else}
6 changes: 6 additions & 0 deletions test/parser/samples/error-else-before-closing/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "unclosed-open-tag",
"message": "Expect to close <li> tag before {:else} block",
"start": { "line": 3, "column": 8, "character": 26 },
"pos": 26
}
4 changes: 4 additions & 0 deletions test/parser/samples/error-else-before-closing/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{#if true}
<li>
{:else}
{/if}
6 changes: 6 additions & 0 deletions test/parser/samples/error-else-if-before-closing-2/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "unclosed-open-tag",
"message": "Expect to close <p> tag before {:else if ...} block",
"start": { "line": 3, "column": 11, "character": 28 },
"pos": 28
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{#if true}
<p>
{:else if false}
{/if}
6 changes: 6 additions & 0 deletions test/parser/samples/error-else-if-before-closing/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "unclosed-open-tag",
"message": "Expect to close {#await} block before {:else if ...} block",
"start": { "line": 3, "column": 11, "character": 37 },
"pos": 37
}
4 changes: 4 additions & 0 deletions test/parser/samples/error-else-if-before-closing/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{#if true}
{#await foo}
{:else if false}
{/if}
6 changes: 6 additions & 0 deletions test/parser/samples/error-else-if-without-if/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "invalid-elseif-placement",
"message": "Cannot have an {:else if ...} block outside an {#if ...} block",
"start": { "line": 3, "column": 11, "character": 36 },
"pos": 36
}
4 changes: 4 additions & 0 deletions test/parser/samples/error-else-if-without-if/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{#await foo}
{:then bar}
{:else if}
{/await}
6 changes: 6 additions & 0 deletions test/parser/samples/error-then-before-closing/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"code": "unclosed-open-tag",
"message": "Expect to close <li> tag before {:then} block",
"start": { "line": 3, "column": 8, "character": 29 },
"pos": 29
}
4 changes: 4 additions & 0 deletions test/parser/samples/error-then-before-closing/input.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{#await true}
<li>
{:then f}
{/await}

0 comments on commit 03e9ad4

Please sign in to comment.