Repository: sveltejs/prettier-plugin-svelte
Pull request #150 (2020-10-08 08:32:22)

do not encode entities in attribute values
Fixes https://github.com/sveltejs/prettier-plugin-svelte/issues/29#issuecomment-704878989 : 

`<i data-icon="&#xE04E;">icon</i>` was turned into `<i data-icon="">icon</i>`

I introduced a new function to explain what `node.raw || node.data` was doing; I hadn't understood it.


Patch:
diff --git a/src/lib/elements.ts b/src/lib/elements.ts
index 54e84eb..8006b96 100644
--- a/src/lib/elements.ts
+++ b/src/lib/elements.ts
@@ -76,7 +76,7 @@ export const inlineElements: TagName[] = [
 /**
  * HTML attributes that we may safely reformat (trim whitespace, add or remove newlines)
  */
-export const formattableAttributes = [
+export const formattableAttributes: string[] = [
   // None at the moment
   // Prettier HTML does not format attributes at all
   // and to be consistent we leave this array empty for now
diff --git a/src/print/index.ts b/src/print/index.ts
index 80ec7e3..5b121a5 100644
--- a/src/print/index.ts
+++ b/src/print/index.ts
@@ -18,6 +18,7 @@ import {
     isOrCanBeConvertedToShorthand,
     getNextNode,
     getNodeEnd,
+    getUnencodedText
 } from './node-helpers';
 import {
     isLine,
@@ -146,7 +147,7 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
                          * allow for flexible grouping of HTML tags in a particular indentation level,
                          * and is similar to how vanilla HTML is handled in Prettier core.
                          */
-                        keepIfLonely: /\n\r?\s*\n\r?/.test(node.raw || node.data),
+                        keepIfLonely: /\n\r?\s*\n\r?/.test(getUnencodedText(node)),
                     };
                 }
 
@@ -156,9 +157,9 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
                  * until this node's current line is out of room, at which `fill` will break at the
                  * most convenient instance of `line`.
                  */
-                return fill(splitTextToDocs(node.raw || node.data));
+                return fill(splitTextToDocs(getUnencodedText(node)));
             } else {
-                return node.data;
+                return getUnencodedText(node);
             }
         case 'Element':
         case 'InlineComponent':
diff --git a/src/print/node-helpers.ts b/src/print/node-helpers.ts
index 0536995..28dd095 100644
--- a/src/print/node-helpers.ts
+++ b/src/print/node-helpers.ts
@@ -53,7 +53,7 @@ export function canBreakBefore(node: Node) {
 export function isInlineNode(node: Node): boolean {
     switch (node.type) {
         case 'Text':
-            const text = node.raw || node.data;
+            const text = getUnencodedText(node);
             const isAllWhitespace = text.trim() === '';
 
             return !isAllWhitespace || text === '';
@@ -105,7 +105,7 @@ export function getNextNode(path: FastPath): Node | undefined {
 }
 
 /**
- * Returns the position that used to be the end of the node before the embed elements were cut out. 
+ * Returns the position that used to be the end of the node before the embed elements were cut out.
  */
 export function getNodeEnd(node: Node, path: FastPath) {
     const root = path.stack[0];
@@ -122,7 +122,7 @@ export function getNodeEnd(node: Node, path: FastPath) {
 }
 
 export function isEmptyNode(node: Node): boolean {
-    return node.type === 'Text' && (node.raw || node.data).trim() === '';
+    return node.type === 'Text' && getUnencodedText(node).trim() === '';
 }
 
 export function isIgnoreDirective(node: Node | undefined | null): boolean {
@@ -211,3 +211,8 @@ export function isOrCanBeConvertedToShorthand(node: AttributeNode): boolean {
 
     return false;
 }
+
+export function getUnencodedText(node: TextNode) {
+    // `raw` will contain HTML entities in unencoded form
+    return node.raw || node.data;
+}


Test patch:
diff --git a/test/printer/samples/text-html-entities.html b/test/printer/samples/text-html-entities.html
index 9e72ba6..05a68b8 100644
--- a/test/printer/samples/text-html-entities.html
+++ b/test/printer/samples/text-html-entities.html
@@ -1,1 +1,1 @@
-&amp;
+<i data-icon="&#xE04E;">&amp;</i>