Repository: prettier/plugin-php
Pull request #104 (2018-02-21 15:31:31)

feat: inline
Feedback welcome :+1: 

Bug: https://github.com/glayzzle/php-parser/issues/120

mgrip: Yessss this is awesome
evilebottnawi: It is really not easy, but i find solution, today i will release first working version :+1: 
evilebottnawi: @mgrip @czosel ready for first release
evilebottnawi: In some places ugly, but it is better than broken code. I think we can merge this as is. And after problem in `php` parser was fixed, i update tests.
evilebottnawi: @mgrip `funciton` name changes :+1: After this PR in theory we don't break code, but i have a lot of project and code base, after merge this i run and fix other problem

Patch:
diff --git a/src/printer.js b/src/printer.js
index 09a55a0..a8bf6b0 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -40,6 +40,23 @@ function getLast(arr) {
   return null;
 }
 
+function getParentNodeListProperty(path) {
+  const parent = path.getParentNode();
+  if (!parent) {
+    return null;
+  }
+  const body = parent.children || parent.body || parent.adaptations;
+  return Array.isArray(body) ? body : null;
+}
+
+function getNodeIndex(path) {
+  const body = getParentNodeListProperty(path);
+  if (!body) {
+    return -1;
+  }
+  return body.indexOf(path.getValue());
+}
+
 function genericPrint(path, options, print) {
   const n = path.getValue();
   if (!n) {
@@ -47,7 +64,31 @@ function genericPrint(path, options, print) {
   } else if (typeof n === "string") {
     return n;
   }
-  return printNode(path, options, print);
+  if (n.kind === "program" && n.children.length === 0) {
+    return concat(["<?php", hardline]);
+  }
+  const printed = printNode(path, options, print);
+  const parentNode = path.getParentNode();
+  const isParentProgramNode = parentNode && parentNode.kind === "program";
+  const nodeBody = getParentNodeListProperty(path);
+  const nodeIndex = getNodeIndex(path);
+  const isFirstNodeInParentProgramNode = isParentProgramNode && nodeIndex === 0;
+  const isLastNodeInParentProgramNode =
+    isParentProgramNode && nodeBody && nodeIndex === nodeBody.length - 1;
+  if (n.kind === "inline") {
+    return concat([
+      isFirstNodeInParentProgramNode ? "" : "?>",
+      printed,
+      isLastNodeInParentProgramNode ? "" : "<?php"
+    ]);
+  }
+  return concat([
+    isFirstNodeInParentProgramNode ? concat(["<?php ", hardline]) : "",
+    printed,
+    n.kind === "program"
+      ? n.children[n.children.length - 1].kind !== "inline" ? hardline : ""
+      : ""
+  ]);
 }
 
 function lineShouldEndWithSemicolon(path) {
@@ -101,13 +142,12 @@ function lineShouldEndWithSemicolon(path) {
 }
 
 function isLastStatement(path) {
-  const parent = path.getParentNode();
-  if (!parent) {
+  const body = getParentNodeListProperty(path);
+  if (!body) {
     return true;
   }
   const node = path.getValue();
-  const body = parent.children;
-  return body && body[body.length - 1] === node;
+  return body[body.length - 1] === node;
 }
 
 function printLines(path, options, print) {
@@ -119,15 +159,15 @@ function printLines(path, options, print) {
     if (lineShouldEndWithSemicolon(stmtPath)) {
       parts.push(";");
     }
-    if (
-      sharedUtil.isNextLineEmpty(text, stmt, options) &&
-      !isLastStatement(stmtPath)
-    ) {
+    if (!isLastStatement(stmtPath)) {
+      if (sharedUtil.isNextLineEmpty(text, stmt, options)) {
+        parts.push(hardline);
+      }
       parts.push(hardline);
     }
     return concat(parts);
   });
-  return join(hardline, printed);
+  return concat(printed);
 }
 
 // special layout for "chained" function calls, i.e.
@@ -586,12 +626,9 @@ function printStatement(path, options, print) {
         );
       case "program": {
         return concat([
-          "<?php",
-          hardline,
           path.call(childrenPath => {
             return printLines(childrenPath, options, print);
-          }, "children"),
-          node.children.length ? hardline : ""
+          }, "children")
         ]);
       }
       case "namespace": {
@@ -767,7 +804,7 @@ function printStatement(path, options, print) {
       case "parameter": {
         const name = concat([
           node.nullable ? "?" : "",
-          node.type ? path.call(print, "type") + " " : "",
+          node.type ? concat([path.call(print, "type"), " "]) : "",
           node.variadic ? "..." : "",
           node.byref ? "&" : "",
           "$",


Test patch:
diff --git a/tests/inline/__snapshots__/jsfmt.spec.js.snap b/tests/inline/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 0000000..134ee1c
--- /dev/null
+++ b/tests/inline/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,133 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`inline.php 1`] = `
+<?php
+
+function inline() {
+    ?>
+    <span>Hello World!</span>
+    <?php
+}
+
+function inline1() {
+    ?><span>Hello World!</span>
+    <?php
+}
+
+function inline2() {
+    ?>
+    <span>Hello World!</span><?php
+}
+
+function inlineInOneLine() {
+    ?><span>Hello World!</span><?php
+}
+
+function inlineNested() {
+    ?>
+    <div>
+      <span>Hello World!</span>
+    </div>
+    <?php
+}
+
+function inlineNested1() {
+    ?><div>
+    <span>Hello World!</span>
+    </div><?php
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+function inline()
+{
+    ?>    <span>Hello World!</span>
+    <?php
+}
+
+function inline1()
+{
+    ?><span>Hello World!</span>
+    <?php
+}
+
+function inline2()
+{
+    ?>    <span>Hello World!</span><?php
+}
+
+function inlineInOneLine()
+{
+    ?><span>Hello World!</span><?php
+}
+
+function inlineNested()
+{
+    ?>    <div>
+      <span>Hello World!</span>
+    </div>
+    <?php
+}
+
+function inlineNested1()
+{
+    ?><div>
+    <span>Hello World!</span>
+    </div><?php
+}
+
+`;
+
+exports[`mixed.php 1`] = `
+<p>Test.</p>
+<?php echo 'String.'; ?>
+<p>Test.</p>
+<?php if ($expression == true): ?>
+  <p>Test.</p>
+<?php else: ?>
+  <p>Test.</p>
+<?php endif; ?>
+<?php echo '<input type="hidden" value="' . htmlspecialchars($data) . '" />'; ?>
+<div></div>
+<?php
+echo 'foo';
+echo 'bar';
+?>
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<p>Test.</p>
+<?php
+echo 'String.';
+?><p>Test.</p>
+<?php
+if ($expression == true):
+    ?>  <p>Test.</p>
+<?php
+else:
+    ?>  <p>Test.</p>
+<?php
+endif;
+echo '<input type="hidden" value="' . htmlspecialchars($data) . '" />';
+?><div></div>
+<?php
+echo 'foo';
+echo 'bar';
+
+`;
+
+exports[`only-html.php 1`] = `
+<!DOCTYPE html>
+<html>
+  <body>
+    <h1>My First Heading</h1>
+    <p>My first paragraph.</p>
+  </body>
+</html>
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<!DOCTYPE html>
+<html>
+  <body>
+    <h1>My First Heading</h1>
+    <p>My first paragraph.</p>
+  </body>
+</html>
+
+`;
diff --git a/tests/inline/inline.php b/tests/inline/inline.php
new file mode 100644
index 0000000..34092ec
--- /dev/null
+++ b/tests/inline/inline.php
@@ -0,0 +1,35 @@
+<?php
+
+function inline() {
+    ?>
+    <span>Hello World!</span>
+    <?php
+}
+
+function inline1() {
+    ?><span>Hello World!</span>
+    <?php
+}
+
+function inline2() {
+    ?>
+    <span>Hello World!</span><?php
+}
+
+function inlineInOneLine() {
+    ?><span>Hello World!</span><?php
+}
+
+function inlineNested() {
+    ?>
+    <div>
+      <span>Hello World!</span>
+    </div>
+    <?php
+}
+
+function inlineNested1() {
+    ?><div>
+    <span>Hello World!</span>
+    </div><?php
+}
diff --git a/tests/inline/jsfmt.spec.js b/tests/inline/jsfmt.spec.js
new file mode 100644
index 0000000..e395434
--- /dev/null
+++ b/tests/inline/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(__dirname, ["php"]);
diff --git a/tests/inline/mixed.php b/tests/inline/mixed.php
new file mode 100644
index 0000000..fa4ada9
--- /dev/null
+++ b/tests/inline/mixed.php
@@ -0,0 +1,14 @@
+<p>Test.</p>
+<?php echo 'String.'; ?>
+<p>Test.</p>
+<?php if ($expression == true): ?>
+  <p>Test.</p>
+<?php else: ?>
+  <p>Test.</p>
+<?php endif; ?>
+<?php echo '<input type="hidden" value="' . htmlspecialchars($data) . '" />'; ?>
+<div></div>
+<?php
+echo 'foo';
+echo 'bar';
+?>
diff --git a/tests/inline/only-html.php b/tests/inline/only-html.php
new file mode 100644
index 0000000..ba0d19f
--- /dev/null
+++ b/tests/inline/only-html.php
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <h1>My First Heading</h1>
+    <p>My first paragraph.</p>
+  </body>
+</html>