From 54c75eed0ba5871788865357b71666b308a808ec Mon Sep 17 00:00:00 2001
From: Nick Messing <dot.nick.dot.messing@gmail.com>
Date: Tue, 8 Jan 2019 12:04:06 +0200
Subject: [PATCH] fix: Trim whitespaces properly, fix #37

---
 .../src/index.js                              | 60 ++++++++++++++-----
 .../test/snapshot.js                          | 13 +++-
 2 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/packages/babel-plugin-transform-vue-jsx/src/index.js b/packages/babel-plugin-transform-vue-jsx/src/index.js
index 424a0a9..787b486 100644
--- a/packages/babel-plugin-transform-vue-jsx/src/index.js
+++ b/packages/babel-plugin-transform-vue-jsx/src/index.js
@@ -65,9 +65,9 @@ const getTag = (t, path) => {
  */
 const getChildren = (t, paths) =>
   paths
-    .map((path, index) => {
+    .map(path => {
       if (path.isJSXText()) {
-        return transformJSXText(t, path, index === 0 ? -1 : index === paths.length - 1 ? 1 : 0)
+        return transformJSXText(t, path)
       }
       if (path.isJSXExpressionContainer()) {
         return transformJSXExpressionContainer(t, path)
@@ -374,24 +374,56 @@ const transformJSXMemberExpression = (t, path) => {
   return t.memberExpression(transformedObject, transformedProperty)
 }
 
-/**
- * Trim text from JSX expressions depending on position
- * @param string string
- * @param position -1 for left, 0 for middle and 1 for right
- * @returns string
- */
-const trimText = (string, position) => (position === 0 ? string : string.replace(position === -1 ? /^\s*/ : /\s*$/, ''))
-
 /**
  * Transform JSXText to StringLiteral
  * @param t
  * @param path JSXText
- * @param position -1 for left, 0 for middle and 1 for right
  * @returns StringLiteral
  */
-const transformJSXText = (t, path, position) => {
-  const string = trimText(path.get('value').node, position)
-  return string ? t.stringLiteral(string) : null
+const transformJSXText = (t, path) => {
+  const node = path.node
+  const lines = node.value.split(/\r\n|\n|\r/)
+
+  let lastNonEmptyLine = 0
+
+  for (let i = 0; i < lines.length; i++) {
+    if (lines[i].match(/[^ \t]/)) {
+      lastNonEmptyLine = i
+    }
+  }
+
+  let str = ''
+
+  for (let i = 0; i < lines.length; i++) {
+    const line = lines[i]
+
+    const isFirstLine = i === 0
+    const isLastLine = i === lines.length - 1
+    const isLastNonEmptyLine = i === lastNonEmptyLine
+
+    // replace rendered whitespace tabs with spaces
+    let trimmedLine = line.replace(/\t/g, ' ')
+
+    // trim whitespace touching a newline
+    if (!isFirstLine) {
+      trimmedLine = trimmedLine.replace(/^[ ]+/, '')
+    }
+
+    // trim whitespace touching an endline
+    if (!isLastLine) {
+      trimmedLine = trimmedLine.replace(/[ ]+$/, '')
+    }
+
+    if (trimmedLine) {
+      if (!isLastNonEmptyLine) {
+        trimmedLine += ' '
+      }
+
+      str += trimmedLine
+    }
+  }
+
+  return str !== '' ? t.stringLiteral(str) : null
 }
 
 /**
diff --git a/packages/babel-plugin-transform-vue-jsx/test/snapshot.js b/packages/babel-plugin-transform-vue-jsx/test/snapshot.js
index 7b6f90b..1738aee 100644
--- a/packages/babel-plugin-transform-vue-jsx/test/snapshot.js
+++ b/packages/babel-plugin-transform-vue-jsx/test/snapshot.js
@@ -58,8 +58,17 @@ render(h => [h(Alpha, ["test"]), h("Beta", ["test"])]);`,
   },
   {
     name: 'Combined content',
-    from: `render(h => <div>  test{test} {...test}<br/>  </div>)`,
-    to: `render(h => h("div", ["test", test, " ", ...test, h("br")]));`,
+    from: `render(h => <div>
+  test{test} {...test}
+  <tag1 />
+  <tag2 />
+
+  Some text
+  goes here
+
+
+</div>)`,
+    to: `render(h => h("div", ["test", test, " ", ...test, h("tag1"), h("tag2"), "Some text goes here"]));`,
   },
   {
     name: 'Plain attrs',