Repository: prettier/plugin-php
Pull request #157 (2018-03-06 09:46:53)

tests: long function with type declaration
From PSR-12: https://github.com/php-fig/fig-standards/blob/master/proposed/extended-coding-style-guide.md#45-method-and-function-arguments


Patch:
diff --git a/src/printer.js b/src/printer.js
index dc3cf16..8af10cf 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -130,6 +130,106 @@ function printLines(path, options, print) {
   return join(hardline, printed);
 }
 
+// special layout for "chained" function calls, i.e.
+// $foo = a()
+//     ->b()
+//     ->c();
+function printMemberChain(path, options, print) {
+  // First step: Linearize and reorder the AST.
+  //
+  // Example:
+  //   a()->b->c()->d()
+  // has the AST structure
+  //   Call (PropertyLookup d (
+  //     Call (PropertyLookup c (
+  //       PropertyLookup b (
+  //         Call (Identifier a)
+  //       )
+  //     ))
+  //   ))
+  // and we transform it into (notice the reversed order)
+  //   [Identifier a, Call, PropertyLookup b, PropertyLookup c, Call,
+  //    PropertyLookup d, Call]
+  const printedNodes = [];
+
+  function traverse(path) {
+    const node = path.getValue();
+    if (node.kind === "call") {
+      printedNodes.unshift({
+        node: node,
+        printed: concat([printArgumentsList(path, options, print)])
+      });
+      path.call(what => traverse(what), "what");
+    } else if (node.kind === "propertylookup") {
+      printedNodes.unshift({
+        node: node,
+        printed: concat(["->", path.call(print, "offset")])
+      });
+      path.call(what => traverse(what), "what");
+    } else {
+      printedNodes.unshift({
+        node: node,
+        printed: path.call(print)
+      });
+    }
+  }
+  traverse(path);
+
+  // create groups from list of nodes, i.e.
+  //   [Identifier a, Call, PropertyLookup b, PropertyLookup c, Call,
+  //    PropertyLookup d, Call]
+  // will be grouped as
+  //   [
+  //     [Identifier a, Call],
+  //     [PropertyLookup b, PropertyLookup c, Call],
+  //     [PropertyLookup d, Call]
+  //   ]
+  // so that we can print it as
+  //   a()
+  //     ->b->c()
+  //     ->d()
+  const groups = [];
+  let currentGroup = [];
+  let hasSeenCall = false;
+  printedNodes.forEach(printedNode => {
+    if (hasSeenCall && printedNode.node.kind === "propertylookup") {
+      groups.push(currentGroup);
+      currentGroup = [printedNode];
+      hasSeenCall = false;
+    } else {
+      currentGroup.push(printedNode);
+    }
+
+    if (printedNode.node.kind === "call") {
+      hasSeenCall = true;
+    }
+  });
+  groups.push(currentGroup);
+
+  function printGroup(printedGroup) {
+    return concat(printedGroup.map(tuple => tuple.printed));
+  }
+  function printIndentedGroup(groups) {
+    if (groups.length === 0) {
+      return "";
+    }
+    return indent(
+      group(concat([hardline, join(hardline, groups.map(printGroup))]))
+    );
+  }
+
+  const printedGroups = groups.map(printGroup);
+  if (groups.length <= 2) {
+    return group(concat(printedGroups));
+  }
+
+  const expanded = concat([
+    printGroup(groups[0]),
+    printIndentedGroup(groups.slice(1))
+  ]);
+  return expanded;
+}
+
 function printArgumentsList(path, options, print) {
   const args = path.getValue().arguments;
   const printed = path.map(print, "arguments");
@@ -836,8 +936,7 @@ function printStatement(path, options, print) {
         group(
           concat([
             "while (",
-            softline,
-            path.call(print, "test"),
+            indent(concat([softline, path.call(print, "test")])),
             softline,
             concat([")", node.shortForm ? ":" : " {"])
           ])
@@ -941,8 +1040,7 @@ function printStatement(path, options, print) {
         group(
           concat([
             "switch (",
-            softline,
-            path.call(print, "test"),
+            indent(concat([softline, path.call(print, "test")])),
             softline,
             concat([")", node.shortForm ? ":" : " {"])
           ])
@@ -960,6 +1058,10 @@ function printStatement(path, options, print) {
         node.shortForm ? "endswitch;" : "}"
       ]);
     case "call": {
+      // chain: Call (PropertyLookup (Call (PropertyLookup (...))))
+      if (node.what.kind === "propertylookup") {
+        return printMemberChain(path, options, print);
+      }
       return concat([
         path.call(print, "what"),
         printArgumentsList(path, options, print)


Test patch:
diff --git a/tests/call/__snapshots__/jsfmt.spec.js.snap b/tests/call/__snapshots__/jsfmt.spec.js.snap
index 99499d0..13edfb2 100644
--- a/tests/call/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/call/__snapshots__/jsfmt.spec.js.snap
@@ -7,6 +7,94 @@ func($a, $b, $c);
 func(...$a);
 func($a, ...$b);
 $foo->func();
+func( $arg1,$arg2 ,$arg3, $arg4 , $arg5 );
+$foo -> bar ( $arg1,$arg2 ,$arg3, $arg4 , $arg5 ) ;
+Foo :: bar( $arg1,$arg2 ,$arg3, $arg4 , $arg5 ) ;
+
+$db->Execute($sql, [
+    $foo,
+    $bar,
+    $foobar,
+    $somewhatLongParameter,
+    $somewhatLongParameterX,
+    $somewhatLongParameterXYZ
+]);
+
+$db->Execute([
+    $foo,
+    $bar,
+    $foobar,
+    $somewhatLongParameter,
+    $somewhatLongParameterX,
+    $somewhatLongParameterXYZ
+], $sql);
+
+$app->get('/hello/{name}', function ($name) use ($app) {
+    return 'Hello ' . $app->escape($name);
+});
+
+$this->something->method($argument, $this->more->stuff(
+    $this->even->more->things->complicatedMethod()
+));
+
+$this->something->method(
+    $this->more->stuff($this->even->more->things->complicatedMethod()),
+    $argument
+);
+
+$this->something->method(
+    $argument,
+    $otherArgument,
+    array("foo" => "bar", "baz" => "buzz"),
+    $this->even->more->things->complicatedMethod()
+);
+
+$this->files->put(
+    $path, $this->expiration($minutes).serialize($value), true
+);
+
+tap(((int) $raw['data']) + $value, function ($newValue) use ($key, $raw) {
+    $this->put($key, $newValue, $raw['time']);
+});
+
+$expire = substr(
+    $contents = $this->files->get($path, true), 0, 10
+);
+$this->app->singleton('session', function ($app) {
+    return new SessionManager($app);
+});
+
+$this->filter([
+    new MergeValue(['First', 'Second']),
+    'Taylor',
+    'Mohamed',
+    $this->mergeWhen(false, ['Adam', 'Matt']),
+    'Jeffrey',
+    new MergeValue(['Abigail', 'Lydia']),
+]);
+
+$this->assertEquals([
+    'First', 'Second', 'Taylor', 'Mohamed', 'Jeffrey', 'Abigail', 'Lydia',
+], $results);
+
+$this->assertEquals(['First'], $results);
+
+$some->other->thing(array(
+    'foo' => 'bar',
+    'buzz' => $this->is->nested(array(
+        'complex' => 'stuff',
+        'foo' => 'bar',
+        'buzz' => 'bazz'
+    ))
+));
+
+$some->other->thing(array(
+    'foo' => 'bar',
+    'buzz' => $this->is->nested(array(12, 34, 45, 67, 89))
+), array(
+    11323123,
+    1231, 13231233243, 324234234
+));
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 func();
@@ -14,5 +102,96 @@ func($a, $b, $c);
 func(...$a);
 func($a, ...$b);
 $foo->func();
+func($arg1, $arg2, $arg3, $arg4, $arg5);
+$foo->bar($arg1, $arg2, $arg3, $arg4, $arg5);
+Foo::bar($arg1, $arg2, $arg3, $arg4, $arg5);
+
+$db->Execute($sql, [
+    $foo,
+    $bar,
+    $foobar,
+    $somewhatLongParameter,
+    $somewhatLongParameterX,
+    $somewhatLongParameterXYZ
+]);
+
+$db->Execute([
+    $foo,
+    $bar,
+    $foobar,
+    $somewhatLongParameter,
+    $somewhatLongParameterX,
+    $somewhatLongParameterXYZ
+], $sql);
+
+$app->get('/hello/{name}', function ($name) use ($app) {
+    return 'Hello ' . $app->escape($name);
+});
+
+$this->something->method(
+    $argument,
+    $this->more->stuff($this->even->more->things->complicatedMethod())
+);
+
+$this->something->method(
+    $this->more->stuff($this->even->more->things->complicatedMethod()),
+    $argument
+);
+
+$this->something->method(
+    $argument,
+    $otherArgument,
+    array("foo" => "bar", "baz" => "buzz"),
+    $this->even->more->things->complicatedMethod()
+);
+
+$this->files->put($path, $this->expiration($minutes) . serialize($value), true);
+
+tap(((int) $raw['data']) + $value, function ($newValue) use ($key, $raw) {
+    $this->put($key, $newValue, $raw['time']);
+});
+
+$expire = substr($contents = $this->files->get($path, true), 0, 10);
+$this->app->singleton('session', function ($app) {
+    return new SessionManager($app);
+});
+
+$this->filter([
+    new MergeValue(['First', 'Second']),
+    'Taylor',
+    'Mohamed',
+    $this->mergeWhen(false, ['Adam', 'Matt']),
+    'Jeffrey',
+    new MergeValue(['Abigail', 'Lydia'])
+]);
+
+$this->assertEquals([
+    'First',
+    'Second',
+    'Taylor',
+    'Mohamed',
+    'Jeffrey',
+    'Abigail',
+    'Lydia'
+], $results);
+
+$this->assertEquals(['First'], $results);
+
+$some->other->thing(array(
+    'foo' => 'bar',
+    'buzz' => $this->is->nested(array(
+        'complex' => 'stuff',
+        'foo' => 'bar',
+        'buzz' => 'bazz'
+    ))
+));
+
+$some->other->thing(
+    array(
+        'foo' => 'bar',
+        'buzz' => $this->is->nested(array(12, 34, 45, 67, 89))
+    ),
+    array(11323123, 1231, 13231233243, 324234234)
+);
 
 `;
diff --git a/tests/call/call.php b/tests/call/call.php
index 1b7d6ca..b8ca852 100644
--- a/tests/call/call.php
+++ b/tests/call/call.php
@@ -4,3 +4,91 @@ func($a, $b, $c);
 func(...$a);
 func($a, ...$b);
 $foo->func();
+func( $arg1,$arg2 ,$arg3, $arg4 , $arg5 );
+$foo -> bar ( $arg1,$arg2 ,$arg3, $arg4 , $arg5 ) ;
+Foo :: bar( $arg1,$arg2 ,$arg3, $arg4 , $arg5 ) ;
+
+$db->Execute($sql, [
+    $foo,
+    $bar,
+    $foobar,
+    $somewhatLongParameter,
+    $somewhatLongParameterX,
+    $somewhatLongParameterXYZ
+]);
+
+$db->Execute([
+    $foo,
+    $bar,
+    $foobar,
+    $somewhatLongParameter,
+    $somewhatLongParameterX,
+    $somewhatLongParameterXYZ
+], $sql);
+
+$app->get('/hello/{name}', function ($name) use ($app) {
+    return 'Hello ' . $app->escape($name);
+});
+
+$this->something->method($argument, $this->more->stuff(
+    $this->even->more->things->complicatedMethod()
+));
+
+$this->something->method(
+    $this->more->stuff($this->even->more->things->complicatedMethod()),
+    $argument
+);
+
+$this->something->method(
+    $argument,
+    $otherArgument,
+    array("foo" => "bar", "baz" => "buzz"),
+    $this->even->more->things->complicatedMethod()
+);
+
+$this->files->put(
+    $path, $this->expiration($minutes).serialize($value), true
+);
+
+tap(((int) $raw['data']) + $value, function ($newValue) use ($key, $raw) {
+    $this->put($key, $newValue, $raw['time']);
+});
+
+$expire = substr(
+    $contents = $this->files->get($path, true), 0, 10
+);
+$this->app->singleton('session', function ($app) {
+    return new SessionManager($app);
+});
+
+$this->filter([
+    new MergeValue(['First', 'Second']),
+    'Taylor',
+    'Mohamed',
+    $this->mergeWhen(false, ['Adam', 'Matt']),
+    'Jeffrey',
+    new MergeValue(['Abigail', 'Lydia']),
+]);
+
+$this->assertEquals([
+    'First', 'Second', 'Taylor', 'Mohamed', 'Jeffrey', 'Abigail', 'Lydia',
+], $results);
+
+$this->assertEquals(['First'], $results);
+
+$some->other->thing(array(
+    'foo' => 'bar',
+    'buzz' => $this->is->nested(array(
+        'complex' => 'stuff',
+        'foo' => 'bar',
+        'buzz' => 'bazz'
+    ))
+));
+
+$some->other->thing(array(
+    'foo' => 'bar',
+    'buzz' => $this->is->nested(array(12, 34, 45, 67, 89))
+), array(
+    11323123,
+    1231, 13231233243, 324234234
+));
diff --git a/tests/class/__snapshots__/jsfmt.spec.js.snap b/tests/class/__snapshots__/jsfmt.spec.js.snap
index c96c914..c876344 100644
--- a/tests/class/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/class/__snapshots__/jsfmt.spec.js.snap
@@ -178,6 +178,14 @@ abstract class ReallyReallyReallyLongClassName extends AbstractModelFactoryResou
   {
     return new SplQueue();
   }
+
+    public function longLongAnotherFunction(
+        string $foo,
+        string $bar,
+        int $baz
+    ): string {
+        return 'foo';
+    }
 }
 
 $this->something->method($argument, $this->more->stuff($this->even->more->things->complicatedMethod()));
@@ -185,6 +193,25 @@ $this->something->method($argument, $this->more->stuff($this->even->more->things
 class A {}
 
 $someVar = new ReaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongClassName();
+
+class ClassName
+
+extends ParentClass
+
+implements \\ArrayAccess, \\Countable
+
+{
+
+    // constants, properties, methods
+
+}
+
+class FooBar { public $property; public $property2; public function method() {} public function method2() {} }
+
+class FooBarFoo
+{
+    public function fooBarBaz ( $x,$y ,$z, $foo , $bar ) { /* Comment */ }
+}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 class Foo extends Bar implements Baz, Buzz
@@ -341,6 +368,15 @@ abstract class ReallyReallyReallyLongClassName
     {
         return new SplQueue();
     }
+
+    public function longLongAnotherFunction(
+        string $foo,
+        string $bar,
+        int $baz
+    ): string
+    {
+        return 'foo';
+    }
 }
 
 $this->something->method(
@@ -355,4 +391,31 @@ class A
 
 $someVar = new ReaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongClassName();
 
+class ClassName extends ParentClass implements \\ArrayAccess, \\Countable
+{
+    // constants, properties, methods
+}
+
+class FooBar
+{
+    public $property;
+    public $property2;
+    public function method()
+    {
+
+    }
+    public function method2()
+    {
+
+    }
+}
+
+class FooBarFoo
+{
+    public function fooBarBaz($x, $y, $z, $foo, $bar)
+    {
+        // Comment
+    }
+}
+
 `;
diff --git a/tests/class/class.php b/tests/class/class.php
index 66e0459..85eee6c 100644
--- a/tests/class/class.php
+++ b/tests/class/class.php
@@ -118,6 +118,14 @@ abstract class ReallyReallyReallyLongClassName extends AbstractModelFactoryResou
   {
     return new SplQueue();
   }
+
+    public function longLongAnotherFunction(
+        string $foo,
+        string $bar,
+        int $baz
+    ): string {
+        return 'foo';
+    }
 }
 
 $this->something->method($argument, $this->more->stuff($this->even->more->things->complicatedMethod()));
@@ -125,3 +133,22 @@ $this->something->method($argument, $this->more->stuff($this->even->more->things
 class A {}
 
 $someVar = new ReaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalyLongClassName();
+
+class ClassName
+
+extends ParentClass
+
+implements \ArrayAccess, \Countable
+
+{
+
+    // constants, properties, methods
+
+}
+
+class FooBar { public $property; public $property2; public function method() {} public function method2() {} }
+
+class FooBarFoo
+{
+    public function fooBarBaz ( $x,$y ,$z, $foo , $bar ) { /* Comment */ }
+}
diff --git a/tests/closure/__snapshots__/jsfmt.spec.js.snap b/tests/closure/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 0000000..45d353b
--- /dev/null
+++ b/tests/closure/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,127 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`closure.php 1`] = `
+<?php
+
+$closureWithArgs = function ($arg1, $arg2) {
+    // body
+};
+
+$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
+    // body
+};
+
+$longArgs_noVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) {
+    // body
+};
+
+$noArgs_longVars = function () use (
+    $longLongLongLongVar1,
+    $longerLongerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$longArgs_longVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) use (
+    $longLongLongLongLongLongLongVar1,
+    $longerLongerLongerLongerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$longArgs_shortVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) use ($var1) {
+    // body
+};
+
+$shortArgs_longVars = function ($arg) use (
+    $longVar1,
+    $longerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$foo->bar(
+    $longLongLongLongLongLongLongLongLongLongArg1,
+    function ($arg2) use ($var1) {
+        // body
+    },
+    $longLongLongLongLongLongLongLongLongLongArg3
+);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+$closureWithArgs = function ($arg1, $arg2) {
+    // body
+};
+
+$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
+    // body
+};
+
+$longArgs_noVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) {
+    // body
+};
+
+$noArgs_longVars = function () use (
+    $longLongLongLongVar1,
+    $longerLongerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$longArgs_longVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) use (
+    $longLongLongLongLongLongLongVar1,
+    $longerLongerLongerLongerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$longArgs_shortVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) use ($var1) {
+    // body
+};
+
+$shortArgs_longVars = function ($arg) use (
+    $longVar1,
+    $longerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$foo->bar(
+    $longLongLongLongLongLongLongLongLongLongArg1,
+    function ($arg2) use ($var1) {
+        // body
+    },
+    $longLongLongLongLongLongLongLongLongLongArg3
+);
+
+`;
diff --git a/tests/closure/closure.php b/tests/closure/closure.php
new file mode 100644
index 0000000..87ed72d
--- /dev/null
+++ b/tests/closure/closure.php
@@ -0,0 +1,61 @@
+<?php
+
+$closureWithArgs = function ($arg1, $arg2) {
+    // body
+};
+
+$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
+    // body
+};
+
+$longArgs_noVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) {
+    // body
+};
+
+$noArgs_longVars = function () use (
+    $longLongLongLongVar1,
+    $longerLongerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$longArgs_longVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) use (
+    $longLongLongLongLongLongLongVar1,
+    $longerLongerLongerLongerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$longArgs_shortVars = function (
+    $longArgument,
+    $longerArgument,
+    $muchLongerArgument
+) use ($var1) {
+    // body
+};
+
+$shortArgs_longVars = function ($arg) use (
+    $longVar1,
+    $longerVar2,
+    $muchLongerVar3
+) {
+    // body
+};
+
+$foo->bar(
+    $longLongLongLongLongLongLongLongLongLongArg1,
+    function ($arg2) use ($var1) {
+        // body
+    },
+    $longLongLongLongLongLongLongLongLongLongArg3
+);
diff --git a/tests/closure/jsfmt.spec.js b/tests/closure/jsfmt.spec.js
new file mode 100644
index 0000000..e395434
--- /dev/null
+++ b/tests/closure/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(__dirname, ["php"]);
diff --git a/tests/do/__snapshots__/jsfmt.spec.js.snap b/tests/do/__snapshots__/jsfmt.spec.js.snap
index a9cbc95..393c8b0 100644
--- a/tests/do/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/do/__snapshots__/jsfmt.spec.js.snap
@@ -19,6 +19,10 @@ do {
 
 do $var++;
 while ($var < 10);
+
+do {} while ($veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable);
+
+do {} while ($veryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable && $veryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable);
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 $i = 1;
@@ -43,4 +47,17 @@ do {
     $var++;
 } while ($var < 10);
 
+do {
+
+} while (
+    $veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable
+);
+
+do {
+
+} while (
+    $veryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable &&
+    $veryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable
+);
+
 `;
diff --git a/tests/do/do.php b/tests/do/do.php
index 4f87840..1773eeb 100644
--- a/tests/do/do.php
+++ b/tests/do/do.php
@@ -16,3 +16,7 @@ do {
 
 do $var++;
 while ($var < 10);
+
+do {} while ($veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable);
+
+do {} while ($veryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable && $veryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable);
diff --git a/tests/functions/__snapshots__/jsfmt.spec.js.snap b/tests/functions/__snapshots__/jsfmt.spec.js.snap
index 7199305..918e5e4 100644
--- a/tests/functions/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/functions/__snapshots__/jsfmt.spec.js.snap
@@ -1,5 +1,58 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`chaining.php 1`] = `
+<?php
+one()->two();
+one()
+    ->two()
+    ->three();
+one()
+    ->two->three()
+    ->four->five();
+
+Route::prefix('api')
+    ->middleware('api')
+    ->namespace($this->namespace)
+    ->group(base_path('routes/api.php'));
+
+return tap($this->forceFill([
+    'approver_id' => $user instanceof User ? $user->id : $user,
+    'approved_at' => $this->freshTimestamp(),
+]))->save();
+
+return collect(parent::jsonSerialize())->mapWithKeys(function ($value, $key) {
+    return [camel_case($key) => $value];
+})->toArray();
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+one()->two();
+one()
+    ->two()
+    ->three();
+one()
+    ->two->three()
+    ->four->five();
+
+Route::prefix('api')
+    ->middleware('api')
+    ->namespace($this->namespace)
+    ->group(base_path('routes/api.php'));
+
+return tap(
+    $this->forceFill([
+        'approver_id' => $user instanceof User ? $user->id : $user,
+        'approved_at' => $this->freshTimestamp()
+    ])
+)->save();
+
+return collect(parent::jsonSerialize())
+    ->mapWithKeys(function ($value, $key) {
+        return [camel_case($key) => $value];
+    })
+    ->toArray();
+
+`;
+
 exports[`functions.php 1`] = `
 <?php
 
@@ -15,6 +68,8 @@ function two_args($x, $y) {
     return $x;
 }
 
+function two_args_other ( $x,$y ,$z, $foo , $bar ) { return $x; }
+
 function reeeeeeeeeeaaaaaaaallllllllyyyyyy_llloooooooonnnnnnggggg($soooooooooooo_looooooooonnnng, $eeeeeeeeevvveeeeeeeennnn_loooooonnngggeeeerrrr) {
     return $soooooooooooo_looooooooonnnng;
 }
@@ -90,91 +145,6 @@ function test(object $obj): object
 {
     return new SplQueue();
 }
-
-$db->Execute($sql, [
-  $foo,
-  $bar,
-  $foobar,
-  $somewhatLongParameter,
-  $somewhatLongParameterX,
-  $somewhatLongParameterXYZ
-]);
-
-$db->Execute([
-  $foo,
-  $bar,
-  $foobar,
-  $somewhatLongParameter,
-  $somewhatLongParameterX,
-  $somewhatLongParameterXYZ
-], $sql);
-
-$app->get('/hello/{name}', function ($name) use ($app) {
-    return 'Hello ' . $app->escape($name);
-});
-
-$this->something->method($argument, $this->more->stuff(
-    $this->even->more->things->complicatedMethod()
-));
-
-$this->something->method(
-    $this->more->stuff($this->even->more->things->complicatedMethod()),
-    $argument
-);
-
-$this->something->method(
-    $argument,
-    $otherArgument,
-    array("foo" => "bar", "baz" => "buzz"),
-    $this->even->more->things->complicatedMethod()
-);
-
-$this->files->put(
-    $path, $this->expiration($minutes).serialize($value), true
-);
-
-tap(((int) $raw['data']) + $value, function ($newValue) use ($key, $raw) {
-    $this->put($key, $newValue, $raw['time']);
-});
-
-$expire = substr(
-    $contents = $this->files->get($path, true), 0, 10
-);
-$this->app->singleton('session', function ($app) {
-    return new SessionManager($app);
-});
-
-$this->filter([
-    new MergeValue(['First', 'Second']),
-    'Taylor',
-    'Mohamed',
-    $this->mergeWhen(false, ['Adam', 'Matt']),
-    'Jeffrey',
-    new MergeValue(['Abigail', 'Lydia']),
-]);
-
-$this->assertEquals([
-    'First', 'Second', 'Taylor', 'Mohamed', 'Jeffrey', 'Abigail', 'Lydia',
-], $results);
-
-$this->assertEquals(['First'], $results);
-
-$some->other->thing(array(
-  'foo' => 'bar',
-  'buzz' => $this->is->nested(array(
-    'complex' => 'stuff',
-    'foo' => 'bar',
-    'buzz' => 'bazz'
-  ))
-));
-
-$some->other->thing(array(
-  'foo' => 'bar',
-  'buzz' => $this->is->nested(array(12, 34, 45, 67, 89))
-), array(
-  11323123,
-  1231, 13231233243, 324234234
-));
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 function hello()
@@ -192,6 +162,11 @@ function two_args($x, $y)
     return $x;
 }
 
+function two_args_other($x, $y, $z, $foo, $bar)
+{
+    return $x;
+}
+
 function reeeeeeeeeeaaaaaaaallllllllyyyyyy_llloooooooonnnnnnggggg(
     $soooooooooooo_looooooooonnnng,
     $eeeeeeeeevvveeeeeeeennnn_loooooonnngggeeeerrrr
@@ -294,92 +269,4 @@ function test(object $obj): object
     return new SplQueue();
 }
 
-$db->Execute($sql, [
-    $foo,
-    $bar,
-    $foobar,
-    $somewhatLongParameter,
-    $somewhatLongParameterX,
-    $somewhatLongParameterXYZ
-]);
-
-$db->Execute([
-    $foo,
-    $bar,
-    $foobar,
-    $somewhatLongParameter,
-    $somewhatLongParameterX,
-    $somewhatLongParameterXYZ
-], $sql);
-
-$app->get('/hello/{name}', function ($name) use ($app) {
-    return 'Hello ' . $app->escape($name);
-});
-
-$this->something->method(
-    $argument,
-    $this->more->stuff($this->even->more->things->complicatedMethod())
-);
-
-$this->something->method(
-    $this->more->stuff($this->even->more->things->complicatedMethod()),
-    $argument
-);
-
-$this->something->method(
-    $argument,
-    $otherArgument,
-    array("foo" => "bar", "baz" => "buzz"),
-    $this->even->more->things->complicatedMethod()
-);
-
-$this->files->put($path, $this->expiration($minutes) . serialize($value), true);
-
-tap(((int) $raw['data']) + $value, function ($newValue) use ($key, $raw) {
-    $this->put($key, $newValue, $raw['time']);
-});
-
-$expire = substr($contents = $this->files->get($path, true), 0, 10);
-$this->app->singleton('session', function ($app) {
-    return new SessionManager($app);
-});
-
-$this->filter([
-    new MergeValue(['First', 'Second']),
-    'Taylor',
-    'Mohamed',
-    $this->mergeWhen(false, ['Adam', 'Matt']),
-    'Jeffrey',
-    new MergeValue(['Abigail', 'Lydia'])
-]);
-
-$this->assertEquals([
-    'First',
-    'Second',
-    'Taylor',
-    'Mohamed',
-    'Jeffrey',
-    'Abigail',
-    'Lydia'
-], $results);
-
-$this->assertEquals(['First'], $results);
-
-$some->other->thing(array(
-    'foo' => 'bar',
-    'buzz' => $this->is->nested(array(
-        'complex' => 'stuff',
-        'foo' => 'bar',
-        'buzz' => 'bazz'
-    ))
-));
-
-$some->other->thing(
-    array(
-        'foo' => 'bar',
-        'buzz' => $this->is->nested(array(12, 34, 45, 67, 89))
-    ),
-    array(11323123, 1231, 13231233243, 324234234)
-);
-
 `;
diff --git a/tests/functions/chaining.php b/tests/functions/chaining.php
new file mode 100644
index 0000000..9e41b2c
--- /dev/null
+++ b/tests/functions/chaining.php
@@ -0,0 +1,22 @@
+<?php
+one()->two();
+one()
+    ->two()
+    ->three();
+one()
+    ->two->three()
+    ->four->five();
+
+Route::prefix('api')
+    ->middleware('api')
+    ->namespace($this->namespace)
+    ->group(base_path('routes/api.php'));
+
+return tap($this->forceFill([
+    'approver_id' => $user instanceof User ? $user->id : $user,
+    'approved_at' => $this->freshTimestamp(),
+]))->save();
+
+return collect(parent::jsonSerialize())->mapWithKeys(function ($value, $key) {
+    return [camel_case($key) => $value];
+})->toArray();
diff --git a/tests/functions/functions.php b/tests/functions/functions.php
index cad754e..920e796 100644
--- a/tests/functions/functions.php
+++ b/tests/functions/functions.php
@@ -12,6 +12,8 @@ function two_args($x, $y) {
     return $x;
 }
 
+function two_args_other ( $x,$y ,$z, $foo , $bar ) { return $x; }
+
 function reeeeeeeeeeaaaaaaaallllllllyyyyyy_llloooooooonnnnnnggggg($soooooooooooo_looooooooonnnng, $eeeeeeeeevvveeeeeeeennnn_loooooonnngggeeeerrrr) {
     return $soooooooooooo_looooooooonnnng;
 }
@@ -87,88 +89,3 @@ function test(object $obj): object
 {
     return new SplQueue();
 }
-
-$db->Execute($sql, [
-  $foo,
-  $bar,
-  $foobar,
-  $somewhatLongParameter,
-  $somewhatLongParameterX,
-  $somewhatLongParameterXYZ
-]);
-
-$db->Execute([
-  $foo,
-  $bar,
-  $foobar,
-  $somewhatLongParameter,
-  $somewhatLongParameterX,
-  $somewhatLongParameterXYZ
-], $sql);
-
-$app->get('/hello/{name}', function ($name) use ($app) {
-    return 'Hello ' . $app->escape($name);
-});
-
-$this->something->method($argument, $this->more->stuff(
-    $this->even->more->things->complicatedMethod()
-));
-
-$this->something->method(
-    $this->more->stuff($this->even->more->things->complicatedMethod()),
-    $argument
-);
-
-$this->something->method(
-    $argument,
-    $otherArgument,
-    array("foo" => "bar", "baz" => "buzz"),
-    $this->even->more->things->complicatedMethod()
-);
-
-$this->files->put(
-    $path, $this->expiration($minutes).serialize($value), true
-);
-
-tap(((int) $raw['data']) + $value, function ($newValue) use ($key, $raw) {
-    $this->put($key, $newValue, $raw['time']);
-});
-
-$expire = substr(
-    $contents = $this->files->get($path, true), 0, 10
-);
-$this->app->singleton('session', function ($app) {
-    return new SessionManager($app);
-});
-
-$this->filter([
-    new MergeValue(['First', 'Second']),
-    'Taylor',
-    'Mohamed',
-    $this->mergeWhen(false, ['Adam', 'Matt']),
-    'Jeffrey',
-    new MergeValue(['Abigail', 'Lydia']),
-]);
-
-$this->assertEquals([
-    'First', 'Second', 'Taylor', 'Mohamed', 'Jeffrey', 'Abigail', 'Lydia',
-], $results);
-
-$this->assertEquals(['First'], $results);
-
-$some->other->thing(array(
-  'foo' => 'bar',
-  'buzz' => $this->is->nested(array(
-    'complex' => 'stuff',
-    'foo' => 'bar',
-    'buzz' => 'bazz'
-  ))
-));
-
-$some->other->thing(array(
-  'foo' => 'bar',
-  'buzz' => $this->is->nested(array(12, 34, 45, 67, 89))
-), array(
-  11323123,
-  1231, 13231233243, 324234234
-));
diff --git a/tests/statement/__snapshots__/jsfmt.spec.js.snap b/tests/statement/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 0000000..19c8f0a
--- /dev/null
+++ b/tests/statement/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,25 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`statement.php 1`] = `
+<?php
+$var = 1; $var = 2; function foo() { return 1; } class Test { public function method() {} } if (true) echo 'good';
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+<?php
+$var = 1;
+$var = 2;
+function foo()
+{
+    return 1;
+}
+class Test
+{
+    public function method()
+    {
+
+    }
+}
+if (true) {
+    echo 'good';
+}
+
+`;
diff --git a/tests/statement/jsfmt.spec.js b/tests/statement/jsfmt.spec.js
new file mode 100644
index 0000000..e395434
--- /dev/null
+++ b/tests/statement/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(__dirname, ["php"]);
diff --git a/tests/statement/statement.php b/tests/statement/statement.php
new file mode 100644
index 0000000..4a1d29b
--- /dev/null
+++ b/tests/statement/statement.php
@@ -0,0 +1,2 @@
+<?php
+$var = 1; $var = 2; function foo() { return 1; } class Test { public function method() {} } if (true) echo 'good';
diff --git a/tests/switch/__snapshots__/jsfmt.spec.js.snap b/tests/switch/__snapshots__/jsfmt.spec.js.snap
index 5dbda2e..3420457 100644
--- a/tests/switch/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/switch/__snapshots__/jsfmt.spec.js.snap
@@ -34,6 +34,27 @@ switch ( 2 ) {
     default:
         $test = 1;
 }
+
+switch ($expr) {
+    case 0:
+        echo 'First case, with a break';
+        break;
+    case 1:
+        echo 'Second case, which falls through';
+        // no break
+    case 2:
+    case 3:
+    case 4:
+        echo 'Third case, return instead of break';
+        return;
+    default:
+        echo 'Default case';
+        break;
+}
+
+switch ($longLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable) {}
+
+switch ($longLongLongLongLongLongLongVariable && $longLongLongLongLongLongLongVariable) {}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 switch (2) {
@@ -69,4 +90,32 @@ switch (2) {
         $test = 1;
 }
 
+switch ($expr) {
+    case 0:
+        echo 'First case, with a break';
+        break;
+    case 1:
+        echo 'Second case, which falls through';
+        // no break
+    case 2:
+    case 3:
+    case 4:
+        echo 'Third case, return instead of break';
+        return;
+    default:
+        echo 'Default case';
+        break;
+}
+
+switch (
+    $longLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable
+) {
+}
+
+switch (
+    $longLongLongLongLongLongLongVariable &&
+    $longLongLongLongLongLongLongVariable
+) {
+}
+
 `;
diff --git a/tests/switch/switch.php b/tests/switch/switch.php
index 6746039..611f65b 100644
--- a/tests/switch/switch.php
+++ b/tests/switch/switch.php
@@ -31,3 +31,24 @@ switch ( 2 ) {
     default:
         $test = 1;
 }
+
+switch ($expr) {
+    case 0:
+        echo 'First case, with a break';
+        break;
+    case 1:
+        echo 'Second case, which falls through';
+        // no break
+    case 2:
+    case 3:
+    case 4:
+        echo 'Third case, return instead of break';
+        return;
+    default:
+        echo 'Default case';
+        break;
+}
+
+switch ($longLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongVariable) {}
+
+switch ($longLongLongLongLongLongLongVariable && $longLongLongLongLongLongLongVariable) {}
diff --git a/tests/while/__snapshots__/jsfmt.spec.js.snap b/tests/while/__snapshots__/jsfmt.spec.js.snap
index 408c267..893605b 100644
--- a/tests/while/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/while/__snapshots__/jsfmt.spec.js.snap
@@ -17,6 +17,10 @@ while ( $i <= 5 ) {
 
 while (true)
     $a = 1;
+
+while ($veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable) {}
+
+while ($veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable && $veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable) {}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 $i = 1;
@@ -36,4 +40,17 @@ while (true) {
     $a = 1;
 }
 
+while (
+    $veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable
+) {
+
+}
+
+while (
+    $veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable &&
+    $veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable
+) {
+
+}
+
 `;
diff --git a/tests/while/while.php b/tests/while/while.php
index ed6799c..b7cfab6 100644
--- a/tests/while/while.php
+++ b/tests/while/while.php
@@ -14,3 +14,7 @@ while ( $i <= 5 ) {
 
 while (true)
     $a = 1;
+
+while ($veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable) {}
+
+while ($veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable && $veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariable) {}