Skip to content

Commit

Permalink
Merge pull request #207 from phpDocumentor/feature/object-shape
Browse files Browse the repository at this point in the history
Add support for object and list shape types
  • Loading branch information
jaapio authored Mar 22, 2024
2 parents f237fbd + b6f5321 commit fc709d3
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 60 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"require": {
"php": "^7.3 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^1.13",
"phpstan/phpdoc-parser": "^1.18",
"doctrine/deprecations": "^1.0"
},
"require-dev": {
Expand Down
14 changes: 7 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 1 addition & 48 deletions src/PseudoTypes/ArrayShapeItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,53 +13,6 @@

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Mixed_;

use function sprintf;

final class ArrayShapeItem
class ArrayShapeItem extends ShapeItem
{
/** @var string|null */
private $key;
/** @var Type */
private $value;
/** @var bool */
private $optional;

public function __construct(?string $key, ?Type $value, bool $optional)
{
$this->key = $key;
$this->value = $value ?? new Mixed_();
$this->optional = $optional;
}

public function getKey(): ?string
{
return $this->key;
}

public function getValue(): Type
{
return $this->value;
}

public function isOptional(): bool
{
return $this->optional;
}

public function __toString(): string
{
if ($this->key !== null) {
return sprintf(
'%s%s: %s',
$this->key,
$this->optional ? '?' : '',
(string) $this->value
);
}

return (string) $this->value;
}
}
16 changes: 16 additions & 0 deletions src/PseudoTypes/ListShape.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use function implode;

/** @psalm-immutable */
final class ListShape extends ArrayShape
{
public function __toString(): string
{
return 'list{' . implode(', ', $this->getItems()) . '}';
}
}
9 changes: 9 additions & 0 deletions src/PseudoTypes/ListShapeItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

final class ListShapeItem extends ArrayShapeItem
{
}
41 changes: 41 additions & 0 deletions src/PseudoTypes/ObjectShape.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\PseudoType;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Object_;

use function implode;

/** @psalm-immutable */
final class ObjectShape implements PseudoType
{
/** @var ObjectShapeItem[] */
private $items;

public function __construct(ObjectShapeItem ...$items)
{
$this->items = $items;
}

/**
* @return ObjectShapeItem[]
*/
public function getItems(): array
{
return $this->items;
}

public function underlyingType(): Type
{
return new Object_();
}

public function __toString(): string
{
return 'object{' . implode(', ', $this->items) . '}';
}
}
9 changes: 9 additions & 0 deletions src/PseudoTypes/ObjectShapeItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

final class ObjectShapeItem extends ShapeItem
{
}
56 changes: 56 additions & 0 deletions src/PseudoTypes/ShapeItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\PseudoTypes;

use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\Types\Mixed_;

use function sprintf;

abstract class ShapeItem
{
/** @var string|null */
private $key;
/** @var Type */
private $value;
/** @var bool */
private $optional;

public function __construct(?string $key, ?Type $value, bool $optional)
{
$this->key = $key;
$this->value = $value ?? new Mixed_();
$this->optional = $optional;
}

public function getKey(): ?string
{
return $this->key;
}

public function getValue(): Type
{
return $this->value;
}

public function isOptional(): bool
{
return $this->optional;
}

public function __toString(): string
{
if ($this->key !== null) {
return sprintf(
'%s%s: %s',
$this->key,
$this->optional ? '?' : '',
(string) $this->value
);
}

return (string) $this->value;
}
}
45 changes: 42 additions & 3 deletions src/TypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
use phpDocumentor\Reflection\PseudoTypes\IntegerValue;
use phpDocumentor\Reflection\PseudoTypes\List_;
use phpDocumentor\Reflection\PseudoTypes\ListShape;
use phpDocumentor\Reflection\PseudoTypes\ListShapeItem;
use phpDocumentor\Reflection\PseudoTypes\LiteralString;
use phpDocumentor\Reflection\PseudoTypes\LowercaseString;
use phpDocumentor\Reflection\PseudoTypes\NegativeInteger;
Expand All @@ -34,6 +36,8 @@
use phpDocumentor\Reflection\PseudoTypes\NonEmptyString;
use phpDocumentor\Reflection\PseudoTypes\Numeric_;
use phpDocumentor\Reflection\PseudoTypes\NumericString;
use phpDocumentor\Reflection\PseudoTypes\ObjectShape;
use phpDocumentor\Reflection\PseudoTypes\ObjectShapeItem;
use phpDocumentor\Reflection\PseudoTypes\PositiveInteger;
use phpDocumentor\Reflection\PseudoTypes\StringValue;
use phpDocumentor\Reflection\PseudoTypes\TraitString;
Expand Down Expand Up @@ -83,6 +87,8 @@
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ObjectShapeItemNode;
use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode;
use PHPStan\PhpDocParser\Ast\Type\OffsetAccessTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
Expand Down Expand Up @@ -236,10 +242,43 @@ public function createType(?TypeNode $type, Context $context): Type
);

case ArrayShapeNode::class:
return new ArrayShape(
switch ($type->kind) {
case ArrayShapeNode::KIND_ARRAY:
return new ArrayShape(
...array_map(
function (ArrayShapeItemNode $item) use ($context): ArrayShapeItem {
return new ArrayShapeItem(
(string) $item->keyName,
$this->createType($item->valueType, $context),
$item->optional
);
},
$type->items
)
);

case ArrayShapeNode::KIND_LIST:
return new ListShape(
...array_map(
function (ArrayShapeItemNode $item) use ($context): ListShapeItem {
return new ListShapeItem(
null,
$this->createType($item->valueType, $context),
$item->optional
);
},
$type->items
)
);

default:
throw new RuntimeException('Unsupported array shape kind');
}
case ObjectShapeNode::class:
return new ObjectShape(
...array_map(
function (ArrayShapeItemNode $item) use ($context): ArrayShapeItem {
return new ArrayShapeItem(
function (ObjectShapeItemNode $item) use ($context): ObjectShapeItem {
return new ObjectShapeItem(
(string) $item->keyName,
$this->createType($item->valueType, $context),
$item->optional
Expand Down
Loading

0 comments on commit fc709d3

Please sign in to comment.