From e5d36f5c884a28cec97b33a1c1464472e545da02 Mon Sep 17 00:00:00 2001
From: Freek Van der Herten <freek@spatie.be>
Date: Tue, 12 Sep 2023 10:08:41 +0200
Subject: [PATCH 1/2] add expand payload

---
 docs/usage/framework-agnostic-php.md | 16 ++++++++++++
 src/Payloads/ExpandPayload.php       | 38 ++++++++++++++++++++++++++++
 src/Ray.php                          | 12 +++++++++
 tests/RayTest.php                    | 26 +++++++++++++++++++
 4 files changed, 92 insertions(+)
 create mode 100644 src/Payloads/ExpandPayload.php

diff --git a/docs/usage/framework-agnostic-php.md b/docs/usage/framework-agnostic-php.md
index 8ec95f9c..5c4174be 100644
--- a/docs/usage/framework-agnostic-php.md
+++ b/docs/usage/framework-agnostic-php.md
@@ -21,6 +21,22 @@ ray($anObject);
 ray('as', 'many' , 'arguments', 'as', 'you', 'like');
 ```
 
+### Expanding arrays and objects
+
+When sending an array or object to Ray, it will be displayed in a collapsed state.
+
+To open up a node, you can use the `expand` method. 
+
+```php
+ray($arrayOrObject)->expand(); // will open up the first level of nodes
+ray($arrayOrObject)->expand(3); // will open up the first three levels of nodes
+ray($arrayOrObject)->expand('myKey'); // will open the node with key named `myKey`
+ray($arrayOrObject)->expand('myKey', 'anotherKey'); // open up all nodes with the given names
+
+// you can use dot notation to expand deeper nodes
+ray($arrayOrObject)->expand('myKey.nestedKey');
+```
+
 ### Using colors
 
 You can colorize things you sent to ray by using one of the color functions.
diff --git a/src/Payloads/ExpandPayload.php b/src/Payloads/ExpandPayload.php
new file mode 100644
index 00000000..348b8ec6
--- /dev/null
+++ b/src/Payloads/ExpandPayload.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Spatie\Ray\Payloads;
+
+class ExpandPayload extends Payload
+{
+    /** @var array */
+    protected $keys = [];
+
+    /** @var int|null */
+    protected $level = null;
+
+    public function __construct(array $values = [])
+    {
+        foreach($values as $value) {
+            if (is_numeric($value)) {
+                $this->level = max($this->level, $value);
+
+                continue;
+            }
+
+            $this->keys[] = $value;
+        }
+    }
+
+    public function getType(): string
+    {
+        return 'expand';
+    }
+
+    public function getContent(): array
+    {
+        return [
+            'keys' => $this->keys,
+            'level' => $this->level,
+        ];
+    }
+}
diff --git a/src/Ray.php b/src/Ray.php
index 25af6707..56ae4083 100644
--- a/src/Ray.php
+++ b/src/Ray.php
@@ -24,6 +24,7 @@
 use Spatie\Ray\Payloads\CustomPayload;
 use Spatie\Ray\Payloads\DecodedJsonPayload;
 use Spatie\Ray\Payloads\ExceptionPayload;
+use Spatie\Ray\Payloads\ExpandPayload;
 use Spatie\Ray\Payloads\FileContentsPayload;
 use Spatie\Ray\Payloads\HideAppPayload;
 use Spatie\Ray\Payloads\HidePayload;
@@ -317,6 +318,17 @@ protected function measureClosure(Closure $closure): self
         return $this->sendRequest($payload);
     }
 
+    public function expand(...$levelOrKey): self
+    {
+        if (empty($levelOrKey)) {
+            $levelOrKey = [1];
+        }
+
+        $payload = new ExpandPayload($levelOrKey);
+
+        return $this->sendRequest($payload);
+    }
+
     public function stopTime(string $stopwatchName = ''): self
     {
         if ($stopwatchName === '') {
diff --git a/tests/RayTest.php b/tests/RayTest.php
index baf936dc..491df371 100644
--- a/tests/RayTest.php
+++ b/tests/RayTest.php
@@ -1140,3 +1140,29 @@ function (InvalidArgumentException $e, $ray) {
 
     expect($sentRequests[0]['payloads'][0]['content']['values'])->toBe(['this is the result of the private method']);
 });
+
+it('can send the expand payload', function(
+    ?array $expandArguments,
+    ?int $expectedLevel,
+    array $expectedKeys
+) {
+
+    $expandArguments === null
+        ? $this->ray->expand()
+        : $this->ray->expand(...$expandArguments);
+
+    $sentRequests = $this->client->sentRequests();
+
+    expect($sentRequests)->toHaveCount(1);
+
+    expect($sentRequests[0]['payloads'][0]['content']['level'])->toBe($expectedLevel);
+    expect($sentRequests[0]['payloads'][0]['content']['keys'])->toBe($expectedKeys);
+})->with([
+    [null, 1, []],
+    [[1], 1, []],
+    [[1,2,3], 3, []],
+    [['key'], null, ['key']],
+    [['key', 'anotherKey'], null, ['key', 'anotherKey']],
+    [['key', 'anotherKey', 2], 2, ['key', 'anotherKey']],
+    [['key', 'anotherKey', 2, 3], 3, ['key', 'anotherKey']],
+]);

From 199fc79512aeb28164c462e7cbdc33d680e8eb79 Mon Sep 17 00:00:00 2001
From: freekmurze <freekmurze@users.noreply.github.com>
Date: Tue, 12 Sep 2023 08:09:39 +0000
Subject: [PATCH 2/2] Fix styling

---
 tests/RayTest.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/RayTest.php b/tests/RayTest.php
index 491df371..b72a5ec6 100644
--- a/tests/RayTest.php
+++ b/tests/RayTest.php
@@ -1141,7 +1141,7 @@ function (InvalidArgumentException $e, $ray) {
     expect($sentRequests[0]['payloads'][0]['content']['values'])->toBe(['this is the result of the private method']);
 });
 
-it('can send the expand payload', function(
+it('can send the expand payload', function (
     ?array $expandArguments,
     ?int $expectedLevel,
     array $expectedKeys