This commit is contained in:
Jaapio
2022-10-28 14:05:33 +02:00
parent 7192e67cfa
commit d6c050a533
16 changed files with 734 additions and 272 deletions
@@ -17,7 +17,11 @@ use Mockery as m;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
use phpDocumentor\Reflection\DocBlock\Tags\See;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\String_;
use PHPUnit\Framework\TestCase;
/**
@@ -83,7 +87,7 @@ DESCRIPTION;
str_replace(
PHP_EOL,
"\n",
$descriptionText
$descriptionText
),
$description->render()
);
@@ -134,7 +138,7 @@ DESCRIPTION;
str_replace(
PHP_EOL,
"\n",
<<<'DESCRIPTION'
<<<'DESCRIPTION'
You can escape the @-sign by surrounding it with braces, for example: @. And escape a closing brace within an
inline tag by adding an opening brace in front of it like this: }.
@@ -149,4 +153,36 @@ DESCRIPTION
$foundDescription
);
}
public function testMultilineTags(): void
{
$docCommment = <<<DOC
/**
* This is an example of a summary.
*
* @param array<
* int,
* string
* > \$store
*/
DOC;
$factory = DocBlockFactory::createInstance();
$docblock = $factory->create($docCommment);
self::assertEquals(
[
new Param(
'store',
new Array_(
new String_(),
new Integer()
),
false,
new Description(''),
),
],
$docblock->getTags()
);
}
}
@@ -1,61 +0,0 @@
<?php
/*
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link http://phpdoc.org
*
*/
declare(strict_types=1);
namespace phpDocumentor\Reflection;
use phpDocumentor\Reflection\DocBlock\Description;
use phpDocumentor\Reflection\DocBlock\Tags\Param;
use phpDocumentor\Reflection\DocBlock\Tags\Return_;
use phpDocumentor\Reflection\PseudoTypes\ArrayShape;
use phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\String_;
use PHPUnit\Framework\TestCase;
class PhpStanDocblockFactoryTest extends TestCase
{
public function testDocblockIsParsed()
{
$docblock = new DocBlock(
'test summary',
new Description(
"This description contains tags \n And is multiline"
),
[
new Param('firstParam', new String_(), false, new Description('Some description'), false),
new Return_(new ArrayShape(new ArrayShapeItem('foo', new String_(), false)))
]
);
$string = <<<DOC
/**
* test summary
*
* THis description contains tags {@see https://phpdoc.org with a description}
* And is multi line
*
* @param string \$firstParam Some description
* @return array{foo: string}
*/
DOC;
$factory = PhpStanDocblockFactory::createInstance();
$actual = $factory->create(
$string,
new Context('/')
);
self::assertEquals($docblock, $actual);
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
/*
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link http://phpdoc.org
*
*/
declare(strict_types=1);
namespace phpDocumentor\Reflection\Assets;
use phpDocumentor\Reflection\DocBlock\Tag;
use phpDocumentor\Reflection\DocBlock\TagFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
use phpDocumentor\Reflection\Types\Context;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
class CustomTagFactory implements TagFactory
{
public $class;
public function addParameter(string $name, $value): void
{
// TODO: Implement addParameter() method.
}
public function create(string $tagLine, ?Context $context = null, CustomServiceClass $class = null): Tag
{
$this->class = $class;
return new Generic('custom');
}
public function addService(object $service): void
{
// TODO: Implement addService() method.
}
public function registerTagHandler(string $tagName, string $handler): void
{
// TODO: Implement registerTagHandler() method.
}
}
@@ -18,6 +18,7 @@ use Mockery as m;
use phpDocumentor\Reflection\Assets\CustomParam;
use phpDocumentor\Reflection\Assets\CustomServiceClass;
use phpDocumentor\Reflection\Assets\CustomServiceInterface;
use phpDocumentor\Reflection\Assets\CustomTagFactory;
use phpDocumentor\Reflection\DocBlock\Tags\Author;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter;
@@ -225,6 +226,22 @@ class StandardTagFactoryTest extends TestCase
$this->assertSame('author', $tag->getName());
}
public function testTagWithHandlerObject(): void
{
$fqsenResolver = new FqsenResolver();
$customFactory = new CustomTagFactory();
$injectedClass = new CustomServiceClass();
$tagFactory = new StandardTagFactory($fqsenResolver);
$tagFactory->addService($injectedClass);
$tagFactory->registerTagHandler('param', $customFactory);
$tag = $tagFactory->create('@param foo');
self::assertSame('custom', $tag->getName());
self::assertSame($injectedClass, $customFactory->class);
}
/**
* @uses \phpDocumentor\Reflection\DocBlock\StandardTagFactory::addService
* @uses \phpDocumentor\Reflection\DocBlock\Tags\Author
@@ -0,0 +1,270 @@
<?php
declare(strict_types=1);
namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\FqsenResolver;
use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
use phpDocumentor\Reflection\PseudoTypes\List_;
use phpDocumentor\Reflection\Type;
use phpDocumentor\Reflection\TypeResolver;
use phpDocumentor\Reflection\Types\Array_;
use phpDocumentor\Reflection\Types\ArrayKey;
use phpDocumentor\Reflection\Types\Callable_;
use phpDocumentor\Reflection\Types\ClassString;
use phpDocumentor\Reflection\Types\Collection;
use phpDocumentor\Reflection\Types\Compound;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Float_;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\InterfaceString;
use phpDocumentor\Reflection\Types\Intersection;
use phpDocumentor\Reflection\Types\Nullable;
use phpDocumentor\Reflection\Types\Object_;
use phpDocumentor\Reflection\Types\Self_;
use phpDocumentor\Reflection\Types\String_;
use phpDocumentor\Reflection\Types\This;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
use PHPUnit\Framework\TestCase;
final class TypeFactoryTest extends TestCase
{
/**
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\TypeFactory::createType
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\TypeFactory::createFromGeneric
* @covers \phpDocumentor\Reflection\DocBlock\Tags\Factory\TypeFactory::createFromCallable
* @dataProvider typeProvider
* @dataProvider genericsProvider
* @dataProvider callableProvider
*/
public function testTypeBuilding(string $type, Type $expected): void
{
$lexer = new Lexer();
$tokens = $lexer->tokenize($type);
$constParser = new ConstExprParser();
$parser = new TypeParser($constParser);
$ast = $parser->parse(new TokenIterator($tokens));
$factory = new TypeFactory(new TypeResolver(new FqsenResolver()));
$actual = $factory->createType($ast, new Context('phpDocumentor'));
self::assertEquals($expected, $actual);
}
public function typeProvider(): array
{
return [
[
'string',
new String_(),
],
[
'( string )',
new String_(),
],
[
'\\Foo\Bar\\Baz',
new Object_(new Fqsen('\\Foo\Bar\\Baz')),
],
[
'string|int',
new Compound(
[
new String_(),
new Integer(),
]
),
],
[
'string&int',
new Intersection(
[
new String_(),
new Integer(),
]
),
],
[
'string & (int | float)',
new Intersection(
[
new String_(),
new Compound(
[
new Integer(),
new Float_(),
]
),
]
),
],
[
'string[]',
new Array_(
new String_()
),
],
[
'$this',
new This(),
],
[
'?int',
new Nullable(
new Integer()
),
],
[
'self',
new Self_(),
],
];
}
public function genericsProvider(): array
{
return [
[
'array<int, Foo\\Bar>',
new Array_(
new Object_(new Fqsen('\\phpDocumentor\\Foo\\Bar')),
new Integer()
),
],
[
'Collection<array-key, int>[]',
new Array_(
new Collection(
new Fqsen('\\phpDocumentor\\Collection'),
new Integer(),
new ArrayKey()
)
),
],
[
'class-string',
new ClassString(null),
],
[
'class-string<Foo>',
new ClassString(new Fqsen('\\phpDocumentor\\Foo')),
],
[
'interface-string<Foo>',
new InterfaceString(new Fqsen('\\phpDocumentor\\Foo')),
],
[
'List<Foo>',
new List_(new Object_(new Fqsen('\\phpDocumentor\\Foo'))),
],
[
'int<1, 100>',
new IntegerRange('1', '100'),
],
];
}
public function callableProvider(): array
{
return [
[
'callable',
new Callable_(),
],
[
'callable()',
new Callable_(),
],
[
'callable(): Foo',
new Callable_(),
],
[
'callable(): (Foo&Bar)',
new Callable_(),
],
[
'callable(A&...$a=, B&...=, C): Foo',
new Callable_(),
],
];
}
public function constExpressions(): array
{
return [
['Foo::FOO_CONSTANT'],
[
'123',
//new ConstTypeNode(new ConstExprIntegerNode('123')),
],
[
'123.2',
//new ConstTypeNode(new ConstExprFloatNode('123.2')),
],
[
'"bar"',
//new ConstTypeNode(new ConstExprStringNode('bar')),
],
[
'Foo::FOO_*',
//new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*')),
],
[
'Foo::FOO_*BAR',
//new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*BAR')),
],
[
'Foo::*FOO*',
//new ConstTypeNode(new ConstFetchNode('Foo', '*FOO*')),
],
[
'Foo::A*B*C',
//new ConstTypeNode(new ConstFetchNode('Foo', 'A*B*C')),
],
[
'self::*BAR',
//new ConstTypeNode(new ConstFetchNode('self', '*BAR')),
],
[
'Foo::*',
//new ConstTypeNode(new ConstFetchNode('Foo', '*')),
],
[
'Foo::**',
//new ConstTypeNode(new ConstFetchNode('Foo', '*')), // fails later in PhpDocParser
//Lexer::TOKEN_WILDCARD,
],
[
'Foo::*a',
//new ConstTypeNode(new ConstFetchNode('Foo', '*a')),
],
[
'( "foo" | Foo::FOO_* )',
// new UnionTypeNode([
// new ConstTypeNode(new ConstExprStringNode('foo')),
// new ConstTypeNode(new ConstFetchNode('Foo', 'FOO_*')),
// ]),
],
[
'DateTimeImmutable::*|DateTime::*',
// new UnionTypeNode([
// new ConstTypeNode(new ConstFetchNode('DateTimeImmutable', '*')),
// new ConstTypeNode(new ConstFetchNode('DateTime', '*')),
// ]),
],
[
'ParameterTier::*|null',
// new UnionTypeNode([
// new ConstTypeNode(new ConstFetchNode('ParameterTier', '*')),
// new IdentifierTypeNode('null'),
// ]),
],
];
}
}