Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 6 additions & 15 deletions src/Support/Generator/Combined/AnyOf.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@

namespace Dedoc\Scramble\Support\Generator\Combined;

use Dedoc\Scramble\Support\Generator\Example;
use Dedoc\Scramble\Support\Generator\MissingValue;
use Dedoc\Scramble\Support\Generator\Types\StringType;
use Dedoc\Scramble\Support\Generator\Types\Type;
use InvalidArgumentException;

class AnyOf extends Type
{
use HasCombinedItems;

public string $combinedOperator = 'anyOf';

/** @var Type[] */
public $items;

Expand All @@ -28,21 +34,6 @@ public function clone(): static
return $clone;
}

public function toArray()
{
$parentArray = parent::toArray();

unset($parentArray['type']);

return [
...$parentArray,
'anyOf' => array_map(
fn ($item) => $item->toArray(),
$this->items,
),
];
}

public function setItems($items)
{
if (collect($items)->contains(fn ($item) => ! $item instanceof Type)) {
Expand Down
120 changes: 120 additions & 0 deletions src/Support/Generator/Combined/HasCombinedItems.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

namespace Dedoc\Scramble\Support\Generator\Combined;

use Dedoc\Scramble\Support\Generator\Example;
use Dedoc\Scramble\Support\Generator\MissingValue;
use Dedoc\Scramble\Support\Generator\Types\Type;

trait HasCombinedItems
{
public function toArray()
{
$parentArray = parent::toArray();

unset($parentArray['type']);

$items = array_map(fn (Type $item) => $item->clone(), $this->items);

$distributedCount = [
'example' => 0,
'examples' => [],
'default' => 0,
];

if (! ($this->example instanceof MissingValue)) {
foreach ($items as $item) {
if ($this->itemMatchesExample($item, $this->example)) {
if ($this->example instanceof Example) {
$item->example($this->example->value);
if (! $item->description && $this->example->summary) {
$item->setDescription($this->example->summary);
}
} else {
$item->example($this->example);
}
$distributedCount['example']++;
}
}
}

if (count($this->examples)) {
$itemExamples = [];
foreach ($this->examples as $i => $example) {
$matched = false;
foreach ($items as $itemIndex => $item) {
if ($this->itemMatchesExample($item, $example)) {
$itemExamples[$itemIndex][] = $example;
$matched = true;
}
}
if ($matched) {
$distributedCount['examples'][] = $i;
}
}

foreach ($itemExamples as $itemIndex => $examples) {
if (count($examples) === 1) {
$example = $examples[0];
if ($example instanceof Example) {
$items[$itemIndex]->example($example->value);
if (! $items[$itemIndex]->description && $example->summary) {
$items[$itemIndex]->setDescription($example->summary);
}
} else {
$items[$itemIndex]->example($example);
}
} else {
$items[$itemIndex]->examples($examples);
}
}
}

if (! ($this->default instanceof MissingValue)) {
foreach ($items as $item) {
if ($item->matches($this->default)) {
$item->default($this->default);
$distributedCount['default']++;
}
}
}

if ($distributedCount['example'] > 0) {
unset($parentArray['example']);
}

if (count($distributedCount['examples']) === count($this->examples) && count($this->examples) > 0) {
unset($parentArray['examples']);
} elseif (count($distributedCount['examples']) > 0) {
$parentArray['examples'] = collect($this->examples)
->filter(fn ($e, $i) => ! in_array($i, $distributedCount['examples']))
->values()
->toArray();
}

if ($distributedCount['default'] > 0) {
unset($parentArray['default']);
}

return [
...$parentArray,
$this->combinedOperator => array_map(
fn ($item) => $item->toArray(),
$items,
),
];
}

private function itemMatchesExample(Type $item, $example): bool
{
if ($example instanceof Example) {
if ($example->type) {
return $item->type === $example->type;
}

return $item->matches($example->value);
}

return $item->matches($example);
}
}
47 changes: 47 additions & 0 deletions src/Support/Generator/Combined/OneOf.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Dedoc\Scramble\Support\Generator\Combined;

use Dedoc\Scramble\Support\Generator\Example;
use Dedoc\Scramble\Support\Generator\MissingValue;
use Dedoc\Scramble\Support\Generator\Types\StringType;
use Dedoc\Scramble\Support\Generator\Types\Type;
use InvalidArgumentException;

class OneOf extends Type
{
use HasCombinedItems;

public string $combinedOperator = 'oneOf';

/** @var Type[] */
public $items;

public function __construct()
{
parent::__construct('oneOf');
$this->items = [new StringType];
}

public function clone(): static
{
$clone = parent::clone();
$clone->items = array_map(
fn (Type $item) => $item->clone(),
$clone->items,
);

return $clone;
}

public function setItems($items)
{
if (collect($items)->contains(fn ($item) => ! $item instanceof Type)) {
throw new InvalidArgumentException('All items should be instances of '.Type::class);
}

$this->items = $items;

return $this;
}
}
10 changes: 9 additions & 1 deletion src/Support/Generator/Example.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ public function __construct(
public ?string $summary = null,
public ?string $description = null,
public ?string $externalValue = null,
) {}
public ?string $type = null,
) {
if ($this->type === 'int') {
$this->type = 'integer';
}
if ($this->type === 'bool') {
$this->type = 'boolean';
}
}

public function toArray()
{
Expand Down
9 changes: 8 additions & 1 deletion src/Support/Generator/Parameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function toArray(): array

return array_merge(
$result,
$this->example instanceof MissingValue ? [] : ['example' => $this->example],
$this->example instanceof MissingValue ? [] : ['example' => $this->example instanceof Example ? $this->example->toArray() : $this->example],
! is_null($this->explode) ? [
'explode' => $this->explode,
] : [],
Expand Down Expand Up @@ -133,6 +133,13 @@ public function example($example)
return $this;
}

public function examples(array $examples)
{
$this->examples = $examples;

return $this;
}

public function setExplode(bool $explode): self
{
$this->explode = $explode;
Expand Down
14 changes: 14 additions & 0 deletions src/Support/Generator/Reference.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ private function getEnumReferenceCasesDescription(): ?string
return $casesDescription;
}

public function matches($value): bool
{
if (parent::matches($value)) {
return true;
}

$resolved = $this->resolve();
if ($resolved instanceof Schema) {
return $resolved->type->matches($value);
}

return false;
}

public function toArray()
{
if ($this->nullable) {
Expand Down
5 changes: 5 additions & 0 deletions src/Support/Generator/TypeTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Dedoc\Scramble\PhpDoc\PhpDocTypeHelper;
use Dedoc\Scramble\Support\Generator\Combined\AllOf;
use Dedoc\Scramble\Support\Generator\Combined\AnyOf;
use Dedoc\Scramble\Support\Generator\Combined\OneOf;
use Dedoc\Scramble\Support\Generator\Types\ArrayType;
use Dedoc\Scramble\Support\Generator\Types\BooleanType;
use Dedoc\Scramble\Support\Generator\Types\IntegerType;
Expand Down Expand Up @@ -267,6 +268,10 @@ private function transformUncached(Type $type): OpenApiType
}

if ($examples = ExamplesExtractor::make($docNode)->extract(preferString: $openApiType instanceof StringType)) {
if (count($examples) > 1 && $openApiType instanceof AnyOf) {
$openApiType = (new OneOf)->setItems($openApiType->items)->addProperties($openApiType);
}

$openApiType->examples($examples);
}

Expand Down
5 changes: 5 additions & 0 deletions src/Support/Generator/Types/ArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ public function setAdditionalItems($additionalItems)
return $this;
}

public function matches($value): bool
{
return is_array($value) && (empty($value) || array_keys($value) === range(0, count($value) - 1));
}

public function toArray()
{
$shouldOmitItems = $this->items->getAttribute('missing')
Expand Down
5 changes: 5 additions & 0 deletions src/Support/Generator/Types/BooleanType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ public function __construct()
{
parent::__construct('boolean');
}

public function matches($value): bool
{
return is_bool($value);
}
}
5 changes: 5 additions & 0 deletions src/Support/Generator/Types/IntegerType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ public function __construct()
{
parent::__construct('integer');
}

public function matches($value): bool
{
return is_int($value);
}
}
5 changes: 5 additions & 0 deletions src/Support/Generator/Types/MixedType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public function __construct()
parent::__construct('mixed');
}

public function matches($value): bool
{
return true;
}

public function toArray()
{
// Yes. It is not an array. I live with it.
Expand Down
5 changes: 5 additions & 0 deletions src/Support/Generator/Types/NullType.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ public function __construct()
{
parent::__construct('null');
}

public function matches($value): bool
{
return is_null($value);
}
}
5 changes: 5 additions & 0 deletions src/Support/Generator/Types/NumberType.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public function setMax($max)
return $this;
}

public function matches($value): bool
{
return is_numeric($value);
}

public function toArray()
{
return array_merge(parent::toArray(), array_filter([
Expand Down
5 changes: 5 additions & 0 deletions src/Support/Generator/Types/ObjectType.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ public function addRequired(array $keys)
return $this;
}

public function matches($value): bool
{
return is_array($value) || is_object($value);
}

public function toArray()
{
$result = parent::toArray();
Expand Down
5 changes: 5 additions & 0 deletions src/Support/Generator/Types/StringType.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public function setMax($max)
return $this;
}

public function matches($value): bool
{
return is_string($value);
}

public function toArray()
{
return array_merge(parent::toArray(), array_filter([
Expand Down
Loading