summaryrefslogtreecommitdiff
path: root/vendor/phpdocumentor/reflection-docblock
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2022-03-22 12:24:31 +0300
committerAndrew Dolgov <[email protected]>2022-03-22 12:24:31 +0300
commit1c4f7ab3b838b23afb2ee4dab14acbf75956e952 (patch)
tree0a19274107d717efe92d2c0376cd3105fead5a11 /vendor/phpdocumentor/reflection-docblock
parent711662948768492e8d05b778a7d80eacaec368d2 (diff)
* add phpunit as a dev dependency
* add some basic tests for UrlHelper::rewrite_relative() * fix UrlHelper::rewrite_relative() to work better on non-absolute relative URL paths
Diffstat (limited to 'vendor/phpdocumentor/reflection-docblock')
-rw-r--r--vendor/phpdocumentor/reflection-docblock/LICENSE21
-rw-r--r--vendor/phpdocumentor/reflection-docblock/README.md75
-rw-r--r--vendor/phpdocumentor/reflection-docblock/composer.json42
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock.php228
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Description.php115
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php178
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php159
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php157
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php348
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php31
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php84
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php102
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php53
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php101
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php109
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php200
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php25
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php24
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php50
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php30
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php89
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php145
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php78
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php279
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php174
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php121
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php121
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php121
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php38
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php22
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php36
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php64
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php106
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php103
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php116
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php66
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php64
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php100
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php122
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php106
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlockFactory.php287
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php23
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/Exception/PcreException.php44
-rw-r--r--vendor/phpdocumentor/reflection-docblock/src/Utils.php62
44 files changed, 4619 insertions, 0 deletions
diff --git a/vendor/phpdocumentor/reflection-docblock/LICENSE b/vendor/phpdocumentor/reflection-docblock/LICENSE
new file mode 100644
index 000000000..792e4040f
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2010 Mike van Riel
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/phpdocumentor/reflection-docblock/README.md b/vendor/phpdocumentor/reflection-docblock/README.md
new file mode 100644
index 000000000..51f10883b
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/README.md
@@ -0,0 +1,75 @@
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+![Qa workflow](https://github.com/phpDocumentor/ReflectionDocBlock/workflows/Qa%20workflow/badge.svg)
+[![Coveralls Coverage](https://img.shields.io/coveralls/github/phpDocumentor/ReflectionDocBlock.svg)](https://coveralls.io/github/phpDocumentor/ReflectionDocBlock?branch=master)
+[![Scrutinizer Code Coverage](https://img.shields.io/scrutinizer/coverage/g/phpDocumentor/ReflectionDocBlock.svg)](https://scrutinizer-ci.com/g/phpDocumentor/ReflectionDocBlock/?branch=master)
+[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/phpDocumentor/ReflectionDocBlock.svg)](https://scrutinizer-ci.com/g/phpDocumentor/ReflectionDocBlock/?branch=master)
+[![Stable Version](https://img.shields.io/packagist/v/phpdocumentor/reflection-docblock.svg)](https://packagist.org/packages/phpdocumentor/reflection-docblock)
+[![Unstable Version](https://img.shields.io/packagist/vpre/phpdocumentor/reflection-docblock.svg)](https://packagist.org/packages/phpdocumentor/reflection-docblock)
+
+ReflectionDocBlock
+==================
+
+Introduction
+------------
+
+The ReflectionDocBlock component of phpDocumentor provides a DocBlock parser
+that is 100% compatible with the [PHPDoc standard](http://phpdoc.org/docs/latest).
+
+With this component, a library can provide support for annotations via DocBlocks
+or otherwise retrieve information that is embedded in a DocBlock.
+
+Installation
+------------
+
+```bash
+composer require phpdocumentor/reflection-docblock
+```
+
+Usage
+-----
+
+In order to parse the DocBlock one needs a DocBlockFactory that can be
+instantiated using its `createInstance` factory method like this:
+
+```php
+$factory = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
+```
+
+Then we can use the `create` method of the factory to interpret the DocBlock.
+Please note that it is also possible to provide a class that has the
+`getDocComment()` method, such as an object of type `ReflectionClass`, the
+create method will read that if it exists.
+
+```php
+$docComment = <<<DOCCOMMENT
+/**
+ * This is an example of a summary.
+ *
+ * This is a Description. A Summary and Description are separated by either
+ * two subsequent newlines (thus a whiteline in between as can be seen in this
+ * example), or when the Summary ends with a dot (`.`) and some form of
+ * whitespace.
+ */
+DOCCOMMENT;
+
+$docblock = $factory->create($docComment);
+```
+
+The `create` method will yield an object of type `\phpDocumentor\Reflection\DocBlock`
+whose methods can be queried:
+
+```php
+// Contains the summary for this DocBlock
+$summary = $docblock->getSummary();
+
+// Contains \phpDocumentor\Reflection\DocBlock\Description object
+$description = $docblock->getDescription();
+
+// You can either cast it to string
+$description = (string) $docblock->getDescription();
+
+// Or use the render method to get a string representation of the Description.
+$description = $docblock->getDescription()->render();
+```
+
+> For more examples it would be best to review the scripts in the [`/examples` folder](/examples).
diff --git a/vendor/phpdocumentor/reflection-docblock/composer.json b/vendor/phpdocumentor/reflection-docblock/composer.json
new file mode 100644
index 000000000..d90763024
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/composer.json
@@ -0,0 +1,42 @@
+{
+ "name": "phpdocumentor/reflection-docblock",
+ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "[email protected]"
+ },
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "[email protected]"
+ }
+ ],
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "phpdocumentor/type-resolver": "^1.3",
+ "webmozart/assert": "^1.9.1",
+ "phpdocumentor/reflection-common": "^2.2",
+ "ext-filter": "*"
+ },
+ "require-dev": {
+ "mockery/mockery": "~1.3.2",
+ "psalm/phar": "^4.8"
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": ["tests/unit", "tests/integration"]
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.x-dev"
+ }
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock.php
new file mode 100644
index 000000000..cc33e60e6
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock.php
@@ -0,0 +1,228 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection;
+
+use phpDocumentor\Reflection\DocBlock\Tag;
+use phpDocumentor\Reflection\DocBlock\Tags\TagWithType;
+use Webmozart\Assert\Assert;
+
+final class DocBlock
+{
+ /** @var string The opening line for this docblock. */
+ private $summary;
+
+ /** @var DocBlock\Description The actual description for this docblock. */
+ private $description;
+
+ /** @var Tag[] An array containing all the tags in this docblock; except inline. */
+ private $tags = [];
+
+ /** @var Types\Context|null Information about the context of this DocBlock. */
+ private $context;
+
+ /** @var Location|null Information about the location of this DocBlock. */
+ private $location;
+
+ /** @var bool Is this DocBlock (the start of) a template? */
+ private $isTemplateStart;
+
+ /** @var bool Does this DocBlock signify the end of a DocBlock template? */
+ private $isTemplateEnd;
+
+ /**
+ * @param DocBlock\Tag[] $tags
+ * @param Types\Context $context The context in which the DocBlock occurs.
+ * @param Location $location The location within the file that this DocBlock occurs in.
+ */
+ public function __construct(
+ string $summary = '',
+ ?DocBlock\Description $description = null,
+ array $tags = [],
+ ?Types\Context $context = null,
+ ?Location $location = null,
+ bool $isTemplateStart = false,
+ bool $isTemplateEnd = false
+ ) {
+ Assert::allIsInstanceOf($tags, Tag::class);
+
+ $this->summary = $summary;
+ $this->description = $description ?: new DocBlock\Description('');
+ foreach ($tags as $tag) {
+ $this->addTag($tag);
+ }
+
+ $this->context = $context;
+ $this->location = $location;
+
+ $this->isTemplateEnd = $isTemplateEnd;
+ $this->isTemplateStart = $isTemplateStart;
+ }
+
+ public function getSummary(): string
+ {
+ return $this->summary;
+ }
+
+ public function getDescription(): DocBlock\Description
+ {
+ return $this->description;
+ }
+
+ /**
+ * Returns the current context.
+ */
+ public function getContext(): ?Types\Context
+ {
+ return $this->context;
+ }
+
+ /**
+ * Returns the current location.
+ */
+ public function getLocation(): ?Location
+ {
+ return $this->location;
+ }
+
+ /**
+ * Returns whether this DocBlock is the start of a Template section.
+ *
+ * A Docblock may serve as template for a series of subsequent DocBlocks. This is indicated by a special marker
+ * (`#@+`) that is appended directly after the opening `/**` of a DocBlock.
+ *
+ * An example of such an opening is:
+ *
+ * ```
+ * /**#@+
+ * * My DocBlock
+ * * /
+ * ```
+ *
+ * The description and tags (not the summary!) are copied onto all subsequent DocBlocks and also applied to all
+ * elements that follow until another DocBlock is found that contains the closing marker (`#@-`).
+ *
+ * @see self::isTemplateEnd() for the check whether a closing marker was provided.
+ */
+ public function isTemplateStart(): bool
+ {
+ return $this->isTemplateStart;
+ }
+
+ /**
+ * Returns whether this DocBlock is the end of a Template section.
+ *
+ * @see self::isTemplateStart() for a more complete description of the Docblock Template functionality.
+ */
+ public function isTemplateEnd(): bool
+ {
+ return $this->isTemplateEnd;
+ }
+
+ /**
+ * Returns the tags for this DocBlock.
+ *
+ * @return Tag[]
+ */
+ public function getTags(): array
+ {
+ return $this->tags;
+ }
+
+ /**
+ * Returns an array of tags matching the given name. If no tags are found
+ * an empty array is returned.
+ *
+ * @param string $name String to search by.
+ *
+ * @return Tag[]
+ */
+ public function getTagsByName(string $name): array
+ {
+ $result = [];
+
+ foreach ($this->getTags() as $tag) {
+ if ($tag->getName() !== $name) {
+ continue;
+ }
+
+ $result[] = $tag;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns an array of tags with type matching the given name. If no tags are found
+ * an empty array is returned.
+ *
+ * @param string $name String to search by.
+ *
+ * @return TagWithType[]
+ */
+ public function getTagsWithTypeByName(string $name): array
+ {
+ $result = [];
+
+ foreach ($this->getTagsByName($name) as $tag) {
+ if (!$tag instanceof TagWithType) {
+ continue;
+ }
+
+ $result[] = $tag;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Checks if a tag of a certain type is present in this DocBlock.
+ *
+ * @param string $name Tag name to check for.
+ */
+ public function hasTag(string $name): bool
+ {
+ foreach ($this->getTags() as $tag) {
+ if ($tag->getName() === $name) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove a tag from this DocBlock.
+ *
+ * @param Tag $tagToRemove The tag to remove.
+ */
+ public function removeTag(Tag $tagToRemove): void
+ {
+ foreach ($this->tags as $key => $tag) {
+ if ($tag === $tagToRemove) {
+ unset($this->tags[$key]);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Adds a tag to this DocBlock.
+ *
+ * @param Tag $tag The tag to add.
+ */
+ private function addTag(Tag $tag): void
+ {
+ $this->tags[] = $tag;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Description.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Description.php
new file mode 100644
index 000000000..a31b2892a
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Description.php
@@ -0,0 +1,115 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock;
+
+use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
+use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter;
+
+use function vsprintf;
+
+/**
+ * Object representing to description for a DocBlock.
+ *
+ * A Description object can consist of plain text but can also include tags. A Description Formatter can then combine
+ * a body template with sprintf-style placeholders together with formatted tags in order to reconstitute a complete
+ * description text using the format that you would prefer.
+ *
+ * Because parsing a Description text can be a verbose process this is handled by the {@see DescriptionFactory}. It is
+ * thus recommended to use that to create a Description object, like this:
+ *
+ * $description = $descriptionFactory->create('This is a {@see Description}', $context);
+ *
+ * The description factory will interpret the given body and create a body template and list of tags from them, and pass
+ * that onto the constructor if this class.
+ *
+ * > The $context variable is a class of type {@see \phpDocumentor\Reflection\Types\Context} and contains the namespace
+ * > and the namespace aliases that apply to this DocBlock. These are used by the Factory to resolve and expand partial
+ * > type names and FQSENs.
+ *
+ * If you do not want to use the DescriptionFactory you can pass a body template and tag listing like this:
+ *
+ * $description = new Description(
+ * 'This is a %1$s',
+ * [ new See(new Fqsen('\phpDocumentor\Reflection\DocBlock\Description')) ]
+ * );
+ *
+ * It is generally recommended to use the Factory as that will also apply escaping rules, while the Description object
+ * is mainly responsible for rendering.
+ *
+ * @see DescriptionFactory to create a new Description.
+ * @see Description\Formatter for the formatting of the body and tags.
+ */
+class Description
+{
+ /** @var string */
+ private $bodyTemplate;
+
+ /** @var Tag[] */
+ private $tags;
+
+ /**
+ * Initializes a Description with its body (template) and a listing of the tags used in the body template.
+ *
+ * @param Tag[] $tags
+ */
+ public function __construct(string $bodyTemplate, array $tags = [])
+ {
+ $this->bodyTemplate = $bodyTemplate;
+ $this->tags = $tags;
+ }
+
+ /**
+ * Returns the body template.
+ */
+ public function getBodyTemplate(): string
+ {
+ return $this->bodyTemplate;
+ }
+
+ /**
+ * Returns the tags for this DocBlock.
+ *
+ * @return Tag[]
+ */
+ public function getTags(): array
+ {
+ return $this->tags;
+ }
+
+ /**
+ * Renders this description as a string where the provided formatter will format the tags in the expected string
+ * format.
+ */
+ public function render(?Formatter $formatter = null): string
+ {
+ if ($formatter === null) {
+ $formatter = new PassthroughFormatter();
+ }
+
+ $tags = [];
+ foreach ($this->tags as $tag) {
+ $tags[] = '{' . $formatter->format($tag) . '}';
+ }
+
+ return vsprintf($this->bodyTemplate, $tags);
+ }
+
+ /**
+ * Returns a plain string representation of this description.
+ */
+ public function __toString(): string
+ {
+ return $this->render();
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php
new file mode 100644
index 000000000..1a519ec4a
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/DescriptionFactory.php
@@ -0,0 +1,178 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock;
+
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+
+use function count;
+use function implode;
+use function ltrim;
+use function min;
+use function str_replace;
+use function strlen;
+use function strpos;
+use function substr;
+use function trim;
+
+use const PREG_SPLIT_DELIM_CAPTURE;
+
+/**
+ * Creates a new Description object given a body of text.
+ *
+ * Descriptions in phpDocumentor are somewhat complex entities as they can contain one or more tags inside their
+ * body that can be replaced with a readable output. The replacing is done by passing a Formatter object to the
+ * Description object's `render` method.
+ *
+ * In addition to the above does a Description support two types of escape sequences:
+ *
+ * 1. `{@}` to escape the `@` character to prevent it from being interpreted as part of a tag, i.e. `{{@}link}`
+ * 2. `{}` to escape the `}` character, this can be used if you want to use the `}` character in the description
+ * of an inline tag.
+ *
+ * If a body consists of multiple lines then this factory will also remove any superfluous whitespace at the beginning
+ * of each line while maintaining any indentation that is used. This will prevent formatting parsers from tripping
+ * over unexpected spaces as can be observed with tag descriptions.
+ */
+class DescriptionFactory
+{
+ /** @var TagFactory */
+ private $tagFactory;
+
+ /**
+ * Initializes this factory with the means to construct (inline) tags.
+ */
+ public function __construct(TagFactory $tagFactory)
+ {
+ $this->tagFactory = $tagFactory;
+ }
+
+ /**
+ * Returns the parsed text of this description.
+ */
+ public function create(string $contents, ?TypeContext $context = null): Description
+ {
+ $tokens = $this->lex($contents);
+ $count = count($tokens);
+ $tagCount = 0;
+ $tags = [];
+
+ for ($i = 1; $i < $count; $i += 2) {
+ $tags[] = $this->tagFactory->create($tokens[$i], $context);
+ $tokens[$i] = '%' . ++$tagCount . '$s';
+ }
+
+ //In order to allow "literal" inline tags, the otherwise invalid
+ //sequence "{@}" is changed to "@", and "{}" is changed to "}".
+ //"%" is escaped to "%%" because of vsprintf.
+ //See unit tests for examples.
+ for ($i = 0; $i < $count; $i += 2) {
+ $tokens[$i] = str_replace(['{@}', '{}', '%'], ['@', '}', '%%'], $tokens[$i]);
+ }
+
+ return new Description(implode('', $tokens), $tags);
+ }
+
+ /**
+ * Strips the contents from superfluous whitespace and splits the description into a series of tokens.
+ *
+ * @return string[] A series of tokens of which the description text is composed.
+ */
+ private function lex(string $contents): array
+ {
+ $contents = $this->removeSuperfluousStartingWhitespace($contents);
+
+ // performance optimalization; if there is no inline tag, don't bother splitting it up.
+ if (strpos($contents, '{@') === false) {
+ return [$contents];
+ }
+
+ return Utils::pregSplit(
+ '/\{
+ # "{@}" is not a valid inline tag. This ensures that we do not treat it as one, but treat it literally.
+ (?!@\})
+ # We want to capture the whole tag line, but without the inline tag delimiters.
+ (\@
+ # Match everything up to the next delimiter.
+ [^{}]*
+ # Nested inline tag content should not be captured, or it will appear in the result separately.
+ (?:
+ # Match nested inline tags.
+ (?:
+ # Because we did not catch the tag delimiters earlier, we must be explicit with them here.
+ # Notice that this also matches "{}", as a way to later introduce it as an escape sequence.
+ \{(?1)?\}
+ |
+ # Make sure we match hanging "{".
+ \{
+ )
+ # Match content after the nested inline tag.
+ [^{}]*
+ )* # If there are more inline tags, match them as well. We use "*" since there may not be any
+ # nested inline tags.
+ )
+ \}/Sux',
+ $contents,
+ 0,
+ PREG_SPLIT_DELIM_CAPTURE
+ );
+ }
+
+ /**
+ * Removes the superfluous from a multi-line description.
+ *
+ * When a description has more than one line then it can happen that the second and subsequent lines have an
+ * additional indentation. This is commonly in use with tags like this:
+ *
+ * {@}since 1.1.0 This is an example
+ * description where we have an
+ * indentation in the second and
+ * subsequent lines.
+ *
+ * If we do not normalize the indentation then we have superfluous whitespace on the second and subsequent
+ * lines and this may cause rendering issues when, for example, using a Markdown converter.
+ */
+ private function removeSuperfluousStartingWhitespace(string $contents): string
+ {
+ $lines = Utils::pregSplit("/\r\n?|\n/", $contents);
+
+ // if there is only one line then we don't have lines with superfluous whitespace and
+ // can use the contents as-is
+ if (count($lines) <= 1) {
+ return $contents;
+ }
+
+ // determine how many whitespace characters need to be stripped
+ $startingSpaceCount = 9999999;
+ for ($i = 1, $iMax = count($lines); $i < $iMax; ++$i) {
+ // lines with a no length do not count as they are not indented at all
+ if (trim($lines[$i]) === '') {
+ continue;
+ }
+
+ // determine the number of prefixing spaces by checking the difference in line length before and after
+ // an ltrim
+ $startingSpaceCount = min($startingSpaceCount, strlen($lines[$i]) - strlen(ltrim($lines[$i])));
+ }
+
+ // strip the number of spaces from each line
+ if ($startingSpaceCount > 0) {
+ for ($i = 1, $iMax = count($lines); $i < $iMax; ++$i) {
+ $lines[$i] = substr($lines[$i], $startingSpaceCount);
+ }
+ }
+
+ return implode("\n", $lines);
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php
new file mode 100644
index 000000000..6a6b47295
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/ExampleFinder.php
@@ -0,0 +1,159 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock;
+
+use phpDocumentor\Reflection\DocBlock\Tags\Example;
+
+use function array_slice;
+use function file;
+use function getcwd;
+use function implode;
+use function is_readable;
+use function rtrim;
+use function sprintf;
+use function trim;
+
+use const DIRECTORY_SEPARATOR;
+
+/**
+ * Class used to find an example file's location based on a given ExampleDescriptor.
+ */
+class ExampleFinder
+{
+ /** @var string */
+ private $sourceDirectory = '';
+
+ /** @var string[] */
+ private $exampleDirectories = [];
+
+ /**
+ * Attempts to find the example contents for the given descriptor.
+ */
+ public function find(Example $example): string
+ {
+ $filename = $example->getFilePath();
+
+ $file = $this->getExampleFileContents($filename);
+ if (!$file) {
+ return sprintf('** File not found : %s **', $filename);
+ }
+
+ return implode('', array_slice($file, $example->getStartingLine() - 1, $example->getLineCount()));
+ }
+
+ /**
+ * Registers the project's root directory where an 'examples' folder can be expected.
+ */
+ public function setSourceDirectory(string $directory = ''): void
+ {
+ $this->sourceDirectory = $directory;
+ }
+
+ /**
+ * Returns the project's root directory where an 'examples' folder can be expected.
+ */
+ public function getSourceDirectory(): string
+ {
+ return $this->sourceDirectory;
+ }
+
+ /**
+ * Registers a series of directories that may contain examples.
+ *
+ * @param string[] $directories
+ */
+ public function setExampleDirectories(array $directories): void
+ {
+ $this->exampleDirectories = $directories;
+ }
+
+ /**
+ * Returns a series of directories that may contain examples.
+ *
+ * @return string[]
+ */
+ public function getExampleDirectories(): array
+ {
+ return $this->exampleDirectories;
+ }
+
+ /**
+ * Attempts to find the requested example file and returns its contents or null if no file was found.
+ *
+ * This method will try several methods in search of the given example file, the first one it encounters is
+ * returned:
+ *
+ * 1. Iterates through all examples folders for the given filename
+ * 2. Checks the source folder for the given filename
+ * 3. Checks the 'examples' folder in the current working directory for examples
+ * 4. Checks the path relative to the current working directory for the given filename
+ *
+ * @return string[] all lines of the example file
+ */
+ private function getExampleFileContents(string $filename): ?array
+ {
+ $normalizedPath = null;
+
+ foreach ($this->exampleDirectories as $directory) {
+ $exampleFileFromConfig = $this->constructExamplePath($directory, $filename);
+ if (is_readable($exampleFileFromConfig)) {
+ $normalizedPath = $exampleFileFromConfig;
+ break;
+ }
+ }
+
+ if (!$normalizedPath) {
+ if (is_readable($this->getExamplePathFromSource($filename))) {
+ $normalizedPath = $this->getExamplePathFromSource($filename);
+ } elseif (is_readable($this->getExamplePathFromExampleDirectory($filename))) {
+ $normalizedPath = $this->getExamplePathFromExampleDirectory($filename);
+ } elseif (is_readable($filename)) {
+ $normalizedPath = $filename;
+ }
+ }
+
+ $lines = $normalizedPath && is_readable($normalizedPath) ? file($normalizedPath) : false;
+
+ return $lines !== false ? $lines : null;
+ }
+
+ /**
+ * Get example filepath based on the example directory inside your project.
+ */
+ private function getExamplePathFromExampleDirectory(string $file): string
+ {
+ return getcwd() . DIRECTORY_SEPARATOR . 'examples' . DIRECTORY_SEPARATOR . $file;
+ }
+
+ /**
+ * Returns a path to the example file in the given directory..
+ */
+ private function constructExamplePath(string $directory, string $file): string
+ {
+ return rtrim($directory, '\\/') . DIRECTORY_SEPARATOR . $file;
+ }
+
+ /**
+ * Get example filepath based on sourcecode.
+ */
+ private function getExamplePathFromSource(string $file): string
+ {
+ return sprintf(
+ '%s%s%s',
+ trim($this->getSourceDirectory(), '\\/'),
+ DIRECTORY_SEPARATOR,
+ trim($file, '"')
+ );
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php
new file mode 100644
index 000000000..77e5fb5fa
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Serializer.php
@@ -0,0 +1,157 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock;
+
+use phpDocumentor\Reflection\DocBlock;
+use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
+use phpDocumentor\Reflection\DocBlock\Tags\Formatter\PassthroughFormatter;
+
+use function sprintf;
+use function str_repeat;
+use function str_replace;
+use function strlen;
+use function wordwrap;
+
+/**
+ * Converts a DocBlock back from an object to a complete DocComment including Asterisks.
+ */
+class Serializer
+{
+ /** @var string The string to indent the comment with. */
+ protected $indentString = ' ';
+
+ /** @var int The number of times the indent string is repeated. */
+ protected $indent = 0;
+
+ /** @var bool Whether to indent the first line with the given indent amount and string. */
+ protected $isFirstLineIndented = true;
+
+ /** @var int|null The max length of a line. */
+ protected $lineLength;
+
+ /** @var Formatter A custom tag formatter. */
+ protected $tagFormatter;
+ /** @var string */
+ private $lineEnding;
+
+ /**
+ * Create a Serializer instance.
+ *
+ * @param int $indent The number of times the indent string is repeated.
+ * @param string $indentString The string to indent the comment with.
+ * @param bool $indentFirstLine Whether to indent the first line.
+ * @param int|null $lineLength The max length of a line or NULL to disable line wrapping.
+ * @param Formatter $tagFormatter A custom tag formatter, defaults to PassthroughFormatter.
+ * @param string $lineEnding Line ending used in the output, by default \n is used.
+ */
+ public function __construct(
+ int $indent = 0,
+ string $indentString = ' ',
+ bool $indentFirstLine = true,
+ ?int $lineLength = null,
+ ?Formatter $tagFormatter = null,
+ string $lineEnding = "\n"
+ ) {
+ $this->indent = $indent;
+ $this->indentString = $indentString;
+ $this->isFirstLineIndented = $indentFirstLine;
+ $this->lineLength = $lineLength;
+ $this->tagFormatter = $tagFormatter ?: new PassthroughFormatter();
+ $this->lineEnding = $lineEnding;
+ }
+
+ /**
+ * Generate a DocBlock comment.
+ *
+ * @param DocBlock $docblock The DocBlock to serialize.
+ *
+ * @return string The serialized doc block.
+ */
+ public function getDocComment(DocBlock $docblock): string
+ {
+ $indent = str_repeat($this->indentString, $this->indent);
+ $firstIndent = $this->isFirstLineIndented ? $indent : '';
+ // 3 === strlen(' * ')
+ $wrapLength = $this->lineLength ? $this->lineLength - strlen($indent) - 3 : null;
+
+ $text = $this->removeTrailingSpaces(
+ $indent,
+ $this->addAsterisksForEachLine(
+ $indent,
+ $this->getSummaryAndDescriptionTextBlock($docblock, $wrapLength)
+ )
+ );
+
+ $comment = $firstIndent . "/**\n";
+ if ($text) {
+ $comment .= $indent . ' * ' . $text . "\n";
+ $comment .= $indent . " *\n";
+ }
+
+ $comment = $this->addTagBlock($docblock, $wrapLength, $indent, $comment);
+
+ return str_replace("\n", $this->lineEnding, $comment . $indent . ' */');
+ }
+
+ private function removeTrailingSpaces(string $indent, string $text): string
+ {
+ return str_replace(
+ sprintf("\n%s * \n", $indent),
+ sprintf("\n%s *\n", $indent),
+ $text
+ );
+ }
+
+ private function addAsterisksForEachLine(string $indent, string $text): string
+ {
+ return str_replace(
+ "\n",
+ sprintf("\n%s * ", $indent),
+ $text
+ );
+ }
+
+ private function getSummaryAndDescriptionTextBlock(DocBlock $docblock, ?int $wrapLength): string
+ {
+ $text = $docblock->getSummary() . ((string) $docblock->getDescription() ? "\n\n" . $docblock->getDescription()
+ : '');
+ if ($wrapLength !== null) {
+ $text = wordwrap($text, $wrapLength);
+
+ return $text;
+ }
+
+ return $text;
+ }
+
+ private function addTagBlock(DocBlock $docblock, ?int $wrapLength, string $indent, string $comment): string
+ {
+ foreach ($docblock->getTags() as $tag) {
+ $tagText = $this->tagFormatter->format($tag);
+ if ($wrapLength !== null) {
+ $tagText = wordwrap($tagText, $wrapLength);
+ }
+
+ $tagText = str_replace(
+ "\n",
+ sprintf("\n%s * ", $indent),
+ $tagText
+ );
+
+ $comment .= sprintf("%s * %s\n", $indent, $tagText);
+ }
+
+ return $comment;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php
new file mode 100644
index 000000000..8d7659510
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/StandardTagFactory.php
@@ -0,0 +1,348 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock;
+
+use InvalidArgumentException;
+use phpDocumentor\Reflection\DocBlock\Tags\Author;
+use phpDocumentor\Reflection\DocBlock\Tags\Covers;
+use phpDocumentor\Reflection\DocBlock\Tags\Deprecated;
+use phpDocumentor\Reflection\DocBlock\Tags\Generic;
+use phpDocumentor\Reflection\DocBlock\Tags\InvalidTag;
+use phpDocumentor\Reflection\DocBlock\Tags\Link as LinkTag;
+use phpDocumentor\Reflection\DocBlock\Tags\Method;
+use phpDocumentor\Reflection\DocBlock\Tags\Param;
+use phpDocumentor\Reflection\DocBlock\Tags\Property;
+use phpDocumentor\Reflection\DocBlock\Tags\PropertyRead;
+use phpDocumentor\Reflection\DocBlock\Tags\PropertyWrite;
+use phpDocumentor\Reflection\DocBlock\Tags\Return_;
+use phpDocumentor\Reflection\DocBlock\Tags\See as SeeTag;
+use phpDocumentor\Reflection\DocBlock\Tags\Since;
+use phpDocumentor\Reflection\DocBlock\Tags\Source;
+use phpDocumentor\Reflection\DocBlock\Tags\Throws;
+use phpDocumentor\Reflection\DocBlock\Tags\Uses;
+use phpDocumentor\Reflection\DocBlock\Tags\Var_;
+use phpDocumentor\Reflection\DocBlock\Tags\Version;
+use phpDocumentor\Reflection\FqsenResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use ReflectionMethod;
+use ReflectionNamedType;
+use ReflectionParameter;
+use Webmozart\Assert\Assert;
+
+use function array_merge;
+use function array_slice;
+use function call_user_func_array;
+use function count;
+use function get_class;
+use function preg_match;
+use function strpos;
+use function trim;
+
+/**
+ * Creates a Tag object given the contents of a tag.
+ *
+ * This Factory is capable of determining the appropriate class for a tag and instantiate it using its `create`
+ * factory method. The `create` factory method of a Tag can have a variable number of arguments; this way you can
+ * pass the dependencies that you need to construct a tag object.
+ *
+ * > Important: each parameter in addition to the body variable for the `create` method must default to null, otherwise
+ * > it violates the constraint with the interface; it is recommended to use the {@see Assert::notNull()} method to
+ * > verify that a dependency is actually passed.
+ *
+ * This Factory also features a Service Locator component that is used to pass the right dependencies to the
+ * `create` method of a tag; each dependency should be registered as a service or as a parameter.
+ *
+ * When you want to use a Tag of your own with custom handling you need to call the `registerTagHandler` method, pass
+ * the name of the tag and a Fully Qualified Class Name pointing to a class that implements the Tag interface.
+ */
+final class StandardTagFactory implements TagFactory
+{
+ /** PCRE regular expression matching a tag name. */
+ public const REGEX_TAGNAME = '[\w\-\_\\\\:]+';
+
+ /**
+ * @var array<class-string<Tag>> An array with a tag as a key, and an
+ * FQCN to a class that handles it as an array value.
+ */
+ private $tagHandlerMappings = [
+ 'author' => Author::class,
+ 'covers' => Covers::class,
+ 'deprecated' => Deprecated::class,
+ // 'example' => '\phpDocumentor\Reflection\DocBlock\Tags\Example',
+ 'link' => LinkTag::class,
+ 'method' => Method::class,
+ 'param' => Param::class,
+ 'property-read' => PropertyRead::class,
+ 'property' => Property::class,
+ 'property-write' => PropertyWrite::class,
+ 'return' => Return_::class,
+ 'see' => SeeTag::class,
+ 'since' => Since::class,
+ 'source' => Source::class,
+ 'throw' => Throws::class,
+ 'throws' => Throws::class,
+ 'uses' => Uses::class,
+ 'var' => Var_::class,
+ 'version' => Version::class,
+ ];
+
+ /**
+ * @var array<class-string<Tag>> An array with a anotation s a key, and an
+ * FQCN to a class that handles it as an array value.
+ */
+ private $annotationMappings = [];
+
+ /**
+ * @var ReflectionParameter[][] a lazy-loading cache containing parameters
+ * for each tagHandler that has been used.
+ */
+ private $tagHandlerParameterCache = [];
+
+ /** @var FqsenResolver */
+ private $fqsenResolver;
+
+ /**
+ * @var mixed[] an array representing a simple Service Locator where we can store parameters and
+ * services that can be inserted into the Factory Methods of Tag Handlers.
+ */
+ private $serviceLocator = [];
+
+ /**
+ * Initialize this tag factory with the means to resolve an FQSEN and optionally a list of tag handlers.
+ *
+ * If no tag handlers are provided than the default list in the {@see self::$tagHandlerMappings} property
+ * is used.
+ *
+ * @see self::registerTagHandler() to add a new tag handler to the existing default list.
+ *
+ * @param array<class-string<Tag>> $tagHandlers
+ */
+ public function __construct(FqsenResolver $fqsenResolver, ?array $tagHandlers = null)
+ {
+ $this->fqsenResolver = $fqsenResolver;
+ if ($tagHandlers !== null) {
+ $this->tagHandlerMappings = $tagHandlers;
+ }
+
+ $this->addService($fqsenResolver, FqsenResolver::class);
+ }
+
+ public function create(string $tagLine, ?TypeContext $context = null): Tag
+ {
+ if (!$context) {
+ $context = new TypeContext('');
+ }
+
+ [$tagName, $tagBody] = $this->extractTagParts($tagLine);
+
+ return $this->createTag(trim($tagBody), $tagName, $context);
+ }
+
+ /**
+ * @param mixed $value
+ */
+ public function addParameter(string $name, $value): void
+ {
+ $this->serviceLocator[$name] = $value;
+ }
+
+ public function addService(object $service, ?string $alias = null): void
+ {
+ $this->serviceLocator[$alias ?: get_class($service)] = $service;
+ }
+
+ public function registerTagHandler(string $tagName, string $handler): void
+ {
+ Assert::stringNotEmpty($tagName);
+ Assert::classExists($handler);
+ Assert::implementsInterface($handler, Tag::class);
+
+ if (strpos($tagName, '\\') && $tagName[0] !== '\\') {
+ throw new InvalidArgumentException(
+ 'A namespaced tag must have a leading backslash as it must be fully qualified'
+ );
+ }
+
+ $this->tagHandlerMappings[$tagName] = $handler;
+ }
+
+ /**
+ * Extracts all components for a tag.
+ *
+ * @return string[]
+ */
+ private function extractTagParts(string $tagLine): array
+ {
+ $matches = [];
+ if (!preg_match('/^@(' . self::REGEX_TAGNAME . ')((?:[\s\(\{])\s*([^\s].*)|$)/us', $tagLine, $matches)) {
+ throw new InvalidArgumentException(
+ 'The tag "' . $tagLine . '" does not seem to be wellformed, please check it for errors'
+ );
+ }
+
+ if (count($matches) < 3) {
+ $matches[] = '';
+ }
+
+ return array_slice($matches, 1);
+ }
+
+ /**
+ * Creates a new tag object with the given name and body or returns null if the tag name was recognized but the
+ * body was invalid.
+ */
+ private function createTag(string $body, string $name, TypeContext $context): Tag
+ {
+ $handlerClassName = $this->findHandlerClassName($name, $context);
+ $arguments = $this->getArgumentsForParametersFromWiring(
+ $this->fetchParametersForHandlerFactoryMethod($handlerClassName),
+ $this->getServiceLocatorWithDynamicParameters($context, $name, $body)
+ );
+
+ try {
+ $callable = [$handlerClassName, 'create'];
+ Assert::isCallable($callable);
+ /** @phpstan-var callable(string): ?Tag $callable */
+ $tag = call_user_func_array($callable, $arguments);
+
+ return $tag ?? InvalidTag::create($body, $name);
+ } catch (InvalidArgumentException $e) {
+ return InvalidTag::create($body, $name)->withError($e);
+ }
+ }
+
+ /**
+ * Determines the Fully Qualified Class Name of the Factory or Tag (containing a Factory Method `create`).
+ *
+ * @return class-string<Tag>
+ */
+ private function findHandlerClassName(string $tagName, TypeContext $context): string
+ {
+ $handlerClassName = Generic::class;
+ if (isset($this->tagHandlerMappings[$tagName])) {
+ $handlerClassName = $this->tagHandlerMappings[$tagName];
+ } elseif ($this->isAnnotation($tagName)) {
+ // TODO: Annotation support is planned for a later stage and as such is disabled for now
+ $tagName = (string) $this->fqsenResolver->resolve($tagName, $context);
+ if (isset($this->annotationMappings[$tagName])) {
+ $handlerClassName = $this->annotationMappings[$tagName];
+ }
+ }
+
+ return $handlerClassName;
+ }
+
+ /**
+ * Retrieves the arguments that need to be passed to the Factory Method with the given Parameters.
+ *
+ * @param ReflectionParameter[] $parameters
+ * @param mixed[] $locator
+ *
+ * @return mixed[] A series of values that can be passed to the Factory Method of the tag whose parameters
+ * is provided with this method.
+ */
+ private function getArgumentsForParametersFromWiring(array $parameters, array $locator): array
+ {
+ $arguments = [];
+ foreach ($parameters as $parameter) {
+ $type = $parameter->getType();
+ $typeHint = null;
+ if ($type instanceof ReflectionNamedType) {
+ $typeHint = $type->getName();
+ if ($typeHint === 'self') {
+ $declaringClass = $parameter->getDeclaringClass();
+ if ($declaringClass !== null) {
+ $typeHint = $declaringClass->getName();
+ }
+ }
+ }
+
+ if (isset($locator[$typeHint])) {
+ $arguments[] = $locator[$typeHint];
+ continue;
+ }
+
+ $parameterName = $parameter->getName();
+ if (isset($locator[$parameterName])) {
+ $arguments[] = $locator[$parameterName];
+ continue;
+ }
+
+ $arguments[] = null;
+ }
+
+ return $arguments;
+ }
+
+ /**
+ * Retrieves a series of ReflectionParameter objects for the static 'create' method of the given
+ * tag handler class name.
+ *
+ * @param class-string $handlerClassName
+ *
+ * @return ReflectionParameter[]
+ */
+ private function fetchParametersForHandlerFactoryMethod(string $handlerClassName): array
+ {
+ if (!isset($this->tagHandlerParameterCache[$handlerClassName])) {
+ $methodReflection = new ReflectionMethod($handlerClassName, 'create');
+ $this->tagHandlerParameterCache[$handlerClassName] = $methodReflection->getParameters();
+ }
+
+ return $this->tagHandlerParameterCache[$handlerClassName];
+ }
+
+ /**
+ * Returns a copy of this class' Service Locator with added dynamic parameters,
+ * such as the tag's name, body and Context.
+ *
+ * @param TypeContext $context The Context (namespace and aliasses) that may be
+ * passed and is used to resolve FQSENs.
+ * @param string $tagName The name of the tag that may be
+ * passed onto the factory method of the Tag class.
+ * @param string $tagBody The body of the tag that may be
+ * passed onto the factory method of the Tag class.
+ *
+ * @return mixed[]
+ */
+ private function getServiceLocatorWithDynamicParameters(
+ TypeContext $context,
+ string $tagName,
+ string $tagBody
+ ): array {
+ return array_merge(
+ $this->serviceLocator,
+ [
+ 'name' => $tagName,
+ 'body' => $tagBody,
+ TypeContext::class => $context,
+ ]
+ );
+ }
+
+ /**
+ * Returns whether the given tag belongs to an annotation.
+ *
+ * @todo this method should be populated once we implement Annotation notation support.
+ */
+ private function isAnnotation(string $tagContent): bool
+ {
+ // 1. Contains a namespace separator
+ // 2. Contains parenthesis
+ // 3. Is present in a list of known annotations (make the algorithm smart by first checking is the last part
+ // of the annotation class name matches the found tag name
+
+ return false;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php
new file mode 100644
index 000000000..7cf07b4dd
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tag.php
@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock;
+
+use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
+
+interface Tag
+{
+ public function getName(): string;
+
+ /**
+ * @return Tag|mixed Class that implements Tag
+ * @phpstan-return ?Tag
+ */
+ public static function create(string $body);
+
+ public function render(?Formatter $formatter = null): string;
+
+ public function __toString(): string;
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php
new file mode 100644
index 000000000..c0868dcbe
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/TagFactory.php
@@ -0,0 +1,84 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock;
+
+use InvalidArgumentException;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+
+interface TagFactory
+{
+ /**
+ * Adds a parameter to the service locator that can be injected in a tag's factory method.
+ *
+ * When calling a tag's "create" method we always check the signature for dependencies to inject. One way is to
+ * typehint a parameter in the signature so that we can use that interface or class name to inject a dependency
+ * (see {@see addService()} for more information on that).
+ *
+ * Another way is to check the name of the argument against the names in the Service Locator. With this method
+ * you can add a variable that will be inserted when a tag's create method is not typehinted and has a matching
+ * name.
+ *
+ * Be aware that there are two reserved names:
+ *
+ * - name, representing the name of the tag.
+ * - body, representing the complete body of the tag.
+ *
+ * These parameters are injected at the last moment and will override any existing parameter with those names.
+ *
+ * @param mixed $value
+ */
+ public function addParameter(string $name, $value): void;
+
+ /**
+ * Factory method responsible for instantiating the correct sub type.
+ *
+ * @param string $tagLine The text for this tag, including description.
+ *
+ * @return Tag A new tag object.
+ *
+ * @throws InvalidArgumentException If an invalid tag line was presented.
+ */
+ public function create(string $tagLine, ?TypeContext $context = null): Tag;
+
+ /**
+ * Registers a service with the Service Locator using the FQCN of the class or the alias, if provided.
+ *
+ * When calling a tag's "create" method we always check the signature for dependencies to inject. If a parameter
+ * has a typehint then the ServiceLocator is queried to see if a Service is registered for that typehint.
+ *
+ * Because interfaces are regularly used as type-hints this method provides an alias parameter; if the FQCN of the
+ * interface is passed as alias then every time that interface is requested the provided service will be returned.
+ */
+ public function addService(object $service): void;
+
+ /**
+ * Registers a handler for tags.
+ *
+ * If you want to use your own tags then you can use this method to instruct the TagFactory
+ * to register the name of a tag with the FQCN of a 'Tag Handler'. The Tag handler should implement
+ * the {@see Tag} interface (and thus the create method).
+ *
+ * @param string $tagName Name of tag to register a handler for. When registering a namespaced
+ * tag, the full name, along with a prefixing slash MUST be provided.
+ * @param class-string<Tag> $handler FQCN of handler.
+ *
+ * @throws InvalidArgumentException If the tag name is not a string.
+ * @throws InvalidArgumentException If the tag name is namespaced (contains backslashes) but
+ * does not start with a backslash.
+ * @throws InvalidArgumentException If the handler is not a string.
+ * @throws InvalidArgumentException If the handler is not an existing class.
+ * @throws InvalidArgumentException If the handler does not implement the {@see Tag} interface.
+ */
+ public function registerTagHandler(string $tagName, string $handler): void;
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php
new file mode 100644
index 000000000..ae09ecf42
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Author.php
@@ -0,0 +1,102 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use InvalidArgumentException;
+
+use function filter_var;
+use function preg_match;
+use function trim;
+
+use const FILTER_VALIDATE_EMAIL;
+
+/**
+ * Reflection class for an {@}author tag in a Docblock.
+ */
+final class Author extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string register that this is the author tag. */
+ protected $name = 'author';
+
+ /** @var string The name of the author */
+ private $authorName;
+
+ /** @var string The email of the author */
+ private $authorEmail;
+
+ /**
+ * Initializes this tag with the author name and e-mail.
+ */
+ public function __construct(string $authorName, string $authorEmail)
+ {
+ if ($authorEmail && !filter_var($authorEmail, FILTER_VALIDATE_EMAIL)) {
+ throw new InvalidArgumentException('The author tag does not have a valid e-mail address');
+ }
+
+ $this->authorName = $authorName;
+ $this->authorEmail = $authorEmail;
+ }
+
+ /**
+ * Gets the author's name.
+ *
+ * @return string The author's name.
+ */
+ public function getAuthorName(): string
+ {
+ return $this->authorName;
+ }
+
+ /**
+ * Returns the author's email.
+ *
+ * @return string The author's email.
+ */
+ public function getEmail(): string
+ {
+ return $this->authorEmail;
+ }
+
+ /**
+ * Returns this tag in string form.
+ */
+ public function __toString(): string
+ {
+ if ($this->authorEmail) {
+ $authorEmail = '<' . $this->authorEmail . '>';
+ } else {
+ $authorEmail = '';
+ }
+
+ $authorName = $this->authorName;
+
+ return $authorName . ($authorEmail !== '' ? ($authorName !== '' ? ' ' : '') . $authorEmail : '');
+ }
+
+ /**
+ * Attempts to create a new Author object based on the tag body.
+ */
+ public static function create(string $body): ?self
+ {
+ $splitTagContent = preg_match('/^([^\<]*)(?:\<([^\>]*)\>)?$/u', $body, $matches);
+ if (!$splitTagContent) {
+ return null;
+ }
+
+ $authorName = trim($matches[1]);
+ $email = isset($matches[2]) ? trim($matches[2]) : '';
+
+ return new static($authorName, $email);
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php
new file mode 100644
index 000000000..a28d5bf98
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/BaseTag.php
@@ -0,0 +1,53 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock;
+use phpDocumentor\Reflection\DocBlock\Description;
+
+/**
+ * Parses a tag definition for a DocBlock.
+ */
+abstract class BaseTag implements DocBlock\Tag
+{
+ /** @var string Name of the tag */
+ protected $name = '';
+
+ /** @var Description|null Description of the tag. */
+ protected $description;
+
+ /**
+ * Gets the name of this tag.
+ *
+ * @return string The name of this tag.
+ */
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function getDescription(): ?Description
+ {
+ return $this->description;
+ }
+
+ public function render(?Formatter $formatter = null): string
+ {
+ if ($formatter === null) {
+ $formatter = new Formatter\PassthroughFormatter();
+ }
+
+ return $formatter->format($this);
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php
new file mode 100644
index 000000000..3eff9d8bc
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Covers.php
@@ -0,0 +1,101 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Fqsen;
+use phpDocumentor\Reflection\FqsenResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+use function array_key_exists;
+use function explode;
+
+/**
+ * Reflection class for a @covers tag in a Docblock.
+ */
+final class Covers extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'covers';
+
+ /** @var Fqsen */
+ private $refers;
+
+ /**
+ * Initializes this tag.
+ */
+ public function __construct(Fqsen $refers, ?Description $description = null)
+ {
+ $this->refers = $refers;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?FqsenResolver $resolver = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::stringNotEmpty($body);
+ Assert::notNull($descriptionFactory);
+ Assert::notNull($resolver);
+
+ $parts = Utils::pregSplit('/\s+/Su', $body, 2);
+
+ return new static(
+ self::resolveFqsen($parts[0], $resolver, $context),
+ $descriptionFactory->create($parts[1] ?? '', $context)
+ );
+ }
+
+ private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
+ {
+ Assert::notNull($fqsenResolver);
+ $fqsenParts = explode('::', $parts);
+ $resolved = $fqsenResolver->resolve($fqsenParts[0], $context);
+
+ if (!array_key_exists(1, $fqsenParts)) {
+ return $resolved;
+ }
+
+ return new Fqsen($resolved . '::' . $fqsenParts[1]);
+ }
+
+ /**
+ * Returns the structural element this tag refers to.
+ */
+ public function getReference(): Fqsen
+ {
+ return $this->refers;
+ }
+
+ /**
+ * Returns a string representation of this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $refers = (string) $this->refers;
+
+ return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php
new file mode 100644
index 000000000..dbcad28c0
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Deprecated.php
@@ -0,0 +1,109 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use Webmozart\Assert\Assert;
+
+use function preg_match;
+
+/**
+ * Reflection class for a {@}deprecated tag in a Docblock.
+ */
+final class Deprecated extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'deprecated';
+
+ /**
+ * PCRE regular expression matching a version vector.
+ * Assumes the "x" modifier.
+ */
+ public const REGEX_VECTOR = '(?:
+ # Normal release vectors.
+ \d\S*
+ |
+ # VCS version vectors. Per PHPCS, they are expected to
+ # follow the form of the VCS name, followed by ":", followed
+ # by the version vector itself.
+ # By convention, popular VCSes like CVS, SVN and GIT use "$"
+ # around the actual version vector.
+ [^\s\:]+\:\s*\$[^\$]+\$
+ )';
+
+ /** @var string|null The version vector. */
+ private $version;
+
+ public function __construct(?string $version = null, ?Description $description = null)
+ {
+ Assert::nullOrNotEmpty($version);
+
+ $this->version = $version;
+ $this->description = $description;
+ }
+
+ /**
+ * @return static
+ */
+ public static function create(
+ ?string $body,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ if (empty($body)) {
+ return new static();
+ }
+
+ $matches = [];
+ if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
+ return new static(
+ null,
+ $descriptionFactory !== null ? $descriptionFactory->create($body, $context) : null
+ );
+ }
+
+ Assert::notNull($descriptionFactory);
+
+ return new static(
+ $matches[1],
+ $descriptionFactory->create($matches[2] ?? '', $context)
+ );
+ }
+
+ /**
+ * Gets the version section of the tag.
+ */
+ public function getVersion(): ?string
+ {
+ return $this->version;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $version = (string) $this->version;
+
+ return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php
new file mode 100644
index 000000000..825355aaf
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Example.php
@@ -0,0 +1,200 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Tag;
+use Webmozart\Assert\Assert;
+
+use function array_key_exists;
+use function preg_match;
+use function rawurlencode;
+use function str_replace;
+use function strpos;
+use function trim;
+
+/**
+ * Reflection class for a {@}example tag in a Docblock.
+ */
+final class Example implements Tag, Factory\StaticMethod
+{
+ /** @var string Path to a file to use as an example. May also be an absolute URI. */
+ private $filePath;
+
+ /**
+ * @var bool Whether the file path component represents an URI. This determines how the file portion
+ * appears at {@link getContent()}.
+ */
+ private $isURI;
+
+ /** @var int */
+ private $startingLine;
+
+ /** @var int */
+ private $lineCount;
+
+ /** @var string|null */
+ private $content;
+
+ public function __construct(
+ string $filePath,
+ bool $isURI,
+ int $startingLine,
+ int $lineCount,
+ ?string $content
+ ) {
+ Assert::stringNotEmpty($filePath);
+ Assert::greaterThanEq($startingLine, 1);
+ Assert::greaterThanEq($lineCount, 0);
+
+ $this->filePath = $filePath;
+ $this->startingLine = $startingLine;
+ $this->lineCount = $lineCount;
+ if ($content !== null) {
+ $this->content = trim($content);
+ }
+
+ $this->isURI = $isURI;
+ }
+
+ public function getContent(): string
+ {
+ if ($this->content === null || $this->content === '') {
+ $filePath = $this->filePath;
+ if ($this->isURI) {
+ $filePath = $this->isUriRelative($this->filePath)
+ ? str_replace('%2F', '/', rawurlencode($this->filePath))
+ : $this->filePath;
+ }
+
+ return trim($filePath);
+ }
+
+ return $this->content;
+ }
+
+ public function getDescription(): ?string
+ {
+ return $this->content;
+ }
+
+ public static function create(string $body): ?Tag
+ {
+ // File component: File path in quotes or File URI / Source information
+ if (!preg_match('/^\s*(?:(\"[^\"]+\")|(\S+))(?:\s+(.*))?$/sux', $body, $matches)) {
+ return null;
+ }
+
+ $filePath = null;
+ $fileUri = null;
+ if ($matches[1] !== '') {
+ $filePath = $matches[1];
+ } else {
+ $fileUri = $matches[2];
+ }
+
+ $startingLine = 1;
+ $lineCount = 0;
+ $description = null;
+
+ if (array_key_exists(3, $matches)) {
+ $description = $matches[3];
+
+ // Starting line / Number of lines / Description
+ if (preg_match('/^([1-9]\d*)(?:\s+((?1))\s*)?(.*)$/sux', $matches[3], $contentMatches)) {
+ $startingLine = (int) $contentMatches[1];
+ if (isset($contentMatches[2])) {
+ $lineCount = (int) $contentMatches[2];
+ }
+
+ if (array_key_exists(3, $contentMatches)) {
+ $description = $contentMatches[3];
+ }
+ }
+ }
+
+ return new static(
+ $filePath ?? ($fileUri ?? ''),
+ $fileUri !== null,
+ $startingLine,
+ $lineCount,
+ $description
+ );
+ }
+
+ /**
+ * Returns the file path.
+ *
+ * @return string Path to a file to use as an example.
+ * May also be an absolute URI.
+ */
+ public function getFilePath(): string
+ {
+ return trim($this->filePath, '"');
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ $filePath = $this->filePath;
+ $isDefaultLine = $this->startingLine === 1 && $this->lineCount === 0;
+ $startingLine = !$isDefaultLine ? (string) $this->startingLine : '';
+ $lineCount = !$isDefaultLine ? (string) $this->lineCount : '';
+ $content = (string) $this->content;
+
+ return $filePath
+ . ($startingLine !== ''
+ ? ($filePath !== '' ? ' ' : '') . $startingLine
+ : '')
+ . ($lineCount !== ''
+ ? ($filePath !== '' || $startingLine !== '' ? ' ' : '') . $lineCount
+ : '')
+ . ($content !== ''
+ ? ($filePath !== '' || $startingLine !== '' || $lineCount !== '' ? ' ' : '') . $content
+ : '');
+ }
+
+ /**
+ * Returns true if the provided URI is relative or contains a complete scheme (and thus is absolute).
+ */
+ private function isUriRelative(string $uri): bool
+ {
+ return strpos($uri, ':') === false;
+ }
+
+ public function getStartingLine(): int
+ {
+ return $this->startingLine;
+ }
+
+ public function getLineCount(): int
+ {
+ return $this->lineCount;
+ }
+
+ public function getName(): string
+ {
+ return 'example';
+ }
+
+ public function render(?Formatter $formatter = null): string
+ {
+ if ($formatter === null) {
+ $formatter = new Formatter\PassthroughFormatter();
+ }
+
+ return $formatter->format($this);
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php
new file mode 100644
index 000000000..f6f0bb5a4
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/StaticMethod.php
@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags\Factory;
+
+/**
+ * @deprecated This contract is totally covered by Tag contract. Every class using StaticMethod also use Tag
+ */
+interface StaticMethod
+{
+ /**
+ * @return mixed
+ */
+ public static function create(string $body);
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php
new file mode 100644
index 000000000..36b9983ea
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Tag;
+
+interface Formatter
+{
+ /**
+ * Formats a tag into a string representation according to a specific format, such as Markdown.
+ */
+ public function format(Tag $tag): string;
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php
new file mode 100644
index 000000000..946443438
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/AlignFormatter.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags\Formatter;
+
+use phpDocumentor\Reflection\DocBlock\Tag;
+use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
+
+use function max;
+use function str_repeat;
+use function strlen;
+
+class AlignFormatter implements Formatter
+{
+ /** @var int The maximum tag name length. */
+ protected $maxLen = 0;
+
+ /**
+ * @param Tag[] $tags All tags that should later be aligned with the formatter.
+ */
+ public function __construct(array $tags)
+ {
+ foreach ($tags as $tag) {
+ $this->maxLen = max($this->maxLen, strlen($tag->getName()));
+ }
+ }
+
+ /**
+ * Formats the given tag to return a simple plain text version.
+ */
+ public function format(Tag $tag): string
+ {
+ return '@' . $tag->getName() .
+ str_repeat(
+ ' ',
+ $this->maxLen - strlen($tag->getName()) + 1
+ ) .
+ $tag;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php
new file mode 100644
index 000000000..2afdfe55d
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Formatter/PassthroughFormatter.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags\Formatter;
+
+use phpDocumentor\Reflection\DocBlock\Tag;
+use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
+
+use function trim;
+
+class PassthroughFormatter implements Formatter
+{
+ /**
+ * Formats the given tag to return a simple plain text version.
+ */
+ public function format(Tag $tag): string
+ {
+ return trim('@' . $tag->getName() . ' ' . $tag);
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php
new file mode 100644
index 000000000..bc1ab10c1
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Generic.php
@@ -0,0 +1,89 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use InvalidArgumentException;
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use Webmozart\Assert\Assert;
+
+use function preg_match;
+
+/**
+ * Parses a tag definition for a DocBlock.
+ */
+final class Generic extends BaseTag implements Factory\StaticMethod
+{
+ /**
+ * Parses a tag and populates the member variables.
+ *
+ * @param string $name Name of the tag.
+ * @param Description $description The contents of the given tag.
+ */
+ public function __construct(string $name, ?Description $description = null)
+ {
+ $this->validateTagName($name);
+
+ $this->name = $name;
+ $this->description = $description;
+ }
+
+ /**
+ * Creates a new tag that represents any unknown tag type.
+ *
+ * @return static
+ */
+ public static function create(
+ string $body,
+ string $name = '',
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::stringNotEmpty($name);
+ Assert::notNull($descriptionFactory);
+
+ $description = $body !== '' ? $descriptionFactory->create($body, $context) : null;
+
+ return new static($name, $description);
+ }
+
+ /**
+ * Returns the tag as a serialized string
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ return $description;
+ }
+
+ /**
+ * Validates if the tag name matches the expected format, otherwise throws an exception.
+ */
+ private function validateTagName(string $name): void
+ {
+ if (!preg_match('/^' . StandardTagFactory::REGEX_TAGNAME . '$/u', $name)) {
+ throw new InvalidArgumentException(
+ 'The tag name "' . $name . '" is not wellformed. Tags may only consist of letters, underscores, '
+ . 'hyphens and backslashes.'
+ );
+ }
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php
new file mode 100644
index 000000000..4e6abb8c4
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/InvalidTag.php
@@ -0,0 +1,145 @@
+<?php
+
+declare(strict_types=1);
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use Closure;
+use Exception;
+use phpDocumentor\Reflection\DocBlock\Tag;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionFunction;
+use Throwable;
+
+use function array_map;
+use function get_class;
+use function get_resource_type;
+use function is_array;
+use function is_object;
+use function is_resource;
+use function sprintf;
+
+/**
+ * This class represents an exception during the tag creation
+ *
+ * Since the internals of the library are relaying on the correct syntax of a docblock
+ * we cannot simply throw exceptions at all time because the exceptions will break the creation of a
+ * docklock. Just silently ignore the exceptions is not an option because the user as an issue to fix.
+ *
+ * This tag holds that error information until a using application is able to display it. The object wil just behave
+ * like any normal tag. So the normal application flow will not break.
+ */
+final class InvalidTag implements Tag
+{
+ /** @var string */
+ private $name;
+
+ /** @var string */
+ private $body;
+
+ /** @var Throwable|null */
+ private $throwable;
+
+ private function __construct(string $name, string $body)
+ {
+ $this->name = $name;
+ $this->body = $body;
+ }
+
+ public function getException(): ?Throwable
+ {
+ return $this->throwable;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public static function create(string $body, string $name = ''): self
+ {
+ return new self($name, $body);
+ }
+
+ public function withError(Throwable $exception): self
+ {
+ $this->flattenExceptionBacktrace($exception);
+ $tag = new self($this->name, $this->body);
+ $tag->throwable = $exception;
+
+ return $tag;
+ }
+
+ /**
+ * Removes all complex types from backtrace
+ *
+ * Not all objects are serializable. So we need to remove them from the
+ * stored exception to be sure that we do not break existing library usage.
+ */
+ private function flattenExceptionBacktrace(Throwable $exception): void
+ {
+ $traceProperty = (new ReflectionClass(Exception::class))->getProperty('trace');
+ $traceProperty->setAccessible(true);
+
+ do {
+ $trace = $exception->getTrace();
+ if (isset($trace[0]['args'])) {
+ $trace = array_map(
+ function (array $call): array {
+ $call['args'] = array_map([$this, 'flattenArguments'], $call['args'] ?? []);
+
+ return $call;
+ },
+ $trace
+ );
+ }
+
+ $traceProperty->setValue($exception, $trace);
+ $exception = $exception->getPrevious();
+ } while ($exception !== null);
+
+ $traceProperty->setAccessible(false);
+ }
+
+ /**
+ * @param mixed $value
+ *
+ * @return mixed
+ *
+ * @throws ReflectionException
+ */
+ private function flattenArguments($value)
+ {
+ if ($value instanceof Closure) {
+ $closureReflection = new ReflectionFunction($value);
+ $value = sprintf(
+ '(Closure at %s:%s)',
+ $closureReflection->getFileName(),
+ $closureReflection->getStartLine()
+ );
+ } elseif (is_object($value)) {
+ $value = sprintf('object(%s)', get_class($value));
+ } elseif (is_resource($value)) {
+ $value = sprintf('resource(%s)', get_resource_type($value));
+ } elseif (is_array($value)) {
+ $value = array_map([$this, 'flattenArguments'], $value);
+ }
+
+ return $value;
+ }
+
+ public function render(?Formatter $formatter = null): string
+ {
+ if ($formatter === null) {
+ $formatter = new Formatter\PassthroughFormatter();
+ }
+
+ return $formatter->format($this);
+ }
+
+ public function __toString(): string
+ {
+ return $this->body;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php
new file mode 100644
index 000000000..ee242e3b2
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Link.php
@@ -0,0 +1,78 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+/**
+ * Reflection class for a {@}link tag in a Docblock.
+ */
+final class Link extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'link';
+
+ /** @var string */
+ private $link;
+
+ /**
+ * Initializes a link to a URL.
+ */
+ public function __construct(string $link, ?Description $description = null)
+ {
+ $this->link = $link;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::notNull($descriptionFactory);
+
+ $parts = Utils::pregSplit('/\s+/Su', $body, 2);
+ $description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null;
+
+ return new static($parts[0], $description);
+ }
+
+ /**
+ * Gets the link
+ */
+ public function getLink(): string
+ {
+ return $this->link;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $link = $this->link;
+
+ return $link . ($description !== '' ? ($link !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php
new file mode 100644
index 000000000..f08bfffda
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Method.php
@@ -0,0 +1,279 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use InvalidArgumentException;
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\TypeResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Types\Mixed_;
+use phpDocumentor\Reflection\Types\Void_;
+use Webmozart\Assert\Assert;
+
+use function array_keys;
+use function explode;
+use function implode;
+use function is_string;
+use function preg_match;
+use function sort;
+use function strpos;
+use function substr;
+use function trim;
+use function var_export;
+
+/**
+ * Reflection class for an {@}method in a Docblock.
+ */
+final class Method extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'method';
+
+ /** @var string */
+ private $methodName;
+
+ /**
+ * @phpstan-var array<int, array{name: string, type: Type}>
+ * @var array<int, array<string, Type|string>>
+ */
+ private $arguments;
+
+ /** @var bool */
+ private $isStatic;
+
+ /** @var Type */
+ private $returnType;
+
+ /**
+ * @param array<int, array<string, Type|string>> $arguments
+ * @phpstan-param array<int, array{name: string, type: Type}|string> $arguments
+ */
+ public function __construct(
+ string $methodName,
+ array $arguments = [],
+ ?Type $returnType = null,
+ bool $static = false,
+ ?Description $description = null
+ ) {
+ Assert::stringNotEmpty($methodName);
+
+ if ($returnType === null) {
+ $returnType = new Void_();
+ }
+
+ $this->methodName = $methodName;
+ $this->arguments = $this->filterArguments($arguments);
+ $this->returnType = $returnType;
+ $this->isStatic = $static;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?TypeResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): ?self {
+ Assert::stringNotEmpty($body);
+ Assert::notNull($typeResolver);
+ Assert::notNull($descriptionFactory);
+
+ // 1. none or more whitespace
+ // 2. optionally the keyword "static" followed by whitespace
+ // 3. optionally a word with underscores followed by whitespace : as
+ // type for the return value
+ // 4. then optionally a word with underscores followed by () and
+ // whitespace : as method name as used by phpDocumentor
+ // 5. then a word with underscores, followed by ( and any character
+ // until a ) and whitespace : as method name with signature
+ // 6. any remaining text : as description
+ if (
+ !preg_match(
+ '/^
+ # Static keyword
+ # Declares a static method ONLY if type is also present
+ (?:
+ (static)
+ \s+
+ )?
+ # Return type
+ (?:
+ (
+ (?:[\w\|_\\\\]*\$this[\w\|_\\\\]*)
+ |
+ (?:
+ (?:[\w\|_\\\\]+)
+ # array notation
+ (?:\[\])*
+ )*+
+ )
+ \s+
+ )?
+ # Method name
+ ([\w_]+)
+ # Arguments
+ (?:
+ \(([^\)]*)\)
+ )?
+ \s*
+ # Description
+ (.*)
+ $/sux',
+ $body,
+ $matches
+ )
+ ) {
+ return null;
+ }
+
+ [, $static, $returnType, $methodName, $argumentLines, $description] = $matches;
+
+ $static = $static === 'static';
+
+ if ($returnType === '') {
+ $returnType = 'void';
+ }
+
+ $returnType = $typeResolver->resolve($returnType, $context);
+ $description = $descriptionFactory->create($description, $context);
+
+ /** @phpstan-var array<int, array{name: string, type: Type}> $arguments */
+ $arguments = [];
+ if ($argumentLines !== '') {
+ $argumentsExploded = explode(',', $argumentLines);
+ foreach ($argumentsExploded as $argument) {
+ $argument = explode(' ', self::stripRestArg(trim($argument)), 2);
+ if (strpos($argument[0], '$') === 0) {
+ $argumentName = substr($argument[0], 1);
+ $argumentType = new Mixed_();
+ } else {
+ $argumentType = $typeResolver->resolve($argument[0], $context);
+ $argumentName = '';
+ if (isset($argument[1])) {
+ $argument[1] = self::stripRestArg($argument[1]);
+ $argumentName = substr($argument[1], 1);
+ }
+ }
+
+ $arguments[] = ['name' => $argumentName, 'type' => $argumentType];
+ }
+ }
+
+ return new static($methodName, $arguments, $returnType, $static, $description);
+ }
+
+ /**
+ * Retrieves the method name.
+ */
+ public function getMethodName(): string
+ {
+ return $this->methodName;
+ }
+
+ /**
+ * @return array<int, array<string, Type|string>>
+ * @phpstan-return array<int, array{name: string, type: Type}>
+ */
+ public function getArguments(): array
+ {
+ return $this->arguments;
+ }
+
+ /**
+ * Checks whether the method tag describes a static method or not.
+ *
+ * @return bool TRUE if the method declaration is for a static method, FALSE otherwise.
+ */
+ public function isStatic(): bool
+ {
+ return $this->isStatic;
+ }
+
+ public function getReturnType(): Type
+ {
+ return $this->returnType;
+ }
+
+ public function __toString(): string
+ {
+ $arguments = [];
+ foreach ($this->arguments as $argument) {
+ $arguments[] = $argument['type'] . ' $' . $argument['name'];
+ }
+
+ $argumentStr = '(' . implode(', ', $arguments) . ')';
+
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $static = $this->isStatic ? 'static' : '';
+
+ $returnType = (string) $this->returnType;
+
+ $methodName = $this->methodName;
+
+ return $static
+ . ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '')
+ . ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $methodName : '')
+ . $argumentStr
+ . ($description !== '' ? ' ' . $description : '');
+ }
+
+ /**
+ * @param mixed[][]|string[] $arguments
+ * @phpstan-param array<int, array{name: string, type: Type}|string> $arguments
+ *
+ * @return mixed[][]
+ * @phpstan-return array<int, array{name: string, type: Type}>
+ */
+ private function filterArguments(array $arguments = []): array
+ {
+ $result = [];
+ foreach ($arguments as $argument) {
+ if (is_string($argument)) {
+ $argument = ['name' => $argument];
+ }
+
+ if (!isset($argument['type'])) {
+ $argument['type'] = new Mixed_();
+ }
+
+ $keys = array_keys($argument);
+ sort($keys);
+ if ($keys !== ['name', 'type']) {
+ throw new InvalidArgumentException(
+ 'Arguments can only have the "name" and "type" fields, found: ' . var_export($keys, true)
+ );
+ }
+
+ $result[] = $argument;
+ }
+
+ return $result;
+ }
+
+ private static function stripRestArg(string $argument): string
+ {
+ if (strpos($argument, '...') === 0) {
+ $argument = trim(substr($argument, 3));
+ }
+
+ return $argument;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php
new file mode 100644
index 000000000..3399649b8
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Param.php
@@ -0,0 +1,174 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\TypeResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+use function array_shift;
+use function array_unshift;
+use function implode;
+use function strpos;
+use function substr;
+
+use const PREG_SPLIT_DELIM_CAPTURE;
+
+/**
+ * Reflection class for the {@}param tag in a Docblock.
+ */
+final class Param extends TagWithType implements Factory\StaticMethod
+{
+ /** @var string|null */
+ private $variableName;
+
+ /** @var bool determines whether this is a variadic argument */
+ private $isVariadic;
+
+ /** @var bool determines whether this is passed by reference */
+ private $isReference;
+
+ public function __construct(
+ ?string $variableName,
+ ?Type $type = null,
+ bool $isVariadic = false,
+ ?Description $description = null,
+ bool $isReference = false
+ ) {
+ $this->name = 'param';
+ $this->variableName = $variableName;
+ $this->type = $type;
+ $this->isVariadic = $isVariadic;
+ $this->description = $description;
+ $this->isReference = $isReference;
+ }
+
+ public static function create(
+ string $body,
+ ?TypeResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::stringNotEmpty($body);
+ Assert::notNull($typeResolver);
+ Assert::notNull($descriptionFactory);
+
+ [$firstPart, $body] = self::extractTypeFromBody($body);
+
+ $type = null;
+ $parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $variableName = '';
+ $isVariadic = false;
+ $isReference = false;
+
+ // if the first item that is encountered is not a variable; it is a type
+ if ($firstPart && !self::strStartsWithVariable($firstPart)) {
+ $type = $typeResolver->resolve($firstPart, $context);
+ } else {
+ // first part is not a type; we should prepend it to the parts array for further processing
+ array_unshift($parts, $firstPart);
+ }
+
+ // if the next item starts with a $ or ...$ or &$ or &...$ it must be the variable name
+ if (isset($parts[0]) && self::strStartsWithVariable($parts[0])) {
+ $variableName = array_shift($parts);
+ if ($type) {
+ array_shift($parts);
+ }
+
+ Assert::notNull($variableName);
+
+ if (strpos($variableName, '$') === 0) {
+ $variableName = substr($variableName, 1);
+ } elseif (strpos($variableName, '&$') === 0) {
+ $isReference = true;
+ $variableName = substr($variableName, 2);
+ } elseif (strpos($variableName, '...$') === 0) {
+ $isVariadic = true;
+ $variableName = substr($variableName, 4);
+ } elseif (strpos($variableName, '&...$') === 0) {
+ $isVariadic = true;
+ $isReference = true;
+ $variableName = substr($variableName, 5);
+ }
+ }
+
+ $description = $descriptionFactory->create(implode('', $parts), $context);
+
+ return new static($variableName, $type, $isVariadic, $description, $isReference);
+ }
+
+ /**
+ * Returns the variable's name.
+ */
+ public function getVariableName(): ?string
+ {
+ return $this->variableName;
+ }
+
+ /**
+ * Returns whether this tag is variadic.
+ */
+ public function isVariadic(): bool
+ {
+ return $this->isVariadic;
+ }
+
+ /**
+ * Returns whether this tag is passed by reference.
+ */
+ public function isReference(): bool
+ {
+ return $this->isReference;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $variableName = '';
+ if ($this->variableName) {
+ $variableName .= ($this->isReference ? '&' : '') . ($this->isVariadic ? '...' : '');
+ $variableName .= '$' . $this->variableName;
+ }
+
+ $type = (string) $this->type;
+
+ return $type
+ . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
+ . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
+ }
+
+ private static function strStartsWithVariable(string $str): bool
+ {
+ return strpos($str, '$') === 0
+ ||
+ strpos($str, '...$') === 0
+ ||
+ strpos($str, '&$') === 0
+ ||
+ strpos($str, '&...$') === 0;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php
new file mode 100644
index 000000000..2521fb3f0
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Property.php
@@ -0,0 +1,121 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\TypeResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+use function array_shift;
+use function array_unshift;
+use function implode;
+use function strpos;
+use function substr;
+
+use const PREG_SPLIT_DELIM_CAPTURE;
+
+/**
+ * Reflection class for a {@}property tag in a Docblock.
+ */
+final class Property extends TagWithType implements Factory\StaticMethod
+{
+ /** @var string|null */
+ protected $variableName;
+
+ public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
+ {
+ Assert::string($variableName);
+
+ $this->name = 'property';
+ $this->variableName = $variableName;
+ $this->type = $type;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?TypeResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::stringNotEmpty($body);
+ Assert::notNull($typeResolver);
+ Assert::notNull($descriptionFactory);
+
+ [$firstPart, $body] = self::extractTypeFromBody($body);
+ $type = null;
+ $parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $variableName = '';
+
+ // if the first item that is encountered is not a variable; it is a type
+ if ($firstPart && $firstPart[0] !== '$') {
+ $type = $typeResolver->resolve($firstPart, $context);
+ } else {
+ // first part is not a type; we should prepend it to the parts array for further processing
+ array_unshift($parts, $firstPart);
+ }
+
+ // if the next item starts with a $ it must be the variable name
+ if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
+ $variableName = array_shift($parts);
+ if ($type) {
+ array_shift($parts);
+ }
+
+ Assert::notNull($variableName);
+
+ $variableName = substr($variableName, 1);
+ }
+
+ $description = $descriptionFactory->create(implode('', $parts), $context);
+
+ return new static($variableName, $type, $description);
+ }
+
+ /**
+ * Returns the variable's name.
+ */
+ public function getVariableName(): ?string
+ {
+ return $this->variableName;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ if ($this->variableName) {
+ $variableName = '$' . $this->variableName;
+ } else {
+ $variableName = '';
+ }
+
+ $type = (string) $this->type;
+
+ return $type
+ . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
+ . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php
new file mode 100644
index 000000000..9491b39c3
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyRead.php
@@ -0,0 +1,121 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\TypeResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+use function array_shift;
+use function array_unshift;
+use function implode;
+use function strpos;
+use function substr;
+
+use const PREG_SPLIT_DELIM_CAPTURE;
+
+/**
+ * Reflection class for a {@}property-read tag in a Docblock.
+ */
+final class PropertyRead extends TagWithType implements Factory\StaticMethod
+{
+ /** @var string|null */
+ protected $variableName;
+
+ public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
+ {
+ Assert::string($variableName);
+
+ $this->name = 'property-read';
+ $this->variableName = $variableName;
+ $this->type = $type;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?TypeResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::stringNotEmpty($body);
+ Assert::notNull($typeResolver);
+ Assert::notNull($descriptionFactory);
+
+ [$firstPart, $body] = self::extractTypeFromBody($body);
+ $type = null;
+ $parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $variableName = '';
+
+ // if the first item that is encountered is not a variable; it is a type
+ if ($firstPart && $firstPart[0] !== '$') {
+ $type = $typeResolver->resolve($firstPart, $context);
+ } else {
+ // first part is not a type; we should prepend it to the parts array for further processing
+ array_unshift($parts, $firstPart);
+ }
+
+ // if the next item starts with a $ it must be the variable name
+ if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
+ $variableName = array_shift($parts);
+ if ($type) {
+ array_shift($parts);
+ }
+
+ Assert::notNull($variableName);
+
+ $variableName = substr($variableName, 1);
+ }
+
+ $description = $descriptionFactory->create(implode('', $parts), $context);
+
+ return new static($variableName, $type, $description);
+ }
+
+ /**
+ * Returns the variable's name.
+ */
+ public function getVariableName(): ?string
+ {
+ return $this->variableName;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ if ($this->variableName) {
+ $variableName = '$' . $this->variableName;
+ } else {
+ $variableName = '';
+ }
+
+ $type = (string) $this->type;
+
+ return $type
+ . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
+ . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php
new file mode 100644
index 000000000..2bfdac6a0
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/PropertyWrite.php
@@ -0,0 +1,121 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\TypeResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+use function array_shift;
+use function array_unshift;
+use function implode;
+use function strpos;
+use function substr;
+
+use const PREG_SPLIT_DELIM_CAPTURE;
+
+/**
+ * Reflection class for a {@}property-write tag in a Docblock.
+ */
+final class PropertyWrite extends TagWithType implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $variableName;
+
+ public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
+ {
+ Assert::string($variableName);
+
+ $this->name = 'property-write';
+ $this->variableName = $variableName;
+ $this->type = $type;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?TypeResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::stringNotEmpty($body);
+ Assert::notNull($typeResolver);
+ Assert::notNull($descriptionFactory);
+
+ [$firstPart, $body] = self::extractTypeFromBody($body);
+ $type = null;
+ $parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $variableName = '';
+
+ // if the first item that is encountered is not a variable; it is a type
+ if ($firstPart && $firstPart[0] !== '$') {
+ $type = $typeResolver->resolve($firstPart, $context);
+ } else {
+ // first part is not a type; we should prepend it to the parts array for further processing
+ array_unshift($parts, $firstPart);
+ }
+
+ // if the next item starts with a $ it must be the variable name
+ if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
+ $variableName = array_shift($parts);
+ if ($type) {
+ array_shift($parts);
+ }
+
+ Assert::notNull($variableName);
+
+ $variableName = substr($variableName, 1);
+ }
+
+ $description = $descriptionFactory->create(implode('', $parts), $context);
+
+ return new static($variableName, $type, $description);
+ }
+
+ /**
+ * Returns the variable's name.
+ */
+ public function getVariableName(): ?string
+ {
+ return $this->variableName;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ if ($this->variableName) {
+ $variableName = '$' . $this->variableName;
+ } else {
+ $variableName = '';
+ }
+
+ $type = (string) $this->type;
+
+ return $type
+ . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
+ . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php
new file mode 100644
index 000000000..532003dd8
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Fqsen.php
@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;
+
+use phpDocumentor\Reflection\Fqsen as RealFqsen;
+
+/**
+ * Fqsen reference used by {@see \phpDocumentor\Reflection\DocBlock\Tags\See}
+ */
+final class Fqsen implements Reference
+{
+ /** @var RealFqsen */
+ private $fqsen;
+
+ public function __construct(RealFqsen $fqsen)
+ {
+ $this->fqsen = $fqsen;
+ }
+
+ /**
+ * @return string string representation of the referenced fqsen
+ */
+ public function __toString(): string
+ {
+ return (string) $this->fqsen;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php
new file mode 100644
index 000000000..e7dea868d
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Reference.php
@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;
+
+/**
+ * Interface for references in {@see \phpDocumentor\Reflection\DocBlock\Tags\See}
+ */
+interface Reference
+{
+ public function __toString(): string;
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php
new file mode 100644
index 000000000..edfba3fde
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Reference/Url.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags\Reference;
+
+use Webmozart\Assert\Assert;
+
+/**
+ * Url reference used by {@see \phpDocumentor\Reflection\DocBlock\Tags\See}
+ */
+final class Url implements Reference
+{
+ /** @var string */
+ private $uri;
+
+ public function __construct(string $uri)
+ {
+ Assert::stringNotEmpty($uri);
+ $this->uri = $uri;
+ }
+
+ public function __toString(): string
+ {
+ return $this->uri;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php
new file mode 100644
index 000000000..f021b6092
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Return_.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\TypeResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use Webmozart\Assert\Assert;
+
+/**
+ * Reflection class for a {@}return tag in a Docblock.
+ */
+final class Return_ extends TagWithType implements Factory\StaticMethod
+{
+ public function __construct(Type $type, ?Description $description = null)
+ {
+ $this->name = 'return';
+ $this->type = $type;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?TypeResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::notNull($typeResolver);
+ Assert::notNull($descriptionFactory);
+
+ [$type, $description] = self::extractTypeFromBody($body);
+
+ $type = $typeResolver->resolve($type, $context);
+ $description = $descriptionFactory->create($description, $context);
+
+ return new static($type, $description);
+ }
+
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $type = $this->type ? '' . $this->type : 'mixed';
+
+ return $type . ($description !== '' ? ' ' . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php
new file mode 100644
index 000000000..a194c7ded
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/See.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\DocBlock\Tags\Reference\Fqsen as FqsenRef;
+use phpDocumentor\Reflection\DocBlock\Tags\Reference\Reference;
+use phpDocumentor\Reflection\DocBlock\Tags\Reference\Url;
+use phpDocumentor\Reflection\Fqsen;
+use phpDocumentor\Reflection\FqsenResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+use function array_key_exists;
+use function explode;
+use function preg_match;
+
+/**
+ * Reflection class for an {@}see tag in a Docblock.
+ */
+final class See extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'see';
+
+ /** @var Reference */
+ protected $refers;
+
+ /**
+ * Initializes this tag.
+ */
+ public function __construct(Reference $refers, ?Description $description = null)
+ {
+ $this->refers = $refers;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?FqsenResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::notNull($descriptionFactory);
+
+ $parts = Utils::pregSplit('/\s+/Su', $body, 2);
+ $description = isset($parts[1]) ? $descriptionFactory->create($parts[1], $context) : null;
+
+ // https://tools.ietf.org/html/rfc2396#section-3
+ if (preg_match('#\w://\w#', $parts[0])) {
+ return new static(new Url($parts[0]), $description);
+ }
+
+ return new static(new FqsenRef(self::resolveFqsen($parts[0], $typeResolver, $context)), $description);
+ }
+
+ private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
+ {
+ Assert::notNull($fqsenResolver);
+ $fqsenParts = explode('::', $parts);
+ $resolved = $fqsenResolver->resolve($fqsenParts[0], $context);
+
+ if (!array_key_exists(1, $fqsenParts)) {
+ return $resolved;
+ }
+
+ return new Fqsen($resolved . '::' . $fqsenParts[1]);
+ }
+
+ /**
+ * Returns the ref of this tag.
+ */
+ public function getReference(): Reference
+ {
+ return $this->refers;
+ }
+
+ /**
+ * Returns a string representation of this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $refers = (string) $this->refers;
+
+ return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php
new file mode 100644
index 000000000..54af43cd4
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Since.php
@@ -0,0 +1,103 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use Webmozart\Assert\Assert;
+
+use function preg_match;
+
+/**
+ * Reflection class for a {@}since tag in a Docblock.
+ */
+final class Since extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'since';
+
+ /**
+ * PCRE regular expression matching a version vector.
+ * Assumes the "x" modifier.
+ */
+ public const REGEX_VECTOR = '(?:
+ # Normal release vectors.
+ \d\S*
+ |
+ # VCS version vectors. Per PHPCS, they are expected to
+ # follow the form of the VCS name, followed by ":", followed
+ # by the version vector itself.
+ # By convention, popular VCSes like CVS, SVN and GIT use "$"
+ # around the actual version vector.
+ [^\s\:]+\:\s*\$[^\$]+\$
+ )';
+
+ /** @var string|null The version vector. */
+ private $version;
+
+ public function __construct(?string $version = null, ?Description $description = null)
+ {
+ Assert::nullOrNotEmpty($version);
+
+ $this->version = $version;
+ $this->description = $description;
+ }
+
+ public static function create(
+ ?string $body,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): ?self {
+ if (empty($body)) {
+ return new static();
+ }
+
+ $matches = [];
+ if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
+ return null;
+ }
+
+ Assert::notNull($descriptionFactory);
+
+ return new static(
+ $matches[1],
+ $descriptionFactory->create($matches[2] ?? '', $context)
+ );
+ }
+
+ /**
+ * Gets the version section of the tag.
+ */
+ public function getVersion(): ?string
+ {
+ return $this->version;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $version = (string) $this->version;
+
+ return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php
new file mode 100644
index 000000000..8b8c0fb47
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Source.php
@@ -0,0 +1,116 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use Webmozart\Assert\Assert;
+
+use function preg_match;
+
+/**
+ * Reflection class for a {@}source tag in a Docblock.
+ */
+final class Source extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'source';
+
+ /** @var int The starting line, relative to the structural element's location. */
+ private $startingLine;
+
+ /** @var int|null The number of lines, relative to the starting line. NULL means "to the end". */
+ private $lineCount;
+
+ /**
+ * @param int|string $startingLine should be a to int convertible value
+ * @param int|string|null $lineCount should be a to int convertible value
+ */
+ public function __construct($startingLine, $lineCount = null, ?Description $description = null)
+ {
+ Assert::integerish($startingLine);
+ Assert::nullOrIntegerish($lineCount);
+
+ $this->startingLine = (int) $startingLine;
+ $this->lineCount = $lineCount !== null ? (int) $lineCount : null;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::stringNotEmpty($body);
+ Assert::notNull($descriptionFactory);
+
+ $startingLine = 1;
+ $lineCount = null;
+ $description = null;
+
+ // Starting line / Number of lines / Description
+ if (preg_match('/^([1-9]\d*)\s*(?:((?1))\s+)?(.*)$/sux', $body, $matches)) {
+ $startingLine = (int) $matches[1];
+ if (isset($matches[2]) && $matches[2] !== '') {
+ $lineCount = (int) $matches[2];
+ }
+
+ $description = $matches[3];
+ }
+
+ return new static($startingLine, $lineCount, $descriptionFactory->create($description ?? '', $context));
+ }
+
+ /**
+ * Gets the starting line.
+ *
+ * @return int The starting line, relative to the structural element's
+ * location.
+ */
+ public function getStartingLine(): int
+ {
+ return $this->startingLine;
+ }
+
+ /**
+ * Returns the number of lines.
+ *
+ * @return int|null The number of lines, relative to the starting line. NULL
+ * means "to the end".
+ */
+ public function getLineCount(): ?int
+ {
+ return $this->lineCount;
+ }
+
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $startingLine = (string) $this->startingLine;
+
+ $lineCount = $this->lineCount !== null ? ' ' . $this->lineCount : '';
+
+ return $startingLine
+ . $lineCount
+ . ($description !== ''
+ ? ' ' . $description
+ : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php
new file mode 100644
index 000000000..158578bd2
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/TagWithType.php
@@ -0,0 +1,66 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\Type;
+
+use function in_array;
+use function strlen;
+use function substr;
+use function trim;
+
+abstract class TagWithType extends BaseTag
+{
+ /** @var ?Type */
+ protected $type;
+
+ /**
+ * Returns the type section of the variable.
+ */
+ public function getType(): ?Type
+ {
+ return $this->type;
+ }
+
+ /**
+ * @return string[]
+ */
+ protected static function extractTypeFromBody(string $body): array
+ {
+ $type = '';
+ $nestingLevel = 0;
+ for ($i = 0, $iMax = strlen($body); $i < $iMax; $i++) {
+ $character = $body[$i];
+
+ if ($nestingLevel === 0 && trim($character) === '') {
+ break;
+ }
+
+ $type .= $character;
+ if (in_array($character, ['<', '(', '[', '{'])) {
+ $nestingLevel++;
+ continue;
+ }
+
+ if (in_array($character, ['>', ')', ']', '}'])) {
+ $nestingLevel--;
+ continue;
+ }
+ }
+
+ $description = trim(substr($body, strlen($type)));
+
+ return [$type, $description];
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php
new file mode 100644
index 000000000..f21c91011
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Throws.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\TypeResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use Webmozart\Assert\Assert;
+
+/**
+ * Reflection class for a {@}throws tag in a Docblock.
+ */
+final class Throws extends TagWithType implements Factory\StaticMethod
+{
+ public function __construct(Type $type, ?Description $description = null)
+ {
+ $this->name = 'throws';
+ $this->type = $type;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?TypeResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::notNull($typeResolver);
+ Assert::notNull($descriptionFactory);
+
+ [$type, $description] = self::extractTypeFromBody($body);
+
+ $type = $typeResolver->resolve($type, $context);
+ $description = $descriptionFactory->create($description, $context);
+
+ return new static($type, $description);
+ }
+
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $type = (string) $this->type;
+
+ return $type . ($description !== '' ? ($type !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php
new file mode 100644
index 000000000..b72f40347
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Uses.php
@@ -0,0 +1,100 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Fqsen;
+use phpDocumentor\Reflection\FqsenResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+use function array_key_exists;
+use function explode;
+
+/**
+ * Reflection class for a {@}uses tag in a Docblock.
+ */
+final class Uses extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'uses';
+
+ /** @var Fqsen */
+ protected $refers;
+
+ /**
+ * Initializes this tag.
+ */
+ public function __construct(Fqsen $refers, ?Description $description = null)
+ {
+ $this->refers = $refers;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?FqsenResolver $resolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::notNull($resolver);
+ Assert::notNull($descriptionFactory);
+
+ $parts = Utils::pregSplit('/\s+/Su', $body, 2);
+
+ return new static(
+ self::resolveFqsen($parts[0], $resolver, $context),
+ $descriptionFactory->create($parts[1] ?? '', $context)
+ );
+ }
+
+ private static function resolveFqsen(string $parts, ?FqsenResolver $fqsenResolver, ?TypeContext $context): Fqsen
+ {
+ Assert::notNull($fqsenResolver);
+ $fqsenParts = explode('::', $parts);
+ $resolved = $fqsenResolver->resolve($fqsenParts[0], $context);
+
+ if (!array_key_exists(1, $fqsenParts)) {
+ return $resolved;
+ }
+
+ return new Fqsen($resolved . '::' . $fqsenParts[1]);
+ }
+
+ /**
+ * Returns the structural element this tag refers to.
+ */
+ public function getReference(): Fqsen
+ {
+ return $this->refers;
+ }
+
+ /**
+ * Returns a string representation of this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $refers = (string) $this->refers;
+
+ return $refers . ($description !== '' ? ($refers !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php
new file mode 100644
index 000000000..fa1f9dbf6
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Var_.php
@@ -0,0 +1,122 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\TypeResolver;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use phpDocumentor\Reflection\Utils;
+use Webmozart\Assert\Assert;
+
+use function array_shift;
+use function array_unshift;
+use function implode;
+use function strpos;
+use function substr;
+
+use const PREG_SPLIT_DELIM_CAPTURE;
+
+/**
+ * Reflection class for a {@}var tag in a Docblock.
+ */
+final class Var_ extends TagWithType implements Factory\StaticMethod
+{
+ /** @var string|null */
+ protected $variableName = '';
+
+ public function __construct(?string $variableName, ?Type $type = null, ?Description $description = null)
+ {
+ Assert::string($variableName);
+
+ $this->name = 'var';
+ $this->variableName = $variableName;
+ $this->type = $type;
+ $this->description = $description;
+ }
+
+ public static function create(
+ string $body,
+ ?TypeResolver $typeResolver = null,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): self {
+ Assert::stringNotEmpty($body);
+ Assert::notNull($typeResolver);
+ Assert::notNull($descriptionFactory);
+
+ [$firstPart, $body] = self::extractTypeFromBody($body);
+
+ $parts = Utils::pregSplit('/(\s+)/Su', $body, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $type = null;
+ $variableName = '';
+
+ // if the first item that is encountered is not a variable; it is a type
+ if ($firstPart && $firstPart[0] !== '$') {
+ $type = $typeResolver->resolve($firstPart, $context);
+ } else {
+ // first part is not a type; we should prepend it to the parts array for further processing
+ array_unshift($parts, $firstPart);
+ }
+
+ // if the next item starts with a $ it must be the variable name
+ if (isset($parts[0]) && strpos($parts[0], '$') === 0) {
+ $variableName = array_shift($parts);
+ if ($type) {
+ array_shift($parts);
+ }
+
+ Assert::notNull($variableName);
+
+ $variableName = substr($variableName, 1);
+ }
+
+ $description = $descriptionFactory->create(implode('', $parts), $context);
+
+ return new static($variableName, $type, $description);
+ }
+
+ /**
+ * Returns the variable's name.
+ */
+ public function getVariableName(): ?string
+ {
+ return $this->variableName;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ if ($this->variableName) {
+ $variableName = '$' . $this->variableName;
+ } else {
+ $variableName = '';
+ }
+
+ $type = (string) $this->type;
+
+ return $type
+ . ($variableName !== '' ? ($type !== '' ? ' ' : '') . $variableName : '')
+ . ($description !== '' ? ($type !== '' || $variableName !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php
new file mode 100644
index 000000000..f46e4b8c0
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Version.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection\DocBlock\Tags;
+
+use phpDocumentor\Reflection\DocBlock\Description;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\Types\Context as TypeContext;
+use Webmozart\Assert\Assert;
+
+use function preg_match;
+
+/**
+ * Reflection class for a {@}version tag in a Docblock.
+ */
+final class Version extends BaseTag implements Factory\StaticMethod
+{
+ /** @var string */
+ protected $name = 'version';
+
+ /**
+ * PCRE regular expression matching a version vector.
+ * Assumes the "x" modifier.
+ */
+ public const REGEX_VECTOR = '(?:
+ # Normal release vectors.
+ \d\S*
+ |
+ # VCS version vectors. Per PHPCS, they are expected to
+ # follow the form of the VCS name, followed by ":", followed
+ # by the version vector itself.
+ # By convention, popular VCSes like CVS, SVN and GIT use "$"
+ # around the actual version vector.
+ [^\s\:]+\:\s*\$[^\$]+\$
+ )';
+
+ /** @var string|null The version vector. */
+ private $version;
+
+ public function __construct(?string $version = null, ?Description $description = null)
+ {
+ Assert::nullOrStringNotEmpty($version);
+
+ $this->version = $version;
+ $this->description = $description;
+ }
+
+ public static function create(
+ ?string $body,
+ ?DescriptionFactory $descriptionFactory = null,
+ ?TypeContext $context = null
+ ): ?self {
+ if (empty($body)) {
+ return new static();
+ }
+
+ $matches = [];
+ if (!preg_match('/^(' . self::REGEX_VECTOR . ')\s*(.+)?$/sux', $body, $matches)) {
+ return null;
+ }
+
+ $description = null;
+ if ($descriptionFactory !== null) {
+ $description = $descriptionFactory->create($matches[2] ?? '', $context);
+ }
+
+ return new static(
+ $matches[1],
+ $description
+ );
+ }
+
+ /**
+ * Gets the version section of the tag.
+ */
+ public function getVersion(): ?string
+ {
+ return $this->version;
+ }
+
+ /**
+ * Returns a string representation for this tag.
+ */
+ public function __toString(): string
+ {
+ if ($this->description) {
+ $description = $this->description->render();
+ } else {
+ $description = '';
+ }
+
+ $version = (string) $this->version;
+
+ return $version . ($description !== '' ? ($version !== '' ? ' ' : '') . $description : '');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlockFactory.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlockFactory.php
new file mode 100644
index 000000000..37f72dd2e
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlockFactory.php
@@ -0,0 +1,287 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection;
+
+use InvalidArgumentException;
+use LogicException;
+use phpDocumentor\Reflection\DocBlock\DescriptionFactory;
+use phpDocumentor\Reflection\DocBlock\StandardTagFactory;
+use phpDocumentor\Reflection\DocBlock\Tag;
+use phpDocumentor\Reflection\DocBlock\TagFactory;
+use Webmozart\Assert\Assert;
+
+use function array_shift;
+use function count;
+use function explode;
+use function is_object;
+use function method_exists;
+use function preg_match;
+use function preg_replace;
+use function str_replace;
+use function strpos;
+use function substr;
+use function trim;
+
+final class DocBlockFactory implements DocBlockFactoryInterface
+{
+ /** @var DocBlock\DescriptionFactory */
+ private $descriptionFactory;
+
+ /** @var DocBlock\TagFactory */
+ private $tagFactory;
+
+ /**
+ * Initializes this factory with the required subcontractors.
+ */
+ public function __construct(DescriptionFactory $descriptionFactory, TagFactory $tagFactory)
+ {
+ $this->descriptionFactory = $descriptionFactory;
+ $this->tagFactory = $tagFactory;
+ }
+
+ /**
+ * Factory method for easy instantiation.
+ *
+ * @param array<string, class-string<Tag>> $additionalTags
+ */
+ public static function createInstance(array $additionalTags = []): self
+ {
+ $fqsenResolver = new FqsenResolver();
+ $tagFactory = new StandardTagFactory($fqsenResolver);
+ $descriptionFactory = new DescriptionFactory($tagFactory);
+
+ $tagFactory->addService($descriptionFactory);
+ $tagFactory->addService(new TypeResolver($fqsenResolver));
+
+ $docBlockFactory = new self($descriptionFactory, $tagFactory);
+ foreach ($additionalTags as $tagName => $tagHandler) {
+ $docBlockFactory->registerTagHandler($tagName, $tagHandler);
+ }
+
+ return $docBlockFactory;
+ }
+
+ /**
+ * @param object|string $docblock A string containing the DocBlock to parse or an object supporting the
+ * getDocComment method (such as a ReflectionClass object).
+ */
+ public function create($docblock, ?Types\Context $context = null, ?Location $location = null): DocBlock
+ {
+ if (is_object($docblock)) {
+ if (!method_exists($docblock, 'getDocComment')) {
+ $exceptionMessage = 'Invalid object passed; the given object must support the getDocComment method';
+
+ throw new InvalidArgumentException($exceptionMessage);
+ }
+
+ $docblock = $docblock->getDocComment();
+ Assert::string($docblock);
+ }
+
+ Assert::stringNotEmpty($docblock);
+
+ if ($context === null) {
+ $context = new Types\Context('');
+ }
+
+ $parts = $this->splitDocBlock($this->stripDocComment($docblock));
+
+ [$templateMarker, $summary, $description, $tags] = $parts;
+
+ return new DocBlock(
+ $summary,
+ $description ? $this->descriptionFactory->create($description, $context) : null,
+ $this->parseTagBlock($tags, $context),
+ $context,
+ $location,
+ $templateMarker === '#@+',
+ $templateMarker === '#@-'
+ );
+ }
+
+ /**
+ * @param class-string<Tag> $handler
+ */
+ public function registerTagHandler(string $tagName, string $handler): void
+ {
+ $this->tagFactory->registerTagHandler($tagName, $handler);
+ }
+
+ /**
+ * Strips the asterisks from the DocBlock comment.
+ *
+ * @param string $comment String containing the comment text.
+ */
+ private function stripDocComment(string $comment): string
+ {
+ $comment = preg_replace('#[ \t]*(?:\/\*\*|\*\/|\*)?[ \t]?(.*)?#u', '$1', $comment);
+ Assert::string($comment);
+ $comment = trim($comment);
+
+ // reg ex above is not able to remove */ from a single line docblock
+ if (substr($comment, -2) === '*/') {
+ $comment = trim(substr($comment, 0, -2));
+ }
+
+ return str_replace(["\r\n", "\r"], "\n", $comment);
+ }
+
+ // phpcs:disable
+ /**
+ * Splits the DocBlock into a template marker, summary, description and block of tags.
+ *
+ * @param string $comment Comment to split into the sub-parts.
+ *
+ * @return string[] containing the template marker (if any), summary, description and a string containing the tags.
+ *
+ * @author Mike van Riel <[email protected]> for extending the regex with template marker support.
+ *
+ * @author Richard van Velzen (@_richardJ) Special thanks to Richard for the regex responsible for the split.
+ */
+ private function splitDocBlock(string $comment) : array
+ {
+ // phpcs:enable
+ // Performance improvement cheat: if the first character is an @ then only tags are in this DocBlock. This
+ // method does not split tags so we return this verbatim as the fourth result (tags). This saves us the
+ // performance impact of running a regular expression
+ if (strpos($comment, '@') === 0) {
+ return ['', '', '', $comment];
+ }
+
+ // clears all extra horizontal whitespace from the line endings to prevent parsing issues
+ $comment = preg_replace('/\h*$/Sum', '', $comment);
+ Assert::string($comment);
+ /*
+ * Splits the docblock into a template marker, summary, description and tags section.
+ *
+ * - The template marker is empty, #@+ or #@- if the DocBlock starts with either of those (a newline may
+ * occur after it and will be stripped).
+ * - The short description is started from the first character until a dot is encountered followed by a
+ * newline OR two consecutive newlines (horizontal whitespace is taken into account to consider spacing
+ * errors). This is optional.
+ * - The long description, any character until a new line is encountered followed by an @ and word
+ * characters (a tag). This is optional.
+ * - Tags; the remaining characters
+ *
+ * Big thanks to RichardJ for contributing this Regular Expression
+ */
+ preg_match(
+ '/
+ \A
+ # 1. Extract the template marker
+ (?:(\#\@\+|\#\@\-)\n?)?
+
+ # 2. Extract the summary
+ (?:
+ (?! @\pL ) # The summary may not start with an @
+ (
+ [^\n.]+
+ (?:
+ (?! \. \n | \n{2} ) # End summary upon a dot followed by newline or two newlines
+ [\n.]* (?! [ \t]* @\pL ) # End summary when an @ is found as first character on a new line
+ [^\n.]+ # Include anything else
+ )*
+ \.?
+ )?
+ )
+
+ # 3. Extract the description
+ (?:
+ \s* # Some form of whitespace _must_ precede a description because a summary must be there
+ (?! @\pL ) # The description may not start with an @
+ (
+ [^\n]+
+ (?: \n+
+ (?! [ \t]* @\pL ) # End description when an @ is found as first character on a new line
+ [^\n]+ # Include anything else
+ )*
+ )
+ )?
+
+ # 4. Extract the tags (anything that follows)
+ (\s+ [\s\S]*)? # everything that follows
+ /ux',
+ $comment,
+ $matches
+ );
+ array_shift($matches);
+
+ while (count($matches) < 4) {
+ $matches[] = '';
+ }
+
+ return $matches;
+ }
+
+ /**
+ * Creates the tag objects.
+ *
+ * @param string $tags Tag block to parse.
+ * @param Types\Context $context Context of the parsed Tag
+ *
+ * @return DocBlock\Tag[]
+ */
+ private function parseTagBlock(string $tags, Types\Context $context): array
+ {
+ $tags = $this->filterTagBlock($tags);
+ if ($tags === null) {
+ return [];
+ }
+
+ $result = [];
+ $lines = $this->splitTagBlockIntoTagLines($tags);
+ foreach ($lines as $key => $tagLine) {
+ $result[$key] = $this->tagFactory->create(trim($tagLine), $context);
+ }
+
+ return $result;
+ }
+
+ /**
+ * @return string[]
+ */
+ private function splitTagBlockIntoTagLines(string $tags): array
+ {
+ $result = [];
+ foreach (explode("\n", $tags) as $tagLine) {
+ if ($tagLine !== '' && strpos($tagLine, '@') === 0) {
+ $result[] = $tagLine;
+ } else {
+ $result[count($result) - 1] .= "\n" . $tagLine;
+ }
+ }
+
+ return $result;
+ }
+
+ private function filterTagBlock(string $tags): ?string
+ {
+ $tags = trim($tags);
+ if (!$tags) {
+ return null;
+ }
+
+ if ($tags[0] !== '@') {
+ // @codeCoverageIgnoreStart
+ // Can't simulate this; this only happens if there is an error with the parsing of the DocBlock that
+ // we didn't foresee.
+
+ throw new LogicException('A tag block started with text instead of an at-sign(@): ' . $tags);
+
+ // @codeCoverageIgnoreEnd
+ }
+
+ return $tags;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php b/vendor/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php
new file mode 100644
index 000000000..9995c0c09
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/DocBlockFactoryInterface.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+namespace phpDocumentor\Reflection;
+
+use phpDocumentor\Reflection\DocBlock\Tag;
+
+// phpcs:ignore SlevomatCodingStandard.Classes.SuperfluousInterfaceNaming.SuperfluousSuffix
+interface DocBlockFactoryInterface
+{
+ /**
+ * Factory method for easy instantiation.
+ *
+ * @param array<string, class-string<Tag>> $additionalTags
+ */
+ public static function createInstance(array $additionalTags = []): DocBlockFactory;
+
+ /**
+ * @param string|object $docblock
+ */
+ public function create($docblock, ?Types\Context $context = null, ?Location $location = null): DocBlock;
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/Exception/PcreException.php b/vendor/phpdocumentor/reflection-docblock/src/Exception/PcreException.php
new file mode 100644
index 000000000..b8b6da8cf
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/Exception/PcreException.php
@@ -0,0 +1,44 @@
+<?php
+
+declare(strict_types=1);
+
+namespace phpDocumentor\Reflection\Exception;
+
+use InvalidArgumentException;
+
+use const PREG_BACKTRACK_LIMIT_ERROR;
+use const PREG_BAD_UTF8_ERROR;
+use const PREG_BAD_UTF8_OFFSET_ERROR;
+use const PREG_INTERNAL_ERROR;
+use const PREG_JIT_STACKLIMIT_ERROR;
+use const PREG_NO_ERROR;
+use const PREG_RECURSION_LIMIT_ERROR;
+
+final class PcreException extends InvalidArgumentException
+{
+ public static function createFromPhpError(int $errorCode): self
+ {
+ switch ($errorCode) {
+ case PREG_BACKTRACK_LIMIT_ERROR:
+ return new self('Backtrack limit error');
+
+ case PREG_RECURSION_LIMIT_ERROR:
+ return new self('Recursion limit error');
+
+ case PREG_BAD_UTF8_ERROR:
+ return new self('Bad UTF8 error');
+
+ case PREG_BAD_UTF8_OFFSET_ERROR:
+ return new self('Bad UTF8 offset error');
+
+ case PREG_JIT_STACKLIMIT_ERROR:
+ return new self('Jit stacklimit error');
+
+ case PREG_NO_ERROR:
+ case PREG_INTERNAL_ERROR:
+ default:
+ }
+
+ return new self('Unknown Pcre error');
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-docblock/src/Utils.php b/vendor/phpdocumentor/reflection-docblock/src/Utils.php
new file mode 100644
index 000000000..ddd0f61d9
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-docblock/src/Utils.php
@@ -0,0 +1,62 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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
+ */
+
+namespace phpDocumentor\Reflection;
+
+use phpDocumentor\Reflection\Exception\PcreException;
+use Webmozart\Assert\Assert;
+
+use function preg_last_error;
+use function preg_split as php_preg_split;
+
+abstract class Utils
+{
+ /**
+ * Wrapper function for phps preg_split
+ *
+ * This function is inspired by {@link https://github.com/thecodingmachine/safe/blob/master/generated/pcre.php}. But
+ * since this library is all about performance we decided to strip everything we don't need. Reducing the amount
+ * of files that have to be loaded, ect.
+ *
+ * @param string $pattern The pattern to search for, as a string.
+ * @param string $subject The input string.
+ * @param int $limit If specified, then only substrings up to limit are returned with the
+ * rest of the string being placed in the last substring. A limit of -1 or 0 means "no limit".
+ * @param int $flags flags can be any combination of the following flags (combined with the | bitwise operator):
+ * *PREG_SPLIT_NO_EMPTY*
+ * If this flag is set, only non-empty pieces will be returned by preg_split().
+ * *PREG_SPLIT_DELIM_CAPTURE*
+ * If this flag is set, parenthesized expression in the delimiter pattern will be captured
+ * and returned as well.
+ * *PREG_SPLIT_OFFSET_CAPTURE*
+ * If this flag is set, for every occurring match the appendant string offset will also be returned.
+ * Note that this changes the return value in an array where every element is an array consisting of the
+ * matched string at offset 0 and its string offset into subject at offset 1.
+ *
+ * @return string[] Returns an array containing substrings of subject
+ * split along boundaries matched by pattern
+ *
+ * @throws PcreException
+ */
+ public static function pregSplit(string $pattern, string $subject, int $limit = -1, int $flags = 0): array
+ {
+ $parts = php_preg_split($pattern, $subject, $limit, $flags);
+ if ($parts === false) {
+ throw PcreException::createFromPhpError(preg_last_error());
+ }
+
+ Assert::allString($parts);
+
+ return $parts;
+ }
+}