Repository: sveltejs/svelte (JavaScript)
Date: 2018-01-05 03:34:33+00:00
Task type: Bug Fix

Issue:
HTML entities treated incorrectly
~~When compiling to custom elements~~, markup [like this](https://svelte.technology/repl?version=1.50.1&gist=ede18c4c99e716c26ecf5074a50645e2)...

```html
<p>this should not be &lt;strong&gt;bold&lt;/strong&gt;</p>
```

...is treated incorrectly — a `<strong>` element appears where none should.
  
(edited: turns out this is nothing to do with custom elements)


Issue discussion:

Solution patch:
diff --git a/src/generators/nodes/Element.ts b/src/generators/nodes/Element.ts
--- a/src/generators/nodes/Element.ts
+++ b/src/generators/nodes/Element.ts
@@ -1,5 +1,5 @@
 import deindent from '../../utils/deindent';
-import { stringify } from '../../utils/stringify';
+import { stringify, escapeHTML } from '../../utils/stringify';
 import flattenReference from '../../utils/flattenReference';
 import isVoidElementName from '../../utils/isVoidElementName';
 import validCalleeObjects from '../../utils/validCalleeObjects';
@@ -414,7 +414,7 @@ export default class Element extends Node {
 		}
 
 		function toHTML(node: Element | Text) {
-			if (node.type === 'Text') return node.data;
+			if (node.type === 'Text') return escapeHTML(node.data);
 
 			let open = `<${node.name}`;
 
diff --git a/src/generators/server-side-rendering/visitors/Text.ts b/src/generators/server-side-rendering/visitors/Text.ts
--- a/src/generators/server-side-rendering/visitors/Text.ts
+++ b/src/generators/server-side-rendering/visitors/Text.ts
@@ -1,6 +1,6 @@
 import { SsrGenerator } from '../index';
 import Block from '../Block';
-import { escape } from '../../../utils/stringify';
+import { escape, escapeHTML } from '../../../utils/stringify';
 import { Node } from '../../../interfaces';
 
 export default function visitText(
@@ -8,5 +8,5 @@ export default function visitText(
 	block: Block,
 	node: Node
 ) {
-	generator.append(escape(node.data).replace(/(\${|`|\\)/g, '\\$1'));
+	generator.append(escapeHTML(escape(node.data).replace(/(\${|`|\\)/g, '\\$1')));
 }
diff --git a/src/utils/stringify.ts b/src/utils/stringify.ts
--- a/src/utils/stringify.ts
+++ b/src/utils/stringify.ts
@@ -7,3 +7,15 @@ export function escape(data: string, { onlyEscapeAtSymbol = false } = {}) {
 		return match + match[0];
 	});
 }
+
+const escaped = {
+	'"': '&quot;',
+	"'": '&##39;',
+	'&': '&amp;',
+	'<': '&lt;',
+	'>': '&gt;'
+};
+
+export function escapeHTML(html) {
+	return String(html).replace(/["'&<>]/g, match => escaped[match]);
+}
\ No newline at end of file


Test patch:
diff --git a/test/runtime/samples/html-entities-inside-elements/_config.js b/test/runtime/samples/html-entities-inside-elements/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/html-entities-inside-elements/_config.js
@@ -0,0 +1,5 @@
+export default {
+	html: `
+		<p>this &lt;em&gt;should&lt;/em&gt; not be <span>&lt;strong&gt;bold&lt;/strong&gt;</span></p>
+	`
+};
\ No newline at end of file
diff --git a/test/runtime/samples/html-entities-inside-elements/main.html b/test/runtime/samples/html-entities-inside-elements/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/html-entities-inside-elements/main.html
@@ -0,0 +1 @@
+<p>this &lt;em&gt;should&lt;/em&gt; not be <span>&lt;strong&gt;bold&lt;/strong&gt;</span></p>
\ No newline at end of file
diff --git a/test/server-side-rendering/samples/component-data-empty/_actual.html b/test/server-side-rendering/samples/component-data-empty/_actual.html
--- a/test/server-side-rendering/samples/component-data-empty/_actual.html
+++ b/test/server-side-rendering/samples/component-data-empty/_actual.html
@@ -1,3 +1,3 @@
 <div>
-	<p>foo: ''</p>
+	<p>foo: &#39;&#39;</p>
 </div>
\ No newline at end of file