summaryrefslogtreecommitdiff
path: root/vendor/phpdocumentor
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
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')
-rw-r--r--vendor/phpdocumentor/reflection-common/.github/dependabot.yml7
-rw-r--r--vendor/phpdocumentor/reflection-common/.github/workflows/push.yml223
-rw-r--r--vendor/phpdocumentor/reflection-common/LICENSE22
-rw-r--r--vendor/phpdocumentor/reflection-common/README.md11
-rw-r--r--vendor/phpdocumentor/reflection-common/composer.json28
-rw-r--r--vendor/phpdocumentor/reflection-common/src/Element.php30
-rw-r--r--vendor/phpdocumentor/reflection-common/src/File.php35
-rw-r--r--vendor/phpdocumentor/reflection-common/src/Fqsen.php89
-rw-r--r--vendor/phpdocumentor/reflection-common/src/Location.php53
-rw-r--r--vendor/phpdocumentor/reflection-common/src/Project.php25
-rw-r--r--vendor/phpdocumentor/reflection-common/src/ProjectFactory.php28
-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
-rw-r--r--vendor/phpdocumentor/type-resolver/LICENSE21
-rw-r--r--vendor/phpdocumentor/type-resolver/README.md177
-rw-r--r--vendor/phpdocumentor/type-resolver/composer.json35
-rw-r--r--vendor/phpdocumentor/type-resolver/src/FqsenResolver.php80
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoType.php19
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/False_.php40
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php61
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/List_.php50
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php47
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/PseudoTypes/True_.php40
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Type.php25
-rw-r--r--vendor/phpdocumentor/type-resolver/src/TypeResolver.php700
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/AbstractList.php83
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php125
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/ArrayKey.php42
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Array_.php29
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Boolean.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Callable_.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/ClassString.php62
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Collection.php68
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Compound.php38
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Context.php95
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/ContextFactory.php420
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Expression.php51
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Float_.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Integer.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/InterfaceString.php56
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Intersection.php37
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Iterable_.php38
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Mixed_.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Never_.php35
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Null_.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Nullable.php51
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Object_.php69
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Parent_.php34
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Resource_.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Scalar.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Self_.php34
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Static_.php39
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/String_.php32
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/This.php35
-rw-r--r--vendor/phpdocumentor/type-resolver/src/Types/Void_.php35
107 files changed, 8619 insertions, 0 deletions
diff --git a/vendor/phpdocumentor/reflection-common/.github/dependabot.yml b/vendor/phpdocumentor/reflection-common/.github/dependabot.yml
new file mode 100644
index 000000000..c630ffa6b
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/.github/dependabot.yml
@@ -0,0 +1,7 @@
+version: 2
+updates:
+- package-ecosystem: composer
+ directory: "/"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
diff --git a/vendor/phpdocumentor/reflection-common/.github/workflows/push.yml b/vendor/phpdocumentor/reflection-common/.github/workflows/push.yml
new file mode 100644
index 000000000..484410e9a
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/.github/workflows/push.yml
@@ -0,0 +1,223 @@
+on:
+ push:
+ branches:
+ - 2.x
+ pull_request:
+name: Qa workflow
+jobs:
+ setup:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Restore/cache vendor folder
+ uses: actions/cache@v1
+ with:
+ path: vendor
+ key: all-build-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ all-build-${{ hashFiles('**/composer.lock') }}
+ all-build-
+
+ - name: Restore/cache tools folder
+ uses: actions/cache@v1
+ with:
+ path: tools
+ key: all-tools-${{ github.sha }}
+ restore-keys: |
+ all-tools-${{ github.sha }}-
+ all-tools-
+
+ - name: composer
+ uses: docker://composer
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ args: install --no-interaction --prefer-dist --optimize-autoloader
+
+ - name: Install phive
+ run: make install-phive
+
+ - name: Install PHAR dependencies
+ run: tools/phive.phar --no-progress install --copy --trust-gpg-keys 4AA394086372C20A,8A03EA3B385DBAA1 --force-accept-unsigned
+
+ phpunit-with-coverage:
+ runs-on: ubuntu-latest
+ name: Unit tests
+ needs: setup
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.2
+ ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
+ coverage: pcov
+
+ - name: Restore/cache tools folder
+ uses: actions/cache@v1
+ with:
+ path: tools
+ key: all-tools-${{ github.sha }}
+ restore-keys: |
+ all-tools-${{ github.sha }}-
+ all-tools-
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v1
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ubuntu-latest-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ubuntu-latest-composer-
+
+ - name: Install Composer dependencies
+ run: |
+ composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
+
+ - name: Run PHPUnit
+ run: php tools/phpunit
+
+ phpunit:
+ runs-on: ${{ matrix.operating-system }}
+ strategy:
+ matrix:
+ operating-system:
+ - ubuntu-latest
+ - windows-latest
+ - macOS-latest
+ php-versions: ['7.2', '7.3', '7.4', '8.0']
+ name: Unit tests for PHP version ${{ matrix.php-versions }} on ${{ matrix.operating-system }}
+ needs:
+ - setup
+ - phpunit-with-coverage
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Restore/cache tools folder
+ uses: actions/cache@v1
+ with:
+ path: tools
+ key: all-tools-${{ github.sha }}
+ restore-keys: |
+ all-tools-${{ github.sha }}-
+ all-tools-
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-versions }}
+ ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
+ coverage: none
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v1
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install Composer dependencies
+ run: |
+ composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
+
+ - name: Run PHPUnit
+ continue-on-error: true
+ run: php tools/phpunit
+
+ codestyle:
+ runs-on: ubuntu-latest
+ needs: [setup, phpunit]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Restore/cache vendor folder
+ uses: actions/cache@v1
+ with:
+ path: vendor
+ key: all-build-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ all-build-${{ hashFiles('**/composer.lock') }}
+ all-build-
+ - name: Code style check
+ uses: phpDocumentor/coding-standard@latest
+ with:
+ args: -s
+
+ phpstan:
+ runs-on: ubuntu-latest
+ needs: [setup, phpunit]
+ steps:
+ - uses: actions/checkout@v2
+ - name: Restore/cache vendor folder
+ uses: actions/cache@v1
+ with:
+ path: vendor
+ key: all-build-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ all-build-${{ hashFiles('**/composer.lock') }}
+ all-build-
+ - name: PHPStan
+ uses: phpDocumentor/phpstan-ga@latest
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ args: analyse src --configuration phpstan.neon
+
+ psalm:
+ runs-on: ubuntu-latest
+ needs: [setup, phpunit]
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: 7.2
+ ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
+ tools: psalm
+ coverage: none
+
+ - name: Get composer cache directory
+ id: composer-cache
+ run: echo "::set-output name=dir::$(composer config cache-files-dir)"
+
+ - name: Cache composer dependencies
+ uses: actions/cache@v1
+ with:
+ path: ${{ steps.composer-cache.outputs.dir }}
+ key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
+ restore-keys: ${{ runner.os }}-composer-
+
+ - name: Install Composer dependencies
+ run: |
+ composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
+
+ - name: Psalm
+ run: psalm --output-format=github
+
+ bc_check:
+ name: BC Check
+ runs-on: ubuntu-latest
+ needs: [setup, phpunit]
+ steps:
+ - uses: actions/checkout@v2
+ - name: fetch tags
+ run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
+ - name: Restore/cache vendor folder
+ uses: actions/cache@v1
+ with:
+ path: vendor
+ key: all-build-${{ hashFiles('**/composer.lock') }}
+ restore-keys: |
+ all-build-${{ hashFiles('**/composer.lock') }}
+ all-build-
+ - name: Roave BC Check
+ uses: docker://nyholm/roave-bc-check-ga
diff --git a/vendor/phpdocumentor/reflection-common/LICENSE b/vendor/phpdocumentor/reflection-common/LICENSE
new file mode 100644
index 000000000..ed6926c1e
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 phpDocumentor
+
+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-common/README.md b/vendor/phpdocumentor/reflection-common/README.md
new file mode 100644
index 000000000..70f830dc7
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/README.md
@@ -0,0 +1,11 @@
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+![Qa workflow](https://github.com/phpDocumentor/ReflectionCommon/workflows/Qa%20workflow/badge.svg)
+[![Coveralls Coverage](https://img.shields.io/coveralls/github/phpDocumentor/ReflectionCommon.svg)](https://coveralls.io/github/phpDocumentor/ReflectionCommon?branch=master)
+[![Scrutinizer Code Coverage](https://img.shields.io/scrutinizer/coverage/g/phpDocumentor/ReflectionCommon.svg)](https://scrutinizer-ci.com/g/phpDocumentor/ReflectionCommon/?branch=master)
+[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/phpDocumentor/ReflectionCommon.svg)](https://scrutinizer-ci.com/g/phpDocumentor/ReflectionCommon/?branch=master)
+[![Stable Version](https://img.shields.io/packagist/v/phpDocumentor/Reflection-Common.svg)](https://packagist.org/packages/phpDocumentor/Reflection-Common)
+[![Unstable Version](https://img.shields.io/packagist/vpre/phpDocumentor/Reflection-Common.svg)](https://packagist.org/packages/phpDocumentor/Reflection-Common)
+
+
+ReflectionCommon
+================
diff --git a/vendor/phpdocumentor/reflection-common/composer.json b/vendor/phpdocumentor/reflection-common/composer.json
new file mode 100644
index 000000000..4d128b49a
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/composer.json
@@ -0,0 +1,28 @@
+{
+ "name": "phpdocumentor/reflection-common",
+ "keywords": ["phpdoc", "phpDocumentor", "reflection", "static analysis", "FQSEN"],
+ "homepage": "http://www.phpdoc.org",
+ "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Jaap van Otterdijk",
+ "email": "[email protected]"
+ }
+ ],
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "autoload" : {
+ "psr-4" : {
+ "phpDocumentor\\Reflection\\": "src/"
+ }
+ },
+ "require-dev": {
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-2.x": "2.x-dev"
+ }
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-common/src/Element.php b/vendor/phpdocumentor/reflection-common/src/Element.php
new file mode 100644
index 000000000..8923e4fb0
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/src/Element.php
@@ -0,0 +1,30 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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;
+
+/**
+ * Interface for Api Elements
+ */
+interface Element
+{
+ /**
+ * Returns the Fqsen of the element.
+ */
+ public function getFqsen() : Fqsen;
+
+ /**
+ * Returns the name of the element.
+ */
+ public function getName() : string;
+}
diff --git a/vendor/phpdocumentor/reflection-common/src/File.php b/vendor/phpdocumentor/reflection-common/src/File.php
new file mode 100644
index 000000000..239c137e7
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/src/File.php
@@ -0,0 +1,35 @@
+<?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;
+
+/**
+ * Interface for files processed by the ProjectFactory
+ */
+interface File
+{
+ /**
+ * Returns the content of the file as a string.
+ */
+ public function getContents() : string;
+
+ /**
+ * Returns md5 hash of the file.
+ */
+ public function md5() : string;
+
+ /**
+ * Returns an relative path to the file.
+ */
+ public function path() : string;
+}
diff --git a/vendor/phpdocumentor/reflection-common/src/Fqsen.php b/vendor/phpdocumentor/reflection-common/src/Fqsen.php
new file mode 100644
index 000000000..8fc5d3441
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/src/Fqsen.php
@@ -0,0 +1,89 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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 function assert;
+use function end;
+use function explode;
+use function is_string;
+use function preg_match;
+use function sprintf;
+use function trim;
+
+/**
+ * Value Object for Fqsen.
+ *
+ * @link https://github.com/phpDocumentor/fig-standards/blob/master/proposed/phpdoc-meta.md
+ *
+ * @psalm-immutable
+ */
+final class Fqsen
+{
+ /** @var string full quallified class name */
+ private $fqsen;
+
+ /** @var string name of the element without path. */
+ private $name;
+
+ /**
+ * Initializes the object.
+ *
+ * @throws InvalidArgumentException when $fqsen is not matching the format.
+ */
+ public function __construct(string $fqsen)
+ {
+ $matches = [];
+
+ $result = preg_match(
+ //phpcs:ignore Generic.Files.LineLength.TooLong
+ '/^\\\\([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff\\\\]*)?(?:[:]{2}\\$?([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*))?(?:\\(\\))?$/',
+ $fqsen,
+ $matches
+ );
+
+ if ($result === 0) {
+ throw new InvalidArgumentException(
+ sprintf('"%s" is not a valid Fqsen.', $fqsen)
+ );
+ }
+
+ $this->fqsen = $fqsen;
+
+ if (isset($matches[2])) {
+ $this->name = $matches[2];
+ } else {
+ $matches = explode('\\', $fqsen);
+ $name = end($matches);
+ assert(is_string($name));
+ $this->name = trim($name, '()');
+ }
+ }
+
+ /**
+ * converts this class to string.
+ */
+ public function __toString() : string
+ {
+ return $this->fqsen;
+ }
+
+ /**
+ * Returns the name of the element without path.
+ */
+ public function getName() : string
+ {
+ return $this->name;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-common/src/Location.php b/vendor/phpdocumentor/reflection-common/src/Location.php
new file mode 100644
index 000000000..177deede6
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/src/Location.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;
+
+/**
+ * The location where an element occurs within a file.
+ *
+ * @psalm-immutable
+ */
+final class Location
+{
+ /** @var int */
+ private $lineNumber = 0;
+
+ /** @var int */
+ private $columnNumber = 0;
+
+ /**
+ * Initializes the location for an element using its line number in the file and optionally the column number.
+ */
+ public function __construct(int $lineNumber, int $columnNumber = 0)
+ {
+ $this->lineNumber = $lineNumber;
+ $this->columnNumber = $columnNumber;
+ }
+
+ /**
+ * Returns the line number that is covered by this location.
+ */
+ public function getLineNumber() : int
+ {
+ return $this->lineNumber;
+ }
+
+ /**
+ * Returns the column number (character position on a line) for this location object.
+ */
+ public function getColumnNumber() : int
+ {
+ return $this->columnNumber;
+ }
+}
diff --git a/vendor/phpdocumentor/reflection-common/src/Project.php b/vendor/phpdocumentor/reflection-common/src/Project.php
new file mode 100644
index 000000000..57839fd14
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/src/Project.php
@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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;
+
+/**
+ * Interface for project. Since the definition of a project can be different per factory this interface will be small.
+ */
+interface Project
+{
+ /**
+ * Returns the name of the project.
+ */
+ public function getName() : string;
+}
diff --git a/vendor/phpdocumentor/reflection-common/src/ProjectFactory.php b/vendor/phpdocumentor/reflection-common/src/ProjectFactory.php
new file mode 100644
index 000000000..8bdc60678
--- /dev/null
+++ b/vendor/phpdocumentor/reflection-common/src/ProjectFactory.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * 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;
+
+/**
+ * Interface for project factories. A project factory shall convert a set of files
+ * into an object implementing the Project interface.
+ */
+interface ProjectFactory
+{
+ /**
+ * Creates a project from the set of files.
+ *
+ * @param File[] $files
+ */
+ public function create(string $name, array $files) : Project;
+}
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;
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/LICENSE b/vendor/phpdocumentor/type-resolver/LICENSE
new file mode 100644
index 000000000..792e4040f
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/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/type-resolver/README.md b/vendor/phpdocumentor/type-resolver/README.md
new file mode 100644
index 000000000..f30d3a24e
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/README.md
@@ -0,0 +1,177 @@
+[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
+![](https://github.com/phpdocumentor/typeresolver/workflows/Qa%20workflow/badge.svg?branch=1.x)
+[![Coveralls Coverage](https://img.shields.io/coveralls/github/phpDocumentor/TypeResolver.svg)](https://coveralls.io/github/phpDocumentor/TypeResolver?branch=1.x)
+[![Scrutinizer Code Coverage](https://img.shields.io/scrutinizer/coverage/g/phpDocumentor/TypeResolver.svg)](https://scrutinizer-ci.com/g/phpDocumentor/TypeResolver/?branch=1.x)
+[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/phpDocumentor/TypeResolver.svg)](https://scrutinizer-ci.com/g/phpDocumentor/TypeResolver/?branch=1.x)
+![Packagist Version](https://img.shields.io/packagist/v/phpdocumentor/type-resolver?label=Packagist%20stable)
+![Packagist Version](https://img.shields.io/packagist/vpre/phpdocumentor/type-resolver?label=Packagist%20unstable)
+
+TypeResolver and FqsenResolver
+==============================
+
+The specification on types in DocBlocks (PSR-5) describes various keywords and special constructs
+but also how to statically resolve the partial name of a Class into a Fully Qualified Class Name (FQCN).
+
+PSR-5 also introduces an additional way to describe deeper elements than Classes, Interfaces and Traits
+called the Fully Qualified Structural Element Name (FQSEN). Using this it is possible to refer to methods,
+properties and class constants but also functions and global constants.
+
+This package provides two Resolvers that are capable of
+
+1. Returning a series of Value Object for given expression while resolving any partial class names, and
+2. Returning an FQSEN object after resolving any partial Structural Element Names into Fully Qualified Structural
+ Element names.
+
+## Installing
+
+The easiest way to install this library is with [Composer](https://getcomposer.org) using the following command:
+
+ $ composer require phpdocumentor/type-resolver
+
+## Examples
+
+Ready to dive in and don't want to read through all that text below? Just consult the [examples](examples) folder and check which type of action that your want to accomplish.
+
+## On Types and Element Names
+
+This component can be used in one of two ways
+
+1. To resolve a Type or
+2. To resolve a Fully Qualified Structural Element Name
+
+The big difference between these two is in the number of things it can resolve.
+
+The TypeResolver can resolve:
+
+- a php primitive or pseudo-primitive such as a string or void (`@var string` or `@return void`).
+- a composite such as an array of string (`@var string[]`).
+- a compound such as a string or integer (`@var string|integer`).
+- an array expression (`@var (string|TypeResolver)[]`)
+- an object or interface such as the TypeResolver class (`@var TypeResolver`
+ or `@var \phpDocumentor\Reflection\TypeResolver`)
+
+ > please note that if you want to pass partial class names that additional steps are necessary, see the
+ > chapter `Resolving partial classes and FQSENs` for more information.
+
+Where the FqsenResolver can resolve:
+
+- Constant expressions (i.e. `@see \MyNamespace\MY_CONSTANT`)
+- Function expressions (i.e. `@see \MyNamespace\myFunction()`)
+- Class expressions (i.e. `@see \MyNamespace\MyClass`)
+- Interface expressions (i.e. `@see \MyNamespace\MyInterface`)
+- Trait expressions (i.e. `@see \MyNamespace\MyTrait`)
+- Class constant expressions (i.e. `@see \MyNamespace\MyClass::MY_CONSTANT`)
+- Property expressions (i.e. `@see \MyNamespace\MyClass::$myProperty`)
+- Method expressions (i.e. `@see \MyNamespace\MyClass::myMethod()`)
+
+## Resolving a type
+
+In order to resolve a type you will have to instantiate the class `\phpDocumentor\Reflection\TypeResolver` and call its `resolve` method like this:
+
+```php
+$typeResolver = new \phpDocumentor\Reflection\TypeResolver();
+$type = $typeResolver->resolve('string|integer');
+```
+
+In this example you will receive a Value Object of class `\phpDocumentor\Reflection\Types\Compound` that has two
+elements, one of type `\phpDocumentor\Reflection\Types\String_` and one of type
+`\phpDocumentor\Reflection\Types\Integer`.
+
+The real power of this resolver is in its capability to expand partial class names into fully qualified class names; but in order to do that we need an additional `\phpDocumentor\Reflection\Types\Context` class that will inform the resolver in which namespace the given expression occurs and which namespace aliases (or imports) apply.
+
+### Resolving nullable types
+
+Php 7.1 introduced nullable types e.g. `?string`. Type resolver will resolve the original type without the nullable notation `?`
+just like it would do without the `?`. After that the type is wrapped in a `\phpDocumentor\Reflection\Types\Nullable` object.
+The `Nullable` type has a method to fetch the actual type.
+
+## Resolving an FQSEN
+
+A Fully Qualified Structural Element Name is a reference to another element in your code bases and can be resolved using the `\phpDocumentor\Reflection\FqsenResolver` class' `resolve` method, like this:
+
+```php
+$fqsenResolver = new \phpDocumentor\Reflection\FqsenResolver();
+$fqsen = $fqsenResolver->resolve('\phpDocumentor\Reflection\FqsenResolver::resolve()');
+```
+
+In this example we resolve a Fully Qualified Structural Element Name (meaning that it includes the full namespace, class name and element name) and receive a Value Object of type `\phpDocumentor\Reflection\Fqsen`.
+
+The real power of this resolver is in its capability to expand partial element names into Fully Qualified Structural Element Names; but in order to do that we need an additional `\phpDocumentor\Reflection\Types\Context` class that will inform the resolver in which namespace the given expression occurs and which namespace aliases (or imports) apply.
+
+## Resolving partial Classes and Structural Element Names
+
+Perhaps the best feature of this library is that it knows how to resolve partial class names into fully qualified class names.
+
+For example, you have this file:
+
+```php
+namespace My\Example;
+
+use phpDocumentor\Reflection\Types;
+
+class Classy
+{
+ /**
+ * @var Types\Context
+ * @see Classy::otherFunction()
+ */
+ public function __construct($context) {}
+
+ public function otherFunction(){}
+}
+```
+
+Suppose that you would want to resolve (and expand) the type in the `@var` tag and the element name in the `@see` tag.
+
+For the resolvers to know how to expand partial names you have to provide a bit of _Context_ for them by instantiating a new class named `\phpDocumentor\Reflection\Types\Context` with the name of the namespace and the aliases that are in play.
+
+### Creating a Context
+
+You can do this by manually creating a Context like this:
+
+```php
+$context = new \phpDocumentor\Reflection\Types\Context(
+ '\My\Example',
+ [ 'Types' => '\phpDocumentor\Reflection\Types']
+);
+```
+
+Or by using the `\phpDocumentor\Reflection\Types\ContextFactory` to instantiate a new context based on a Reflector object or by providing the namespace that you'd like to extract and the source code of the file in which the given type expression occurs.
+
+```php
+$contextFactory = new \phpDocumentor\Reflection\Types\ContextFactory();
+$context = $contextFactory->createFromReflector(new ReflectionMethod('\My\Example\Classy', '__construct'));
+```
+
+or
+
+```php
+$contextFactory = new \phpDocumentor\Reflection\Types\ContextFactory();
+$context = $contextFactory->createForNamespace('\My\Example', file_get_contents('My/Example/Classy.php'));
+```
+
+### Using the Context
+
+After you have obtained a Context it is just a matter of passing it along with the `resolve` method of either Resolver class as second argument and the Resolvers will take this into account when resolving partial names.
+
+To obtain the resolved class name for the `@var` tag in the example above you can do:
+
+```php
+$typeResolver = new \phpDocumentor\Reflection\TypeResolver();
+$type = $typeResolver->resolve('Types\Context', $context);
+```
+
+When you do this you will receive an object of class `\phpDocumentor\Reflection\Types\Object_` for which you can call the `getFqsen` method to receive a Value Object that represents the complete FQSEN. So that would be `phpDocumentor\Reflection\Types\Context`.
+
+> Why is the FQSEN wrapped in another object `Object_`?
+>
+> The resolve method of the TypeResolver only returns object with the interface `Type` and the FQSEN is a common type that does not represent a Type. Also: in some cases a type can represent an "Untyped Object", meaning that it is an object (signified by the `object` keyword) but does not refer to a specific element using an FQSEN.
+
+Another example is on how to resolve the FQSEN of a method as can be seen with the `@see` tag in the example above. To resolve that you can do the following:
+
+```php
+$fqsenResolver = new \phpDocumentor\Reflection\FqsenResolver();
+$type = $fqsenResolver->resolve('Classy::otherFunction()', $context);
+```
+
+Because Classy is a Class in the current namespace its FQSEN will have the `My\Example` namespace and by calling the `resolve` method of the FQSEN Resolver you will receive an `Fqsen` object that refers to `\My\Example\Classy::otherFunction()`.
diff --git a/vendor/phpdocumentor/type-resolver/composer.json b/vendor/phpdocumentor/type-resolver/composer.json
new file mode 100644
index 000000000..4dbf6237e
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "phpdocumentor/type-resolver",
+ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "[email protected]"
+ }
+ ],
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "phpdocumentor/reflection-common": "^2.0"
+ },
+ "require-dev": {
+ "ext-tokenizer": "*",
+ "psalm/phar": "^4.8"
+ },
+ "autoload": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": "src"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "phpDocumentor\\Reflection\\": ["tests/unit", "tests/benchmark"]
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-1.x": "1.x-dev"
+ }
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/FqsenResolver.php b/vendor/phpdocumentor/type-resolver/src/FqsenResolver.php
new file mode 100644
index 000000000..068fa2085
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/FqsenResolver.php
@@ -0,0 +1,80 @@
+<?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 phpDocumentor\Reflection\Types\Context;
+
+use function explode;
+use function implode;
+use function strpos;
+
+/**
+ * Resolver for Fqsen using Context information
+ *
+ * @psalm-immutable
+ */
+class FqsenResolver
+{
+ /** @var string Definition of the NAMESPACE operator in PHP */
+ private const OPERATOR_NAMESPACE = '\\';
+
+ public function resolve(string $fqsen, ?Context $context = null): Fqsen
+ {
+ if ($context === null) {
+ $context = new Context('');
+ }
+
+ if ($this->isFqsen($fqsen)) {
+ return new Fqsen($fqsen);
+ }
+
+ return $this->resolvePartialStructuralElementName($fqsen, $context);
+ }
+
+ /**
+ * Tests whether the given type is a Fully Qualified Structural Element Name.
+ */
+ private function isFqsen(string $type): bool
+ {
+ return strpos($type, self::OPERATOR_NAMESPACE) === 0;
+ }
+
+ /**
+ * Resolves a partial Structural Element Name (i.e. `Reflection\DocBlock`) to its FQSEN representation
+ * (i.e. `\phpDocumentor\Reflection\DocBlock`) based on the Namespace and aliases mentioned in the Context.
+ *
+ * @throws InvalidArgumentException When type is not a valid FQSEN.
+ */
+ private function resolvePartialStructuralElementName(string $type, Context $context): Fqsen
+ {
+ $typeParts = explode(self::OPERATOR_NAMESPACE, $type, 2);
+
+ $namespaceAliases = $context->getNamespaceAliases();
+
+ // if the first segment is not an alias; prepend namespace name and return
+ if (!isset($namespaceAliases[$typeParts[0]])) {
+ $namespace = $context->getNamespace();
+ if ($namespace !== '') {
+ $namespace .= self::OPERATOR_NAMESPACE;
+ }
+
+ return new Fqsen(self::OPERATOR_NAMESPACE . $namespace . $type);
+ }
+
+ $typeParts[0] = $namespaceAliases[$typeParts[0]];
+
+ return new Fqsen(self::OPERATOR_NAMESPACE . implode(self::OPERATOR_NAMESPACE, $typeParts));
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoType.php b/vendor/phpdocumentor/type-resolver/src/PseudoType.php
new file mode 100644
index 000000000..dd91ed798
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoType.php
@@ -0,0 +1,19 @@
+<?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;
+
+interface PseudoType extends Type
+{
+ public function underlyingType(): Type;
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php
new file mode 100644
index 000000000..b69345617
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/CallableString.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\String_;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class CallableString extends String_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'callable-string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/False_.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/False_.php
new file mode 100644
index 000000000..4ec6885f6
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/False_.php
@@ -0,0 +1,40 @@
+<?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 https://phpdoc.org
+ */
+
+namespace phpDocumentor\Reflection\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\Boolean;
+
+use function class_alias;
+
+/**
+ * Value Object representing the PseudoType 'False', which is a Boolean type.
+ *
+ * @psalm-immutable
+ */
+final class False_ extends Boolean implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new Boolean();
+ }
+
+ public function __toString(): string
+ {
+ return 'false';
+ }
+}
+
+class_alias('\phpDocumentor\Reflection\PseudoTypes\False_', 'phpDocumentor\Reflection\Types\False_', false);
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php
new file mode 100644
index 000000000..aa4d8db56
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/HtmlEscapedString.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\String_;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class HtmlEscapedString extends String_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'html-escaped-string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php
new file mode 100644
index 000000000..c5a3bc535
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/IntegerRange.php
@@ -0,0 +1,61 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\Integer;
+
+/**
+ * Value Object representing the type 'int'.
+ *
+ * @psalm-immutable
+ */
+final class IntegerRange extends Integer implements PseudoType
+{
+ /** @var string */
+ private $minValue;
+
+ /** @var string */
+ private $maxValue;
+
+ public function __construct(string $minValue, string $maxValue)
+ {
+ $this->minValue = $minValue;
+ $this->maxValue = $maxValue;
+ }
+
+ public function underlyingType(): Type
+ {
+ return new Integer();
+ }
+
+ public function getMinValue(): string
+ {
+ return $this->minValue;
+ }
+
+ public function getMaxValue(): string
+ {
+ return $this->maxValue;
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'int<' . $this->minValue . ', ' . $this->maxValue . '>';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/List_.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/List_.php
new file mode 100644
index 000000000..f9f0c6b5c
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/List_.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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\Array_;
+use phpDocumentor\Reflection\Types\Integer;
+use phpDocumentor\Reflection\Types\Mixed_;
+
+/**
+ * Value Object representing the type 'list'.
+ *
+ * @psalm-immutable
+ */
+final class List_ extends Array_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new Array_();
+ }
+
+ public function __construct(?Type $valueType = null)
+ {
+ parent::__construct($valueType, new Integer());
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ if ($this->valueType instanceof Mixed_) {
+ return 'list';
+ }
+
+ return 'list<' . $this->valueType . '>';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php
new file mode 100644
index 000000000..690f782b7
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/LiteralString.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\String_;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class LiteralString extends String_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'literal-string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php
new file mode 100644
index 000000000..6325492ad
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/LowercaseString.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\String_;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class LowercaseString extends String_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'lowercase-string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php
new file mode 100644
index 000000000..c51d3feab
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NegativeInteger.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\Integer;
+
+/**
+ * Value Object representing the type 'int'.
+ *
+ * @psalm-immutable
+ */
+final class NegativeInteger extends Integer implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new Integer();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'negative-int';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php
new file mode 100644
index 000000000..86400165a
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyLowercaseString.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\String_;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class NonEmptyLowercaseString extends String_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'non-empty-lowercase-string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php
new file mode 100644
index 000000000..d72d127cf
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NonEmptyString.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\String_;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class NonEmptyString extends String_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'non-empty-string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php
new file mode 100644
index 000000000..b62aa45a5
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/NumericString.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\String_;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class NumericString extends String_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'numeric-string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php
new file mode 100644
index 000000000..46620cd21
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/Numeric_.php
@@ -0,0 +1,47 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\AggregatedType;
+use phpDocumentor\Reflection\Types\Compound;
+use phpDocumentor\Reflection\Types\Float_;
+use phpDocumentor\Reflection\Types\Integer;
+
+/**
+ * Value Object representing the 'numeric' pseudo-type, which is either a numeric-string, integer or float.
+ *
+ * @psalm-immutable
+ */
+final class Numeric_ extends AggregatedType implements PseudoType
+{
+ public function __construct()
+ {
+ AggregatedType::__construct([new NumericString(), new Integer(), new Float_()], '|');
+ }
+
+ public function underlyingType(): Type
+ {
+ return new Compound([new NumericString(), new Integer(), new Float_()]);
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'numeric';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php
new file mode 100644
index 000000000..c52184dc5
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/PositiveInteger.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\Integer;
+
+/**
+ * Value Object representing the type 'int'.
+ *
+ * @psalm-immutable
+ */
+final class PositiveInteger extends Integer implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new Integer();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'positive-int';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php
new file mode 100644
index 000000000..ac217c25d
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/TraitString.php
@@ -0,0 +1,39 @@
+<?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\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\String_;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class TraitString extends String_ implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'trait-string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/PseudoTypes/True_.php b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/True_.php
new file mode 100644
index 000000000..dc970b3aa
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/PseudoTypes/True_.php
@@ -0,0 +1,40 @@
+<?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 https://phpdoc.org
+ */
+
+namespace phpDocumentor\Reflection\PseudoTypes;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+use phpDocumentor\Reflection\Types\Boolean;
+
+use function class_alias;
+
+/**
+ * Value Object representing the PseudoType 'False', which is a Boolean type.
+ *
+ * @psalm-immutable
+ */
+final class True_ extends Boolean implements PseudoType
+{
+ public function underlyingType(): Type
+ {
+ return new Boolean();
+ }
+
+ public function __toString(): string
+ {
+ return 'true';
+ }
+}
+
+class_alias('\phpDocumentor\Reflection\PseudoTypes\True_', 'phpDocumentor\Reflection\Types\True_', false);
diff --git a/vendor/phpdocumentor/type-resolver/src/Type.php b/vendor/phpdocumentor/type-resolver/src/Type.php
new file mode 100644
index 000000000..c71d8b08b
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Type.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;
+
+/**
+ * @psalm-immutable
+ */
+interface Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string;
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/TypeResolver.php b/vendor/phpdocumentor/type-resolver/src/TypeResolver.php
new file mode 100644
index 000000000..0c9a73cb3
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/TypeResolver.php
@@ -0,0 +1,700 @@
+<?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 ArrayIterator;
+use InvalidArgumentException;
+use phpDocumentor\Reflection\PseudoTypes\IntegerRange;
+use phpDocumentor\Reflection\PseudoTypes\List_;
+use phpDocumentor\Reflection\Types\Array_;
+use phpDocumentor\Reflection\Types\ArrayKey;
+use phpDocumentor\Reflection\Types\ClassString;
+use phpDocumentor\Reflection\Types\Collection;
+use phpDocumentor\Reflection\Types\Compound;
+use phpDocumentor\Reflection\Types\Context;
+use phpDocumentor\Reflection\Types\Expression;
+use phpDocumentor\Reflection\Types\Integer;
+use phpDocumentor\Reflection\Types\InterfaceString;
+use phpDocumentor\Reflection\Types\Intersection;
+use phpDocumentor\Reflection\Types\Iterable_;
+use phpDocumentor\Reflection\Types\Nullable;
+use phpDocumentor\Reflection\Types\Object_;
+use phpDocumentor\Reflection\Types\String_;
+use RuntimeException;
+
+use function array_key_exists;
+use function array_pop;
+use function array_values;
+use function class_exists;
+use function class_implements;
+use function count;
+use function current;
+use function end;
+use function in_array;
+use function is_numeric;
+use function key;
+use function preg_split;
+use function strpos;
+use function strtolower;
+use function trim;
+
+use const PREG_SPLIT_DELIM_CAPTURE;
+use const PREG_SPLIT_NO_EMPTY;
+
+final class TypeResolver
+{
+ /** @var string Definition of the ARRAY operator for types */
+ private const OPERATOR_ARRAY = '[]';
+
+ /** @var string Definition of the NAMESPACE operator in PHP */
+ private const OPERATOR_NAMESPACE = '\\';
+
+ /** @var int the iterator parser is inside a compound context */
+ private const PARSER_IN_COMPOUND = 0;
+
+ /** @var int the iterator parser is inside a nullable expression context */
+ private const PARSER_IN_NULLABLE = 1;
+
+ /** @var int the iterator parser is inside an array expression context */
+ private const PARSER_IN_ARRAY_EXPRESSION = 2;
+
+ /** @var int the iterator parser is inside a collection expression context */
+ private const PARSER_IN_COLLECTION_EXPRESSION = 3;
+
+ /**
+ * @var array<string, string> List of recognized keywords and unto which Value Object they map
+ * @psalm-var array<string, class-string<Type>>
+ */
+ private $keywords = [
+ 'string' => Types\String_::class,
+ 'class-string' => Types\ClassString::class,
+ 'interface-string' => Types\InterfaceString::class,
+ 'html-escaped-string' => PseudoTypes\HtmlEscapedString::class,
+ 'lowercase-string' => PseudoTypes\LowercaseString::class,
+ 'non-empty-lowercase-string' => PseudoTypes\NonEmptyLowercaseString::class,
+ 'non-empty-string' => PseudoTypes\NonEmptyString::class,
+ 'numeric-string' => PseudoTypes\NumericString::class,
+ 'numeric' => PseudoTypes\Numeric_::class,
+ 'trait-string' => PseudoTypes\TraitString::class,
+ 'int' => Types\Integer::class,
+ 'integer' => Types\Integer::class,
+ 'positive-int' => PseudoTypes\PositiveInteger::class,
+ 'negative-int' => PseudoTypes\NegativeInteger::class,
+ 'bool' => Types\Boolean::class,
+ 'boolean' => Types\Boolean::class,
+ 'real' => Types\Float_::class,
+ 'float' => Types\Float_::class,
+ 'double' => Types\Float_::class,
+ 'object' => Types\Object_::class,
+ 'mixed' => Types\Mixed_::class,
+ 'array' => Types\Array_::class,
+ 'array-key' => Types\ArrayKey::class,
+ 'resource' => Types\Resource_::class,
+ 'void' => Types\Void_::class,
+ 'null' => Types\Null_::class,
+ 'scalar' => Types\Scalar::class,
+ 'callback' => Types\Callable_::class,
+ 'callable' => Types\Callable_::class,
+ 'callable-string' => PseudoTypes\CallableString::class,
+ 'false' => PseudoTypes\False_::class,
+ 'true' => PseudoTypes\True_::class,
+ 'literal-string' => PseudoTypes\LiteralString::class,
+ 'self' => Types\Self_::class,
+ '$this' => Types\This::class,
+ 'static' => Types\Static_::class,
+ 'parent' => Types\Parent_::class,
+ 'iterable' => Types\Iterable_::class,
+ 'never' => Types\Never_::class,
+ 'list' => PseudoTypes\List_::class,
+ ];
+
+ /**
+ * @var FqsenResolver
+ * @psalm-readonly
+ */
+ private $fqsenResolver;
+
+ /**
+ * Initializes this TypeResolver with the means to create and resolve Fqsen objects.
+ */
+ public function __construct(?FqsenResolver $fqsenResolver = null)
+ {
+ $this->fqsenResolver = $fqsenResolver ?: new FqsenResolver();
+ }
+
+ /**
+ * Analyzes the given type and returns the FQCN variant.
+ *
+ * When a type is provided this method checks whether it is not a keyword or
+ * Fully Qualified Class Name. If so it will use the given namespace and
+ * aliases to expand the type to a FQCN representation.
+ *
+ * This method only works as expected if the namespace and aliases are set;
+ * no dynamic reflection is being performed here.
+ *
+ * @uses Context::getNamespaceAliases() to check whether the first part of the relative type name should not be
+ * replaced with another namespace.
+ * @uses Context::getNamespace() to determine with what to prefix the type name.
+ *
+ * @param string $type The relative or absolute type.
+ */
+ public function resolve(string $type, ?Context $context = null): Type
+ {
+ $type = trim($type);
+ if (!$type) {
+ throw new InvalidArgumentException('Attempted to resolve "' . $type . '" but it appears to be empty');
+ }
+
+ if ($context === null) {
+ $context = new Context('');
+ }
+
+ // split the type string into tokens `|`, `?`, `<`, `>`, `,`, `(`, `)`, `[]`, '<', '>' and type names
+ $tokens = preg_split(
+ '/(\\||\\?|<|>|&|, ?|\\(|\\)|\\[\\]+)/',
+ $type,
+ -1,
+ PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
+ );
+
+ if ($tokens === false) {
+ throw new InvalidArgumentException('Unable to split the type string "' . $type . '" into tokens');
+ }
+
+ /** @var ArrayIterator<int, string|null> $tokenIterator */
+ $tokenIterator = new ArrayIterator($tokens);
+
+ return $this->parseTypes($tokenIterator, $context, self::PARSER_IN_COMPOUND);
+ }
+
+ /**
+ * Analyse each tokens and creates types
+ *
+ * @param ArrayIterator<int, string|null> $tokens the iterator on tokens
+ * @param int $parserContext on of self::PARSER_* constants, indicating
+ * the context where we are in the parsing
+ */
+ private function parseTypes(ArrayIterator $tokens, Context $context, int $parserContext): Type
+ {
+ $types = [];
+ $token = '';
+ $compoundToken = '|';
+ while ($tokens->valid()) {
+ $token = $tokens->current();
+ if ($token === null) {
+ throw new RuntimeException(
+ 'Unexpected nullable character'
+ );
+ }
+
+ if ($token === '|' || $token === '&') {
+ if (count($types) === 0) {
+ throw new RuntimeException(
+ 'A type is missing before a type separator'
+ );
+ }
+
+ if (
+ !in_array($parserContext, [
+ self::PARSER_IN_COMPOUND,
+ self::PARSER_IN_ARRAY_EXPRESSION,
+ self::PARSER_IN_COLLECTION_EXPRESSION,
+ ], true)
+ ) {
+ throw new RuntimeException(
+ 'Unexpected type separator'
+ );
+ }
+
+ $compoundToken = $token;
+ $tokens->next();
+ } elseif ($token === '?') {
+ if (
+ !in_array($parserContext, [
+ self::PARSER_IN_COMPOUND,
+ self::PARSER_IN_ARRAY_EXPRESSION,
+ self::PARSER_IN_COLLECTION_EXPRESSION,
+ ], true)
+ ) {
+ throw new RuntimeException(
+ 'Unexpected nullable character'
+ );
+ }
+
+ $tokens->next();
+ $type = $this->parseTypes($tokens, $context, self::PARSER_IN_NULLABLE);
+ $types[] = new Nullable($type);
+ } elseif ($token === '(') {
+ $tokens->next();
+ $type = $this->parseTypes($tokens, $context, self::PARSER_IN_ARRAY_EXPRESSION);
+
+ $token = $tokens->current();
+ if ($token === null) { // Someone did not properly close their array expression ..
+ break;
+ }
+
+ $tokens->next();
+
+ $resolvedType = new Expression($type);
+
+ $types[] = $resolvedType;
+ } elseif ($parserContext === self::PARSER_IN_ARRAY_EXPRESSION && isset($token[0]) && $token[0] === ')') {
+ break;
+ } elseif ($token === '<') {
+ if (count($types) === 0) {
+ throw new RuntimeException(
+ 'Unexpected collection operator "<", class name is missing'
+ );
+ }
+
+ $classType = array_pop($types);
+ if ($classType !== null) {
+ if ((string) $classType === 'class-string') {
+ $types[] = $this->resolveClassString($tokens, $context);
+ } elseif ((string) $classType === 'int') {
+ $types[] = $this->resolveIntRange($tokens);
+ } elseif ((string) $classType === 'interface-string') {
+ $types[] = $this->resolveInterfaceString($tokens, $context);
+ } else {
+ $types[] = $this->resolveCollection($tokens, $classType, $context);
+ }
+ }
+
+ $tokens->next();
+ } elseif (
+ $parserContext === self::PARSER_IN_COLLECTION_EXPRESSION
+ && ($token === '>' || trim($token) === ',')
+ ) {
+ break;
+ } elseif ($token === self::OPERATOR_ARRAY) {
+ end($types);
+ $last = key($types);
+ if ($last === null) {
+ throw new InvalidArgumentException('Unexpected array operator');
+ }
+
+ $lastItem = $types[$last];
+ if ($lastItem instanceof Expression) {
+ $lastItem = $lastItem->getValueType();
+ }
+
+ $types[$last] = new Array_($lastItem);
+
+ $tokens->next();
+ } else {
+ $type = $this->resolveSingleType($token, $context);
+ $tokens->next();
+ if ($parserContext === self::PARSER_IN_NULLABLE) {
+ return $type;
+ }
+
+ $types[] = $type;
+ }
+ }
+
+ if ($token === '|' || $token === '&') {
+ throw new RuntimeException(
+ 'A type is missing after a type separator'
+ );
+ }
+
+ if (count($types) === 0) {
+ if ($parserContext === self::PARSER_IN_NULLABLE) {
+ throw new RuntimeException(
+ 'A type is missing after a nullable character'
+ );
+ }
+
+ if ($parserContext === self::PARSER_IN_ARRAY_EXPRESSION) {
+ throw new RuntimeException(
+ 'A type is missing in an array expression'
+ );
+ }
+
+ if ($parserContext === self::PARSER_IN_COLLECTION_EXPRESSION) {
+ throw new RuntimeException(
+ 'A type is missing in a collection expression'
+ );
+ }
+ } elseif (count($types) === 1) {
+ return current($types);
+ }
+
+ if ($compoundToken === '|') {
+ return new Compound(array_values($types));
+ }
+
+ return new Intersection(array_values($types));
+ }
+
+ /**
+ * resolve the given type into a type object
+ *
+ * @param string $type the type string, representing a single type
+ *
+ * @return Type|Array_|Object_
+ *
+ * @psalm-mutation-free
+ */
+ private function resolveSingleType(string $type, Context $context): object
+ {
+ switch (true) {
+ case $this->isKeyword($type):
+ return $this->resolveKeyword($type);
+
+ case $this->isFqsen($type):
+ return $this->resolveTypedObject($type);
+
+ case $this->isPartialStructuralElementName($type):
+ return $this->resolveTypedObject($type, $context);
+
+ // @codeCoverageIgnoreStart
+ default:
+ // I haven't got the foggiest how the logic would come here but added this as a defense.
+ throw new RuntimeException(
+ 'Unable to resolve type "' . $type . '", there is no known method to resolve it'
+ );
+ }
+
+ // @codeCoverageIgnoreEnd
+ }
+
+ /**
+ * Adds a keyword to the list of Keywords and associates it with a specific Value Object.
+ *
+ * @psalm-param class-string<Type> $typeClassName
+ */
+ public function addKeyword(string $keyword, string $typeClassName): void
+ {
+ if (!class_exists($typeClassName)) {
+ throw new InvalidArgumentException(
+ 'The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class'
+ . ' but we could not find the class ' . $typeClassName
+ );
+ }
+
+ $interfaces = class_implements($typeClassName);
+ if ($interfaces === false) {
+ throw new InvalidArgumentException(
+ 'The Value Object that needs to be created with a keyword "' . $keyword . '" must be an existing class'
+ . ' but we could not find the class ' . $typeClassName
+ );
+ }
+
+ if (!in_array(Type::class, $interfaces, true)) {
+ throw new InvalidArgumentException(
+ 'The class "' . $typeClassName . '" must implement the interface "phpDocumentor\Reflection\Type"'
+ );
+ }
+
+ $this->keywords[$keyword] = $typeClassName;
+ }
+
+ /**
+ * Detects whether the given type represents a PHPDoc keyword.
+ *
+ * @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
+ *
+ * @psalm-mutation-free
+ */
+ private function isKeyword(string $type): bool
+ {
+ return array_key_exists(strtolower($type), $this->keywords);
+ }
+
+ /**
+ * Detects whether the given type represents a relative structural element name.
+ *
+ * @param string $type A relative or absolute type as defined in the phpDocumentor documentation.
+ *
+ * @psalm-mutation-free
+ */
+ private function isPartialStructuralElementName(string $type): bool
+ {
+ return (isset($type[0]) && $type[0] !== self::OPERATOR_NAMESPACE) && !$this->isKeyword($type);
+ }
+
+ /**
+ * Tests whether the given type is a Fully Qualified Structural Element Name.
+ *
+ * @psalm-mutation-free
+ */
+ private function isFqsen(string $type): bool
+ {
+ return strpos($type, self::OPERATOR_NAMESPACE) === 0;
+ }
+
+ /**
+ * Resolves the given keyword (such as `string`) into a Type object representing that keyword.
+ *
+ * @psalm-mutation-free
+ */
+ private function resolveKeyword(string $type): Type
+ {
+ $className = $this->keywords[strtolower($type)];
+
+ return new $className();
+ }
+
+ /**
+ * Resolves the given FQSEN string into an FQSEN object.
+ *
+ * @psalm-mutation-free
+ */
+ private function resolveTypedObject(string $type, ?Context $context = null): Object_
+ {
+ return new Object_($this->fqsenResolver->resolve($type, $context));
+ }
+
+ /**
+ * Resolves class string
+ *
+ * @param ArrayIterator<int, (string|null)> $tokens
+ */
+ private function resolveClassString(ArrayIterator $tokens, Context $context): Type
+ {
+ $tokens->next();
+
+ $classType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
+
+ if (!$classType instanceof Object_ || $classType->getFqsen() === null) {
+ throw new RuntimeException(
+ $classType . ' is not a class string'
+ );
+ }
+
+ $token = $tokens->current();
+ if ($token !== '>') {
+ if (empty($token)) {
+ throw new RuntimeException(
+ 'class-string: ">" is missing'
+ );
+ }
+
+ throw new RuntimeException(
+ 'Unexpected character "' . $token . '", ">" is missing'
+ );
+ }
+
+ return new ClassString($classType->getFqsen());
+ }
+
+ /**
+ * Resolves integer ranges
+ *
+ * @param ArrayIterator<int, (string|null)> $tokens
+ */
+ private function resolveIntRange(ArrayIterator $tokens): Type
+ {
+ $tokens->next();
+
+ $token = '';
+ $minValue = null;
+ $maxValue = null;
+ $commaFound = false;
+ $tokenCounter = 0;
+ while ($tokens->valid()) {
+ $tokenCounter++;
+ $token = $tokens->current();
+ if ($token === null) {
+ throw new RuntimeException(
+ 'Unexpected nullable character'
+ );
+ }
+
+ $token = trim($token);
+
+ if ($token === '>') {
+ break;
+ }
+
+ if ($token === ',') {
+ $commaFound = true;
+ }
+
+ if ($commaFound === false && $minValue === null) {
+ if (is_numeric($token) || $token === 'max' || $token === 'min') {
+ $minValue = $token;
+ }
+ }
+
+ if ($commaFound === true && $maxValue === null) {
+ if (is_numeric($token) || $token === 'max' || $token === 'min') {
+ $maxValue = $token;
+ }
+ }
+
+ $tokens->next();
+ }
+
+ if ($token !== '>') {
+ if (empty($token)) {
+ throw new RuntimeException(
+ 'interface-string: ">" is missing'
+ );
+ }
+
+ throw new RuntimeException(
+ 'Unexpected character "' . $token . '", ">" is missing'
+ );
+ }
+
+ if (!$minValue || !$maxValue || $tokenCounter > 4) {
+ throw new RuntimeException(
+ 'int<min,max> has not the correct format'
+ );
+ }
+
+ return new IntegerRange($minValue, $maxValue);
+ }
+
+ /**
+ * Resolves class string
+ *
+ * @param ArrayIterator<int, (string|null)> $tokens
+ */
+ private function resolveInterfaceString(ArrayIterator $tokens, Context $context): Type
+ {
+ $tokens->next();
+
+ $classType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
+
+ if (!$classType instanceof Object_ || $classType->getFqsen() === null) {
+ throw new RuntimeException(
+ $classType . ' is not a interface string'
+ );
+ }
+
+ $token = $tokens->current();
+ if ($token !== '>') {
+ if (empty($token)) {
+ throw new RuntimeException(
+ 'interface-string: ">" is missing'
+ );
+ }
+
+ throw new RuntimeException(
+ 'Unexpected character "' . $token . '", ">" is missing'
+ );
+ }
+
+ return new InterfaceString($classType->getFqsen());
+ }
+
+ /**
+ * Resolves the collection values and keys
+ *
+ * @param ArrayIterator<int, (string|null)> $tokens
+ *
+ * @return Array_|Iterable_|Collection
+ */
+ private function resolveCollection(ArrayIterator $tokens, Type $classType, Context $context): Type
+ {
+ $isArray = ((string) $classType === 'array');
+ $isIterable = ((string) $classType === 'iterable');
+ $isList = ((string) $classType === 'list');
+
+ // allow only "array", "iterable" or class name before "<"
+ if (
+ !$isArray && !$isIterable && !$isList
+ && (!$classType instanceof Object_ || $classType->getFqsen() === null)
+ ) {
+ throw new RuntimeException(
+ $classType . ' is not a collection'
+ );
+ }
+
+ $tokens->next();
+
+ $valueType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
+ $keyType = null;
+
+ $token = $tokens->current();
+ if ($token !== null && trim($token) === ',' && !$isList) {
+ // if we have a comma, then we just parsed the key type, not the value type
+ $keyType = $valueType;
+ if ($isArray) {
+ // check the key type for an "array" collection. We allow only
+ // strings or integers.
+ if (
+ !$keyType instanceof ArrayKey &&
+ !$keyType instanceof String_ &&
+ !$keyType instanceof Integer &&
+ !$keyType instanceof Compound
+ ) {
+ throw new RuntimeException(
+ 'An array can have only integers or strings as keys'
+ );
+ }
+
+ if ($keyType instanceof Compound) {
+ foreach ($keyType->getIterator() as $item) {
+ if (
+ !$item instanceof ArrayKey &&
+ !$item instanceof String_ &&
+ !$item instanceof Integer
+ ) {
+ throw new RuntimeException(
+ 'An array can have only integers or strings as keys'
+ );
+ }
+ }
+ }
+ }
+
+ $tokens->next();
+ // now let's parse the value type
+ $valueType = $this->parseTypes($tokens, $context, self::PARSER_IN_COLLECTION_EXPRESSION);
+ }
+
+ $token = $tokens->current();
+ if ($token !== '>') {
+ if (empty($token)) {
+ throw new RuntimeException(
+ 'Collection: ">" is missing'
+ );
+ }
+
+ throw new RuntimeException(
+ 'Unexpected character "' . $token . '", ">" is missing'
+ );
+ }
+
+ if ($isArray) {
+ return new Array_($valueType, $keyType);
+ }
+
+ if ($isIterable) {
+ return new Iterable_($valueType, $keyType);
+ }
+
+ if ($isList) {
+ return new List_($valueType);
+ }
+
+ if ($classType instanceof Object_) {
+ return $this->makeCollectionFromObject($classType, $valueType, $keyType);
+ }
+
+ throw new RuntimeException('Invalid $classType provided');
+ }
+
+ /**
+ * @psalm-pure
+ */
+ private function makeCollectionFromObject(Object_ $object, Type $valueType, ?Type $keyType = null): Collection
+ {
+ return new Collection($object->getFqsen(), $valueType, $keyType);
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/AbstractList.php b/vendor/phpdocumentor/type-resolver/src/Types/AbstractList.php
new file mode 100644
index 000000000..b674862af
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/AbstractList.php
@@ -0,0 +1,83 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Represents a list of values. This is an abstract class for Array_ and Collection.
+ *
+ * @psalm-immutable
+ */
+abstract class AbstractList implements Type
+{
+ /** @var Type */
+ protected $valueType;
+
+ /** @var Type|null */
+ protected $keyType;
+
+ /** @var Type */
+ protected $defaultKeyType;
+
+ /**
+ * Initializes this representation of an array with the given Type.
+ */
+ public function __construct(?Type $valueType = null, ?Type $keyType = null)
+ {
+ if ($valueType === null) {
+ $valueType = new Mixed_();
+ }
+
+ $this->valueType = $valueType;
+ $this->defaultKeyType = new Compound([new String_(), new Integer()]);
+ $this->keyType = $keyType;
+ }
+
+ /**
+ * Returns the type for the keys of this array.
+ */
+ public function getKeyType(): Type
+ {
+ return $this->keyType ?? $this->defaultKeyType;
+ }
+
+ /**
+ * Returns the value for the keys of this array.
+ */
+ public function getValueType(): Type
+ {
+ return $this->valueType;
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ if ($this->keyType) {
+ return 'array<' . $this->keyType . ',' . $this->valueType . '>';
+ }
+
+ if ($this->valueType instanceof Mixed_) {
+ return 'array';
+ }
+
+ if ($this->valueType instanceof Compound) {
+ return '(' . $this->valueType . ')[]';
+ }
+
+ return $this->valueType . '[]';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php b/vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php
new file mode 100644
index 000000000..472a1cdc6
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/AggregatedType.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * This file is part of phpDocumentor.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @link http://phpdoc.org
+ */
+
+declare(strict_types=1);
+
+namespace phpDocumentor\Reflection\Types;
+
+use ArrayIterator;
+use IteratorAggregate;
+use phpDocumentor\Reflection\Type;
+
+use function array_key_exists;
+use function implode;
+
+/**
+ * Base class for aggregated types like Compound and Intersection
+ *
+ * A Aggregated Type is not so much a special keyword or object reference but is a series of Types that are separated
+ * using separator.
+ *
+ * @psalm-immutable
+ * @template-implements IteratorAggregate<int, Type>
+ */
+abstract class AggregatedType implements Type, IteratorAggregate
+{
+ /**
+ * @psalm-allow-private-mutation
+ * @var array<int, Type>
+ */
+ private $types = [];
+
+ /** @var string */
+ private $token;
+
+ /**
+ * @param array<Type> $types
+ */
+ public function __construct(array $types, string $token)
+ {
+ foreach ($types as $type) {
+ $this->add($type);
+ }
+
+ $this->token = $token;
+ }
+
+ /**
+ * Returns the type at the given index.
+ */
+ public function get(int $index): ?Type
+ {
+ if (!$this->has($index)) {
+ return null;
+ }
+
+ return $this->types[$index];
+ }
+
+ /**
+ * Tests if this compound type has a type with the given index.
+ */
+ public function has(int $index): bool
+ {
+ return array_key_exists($index, $this->types);
+ }
+
+ /**
+ * Tests if this compound type contains the given type.
+ */
+ public function contains(Type $type): bool
+ {
+ foreach ($this->types as $typePart) {
+ // if the type is duplicate; do not add it
+ if ((string) $typePart === (string) $type) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return implode($this->token, $this->types);
+ }
+
+ /**
+ * @return ArrayIterator<int, Type>
+ */
+ public function getIterator(): ArrayIterator
+ {
+ return new ArrayIterator($this->types);
+ }
+
+ /**
+ * @psalm-suppress ImpureMethodCall
+ */
+ private function add(Type $type): void
+ {
+ if ($type instanceof self) {
+ foreach ($type->getIterator() as $subType) {
+ $this->add($subType);
+ }
+
+ return;
+ }
+
+ // if the type is duplicate; do not add it
+ if ($this->contains($type)) {
+ return;
+ }
+
+ $this->types[] = $type;
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/ArrayKey.php b/vendor/phpdocumentor/type-resolver/src/Types/ArrayKey.php
new file mode 100644
index 000000000..cf86df007
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/ArrayKey.php
@@ -0,0 +1,42 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing a array-key Type.
+ *
+ * A array-key Type is the supertype (but not a union) of int and string.
+ *
+ * @psalm-immutable
+ */
+final class ArrayKey extends AggregatedType implements PseudoType
+{
+ public function __construct()
+ {
+ parent::__construct([new String_(), new Integer()], '|');
+ }
+
+ public function underlyingType(): Type
+ {
+ return new Compound([new String_(), new Integer()]);
+ }
+
+ public function __toString(): string
+ {
+ return 'array-key';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Array_.php b/vendor/phpdocumentor/type-resolver/src/Types/Array_.php
new file mode 100644
index 000000000..bc17225f5
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Array_.php
@@ -0,0 +1,29 @@
+<?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\Types;
+
+/**
+ * Represents an array type as described in the PSR-5, the PHPDoc Standard.
+ *
+ * An array can be represented in two forms:
+ *
+ * 1. Untyped (`array`), where the key and value type is unknown and hence classified as 'Mixed_'.
+ * 2. Types (`string[]`), where the value type is provided by preceding an opening and closing square bracket with a
+ * type name.
+ *
+ * @psalm-immutable
+ */
+class Array_ extends AbstractList
+{
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Boolean.php b/vendor/phpdocumentor/type-resolver/src/Types/Boolean.php
new file mode 100644
index 000000000..8b1a3f34e
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Boolean.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing a Boolean type.
+ *
+ * @psalm-immutable
+ */
+class Boolean implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'bool';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Callable_.php b/vendor/phpdocumentor/type-resolver/src/Types/Callable_.php
new file mode 100644
index 000000000..4e67aa4a0
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Callable_.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing a Callable type.
+ *
+ * @psalm-immutable
+ */
+final class Callable_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'callable';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/ClassString.php b/vendor/phpdocumentor/type-resolver/src/Types/ClassString.php
new file mode 100644
index 000000000..fbdd879bb
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/ClassString.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\Types;
+
+use phpDocumentor\Reflection\Fqsen;
+use phpDocumentor\Reflection\PseudoType;
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class ClassString extends String_ implements PseudoType
+{
+ /** @var Fqsen|null */
+ private $fqsen;
+
+ /**
+ * Initializes this representation of a class string with the given Fqsen.
+ */
+ public function __construct(?Fqsen $fqsen = null)
+ {
+ $this->fqsen = $fqsen;
+ }
+
+ public function underlyingType(): Type
+ {
+ return new String_();
+ }
+
+ /**
+ * Returns the FQSEN associated with this object.
+ */
+ public function getFqsen(): ?Fqsen
+ {
+ return $this->fqsen;
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ if ($this->fqsen === null) {
+ return 'class-string';
+ }
+
+ return 'class-string<' . (string) $this->fqsen . '>';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Collection.php b/vendor/phpdocumentor/type-resolver/src/Types/Collection.php
new file mode 100644
index 000000000..943cc22e5
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Collection.php
@@ -0,0 +1,68 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Fqsen;
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Represents a collection type as described in the PSR-5, the PHPDoc Standard.
+ *
+ * A collection can be represented in two forms:
+ *
+ * 1. `ACollectionObject<aValueType>`
+ * 2. `ACollectionObject<aValueType,aKeyType>`
+ *
+ * - ACollectionObject can be 'array' or an object that can act as an array
+ * - aValueType and aKeyType can be any type expression
+ *
+ * @psalm-immutable
+ */
+final class Collection extends AbstractList
+{
+ /** @var Fqsen|null */
+ private $fqsen;
+
+ /**
+ * Initializes this representation of an array with the given Type or Fqsen.
+ */
+ public function __construct(?Fqsen $fqsen, Type $valueType, ?Type $keyType = null)
+ {
+ parent::__construct($valueType, $keyType);
+
+ $this->fqsen = $fqsen;
+ }
+
+ /**
+ * Returns the FQSEN associated with this object.
+ */
+ public function getFqsen(): ?Fqsen
+ {
+ return $this->fqsen;
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ $objectType = (string) ($this->fqsen ?? 'object');
+
+ if ($this->keyType === null) {
+ return $objectType . '<' . $this->valueType . '>';
+ }
+
+ return $objectType . '<' . $this->keyType . ',' . $this->valueType . '>';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Compound.php b/vendor/phpdocumentor/type-resolver/src/Types/Compound.php
new file mode 100644
index 000000000..ad426cc2c
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Compound.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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing a Compound Type.
+ *
+ * A Compound Type is not so much a special keyword or object reference but is a series of Types that are separated
+ * using an OR operator (`|`). This combination of types signifies that whatever is associated with this compound type
+ * may contain a value with any of the given types.
+ *
+ * @psalm-immutable
+ */
+final class Compound extends AggregatedType
+{
+ /**
+ * Initializes a compound type (i.e. `string|int`) and tests if the provided types all implement the Type interface.
+ *
+ * @param array<Type> $types
+ */
+ public function __construct(array $types)
+ {
+ parent::__construct($types, '|');
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Context.php b/vendor/phpdocumentor/type-resolver/src/Types/Context.php
new file mode 100644
index 000000000..79aadaf88
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Context.php
@@ -0,0 +1,95 @@
+<?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\Types;
+
+use function strlen;
+use function substr;
+use function trim;
+
+/**
+ * Provides information about the Context in which the DocBlock occurs that receives this context.
+ *
+ * A DocBlock does not know of its own accord in which namespace it occurs and which namespace aliases are applicable
+ * for the block of code in which it is in. This information is however necessary to resolve Class names in tags since
+ * you can provide a short form or make use of namespace aliases.
+ *
+ * The phpDocumentor Reflection component knows how to create this class but if you use the DocBlock parser from your
+ * own application it is possible to generate a Context class using the ContextFactory; this will analyze the file in
+ * which an associated class resides for its namespace and imports.
+ *
+ * @see ContextFactory::createFromClassReflector()
+ * @see ContextFactory::createForNamespace()
+ *
+ * @psalm-immutable
+ */
+final class Context
+{
+ /** @var string The current namespace. */
+ private $namespace;
+
+ /**
+ * @var string[] List of namespace aliases => Fully Qualified Namespace.
+ * @psalm-var array<string, string>
+ */
+ private $namespaceAliases;
+
+ /**
+ * Initializes the new context and normalizes all passed namespaces to be in Qualified Namespace Name (QNN)
+ * format (without a preceding `\`).
+ *
+ * @param string $namespace The namespace where this DocBlock resides in.
+ * @param string[] $namespaceAliases List of namespace aliases => Fully Qualified Namespace.
+ * @psalm-param array<string, string> $namespaceAliases
+ */
+ public function __construct(string $namespace, array $namespaceAliases = [])
+ {
+ $this->namespace = $namespace !== 'global' && $namespace !== 'default'
+ ? trim($namespace, '\\')
+ : '';
+
+ foreach ($namespaceAliases as $alias => $fqnn) {
+ if ($fqnn[0] === '\\') {
+ $fqnn = substr($fqnn, 1);
+ }
+
+ if ($fqnn[strlen($fqnn) - 1] === '\\') {
+ $fqnn = substr($fqnn, 0, -1);
+ }
+
+ $namespaceAliases[$alias] = $fqnn;
+ }
+
+ $this->namespaceAliases = $namespaceAliases;
+ }
+
+ /**
+ * Returns the Qualified Namespace Name (thus without `\` in front) where the associated element is in.
+ */
+ public function getNamespace(): string
+ {
+ return $this->namespace;
+ }
+
+ /**
+ * Returns a list of Qualified Namespace Names (thus without `\` in front) that are imported, the keys represent
+ * the alias for the imported Namespace.
+ *
+ * @return string[]
+ * @psalm-return array<string, string>
+ */
+ public function getNamespaceAliases(): array
+ {
+ return $this->namespaceAliases;
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/ContextFactory.php b/vendor/phpdocumentor/type-resolver/src/Types/ContextFactory.php
new file mode 100644
index 000000000..892ee0f90
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/ContextFactory.php
@@ -0,0 +1,420 @@
+<?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\Types;
+
+use ArrayIterator;
+use InvalidArgumentException;
+use ReflectionClass;
+use ReflectionClassConstant;
+use ReflectionMethod;
+use ReflectionParameter;
+use ReflectionProperty;
+use Reflector;
+use RuntimeException;
+use UnexpectedValueException;
+
+use function define;
+use function defined;
+use function file_exists;
+use function file_get_contents;
+use function get_class;
+use function in_array;
+use function is_string;
+use function strrpos;
+use function substr;
+use function token_get_all;
+use function trim;
+
+use const T_AS;
+use const T_CLASS;
+use const T_CURLY_OPEN;
+use const T_DOLLAR_OPEN_CURLY_BRACES;
+use const T_NAME_FULLY_QUALIFIED;
+use const T_NAME_QUALIFIED;
+use const T_NAMESPACE;
+use const T_NS_SEPARATOR;
+use const T_STRING;
+use const T_USE;
+
+if (!defined('T_NAME_QUALIFIED')) {
+ define('T_NAME_QUALIFIED', 'T_NAME_QUALIFIED');
+}
+
+if (!defined('T_NAME_FULLY_QUALIFIED')) {
+ define('T_NAME_FULLY_QUALIFIED', 'T_NAME_FULLY_QUALIFIED');
+}
+
+/**
+ * Convenience class to create a Context for DocBlocks when not using the Reflection Component of phpDocumentor.
+ *
+ * For a DocBlock to be able to resolve types that use partial namespace names or rely on namespace imports we need to
+ * provide a bit of context so that the DocBlock can read that and based on it decide how to resolve the types to
+ * Fully Qualified names.
+ *
+ * @see Context for more information.
+ */
+final class ContextFactory
+{
+ /** The literal used at the end of a use statement. */
+ private const T_LITERAL_END_OF_USE = ';';
+
+ /** The literal used between sets of use statements */
+ private const T_LITERAL_USE_SEPARATOR = ',';
+
+ /**
+ * Build a Context given a Class Reflection.
+ *
+ * @see Context for more information on Contexts.
+ */
+ public function createFromReflector(Reflector $reflector): Context
+ {
+ if ($reflector instanceof ReflectionClass) {
+ //phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable
+ /** @var ReflectionClass<object> $reflector */
+
+ return $this->createFromReflectionClass($reflector);
+ }
+
+ if ($reflector instanceof ReflectionParameter) {
+ return $this->createFromReflectionParameter($reflector);
+ }
+
+ if ($reflector instanceof ReflectionMethod) {
+ return $this->createFromReflectionMethod($reflector);
+ }
+
+ if ($reflector instanceof ReflectionProperty) {
+ return $this->createFromReflectionProperty($reflector);
+ }
+
+ if ($reflector instanceof ReflectionClassConstant) {
+ return $this->createFromReflectionClassConstant($reflector);
+ }
+
+ throw new UnexpectedValueException('Unhandled \Reflector instance given: ' . get_class($reflector));
+ }
+
+ private function createFromReflectionParameter(ReflectionParameter $parameter): Context
+ {
+ $class = $parameter->getDeclaringClass();
+ if (!$class) {
+ throw new InvalidArgumentException('Unable to get class of ' . $parameter->getName());
+ }
+
+ return $this->createFromReflectionClass($class);
+ }
+
+ private function createFromReflectionMethod(ReflectionMethod $method): Context
+ {
+ $class = $method->getDeclaringClass();
+
+ return $this->createFromReflectionClass($class);
+ }
+
+ private function createFromReflectionProperty(ReflectionProperty $property): Context
+ {
+ $class = $property->getDeclaringClass();
+
+ return $this->createFromReflectionClass($class);
+ }
+
+ private function createFromReflectionClassConstant(ReflectionClassConstant $constant): Context
+ {
+ //phpcs:ignore SlevomatCodingStandard.Commenting.InlineDocCommentDeclaration.MissingVariable
+ /** @phpstan-var ReflectionClass<object> $class */
+ $class = $constant->getDeclaringClass();
+
+ return $this->createFromReflectionClass($class);
+ }
+
+ /**
+ * @phpstan-param ReflectionClass<object> $class
+ */
+ private function createFromReflectionClass(ReflectionClass $class): Context
+ {
+ $fileName = $class->getFileName();
+ $namespace = $class->getNamespaceName();
+
+ if (is_string($fileName) && file_exists($fileName)) {
+ $contents = file_get_contents($fileName);
+ if ($contents === false) {
+ throw new RuntimeException('Unable to read file "' . $fileName . '"');
+ }
+
+ return $this->createForNamespace($namespace, $contents);
+ }
+
+ return new Context($namespace, []);
+ }
+
+ /**
+ * Build a Context for a namespace in the provided file contents.
+ *
+ * @see Context for more information on Contexts.
+ *
+ * @param string $namespace It does not matter if a `\` precedes the namespace name,
+ * this method first normalizes.
+ * @param string $fileContents The file's contents to retrieve the aliases from with the given namespace.
+ */
+ public function createForNamespace(string $namespace, string $fileContents): Context
+ {
+ $namespace = trim($namespace, '\\');
+ $useStatements = [];
+ $currentNamespace = '';
+ $tokens = new ArrayIterator(token_get_all($fileContents));
+
+ while ($tokens->valid()) {
+ $currentToken = $tokens->current();
+ switch ($currentToken[0]) {
+ case T_NAMESPACE:
+ $currentNamespace = $this->parseNamespace($tokens);
+ break;
+ case T_CLASS:
+ // Fast-forward the iterator through the class so that any
+ // T_USE tokens found within are skipped - these are not
+ // valid namespace use statements so should be ignored.
+ $braceLevel = 0;
+ $firstBraceFound = false;
+ while ($tokens->valid() && ($braceLevel > 0 || !$firstBraceFound)) {
+ $currentToken = $tokens->current();
+ if (
+ $currentToken === '{'
+ || in_array($currentToken[0], [T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES], true)
+ ) {
+ if (!$firstBraceFound) {
+ $firstBraceFound = true;
+ }
+
+ ++$braceLevel;
+ }
+
+ if ($currentToken === '}') {
+ --$braceLevel;
+ }
+
+ $tokens->next();
+ }
+
+ break;
+ case T_USE:
+ if ($currentNamespace === $namespace) {
+ $useStatements += $this->parseUseStatement($tokens);
+ }
+
+ break;
+ }
+
+ $tokens->next();
+ }
+
+ return new Context($namespace, $useStatements);
+ }
+
+ /**
+ * Deduce the name from tokens when we are at the T_NAMESPACE token.
+ *
+ * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
+ */
+ private function parseNamespace(ArrayIterator $tokens): string
+ {
+ // skip to the first string or namespace separator
+ $this->skipToNextStringOrNamespaceSeparator($tokens);
+
+ $name = '';
+ $acceptedTokens = [T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED];
+ while ($tokens->valid() && in_array($tokens->current()[0], $acceptedTokens, true)) {
+ $name .= $tokens->current()[1];
+ $tokens->next();
+ }
+
+ return $name;
+ }
+
+ /**
+ * Deduce the names of all imports when we are at the T_USE token.
+ *
+ * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
+ *
+ * @return string[]
+ * @psalm-return array<string, string>
+ */
+ private function parseUseStatement(ArrayIterator $tokens): array
+ {
+ $uses = [];
+
+ while ($tokens->valid()) {
+ $this->skipToNextStringOrNamespaceSeparator($tokens);
+
+ $uses += $this->extractUseStatements($tokens);
+ $currentToken = $tokens->current();
+ if ($currentToken[0] === self::T_LITERAL_END_OF_USE) {
+ return $uses;
+ }
+ }
+
+ return $uses;
+ }
+
+ /**
+ * Fast-forwards the iterator as longs as we don't encounter a T_STRING or T_NS_SEPARATOR token.
+ *
+ * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
+ */
+ private function skipToNextStringOrNamespaceSeparator(ArrayIterator $tokens): void
+ {
+ while ($tokens->valid()) {
+ $currentToken = $tokens->current();
+ if (in_array($currentToken[0], [T_STRING, T_NS_SEPARATOR], true)) {
+ break;
+ }
+
+ if ($currentToken[0] === T_NAME_QUALIFIED) {
+ break;
+ }
+
+ if (defined('T_NAME_FULLY_QUALIFIED') && $currentToken[0] === T_NAME_FULLY_QUALIFIED) {
+ break;
+ }
+
+ $tokens->next();
+ }
+ }
+
+ /**
+ * Deduce the namespace name and alias of an import when we are at the T_USE token or have not reached the end of
+ * a USE statement yet. This will return a key/value array of the alias => namespace.
+ *
+ * @param ArrayIterator<int, string|array{0:int,1:string,2:int}> $tokens
+ *
+ * @return string[]
+ * @psalm-return array<string, string>
+ *
+ * @psalm-suppress TypeDoesNotContainType
+ */
+ private function extractUseStatements(ArrayIterator $tokens): array
+ {
+ $extractedUseStatements = [];
+ $groupedNs = '';
+ $currentNs = '';
+ $currentAlias = '';
+ $state = 'start';
+
+ while ($tokens->valid()) {
+ $currentToken = $tokens->current();
+ $tokenId = is_string($currentToken) ? $currentToken : $currentToken[0];
+ $tokenValue = is_string($currentToken) ? null : $currentToken[1];
+ switch ($state) {
+ case 'start':
+ switch ($tokenId) {
+ case T_STRING:
+ case T_NS_SEPARATOR:
+ $currentNs .= (string) $tokenValue;
+ $currentAlias = $tokenValue;
+ break;
+ case T_NAME_QUALIFIED:
+ case T_NAME_FULLY_QUALIFIED:
+ $currentNs .= (string) $tokenValue;
+ $currentAlias = substr(
+ (string) $tokenValue,
+ (int) (strrpos((string) $tokenValue, '\\')) + 1
+ );
+ break;
+ case T_CURLY_OPEN:
+ case '{':
+ $state = 'grouped';
+ $groupedNs = $currentNs;
+ break;
+ case T_AS:
+ $state = 'start-alias';
+ break;
+ case self::T_LITERAL_USE_SEPARATOR:
+ case self::T_LITERAL_END_OF_USE:
+ $state = 'end';
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case 'start-alias':
+ switch ($tokenId) {
+ case T_STRING:
+ $currentAlias = $tokenValue;
+ break;
+ case self::T_LITERAL_USE_SEPARATOR:
+ case self::T_LITERAL_END_OF_USE:
+ $state = 'end';
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case 'grouped':
+ switch ($tokenId) {
+ case T_STRING:
+ case T_NS_SEPARATOR:
+ $currentNs .= (string) $tokenValue;
+ $currentAlias = $tokenValue;
+ break;
+ case T_AS:
+ $state = 'grouped-alias';
+ break;
+ case self::T_LITERAL_USE_SEPARATOR:
+ $state = 'grouped';
+ $extractedUseStatements[(string) $currentAlias] = $currentNs;
+ $currentNs = $groupedNs;
+ $currentAlias = '';
+ break;
+ case self::T_LITERAL_END_OF_USE:
+ $state = 'end';
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case 'grouped-alias':
+ switch ($tokenId) {
+ case T_STRING:
+ $currentAlias = $tokenValue;
+ break;
+ case self::T_LITERAL_USE_SEPARATOR:
+ $state = 'grouped';
+ $extractedUseStatements[(string) $currentAlias] = $currentNs;
+ $currentNs = $groupedNs;
+ $currentAlias = '';
+ break;
+ case self::T_LITERAL_END_OF_USE:
+ $state = 'end';
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ($state === 'end') {
+ break;
+ }
+
+ $tokens->next();
+ }
+
+ if ($groupedNs !== $currentNs) {
+ $extractedUseStatements[(string) $currentAlias] = $currentNs;
+ }
+
+ return $extractedUseStatements;
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Expression.php b/vendor/phpdocumentor/type-resolver/src/Types/Expression.php
new file mode 100644
index 000000000..da5f65d59
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Expression.php
@@ -0,0 +1,51 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Represents an expression type as described in the PSR-5, the PHPDoc Standard.
+ *
+ * @psalm-immutable
+ */
+final class Expression implements Type
+{
+ /** @var Type */
+ protected $valueType;
+
+ /**
+ * Initializes this representation of an array with the given Type.
+ */
+ public function __construct(Type $valueType)
+ {
+ $this->valueType = $valueType;
+ }
+
+ /**
+ * Returns the value for the keys of this array.
+ */
+ public function getValueType(): Type
+ {
+ return $this->valueType;
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return '(' . $this->valueType . ')';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Float_.php b/vendor/phpdocumentor/type-resolver/src/Types/Float_.php
new file mode 100644
index 000000000..86138c0e7
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Float_.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing a Float.
+ *
+ * @psalm-immutable
+ */
+final class Float_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'float';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Integer.php b/vendor/phpdocumentor/type-resolver/src/Types/Integer.php
new file mode 100644
index 000000000..10ce3c58c
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Integer.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value object representing Integer type
+ *
+ * @psalm-immutable
+ */
+class Integer implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'int';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/InterfaceString.php b/vendor/phpdocumentor/type-resolver/src/Types/InterfaceString.php
new file mode 100644
index 000000000..9836961fd
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/InterfaceString.php
@@ -0,0 +1,56 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Fqsen;
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+final class InterfaceString implements Type
+{
+ /** @var Fqsen|null */
+ private $fqsen;
+
+ /**
+ * Initializes this representation of a class string with the given Fqsen.
+ */
+ public function __construct(?Fqsen $fqsen = null)
+ {
+ $this->fqsen = $fqsen;
+ }
+
+ /**
+ * Returns the FQSEN associated with this object.
+ */
+ public function getFqsen(): ?Fqsen
+ {
+ return $this->fqsen;
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ if ($this->fqsen === null) {
+ return 'interface-string';
+ }
+
+ return 'interface-string<' . (string) $this->fqsen . '>';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Intersection.php b/vendor/phpdocumentor/type-resolver/src/Types/Intersection.php
new file mode 100644
index 000000000..ced37b626
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Intersection.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * This file is part of phpDocumentor.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @link http://phpdoc.org
+ */
+
+declare(strict_types=1);
+
+namespace phpDocumentor\Reflection\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing a Compound Type.
+ *
+ * A Intersection Type is not so much a special keyword or object reference but is a series of Types that are separated
+ * using an AND operator (`&`). This combination of types signifies that whatever is associated with this Intersection
+ * type may contain a value with any of the given types.
+ *
+ * @psalm-immutable
+ */
+final class Intersection extends AggregatedType
+{
+ /**
+ * Initializes a intersection type (i.e. `\A&\B`) and tests if the provided types all implement the Type interface.
+ *
+ * @param array<Type> $types
+ */
+ public function __construct(array $types)
+ {
+ parent::__construct($types, '&');
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Iterable_.php b/vendor/phpdocumentor/type-resolver/src/Types/Iterable_.php
new file mode 100644
index 000000000..1ca069f2e
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Iterable_.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\Types;
+
+/**
+ * Value Object representing iterable type
+ *
+ * @psalm-immutable
+ */
+final class Iterable_ extends AbstractList
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ if ($this->keyType) {
+ return 'iterable<' . $this->keyType . ',' . $this->valueType . '>';
+ }
+
+ if ($this->valueType instanceof Mixed_) {
+ return 'iterable';
+ }
+
+ return 'iterable<' . $this->valueType . '>';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Mixed_.php b/vendor/phpdocumentor/type-resolver/src/Types/Mixed_.php
new file mode 100644
index 000000000..56d1b6dab
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Mixed_.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing an unknown, or mixed, type.
+ *
+ * @psalm-immutable
+ */
+final class Mixed_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'mixed';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Never_.php b/vendor/phpdocumentor/type-resolver/src/Types/Never_.php
new file mode 100644
index 000000000..40a99c9ad
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Never_.php
@@ -0,0 +1,35 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the return-type 'never'.
+ *
+ * Never is generally only used when working with return types as it signifies that the method that only
+ * ever throw or exit.
+ *
+ * @psalm-immutable
+ */
+final class Never_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'never';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Null_.php b/vendor/phpdocumentor/type-resolver/src/Types/Null_.php
new file mode 100644
index 000000000..7ae802c4c
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Null_.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing a null value or type.
+ *
+ * @psalm-immutable
+ */
+final class Null_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'null';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Nullable.php b/vendor/phpdocumentor/type-resolver/src/Types/Nullable.php
new file mode 100644
index 000000000..a94693507
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Nullable.php
@@ -0,0 +1,51 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing a nullable type. The real type is wrapped.
+ *
+ * @psalm-immutable
+ */
+final class Nullable implements Type
+{
+ /** @var Type The actual type that is wrapped */
+ private $realType;
+
+ /**
+ * Initialises this nullable type using the real type embedded
+ */
+ public function __construct(Type $realType)
+ {
+ $this->realType = $realType;
+ }
+
+ /**
+ * Provide access to the actual type directly, if needed.
+ */
+ public function getActualType(): Type
+ {
+ return $this->realType;
+ }
+
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return '?' . $this->realType->__toString();
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Object_.php b/vendor/phpdocumentor/type-resolver/src/Types/Object_.php
new file mode 100644
index 000000000..90dee57ac
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Object_.php
@@ -0,0 +1,69 @@
+<?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\Types;
+
+use InvalidArgumentException;
+use phpDocumentor\Reflection\Fqsen;
+use phpDocumentor\Reflection\Type;
+
+use function strpos;
+
+/**
+ * Value Object representing an object.
+ *
+ * An object can be either typed or untyped. When an object is typed it means that it has an identifier, the FQSEN,
+ * pointing to an element in PHP. Object types that are untyped do not refer to a specific class but represent objects
+ * in general.
+ *
+ * @psalm-immutable
+ */
+final class Object_ implements Type
+{
+ /** @var Fqsen|null */
+ private $fqsen;
+
+ /**
+ * Initializes this object with an optional FQSEN, if not provided this object is considered 'untyped'.
+ *
+ * @throws InvalidArgumentException When provided $fqsen is not a valid type.
+ */
+ public function __construct(?Fqsen $fqsen = null)
+ {
+ if (strpos((string) $fqsen, '::') !== false || strpos((string) $fqsen, '()') !== false) {
+ throw new InvalidArgumentException(
+ 'Object types can only refer to a class, interface or trait but a method, function, constant or '
+ . 'property was received: ' . (string) $fqsen
+ );
+ }
+
+ $this->fqsen = $fqsen;
+ }
+
+ /**
+ * Returns the FQSEN associated with this object.
+ */
+ public function getFqsen(): ?Fqsen
+ {
+ return $this->fqsen;
+ }
+
+ public function __toString(): string
+ {
+ if ($this->fqsen) {
+ return (string) $this->fqsen;
+ }
+
+ return 'object';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Parent_.php b/vendor/phpdocumentor/type-resolver/src/Types/Parent_.php
new file mode 100644
index 000000000..348385991
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Parent_.php
@@ -0,0 +1,34 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the 'parent' type.
+ *
+ * Parent, as a Type, represents the parent class of class in which the associated element was defined.
+ *
+ * @psalm-immutable
+ */
+final class Parent_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'parent';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Resource_.php b/vendor/phpdocumentor/type-resolver/src/Types/Resource_.php
new file mode 100644
index 000000000..1998ee0ad
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Resource_.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the 'resource' Type.
+ *
+ * @psalm-immutable
+ */
+final class Resource_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'resource';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Scalar.php b/vendor/phpdocumentor/type-resolver/src/Types/Scalar.php
new file mode 100644
index 000000000..80241c21e
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Scalar.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the 'scalar' pseudo-type, which is either a string, integer, float or boolean.
+ *
+ * @psalm-immutable
+ */
+final class Scalar implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'scalar';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Self_.php b/vendor/phpdocumentor/type-resolver/src/Types/Self_.php
new file mode 100644
index 000000000..5096126e5
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Self_.php
@@ -0,0 +1,34 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the 'self' type.
+ *
+ * Self, as a Type, represents the class in which the associated element was defined.
+ *
+ * @psalm-immutable
+ */
+final class Self_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'self';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Static_.php b/vendor/phpdocumentor/type-resolver/src/Types/Static_.php
new file mode 100644
index 000000000..6fe365ff1
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Static_.php
@@ -0,0 +1,39 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the 'static' type.
+ *
+ * Self, as a Type, represents the class in which the associated element was called. This differs from self as self does
+ * not take inheritance into account but static means that the return type is always that of the class of the called
+ * element.
+ *
+ * See the documentation on late static binding in the PHP Documentation for more information on the difference between
+ * static and self.
+ *
+ * @psalm-immutable
+ */
+final class Static_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'static';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/String_.php b/vendor/phpdocumentor/type-resolver/src/Types/String_.php
new file mode 100644
index 000000000..a4bb47f1a
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/String_.php
@@ -0,0 +1,32 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the type 'string'.
+ *
+ * @psalm-immutable
+ */
+class String_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'string';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/This.php b/vendor/phpdocumentor/type-resolver/src/Types/This.php
new file mode 100644
index 000000000..602fc698f
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/This.php
@@ -0,0 +1,35 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the '$this' pseudo-type.
+ *
+ * $this, as a Type, represents the instance of the class associated with the element as it was called. $this is
+ * commonly used when documenting fluent interfaces since it represents that the same object is returned.
+ *
+ * @psalm-immutable
+ */
+final class This implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return '$this';
+ }
+}
diff --git a/vendor/phpdocumentor/type-resolver/src/Types/Void_.php b/vendor/phpdocumentor/type-resolver/src/Types/Void_.php
new file mode 100644
index 000000000..23a601d47
--- /dev/null
+++ b/vendor/phpdocumentor/type-resolver/src/Types/Void_.php
@@ -0,0 +1,35 @@
+<?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\Types;
+
+use phpDocumentor\Reflection\Type;
+
+/**
+ * Value Object representing the return-type 'void'.
+ *
+ * Void is generally only used when working with return types as it signifies that the method intentionally does not
+ * return any value.
+ *
+ * @psalm-immutable
+ */
+final class Void_ implements Type
+{
+ /**
+ * Returns a rendered output of the Type as it would be used in a DocBlock.
+ */
+ public function __toString(): string
+ {
+ return 'void';
+ }
+}