diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 43e685017b..5465f6f3e1 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -5,16 +5,20 @@ import { decodeCharacterReferences } from '../utils/html'; import isVoidElementName from '../../utils/isVoidElementName'; import { Parser } from '../index'; import { Node } from '../../interfaces'; +import fuzzymatch from '../../utils/fuzzymatch'; +import list from '../../utils/list'; const validTagName = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/; const metaTags = new Map([ - ['svelte:document', 'Document'], - ['svelte:window', 'Window'], + ['svelte:head', 'Head'], ['svelte:meta', 'Meta'], - ['svelte:head', 'Head'] + ['svelte:window', 'Window'], + ['svelte:document', 'Document'] ]); +const valid_meta_tags = [...metaTags.keys(), 'svelte:self', 'svelte:component']; + const specials = new Map([ [ 'script', @@ -32,8 +36,8 @@ const specials = new Map([ ], ]); -const SELF = 'svelte:self'; -const COMPONENT = 'svelte:component'; +const SELF = /^svelte:self[\s\/>]/; +const COMPONENT = /^svelte:component[\s\/>]/; // based on http://developers.whatwg.org/syntax.html#syntax-tag-omission const disallowedContents = new Map([ @@ -278,7 +282,7 @@ export default function tag(parser: Parser) { function readTagName(parser: Parser) { const start = parser.index; - if (parser.eat(SELF)) { + if (parser.read(SELF)) { // check we're inside a block, otherwise this // will cause infinite recursion let i = parser.stack.length; @@ -295,19 +299,31 @@ function readTagName(parser: Parser) { if (!legal) { parser.error({ code: `invalid-self-placement`, - message: `<${SELF}> components can only exist inside if-blocks or each-blocks` + message: ` components can only exist inside if-blocks or each-blocks` }, start); } - return SELF; + return 'svelte:self'; } - if (parser.eat(COMPONENT)) return COMPONENT; + if (parser.read(COMPONENT)) return 'svelte:component'; const name = parser.readUntil(/(\s|\/|>)/); if (metaTags.has(name)) return name; + if (name.startsWith('svelte:')) { + const match = fuzzymatch(name.slice(7), valid_meta_tags); + + let message = `Valid tag names are ${list(valid_meta_tags)}`; + if (match) message += ` (did you mean '${match}'?)`; + + parser.error({ + code: 'invalid-tag-name', + message + }, start); + } + if (!validTagName.test(name)) { parser.error({ code: `invalid-tag-name`, diff --git a/test/parser/samples/error-svelte-selfdestructive/error.json b/test/parser/samples/error-svelte-selfdestructive/error.json new file mode 100644 index 0000000000..1b4dc7fdec --- /dev/null +++ b/test/parser/samples/error-svelte-selfdestructive/error.json @@ -0,0 +1,10 @@ +{ + "code": "invalid-tag-name", + "message": "Valid tag names are svelte:head, svelte:meta, svelte:window, svelte:document, svelte:self or svelte:component", + "pos": 10, + "start": { + "character": 10, + "line": 2, + "column": 2 + } +} \ No newline at end of file diff --git a/test/parser/samples/error-svelte-selfdestructive/input.html b/test/parser/samples/error-svelte-selfdestructive/input.html new file mode 100644 index 0000000000..6bf1e83aa4 --- /dev/null +++ b/test/parser/samples/error-svelte-selfdestructive/input.html @@ -0,0 +1,3 @@ +{#if x} + +{/if} \ No newline at end of file