Repository: sveltejs/svelte (JavaScript)
Date: 2020-04-08 02:19:45+00:00
Task type: Bug Fix

Issue:
Stray } in element is interpreted as an attribute and causes a runtime error
**Describe the bug**
When Svelte sees an element with an orphaned `}` character it interprets the bracket as an attribute. e.g. 

`<h1 }>text</h1>`
causes this to be generated in the create function:
`attr(h1, "}", "");` 
and causes the runtime error
`Failed to execute 'setAttribute' on 'Element': '}' is not a valid attribute name.`

REPL: https://svelte.dev/repl/14ee9617902447809daec74565b61a8e?version=3.20.1

**Expected behavior**
IMO the compiler should throw an error instead of generating code for this.

**Severity**
Not too important. Was pretty obvious what happened when I looked back at my source file and saw the `}` character I missed deleting.


Issue discussion:

Solution patch:
diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts
--- a/src/compiler/compile/nodes/Element.ts
+++ b/src/compiler/compile/nodes/Element.ts
@@ -378,6 +378,14 @@ export default class Element extends Node {
 				}
 			}
 
+
+			if (/(^[0-9-.])|[\^$@%&#?!|()[\]{}^*+~;]/.test(name)) {
+				component.error(attribute, {
+					code: `illegal-attribute`,
+					message: `'${name}' is not a valid attribute name`,
+				});
+			}
+
 			if (name === 'slot') {
 				if (!attribute.is_static) {
 					component.error(attribute, {
@@ -768,4 +776,4 @@ function within_custom_element(parent: INode) {
 		parent = parent.parent;
 	}
 	return false;
-}
\ No newline at end of file
+}


Test patch:
diff --git a/test/validator/samples/attribute-invalid-name-2/errors.json b/test/validator/samples/attribute-invalid-name-2/errors.json
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name-2/errors.json
@@ -0,0 +1,15 @@
+[{
+	"code": "illegal-attribute",
+	"message": "'3aa' is not a valid attribute name",
+	"start": {
+		"line": 1,
+		"column": 3,
+		"character": 3
+	},
+	"end": {
+		"line": 1,
+		"column": 12,
+		"character": 12
+	},
+	"pos": 3
+}]
diff --git a/test/validator/samples/attribute-invalid-name-2/input.svelte b/test/validator/samples/attribute-invalid-name-2/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name-2/input.svelte
@@ -0,0 +1 @@
+<p 3aa="abc">Test</p>
diff --git a/test/validator/samples/attribute-invalid-name-3/errors.json b/test/validator/samples/attribute-invalid-name-3/errors.json
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name-3/errors.json
@@ -0,0 +1,15 @@
+[{
+	"code": "illegal-attribute",
+	"message": "'a*a' is not a valid attribute name",
+	"start": {
+		"line": 1,
+		"column": 3,
+		"character": 3
+	},
+	"end": {
+		"line": 1,
+		"column": 6,
+		"character": 6
+	},
+	"pos": 3
+}]
diff --git a/test/validator/samples/attribute-invalid-name-3/input.svelte b/test/validator/samples/attribute-invalid-name-3/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name-3/input.svelte
@@ -0,0 +1 @@
+<p a*a>Test</p>
diff --git a/test/validator/samples/attribute-invalid-name-4/errors.json b/test/validator/samples/attribute-invalid-name-4/errors.json
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name-4/errors.json
@@ -0,0 +1,15 @@
+[{
+	"code": "illegal-attribute",
+	"message": "'-a' is not a valid attribute name",
+	"start": {
+		"line": 1,
+		"column": 3,
+		"character": 3
+	},
+	"end": {
+		"line": 1,
+		"column": 5,
+		"character": 5
+	},
+	"pos": 3
+}]
diff --git a/test/validator/samples/attribute-invalid-name-4/input.svelte b/test/validator/samples/attribute-invalid-name-4/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name-4/input.svelte
@@ -0,0 +1 @@
+<p -a>Test</p>
diff --git a/test/validator/samples/attribute-invalid-name-5/errors.json b/test/validator/samples/attribute-invalid-name-5/errors.json
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name-5/errors.json
@@ -0,0 +1,15 @@
+[{
+	"code": "illegal-attribute",
+	"message": "'a;' is not a valid attribute name",
+	"start": {
+		"line": 1,
+		"column": 3,
+		"character": 3
+	},
+	"end": {
+		"line": 1,
+		"column": 11,
+		"character": 11
+	},
+	"pos": 3
+}]
diff --git a/test/validator/samples/attribute-invalid-name-5/input.svelte b/test/validator/samples/attribute-invalid-name-5/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name-5/input.svelte
@@ -0,0 +1 @@
+<p a;="abc">Test</p>
diff --git a/test/validator/samples/attribute-invalid-name/errors.json b/test/validator/samples/attribute-invalid-name/errors.json
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name/errors.json
@@ -0,0 +1,15 @@
+[{
+	"code": "illegal-attribute",
+	"message": "'}' is not a valid attribute name",
+	"start": {
+		"line": 1,
+		"column": 3,
+		"character": 3
+	},
+	"end": {
+		"line": 1,
+		"column": 4,
+		"character": 4
+	},
+	"pos": 3
+}]
diff --git a/test/validator/samples/attribute-invalid-name/input.svelte b/test/validator/samples/attribute-invalid-name/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/validator/samples/attribute-invalid-name/input.svelte
@@ -0,0 +1 @@
+<p }>Test</p>