Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
princejohnsantillan authored Mar 10, 2024
2 parents 59b287a + 6bd44d3 commit da76921
Show file tree
Hide file tree
Showing 61 changed files with 387 additions and 142 deletions.
13 changes: 7 additions & 6 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest]
php: [8.1]
laravel: [10.*, 9.*, 8.81.*]
php: [8.1, 8.2]
laravel: [11.*, 10.*]
stability: [prefer-lowest, prefer-stable]
include:
- laravel: 10.*
testbench: 8.*
- laravel: 9.*
testbench: 7.*
- laravel: 8.81.*
testbench: 6.24.*
- laravel: 11.*
testbench: 9.*
exclude:
- laravel: 11.*
php: 8.1

name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}

Expand Down
17 changes: 8 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,19 @@
],
"require": {
"php": "^8.1",
"illuminate/contracts": "^8.0.0|^9.0.0|^10.0.0",
"nikic/php-parser": "^4.0",
"illuminate/contracts": "^10.0|^11.0",
"nikic/php-parser": "^5.0",
"phpstan/phpdoc-parser": "^1.0",
"spatie/laravel-package-tools": "^1.9.2"
},
"require-dev": {
"doctrine/dbal": "^3.4",
"laravel/pint": "^v1.1.0",
"nunomaduro/collision": "^5.0|^v6.0",
"orchestra/testbench": "^6.0|^7.0|^8.0",
"pestphp/pest": "^1.21",
"pestphp/pest-plugin-laravel": "^1.2",
"phpunit/phpunit": "^9.5",
"spatie/pest-plugin-snapshots": "^1.1"
"nunomaduro/collision": "^7.0|^8.0",
"orchestra/testbench": "^8.0|^9.0",
"pestphp/pest": "^2.34",
"pestphp/pest-plugin-laravel": "^2.3",
"phpunit/phpunit": "^10.5",
"spatie/pest-plugin-snapshots": "^2.1"
},
"autoload": {
"psr-4": {
Expand Down
6 changes: 6 additions & 0 deletions config/scramble.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
*/
'export_path' => 'api.json',

/*
* Define the theme of the documentation.
* Available options are `light` and `dark`.
*/
'theme' => 'dark',

'info' => [
/*
* API version.
Expand Down
2 changes: 1 addition & 1 deletion resources/views/docs.blade.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!doctype html>
<html lang="en">
<html lang="en" data-theme="{{ config('scramble.theme', 'light') }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
Expand Down
2 changes: 1 addition & 1 deletion src/Infer/Definition/ClassDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public function getPropertyDefinition($name)
return $this->properties[$name] ?? null;
}

public function getMethodCallType(string $name, ObjectType $calledOn = null)
public function getMethodCallType(string $name, ?ObjectType $calledOn = null)
{
$methodDefinition = $this->methods[$name] ?? null;

Expand Down
2 changes: 1 addition & 1 deletion src/Infer/Definition/FunctionLikeDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class FunctionLikeDefinition
public bool $isFullyAnalyzed = false;

/**
* @param array<string, Type> $argumentsDefaults A map where the key is arg name and value is a default type.
* @param array<string, Type> $argumentsDefaults A map where the key is arg name and value is a default type.
*/
public function __construct(
public FunctionType $type,
Expand Down
4 changes: 2 additions & 2 deletions src/Infer/Handler/ThrowHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ class ThrowHandler
{
public function shouldHandle($node)
{
return $node instanceof Node\Stmt\Throw_;
return $node instanceof Node\Expr\Throw_;
}

public function leave(Node\Stmt\Throw_ $node, Scope $scope)
public function leave(Node\Expr\Throw_ $node, Scope $scope)
{
if (! $scope->isInFunction()) {
return;
Expand Down
2 changes: 2 additions & 0 deletions src/Infer/Reflector/ClassReflector.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class ClassReflector

private ?NameContext $nameContext = null;

private array $methods = [];

private function __construct(
private FileParser $parser,
private string $className,
Expand Down
2 changes: 1 addition & 1 deletion src/Infer/Reflector/MethodReflector.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public function __construct($nameContext)
$this->nameContext = $nameContext;
}

public function beforeTraverse(array $nodes)
public function beforeTraverse(array $nodes): ?array
{
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Infer/Scope/Scope.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public function setType(Node $node, Type $type)
return $type;
}

public function createChildScope(ScopeContext $context = null)
public function createChildScope(?ScopeContext $context = null)
{
return new Scope(
$this->index,
Expand Down
4 changes: 2 additions & 2 deletions src/Infer/Services/ReferenceTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ private function getFunctionCallResult(
FunctionLikeDefinition $callee,
array $arguments,
/* When this is a handling for method call */
ObjectType|SelfType $calledOnType = null,
ObjectType|SelfType|null $calledOnType = null,
) {
$returnType = $callee->type->getReturnType();
$isSelf = false;
Expand Down Expand Up @@ -401,7 +401,7 @@ private function getFunctionCallResult(
* arguments defaults.
*
* @param ?FunctionLikeDefinition $callee
* @param array $realArguments The list of arguments a function has been called with.
* @param array $realArguments The list of arguments a function has been called with.
* @return array The actual list of arguments where not passed arguments replaced with default values.
*/
private function prepareArguments(?FunctionLikeDefinition $callee, array $realArguments)
Expand Down
4 changes: 3 additions & 1 deletion src/ScrambleServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Dedoc\Scramble\Support\InferExtensions\ResponseFactoryTypeInfer;
use Dedoc\Scramble\Support\InferExtensions\ValidatorTypeInfer;
use Dedoc\Scramble\Support\OperationBuilder;
use Dedoc\Scramble\Support\OperationExtensions\DeprecationExtension;
use Dedoc\Scramble\Support\OperationExtensions\ErrorResponsesExtension;
use Dedoc\Scramble\Support\OperationExtensions\RequestBodyExtension;
use Dedoc\Scramble\Support\OperationExtensions\RequestEssentialsExtension;
Expand Down Expand Up @@ -55,7 +56,7 @@ public function configurePackage(Package $package): void

$this->app->singleton(FileParser::class, function () {
return new FileParser(
(new ParserFactory)->create(ParserFactory::PREFER_PHP7)
(new ParserFactory)->createForHostVersion()
);
});

Expand Down Expand Up @@ -110,6 +111,7 @@ public function configurePackage(Package $package): void
RequestBodyExtension::class,
ErrorResponsesExtension::class,
ResponseExtension::class,
DeprecationExtension::class,
], $operationExtensions);
});

Expand Down
13 changes: 13 additions & 0 deletions src/Support/Generator/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class Operation

public string $summary = '';

public bool $deprecated = false;

/** @var array<Security|array> */
public array $security = [];

Expand Down Expand Up @@ -111,6 +113,13 @@ public function description(string $description)
return $this;
}

public function deprecated(bool $deprecated)
{
$this->deprecated = $deprecated;

return $this;
}

public function setTags(array $tags)
{
$this->tags = array_map(fn ($t) => (string) $t, $tags);
Expand Down Expand Up @@ -141,6 +150,10 @@ public function toArray()
$result['summary'] = $this->summary;
}

if ($this->deprecated) {
$result['deprecated'] = $this->deprecated;
}

if (count($this->tags)) {
$result['tags'] = $this->tags;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Support/Generator/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function toArray()

$content = [];
foreach ($this->content as $mediaType => $schema) {
$content[$mediaType] = $schema ? ['schema' => $schema->toArray()] : [];
$content[$mediaType] = $schema ? ['schema' => $schema->toArray()] : (object) [];
}

$result['content'] = $content;
Expand Down
15 changes: 9 additions & 6 deletions src/Support/Generator/SecuritySchemes/OAuthFlow.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,14 @@ public function addScope(string $name, string $description = '')

public function toArray()
{
return array_filter([
'authorizationUrl' => $this->authorizationUrl,
'tokenUrl' => $this->tokenUrl,
'refreshUrl' => $this->refreshUrl,
'scopes' => $this->scopes,
]);
return [
...array_filter([
'authorizationUrl' => $this->authorizationUrl,
'tokenUrl' => $this->tokenUrl,
'refreshUrl' => $this->refreshUrl,
]),
// Never filter 'scopes' as it is allowed to be empty. If empty it must be an object
'scopes' => empty($this->scopes) ? new \stdClass() : $this->scopes,
];
}
}
4 changes: 2 additions & 2 deletions src/Support/Generator/ServerVariable.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ServerVariable
public function __construct(
string $default,
array $enum = [],
string $description = null
?string $description = null
) {
$this->default = $default;
$this->enum = $enum;
Expand All @@ -23,7 +23,7 @@ public function __construct(
public static function make(
string $default,
array $enum = [],
string $description = null
?string $description = null
) {
return new self($default, $enum, $description);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Support/Generator/UniqueNamesOptionsCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function push(UniqueNameOptions $name)
return $this;
}

public function getUniqueName(UniqueNameOptions $name, callable $onNotUniqueFallback = null): string
public function getUniqueName(UniqueNameOptions $name, ?callable $onNotUniqueFallback = null): string
{
if ($name->eloquent && count($this->eloquentNames[$name->eloquent]) === 1) {
return $name->eloquent;
Expand Down
14 changes: 5 additions & 9 deletions src/Support/InferExtensions/JsonResourceTypeInfer.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,17 +147,13 @@ private static function modelType(ClassDefinition $jsonClass, Scope $scope): ?Ty
$modelType = new UnknownType("Cannot resolve [$modelClass] model type.");
$modelClassDefinition = null;
if ($modelClass && is_a($modelClass, Model::class, true)) {
try {
$modelClassDefinition = (new ModelInfo($modelClass))->type();
// @todo Use ModelExtension implementation of model info to type conversion.
// @todo The problem is that model extension type is dynamic and I'm not sure how to use it here.
$modelClassDefinition = (new ModelInfo($modelClass))->type();

$scope->index->registerClassDefinition($modelClassDefinition);
$scope->index->registerClassDefinition($modelClassDefinition);

$modelType = new ObjectType($modelClassDefinition->name);
} catch (\LogicException $e) {
// Here doctrine/dbal is not installed.
$modelType = null;
$modelClassDefinition = null;
}
$modelType = new ObjectType($modelClassDefinition->name);
}

static::$jsonResourcesModelTypesCache[$jsonClass->name] = [$modelType, $modelClassDefinition];
Expand Down
14 changes: 9 additions & 5 deletions src/Support/InferExtensions/ModelExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,22 @@ public function getPropertyType(PropertyFetchEvent $event): ?Type

private function getBaseAttributeType(Model $model, string $key, array $value)
{
$type = explode(' ', $value['type']);
$typeName = explode('(', $type[0])[0];
$type = explode(' ', $value['type'] ?? '');
$typeName = explode('(', $type[0] ?? '')[0];

if (in_array($key, $model->getDates())) {
if (
($model->getCasts()[$key] ?? null) === 'datetime'
|| in_array($key, $model->getDates())
) {
return new ObjectType(Carbon::class);
}

// @todo Fix to native types
$attributeType = match ($typeName) {
'int', 'integer', 'bigint' => new IntegerType(),
'float', 'double', 'decimal' => new FloatType(),
'string', 'text', 'datetime' => new StringType(),
'bool', 'boolean' => new BooleanType(),
'varchar', 'string', 'text', 'datetime' => new StringType(), // string, text - needed?
'tinyint', 'bool', 'boolean' => new BooleanType(), // bool, boolean - needed?
'json', 'array' => new ArrayType(),
default => new UnknownType("unimplemented DB column type [$type[0]]"),
};
Expand Down
71 changes: 71 additions & 0 deletions src/Support/OperationExtensions/DeprecationExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace Dedoc\Scramble\Support\OperationExtensions;

use Dedoc\Scramble\Extensions\OperationExtension;
use Dedoc\Scramble\Infer\Reflector\ClassReflector;
use Dedoc\Scramble\Support\Generator\Operation;
use Dedoc\Scramble\Support\PhpDoc;
use Dedoc\Scramble\Support\RouteInfo;
use Illuminate\Support\Str;
use PHPStan\PhpDocParser\Ast\PhpDoc\DeprecatedTagValueNode;

/**
* Extension to add deprecation notice to the operation description
* Skips if method is not deprecated
* If a whole class is deprecated, all methods are deprecated, only add the description if exists
*/
class DeprecationExtension extends OperationExtension
{
public function handle(Operation $operation, RouteInfo $routeInfo)
{
// Skip if method is not deprecated
if (! $routeInfo->reflectionMethod() || $routeInfo->phpDoc()->getTagsByName('@not-deprecated')) {
return;
}

$fqdn = $routeInfo->reflectionMethod()->getDeclaringClass()->getName();
$deprecatedClass = $this->getClassDeprecatedValues($fqdn);
$deprecatedTags = $routeInfo->phpDoc()->getDeprecatedTagValues();

// Skip if no deprecations found
if (! $deprecatedClass && ! $deprecatedTags) {
return;
}

$description = Str::of($this->generateDescription($deprecatedClass));

if ($description->isNotEmpty()) {
$description = $description->append("\n\n");
}

$description = $description->append($this->generateDescription($deprecatedTags));

$operation
->description((string) $description)
->deprecated(true);
}

/**
* @return array<DeprecatedTagValueNode>
*/
protected function getClassDeprecatedValues(string $fqdn)
{
$reflector = ClassReflector::make($fqdn);
$classPhpDocString = $reflector->getReflection()->getDocComment();

if ($classPhpDocString === false) {
return [];
}

return PhpDoc::parse($classPhpDocString)->getDeprecatedTagValues();
}

/**
* @return string
*/
private function generateDescription(array $deprecation)
{
return implode("\n", array_map(fn ($tag) => $tag->description, $deprecation));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ private function extractTagsForMethod(RouteInfo $routeInfo)
return [];
}

return explode(',', $tagNodes[0]->value->value);
return explode(',', array_values($tagNodes)[0]->value->value);
}

private function getParametersFromString(?string $str)
Expand Down
Loading

0 comments on commit da76921

Please sign in to comment.