From f5694432dab03d4fad4b277bc269f7a61f3742b4 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 4 Jan 2019 22:02:12 -0500 Subject: [PATCH 1/3] prevent invalid svelte: tags - fixes #1948 --- src/parse/state/tag.ts | 34 ++++++++++++++----- .../error-svelte-selfdestructive/error.json | 10 ++++++ .../error-svelte-selfdestructive/input.html | 3 ++ 3 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 test/parser/samples/error-svelte-selfdestructive/error.json create mode 100644 test/parser/samples/error-svelte-selfdestructive/input.html 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 From 0fba94b8bc50a69f43609d96d6dbe2b10505ce0f Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 4 Jan 2019 22:09:21 -0500 Subject: [PATCH 2/3] oops --- src/parse/state/tag.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 1ed7b3d1e8..64108057ce 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -283,6 +283,8 @@ function readTagName(parser: Parser) { const start = parser.index; if (parser.read(SELF)) { + parser.index -= 1; + // check we're inside a block, otherwise this // will cause infinite recursion let i = parser.stack.length; @@ -306,7 +308,10 @@ function readTagName(parser: Parser) { return 'svelte:self'; } - if (parser.read(COMPONENT)) return 'svelte:component'; + if (parser.read(COMPONENT)) { + parser.index -= 1; + return 'svelte:component'; + } const name = parser.readUntil(/(\s|\/|>)/); From 64a718eaf661885a080a1b634628195e4bffab68 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Fri, 4 Jan 2019 22:32:32 -0500 Subject: [PATCH 3/3] nicer --- src/parse/state/tag.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index 64108057ce..d2cc9cc9ba 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -36,8 +36,8 @@ const specials = new Map([ ], ]); -const SELF = /^svelte:self[\s\/>]/; -const COMPONENT = /^svelte:component[\s\/>]/; +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([ @@ -283,8 +283,6 @@ function readTagName(parser: Parser) { const start = parser.index; if (parser.read(SELF)) { - parser.index -= 1; - // check we're inside a block, otherwise this // will cause infinite recursion let i = parser.stack.length; @@ -308,10 +306,7 @@ function readTagName(parser: Parser) { return 'svelte:self'; } - if (parser.read(COMPONENT)) { - parser.index -= 1; - return 'svelte:component'; - } + if (parser.read(COMPONENT)) return 'svelte:component'; const name = parser.readUntil(/(\s|\/|>)/);