From 0faa36a60a0c811127734d1c059749dc45c82ecb Mon Sep 17 00:00:00 2001
From: Shalvah <diakon.ng@gmail.com>
Date: Sun, 19 Jan 2025 00:07:43 +0100
Subject: [PATCH] Upgrade PHPStan, cleanup

---
 .github/workflows/lint.yml                       |  2 +-
 camel/Camel.php                                  |  2 +-
 composer.json                                    | 11 +++++++----
 phpstan.neon                                     |  9 ++++++++-
 src/Commands/GenerateDocumentation.php           |  1 +
 src/Extracting/Shared/ResponseFileTools.php      |  4 +---
 src/Extracting/Shared/UrlParamsNormalizer.php    |  6 +-----
 src/GroupedEndpoints/GroupedEndpointsFromApp.php |  2 +-
 src/Writing/Writer.php                           | 10 +++++++---
 9 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 035ba58c..8a86313e 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -25,7 +25,7 @@ jobs:
           extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, intl, gd
 
       - name: Cache composer dependencies
-        uses: actions/cache@@v4
+        uses: actions/cache@v4
         with:
           path: vendor
           key: composer-${{ hashFiles('composer.lock') }}
diff --git a/camel/Camel.php b/camel/Camel.php
index 0a858c72..ff28496d 100644
--- a/camel/Camel.php
+++ b/camel/Camel.php
@@ -83,7 +83,7 @@ public static function loadUserDefinedEndpoints(string $folder): array
 
         $userDefinedEndpoints = [];
         foreach ($contents as $object) {
-            // Flysystem v1 had items as arrays; v2 has objects.
+            // todo Flysystem v1 had items as arrays; v2 has objects.
             // v2 allows ArrayAccess, but when we drop v1 support (Laravel <9), we should switch to methods
             if (
                 $object['type'] == 'file'
diff --git a/composer.json b/composer.json
index 213bdc3d..5fdfb795 100644
--- a/composer.json
+++ b/composer.json
@@ -19,7 +19,7 @@
         "ext-json": "*",
         "ext-pdo": "*",
         "erusev/parsedown": "1.7.4",
-        "fakerphp/faker": "^1.9.1",
+        "fakerphp/faker": "^1.23.1",
         "illuminate/console": "^8.0|^9.0|^10.0|^11.0",
         "illuminate/routing": "^8.0|^9.0|^10.0|^11.0",
         "illuminate/support": "^8.0|^9.0|^10.0|^11.0",
@@ -35,14 +35,14 @@
         "symfony/yaml": "^5.4|^6.0|^7.0"
     },
     "require-dev": {
-        "brianium/paratest": "^6.0",
+        "brianium/paratest": "^v6.11.1",
         "dms/phpunit-arraysubset-asserts": "^0.4",
         "laravel/legacy-factories": "^1.3.0",
         "league/fractal": "^0.20",
         "nikic/fast-route": "^1.3",
         "orchestra/testbench": "^6.0|^7.0|^8.0",
         "pestphp/pest": "^1.21",
-        "phpstan/phpstan": "^1.0",
+        "phpstan/phpstan": "^2.1.1",
         "phpunit/phpunit": "^9.0|^10.0",
         "symfony/css-selector": "^5.4|^6.0",
         "symfony/dom-crawler": "^5.4|^6.0"
@@ -78,7 +78,10 @@
         "process-timeout": 600,
         "allow-plugins": {
             "pestphp/pest-plugin": true
-        }
+        },
+      "platform": {
+        "php": "8.1"
+      }
     },
     "replace": {
         "mpociot/laravel-apidoc-generator": "*"
diff --git a/phpstan.neon b/phpstan.neon
index 2939c97d..516642d8 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,8 +1,15 @@
 parameters:
-    level: 5
+    level: 6
     reportUnmatchedIgnoredErrors: true
     inferPrivatePropertyTypeFromConstructor: true
     ignoreErrors:
+        - identifier: missingType.iterableValue
+        - identifier: missingType.return
+        - identifier: missingType.parameter
+        - identifier: missingType.generics
+        - identifier: missingType.property
+          path: src\Tools\Globals.php
+        - identifier: argument.templateType
         - '#Call to an undefined method ReflectionType::getName\(\).#'
         - '#Call to an undefined method Illuminate\\Contracts\\Filesystem\\Filesystem::path\(\)#'
         - '#Call to an undefined method Illuminate\\Contracts\\Foundation\\Application::forgetInstance\(\)#'
diff --git a/src/Commands/GenerateDocumentation.php b/src/Commands/GenerateDocumentation.php
index 75e9ac43..dac9c8f0 100644
--- a/src/Commands/GenerateDocumentation.php
+++ b/src/Commands/GenerateDocumentation.php
@@ -63,6 +63,7 @@ public function handle(RouteMatcherInterface $routeMatcher, GroupedEndpointsFact
             $this->writeExampleCustomEndpoint();
         }
 
+        /** @var Writer $writer */
         $writer = app(Writer::class, ['config' => $this->docConfig, 'paths' => $this->paths]);
         $writer->writeDocs($groupedEndpoints);
 
diff --git a/src/Extracting/Shared/ResponseFileTools.php b/src/Extracting/Shared/ResponseFileTools.php
index 1a0a8b21..59154b3a 100644
--- a/src/Extracting/Shared/ResponseFileTools.php
+++ b/src/Extracting/Shared/ResponseFileTools.php
@@ -16,9 +16,7 @@ public static function getResponseContents($filePath, array|string|null $merge):
             return json_encode(array_merge(json_decode($content, true), json_decode($json, true)));
         }
 
-        if (is_array($merge)) {
-            return json_encode(array_merge(json_decode($content, true), $merge));
-        }
+        return json_encode(array_merge(json_decode($content, true), $merge));
     }
 
     protected static function getFileContents($filePath): string
diff --git a/src/Extracting/Shared/UrlParamsNormalizer.php b/src/Extracting/Shared/UrlParamsNormalizer.php
index 332b969d..90e4ace1 100644
--- a/src/Extracting/Shared/UrlParamsNormalizer.php
+++ b/src/Extracting/Shared/UrlParamsNormalizer.php
@@ -165,11 +165,7 @@ protected static function getRouteKeyForUrlParam(
      */
     protected static function getInlineRouteKey(Route $route, string $paramName): ?string
     {
-        // Was added in Laravel 7.x
-        if (method_exists($route, 'bindingFieldFor')) {
-            return $route->bindingFieldFor($paramName);
-        }
-        return null;
+        return $route->bindingFieldFor($paramName);
     }
 
     /**
diff --git a/src/GroupedEndpoints/GroupedEndpointsFromApp.php b/src/GroupedEndpoints/GroupedEndpointsFromApp.php
index 49669122..09526af0 100644
--- a/src/GroupedEndpoints/GroupedEndpointsFromApp.php
+++ b/src/GroupedEndpoints/GroupedEndpointsFromApp.php
@@ -190,7 +190,7 @@ private function mergeAnyEndpointDataUpdates(ExtractedEndpointData $endpointData
     protected function writeEndpointsToDisk(array $grouped): void
     {
         Utils::deleteFilesMatching(static::$camelDir, function ($file) {
-            /** @var $file array|\League\Flysystem\StorageAttributes */
+            /** @var array|\League\Flysystem\StorageAttributes $file */
             return !Str::startsWith(basename($file['path']), 'custom.');
         });
         Utils::deleteDirectoryAndContents(static::$cacheDir);
diff --git a/src/Writing/Writer.php b/src/Writing/Writer.php
index 87f750af..96bd12bf 100644
--- a/src/Writing/Writer.php
+++ b/src/Writing/Writer.php
@@ -3,6 +3,7 @@
 namespace Knuckles\Scribe\Writing;
 
 use Illuminate\Support\Facades\Storage;
+use Knuckles\Camel\Output\OutputEndpointData;
 use Knuckles\Scribe\Tools\ConsoleOutputUtils as c;
 use Knuckles\Scribe\Tools\DocumentationConfig;
 use Knuckles\Scribe\Tools\Globals;
@@ -46,9 +47,9 @@ public function __construct(protected DocumentationConfig $config, public PathCo
     }
 
     /**
-     * @param array[] $groupedEndpoints
+     * @param array<string,array> $groupedEndpoints
      */
-    public function writeDocs(array $groupedEndpoints)
+    public function writeDocs(array $groupedEndpoints): void
     {
         // The static assets (js/, css/, and images/) always go in public/docs/.
         // For 'static' docs, the output files (index.html, collection.json) go in public/docs/.
@@ -178,12 +179,15 @@ protected function performFinalTasksForLaravelType(): void
         $contents = str_replace('href="../docs/collection.json"', 'href="{{ route("' . $this->paths->outputPath('postman', '.') . '") }}"', $contents);
         $contents = str_replace('href="../docs/openapi.yaml"', 'href="{{ route("' . $this->paths->outputPath('openapi', '.') . '") }}"', $contents);
         $contents = str_replace('url="../docs/openapi.yaml"', 'url="{{ route("' . $this->paths->outputPath('openapi', '.') . '") }}"', $contents);
-        // With Elements theme, we'd have <elements-api apiDescriptionUrl="../docs/openapi.yaml" 
+        // With Elements theme, we'd have <elements-api apiDescriptionUrl="../docs/openapi.yaml"
         $contents = str_replace('Url="../docs/openapi.yaml"', 'Url="{{ route("' . $this->paths->outputPath('openapi', '.') . '") }}"', $contents);
 
         file_put_contents("$this->laravelTypeOutputPath/index.blade.php", $contents);
     }
 
+    /**
+     * @param array[] $groupedEndpoints
+     */
     public function writeHtmlDocs(array $groupedEndpoints): void
     {
         c::info('Writing ' . ($this->isStatic ? 'HTML' : 'Blade') . ' docs...');