diff --git a/src/Generator.php b/src/Generator.php index b30b96a7..692af4a1 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -38,6 +38,7 @@ public function __invoke() try { return $this->routeToOperation($route); } catch (Throwable $e) { + throw $e; throw RouteAnalysisErrorException::make($route, $e); } }) diff --git a/src/Support/ExceptionToResponseExtensions/AuthorizationExceptionToResponseExtension.php b/src/Support/ExceptionToResponseExtensions/AuthorizationExceptionToResponseExtension.php index 02885717..2d5ccedc 100644 --- a/src/Support/ExceptionToResponseExtensions/AuthorizationExceptionToResponseExtension.php +++ b/src/Support/ExceptionToResponseExtensions/AuthorizationExceptionToResponseExtension.php @@ -10,6 +10,7 @@ use Dedoc\Scramble\Support\Type\ObjectType; use Dedoc\Scramble\Support\Type\Type; use Illuminate\Auth\Access\AuthorizationException; +use Illuminate\Support\Str; class AuthorizationExceptionToResponseExtension extends ExceptionToResponseExtension { @@ -39,6 +40,6 @@ public function toResponse(Type $type) public function reference(ObjectType $type) { - return new Reference('responses', $type->name, $this->components); + return new Reference('responses', Str::start($type->name, '\\'), $this->components); } } diff --git a/src/Support/ExceptionToResponseExtensions/NotFoundExceptionToResponseExtension.php b/src/Support/ExceptionToResponseExtensions/NotFoundExceptionToResponseExtension.php index 087e1c12..13e78734 100644 --- a/src/Support/ExceptionToResponseExtensions/NotFoundExceptionToResponseExtension.php +++ b/src/Support/ExceptionToResponseExtensions/NotFoundExceptionToResponseExtension.php @@ -10,6 +10,7 @@ use Dedoc\Scramble\Support\Type\ObjectType; use Dedoc\Scramble\Support\Type\Type; use Illuminate\Database\RecordsNotFoundException; +use Illuminate\Support\Str; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class NotFoundExceptionToResponseExtension extends ExceptionToResponseExtension @@ -43,6 +44,6 @@ public function toResponse(Type $type) public function reference(ObjectType $type) { - return new Reference('responses', $type->name, $this->components); + return new Reference('responses', Str::start($type->name, '\\'), $this->components); } } diff --git a/src/Support/ExceptionToResponseExtensions/ValidationExceptionToResponseExtension.php b/src/Support/ExceptionToResponseExtensions/ValidationExceptionToResponseExtension.php index cda15dbd..eb4817d1 100644 --- a/src/Support/ExceptionToResponseExtensions/ValidationExceptionToResponseExtension.php +++ b/src/Support/ExceptionToResponseExtensions/ValidationExceptionToResponseExtension.php @@ -9,6 +9,7 @@ use Dedoc\Scramble\Support\Generator\Types as OpenApiTypes; use Dedoc\Scramble\Support\Type\ObjectType; use Dedoc\Scramble\Support\Type\Type; +use Illuminate\Support\Str; use Illuminate\Validation\ValidationException; class ValidationExceptionToResponseExtension extends ExceptionToResponseExtension @@ -45,6 +46,6 @@ public function toResponse(Type $type) public function reference(ObjectType $type) { - return new Reference('responses', $type->name, $this->components); + return new Reference('responses', Str::start($type->name, '\\'), $this->components); } } diff --git a/src/Support/Generator/TypeTransformer.php b/src/Support/Generator/TypeTransformer.php index b7200c82..e9b21cb4 100644 --- a/src/Support/Generator/TypeTransformer.php +++ b/src/Support/Generator/TypeTransformer.php @@ -207,6 +207,10 @@ function ($acc, $extensionClass) use ($type) { public function toResponse(Type $type) { if (! $response = $this->handleResponseUsingExtensions($type)) { + if ($type->isInstanceOf(\Throwable::class)) { + return null; + } + $response = Response::make(200) ->setContent( 'application/json', diff --git a/src/Support/InferExtensions/JsonResourceCallsTypeInfer.php b/src/Support/InferExtensions/JsonResourceCallsTypeInfer.php index e0993ecd..6c4a0e90 100644 --- a/src/Support/InferExtensions/JsonResourceCallsTypeInfer.php +++ b/src/Support/InferExtensions/JsonResourceCallsTypeInfer.php @@ -4,6 +4,7 @@ use Dedoc\Scramble\Infer\Extensions\ExpressionTypeInferExtension; use Dedoc\Scramble\Infer\Scope\Scope; +use Dedoc\Scramble\Support\Type\ObjectType; use Dedoc\Scramble\Support\Type\Type; use Dedoc\Scramble\Support\Type\TypeHelper; use Illuminate\Http\Resources\Json\JsonResource; @@ -25,7 +26,15 @@ public function getType(Expr $node, Scope $scope): ?Type if ($node->name->toString() === 'additional' && isset($node->args[0])) { $type = $scope->getType($node->var); - $type->properties = array_merge($type->properties, [ + $objectType = $type instanceof ObjectType + ? $type + : $type->type ?? null; // the case then type is Generic. This is the documented case of resources. + + if (! $objectType instanceof ObjectType) { + return null; + } + + $objectType->properties = array_merge($objectType->properties, [ 'additional' => TypeHelper::getArgType($scope, $node->args, ['data', 0]), ]); diff --git a/src/Support/InferHandlers/PhpDocHandler.php b/src/Support/InferHandlers/PhpDocHandler.php index b018f186..70ec0429 100644 --- a/src/Support/InferHandlers/PhpDocHandler.php +++ b/src/Support/InferHandlers/PhpDocHandler.php @@ -8,6 +8,7 @@ use Dedoc\Scramble\PhpDoc\ResolveFqnPhpDocTypeVisitor; use Dedoc\Scramble\Support\PhpDoc; use Dedoc\Scramble\Support\Type\Type; +use Dedoc\Scramble\Support\Type\Union; use Illuminate\Support\Str; use PhpParser\Comment; use PhpParser\Comment\Doc; @@ -59,10 +60,16 @@ public function leave(Node $node, Scope $scope): ?Type if ($node instanceof Node\Stmt\ClassMethod && ($methodType = $scope->getType($node)) && $doc = $node->getDocComment()) { $docNode = $this->getDocNode($scope, $doc); - $thrownExceptions = array_map( - fn (ThrowsTagValueNode $t) => PhpDocTypeHelper::toType($t->type), - $docNode->getThrowsTagValues(), - ); + $thrownExceptions = collect($docNode->getThrowsTagValues()) + ->flatMap(function (ThrowsTagValueNode $t) { + $type = PhpDocTypeHelper::toType($t->type); + + if ($type instanceof Union) { + return $type->types; + } + + return [$type]; + }); $methodType->exceptions = [ ...$methodType->exceptions, diff --git a/src/Support/OperationExtensions/ResponseExtension.php b/src/Support/OperationExtensions/ResponseExtension.php index 28af8297..0e58e7fe 100644 --- a/src/Support/OperationExtensions/ResponseExtension.php +++ b/src/Support/OperationExtensions/ResponseExtension.php @@ -28,12 +28,12 @@ public function handle(Operation $operation, RouteInfo $routeInfo) $responses = collect($returnTypes) ->merge($routeInfo->getMethodType()->exceptions) - ->map(fn ($returnType) => $this->openApiTransformer->toResponse($returnType)); + ->map(fn ($returnType) => $this->openApiTransformer->toResponse($returnType)) + ->filter(); [$responses, $references] = $responses->partition(fn ($r) => $r instanceof Response); $responses = $responses - ->filter() ->groupBy('code') ->map(function (Collection $responses, $code) { if (count($responses) === 1) { diff --git a/src/Support/Type/Generic.php b/src/Support/Type/Generic.php index 87cf9747..292c5741 100644 --- a/src/Support/Type/Generic.php +++ b/src/Support/Type/Generic.php @@ -19,6 +19,11 @@ public function isInstanceOf(string $className) return $this->type->isInstanceOf($className); } + public function getPropertyFetchType(string $propertyName): Type + { + return $this->type->getPropertyFetchType($propertyName); + } + public function children(): array { return [ diff --git a/src/Support/TypeToSchemaExtensions/JsonResourceTypeToSchema.php b/src/Support/TypeToSchemaExtensions/JsonResourceTypeToSchema.php index 09079edf..2b9e7b39 100644 --- a/src/Support/TypeToSchemaExtensions/JsonResourceTypeToSchema.php +++ b/src/Support/TypeToSchemaExtensions/JsonResourceTypeToSchema.php @@ -46,6 +46,10 @@ public function toSchema(Type $type) } } + if (! $array instanceof ArrayType) { + return new UnknownType(); + } + $array->items = $this->flattenMergeValues($array->items); return $this->openApiTransformer->transform($array);