From 35ea2468de3f72acb6f6b1899f5ee8f00ef688c1 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sat, 21 Dec 2019 12:14:22 +0800 Subject: [PATCH 1/7] feat better error message for else,elseif,then,catch with unclosed tag --- src/compiler/parse/index.ts | 9 ++++++ src/compiler/parse/state/mustache.ts | 30 ++++++++++++++++++- src/compiler/parse/utils/node.ts | 30 +++++++++++++++++++ .../error-catch-before-closing/error.json | 6 ++++ .../error-catch-before-closing/input.svelte | 4 +++ .../error-else-before-closing-2/error.json | 6 ++++ .../error-else-before-closing-2/input.svelte | 4 +++ .../error-else-before-closing-3/error.json | 6 ++++ .../error-else-before-closing-3/input.svelte | 2 ++ .../error-else-before-closing-2/error.json | 6 ++++ .../error-else-before-closing-2/input.svelte | 4 +++ .../error-else-before-closing-3/error.json | 6 ++++ .../error-else-before-closing-3/input.svelte | 2 ++ .../error-else-before-closing/error.json | 6 ++++ .../error-else-before-closing/input.svelte | 4 +++ .../error-else-if-before-closing-2/error.json | 6 ++++ .../input.svelte | 4 +++ .../error-else-if-before-closing/error.json | 6 ++++ .../error-else-if-before-closing/input.svelte | 4 +++ .../error-else-if-without-if/error.json | 6 ++++ .../error-else-if-without-if/input.svelte | 4 +++ .../error-then-before-closing/error.json | 6 ++++ .../error-then-before-closing/input.svelte | 4 +++ 23 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/compiler/parse/utils/node.ts create mode 100644 test/parser/samples/error-catch-before-closing/error.json create mode 100644 test/parser/samples/error-catch-before-closing/input.svelte create mode 100644 test/parser/samples/error-else-before-closing-2/error.json create mode 100644 test/parser/samples/error-else-before-closing-2/input.svelte create mode 100644 test/parser/samples/error-else-before-closing-3/error.json create mode 100644 test/parser/samples/error-else-before-closing-3/input.svelte create mode 100644 test/parser/samples/error-else-before-closing/error-else-before-closing-2/error.json create mode 100644 test/parser/samples/error-else-before-closing/error-else-before-closing-2/input.svelte create mode 100644 test/parser/samples/error-else-before-closing/error-else-before-closing-3/error.json create mode 100644 test/parser/samples/error-else-before-closing/error-else-before-closing-3/input.svelte create mode 100644 test/parser/samples/error-else-before-closing/error.json create mode 100644 test/parser/samples/error-else-before-closing/input.svelte create mode 100644 test/parser/samples/error-else-if-before-closing-2/error.json create mode 100644 test/parser/samples/error-else-if-before-closing-2/input.svelte create mode 100644 test/parser/samples/error-else-if-before-closing/error.json create mode 100644 test/parser/samples/error-else-if-before-closing/input.svelte create mode 100644 test/parser/samples/error-else-if-without-if/error.json create mode 100644 test/parser/samples/error-else-if-without-if/input.svelte create mode 100644 test/parser/samples/error-then-before-closing/error.json create mode 100644 test/parser/samples/error-then-before-closing/input.svelte diff --git a/src/compiler/parse/index.ts b/src/compiler/parse/index.ts index e5523746980f..fed39f6bfd01 100644 --- a/src/compiler/parse/index.ts +++ b/src/compiler/parse/index.ts @@ -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`, diff --git a/src/compiler/parse/state/mustache.ts b/src/compiler/parse/state/mustache.ts index 140e722b1027..a0241fe8b9f1 100644 --- a/src/compiler/parse/state/mustache.ts +++ b/src/compiler/parse/state/mustache.ts @@ -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'; @@ -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(); @@ -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' @@ -166,6 +182,12 @@ 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' @@ -173,6 +195,12 @@ export default function mustache(parser: Parser) { } } 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' diff --git a/src/compiler/parse/utils/node.ts b/src/compiler/parse/utils/node.ts new file mode 100644 index 000000000000..0d39529b5941 --- /dev/null +++ b/src/compiler/parse/utils/node.ts @@ -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; + } +} diff --git a/test/parser/samples/error-catch-before-closing/error.json b/test/parser/samples/error-catch-before-closing/error.json new file mode 100644 index 000000000000..6bc5ebc7fe84 --- /dev/null +++ b/test/parser/samples/error-catch-before-closing/error.json @@ -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 +} diff --git a/test/parser/samples/error-catch-before-closing/input.svelte b/test/parser/samples/error-catch-before-closing/input.svelte new file mode 100644 index 000000000000..9f4cf29f2682 --- /dev/null +++ b/test/parser/samples/error-catch-before-closing/input.svelte @@ -0,0 +1,4 @@ +{#await true} + {#each foo as bar} + {:catch f} +{/await} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing-2/error.json b/test/parser/samples/error-else-before-closing-2/error.json new file mode 100644 index 000000000000..c15b47bbb9ed --- /dev/null +++ b/test/parser/samples/error-else-before-closing-2/error.json @@ -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 +} diff --git a/test/parser/samples/error-else-before-closing-2/input.svelte b/test/parser/samples/error-else-before-closing-2/input.svelte new file mode 100644 index 000000000000..f4098bc521bd --- /dev/null +++ b/test/parser/samples/error-else-before-closing-2/input.svelte @@ -0,0 +1,4 @@ +{#if true} + {#await p} + {:else} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing-3/error.json b/test/parser/samples/error-else-before-closing-3/error.json new file mode 100644 index 000000000000..e5ec210c759d --- /dev/null +++ b/test/parser/samples/error-else-before-closing-3/error.json @@ -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 +} diff --git a/test/parser/samples/error-else-before-closing-3/input.svelte b/test/parser/samples/error-else-before-closing-3/input.svelte new file mode 100644 index 000000000000..fb434f26a3c1 --- /dev/null +++ b/test/parser/samples/error-else-before-closing-3/input.svelte @@ -0,0 +1,2 @@ +
  • +{:else} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing/error-else-before-closing-2/error.json b/test/parser/samples/error-else-before-closing/error-else-before-closing-2/error.json new file mode 100644 index 000000000000..c15b47bbb9ed --- /dev/null +++ b/test/parser/samples/error-else-before-closing/error-else-before-closing-2/error.json @@ -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 +} diff --git a/test/parser/samples/error-else-before-closing/error-else-before-closing-2/input.svelte b/test/parser/samples/error-else-before-closing/error-else-before-closing-2/input.svelte new file mode 100644 index 000000000000..f4098bc521bd --- /dev/null +++ b/test/parser/samples/error-else-before-closing/error-else-before-closing-2/input.svelte @@ -0,0 +1,4 @@ +{#if true} + {#await p} + {:else} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing/error-else-before-closing-3/error.json b/test/parser/samples/error-else-before-closing/error-else-before-closing-3/error.json new file mode 100644 index 000000000000..e5ec210c759d --- /dev/null +++ b/test/parser/samples/error-else-before-closing/error-else-before-closing-3/error.json @@ -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 +} diff --git a/test/parser/samples/error-else-before-closing/error-else-before-closing-3/input.svelte b/test/parser/samples/error-else-before-closing/error-else-before-closing-3/input.svelte new file mode 100644 index 000000000000..fb434f26a3c1 --- /dev/null +++ b/test/parser/samples/error-else-before-closing/error-else-before-closing-3/input.svelte @@ -0,0 +1,2 @@ +
  • +{:else} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing/error.json b/test/parser/samples/error-else-before-closing/error.json new file mode 100644 index 000000000000..c3a8c74cf06f --- /dev/null +++ b/test/parser/samples/error-else-before-closing/error.json @@ -0,0 +1,6 @@ +{ + "code": "unclosed-open-tag", + "message": "Expect to close
  • tag before {:else} block", + "start": { "line": 3, "column": 8, "character": 26 }, + "pos": 26 +} diff --git a/test/parser/samples/error-else-before-closing/input.svelte b/test/parser/samples/error-else-before-closing/input.svelte new file mode 100644 index 000000000000..51c23b2a30a2 --- /dev/null +++ b/test/parser/samples/error-else-before-closing/input.svelte @@ -0,0 +1,4 @@ +{#if true} +
  • + {:else} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-before-closing-2/error.json b/test/parser/samples/error-else-if-before-closing-2/error.json new file mode 100644 index 000000000000..717d51044270 --- /dev/null +++ b/test/parser/samples/error-else-if-before-closing-2/error.json @@ -0,0 +1,6 @@ +{ + "code": "unclosed-open-tag", + "message": "Expect to close

    tag before {:else if ...} block", + "start": { "line": 3, "column": 11, "character": 28 }, + "pos": 28 +} diff --git a/test/parser/samples/error-else-if-before-closing-2/input.svelte b/test/parser/samples/error-else-if-before-closing-2/input.svelte new file mode 100644 index 000000000000..03fb7726cba9 --- /dev/null +++ b/test/parser/samples/error-else-if-before-closing-2/input.svelte @@ -0,0 +1,4 @@ +{#if true} +

    + {:else if false} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-before-closing/error.json b/test/parser/samples/error-else-if-before-closing/error.json new file mode 100644 index 000000000000..3d9120fc0f90 --- /dev/null +++ b/test/parser/samples/error-else-if-before-closing/error.json @@ -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 +} diff --git a/test/parser/samples/error-else-if-before-closing/input.svelte b/test/parser/samples/error-else-if-before-closing/input.svelte new file mode 100644 index 000000000000..b6684a9496e0 --- /dev/null +++ b/test/parser/samples/error-else-if-before-closing/input.svelte @@ -0,0 +1,4 @@ +{#if true} + {#await foo} + {:else if false} +{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-without-if/error.json b/test/parser/samples/error-else-if-without-if/error.json new file mode 100644 index 000000000000..1ff8aa45b8ca --- /dev/null +++ b/test/parser/samples/error-else-if-without-if/error.json @@ -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 +} diff --git a/test/parser/samples/error-else-if-without-if/input.svelte b/test/parser/samples/error-else-if-without-if/input.svelte new file mode 100644 index 000000000000..084cf7434637 --- /dev/null +++ b/test/parser/samples/error-else-if-without-if/input.svelte @@ -0,0 +1,4 @@ +{#await foo} +{:then bar} + {:else if} +{/await} \ No newline at end of file diff --git a/test/parser/samples/error-then-before-closing/error.json b/test/parser/samples/error-then-before-closing/error.json new file mode 100644 index 000000000000..22e08f2bd622 --- /dev/null +++ b/test/parser/samples/error-then-before-closing/error.json @@ -0,0 +1,6 @@ +{ + "code": "unclosed-open-tag", + "message": "Expect to close

  • tag before {:then} block", + "start": { "line": 3, "column": 8, "character": 29 }, + "pos": 29 +} diff --git a/test/parser/samples/error-then-before-closing/input.svelte b/test/parser/samples/error-then-before-closing/input.svelte new file mode 100644 index 000000000000..720b292fe733 --- /dev/null +++ b/test/parser/samples/error-then-before-closing/input.svelte @@ -0,0 +1,4 @@ +{#await true} +
  • + {:then f} +{/await} \ No newline at end of file From 4e3f840c790ff85a32939e62d1ebd33bae974aa3 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Wed, 25 Dec 2019 00:23:51 +0800 Subject: [PATCH 2/7] add test prevent false positive --- .../no-error-if-before-closing/input.svelte | 19 ++ .../no-error-if-before-closing/output.json | 218 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 test/parser/samples/no-error-if-before-closing/input.svelte create mode 100644 test/parser/samples/no-error-if-before-closing/output.json diff --git a/test/parser/samples/no-error-if-before-closing/input.svelte b/test/parser/samples/no-error-if-before-closing/input.svelte new file mode 100644 index 000000000000..7a1cc93fbd57 --- /dev/null +++ b/test/parser/samples/no-error-if-before-closing/input.svelte @@ -0,0 +1,19 @@ +{#if true} + +{:else} +{/if} + +{#if true} +
    +{:else} +{/if} + +{#await true} + +{:then f} +{/await} + +{#await true} +
    +{:then f} +{/await} \ No newline at end of file diff --git a/test/parser/samples/no-error-if-before-closing/output.json b/test/parser/samples/no-error-if-before-closing/output.json new file mode 100644 index 000000000000..283feee4e569 --- /dev/null +++ b/test/parser/samples/no-error-if-before-closing/output.json @@ -0,0 +1,218 @@ +{ + "html": { + "start": 0, + "end": 148, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 33, + "type": "IfBlock", + "expression": { + "type": "Literal", + "start": 5, + "end": 9, + "value": true, + "raw": "true" + }, + "children": [ + { + "start": 11, + "end": 19, + "type": "Element", + "name": "input", + "attributes": [], + "children": [] + } + ], + "else": { + "start": 27, + "end": 28, + "type": "ElseBlock", + "children": [] + } + }, + { + "start": 33, + "end": 35, + "type": "Text", + "raw": "\n\n", + "data": "\n\n" + }, + { + "start": 35, + "end": 65, + "type": "IfBlock", + "expression": { + "type": "Literal", + "start": 40, + "end": 44, + "value": true, + "raw": "true" + }, + "children": [ + { + "start": 46, + "end": 51, + "type": "Element", + "name": "br", + "attributes": [], + "children": [] + } + ], + "else": { + "start": 59, + "end": 60, + "type": "ElseBlock", + "children": [] + } + }, + { + "start": 65, + "end": 67, + "type": "Text", + "raw": "\n\n", + "data": "\n\n" + }, + { + "start": 67, + "end": 108, + "type": "AwaitBlock", + "expression": { + "type": "Literal", + "start": 75, + "end": 79, + "value": true, + "raw": "true" + }, + "value": "f", + "error": null, + "pending": { + "start": 80, + "end": 90, + "type": "PendingBlock", + "children": [ + { + "start": 80, + "end": 81, + "type": "Text", + "raw": "\n", + "data": "\n" + }, + { + "start": 81, + "end": 89, + "type": "Element", + "name": "input", + "attributes": [], + "children": [] + }, + { + "start": 89, + "end": 90, + "type": "Text", + "raw": "\n", + "data": "\n" + } + ], + "skip": false + }, + "then": { + "start": 90, + "end": 100, + "type": "ThenBlock", + "children": [ + { + "start": 99, + "end": 100, + "type": "Text", + "raw": "\n", + "data": "\n" + } + ], + "skip": false + }, + "catch": { + "start": null, + "end": null, + "type": "CatchBlock", + "children": [], + "skip": true + } + }, + { + "start": 108, + "end": 110, + "type": "Text", + "raw": "\n\n", + "data": "\n\n" + }, + { + "start": 110, + "end": 148, + "type": "AwaitBlock", + "expression": { + "type": "Literal", + "start": 118, + "end": 122, + "value": true, + "raw": "true" + }, + "value": "f", + "error": null, + "pending": { + "start": 123, + "end": 130, + "type": "PendingBlock", + "children": [ + { + "start": 123, + "end": 124, + "type": "Text", + "raw": "\n", + "data": "\n" + }, + { + "start": 124, + "end": 129, + "type": "Element", + "name": "br", + "attributes": [], + "children": [] + }, + { + "start": 129, + "end": 130, + "type": "Text", + "raw": "\n", + "data": "\n" + } + ], + "skip": false + }, + "then": { + "start": 130, + "end": 140, + "type": "ThenBlock", + "children": [ + { + "start": 139, + "end": 140, + "type": "Text", + "raw": "\n", + "data": "\n" + } + ], + "skip": false + }, + "catch": { + "start": null, + "end": null, + "type": "CatchBlock", + "children": [], + "skip": true + } + } + ] + } +} \ No newline at end of file From fb1961065eb82b56597762ec97a2ba037aa37c0a Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sat, 8 Feb 2020 23:13:52 -0500 Subject: [PATCH 3/7] simplify detection --- src/compiler/parse/index.ts | 9 --------- src/compiler/parse/state/mustache.ts | 8 ++++---- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/compiler/parse/index.ts b/src/compiler/parse/index.ts index fed39f6bfd01..e5523746980f 100644 --- a/src/compiler/parse/index.ts +++ b/src/compiler/parse/index.ts @@ -82,15 +82,6 @@ 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`, diff --git a/src/compiler/parse/state/mustache.ts b/src/compiler/parse/state/mustache.ts index a0241fe8b9f1..b04f0aab83b4 100644 --- a/src/compiler/parse/state/mustache.ts +++ b/src/compiler/parse/state/mustache.ts @@ -108,7 +108,7 @@ export default function mustache(parser: Parser) { if (parser.eat('if')) { const block = parser.current(); if (block.type !== 'IfBlock') { - if (parser.find_in_stack(block => block.type === 'IfBlock')) { + if (parser.stack.some(block => block.type === 'IfBlock')) { parser.error({ code: 'unclosed-open-tag', message: `Expect to close ${to_string(block)} before {:else if ...} block` @@ -151,7 +151,7 @@ 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')) { + if (parser.stack.some(block => block.type === 'IfBlock' || block.type === 'EachBlock')) { parser.error({ code: 'unclosed-open-tag', message: `Expect to close ${to_string(block)} before {:else} block` @@ -182,7 +182,7 @@ export default function mustache(parser: Parser) { if (is_then) { if (block.type !== 'PendingBlock') { - if (parser.find_in_stack(block => block.type === 'PendingBlock')) { + if (parser.stack.some(block => block.type === 'PendingBlock')) { parser.error({ code: 'unclosed-open-tag', message: `Expect to close ${to_string(block)} before {:then} block` @@ -195,7 +195,7 @@ export default function mustache(parser: Parser) { } } else { if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') { - if (parser.find_in_stack(block => block.type === 'ThenBlock' || block.type === 'PendingBlock')) { + if (parser.stack.some(block => block.type === 'ThenBlock' || block.type === 'PendingBlock')) { parser.error({ code: 'unclosed-open-tag', message: `Expect to close ${to_string(block)} before {:catch} block` From 6562fd518732712031c361a3a9d2e03c3b116af2 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sat, 8 Feb 2020 23:27:36 -0500 Subject: [PATCH 4/7] tidy tests --- .../samples/error-catch-before-closing/input.svelte | 4 ++-- .../samples/error-else-before-closing-2/input.svelte | 4 ++-- .../error-else-before-closing-2/error.json | 6 ------ .../error-else-before-closing-2/input.svelte | 4 ---- .../error-else-before-closing-3/error.json | 6 ------ .../error-else-before-closing-3/input.svelte | 2 -- .../parser/samples/error-else-before-closing/input.svelte | 4 ++-- .../samples/error-else-if-before-closing-2/input.svelte | 4 ++-- .../samples/error-else-if-before-closing/input.svelte | 4 ++-- test/parser/samples/error-else-if-without-if/input.svelte | 2 +- .../parser/samples/error-then-before-closing/input.svelte | 4 ++-- .../samples/no-error-if-before-closing/input.svelte | 8 ++++---- 12 files changed, 17 insertions(+), 35 deletions(-) delete mode 100644 test/parser/samples/error-else-before-closing/error-else-before-closing-2/error.json delete mode 100644 test/parser/samples/error-else-before-closing/error-else-before-closing-2/input.svelte delete mode 100644 test/parser/samples/error-else-before-closing/error-else-before-closing-3/error.json delete mode 100644 test/parser/samples/error-else-before-closing/error-else-before-closing-3/input.svelte diff --git a/test/parser/samples/error-catch-before-closing/input.svelte b/test/parser/samples/error-catch-before-closing/input.svelte index 9f4cf29f2682..bd771701e2b6 100644 --- a/test/parser/samples/error-catch-before-closing/input.svelte +++ b/test/parser/samples/error-catch-before-closing/input.svelte @@ -1,4 +1,4 @@ {#await true} - {#each foo as bar} - {:catch f} + {#each foo as bar} +{:catch f} {/await} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing-2/input.svelte b/test/parser/samples/error-else-before-closing-2/input.svelte index f4098bc521bd..f865a9a53306 100644 --- a/test/parser/samples/error-else-before-closing-2/input.svelte +++ b/test/parser/samples/error-else-before-closing-2/input.svelte @@ -1,4 +1,4 @@ {#if true} - {#await p} - {:else} + {#await p} +{:else} {/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing/error-else-before-closing-2/error.json b/test/parser/samples/error-else-before-closing/error-else-before-closing-2/error.json deleted file mode 100644 index c15b47bbb9ed..000000000000 --- a/test/parser/samples/error-else-before-closing/error-else-before-closing-2/error.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "code": "unclosed-open-tag", - "message": "Expect to close {#await} block before {:else} block", - "start": { "line": 3, "column": 8, "character": 32 }, - "pos": 32 -} diff --git a/test/parser/samples/error-else-before-closing/error-else-before-closing-2/input.svelte b/test/parser/samples/error-else-before-closing/error-else-before-closing-2/input.svelte deleted file mode 100644 index f4098bc521bd..000000000000 --- a/test/parser/samples/error-else-before-closing/error-else-before-closing-2/input.svelte +++ /dev/null @@ -1,4 +0,0 @@ -{#if true} - {#await p} - {:else} -{/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing/error-else-before-closing-3/error.json b/test/parser/samples/error-else-before-closing/error-else-before-closing-3/error.json deleted file mode 100644 index e5ec210c759d..000000000000 --- a/test/parser/samples/error-else-before-closing/error-else-before-closing-3/error.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "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 -} diff --git a/test/parser/samples/error-else-before-closing/error-else-before-closing-3/input.svelte b/test/parser/samples/error-else-before-closing/error-else-before-closing-3/input.svelte deleted file mode 100644 index fb434f26a3c1..000000000000 --- a/test/parser/samples/error-else-before-closing/error-else-before-closing-3/input.svelte +++ /dev/null @@ -1,2 +0,0 @@ -
  • -{:else} \ No newline at end of file diff --git a/test/parser/samples/error-else-before-closing/input.svelte b/test/parser/samples/error-else-before-closing/input.svelte index 51c23b2a30a2..a22863192da2 100644 --- a/test/parser/samples/error-else-before-closing/input.svelte +++ b/test/parser/samples/error-else-before-closing/input.svelte @@ -1,4 +1,4 @@ {#if true} -
  • - {:else} +
  • +{:else} {/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-before-closing-2/input.svelte b/test/parser/samples/error-else-if-before-closing-2/input.svelte index 03fb7726cba9..5ae36df4eb08 100644 --- a/test/parser/samples/error-else-if-before-closing-2/input.svelte +++ b/test/parser/samples/error-else-if-before-closing-2/input.svelte @@ -1,4 +1,4 @@ {#if true} -

    - {:else if false} +

    +{:else if false} {/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-before-closing/input.svelte b/test/parser/samples/error-else-if-before-closing/input.svelte index b6684a9496e0..486a921a9a49 100644 --- a/test/parser/samples/error-else-if-before-closing/input.svelte +++ b/test/parser/samples/error-else-if-before-closing/input.svelte @@ -1,4 +1,4 @@ {#if true} - {#await foo} - {:else if false} + {#await foo} +{:else if false} {/if} \ No newline at end of file diff --git a/test/parser/samples/error-else-if-without-if/input.svelte b/test/parser/samples/error-else-if-without-if/input.svelte index 084cf7434637..06baf335111b 100644 --- a/test/parser/samples/error-else-if-without-if/input.svelte +++ b/test/parser/samples/error-else-if-without-if/input.svelte @@ -1,4 +1,4 @@ {#await foo} {:then bar} - {:else if} + {:else if} {/await} \ No newline at end of file diff --git a/test/parser/samples/error-then-before-closing/input.svelte b/test/parser/samples/error-then-before-closing/input.svelte index 720b292fe733..bb0b993bdfe7 100644 --- a/test/parser/samples/error-then-before-closing/input.svelte +++ b/test/parser/samples/error-then-before-closing/input.svelte @@ -1,4 +1,4 @@ {#await true} -

  • - {:then f} +
  • +{:then f} {/await} \ No newline at end of file diff --git a/test/parser/samples/no-error-if-before-closing/input.svelte b/test/parser/samples/no-error-if-before-closing/input.svelte index 7a1cc93fbd57..4059e0d4d108 100644 --- a/test/parser/samples/no-error-if-before-closing/input.svelte +++ b/test/parser/samples/no-error-if-before-closing/input.svelte @@ -1,19 +1,19 @@ {#if true} - + {:else} {/if} {#if true} -
    +
    {:else} {/if} {#await true} - + {:then f} {/await} {#await true} -
    +
    {:then f} {/await} \ No newline at end of file From 1c8329e15d4889d22daeb757b0211175a6c7507b Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sat, 8 Feb 2020 23:40:58 -0500 Subject: [PATCH 5/7] simplify parser errors --- src/compiler/parse/state/mustache.ts | 42 ++++++++-------------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/src/compiler/parse/state/mustache.ts b/src/compiler/parse/state/mustache.ts index b04f0aab83b4..e5e365dddfaf 100644 --- a/src/compiler/parse/state/mustache.ts +++ b/src/compiler/parse/state/mustache.ts @@ -108,16 +108,11 @@ export default function mustache(parser: Parser) { if (parser.eat('if')) { const block = parser.current(); if (block.type !== 'IfBlock') { - if (parser.stack.some(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' + message: parser.stack.some(block => block.type === 'IfBlock') + ? `Expected to close ${to_string(block)} before seeing {:else if ...} block` + : `Cannot have an {:else if ...} block outside an {#if ...} block` }); } @@ -151,16 +146,11 @@ export default function mustache(parser: Parser) { else { const block = parser.current(); if (block.type !== 'IfBlock' && block.type !== 'EachBlock') { - if (parser.stack.some(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' + message: parser.stack.some(block => block.type === 'IfBlock' || block.type === 'EachBlock') + ? `Expected to close ${to_string(block)} before seeing {:else} block` + : `Cannot have an {:else} block outside an {#if ...} or {#each ...} block` }); } @@ -182,28 +172,20 @@ export default function mustache(parser: Parser) { if (is_then) { if (block.type !== 'PendingBlock') { - if (parser.stack.some(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' + message: parser.stack.some(block => block.type === 'PendingBlock') + ? `Expected to close ${to_string(block)} before seeing {:then} block` + : `Cannot have an {:then} block outside an {#await ...} block` }); } } else { if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') { - if (parser.stack.some(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' + message: parser.stack.some(block => block.type === 'ThenBlock' || block.type === 'PendingBlock') + ? `Expected to close ${to_string(block)} before seeing {:catch} block` + : `Cannot have an {:catch} block outside an {#await ...} block` }); } } From b1b48bc7f4f9c037d09f16ad71f99691904cb87c Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sat, 8 Feb 2020 23:55:10 -0500 Subject: [PATCH 6/7] update tests --- .../error-catch-before-closing/error.json | 8 ++++---- .../error-else-before-closing-2/error.json | 8 ++++---- .../error-else-before-closing/error.json | 8 ++++---- .../error-else-if-before-closing-2/error.json | 8 ++++---- .../error-else-if-before-closing/error.json | 8 ++++---- .../error-else-if-without-if/error.json | 4 ++-- .../error-then-before-closing/error.json | 8 ++++---- .../no-error-if-before-closing/output.json | 20 +++++++++---------- 8 files changed, 36 insertions(+), 36 deletions(-) diff --git a/test/parser/samples/error-catch-before-closing/error.json b/test/parser/samples/error-catch-before-closing/error.json index 6bc5ebc7fe84..30fbf5fbd523 100644 --- a/test/parser/samples/error-catch-before-closing/error.json +++ b/test/parser/samples/error-catch-before-closing/error.json @@ -1,6 +1,6 @@ { - "code": "unclosed-open-tag", - "message": "Expect to close {#each} block before {:catch} block", - "start": { "line": 3, "column": 9, "character": 44 }, - "pos": 44 + "code": "invalid-catch-placement", + "message": "Expected to close {#each} block before seeing {:catch} block", + "start": { "line": 3, "column": 7, "character": 41 }, + "pos": 41 } diff --git a/test/parser/samples/error-else-before-closing-2/error.json b/test/parser/samples/error-else-before-closing-2/error.json index c15b47bbb9ed..d35be1abf5e7 100644 --- a/test/parser/samples/error-else-before-closing-2/error.json +++ b/test/parser/samples/error-else-before-closing-2/error.json @@ -1,6 +1,6 @@ { - "code": "unclosed-open-tag", - "message": "Expect to close {#await} block before {:else} block", - "start": { "line": 3, "column": 8, "character": 32 }, - "pos": 32 + "code": "invalid-else-placement", + "message": "Expected to close {#await} block before seeing {:else} block", + "start": { "line": 3, "column": 6, "character": 29 }, + "pos": 29 } diff --git a/test/parser/samples/error-else-before-closing/error.json b/test/parser/samples/error-else-before-closing/error.json index c3a8c74cf06f..5b6e490c0f9a 100644 --- a/test/parser/samples/error-else-before-closing/error.json +++ b/test/parser/samples/error-else-before-closing/error.json @@ -1,6 +1,6 @@ { - "code": "unclosed-open-tag", - "message": "Expect to close
  • tag before {:else} block", - "start": { "line": 3, "column": 8, "character": 26 }, - "pos": 26 + "code": "invalid-else-placement", + "message": "Expected to close
  • tag before seeing {:else} block", + "start": { "line": 3, "column": 6, "character": 23 }, + "pos": 23 } diff --git a/test/parser/samples/error-else-if-before-closing-2/error.json b/test/parser/samples/error-else-if-before-closing-2/error.json index 717d51044270..e55f4f11e567 100644 --- a/test/parser/samples/error-else-if-before-closing-2/error.json +++ b/test/parser/samples/error-else-if-before-closing-2/error.json @@ -1,6 +1,6 @@ { - "code": "unclosed-open-tag", - "message": "Expect to close

    tag before {:else if ...} block", - "start": { "line": 3, "column": 11, "character": 28 }, - "pos": 28 + "code": "invalid-elseif-placement", + "message": "Expected to close

    tag before seeing {:else if ...} block", + "start": { "line": 3, "column": 9, "character": 25 }, + "pos": 25 } diff --git a/test/parser/samples/error-else-if-before-closing/error.json b/test/parser/samples/error-else-if-before-closing/error.json index 3d9120fc0f90..21d16c72a4d6 100644 --- a/test/parser/samples/error-else-if-before-closing/error.json +++ b/test/parser/samples/error-else-if-before-closing/error.json @@ -1,6 +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 + "code": "invalid-elseif-placement", + "message": "Expected to close {#await} block before seeing {:else if ...} block", + "start": { "line": 3, "column": 9, "character": 34 }, + "pos": 34 } diff --git a/test/parser/samples/error-else-if-without-if/error.json b/test/parser/samples/error-else-if-without-if/error.json index 1ff8aa45b8ca..dd69df677236 100644 --- a/test/parser/samples/error-else-if-without-if/error.json +++ b/test/parser/samples/error-else-if-without-if/error.json @@ -1,6 +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 + "start": { "line": 3, "column": 10, "character": 35 }, + "pos": 35 } diff --git a/test/parser/samples/error-then-before-closing/error.json b/test/parser/samples/error-then-before-closing/error.json index 22e08f2bd622..07310c93fae9 100644 --- a/test/parser/samples/error-then-before-closing/error.json +++ b/test/parser/samples/error-then-before-closing/error.json @@ -1,6 +1,6 @@ { - "code": "unclosed-open-tag", - "message": "Expect to close

  • tag before {:then} block", - "start": { "line": 3, "column": 8, "character": 29 }, - "pos": 29 + "code": "invalid-then-placement", + "message": "Expected to close
  • tag before seeing {:then} block", + "start": { "line": 3, "column": 6, "character": 26 }, + "pos": 26 } diff --git a/test/parser/samples/no-error-if-before-closing/output.json b/test/parser/samples/no-error-if-before-closing/output.json index 283feee4e569..ad8ccd0f91aa 100644 --- a/test/parser/samples/no-error-if-before-closing/output.json +++ b/test/parser/samples/no-error-if-before-closing/output.json @@ -17,7 +17,7 @@ }, "children": [ { - "start": 11, + "start": 12, "end": 19, "type": "Element", "name": "input", @@ -52,7 +52,7 @@ }, "children": [ { - "start": 46, + "start": 47, "end": 51, "type": "Element", "name": "br", @@ -94,13 +94,13 @@ "children": [ { "start": 80, - "end": 81, + "end": 82, "type": "Text", - "raw": "\n", - "data": "\n" + "raw": "\n\t", + "data": "\n\t" }, { - "start": 81, + "start": 82, "end": 89, "type": "Element", "name": "input", @@ -167,13 +167,13 @@ "children": [ { "start": 123, - "end": 124, + "end": 125, "type": "Text", - "raw": "\n", - "data": "\n" + "raw": "\n\t", + "data": "\n\t" }, { - "start": 124, + "start": 125, "end": 129, "type": "Element", "name": "br", From 2c44980eb478ec9b74b1b845399ad2aa0a78bf47 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Sat, 8 Feb 2020 23:55:51 -0500 Subject: [PATCH 7/7] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 899e0d5b8389..6337653fb178 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased * Fix binding to module-level variables ([#4086](https://github.com/sveltejs/svelte/issues/4086)) +* Improve parsing error messages when there is a pending unclosed tag ([#4131](https://github.com/sveltejs/svelte/issues/4131)) * Disallow attribute/prop names from matching two-way-bound names or `{shorthand}` attribute/prop names ([#4325](https://github.com/sveltejs/svelte/issues/4325)) * Improve performance of `flush()` by not using `.shift()` ([#4356](https://github.com/sveltejs/svelte/pull/4356)) * Fix code generation error with precedence of arrow functions ([#4384](https://github.com/sveltejs/svelte/issues/4384))