feat better error message for else,elseif,then,catch with unclosed tag

pull/4136/head
Tan Li Hau 6 years ago
parent 709b4d30ff
commit 35ea2468de

@ -82,6 +82,15 @@ export class Parser {
return this.stack[this.stack.length - 1]; 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) { acorn_error(err: any) {
this.error({ this.error({
code: `parse-error`, code: `parse-error`,

@ -3,6 +3,7 @@ import read_expression from '../read/expression';
import { closing_tag_omitted } from '../utils/html'; import { closing_tag_omitted } from '../utils/html';
import { whitespace } from '../../utils/patterns'; import { whitespace } from '../../utils/patterns';
import { trim_start, trim_end } from '../../utils/trim'; import { trim_start, trim_end } from '../../utils/trim';
import { to_string } from '../utils/node';
import { Parser } from '../index'; import { Parser } from '../index';
import { TemplateNode } from '../../interfaces'; import { TemplateNode } from '../../interfaces';
@ -106,11 +107,19 @@ export default function mustache(parser: Parser) {
// :else if // :else if
if (parser.eat('if')) { if (parser.eat('if')) {
const block = parser.current(); 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({ parser.error({
code: `invalid-elseif-placement`, code: `invalid-elseif-placement`,
message: 'Cannot have an {:else if ...} block outside an {#if ...} block' message: 'Cannot have an {:else if ...} block outside an {#if ...} block'
}); });
}
parser.require_whitespace(); parser.require_whitespace();
@ -142,6 +151,13 @@ export default function mustache(parser: Parser) {
else { else {
const block = parser.current(); const block = parser.current();
if (block.type !== 'IfBlock' && block.type !== 'EachBlock') { 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({ parser.error({
code: `invalid-else-placement`, code: `invalid-else-placement`,
message: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block' message: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block'
@ -166,6 +182,12 @@ export default function mustache(parser: Parser) {
if (is_then) { if (is_then) {
if (block.type !== 'PendingBlock') { 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({ parser.error({
code: `invalid-then-placement`, code: `invalid-then-placement`,
message: 'Cannot have an {:then} block outside an {#await ...} block' message: 'Cannot have an {:then} block outside an {#await ...} block'
@ -173,6 +195,12 @@ export default function mustache(parser: Parser) {
} }
} else { } else {
if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') { 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({ parser.error({
code: `invalid-catch-placement`, code: `invalid-catch-placement`,
message: 'Cannot have an {:catch} block outside an {#await ...} block' message: 'Cannot have an {:catch} block outside an {#await ...} block'

@ -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;
}
}

@ -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
}

@ -0,0 +1,4 @@
{#await true}
{#each foo as bar}
{:catch f}
{/await}

@ -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
}

@ -0,0 +1,4 @@
{#if true}
{#await p}
{:else}
{/if}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -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
}

@ -0,0 +1,4 @@
{#if true}
<p>
{:else if false}
{/if}

@ -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
}

@ -0,0 +1,4 @@
{#if true}
{#await foo}
{:else if false}
{/if}

@ -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
}

@ -0,0 +1,4 @@
{#await foo}
{:then bar}
{:else if}
{/await}

@ -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
}

@ -0,0 +1,4 @@
{#await true}
<li>
{:then f}
{/await}
Loading…
Cancel
Save